gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3a3c6509d
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 +3 -3
- 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/claude-code-cli/stream-adapter.js +1 -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 +81 -31
- 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-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -10
- package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-verification.js +17 -4
- package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
- package/dist/resources/extensions/gsd/auto.js +37 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
- 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 +14 -2
- package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
- package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
- 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/forensics.js +3 -3
- package/dist/resources/extensions/gsd/git-service.js +45 -3
- package/dist/resources/extensions/gsd/gsd-db.js +21 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +101 -116
- 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/queue-reorder-ui.js +30 -13
- 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/state.js +1 -1
- package/dist/resources/extensions/gsd/status-guards.js +11 -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-mcp.js +17 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
- 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 +11 -11
- 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/browse-directories/route.js +1 -1
- 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 +11 -11
- 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/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
- 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/google-gemini-cli.test.ts +49 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -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/core/chat-controller-ordering.test.js +44 -3
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.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/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -8
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.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/core/chat-controller-ordering.test.ts +53 -3
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +14 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +23 -8
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +12 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/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/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- 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 +90 -38
- 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-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +78 -8
- package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-verification.ts +22 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
- package/src/resources/extensions/gsd/auto.ts +40 -5
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
- 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 +17 -2
- package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
- package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
- 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/forensics.ts +3 -3
- package/src/resources/extensions/gsd/git-service.ts +51 -4
- package/src/resources/extensions/gsd/gsd-db.ts +21 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +134 -133
- 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/queue-reorder-ui.ts +31 -13
- 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/state.ts +1 -1
- package/src/resources/extensions/gsd/status-guards.ts +13 -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 +56 -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 +35 -7
- 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 +91 -6
- 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/checkout-branch-stash-guard.test.ts +87 -0
- 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 +86 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- 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 +66 -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/gsd-db.test.ts +11 -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 +112 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- 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/pipeline-variant-dispatch.test.ts +2 -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-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/prefs-wizard-coverage.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- 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/status-guards.test.ts +13 -1
- 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 +82 -7
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -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-mcp.ts +18 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
- 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 → O6femb9LLl3nlgsDaYwS-}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_ssgManifest.js +0 -0
|
@@ -23,7 +23,7 @@ import { rebuildState } from "./doctor.js";
|
|
|
23
23
|
import { parseUnitId } from "./unit-id.js";
|
|
24
24
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
25
25
|
import { runTurnGitAction, } from "./git-service.js";
|
|
26
|
-
import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceholder, diagnoseExpectedArtifact, } from "./auto-recovery.js";
|
|
26
|
+
import { verifyExpectedArtifact, resolveExpectedArtifactPath, writeBlockerPlaceholder, diagnoseExpectedArtifact, diagnoseWorktreeIntegrityFailure, } from "./auto-recovery.js";
|
|
27
27
|
import { regenerateIfMissing } from "./workflow-projections.js";
|
|
28
28
|
import { WorktreeStateProjection } from "./worktree-state-projection.js";
|
|
29
29
|
import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
@@ -125,7 +125,7 @@ async function buildTaskCommitContextForUnit(basePath, unitId) {
|
|
|
125
125
|
sliceId: sid,
|
|
126
126
|
sliceTitle: stripKnownIdPrefix(slice?.title, sid),
|
|
127
127
|
oneLiner: summary?.oneLiner || task?.one_liner || undefined,
|
|
128
|
-
keyFiles: summary?.frontmatter.key_files?.filter(f => !f.includes("{{")) ??
|
|
128
|
+
keyFiles: summary?.frontmatter.key_files?.filter(f => !f.includes("{{") && f.trim() !== "(none)") ??
|
|
129
129
|
task?.key_files ??
|
|
130
130
|
undefined,
|
|
131
131
|
issueNumber: ghIssueNumber,
|
|
@@ -303,6 +303,19 @@ export function buildStepCompleteMessage(nextState) {
|
|
|
303
303
|
return `Step complete. Next: ${next.label}\n`
|
|
304
304
|
+ `Run /clear, then /gsd to continue (or /gsd auto to run continuously).`;
|
|
305
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Decide whether step mode should stop at the step wizard after a unit finishes.
|
|
308
|
+
*
|
|
309
|
+
* @param currentUnitType The just-finished unit type, such as "execute-task" or
|
|
310
|
+
* "complete-milestone"; may be null/undefined when no current unit is known.
|
|
311
|
+
* @param phaseAfterUnit The freshly derived next phase, such as "executing" or
|
|
312
|
+
* "complete"; may be null/undefined if state derivation failed.
|
|
313
|
+
* @returns true to show the step wizard; false to keep the loop running so
|
|
314
|
+
* terminal milestone completion can reach the merge/finalization path.
|
|
315
|
+
*/
|
|
316
|
+
export function shouldReturnStepWizardAfterUnit(currentUnitType, phaseAfterUnit) {
|
|
317
|
+
return currentUnitType !== "complete-milestone" && phaseAfterUnit !== "complete";
|
|
318
|
+
}
|
|
306
319
|
export const USER_DRIVEN_DEEP_UNITS = new Set([
|
|
307
320
|
"discuss-project",
|
|
308
321
|
"discuss-requirements",
|
|
@@ -318,6 +331,10 @@ function artifactValidationKind(unitType) {
|
|
|
318
331
|
return null;
|
|
319
332
|
}
|
|
320
333
|
function describeArtifactVerificationFailure(unitType, unitId, basePath) {
|
|
334
|
+
const worktreeFailure = diagnoseWorktreeIntegrityFailure(basePath);
|
|
335
|
+
if (worktreeFailure) {
|
|
336
|
+
return `${worktreeFailure} Unit: ${unitType} ${unitId}.`;
|
|
337
|
+
}
|
|
321
338
|
const artifactPath = resolveExpectedArtifactPath(unitType, unitId, basePath);
|
|
322
339
|
if (!artifactPath) {
|
|
323
340
|
return `Artifact verification failed: ${unitType} "${unitId}" has no resolvable artifact path.`;
|
|
@@ -362,7 +379,14 @@ export async function autoCommitUnit(basePath, unitType, unitId, ctx) {
|
|
|
362
379
|
return null;
|
|
363
380
|
}
|
|
364
381
|
}
|
|
365
|
-
|
|
382
|
+
/**
|
|
383
|
+
* Execute the turn-level git action (commit, snapshot, or status-only).
|
|
384
|
+
*
|
|
385
|
+
* @param opts.softFailure - Defaults to false. When true, retry git failures,
|
|
386
|
+
* warn, and continue without pausing auto-mode; use for best-effort deferred
|
|
387
|
+
* closeout work where a git failure should not block the run.
|
|
388
|
+
*/
|
|
389
|
+
async function runCloseoutGitAction(pctx, unit, opts) {
|
|
366
390
|
const { s, ctx, pi, pauseAuto } = pctx;
|
|
367
391
|
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
368
392
|
const uokFlags = resolveUokFlags(prefs);
|
|
@@ -390,13 +414,24 @@ async function runCloseoutGitAction(pctx, unit) {
|
|
|
390
414
|
});
|
|
391
415
|
}
|
|
392
416
|
else {
|
|
393
|
-
const
|
|
417
|
+
const maxAttempts = opts?.softFailure ? 3 : 1;
|
|
418
|
+
let gitResult = runTurnGitAction({
|
|
394
419
|
basePath: s.basePath,
|
|
395
420
|
action: turnAction,
|
|
396
421
|
unitType: unit.type,
|
|
397
422
|
unitId: unit.id,
|
|
398
423
|
taskContext,
|
|
399
424
|
});
|
|
425
|
+
for (let attempt = 1; gitResult.status === "failed" && attempt < maxAttempts; attempt++) {
|
|
426
|
+
await new Promise((resolve) => setTimeout(resolve, 250 * attempt));
|
|
427
|
+
gitResult = runTurnGitAction({
|
|
428
|
+
basePath: s.basePath,
|
|
429
|
+
action: turnAction,
|
|
430
|
+
unitType: unit.type,
|
|
431
|
+
unitId: unit.id,
|
|
432
|
+
taskContext,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
400
435
|
if (uokFlags.gitops) {
|
|
401
436
|
writeTurnGitTransaction({
|
|
402
437
|
basePath: s.basePath,
|
|
@@ -444,12 +479,15 @@ async function runCloseoutGitAction(pctx, unit) {
|
|
|
444
479
|
});
|
|
445
480
|
}
|
|
446
481
|
const failureMsg = `Git ${turnAction} failed: ${(gitResult.error ?? "unknown error").split("\n")[0]}`;
|
|
447
|
-
ctx.ui.notify(failureMsg, "error");
|
|
482
|
+
ctx.ui.notify(failureMsg, opts?.softFailure ? "warning" : "error");
|
|
448
483
|
debugLog("postUnit", {
|
|
449
|
-
phase: "git-action-failed-blocking",
|
|
484
|
+
phase: opts?.softFailure ? "git-action-failed-soft" : "git-action-failed-blocking",
|
|
450
485
|
action: turnAction,
|
|
451
486
|
error: gitResult.error ?? "unknown error",
|
|
452
487
|
});
|
|
488
|
+
if (opts?.softFailure) {
|
|
489
|
+
return "continue";
|
|
490
|
+
}
|
|
453
491
|
await pauseAuto(ctx, pi);
|
|
454
492
|
return "dispatched";
|
|
455
493
|
}
|
|
@@ -467,7 +505,10 @@ async function runCloseoutGitAction(pctx, unit) {
|
|
|
467
505
|
s.lastGitActionFailure = message;
|
|
468
506
|
s.lastGitActionStatus = "failed";
|
|
469
507
|
debugLog("postUnit", { phase: "git-action", error: message, action: turnAction });
|
|
470
|
-
ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`,
|
|
508
|
+
ctx.ui.notify(`Git ${turnAction} failed: ${message.split("\n")[0]}`, opts?.softFailure ? "warning" : "error");
|
|
509
|
+
if (opts?.softFailure) {
|
|
510
|
+
return "continue";
|
|
511
|
+
}
|
|
471
512
|
if (uokFlags.gitops) {
|
|
472
513
|
await pauseAuto(ctx, pi);
|
|
473
514
|
return "dispatched";
|
|
@@ -958,9 +999,25 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
958
999
|
s.verificationRetryCount.delete(retryKey);
|
|
959
1000
|
s.verificationRetryFailureHashes.delete(retryKey);
|
|
960
1001
|
writeBlockerPlaceholder(s.currentUnit.type, s.currentUnit.id, s.basePath, reason);
|
|
961
|
-
ctx.ui.notify(`${s.currentUnit.type} ${s.currentUnit.id} — deterministic policy rejection, wrote blocker placeholder (no retries)
|
|
1002
|
+
ctx.ui.notify(`${s.currentUnit.type} ${s.currentUnit.id} — deterministic policy rejection, wrote blocker placeholder (no retries)`, "warning");
|
|
962
1003
|
// Fall through to "continue" — do NOT enter the retry or db-unavailable paths.
|
|
963
1004
|
}
|
|
1005
|
+
else if (!triggerArtifactVerified && diagnoseWorktreeIntegrityFailure(s.basePath)) {
|
|
1006
|
+
const retryKey = `${s.currentUnit.type}:${s.currentUnit.id}`;
|
|
1007
|
+
const worktreeFailure = diagnoseWorktreeIntegrityFailure(s.basePath);
|
|
1008
|
+
s.pendingVerificationRetry = null;
|
|
1009
|
+
s.verificationRetryCount.delete(retryKey);
|
|
1010
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
1011
|
+
debugLog("postUnit", {
|
|
1012
|
+
phase: "worktree-integrity-failure",
|
|
1013
|
+
unitType: s.currentUnit.type,
|
|
1014
|
+
unitId: s.currentUnit.id,
|
|
1015
|
+
basePath: s.basePath,
|
|
1016
|
+
});
|
|
1017
|
+
ctx.ui.notify(`${worktreeFailure} Retry ${s.currentUnit.id} after repair.`, "error");
|
|
1018
|
+
await pauseAuto(ctx, pi);
|
|
1019
|
+
return "dispatched";
|
|
1020
|
+
}
|
|
964
1021
|
else if (!triggerArtifactVerified && !isDbAvailable()) {
|
|
965
1022
|
debugLog("postUnit", { phase: "artifact-verify-skip-db-unavailable", unitType: s.currentUnit.type, unitId: s.currentUnit.id });
|
|
966
1023
|
const dbSkipDiag = diagnoseExpectedArtifact(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
@@ -1032,7 +1089,7 @@ export async function postUnitPostVerification(pctx) {
|
|
|
1032
1089
|
const { s, ctx, pi, buildSnapshotOpts, lockBase, stopAuto, pauseAuto, updateProgressWidget } = pctx;
|
|
1033
1090
|
if (s.currentUnit) {
|
|
1034
1091
|
if (shouldDeferCloseoutGitAction(s.currentUnit.type)) {
|
|
1035
|
-
const gitActionResult = await runCloseoutGitAction(pctx, s.currentUnit);
|
|
1092
|
+
const gitActionResult = await runCloseoutGitAction(pctx, s.currentUnit, { softFailure: true });
|
|
1036
1093
|
if (gitActionResult === "dispatched") {
|
|
1037
1094
|
return "stopped";
|
|
1038
1095
|
}
|
|
@@ -1404,15 +1461,19 @@ export async function postUnitPostVerification(pctx) {
|
|
|
1404
1461
|
// Without this notify(), /gsd in step mode finishes a unit and silently
|
|
1405
1462
|
// exits the loop, leaving the user with no hint to /clear and /gsd again.
|
|
1406
1463
|
if (s.stepMode) {
|
|
1464
|
+
let phaseAfterUnit = null;
|
|
1407
1465
|
try {
|
|
1408
1466
|
const nextState = await deriveState(s.canonicalProjectRoot);
|
|
1467
|
+
phaseAfterUnit = nextState.phase;
|
|
1409
1468
|
ctx.ui.notify(buildStepCompleteMessage(nextState), "info");
|
|
1410
1469
|
}
|
|
1411
1470
|
catch (e) {
|
|
1412
1471
|
debugLog("postUnit", { phase: "step-wizard-notify", error: String(e) });
|
|
1413
1472
|
ctx.ui.notify(STEP_COMPLETE_FALLBACK_MESSAGE, "info");
|
|
1414
1473
|
}
|
|
1415
|
-
return
|
|
1474
|
+
return shouldReturnStepWizardAfterUnit(s.currentUnit?.type, phaseAfterUnit)
|
|
1475
|
+
? "step-wizard"
|
|
1476
|
+
: "continue";
|
|
1416
1477
|
}
|
|
1417
1478
|
return "continue";
|
|
1418
1479
|
}
|
|
@@ -14,7 +14,8 @@ import { clearParseCache } from "./files.js";
|
|
|
14
14
|
import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
|
|
15
15
|
import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk, getCompletedMilestoneTaskFileHints, getMilestoneCommitAttributionShas, recordMilestoneCommitAttribution } from "./gsd-db.js";
|
|
16
16
|
import { isValidationTerminal } from "./state.js";
|
|
17
|
-
import {
|
|
17
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
18
|
+
import { logWarning, logError } from "./workflow-logger.js";
|
|
18
19
|
import { readIntegrationBranch } from "./git-service.js";
|
|
19
20
|
import { isClosedStatus } from "./status-guards.js";
|
|
20
21
|
import { resolveSlicePath, resolveSliceFile, resolveTasksDir, resolveTaskFiles, relMilestoneFile, relSliceFile, buildSliceFileName, resolveMilestoneFile, clearPathCache, resolveGsdRootFile, } from "./paths.js";
|
|
@@ -25,9 +26,33 @@ import { resolveExpectedArtifactPath, diagnoseExpectedArtifact, } from "./auto-a
|
|
|
25
26
|
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
26
27
|
import { validateArtifact } from "./schemas/validate.js";
|
|
27
28
|
import { getProjectResearchStatus } from "./project-research-policy.js";
|
|
29
|
+
import { isGsdWorktreePath } from "./worktree-root.js";
|
|
28
30
|
// Re-export so existing consumers of auto-recovery.ts keep working.
|
|
29
31
|
export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
|
|
30
32
|
export { classifyMilestoneSummaryContent, } from "./milestone-summary-classifier.js";
|
|
33
|
+
// ─── Artifact Resolution & Verification ───────────────────────────────────────
|
|
34
|
+
export function diagnoseWorktreeIntegrityFailure(basePath) {
|
|
35
|
+
if (!isGsdWorktreePath(basePath))
|
|
36
|
+
return null;
|
|
37
|
+
if (!existsSync(basePath)) {
|
|
38
|
+
return `Worktree integrity failure: ${basePath} does not exist. Repair or recreate the worktree before retrying.`;
|
|
39
|
+
}
|
|
40
|
+
const gitPath = join(basePath, ".git");
|
|
41
|
+
if (!existsSync(gitPath)) {
|
|
42
|
+
return `Worktree integrity failure: ${basePath} is not a valid git worktree (.git missing). Repair or recreate the worktree before retrying.`;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
execFileSync("git", ["rev-parse", "--git-dir"], {
|
|
46
|
+
cwd: basePath,
|
|
47
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
});
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return `Worktree integrity failure: ${basePath} is not a valid git worktree (git rev-parse failed: ${getErrorMessage(err).split("\n")[0]}). Repair or recreate the worktree before retrying.`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
31
56
|
export function refreshRecoveryDbForArtifact(unitType, unitId) {
|
|
32
57
|
if (unitType !== "plan-slice" && unitType !== "execute-task")
|
|
33
58
|
return { ok: true };
|
|
@@ -137,9 +162,16 @@ export function hasImplementationArtifacts(basePath, milestoneId) {
|
|
|
137
162
|
// Strategy: check `git diff --name-only` against the merge-base with the
|
|
138
163
|
// main branch. This captures ALL files changed during the milestone's
|
|
139
164
|
// lifetime while running on a milestone branch.
|
|
140
|
-
const
|
|
141
|
-
? readIntegrationBranch(basePath, milestoneId)
|
|
142
|
-
:
|
|
165
|
+
const recordedIntegrationBranch = milestoneId
|
|
166
|
+
? readIntegrationBranch(basePath, milestoneId)
|
|
167
|
+
: null;
|
|
168
|
+
let integrationBranch;
|
|
169
|
+
if (recordedIntegrationBranch?.startsWith("milestone/")) {
|
|
170
|
+
integrationBranch = detectMainBranch(basePath);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
integrationBranch = recordedIntegrationBranch ?? detectMainBranch(basePath);
|
|
174
|
+
}
|
|
143
175
|
const currentBranch = getCurrentBranch(basePath);
|
|
144
176
|
const branchDiff = getChangedFilesSinceBranch(basePath, integrationBranch);
|
|
145
177
|
if (!branchDiff.ok)
|
|
@@ -471,29 +503,49 @@ function commitMatchesMilestone(basePath, message, milestoneId, files) {
|
|
|
471
503
|
// rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone when
|
|
472
504
|
// either the commit touched this milestone's artifacts, or — for projects
|
|
473
505
|
// where .gsd/ is gitignored/external (#5033) — the message explicitly
|
|
474
|
-
// names the milestone
|
|
506
|
+
// names the milestone, local GSD state proves the task belongs here, or the
|
|
507
|
+
// commit is implementation-bearing evidence itself (#5100).
|
|
475
508
|
if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
|
|
476
509
|
if (files.some((file) => isMilestoneArtifactPath(file, milestoneId)))
|
|
477
510
|
return true;
|
|
478
511
|
if (commitMessageMentionsMilestone(message, milestoneId))
|
|
479
512
|
return true;
|
|
480
|
-
|
|
513
|
+
const taskTrailerOwnership = getTaskOwnershipStatus(basePath, message, milestoneId);
|
|
514
|
+
if (taskTrailerOwnership === true)
|
|
515
|
+
return true;
|
|
516
|
+
if (taskTrailerOwnership === false)
|
|
517
|
+
return false;
|
|
518
|
+
// taskTrailerOwnership === null: unknown ownership. Apply fallback only
|
|
519
|
+
// in this case to avoid cross-milestone attribution.
|
|
520
|
+
if (MILESTONE_ID_RE.test(milestoneId) && classifyImplementationFiles(files) === "present")
|
|
481
521
|
return true;
|
|
482
522
|
}
|
|
483
523
|
return false;
|
|
484
524
|
}
|
|
485
|
-
|
|
525
|
+
/**
|
|
526
|
+
* Tri-state task ownership probe.
|
|
527
|
+
* true => DB or local files confirm this milestone owns the task.
|
|
528
|
+
* false => DB is available and this milestone is registered, but task is absent.
|
|
529
|
+
* null => ownership unknown (milestone not in DB yet, or no DB + no local files).
|
|
530
|
+
*/
|
|
531
|
+
function getTaskOwnershipStatus(basePath, message, milestoneId) {
|
|
486
532
|
const match = message.match(/^GSD-Task:\s*(S[^/\s]+)\/(T[^\s]+)/m);
|
|
487
533
|
if (!match)
|
|
488
|
-
return
|
|
534
|
+
return null;
|
|
489
535
|
const [, sliceId, taskId] = match;
|
|
490
|
-
if (
|
|
491
|
-
|
|
536
|
+
if (isDbAvailable()) {
|
|
537
|
+
if (!getMilestone(milestoneId))
|
|
538
|
+
return null;
|
|
539
|
+
return getTask(milestoneId, sliceId, taskId) ? true : false;
|
|
540
|
+
}
|
|
541
|
+
// DB unavailable: fallback to local task-file presence.
|
|
492
542
|
const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId);
|
|
493
|
-
if (
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
543
|
+
if (tasksDir
|
|
544
|
+
&& (existsSync(join(tasksDir, `${taskId}-PLAN.md`))
|
|
545
|
+
|| existsSync(join(tasksDir, `${taskId}-SUMMARY.md`)))) {
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
return null;
|
|
497
549
|
}
|
|
498
550
|
function commitMessageMentionsMilestone(message, milestoneId) {
|
|
499
551
|
if (!MILESTONE_ID_RE.test(milestoneId))
|
|
@@ -673,6 +725,11 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
673
725
|
return false;
|
|
674
726
|
}
|
|
675
727
|
if (!existsSync(absPath)) {
|
|
728
|
+
const worktreeFailure = diagnoseWorktreeIntegrityFailure(base);
|
|
729
|
+
if (worktreeFailure) {
|
|
730
|
+
logError("recovery", `${worktreeFailure} Unit: ${unitType} ${unitId}.`);
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
676
733
|
logWarning("recovery", `verify-fail ${unitType} ${unitId}: existsSync false for ${absPath}`);
|
|
677
734
|
return false;
|
|
678
735
|
}
|
|
@@ -21,10 +21,10 @@ import { invalidateAllCaches } from "./cache.js";
|
|
|
21
21
|
import { writeLock, clearLock } from "./crash-recovery.js";
|
|
22
22
|
import { acquireSessionLock, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
23
23
|
import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
|
|
24
|
-
import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch,
|
|
24
|
+
import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchList, nativeBranchExists, nativeBranchListMerged, nativeBranchDelete, nativeWorktreeRemove, nativeCommitCountBetween, } from "./native-git-bridge.js";
|
|
25
25
|
import { GitServiceImpl } from "./git-service.js";
|
|
26
26
|
import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
|
|
27
|
-
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
27
|
+
import { getAutoWorktreePath, checkoutBranchWithStashGuard } from "./auto-worktree.js";
|
|
28
28
|
import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
|
|
29
29
|
import { worktreePath as getWorktreeDir, isInsideWorktreesDir } from "./worktree-manager.js";
|
|
30
30
|
import { emitWorktreeOrphaned } from "./worktree-telemetry.js";
|
|
@@ -33,7 +33,7 @@ import { initRoutingHistory } from "./routing-history.js";
|
|
|
33
33
|
import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
|
|
34
34
|
import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
|
|
35
35
|
import { snapshotSkills } from "./skill-discovery.js";
|
|
36
|
-
import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
36
|
+
import { isDbAvailable, getMilestone, getAllMilestones, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
37
37
|
import { isClosedStatus } from "./status-guards.js";
|
|
38
38
|
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
39
39
|
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
@@ -88,9 +88,11 @@ export function decideSurvivorAction(hasSurvivorBranch, phase) {
|
|
|
88
88
|
return "finalize";
|
|
89
89
|
return "none";
|
|
90
90
|
}
|
|
91
|
-
export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
|
|
91
|
+
export function auditOrphanedMilestoneBranches(basePath, isolationMode, gitDeps = {}) {
|
|
92
92
|
const recovered = [];
|
|
93
93
|
const warnings = [];
|
|
94
|
+
const branchList = gitDeps.branchList ?? nativeBranchList;
|
|
95
|
+
const branchExists = gitDeps.branchExists ?? nativeBranchExists;
|
|
94
96
|
// Skip in none mode — no milestone branches are created
|
|
95
97
|
if (isolationMode === "none")
|
|
96
98
|
return { recovered, warnings };
|
|
@@ -98,15 +100,16 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
|
|
|
98
100
|
if (!isDbAvailable())
|
|
99
101
|
return { recovered, warnings };
|
|
100
102
|
let milestoneBranches;
|
|
103
|
+
let milestoneBranchListAvailable = true;
|
|
101
104
|
try {
|
|
102
|
-
milestoneBranches =
|
|
105
|
+
milestoneBranches = branchList(basePath, "milestone/*");
|
|
103
106
|
}
|
|
104
107
|
catch {
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
milestoneBranchListAvailable = false;
|
|
109
|
+
// git branch list failed — fall through with an empty branch set so the
|
|
110
|
+
// branch-less orphan pass can still run after per-milestone verification.
|
|
111
|
+
milestoneBranches = [];
|
|
107
112
|
}
|
|
108
|
-
if (milestoneBranches.length === 0)
|
|
109
|
-
return { recovered, warnings };
|
|
110
113
|
// Detect main branch for merge-check
|
|
111
114
|
let mainBranch;
|
|
112
115
|
try {
|
|
@@ -236,6 +239,71 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
|
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
241
|
}
|
|
242
|
+
// Second pass (#5879): catch worktree directories stranded by a previous
|
|
243
|
+
// audit that deleted the milestone/* branch but failed to remove the
|
|
244
|
+
// directory (or the dir was orphaned by a separate path entirely, e.g.
|
|
245
|
+
// postflight-stash-restore-failed during closeout). The branch-keyed loop
|
|
246
|
+
// above is invisible to these cases — `nativeBranchList` returns nothing
|
|
247
|
+
// for the milestone, so the dir-cleanup block at line ~310 is never
|
|
248
|
+
// reached.
|
|
249
|
+
//
|
|
250
|
+
// Keyed on milestones whose DB status is `complete`. We do not iterate
|
|
251
|
+
// over arbitrary directories under .gsd/worktrees/ to avoid touching
|
|
252
|
+
// dirs that belong to an in-progress milestone whose branch was deleted
|
|
253
|
+
// separately — those are handled by the in-progress orphan path above
|
|
254
|
+
// when the branch is present, and by `/gsd doctor` when it is not.
|
|
255
|
+
const seenMilestoneIds = new Set(milestoneBranches.map((branch) => branch.replace(/^milestone\//, "")));
|
|
256
|
+
let completedMilestones = [];
|
|
257
|
+
try {
|
|
258
|
+
completedMilestones = getAllMilestones();
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// DB read failure — skip the second pass; the first pass is still useful.
|
|
262
|
+
completedMilestones = [];
|
|
263
|
+
}
|
|
264
|
+
for (const m of completedMilestones) {
|
|
265
|
+
if (m.status !== "complete")
|
|
266
|
+
continue;
|
|
267
|
+
if (seenMilestoneIds.has(m.id))
|
|
268
|
+
continue; // already processed in the branch loop
|
|
269
|
+
if (!milestoneBranchListAvailable) {
|
|
270
|
+
try {
|
|
271
|
+
if (branchExists(basePath, `milestone/${m.id}`))
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
warnings.push(`Could not verify whether milestone/${m.id} still exists; skipping branch-less worktree cleanup for safety: ${err instanceof Error ? err.message : String(err)}`);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const wtDir = getWorktreeDir(basePath, m.id);
|
|
280
|
+
if (!existsSync(wtDir))
|
|
281
|
+
continue;
|
|
282
|
+
if (!isInsideWorktreesDir(basePath, wtDir)) {
|
|
283
|
+
warnings.push(`Orphaned worktree directory for ${m.id} is outside .gsd/worktrees/ — skipping removal for safety.`);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
// Try `git worktree remove` first in case the dir is still registered
|
|
287
|
+
// (defensive — usually it is not when we reach this branch-less pass).
|
|
288
|
+
try {
|
|
289
|
+
nativeWorktreeRemove(basePath, wtDir, true);
|
|
290
|
+
}
|
|
291
|
+
catch (e) {
|
|
292
|
+
logWarning("engine", `worktree remove failed (expected for branch-less orphans): ${e instanceof Error ? e.message : String(e)}`);
|
|
293
|
+
}
|
|
294
|
+
if (existsSync(wtDir)) {
|
|
295
|
+
try {
|
|
296
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
297
|
+
recovered.push(`Removed orphaned worktree directory for ${m.id} (branch already deleted).`);
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
warnings.push(`Failed to remove orphaned worktree directory for ${m.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
recovered.push(`Removed orphaned worktree directory for ${m.id} (branch already deleted).`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
239
307
|
return { recovered, warnings };
|
|
240
308
|
}
|
|
241
309
|
/**
|
|
@@ -368,7 +436,7 @@ export function _mergeOrphanCompletedMilestone(lifecycle, orphanId, ui) {
|
|
|
368
436
|
return { merged: false, error: err };
|
|
369
437
|
}
|
|
370
438
|
export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, requestedStepMode, deps, interrupted) {
|
|
371
|
-
const { shouldUseWorktreeIsolation, registerSigtermHandler, lockBase, buildLifecycle, } = deps;
|
|
439
|
+
const { shouldUseWorktreeIsolation, registerSigtermHandler, registerAutoWorkerForSession, lockBase, buildLifecycle, } = deps;
|
|
372
440
|
const dirCheck = validateDirectory(base);
|
|
373
441
|
if (dirCheck.severity === "blocked") {
|
|
374
442
|
ctx.ui.notify(dirCheck.reason, "error");
|
|
@@ -523,6 +591,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
523
591
|
// consult DB status and avoid clearing runtime units for milestones that
|
|
524
592
|
// only have a failure-path SUMMARY on disk (#4663).
|
|
525
593
|
await openProjectDbIfPresent(base);
|
|
594
|
+
registerAutoWorkerForSession(base);
|
|
526
595
|
// Clean stale runtime unit files for completed milestones (#887).
|
|
527
596
|
// DB-authoritative: when DB is available, require DB status to be closed
|
|
528
597
|
// before clearing runtime units. A SUMMARY file alone is no longer
|
|
@@ -606,12 +675,16 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
606
675
|
// worktree cleanup) was never run — the survivor branch must be merged.
|
|
607
676
|
// Applies to both worktree and branch isolation modes.
|
|
608
677
|
let hasSurvivorBranch = false;
|
|
609
|
-
|
|
678
|
+
let survivorMilestoneId = state.activeMilestone?.id ?? null;
|
|
679
|
+
if (!survivorMilestoneId && state.phase === "complete") {
|
|
680
|
+
survivorMilestoneId = findUnmergedCompletedMilestone(base, getIsolationMode(base));
|
|
681
|
+
}
|
|
682
|
+
if (survivorMilestoneId &&
|
|
610
683
|
(state.phase === "pre-planning" || state.phase === "complete") &&
|
|
611
684
|
getIsolationMode(base) !== "none" &&
|
|
612
685
|
!detectWorktreeName(base) &&
|
|
613
686
|
!base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)) {
|
|
614
|
-
const milestoneBranch = `milestone/${
|
|
687
|
+
const milestoneBranch = `milestone/${survivorMilestoneId}`;
|
|
615
688
|
const { nativeBranchExists } = await import("./native-git-bridge.js");
|
|
616
689
|
hasSurvivorBranch = nativeBranchExists(base, milestoneBranch);
|
|
617
690
|
if (hasSurvivorBranch) {
|
|
@@ -645,7 +718,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
645
718
|
// Re-evaluate via the helper — the discuss branch above may have cleared
|
|
646
719
|
// hasSurvivorBranch after a successful promotion.
|
|
647
720
|
if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
|
|
648
|
-
const mid =
|
|
721
|
+
const mid = survivorMilestoneId;
|
|
649
722
|
// Commit 68ef58a3c made `_mergeBranchMode` throw on wrong-branch
|
|
650
723
|
// instead of returning false silently. Wrap the call so the throw is
|
|
651
724
|
// converted into an error notify + clean bootstrap abort, not an
|
|
@@ -828,7 +901,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
828
901
|
const integrationBranch = nativeDetectMainBranch(base);
|
|
829
902
|
const branchToCheckout = resolveIsolationNoneBranchCheckout(currentBranch, integrationBranch, isolationMode, isRepo);
|
|
830
903
|
if (branchToCheckout) {
|
|
831
|
-
|
|
904
|
+
checkoutBranchWithStashGuard(base, branchToCheckout, "isolation-none-recovery");
|
|
832
905
|
logWarning("bootstrap", `Returned to "${branchToCheckout}" — HEAD was on stale milestone branch "${currentBranch}" (isolation: none does not use milestone branches).`);
|
|
833
906
|
}
|
|
834
907
|
}
|
|
@@ -65,12 +65,25 @@ async function runValidateMilestonePostCheck(vctx, pauseAuto) {
|
|
|
65
65
|
const { milestone: mid } = parseUnitId(s.currentUnit.id);
|
|
66
66
|
if (!mid)
|
|
67
67
|
return "continue";
|
|
68
|
+
const setToolFailureRetry = (message) => {
|
|
69
|
+
const retryKey = verificationRetryKey(s.currentUnit.type, s.currentUnit.id);
|
|
70
|
+
const attempt = (s.verificationRetryCount.get(retryKey) ?? 0) + 1;
|
|
71
|
+
s.verificationRetryCount.set(retryKey, attempt);
|
|
72
|
+
s.pendingVerificationRetry = {
|
|
73
|
+
unitId: s.currentUnit.id,
|
|
74
|
+
failureContext: message,
|
|
75
|
+
attempt,
|
|
76
|
+
};
|
|
77
|
+
return "retry";
|
|
78
|
+
};
|
|
68
79
|
const validationFile = resolveMilestoneFile(s.basePath, mid, "VALIDATION");
|
|
69
|
-
if (!validationFile)
|
|
70
|
-
return "
|
|
80
|
+
if (!validationFile) {
|
|
81
|
+
return setToolFailureRetry("You must call gsd_validate_milestone to persist the validation results. No VALIDATION.md was created.");
|
|
82
|
+
}
|
|
71
83
|
const validationContent = await loadFile(validationFile);
|
|
72
|
-
if (!validationContent)
|
|
73
|
-
return "
|
|
84
|
+
if (!validationContent) {
|
|
85
|
+
return setToolFailureRetry("You must call gsd_validate_milestone to persist the validation results. VALIDATION.md exists but is empty.");
|
|
86
|
+
}
|
|
74
87
|
const verdict = extractVerdict(validationContent);
|
|
75
88
|
if (verdict !== "needs-remediation") {
|
|
76
89
|
await persistMilestoneValidationGate("pass", "none", `milestone validation verdict is ${verdict}; no remediation loop risk`, "", mid);
|