gsd-pi 2.82.0-dev.725028083 → 2.82.0-dev.98ea09b1e
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/README.md +4 -3
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +8 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
- package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +85 -12
- package/dist/resources/extensions/gsd/auto-verification.js +28 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +158 -55
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +39 -1
- package/dist/resources/extensions/gsd/gsd-db.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +13 -6
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +4 -4
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/mcp-server/README.md +13 -4
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +7 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
- package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +92 -9
- package/src/resources/extensions/gsd/auto-verification.ts +36 -34
- package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +167 -53
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/git-service.ts +45 -1
- package/src/resources/extensions/gsd/gsd-db.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +14 -7
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → euQ0CLP_v8V4e76Tu3odJ}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -336,7 +336,7 @@ Plan (with integrated research) → Execute (per task) → Complete → Reassess
|
|
|
336
336
|
Validate Milestone → Complete Milestone
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
-
**Plan** scouts the codebase, researches relevant docs, and decomposes the slice into tasks with must-haves (mechanically verifiable outcomes). **Execute** runs each task in a fresh context window with only the relevant files pre-loaded
|
|
339
|
+
**Plan** scouts the codebase, researches relevant docs, and decomposes the slice into tasks with must-haves (mechanically verifiable outcomes). **Execute** runs each task in a fresh context window with only the relevant files pre-loaded, then runs configured verification commands (lint, test, etc.) with auto-fix retries before the task closeout commit or snapshot is published. Failed or incomplete verification blocks execute-task closeout. **Complete** writes the summary, UAT script, marks the roadmap, and commits with meaningful messages derived from task summaries. **Reassess** checks if the roadmap still makes sense given what was learned. **Validate Milestone** runs a reconciliation gate after all slices complete — comparing roadmap success criteria against actual results before sealing the milestone.
|
|
340
340
|
|
|
341
341
|
When progressive planning is enabled, the first slice is fully planned up front while later slices may appear in `M###-ROADMAP.md` with a `` `[sketch]` `` badge. A sketch slice has an approved title, dependency shape, demo line, and scope boundary, but it has not yet been expanded into task plans; auto mode runs `refine-slice` just before execution to turn the sketch into a full slice plan using the latest prior-slice summaries.
|
|
342
342
|
|
|
@@ -376,7 +376,7 @@ The database is authoritative for milestones, slices, tasks, requirements, summa
|
|
|
376
376
|
|
|
377
377
|
10. **Adaptive replanning** — After each slice completes, the roadmap is reassessed. If the work revealed new information that changes the plan, slices are reordered, added, or removed before continuing.
|
|
378
378
|
|
|
379
|
-
11. **Verification enforcement** — Configure
|
|
379
|
+
11. **Verification enforcement** — Configure simple executable commands (`npm run lint`, `npm run test`, etc.) that run automatically after task execution. Verification commands must not use shell composition or control syntax such as pipes, redirects, semicolons, backticks, or command substitution. Failures trigger auto-fix retries before advancing. Execute-task commits and snapshots are deferred until verification passes; failed or incomplete verification blocks closeout instead of publishing changes. Auto-discovered checks from `package.json` and Python pytest project markers (`python-project`) run in advisory mode — they log warnings but don't block on pre-existing errors. Configurable via `verification_commands`, `verification_auto_fix`, and `verification_max_retries` preferences.
|
|
380
380
|
|
|
381
381
|
12. **Milestone validation** — After all slices complete, a `validate-milestone` gate compares roadmap success criteria against actual results before sealing the milestone.
|
|
382
382
|
|
|
@@ -502,6 +502,7 @@ On first run, GSD launches a branded setup wizard that walks you through LLM pro
|
|
|
502
502
|
| `/gsd rethink` | Conversational project reorganization |
|
|
503
503
|
| `/gsd mcp` | MCP server status and connectivity |
|
|
504
504
|
| `/gsd status` | Progress dashboard |
|
|
505
|
+
| `/gsd brief <mode>` | Generate a visual HTML brief (diagram, plan, diff, recap, table, slides) |
|
|
505
506
|
| `/gsd queue` | Queue future milestones (safe during auto mode) |
|
|
506
507
|
| `/gsd prefs` | Model selection, timeouts, budget ceiling |
|
|
507
508
|
| `/gsd migrate` | Migrate a v1 `.planning` directory to `.gsd` format |
|
|
@@ -669,7 +670,7 @@ auto_report: true
|
|
|
669
670
|
| `context_mode.exec_stdout_cap_bytes` | Persisted stdout cap for `gsd_exec` output (default: 1048576) |
|
|
670
671
|
| `context_mode.exec_digest_chars` | Trailing stdout characters returned to the agent context (default: 300) |
|
|
671
672
|
| `context_mode.exec_env_allowlist` | Environment variables forwarded to sandboxed `gsd_exec` runs in addition to `PATH` and `HOME` |
|
|
672
|
-
| `verification_commands` | Array of
|
|
673
|
+
| `verification_commands` | Array of simple executable commands to run after task execution (e.g., `["npm run lint", "npm run test"]`); avoid pipes, redirects, semicolons, backticks, and command substitution |
|
|
673
674
|
| `verification_auto_fix` | Auto-retry on verification failures (default: true) |
|
|
674
675
|
| `verification_max_retries` | Max retries for verification failures (default: 2) |
|
|
675
676
|
| `phases.require_slice_discussion` | Pause auto-mode before each slice for human discussion review |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
d6d64d2fc180293c
|
|
@@ -448,6 +448,13 @@ What differed from the plan and why (or "None").
|
|
|
448
448
|
|
|
449
449
|
The one-liner must be substantive: "JWT auth with refresh rotation using jose" not "Authentication implemented."
|
|
450
450
|
|
|
451
|
+
When `key_files` or `key_decisions` are empty, render them as empty YAML lists:
|
|
452
|
+
|
|
453
|
+
```yaml
|
|
454
|
+
key_files: []
|
|
455
|
+
key_decisions: []
|
|
456
|
+
```
|
|
457
|
+
|
|
451
458
|
**Slice summary:** Written when all tasks in a slice complete. Compresses all task summaries. Includes `drill_down_paths` to each task summary. During slice completion, review task summaries for `key_decisions` and ensure any significant ones are captured in `.gsd/DECISIONS.md`.
|
|
452
459
|
|
|
453
460
|
**Milestone summary:** Updated each time a slice completes. Compresses all slice summaries. This is what gets injected into later slice planning instead of loading many individual summaries.
|
|
@@ -560,7 +567,7 @@ In all modes, slices and tasks commit sequentially on the active branch; there a
|
|
|
560
567
|
|
|
561
568
|
1. **Milestone starts** → capture the current integration branch.
|
|
562
569
|
2. **Optional isolation** → create `milestone/M001` only when `git.isolation` is `worktree` or `branch`.
|
|
563
|
-
3. **Per-task commits** — atomic, descriptive, bisectable.
|
|
570
|
+
3. **Per-task commits** — atomic, descriptive, bisectable, and published only after execute-task verification passes.
|
|
564
571
|
4. **Slice completes** → write slice summary, UAT script, roadmap checkbox, and milestone summary.
|
|
565
572
|
5. **Milestone completes** → if isolated, squash-merge the milestone branch back to the captured integration branch and clean up the worktree/branch.
|
|
566
573
|
|
|
@@ -574,6 +581,8 @@ fix: handle empty state rebuild
|
|
|
574
581
|
|
|
575
582
|
In `none` mode these commits land directly on the current branch. In isolated modes they land on `milestone/<MID>` and are squashed back at milestone completion.
|
|
576
583
|
|
|
584
|
+
Execute-task closeout is fail-closed: the system writes verification evidence first, defers the task commit or snapshot until verification passes, and pauses instead of publishing changes when verification fails or cannot complete.
|
|
585
|
+
|
|
577
586
|
### Commit Conventions
|
|
578
587
|
|
|
579
588
|
| When | Format | Example |
|
|
@@ -105,9 +105,10 @@ export function mapUsage(sdkUsage, totalCostUsd) {
|
|
|
105
105
|
output: sdkUsage.output_tokens,
|
|
106
106
|
cacheRead: sdkUsage.cache_read_input_tokens,
|
|
107
107
|
cacheWrite: sdkUsage.cache_creation_input_tokens,
|
|
108
|
+
// Claude Agent SDK result usage is cumulative across its internal loop;
|
|
109
|
+
// repeated cache reads do not represent additional live context.
|
|
108
110
|
totalTokens: sdkUsage.input_tokens +
|
|
109
111
|
sdkUsage.output_tokens +
|
|
110
|
-
sdkUsage.cache_read_input_tokens +
|
|
111
112
|
sdkUsage.cache_creation_input_tokens,
|
|
112
113
|
cost: {
|
|
113
114
|
input: 0,
|
|
@@ -319,6 +319,11 @@ export class CmuxClient {
|
|
|
319
319
|
const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, payload]);
|
|
320
320
|
return stdout !== null;
|
|
321
321
|
}
|
|
322
|
+
// Send Ctrl-C (ETX) to a surface to interrupt the running command.
|
|
323
|
+
async sendInterrupt(surfaceId) {
|
|
324
|
+
const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, "\x03"]);
|
|
325
|
+
return stdout !== null;
|
|
326
|
+
}
|
|
322
327
|
}
|
|
323
328
|
export function syncCmuxSidebar(preferences, state) {
|
|
324
329
|
const client = CmuxClient.fromPreferences(preferences);
|
|
@@ -6,9 +6,14 @@
|
|
|
6
6
|
* failures that merit retry.
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* Error codes indicating infrastructure failures
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Error codes indicating infrastructure-level failures from the OS,
|
|
10
|
+
* filesystem, or network. This set includes permanent resource failures
|
|
11
|
+
* (ENOSPC, ENOMEM, EROFS), transient resource exhaustion (EAGAIN, ENOBUFS),
|
|
12
|
+
* and network/offline errors (ECONNREFUSED, ENOTFOUND, ENETUNREACH).
|
|
13
|
+
*
|
|
14
|
+
* Transient git failures are retried separately through
|
|
15
|
+
* TRANSIENT_GIT_RETRY_CODES in native-git-bridge.ts before escalating to the
|
|
16
|
+
* auto-loop.
|
|
12
17
|
*/
|
|
13
18
|
export const INFRA_ERROR_CODES = new Set([
|
|
14
19
|
"ENOSPC", // disk full
|
|
@@ -18,6 +23,7 @@ export const INFRA_ERROR_CODES = new Set([
|
|
|
18
23
|
"EMFILE", // too many open files (process)
|
|
19
24
|
"ENFILE", // too many open files (system)
|
|
20
25
|
"EAGAIN", // resource temporarily unavailable (resource exhaustion)
|
|
26
|
+
"ENOBUFS", // no buffer space available (transient pipe exhaustion)
|
|
21
27
|
"ECONNREFUSED", // connection refused (offline / local server down)
|
|
22
28
|
"ENOTFOUND", // DNS lookup failed (offline / no network)
|
|
23
29
|
"ENETUNREACH", // network unreachable (offline / no route)
|
|
@@ -35,7 +35,7 @@ import { createWorkflowTurnReporter } from "./workflow-turn-reporter.js";
|
|
|
35
35
|
import { validateWorkflowSessionLock } from "./workflow-session-lock.js";
|
|
36
36
|
import { dequeueSidecarItem } from "./workflow-sidecar-queue.js";
|
|
37
37
|
import { maintainWorkerHeartbeat } from "./workflow-worker-heartbeat.js";
|
|
38
|
-
import { measureMemoryPressure } from "./workflow-memory-pressure.js";
|
|
38
|
+
import { measureMemoryPressure, shouldCheckMemoryPressure, } from "./workflow-memory-pressure.js";
|
|
39
39
|
import { buildSidecarIterationData } from "./workflow-sidecar-iteration.js";
|
|
40
40
|
import { createExecutionGraphUnitDispatchDeps, runUnitPhaseViaContract, } from "./workflow-unit-dispatch.js";
|
|
41
41
|
import { handleCustomEngineDispatchOutcome } from "./workflow-custom-engine-dispatch-outcome.js";
|
|
@@ -130,9 +130,9 @@ function logCustomVerifyRetrySaveFailure(err) {
|
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
// ── Memory pressure monitoring (#3331) ──────────────────────────────────
|
|
133
|
-
// Check heap usage every N iterations and trigger
|
|
134
|
-
// the OS OOM killer sends SIGKILL. The threshold is
|
|
135
|
-
// limit (--max-old-space-size or default ~1.5-4GB depending on platform).
|
|
133
|
+
// Check heap usage on session startup, then every N iterations, and trigger
|
|
134
|
+
// graceful shutdown before the OS OOM killer sends SIGKILL. The threshold is
|
|
135
|
+
// 90% of the V8 heap limit (--max-old-space-size or default ~1.5-4GB depending on platform).
|
|
136
136
|
const MEMORY_CHECK_INTERVAL = 5; // check every 5 iterations
|
|
137
137
|
const MAX_CUSTOM_ENGINE_VERIFY_RETRIES = 3;
|
|
138
138
|
async function enforceMinRequestInterval(s, prefs) {
|
|
@@ -262,7 +262,7 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
262
262
|
}
|
|
263
263
|
// ── Memory pressure check (#3331) ──
|
|
264
264
|
// Graceful shutdown before OOM killer sends SIGKILL.
|
|
265
|
-
if (iteration
|
|
265
|
+
if (shouldCheckMemoryPressure(iteration, MEMORY_CHECK_INTERVAL)) {
|
|
266
266
|
const mem = measureMemoryPressure();
|
|
267
267
|
debugLog("autoLoop", { phase: "memory-check", ...mem });
|
|
268
268
|
const memoryDecision = decideMemoryPressure({ ...mem, iteration });
|
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
function now() {
|
|
4
4
|
return Date.now();
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Size of the dispatch-decision ring buffer used by the Auto Orchestration
|
|
8
|
+
* module's stuck-loop detector. When the same `${unitType}:${unitId}` key
|
|
9
|
+
* fills the window, advance() blocks with `action: "stop"`.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the legacy `STUCK_WINDOW_SIZE` in auto/phases.ts so behaviour is
|
|
12
|
+
* preserved across the eventual cutover (issue #5791).
|
|
13
|
+
*/
|
|
14
|
+
export const STUCK_WINDOW_SIZE = 6;
|
|
6
15
|
export class AutoOrchestrator {
|
|
7
16
|
status = {
|
|
8
17
|
phase: "idle",
|
|
@@ -10,11 +19,13 @@ export class AutoOrchestrator {
|
|
|
10
19
|
};
|
|
11
20
|
deps;
|
|
12
21
|
lastAdvanceKey = null;
|
|
22
|
+
dispatchKeyWindow = [];
|
|
13
23
|
constructor(deps) {
|
|
14
24
|
this.deps = deps;
|
|
15
25
|
}
|
|
16
26
|
async start(_sessionContext) {
|
|
17
27
|
this.lastAdvanceKey = null;
|
|
28
|
+
this.dispatchKeyWindow = [];
|
|
18
29
|
this.status.phase = "running";
|
|
19
30
|
this.bumpTransition();
|
|
20
31
|
await this.deps.runtime.journalTransition({ name: "start" });
|
|
@@ -24,18 +35,70 @@ export class AutoOrchestrator {
|
|
|
24
35
|
async advance() {
|
|
25
36
|
try {
|
|
26
37
|
await this.deps.runtime.ensureLockOwnership();
|
|
38
|
+
const staleMsg = this.deps.health.checkResourcesStale();
|
|
39
|
+
if (staleMsg) {
|
|
40
|
+
await this.deps.uokGate.emit({
|
|
41
|
+
gateId: "resource-version-guard",
|
|
42
|
+
gateType: "policy",
|
|
43
|
+
outcome: "fail",
|
|
44
|
+
failureClass: "policy",
|
|
45
|
+
rationale: "resource version guard blocked dispatch",
|
|
46
|
+
findings: staleMsg,
|
|
47
|
+
});
|
|
48
|
+
const blocked = { kind: "blocked", reason: staleMsg, action: "stop" };
|
|
49
|
+
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
50
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
51
|
+
return blocked;
|
|
52
|
+
}
|
|
53
|
+
await this.deps.uokGate.emit({
|
|
54
|
+
gateId: "resource-version-guard",
|
|
55
|
+
gateType: "policy",
|
|
56
|
+
outcome: "pass",
|
|
57
|
+
failureClass: "none",
|
|
58
|
+
rationale: "resource version guard passed",
|
|
59
|
+
});
|
|
27
60
|
const gate = await this.deps.health.preAdvanceGate();
|
|
28
|
-
if (
|
|
29
|
-
|
|
61
|
+
if (gate.kind === "fail") {
|
|
62
|
+
await this.deps.uokGate.emit({
|
|
63
|
+
gateId: "pre-dispatch-health-gate",
|
|
64
|
+
gateType: "execution",
|
|
65
|
+
outcome: "manual-attention",
|
|
66
|
+
failureClass: "manual-attention",
|
|
67
|
+
rationale: "pre-dispatch health gate blocked dispatch",
|
|
68
|
+
findings: gate.reason,
|
|
69
|
+
});
|
|
70
|
+
const blocked = { kind: "blocked", reason: gate.reason, action: "pause" };
|
|
30
71
|
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
31
72
|
await this.deps.health.postAdvanceRecord(blocked);
|
|
32
73
|
return blocked;
|
|
33
74
|
}
|
|
75
|
+
if (gate.kind === "threw") {
|
|
76
|
+
await this.deps.uokGate.emit({
|
|
77
|
+
gateId: "pre-dispatch-health-gate",
|
|
78
|
+
gateType: "execution",
|
|
79
|
+
outcome: "manual-attention",
|
|
80
|
+
failureClass: "manual-attention",
|
|
81
|
+
rationale: "pre-dispatch health gate threw unexpectedly",
|
|
82
|
+
findings: String(gate.error),
|
|
83
|
+
});
|
|
84
|
+
// intentional fall-through: matches runPreDispatch behaviour
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
await this.deps.uokGate.emit({
|
|
88
|
+
gateId: "pre-dispatch-health-gate",
|
|
89
|
+
gateType: "execution",
|
|
90
|
+
outcome: "pass",
|
|
91
|
+
failureClass: "none",
|
|
92
|
+
rationale: "pre-dispatch health gate passed",
|
|
93
|
+
findings: gate.fixesApplied?.join(", ") ?? "",
|
|
94
|
+
});
|
|
95
|
+
}
|
|
34
96
|
const reconciliation = await this.deps.stateReconciliation.reconcileBeforeDispatch();
|
|
35
97
|
if (!reconciliation.ok || !reconciliation.stateSnapshot) {
|
|
36
98
|
const blocked = {
|
|
37
99
|
kind: "blocked",
|
|
38
|
-
reason: reconciliation.reason,
|
|
100
|
+
reason: reconciliation.reason ?? "state reconciliation produced no snapshot",
|
|
101
|
+
action: "pause",
|
|
39
102
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
40
103
|
};
|
|
41
104
|
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
@@ -48,14 +111,60 @@ export class AutoOrchestrator {
|
|
|
48
111
|
this.status.phase = "stopped";
|
|
49
112
|
this.status.activeUnit = undefined;
|
|
50
113
|
this.lastAdvanceKey = null;
|
|
114
|
+
this.dispatchKeyWindow = [];
|
|
51
115
|
this.bumpTransition();
|
|
52
116
|
await this.deps.runtime.journalTransition({ name: "advance-stopped", reason: stopped.reason });
|
|
53
117
|
await this.deps.health.postAdvanceRecord(stopped);
|
|
54
118
|
return stopped;
|
|
55
119
|
}
|
|
120
|
+
if (!("unitType" in decision)) {
|
|
121
|
+
const blocked = {
|
|
122
|
+
kind: "blocked",
|
|
123
|
+
reason: decision.reason,
|
|
124
|
+
action: decision.action,
|
|
125
|
+
stateSnapshot: reconciliation.stateSnapshot,
|
|
126
|
+
};
|
|
127
|
+
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
128
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
129
|
+
return blocked;
|
|
130
|
+
}
|
|
56
131
|
const nextKey = `${decision.unitType}:${decision.unitId}`;
|
|
57
|
-
|
|
58
|
-
|
|
132
|
+
// Record every dispatch decision in the ring buffer before pre-flight
|
|
133
|
+
// checks so the stuck-loop detector observes the full decision history
|
|
134
|
+
// (including decisions that idempotency would otherwise short-circuit).
|
|
135
|
+
// The ring is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
|
|
136
|
+
this.dispatchKeyWindow.push(nextKey);
|
|
137
|
+
if (this.dispatchKeyWindow.length > STUCK_WINDOW_SIZE) {
|
|
138
|
+
this.dispatchKeyWindow.shift();
|
|
139
|
+
}
|
|
140
|
+
// Idempotency: same key as immediately previous successful advance.
|
|
141
|
+
// This is the soft, fast-path block kept from #5786. It only fires when
|
|
142
|
+
// the ring is NOT yet saturated for this key — once the ring is full of
|
|
143
|
+
// `nextKey`, the stuck-loop verdict takes precedence (see below). Both
|
|
144
|
+
// checks coexist: idempotency for the common immediate-repeat case,
|
|
145
|
+
// stuck-loop for the saturated-window case.
|
|
146
|
+
const matchingCount = this.dispatchKeyWindow.filter((k) => k === nextKey).length;
|
|
147
|
+
if (this.lastAdvanceKey === nextKey && matchingCount < STUCK_WINDOW_SIZE) {
|
|
148
|
+
const blocked = { kind: "blocked", reason: "idempotent advance: unit already active", action: "stop" };
|
|
149
|
+
await this.deps.runtime.journalTransition({
|
|
150
|
+
name: "advance-blocked",
|
|
151
|
+
reason: blocked.reason,
|
|
152
|
+
unitType: decision.unitType,
|
|
153
|
+
unitId: decision.unitId,
|
|
154
|
+
});
|
|
155
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
156
|
+
return blocked;
|
|
157
|
+
}
|
|
158
|
+
// Stuck-loop detection: when the ring is saturated with copies of
|
|
159
|
+
// `nextKey` (count >= STUCK_WINDOW_SIZE), the orchestrator has been
|
|
160
|
+
// picking the same unit across the whole window and must hard-stop with
|
|
161
|
+
// a diagnosable reason.
|
|
162
|
+
if (matchingCount >= STUCK_WINDOW_SIZE) {
|
|
163
|
+
const blocked = {
|
|
164
|
+
kind: "blocked",
|
|
165
|
+
reason: `stuck-loop: ${nextKey} picked ${matchingCount} times`,
|
|
166
|
+
action: "stop",
|
|
167
|
+
};
|
|
59
168
|
await this.deps.runtime.journalTransition({
|
|
60
169
|
name: "advance-blocked",
|
|
61
170
|
reason: blocked.reason,
|
|
@@ -70,6 +179,7 @@ export class AutoOrchestrator {
|
|
|
70
179
|
const blocked = {
|
|
71
180
|
kind: "blocked",
|
|
72
181
|
reason: contract.reason,
|
|
182
|
+
action: "pause",
|
|
73
183
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
74
184
|
};
|
|
75
185
|
await this.deps.runtime.journalTransition({
|
|
@@ -86,6 +196,7 @@ export class AutoOrchestrator {
|
|
|
86
196
|
const blocked = {
|
|
87
197
|
kind: "blocked",
|
|
88
198
|
reason: worktree.reason,
|
|
199
|
+
action: "pause",
|
|
89
200
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
90
201
|
};
|
|
91
202
|
await this.deps.runtime.journalTransition({
|
|
@@ -108,7 +219,11 @@ export class AutoOrchestrator {
|
|
|
108
219
|
unitId: decision.unitId,
|
|
109
220
|
});
|
|
110
221
|
await this.deps.worktree.syncAfterUnit(decision.unitType, decision.unitId);
|
|
111
|
-
const advanced = {
|
|
222
|
+
const advanced = {
|
|
223
|
+
kind: "advanced",
|
|
224
|
+
unit: { unitType: decision.unitType, unitId: decision.unitId },
|
|
225
|
+
stateSnapshot: reconciliation.stateSnapshot,
|
|
226
|
+
};
|
|
112
227
|
await this.deps.health.postAdvanceRecord(advanced);
|
|
113
228
|
return advanced;
|
|
114
229
|
}
|
|
@@ -134,6 +249,7 @@ export class AutoOrchestrator {
|
|
|
134
249
|
}
|
|
135
250
|
if (result.kind === "stopped") {
|
|
136
251
|
this.lastAdvanceKey = null;
|
|
252
|
+
this.dispatchKeyWindow = [];
|
|
137
253
|
this.status.activeUnit = undefined;
|
|
138
254
|
}
|
|
139
255
|
this.bumpTransition();
|
|
@@ -158,6 +274,7 @@ export class AutoOrchestrator {
|
|
|
158
274
|
}
|
|
159
275
|
async resume() {
|
|
160
276
|
this.lastAdvanceKey = null;
|
|
277
|
+
this.dispatchKeyWindow = [];
|
|
161
278
|
this.status.phase = "running";
|
|
162
279
|
this.bumpTransition();
|
|
163
280
|
await this.deps.runtime.journalTransition({ name: "resume" });
|
|
@@ -172,6 +289,7 @@ export class AutoOrchestrator {
|
|
|
172
289
|
this.status.phase = "stopped";
|
|
173
290
|
this.status.activeUnit = undefined;
|
|
174
291
|
this.lastAdvanceKey = null;
|
|
292
|
+
this.dispatchKeyWindow = [];
|
|
175
293
|
this.bumpTransition();
|
|
176
294
|
await this.deps.runtime.journalTransition({ name: "stop", reason });
|
|
177
295
|
await this.deps.notifications.notifyLifecycle({ name: "stop", detail: reason });
|
|
@@ -968,7 +968,14 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
968
968
|
prompt = preDispatchResult.prompt;
|
|
969
969
|
}
|
|
970
970
|
const guardBasePath = _resolveDispatchGuardBasePath(s);
|
|
971
|
-
|
|
971
|
+
let mainBranch = "main";
|
|
972
|
+
try {
|
|
973
|
+
mainBranch = deps.getMainBranch(guardBasePath);
|
|
974
|
+
}
|
|
975
|
+
catch (err) {
|
|
976
|
+
debugLog("autoLoop", { phase: "getMainBranch-failed", error: String(err) });
|
|
977
|
+
}
|
|
978
|
+
const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(guardBasePath, mainBranch, unitType, unitId);
|
|
972
979
|
if (priorSliceBlocker) {
|
|
973
980
|
await deps.stopAuto(ctx, pi, priorSliceBlocker);
|
|
974
981
|
debugLog("autoLoop", { phase: "exit", reason: "prior-slice-blocker" });
|
|
@@ -4,6 +4,18 @@ import { createRequire } from "node:module";
|
|
|
4
4
|
const require = createRequire(import.meta.url);
|
|
5
5
|
const DEFAULT_MEMORY_PRESSURE_THRESHOLD = 0.85;
|
|
6
6
|
const DEFAULT_HEAP_LIMIT_MB = 4096;
|
|
7
|
+
/**
|
|
8
|
+
* Returns true on auto-mode startup, then every configured interval.
|
|
9
|
+
*
|
|
10
|
+
* Iteration 1 is checked explicitly so early session memory pressure cannot
|
|
11
|
+
* bypass the periodic interval guard.
|
|
12
|
+
*/
|
|
13
|
+
export function shouldCheckMemoryPressure(iteration, interval) {
|
|
14
|
+
if (!Number.isInteger(interval) || interval <= 0) {
|
|
15
|
+
throw new Error("Memory pressure check interval must be a positive integer");
|
|
16
|
+
}
|
|
17
|
+
return iteration === 1 || iteration % interval === 0;
|
|
18
|
+
}
|
|
7
19
|
function defaultHeapLimitBytes() {
|
|
8
20
|
const v8 = require("node:v8");
|
|
9
21
|
const limit = v8.getHeapStatistics?.().heap_size_limit;
|
|
@@ -102,6 +102,9 @@ function missingSliceStop(mid, phase) {
|
|
|
102
102
|
level: "error",
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
function isRegistryMilestoneComplete(state, mid) {
|
|
106
|
+
return state.registry.some((milestone) => milestone.id === mid && milestone.status === "complete");
|
|
107
|
+
}
|
|
105
108
|
/**
|
|
106
109
|
* Check for milestone slices missing SUMMARY files.
|
|
107
110
|
* Returns array of missing slice IDs, or empty array if all present or DB unavailable.
|
|
@@ -247,6 +250,8 @@ export const DISPATCH_RULES = [
|
|
|
247
250
|
return null;
|
|
248
251
|
if (!MILESTONE_ID_RE.test(mid))
|
|
249
252
|
return null;
|
|
253
|
+
if (isRegistryMilestoneComplete(state, mid))
|
|
254
|
+
return null;
|
|
250
255
|
// Align with the plan-v2 gate's lookup semantics: whitespace-only counts
|
|
251
256
|
// as missing, and an auto worktree may fall back to GSD_PROJECT_ROOT.
|
|
252
257
|
if (hasFinalizedMilestoneContext(basePath, mid))
|
|
@@ -557,6 +562,8 @@ export const DISPATCH_RULES = [
|
|
|
557
562
|
match: async ({ state, mid, midTitle, basePath, prefs, structuredQuestionsAvailable }) => {
|
|
558
563
|
if (state.phase !== "pre-planning")
|
|
559
564
|
return null;
|
|
565
|
+
if (isRegistryMilestoneComplete(state, mid))
|
|
566
|
+
return null;
|
|
560
567
|
const contextFile = resolveMilestoneFile(basePath, mid, "CONTEXT");
|
|
561
568
|
const hasContext = !!(contextFile && (await loadFile(contextFile)));
|
|
562
569
|
if (hasContext)
|
|
@@ -1091,19 +1098,19 @@ export const DISPATCH_RULES = [
|
|
|
1091
1098
|
return { action: "skip" };
|
|
1092
1099
|
}
|
|
1093
1100
|
}
|
|
1094
|
-
// Safety guard (#2675): block completion when VALIDATION
|
|
1095
|
-
//
|
|
1096
|
-
// terminal
|
|
1097
|
-
//
|
|
1101
|
+
// Safety guard (#2675, #5747): block completion when VALIDATION
|
|
1102
|
+
// verdict is non-passing. The state machine treats these verdicts as
|
|
1103
|
+
// terminal, but completing-milestone should NOT proceed — remediation
|
|
1104
|
+
// or human attention is needed.
|
|
1098
1105
|
const validationFile = resolveMilestoneFile(basePath, mid, "VALIDATION");
|
|
1099
1106
|
if (validationFile) {
|
|
1100
1107
|
const validationContent = await loadFile(validationFile);
|
|
1101
1108
|
if (validationContent) {
|
|
1102
1109
|
const verdict = extractVerdict(validationContent);
|
|
1103
|
-
if (verdict === "needs-remediation") {
|
|
1110
|
+
if (verdict === "needs-remediation" || verdict === "needs-attention") {
|
|
1104
1111
|
return {
|
|
1105
1112
|
action: "stop",
|
|
1106
|
-
reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "
|
|
1113
|
+
reason: `Cannot complete milestone ${mid}: VALIDATION verdict is "${verdict}". Address the validation findings and re-run validation, or update the verdict manually.`,
|
|
1107
1114
|
level: "warning",
|
|
1108
1115
|
};
|
|
1109
1116
|
}
|
|
@@ -494,6 +494,8 @@ autoModeStartThinkingLevel) {
|
|
|
494
494
|
* Handles formats: "provider/model", "bare-id", "org/model-name" (OpenRouter).
|
|
495
495
|
*/
|
|
496
496
|
export function resolveModelId(modelId, availableModels, currentProvider) {
|
|
497
|
+
if (!modelId)
|
|
498
|
+
return undefined;
|
|
497
499
|
const slashIdx = modelId.indexOf("/");
|
|
498
500
|
if (slashIdx !== -1) {
|
|
499
501
|
const maybeProvider = modelId.substring(0, slashIdx);
|