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,338 @@
|
|
|
1
|
+
// FCIS rewrite — imperative shell: the per-attempt runner loop driver.
|
|
2
|
+
//
|
|
3
|
+
// Ports the original `src/agent/runner.ts:runAttempt` phase pipeline (read for
|
|
4
|
+
// reference, never modified). This is the THIN imperative shell: every routing /
|
|
5
|
+
// precedence / classification DECISION lives in the functional core
|
|
6
|
+
// (src/core/runner/{dispatch-config,injection,vm-plan,turn}.ts and
|
|
7
|
+
// src/core/actions/run-fold.ts). The shell only EXECUTES: it sequences the
|
|
8
|
+
// phases, drives real IO through the injected ports, and owns the per-attempt
|
|
9
|
+
// unwind (teardown safety net).
|
|
10
|
+
//
|
|
11
|
+
// Per the FCIS layout rule, a shell module imports from src/types ONLY (the
|
|
12
|
+
// composition root is the one place core is wired in). So the pure-core decision
|
|
13
|
+
// functions this loop needs are INJECTED through `RunnerLoopCore` — the
|
|
14
|
+
// composition root (src/shell/main.ts) binds the real core fns to it. The ports
|
|
15
|
+
// (WorkspacePort, VmClient, AcpPort, IssueTracker, …) come from src/types/ports.
|
|
16
|
+
//
|
|
17
|
+
// Phase pipeline (faithful to the reference runAttemptCore):
|
|
18
|
+
// 1. resolve dispatch config (core: resolveDispatchConfig — pinned ONCE)
|
|
19
|
+
// 2. workspace setup (WorkspacePort.ensureFor + fetchBaseInWorkspace)
|
|
20
|
+
// 3. adapter prep (AdapterRegistry + core: applyRuntimeInjections)
|
|
21
|
+
// 4. validate ACP transport (core: buildControlPlaneTunnel)
|
|
22
|
+
// 5. VM bring-up from VmPlan (core: buildVmPlan → VmBringUp/GondolinDispatcher)
|
|
23
|
+
// 6. ACP session (AcpPort.sessionNew)
|
|
24
|
+
// 7. turn loop (core: turn deciders) — drives AcpPort.runPrompt
|
|
25
|
+
// 8. terminal actions (core: run-fold) — the per-state cleanup block
|
|
26
|
+
// 9. teardown safety net (close VM + deregister secret manager; idempotent)
|
|
27
|
+
import { runTurnLoop } from './runner-loop-turn.js';
|
|
28
|
+
/** Fail a phase: same shape the reference `failPhase` returned. */
|
|
29
|
+
function fail(reason) {
|
|
30
|
+
return { ok: false, reason, threadId: null, turnsCompleted: 0 };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Drive one attempt for `issue`. Mirrors the reference runAttempt: a strict
|
|
34
|
+
* phase pipeline where any phase failure short-circuits to a RunAttemptResult,
|
|
35
|
+
* and a teardown safety net guarantees the VM + per-VM secret registration are
|
|
36
|
+
* released on every exit path (idempotent — teardown guards re-entry).
|
|
37
|
+
*/
|
|
38
|
+
export async function runAttempt(deps, issue, attempt, cancelSignal, runningEntry) {
|
|
39
|
+
const log = deps.log.withIssue(issue.id);
|
|
40
|
+
// Phases 1–5 (config → workspace → injection → VmPlan): all pure failures
|
|
41
|
+
// short-circuit before any VM exists, so no teardown is owed yet.
|
|
42
|
+
const prep = await prepareAttempt(deps, issue, runningEntry, log);
|
|
43
|
+
if (prep.kind === 'fail')
|
|
44
|
+
return fail(prep.reason);
|
|
45
|
+
const { resolved, adapterId, workspacePath, plan, launchEnv } = prep;
|
|
46
|
+
// Bring the VM up through the SINGLE dispatch path (the real GondolinDispatcher:
|
|
47
|
+
// it stages the plan's guest files — INCLUDING the /opt/symphony/vm-agent.mjs
|
|
48
|
+
// launcher — builds the { tcp: { hosts }, dns } tunnel shape, runs the BYO probe +
|
|
49
|
+
// the credential-mount guard, and LAUNCHES the in-VM agent, returning its live
|
|
50
|
+
// exec). After bring-up succeeds ONLY this attempt's teardown can release the
|
|
51
|
+
// handle + the per-VM secret registration, so every post-bring-up exit path runs
|
|
52
|
+
// through `unwind` (reference runSessionOrTeardown).
|
|
53
|
+
let brought;
|
|
54
|
+
try {
|
|
55
|
+
brought = await deps.bringUp.bringUp({
|
|
56
|
+
issue,
|
|
57
|
+
adapterId,
|
|
58
|
+
plan,
|
|
59
|
+
launchEnv,
|
|
60
|
+
workspacePath,
|
|
61
|
+
onStderr: (chunk) => pipeStderrChunk(deps, issue, chunk),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
log.emit('error', 'gondolin dispatch failed', { error: err.message });
|
|
66
|
+
return fail('gondolin dispatch error');
|
|
67
|
+
}
|
|
68
|
+
const vm = brought.vm;
|
|
69
|
+
// From here every failure path MUST tear the VM down. `unwind` is idempotent (the
|
|
70
|
+
// bring-up handle's teardown guards re-entry: kill exec + close VM + deregister).
|
|
71
|
+
let teardownDone = false;
|
|
72
|
+
const unwind = async (reason) => {
|
|
73
|
+
if (teardownDone)
|
|
74
|
+
return;
|
|
75
|
+
teardownDone = true;
|
|
76
|
+
deps.runlog.system(issue.id, 'vm_teardown', { reason });
|
|
77
|
+
// Unpark any awaiting steering reply by EMITTING a steering.cancel Effect through the
|
|
78
|
+
// central interpreter (the SAME seam the HTTP reply path uses), never poking the awaiter.
|
|
79
|
+
// Fire-and-forget: the cancel has no reply and execute() never rejects.
|
|
80
|
+
if (runningEntry)
|
|
81
|
+
void deps.performSteering({ family: 'steering', kind: 'cancel', identifier: runningEntry.identifier });
|
|
82
|
+
try {
|
|
83
|
+
await brought.teardown(reason);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
log.emit('warn', 'gondolin dispatch teardown threw', { error: err.message });
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
try {
|
|
90
|
+
// The in-VM agent is already launched by the bring-up; it dials back the /acp
|
|
91
|
+
// WebSocket and the host AcpPort completes the session over it.
|
|
92
|
+
return await runSession(deps, {
|
|
93
|
+
issue, runningEntry, resolved, adapterId, cancelSignal, attempt, workspacePath, vm, plan, log, unwind,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
// A post-bring-up step threw without unwinding. Release the VM before
|
|
98
|
+
// re-propagating (reference's runSessionOrTeardown catch).
|
|
99
|
+
await unwind('post_dispatch_failure');
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Phases 1–5 minus createVm: resolve dispatch config, set up the workspace,
|
|
105
|
+
* stage runtime injections + fake creds, and assemble the VmPlan. Every failure
|
|
106
|
+
* is returned as data (no VM exists yet, so no teardown is owed).
|
|
107
|
+
*/
|
|
108
|
+
async function prepareAttempt(deps, issue, runningEntry, log) {
|
|
109
|
+
// ── Phase 1: dispatch config (pinned ONCE; reload can't redirect it) ────────
|
|
110
|
+
const resolved = deps.core.resolveDispatchConfig(deps.cfg, issue.state);
|
|
111
|
+
if (resolved instanceof Error) {
|
|
112
|
+
log.emit('error', 'dispatch resolution failed', { error: resolved.message, state: issue.state });
|
|
113
|
+
return { kind: 'fail', reason: 'dispatch resolution error' };
|
|
114
|
+
}
|
|
115
|
+
if (!deps.adapters.isKnown(resolved.adapter)) {
|
|
116
|
+
log.emit('error', 'unknown acp adapter for state', { adapter: resolved.adapter, state: issue.state });
|
|
117
|
+
return { kind: 'fail', reason: 'unknown acp adapter' };
|
|
118
|
+
}
|
|
119
|
+
const adapterId = resolved.adapter;
|
|
120
|
+
// ── Phase 2: workspace setup (ensureFor + pre-dispatch base fetch) ──────────
|
|
121
|
+
// Use repo/base pinned at dispatch so a mid-run WORKFLOW.yaml reload can't
|
|
122
|
+
// retarget the workspace origin / PR base (reference setupSnapshot).
|
|
123
|
+
const githubRepo = runningEntry?.github_repo_at_dispatch || deps.cfg.workspace.github_repo;
|
|
124
|
+
const baseBranch = runningEntry?.base_branch_at_dispatch || deps.cfg.workspace.base_branch;
|
|
125
|
+
const ws = await setupWorkspace(deps, issue, baseBranch, githubRepo, log);
|
|
126
|
+
if (ws === null)
|
|
127
|
+
return { kind: 'fail', reason: 'workspace error' };
|
|
128
|
+
if (ws.fetchFailed)
|
|
129
|
+
return { kind: 'fail', reason: 'pre-dispatch base fetch failed' };
|
|
130
|
+
// ── Phase 3+4+5: injections → fake creds → VmPlan ───────────────────────────
|
|
131
|
+
const built = await buildPlan(deps, issue, resolved, adapterId, ws.path, log);
|
|
132
|
+
if (built.kind === 'fail')
|
|
133
|
+
return built;
|
|
134
|
+
return { kind: 'ok', resolved, adapterId, workspacePath: ws.path, plan: built.plan, launchEnv: built.launchEnv };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Phases 3–5: stage the model/effort injections (pure fold) and per-adapter fake
|
|
138
|
+
* creds (host reads), then assemble the VmPlan in core. validateAcpTransport
|
|
139
|
+
* collapses into the plan's tunnel: a null acpWsGuestUrl means no reachable
|
|
140
|
+
* control plane → fail fast. Failures are returned as data.
|
|
141
|
+
*/
|
|
142
|
+
async function buildPlan(deps, issue, resolved, adapterId, workspacePath, log) {
|
|
143
|
+
let injected;
|
|
144
|
+
let fakeCreds;
|
|
145
|
+
try {
|
|
146
|
+
injected = deps.core.applyRuntimeInjections(deps.adapters.profile(adapterId), { model: resolved.model, effort: resolved.effort });
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
log.emit('error', 'runtime injection staging failed', { adapter: adapterId, error: err.message });
|
|
150
|
+
return { kind: 'fail', reason: 'runtime injection staging error' };
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
fakeCreds = await deps.credStager.stageFakeCreds(adapterId);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
log.emit('error', 'fake-cred staging failed', { adapter: adapterId, error: err.message });
|
|
157
|
+
return { kind: 'fail', reason: 'credential staging error' };
|
|
158
|
+
}
|
|
159
|
+
const { plan, launchEnv } = deps.core.buildVmPlan({
|
|
160
|
+
cfg: deps.cfg,
|
|
161
|
+
resolved,
|
|
162
|
+
identifier: issue.identifier,
|
|
163
|
+
workspacePath,
|
|
164
|
+
adapterBin: injected.adapterBin,
|
|
165
|
+
adapterArgs: injected.effectiveAdapterArgs,
|
|
166
|
+
runtimeEnv: injected.runtimeEnv,
|
|
167
|
+
runtimeExtraFiles: injected.runtimeExtraFiles,
|
|
168
|
+
fakeCreds,
|
|
169
|
+
launcherSource: deps.launcherSource,
|
|
170
|
+
// The symphony-bundled mise SYSTEM config (issue 209); core always stages it at
|
|
171
|
+
// /etc/mise/config.toml (mise provisioning is unconditional, issue 233).
|
|
172
|
+
miseSystemConfigSource: deps.miseSystemConfigSource,
|
|
173
|
+
// The SAME token the dispatch slice registered with the AcpWsRegistry BEFORE
|
|
174
|
+
// bring-up — so the launch env bearer matches the pending registration the guest
|
|
175
|
+
// dials back against (NOT a second, divergent `random.newToken()`).
|
|
176
|
+
acpToken: deps.acpToken,
|
|
177
|
+
resolvedNodeBin: deps.resolvedNodeBin,
|
|
178
|
+
boundMcpPort: deps.boundMcpPort,
|
|
179
|
+
allowWebSockets: deps.allowWebSockets(adapterId),
|
|
180
|
+
// The asset auto-converted from `gondolin.oci_image` (issue 206); core uses it
|
|
181
|
+
// as the boot imagePath only when the `gondolin.image` escape hatch is unset.
|
|
182
|
+
convertedImageSelector: deps.convertedImageSelector ?? null,
|
|
183
|
+
readEnv: deps.readEnv,
|
|
184
|
+
});
|
|
185
|
+
if (plan.tunnel.acpWsGuestUrl === null) {
|
|
186
|
+
log.emit('error', 'acp ws has no reachable guest dial-back URL', {
|
|
187
|
+
mcp_enabled: deps.cfg.mcp.enabled,
|
|
188
|
+
explicit_host_url: deps.cfg.mcp.explicit_host_url,
|
|
189
|
+
});
|
|
190
|
+
return { kind: 'fail', reason: 'acp ws url unavailable' };
|
|
191
|
+
}
|
|
192
|
+
return { kind: 'ok', plan, launchEnv };
|
|
193
|
+
}
|
|
194
|
+
/** Workspace ensure + pre-dispatch base fetch; null = ensure failed. */
|
|
195
|
+
async function setupWorkspace(deps, issue, baseBranch, githubRepo, log) {
|
|
196
|
+
let path;
|
|
197
|
+
try {
|
|
198
|
+
path = (await deps.workspaces.ensureFor(issue.identifier, { baseBranch, githubRepo })).path;
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
log.emit('error', 'workspace error', { error: err.message });
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
await deps.workspaces.fetchBaseInWorkspace(path, baseBranch);
|
|
206
|
+
deps.runlog.system(issue.id, 'pre_dispatch_base_fetch_ok', { base_branch: baseBranch });
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
log.emit('error', 'pre-dispatch base fetch failed; aborting attempt', {
|
|
210
|
+
base_branch: baseBranch,
|
|
211
|
+
error: err.message,
|
|
212
|
+
});
|
|
213
|
+
deps.runlog.system(issue.id, 'pre_dispatch_base_fetch_failed', {
|
|
214
|
+
base_branch: baseBranch,
|
|
215
|
+
error: err.message,
|
|
216
|
+
});
|
|
217
|
+
return { path, fetchFailed: true };
|
|
218
|
+
}
|
|
219
|
+
return { path, fetchFailed: false };
|
|
220
|
+
}
|
|
221
|
+
/** Phases 6–9: open the ACP session, run the turn loop, run terminal actions, tear down. */
|
|
222
|
+
async function runSession(deps, a) {
|
|
223
|
+
// ── Phase 6: ACP session over the /acp WebSocket (dial-back) ────────────────
|
|
224
|
+
let sessionId;
|
|
225
|
+
try {
|
|
226
|
+
sessionId = (await deps.acp.sessionNew(a.vm.id, { mcpEnabled: deps.cfg.mcp.enabled })).sessionId;
|
|
227
|
+
deps.runlog.system(a.issue.id, 'acp_ws_connected', { acp_url: a.plan.tunnel.acpWsGuestUrl });
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
a.log.emit('error', 'acp init failed', { error: err.message, adapter: a.adapterId });
|
|
231
|
+
await a.unwind('init_failed');
|
|
232
|
+
return fail('agent session startup error');
|
|
233
|
+
}
|
|
234
|
+
// ── Phase 7: autonomous turn loop ───────────────────────────────────────────
|
|
235
|
+
const activeStates = new Set(deps.core.activeStateNames(deps.cfg.states).map((s) => s.toLowerCase()));
|
|
236
|
+
const loop = await runTurnLoop(deps, {
|
|
237
|
+
issue: a.issue,
|
|
238
|
+
runningEntry: a.runningEntry,
|
|
239
|
+
resolved: a.resolved,
|
|
240
|
+
adapterId: a.adapterId,
|
|
241
|
+
cancelSignal: a.cancelSignal,
|
|
242
|
+
attempt: a.attempt,
|
|
243
|
+
sessionId,
|
|
244
|
+
activeStates,
|
|
245
|
+
log: a.log,
|
|
246
|
+
});
|
|
247
|
+
// ── Phase 8: terminal-state actions (cleanup block; VM still alive) ─────────
|
|
248
|
+
const nonRouted = a.runningEntry ? await runTerminalActions(deps, a, a.runningEntry) : null;
|
|
249
|
+
// ── Phase 9: teardown + compose result ──────────────────────────────────────
|
|
250
|
+
await a.unwind(loop.kind === 'mid_failure' ? loop.cleanupReason : loop.lastReason);
|
|
251
|
+
if (loop.kind === 'mid_failure') {
|
|
252
|
+
return { ok: false, reason: loop.publicReason, threadId: sessionId, turnsCompleted: loop.turnsCompleted };
|
|
253
|
+
}
|
|
254
|
+
return deps.core.decideAttemptOutcome({
|
|
255
|
+
agentFailure: loop.agentFailure,
|
|
256
|
+
nonRoutedActionFailureReason: nonRouted,
|
|
257
|
+
lastReason: loop.lastReason,
|
|
258
|
+
sessionId,
|
|
259
|
+
turnsCompleted: loop.turnsCompleted,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Phase 8: run the issue's state `actions:` block (the VM is still alive so a
|
|
264
|
+
* `run_in_vm` action can exec into it), then RETAIN the workspace on any failed
|
|
265
|
+
* handoff. Returns the non-routed (abort) failure reason for the attempt outcome;
|
|
266
|
+
* a route — the issue already moved out into the HandoffFailed holding state (235) —
|
|
267
|
+
* returns null (a clean attempt). The workspace is marked for retention (234's
|
|
268
|
+
* handoff-pending marker) whenever the handoff failed at all, routed OR aborted, so
|
|
269
|
+
* the only copy of the completed commit survives for a manual push.
|
|
270
|
+
*/
|
|
271
|
+
async function runTerminalActions(deps, a, entry) {
|
|
272
|
+
const actionState = entry.issue.state ?? a.issue.state;
|
|
273
|
+
let nonRouted = null;
|
|
274
|
+
let markHandoffReason = null;
|
|
275
|
+
try {
|
|
276
|
+
const run = await deps.actions.runStateActions({ state: actionState, entry, workspacePath: a.workspacePath, vm: a.vm });
|
|
277
|
+
nonRouted = run.nonRouted;
|
|
278
|
+
markHandoffReason = run.markHandoffReason;
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
nonRouted = err.message;
|
|
282
|
+
markHandoffReason = nonRouted;
|
|
283
|
+
}
|
|
284
|
+
if (markHandoffReason !== null)
|
|
285
|
+
await markHandoffIfTerminal(deps, a, actionState, markHandoffReason);
|
|
286
|
+
return nonRouted;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* On a terminal-state phase-8 handoff FAILURE, drop the workspace's handoff-pending
|
|
290
|
+
* marker so the janitor RETAINS the dir (the only copy of the completed commit lives
|
|
291
|
+
* there) instead of reaping it ~5 min later — turning a recoverable push failure into
|
|
292
|
+
* permanent loss (issue 234). No-op for a non-terminal state (its workspace is desired,
|
|
293
|
+
* never reaped). Best-effort: a marker-write failure never changes the attempt outcome.
|
|
294
|
+
*/
|
|
295
|
+
async function markHandoffIfTerminal(deps, a, state, reason) {
|
|
296
|
+
if (!isTerminalState(deps.cfg, state))
|
|
297
|
+
return;
|
|
298
|
+
try {
|
|
299
|
+
await deps.workspaces.markHandoffPending(a.issue.identifier, reason);
|
|
300
|
+
deps.runlog.system(a.issue.id, 'handoff_marker_written', { state, reason });
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
a.log.emit('warn', 'failed to write handoff-pending marker', { error: err.message });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/** Case-insensitive terminal-role check: the issue's front-matter state may differ in
|
|
307
|
+
* casing from the declared state key (mirrors core/state-resolve.ts's resolution). */
|
|
308
|
+
function isTerminalState(cfg, state) {
|
|
309
|
+
const exact = cfg.states[state];
|
|
310
|
+
if (exact)
|
|
311
|
+
return exact.role === 'terminal';
|
|
312
|
+
const lower = state.toLowerCase();
|
|
313
|
+
for (const [name, sc] of Object.entries(cfg.states)) {
|
|
314
|
+
if (name.toLowerCase() === lower)
|
|
315
|
+
return sc.role === 'terminal';
|
|
316
|
+
}
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* The diagnostic-stderr sink: fold ONE chunk of the in-VM agent's stderr into the
|
|
321
|
+
* run log. Mirrors the reference `onAgentStderr` (truncated runtime event + run-log
|
|
322
|
+
* record). The bring-up (GondolinDispatcher) owns the stream tap and hands each
|
|
323
|
+
* chunk here. Fire-and-forget — failures here never fail the attempt.
|
|
324
|
+
*/
|
|
325
|
+
function pipeStderrChunk(deps, issue, chunk) {
|
|
326
|
+
try {
|
|
327
|
+
const entry = { channel: 'stderr', text: chunk };
|
|
328
|
+
deps.runlog.record(issue.id, entry);
|
|
329
|
+
const text = chunk.trim();
|
|
330
|
+
if (text.length === 0)
|
|
331
|
+
return;
|
|
332
|
+
deps.log.withIssue(issue.id).emit('info', 'agent stderr', { text: text.slice(0, 500) });
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
// Best-effort tap; a malformed chunk just yields no record.
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=runner-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-loop.js","sourceRoot":"","sources":["../../../src/shell/runner-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// FCIS rewrite — node:http transport adapter (kind: server).
|
|
2
|
+
//
|
|
3
|
+
// THIN imperative shell for the unified HTTP server. Implements `HttpServerPort`
|
|
4
|
+
// (bind/stop) and does ONE job per request: read the wire (method, headers, body)
|
|
5
|
+
// into an `HttpRequestView`, hand it to the injected `handle` (wired in the
|
|
6
|
+
// composition root to core http/routes + http/decisions + http/views + http/render),
|
|
7
|
+
// then write the `HttpResponseSpec` core returns. EVERY domain decision — route
|
|
8
|
+
// matching, CSRF gating, create-issue validation, triage transitions, all HTML
|
|
9
|
+
// rendering — lives in core; this file only moves bytes.
|
|
10
|
+
//
|
|
11
|
+
// It also hosts the two non-request concerns that are legitimately transport:
|
|
12
|
+
// • the `/acp` WebSocket `Upgrade` the in-VM agent dials back on (forwarded to
|
|
13
|
+
// the injected AcpWsRegistry.handleUpgrade — see src/shell/interp/acp-ws.ts);
|
|
14
|
+
// • `clientError` (a malformed request line / oversized header) → a raw
|
|
15
|
+
// `400 Bad Request` on the socket;
|
|
16
|
+
// • a malformed `Host`/request-URL that would otherwise throw inside `new URL`
|
|
17
|
+
// → a structured `400` JSON body (the critic gap the reference guards against
|
|
18
|
+
// at src/http.ts handleRequest).
|
|
19
|
+
//
|
|
20
|
+
// The preview asset (`.impeccable/preview/dashboard.html`) is served by the
|
|
21
|
+
// injected `handle` itself: reading that file is async IO the composition-root
|
|
22
|
+
// wiring performs, so the route stays core-owned while the read stays in the shell.
|
|
23
|
+
//
|
|
24
|
+
// Reference (read-only, do not edit): src/http.ts — startHttpServer / handleRequest.
|
|
25
|
+
import { createServer } from 'node:http';
|
|
26
|
+
const DEFAULT_MAX_BODY_BYTES = 1_000_000;
|
|
27
|
+
/** A JSON error body in the reference's `{ error: { code, message } }` shape. */
|
|
28
|
+
function jsonError(status, code, message) {
|
|
29
|
+
return {
|
|
30
|
+
status,
|
|
31
|
+
contentType: 'application/json; charset=utf-8',
|
|
32
|
+
body: JSON.stringify({ error: { code, message } }),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Drain the request body to a UTF-8 string, capping at `maxBytes`. Rejects on
|
|
36
|
+
* overflow (the reference destroys the socket + surfaces "request body too
|
|
37
|
+
* large"); core decides what an empty body means. */
|
|
38
|
+
function readRawBody(req, maxBytes) {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const chunks = [];
|
|
41
|
+
let size = 0;
|
|
42
|
+
req.on('data', (chunk) => {
|
|
43
|
+
size += chunk.length;
|
|
44
|
+
if (size > maxBytes) {
|
|
45
|
+
req.destroy();
|
|
46
|
+
reject(new Error('request body too large'));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
chunks.push(chunk);
|
|
50
|
+
});
|
|
51
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
52
|
+
req.on('error', reject);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** Flatten node's `string | string[] | undefined` header values to a lowercased
|
|
56
|
+
* single-string map (array headers collapse to their first value — none of the
|
|
57
|
+
* headers core inspects are legitimately repeated). */
|
|
58
|
+
function viewHeaders(req) {
|
|
59
|
+
const out = {};
|
|
60
|
+
for (const [k, v] of Object.entries(req.headers)) {
|
|
61
|
+
out[k.toLowerCase()] = Array.isArray(v) ? v[0] : v;
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
/** Write a `HttpResponseSpec` to the live `ServerResponse`. Sets content-type +
|
|
66
|
+
* content-length and any extra headers core asked for (e.g. cache-control). */
|
|
67
|
+
function writeSpec(res, spec) {
|
|
68
|
+
res.statusCode = spec.status;
|
|
69
|
+
res.setHeader('content-type', spec.contentType);
|
|
70
|
+
if (spec.headers) {
|
|
71
|
+
for (const [k, v] of Object.entries(spec.headers))
|
|
72
|
+
res.setHeader(k, v);
|
|
73
|
+
}
|
|
74
|
+
res.setHeader('content-length', Buffer.byteLength(spec.body));
|
|
75
|
+
res.end(spec.body);
|
|
76
|
+
}
|
|
77
|
+
/** Parse the request pathname, defending the listener against a malformed
|
|
78
|
+
* `Host`/request-target that would throw inside `new URL` (the critic gap). */
|
|
79
|
+
function parsePathname(req) {
|
|
80
|
+
try {
|
|
81
|
+
return new URL(req.url ?? '/', 'http://symphony.local').pathname;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function handleRequest(req, res, deps, maxBytes) {
|
|
88
|
+
const pathname = parsePathname(req);
|
|
89
|
+
if (pathname === null) {
|
|
90
|
+
writeSpec(res, jsonError(400, 'bad_request', 'invalid request URL'));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Body is drained for every method; core ignores it for GET/HEAD. An overflow
|
|
94
|
+
// is the one read failure the transport owns — map it to a structured 400.
|
|
95
|
+
let rawBody;
|
|
96
|
+
try {
|
|
97
|
+
rawBody = await readRawBody(req, maxBytes);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
writeSpec(res, jsonError(400, 'bad_request', err.message));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const view = {
|
|
104
|
+
method: (req.method ?? 'GET').toUpperCase(),
|
|
105
|
+
pathname,
|
|
106
|
+
headers: viewHeaders(req),
|
|
107
|
+
rawBody,
|
|
108
|
+
};
|
|
109
|
+
const spec = await deps.handle(view);
|
|
110
|
+
writeSpec(res, spec);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Build the node:http server adapter implementing `HttpServerPort`. Construction
|
|
114
|
+
* does not bind; `bind` listens (resolving the actually-bound port, relevant for
|
|
115
|
+
* a `--port 0` request) and `stop` closes the listener + tears down any pending
|
|
116
|
+
* `/acp` socket via the registry's own `stop` (the registry, not this file, owns
|
|
117
|
+
* upgraded-socket lifecycle).
|
|
118
|
+
*/
|
|
119
|
+
export function createHttpServer(deps) {
|
|
120
|
+
const maxBytes = deps.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
121
|
+
let server = null;
|
|
122
|
+
function build() {
|
|
123
|
+
const s = createServer((req, res) => {
|
|
124
|
+
void handleRequest(req, res, deps, maxBytes).catch((err) => {
|
|
125
|
+
deps.log.emit('error', 'http handler error', { error: err.message });
|
|
126
|
+
try {
|
|
127
|
+
writeSpec(res, jsonError(500, 'internal_error', err.message));
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
/* response already started — nothing safe to write */
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
// A malformed request line / oversized header never reaches handleRequest;
|
|
135
|
+
// node emits clientError instead. Mirror the reference: raw 400 on the wire.
|
|
136
|
+
s.on('clientError', (err, socket) => {
|
|
137
|
+
deps.log.emit('debug', 'http client error', { error: err.message });
|
|
138
|
+
try {
|
|
139
|
+
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* socket may already be closed */
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
// The in-VM agent dials `ws://…/acp`; the registry completes the RFC-6455
|
|
146
|
+
// handshake + first-message bearer auth. No registry ⇒ refuse the upgrade by
|
|
147
|
+
// destroying the socket (an un-answered upgrade would otherwise hang the peer).
|
|
148
|
+
s.on('upgrade', (req, socket, head) => {
|
|
149
|
+
// Node types the upgrade socket as a bare Duplex; at runtime it is the
|
|
150
|
+
// underlying net.Socket the registry needs for setNoDelay / remote-address.
|
|
151
|
+
const sock = socket;
|
|
152
|
+
if (deps.acpUpgrade)
|
|
153
|
+
deps.acpUpgrade(req, sock, head);
|
|
154
|
+
else
|
|
155
|
+
sock.destroy();
|
|
156
|
+
});
|
|
157
|
+
return s;
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
async bind(requestedPort, host) {
|
|
161
|
+
const s = build();
|
|
162
|
+
server = s;
|
|
163
|
+
const listenPort = requestedPort ?? 0;
|
|
164
|
+
await new Promise((resolve, reject) => {
|
|
165
|
+
const onError = (err) => {
|
|
166
|
+
s.removeListener('listening', onListening);
|
|
167
|
+
reject(err);
|
|
168
|
+
};
|
|
169
|
+
const onListening = () => {
|
|
170
|
+
s.removeListener('error', onError);
|
|
171
|
+
resolve();
|
|
172
|
+
};
|
|
173
|
+
s.once('error', onError);
|
|
174
|
+
s.once('listening', onListening);
|
|
175
|
+
s.listen(listenPort, host);
|
|
176
|
+
});
|
|
177
|
+
// After a clean bind, swap the fatal bind-error listener for a permanent
|
|
178
|
+
// one so later runtime socket faults (ENOTCONN, resets) log instead of
|
|
179
|
+
// crashing the process.
|
|
180
|
+
s.on('error', (err) => {
|
|
181
|
+
deps.log.emit('warn', 'http server error', { error: err.message });
|
|
182
|
+
});
|
|
183
|
+
const addr = s.address();
|
|
184
|
+
const port = typeof addr === 'object' && addr ? addr.port : listenPort;
|
|
185
|
+
deps.log.emit('info', 'http server listening', { host, port });
|
|
186
|
+
return { port };
|
|
187
|
+
},
|
|
188
|
+
async stop() {
|
|
189
|
+
const s = server;
|
|
190
|
+
if (!s)
|
|
191
|
+
return;
|
|
192
|
+
server = null;
|
|
193
|
+
// Force-close the registry's upgraded `/acp` sockets FIRST: server.close()
|
|
194
|
+
// only refuses new connections and resolves once existing ones drain, so a
|
|
195
|
+
// live WebSocket would otherwise hang the close() callback forever. The
|
|
196
|
+
// registry's stop() rejects pending registrations + destroys every tracked
|
|
197
|
+
// socket, letting the listener drain cleanly. Best-effort (never block the
|
|
198
|
+
// listener teardown on a registry fault).
|
|
199
|
+
if (deps.acpStop) {
|
|
200
|
+
await deps.acpStop().catch((err) => {
|
|
201
|
+
deps.log.emit('warn', 'acp ws registry stop failed', { error: err.message });
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
await new Promise((resolve) => s.close(() => resolve()));
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../../src/shell/server/http.ts"],"names":[],"mappings":"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"}
|