smol-symphony 0.1.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 +125 -39
- package/DESIGN.md +494 -273
- package/PRODUCT.md +2 -1
- package/README.md +259 -110
- package/SPEC.md +565 -1928
- package/WORKFLOW.minimal.yaml +34 -0
- package/WORKFLOW.template.yaml +1100 -0
- 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/src/core/actions/parse.js +192 -0
- 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/src/core/http/render.js +1635 -0
- package/dist/src/core/http/render.js.map +1 -0
- package/dist/src/core/http/routes.js +145 -0
- 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/src/core/reconcile/pr-decide.js +180 -0
- 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 +31 -11
- 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 +433 -0
- package/WORKFLOW.md +0 -269
- package/WORKFLOW.template.md +0 -307
- package/dist/agent/acp.js +0 -304
- package/dist/agent/acp.js.map +0 -1
- package/dist/agent/adapters.js +0 -275
- package/dist/agent/adapters.js.map +0 -1
- package/dist/agent/codex.js +0 -439
- package/dist/agent/codex.js.map +0 -1
- package/dist/agent/runner.js +0 -394
- package/dist/agent/runner.js.map +0 -1
- package/dist/agent/smolvm.js +0 -174
- package/dist/agent/smolvm.js.map +0 -1
- package/dist/bin/symphony.js +0 -205
- package/dist/bin/symphony.js.map +0 -1
- package/dist/http.js +0 -1189
- package/dist/http.js.map +0 -1
- package/dist/logging.js +0 -45
- package/dist/logging.js.map +0 -1
- package/dist/mcp.js +0 -478
- package/dist/mcp.js.map +0 -1
- package/dist/orchestrator.js +0 -683
- package/dist/orchestrator.js.map +0 -1
- package/dist/prompt.js +0 -65
- package/dist/prompt.js.map +0 -1
- package/dist/trackers/local.js +0 -344
- 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/workflow.js +0 -385
- package/dist/workflow.js.map +0 -1
- package/dist/workspace.js +0 -196
- package/dist/workspace.js.map +0 -1
- package/scripts/build-vm.sh +0 -67
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// FCIS rewrite — pure per-PR cache TTL freshness predicates.
|
|
2
|
+
//
|
|
3
|
+
// Extracted from the original `src/reconciler/pr.ts` (`PrResource.lookupPrSummary`
|
|
4
|
+
// + `PrResource.fetchPrView`), which tangled these freshness checks into the same
|
|
5
|
+
// async methods that shelled out to `gh pr list`/`gh pr view` and mutated state.
|
|
6
|
+
// Here it is ONLY the decision: given an injected `now` plus the prior
|
|
7
|
+
// `lastLookupAt`/`lastViewAt` and the cached payloads, reuse or re-poll/re-fetch.
|
|
8
|
+
//
|
|
9
|
+
// Two INDEPENDENT predicates (issue 70 "sticky cache" mustFix):
|
|
10
|
+
// 1. Summary (sticky): once a PR is FOUND it is reused forever — PR numbers
|
|
11
|
+
// don't change and a found PR moving OPEN→MERGED/CLOSED must keep its cached
|
|
12
|
+
// number so the autopilot can observe the terminal state. `lastLookupAt`
|
|
13
|
+
// governs ONLY the cache-MISS (null) re-poll.
|
|
14
|
+
// 2. View (TTL): plain time-to-live on the detailed view, keyed solely on its
|
|
15
|
+
// own `lastViewAt` — never coupled to the summary re-poll.
|
|
16
|
+
//
|
|
17
|
+
// `pollIntervalMs === 0` disables caching on both paths: the strict `<` makes any
|
|
18
|
+
// elapsed (>= 0) fall outside the window. Pure + synchronous: `now` is injected.
|
|
19
|
+
/** Mirrors the head of `PrResource.lookupPrSummary`: sticky short-circuit, then null-result TTL guard. */
|
|
20
|
+
export function decidePrSummaryFreshness(input) {
|
|
21
|
+
if (input.summary)
|
|
22
|
+
return { kind: 'reuse', summary: input.summary };
|
|
23
|
+
if (input.summary === null && input.now - input.lastLookupAt < input.pollIntervalMs) {
|
|
24
|
+
return { kind: 'defer' };
|
|
25
|
+
}
|
|
26
|
+
return { kind: 'repoll' };
|
|
27
|
+
}
|
|
28
|
+
/** Mirrors the head of `PrResource.fetchPrView`: reuse while inside the TTL, else re-fetch (strict `<`). */
|
|
29
|
+
export function decidePrViewFreshness(input) {
|
|
30
|
+
if (input.view !== null && input.now - input.lastViewAt < input.pollIntervalMs) {
|
|
31
|
+
return { kind: 'reuse', view: input.view };
|
|
32
|
+
}
|
|
33
|
+
return { kind: 'refetch' };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=pr-notes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-notes.js","sourceRoot":"","sources":["../../../../src/core/reconcile/pr-notes.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,mFAAmF;AACnF,kFAAkF;AAClF,iFAAiF;AACjF,uEAAuE;AACvE,kFAAkF;AAClF,EAAE;AACF,gEAAgE;AAChE,8EAA8E;AAC9E,kFAAkF;AAClF,8EAA8E;AAC9E,mDAAmD;AACnD,gFAAgF;AAChF,gEAAgE;AAChE,EAAE;AACF,kFAAkF;AAClF,iFAAiF;AAsBjF,0GAA0G;AAC1G,MAAM,UAAU,wBAAwB,CAAC,KAA8B;IACrE,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;IACpE,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;QACpF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAmBD,4GAA4G;AAC5G,MAAM,UAAU,qBAAqB,CAAC,KAA2B;IAC/D,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;QAC/E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// FCIS rewrite — pure VM-reaper decision core (issue 33 / reconciler stage 2;
|
|
2
|
+
// Gondolin migration Phase 4).
|
|
3
|
+
//
|
|
4
|
+
// Verbatim port of the original `src/reconciler/vm.ts:decideVm`. The original
|
|
5
|
+
// module mixed the pure decision (`decideVm`) with the imperative reaper loop
|
|
6
|
+
// (`VmResource`, gc / listSessions / process.kill / setTimeout). This rewrite
|
|
7
|
+
// extracts ONLY the pure decision; the SIGTERM→grace→SIGKILL escalation, the
|
|
8
|
+
// Gondolin gc, the session enumeration, and the ledger all live in the shell.
|
|
9
|
+
//
|
|
10
|
+
// The decision: given the observed live Gondolin session set, the orchestrator's
|
|
11
|
+
// intended label set, and the reaper's own pid, return one `kill_session`
|
|
12
|
+
// effect per session that is a LIVE orphan — a `symphony-`-prefixed session that
|
|
13
|
+
// the orchestrator does NOT intend to keep alive AND whose host pid is safe to
|
|
14
|
+
// signal (a sane positive integer that is not the reaper itself).
|
|
15
|
+
//
|
|
16
|
+
// Pid safety (verbatim from the original): a host signal is only ever emitted
|
|
17
|
+
// for a `pid` that is a safe positive integer and is NOT the reaper's own pid.
|
|
18
|
+
// The shell delivers the signal with `process.kill(pid, sig)`, which signals the
|
|
19
|
+
// whole PROCESS GROUP for `pid <= 0` and would target the orchestrator itself
|
|
20
|
+
// for `pid === selfPid`. A session carrying a `0`/`NaN`/negative/self pid is a
|
|
21
|
+
// registry anomaly, never a legitimate orphan, so it is left untouched here.
|
|
22
|
+
//
|
|
23
|
+
// Namespace safety (verbatim): anything outside the symphony-prefixed namespace
|
|
24
|
+
// — a session with no label, or a label that doesn't start with the prefix — is
|
|
25
|
+
// left untouched (operator VMs, sibling tools' sessions). STALE/dead-pid
|
|
26
|
+
// sessions and orphan sockets are NOT this function's concern; Gondolin's
|
|
27
|
+
// `gc()` collects them in the shell before the live session set reaches here.
|
|
28
|
+
//
|
|
29
|
+
// HARD CONSTRAINTS (gate-enforced): 100% synchronous; no async/await/Promise; no
|
|
30
|
+
// IO, node: imports, process, clock, or randomness. Imports ONLY from
|
|
31
|
+
// src/types. Every side effect is RETURNED as a `KillSessionAction[]`; the
|
|
32
|
+
// shell executes it.
|
|
33
|
+
/**
|
|
34
|
+
* Domain constant. Every VM the orchestrator creates is labelled with this
|
|
35
|
+
* prefix (the runner mints `sessionLabel = symphony-<identifier>`); the reaper
|
|
36
|
+
* only acts on labels that match. The vm-port adapter in the shell mirrors the
|
|
37
|
+
* same value — keep them in sync.
|
|
38
|
+
*/
|
|
39
|
+
export const SYMPHONY_VM_PREFIX = 'symphony-';
|
|
40
|
+
/**
|
|
41
|
+
* Pure decision: given the observed Gondolin session state, return the
|
|
42
|
+
* `kill_session` effects the shell should apply. No IO, no clock reads, no
|
|
43
|
+
* logging.
|
|
44
|
+
*
|
|
45
|
+
* Effect rule:
|
|
46
|
+
* • Session has a `label` that starts with SYMPHONY_VM_PREFIX and isn't
|
|
47
|
+
* intended, AND a sane, non-self host pid → `kill_session` (the shell
|
|
48
|
+
* SIGTERM→SIGKILLs its host pid).
|
|
49
|
+
*/
|
|
50
|
+
export function decideVm(state) {
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const s of state.sessions) {
|
|
53
|
+
const label = s.label;
|
|
54
|
+
if (label === undefined)
|
|
55
|
+
continue;
|
|
56
|
+
if (!label.startsWith(SYMPHONY_VM_PREFIX))
|
|
57
|
+
continue;
|
|
58
|
+
if (state.intendedLabels.has(label))
|
|
59
|
+
continue;
|
|
60
|
+
// Pid safety: skip anomalous pids (0/NaN/negative — process-group / invalid)
|
|
61
|
+
// and never signal the reaper's own process.
|
|
62
|
+
if (!Number.isSafeInteger(s.pid) || s.pid <= 0)
|
|
63
|
+
continue;
|
|
64
|
+
if (s.pid === state.selfPid)
|
|
65
|
+
continue;
|
|
66
|
+
out.push({ kind: 'kill_session', pid: s.pid, label });
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=vm-decide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm-decide.js","sourceRoot":"","sources":["../../../../src/core/reconcile/vm-decide.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+BAA+B;AAC/B,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,EAAE;AACF,iFAAiF;AACjF,0EAA0E;AAC1E,iFAAiF;AACjF,+EAA+E;AAC/E,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,iFAAiF;AACjF,8EAA8E;AAC9E,+EAA+E;AAC/E,6EAA6E;AAC7E,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,yEAAyE;AACzE,0EAA0E;AAC1E,8EAA8E;AAC9E,EAAE;AACF,iFAAiF;AACjF,sEAAsE;AACtE,2EAA2E;AAC3E,qBAAqB;AAIrB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,WAAW,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAsB;IAC7C,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QACtB,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC;YAAE,SAAS;QACpD,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QAC9C,6EAA6E;QAC7E,6CAA6C;QAC7C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;YAAE,SAAS;QACzD,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,OAAO;YAAE,SAAS;QACtC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// FCIS rewrite — pure VM-reaper KILL state machine (the per-session
|
|
2
|
+
// SIGTERM → grace → probe → SIGKILL escalation).
|
|
3
|
+
//
|
|
4
|
+
// Ported faithfully from the reference `VmResource.killSession`
|
|
5
|
+
// (REF: src/reconciler/vm.ts). The reference was a single async method that
|
|
6
|
+
// interleaved IO (`process.kill`, an inline `setTimeout` grace) with ledger
|
|
7
|
+
// bookkeeping. Under FCIS that method splits into two halves:
|
|
8
|
+
//
|
|
9
|
+
// • the SHELL drives the loop and performs the IO — it sends each host signal
|
|
10
|
+
// (a `process.kill`-backed `ProcessEffect`), sleeps the grace window (a
|
|
11
|
+
// `TimerEffect`), and probes liveness (signal-0). After each it hands the
|
|
12
|
+
// observed `KillStepResult` back here.
|
|
13
|
+
// • this CORE owns every DECISION as a pure fold: given the current `KillStep`
|
|
14
|
+
// (which signal/probe is in flight) and the `KillStepResult` the shell just
|
|
15
|
+
// observed, it returns the NEXT `KillStep` (wrapped as a `ReaperEffect` +,
|
|
16
|
+
// for `wait_grace`, the matching `TimerEffect`) PLUS the ledger transition
|
|
17
|
+
// to record. No IO, no clock, no `process`.
|
|
18
|
+
//
|
|
19
|
+
// The escalation, branch-for-branch with the reference:
|
|
20
|
+
//
|
|
21
|
+
// ① SIGTERM (start key, send SIGTERM).
|
|
22
|
+
// gone(ESRCH) → already dead → ledger done. (ref: ESRCH→done)
|
|
23
|
+
// no_perm(EPERM)→ can't signal → ledger error. (ref: throw→error)
|
|
24
|
+
// signalled → enter the grace window (wait_grace). (ref: await sleep)
|
|
25
|
+
// ② wait_grace (sleep killGraceMs), then probe.
|
|
26
|
+
// signalled → grace elapsed → probe liveness.
|
|
27
|
+
// ③ probe (signal 0 — liveness test).
|
|
28
|
+
// gone(ESRCH) → exited during grace → ledger done. (ref: !alive→done)
|
|
29
|
+
// no_perm(EPERM)→ alive but unreachable → ledger error. (ref: code!==ESRCH→error)
|
|
30
|
+
// alive(signal0 ok) → still running → escalate to SIGKILL.
|
|
31
|
+
// ④ SIGKILL.
|
|
32
|
+
// gone(ESRCH) → raced to exit → ledger done. (ref: ESRCH→done)
|
|
33
|
+
// signalled → killed → ledger done. (ref: success→done)
|
|
34
|
+
// no_perm(EPERM)→ unkillable → ledger error. (ref: throw→error)
|
|
35
|
+
//
|
|
36
|
+
// Pid safety (the keystone): the host signal is delivered by `process.kill`,
|
|
37
|
+
// which signals the whole PROCESS GROUP for `pid <= 0` and would target the
|
|
38
|
+
// orchestrator itself for `pid === selfPid`. `decideVm` already excludes those,
|
|
39
|
+
// but the reference re-guards once more before any signal leaves the shell
|
|
40
|
+
// ("belt-and-suspenders"). That guard is reproduced PURELY here in
|
|
41
|
+
// {@link beginKill}: an unsafe pid never yields a `signal` step — it yields an
|
|
42
|
+
// immediate terminal error decision, so the shell has no path to call
|
|
43
|
+
// `process.kill` on a bad pid.
|
|
44
|
+
//
|
|
45
|
+
// 100% SYNCHRONOUS. No async / await / Promise. No IO, no node: imports, no
|
|
46
|
+
// wall clock or randomness. Imports ONLY from src/types. (NodeNext ESM → .js
|
|
47
|
+
// extensions on relative imports.)
|
|
48
|
+
/**
|
|
49
|
+
* SIGTERM-to-SIGKILL grace period (ms). A session runner that ignores SIGTERM is
|
|
50
|
+
* SIGKILL'd after this delay. Mirrors the reference `DEFAULT_KILL_GRACE_MS`.
|
|
51
|
+
* Tests pass a small value so the grace path is observable in fast suites; the
|
|
52
|
+
* value is injected into {@link beginKill} (core never reads a config or a clock).
|
|
53
|
+
*/
|
|
54
|
+
export const DEFAULT_KILL_GRACE_MS = 3_000;
|
|
55
|
+
/** The ledger key for one session's kill action — `kill_session:<pid>` (ref). */
|
|
56
|
+
export function killKey(pid) {
|
|
57
|
+
return `kill_session:${pid}`;
|
|
58
|
+
}
|
|
59
|
+
/** Wrap a `KillStep` as the `reaper` Effect the shell's interpreter drains. */
|
|
60
|
+
function reaperEffect(step) {
|
|
61
|
+
return { family: 'reaper', step };
|
|
62
|
+
}
|
|
63
|
+
/** The `timer.sleep` effect backing the grace window. */
|
|
64
|
+
function sleepEffect(ms) {
|
|
65
|
+
return { family: 'timer', kind: 'sleep', ms };
|
|
66
|
+
}
|
|
67
|
+
/** Whether a pid is safe to signal: a positive safe integer that isn't us. */
|
|
68
|
+
export function isSafeKillPid(pid, selfPid) {
|
|
69
|
+
// `process.kill(pid, sig)` signals the whole process group for `pid <= 0`
|
|
70
|
+
// and the orchestrator itself for `pid === selfPid` — both catastrophic.
|
|
71
|
+
return Number.isSafeInteger(pid) && pid > 0 && pid !== selfPid;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Begin the escalation for one `kill_session` action. Reproduces the reference
|
|
75
|
+
* belt-and-suspenders guard PURELY: an unsafe pid (self / `<= 0` / non-finite)
|
|
76
|
+
* never produces a `signal` step — it returns a terminal `done` state carrying
|
|
77
|
+
* an `error` ledger op, so the shell has no path to `process.kill` a bad pid.
|
|
78
|
+
*
|
|
79
|
+
* A safe pid yields the opening step: `start` the ledger row and emit the
|
|
80
|
+
* SIGTERM signal (the shell sends it, then folds the observed result via
|
|
81
|
+
* {@link foldKillStep}).
|
|
82
|
+
*
|
|
83
|
+
* @param graceMs Injected grace window (the shell read it from config). Carried
|
|
84
|
+
* into the eventual `wait_grace` step's sleep effect.
|
|
85
|
+
*/
|
|
86
|
+
export function beginKill(action, selfPid) {
|
|
87
|
+
const key = killKey(action.pid);
|
|
88
|
+
if (!isSafeKillPid(action.pid, selfPid)) {
|
|
89
|
+
// Reference: `start(key)` then `error(key, msg)` — surfaced as a row so the
|
|
90
|
+
// dashboard shows the refusal — and NO signal is ever emitted.
|
|
91
|
+
return {
|
|
92
|
+
next: { kind: 'done', pid: action.pid },
|
|
93
|
+
effects: [],
|
|
94
|
+
ledger: { op: 'error', key, message: `refused to signal unsafe pid ${action.pid}` },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
next: { kind: 'signal', pid: action.pid, signal: 'SIGTERM' },
|
|
99
|
+
effects: [reaperEffect({ kind: 'signal', pid: action.pid, signal: 'SIGTERM' })],
|
|
100
|
+
ledger: { op: 'start', key },
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The core fold: given the `step` whose effect was just executed and the
|
|
105
|
+
* `result` the shell observed, return the NEXT step + effects + ledger op.
|
|
106
|
+
*
|
|
107
|
+
* `graceMs` is the injected grace window (only consulted when transitioning into
|
|
108
|
+
* `wait_grace`). Every branch returns a fresh decision; nothing is mutated.
|
|
109
|
+
*
|
|
110
|
+
* Terminal states return `{ kind: 'done' }` with NO effects — the shell stops
|
|
111
|
+
* driving and applies the `ledger` op. Intermediate states return the next
|
|
112
|
+
* `reaper` step (and, for the grace window, the `timer.sleep`) and the loop
|
|
113
|
+
* continues.
|
|
114
|
+
*/
|
|
115
|
+
export function foldKillStep(step, result, graceMs = DEFAULT_KILL_GRACE_MS) {
|
|
116
|
+
const pid = step.pid;
|
|
117
|
+
const key = killKey(pid);
|
|
118
|
+
const terminalDone = { kind: 'done', pid };
|
|
119
|
+
switch (step.kind) {
|
|
120
|
+
// ── ① SIGTERM / ④ SIGKILL share the same signal-result table. ──────────
|
|
121
|
+
case 'signal': {
|
|
122
|
+
switch (result.kind) {
|
|
123
|
+
case 'gone':
|
|
124
|
+
// ESRCH: already gone — treat as success (ref: ESRCH → done).
|
|
125
|
+
return { next: terminalDone, effects: [], ledger: { op: 'done', key } };
|
|
126
|
+
case 'no_perm': {
|
|
127
|
+
// EPERM: can't deliver the signal — surface as an error and stop.
|
|
128
|
+
const phase = step.signal === 'SIGTERM' ? 'SIGTERM' : 'SIGKILL';
|
|
129
|
+
return {
|
|
130
|
+
next: terminalDone,
|
|
131
|
+
effects: [],
|
|
132
|
+
ledger: { op: 'error', key, message: `${phase} failed: EPERM` },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
case 'signalled':
|
|
136
|
+
if (step.signal === 'SIGTERM') {
|
|
137
|
+
// Reference: `await sleep(graceMs)` then probe. Emit the grace
|
|
138
|
+
// window's sleep AND the next reaper step (wait_grace) so the shell
|
|
139
|
+
// sleeps before probing.
|
|
140
|
+
const next = { kind: 'wait_grace', pid, ms: graceMs };
|
|
141
|
+
return {
|
|
142
|
+
next,
|
|
143
|
+
effects: [sleepEffect(graceMs), reaperEffect(next)],
|
|
144
|
+
ledger: { op: 'none' },
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// SIGKILL succeeded → terminal done (ref: success → done).
|
|
148
|
+
return { next: terminalDone, effects: [], ledger: { op: 'done', key } };
|
|
149
|
+
case 'alive':
|
|
150
|
+
// A `signal`/`SIGKILL` reporting "still alive" is not a normal result
|
|
151
|
+
// path (the shell maps signal-send success to `signalled`); treat a
|
|
152
|
+
// surviving SIGKILL target as terminal success to avoid a kill loop,
|
|
153
|
+
// matching the reference (post-SIGKILL it always lands in done).
|
|
154
|
+
return { next: terminalDone, effects: [], ledger: { op: 'done', key } };
|
|
155
|
+
}
|
|
156
|
+
// Exhaustive; unreachable.
|
|
157
|
+
return { next: terminalDone, effects: [], ledger: { op: 'none' } };
|
|
158
|
+
}
|
|
159
|
+
// ── ② grace window elapsed → probe liveness. ────────────────────────────
|
|
160
|
+
case 'wait_grace': {
|
|
161
|
+
// Reference: after the sleep, probe with signal 0. The sleep already ran
|
|
162
|
+
// (shell applied the timer.sleep); regardless of the observed result we
|
|
163
|
+
// advance to the probe step. No ledger change here.
|
|
164
|
+
const next = { kind: 'probe', pid };
|
|
165
|
+
return { next, effects: [reaperEffect(next)], ledger: { op: 'none' } };
|
|
166
|
+
}
|
|
167
|
+
// ── ③ probe (signal 0) → done / error / escalate to SIGKILL. ────────────
|
|
168
|
+
case 'probe': {
|
|
169
|
+
switch (result.kind) {
|
|
170
|
+
case 'gone':
|
|
171
|
+
// ESRCH from the probe: the process exited during the grace window
|
|
172
|
+
// (ref: `!alive` → done).
|
|
173
|
+
return { next: terminalDone, effects: [], ledger: { op: 'done', key } };
|
|
174
|
+
case 'no_perm':
|
|
175
|
+
// EPERM: alive but unreachable — surface as error (ref: code !== ESRCH
|
|
176
|
+
// → error, "assume alive but unkillable").
|
|
177
|
+
return {
|
|
178
|
+
next: terminalDone,
|
|
179
|
+
effects: [],
|
|
180
|
+
ledger: { op: 'error', key, message: 'alive-probe failed: EPERM' },
|
|
181
|
+
};
|
|
182
|
+
case 'alive':
|
|
183
|
+
case 'signalled': {
|
|
184
|
+
// Still alive after the grace → escalate to SIGKILL (ref: `alive` →
|
|
185
|
+
// SIGKILL). `signalled` from a signal-0 probe is treated the same as
|
|
186
|
+
// `alive` (the process accepted the no-op signal ⇒ it exists).
|
|
187
|
+
const next = { kind: 'signal', pid, signal: 'SIGKILL' };
|
|
188
|
+
return { next, effects: [reaperEffect(next)], ledger: { op: 'none' } };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Exhaustive; unreachable.
|
|
192
|
+
return { next: terminalDone, effects: [], ledger: { op: 'none' } };
|
|
193
|
+
}
|
|
194
|
+
// ── terminal ─────────────────────────────────────────────────────────────
|
|
195
|
+
case 'done':
|
|
196
|
+
// No further work; a result observed against a terminal step is a no-op.
|
|
197
|
+
return { next: step, effects: [], ledger: { op: 'none' } };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Whether a `KillStep` is terminal (the shell stops driving the per-session
|
|
202
|
+
* escalation when it reaches this).
|
|
203
|
+
*/
|
|
204
|
+
export function isKillTerminal(step) {
|
|
205
|
+
return step.kind === 'done';
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=vm-reap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vm-reap.js","sourceRoot":"","sources":["../../../../src/core/reconcile/vm-reap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// FCIS rewrite — pure workspace-janitor decision core.
|
|
2
|
+
//
|
|
3
|
+
// Functional-core port of the diff half of the original
|
|
4
|
+
// `src/reconciler/workspace.ts:WorkspaceResource.reconcile`. The original was an
|
|
5
|
+
// async class method that interleaved IO (tracker read, dir listing, base-ref
|
|
6
|
+
// lookup, per-dir git inspection, rm, create) with the diff logic and recorded
|
|
7
|
+
// every step into a `ResourceActionLedger`. In the FCIS layout ALL of that IO
|
|
8
|
+
// moves OUT into the shell:
|
|
9
|
+
//
|
|
10
|
+
// - The desired set (active non-terminal + in-flight identifiers with their
|
|
11
|
+
// current state) is SUPPLIED here as plain data (`WorkspaceObservedState.
|
|
12
|
+
// desired`). The shell does the (fail-closed) tracker read; if it throws,
|
|
13
|
+
// the shell never calls this decider — exactly matching the original's
|
|
14
|
+
// "bail and leave existing workspaces untouched" rule.
|
|
15
|
+
// - The dir listing, the source-repo base SHA, and the per-dir git inspection
|
|
16
|
+
// are SUPPLIED as plain data (`observed`, `baseRefSha`, `inspections`). When
|
|
17
|
+
// `baseRefSha` is null the shell couldn't resolve base → this decider skips
|
|
18
|
+
// drift detection entirely (orphan removal still fires), mirroring the
|
|
19
|
+
// original `if (baseRef === null) continue;`.
|
|
20
|
+
// - The merge-state guard the original applied INSIDE its create callback
|
|
21
|
+
// (`WorkspaceManager.ensureFor` skips eager recreation while the owning
|
|
22
|
+
// issue sits in the PR/merge state) is applied here as data: a desired
|
|
23
|
+
// entry whose `state === prMergeState` does NOT get a `create_workspace`.
|
|
24
|
+
//
|
|
25
|
+
// The decider RETURNS:
|
|
26
|
+
// - `actions`: `create_workspace` / `remove_workspace` `ReconcilerAction[]`
|
|
27
|
+
// the shell executes (each maps to a `workspace.ensure` / `workspace.remove`
|
|
28
|
+
// Effect). `remove` carries the sanitized dir name; `create` carries the raw
|
|
29
|
+
// operator-visible identifier (the shell's `ensure` re-sanitizes).
|
|
30
|
+
// - `marks`: non-destructive `mark_stale` / `mark_stuck` drift annotations the
|
|
31
|
+
// shell records into the ledger (the original never auto-removes for drift
|
|
32
|
+
// in v1 — it only annotates so the dashboard renders a badge).
|
|
33
|
+
// - `logs`: `LogEffect[]` so the shell can re-emit the same structured lines
|
|
34
|
+
// the original logged at each branch.
|
|
35
|
+
//
|
|
36
|
+
// Pure + synchronous: (data) -> data + Effect[]. Imports ONLY from src/types.
|
|
37
|
+
//
|
|
38
|
+
// HARD CONSTRAINTS (gate-enforced):
|
|
39
|
+
// - 100% SYNCHRONOUS. No async/await/Promise anywhere.
|
|
40
|
+
// - No IO, no node: imports, no process/fetch, no wall clock, no randomness.
|
|
41
|
+
// - Imports ONLY from src/types/**.
|
|
42
|
+
import { sanitizeWorkspaceKey } from '../workspace-key.js';
|
|
43
|
+
function log(level, message, fields) {
|
|
44
|
+
return fields === undefined
|
|
45
|
+
? { family: 'log', kind: 'emit', level, message }
|
|
46
|
+
: { family: 'log', kind: 'emit', level, message, fields };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Pure janitor diff. Given the desired set (active + in-flight identifiers with
|
|
50
|
+
* state), the observed dirs on disk, the source repo's current base SHA, and the
|
|
51
|
+
* per-dir git inspections, return the create/remove actions, the drift marks,
|
|
52
|
+
* and the log effects.
|
|
53
|
+
*
|
|
54
|
+
* Branch parity with the original `WorkspaceResource.reconcile`:
|
|
55
|
+
* 1. Build `wanted`: sanitize in-flight ids first, then active ids (active
|
|
56
|
+
* wins on overlap so the tracker's authoritative state beats an in-flight
|
|
57
|
+
* target_state). Keyed by sanitized dir name → { identifier, state }.
|
|
58
|
+
* 2. For each observed dir: not in `wanted` ⇒ `remove_workspace` (stale_issue),
|
|
59
|
+
* UNLESS it carries a handoff-pending marker (`obs.handoffPending`) — a
|
|
60
|
+
* terminal issue whose push handoff failed, RETAINED so the only commit copy
|
|
61
|
+
* survives for recovery (234). Else mark present; if a base SHA is present,
|
|
62
|
+
* fold the inspection for drift (mark_stuck when there's agent work to lose,
|
|
63
|
+
* else mark_stale).
|
|
64
|
+
* 3. For each wanted id with no dir on disk ⇒ `create_workspace`, UNLESS the
|
|
65
|
+
* merge-state guard fires (its state === prMergeState).
|
|
66
|
+
*/
|
|
67
|
+
export function decideWorkspace(obs) {
|
|
68
|
+
const actions = [];
|
|
69
|
+
const marks = [];
|
|
70
|
+
const logs = [];
|
|
71
|
+
let staleCount = 0;
|
|
72
|
+
let stuckCount = 0;
|
|
73
|
+
let createdCount = 0;
|
|
74
|
+
let lastError = null;
|
|
75
|
+
// Step 1 — build the desired map keyed by sanitized dir name. The original
|
|
76
|
+
// iterated in-flight first then active so active (the tracker's authoritative
|
|
77
|
+
// state) overwrites any overlapping in-flight entry. `obs.desired` here is the
|
|
78
|
+
// already-merged sequence the shell hands us in that same precedence order;
|
|
79
|
+
// we sanitize and last-write-wins to reproduce the overlap rule even if a
|
|
80
|
+
// caller supplies raw (in-flight, active) pairs in order.
|
|
81
|
+
const wanted = new Map();
|
|
82
|
+
for (const entry of obs.desired) {
|
|
83
|
+
wanted.set(sanitizeWorkspaceKey(entry.identifier), {
|
|
84
|
+
identifier: entry.identifier,
|
|
85
|
+
state: entry.state,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Step 2 — reap orphans + annotate drift on the dirs that survive.
|
|
89
|
+
const present = new Set();
|
|
90
|
+
for (const { name } of obs.observed) {
|
|
91
|
+
if (!wanted.has(name)) {
|
|
92
|
+
// A terminal issue whose phase-8 handoff push FAILED left a marker: the only
|
|
93
|
+
// copy of its completed commit lives in this dir, so RETAIN it (skip the reap)
|
|
94
|
+
// until it's pushed/recovered — reaping it would be unrecoverable loss (234).
|
|
95
|
+
if (obs.handoffPending.has(name)) {
|
|
96
|
+
logs.push(log('warn', 'workspace reconcile: retained (handoff pending)', { identifier: name, reason: 'handoff_pending' }));
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
actions.push({ kind: 'remove_workspace', identifier: name });
|
|
100
|
+
logs.push(log('info', 'workspace reconcile: removed', { identifier: name, reason: 'stale_issue' }));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
present.add(name);
|
|
104
|
+
// In the desired set. Drift detection needs a base SHA to compare against;
|
|
105
|
+
// null means the shell couldn't resolve base this pass — skip (workspace ok).
|
|
106
|
+
if (obs.baseRefSha === null)
|
|
107
|
+
continue;
|
|
108
|
+
const inspection = obs.inspections[name];
|
|
109
|
+
// No inspection supplied (shell skipped or the inspect call failed) — treat
|
|
110
|
+
// as ok, matching the original's `catch { continue; }` around inspect.
|
|
111
|
+
if (inspection === undefined)
|
|
112
|
+
continue;
|
|
113
|
+
if (inspection.head === null)
|
|
114
|
+
continue;
|
|
115
|
+
// Workspace has no local copy of the base branch — operator likely deleted
|
|
116
|
+
// it. Skip drift detection rather than guess.
|
|
117
|
+
if (inspection.workspaceBaseSha === null)
|
|
118
|
+
continue;
|
|
119
|
+
// Drift = workspace's frozen base SHA disagrees with source's current base
|
|
120
|
+
// SHA. Any disagreement counts (fast-forward, divergence, rewind all surface
|
|
121
|
+
// as "the operator's base moved out from under us").
|
|
122
|
+
if (inspection.workspaceBaseSha === obs.baseRefSha)
|
|
123
|
+
continue;
|
|
124
|
+
// Drift detected. v1 never auto-removes for drift; annotate and move on.
|
|
125
|
+
if (inspection.hasUncommitted || inspection.commitsAheadOfBase > 0) {
|
|
126
|
+
stuckCount += 1;
|
|
127
|
+
const reason = inspection.hasUncommitted
|
|
128
|
+
? 'uncommitted changes present'
|
|
129
|
+
: `${inspection.commitsAheadOfBase} commit(s) ahead of base`;
|
|
130
|
+
lastError = `workspace ${name} stuck: base advanced and ${reason}`;
|
|
131
|
+
marks.push({ status: 'stuck', identifier: name, reason });
|
|
132
|
+
logs.push(log('warn', 'workspace reconcile: stuck (drift, agent work present)', { identifier: name, reason }));
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
staleCount += 1;
|
|
136
|
+
const staleReason = 'base advanced past workspace HEAD; re-clone is opt-in';
|
|
137
|
+
lastError = `workspace ${name} stale: ${staleReason}`;
|
|
138
|
+
marks.push({ status: 'stale', identifier: name, reason: staleReason });
|
|
139
|
+
logs.push(log('info', 'workspace reconcile: stale (drift, no agent work to lose)', { identifier: name, reason: staleReason }));
|
|
140
|
+
}
|
|
141
|
+
// Step 3 — create any desired identifier with no dir on disk, modulo the
|
|
142
|
+
// merge-state guard. The original deferred to `WorkspaceManager.ensureFor`,
|
|
143
|
+
// which is idempotent; the guard (skip while the owning issue sits in the
|
|
144
|
+
// PR/merge state) was applied inside that create callback. Here it's data:
|
|
145
|
+
// `state === prMergeState` ⇒ no create_workspace.
|
|
146
|
+
for (const [key, { identifier, state }] of wanted) {
|
|
147
|
+
if (present.has(key))
|
|
148
|
+
continue;
|
|
149
|
+
if (obs.prMergeState !== null && state === obs.prMergeState) {
|
|
150
|
+
logs.push(log('debug', 'workspace reconcile: create skipped (merge-state guard)', {
|
|
151
|
+
identifier,
|
|
152
|
+
state,
|
|
153
|
+
}));
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
actions.push({ kind: 'create_workspace', identifier });
|
|
157
|
+
createdCount += 1;
|
|
158
|
+
logs.push(log('info', 'workspace reconcile: created', { identifier, state }));
|
|
159
|
+
}
|
|
160
|
+
return { actions, marks, logs, staleCount, stuckCount, createdCount, lastError };
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=workspace-decide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-decide.js","sourceRoot":"","sources":["../../../../src/core/reconcile/workspace-decide.ts"],"names":[],"mappings":"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"}
|