gsd-pi 2.82.0 → 3.0.0
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 +51 -32
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +19 -6
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +90 -31
- package/dist/resources/extensions/gsd/auto/session.js +4 -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 +246 -133
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- 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 +178 -63
- 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 +9 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +17 -3
- 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 +39 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- 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/context-store.js +112 -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-writer.js +150 -84
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +87 -7
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/forensics.js +3 -3
- package/dist/resources/extensions/gsd/git-service.js +45 -3
- package/dist/resources/extensions/gsd/gsd-db.js +21 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +101 -116
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +16 -9
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/paths.js +4 -0
- 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/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/state.js +3 -3
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -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 +87 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-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/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/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/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-b23b3f6858dc6dc8.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 +6 -5
- 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 +14 -3
- 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-parity.test.ts +244 -0
- 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-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +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/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- 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/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +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/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- 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/sdk.ts +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +30 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +29 -10
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- 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/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +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/src/tui.ts +6 -0
- 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/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +22 -6
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +104 -38
- package/src/resources/extensions/gsd/auto/session.ts +4 -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 +279 -144
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- 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 +187 -61
- 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 +10 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +20 -4
- 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 +42 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- 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/context-store.ts +120 -1
- 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-writer.ts +167 -84
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +89 -7
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +3 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/forensics.ts +3 -3
- package/src/resources/extensions/gsd/git-service.ts +51 -4
- package/src/resources/extensions/gsd/gsd-db.ts +21 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +134 -133
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +16 -9
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/paths.ts +5 -0
- 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/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/state.ts +3 -3
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -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 +131 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +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 +91 -6
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-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/browser-tools-compatibility-declarations.test.ts +62 -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/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/context-store-decisions-from-memories.test.ts +312 -0
- 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-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -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/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- 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/integration/doctor-git.test.ts +44 -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/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/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-sketch-render.test.ts +157 -0
- 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 +251 -2
- 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/post-unit-state-rebuild.test.ts +84 -0
- 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-contracts.test.ts +8 -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/provider-switch-observer.test.ts +252 -0
- 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/run-uat-replay-cap.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- 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-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 +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 +103 -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-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/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 +97 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -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/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/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/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-9ecfd95f343793f0.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/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { clearParseCache } from "../files.js";
|
|
2
2
|
import { isClosedStatus } from "../status-guards.js";
|
|
3
|
-
import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
3
|
+
import { isNonEmptyString, validateStringArray, validateTitle } from "../validation.js";
|
|
4
4
|
import {
|
|
5
5
|
transaction,
|
|
6
6
|
getMilestone,
|
|
@@ -148,6 +148,8 @@ function validateSlices(value: unknown): PlanMilestoneSliceInput[] {
|
|
|
148
148
|
if (seen.has(sliceId)) throw new Error(`slices[${index}].sliceId must be unique`);
|
|
149
149
|
seen.add(sliceId);
|
|
150
150
|
if (!isNonEmptyString(title)) throw new Error(`slices[${index}].title must be a non-empty string`);
|
|
151
|
+
const titleIssue = validateTitle(title);
|
|
152
|
+
if (titleIssue) throw new Error(`slices[${index}].title is invalid: ${titleIssue}`);
|
|
151
153
|
if (!isNonEmptyString(risk)) throw new Error(`slices[${index}].risk must be a non-empty string`);
|
|
152
154
|
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item))) {
|
|
153
155
|
throw new Error(`slices[${index}].depends must be an array of non-empty strings`);
|
|
@@ -190,6 +192,8 @@ function validateParams(params: PlanMilestoneParams): PlanMilestoneParams {
|
|
|
190
192
|
if (!isNonEmptyString(params?.milestoneId)) throw new Error("milestoneId is required");
|
|
191
193
|
if (!isNonEmptyString(params?.title)) throw new Error("title is required");
|
|
192
194
|
if (!isNonEmptyString(params?.vision)) throw new Error("vision is required");
|
|
195
|
+
const milestoneTitleIssue = validateTitle(params.title);
|
|
196
|
+
if (milestoneTitleIssue) throw new Error(`title is invalid: ${milestoneTitleIssue}`);
|
|
193
197
|
|
|
194
198
|
return {
|
|
195
199
|
...params,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync, rmSync } from "node:fs";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
1
3
|
import { clearParseCache } from "../files.js";
|
|
2
4
|
import { isClosedStatus, isDeferredStatus } from "../status-guards.js";
|
|
3
5
|
import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
@@ -5,11 +7,15 @@ import {
|
|
|
5
7
|
transaction,
|
|
6
8
|
getMilestone,
|
|
7
9
|
getSlice,
|
|
10
|
+
getSliceTasks,
|
|
8
11
|
insertTask,
|
|
9
12
|
upsertSlicePlanning,
|
|
10
13
|
upsertTaskPlanning,
|
|
11
14
|
insertGateRow,
|
|
12
15
|
updateSliceStatus,
|
|
16
|
+
setSliceSketchFlag,
|
|
17
|
+
deleteTask,
|
|
18
|
+
deleteArtifactByPath,
|
|
13
19
|
} from "../gsd-db.js";
|
|
14
20
|
import type { GateId } from "../types.js";
|
|
15
21
|
import { invalidateStateCache } from "../state.js";
|
|
@@ -19,6 +25,9 @@ import { writeManifest } from "../workflow-manifest.js";
|
|
|
19
25
|
import { appendEvent } from "../workflow-events.js";
|
|
20
26
|
import { logWarning } from "../workflow-logger.js";
|
|
21
27
|
import { validatePlanningPathScope } from "../planning-path-scope.js";
|
|
28
|
+
import { checkFilePathConsistency, checkTaskOrdering } from "../pre-execution-checks.js";
|
|
29
|
+
import type { TaskRow } from "../db-task-slice-rows.js";
|
|
30
|
+
import { buildTaskFileName, gsdProjectionRoot } from "../paths.js";
|
|
22
31
|
|
|
23
32
|
export interface PlanSliceTaskInput {
|
|
24
33
|
taskId: string;
|
|
@@ -86,16 +95,10 @@ function validateTasks(value: unknown): PlanSliceTaskInput[] {
|
|
|
86
95
|
if (!isNonEmptyString(title)) throw new Error(`tasks[${index}].title must be a non-empty string`);
|
|
87
96
|
if (!isNonEmptyString(description)) throw new Error(`tasks[${index}].description must be a non-empty string`);
|
|
88
97
|
if (!isNonEmptyString(estimate)) throw new Error(`tasks[${index}].estimate must be a non-empty string`);
|
|
89
|
-
|
|
90
|
-
throw new Error(`tasks[${index}].files must be an array of non-empty strings`);
|
|
91
|
-
}
|
|
98
|
+
const validatedFiles = validateStringArray(files, `tasks[${index}].files`);
|
|
92
99
|
if (!isNonEmptyString(verify)) throw new Error(`tasks[${index}].verify must be a non-empty string`);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
if (!Array.isArray(expectedOutput) || expectedOutput.some((item) => !isNonEmptyString(item))) {
|
|
97
|
-
throw new Error(`tasks[${index}].expectedOutput must be an array of non-empty strings`);
|
|
98
|
-
}
|
|
100
|
+
const validatedInputs = validateStringArray(inputs, `tasks[${index}].inputs`);
|
|
101
|
+
const validatedExpectedOutput = validateStringArray(expectedOutput, `tasks[${index}].expectedOutput`);
|
|
99
102
|
if (observabilityImpact !== undefined && !isNonEmptyString(observabilityImpact)) {
|
|
100
103
|
throw new Error(`tasks[${index}].observabilityImpact must be a non-empty string when provided`);
|
|
101
104
|
}
|
|
@@ -105,10 +108,10 @@ function validateTasks(value: unknown): PlanSliceTaskInput[] {
|
|
|
105
108
|
title,
|
|
106
109
|
description,
|
|
107
110
|
estimate,
|
|
108
|
-
files,
|
|
111
|
+
files: validatedFiles,
|
|
109
112
|
verify,
|
|
110
|
-
inputs,
|
|
111
|
-
expectedOutput,
|
|
113
|
+
inputs: validatedInputs,
|
|
114
|
+
expectedOutput: validatedExpectedOutput,
|
|
112
115
|
observabilityImpact: typeof observabilityImpact === "string" ? observabilityImpact : "",
|
|
113
116
|
};
|
|
114
117
|
});
|
|
@@ -131,6 +134,56 @@ function validateParams(params: PlanSliceParams): PlanSliceParams {
|
|
|
131
134
|
};
|
|
132
135
|
}
|
|
133
136
|
|
|
137
|
+
function toTaskRows(params: PlanSliceParams): TaskRow[] {
|
|
138
|
+
return params.tasks.map((task, index) => ({
|
|
139
|
+
milestone_id: params.milestoneId,
|
|
140
|
+
slice_id: params.sliceId,
|
|
141
|
+
id: task.taskId,
|
|
142
|
+
title: task.title,
|
|
143
|
+
status: "pending",
|
|
144
|
+
one_liner: "",
|
|
145
|
+
narrative: "",
|
|
146
|
+
verification_result: "",
|
|
147
|
+
duration: "",
|
|
148
|
+
completed_at: null,
|
|
149
|
+
blocker_discovered: false,
|
|
150
|
+
deviations: "",
|
|
151
|
+
known_issues: "",
|
|
152
|
+
key_files: [],
|
|
153
|
+
key_decisions: [],
|
|
154
|
+
full_summary_md: "",
|
|
155
|
+
description: task.description,
|
|
156
|
+
estimate: task.estimate,
|
|
157
|
+
files: task.files,
|
|
158
|
+
verify: task.verify,
|
|
159
|
+
inputs: task.inputs,
|
|
160
|
+
expected_output: task.expectedOutput,
|
|
161
|
+
observability_impact: task.observabilityImpact ?? "",
|
|
162
|
+
full_plan_md: task.fullPlanMd ?? "",
|
|
163
|
+
sequence: index + 1,
|
|
164
|
+
blocker_source: "",
|
|
165
|
+
escalation_pending: 0,
|
|
166
|
+
escalation_awaiting_review: 0,
|
|
167
|
+
escalation_artifact_path: null,
|
|
168
|
+
escalation_override_applied_at: null,
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function validateTaskPathsBeforePersist(params: PlanSliceParams, basePath: string): string | null {
|
|
173
|
+
const taskRows = toTaskRows(params);
|
|
174
|
+
const checks = [
|
|
175
|
+
...checkFilePathConsistency(taskRows, basePath),
|
|
176
|
+
...checkTaskOrdering(taskRows, basePath),
|
|
177
|
+
];
|
|
178
|
+
const blocking = checks.filter((check) => !check.passed && check.blocking);
|
|
179
|
+
|
|
180
|
+
if (blocking.length === 0) return null;
|
|
181
|
+
|
|
182
|
+
return blocking
|
|
183
|
+
.map((check) => `[${check.category}] ${check.target}: ${check.message}`)
|
|
184
|
+
.join("\n");
|
|
185
|
+
}
|
|
186
|
+
|
|
134
187
|
export async function handlePlanSlice(
|
|
135
188
|
rawParams: PlanSliceParams,
|
|
136
189
|
basePath: string,
|
|
@@ -154,10 +207,16 @@ export async function handlePlanSlice(
|
|
|
154
207
|
return { error: `validation failed: ${pathScopeError}` };
|
|
155
208
|
}
|
|
156
209
|
|
|
210
|
+
const pathError = validateTaskPathsBeforePersist(params, basePath);
|
|
211
|
+
if (pathError) {
|
|
212
|
+
return { error: `pre-execution validation failed:\n${pathError}` };
|
|
213
|
+
}
|
|
214
|
+
|
|
157
215
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
158
216
|
// Guards must be inside the transaction so the state they check cannot
|
|
159
217
|
// change between the read and the write (#2723).
|
|
160
218
|
let guardError: string | null = null;
|
|
219
|
+
let omittedTaskIds: string[] = [];
|
|
161
220
|
|
|
162
221
|
try {
|
|
163
222
|
transaction(() => {
|
|
@@ -181,9 +240,23 @@ export async function handlePlanSlice(
|
|
|
181
240
|
return;
|
|
182
241
|
}
|
|
183
242
|
|
|
243
|
+
const newTaskIds = new Set(params.tasks.map((task) => task.taskId));
|
|
244
|
+
const existingTasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
245
|
+
omittedTaskIds = existingTasks
|
|
246
|
+
.filter((task) => !newTaskIds.has(task.id))
|
|
247
|
+
.map((task) => task.id);
|
|
248
|
+
|
|
249
|
+
for (const task of existingTasks) {
|
|
250
|
+
if (!newTaskIds.has(task.id) && isClosedStatus(task.status)) {
|
|
251
|
+
guardError = `cannot remove completed task ${task.id}`;
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
184
256
|
if (isDeferredStatus(parentSlice.status)) {
|
|
185
257
|
updateSliceStatus(params.milestoneId, params.sliceId, "pending");
|
|
186
258
|
}
|
|
259
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
187
260
|
|
|
188
261
|
upsertSlicePlanning(params.milestoneId, params.sliceId, {
|
|
189
262
|
goal: params.goal,
|
|
@@ -193,6 +266,10 @@ export async function handlePlanSlice(
|
|
|
193
266
|
observabilityImpact: params.observabilityImpact,
|
|
194
267
|
});
|
|
195
268
|
|
|
269
|
+
for (const taskId of omittedTaskIds) {
|
|
270
|
+
deleteTask(params.milestoneId, params.sliceId, taskId);
|
|
271
|
+
}
|
|
272
|
+
|
|
196
273
|
for (const task of params.tasks) {
|
|
197
274
|
insertTask({
|
|
198
275
|
id: task.taskId,
|
|
@@ -237,6 +314,14 @@ export async function handlePlanSlice(
|
|
|
237
314
|
}
|
|
238
315
|
|
|
239
316
|
try {
|
|
317
|
+
const tasksDir = join(gsdProjectionRoot(basePath), "milestones", params.milestoneId, "slices", params.sliceId, "tasks");
|
|
318
|
+
for (const taskId of omittedTaskIds) {
|
|
319
|
+
const taskPlanPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
320
|
+
if (existsSync(taskPlanPath)) rmSync(taskPlanPath, { force: true });
|
|
321
|
+
const artifactPath = relative(gsdProjectionRoot(basePath), taskPlanPath).replace(/\\/g, "/");
|
|
322
|
+
deleteArtifactByPath(artifactPath);
|
|
323
|
+
}
|
|
324
|
+
|
|
240
325
|
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
241
326
|
invalidateStateCache();
|
|
242
327
|
clearParseCache();
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Adapts shared GSD workflow handlers for MCP executor calls.
|
|
3
|
+
|
|
1
4
|
import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
|
|
2
5
|
import { sanitizeCompleteMilestoneParams } from "../bootstrap/sanitize-complete-milestone.js";
|
|
3
6
|
import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, shouldBlockRootArtifactSaveInSnapshot } from "../bootstrap/write-gate.js";
|
|
@@ -25,6 +28,12 @@ import type { PlanSliceParams } from "./plan-slice.js";
|
|
|
25
28
|
import { handlePlanSlice } from "./plan-slice.js";
|
|
26
29
|
import type { ReplanSliceParams } from "./replan-slice.js";
|
|
27
30
|
import { handleReplanSlice } from "./replan-slice.js";
|
|
31
|
+
import type { ReopenMilestoneParams } from "./reopen-milestone.js";
|
|
32
|
+
import { handleReopenMilestone } from "./reopen-milestone.js";
|
|
33
|
+
import type { ReopenSliceParams } from "./reopen-slice.js";
|
|
34
|
+
import { handleReopenSlice } from "./reopen-slice.js";
|
|
35
|
+
import type { ReopenTaskParams } from "./reopen-task.js";
|
|
36
|
+
import { handleReopenTask } from "./reopen-task.js";
|
|
28
37
|
import type { ReassessRoadmapParams } from "./reassess-roadmap.js";
|
|
29
38
|
import { handleReassessRoadmap } from "./reassess-roadmap.js";
|
|
30
39
|
import type { ValidateMilestoneParams } from "./validate-milestone.js";
|
|
@@ -311,6 +320,9 @@ export type SliceCompleteExecutorParams = CompleteSliceParams;
|
|
|
311
320
|
export type PlanMilestoneExecutorParams = PlanMilestoneParams;
|
|
312
321
|
export type PlanSliceExecutorParams = PlanSliceParams;
|
|
313
322
|
export type ReplanSliceExecutorParams = ReplanSliceParams;
|
|
323
|
+
export type ReopenTaskExecutorParams = ReopenTaskParams;
|
|
324
|
+
export type ReopenSliceExecutorParams = ReopenSliceParams;
|
|
325
|
+
export type ReopenMilestoneExecutorParams = ReopenMilestoneParams;
|
|
314
326
|
export type ValidateMilestoneExecutorParams = ValidateMilestoneParams;
|
|
315
327
|
export type ReassessRoadmapExecutorParams = ReassessRoadmapParams;
|
|
316
328
|
|
|
@@ -371,6 +383,129 @@ export async function executeTaskComplete(
|
|
|
371
383
|
}
|
|
372
384
|
}
|
|
373
385
|
|
|
386
|
+
export async function executeTaskReopen(
|
|
387
|
+
params: ReopenTaskExecutorParams,
|
|
388
|
+
basePath: string = process.cwd(),
|
|
389
|
+
): Promise<ToolExecutionResult> {
|
|
390
|
+
const dbAvailable = await ensureDbOpen(basePath);
|
|
391
|
+
if (!dbAvailable) {
|
|
392
|
+
return {
|
|
393
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot reopen task." }],
|
|
394
|
+
details: { operation: "reopen_task", error: "db_unavailable" },
|
|
395
|
+
isError: true,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
const result = await handleReopenTask(params, basePath);
|
|
400
|
+
if ("error" in result) {
|
|
401
|
+
return {
|
|
402
|
+
content: [{ type: "text", text: `Error reopening task: ${result.error}` }],
|
|
403
|
+
details: { operation: "reopen_task", error: result.error },
|
|
404
|
+
isError: true,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
content: [{ type: "text", text: `Reopened task ${result.taskId} (${result.sliceId}/${result.milestoneId})` }],
|
|
409
|
+
details: {
|
|
410
|
+
operation: "reopen_task",
|
|
411
|
+
taskId: result.taskId,
|
|
412
|
+
sliceId: result.sliceId,
|
|
413
|
+
milestoneId: result.milestoneId,
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
} catch (err) {
|
|
417
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
418
|
+
logError("tool", `reopen_task tool failed: ${msg}`, { tool: "gsd_task_reopen", error: String(err) });
|
|
419
|
+
return {
|
|
420
|
+
content: [{ type: "text", text: `Error reopening task: ${msg}` }],
|
|
421
|
+
details: { operation: "reopen_task", error: msg },
|
|
422
|
+
isError: true,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export async function executeSliceReopen(
|
|
428
|
+
params: ReopenSliceExecutorParams,
|
|
429
|
+
basePath: string = process.cwd(),
|
|
430
|
+
): Promise<ToolExecutionResult> {
|
|
431
|
+
const dbAvailable = await ensureDbOpen(basePath);
|
|
432
|
+
if (!dbAvailable) {
|
|
433
|
+
return {
|
|
434
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot reopen slice." }],
|
|
435
|
+
details: { operation: "reopen_slice", error: "db_unavailable" },
|
|
436
|
+
isError: true,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
const result = await handleReopenSlice(params, basePath);
|
|
441
|
+
if ("error" in result) {
|
|
442
|
+
return {
|
|
443
|
+
content: [{ type: "text", text: `Error reopening slice: ${result.error}` }],
|
|
444
|
+
details: { operation: "reopen_slice", error: result.error },
|
|
445
|
+
isError: true,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
content: [{ type: "text", text: `Reopened slice ${result.sliceId} (${result.milestoneId})` }],
|
|
450
|
+
details: {
|
|
451
|
+
operation: "reopen_slice",
|
|
452
|
+
sliceId: result.sliceId,
|
|
453
|
+
milestoneId: result.milestoneId,
|
|
454
|
+
tasksReset: result.tasksReset,
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
} catch (err) {
|
|
458
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
459
|
+
logError("tool", `reopen_slice tool failed: ${msg}`, { tool: "gsd_slice_reopen", error: String(err) });
|
|
460
|
+
return {
|
|
461
|
+
content: [{ type: "text", text: `Error reopening slice: ${msg}` }],
|
|
462
|
+
details: { operation: "reopen_slice", error: msg },
|
|
463
|
+
isError: true,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export async function executeMilestoneReopen(
|
|
469
|
+
params: ReopenMilestoneExecutorParams,
|
|
470
|
+
basePath: string = process.cwd(),
|
|
471
|
+
): Promise<ToolExecutionResult> {
|
|
472
|
+
const dbAvailable = await ensureDbOpen(basePath);
|
|
473
|
+
if (!dbAvailable) {
|
|
474
|
+
return {
|
|
475
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot reopen milestone." }],
|
|
476
|
+
details: { operation: "reopen_milestone", error: "db_unavailable" },
|
|
477
|
+
isError: true,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
try {
|
|
481
|
+
const result = await handleReopenMilestone(params, basePath);
|
|
482
|
+
if ("error" in result) {
|
|
483
|
+
return {
|
|
484
|
+
content: [{ type: "text", text: `Error reopening milestone: ${result.error}` }],
|
|
485
|
+
details: { operation: "reopen_milestone", error: result.error },
|
|
486
|
+
isError: true,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
content: [{ type: "text", text: `Reopened milestone ${result.milestoneId}` }],
|
|
491
|
+
details: {
|
|
492
|
+
operation: "reopen_milestone",
|
|
493
|
+
milestoneId: result.milestoneId,
|
|
494
|
+
slicesReset: result.slicesReset,
|
|
495
|
+
tasksReset: result.tasksReset,
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
} catch (err) {
|
|
499
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
500
|
+
logError("tool", `reopen_milestone tool failed: ${msg}`, { tool: "gsd_milestone_reopen", error: String(err) });
|
|
501
|
+
return {
|
|
502
|
+
content: [{ type: "text", text: `Error reopening milestone: ${msg}` }],
|
|
503
|
+
details: { operation: "reopen_milestone", error: msg },
|
|
504
|
+
isError: true,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
374
509
|
export async function executeSliceComplete(
|
|
375
510
|
params: SliceCompleteExecutorParams,
|
|
376
511
|
basePath: string = process.cwd(),
|
|
@@ -106,7 +106,7 @@ export interface AuditWarning {
|
|
|
106
106
|
export interface VerificationResult {
|
|
107
107
|
passed: boolean; // true if all checks passed (or no checks discovered)
|
|
108
108
|
checks: VerificationCheck[]; // per-command results
|
|
109
|
-
discoverySource: "preference" | "task-plan" | "package-json" | "none";
|
|
109
|
+
discoverySource: "preference" | "task-plan" | "package-json" | "python-project" | "none";
|
|
110
110
|
timestamp: number; // Date.now() at gate start
|
|
111
111
|
runtimeErrors?: RuntimeError[]; // optional — populated by captureRuntimeErrors()
|
|
112
112
|
auditWarnings?: AuditWarning[]; // optional — populated by runDependencyAudit()
|
|
@@ -132,6 +132,9 @@ export type ContextModePolicy =
|
|
|
132
132
|
* the explicit `allowedPathGlobs` set; Bash safe-allowlist;
|
|
133
133
|
* no subagents. Reserved for rewrite-docs, which legitimately
|
|
134
134
|
* edits project markdown outside .gsd/.
|
|
135
|
+
* - "verification"
|
|
136
|
+
* — Read tools + Bash for verification commands, writes
|
|
137
|
+
* restricted to .gsd/**, no subagents.
|
|
135
138
|
*
|
|
136
139
|
* The allowlist for "docs" is declared per-manifest rather than hardcoded so
|
|
137
140
|
* projects with non-standard doc layouts can extend it without forking the
|
|
@@ -143,7 +146,8 @@ export type ToolsPolicy =
|
|
|
143
146
|
| { readonly mode: "read-only" }
|
|
144
147
|
| { readonly mode: "planning" }
|
|
145
148
|
| { readonly mode: "planning-dispatch"; readonly allowedSubagents: readonly string[] }
|
|
146
|
-
| { readonly mode: "docs"; readonly allowedPathGlobs: readonly string[] }
|
|
149
|
+
| { readonly mode: "docs"; readonly allowedPathGlobs: readonly string[] }
|
|
150
|
+
| { readonly mode: "verification" };
|
|
147
151
|
|
|
148
152
|
// ─── Computed-artifact registry (#4924 v2 contract) ───────────────────────
|
|
149
153
|
|
|
@@ -288,6 +292,7 @@ const COMMON_BUDGET_SMALL = 250_000; // ~65K tokens
|
|
|
288
292
|
|
|
289
293
|
const TOOLS_ALL: ToolsPolicy = { mode: "all" };
|
|
290
294
|
const TOOLS_PLANNING: ToolsPolicy = { mode: "planning" };
|
|
295
|
+
const TOOLS_VERIFICATION: ToolsPolicy = { mode: "verification" };
|
|
291
296
|
// Like TOOLS_PLANNING but permits dispatch to read-only recon/planning
|
|
292
297
|
// specialists. Runtime-enforced by write-gate.ts before the subagent tool runs.
|
|
293
298
|
const TOOLS_PLANNING_DISPATCH_RECON: ToolsPolicy = {
|
|
@@ -406,8 +411,8 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
406
411
|
contextMode: "verification",
|
|
407
412
|
// planning-dispatch: validation is a verification-fan-out unit. It reads
|
|
408
413
|
// the milestone surface and dispatches reviewer/security/tester subagents
|
|
409
|
-
// to report findings without touching user source.
|
|
410
|
-
//
|
|
414
|
+
// to report findings without touching user source. Write isolation to
|
|
415
|
+
// .gsd/ is preserved.
|
|
411
416
|
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
412
417
|
artifacts: {
|
|
413
418
|
inline: ["roadmap", "slice-summary", "slice-uat", "requirements", "decisions", "templates"],
|
|
@@ -423,11 +428,9 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
423
428
|
codebaseMap: false,
|
|
424
429
|
preferences: "active-only",
|
|
425
430
|
contextMode: "verification",
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
// preserved.
|
|
430
|
-
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
431
|
+
// Milestone closeout must run unrestricted shell verification commands
|
|
432
|
+
// against the final diff before recording completion.
|
|
433
|
+
tools: TOOLS_ALL,
|
|
431
434
|
artifacts: {
|
|
432
435
|
// #4780 landed slice-summary as excerpt for this unit; phase 2 of
|
|
433
436
|
// the architecture will read this manifest as the source of truth
|
|
@@ -447,7 +450,9 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
447
450
|
codebaseMap: true,
|
|
448
451
|
preferences: "active-only",
|
|
449
452
|
contextMode: "research",
|
|
450
|
-
|
|
453
|
+
// Multi-slice research dispatches use the research-slice unit contract to
|
|
454
|
+
// fan out scout subagents that write .gsd research artifacts.
|
|
455
|
+
tools: TOOLS_PLANNING_DISPATCH_RECON,
|
|
451
456
|
artifacts: {
|
|
452
457
|
inline: ["roadmap", "milestone-research", "dependency-summaries", "templates"],
|
|
453
458
|
excerpt: [],
|
|
@@ -587,7 +592,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
587
592
|
codebaseMap: false,
|
|
588
593
|
preferences: "active-only",
|
|
589
594
|
contextMode: "verification",
|
|
590
|
-
tools:
|
|
595
|
+
tools: TOOLS_VERIFICATION,
|
|
591
596
|
artifacts: {
|
|
592
597
|
// Phase 3 migration (#4782): manifest matches today's actual
|
|
593
598
|
// buildRunUatPrompt inlining. Prior phase-1 entry listed
|
|
@@ -606,7 +611,9 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
606
611
|
codebaseMap: false,
|
|
607
612
|
preferences: "active-only",
|
|
608
613
|
contextMode: "verification",
|
|
609
|
-
|
|
614
|
+
// Gate evaluation fans out tester-style subagents, which read the slice
|
|
615
|
+
// plan and report via the DB-backed gate-result tool.
|
|
616
|
+
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
610
617
|
artifacts: {
|
|
611
618
|
inline: ["slice-plan", "prior-task-summaries"],
|
|
612
619
|
excerpt: [],
|
|
@@ -734,3 +741,32 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
734
741
|
export function resolveManifest(unitType: string): UnitContextManifest | null {
|
|
735
742
|
return (UNIT_MANIFESTS as Record<string, UnitContextManifest>)[unitType] ?? null;
|
|
736
743
|
}
|
|
744
|
+
|
|
745
|
+
export interface SubagentPermissionContract {
|
|
746
|
+
readonly allowed: boolean;
|
|
747
|
+
readonly allowedSubagents: readonly string[];
|
|
748
|
+
readonly toolsMode: ToolsPolicy["mode"] | "unknown";
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
export function compileSubagentPermissionContract(
|
|
752
|
+
policy: ToolsPolicy | null | undefined,
|
|
753
|
+
): SubagentPermissionContract {
|
|
754
|
+
if (!policy) {
|
|
755
|
+
return { allowed: false, allowedSubagents: [], toolsMode: "unknown" };
|
|
756
|
+
}
|
|
757
|
+
if (policy.mode === "all") {
|
|
758
|
+
return { allowed: true, allowedSubagents: ["*"], toolsMode: policy.mode };
|
|
759
|
+
}
|
|
760
|
+
if (policy.mode === "planning-dispatch") {
|
|
761
|
+
return {
|
|
762
|
+
allowed: true,
|
|
763
|
+
allowedSubagents: [...policy.allowedSubagents],
|
|
764
|
+
toolsMode: policy.mode,
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
return { allowed: false, allowedSubagents: [], toolsMode: policy.mode };
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
export function resolveSubagentPermissionContract(unitType: string): SubagentPermissionContract {
|
|
771
|
+
return compileSubagentPermissionContract(resolveManifest(unitType)?.tools);
|
|
772
|
+
}
|
|
@@ -7,6 +7,27 @@ export function isNonEmptyString(value: unknown): value is string {
|
|
|
7
7
|
return typeof value === "string" && value.trim().length > 0;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Characters that are used as delimiters in GSD state management documents
|
|
12
|
+
* and should not appear in milestone or slice titles.
|
|
13
|
+
*/
|
|
14
|
+
const TITLE_DELIMITER_RE = /[\u2014\u2013\/]/; // em dash, en dash, forward slash
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Check whether a milestone or slice title contains characters that conflict
|
|
18
|
+
* with GSD's state document delimiter conventions.
|
|
19
|
+
* Returns a human-readable description of the problem, or null if the title is safe.
|
|
20
|
+
*/
|
|
21
|
+
export function validateTitle(title: string): string | null {
|
|
22
|
+
if (TITLE_DELIMITER_RE.test(title)) {
|
|
23
|
+
const found: string[] = [];
|
|
24
|
+
if (/[\u2014\u2013]/.test(title)) found.push("em/en dash (\u2014 or \u2013)");
|
|
25
|
+
if (/\//.test(title)) found.push("forward slash (/)");
|
|
26
|
+
return `title contains ${found.join(" and ")}, which conflict with GSD state document delimiters`;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
/**
|
|
11
32
|
* Validate that `value` is an array of non-empty strings.
|
|
12
33
|
* Throws with a message referencing `field` on failure.
|
|
@@ -14,7 +35,8 @@ export function isNonEmptyString(value: unknown): value is string {
|
|
|
14
35
|
*/
|
|
15
36
|
export function validateStringArray(value: unknown, field: string): string[] {
|
|
16
37
|
if (!Array.isArray(value)) {
|
|
17
|
-
|
|
38
|
+
const received = value === null ? "null" : typeof value;
|
|
39
|
+
throw new Error(`${field} must be an array of strings, not ${received}`);
|
|
18
40
|
}
|
|
19
41
|
if (value.some((item) => !isNonEmptyString(item))) {
|
|
20
42
|
throw new Error(`${field} must contain only non-empty strings`);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// First non-empty source wins.
|
|
5
5
|
|
|
6
6
|
import { spawnSync, type SpawnSyncReturns } from "node:child_process";
|
|
7
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
+
import { existsSync, readFileSync, readdirSync, type Dirent } from "node:fs";
|
|
8
8
|
import { join, basename } from "node:path";
|
|
9
9
|
import type { AuditWarning, RuntimeError, VerificationCheck, VerificationResult } from "./types.js";
|
|
10
10
|
import { DEFAULT_COMMAND_TIMEOUT_MS } from "./constants.js";
|
|
@@ -44,7 +44,8 @@ const PACKAGE_SCRIPT_KEYS = ["typecheck", "lint", "test"] as const;
|
|
|
44
44
|
* 1. Explicit preference commands
|
|
45
45
|
* 2. Task plan verify field (split on &&)
|
|
46
46
|
* 3. package.json scripts (typecheck, lint, test)
|
|
47
|
-
* 4.
|
|
47
|
+
* 4. Python pytest project markers
|
|
48
|
+
* 5. None found
|
|
48
49
|
*/
|
|
49
50
|
export function discoverCommands(options: DiscoverCommandsOptions): DiscoveredCommands {
|
|
50
51
|
// 1. Preference commands
|
|
@@ -91,10 +92,67 @@ export function discoverCommands(options: DiscoverCommandsOptions): DiscoveredCo
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
|
|
95
|
+
const pythonCommand = discoverPythonPytestCommand(options.cwd);
|
|
96
|
+
if (pythonCommand) {
|
|
97
|
+
return { commands: [pythonCommand], source: "python-project" };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 5. Nothing found
|
|
95
101
|
return { commands: [], source: "none" };
|
|
96
102
|
}
|
|
97
103
|
|
|
104
|
+
function discoverPythonPytestCommand(cwd: string): string | null {
|
|
105
|
+
const hasPythonTestFiles = hasPythonTests(join(cwd, "tests"));
|
|
106
|
+
const hasPytestConfig = existsSync(join(cwd, "pytest.ini"));
|
|
107
|
+
const pyprojectPath = join(cwd, "pyproject.toml");
|
|
108
|
+
const hasPyproject = existsSync(pyprojectPath);
|
|
109
|
+
|
|
110
|
+
if (!hasPythonTestFiles && !hasPytestConfig && !hasPyproject) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (hasPytestConfig || hasPythonTestFiles) {
|
|
115
|
+
return "python3 -m pytest";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const pyproject = readFileSync(pyprojectPath, "utf-8");
|
|
120
|
+
if (
|
|
121
|
+
pyproject.includes("[tool.pytest]") ||
|
|
122
|
+
pyproject.includes("[tool.pytest.") ||
|
|
123
|
+
pyproject.includes("[pytest]") ||
|
|
124
|
+
pyproject.includes("[tool:pytest]")
|
|
125
|
+
) {
|
|
126
|
+
return "python3 -m pytest";
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
// Ignore unreadable pyproject.toml and fall through.
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function hasPythonTests(dir: string): boolean {
|
|
136
|
+
let entries: Dirent[];
|
|
137
|
+
try {
|
|
138
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
139
|
+
} catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for (const entry of entries) {
|
|
144
|
+
const path = join(dir, entry.name);
|
|
145
|
+
if (entry.isDirectory() && hasPythonTests(path)) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
if (entry.isFile() && /^test_.*\.py$|^.*_test\.py$/.test(entry.name)) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
98
156
|
// ─── Failure Context Formatting ──────────────────────────────────────────────
|
|
99
157
|
|
|
100
158
|
/** Maximum chars of stderr to include per failed check in failure context. */
|
|
@@ -144,7 +202,7 @@ export function formatFailureContext(result: VerificationResult): string {
|
|
|
144
202
|
// ─── Gate Execution ─────────────────────────────────────────────────────────
|
|
145
203
|
|
|
146
204
|
/** Characters that indicate shell injection when found in a command string. */
|
|
147
|
-
const SHELL_INJECTION_PATTERN = /[
|
|
205
|
+
const SHELL_INJECTION_PATTERN = /[;|`<>]|\$\(/;
|
|
148
206
|
|
|
149
207
|
/**
|
|
150
208
|
* Known executable first-tokens that are safe to run.
|
|
@@ -182,6 +240,7 @@ const KNOWN_COMMAND_PREFIXES = new Set([
|
|
|
182
240
|
* Heuristics (any true → prose-like):
|
|
183
241
|
* 1. First token starts with an uppercase letter and the string has 4+ words
|
|
184
242
|
* 2. String contains commas followed by spaces (prose clause structure)
|
|
243
|
+
* 3. First token has no ASCII letters or digits and the string has 4+ words
|
|
185
244
|
*/
|
|
186
245
|
export function isLikelyCommand(cmd: string): boolean {
|
|
187
246
|
const trimmed = cmd.trim();
|
|
@@ -208,6 +267,9 @@ export function isLikelyCommand(cmd: string): boolean {
|
|
|
208
267
|
// First token has uppercase letters and no path separators → prose
|
|
209
268
|
if (/[A-Z]/.test(firstToken) && !firstToken.includes("/")) return false;
|
|
210
269
|
|
|
270
|
+
// Non-ASCII prose with multiple words should not be executed as a command.
|
|
271
|
+
if (!/[A-Za-z0-9]/.test(firstToken) && tokens.length >= 4) return false;
|
|
272
|
+
|
|
211
273
|
return true;
|
|
212
274
|
}
|
|
213
275
|
|
|
@@ -215,9 +277,19 @@ export function isLikelyCommand(cmd: string): boolean {
|
|
|
215
277
|
* Validate a command string for obvious shell injection patterns.
|
|
216
278
|
* Returns the command unchanged if safe, or null if suspicious.
|
|
217
279
|
*/
|
|
280
|
+
export function validateVerificationCommand(cmd: string): { ok: true } | { ok: false; reason: string } {
|
|
281
|
+
if (SHELL_INJECTION_PATTERN.test(cmd)) {
|
|
282
|
+
return { ok: false, reason: "contains shell control syntax such as pipes, redirects, semicolons, backticks, or command substitution" };
|
|
283
|
+
}
|
|
284
|
+
if (!isLikelyCommand(cmd)) {
|
|
285
|
+
return { ok: false, reason: "does not look like a runnable command" };
|
|
286
|
+
}
|
|
287
|
+
return { ok: true };
|
|
288
|
+
}
|
|
289
|
+
|
|
218
290
|
function sanitizeCommand(cmd: string): string | null {
|
|
219
|
-
|
|
220
|
-
if (!
|
|
291
|
+
const validation = validateVerificationCommand(cmd);
|
|
292
|
+
if (!validation.ok) return null;
|
|
221
293
|
return cmd;
|
|
222
294
|
}
|
|
223
295
|
|