smol-symphony 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +41 -22
- package/DESIGN.md +494 -273
- package/README.md +109 -57
- package/SPEC.md +33 -24
- package/WORKFLOW.minimal.yaml +34 -0
- package/{WORKFLOW.template.md → WORKFLOW.template.yaml} +409 -256
- package/WORKFLOW.yaml +487 -0
- package/assets/skills/symphony-issues/SKILL.md +136 -0
- package/assets/symphony-mise.system.toml +68 -0
- package/dist/src/bin/symphony.js +30 -0
- package/dist/src/bin/symphony.js.map +1 -0
- package/dist/src/core/actions/context.js +109 -0
- package/dist/src/core/actions/context.js.map +1 -0
- package/dist/{actions/parsing.js → src/core/actions/parse.js} +33 -114
- package/dist/src/core/actions/parse.js.map +1 -0
- package/dist/src/core/actions/plan.js +197 -0
- package/dist/src/core/actions/plan.js.map +1 -0
- package/dist/src/core/actions/predicates.js +111 -0
- package/dist/src/core/actions/predicates.js.map +1 -0
- package/dist/src/core/actions/run-fold.js +248 -0
- package/dist/src/core/actions/run-fold.js.map +1 -0
- package/dist/src/core/actions/template.js +118 -0
- package/dist/src/core/actions/template.js.map +1 -0
- package/dist/src/core/cli/args.js +116 -0
- package/dist/src/core/cli/args.js.map +1 -0
- package/dist/src/core/coerce.js +75 -0
- package/dist/src/core/coerce.js.map +1 -0
- package/dist/src/core/credential/account-id.js +20 -0
- package/dist/src/core/credential/account-id.js.map +1 -0
- package/dist/src/core/credential/adapter-config.js +136 -0
- package/dist/src/core/credential/adapter-config.js.map +1 -0
- package/dist/src/core/credential/availability.js +98 -0
- package/dist/src/core/credential/availability.js.map +1 -0
- package/dist/src/core/credential/extract.js +228 -0
- package/dist/src/core/credential/extract.js.map +1 -0
- package/dist/src/core/credential/fake-creds.js +171 -0
- package/dist/src/core/credential/fake-creds.js.map +1 -0
- package/dist/src/core/credential/identity.js +125 -0
- package/dist/src/core/credential/identity.js.map +1 -0
- package/dist/src/core/credential/shape.js +230 -0
- package/dist/src/core/credential/shape.js.map +1 -0
- package/dist/src/core/credential/strings.js +15 -0
- package/dist/src/core/credential/strings.js.map +1 -0
- package/dist/src/core/doctor/checks.js +303 -0
- package/dist/src/core/doctor/checks.js.map +1 -0
- package/dist/src/core/git/result.js +107 -0
- package/dist/src/core/git/result.js.map +1 -0
- package/dist/src/core/http/decisions.js +225 -0
- package/dist/src/core/http/decisions.js.map +1 -0
- package/dist/{http.js → src/core/http/render.js} +472 -738
- package/dist/src/core/http/render.js.map +1 -0
- package/dist/{http-handlers.js → src/core/http/routes.js} +52 -87
- package/dist/src/core/http/routes.js.map +1 -0
- package/dist/src/core/http/views.js +181 -0
- package/dist/src/core/http/views.js.map +1 -0
- package/dist/src/core/image/managed-image.js +95 -0
- package/dist/src/core/image/managed-image.js.map +1 -0
- package/dist/src/core/issue/file.js +149 -0
- package/dist/src/core/issue/file.js.map +1 -0
- package/dist/src/core/issue/parse.js +210 -0
- package/dist/src/core/issue/parse.js.map +1 -0
- package/dist/src/core/mcp/dispatch.js +239 -0
- package/dist/src/core/mcp/dispatch.js.map +1 -0
- package/dist/src/core/mcp/post-move.js +92 -0
- package/dist/src/core/mcp/post-move.js.map +1 -0
- package/dist/src/core/mcp/protocol.js +293 -0
- package/dist/src/core/mcp/protocol.js.map +1 -0
- package/dist/src/core/mcp/url.js +162 -0
- package/dist/src/core/mcp/url.js.map +1 -0
- package/dist/src/core/path.js +63 -0
- package/dist/src/core/path.js.map +1 -0
- package/dist/src/core/reconcile/image-decide.js +48 -0
- package/dist/src/core/reconcile/image-decide.js.map +1 -0
- package/dist/src/core/reconcile/ledger.js +142 -0
- package/dist/src/core/reconcile/ledger.js.map +1 -0
- package/dist/src/core/reconcile/pr-classify.js +62 -0
- package/dist/src/core/reconcile/pr-classify.js.map +1 -0
- package/dist/{reconciler → src/core/reconcile}/pr-decide.js +25 -12
- package/dist/src/core/reconcile/pr-decide.js.map +1 -0
- package/dist/src/core/reconcile/pr-loop.js +161 -0
- package/dist/src/core/reconcile/pr-loop.js.map +1 -0
- package/dist/src/core/reconcile/pr-notes.js +35 -0
- package/dist/src/core/reconcile/pr-notes.js.map +1 -0
- package/dist/src/core/reconcile/vm-decide.js +70 -0
- package/dist/src/core/reconcile/vm-decide.js.map +1 -0
- package/dist/src/core/reconcile/vm-reap.js +207 -0
- package/dist/src/core/reconcile/vm-reap.js.map +1 -0
- package/dist/src/core/reconcile/workspace-decide.js +162 -0
- package/dist/src/core/reconcile/workspace-decide.js.map +1 -0
- package/dist/src/core/runlog/summary.js +231 -0
- package/dist/src/core/runlog/summary.js.map +1 -0
- package/dist/src/core/runner/dispatch-config.js +95 -0
- package/dist/src/core/runner/dispatch-config.js.map +1 -0
- package/dist/src/core/runner/injection.js +61 -0
- package/dist/src/core/runner/injection.js.map +1 -0
- package/dist/src/core/runner/mise.js +210 -0
- package/dist/src/core/runner/mise.js.map +1 -0
- package/dist/src/core/runner/prompt.js +720 -0
- package/dist/src/core/runner/prompt.js.map +1 -0
- package/dist/src/core/runner/turn.js +242 -0
- package/dist/src/core/runner/turn.js.map +1 -0
- package/dist/src/core/runner/vm-plan.js +390 -0
- package/dist/src/core/runner/vm-plan.js.map +1 -0
- package/dist/src/core/schedule/admission.js +123 -0
- package/dist/src/core/schedule/admission.js.map +1 -0
- package/dist/src/core/schedule/circuit-breaker.js +111 -0
- package/dist/src/core/schedule/circuit-breaker.js.map +1 -0
- package/dist/src/core/schedule/eligibility.js +83 -0
- package/dist/src/core/schedule/eligibility.js.map +1 -0
- package/dist/src/core/schedule/reconcile-issue.js +82 -0
- package/dist/src/core/schedule/reconcile-issue.js.map +1 -0
- package/dist/src/core/schedule/retry.js +96 -0
- package/dist/src/core/schedule/retry.js.map +1 -0
- package/dist/src/core/schedule/sleep-cycle.js +133 -0
- package/dist/src/core/schedule/sleep-cycle.js.map +1 -0
- package/dist/src/core/schedule/slots.js +124 -0
- package/dist/src/core/schedule/slots.js.map +1 -0
- package/dist/src/core/schedule/tick.js +553 -0
- package/dist/src/core/schedule/tick.js.map +1 -0
- package/dist/src/core/schedule/token-fold.js +181 -0
- package/dist/src/core/schedule/token-fold.js.map +1 -0
- package/dist/src/core/state-resolve.js +86 -0
- package/dist/src/core/state-resolve.js.map +1 -0
- package/dist/src/core/vm-guards.js +278 -0
- package/dist/src/core/vm-guards.js.map +1 -0
- package/dist/src/core/workflow/derive.js +107 -0
- package/dist/src/core/workflow/derive.js.map +1 -0
- package/dist/src/core/workflow/parse.js +687 -0
- package/dist/src/core/workflow/parse.js.map +1 -0
- package/dist/src/core/workflow/prompt-probe.js +78 -0
- package/dist/src/core/workflow/prompt-probe.js.map +1 -0
- package/dist/src/core/workflow/validate.js +189 -0
- package/dist/src/core/workflow/validate.js.map +1 -0
- package/dist/src/core/workspace-key.js +19 -0
- package/dist/src/core/workspace-key.js.map +1 -0
- package/dist/src/shell/actions-runner.js +356 -0
- package/dist/src/shell/actions-runner.js.map +1 -0
- package/dist/src/shell/adapter/adapter-registry.js +45 -0
- package/dist/src/shell/adapter/adapter-registry.js.map +1 -0
- package/dist/src/shell/adapter/clock-random.js +96 -0
- package/dist/src/shell/adapter/clock-random.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-dispatch-helpers.js +158 -0
- package/dist/src/shell/adapter/gondolin-dispatch-helpers.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-dispatch.js +385 -0
- package/dist/src/shell/adapter/gondolin-dispatch.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-image-converter.js +233 -0
- package/dist/src/shell/adapter/gondolin-image-converter.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-image-fetch.js +180 -0
- package/dist/src/shell/adapter/gondolin-image-fetch.js.map +1 -0
- package/dist/src/shell/adapter/launcher-asset.js +57 -0
- package/dist/src/shell/adapter/launcher-asset.js.map +1 -0
- package/dist/src/shell/adapter/mise-config-asset.js +65 -0
- package/dist/src/shell/adapter/mise-config-asset.js.map +1 -0
- package/dist/src/shell/adapter/workflow-loader.js +304 -0
- package/dist/src/shell/adapter/workflow-loader.js.map +1 -0
- package/dist/src/shell/cli/doctor.js +268 -0
- package/dist/src/shell/cli/doctor.js.map +1 -0
- package/dist/src/shell/effect-interpreter-families.js +314 -0
- package/dist/src/shell/effect-interpreter-families.js.map +1 -0
- package/dist/src/shell/effect-interpreter.js +29 -0
- package/dist/src/shell/effect-interpreter.js.map +1 -0
- package/dist/src/shell/interp/acp-frame.js +137 -0
- package/dist/src/shell/interp/acp-frame.js.map +1 -0
- package/dist/src/shell/interp/acp-ws-conn.js +320 -0
- package/dist/src/shell/interp/acp-ws-conn.js.map +1 -0
- package/dist/src/shell/interp/acp-ws-frames.js +159 -0
- package/dist/src/shell/interp/acp-ws-frames.js.map +1 -0
- package/dist/src/shell/interp/acp-ws.js +197 -0
- package/dist/src/shell/interp/acp-ws.js.map +1 -0
- package/dist/src/shell/interp/acp.js +319 -0
- package/dist/src/shell/interp/acp.js.map +1 -0
- package/dist/src/shell/interp/credential-defaults.js +128 -0
- package/dist/src/shell/interp/credential-defaults.js.map +1 -0
- package/dist/src/shell/interp/credential-hooks.js +149 -0
- package/dist/src/shell/interp/credential-hooks.js.map +1 -0
- package/dist/src/shell/interp/credential-registry.js +226 -0
- package/dist/src/shell/interp/credential-registry.js.map +1 -0
- package/dist/src/shell/interp/credential.js +103 -0
- package/dist/src/shell/interp/credential.js.map +1 -0
- package/dist/src/shell/interp/gh.js +163 -0
- package/dist/src/shell/interp/gh.js.map +1 -0
- package/dist/src/shell/interp/git.js +28 -0
- package/dist/src/shell/interp/git.js.map +1 -0
- package/dist/src/shell/interp/log.js +213 -0
- package/dist/src/shell/interp/log.js.map +1 -0
- package/dist/src/shell/interp/process.js +178 -0
- package/dist/src/shell/interp/process.js.map +1 -0
- package/dist/src/shell/interp/runlog.js +193 -0
- package/dist/src/shell/interp/runlog.js.map +1 -0
- package/dist/src/shell/interp/timer.js +64 -0
- package/dist/src/shell/interp/timer.js.map +1 -0
- package/dist/src/shell/interp/tracker-disk.js +99 -0
- package/dist/src/shell/interp/tracker-disk.js.map +1 -0
- package/dist/src/shell/interp/tracker-parse.js +71 -0
- package/dist/src/shell/interp/tracker-parse.js.map +1 -0
- package/dist/src/shell/interp/tracker-scan.js +238 -0
- package/dist/src/shell/interp/tracker-scan.js.map +1 -0
- package/dist/src/shell/interp/tracker-write.js +91 -0
- package/dist/src/shell/interp/tracker-write.js.map +1 -0
- package/dist/src/shell/interp/tracker.js +41 -0
- package/dist/src/shell/interp/tracker.js.map +1 -0
- package/dist/src/shell/interp/tty.js +48 -0
- package/dist/src/shell/interp/tty.js.map +1 -0
- package/dist/src/shell/interp/vm.js +199 -0
- package/dist/src/shell/interp/vm.js.map +1 -0
- package/dist/src/shell/interp/workspace.js +310 -0
- package/dist/src/shell/interp/workspace.js.map +1 -0
- package/dist/src/shell/main-acp.js +78 -0
- package/dist/src/shell/main-acp.js.map +1 -0
- package/dist/src/shell/main-adapters.js +222 -0
- package/dist/src/shell/main-adapters.js.map +1 -0
- package/dist/src/shell/main-credential.js +122 -0
- package/dist/src/shell/main-credential.js.map +1 -0
- package/dist/src/shell/main-doctor.js +22 -0
- package/dist/src/shell/main-doctor.js.map +1 -0
- package/dist/src/shell/main-entry.js +46 -0
- package/dist/src/shell/main-entry.js.map +1 -0
- package/dist/src/shell/main-http-csrf.js +45 -0
- package/dist/src/shell/main-http-csrf.js.map +1 -0
- package/dist/src/shell/main-http-handler.js +389 -0
- package/dist/src/shell/main-http-handler.js.map +1 -0
- package/dist/src/shell/main-http-mcp.js +122 -0
- package/dist/src/shell/main-http-mcp.js.map +1 -0
- package/dist/src/shell/main-http-views.js +253 -0
- package/dist/src/shell/main-http-views.js.map +1 -0
- package/dist/src/shell/main-http.js +76 -0
- package/dist/src/shell/main-http.js.map +1 -0
- package/dist/src/shell/main-loops.js +130 -0
- package/dist/src/shell/main-loops.js.map +1 -0
- package/dist/src/shell/main-mcp.js +129 -0
- package/dist/src/shell/main-mcp.js.map +1 -0
- package/dist/src/shell/main-orchestrator.js +120 -0
- package/dist/src/shell/main-orchestrator.js.map +1 -0
- package/dist/src/shell/main-preflight.js +43 -0
- package/dist/src/shell/main-preflight.js.map +1 -0
- package/dist/src/shell/main-reconcilers-helpers.js +244 -0
- package/dist/src/shell/main-reconcilers-helpers.js.map +1 -0
- package/dist/src/shell/main-reconcilers-pr.js +148 -0
- package/dist/src/shell/main-reconcilers-pr.js.map +1 -0
- package/dist/src/shell/main-reconcilers.js +225 -0
- package/dist/src/shell/main-reconcilers.js.map +1 -0
- package/dist/src/shell/main-runner.js +355 -0
- package/dist/src/shell/main-runner.js.map +1 -0
- package/dist/src/shell/main-scaffold.js +116 -0
- package/dist/src/shell/main-scaffold.js.map +1 -0
- package/dist/src/shell/main-shutdown.js +115 -0
- package/dist/src/shell/main-shutdown.js.map +1 -0
- package/dist/src/shell/main-startup.js +48 -0
- package/dist/src/shell/main-startup.js.map +1 -0
- package/dist/src/shell/main-substrates.js +43 -0
- package/dist/src/shell/main-substrates.js.map +1 -0
- package/dist/src/shell/main.js +385 -0
- package/dist/src/shell/main.js.map +1 -0
- package/dist/src/shell/orchestrator-feedback.js +69 -0
- package/dist/src/shell/orchestrator-feedback.js.map +1 -0
- package/dist/src/shell/orchestrator-image.js +167 -0
- package/dist/src/shell/orchestrator-image.js.map +1 -0
- package/dist/src/shell/orchestrator-loop.js +468 -0
- package/dist/src/shell/orchestrator-loop.js.map +1 -0
- package/dist/src/shell/orchestrator-reconcile.js +36 -0
- package/dist/src/shell/orchestrator-reconcile.js.map +1 -0
- package/dist/src/shell/reconciler-loop.js +228 -0
- package/dist/src/shell/reconciler-loop.js.map +1 -0
- package/dist/src/shell/runner-loop-turn.js +301 -0
- package/dist/src/shell/runner-loop-turn.js.map +1 -0
- package/dist/src/shell/runner-loop.js +338 -0
- package/dist/src/shell/runner-loop.js.map +1 -0
- package/dist/src/shell/server/http.js +208 -0
- package/dist/src/shell/server/http.js.map +1 -0
- package/dist/src/shell/server/mcp-runtime-effects.js +237 -0
- package/dist/src/shell/server/mcp-runtime-effects.js.map +1 -0
- package/dist/src/shell/server/mcp-runtime.js +99 -0
- package/dist/src/shell/server/mcp-runtime.js.map +1 -0
- package/dist/src/shell/workspace-key.js +14 -0
- package/dist/src/shell/workspace-key.js.map +1 -0
- package/dist/src/types/acp.js +8 -0
- package/dist/src/types/acp.js.map +1 -0
- package/dist/src/types/actions/plan.js +6 -0
- package/dist/src/types/actions/plan.js.map +1 -0
- package/dist/src/types/actions/predicates.js +6 -0
- package/dist/src/types/actions/predicates.js.map +1 -0
- package/dist/src/types/actions/run-fold.js +8 -0
- package/dist/src/types/actions/run-fold.js.map +1 -0
- package/dist/src/types/actions.js +7 -0
- package/dist/src/types/actions.js.map +1 -0
- package/dist/src/types/adapter/clock-random.js +4 -0
- package/dist/src/types/adapter/clock-random.js.map +1 -0
- package/dist/src/types/adapter/gondolin-image-converter.js +5 -0
- package/dist/src/types/adapter/gondolin-image-converter.js.map +1 -0
- package/dist/src/types/adapter/gondolin-image-fetch.js +5 -0
- package/dist/src/types/adapter/gondolin-image-fetch.js.map +1 -0
- package/dist/src/types/adapter/workflow-loader.js +4 -0
- package/dist/src/types/adapter/workflow-loader.js.map +1 -0
- package/dist/src/types/cli/args.js +8 -0
- package/dist/src/types/cli/args.js.map +1 -0
- package/dist/src/types/config.js +8 -0
- package/dist/src/types/config.js.map +1 -0
- package/dist/src/types/credential-interp.js +6 -0
- package/dist/src/types/credential-interp.js.map +1 -0
- package/dist/src/types/credentials.js +10 -0
- package/dist/src/types/credentials.js.map +1 -0
- package/dist/src/types/doctor.js +7 -0
- package/dist/src/types/doctor.js.map +1 -0
- package/dist/src/types/domain.js +7 -0
- package/dist/src/types/domain.js.map +1 -0
- package/dist/src/types/effect.js +15 -0
- package/dist/src/types/effect.js.map +1 -0
- package/dist/src/types/errors.js +39 -0
- package/dist/src/types/errors.js.map +1 -0
- package/dist/src/types/http/decisions.js +6 -0
- package/dist/src/types/http/decisions.js.map +1 -0
- package/dist/src/types/http/render.js +10 -0
- package/dist/src/types/http/render.js.map +1 -0
- package/dist/src/types/http/views.js +6 -0
- package/dist/src/types/http/views.js.map +1 -0
- package/dist/src/types/http.js +9 -0
- package/dist/src/types/http.js.map +1 -0
- package/dist/src/types/image/managed-image.js +7 -0
- package/dist/src/types/image/managed-image.js.map +1 -0
- package/dist/src/types/interp/effect-interpreter.js +8 -0
- package/dist/src/types/interp/effect-interpreter.js.map +1 -0
- package/dist/src/types/interp/tracker.js +7 -0
- package/dist/src/types/interp/tracker.js.map +1 -0
- package/dist/src/types/issue/file.js +6 -0
- package/dist/src/types/issue/file.js.map +1 -0
- package/dist/src/types/issue/parse.js +8 -0
- package/dist/src/types/issue/parse.js.map +1 -0
- package/dist/src/types/main-acp.js +13 -0
- package/dist/src/types/main-acp.js.map +1 -0
- package/dist/src/types/main-adapters.js +5 -0
- package/dist/src/types/main-adapters.js.map +1 -0
- package/dist/src/types/main-credential.js +21 -0
- package/dist/src/types/main-credential.js.map +1 -0
- package/dist/src/types/main-doctor.js +6 -0
- package/dist/src/types/main-doctor.js.map +1 -0
- package/dist/src/types/main-http-handler.js +12 -0
- package/dist/src/types/main-http-handler.js.map +1 -0
- package/dist/src/types/main-http.js +5 -0
- package/dist/src/types/main-http.js.map +1 -0
- package/dist/src/types/main-loops.js +5 -0
- package/dist/src/types/main-loops.js.map +1 -0
- package/dist/src/types/main-mcp.js +12 -0
- package/dist/src/types/main-mcp.js.map +1 -0
- package/dist/src/types/main-orchestrator.js +5 -0
- package/dist/src/types/main-orchestrator.js.map +1 -0
- package/dist/src/types/main-reconcilers.js +11 -0
- package/dist/src/types/main-reconcilers.js.map +1 -0
- package/dist/src/types/main-runner.js +13 -0
- package/dist/src/types/main-runner.js.map +1 -0
- package/dist/src/types/main-startup.js +5 -0
- package/dist/src/types/main-startup.js.map +1 -0
- package/dist/src/types/main-substrates.js +5 -0
- package/dist/src/types/main-substrates.js.map +1 -0
- package/dist/src/types/mcp/dispatch.js +4 -0
- package/dist/src/types/mcp/dispatch.js.map +1 -0
- package/dist/src/types/mcp/post-move.js +7 -0
- package/dist/src/types/mcp/post-move.js.map +1 -0
- package/dist/src/types/mcp.js +9 -0
- package/dist/src/types/mcp.js.map +1 -0
- package/dist/src/types/ports.js +12 -0
- package/dist/src/types/ports.js.map +1 -0
- package/dist/src/types/reconcile/image-decide.js +5 -0
- package/dist/src/types/reconcile/image-decide.js.map +1 -0
- package/dist/src/types/reconcile/ledger.js +7 -0
- package/dist/src/types/reconcile/ledger.js.map +1 -0
- package/dist/src/types/reconcile/pr-loop.js +8 -0
- package/dist/src/types/reconcile/pr-loop.js.map +1 -0
- package/dist/src/types/reconcile/vm-reap.js +8 -0
- package/dist/src/types/reconcile/vm-reap.js.map +1 -0
- package/dist/src/types/reconcile/workspace-decide.js +7 -0
- package/dist/src/types/reconcile/workspace-decide.js.map +1 -0
- package/dist/src/types/reconcile.js +9 -0
- package/dist/src/types/reconcile.js.map +1 -0
- package/dist/src/types/runlog.js +7 -0
- package/dist/src/types/runlog.js.map +1 -0
- package/dist/src/types/runner/actions-runner.js +12 -0
- package/dist/src/types/runner/actions-runner.js.map +1 -0
- package/dist/src/types/runner/gondolin-dispatch.js +5 -0
- package/dist/src/types/runner/gondolin-dispatch.js.map +1 -0
- package/dist/src/types/runner/injection.js +6 -0
- package/dist/src/types/runner/injection.js.map +1 -0
- package/dist/src/types/runner/runner-loop.js +5 -0
- package/dist/src/types/runner/runner-loop.js.map +1 -0
- package/dist/src/types/runner/turn.js +4 -0
- package/dist/src/types/runner/turn.js.map +1 -0
- package/dist/src/types/runner/vm-plan.js +4 -0
- package/dist/src/types/runner/vm-plan.js.map +1 -0
- package/dist/src/types/runtime.js +9 -0
- package/dist/src/types/runtime.js.map +1 -0
- package/dist/src/types/schedule/admission.js +7 -0
- package/dist/src/types/schedule/admission.js.map +1 -0
- package/dist/src/types/schedule/circuit-breaker.js +2 -0
- package/dist/src/types/schedule/circuit-breaker.js.map +1 -0
- package/dist/src/types/schedule/eligibility.js +9 -0
- package/dist/src/types/schedule/eligibility.js.map +1 -0
- package/dist/src/types/schedule/orchestrator-loop.js +10 -0
- package/dist/src/types/schedule/orchestrator-loop.js.map +1 -0
- package/dist/src/types/schedule/sleep-cycle.js +4 -0
- package/dist/src/types/schedule/sleep-cycle.js.map +1 -0
- package/dist/src/types/schedule/slots.js +8 -0
- package/dist/src/types/schedule/slots.js.map +1 -0
- package/dist/src/types/schedule/tick.js +9 -0
- package/dist/src/types/schedule/tick.js.map +1 -0
- package/dist/src/types/server/mcp-runtime.js +8 -0
- package/dist/src/types/server/mcp-runtime.js.map +1 -0
- package/dist/src/types/workflow/parse.js +4 -0
- package/dist/src/types/workflow/parse.js.map +1 -0
- package/dist/tests/core/account-id.test.js +35 -0
- package/dist/tests/core/account-id.test.js.map +1 -0
- package/dist/tests/core/actions-parse.test.js +176 -0
- package/dist/tests/core/actions-parse.test.js.map +1 -0
- package/dist/tests/core/adapter-config.test.js +133 -0
- package/dist/tests/core/adapter-config.test.js.map +1 -0
- package/dist/tests/core/admission.test.js +215 -0
- package/dist/tests/core/admission.test.js.map +1 -0
- package/dist/tests/core/args.test.js +132 -0
- package/dist/tests/core/args.test.js.map +1 -0
- package/dist/tests/core/availability.test.js +62 -0
- package/dist/tests/core/availability.test.js.map +1 -0
- package/dist/tests/core/checks.test.js +395 -0
- package/dist/tests/core/checks.test.js.map +1 -0
- package/dist/tests/core/circuit-breaker.test.js +172 -0
- package/dist/tests/core/circuit-breaker.test.js.map +1 -0
- package/dist/tests/core/coerce.test.js +87 -0
- package/dist/tests/core/coerce.test.js.map +1 -0
- package/dist/tests/core/context.test.js +228 -0
- package/dist/tests/core/context.test.js.map +1 -0
- package/dist/tests/core/decisions.test.js +310 -0
- package/dist/tests/core/decisions.test.js.map +1 -0
- package/dist/tests/core/derive.test.js +205 -0
- package/dist/tests/core/derive.test.js.map +1 -0
- package/dist/tests/core/dispatch-config.test.js +164 -0
- package/dist/tests/core/dispatch-config.test.js.map +1 -0
- package/dist/tests/core/dispatch.test.js +302 -0
- package/dist/tests/core/dispatch.test.js.map +1 -0
- package/dist/tests/core/eligibility.test.js +163 -0
- package/dist/tests/core/eligibility.test.js.map +1 -0
- package/dist/tests/core/extract.test.js +139 -0
- package/dist/tests/core/extract.test.js.map +1 -0
- package/dist/tests/core/fake-creds.test.js +134 -0
- package/dist/tests/core/fake-creds.test.js.map +1 -0
- package/dist/tests/core/file.test.js +197 -0
- package/dist/tests/core/file.test.js.map +1 -0
- package/dist/tests/core/git-result.test.js +113 -0
- package/dist/tests/core/git-result.test.js.map +1 -0
- package/dist/tests/core/identity.test.js +180 -0
- package/dist/tests/core/identity.test.js.map +1 -0
- package/dist/tests/core/image-decide.test.js +59 -0
- package/dist/tests/core/image-decide.test.js.map +1 -0
- package/dist/tests/core/injection.test.js +163 -0
- package/dist/tests/core/injection.test.js.map +1 -0
- package/dist/tests/core/ledger.test.js +218 -0
- package/dist/tests/core/ledger.test.js.map +1 -0
- package/dist/tests/core/managed-image.test.js +68 -0
- package/dist/tests/core/managed-image.test.js.map +1 -0
- package/dist/tests/core/mise.test.js +138 -0
- package/dist/tests/core/mise.test.js.map +1 -0
- package/dist/tests/core/parse.test.js +174 -0
- package/dist/tests/core/parse.test.js.map +1 -0
- package/dist/tests/core/path.test.js +50 -0
- package/dist/tests/core/path.test.js.map +1 -0
- package/dist/tests/core/plan.test.js +218 -0
- package/dist/tests/core/plan.test.js.map +1 -0
- package/dist/tests/core/post-move.test.js +162 -0
- package/dist/tests/core/post-move.test.js.map +1 -0
- package/dist/tests/core/pr-classify.test.js +117 -0
- package/dist/tests/core/pr-classify.test.js.map +1 -0
- package/dist/tests/core/pr-decide.test.js +298 -0
- package/dist/tests/core/pr-decide.test.js.map +1 -0
- package/dist/tests/core/pr-loop.test.js +301 -0
- package/dist/tests/core/pr-loop.test.js.map +1 -0
- package/dist/tests/core/pr-notes.test.js +165 -0
- package/dist/tests/core/pr-notes.test.js.map +1 -0
- package/dist/tests/core/predicates.test.js +154 -0
- package/dist/tests/core/predicates.test.js.map +1 -0
- package/dist/tests/core/prompt.test.js +189 -0
- package/dist/tests/core/prompt.test.js.map +1 -0
- package/dist/tests/core/protocol.test.js +195 -0
- package/dist/tests/core/protocol.test.js.map +1 -0
- package/dist/tests/core/reconcile-issue.test.js +116 -0
- package/dist/tests/core/reconcile-issue.test.js.map +1 -0
- package/dist/tests/core/render.test.js +549 -0
- package/dist/tests/core/render.test.js.map +1 -0
- package/dist/tests/core/retry.test.js +186 -0
- package/dist/tests/core/retry.test.js.map +1 -0
- package/dist/tests/core/routes.test.js +247 -0
- package/dist/tests/core/routes.test.js.map +1 -0
- package/dist/tests/core/run-fold.test.js +299 -0
- package/dist/tests/core/run-fold.test.js.map +1 -0
- package/dist/tests/core/shape.test.js +185 -0
- package/dist/tests/core/shape.test.js.map +1 -0
- package/dist/tests/core/sleep-cycle.test.js +150 -0
- package/dist/tests/core/sleep-cycle.test.js.map +1 -0
- package/dist/tests/core/slots.test.js +201 -0
- package/dist/tests/core/slots.test.js.map +1 -0
- package/dist/tests/core/state-resolve.test.js +80 -0
- package/dist/tests/core/state-resolve.test.js.map +1 -0
- package/dist/tests/core/summary.test.js +200 -0
- package/dist/tests/core/summary.test.js.map +1 -0
- package/dist/tests/core/template.test.js +116 -0
- package/dist/tests/core/template.test.js.map +1 -0
- package/dist/tests/core/tick.test.js +558 -0
- package/dist/tests/core/tick.test.js.map +1 -0
- package/dist/tests/core/token-fold.test.js +176 -0
- package/dist/tests/core/token-fold.test.js.map +1 -0
- package/dist/tests/core/turn.test.js +388 -0
- package/dist/tests/core/turn.test.js.map +1 -0
- package/dist/tests/core/url.test.js +118 -0
- package/dist/tests/core/url.test.js.map +1 -0
- package/dist/tests/core/validate.test.js +247 -0
- package/dist/tests/core/validate.test.js.map +1 -0
- package/dist/tests/core/views.test.js +252 -0
- package/dist/tests/core/views.test.js.map +1 -0
- package/dist/tests/core/vm-decide.test.js +110 -0
- package/dist/tests/core/vm-decide.test.js.map +1 -0
- package/dist/tests/core/vm-guards.test.js +153 -0
- package/dist/tests/core/vm-guards.test.js.map +1 -0
- package/dist/tests/core/vm-plan.test.js +332 -0
- package/dist/tests/core/vm-plan.test.js.map +1 -0
- package/dist/tests/core/vm-reap.test.js +196 -0
- package/dist/tests/core/vm-reap.test.js.map +1 -0
- package/dist/tests/core/workflow-parse.test.js +493 -0
- package/dist/tests/core/workflow-parse.test.js.map +1 -0
- package/dist/tests/core/workspace-decide.test.js +236 -0
- package/dist/tests/core/workspace-decide.test.js.map +1 -0
- package/dist/tests/helpers/fixtures.js +167 -0
- package/dist/tests/helpers/fixtures.js.map +1 -0
- package/dist/tests/shell/acp-substrate.test.js +101 -0
- package/dist/tests/shell/acp-substrate.test.js.map +1 -0
- package/dist/tests/shell/actions-runner-push.test.js +203 -0
- package/dist/tests/shell/actions-runner-push.test.js.map +1 -0
- package/dist/tests/shell/credential-hooks.test.js +36 -0
- package/dist/tests/shell/credential-hooks.test.js.map +1 -0
- package/dist/tests/shell/credential-registry.test.js +165 -0
- package/dist/tests/shell/credential-registry.test.js.map +1 -0
- package/dist/tests/shell/credential-substrate.test.js +179 -0
- package/dist/tests/shell/credential-substrate.test.js.map +1 -0
- package/dist/tests/shell/dockerfile-mise-pin.test.js +51 -0
- package/dist/tests/shell/dockerfile-mise-pin.test.js.map +1 -0
- package/dist/tests/shell/doctor.test.js +101 -0
- package/dist/tests/shell/doctor.test.js.map +1 -0
- package/dist/tests/shell/effect-vm-create.test.js +52 -0
- package/dist/tests/shell/effect-vm-create.test.js.map +1 -0
- package/dist/tests/shell/gh-port.test.js +63 -0
- package/dist/tests/shell/gh-port.test.js.map +1 -0
- package/dist/tests/shell/gondolin-dispatch-guard.test.js +144 -0
- package/dist/tests/shell/gondolin-dispatch-guard.test.js.map +1 -0
- package/dist/tests/shell/gondolin-dispatch-shquote.test.js +168 -0
- package/dist/tests/shell/gondolin-dispatch-shquote.test.js.map +1 -0
- package/dist/tests/shell/gondolin-image-converter.test.js +208 -0
- package/dist/tests/shell/gondolin-image-converter.test.js.map +1 -0
- package/dist/tests/shell/gondolin-image-fetch.test.js +93 -0
- package/dist/tests/shell/gondolin-image-fetch.test.js.map +1 -0
- package/dist/tests/shell/http-handler.test.js +608 -0
- package/dist/tests/shell/http-handler.test.js.map +1 -0
- package/dist/tests/shell/http-server.test.js +53 -0
- package/dist/tests/shell/http-server.test.js.map +1 -0
- package/dist/tests/shell/mcp-runtime.test.js +366 -0
- package/dist/tests/shell/mcp-runtime.test.js.map +1 -0
- package/dist/tests/shell/mise-config-asset.test.js +87 -0
- package/dist/tests/shell/mise-config-asset.test.js.map +1 -0
- package/dist/tests/shell/orchestrator-loop.test.js +583 -0
- package/dist/tests/shell/orchestrator-loop.test.js.map +1 -0
- package/dist/tests/shell/reconciler-passes.test.js +314 -0
- package/dist/tests/shell/reconciler-passes.test.js.map +1 -0
- package/dist/tests/shell/runner-loop-turn.test.js +97 -0
- package/dist/tests/shell/runner-loop-turn.test.js.map +1 -0
- package/dist/tests/shell/runner-slice.test.js +536 -0
- package/dist/tests/shell/runner-slice.test.js.map +1 -0
- package/dist/tests/shell/scaffold.test.js +65 -0
- package/dist/tests/shell/scaffold.test.js.map +1 -0
- package/dist/tests/shell/tick-config.test.js +83 -0
- package/dist/tests/shell/tick-config.test.js.map +1 -0
- package/dist/tests/shell/tracker-parse-dates.test.js +44 -0
- package/dist/tests/shell/tracker-parse-dates.test.js.map +1 -0
- package/dist/tests/shell/tracker-write-issue.test.js +154 -0
- package/dist/tests/shell/tracker-write-issue.test.js.map +1 -0
- package/dist/tests/shell/workflow-prompt-split.test.js +208 -0
- package/dist/tests/shell/workflow-prompt-split.test.js.map +1 -0
- package/dist/tests/shell/workspace-live-config.test.js +140 -0
- package/dist/tests/shell/workspace-live-config.test.js.map +1 -0
- package/package.json +21 -9
- package/patches/@earendil-works+gondolin+0.12.0.patch +173 -0
- package/prompts/Reflect.md +91 -0
- package/prompts/Review.md +97 -0
- package/prompts/Todo.md +96 -0
- package/prompts/_footer.md +41 -0
- package/prompts/_preamble.md +42 -0
- package/prompts-minimal/Todo.md +26 -0
- package/scripts/postinstall.mjs +63 -0
- package/scripts/vm-agent.mjs +312 -90
- package/WORKFLOW.md +0 -744
- package/dist/acp-bridge.js +0 -324
- package/dist/acp-bridge.js.map +0 -1
- package/dist/actions/cache.js +0 -191
- package/dist/actions/cache.js.map +0 -1
- package/dist/actions/effects.js +0 -41
- package/dist/actions/effects.js.map +0 -1
- package/dist/actions/executor.js +0 -570
- package/dist/actions/executor.js.map +0 -1
- package/dist/actions/index.js +0 -13
- package/dist/actions/index.js.map +0 -1
- package/dist/actions/parsing.js.map +0 -1
- package/dist/actions/predicate-env.js +0 -27
- package/dist/actions/predicate-env.js.map +0 -1
- package/dist/actions/predicates.js +0 -49
- package/dist/actions/predicates.js.map +0 -1
- package/dist/actions/templating.js +0 -66
- package/dist/actions/templating.js.map +0 -1
- package/dist/actions/types.js +0 -15
- package/dist/actions/types.js.map +0 -1
- package/dist/agent/acp.js +0 -473
- package/dist/agent/acp.js.map +0 -1
- package/dist/agent/adapter-names.js +0 -159
- package/dist/agent/adapter-names.js.map +0 -1
- package/dist/agent/adapters.js +0 -511
- package/dist/agent/adapters.js.map +0 -1
- package/dist/agent/credential-extractors.js +0 -342
- package/dist/agent/credential-extractors.js.map +0 -1
- package/dist/agent/credential-secrets.js +0 -628
- package/dist/agent/credential-secrets.js.map +0 -1
- package/dist/agent/credential-ticker.js +0 -57
- package/dist/agent/credential-ticker.js.map +0 -1
- package/dist/agent/gondolin-creds-staging.js +0 -356
- package/dist/agent/gondolin-creds-staging.js.map +0 -1
- package/dist/agent/gondolin-dispatch.js +0 -375
- package/dist/agent/gondolin-dispatch.js.map +0 -1
- package/dist/agent/gondolin.js +0 -124
- package/dist/agent/gondolin.js.map +0 -1
- package/dist/agent/runner-decisions.js +0 -134
- package/dist/agent/runner-decisions.js.map +0 -1
- package/dist/agent/runner.js +0 -1456
- package/dist/agent/runner.js.map +0 -1
- package/dist/agent/tool-call-summary.js +0 -102
- package/dist/agent/tool-call-summary.js.map +0 -1
- package/dist/agent/vm-acp-mapping.js +0 -73
- package/dist/agent/vm-acp-mapping.js.map +0 -1
- package/dist/agent/vm-guards.js +0 -262
- package/dist/agent/vm-guards.js.map +0 -1
- package/dist/agent/vm-port.js +0 -22
- package/dist/agent/vm-port.js.map +0 -1
- package/dist/agent/vm-process-registry.js +0 -79
- package/dist/agent/vm-process-registry.js.map +0 -1
- package/dist/bin/cli-args.js +0 -105
- package/dist/bin/cli-args.js.map +0 -1
- package/dist/bin/symphony.js +0 -794
- package/dist/bin/symphony.js.map +0 -1
- package/dist/errors.js +0 -15
- package/dist/errors.js.map +0 -1
- package/dist/http-disk.js +0 -135
- package/dist/http-disk.js.map +0 -1
- package/dist/http-handlers.js.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/issues.js +0 -178
- package/dist/issues.js.map +0 -1
- package/dist/logging.js +0 -203
- package/dist/logging.js.map +0 -1
- package/dist/mcp.js +0 -706
- package/dist/mcp.js.map +0 -1
- package/dist/memory.js +0 -85
- package/dist/memory.js.map +0 -1
- package/dist/orchestrator-decisions.js +0 -331
- package/dist/orchestrator-decisions.js.map +0 -1
- package/dist/orchestrator.js +0 -1569
- package/dist/orchestrator.js.map +0 -1
- package/dist/prompt.js +0 -65
- package/dist/prompt.js.map +0 -1
- package/dist/reconciler/cache.js +0 -65
- package/dist/reconciler/cache.js.map +0 -1
- package/dist/reconciler/index.js +0 -448
- package/dist/reconciler/index.js.map +0 -1
- package/dist/reconciler/ledger.js +0 -131
- package/dist/reconciler/ledger.js.map +0 -1
- package/dist/reconciler/pr-adapters.js +0 -174
- package/dist/reconciler/pr-adapters.js.map +0 -1
- package/dist/reconciler/pr-decide.js.map +0 -1
- package/dist/reconciler/pr.js +0 -422
- package/dist/reconciler/pr.js.map +0 -1
- package/dist/reconciler/types.js +0 -12
- package/dist/reconciler/types.js.map +0 -1
- package/dist/reconciler/vm.js +0 -243
- package/dist/reconciler/vm.js.map +0 -1
- package/dist/reconciler/workspace-defaults.js +0 -83
- package/dist/reconciler/workspace-defaults.js.map +0 -1
- package/dist/reconciler/workspace.js +0 -272
- package/dist/reconciler/workspace.js.map +0 -1
- package/dist/runlog.js +0 -403
- package/dist/runlog.js.map +0 -1
- package/dist/scaffold.js +0 -165
- package/dist/scaffold.js.map +0 -1
- package/dist/trackers/local.js +0 -445
- package/dist/trackers/local.js.map +0 -1
- package/dist/trackers/types.js +0 -10
- package/dist/trackers/types.js.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/util/clock.js +0 -12
- package/dist/util/clock.js.map +0 -1
- package/dist/util/crypto.js +0 -25
- package/dist/util/crypto.js.map +0 -1
- package/dist/util/frontmatter.js +0 -70
- package/dist/util/frontmatter.js.map +0 -1
- package/dist/util/fs-issues.js +0 -22
- package/dist/util/fs-issues.js.map +0 -1
- package/dist/util/process.js +0 -152
- package/dist/util/process.js.map +0 -1
- package/dist/util/workspace-key.js +0 -10
- package/dist/util/workspace-key.js.map +0 -1
- package/dist/workflow-loader.js +0 -147
- package/dist/workflow-loader.js.map +0 -1
- package/dist/workflow.js +0 -822
- package/dist/workflow.js.map +0 -1
- package/dist/workspace-types.js +0 -8
- package/dist/workspace-types.js.map +0 -1
- package/dist/workspace.js +0 -443
- package/dist/workspace.js.map +0 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// FCIS rewrite — programmatic OCI→gondolin image converter (kind: adapter, issue 206).
|
|
2
|
+
//
|
|
3
|
+
// The programmatic equivalent of `images/agents/build-image-oci.sh` Stage 2: take a
|
|
4
|
+
// normal OCI image reference (a docker/podman repo string), convert it into a
|
|
5
|
+
// content-addressed Gondolin asset bundle (rootfs.ext4 / vmlinuz-virt /
|
|
6
|
+
// initramfs.cpio.lz4 + manifest), and cache it in the local Gondolin image store so
|
|
7
|
+
// a second call for the same image is a no-op. Symphony's reconcile loop calls this
|
|
8
|
+
// on demand (`OrchestratorLoop.ensureImage`) so the operator no longer has to run
|
|
9
|
+
// `npm run build:image` by hand before dispatch can start. The shell script stays as
|
|
10
|
+
// a manual fallback.
|
|
11
|
+
//
|
|
12
|
+
// Caching: the cache key is the resolved OCI digest PLUS the guest-contract overlay
|
|
13
|
+
// version, tagged under a `symphony-oci:<digest>-<overlay>` ref in the Gondolin
|
|
14
|
+
// store. A digest-pinned source (`repo@sha256:…`) caches exactly; a moving tag
|
|
15
|
+
// (`repo:latest`) reconverts when the underlying image's digest changes, because the
|
|
16
|
+
// digest — not the tag string — is the key.
|
|
17
|
+
//
|
|
18
|
+
// Scope (MVP): the golden-image path — a published OCI ref that already satisfies the
|
|
19
|
+
// guest contract (Node ≥ 21 + the ACP CLIs on PATH; the in-VM launcher is staged at
|
|
20
|
+
// dispatch, not baked). The `postBuild.copy`/`.commands` overlay that would project
|
|
21
|
+
// the guest contract onto an ARBITRARY base is a clearly-marked extension point below.
|
|
22
|
+
//
|
|
23
|
+
// Shell rule: this lives in src/shell/adapter (an IO home) so its docker/podman +
|
|
24
|
+
// filesystem + Gondolin-SDK IO is sanctioned. All Gondolin/runtime operations are
|
|
25
|
+
// injectable (`ConverterDeps`) so the cache-hit path is unit-testable without docker.
|
|
26
|
+
import { mkdtempSync } from 'node:fs';
|
|
27
|
+
import { spawnSync } from 'node:child_process';
|
|
28
|
+
import os from 'node:os';
|
|
29
|
+
import path from 'node:path';
|
|
30
|
+
import { buildAssets, getDefaultBuildConfig, importImageFromDirectory, resolveImageSelector, setImageRef, } from '@earendil-works/gondolin';
|
|
31
|
+
/**
|
|
32
|
+
* Guest-contract overlay version — part of the cache key. The MVP overlays nothing
|
|
33
|
+
* (the golden base already satisfies the contract), so this is a constant; bump it
|
|
34
|
+
* when the conversion-time overlay (postBuild) changes so stale assets re-convert.
|
|
35
|
+
*/
|
|
36
|
+
export const GUEST_CONTRACT_OVERLAY_VERSION = 'v1';
|
|
37
|
+
/** The cache ref a converted asset is tagged under (digest + overlay version). */
|
|
38
|
+
export function cacheRefFor(digest, overlayVersion = GUEST_CONTRACT_OVERLAY_VERSION) {
|
|
39
|
+
const tag = `${digest.replace(/[^a-z0-9]/gi, '-')}-${overlayVersion}`;
|
|
40
|
+
return `symphony-oci:${tag}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The runtime image selector for a converted asset (issue 206): the content-derived
|
|
44
|
+
* build id when known (what `npm run build:image` prints + the operator would pin),
|
|
45
|
+
* else the resolved asset directory (a `path` selector, always present). The
|
|
46
|
+
* orchestrator boots the cached asset with this when `gondolin.image` is unset.
|
|
47
|
+
*/
|
|
48
|
+
function runtimeSelector(buildId, assetDir) {
|
|
49
|
+
return buildId.length > 0 ? buildId : assetDir;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Convert + cache `ociRef` into a Gondolin asset, returning the resolved asset (or a
|
|
53
|
+
* cache hit). Resolves the OCI digest (pulling per `pullPolicy`), checks the local
|
|
54
|
+
* store for an already-converted asset at the digest+overlay cache ref, and only
|
|
55
|
+
* runs `buildAssets` on a miss.
|
|
56
|
+
*/
|
|
57
|
+
export async function ensureConvertedImage(ociRef, opts = {}) {
|
|
58
|
+
const pullPolicy = opts.pullPolicy ?? 'if-not-present';
|
|
59
|
+
const runtime = opts.runtime ?? null;
|
|
60
|
+
const deps = opts.deps ?? defaultConverterDeps();
|
|
61
|
+
const log = opts.log;
|
|
62
|
+
// Resolve the immutable OCI digest honoring the FULL pull policy → cache ref. The
|
|
63
|
+
// policy is preserved (not reduced to a pull/skip boolean) so `always` re-pulls
|
|
64
|
+
// even when the ref is present locally and the POST-pull digest keys the cache;
|
|
65
|
+
// otherwise a moving tag (`repo:latest`) under `always` would cache against a stale
|
|
66
|
+
// local digest.
|
|
67
|
+
const digest = deps.resolveOciDigest(ociRef, runtime, pullPolicy);
|
|
68
|
+
const cacheRef = cacheRefFor(digest);
|
|
69
|
+
// Cache lookup — an already-converted asset tagged at this digest+overlay?
|
|
70
|
+
const hit = tryResolve(deps, cacheRef);
|
|
71
|
+
if (hit) {
|
|
72
|
+
const buildId = hit.buildId ?? '';
|
|
73
|
+
log?.emit('info', 'gondolin-image-converter: cache hit', { oci_image: ociRef, digest, cacheRef });
|
|
74
|
+
return {
|
|
75
|
+
buildId,
|
|
76
|
+
assetDir: hit.assetDir,
|
|
77
|
+
selector: runtimeSelector(buildId, hit.assetDir),
|
|
78
|
+
cached: true,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return convertAndTag(deps, { ociRef, runtime, digest, cacheRef, log });
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Cache miss: convert the OCI base into a fresh asset bundle, import it, and tag it
|
|
85
|
+
* under the cache ref so the next call is a no-op. EXTENSION: to support an arbitrary
|
|
86
|
+
* base that does NOT bake the guest contract, set `postBuild.copy` / `.commands` on
|
|
87
|
+
* `config` here to project the guest contract at conversion time.
|
|
88
|
+
*/
|
|
89
|
+
async function convertAndTag(deps, ctx) {
|
|
90
|
+
const { ociRef, runtime, digest, cacheRef, log } = ctx;
|
|
91
|
+
log?.emit('info', 'gondolin-image-converter: building (one-time)', { oci_image: ociRef, digest, cacheRef });
|
|
92
|
+
// We already enforced the operator's pull policy when resolving `digest` (above),
|
|
93
|
+
// so the LOCAL image at `ociRef` now IS that digest. Hand `buildAssets` an
|
|
94
|
+
// `if-not-present` pull so it converts that exact local image rather than re-pulling
|
|
95
|
+
// — guaranteeing the digest we keyed the cache on (`cacheRef`) is the digest the
|
|
96
|
+
// asset is built from, never tagging a freshly re-pulled image under a stale digest.
|
|
97
|
+
const config = {
|
|
98
|
+
...deps.defaultBuildConfig(),
|
|
99
|
+
oci: { image: ociRef, pullPolicy: 'if-not-present', ...(runtime ? { runtime } : {}) },
|
|
100
|
+
};
|
|
101
|
+
const result = await deps.buildAssets(config, { outputDir: deps.mkOutputDir(), verbose: false });
|
|
102
|
+
const imported = deps.importImageFromDirectory(result.outputDir);
|
|
103
|
+
deps.setImageRef(cacheRef, imported.buildId, imported.arch);
|
|
104
|
+
log?.emit('info', 'gondolin-image-converter: converted + cached', {
|
|
105
|
+
oci_image: ociRef,
|
|
106
|
+
digest,
|
|
107
|
+
cacheRef,
|
|
108
|
+
build_id: imported.buildId,
|
|
109
|
+
});
|
|
110
|
+
return {
|
|
111
|
+
buildId: imported.buildId,
|
|
112
|
+
assetDir: imported.assetDir,
|
|
113
|
+
selector: runtimeSelector(imported.buildId, imported.assetDir),
|
|
114
|
+
cached: false,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Probe whether `ociRef` is already converted + locally resolvable, WITHOUT pulling
|
|
119
|
+
* or building. Used by BOTH the doctor's read-only preflight AND the reconcile loop's
|
|
120
|
+
* per-tick readiness check (issue 206 rework). It resolves the ref's CURRENT local
|
|
121
|
+
* digest and looks up the cached asset at that digest, so readiness tracks the live
|
|
122
|
+
* digest rather than the ref string: a moving tag whose underlying image changed
|
|
123
|
+
* reports `converted: false` (a stale selector is dropped) until the new digest is
|
|
124
|
+
* reconverted.
|
|
125
|
+
*
|
|
126
|
+
* - `digest` — the ref's resolved local OCI digest, or null when it
|
|
127
|
+
* can't be inspected (not pulled yet / pull disabled).
|
|
128
|
+
* - `selector` — the cached asset's runtime image selector for that digest
|
|
129
|
+
* (what dispatch boots), or null when not yet converted.
|
|
130
|
+
* - `converted` — a cached asset for the current digest resolves.
|
|
131
|
+
* - `locallyResolvable` — the OCI image's digest is readable from the local store.
|
|
132
|
+
*/
|
|
133
|
+
export function probeConvertedImage(ociRef, opts = {}) {
|
|
134
|
+
const deps = opts.deps ?? defaultConverterDeps();
|
|
135
|
+
const runtime = opts.runtime ?? null;
|
|
136
|
+
let digest = null;
|
|
137
|
+
try {
|
|
138
|
+
digest = deps.resolveOciDigest(ociRef, runtime, 'never'); // read-only: never pulls
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return { converted: false, locallyResolvable: false, digest: null, selector: null };
|
|
142
|
+
}
|
|
143
|
+
const hit = tryResolve(deps, cacheRefFor(digest));
|
|
144
|
+
if (hit === null)
|
|
145
|
+
return { converted: false, locallyResolvable: true, digest, selector: null };
|
|
146
|
+
const buildId = hit.buildId ?? '';
|
|
147
|
+
return { converted: true, locallyResolvable: true, digest, selector: runtimeSelector(buildId, hit.assetDir) };
|
|
148
|
+
}
|
|
149
|
+
function tryResolve(deps, selector) {
|
|
150
|
+
try {
|
|
151
|
+
return deps.resolveImageSelector(selector);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// ─── production wiring (real docker/podman + Gondolin SDK) ─────────────────────
|
|
158
|
+
/** The real Gondolin/runtime ops. Tests inject a stub bundle instead. */
|
|
159
|
+
export function defaultConverterDeps() {
|
|
160
|
+
return {
|
|
161
|
+
resolveOciDigest: resolveOciDigestViaRuntime,
|
|
162
|
+
resolveImageSelector,
|
|
163
|
+
buildAssets,
|
|
164
|
+
importImageFromDirectory,
|
|
165
|
+
setImageRef,
|
|
166
|
+
defaultBuildConfig: getDefaultBuildConfig,
|
|
167
|
+
mkOutputDir: () => mkdtempSync(path.join(os.tmpdir(), 'symphony-oci-')),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Drive the OCI digest resolution honoring the FULL pull policy, given injected
|
|
172
|
+
* runtime effects. Pure ordering logic (no spawn), so the policy semantics are
|
|
173
|
+
* unit-testable without docker:
|
|
174
|
+
*
|
|
175
|
+
* - `always` — pull FIRST, unconditionally (even when the ref is already
|
|
176
|
+
* present locally), then inspect, so the POST-pull digest wins.
|
|
177
|
+
* - `if-not-present` — inspect first; pull only on a local miss, then re-inspect.
|
|
178
|
+
* - `never` — never pull; a missing ref resolves to null (caller errors).
|
|
179
|
+
*
|
|
180
|
+
* Returns the resolved local image id, or null when unresolvable.
|
|
181
|
+
*/
|
|
182
|
+
export function resolveDigestForPolicy(pullPolicy, io) {
|
|
183
|
+
if (pullPolicy === 'always')
|
|
184
|
+
io.pull();
|
|
185
|
+
let id = io.inspect();
|
|
186
|
+
if (id === null && pullPolicy === 'if-not-present') {
|
|
187
|
+
io.pull();
|
|
188
|
+
id = io.inspect();
|
|
189
|
+
}
|
|
190
|
+
return id;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Resolve an OCI ref to its immutable local image id (`sha256:…`) via the container
|
|
194
|
+
* runtime, pulling per `pullPolicy`. Mirrors what Gondolin's own OCI export path does
|
|
195
|
+
* (the package does not re-export `resolveLocalOciImageDigest`, so we shell out to the
|
|
196
|
+
* same runtime). Throws a precise, operator-facing error on failure.
|
|
197
|
+
*/
|
|
198
|
+
function resolveOciDigestViaRuntime(ref, runtime, pullPolicy) {
|
|
199
|
+
const rt = runtime ?? detectRuntime();
|
|
200
|
+
const id = resolveDigestForPolicy(pullPolicy, {
|
|
201
|
+
inspect: () => inspectImageId(rt, ref),
|
|
202
|
+
pull: () => pullImage(rt, ref),
|
|
203
|
+
});
|
|
204
|
+
if (id === null) {
|
|
205
|
+
throw new Error(`cannot resolve OCI image "${ref}" via ${rt}${pullPolicy === 'never' ? ' (not present locally; pull disabled)' : ' (after pull)'}`);
|
|
206
|
+
}
|
|
207
|
+
return id;
|
|
208
|
+
}
|
|
209
|
+
/** `<runtime> pull <ref>`; throws a precise, operator-facing error on failure. */
|
|
210
|
+
function pullImage(runtime, ref) {
|
|
211
|
+
const pulled = spawnSync(runtime, ['pull', ref], { encoding: 'utf8' });
|
|
212
|
+
if (pulled.status !== 0) {
|
|
213
|
+
throw new Error(`failed to pull OCI image "${ref}" via ${runtime}: ${(pulled.stderr || pulled.error?.message || '').trim()}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/** `<runtime> image inspect --format {{.Id}} <ref>` → the local config digest, or null. */
|
|
217
|
+
function inspectImageId(runtime, ref) {
|
|
218
|
+
const r = spawnSync(runtime, ['image', 'inspect', '--format', '{{.Id}}', ref], { encoding: 'utf8' });
|
|
219
|
+
if (r.status !== 0)
|
|
220
|
+
return null;
|
|
221
|
+
const id = (r.stdout || '').trim();
|
|
222
|
+
return id.length > 0 ? id : null;
|
|
223
|
+
}
|
|
224
|
+
/** Pick docker, else podman, by which `--version` answers; defaults to docker. */
|
|
225
|
+
function detectRuntime() {
|
|
226
|
+
for (const rt of ['docker', 'podman']) {
|
|
227
|
+
const r = spawnSync(rt, ['--version'], { encoding: 'utf8' });
|
|
228
|
+
if (r.status === 0)
|
|
229
|
+
return rt;
|
|
230
|
+
}
|
|
231
|
+
return 'docker';
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=gondolin-image-converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gondolin-image-converter.js","sourceRoot":"","sources":["../../../../src/shell/adapter/gondolin-image-converter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// FCIS rewrite — managed prebuilt-image fetcher (kind: adapter, issue 224 "Rung 2a").
|
|
2
|
+
//
|
|
3
|
+
// The runtime counterpart of `gondolin-image-converter.ts`, but instead of building an
|
|
4
|
+
// asset from a local OCI base it FETCHES a prebuilt Gondolin asset bundle published by
|
|
5
|
+
// CI to smol-symphony's GitHub releases, verifies it against a published `.sha256`,
|
|
6
|
+
// imports it into the local Gondolin store, and tags it under the managed `name:tag`
|
|
7
|
+
// ref. Onboarding becomes `scaffold → run`: no docker, no `npm run build:image`, no
|
|
8
|
+
// local convert. The orchestrator drives this through the SAME `image:ensure` effect +
|
|
9
|
+
// `ImageBuildTracker` readiness path the convert path uses (main-loops routes the
|
|
10
|
+
// managed ref here, every other ref to the converter).
|
|
11
|
+
//
|
|
12
|
+
// The pure half — asset name / store ref / download-URL / arch map / sha256-sidecar
|
|
13
|
+
// parse — lives in `src/core/image/managed-image.ts` and is reused here
|
|
14
|
+
// (`parseSha256Sidecar`). This module is the IO home: network download, sha256, tar/zstd
|
|
15
|
+
// extract, and the Gondolin SDK import/tag. All of it is injectable (`FetchDeps`) so the
|
|
16
|
+
// cache-hit + verify paths are unit-testable without network or a real store.
|
|
17
|
+
import { createHash } from 'node:crypto';
|
|
18
|
+
import { createReadStream, createWriteStream, existsSync, mkdtempSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
19
|
+
import { spawnSync } from 'node:child_process';
|
|
20
|
+
import { Readable } from 'node:stream';
|
|
21
|
+
import { finished } from 'node:stream/promises';
|
|
22
|
+
import os from 'node:os';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
import { importImageFromDirectory, resolveImageSelector, setImageRef, } from '@earendil-works/gondolin';
|
|
25
|
+
import { parseSha256Sidecar } from '../../core/image/managed-image.js';
|
|
26
|
+
/** Mirrors the converter's `runtimeSelector`: prefer the content-derived build id, else
|
|
27
|
+
* the asset dir (a `path` selector). Always non-empty so dispatch never boots empty. */
|
|
28
|
+
function runtimeSelector(buildId, assetDir) {
|
|
29
|
+
return buildId.length > 0 ? buildId : assetDir;
|
|
30
|
+
}
|
|
31
|
+
/** Resolve a managed ref WITHOUT throwing — null is the cache-miss signal. */
|
|
32
|
+
function tryResolve(deps, ref) {
|
|
33
|
+
try {
|
|
34
|
+
return deps.resolveImageSelector(ref);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Probe whether the managed asset is already imported + resolvable, read-only (no
|
|
42
|
+
* download). The reconcile loop's per-tick readiness check calls this; mirrors the
|
|
43
|
+
* converter's `probeConvertedImage` shape. `digest` is the resolved build id (a stable
|
|
44
|
+
* marker the tracker keys failure-suppression on); both null on a miss.
|
|
45
|
+
*/
|
|
46
|
+
export function probeFetchedImage(wiring, opts = {}) {
|
|
47
|
+
const deps = opts.deps ?? defaultFetchDeps();
|
|
48
|
+
const hit = tryResolve(deps, wiring.ref);
|
|
49
|
+
if (hit === null)
|
|
50
|
+
return { digest: null, selector: null };
|
|
51
|
+
const buildId = hit.buildId ?? '';
|
|
52
|
+
return {
|
|
53
|
+
digest: buildId.length > 0 ? buildId : wiring.ref,
|
|
54
|
+
selector: runtimeSelector(buildId, hit.assetDir),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Fetch + import the managed asset, returning the resolved asset (or a cache hit). On a
|
|
59
|
+
* cache hit (`resolveImageSelector(ref)` succeeds) returns the cached selector with NO
|
|
60
|
+
* download. On a miss: download the asset + its `.sha256` sidecar (trying each release-tag
|
|
61
|
+
* candidate), VERIFY the sha256 (a mismatch or a digest-less sidecar THROWS before import),
|
|
62
|
+
* extract, `importImageFromDirectory`, and `setImageRef` under the managed ref.
|
|
63
|
+
*/
|
|
64
|
+
export async function ensureFetchedImage(wiring, opts = {}) {
|
|
65
|
+
const deps = opts.deps ?? defaultFetchDeps();
|
|
66
|
+
const log = opts.log;
|
|
67
|
+
const hit = tryResolve(deps, wiring.ref);
|
|
68
|
+
if (hit !== null) {
|
|
69
|
+
const buildId = hit.buildId ?? '';
|
|
70
|
+
log?.emit('info', 'gondolin-image-fetch: cache hit', { ref: wiring.ref });
|
|
71
|
+
return { buildId, assetDir: hit.assetDir, selector: runtimeSelector(buildId, hit.assetDir), cached: true };
|
|
72
|
+
}
|
|
73
|
+
const tmp = deps.mkTempDir();
|
|
74
|
+
const archivePath = path.join(tmp, wiring.assetName);
|
|
75
|
+
const sidecarPath = `${archivePath}.sha256`;
|
|
76
|
+
log?.emit('info', 'gondolin-image-fetch: downloading (one-time)', { ref: wiring.ref, asset: wiring.assetName });
|
|
77
|
+
const chosen = await downloadFirstCandidate(deps, wiring, archivePath, sidecarPath);
|
|
78
|
+
return verifyExtractImport(deps, wiring, { archivePath, sidecarPath, extractDir: path.join(tmp, 'extracted'), chosen, log });
|
|
79
|
+
}
|
|
80
|
+
/** Verify the downloaded asset against its sidecar, extract, import, and tag it. A
|
|
81
|
+
* digest-less sidecar or a sha256 mismatch THROWS before any import. */
|
|
82
|
+
async function verifyExtractImport(deps, wiring, ctx) {
|
|
83
|
+
const { archivePath, sidecarPath, extractDir, chosen, log } = ctx;
|
|
84
|
+
// VERIFY before import — a published asset is only trusted against its published digest.
|
|
85
|
+
const expected = parseSha256Sidecar(deps.readTextFile(sidecarPath));
|
|
86
|
+
if (expected === null) {
|
|
87
|
+
throw new Error(`managed image ${wiring.ref}: sha256 sidecar at ${chosen.sha256Url} is missing or malformed; refusing to import unverified asset`);
|
|
88
|
+
}
|
|
89
|
+
const actual = (await deps.sha256OfFile(archivePath)).toLowerCase();
|
|
90
|
+
if (actual !== expected) {
|
|
91
|
+
throw new Error(`managed image ${wiring.ref}: sha256 mismatch (expected ${expected}, got ${actual}) for ${chosen.assetUrl}; refusing to import`);
|
|
92
|
+
}
|
|
93
|
+
const assetDir = await deps.extractAsset(archivePath, extractDir);
|
|
94
|
+
const imported = deps.importImageFromDirectory(assetDir);
|
|
95
|
+
deps.setImageRef(wiring.ref, imported.buildId, imported.arch);
|
|
96
|
+
log?.emit('info', 'gondolin-image-fetch: imported + tagged', { ref: wiring.ref, build_id: imported.buildId, tag: chosen.tag });
|
|
97
|
+
return {
|
|
98
|
+
buildId: imported.buildId,
|
|
99
|
+
assetDir: imported.assetDir,
|
|
100
|
+
selector: runtimeSelector(imported.buildId, imported.assetDir),
|
|
101
|
+
cached: false,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Download the asset + sidecar, trying each release-tag candidate (`v<version>`, then a
|
|
106
|
+
* bare `<version>`) until one yields BOTH. Throws an aggregate error when none resolve.
|
|
107
|
+
*/
|
|
108
|
+
async function downloadFirstCandidate(deps, wiring, archivePath, sidecarPath) {
|
|
109
|
+
const errors = [];
|
|
110
|
+
for (const candidate of wiring.candidates) {
|
|
111
|
+
try {
|
|
112
|
+
await deps.downloadToFile(candidate.assetUrl, archivePath);
|
|
113
|
+
await deps.downloadToFile(candidate.sha256Url, sidecarPath);
|
|
114
|
+
return candidate;
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
errors.push(`${candidate.tag}: ${err.message}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`managed image ${wiring.ref}: no published asset found for ${wiring.assetName} (tried ${wiring.candidates
|
|
121
|
+
.map((c) => c.tag)
|
|
122
|
+
.join(', ')}). Publish the release asset, or set gondolin.image / gondolin.oci_image. [${errors.join('; ')}]`);
|
|
123
|
+
}
|
|
124
|
+
// ─── production wiring (real fetch + tar/zstd + Gondolin SDK) ──────────────────
|
|
125
|
+
/** The real network + filesystem + Gondolin SDK ops. Tests inject a stub bundle. */
|
|
126
|
+
export function defaultFetchDeps() {
|
|
127
|
+
return {
|
|
128
|
+
resolveImageSelector,
|
|
129
|
+
importImageFromDirectory,
|
|
130
|
+
setImageRef,
|
|
131
|
+
downloadToFile: downloadToFileViaFetch,
|
|
132
|
+
readTextFile: (p) => readFileSync(p, 'utf8'),
|
|
133
|
+
sha256OfFile: sha256OfFileStreaming,
|
|
134
|
+
extractAsset: extractTarZst,
|
|
135
|
+
mkTempDir: () => mkdtempSync(path.join(os.tmpdir(), 'symphony-managed-')),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/** Stream a URL to `destPath`; throws on a non-OK response (so the candidate loop falls
|
|
139
|
+
* through to the next release tag). */
|
|
140
|
+
async function downloadToFileViaFetch(url, destPath) {
|
|
141
|
+
const res = await fetch(url);
|
|
142
|
+
if (!res.ok || res.body === null) {
|
|
143
|
+
throw new Error(`GET ${url} → ${res.status} ${res.statusText}`);
|
|
144
|
+
}
|
|
145
|
+
const out = createWriteStream(destPath);
|
|
146
|
+
await finished(Readable.fromWeb(res.body).pipe(out));
|
|
147
|
+
}
|
|
148
|
+
/** Lowercased hex sha256 of a file, streamed (the asset is hundreds of MB). */
|
|
149
|
+
async function sha256OfFileStreaming(filePath) {
|
|
150
|
+
const hash = createHash('sha256');
|
|
151
|
+
await finished(createReadStream(filePath).on('data', (chunk) => hash.update(chunk)));
|
|
152
|
+
return hash.digest('hex');
|
|
153
|
+
}
|
|
154
|
+
/** Extract a `.tar.zst` into `destDir`; return the asset dir (the one holding
|
|
155
|
+
* `manifest.json` — `destDir` itself, else a single nested subdir). */
|
|
156
|
+
async function extractTarZst(archivePath, destDir) {
|
|
157
|
+
mkdirSync(destDir, { recursive: true });
|
|
158
|
+
const r = spawnSync('tar', ['--use-compress-program=unzstd', '-xf', archivePath, '-C', destDir], {
|
|
159
|
+
encoding: 'utf8',
|
|
160
|
+
});
|
|
161
|
+
if (r.status !== 0) {
|
|
162
|
+
throw new Error(`tar extract of ${archivePath} failed: ${(r.stderr || r.error?.message || '').trim()}`);
|
|
163
|
+
}
|
|
164
|
+
return locateAssetDir(destDir);
|
|
165
|
+
}
|
|
166
|
+
/** The dir holding `manifest.json`: `destDir` itself, else its single subdir. */
|
|
167
|
+
function locateAssetDir(destDir) {
|
|
168
|
+
if (existsSync(path.join(destDir, 'manifest.json')))
|
|
169
|
+
return destDir;
|
|
170
|
+
const subdirs = readdirSync(destDir).filter((name) => statSync(path.join(destDir, name)).isDirectory());
|
|
171
|
+
for (const name of subdirs) {
|
|
172
|
+
const candidate = path.join(destDir, name);
|
|
173
|
+
if (existsSync(path.join(candidate, 'manifest.json')))
|
|
174
|
+
return candidate;
|
|
175
|
+
}
|
|
176
|
+
// No manifest located — return destDir and let importImageFromDirectory surface the
|
|
177
|
+
// precise error against the actual contents.
|
|
178
|
+
return destDir;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=gondolin-image-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gondolin-image-fetch.js","sourceRoot":"","sources":["../../../../src/shell/adapter/gondolin-image-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// FCIS rewrite — in-VM launcher asset loader (shell adapter).
|
|
2
|
+
//
|
|
3
|
+
// Ports the reference `src/agent/launcher-asset.ts`: reads `scripts/vm-agent.mjs`
|
|
4
|
+
// off the orchestrator's OWN disk once at load, returning the UTF-8 source for
|
|
5
|
+
// per-dispatch staging into the guest. Reading the launcher from host disk (rather
|
|
6
|
+
// than baking it into the image) guarantees the staged launcher is byte-identical
|
|
7
|
+
// to the version the running `acp-ws.ts` speaks — eliminating the image⇄host
|
|
8
|
+
// version lock (see project memory: agent image ⇄ host coupling).
|
|
9
|
+
//
|
|
10
|
+
// Resolution is anchored to THIS module via import.meta.url (never cwd) so it works
|
|
11
|
+
// from both `src/shell/adapter` (tsx) and a built `dist/shell/adapter` layout: both
|
|
12
|
+
// sit three levels under a root that holds `scripts/vm-agent.mjs`. A sibling
|
|
13
|
+
// fallback covers a packaging layout that co-locates the launcher next to dist.
|
|
14
|
+
//
|
|
15
|
+
// Fail-fast: a missing/empty asset throws at load (surfacing the packaging miss at
|
|
16
|
+
// boot, not mid-dispatch). Shell rule: node builtins only; no core, no src/types.
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
/** Guest path the launcher is staged to (mirrors the historical bake path). */
|
|
22
|
+
export const VM_AGENT_GUEST_PATH = '/opt/symphony/vm-agent.mjs';
|
|
23
|
+
/** Candidate on-disk locations of `scripts/vm-agent.mjs`, resolved relative to here. */
|
|
24
|
+
function candidatePaths() {
|
|
25
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
return [
|
|
27
|
+
path.resolve(here, '../../../scripts/vm-agent.mjs'),
|
|
28
|
+
path.resolve(here, './vm-agent.mjs'),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
/** Read the launcher source from the first candidate that exists; throw if none. */
|
|
32
|
+
function loadLauncherSource() {
|
|
33
|
+
const candidates = candidatePaths();
|
|
34
|
+
for (const candidate of candidates) {
|
|
35
|
+
try {
|
|
36
|
+
const source = readFileSync(candidate, 'utf8');
|
|
37
|
+
if (source.length === 0)
|
|
38
|
+
throw new Error(`in-VM launcher asset is empty at ${candidate}`);
|
|
39
|
+
return { source, resolvedPath: candidate };
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (err.code !== 'ENOENT')
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`in-VM launcher asset (scripts/vm-agent.mjs) not found; looked in: ${candidates.join(', ')}.`);
|
|
47
|
+
}
|
|
48
|
+
let cached = null;
|
|
49
|
+
/** Load (once) + return the launcher source + path + sha256. Throws if absent. */
|
|
50
|
+
export function loadLauncherAsset() {
|
|
51
|
+
if (cached)
|
|
52
|
+
return cached;
|
|
53
|
+
const { source, resolvedPath } = loadLauncherSource();
|
|
54
|
+
cached = { source, resolvedPath, sha256: createHash('sha256').update(source, 'utf8').digest('hex') };
|
|
55
|
+
return cached;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=launcher-asset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launcher-asset.js","sourceRoot":"","sources":["../../../../src/shell/adapter/launcher-asset.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kFAAkF;AAClF,+EAA+E;AAC/E,mFAAmF;AACnF,kFAAkF;AAClF,6EAA6E;AAC7E,kEAAkE;AAClE,EAAE;AACF,oFAAoF;AACpF,oFAAoF;AACpF,6EAA6E;AAC7E,gFAAgF;AAChF,EAAE;AACF,mFAAmF;AACnF,kFAAkF;AAElF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,4BAA4B,CAAC;AAEhE,wFAAwF;AACxF,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO;QACL,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,+BAA+B,CAAC;QACnD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,SAAS,kBAAkB;IACzB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC/C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,SAAS,EAAE,CAAC,CAAC;YAC1F,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QAClE,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,qEAAqE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC9F,CAAC;AACJ,CAAC;AAED,IAAI,MAAM,GAAoE,IAAI,CAAC;AAEnF,kFAAkF;AAClF,MAAM,UAAU,iBAAiB;IAC/B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,kBAAkB,EAAE,CAAC;IACtD,MAAM,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACrG,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// FCIS rewrite — mise SYSTEM config asset loader (shell adapter; issue 209/224).
|
|
2
|
+
//
|
|
3
|
+
// Reads the symphony-bundled mise SYSTEM config (`assets/symphony-mise.system.toml`)
|
|
4
|
+
// off the orchestrator's OWN disk once at load, returning the UTF-8 source for
|
|
5
|
+
// per-dispatch staging into the guest at /etc/mise/config.toml. Shipping the config
|
|
6
|
+
// from host disk (rather than baking node + the agent CLIs into the image) is the
|
|
7
|
+
// whole point of issue 209: bump a pin in this file → no image rebuild + digest repin.
|
|
8
|
+
// It mirrors launcher-asset.ts exactly (the launcher gets the same treatment).
|
|
9
|
+
//
|
|
10
|
+
// The asset lives under `assets/` (issue 224 Part 5): it is read at RUNTIME and staged
|
|
11
|
+
// per dispatch, so it must NOT live in the CI-build-only `images/agents/` (the image
|
|
12
|
+
// build does not consume it). A back-compat `images/agents/` candidate keeps an older
|
|
13
|
+
// checkout/package working through the transition.
|
|
14
|
+
//
|
|
15
|
+
// Resolution is anchored to THIS module via import.meta.url (never cwd) so it works
|
|
16
|
+
// from both `src/shell/adapter` (tsx) and a built `dist/shell/adapter` layout: both
|
|
17
|
+
// sit three levels under a root that holds `assets/symphony-mise.system.toml`. A
|
|
18
|
+
// sibling fallback covers a packaging layout that co-locates the asset next to dist.
|
|
19
|
+
//
|
|
20
|
+
// Fail-fast: a missing/empty asset throws at load (surfacing the packaging miss at
|
|
21
|
+
// boot, not mid-dispatch). Shell rule: node builtins only; no core, no src/types.
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
import { createHash } from 'node:crypto';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
/** Asset filename (kept in sync with the staged guest path in core `runner/mise.ts`). */
|
|
27
|
+
const ASSET_NAME = 'symphony-mise.system.toml';
|
|
28
|
+
/** Candidate on-disk locations of the mise SYSTEM config, resolved relative to here.
|
|
29
|
+
* `assets/` is the runtime home (issue 224 Part 5); `images/agents/` is a back-compat
|
|
30
|
+
* candidate for an older checkout/package; the sibling covers a co-located layout. */
|
|
31
|
+
function candidatePaths() {
|
|
32
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
33
|
+
return [
|
|
34
|
+
path.resolve(here, '../../../assets', ASSET_NAME),
|
|
35
|
+
path.resolve(here, '../../../images/agents', ASSET_NAME),
|
|
36
|
+
path.resolve(here, ASSET_NAME),
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
/** Read the config source from the first candidate that exists; throw if none. */
|
|
40
|
+
function loadMiseConfigSource() {
|
|
41
|
+
const candidates = candidatePaths();
|
|
42
|
+
for (const candidate of candidates) {
|
|
43
|
+
try {
|
|
44
|
+
const source = readFileSync(candidate, 'utf8');
|
|
45
|
+
if (source.length === 0)
|
|
46
|
+
throw new Error(`mise SYSTEM config asset is empty at ${candidate}`);
|
|
47
|
+
return { source, resolvedPath: candidate };
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
if (err.code !== 'ENOENT')
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`mise SYSTEM config asset (assets/${ASSET_NAME}) not found; looked in: ${candidates.join(', ')}.`);
|
|
55
|
+
}
|
|
56
|
+
let cached = null;
|
|
57
|
+
/** Load (once) + return the mise SYSTEM config source + path + sha256. Throws if absent. */
|
|
58
|
+
export function loadMiseConfigAsset() {
|
|
59
|
+
if (cached)
|
|
60
|
+
return cached;
|
|
61
|
+
const { source, resolvedPath } = loadMiseConfigSource();
|
|
62
|
+
cached = { source, resolvedPath, sha256: createHash('sha256').update(source, 'utf8').digest('hex') };
|
|
63
|
+
return cached;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=mise-config-asset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mise-config-asset.js","sourceRoot":"","sources":["../../../../src/shell/adapter/mise-config-asset.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,EAAE;AACF,qFAAqF;AACrF,+EAA+E;AAC/E,oFAAoF;AACpF,kFAAkF;AAClF,uFAAuF;AACvF,+EAA+E;AAC/E,EAAE;AACF,uFAAuF;AACvF,qFAAqF;AACrF,sFAAsF;AACtF,mDAAmD;AACnD,EAAE;AACF,oFAAoF;AACpF,oFAAoF;AACpF,iFAAiF;AACjF,qFAAqF;AACrF,EAAE;AACF,mFAAmF;AACnF,kFAAkF;AAElF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,yFAAyF;AACzF,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAE/C;;uFAEuF;AACvF,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO;QACL,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,iBAAiB,EAAE,UAAU,CAAC;QACjD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,wBAAwB,EAAE,UAAU,CAAC;QACxD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,oBAAoB;IAC3B,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC/C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,SAAS,EAAE,CAAC,CAAC;YAC9F,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QAClE,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,oCAAoC,UAAU,2BAA2B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAClG,CAAC;AACJ,CAAC;AAED,IAAI,MAAM,GAAoE,IAAI,CAAC;AAEnF,4FAA4F;AAC5F,MAAM,UAAU,mBAAmB;IACjC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,oBAAoB,EAAE,CAAC;IACxD,MAAM,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACrG,OAAO,MAAM,CAAC;AAChB,CAAC"}
|