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,390 @@
|
|
|
1
|
+
// FCIS rewrite — pure assembly of the per-dispatch VmPlan.
|
|
2
|
+
//
|
|
3
|
+
// Functional core: every export here is a pure, synchronous (data) -> data
|
|
4
|
+
// function. No IO, no async/await/Promise, no wall clock, no randomness, no
|
|
5
|
+
// node: imports, no process/fetch. Imports ONLY from src/types.
|
|
6
|
+
//
|
|
7
|
+
// Ports the PLAN half of the original Gondolin dispatch path (read for
|
|
8
|
+
// reference, never modified):
|
|
9
|
+
// • src/agent/runner.ts — buildVmMounts, buildForwardedEnv,
|
|
10
|
+
// mcpDispatchTarget, computeAcpWsUrl,
|
|
11
|
+
// buildDispatchOptions (the data half).
|
|
12
|
+
// • src/agent/vm-acp-mapping.ts — buildMcpTcpHostEntry, acpWsUrlFromExplicit,
|
|
13
|
+
// the synthetic-host constants + guest URLs.
|
|
14
|
+
// • src/agent/gondolin-dispatch.ts — buildCreateVmOptions, buildTunnelMapping,
|
|
15
|
+
// buildLaunchEnv, the launch argv + the staged
|
|
16
|
+
// guest-file set (gitconfig + launcher + fake
|
|
17
|
+
// creds + effort settings), the fixed guest
|
|
18
|
+
// PATH/gitconfig constants, sessionLabel.
|
|
19
|
+
//
|
|
20
|
+
// All of that imperative-shell code was making PURE decisions inline (which
|
|
21
|
+
// mounts, which env, which tunnel, which argv, which staged files). This module
|
|
22
|
+
// hoists those decisions out as a single (data) -> VmPlan assembly so the shell
|
|
23
|
+
// dispatcher only has to EXECUTE the plan (createVm + the base64-pipe writes +
|
|
24
|
+
// the exec) — every routing/precedence decision is testable here without a VM.
|
|
25
|
+
//
|
|
26
|
+
// mustFix (unified in-VM control plane): Gondolin blocks guest→host loopback, so
|
|
27
|
+
// ACP (the `/acp` WebSocket) and MCP (HTTP JSON-RPC) share ONE `tcp.hosts` entry
|
|
28
|
+
// (`symphony-mcp:7001`) + synthetic per-host DNS. The guest dials
|
|
29
|
+
// `ws://symphony-mcp:7001/acp` for ACP and `http://symphony-mcp:7001` for MCP
|
|
30
|
+
// over the same mapping. When MCP is reached via an explicit host URL (direct
|
|
31
|
+
// reachability, no tunnel) the entry is empty and the guest reaches the host
|
|
32
|
+
// directly. buildMcpTcpHostEntry + acpWsUrlFromExplicit are the load-bearing
|
|
33
|
+
// halves of that decision.
|
|
34
|
+
import { buildEvalModeMounts } from './dispatch-config.js';
|
|
35
|
+
import { buildMiseEnv, buildMiseMount, buildMisePrepCommand, buildMiseInstallCommand, miseSystemConfigFile, MISE_SHIMS_GUEST_DIR, } from './mise.js';
|
|
36
|
+
import { sanitizeWorkspaceKey } from '../workspace-key.js';
|
|
37
|
+
import { isCredentialEnvName, isCredentialTokenName, stripCredentialTokenVars, acpWsUrlFromExplicit, buildMcpTcpHostEntry, MCP_GUEST_BASE_URL, ACP_WS_GUEST_URL, } from '../vm-guards.js';
|
|
38
|
+
// The control-plane URL/tunnel + credential-strip primitives live canonically in
|
|
39
|
+
// core/vm-guards.ts; re-exported here so this file's importers (and its test) keep
|
|
40
|
+
// the `vm-plan.js` specifier without duplicating the definitions.
|
|
41
|
+
export { isCredentialTokenName, acpWsUrlFromExplicit, buildMcpTcpHostEntry, MCP_GUEST_BASE_URL, ACP_WS_GUEST_URL, } from '../vm-guards.js';
|
|
42
|
+
// ─── Constants ported verbatim from the reference ────────────────────────────
|
|
43
|
+
// The control-plane URL/host/port constants (MCP_GUEST_BASE_URL, ACP_WS_GUEST_URL,
|
|
44
|
+
// and the synthetic host/port/path they derive from) live canonically in
|
|
45
|
+
// core/vm-guards.ts; imported + re-exported above to avoid duplicating them.
|
|
46
|
+
/** VM session-label / name prefix (reference `vm-port.ts:SYMPHONY_VM_PREFIX`). */
|
|
47
|
+
export const SYMPHONY_VM_PREFIX = 'symphony-';
|
|
48
|
+
/**
|
|
49
|
+
* Default guest path the in-VM ACP launcher (`scripts/vm-agent.mjs`) is staged +
|
|
50
|
+
* exec'd at (reference `gondolin-dispatch.ts:DEFAULT_VM_AGENT_GUEST_PATH`).
|
|
51
|
+
*/
|
|
52
|
+
export const DEFAULT_VM_AGENT_GUEST_PATH = '/opt/symphony/vm-agent.mjs';
|
|
53
|
+
/** Non-secret mode for the staged launcher — it is code, not a credential. */
|
|
54
|
+
export const VM_AGENT_LAUNCHER_MODE = 0o644;
|
|
55
|
+
/**
|
|
56
|
+
* Fixed guest agent search PATH (reference `gondolin-dispatch.ts:GUEST_AGENT_PATH`).
|
|
57
|
+
* `vm.exec` runs without a login shell so the profile PATH does not apply. The mise
|
|
58
|
+
* shims dir leads (issue 209) so the agent's CHILD processes resolve the project's
|
|
59
|
+
* tools; the `mise` binary itself + any baked node sit under /usr/local/bin. A
|
|
60
|
+
* non-existent shims dir (not yet installed) is harmlessly skipped.
|
|
61
|
+
* Carries no secret.
|
|
62
|
+
*/
|
|
63
|
+
export const GUEST_AGENT_PATH = `${MISE_SHIMS_GUEST_DIR}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`;
|
|
64
|
+
/**
|
|
65
|
+
* Map a non-zero BYO pre-launch probe exit code to a precise, operator-facing
|
|
66
|
+
* contract-violation message. The enumerated codes (11/12/21/13) map to a fixed
|
|
67
|
+
* diagnostic; the default branch echoes the guest's own stderr token (when any)
|
|
68
|
+
* so an unanticipated non-zero exit still carries what the guest emitted rather
|
|
69
|
+
* than a bare number. Ported verbatim from the shell `probeFailureMessage` (§4a).
|
|
70
|
+
*
|
|
71
|
+
* Pure: the shell runs the probe exec (IO) and hands the captured code/stderr to
|
|
72
|
+
* this decider for the message it throws as a ByoContractError.
|
|
73
|
+
*/
|
|
74
|
+
export function byoProbeFailureMessage(code, adapterBin, stderr, guestPath) {
|
|
75
|
+
const base = 'BYO image contract violation: ';
|
|
76
|
+
switch (code) {
|
|
77
|
+
case 11:
|
|
78
|
+
return `${base}the "node" binary is not on PATH (${guestPath}). The image must ship Node ≥ 21.`;
|
|
79
|
+
case 12:
|
|
80
|
+
return `${base}mise did not produce the "${adapterBin}" adapter shim on PATH (${guestPath}). The staged mise SYSTEM config must pin the chosen agent CLI and \`mise install\` must have succeeded.`;
|
|
81
|
+
case 21:
|
|
82
|
+
return `${base}node is present but lacks the global WebSocket (Node < 21). The in-VM launcher requires Node ≥ 21.`;
|
|
83
|
+
case 13:
|
|
84
|
+
return `${base}the in-VM launcher failed to materialize in the guest before launch.`;
|
|
85
|
+
default: {
|
|
86
|
+
const tail = stderr.trim();
|
|
87
|
+
const detail = tail ? ` Guest stderr: ${tail}` : '';
|
|
88
|
+
return `${base}the pre-launch probe failed (exit ${code}). Check that the image ships Node ≥ 21 + "${adapterBin}" + /bin/sh on PATH and a writable rootfs.${detail}`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Guest path of the bind-mount-trust gitconfig (reference `GUEST_GITCONFIG_PATH`).
|
|
94
|
+
* Lives OUTSIDE the workspace mount so it never shows in the repo's git status.
|
|
95
|
+
*/
|
|
96
|
+
export const GUEST_GITCONFIG_PATH = '/opt/symphony/gitconfig';
|
|
97
|
+
/** Disarms git's bind-mount ownership guard for every workspace path (issue 149). */
|
|
98
|
+
export const GUEST_GITCONFIG_CONTENT = '[safe]\n\tdirectory = *\n';
|
|
99
|
+
/** Non-secret mode for the staged gitconfig. */
|
|
100
|
+
export const GUEST_GITCONFIG_MODE = 0o644;
|
|
101
|
+
// ─── Control-plane tunnel (synthetic DNS / tcp.hosts) ────────────────────────
|
|
102
|
+
// buildMcpTcpHostEntry + acpWsUrlFromExplicit are imported + re-exported from
|
|
103
|
+
// core/vm-guards.ts (their canonical home) — see the top-of-file re-export.
|
|
104
|
+
/**
|
|
105
|
+
* The host control-plane endpoint to tunnel into the guest, or null when no
|
|
106
|
+
* tunnel is needed/possible. Reference `runner.ts:mcpDispatchTarget`. Returns
|
|
107
|
+
* null when MCP is disabled, an `explicit_host_url` already points the guest at a
|
|
108
|
+
* directly-reachable URL, or the HTTP server has not bound a port
|
|
109
|
+
* (`boundMcpPort === null`). The bound port is INJECTED (it is a runtime fact the
|
|
110
|
+
* shell observes after the server binds) so this stays pure.
|
|
111
|
+
*/
|
|
112
|
+
export function mcpDispatchTarget(cfg, boundMcpPort) {
|
|
113
|
+
if (!cfg.mcp.enabled || cfg.mcp.explicit_host_url)
|
|
114
|
+
return null;
|
|
115
|
+
if (boundMcpPort === null)
|
|
116
|
+
return null;
|
|
117
|
+
return { host: cfg.mcp.host, port: boundMcpPort };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Assemble the unified control-plane tunnel decision. Mirrors the reference's
|
|
121
|
+
* three coupled decisions (`buildTunnelMapping`, `computeAcpWsUrl`, the MCP base
|
|
122
|
+
* URL) so the ACP URL and the `tcp.hosts` entry that backs it stay consistent:
|
|
123
|
+
*
|
|
124
|
+
* • synthetic tunnel present (MCP enabled, port bound, no explicit URL):
|
|
125
|
+
* tcpHostEntry = { 'symphony-mcp:7001': '<host>:<port>' }
|
|
126
|
+
* mcpGuestBaseUrl = http://symphony-mcp:7001
|
|
127
|
+
* acpWsGuestUrl = ws://symphony-mcp:7001/acp
|
|
128
|
+
* • explicit host URL (direct reachability, no tunnel):
|
|
129
|
+
* tcpHostEntry = {}
|
|
130
|
+
* mcpGuestBaseUrl = the explicit URL verbatim
|
|
131
|
+
* acpWsGuestUrl = ws(s)://<explicit-host>/acp (null if unparseable)
|
|
132
|
+
* • neither (MCP disabled / no bound port and no explicit URL):
|
|
133
|
+
* tcpHostEntry = {}, mcpGuestBaseUrl = the synthetic base (unreachable),
|
|
134
|
+
* acpWsGuestUrl = null — the runner's validateAcpTransport fails the
|
|
135
|
+
* attempt fast in this case (no reachable dial-back URL).
|
|
136
|
+
*/
|
|
137
|
+
export function buildControlPlaneTunnel(cfg, boundMcpPort) {
|
|
138
|
+
const target = mcpDispatchTarget(cfg, boundMcpPort);
|
|
139
|
+
if (target) {
|
|
140
|
+
return {
|
|
141
|
+
mcpGuestBaseUrl: MCP_GUEST_BASE_URL,
|
|
142
|
+
acpWsGuestUrl: ACP_WS_GUEST_URL,
|
|
143
|
+
tcpHostEntry: buildMcpTcpHostEntry(target.host, target.port),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const explicit = cfg.mcp.explicit_host_url;
|
|
147
|
+
if (explicit) {
|
|
148
|
+
return {
|
|
149
|
+
mcpGuestBaseUrl: explicit,
|
|
150
|
+
acpWsGuestUrl: acpWsUrlFromExplicit(explicit),
|
|
151
|
+
tcpHostEntry: {},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// No synthetic tunnel and no explicit URL: the guest has no reachable control
|
|
155
|
+
// plane. Surfaced as a null ACP URL so the shell fails the attempt fast
|
|
156
|
+
// (reference validateAcpTransport: 'acp ws url unavailable').
|
|
157
|
+
return {
|
|
158
|
+
mcpGuestBaseUrl: MCP_GUEST_BASE_URL,
|
|
159
|
+
acpWsGuestUrl: null,
|
|
160
|
+
tcpHostEntry: {},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
// ─── Mounts ──────────────────────────────────────────────────────────────────
|
|
164
|
+
/**
|
|
165
|
+
* The host→guest mount set for a dispatch. Reference `runner.ts:buildVmMounts`:
|
|
166
|
+
* the workspace RW at its OWN host path (so `cwd` is identical inside/outside the
|
|
167
|
+
* VM), then the symphony-managed mise download-cache dir RW (issue 222; NOT the
|
|
168
|
+
* install dir — that lives on the ephemeral rootfs — and NOT a user `gondolin.volumes`
|
|
169
|
+
* entry; always present, mise provisioning is unconditional — issue 233),
|
|
170
|
+
* then every configured `gondolin.volumes` entry, then the eval-mode RO mounts
|
|
171
|
+
* (`tracker.root` → /symphony/issues, `logs.root` → /symphony/logs) when the
|
|
172
|
+
* resolved state opted in. Order is preserved exactly.
|
|
173
|
+
*
|
|
174
|
+
* SECURITY: the credential-mount denylist guard (`assertNoCredentialMounts`)
|
|
175
|
+
* lives in the shell (it needs `os.homedir()` + `fs.realpath`); this pure builder
|
|
176
|
+
* only assembles the list. The shell HARD-FAILs before createVm if any entry
|
|
177
|
+
* overlaps a credential directory.
|
|
178
|
+
*/
|
|
179
|
+
export function buildVmMounts(cfg, resolved, workspacePath) {
|
|
180
|
+
const mounts = [{ host: workspacePath, guest: workspacePath, readonly: false }];
|
|
181
|
+
// mise provisioning is unconditional (issue 233): the download-cache mount always rides.
|
|
182
|
+
mounts.push(buildMiseMount(cfg));
|
|
183
|
+
for (const v of cfg.gondolin.volumes) {
|
|
184
|
+
mounts.push({ host: v.host, guest: v.guest, readonly: v.readonly });
|
|
185
|
+
}
|
|
186
|
+
for (const m of buildEvalModeMounts(cfg, resolved)) {
|
|
187
|
+
mounts.push({ host: m.host, guest: m.guest, readonly: m.readonly });
|
|
188
|
+
}
|
|
189
|
+
return mounts;
|
|
190
|
+
}
|
|
191
|
+
// ─── Env ──────────────────────────────────────────────────────────────────────
|
|
192
|
+
/**
|
|
193
|
+
* The stripped VM boot env. Reference `runner.ts:buildForwardedEnv`: forward the
|
|
194
|
+
* configured `gondolin.forward_env` vars, then STRIP every credential-bearing var
|
|
195
|
+
* (defense in depth). `readEnv` is INJECTED so this stays pure (no `process.env`
|
|
196
|
+
* in core). The credential strip is applied at compute time via the shared
|
|
197
|
+
* `isCredentialEnvName` policy (canonically core/vm-guards.ts) — equivalent to
|
|
198
|
+
* the reference's `stripCredentialEnv(computeForwardedEnv(...))` two-step, since
|
|
199
|
+
* folding the strip into the per-name filter already drops credential names. The
|
|
200
|
+
* guest holds only the placeholder bearer Gondolin substitutes at egress.
|
|
201
|
+
*/
|
|
202
|
+
export function buildForwardedEnv(cfg, readEnv) {
|
|
203
|
+
const env = {};
|
|
204
|
+
for (const k of cfg.gondolin.forward_env) {
|
|
205
|
+
if (isCredentialEnvName(k))
|
|
206
|
+
continue;
|
|
207
|
+
const v = readEnv(k);
|
|
208
|
+
if (v && v.length > 0)
|
|
209
|
+
env[k] = v;
|
|
210
|
+
}
|
|
211
|
+
return env;
|
|
212
|
+
}
|
|
213
|
+
// ─── Staged guest files ────────────────────────────────────────────────────────
|
|
214
|
+
/** The bind-mount-trust gitconfig as a guest file (reference `guestGitconfigFile`). */
|
|
215
|
+
export function guestGitconfigFile() {
|
|
216
|
+
return {
|
|
217
|
+
guestPath: GUEST_GITCONFIG_PATH,
|
|
218
|
+
content: GUEST_GITCONFIG_CONTENT,
|
|
219
|
+
mode: GUEST_GITCONFIG_MODE,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
/** The injected in-VM launcher as a guest file (reference `launcherFile`). Carries no secret → 0644. */
|
|
223
|
+
export function launcherFile(source, guestPath) {
|
|
224
|
+
return { guestPath, content: source, mode: VM_AGENT_LAUNCHER_MODE };
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* The full ordered guest-file set staged BEFORE the agent launches, mirroring the
|
|
228
|
+
* reference `bringUpOrTeardown` staging order:
|
|
229
|
+
* 1. the gitconfig (so in-guest git accepts the host-owned workspace from its
|
|
230
|
+
* first command — issue 149),
|
|
231
|
+
* 2. the mise SYSTEM config (issue 209) — always staged (issue 233),
|
|
232
|
+
* 3. the fake native creds (placeholders only — the guest bearer + identity),
|
|
233
|
+
* 4. the model/effort runtime files (e.g. claude's settings.json effortLevel),
|
|
234
|
+
* then (separately, written first in the reference) the launcher itself. We keep
|
|
235
|
+
* the launcher at the FRONT here because the shell needs its landed path before
|
|
236
|
+
* the probe; the relative order of the remaining files matches the reference.
|
|
237
|
+
*
|
|
238
|
+
* NOTE: the reference staged the launcher with a `/tmp` fallback when the primary
|
|
239
|
+
* write fails (a readonly-rootfs BYO image). That fallback is a RUNTIME decision
|
|
240
|
+
* (it inspects the write's exit code), so it stays in the shell — this plan
|
|
241
|
+
* carries only the PRIMARY launcher path; the shell may re-stage under `/tmp` and
|
|
242
|
+
* exec THAT path. By design the fallback path is not part of VmPlan.
|
|
243
|
+
*/
|
|
244
|
+
export function buildGuestFiles(args) {
|
|
245
|
+
return [
|
|
246
|
+
launcherFile(args.launcherSource, args.guestAgentPath),
|
|
247
|
+
guestGitconfigFile(),
|
|
248
|
+
args.miseSystemConfig,
|
|
249
|
+
...args.fakeCreds.files,
|
|
250
|
+
...args.runtimeExtraFiles,
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
// ─── Launch env + agent command ──────────────────────────────────────────────
|
|
254
|
+
/**
|
|
255
|
+
* The launch env the in-VM `vm-agent.mjs` reads to dial back + spawn the adapter.
|
|
256
|
+
* Reference `gondolin-dispatch.ts:buildLaunchEnv`.
|
|
257
|
+
*
|
|
258
|
+
* ORDERING (load-bearing): the placeholder bearer (`fakeCreds.env`, a FAKE value
|
|
259
|
+
* keyed by the credential var name itself, e.g. `ANTHROPIC_AUTH_TOKEN`) is merged
|
|
260
|
+
* LAST — after `stripCredentialTokenVars(runtimeEnv)` — so the strip drops a real
|
|
261
|
+
* token smuggled via runtimeEnv but the placeholder survives. PATH/GIT_CONFIG_GLOBAL
|
|
262
|
+
* lead so a runtimeEnv-supplied PATH (rare) can still override via the spread.
|
|
263
|
+
*
|
|
264
|
+
* `agentCommand` carries the absolute node + adapter paths the pre-launch probe
|
|
265
|
+
* resolves; those are runtime facts (the probe is IO), so the shell fills them.
|
|
266
|
+
* This builder fixes only the PATH-independent, secret-free env shape.
|
|
267
|
+
*/
|
|
268
|
+
export function buildLaunchEnv(args) {
|
|
269
|
+
return {
|
|
270
|
+
PATH: GUEST_AGENT_PATH,
|
|
271
|
+
GIT_CONFIG_GLOBAL: GUEST_GITCONFIG_PATH,
|
|
272
|
+
...(args.miseEnv ?? {}),
|
|
273
|
+
SYMPHONY_ACP_URL: args.acpWsGuestUrl,
|
|
274
|
+
SYMPHONY_ACP_TOKEN: args.acpToken,
|
|
275
|
+
SYMPHONY_ADAPTER_BIN: args.adapterBin,
|
|
276
|
+
SYMPHONY_ADAPTER_ARGS: JSON.stringify(args.adapterArgs),
|
|
277
|
+
...(args.heartbeatIntervalMs !== undefined
|
|
278
|
+
? { SYMPHONY_HEARTBEAT_INTERVAL_MS: String(args.heartbeatIntervalMs) }
|
|
279
|
+
: {}),
|
|
280
|
+
...(args.heartbeatTimeoutMs !== undefined
|
|
281
|
+
? { SYMPHONY_HEARTBEAT_TIMEOUT_MS: String(args.heartbeatTimeoutMs) }
|
|
282
|
+
: {}),
|
|
283
|
+
...stripCredentialTokenVars(args.runtimeEnv),
|
|
284
|
+
// The placeholder (a fake) is ADDED after the strip — see the ordering note.
|
|
285
|
+
...args.placeholderEnv,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// isCredentialTokenName + stripCredentialTokenVars (the runtime-env token strip)
|
|
289
|
+
// are imported + re-exported from core/vm-guards.ts — see the top-of-file
|
|
290
|
+
// re-export. They preserve non-secret vendor config (e.g. ANTHROPIC_MODEL) while
|
|
291
|
+
// dropping the named credential vars + the *_API_KEY/*_TOKEN/*_SECRET suffixes.
|
|
292
|
+
/**
|
|
293
|
+
* The agent argv exec'd inside the guest. Reference `launchAgent`:
|
|
294
|
+
* `[node, launcherGuestPath]`. The probe resolves the ABSOLUTE node path at
|
|
295
|
+
* runtime (PATH-independent), so the shell passes that as `resolvedNodeBin`; this
|
|
296
|
+
* builder only fixes the [node, launcher] shape.
|
|
297
|
+
*/
|
|
298
|
+
export function buildAgentCommand(resolvedNodeBin, guestAgentPath) {
|
|
299
|
+
return [resolvedNodeBin, guestAgentPath];
|
|
300
|
+
}
|
|
301
|
+
// ─── Session label ──────────────────────────────────────────────────────────
|
|
302
|
+
/**
|
|
303
|
+
* The Gondolin session label / VM name. Reference `runner.ts:vmNameFor` +
|
|
304
|
+
* `gondolin-dispatch.ts:buildCreateVmOptions.sessionLabel`:
|
|
305
|
+
* `symphony-<sanitized-identifier>`, lowercased.
|
|
306
|
+
*/
|
|
307
|
+
export function buildSessionLabel(identifier) {
|
|
308
|
+
return `${SYMPHONY_VM_PREFIX}${sanitizeWorkspaceKey(identifier)}`.toLowerCase();
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Resolve the boot `imagePath` selector (issue 206). The `gondolin.image` escape
|
|
312
|
+
* hatch (a pre-converted asset selector) ALWAYS wins when set; otherwise fall back
|
|
313
|
+
* to the asset the reconcile loop auto-converted from `gondolin.oci_image`
|
|
314
|
+
* (`convertedImageSelector`), and finally to the empty string (no image source —
|
|
315
|
+
* doctor/boot surfaces it). Keeps the convert→dispatch handoff a pure decision.
|
|
316
|
+
*/
|
|
317
|
+
export function resolveImagePath(image, convertedSelector) {
|
|
318
|
+
if (image && image.length > 0)
|
|
319
|
+
return image;
|
|
320
|
+
return convertedSelector ?? '';
|
|
321
|
+
}
|
|
322
|
+
// ─── Top-level assembly ────────────────────────────────────────────────────────
|
|
323
|
+
/**
|
|
324
|
+
* Assemble the complete VmPlan for one dispatch — the single (data) -> VmPlan
|
|
325
|
+
* entry point. Composes every sub-decision (session label, mounts, stripped boot
|
|
326
|
+
* env, staged files, agent argv, control-plane tunnel) so the shell dispatcher
|
|
327
|
+
* only EXECUTES the plan. Pure: no IO, no clock, no randomness.
|
|
328
|
+
*
|
|
329
|
+
* The guest path the launcher is staged/exec'd at comes from
|
|
330
|
+
* `cfg.gondolin.guest_agent_path` (the SINGLE source of truth — same value drives
|
|
331
|
+
* the staged file AND the exec arg, so they can never drift); falls back to the
|
|
332
|
+
* default when unset. The launch env rides on VmPlan via the assembled launch env
|
|
333
|
+
* — but VmPlan's shape carries only `env` (boot env), `guestFiles`, and
|
|
334
|
+
* `agentCommand`, so the LAUNCH env (distinct from the boot env) is returned
|
|
335
|
+
* alongside the plan for the shell's `vm.exec` env. By design VmPlan has no
|
|
336
|
+
* `launchEnv` field; we surface it next to the plan rather than widening the type
|
|
337
|
+
* another slice owns.
|
|
338
|
+
*/
|
|
339
|
+
export function buildVmPlan(input) {
|
|
340
|
+
const { cfg, resolved } = input;
|
|
341
|
+
const guestAgentPath = cfg.gondolin.guest_agent_path && cfg.gondolin.guest_agent_path.length > 0
|
|
342
|
+
? cfg.gondolin.guest_agent_path
|
|
343
|
+
: DEFAULT_VM_AGENT_GUEST_PATH;
|
|
344
|
+
const tunnel = buildControlPlaneTunnel(cfg, input.boundMcpPort);
|
|
345
|
+
// mise toolchain slice (issue 209): the env rides the boot env + the install/
|
|
346
|
+
// probe/launch execs; the system config is always staged (issue 233).
|
|
347
|
+
const miseEnv = buildMiseEnv();
|
|
348
|
+
const mise = {
|
|
349
|
+
env: miseEnv,
|
|
350
|
+
prepCommand: buildMisePrepCommand(),
|
|
351
|
+
installCommand: buildMiseInstallCommand(input.workspacePath),
|
|
352
|
+
};
|
|
353
|
+
const plan = {
|
|
354
|
+
sessionLabel: buildSessionLabel(input.identifier),
|
|
355
|
+
imagePath: resolveImagePath(cfg.gondolin.image, input.convertedImageSelector),
|
|
356
|
+
cpus: cfg.gondolin.cpus,
|
|
357
|
+
memMib: cfg.gondolin.mem_mib,
|
|
358
|
+
rootfsSize: cfg.gondolin.rootfs_size,
|
|
359
|
+
mounts: buildVmMounts(cfg, resolved, input.workspacePath),
|
|
360
|
+
env: { ...buildForwardedEnv(cfg, input.readEnv), ...miseEnv },
|
|
361
|
+
guestFiles: buildGuestFiles({
|
|
362
|
+
launcherSource: input.launcherSource,
|
|
363
|
+
guestAgentPath,
|
|
364
|
+
fakeCreds: input.fakeCreds,
|
|
365
|
+
runtimeExtraFiles: input.runtimeExtraFiles,
|
|
366
|
+
miseSystemConfig: miseSystemConfigFile(input.miseSystemConfigSource),
|
|
367
|
+
}),
|
|
368
|
+
agentCommand: buildAgentCommand(input.resolvedNodeBin, guestAgentPath),
|
|
369
|
+
tunnel,
|
|
370
|
+
allowWebSockets: input.allowWebSockets,
|
|
371
|
+
mise,
|
|
372
|
+
};
|
|
373
|
+
// The launch env needs the resolved ACP WS URL; when the tunnel produced none
|
|
374
|
+
// (no reachable control plane) the shell should already have failed the attempt
|
|
375
|
+
// (validateAcpTransport). We carry the empty string here so the type stays a
|
|
376
|
+
// plain string; the shell never reaches launch without a URL.
|
|
377
|
+
const launchEnv = buildLaunchEnv({
|
|
378
|
+
acpWsGuestUrl: tunnel.acpWsGuestUrl ?? '',
|
|
379
|
+
acpToken: input.acpToken,
|
|
380
|
+
adapterBin: input.adapterBin,
|
|
381
|
+
adapterArgs: input.adapterArgs,
|
|
382
|
+
runtimeEnv: input.runtimeEnv,
|
|
383
|
+
placeholderEnv: input.fakeCreds.env,
|
|
384
|
+
miseEnv,
|
|
385
|
+
heartbeatIntervalMs: cfg.acp.heartbeat_interval_ms,
|
|
386
|
+
heartbeatTimeoutMs: cfg.acp.heartbeat_timeout_ms,
|
|
387
|
+
});
|
|
388
|
+
return { plan, launchEnv };
|
|
389
|
+
}
|
|
390
|
+
//# sourceMappingURL=vm-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm-plan.js","sourceRoot":"","sources":["../../../../src/core/runner/vm-plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// FCIS rewrite — memory-aware admission decider (issue 27).
|
|
2
|
+
//
|
|
3
|
+
// Pure port of the original `computeMemoryAdmission` / `parseMemAvailableMib`
|
|
4
|
+
// (REF: src/memory.ts) plus the clamp-transition log decision that lived inline
|
|
5
|
+
// in the orchestrator's `availableGlobalSlots` (REF: src/orchestrator.ts).
|
|
6
|
+
//
|
|
7
|
+
// The /proc/meminfo READ is impure and stays in the shell (a MemProbe adapter);
|
|
8
|
+
// the shell hands this decider a MemorySnapshot. This is the impureCoreRisk fix:
|
|
9
|
+
// core never touches the wall clock, the filesystem, or /proc — it only folds the
|
|
10
|
+
// supplied reading + running count + config into the effective cap and a clamp
|
|
11
|
+
// log decision.
|
|
12
|
+
//
|
|
13
|
+
// Effective cap is `min(static_cap, running + admission_room)` where
|
|
14
|
+
// admission_room = max(0, floor((MemAvailable - reserve) / per_vm)).
|
|
15
|
+
// We add `running` because MemAvailable already reflects the memory the live VMs
|
|
16
|
+
// are using, so admission_room is the count of *additional* VMs that fit; adding
|
|
17
|
+
// the current running count yields a total cap consistent with the static one.
|
|
18
|
+
/**
|
|
19
|
+
* Parse a `/proc/meminfo` body and pull out `MemAvailable`. The kernel emits the
|
|
20
|
+
* value in KiB (`MemAvailable: 12345678 kB`); we return MiB for symmetry with
|
|
21
|
+
* `gondolin.mem_mib` and `agent.host_memory_reserve_mib`. Returns null when the
|
|
22
|
+
* line is missing or unparseable — the decider treats null the same as "probe
|
|
23
|
+
* unsupported" and skips the clamp.
|
|
24
|
+
*
|
|
25
|
+
* Pure: takes the already-read file body as data (the shell's MemProbe does the
|
|
26
|
+
* actual /proc read). No IO, no node builtins.
|
|
27
|
+
*/
|
|
28
|
+
export function parseMemAvailableMib(meminfo) {
|
|
29
|
+
const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB\s*$/m);
|
|
30
|
+
if (!match)
|
|
31
|
+
return null;
|
|
32
|
+
const kb = parseInt(match[1], 10);
|
|
33
|
+
if (!Number.isFinite(kb))
|
|
34
|
+
return null;
|
|
35
|
+
return Math.floor(kb / 1024);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Fold the memory snapshot + running count + config into the admission summary.
|
|
39
|
+
*
|
|
40
|
+
* Skips the clamp (returns the static cap, `clampActive: false`,
|
|
41
|
+
* `admissionRoom: null`) when admission is disabled, the probe returned a null
|
|
42
|
+
* reading (unsupported host / unparseable line), or `perVmMib <= 0`. Otherwise
|
|
43
|
+
* computes the headroom-derived room and clamps the effective cap down to it.
|
|
44
|
+
*/
|
|
45
|
+
export function computeMemoryAdmission(input) {
|
|
46
|
+
const { enabled, staticCap, running, probe, reserveMib, perVmMib } = input;
|
|
47
|
+
if (!enabled || probe.memAvailableMib === null || perVmMib <= 0) {
|
|
48
|
+
return {
|
|
49
|
+
enabled,
|
|
50
|
+
staticCap,
|
|
51
|
+
effectiveCap: staticCap,
|
|
52
|
+
admissionRoom: null,
|
|
53
|
+
memAvailableMib: probe.memAvailableMib,
|
|
54
|
+
reserveMib,
|
|
55
|
+
perVmMib,
|
|
56
|
+
clampActive: false,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const headroom = probe.memAvailableMib - reserveMib;
|
|
60
|
+
const room = headroom <= 0 ? 0 : Math.floor(headroom / perVmMib);
|
|
61
|
+
const memoryCap = running + room;
|
|
62
|
+
const effectiveCap = Math.min(staticCap, memoryCap);
|
|
63
|
+
return {
|
|
64
|
+
enabled,
|
|
65
|
+
staticCap,
|
|
66
|
+
effectiveCap,
|
|
67
|
+
admissionRoom: room,
|
|
68
|
+
memAvailableMib: probe.memAvailableMib,
|
|
69
|
+
reserveMib,
|
|
70
|
+
perVmMib,
|
|
71
|
+
clampActive: memoryCap < staticCap,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Compute the number of free global dispatch slots, AND the clamp-transition log
|
|
76
|
+
* decision, from an admission summary.
|
|
77
|
+
*
|
|
78
|
+
* The shell owns the persisted "was the clamp active last tick?" flag and passes
|
|
79
|
+
* it in as `previousClampActive`; this decider returns the next flag plus a
|
|
80
|
+
* LogEffect[] (empty unless the clamp toggled). Only logging on the transition —
|
|
81
|
+
* rather than every tick — keeps the log quiet while memory stays low, matching
|
|
82
|
+
* the original orchestrator behavior.
|
|
83
|
+
*
|
|
84
|
+
* Pending continuations hold their slot (the post-transition resume of an issue
|
|
85
|
+
* that just normal-exited), so the shell subtracts them here too; failure-backoff
|
|
86
|
+
* retries do NOT hold a slot and are excluded by the caller.
|
|
87
|
+
*/
|
|
88
|
+
export function decideAvailableGlobalSlots(args) {
|
|
89
|
+
const { admission, running, pendingContinuations, previousClampActive } = args;
|
|
90
|
+
const logs = [];
|
|
91
|
+
if (admission.clampActive !== previousClampActive) {
|
|
92
|
+
if (admission.clampActive) {
|
|
93
|
+
logs.push({
|
|
94
|
+
family: 'log',
|
|
95
|
+
kind: 'emit',
|
|
96
|
+
level: 'info',
|
|
97
|
+
message: 'memory admission clamping concurrency',
|
|
98
|
+
fields: {
|
|
99
|
+
static_cap: admission.staticCap,
|
|
100
|
+
effective_cap: admission.effectiveCap,
|
|
101
|
+
mem_available_mib: admission.memAvailableMib,
|
|
102
|
+
reserve_mib: admission.reserveMib,
|
|
103
|
+
per_vm_mib: admission.perVmMib,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
logs.push({
|
|
109
|
+
family: 'log',
|
|
110
|
+
kind: 'emit',
|
|
111
|
+
level: 'info',
|
|
112
|
+
message: 'memory admission cleared; full static cap available',
|
|
113
|
+
fields: {
|
|
114
|
+
static_cap: admission.staticCap,
|
|
115
|
+
mem_available_mib: admission.memAvailableMib,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const availableSlots = Math.max(0, admission.effectiveCap - running - pendingContinuations);
|
|
121
|
+
return { availableSlots, nextClampActive: admission.clampActive, logs };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=admission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admission.js","sourceRoot":"","sources":["../../../../src/core/schedule/admission.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// FCIS rewrite — pure circuit-breaker core (issue 128; hardened in issue 135).
|
|
2
|
+
//
|
|
3
|
+
// Ported faithfully from the original `src/orchestrator-decisions.ts`
|
|
4
|
+
// (`normalizeFailureReason`, `decideCircuitBreaker`) plus the holding-state
|
|
5
|
+
// trip-notes text the original `Orchestrator.routeToHolding` rendered inline.
|
|
6
|
+
//
|
|
7
|
+
// The retry path retries an abnormally-exited dispatch with exponential backoff
|
|
8
|
+
// and NO upper bound: a deterministically-failing dispatch loops indefinitely,
|
|
9
|
+
// booting + reaping a VM every backoff interval. These pure helpers bound that
|
|
10
|
+
// loop — count CONSECUTIVE failed dispatches and stop once an issue has made no
|
|
11
|
+
// progress for `threshold` attempts in a row — without the streak bookkeeping
|
|
12
|
+
// leaking into the shell.
|
|
13
|
+
//
|
|
14
|
+
// Issue 135 fix — count by STREAK LENGTH, NOT by same-reason. The original
|
|
15
|
+
// breaker only incremented when the *normalized reason matched the prior one*,
|
|
16
|
+
// so a dispatch that kept failing with FLAPPING reasons reset the counter every
|
|
17
|
+
// time the reason changed and never tripped. Issue 135 looped 8× exactly this
|
|
18
|
+
// way — four `ECONNRESET` turns (streak → 4), then a single `401` (different
|
|
19
|
+
// reason → streak reset to 1), then `ECONNRESET` again (reset to 1) — the lone
|
|
20
|
+
// interleaved 401 landed one short of the threshold and re-armed the breaker
|
|
21
|
+
// from zero. The signal we actually want is "this issue has made no progress
|
|
22
|
+
// for N attempts in a row", which is reason-independent: increment on every
|
|
23
|
+
// consecutive abnormal exit; reset only when a dispatch exits cleanly (the
|
|
24
|
+
// issue progressed). The normalized reason is still tracked, but only to label
|
|
25
|
+
// the trip — it no longer gates counting.
|
|
26
|
+
//
|
|
27
|
+
// Every function here is pure and SYNCHRONOUS: (data) -> data. The single side
|
|
28
|
+
// effect the original performed at the trip site — moving the issue into a
|
|
29
|
+
// holding state with a diagnostic note — becomes a returned `tracker.move_state`
|
|
30
|
+
// Effect (see `tripToHoldingEffect`), which the shell EXECUTES. No clock, no
|
|
31
|
+
// randomness, no IO. Imports are restricted to src/types.
|
|
32
|
+
/**
|
|
33
|
+
* Normalize a failure `reason` for the trip log / holding-state route note so
|
|
34
|
+
* the human-facing message is stable even when the underlying message embeds
|
|
35
|
+
* volatile tokens (request ids, status codes, timestamps, hashes, per-dispatch
|
|
36
|
+
* sentinels).
|
|
37
|
+
*
|
|
38
|
+
* Rule: lowercase, then collapse every whitespace-delimited token that contains
|
|
39
|
+
* a digit into `<id>` — volatile identifiers almost always carry a digit (a
|
|
40
|
+
* request id, an HTTP status, a timestamp fragment, a counter, a hex hash),
|
|
41
|
+
* whereas the human-readable words that carry a failure's *identity* (`agent
|
|
42
|
+
* turn refusal`, `agent turn transport_error`, `vm bring-up error`) do not.
|
|
43
|
+
* Used only for reporting now (counting no longer keys on it — see issue 135).
|
|
44
|
+
*/
|
|
45
|
+
export function normalizeFailureReason(reason) {
|
|
46
|
+
return reason
|
|
47
|
+
.toLowerCase()
|
|
48
|
+
.replace(/\S*\d\S*/g, '<id>')
|
|
49
|
+
.replace(/\s+/g, ' ')
|
|
50
|
+
.trim();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Fold one worker exit into the circuit-breaker streak. A clean exit (`normal`)
|
|
54
|
+
* resets it — the issue made progress. Any abnormal exit increments the streak
|
|
55
|
+
* by one REGARDLESS of reason (issue 135: keying on same-reason let flapping
|
|
56
|
+
* failures dodge the breaker forever). When `threshold > 0` and the streak
|
|
57
|
+
* reaches it, the breaker trips. `threshold <= 0` disables tripping entirely
|
|
58
|
+
* (the streak is still tracked but never trips), so an operator can turn the
|
|
59
|
+
* breaker off. `reason` is normalized only to label the eventual trip.
|
|
60
|
+
*/
|
|
61
|
+
export function decideCircuitBreaker(input) {
|
|
62
|
+
if (input.normal)
|
|
63
|
+
return { kind: 'reset' };
|
|
64
|
+
const normalizedReason = normalizeFailureReason(input.reason);
|
|
65
|
+
const count = input.prior ? input.prior.count + 1 : 1;
|
|
66
|
+
if (input.threshold > 0 && count >= input.threshold) {
|
|
67
|
+
return { kind: 'trip', normalizedReason, count };
|
|
68
|
+
}
|
|
69
|
+
return { kind: 'continue', normalizedReason, count };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Render the diagnostic note appended to the issue when the breaker trips and
|
|
73
|
+
* routes it to a holding state, so the operator sees why it stopped. Ported
|
|
74
|
+
* verbatim from the original `Orchestrator.routeToHolding`.
|
|
75
|
+
*
|
|
76
|
+
* `reason` is the human-facing failure reason (the original passed the RAW exit
|
|
77
|
+
* reason here, not the normalized one — the normalized form is for streak
|
|
78
|
+
* labeling/logging). `count` is the consecutive-failure streak length that
|
|
79
|
+
* tripped the breaker.
|
|
80
|
+
*/
|
|
81
|
+
export function tripHoldingNotes(holdingState, reason, count) {
|
|
82
|
+
return [
|
|
83
|
+
`**Circuit breaker tripped** — routed to \`${holdingState}\` for human inspection.`,
|
|
84
|
+
'',
|
|
85
|
+
`Symphony stopped retrying after **${count} consecutive attempts failed with the same error**, to avoid an unbounded dispatch loop (issue 128).`,
|
|
86
|
+
'',
|
|
87
|
+
`**Last failure reason:** ${reason}`,
|
|
88
|
+
'',
|
|
89
|
+
`Resolve the underlying cause, then move the issue back into an active state to resume dispatch.`,
|
|
90
|
+
].join('\n');
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Fold a tripped breaker into the `tracker.move_state` Effect the shell executes
|
|
94
|
+
* to move the issue into its holding state with the rendered diagnostic note.
|
|
95
|
+
* This is the single seam where the trip decision becomes a side effect: core
|
|
96
|
+
* returns the Effect, the shell performs the tracker move (the original did this
|
|
97
|
+
* inline in `routeToHolding`).
|
|
98
|
+
*/
|
|
99
|
+
export function tripToHoldingEffect(input) {
|
|
100
|
+
return {
|
|
101
|
+
family: 'tracker',
|
|
102
|
+
kind: 'move_state',
|
|
103
|
+
issueId: input.issueId,
|
|
104
|
+
toState: input.holdingState,
|
|
105
|
+
fromRoot: input.fromRoot,
|
|
106
|
+
fromState: input.fromState,
|
|
107
|
+
notes: tripHoldingNotes(input.holdingState, input.reason, input.count),
|
|
108
|
+
actor: input.actor,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../../../src/core/schedule/circuit-breaker.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,sEAAsE;AACtE,4EAA4E;AAC5E,8EAA8E;AAC9E,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,0BAA0B;AAC1B,EAAE;AACF,2EAA2E;AAC3E,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,2EAA2E;AAC3E,+EAA+E;AAC/E,0CAA0C;AAC1C,EAAE;AACF,+EAA+E;AAC/E,2EAA2E;AAC3E,iFAAiF;AACjF,6EAA6E;AAC7E,0DAA0D;AAU1D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,OAAO,MAAM;SACV,WAAW,EAAE;SACb,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;SAC5B,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAaD;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAgC;IACnE,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC3C,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,KAAK,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAAoB,EAAE,MAAc,EAAE,KAAa;IAClF,OAAO;QACL,6CAA6C,YAAY,0BAA0B;QACnF,EAAE;QACF,qCAAqC,KAAK,sGAAsG;QAChJ,EAAE;QACF,4BAA4B,MAAM,EAAE;QACpC,EAAE;QACF,iGAAiG;KAClG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAmBD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAyB;IAC3D,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,YAAY;QAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC;QACtE,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;AACJ,CAAC"}
|