feat: support prebuilt VPP packages (runtime-v4 upload + arduino-cli mixed compile/link) - #886
Conversation
Supports runtime-v4 native plugins shipped as precompiled objects (hal.provisioning === "prebuilt", Option C of the packages repo). In prebuilt mode hal.pluginEntry is the plugin DIRECTORY (holding the .o objects + link-only Makefile) rather than an entry source file, so handleVendorPluginPackaging resolves the dir directly instead of via dirname(). The existing collectAndCopy + checksum then copy the .o + Makefile into vpp_plugin/ unchanged (config_template is still excluded), and the runtime links them as it already does for sources. - types.ts: add optional hal.provisioning and hal.minRuntimeVersion (the zod transport schema stays untouched — it is passthrough by design). - compiler-module.ts: branch the plugin-dir resolution on provisioning; mode-aware success log. No change for existing source packages (provisioning absent => source). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… branch The prebuilt-object plugin support didn't require any runtime change, so the minRuntimeVersion ABI floor was never consumed — drop the field from the shared PackageManifest.hal type (provisioning stays). Add a direct test for handleVendorPluginPackaging's prebuilt-vs-source provisioning branch (pluginEntry as directory vs file), exclusion of editor-only files, and the deterministic checksum. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…led lib) Wire the editor compile path for prebuilt arduino-hal VPPs, which ship an open hal.source integration layer (compiled locally, owns the OpenPLC contract and defines.h/vpp_config.h coupling) plus a precompiled vendor library linked via --library. - types: PackageManifest gains target.coreVersion and hal.precompiledLibrary - board-info-resolver: BoardBuildInfo carries coreVersion/precompiledLibraryDir; #fromVppDevice maps them from the manifest - resolve-board-selection: forward both fields onto boardEntry - pipeline: pass coreVersion to installArduinoCore and precompiledLibraryDir as prebuiltLibraryPath to the arduino-cli arg builder - build-arduino-cli-args: emit a 2nd --library when prebuiltLibraryPath is set - compiler-platform-port + adapter: thread coreVersion through - compiler-module: handleCoreInstallation installs core@version (pins and verifies the ABI-locked core; fails on mismatch) The source layer still compiles through the existing arduino-cli path, so it sees defines.h/vpp_config.h; no runtime pin-config shim and no generate-defines marker. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
handleCompileArduinoProgram (the editor's real arduino-cli compile path, distinct from the shared pipeline.ts) composed its args without the vendor precompiled library, so a prebuilt arduino-hal VPP failed with "p1am_vendor.h: No such file or directory" — arduino-cli never saw the lib. The open hal.source layer is renamed to arduino.cpp and compiled here alongside the sketch (NOT in the precompile pass), and it includes the vendor boundary header. Pass info.precompiledLibraryDir as a 2nd --library so arduino-cli puts the lib's src/ on the include path (resolves the header) and auto-links the src/<build.mcu>/lib*.a archive (the lib ships precompiled=full). Preserves the OpenPLCUserLib ldflags. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The prebuilt arduino library is ABI-locked to target.coreVersion, so the strict policy installed and verified exactly that version. Relax it for now: if the same core (by id) is already installed, accept any version instead of forcing the pinned one. The pinned version is still used to choose what to install when the core is absent. Left a TODO to re-introduce exact-version verification once the team settles the ABI-pin policy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- build-arduino-cli-args: a 2nd --library is emitted for the vendor precompiled lib (right after the main one, before --export-binaries), and a single --library when prebuiltLibraryPath is absent. - resolve-board-selection: a prebuilt arduino-hal VPP board surfaces coreVersion and the package-resolved precompiledLibraryDir on boardEntry. - handle-core-installation: the relaxed core pin skips install (no spawn) when the same core is already present, even with a divergent pinned version, and logs accordingly. The handleCoreInstallation test lives in __tests__/ rather than the existing compiler-module.spec.ts because jest only collects .test.ts under __tests__/ here — the .spec.ts files are not picked up by the current testMatch config. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Revert the relaxed "same core present" policy. A prebuilt arduino library is ABI-locked to target.coreVersion, so the editor must install exactly that version. With a pinned version, always run `core install <id>@<version>` (arduino-cli installs that exact version and fails if it does not exist), which both pins and verifies it; a divergent already-installed version is replaced. Without a pinned version (source-mode boards), any installed version is still accepted. Update the tests to assert the exact-version install (core present with a divergent version, and core absent), the non-zero-exit rejection, and that the skip path only triggers for an unpinned, already-installed core. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds end-to-end support for prebuilt arduino-hal boards with ABI-locked Arduino core versions. Extends ChangesPrebuilt arduino-hal board support
Sequence Diagram(s)sequenceDiagram
participant Pipeline
participant EditorPort as editor-compiler-platform-port
participant HandleCore as handleCoreInstallation
participant HandleCompile as handleCompileArduinoProgram
participant ArduinoCLI as arduino-cli
rect rgba(70, 130, 180, 0.5)
note over Pipeline,HandleCore: Core install step
Pipeline->>EditorPort: installArduinoCore({coreId, coreVersion?})
EditorPort->>HandleCore: handleCoreInstallation(boardCore, logCb, coreVersion?)
alt coreVersion provided
HandleCore->>ArduinoCLI: core install boardCore@coreVersion
else already installed, no pin
HandleCore-->>EditorPort: skip — log "already installed"
end
end
rect rgba(60, 160, 80, 0.5)
note over Pipeline,ArduinoCLI: Compile step
Pipeline->>HandleCompile: buildArduinoCliCompileArgs({libraryPath, prebuiltLibraryPath?})
HandleCompile->>ArduinoCLI: compile --library libraryPath
opt prebuiltLibraryPath present
HandleCompile->>ArduinoCLI: --library prebuiltLibraryPath
end
HandleCompile->>ArduinoCLI: --export-binaries -b platform sketchPath
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ll verify The coreVersion comments claimed the editor "verifies the installed version matches", but there is no separate post-install verification step. Reword both the InstallArduinoCoreArgs.coreVersion doc and the handleCoreInstallation comment to describe what the code actually does: run `core install <id>@<version>`, which installs exactly that version and fails if it is unavailable. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes the CI Format Check (npx prettier --check). Formatting only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/backend/editor/compiler/compiler-module.ts (1)
1065-1084:⚠️ Potential issue | 🟠 Major | ⚡ Quick winHandle
spawnerrors in core installation path to avoid hangs/unhandled process errors.The Promise only resolves/rejects on
close; if process launch fails, there is noerrorlistener, so this path can fail noisily or never settle.Suggested fix
return new Promise<MethodsResult<string | Buffer>>((resolve, reject) => { const executeCommand = spawn(binaryPath, ['core', 'install', coreRef, ...this.arduinoCliBaseParameters]) + executeCommand.on('error', (err: Error) => { + reject(new Error(`Failed to start Arduino CLI core install: ${err.message}`)) + }) let stderrData = ''🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/backend/editor/compiler/compiler-module.ts` around lines 1065 - 1084, The spawn process for core installation does not have an error listener, causing the Promise to never settle if the process fails to launch. Add an error event listener to the executeCommand object returned by spawn to properly handle process launch failures. The listener should call reject with the error that is emitted, ensuring the Promise resolves or rejects in all cases and preventing unhandled errors from occurring.src/backend/editor/compiler/__tests__/handle-core-installation.test.ts (1)
1-127:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPrettier check is failing for this test file.
CI reports formatting issues here; please run Prettier on this file so the format job passes.
As per coding guidelines,
**/*.{ts,tsx,js,jsx}must follow Prettier formatting (120 char width, no semicolons, single quotes, trailing commas).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/backend/editor/compiler/__tests__/handle-core-installation.test.ts` around lines 1 - 127, The test file handle-core-installation.test.ts has Prettier formatting violations that need to be corrected. Run Prettier on this file to automatically fix all formatting issues according to the project's style guidelines (120 character line width, no semicolons, single quotes, and trailing commas). This will ensure the file passes the CI formatting checks.Sources: Coding guidelines, Pipeline failures
🧹 Nitpick comments (2)
src/backend/editor/compiler/__tests__/handle-vendor-plugin-packaging.test.ts (1)
33-41: ⚡ Quick winUse
@root/*imports instead of relative paths in this test.Please replace
../../package-managerand../compiler-modulewith@root/*aliases to match repository import conventions.As per coding guidelines, "
**/*.{ts,tsx,js,jsx}: ... Use path alias@root/*to reference./src/*".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/backend/editor/compiler/__tests__/handle-vendor-plugin-packaging.test.ts` around lines 33 - 41, Replace the relative path strings used in the jest.mock() call and the import statement with `@root/`* path aliases to match repository conventions. Specifically, update the string argument in jest.mock() from the relative path to the corresponding `@root/`* alias pointing to the package-manager module, and change the import statement for CompilerModule from the relative path to use the `@root/`* alias pointing to the compiler-module file. Ensure both import paths follow the repository's path alias pattern where `@root/`* references ./src/*.Source: Coding guidelines
src/middleware/shared/ports/types.ts (1)
759-769: ⚡ Quick winNarrow
hal.provisioningto a literal union.Using
provisioning?: stringweakens the new contract and allows silent typos ('prebuit') to bypass the prebuilt path. Please type it as'source' | 'prebuilt'(and keepprecompiledLibrarydocumented as prebuilt-only).♻️ Proposed fix
+type HalProvisioningMode = 'source' | 'prebuilt' + export interface PackageManifest { ... hal: { type: string pluginType?: string /** * Native runtime-v4 plugin provisioning. "source" (default when absent): * pluginEntry is the entry source file and its directory is compiled on * the runtime. "prebuilt": pluginEntry is the directory holding the * precompiled .o objects plus a link-only Makefile; the runtime only links. */ - provisioning?: string + provisioning?: HalProvisioningMode pluginEntry?: string ... precompiledLibrary?: string🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/middleware/shared/ports/types.ts` around lines 759 - 769, The provisioning property in the type definition is currently typed as a generic string, which allows typos and invalid values to pass undetected. Change the type of the provisioning property from string to a literal union type that only accepts the valid values 'source' or 'prebuilt'. This will ensure type safety and prevent silent errors from typos in the provisioning value. Keep the existing documentation comment for precompiledLibrary that explains it is prebuilt-only.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/backend/editor/compiler/__tests__/handle-vendor-plugin-packaging.test.ts`:
- Around line 156-157: The readFileSync call in the test is reading the binary
object file with 'utf-8' encoding, which can mask binary differences. Remove the
'utf-8' encoding parameter from the readFileSync function call for the
rpi_plugin.o file so that it returns a Buffer instead of a UTF-8 string. Then
update the expect assertion to compare the returned Buffer directly against a
Buffer value (rather than the string 'OBJECT-BYTES') to properly verify
byte-for-byte preservation of the binary file.
In `@src/backend/shared/hardware/board-info-resolver.ts`:
- Around line 288-296: The code currently allows hal.precompiledLibrary to be
set independently of target.coreVersion, but prebuilt libraries require the core
version to be pinned for ABI compatibility. Add validation in the manifest
schema or validation logic to enforce that whenever
device.hal.precompiledLibrary is declared, device.target.coreVersion must also
be present. This validation should run before the resolution logic that
populates the info object to catch the constraint violation early.
---
Outside diff comments:
In `@src/backend/editor/compiler/__tests__/handle-core-installation.test.ts`:
- Around line 1-127: The test file handle-core-installation.test.ts has Prettier
formatting violations that need to be corrected. Run Prettier on this file to
automatically fix all formatting issues according to the project's style
guidelines (120 character line width, no semicolons, single quotes, and trailing
commas). This will ensure the file passes the CI formatting checks.
In `@src/backend/editor/compiler/compiler-module.ts`:
- Around line 1065-1084: The spawn process for core installation does not have
an error listener, causing the Promise to never settle if the process fails to
launch. Add an error event listener to the executeCommand object returned by
spawn to properly handle process launch failures. The listener should call
reject with the error that is emitted, ensuring the Promise resolves or rejects
in all cases and preventing unhandled errors from occurring.
---
Nitpick comments:
In
`@src/backend/editor/compiler/__tests__/handle-vendor-plugin-packaging.test.ts`:
- Around line 33-41: Replace the relative path strings used in the jest.mock()
call and the import statement with `@root/`* path aliases to match repository
conventions. Specifically, update the string argument in jest.mock() from the
relative path to the corresponding `@root/`* alias pointing to the package-manager
module, and change the import statement for CompilerModule from the relative
path to use the `@root/`* alias pointing to the compiler-module file. Ensure both
import paths follow the repository's path alias pattern where `@root/`* references
./src/*.
In `@src/middleware/shared/ports/types.ts`:
- Around line 759-769: The provisioning property in the type definition is
currently typed as a generic string, which allows typos and invalid values to
pass undetected. Change the type of the provisioning property from string to a
literal union type that only accepts the valid values 'source' or 'prebuilt'.
This will ensure type safety and prevent silent errors from typos in the
provisioning value. Keep the existing documentation comment for
precompiledLibrary that explains it is prebuilt-only.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 14c20695-d7f6-473a-a2a0-9e318a6c2a01
📒 Files selected for processing (12)
src/backend/editor/compiler/__tests__/handle-core-installation.test.tssrc/backend/editor/compiler/__tests__/handle-vendor-plugin-packaging.test.tssrc/backend/editor/compiler/compiler-module.tssrc/backend/editor/compiler/editor-compiler-platform-port.tssrc/backend/shared/compile/__tests__/resolve-board-selection.test.tssrc/backend/shared/compile/pipeline.tssrc/backend/shared/compile/steps/resolve-board-selection.tssrc/backend/shared/firmware/__tests__/build-arduino-cli-args.test.tssrc/backend/shared/firmware/build-arduino-cli-args.tssrc/backend/shared/hardware/board-info-resolver.tssrc/middleware/shared/ports/compiler-platform-port.tssrc/middleware/shared/ports/types.ts
| const copied = readFileSync(join(targetDir, 'vpp_plugin', 'rpi_plugin.o'), 'utf-8') | ||
| expect(copied).toBe('OBJECT-BYTES') |
There was a problem hiding this comment.
The “byte-for-byte” assertion should compare binary buffers, not UTF-8 text.
Reading with 'utf-8' can mask binary differences for real .o payloads. Compare Buffer values directly to make this test truly byte-preserving.
Proposed fix
- const copied = readFileSync(join(targetDir, 'vpp_plugin', 'rpi_plugin.o'), 'utf-8')
- expect(copied).toBe('OBJECT-BYTES')
+ const copied = readFileSync(join(targetDir, 'vpp_plugin', 'rpi_plugin.o'))
+ expect(copied.equals(Buffer.from('OBJECT-BYTES'))).toBe(true)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const copied = readFileSync(join(targetDir, 'vpp_plugin', 'rpi_plugin.o'), 'utf-8') | |
| expect(copied).toBe('OBJECT-BYTES') | |
| const copied = readFileSync(join(targetDir, 'vpp_plugin', 'rpi_plugin.o')) | |
| expect(copied.equals(Buffer.from('OBJECT-BYTES'))).toBe(true) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/backend/editor/compiler/__tests__/handle-vendor-plugin-packaging.test.ts`
around lines 156 - 157, The readFileSync call in the test is reading the binary
object file with 'utf-8' encoding, which can mask binary differences. Remove the
'utf-8' encoding parameter from the readFileSync function call for the
rpi_plugin.o file so that it returns a Buffer instead of a UTF-8 string. Then
update the expect assertion to compare the returned Buffer directly against a
Buffer value (rather than the string 'OBJECT-BYTES') to properly verify
byte-for-byte preservation of the binary file.
| if (device.target.coreVersion) info.coreVersion = device.target.coreVersion | ||
|
|
||
| const resolveRel = this.config.resolvePackageRelativePath | ||
| if (device.hal.source) info.halSourceFile = resolveRel(pkg.path, device.hal.source) | ||
| if (device.hal.pluginEntry) info.pluginEntry = resolveRel(pkg.path, device.hal.pluginEntry) | ||
| if (device.hal.configTemplate) info.configTemplate = resolveRel(pkg.path, device.hal.configTemplate) | ||
| if (device.hal.requirements) info.requirements = resolveRel(pkg.path, device.hal.requirements) | ||
| if (device.hal.libraries) info.localLibrariesDir = resolveRel(pkg.path, device.hal.libraries) | ||
| if (device.hal.precompiledLibrary) info.precompiledLibraryDir = resolveRel(pkg.path, device.hal.precompiledLibrary) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Locate manifest schema/rules that define prebuilt HAL requirements
fd -i 'manifest.schema.json|schema.*manifest.*\.json|package-manifest.*\.json'
# 2) Inspect whether prebuilt implies target.coreVersion and hal.precompiledLibrary
rg -n -C3 '"provisioning"|coreVersion|precompiledLibrary|if|then|required|allOf|oneOf' $(fd -i 'manifest.schema.json|schema.*manifest.*\.json|package-manifest.*\.json')
# 3) Confirm runtime mapping + downstream pinning conditions
rg -n -C4 'coreVersion|precompiledLibraryDir|precompiledLibrary|handleCoreInstallation|core install' \
src/backend/shared/hardware/board-info-resolver.ts \
src/backend/shared/compile/steps/resolve-board-selection.ts \
src/backend/editor/compiler/compiler-module.tsRepository: Autonomy-Logic/openplc-editor
Length of output: 50388
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find manifest schema files in backend directories
fd -i 'schema|manifest' src/backend | grep -i 'json\|ts' | head -20
# 2) Look for device/hal type definitions
fd 'device\|board' src/backend | grep -E '\.(ts|json)$' | head -20
# 3) Check for validation or constraint logic
rg -l 'precompiledLibrary|coreVersion' src/backend --type ts | head -10Repository: Autonomy-Logic/openplc-editor
Length of output: 307
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the board-info-resolver file to understand the device structure
head -100 src/backend/shared/hardware/board-info-resolver.ts
# Find device/hal type definitions
rg -n 'interface.*device|type.*device' src/backend --type ts -A 5 | head -40
# Search for precompiledLibrary and coreVersion usage
rg -n 'precompiledLibrary|coreVersion' src/backend/shared/hardware/board-info-resolver.ts -B 2 -A 2Repository: Autonomy-Logic/openplc-editor
Length of output: 9074
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the type definition for `device` parameter in `#fromVppDevice`
rg -n 'fromVppDevice|device.*:.*Device' src/backend/shared/hardware/board-info-resolver.ts -B 2 -A 2
# Look at PackageManifest type definition
rg -n 'export.*type PackageManifest|interface PackageManifest' src/middleware/shared/ports/types.ts -A 30
# Check downstream code that consumes coreVersion
rg -n 'coreVersion|precompiledLibraryDir' src/backend --type ts -lRepository: Autonomy-Logic/openplc-editor
Length of output: 1776
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Get the full PackageManifest device structure
rg -n 'devices: Array' src/middleware/shared/ports/types.ts -A 100 | head -150
# Look for hal field in the device definition
rg -n 'hal:\s*\{' src/middleware/shared/ports/types.ts -A 20
# Check if there's a manifest.schema.json in resources
find . -name 'manifest.schema.json' -o -name '*manifest*schema*.json' 2>/dev/null | head -10Repository: Autonomy-Logic/openplc-editor
Length of output: 4896
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check how precompiledLibraryDir and coreVersion are used downstream in resolve-board-selection
cat src/backend/shared/compile/steps/resolve-board-selection.ts
# Also check compiler-module for core installation
rg -n 'coreVersion|handleCoreInstallation|core.*install' src/backend/editor/compiler/compiler-module.ts -B 3 -A 3Repository: Autonomy-Logic/openplc-editor
Length of output: 8652
Prebuilt Arduino HAL packages must enforce coreVersion alongside precompiledLibrary.
The manifest schema allows hal.precompiledLibrary and target.coreVersion to be declared independently. If a package declares hal.precompiledLibrary without target.coreVersion, the downstream core installation skips pinning (see handleCoreInstallation line 1049: core install only pins when coreVersion is present). Since prebuilt libraries are ABI-locked to their build core version (per code comments), this creates a contract violation: the wrong core version can be installed, breaking binary compatibility.
Add manifest schema validation to require target.coreVersion whenever hal.precompiledLibrary is declared.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/backend/shared/hardware/board-info-resolver.ts` around lines 288 - 296,
The code currently allows hal.precompiledLibrary to be set independently of
target.coreVersion, but prebuilt libraries require the core version to be pinned
for ABI compatibility. Add validation in the manifest schema or validation logic
to enforce that whenever device.hal.precompiledLibrary is declared,
device.target.coreVersion must also be present. This validation should run
before the resolution logic that populates the info object to catch the
constraint violation early.
Summary
Editor-side support for
provisioning: "prebuilt"VPP packages (vendor IP protection). Consumes the packages produced by the openplc-packages PR:hal.sourceintegration layer locally and links the precompiled vendor library; pins the ABI-locked core.What's in here
BoardInfoResolver: surfacetarget.coreVersionandhal.precompiledLibrary(resolved to an absolute dir) on the board build info.handleCompileArduinoProgram): pass the precompiled lib as a 2nd--libraryso arduino-cli resolves the vendor boundary header and auto-linkssrc/<build.mcu>/lib*.a(precompiled=full). Thehal.sourcelayer still compiles locally alongside the sketch (seesdefines.h/vpp_config.h).target.coreVersion(core install <id>@<version>, replacing a divergent installed version, failing if it does not exist) — aligned with the producer-sidebuild:objects. Unpinned source-mode boards still accept any installed version.--libraryemission, resolver mapping ofcoreVersion/precompiledLibraryDir, and the exact-version core pin.Verification
tsc --noEmitclean on touched files; new/updated jest suites pass..vppand compiling a POU pinsFACTS:samd@1.7.13, compiles the source layer, links the vendor lib, and produces a.hex.Relates to DOPE-313.
Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests