gsd-pi 2.82.0-dev.ed17d078d → 3.0.0-dev.8b8d129d7
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 +93 -18
- package/dist/cli.js +20 -9
- package/dist/headless.js +9 -2
- 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 +44 -6
- 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 +110 -37
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -1
- package/dist/resources/extensions/gsd/auto/phases.js +97 -38
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +3 -0
- 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 +278 -137
- package/dist/resources/extensions/gsd/auto-prompts.js +36 -10
- package/dist/resources/extensions/gsd/auto-recovery.js +79 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-timers.js +11 -3
- package/dist/resources/extensions/gsd/auto-verification.js +102 -34
- package/dist/resources/extensions/gsd/auto-worktree.js +178 -11
- package/dist/resources/extensions/gsd/auto.js +98 -54
- 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 +5 -4
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +24 -9
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +10 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +38 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +20 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +2 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +9 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +139 -0
- 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/db-base-schema.js +2 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +4 -0
- package/dist/resources/extensions/gsd/db-task-slice-rows.js +2 -0
- package/dist/resources/extensions/gsd/dispatch-guard.js +46 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- 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 +8 -3
- package/dist/resources/extensions/gsd/git-service.js +138 -10
- package/dist/resources/extensions/gsd/gsd-db.js +76 -33
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +110 -117
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/init-wizard.js +17 -2
- package/dist/resources/extensions/gsd/markdown-renderer.js +10 -8
- package/dist/resources/extensions/gsd/mcp-filter.js +58 -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 +57 -14
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -0
- package/dist/resources/extensions/gsd/paths.js +4 -0
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +9 -3
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -9
- package/dist/resources/extensions/gsd/pre-execution-checks.js +38 -11
- package/dist/resources/extensions/gsd/preferences-mcp.js +19 -0
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +138 -0
- package/dist/resources/extensions/gsd/preferences.js +2 -0
- 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/forensics.md +3 -3
- 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/reactive-execute.md +1 -1
- 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/repository-registry.js +44 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +2 -0
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +42 -18
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +59 -2
- 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 +14 -4
- package/dist/resources/extensions/gsd/status-guards.js +14 -2
- package/dist/resources/extensions/gsd/templates/plan.md +9 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +10 -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 +151 -15
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +36 -17
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +142 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +2 -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 +54 -10
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
- package/dist/resources/extensions/gsd/worktree-state-projection.js +31 -0
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/shared/interview-ui.js +6 -4
- 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/ttsr/ttsr-manager.js +3 -1
- 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/resources/skills/forensics/SKILL.md +1 -1
- 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 +9 -9
- 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 +5 -5
- 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 +9 -9
- 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.65b24fac92188a6b.js +10 -0
- package/dist/web/standalone/.next/static/chunks/9441.ff70bb53f6835771.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-855d616060cb6e59.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +4 -4
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +13 -4
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +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/package.json +1 -1
- 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/compaction/compaction.d.ts +6 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +7 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +14 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.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/controllers/input-controller.js +7 -7
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +25 -1
- 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 +2 -0
- 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 +24 -10
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +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/compaction/compaction.test.ts +23 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +7 -2
- 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/controllers/input-controller.test.ts +15 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +30 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +29 -10
- 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/__tests__/tui.test.js +45 -2
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- 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/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +106 -27
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +59 -2
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/src/tui.ts +108 -27
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +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 +52 -6
- 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 +49 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +17 -6
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +111 -38
- package/src/resources/extensions/gsd/auto/orchestrator.ts +12 -1
- package/src/resources/extensions/gsd/auto/phases.ts +115 -49
- package/src/resources/extensions/gsd/auto/session.ts +16 -0
- package/src/resources/extensions/gsd/auto/types.ts +3 -0
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +5 -1
- 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 +312 -148
- package/src/resources/extensions/gsd/auto-prompts.ts +36 -13
- package/src/resources/extensions/gsd/auto-recovery.ts +83 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-timers.ts +10 -3
- package/src/resources/extensions/gsd/auto-verification.ts +124 -42
- package/src/resources/extensions/gsd/auto-worktree.ts +195 -11
- package/src/resources/extensions/gsd/auto.ts +91 -42
- 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 +5 -4
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +27 -10
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +10 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +41 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +21 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +2 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +8 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/commands-verdict.ts +202 -0
- 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/db-base-schema.ts +2 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +5 -0
- package/src/resources/extensions/gsd/db-task-slice-rows.ts +4 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +60 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
- 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 +7 -3
- package/src/resources/extensions/gsd/git-service.ts +166 -11
- package/src/resources/extensions/gsd/gsd-db.ts +80 -31
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +142 -134
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/init-wizard.ts +17 -2
- package/src/resources/extensions/gsd/journal.ts +8 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +10 -8
- package/src/resources/extensions/gsd/mcp-filter.ts +80 -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 +63 -14
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -0
- package/src/resources/extensions/gsd/paths.ts +5 -0
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +10 -2
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -12
- package/src/resources/extensions/gsd/pre-execution-checks.ts +49 -11
- package/src/resources/extensions/gsd/preferences-mcp.ts +27 -0
- package/src/resources/extensions/gsd/preferences-types.ts +33 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +145 -0
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- 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/forensics.md +3 -3
- 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/reactive-execute.md +1 -1
- 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/repository-registry.ts +77 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +2 -0
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +54 -19
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +52 -1
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/state.ts +15 -4
- package/src/resources/extensions/gsd/status-guards.ts +16 -2
- package/src/resources/extensions/gsd/templates/plan.md +9 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +10 -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 +300 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +174 -8
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +151 -12
- 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 +18 -6
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +129 -6
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +12 -0
- 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/autocomplete-regressions-1675.test.ts +21 -0
- 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 +32 -4
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +378 -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/db-task-slice-rows.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +61 -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 +68 -1
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +5 -2
- 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/init-prefs-routing.test.ts +22 -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 +199 -2
- 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 +49 -3
- package/src/resources/extensions/gsd/tests/journal.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +287 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +11 -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 +80 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +55 -0
- 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 +343 -3
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +18 -1
- 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 +105 -3
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/preferences-mcp.test.ts +128 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +70 -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/quality-gates.test.ts +6 -0
- 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/repository-registry.test.ts +52 -0
- 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/slice-parallel-orchestrator.test.ts +72 -1
- 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-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +17 -1
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +2 -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 +128 -9
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +42 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +173 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -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/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +59 -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 +172 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +51 -18
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +170 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +2 -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 +61 -10
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
- package/src/resources/extensions/gsd/worktree-state-projection.ts +43 -0
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/shared/interview-ui.ts +6 -4
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +15 -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/ttsr/ttsr-manager.ts +5 -1
- 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/src/resources/skills/forensics/SKILL.md +1 -1
- 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/8359.e059d86b255fce1c.js +0 -10
- package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.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/{YEvjuT-fsFfYQhDSWtueS → _kljR-_Miq_YV1IW0wpRO}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{YEvjuT-fsFfYQhDSWtueS → _kljR-_Miq_YV1IW0wpRO}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
import { loadFile } from "./files.js";
|
|
4
|
+
import { resolveMilestoneFile } from "./paths.js";
|
|
5
|
+
import { deriveState } from "./state.js";
|
|
6
|
+
import { executeValidateMilestone } from "./tools/workflow-tool-executors.js";
|
|
7
|
+
import {
|
|
8
|
+
VALIDATION_VERDICTS,
|
|
9
|
+
extractVerdict,
|
|
10
|
+
isValidMilestoneVerdict,
|
|
11
|
+
type ValidationVerdict,
|
|
12
|
+
} from "./verdict-parser.js";
|
|
13
|
+
|
|
14
|
+
const USAGE =
|
|
15
|
+
'Usage: /gsd verdict <pass|needs-attention|needs-remediation> [--milestone Mxxx] [--rationale "..."]';
|
|
16
|
+
|
|
17
|
+
interface ParsedArgs {
|
|
18
|
+
verdict?: ValidationVerdict;
|
|
19
|
+
milestoneId?: string;
|
|
20
|
+
rationale?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface ParsedValidation {
|
|
24
|
+
verdict: string | undefined;
|
|
25
|
+
remediationRound: number;
|
|
26
|
+
successCriteriaChecklist: string;
|
|
27
|
+
sliceDeliveryAudit: string;
|
|
28
|
+
crossSliceIntegration: string;
|
|
29
|
+
requirementCoverage: string;
|
|
30
|
+
verificationClasses?: string;
|
|
31
|
+
verdictRationale: string;
|
|
32
|
+
remediationPlan?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function tokenize(raw: string): string[] {
|
|
36
|
+
const tokens: string[] = [];
|
|
37
|
+
const re = /"([^"]*)"|(\S+)/g;
|
|
38
|
+
let match: RegExpExecArray | null;
|
|
39
|
+
while ((match = re.exec(raw)) !== null) {
|
|
40
|
+
tokens.push(match[1] ?? match[2]);
|
|
41
|
+
}
|
|
42
|
+
return tokens;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseArgs(raw: string): ParsedArgs | { error: string } {
|
|
46
|
+
const tokens = tokenize(raw);
|
|
47
|
+
const out: ParsedArgs = {};
|
|
48
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
49
|
+
const t = tokens[i];
|
|
50
|
+
if (t === "--milestone") {
|
|
51
|
+
const next = tokens[++i];
|
|
52
|
+
if (!next) return { error: "--milestone requires a milestone ID" };
|
|
53
|
+
out.milestoneId = next;
|
|
54
|
+
} else if (t === "--rationale") {
|
|
55
|
+
const next = tokens[++i];
|
|
56
|
+
if (next == null) return { error: "--rationale requires a value" };
|
|
57
|
+
out.rationale = next;
|
|
58
|
+
} else if (!out.verdict) {
|
|
59
|
+
if (!isValidMilestoneVerdict(t)) {
|
|
60
|
+
return {
|
|
61
|
+
error: `Invalid verdict "${t}". Must be one of: ${VALIDATION_VERDICTS.join(", ")}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
out.verdict = t;
|
|
65
|
+
} else {
|
|
66
|
+
return { error: `Unexpected argument: ${t}` };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function extractRemediationRound(content: string): number {
|
|
73
|
+
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
74
|
+
if (!fm) return 0;
|
|
75
|
+
const m = fm[1].match(/^remediation_round:\s*(\d+)/im);
|
|
76
|
+
return m ? Number.parseInt(m[1], 10) : 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function extractSection(content: string, heading: string): string | undefined {
|
|
80
|
+
const escaped = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
81
|
+
// Match section bodies bounded by the next "## " heading or end-of-string.
|
|
82
|
+
// Leading "\n" prefix lets a single pattern handle first-line headings too.
|
|
83
|
+
// No /m flag — we want `$` to mean end-of-string, not end-of-line.
|
|
84
|
+
const re = new RegExp(`\\n## ${escaped}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`);
|
|
85
|
+
const m = ("\n" + content).match(re);
|
|
86
|
+
if (!m) return undefined;
|
|
87
|
+
return m[1].replace(/\s+$/, "");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function parseValidationFile(content: string): ParsedValidation {
|
|
91
|
+
return {
|
|
92
|
+
verdict: extractVerdict(content),
|
|
93
|
+
remediationRound: extractRemediationRound(content),
|
|
94
|
+
successCriteriaChecklist: extractSection(content, "Success Criteria Checklist") ?? "",
|
|
95
|
+
sliceDeliveryAudit: extractSection(content, "Slice Delivery Audit") ?? "",
|
|
96
|
+
crossSliceIntegration: extractSection(content, "Cross-Slice Integration") ?? "",
|
|
97
|
+
requirementCoverage: extractSection(content, "Requirement Coverage") ?? "",
|
|
98
|
+
verificationClasses: extractSection(content, "Verification Class Compliance"),
|
|
99
|
+
verdictRationale: extractSection(content, "Verdict Rationale") ?? "",
|
|
100
|
+
remediationPlan: extractSection(content, "Remediation Plan"),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function handleVerdict(
|
|
105
|
+
rawArgs: string,
|
|
106
|
+
ctx: ExtensionCommandContext,
|
|
107
|
+
basePath: string,
|
|
108
|
+
): Promise<void> {
|
|
109
|
+
if (!rawArgs.trim()) {
|
|
110
|
+
ctx.ui.notify(USAGE, "warning");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const parsed = parseArgs(rawArgs);
|
|
115
|
+
if ("error" in parsed) {
|
|
116
|
+
ctx.ui.notify(`${parsed.error}\n${USAGE}`, "warning");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (!parsed.verdict) {
|
|
120
|
+
ctx.ui.notify(USAGE, "warning");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let milestoneId = parsed.milestoneId;
|
|
125
|
+
if (!milestoneId) {
|
|
126
|
+
const state = await deriveState(basePath);
|
|
127
|
+
if (!state.activeMilestone) {
|
|
128
|
+
ctx.ui.notify(
|
|
129
|
+
"No active milestone — pass --milestone Mxxx to target a specific milestone.",
|
|
130
|
+
"warning",
|
|
131
|
+
);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
milestoneId = state.activeMilestone.id;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const validationPath = resolveMilestoneFile(basePath, milestoneId, "VALIDATION");
|
|
138
|
+
if (!validationPath) {
|
|
139
|
+
ctx.ui.notify(
|
|
140
|
+
`No VALIDATION file found for ${milestoneId}. Run gsd_validate_milestone first to produce one.`,
|
|
141
|
+
"warning",
|
|
142
|
+
);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const existing = await loadFile(validationPath);
|
|
146
|
+
if (!existing) {
|
|
147
|
+
ctx.ui.notify(
|
|
148
|
+
`Could not read VALIDATION file for ${milestoneId} (${validationPath}).`,
|
|
149
|
+
"warning",
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const current = parseValidationFile(existing);
|
|
155
|
+
|
|
156
|
+
if (parsed.verdict !== "pass" && !parsed.rationale) {
|
|
157
|
+
ctx.ui.notify(
|
|
158
|
+
`--rationale is required when overriding to ${parsed.verdict}.`,
|
|
159
|
+
"warning",
|
|
160
|
+
);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const verdictRationale =
|
|
165
|
+
parsed.rationale ?? "Manually overridden via /gsd verdict";
|
|
166
|
+
|
|
167
|
+
const result = await executeValidateMilestone(
|
|
168
|
+
{
|
|
169
|
+
milestoneId,
|
|
170
|
+
verdict: parsed.verdict,
|
|
171
|
+
remediationRound: current.remediationRound,
|
|
172
|
+
successCriteriaChecklist: current.successCriteriaChecklist,
|
|
173
|
+
sliceDeliveryAudit: current.sliceDeliveryAudit,
|
|
174
|
+
crossSliceIntegration: current.crossSliceIntegration,
|
|
175
|
+
requirementCoverage: current.requirementCoverage,
|
|
176
|
+
verificationClasses: current.verificationClasses,
|
|
177
|
+
verdictRationale,
|
|
178
|
+
remediationPlan: current.remediationPlan,
|
|
179
|
+
},
|
|
180
|
+
basePath,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
if (result.isError) {
|
|
184
|
+
const msg =
|
|
185
|
+
result.content[0]?.type === "text" ? result.content[0].text : "Unknown error";
|
|
186
|
+
ctx.ui.notify(msg, "error");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const prevVerdict = current.verdict ?? "unknown";
|
|
191
|
+
ctx.ui.notify(
|
|
192
|
+
`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${parsed.verdict}`,
|
|
193
|
+
"success",
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (parsed.verdict === "needs-remediation") {
|
|
197
|
+
ctx.ui.notify(
|
|
198
|
+
"Follow up with gsd_reassess_roadmap to add remediation slices, then re-run /gsd auto.",
|
|
199
|
+
"info",
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -30,9 +30,12 @@ import { join } from "node:path";
|
|
|
30
30
|
import {
|
|
31
31
|
findStaleWorkerForProject,
|
|
32
32
|
getAllAutoWorkers,
|
|
33
|
+
markWorkerCrashed,
|
|
34
|
+
markWorkerStopping,
|
|
33
35
|
type AutoWorkerRow,
|
|
34
36
|
} from "./db/auto-workers.js";
|
|
35
|
-
import {
|
|
37
|
+
import { forceReleaseLeasesForWorker } from "./db/milestone-leases.js";
|
|
38
|
+
import { markLatestActiveForWorkerCanceled, type DispatchStatus } from "./db/unit-dispatches.js";
|
|
36
39
|
import { getRuntimeKv, setRuntimeKv, deleteRuntimeKv } from "./db/runtime-kv.js";
|
|
37
40
|
import { _getAdapter, isDbAvailable } from "./gsd-db.js";
|
|
38
41
|
import { gsdRoot, normalizeRealPath } from "./paths.js";
|
|
@@ -56,6 +59,15 @@ function lockPath(basePath: string): string {
|
|
|
56
59
|
return join(gsdRoot(basePath), effectiveLockFile());
|
|
57
60
|
}
|
|
58
61
|
|
|
62
|
+
function clearLegacyLockFile(basePath: string): void {
|
|
63
|
+
try {
|
|
64
|
+
const p = lockPath(basePath);
|
|
65
|
+
if (existsSync(p)) unlinkSync(p);
|
|
66
|
+
} catch {
|
|
67
|
+
// Best-effort.
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
function readLegacyLock(basePath: string): LockData | null {
|
|
60
72
|
try {
|
|
61
73
|
const p = lockPath(basePath);
|
|
@@ -204,18 +216,46 @@ export function writeLock(
|
|
|
204
216
|
* stale session-file pointer.
|
|
205
217
|
*/
|
|
206
218
|
export function clearLock(basePath: string): void {
|
|
219
|
+
clearLegacyLockFile(basePath);
|
|
220
|
+
|
|
221
|
+
if (!isDbAvailable()) return;
|
|
207
222
|
try {
|
|
208
|
-
const
|
|
209
|
-
|
|
223
|
+
const projectRoot = normalizeRealPath(basePath);
|
|
224
|
+
const staleWorker = findStaleWorkerForProject(projectRoot);
|
|
225
|
+
if (staleWorker) {
|
|
226
|
+
markWorkerCrashed(staleWorker.worker_id);
|
|
227
|
+
forceReleaseLeasesForWorker(staleWorker.worker_id);
|
|
228
|
+
deleteRuntimeKv("worker", staleWorker.worker_id, SESSION_FILE_KV_KEY);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const worker = findActiveWorkerForCurrentProcess(projectRoot);
|
|
232
|
+
if (worker) deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
|
|
233
|
+
|
|
234
|
+
const stale = findStaleWorkerForProject(projectRoot);
|
|
235
|
+
if (stale) {
|
|
236
|
+
markWorkerStopping(stale.worker_id);
|
|
237
|
+
deleteRuntimeKv("worker", stale.worker_id, SESSION_FILE_KV_KEY);
|
|
238
|
+
}
|
|
210
239
|
} catch {
|
|
211
240
|
// Best-effort.
|
|
212
241
|
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Clear a stale DB-backed worker lock after readCrashLock/findStaleWorkerForProject
|
|
246
|
+
* has identified a dead worker. Unlike clearLock(), this targets the stale
|
|
247
|
+
* worker row instead of the current process's active worker.
|
|
248
|
+
*/
|
|
249
|
+
export function clearStaleWorkerLock(basePath: string): void {
|
|
250
|
+
clearLegacyLockFile(basePath);
|
|
213
251
|
|
|
214
252
|
if (!isDbAvailable()) return;
|
|
215
253
|
try {
|
|
216
254
|
const projectRoot = normalizeRealPath(basePath);
|
|
217
|
-
const worker =
|
|
255
|
+
const worker = findStaleWorkerForProject(projectRoot);
|
|
218
256
|
if (!worker) return;
|
|
257
|
+
markLatestActiveForWorkerCanceled(worker.worker_id, "crash-recovered");
|
|
258
|
+
markWorkerCrashed(worker.worker_id);
|
|
219
259
|
deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
|
|
220
260
|
} catch {
|
|
221
261
|
// Best-effort.
|
|
@@ -255,6 +255,32 @@ export function releaseMilestoneLease(
|
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Force-release all held leases for a worker.
|
|
260
|
+
*
|
|
261
|
+
* Used by crash recovery once PID liveness has confirmed the worker is dead.
|
|
262
|
+
* No fencing token is required because this path is cleanup-only for a
|
|
263
|
+
* non-running process.
|
|
264
|
+
*/
|
|
265
|
+
export function forceReleaseLeasesForWorker(workerId: string): number {
|
|
266
|
+
if (!isDbAvailable()) return 0;
|
|
267
|
+
const db = _getAdapter()!;
|
|
268
|
+
let changes = 0;
|
|
269
|
+
transaction(() => {
|
|
270
|
+
const result = db.prepare(
|
|
271
|
+
`UPDATE milestone_leases
|
|
272
|
+
SET status = 'released'
|
|
273
|
+
WHERE worker_id = :worker_id
|
|
274
|
+
AND status = 'held'`,
|
|
275
|
+
).run({ ":worker_id": workerId });
|
|
276
|
+
changes =
|
|
277
|
+
typeof (result as { changes?: unknown }).changes === "number"
|
|
278
|
+
? (result as { changes: number }).changes
|
|
279
|
+
: 0;
|
|
280
|
+
});
|
|
281
|
+
return changes;
|
|
282
|
+
}
|
|
283
|
+
|
|
258
284
|
/**
|
|
259
285
|
* Read current lease row for diagnostics. Returns null if no row exists.
|
|
260
286
|
*/
|
|
@@ -524,17 +524,18 @@ export function getRecentUnitKeysForProjectRoot(
|
|
|
524
524
|
if (!isDbAvailable()) return [];
|
|
525
525
|
const db = _getAdapter()!;
|
|
526
526
|
const rows = db.prepare(
|
|
527
|
-
`SELECT ud.unit_id
|
|
527
|
+
`SELECT ud.unit_type, ud.unit_id
|
|
528
528
|
FROM unit_dispatches ud
|
|
529
529
|
INNER JOIN workers w ON w.worker_id = ud.worker_id
|
|
530
530
|
WHERE w.project_root_realpath = :project_root_realpath
|
|
531
|
+
AND w.status != 'crashed'
|
|
531
532
|
ORDER BY ud.started_at DESC, ud.id DESC
|
|
532
533
|
LIMIT :limit`,
|
|
533
534
|
).all({
|
|
534
535
|
":project_root_realpath": projectRootRealpath,
|
|
535
536
|
":limit": limit,
|
|
536
|
-
}) as Array<{ unit_id: string }>;
|
|
537
|
-
return rows.reverse().map((r) => ({ key: r.unit_id }));
|
|
537
|
+
}) as Array<{ unit_type: string; unit_id: string }>;
|
|
538
|
+
return rows.reverse().map((r) => ({ key: `${r.unit_type}/${r.unit_id}` }));
|
|
538
539
|
}
|
|
539
540
|
|
|
540
541
|
/**
|
|
@@ -168,6 +168,7 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
|
|
|
168
168
|
proof_level TEXT NOT NULL DEFAULT '',
|
|
169
169
|
integration_closure TEXT NOT NULL DEFAULT '',
|
|
170
170
|
observability_impact TEXT NOT NULL DEFAULT '',
|
|
171
|
+
target_repositories TEXT NOT NULL DEFAULT '[]',
|
|
171
172
|
sequence INTEGER DEFAULT 0,
|
|
172
173
|
replan_triggered_at TEXT DEFAULT NULL,
|
|
173
174
|
is_sketch INTEGER NOT NULL DEFAULT 0,
|
|
@@ -208,6 +209,7 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
|
|
|
208
209
|
expected_output TEXT NOT NULL DEFAULT '[]',
|
|
209
210
|
observability_impact TEXT NOT NULL DEFAULT '',
|
|
210
211
|
full_plan_md TEXT NOT NULL DEFAULT '',
|
|
212
|
+
target_repositories TEXT NOT NULL DEFAULT '[]',
|
|
211
213
|
sequence INTEGER DEFAULT 0,
|
|
212
214
|
PRIMARY KEY (milestone_id, slice_id, id),
|
|
213
215
|
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
@@ -424,6 +424,11 @@ export function applyMigrationV28MemoryLastHitAt(db: DbAdapter): void {
|
|
|
424
424
|
ensureColumn(db, "memories", "last_hit_at", "ALTER TABLE memories ADD COLUMN last_hit_at TEXT DEFAULT NULL");
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
+
export function applyMigrationV29RepositoryTargets(db: DbAdapter): void {
|
|
428
|
+
ensureColumn(db, "slices", "target_repositories", "ALTER TABLE slices ADD COLUMN target_repositories TEXT NOT NULL DEFAULT '[]'");
|
|
429
|
+
ensureColumn(db, "tasks", "target_repositories", "ALTER TABLE tasks ADD COLUMN target_repositories TEXT NOT NULL DEFAULT '[]'");
|
|
430
|
+
}
|
|
431
|
+
|
|
427
432
|
export interface MigrationV22Hooks {
|
|
428
433
|
copyQualityGateRowsToRepairedTable(db: DbAdapter): void;
|
|
429
434
|
}
|
|
@@ -22,6 +22,7 @@ export interface SliceRow {
|
|
|
22
22
|
replan_triggered_at: string | null;
|
|
23
23
|
is_sketch: number;
|
|
24
24
|
sketch_scope: string;
|
|
25
|
+
target_repositories?: string[];
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export interface TaskRow {
|
|
@@ -55,6 +56,7 @@ export interface TaskRow {
|
|
|
55
56
|
escalation_awaiting_review: number;
|
|
56
57
|
escalation_artifact_path: string | null;
|
|
57
58
|
escalation_override_applied_at: string | null;
|
|
59
|
+
target_repositories?: string[];
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
type DbRow = Record<string, unknown>;
|
|
@@ -107,6 +109,7 @@ export function rowToSlice(row: DbRow): SliceRow {
|
|
|
107
109
|
replan_triggered_at: (row["replan_triggered_at"] as string) ?? null,
|
|
108
110
|
is_sketch: (row["is_sketch"] as number) ?? 0,
|
|
109
111
|
sketch_scope: (row["sketch_scope"] as string) ?? "",
|
|
112
|
+
target_repositories: parseTaskArrayColumn(row["target_repositories"]),
|
|
110
113
|
};
|
|
111
114
|
}
|
|
112
115
|
|
|
@@ -142,5 +145,6 @@ export function rowToTask(row: DbRow): TaskRow {
|
|
|
142
145
|
escalation_awaiting_review: (row["escalation_awaiting_review"] as number) ?? 0,
|
|
143
146
|
escalation_artifact_path: (row["escalation_artifact_path"] as string) ?? null,
|
|
144
147
|
escalation_override_applied_at: (row["escalation_override_applied_at"] as string) ?? null,
|
|
148
|
+
target_repositories: parseTaskArrayColumn(row["target_repositories"]),
|
|
145
149
|
};
|
|
146
150
|
}
|
|
@@ -5,9 +5,10 @@ import { findMilestoneIds } from "./guided-flow.js";
|
|
|
5
5
|
import { parseUnitId } from "./unit-id.js";
|
|
6
6
|
import { isDbAvailable, getMilestoneSlices, getMilestone } from "./gsd-db.js";
|
|
7
7
|
import { parseRoadmap } from "./parsers-legacy.js";
|
|
8
|
-
import { isClosedStatus } from "./status-guards.js";
|
|
8
|
+
import { isClosedStatus, isSkippedForDispatch } from "./status-guards.js";
|
|
9
9
|
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
10
10
|
import { readFileSync } from "node:fs";
|
|
11
|
+
import type { LoopState } from "./auto/types.js";
|
|
11
12
|
|
|
12
13
|
const SLICE_DISPATCH_TYPES = new Set([
|
|
13
14
|
"research-slice",
|
|
@@ -17,6 +18,63 @@ const SLICE_DISPATCH_TYPES = new Set([
|
|
|
17
18
|
"complete-slice",
|
|
18
19
|
]);
|
|
19
20
|
|
|
21
|
+
const CONSECUTIVE_SAME_UNIT_CAP_TYPES = new Set([
|
|
22
|
+
"complete-milestone",
|
|
23
|
+
"validate-milestone",
|
|
24
|
+
"research-slice",
|
|
25
|
+
]);
|
|
26
|
+
const CONSECUTIVE_SAME_UNIT_CAP = 2;
|
|
27
|
+
|
|
28
|
+
type ConsecutiveDispatchState = Pick<
|
|
29
|
+
LoopState,
|
|
30
|
+
"consecutiveDispatchCount" | "lastDispatchedKey" | "lastDispatchPhase"
|
|
31
|
+
>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Prevent repeated dispatches of the same unit within the same phase.
|
|
35
|
+
*
|
|
36
|
+
* Applies only to unit types in `CONSECUTIVE_SAME_UNIT_CAP_TYPES`. The first
|
|
37
|
+
* dispatch for a unit/phase pair starts a counter, unit or phase changes reset
|
|
38
|
+
* tracking, and dispatch is blocked once the counter reaches
|
|
39
|
+
* `CONSECUTIVE_SAME_UNIT_CAP`.
|
|
40
|
+
*
|
|
41
|
+
* Side effects: mutates `state.consecutiveDispatchCount`,
|
|
42
|
+
* `state.lastDispatchedKey`, and `state.lastDispatchPhase`.
|
|
43
|
+
*
|
|
44
|
+
* Returns `null` when dispatch is allowed, or a blocker message (including
|
|
45
|
+
* guidance to run `/gsd resume`) when the cap is reached.
|
|
46
|
+
*/
|
|
47
|
+
export function getConsecutiveDispatchBlocker(
|
|
48
|
+
state: ConsecutiveDispatchState,
|
|
49
|
+
phase: string,
|
|
50
|
+
unitType: string,
|
|
51
|
+
unitId: string,
|
|
52
|
+
): string | null {
|
|
53
|
+
if (!CONSECUTIVE_SAME_UNIT_CAP_TYPES.has(unitType)) return null;
|
|
54
|
+
if (!state.consecutiveDispatchCount) state.consecutiveDispatchCount = new Map<string, number>();
|
|
55
|
+
|
|
56
|
+
const key = `${unitType}:${unitId}`;
|
|
57
|
+
const phaseChanged = state.lastDispatchPhase !== phase;
|
|
58
|
+
const switchedUnit = state.lastDispatchedKey !== key;
|
|
59
|
+
if (phaseChanged || switchedUnit) {
|
|
60
|
+
state.consecutiveDispatchCount.clear();
|
|
61
|
+
state.consecutiveDispatchCount.set(key, 1);
|
|
62
|
+
state.lastDispatchedKey = key;
|
|
63
|
+
state.lastDispatchPhase = phase;
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const count = state.consecutiveDispatchCount.get(key) ?? 0;
|
|
68
|
+
if (count >= CONSECUTIVE_SAME_UNIT_CAP) {
|
|
69
|
+
return `Cannot dispatch ${unitType} ${unitId}: dispatched ${count} consecutive times; same-unit repeat cap reached. Resolve via /gsd resume.`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
state.consecutiveDispatchCount.set(key, count + 1);
|
|
73
|
+
state.lastDispatchedKey = key;
|
|
74
|
+
state.lastDispatchPhase = phase;
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
20
78
|
export function getPriorSliceCompletionBlocker(
|
|
21
79
|
base: string,
|
|
22
80
|
_mainBranch: string,
|
|
@@ -58,7 +116,7 @@ export function getPriorSliceCompletionBlocker(
|
|
|
58
116
|
// DB-backed projects must not treat SUMMARY.md as authoritative.
|
|
59
117
|
if (isDbAvailable()) {
|
|
60
118
|
const milestoneRow = getMilestone(mid);
|
|
61
|
-
if (milestoneRow &&
|
|
119
|
+
if (milestoneRow && isSkippedForDispatch(milestoneRow.status)) continue;
|
|
62
120
|
} else {
|
|
63
121
|
const summaryPath = resolveMilestoneFile(base, mid, "SUMMARY");
|
|
64
122
|
let summaryContent: string | null = null;
|
|
@@ -147,6 +147,14 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|
|
147
147
|
|
|
148
148
|
- `unique_milestone_ids`: boolean — when `true`, generates milestone IDs in `M{seq}-{rand6}` format (e.g. `M001-eh88as`) instead of plain sequential `M001`. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existing `M001`-style milestones remain valid. Default: `false`.
|
|
149
149
|
|
|
150
|
+
- `workspace`: optional parent-workspace repository registry. Keys:
|
|
151
|
+
- `mode`: `"project"` or `"parent"` — registry mode for repository lookup. Default: `"project"`.
|
|
152
|
+
- `repositories`: object keyed by repository id. A default `"project"` repository pointing at the project root is always available, even when not listed here (and can be overridden by explicitly defining `"project"`). Each repository supports:
|
|
153
|
+
- `path`: string — repository root path relative to project root.
|
|
154
|
+
- `role`: string — optional human label for prompts/reporting.
|
|
155
|
+
- `verification`: string[] — optional default verification commands.
|
|
156
|
+
- `commit_policy`: `"auto"` or `"skip"` — optional turn-commit policy for auto-mode commit actions. Defaults to `"auto"` when omitted. `"skip"` suppresses commit execution for that target repo.
|
|
157
|
+
|
|
150
158
|
- `budget_ceiling`: number — maximum dollar amount to spend on auto-mode. When reached, behavior is controlled by `budget_enforcement`. Default: no limit.
|
|
151
159
|
|
|
152
160
|
- `budget_enforcement`: `"warn"`, `"pause"`, or `"halt"` — action taken when `budget_ceiling` is reached.
|
|
@@ -9,7 +9,7 @@ import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
|
|
|
9
9
|
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
10
10
|
import { resolveMilestoneFile } from "./paths.js";
|
|
11
11
|
import { deriveState, isMilestoneComplete } from "./state.js";
|
|
12
|
-
import { listWorktrees, resolveGitDir, worktreesDir } from "./worktree-manager.js";
|
|
12
|
+
import { createWorktree, listWorktrees, resolveGitDir, worktreesDir } from "./worktree-manager.js";
|
|
13
13
|
import { abortAndReset } from "./git-self-heal.js";
|
|
14
14
|
import { RUNTIME_EXCLUSION_PATHS, resolveMilestoneIntegrationBranch, writeIntegrationBranch } from "./git-service.js";
|
|
15
15
|
import { nativeIsRepo, nativeWorktreeList, nativeWorktreeRemove, nativeBranchList, nativeBranchDelete, nativeLsFiles, nativeRmCached, nativeHasChanges, nativeLastCommitEpoch, nativeGetCurrentBranch, nativeAddTracked, nativeCommit } from "./native-git-bridge.js";
|
|
@@ -54,6 +54,19 @@ function isSameOrNestedPath(candidate: string, container: string): boolean {
|
|
|
54
54
|
normalizedCandidate.startsWith(`${normalizedContainer}/`);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function hasProjectContentOnDisk(dirPath: string): boolean {
|
|
58
|
+
try {
|
|
59
|
+
for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
|
|
60
|
+
if (entry.name === ".git" || entry.name === ".gsd") continue;
|
|
61
|
+
if (entry.name === ".DS_Store") continue;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
function getSnapshotDiffCheckFailure(basePath: string): string | null {
|
|
58
71
|
const failures: string[] = [];
|
|
59
72
|
|
|
@@ -123,6 +136,37 @@ export async function checkGitHealth(
|
|
|
123
136
|
? await isCompletedMilestoneTerminal(basePath, milestoneId)
|
|
124
137
|
: false;
|
|
125
138
|
|
|
139
|
+
if (!isComplete && !hasProjectContentOnDisk(wt.path) && hasProjectContentOnDisk(basePath)) {
|
|
140
|
+
issues.push({
|
|
141
|
+
severity: "error",
|
|
142
|
+
code: "worktree_empty_with_project_content",
|
|
143
|
+
scope: "milestone",
|
|
144
|
+
unitId: milestoneId,
|
|
145
|
+
message: `Worktree ${wt.path} has no project content, but project root ${basePath} does. Run doctor --fix to recreate the worktree.`,
|
|
146
|
+
fixable: true,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (shouldFix("worktree_empty_with_project_content")) {
|
|
150
|
+
try {
|
|
151
|
+
nativeWorktreeRemove(basePath, wt.path, true);
|
|
152
|
+
const recreated = createWorktree(basePath, milestoneId, {
|
|
153
|
+
branch: wt.branch,
|
|
154
|
+
reuseExistingBranch: true,
|
|
155
|
+
});
|
|
156
|
+
const reset = spawnSync("git", ["reset", "--hard"], {
|
|
157
|
+
cwd: recreated.path,
|
|
158
|
+
encoding: "utf-8",
|
|
159
|
+
});
|
|
160
|
+
if (reset.status !== 0) {
|
|
161
|
+
throw new Error(reset.stderr || reset.error?.message || "git reset --hard failed");
|
|
162
|
+
}
|
|
163
|
+
fixesApplied.push(`recreated empty worktree ${wt.path}`);
|
|
164
|
+
} catch {
|
|
165
|
+
fixesApplied.push(`failed to recreate empty worktree ${wt.path}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
126
170
|
if (isComplete) {
|
|
127
171
|
issues.push({
|
|
128
172
|
severity: "warning",
|
|
@@ -7,7 +7,7 @@ import { milestonesDir, gsdRoot, resolveGsdRootFile } from "./paths.js";
|
|
|
7
7
|
import { deriveState, isGhostMilestone, isReusableGhostMilestone } from "./state.js";
|
|
8
8
|
import { saveFile } from "./files.js";
|
|
9
9
|
import { nativeIsRepo, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
|
|
10
|
-
import { readCrashLock, isLockProcessAlive,
|
|
10
|
+
import { readCrashLock, isLockProcessAlive, clearStaleWorkerLock } from "./crash-recovery.js";
|
|
11
11
|
import { getActiveAutoWorkers } from "./db/auto-workers.js";
|
|
12
12
|
import { normalizeRealPath } from "./paths.js";
|
|
13
13
|
import { ensureGitignore, isGsdGitignored } from "./gitignore.js";
|
|
@@ -56,7 +56,7 @@ export async function checkRuntimeHealth(
|
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
if (shouldFix("stale_crash_lock")) {
|
|
59
|
-
|
|
59
|
+
clearStaleWorkerLock(basePath);
|
|
60
60
|
fixesApplied.push("cleared stale auto-mode worker state");
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -80,17 +80,29 @@ export async function checkRuntimeHealth(
|
|
|
80
80
|
// heartbeat for this project?" — readCrashLock returns null for
|
|
81
81
|
// healthy live workers (it surfaces stale ones only), so we must
|
|
82
82
|
// consult getActiveAutoWorkers directly.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
83
|
+
let lockHolderAlive = false;
|
|
84
|
+
try {
|
|
85
|
+
const projectRoot = normalizeRealPath(basePath);
|
|
86
|
+
for (const worker of getActiveAutoWorkers()) {
|
|
87
|
+
if (worker.project_root_realpath !== projectRoot) continue;
|
|
88
|
+
try {
|
|
89
|
+
if (isLockProcessAlive({
|
|
90
|
+
pid: worker.pid,
|
|
91
|
+
startedAt: worker.started_at,
|
|
92
|
+
unitType: "starting",
|
|
93
|
+
unitId: "bootstrap",
|
|
94
|
+
unitStartedAt: worker.started_at,
|
|
95
|
+
})) {
|
|
96
|
+
lockHolderAlive = true;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
// Ignore malformed worker rows or transient PID probe failures.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
// If worker lookup fails, continue with the stranded lock diagnosis.
|
|
105
|
+
}
|
|
94
106
|
if (!lockHolderAlive) {
|
|
95
107
|
issues.push({
|
|
96
108
|
severity: "error",
|
|
@@ -51,6 +51,7 @@ export type DoctorIssueCode =
|
|
|
51
51
|
// Git / worktree integrity checks
|
|
52
52
|
| "integration_branch_missing"
|
|
53
53
|
| "worktree_directory_orphaned"
|
|
54
|
+
| "worktree_empty_with_project_content"
|
|
54
55
|
// GSD state structural checks
|
|
55
56
|
| "circular_slice_dependency"
|
|
56
57
|
| "orphaned_slice_directory"
|
|
@@ -16,6 +16,7 @@ import type { RoadmapSliceEntry } from "./types.js";
|
|
|
16
16
|
import { checkGitHealth, checkRuntimeHealth, checkGlobalHealth, checkEngineHealth } from "./doctor-checks.js";
|
|
17
17
|
import { checkEnvironmentHealth } from "./doctor-environment.js";
|
|
18
18
|
import { runProviderChecks } from "./doctor-providers.js";
|
|
19
|
+
import { validateTitle } from "./validation.js";
|
|
19
20
|
|
|
20
21
|
// ── Re-exports ─────────────────────────────────────────────────────────────
|
|
21
22
|
// All public types and functions from extracted modules are re-exported here
|
|
@@ -25,33 +26,7 @@ export { summarizeDoctorIssues, filterDoctorIssues, formatDoctorReport, formatDo
|
|
|
25
26
|
export { runEnvironmentChecks, runFullEnvironmentChecks, formatEnvironmentReport, type EnvironmentCheckResult } from "./doctor-environment.js";
|
|
26
27
|
export { computeProgressScore, computeProgressScoreWithContext, formatProgressLine, formatProgressReport, type ProgressScore, type ProgressLevel } from "./progress-score.js";
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
* Characters that are used as delimiters in GSD state management documents
|
|
30
|
-
* and should not appear in milestone or slice titles.
|
|
31
|
-
*
|
|
32
|
-
* - "\u2014" (em dash, U+2014): used as a display separator in STATE.md and other docs.
|
|
33
|
-
* A title containing "\u2014" makes the separator ambiguous, corrupting state display
|
|
34
|
-
* and confusing the LLM agent that reads and writes these files.
|
|
35
|
-
* - "\u2013" (en dash, U+2013): visually similar to em dash; same ambiguity risk.
|
|
36
|
-
* - "/" (forward slash, U+002F): used as the path separator in unit IDs (M001/S01)
|
|
37
|
-
* and git branch names (gsd/M001/S01). A slash in a title can break path resolution.
|
|
38
|
-
*/
|
|
39
|
-
const TITLE_DELIMITER_RE = /[\u2014\u2013\/]/; // em dash, en dash, forward slash
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Check whether a milestone or slice title contains characters that conflict
|
|
43
|
-
* with GSD's state document delimiter conventions.
|
|
44
|
-
* Returns a human-readable description of the problem, or null if the title is safe.
|
|
45
|
-
*/
|
|
46
|
-
export function validateTitle(title: string): string | null {
|
|
47
|
-
if (TITLE_DELIMITER_RE.test(title)) {
|
|
48
|
-
const found: string[] = [];
|
|
49
|
-
if (/[\u2014\u2013]/.test(title)) found.push("em/en dash (\u2014 or \u2013)");
|
|
50
|
-
if (/\//.test(title)) found.push("forward slash (/)");
|
|
51
|
-
return `title contains ${found.join(" and ")}, which conflict with GSD state document delimiters`;
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
29
|
+
export { validateTitle } from "./validation.js";
|
|
55
30
|
|
|
56
31
|
function validatePreferenceShape(preferences: GSDPreferences): string[] {
|
|
57
32
|
const issues: string[] = [];
|