gsd-pi 2.82.0-dev.c22380fc3 → 2.82.0-dev.e7a7f1ed5
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 +5 -4
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +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 +18 -17
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
- package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-verification.js +45 -26
- 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 +9 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/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/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/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 +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-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/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/api/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 +13 -13
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +4 -4
- package/packages/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/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/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 +10 -1
- 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/cmux/index.ts +6 -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 +19 -17
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
- package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-verification.ts +58 -36
- 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 +9 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/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/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/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/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +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/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/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/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/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 +86 -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/verification-verdict.test.ts +78 -0
- 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 +54 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-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/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Wop3A7KRGyR06H3rla_1- → 4dSwdrs__8NwCZggxP9KF}/_ssgManifest.js +0 -0
|
@@ -42,8 +42,8 @@ import {
|
|
|
42
42
|
nativeCommit,
|
|
43
43
|
nativeGetCurrentBranch,
|
|
44
44
|
nativeDetectMainBranch,
|
|
45
|
-
nativeCheckoutBranch,
|
|
46
45
|
nativeBranchList,
|
|
46
|
+
nativeBranchExists,
|
|
47
47
|
nativeBranchListMerged,
|
|
48
48
|
nativeBranchDelete,
|
|
49
49
|
nativeWorktreeRemove,
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
detectWorktreeName,
|
|
56
56
|
setActiveMilestoneId,
|
|
57
57
|
} from "./worktree.js";
|
|
58
|
-
import { getAutoWorktreePath, isInAutoWorktree } from "./auto-worktree.js";
|
|
58
|
+
import { getAutoWorktreePath, isInAutoWorktree, checkoutBranchWithStashGuard } from "./auto-worktree.js";
|
|
59
59
|
import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
|
|
60
60
|
import { worktreePath as getWorktreeDir, isInsideWorktreesDir } from "./worktree-manager.js";
|
|
61
61
|
import { emitWorktreeOrphaned } from "./worktree-telemetry.js";
|
|
@@ -64,7 +64,7 @@ import { initRoutingHistory } from "./routing-history.js";
|
|
|
64
64
|
import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
|
|
65
65
|
import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
|
|
66
66
|
import { snapshotSkills } from "./skill-discovery.js";
|
|
67
|
-
import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
67
|
+
import { isDbAvailable, getMilestone, getAllMilestones, openDatabase, getDbStatus } from "./gsd-db.js";
|
|
68
68
|
import { isClosedStatus } from "./status-guards.js";
|
|
69
69
|
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
70
70
|
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
@@ -101,6 +101,7 @@ import { getSessionModelOverride } from "./session-model-override.js";
|
|
|
101
101
|
export interface BootstrapDeps {
|
|
102
102
|
shouldUseWorktreeIsolation: (basePath?: string) => boolean;
|
|
103
103
|
registerSigtermHandler: (basePath: string) => void;
|
|
104
|
+
registerAutoWorkerForSession: (basePath: string) => void;
|
|
104
105
|
lockBase: () => string;
|
|
105
106
|
buildLifecycle: () => WorktreeLifecycle;
|
|
106
107
|
}
|
|
@@ -202,9 +203,15 @@ export function decideSurvivorAction(
|
|
|
202
203
|
export function auditOrphanedMilestoneBranches(
|
|
203
204
|
basePath: string,
|
|
204
205
|
isolationMode: "worktree" | "branch" | "none",
|
|
206
|
+
gitDeps: {
|
|
207
|
+
branchList?: typeof nativeBranchList;
|
|
208
|
+
branchExists?: typeof nativeBranchExists;
|
|
209
|
+
} = {},
|
|
205
210
|
): { recovered: string[]; warnings: string[] } {
|
|
206
211
|
const recovered: string[] = [];
|
|
207
212
|
const warnings: string[] = [];
|
|
213
|
+
const branchList = gitDeps.branchList ?? nativeBranchList;
|
|
214
|
+
const branchExists = gitDeps.branchExists ?? nativeBranchExists;
|
|
208
215
|
|
|
209
216
|
// Skip in none mode — no milestone branches are created
|
|
210
217
|
if (isolationMode === "none") return { recovered, warnings };
|
|
@@ -213,15 +220,16 @@ export function auditOrphanedMilestoneBranches(
|
|
|
213
220
|
if (!isDbAvailable()) return { recovered, warnings };
|
|
214
221
|
|
|
215
222
|
let milestoneBranches: string[];
|
|
223
|
+
let milestoneBranchListAvailable = true;
|
|
216
224
|
try {
|
|
217
|
-
milestoneBranches =
|
|
225
|
+
milestoneBranches = branchList(basePath, "milestone/*");
|
|
218
226
|
} catch {
|
|
219
|
-
|
|
220
|
-
|
|
227
|
+
milestoneBranchListAvailable = false;
|
|
228
|
+
// git branch list failed — fall through with an empty branch set so the
|
|
229
|
+
// branch-less orphan pass can still run after per-milestone verification.
|
|
230
|
+
milestoneBranches = [];
|
|
221
231
|
}
|
|
222
232
|
|
|
223
|
-
if (milestoneBranches.length === 0) return { recovered, warnings };
|
|
224
|
-
|
|
225
233
|
// Detect main branch for merge-check
|
|
226
234
|
let mainBranch: string;
|
|
227
235
|
try {
|
|
@@ -354,6 +362,74 @@ export function auditOrphanedMilestoneBranches(
|
|
|
354
362
|
}
|
|
355
363
|
}
|
|
356
364
|
|
|
365
|
+
// Second pass (#5879): catch worktree directories stranded by a previous
|
|
366
|
+
// audit that deleted the milestone/* branch but failed to remove the
|
|
367
|
+
// directory (or the dir was orphaned by a separate path entirely, e.g.
|
|
368
|
+
// postflight-stash-restore-failed during closeout). The branch-keyed loop
|
|
369
|
+
// above is invisible to these cases — `nativeBranchList` returns nothing
|
|
370
|
+
// for the milestone, so the dir-cleanup block at line ~310 is never
|
|
371
|
+
// reached.
|
|
372
|
+
//
|
|
373
|
+
// Keyed on milestones whose DB status is `complete`. We do not iterate
|
|
374
|
+
// over arbitrary directories under .gsd/worktrees/ to avoid touching
|
|
375
|
+
// dirs that belong to an in-progress milestone whose branch was deleted
|
|
376
|
+
// separately — those are handled by the in-progress orphan path above
|
|
377
|
+
// when the branch is present, and by `/gsd doctor` when it is not.
|
|
378
|
+
const seenMilestoneIds = new Set(
|
|
379
|
+
milestoneBranches.map((branch) => branch.replace(/^milestone\//, "")),
|
|
380
|
+
);
|
|
381
|
+
let completedMilestones: readonly { id: string; status: string }[] = [];
|
|
382
|
+
try {
|
|
383
|
+
completedMilestones = getAllMilestones();
|
|
384
|
+
} catch {
|
|
385
|
+
// DB read failure — skip the second pass; the first pass is still useful.
|
|
386
|
+
completedMilestones = [];
|
|
387
|
+
}
|
|
388
|
+
for (const m of completedMilestones) {
|
|
389
|
+
if (m.status !== "complete") continue;
|
|
390
|
+
if (seenMilestoneIds.has(m.id)) continue; // already processed in the branch loop
|
|
391
|
+
if (!milestoneBranchListAvailable) {
|
|
392
|
+
try {
|
|
393
|
+
if (branchExists(basePath, `milestone/${m.id}`)) continue;
|
|
394
|
+
} catch (err) {
|
|
395
|
+
warnings.push(
|
|
396
|
+
`Could not verify whether milestone/${m.id} still exists; skipping branch-less worktree cleanup for safety: ${err instanceof Error ? err.message : String(err)}`,
|
|
397
|
+
);
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
const wtDir = getWorktreeDir(basePath, m.id);
|
|
402
|
+
if (!existsSync(wtDir)) continue;
|
|
403
|
+
if (!isInsideWorktreesDir(basePath, wtDir)) {
|
|
404
|
+
warnings.push(
|
|
405
|
+
`Orphaned worktree directory for ${m.id} is outside .gsd/worktrees/ — skipping removal for safety.`,
|
|
406
|
+
);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
// Try `git worktree remove` first in case the dir is still registered
|
|
410
|
+
// (defensive — usually it is not when we reach this branch-less pass).
|
|
411
|
+
try {
|
|
412
|
+
nativeWorktreeRemove(basePath, wtDir, true);
|
|
413
|
+
} catch (e) {
|
|
414
|
+
logWarning(
|
|
415
|
+
"engine",
|
|
416
|
+
`worktree remove failed (expected for branch-less orphans): ${e instanceof Error ? e.message : String(e)}`,
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
if (existsSync(wtDir)) {
|
|
420
|
+
try {
|
|
421
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
422
|
+
recovered.push(`Removed orphaned worktree directory for ${m.id} (branch already deleted).`);
|
|
423
|
+
} catch (err) {
|
|
424
|
+
warnings.push(
|
|
425
|
+
`Failed to remove orphaned worktree directory for ${m.id}: ${err instanceof Error ? err.message : String(err)}`,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
} else {
|
|
429
|
+
recovered.push(`Removed orphaned worktree directory for ${m.id} (branch already deleted).`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
357
433
|
return { recovered, warnings };
|
|
358
434
|
}
|
|
359
435
|
|
|
@@ -533,6 +609,7 @@ export async function bootstrapAutoSession(
|
|
|
533
609
|
const {
|
|
534
610
|
shouldUseWorktreeIsolation,
|
|
535
611
|
registerSigtermHandler,
|
|
612
|
+
registerAutoWorkerForSession,
|
|
536
613
|
lockBase,
|
|
537
614
|
buildLifecycle,
|
|
538
615
|
} = deps;
|
|
@@ -722,6 +799,7 @@ export async function bootstrapAutoSession(
|
|
|
722
799
|
// consult DB status and avoid clearing runtime units for milestones that
|
|
723
800
|
// only have a failure-path SUMMARY on disk (#4663).
|
|
724
801
|
await openProjectDbIfPresent(base);
|
|
802
|
+
registerAutoWorkerForSession(base);
|
|
725
803
|
|
|
726
804
|
// Clean stale runtime unit files for completed milestones (#887).
|
|
727
805
|
// DB-authoritative: when DB is available, require DB status to be closed
|
|
@@ -818,14 +896,18 @@ export async function bootstrapAutoSession(
|
|
|
818
896
|
// worktree cleanup) was never run — the survivor branch must be merged.
|
|
819
897
|
// Applies to both worktree and branch isolation modes.
|
|
820
898
|
let hasSurvivorBranch = false;
|
|
899
|
+
let survivorMilestoneId = state.activeMilestone?.id ?? null;
|
|
900
|
+
if (!survivorMilestoneId && state.phase === "complete") {
|
|
901
|
+
survivorMilestoneId = findUnmergedCompletedMilestone(base, getIsolationMode(base));
|
|
902
|
+
}
|
|
821
903
|
if (
|
|
822
|
-
|
|
904
|
+
survivorMilestoneId &&
|
|
823
905
|
(state.phase === "pre-planning" || state.phase === "complete") &&
|
|
824
906
|
getIsolationMode(base) !== "none" &&
|
|
825
907
|
!detectWorktreeName(base) &&
|
|
826
908
|
!base.includes(`${pathSep}.gsd${pathSep}worktrees${pathSep}`)
|
|
827
909
|
) {
|
|
828
|
-
const milestoneBranch = `milestone/${
|
|
910
|
+
const milestoneBranch = `milestone/${survivorMilestoneId}`;
|
|
829
911
|
const { nativeBranchExists } = await import("./native-git-bridge.js");
|
|
830
912
|
hasSurvivorBranch = nativeBranchExists(base, milestoneBranch);
|
|
831
913
|
if (hasSurvivorBranch) {
|
|
@@ -869,7 +951,7 @@ export async function bootstrapAutoSession(
|
|
|
869
951
|
// Re-evaluate via the helper — the discuss branch above may have cleared
|
|
870
952
|
// hasSurvivorBranch after a successful promotion.
|
|
871
953
|
if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
|
|
872
|
-
const mid =
|
|
954
|
+
const mid = survivorMilestoneId!;
|
|
873
955
|
// Commit 68ef58a3c made `_mergeBranchMode` throw on wrong-branch
|
|
874
956
|
// instead of returning false silently. Wrap the call so the throw is
|
|
875
957
|
// converted into an error notify + clean bootstrap abort, not an
|
|
@@ -1087,7 +1169,7 @@ export async function bootstrapAutoSession(
|
|
|
1087
1169
|
isRepo,
|
|
1088
1170
|
);
|
|
1089
1171
|
if (branchToCheckout) {
|
|
1090
|
-
|
|
1172
|
+
checkoutBranchWithStashGuard(base, branchToCheckout, "isolation-none-recovery");
|
|
1091
1173
|
logWarning("bootstrap", `Returned to "${branchToCheckout}" — HEAD was on stale milestone branch "${currentBranch}" (isolation: none does not use milestone branches).`);
|
|
1092
1174
|
}
|
|
1093
1175
|
} catch (err) {
|
|
@@ -40,6 +40,7 @@ import { join } from "node:path";
|
|
|
40
40
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
41
41
|
import { UokGateRunner } from "./uok/gate-runner.js";
|
|
42
42
|
import { verificationRetryKey } from "./auto/verification-retry-policy.js";
|
|
43
|
+
import { decideVerificationVerdict } from "./verification-verdict.js";
|
|
43
44
|
|
|
44
45
|
export interface VerificationContext {
|
|
45
46
|
s: AutoSession;
|
|
@@ -49,12 +50,6 @@ export interface VerificationContext {
|
|
|
49
50
|
|
|
50
51
|
export type VerificationResult = "continue" | "retry" | "pause";
|
|
51
52
|
|
|
52
|
-
function isInfraVerificationFailure(stderr: string): boolean {
|
|
53
|
-
return /\b(ENOENT|ENOTFOUND|ETIMEDOUT|ECONNRESET|EAI_AGAIN|spawn\s+\S+\s+ENOENT|command not found)\b/i.test(
|
|
54
|
-
stderr,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
53
|
/**
|
|
59
54
|
* Post-unit guard for `validate-milestone` units (#4094).
|
|
60
55
|
*
|
|
@@ -110,11 +105,31 @@ async function runValidateMilestonePostCheck(
|
|
|
110
105
|
const { milestone: mid } = parseUnitId(s.currentUnit.id);
|
|
111
106
|
if (!mid) return "continue";
|
|
112
107
|
|
|
108
|
+
const setToolFailureRetry = (message: string): VerificationResult => {
|
|
109
|
+
const retryKey = verificationRetryKey(s.currentUnit!.type, s.currentUnit!.id);
|
|
110
|
+
const attempt = (s.verificationRetryCount.get(retryKey) ?? 0) + 1;
|
|
111
|
+
s.verificationRetryCount.set(retryKey, attempt);
|
|
112
|
+
s.pendingVerificationRetry = {
|
|
113
|
+
unitId: s.currentUnit!.id,
|
|
114
|
+
failureContext: message,
|
|
115
|
+
attempt,
|
|
116
|
+
};
|
|
117
|
+
return "retry";
|
|
118
|
+
};
|
|
119
|
+
|
|
113
120
|
const validationFile = resolveMilestoneFile(s.basePath, mid, "VALIDATION");
|
|
114
|
-
if (!validationFile)
|
|
121
|
+
if (!validationFile) {
|
|
122
|
+
return setToolFailureRetry(
|
|
123
|
+
"You must call gsd_validate_milestone to persist the validation results. No VALIDATION.md was created.",
|
|
124
|
+
);
|
|
125
|
+
}
|
|
115
126
|
|
|
116
127
|
const validationContent = await loadFile(validationFile);
|
|
117
|
-
if (!validationContent)
|
|
128
|
+
if (!validationContent) {
|
|
129
|
+
return setToolFailureRetry(
|
|
130
|
+
"You must call gsd_validate_milestone to persist the validation results. VALIDATION.md exists but is empty.",
|
|
131
|
+
);
|
|
132
|
+
}
|
|
118
133
|
|
|
119
134
|
const verdict = extractVerdict(validationContent);
|
|
120
135
|
if (verdict !== "needs-remediation") {
|
|
@@ -196,7 +211,7 @@ async function countIncompleteSlices(basePath: string, milestoneId: string): Pro
|
|
|
196
211
|
/**
|
|
197
212
|
* Run the verification gate for the current execute-task unit.
|
|
198
213
|
* Returns:
|
|
199
|
-
* - "continue" —
|
|
214
|
+
* - "continue" — host-owned verification passed, proceed normally
|
|
200
215
|
* - "retry" — gate failed with retries remaining, s.pendingVerificationRetry set for loop re-iteration
|
|
201
216
|
* - "pause" — gate failed with retries exhausted, pauseAuto already called
|
|
202
217
|
*/
|
|
@@ -260,6 +275,11 @@ export async function runPostUnitVerification(
|
|
|
260
275
|
}
|
|
261
276
|
}
|
|
262
277
|
|
|
278
|
+
const verdict = decideVerificationVerdict(s.currentUnit.type, result);
|
|
279
|
+
if (!verdict.passed) {
|
|
280
|
+
result.passed = false;
|
|
281
|
+
}
|
|
282
|
+
|
|
263
283
|
if (uokFlags.gates) {
|
|
264
284
|
const gateRunner = new UokGateRunner();
|
|
265
285
|
gateRunner.register({
|
|
@@ -272,10 +292,12 @@ export async function runPostUnitVerification(
|
|
|
272
292
|
: "verification",
|
|
273
293
|
rationale: result.passed
|
|
274
294
|
? "verification checks passed"
|
|
275
|
-
:
|
|
295
|
+
: verdict.reason === "no-host-checks"
|
|
296
|
+
? "no runnable host-owned verification checks discovered"
|
|
297
|
+
: "verification checks failed",
|
|
276
298
|
findings: result.passed
|
|
277
299
|
? ""
|
|
278
|
-
: formatFailureContext(result),
|
|
300
|
+
: verdict.failureContext || formatFailureContext(result),
|
|
279
301
|
}),
|
|
280
302
|
});
|
|
281
303
|
|
|
@@ -343,13 +365,18 @@ export async function runPostUnitVerification(
|
|
|
343
365
|
writeVerificationJSON(result, tasksDir, tid, s.currentUnit.id);
|
|
344
366
|
} else {
|
|
345
367
|
const nextAttempt = attempt + 1;
|
|
368
|
+
const includeRetryMetadata =
|
|
369
|
+
!result.passed &&
|
|
370
|
+
verdict.retryable &&
|
|
371
|
+
autoFixEnabled &&
|
|
372
|
+
nextAttempt <= maxRetries;
|
|
346
373
|
writeVerificationJSON(
|
|
347
374
|
result,
|
|
348
375
|
tasksDir,
|
|
349
376
|
tid,
|
|
350
377
|
s.currentUnit.id,
|
|
351
|
-
nextAttempt,
|
|
352
|
-
maxRetries,
|
|
378
|
+
includeRetryMetadata ? nextAttempt : undefined,
|
|
379
|
+
includeRetryMetadata ? maxRetries : undefined,
|
|
353
380
|
);
|
|
354
381
|
}
|
|
355
382
|
}
|
|
@@ -358,26 +385,6 @@ export async function runPostUnitVerification(
|
|
|
358
385
|
}
|
|
359
386
|
}
|
|
360
387
|
|
|
361
|
-
const advisoryFailure =
|
|
362
|
-
!result.passed &&
|
|
363
|
-
(result.discoverySource === "package-json" ||
|
|
364
|
-
result.checks.some((check) =>
|
|
365
|
-
isInfraVerificationFailure(check.stderr),
|
|
366
|
-
));
|
|
367
|
-
|
|
368
|
-
if (advisoryFailure) {
|
|
369
|
-
s.verificationRetryCount.delete(retryKey);
|
|
370
|
-
s.verificationRetryFailureHashes.delete(retryKey);
|
|
371
|
-
s.pendingVerificationRetry = null;
|
|
372
|
-
ctx.ui.notify(
|
|
373
|
-
result.discoverySource === "package-json"
|
|
374
|
-
? "Verification failed in auto-discovered package.json checks — treating as advisory."
|
|
375
|
-
: "Verification failed due to infrastructure/runtime environment issues — treating as advisory.",
|
|
376
|
-
"warning",
|
|
377
|
-
);
|
|
378
|
-
return "continue";
|
|
379
|
-
}
|
|
380
|
-
|
|
381
388
|
// ── Post-execution checks (run after main verification passes for execute-task units) ──
|
|
382
389
|
let postExecChecks: PostExecutionCheckJSON[] | undefined;
|
|
383
390
|
let postExecBlockingFailure = false;
|
|
@@ -572,6 +579,17 @@ export async function runPostUnitVerification(
|
|
|
572
579
|
s.verificationRetryFailureHashes.delete(retryKey);
|
|
573
580
|
s.pendingVerificationRetry = null;
|
|
574
581
|
return "continue";
|
|
582
|
+
} else if (verdict.reason === "no-host-checks") {
|
|
583
|
+
s.verificationRetryCount.delete(retryKey);
|
|
584
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
585
|
+
s.pendingVerificationRetry = null;
|
|
586
|
+
ctx.ui.notify(
|
|
587
|
+
"Verification gate FAILED — no runnable host-owned verification checks were discovered. Pausing for human review.",
|
|
588
|
+
"error",
|
|
589
|
+
);
|
|
590
|
+
process.stderr.write(`verification-gate: ${verdict.failureContext}\n`);
|
|
591
|
+
await pauseAuto(ctx, pi);
|
|
592
|
+
return "pause";
|
|
575
593
|
} else if (postExecBlockingFailure) {
|
|
576
594
|
// Post-execution failures are cross-task consistency issues — retrying the same task won't fix them.
|
|
577
595
|
// Skip retry and pause immediately for human review.
|
|
@@ -589,7 +607,7 @@ export async function runPostUnitVerification(
|
|
|
589
607
|
s.verificationRetryCount.set(retryKey, nextAttempt);
|
|
590
608
|
s.pendingVerificationRetry = {
|
|
591
609
|
unitId: s.currentUnit.id,
|
|
592
|
-
failureContext: formatFailureContext(result),
|
|
610
|
+
failureContext: verdict.failureContext || formatFailureContext(result),
|
|
593
611
|
attempt: nextAttempt,
|
|
594
612
|
};
|
|
595
613
|
const failedCmds = result.checks
|
|
@@ -623,9 +641,13 @@ export async function runPostUnitVerification(
|
|
|
623
641
|
return "pause";
|
|
624
642
|
}
|
|
625
643
|
} catch (err) {
|
|
626
|
-
// Gate errors are non-fatal
|
|
627
644
|
logWarning("engine", `verification-gate error: ${(err as Error).message}`);
|
|
628
|
-
|
|
645
|
+
ctx.ui.notify(
|
|
646
|
+
`Verification gate errored before producing an authoritative verdict: ${(err as Error).message}`,
|
|
647
|
+
"error",
|
|
648
|
+
);
|
|
649
|
+
await pauseAuto(ctx, pi);
|
|
650
|
+
return "pause";
|
|
629
651
|
}
|
|
630
652
|
}
|
|
631
653
|
|
|
@@ -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
|
|
@@ -949,7 +1007,73 @@ export function enterBranchModeForMilestone(
|
|
|
949
1007
|
});
|
|
950
1008
|
}
|
|
951
1009
|
|
|
952
|
-
|
|
1010
|
+
checkoutBranchWithStashGuard(basePath, branch, `enter-branch-mode:${milestoneId}`);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
export function checkoutBranchWithStashGuard(
|
|
1014
|
+
basePath: string,
|
|
1015
|
+
branch: string,
|
|
1016
|
+
reason: string,
|
|
1017
|
+
): void {
|
|
1018
|
+
let stashMarker: string | null = null;
|
|
1019
|
+
let stashed = false;
|
|
1020
|
+
|
|
1021
|
+
const status = nativeWorkingTreeStatus(basePath).trim();
|
|
1022
|
+
if (status.length > 0) {
|
|
1023
|
+
stashMarker = `gsd-checkout-stash:${reason}:${process.pid}:${Date.now()}:${process.hrtime.bigint().toString(36)}`;
|
|
1024
|
+
const stashListBefore = execFileSync("git", ["stash", "list"], {
|
|
1025
|
+
cwd: basePath,
|
|
1026
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1027
|
+
encoding: "utf-8",
|
|
1028
|
+
});
|
|
1029
|
+
execFileSync(
|
|
1030
|
+
"git",
|
|
1031
|
+
["stash", "push", "--include-untracked", "-m", `gsd: checkout stash [${stashMarker}]`],
|
|
1032
|
+
{
|
|
1033
|
+
cwd: basePath,
|
|
1034
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1035
|
+
encoding: "utf-8",
|
|
1036
|
+
},
|
|
1037
|
+
);
|
|
1038
|
+
const stashListAfter = execFileSync("git", ["stash", "list"], {
|
|
1039
|
+
cwd: basePath,
|
|
1040
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1041
|
+
encoding: "utf-8",
|
|
1042
|
+
});
|
|
1043
|
+
stashed = stashListAfter !== stashListBefore;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// Checkout and stash-restore are split so we can distinguish two failure
|
|
1047
|
+
// modes: (a) checkout failed → HEAD did not move, restore stash and rethrow;
|
|
1048
|
+
// (b) checkout succeeded but stash pop failed → HEAD moved to `branch` but
|
|
1049
|
+
// the working-tree changes remain in the stash list. We surface a distinct
|
|
1050
|
+
// error in case (b) so callers don't assume the branch switch was rolled back.
|
|
1051
|
+
try {
|
|
1052
|
+
nativeCheckoutBranch(basePath, branch);
|
|
1053
|
+
} catch (checkoutErr) {
|
|
1054
|
+
if (stashed) {
|
|
1055
|
+
try {
|
|
1056
|
+
popStashByRef(basePath, stashMarker);
|
|
1057
|
+
} catch (restoreErr) {
|
|
1058
|
+
logWarning("worktree", `git stash pop failed during checkout restore: ${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)}`);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
throw checkoutErr;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
if (stashed) {
|
|
1065
|
+
try {
|
|
1066
|
+
popStashByRef(basePath, stashMarker);
|
|
1067
|
+
} catch (popErr) {
|
|
1068
|
+
const msg = popErr instanceof Error ? popErr.message : String(popErr);
|
|
1069
|
+
const wrapped = new Error(
|
|
1070
|
+
`checkout to '${branch}' succeeded but stash restore failed; working tree changes remain in the stash list. Original error: ${msg}`,
|
|
1071
|
+
);
|
|
1072
|
+
const ref = (popErr as { stashRef?: string } | null)?.stashRef;
|
|
1073
|
+
if (ref) (wrapped as { stashRef?: string }).stashRef = ref;
|
|
1074
|
+
throw wrapped;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
953
1077
|
}
|
|
954
1078
|
|
|
955
1079
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
@@ -1739,6 +1863,66 @@ export function mergeMilestoneToMain(
|
|
|
1739
1863
|
}
|
|
1740
1864
|
}
|
|
1741
1865
|
|
|
1866
|
+
// Already regular-merged milestones can skip the squash path and proceed to cleanup (#5831).
|
|
1867
|
+
if (nativeIsAncestor(originalBasePath_, milestoneBranch, mainBranch)) {
|
|
1868
|
+
const codeChanges = nativeDiffNumstat(
|
|
1869
|
+
originalBasePath_,
|
|
1870
|
+
mainBranch,
|
|
1871
|
+
milestoneBranch,
|
|
1872
|
+
).filter((entry) => !entry.path.startsWith(".gsd/"));
|
|
1873
|
+
if (codeChanges.length > 0) {
|
|
1874
|
+
const regularMergeChangedPaths = findRegularMergeChangedPaths(
|
|
1875
|
+
originalBasePath_,
|
|
1876
|
+
milestoneBranch,
|
|
1877
|
+
mainBranch,
|
|
1878
|
+
);
|
|
1879
|
+
const unanchoredCodeChanges = codeChanges.filter((entry) =>
|
|
1880
|
+
regularMergeChangedPaths.has(entry.path)
|
|
1881
|
+
);
|
|
1882
|
+
if (unanchoredCodeChanges.length > 0) {
|
|
1883
|
+
process.chdir(previousCwd);
|
|
1884
|
+
throw new GSDError(
|
|
1885
|
+
GSD_GIT_ERROR,
|
|
1886
|
+
`Milestone branch "${milestoneBranch}" is reachable from "${mainBranch}" ` +
|
|
1887
|
+
`but has ${unanchoredCodeChanges.length} milestone-touched code file(s) not on current "${mainBranch}". ` +
|
|
1888
|
+
`Aborting worktree teardown to prevent data loss.`,
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
debugLog("mergeMilestoneToMain", {
|
|
1893
|
+
action: "skip-squash-already-merged",
|
|
1894
|
+
milestoneId,
|
|
1895
|
+
milestoneBranch,
|
|
1896
|
+
mainBranch,
|
|
1897
|
+
});
|
|
1898
|
+
try {
|
|
1899
|
+
clearProjectRootStateFiles(originalBasePath_, milestoneId);
|
|
1900
|
+
} catch (err) {
|
|
1901
|
+
logWarning("worktree", `clearProjectRootStateFiles failed during already-merged cleanup: ${err instanceof Error ? err.message : String(err)}`);
|
|
1902
|
+
}
|
|
1903
|
+
try {
|
|
1904
|
+
removeWorktree(originalBasePath_, milestoneId, {
|
|
1905
|
+
branch: milestoneBranch,
|
|
1906
|
+
deleteBranch: false,
|
|
1907
|
+
});
|
|
1908
|
+
} catch (err) {
|
|
1909
|
+
logWarning("worktree", `worktree removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1910
|
+
}
|
|
1911
|
+
try {
|
|
1912
|
+
nativeBranchDelete(originalBasePath_, milestoneBranch);
|
|
1913
|
+
} catch (err) {
|
|
1914
|
+
logWarning("worktree", `git branch-delete failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1915
|
+
}
|
|
1916
|
+
setActiveWorkspace(null);
|
|
1917
|
+
nudgeGitBranchCache(previousCwd);
|
|
1918
|
+
try {
|
|
1919
|
+
process.chdir(originalBasePath_);
|
|
1920
|
+
} catch (err) {
|
|
1921
|
+
logWarning("worktree", `chdir to project root after already-merged cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1922
|
+
}
|
|
1923
|
+
return { commitMessage, pushed: false, prCreated: false, codeFilesChanged: true };
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1742
1926
|
// 7. Shelter queued milestone directories before the squash merge (#2505).
|
|
1743
1927
|
// The milestone branch may contain copies of queued milestone dirs (via
|
|
1744
1928
|
// copyPlanningArtifacts), so `git merge --squash` rejects when those same
|
|
@@ -1874,14 +2058,6 @@ export function mergeMilestoneToMain(
|
|
|
1874
2058
|
logWarning("worktree", `git stash failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1875
2059
|
}
|
|
1876
2060
|
|
|
1877
|
-
if (needsDbCycle && dbPathToReopen) {
|
|
1878
|
-
try {
|
|
1879
|
-
openDatabase(dbPathToReopen);
|
|
1880
|
-
} catch (err) {
|
|
1881
|
-
logWarning("worktree", `post-stash db reopen failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1882
|
-
}
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
2061
|
// 7b. Clean up stale merge state before attempting squash merge (#2912).
|
|
1886
2062
|
// A leftover MERGE_HEAD (from a previous failed merge, libgit2 native path,
|
|
1887
2063
|
// or interrupted operation) causes `git merge --squash` to refuse with
|
|
@@ -1891,6 +2067,13 @@ export function mergeMilestoneToMain(
|
|
|
1891
2067
|
|
|
1892
2068
|
// 8. Squash merge — auto-resolve .gsd/ state file conflicts (#530)
|
|
1893
2069
|
const mergeResult = nativeMergeSquash(originalBasePath_, milestoneBranch);
|
|
2070
|
+
if (needsDbCycle && dbPathToReopen) {
|
|
2071
|
+
try {
|
|
2072
|
+
openDatabase(dbPathToReopen);
|
|
2073
|
+
} catch (err) {
|
|
2074
|
+
logWarning("worktree", `post-merge db reopen failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
1894
2077
|
|
|
1895
2078
|
if (!mergeResult.success) {
|
|
1896
2079
|
// Dirty working tree — the merge was rejected before it started (e.g.
|