gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3709f22a5
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 +2 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +7 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- 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 +11 -0
- package/dist/resources/extensions/gsd/auto/phases.js +28 -2
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- 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 +70 -9
- 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-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +37 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +25 -6
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +13 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
- 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-git-checks.js +46 -1
- 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 +93 -111
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- 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/pending-auto-start.js +52 -0
- 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/smart-entry-routing.js +36 -0
- 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/unit-context-manifest.js +7 -8
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
- package/dist/resources/extensions/visual-brief/prompts.js +29 -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 +15 -15
- 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/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 +15 -15
- 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/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/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +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/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.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/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +7 -0
- 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/gsd/auto/contracts.ts +14 -6
- 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 +11 -0
- package/src/resources/extensions/gsd/auto/phases.ts +30 -2
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- 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 +77 -7
- 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-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +40 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +33 -6
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +16 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
- 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-git-checks.ts +45 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +1 -0
- 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 +126 -128
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- 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/pending-auto-start.ts +79 -0
- 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/smart-entry-routing.ts +77 -0
- 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-dashboard.test.ts +71 -0
- 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 +80 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- 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-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- 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/doctor-empty-worktree.test.ts +65 -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-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- 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/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -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/pending-autostart-scope.test.ts +29 -5
- 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-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/provider-errors.test.ts +20 -1
- 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/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- 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 +65 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- 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/write-gate-planning-unit.test.ts +38 -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/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
- package/src/resources/extensions/visual-brief/prompts.ts +37 -1
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/0262768ec1b89d34.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/{Qgr2B_MRhPxC0z8fwv4vT → kkGf3_VaPFkiDNV_D7Dtl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → kkGf3_VaPFkiDNV_D7Dtl}/_ssgManifest.js +0 -0
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
nativeDetectMainBranch,
|
|
45
45
|
nativeCheckoutBranch,
|
|
46
46
|
nativeBranchList,
|
|
47
|
+
nativeBranchExists,
|
|
47
48
|
nativeBranchListMerged,
|
|
48
49
|
nativeBranchDelete,
|
|
49
50
|
nativeWorktreeRemove,
|
|
@@ -64,7 +65,7 @@ import { initRoutingHistory } from "./routing-history.js";
|
|
|
64
65
|
import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
|
|
65
66
|
import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
|
|
66
67
|
import { snapshotSkills } from "./skill-discovery.js";
|
|
67
|
-
import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
68
|
+
import { isDbAvailable, getMilestone, getAllMilestones, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
68
69
|
import { isClosedStatus } from "./status-guards.js";
|
|
69
70
|
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
70
71
|
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
@@ -101,6 +102,7 @@ import { getSessionModelOverride } from "./session-model-override.js";
|
|
|
101
102
|
export interface BootstrapDeps {
|
|
102
103
|
shouldUseWorktreeIsolation: (basePath?: string) => boolean;
|
|
103
104
|
registerSigtermHandler: (basePath: string) => void;
|
|
105
|
+
registerAutoWorkerForSession: (basePath: string) => void;
|
|
104
106
|
lockBase: () => string;
|
|
105
107
|
buildLifecycle: () => WorktreeLifecycle;
|
|
106
108
|
}
|
|
@@ -202,9 +204,15 @@ export function decideSurvivorAction(
|
|
|
202
204
|
export function auditOrphanedMilestoneBranches(
|
|
203
205
|
basePath: string,
|
|
204
206
|
isolationMode: "worktree" | "branch" | "none",
|
|
207
|
+
gitDeps: {
|
|
208
|
+
branchList?: typeof nativeBranchList;
|
|
209
|
+
branchExists?: typeof nativeBranchExists;
|
|
210
|
+
} = {},
|
|
205
211
|
): { recovered: string[]; warnings: string[] } {
|
|
206
212
|
const recovered: string[] = [];
|
|
207
213
|
const warnings: string[] = [];
|
|
214
|
+
const branchList = gitDeps.branchList ?? nativeBranchList;
|
|
215
|
+
const branchExists = gitDeps.branchExists ?? nativeBranchExists;
|
|
208
216
|
|
|
209
217
|
// Skip in none mode — no milestone branches are created
|
|
210
218
|
if (isolationMode === "none") return { recovered, warnings };
|
|
@@ -213,15 +221,16 @@ export function auditOrphanedMilestoneBranches(
|
|
|
213
221
|
if (!isDbAvailable()) return { recovered, warnings };
|
|
214
222
|
|
|
215
223
|
let milestoneBranches: string[];
|
|
224
|
+
let milestoneBranchListAvailable = true;
|
|
216
225
|
try {
|
|
217
|
-
milestoneBranches =
|
|
226
|
+
milestoneBranches = branchList(basePath, "milestone/*");
|
|
218
227
|
} catch {
|
|
219
|
-
|
|
220
|
-
|
|
228
|
+
milestoneBranchListAvailable = false;
|
|
229
|
+
// git branch list failed — fall through with an empty branch set so the
|
|
230
|
+
// branch-less orphan pass can still run after per-milestone verification.
|
|
231
|
+
milestoneBranches = [];
|
|
221
232
|
}
|
|
222
233
|
|
|
223
|
-
if (milestoneBranches.length === 0) return { recovered, warnings };
|
|
224
|
-
|
|
225
234
|
// Detect main branch for merge-check
|
|
226
235
|
let mainBranch: string;
|
|
227
236
|
try {
|
|
@@ -354,6 +363,74 @@ export function auditOrphanedMilestoneBranches(
|
|
|
354
363
|
}
|
|
355
364
|
}
|
|
356
365
|
|
|
366
|
+
// Second pass (#5879): catch worktree directories stranded by a previous
|
|
367
|
+
// audit that deleted the milestone/* branch but failed to remove the
|
|
368
|
+
// directory (or the dir was orphaned by a separate path entirely, e.g.
|
|
369
|
+
// postflight-stash-restore-failed during closeout). The branch-keyed loop
|
|
370
|
+
// above is invisible to these cases — `nativeBranchList` returns nothing
|
|
371
|
+
// for the milestone, so the dir-cleanup block at line ~310 is never
|
|
372
|
+
// reached.
|
|
373
|
+
//
|
|
374
|
+
// Keyed on milestones whose DB status is `complete`. We do not iterate
|
|
375
|
+
// over arbitrary directories under .gsd/worktrees/ to avoid touching
|
|
376
|
+
// dirs that belong to an in-progress milestone whose branch was deleted
|
|
377
|
+
// separately — those are handled by the in-progress orphan path above
|
|
378
|
+
// when the branch is present, and by `/gsd doctor` when it is not.
|
|
379
|
+
const seenMilestoneIds = new Set(
|
|
380
|
+
milestoneBranches.map((branch) => branch.replace(/^milestone\//, "")),
|
|
381
|
+
);
|
|
382
|
+
let completedMilestones: readonly { id: string; status: string }[] = [];
|
|
383
|
+
try {
|
|
384
|
+
completedMilestones = getAllMilestones();
|
|
385
|
+
} catch {
|
|
386
|
+
// DB read failure — skip the second pass; the first pass is still useful.
|
|
387
|
+
completedMilestones = [];
|
|
388
|
+
}
|
|
389
|
+
for (const m of completedMilestones) {
|
|
390
|
+
if (m.status !== "complete") continue;
|
|
391
|
+
if (seenMilestoneIds.has(m.id)) continue; // already processed in the branch loop
|
|
392
|
+
if (!milestoneBranchListAvailable) {
|
|
393
|
+
try {
|
|
394
|
+
if (branchExists(basePath, `milestone/${m.id}`)) continue;
|
|
395
|
+
} catch (err) {
|
|
396
|
+
warnings.push(
|
|
397
|
+
`Could not verify whether milestone/${m.id} still exists; skipping branch-less worktree cleanup for safety: ${err instanceof Error ? err.message : String(err)}`,
|
|
398
|
+
);
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const wtDir = getWorktreeDir(basePath, m.id);
|
|
403
|
+
if (!existsSync(wtDir)) continue;
|
|
404
|
+
if (!isInsideWorktreesDir(basePath, wtDir)) {
|
|
405
|
+
warnings.push(
|
|
406
|
+
`Orphaned worktree directory for ${m.id} is outside .gsd/worktrees/ — skipping removal for safety.`,
|
|
407
|
+
);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
// Try `git worktree remove` first in case the dir is still registered
|
|
411
|
+
// (defensive — usually it is not when we reach this branch-less pass).
|
|
412
|
+
try {
|
|
413
|
+
nativeWorktreeRemove(basePath, wtDir, true);
|
|
414
|
+
} catch (e) {
|
|
415
|
+
logWarning(
|
|
416
|
+
"engine",
|
|
417
|
+
`worktree remove failed (expected for branch-less orphans): ${e instanceof Error ? e.message : String(e)}`,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
if (existsSync(wtDir)) {
|
|
421
|
+
try {
|
|
422
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
423
|
+
recovered.push(`Removed orphaned worktree directory for ${m.id} (branch already deleted).`);
|
|
424
|
+
} catch (err) {
|
|
425
|
+
warnings.push(
|
|
426
|
+
`Failed to remove orphaned worktree directory for ${m.id}: ${err instanceof Error ? err.message : String(err)}`,
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
} else {
|
|
430
|
+
recovered.push(`Removed orphaned worktree directory for ${m.id} (branch already deleted).`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
357
434
|
return { recovered, warnings };
|
|
358
435
|
}
|
|
359
436
|
|
|
@@ -533,6 +610,7 @@ export async function bootstrapAutoSession(
|
|
|
533
610
|
const {
|
|
534
611
|
shouldUseWorktreeIsolation,
|
|
535
612
|
registerSigtermHandler,
|
|
613
|
+
registerAutoWorkerForSession,
|
|
536
614
|
lockBase,
|
|
537
615
|
buildLifecycle,
|
|
538
616
|
} = deps;
|
|
@@ -722,6 +800,7 @@ export async function bootstrapAutoSession(
|
|
|
722
800
|
// consult DB status and avoid clearing runtime units for milestones that
|
|
723
801
|
// only have a failure-path SUMMARY on disk (#4663).
|
|
724
802
|
await openProjectDbIfPresent(base);
|
|
803
|
+
registerAutoWorkerForSession(base);
|
|
725
804
|
|
|
726
805
|
// Clean stale runtime unit files for completed milestones (#887).
|
|
727
806
|
// DB-authoritative: when DB is available, require DB status to be closed
|
|
@@ -818,14 +897,18 @@ export async function bootstrapAutoSession(
|
|
|
818
897
|
// worktree cleanup) was never run — the survivor branch must be merged.
|
|
819
898
|
// Applies to both worktree and branch isolation modes.
|
|
820
899
|
let hasSurvivorBranch = false;
|
|
900
|
+
let survivorMilestoneId = state.activeMilestone?.id ?? null;
|
|
901
|
+
if (!survivorMilestoneId && state.phase === "complete") {
|
|
902
|
+
survivorMilestoneId = findUnmergedCompletedMilestone(base, getIsolationMode(base));
|
|
903
|
+
}
|
|
821
904
|
if (
|
|
822
|
-
|
|
905
|
+
survivorMilestoneId &&
|
|
823
906
|
(state.phase === "pre-planning" || state.phase === "complete") &&
|
|
824
907
|
getIsolationMode(base) !== "none" &&
|
|
825
908
|
!detectWorktreeName(base) &&
|
|
826
909
|
!base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)
|
|
827
910
|
) {
|
|
828
|
-
const milestoneBranch = `milestone/${
|
|
911
|
+
const milestoneBranch = `milestone/${survivorMilestoneId}`;
|
|
829
912
|
const { nativeBranchExists } = await import("./native-git-bridge.js");
|
|
830
913
|
hasSurvivorBranch = nativeBranchExists(base, milestoneBranch);
|
|
831
914
|
if (hasSurvivorBranch) {
|
|
@@ -869,7 +952,7 @@ export async function bootstrapAutoSession(
|
|
|
869
952
|
// Re-evaluate via the helper — the discuss branch above may have cleared
|
|
870
953
|
// hasSurvivorBranch after a successful promotion.
|
|
871
954
|
if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
|
|
872
|
-
const mid =
|
|
955
|
+
const mid = survivorMilestoneId!;
|
|
873
956
|
// Commit 68ef58a3c made `_mergeBranchMode` throw on wrong-branch
|
|
874
957
|
// instead of returning false silently. Wrap the call so the throw is
|
|
875
958
|
// converted into an error notify + clean bootstrap abort, not an
|
|
@@ -252,7 +252,17 @@ function gitPathspecForWorktreePath(basePath: string, targetPath: string): strin
|
|
|
252
252
|
let base = basePath;
|
|
253
253
|
let target = targetPath;
|
|
254
254
|
try {
|
|
255
|
-
base =
|
|
255
|
+
base = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
256
|
+
cwd: basePath,
|
|
257
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
258
|
+
encoding: "utf-8",
|
|
259
|
+
}).trim() || basePath;
|
|
260
|
+
} catch {
|
|
261
|
+
/* keep original */
|
|
262
|
+
void base;
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
base = realpathSync.native(base);
|
|
256
266
|
} catch {
|
|
257
267
|
/* keep original */
|
|
258
268
|
void base;
|
|
@@ -269,6 +279,10 @@ function gitPathspecForWorktreePath(basePath: string, targetPath: string): strin
|
|
|
269
279
|
return rel.replaceAll("\\", "/");
|
|
270
280
|
}
|
|
271
281
|
|
|
282
|
+
export function _gitPathspecForWorktreePath(basePath: string, targetPath: string): string | null {
|
|
283
|
+
return gitPathspecForWorktreePath(basePath, targetPath);
|
|
284
|
+
}
|
|
285
|
+
|
|
272
286
|
function gitRemoteExists(basePath: string, remote: string): boolean {
|
|
273
287
|
try {
|
|
274
288
|
execFileSync("git", ["remote", "get-url", remote], {
|
|
@@ -282,6 +296,50 @@ function gitRemoteExists(basePath: string, remote: string): boolean {
|
|
|
282
296
|
}
|
|
283
297
|
}
|
|
284
298
|
|
|
299
|
+
function findRegularMergeChangedPaths(basePath: string, milestoneBranch: string, mainBranch: string): Set<string> {
|
|
300
|
+
const changedPaths = new Set<string>();
|
|
301
|
+
let mergeLog = "";
|
|
302
|
+
try {
|
|
303
|
+
mergeLog = execFileSync("git", ["rev-list", "--merges", "--parents", mainBranch], {
|
|
304
|
+
cwd: basePath,
|
|
305
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
306
|
+
encoding: "utf-8",
|
|
307
|
+
}).trim();
|
|
308
|
+
} catch (err) {
|
|
309
|
+
logWarning("worktree", `regular merge lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
310
|
+
return changedPaths;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
for (const line of mergeLog.split("\n").filter(Boolean)) {
|
|
314
|
+
const [mergeCommit, firstParent, ...otherParents] = line.split(" ");
|
|
315
|
+
if (!mergeCommit || !firstParent || otherParents.length === 0) continue;
|
|
316
|
+
const mergedMilestone = otherParents.some((parent) => {
|
|
317
|
+
try {
|
|
318
|
+
return nativeIsAncestor(basePath, milestoneBranch, parent);
|
|
319
|
+
} catch {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
if (!mergedMilestone) continue;
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
const output = execFileSync("git", ["diff", "--name-only", firstParent, mergeCommit], {
|
|
327
|
+
cwd: basePath,
|
|
328
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
329
|
+
encoding: "utf-8",
|
|
330
|
+
}).trim();
|
|
331
|
+
for (const path of output.split("\n").filter(Boolean)) {
|
|
332
|
+
if (!path.startsWith(".gsd/")) changedPaths.add(path);
|
|
333
|
+
}
|
|
334
|
+
} catch (err) {
|
|
335
|
+
logWarning("worktree", `regular merge diff lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
336
|
+
}
|
|
337
|
+
return changedPaths;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return changedPaths;
|
|
341
|
+
}
|
|
342
|
+
|
|
285
343
|
function clearProjectRootStateFiles(basePath: string, milestoneId: string): void {
|
|
286
344
|
const gsdDir = gsdRoot(basePath);
|
|
287
345
|
// Phase C pt 2: auto.lock removed from this list — the file is gone
|
|
@@ -1739,6 +1797,66 @@ export function mergeMilestoneToMain(
|
|
|
1739
1797
|
}
|
|
1740
1798
|
}
|
|
1741
1799
|
|
|
1800
|
+
// Already regular-merged milestones can skip the squash path and proceed to cleanup (#5831).
|
|
1801
|
+
if (nativeIsAncestor(originalBasePath_, milestoneBranch, mainBranch)) {
|
|
1802
|
+
const codeChanges = nativeDiffNumstat(
|
|
1803
|
+
originalBasePath_,
|
|
1804
|
+
mainBranch,
|
|
1805
|
+
milestoneBranch,
|
|
1806
|
+
).filter((entry) => !entry.path.startsWith(".gsd/"));
|
|
1807
|
+
if (codeChanges.length > 0) {
|
|
1808
|
+
const regularMergeChangedPaths = findRegularMergeChangedPaths(
|
|
1809
|
+
originalBasePath_,
|
|
1810
|
+
milestoneBranch,
|
|
1811
|
+
mainBranch,
|
|
1812
|
+
);
|
|
1813
|
+
const unanchoredCodeChanges = codeChanges.filter((entry) =>
|
|
1814
|
+
regularMergeChangedPaths.has(entry.path)
|
|
1815
|
+
);
|
|
1816
|
+
if (unanchoredCodeChanges.length > 0) {
|
|
1817
|
+
process.chdir(previousCwd);
|
|
1818
|
+
throw new GSDError(
|
|
1819
|
+
GSD_GIT_ERROR,
|
|
1820
|
+
`Milestone branch "${milestoneBranch}" is reachable from "${mainBranch}" ` +
|
|
1821
|
+
`but has ${unanchoredCodeChanges.length} milestone-touched code file(s) not on current "${mainBranch}". ` +
|
|
1822
|
+
`Aborting worktree teardown to prevent data loss.`,
|
|
1823
|
+
);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
debugLog("mergeMilestoneToMain", {
|
|
1827
|
+
action: "skip-squash-already-merged",
|
|
1828
|
+
milestoneId,
|
|
1829
|
+
milestoneBranch,
|
|
1830
|
+
mainBranch,
|
|
1831
|
+
});
|
|
1832
|
+
try {
|
|
1833
|
+
clearProjectRootStateFiles(originalBasePath_, milestoneId);
|
|
1834
|
+
} catch (err) {
|
|
1835
|
+
logWarning("worktree", `clearProjectRootStateFiles failed during already-merged cleanup: ${err instanceof Error ? err.message : String(err)}`);
|
|
1836
|
+
}
|
|
1837
|
+
try {
|
|
1838
|
+
removeWorktree(originalBasePath_, milestoneId, {
|
|
1839
|
+
branch: milestoneBranch,
|
|
1840
|
+
deleteBranch: false,
|
|
1841
|
+
});
|
|
1842
|
+
} catch (err) {
|
|
1843
|
+
logWarning("worktree", `worktree removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1844
|
+
}
|
|
1845
|
+
try {
|
|
1846
|
+
nativeBranchDelete(originalBasePath_, milestoneBranch);
|
|
1847
|
+
} catch (err) {
|
|
1848
|
+
logWarning("worktree", `git branch-delete failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1849
|
+
}
|
|
1850
|
+
setActiveWorkspace(null);
|
|
1851
|
+
nudgeGitBranchCache(previousCwd);
|
|
1852
|
+
try {
|
|
1853
|
+
process.chdir(originalBasePath_);
|
|
1854
|
+
} catch (err) {
|
|
1855
|
+
logWarning("worktree", `chdir to project root after already-merged cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1856
|
+
}
|
|
1857
|
+
return { commitMessage, pushed: false, prCreated: false, codeFilesChanged: true };
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1742
1860
|
// 7. Shelter queued milestone directories before the squash merge (#2505).
|
|
1743
1861
|
// The milestone branch may contain copies of queued milestone dirs (via
|
|
1744
1862
|
// copyPlanningArtifacts), so `git merge --squash` rejects when those same
|
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
import {
|
|
59
59
|
writeLock,
|
|
60
60
|
clearLock,
|
|
61
|
+
clearStaleWorkerLock,
|
|
61
62
|
readCrashLock,
|
|
62
63
|
isLockProcessAlive,
|
|
63
64
|
formatCrashInfo,
|
|
@@ -240,7 +241,7 @@ import { runAutoLoopWithUok } from "./uok/kernel.js";
|
|
|
240
241
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
241
242
|
import { validateDirectory } from "./validate-directory.js";
|
|
242
243
|
import { createAutoOrchestrator } from "./auto/orchestrator.js";
|
|
243
|
-
import type { AutoOrchestrationModule, AutoOrchestratorDeps, DispatchAdapter } from "./auto/contracts.js";
|
|
244
|
+
import type { AutoAdvanceResult, AutoOrchestrationModule, AutoOrchestratorDeps, DispatchAdapter } from "./auto/contracts.js";
|
|
244
245
|
import { reconcileBeforeDispatch } from "./state-reconciliation.js";
|
|
245
246
|
import { compileUnitToolContract } from "./tool-contract.js";
|
|
246
247
|
import { createWorktreeSafetyModule } from "./worktree-safety.js";
|
|
@@ -316,6 +317,13 @@ import { normalizeRealPath } from "./paths.js";
|
|
|
316
317
|
/** Throttle STATE.md rebuilds — at most once per 30 seconds */
|
|
317
318
|
const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
|
|
318
319
|
|
|
320
|
+
export function formatAutoStopNotification(prefix: string, totals: { cost: number; tokens: { total: number } }, unitCount: number): string {
|
|
321
|
+
return [
|
|
322
|
+
`${prefix}.`,
|
|
323
|
+
`Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${unitCount} units`,
|
|
324
|
+
].join("\n");
|
|
325
|
+
}
|
|
326
|
+
|
|
319
327
|
/**
|
|
320
328
|
* Phase B — register this auto-mode process in the workers table so other
|
|
321
329
|
* workers and janitors can detect liveness via heartbeat. Best-effort: if
|
|
@@ -1044,6 +1052,7 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
|
|
|
1044
1052
|
// visible so the user still has a resumable auto-mode signal on screen.
|
|
1045
1053
|
if (!s.paused) {
|
|
1046
1054
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
1055
|
+
ctx.ui.setWidget("gsd-progress", undefined);
|
|
1047
1056
|
if (s.completionStopInProgress) {
|
|
1048
1057
|
s.completionStopInProgress = false;
|
|
1049
1058
|
}
|
|
@@ -1415,7 +1424,7 @@ export async function stopAuto(
|
|
|
1415
1424
|
if (ledger && ledger.units.length > 0) {
|
|
1416
1425
|
const totals = getProjectTotals(ledger.units);
|
|
1417
1426
|
ctx?.ui.notify(
|
|
1418
|
-
|
|
1427
|
+
formatAutoStopNotification(notificationPrefix, totals, ledger.units.length),
|
|
1419
1428
|
"info",
|
|
1420
1429
|
);
|
|
1421
1430
|
} else {
|
|
@@ -1839,6 +1848,13 @@ export function createWiredDispatchAdapter(
|
|
|
1839
1848
|
modelRegistry,
|
|
1840
1849
|
});
|
|
1841
1850
|
|
|
1851
|
+
if (action.action === "stop") {
|
|
1852
|
+
return {
|
|
1853
|
+
kind: "blocked",
|
|
1854
|
+
reason: action.reason,
|
|
1855
|
+
action: action.level === "warning" ? "pause" : "stop",
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1842
1858
|
if (action.action !== "dispatch") return null;
|
|
1843
1859
|
return {
|
|
1844
1860
|
unitType: action.unitType,
|
|
@@ -2065,6 +2081,18 @@ export function createWiredAutoOrchestrationModule(
|
|
|
2065
2081
|
return createAutoOrchestrator(deps);
|
|
2066
2082
|
}
|
|
2067
2083
|
|
|
2084
|
+
function notifyResumeBlocked(ctx: ExtensionContext, result: Extract<AutoAdvanceResult, { kind: "blocked" }>): void {
|
|
2085
|
+
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
2086
|
+
ctx.ui.notify(`Auto-mode blocked: ${result.reason}. Fix and run ${resumeCmd} to resume.`, "warning");
|
|
2087
|
+
setLifecycleOutcome(ctx, {
|
|
2088
|
+
status: "blocked",
|
|
2089
|
+
title: "Auto-mode blocked",
|
|
2090
|
+
detail: result.reason,
|
|
2091
|
+
nextAction: `Fix the blocker, then run ${resumeCmd} to resume.`,
|
|
2092
|
+
commands: ["/gsd status for overview", `${resumeCmd} to resume`, "/gsd doctor to diagnose"],
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2068
2096
|
function ensureOrchestrationModule(ctx: ExtensionContext, pi: ExtensionAPI, basePath: string): void {
|
|
2069
2097
|
s.orchestration = createWiredAutoOrchestrationModule(ctx, pi, basePath, lockBase());
|
|
2070
2098
|
}
|
|
@@ -2402,7 +2430,7 @@ export async function startAuto(
|
|
|
2402
2430
|
// This closes the journal gap reported in #3348 where the worker wrote side
|
|
2403
2431
|
// effects (SUMMARY.md, DB updates) but died before emitting unit-end.
|
|
2404
2432
|
emitCrashRecoveredUnitEnd(base, freshStartAssessment.lock);
|
|
2405
|
-
|
|
2433
|
+
clearStaleWorkerLock(base);
|
|
2406
2434
|
}
|
|
2407
2435
|
|
|
2408
2436
|
if (!s.paused) {
|
|
@@ -2473,6 +2501,8 @@ export async function startAuto(
|
|
|
2473
2501
|
s.unitLifetimeDispatches.clear();
|
|
2474
2502
|
if (!getLedger()) initMetrics(base);
|
|
2475
2503
|
if (s.currentMilestoneId) setActiveMilestoneId(base, s.currentMilestoneId);
|
|
2504
|
+
await openProjectDbIfPresent(base);
|
|
2505
|
+
registerAutoWorkerForSession(s, base);
|
|
2476
2506
|
|
|
2477
2507
|
// Re-register health level notification callback lost across process restart
|
|
2478
2508
|
setLevelChangeCallback((_from, to, summary) => {
|
|
@@ -2580,7 +2610,12 @@ export async function startAuto(
|
|
|
2580
2610
|
pi.events.emit(CMUX_CHANNELS.LOG, { preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, message: s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", level: "progress" });
|
|
2581
2611
|
|
|
2582
2612
|
try {
|
|
2583
|
-
await s.orchestration?.resume();
|
|
2613
|
+
const resumeResult = await s.orchestration?.resume();
|
|
2614
|
+
if (resumeResult?.kind === "blocked") {
|
|
2615
|
+
notifyResumeBlocked(ctx, resumeResult);
|
|
2616
|
+
await cleanupAfterLoopExit(ctx);
|
|
2617
|
+
return;
|
|
2618
|
+
}
|
|
2584
2619
|
} catch (err) {
|
|
2585
2620
|
debugLog("resume-orchestration-resume", { error: err instanceof Error ? err.message : String(err) });
|
|
2586
2621
|
}
|
|
@@ -2601,6 +2636,7 @@ export async function startAuto(
|
|
|
2601
2636
|
const bootstrapDeps: BootstrapDeps = {
|
|
2602
2637
|
shouldUseWorktreeIsolation,
|
|
2603
2638
|
registerSigtermHandler,
|
|
2639
|
+
registerAutoWorkerForSession: (projectRoot) => registerAutoWorkerForSession(s, projectRoot),
|
|
2604
2640
|
lockBase,
|
|
2605
2641
|
buildLifecycle,
|
|
2606
2642
|
};
|
|
@@ -32,6 +32,7 @@ import { shouldIgnoreAgentEndForActiveUnit } from "../auto/unit-runner-events.js
|
|
|
32
32
|
import { resolveModelId } from "../auto-model-selection.js";
|
|
33
33
|
import { resolveProjectRoot } from "../worktree.js";
|
|
34
34
|
import { clearDiscussionFlowState } from "./write-gate.js";
|
|
35
|
+
import { clearGuidedUnitContext } from "../guided-unit-context.js";
|
|
35
36
|
import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
|
|
36
37
|
import {
|
|
37
38
|
classifyError,
|
|
@@ -48,6 +49,11 @@ const MAX_NETWORK_RETRIES = 2;
|
|
|
48
49
|
function isObjectRecord(value: unknown): value is Record<string, unknown> {
|
|
49
50
|
return !!value && typeof value === "object";
|
|
50
51
|
}
|
|
52
|
+
|
|
53
|
+
export function _hasEmptyAgentEndContent(content: unknown): boolean {
|
|
54
|
+
return content == null || (Array.isArray(content) && content.length === 0);
|
|
55
|
+
}
|
|
56
|
+
|
|
51
57
|
/**
|
|
52
58
|
* Cap on auto-resume attempts for sustained transient-provider errors.
|
|
53
59
|
*
|
|
@@ -196,6 +202,14 @@ export function resolveAgentEndErrorDisplay(
|
|
|
196
202
|
return rawErrorMsg;
|
|
197
203
|
}
|
|
198
204
|
|
|
205
|
+
export function isTerminalDeletedWorktreeProviderError(
|
|
206
|
+
message: string | undefined | null,
|
|
207
|
+
): boolean {
|
|
208
|
+
if (!message) return false;
|
|
209
|
+
if (!/\bdoes not exist\b/i.test(message)) return false;
|
|
210
|
+
return /[/\\]\.gsd[/\\](?:projects[/\\][^/\\]+[/\\])?worktrees[/\\][^/\\\s"']+/i.test(message);
|
|
211
|
+
}
|
|
212
|
+
|
|
199
213
|
async function pauseTransientWithBackoff(
|
|
200
214
|
cls: ErrorClass,
|
|
201
215
|
pi: ExtensionAPI,
|
|
@@ -244,9 +258,11 @@ export async function handleAgentEnd(
|
|
|
244
258
|
// falsely report files as missing — producing a spurious "ready signal
|
|
245
259
|
// rejected" loop even though the files are on disk.
|
|
246
260
|
clearPathCache();
|
|
261
|
+
const basePath = resolveAgentEndBasePath();
|
|
262
|
+
clearGuidedUnitContext(basePath);
|
|
247
263
|
|
|
248
264
|
try {
|
|
249
|
-
if (await checkDeepProjectSetupAfterTurn(event, ctx,
|
|
265
|
+
if (await checkDeepProjectSetupAfterTurn(event, ctx, basePath)) {
|
|
250
266
|
return;
|
|
251
267
|
}
|
|
252
268
|
} catch (err) {
|
|
@@ -254,8 +270,8 @@ export async function handleAgentEnd(
|
|
|
254
270
|
logWarning("bootstrap", `checkDeepProjectSetupAfterTurn failed: ${message}`);
|
|
255
271
|
}
|
|
256
272
|
|
|
257
|
-
if (checkAutoStartAfterDiscuss()) {
|
|
258
|
-
clearDiscussionFlowState(
|
|
273
|
+
if (checkAutoStartAfterDiscuss(basePath)) {
|
|
274
|
+
clearDiscussionFlowState(basePath ?? process.cwd());
|
|
259
275
|
return;
|
|
260
276
|
}
|
|
261
277
|
|
|
@@ -263,14 +279,14 @@ export async function handleAgentEnd(
|
|
|
263
279
|
// are missing, `checkAutoStartAfterDiscuss` returns false silently. Surface
|
|
264
280
|
// that and nudge the LLM to complete the writes before the user hits the
|
|
265
281
|
// downstream "All milestones complete" warning loop.
|
|
266
|
-
if (maybeHandleReadyPhraseWithoutFiles(event)) return;
|
|
282
|
+
if (maybeHandleReadyPhraseWithoutFiles(event, basePath)) return;
|
|
267
283
|
|
|
268
284
|
// #4573 — Empty-turn recovery: if the LLM announced intent in prose but
|
|
269
285
|
// emitted no tool calls, nudge it to execute. Fires only when auto-mode is
|
|
270
286
|
// active or a discussion autostart is pending (non-auto interactive discuss
|
|
271
287
|
// is user-driven). Runs before `isAutoActive` early return so pending
|
|
272
288
|
// discussions (where isAutoActive may be false) still get recovered.
|
|
273
|
-
if (maybeHandleEmptyIntentTurn(event, isAutoActive())) return;
|
|
289
|
+
if (maybeHandleEmptyIntentTurn(event, isAutoActive(), basePath)) return;
|
|
274
290
|
|
|
275
291
|
if (!isAutoActive()) return;
|
|
276
292
|
|
|
@@ -310,7 +326,7 @@ export async function handleAgentEnd(
|
|
|
310
326
|
// that carry error context — e.g. errorMessage field or non-empty content
|
|
311
327
|
// indicating a mid-stream failure. (#2695)
|
|
312
328
|
const content = "content" in lastMsg ? lastMsg.content : undefined;
|
|
313
|
-
const hasEmptyContent =
|
|
329
|
+
const hasEmptyContent = _hasEmptyAgentEndContent(content);
|
|
314
330
|
const hasErrorMessage = "errorMessage" in lastMsg && !!lastMsg.errorMessage;
|
|
315
331
|
|
|
316
332
|
if (hasEmptyContent && !hasErrorMessage) {
|
|
@@ -355,6 +371,17 @@ export async function handleAgentEnd(
|
|
|
355
371
|
rawErrorMsg,
|
|
356
372
|
"content" in lastMsg ? lastMsg.content : undefined,
|
|
357
373
|
);
|
|
374
|
+
if (
|
|
375
|
+
isAutoCompletionStopInProgress() &&
|
|
376
|
+
isTerminalDeletedWorktreeProviderError(`${rawErrorMsg}\n${displayMsg}`)
|
|
377
|
+
) {
|
|
378
|
+
resetRetryState(retryState);
|
|
379
|
+
logWarning(
|
|
380
|
+
"bootstrap",
|
|
381
|
+
`Ignoring stale deleted-worktree provider error during terminal completion reroot: ${displayMsg || rawErrorMsg}`,
|
|
382
|
+
);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
358
385
|
const errorDetail = displayMsg ? `: ${displayMsg}` : "";
|
|
359
386
|
const explicitRetryAfterMs = ("retryAfterMs" in lastMsg && typeof lastMsg.retryAfterMs === "number") ? lastMsg.retryAfterMs : undefined;
|
|
360
387
|
|
|
@@ -487,17 +487,18 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
487
487
|
promptGuidelines: [
|
|
488
488
|
"Use gsd_plan_milestone for milestone planning instead of writing ROADMAP.md directly.",
|
|
489
489
|
"Keep parameters flat and provide the full milestone planning payload, including slices.",
|
|
490
|
+
"Milestone and slice titles must not contain forward slash (/), en dash, or em dash characters.",
|
|
490
491
|
"The tool validates input, writes milestone and slice planning data transactionally, renders ROADMAP.md from DB, and clears both state and parse caches after success.",
|
|
491
492
|
"Use the canonical name gsd_plan_milestone; gsd_milestone_plan is only an alias.",
|
|
492
493
|
],
|
|
493
494
|
parameters: Type.Object({
|
|
494
495
|
// ── Core identification + content (required) ──────────────────────
|
|
495
496
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
496
|
-
title: Type.String({ description: "Milestone title" }),
|
|
497
|
+
title: Type.String({ description: "Milestone title; must not contain forward slash (/), en dash, or em dash characters" }),
|
|
497
498
|
vision: Type.String({ description: "Milestone vision" }),
|
|
498
499
|
slices: Type.Array(Type.Object({
|
|
499
500
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
500
|
-
title: Type.String({ description: "Slice title" }),
|
|
501
|
+
title: Type.String({ description: "Slice title; must not contain forward slash (/), en dash, or em dash characters" }),
|
|
501
502
|
risk: Type.String({ description: "Slice risk" }),
|
|
502
503
|
depends: Type.Array(Type.String(), { description: "Slice dependency IDs" }),
|
|
503
504
|
demo: Type.String({ description: "Roadmap demo text / After this" }),
|
|
@@ -570,10 +571,10 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
570
571
|
title: Type.String({ description: "Task title" }),
|
|
571
572
|
description: Type.String({ description: "Task description / steps block" }),
|
|
572
573
|
estimate: Type.String({ description: "Task estimate string" }),
|
|
573
|
-
files: Type.Array(Type.String(), { description: "
|
|
574
|
+
files: Type.Array(Type.String(), { description: "Array<string> of files likely touched; pass [\"path\"] or [], never a single string" }),
|
|
574
575
|
verify: Type.String({ description: "Verification command or block" }),
|
|
575
|
-
inputs: Type.Array(Type.String(), { description: "
|
|
576
|
-
expectedOutput: Type.Array(Type.String(), { description: "
|
|
576
|
+
inputs: Type.Array(Type.String(), { description: "Array<string> of input files or references; pass [\"path\"] or [], never a single string" }),
|
|
577
|
+
expectedOutput: Type.Array(Type.String(), { description: "Array<string> of expected output files or artifacts; pass [\"path\"] or [], never a single string" }),
|
|
577
578
|
observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
|
|
578
579
|
}), { description: "Planned tasks for the slice" }),
|
|
579
580
|
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
@@ -650,10 +651,10 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
650
651
|
title: Type.String({ description: "Task title" }),
|
|
651
652
|
description: Type.String({ description: "Task description / steps block" }),
|
|
652
653
|
estimate: Type.String({ description: "Task estimate string" }),
|
|
653
|
-
files: Type.Array(Type.String(), { description: "
|
|
654
|
+
files: Type.Array(Type.String(), { description: "Array<string> of files likely touched; pass [\"path\"] or [], never a single string" }),
|
|
654
655
|
verify: Type.String({ description: "Verification command or block" }),
|
|
655
|
-
inputs: Type.Array(Type.String(), { description: "
|
|
656
|
-
expectedOutput: Type.Array(Type.String(), { description: "
|
|
656
|
+
inputs: Type.Array(Type.String(), { description: "Array<string> of input files or references; pass [\"path\"] or [], never a single string" }),
|
|
657
|
+
expectedOutput: Type.Array(Type.String(), { description: "Array<string> of expected output files or artifacts; pass [\"path\"] or [], never a single string" }),
|
|
657
658
|
observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
|
|
658
659
|
// Single-writer v3 audit trail (Stream 2): caller-provided actor identity + causation.
|
|
659
660
|
actorName: Type.Optional(Type.String({ description: "Caller-provided actor identity for the audit trail (e.g. 'executor-01', 'gsd-orchestrator')" })),
|
|
@@ -31,6 +31,7 @@ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
|
31
31
|
import { extractSubagentAgentClasses } from "./subagent-input.js";
|
|
32
32
|
import { approvalGateIdForUnit, isExplicitApprovalResponse, shouldPauseForUserApprovalQuestion } from "../user-input-boundary.js";
|
|
33
33
|
import { resolveSkillManifest } from "../skill-manifest.js";
|
|
34
|
+
import { getGuidedUnitContext } from "../guided-unit-context.js";
|
|
34
35
|
|
|
35
36
|
let approvalQuestionAbortInFlight = false;
|
|
36
37
|
|
|
@@ -772,7 +773,8 @@ export function registerHooks(
|
|
|
772
773
|
// subagent dispatch. Closes the b23 bug class where a discuss-milestone
|
|
773
774
|
// turn used the host Edit tool to modify user source files.
|
|
774
775
|
const dash = getAutoRuntimeSnapshot();
|
|
775
|
-
const
|
|
776
|
+
const guidedUnit = getGuidedUnitContext(discussionBasePath);
|
|
777
|
+
const activeUnitType = dash.currentUnit?.type ?? guidedUnit?.unitType;
|
|
776
778
|
if (activeUnitType) {
|
|
777
779
|
const manifest = resolveManifest(activeUnitType);
|
|
778
780
|
if (manifest) {
|
|
@@ -791,7 +793,7 @@ export function registerHooks(
|
|
|
791
793
|
const planningGuard = shouldBlockPlanningUnit(
|
|
792
794
|
event.toolName,
|
|
793
795
|
planningInput,
|
|
794
|
-
dash.basePath || discussionBasePath,
|
|
796
|
+
dash.basePath || guidedUnit?.basePath || discussionBasePath,
|
|
795
797
|
activeUnitType,
|
|
796
798
|
manifest.tools,
|
|
797
799
|
agentClasses,
|
|
@@ -4,7 +4,9 @@ export function extractSubagentAgentClasses(input: unknown): string[] {
|
|
|
4
4
|
const agentClasses: string[] = [];
|
|
5
5
|
const visited = new WeakSet<object>();
|
|
6
6
|
const addAgentClass = (value: unknown): void => {
|
|
7
|
-
if (typeof value
|
|
7
|
+
if (typeof value !== "string") return;
|
|
8
|
+
const normalized = value.trim().replace(/\.md$/i, "");
|
|
9
|
+
if (normalized.length > 0) agentClasses.push(normalized);
|
|
8
10
|
};
|
|
9
11
|
|
|
10
12
|
const visitItems = (value: unknown): void => {
|