gsd-pi 2.82.0-dev.ed17d078d → 3.0.0-dev.1b44e695b
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-ui.js +13 -6
- 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/detect-stuck.js +1 -1
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +122 -40
- package/dist/resources/extensions/gsd/auto/orchestrator.js +15 -4
- package/dist/resources/extensions/gsd/auto/phases.js +134 -49
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto/unit-runner-events.js +7 -1
- 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-budget.js +9 -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 +144 -30
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +329 -137
- package/dist/resources/extensions/gsd/auto-prompts.js +36 -10
- package/dist/resources/extensions/gsd/auto-recovery.js +82 -16
- package/dist/resources/extensions/gsd/auto-start.js +99 -16
- package/dist/resources/extensions/gsd/auto-timers.js +11 -3
- package/dist/resources/extensions/gsd/auto-verification.js +146 -34
- package/dist/resources/extensions/gsd/auto-worktree.js +185 -26
- package/dist/resources/extensions/gsd/auto.js +135 -74
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +65 -10
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +13 -10
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +14 -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 +10 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +139 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +55 -7
- package/dist/resources/extensions/gsd/db/auto-workers.js +30 -0
- 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 +10 -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 +10 -3
- package/dist/resources/extensions/gsd/git-service.js +152 -15
- 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 +14 -11
- package/dist/resources/extensions/gsd/mcp-filter.js +58 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +121 -2
- 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 +54 -19
- package/dist/resources/extensions/gsd/preferences-mcp.js +19 -0
- package/dist/resources/extensions/gsd/preferences-types.js +3 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +147 -0
- package/dist/resources/extensions/gsd/preferences.js +6 -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/repo-identity.js +39 -22
- 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/session-lock.js +15 -2
- package/dist/resources/extensions/gsd/slice-parallel-conflict.js +2 -2
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +84 -5
- 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 +28 -7
- package/dist/resources/extensions/gsd/status-guards.js +14 -2
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- 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 +15 -9
- package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -10
- package/dist/resources/extensions/gsd/tools/exec-tool.js +87 -5
- 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/validate-milestone.js +32 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +185 -40
- package/dist/resources/extensions/gsd/unit-context-composer.js +2 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +69 -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 +86 -19
- package/dist/resources/extensions/gsd/worktree-manager.js +11 -2
- package/dist/resources/extensions/gsd/worktree-safety.js +43 -4
- package/dist/resources/extensions/gsd/worktree-state-projection.js +31 -0
- package/dist/resources/extensions/gsd/worktree-telemetry.js +32 -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/shared/next-action-ui.js +13 -5
- 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 +7 -7
- 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/required-server-files.json +1 -1
- 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 +7 -7
- 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/dist/web/standalone/server.js +1 -1
- 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/__tests__/tool-execution.test.js +8 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.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/components/tool-execution.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.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 +82 -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/__tests__/tool-execution.test.ts +17 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +91 -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 +19 -6
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +1 -0
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +123 -40
- package/src/resources/extensions/gsd/auto/orchestrator.ts +15 -4
- package/src/resources/extensions/gsd/auto/phases.ts +160 -60
- 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/unit-runner-events.ts +6 -2
- 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-budget.ts +11 -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 +164 -29
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +369 -148
- package/src/resources/extensions/gsd/auto-prompts.ts +36 -13
- package/src/resources/extensions/gsd/auto-recovery.ts +86 -13
- package/src/resources/extensions/gsd/auto-start.ts +109 -14
- package/src/resources/extensions/gsd/auto-timers.ts +10 -3
- package/src/resources/extensions/gsd/auto-verification.ts +174 -42
- package/src/resources/extensions/gsd/auto-worktree.ts +202 -30
- package/src/resources/extensions/gsd/auto.ts +172 -81
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +66 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +13 -10
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +13 -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 +11 -3
- package/src/resources/extensions/gsd/commands-verdict.ts +202 -0
- package/src/resources/extensions/gsd/crash-recovery.ts +55 -6
- package/src/resources/extensions/gsd/db/auto-workers.ts +37 -0
- 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 +10 -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 +9 -3
- package/src/resources/extensions/gsd/git-service.ts +182 -16
- 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 +14 -11
- package/src/resources/extensions/gsd/mcp-filter.ts +80 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +139 -2
- 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 +67 -19
- package/src/resources/extensions/gsd/preferences-mcp.ts +27 -0
- package/src/resources/extensions/gsd/preferences-types.ts +35 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +154 -0
- package/src/resources/extensions/gsd/preferences.ts +9 -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/repo-identity.ts +45 -25
- 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/session-lock.ts +15 -2
- package/src/resources/extensions/gsd/slice-parallel-conflict.ts +2 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +75 -3
- 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 +33 -7
- package/src/resources/extensions/gsd/status-guards.ts +16 -2
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- 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/artifact-retry-cap.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +10 -1
- 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 +775 -34
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +245 -28
- 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 +136 -13
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +64 -0
- 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-workers.test.ts +29 -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 +55 -2
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +60 -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 +104 -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 +111 -1
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +68 -1
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +140 -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/exec-sandbox.test.ts +99 -1
- package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +15 -1
- 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 +226 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +5 -21
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +40 -0
- 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/merge-self-branch-guard.test.ts +21 -40
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +59 -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 +8 -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 +147 -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 +79 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +42 -1
- 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/repo-identity-worktree.test.ts +28 -1
- 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-lock-regression.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +59 -1
- package/src/resources/extensions/gsd/tests/slice-parallel-conflict.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +112 -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 +94 -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-composer.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +131 -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-write-order.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +42 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +188 -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 +153 -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 +73 -2
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +16 -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 +18 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +57 -10
- package/src/resources/extensions/gsd/tools/exec-tool.ts +98 -5
- 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/validate-milestone.ts +31 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +166 -17
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +3 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +86 -19
- 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 +98 -20
- package/src/resources/extensions/gsd/worktree-manager.ts +14 -2
- package/src/resources/extensions/gsd/worktree-safety.ts +57 -10
- package/src/resources/extensions/gsd/worktree-state-projection.ts +43 -0
- package/src/resources/extensions/gsd/worktree-telemetry.ts +39 -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/next-action-ui.ts +11 -5
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +15 -0
- package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +32 -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 → Z8H5evS-hDo0qdP22XJPA}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{YEvjuT-fsFfYQhDSWtueS → Z8H5evS-hDo0qdP22XJPA}/_ssgManifest.js +0 -0
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getMilestone,
|
|
16
16
|
getMilestoneSlices,
|
|
17
17
|
getSliceTasks,
|
|
18
|
+
getLatestAssessmentByScope,
|
|
18
19
|
updateMilestoneStatus,
|
|
19
20
|
} from "../gsd-db.js";
|
|
20
21
|
import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
@@ -38,9 +39,9 @@ export interface CompleteMilestoneParams {
|
|
|
38
39
|
definitionOfDoneResults?: string;
|
|
39
40
|
/** @optional — empty/omitted renders as "Not provided." */
|
|
40
41
|
requirementOutcomes?: string;
|
|
41
|
-
/** @optional — empty/omitted renders as
|
|
42
|
+
/** @optional — empty/omitted renders as an empty frontmatter list */
|
|
42
43
|
keyDecisions?: string[];
|
|
43
|
-
/** @optional — empty/omitted renders as
|
|
44
|
+
/** @optional — empty/omitted renders as an empty frontmatter list */
|
|
44
45
|
keyFiles?: string[];
|
|
45
46
|
/** @optional — empty/omitted renders as "(none)" */
|
|
46
47
|
lessonsLearned?: string[];
|
|
@@ -70,12 +71,12 @@ function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams, complet
|
|
|
70
71
|
const lessonsLearned = params.lessonsLearned ?? [];
|
|
71
72
|
|
|
72
73
|
const keyDecisionsYaml = keyDecisions.length > 0
|
|
73
|
-
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
74
|
-
: "
|
|
74
|
+
? `\n${keyDecisions.map(d => ` - ${d}`).join("\n")}`
|
|
75
|
+
: " []";
|
|
75
76
|
|
|
76
77
|
const keyFilesYaml = keyFiles.length > 0
|
|
77
|
-
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
78
|
-
: "
|
|
78
|
+
? `\n${keyFiles.map(f => ` - ${f}`).join("\n")}`
|
|
79
|
+
: " []";
|
|
79
80
|
|
|
80
81
|
const lessonsYaml = lessonsLearned.length > 0
|
|
81
82
|
? lessonsLearned.map(l => ` - ${l}`).join("\n")
|
|
@@ -86,10 +87,8 @@ id: ${params.milestoneId}
|
|
|
86
87
|
title: "${displayTitle}"
|
|
87
88
|
status: complete
|
|
88
89
|
completed_at: ${completedAt}
|
|
89
|
-
key_decisions
|
|
90
|
-
|
|
91
|
-
key_files:
|
|
92
|
-
${keyFilesYaml}
|
|
90
|
+
key_decisions:${keyDecisionsYaml}
|
|
91
|
+
key_files:${keyFilesYaml}
|
|
93
92
|
lessons_learned:
|
|
94
93
|
${lessonsYaml}
|
|
95
94
|
---
|
|
@@ -158,6 +157,15 @@ export async function handleCompleteMilestone(
|
|
|
158
157
|
return;
|
|
159
158
|
}
|
|
160
159
|
|
|
160
|
+
// Defense-in-depth: only a passing milestone validation permits closeout.
|
|
161
|
+
const validation = getLatestAssessmentByScope(params.milestoneId, "milestone-validation");
|
|
162
|
+
if (validation?.status !== "pass") {
|
|
163
|
+
guardError =
|
|
164
|
+
`Refusing to complete ${params.milestoneId}: latest milestone-validation verdict is ` +
|
|
165
|
+
`"${validation?.status ?? "absent"}". Only verdict=pass permits closeout.`;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
161
169
|
// Verify all slices are complete
|
|
162
170
|
const slices = getMilestoneSlices(params.milestoneId);
|
|
163
171
|
if (slices.length === 0) {
|
|
@@ -104,12 +104,12 @@ function renderSliceSummaryMarkdown(params: CompleteSliceParams): string {
|
|
|
104
104
|
: " []";
|
|
105
105
|
|
|
106
106
|
const keyFilesYaml = keyFiles.length > 0
|
|
107
|
-
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
108
|
-
: "
|
|
107
|
+
? `\n${keyFiles.map(f => ` - ${f}`).join("\n")}`
|
|
108
|
+
: " []";
|
|
109
109
|
|
|
110
110
|
const keyDecisionsYaml = keyDecisions.length > 0
|
|
111
|
-
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
112
|
-
: "
|
|
111
|
+
? `\n${keyDecisions.map(d => ` - ${d}`).join("\n")}`
|
|
112
|
+
: " []";
|
|
113
113
|
|
|
114
114
|
const patternsYaml = patternsEstablished.length > 0
|
|
115
115
|
? patternsEstablished.map(p => ` - ${p}`).join("\n")
|
|
@@ -155,10 +155,8 @@ requires:
|
|
|
155
155
|
${requiresYaml}
|
|
156
156
|
affects:
|
|
157
157
|
${affectsYaml}
|
|
158
|
-
key_files
|
|
159
|
-
|
|
160
|
-
key_decisions:
|
|
161
|
-
${keyDecisionsYaml}
|
|
158
|
+
key_files:${keyFilesYaml}
|
|
159
|
+
key_decisions:${keyDecisionsYaml}
|
|
162
160
|
patterns_established:
|
|
163
161
|
${patternsYaml}
|
|
164
162
|
observability_surfaces:
|
|
@@ -234,6 +232,34 @@ ${params.uatContent}
|
|
|
234
232
|
`;
|
|
235
233
|
}
|
|
236
234
|
|
|
235
|
+
function parseRequirementSection(
|
|
236
|
+
summaryMd: string,
|
|
237
|
+
heading: "Requirements Advanced" | "Requirements Validated" | "Requirements Invalidated or Re-scoped",
|
|
238
|
+
field: "how" | "proof" | "what",
|
|
239
|
+
): Array<{ id: string; how?: string; proof?: string; what?: string }> {
|
|
240
|
+
const headingLine = `## ${heading}\n\n`;
|
|
241
|
+
const start = summaryMd.indexOf(headingLine);
|
|
242
|
+
if (start === -1) return [];
|
|
243
|
+
const contentStart = start + headingLine.length;
|
|
244
|
+
const nextHeading = summaryMd.indexOf("\n\n## ", contentStart);
|
|
245
|
+
const content = nextHeading === -1
|
|
246
|
+
? summaryMd.slice(contentStart)
|
|
247
|
+
: summaryMd.slice(contentStart, nextHeading);
|
|
248
|
+
return content
|
|
249
|
+
.split("\n")
|
|
250
|
+
.map((line) => line.trim())
|
|
251
|
+
.filter((line) => line.startsWith("- "))
|
|
252
|
+
.map((line) => line.slice(2).trim())
|
|
253
|
+
.map((line) => {
|
|
254
|
+
const pair = line.match(/^(.+?)\s*(?:—|-)\s+(.+)$/);
|
|
255
|
+
const id = pair ? pair[1].trim() : line.trim();
|
|
256
|
+
const detail = pair ? pair[2].trim() : "";
|
|
257
|
+
if (!id || !detail) return null;
|
|
258
|
+
return { id, [field]: detail };
|
|
259
|
+
})
|
|
260
|
+
.filter((entry): entry is { id: string; how?: string; proof?: string; what?: string } => entry !== null);
|
|
261
|
+
}
|
|
262
|
+
|
|
237
263
|
/**
|
|
238
264
|
* Handle the complete_slice operation end-to-end.
|
|
239
265
|
*
|
|
@@ -279,6 +305,7 @@ export async function handleCompleteSlice(
|
|
|
279
305
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
280
306
|
const completedAt = new Date().toISOString();
|
|
281
307
|
let guardError: string | null = null;
|
|
308
|
+
let existingSummaryMd = "";
|
|
282
309
|
|
|
283
310
|
transaction(() => {
|
|
284
311
|
// State machine preconditions (inside txn for atomicity).
|
|
@@ -291,6 +318,7 @@ export async function handleCompleteSlice(
|
|
|
291
318
|
}
|
|
292
319
|
|
|
293
320
|
const slice = getSlice(params.milestoneId, params.sliceId);
|
|
321
|
+
existingSummaryMd = slice?.full_summary_md?.trim() ?? "";
|
|
294
322
|
if (slice && isClosedStatus(slice.status)) {
|
|
295
323
|
if (isStaleWrite("complete-slice")) {
|
|
296
324
|
guardError = "__stale_duplicate__";
|
|
@@ -349,8 +377,27 @@ export async function handleCompleteSlice(
|
|
|
349
377
|
return { error: guardError };
|
|
350
378
|
}
|
|
351
379
|
|
|
380
|
+
const effectiveParams: CompleteSliceParams = { ...params };
|
|
381
|
+
if (existingSummaryMd) {
|
|
382
|
+
// Keep these heading names in lock-step with renderSliceSummaryMarkdown's
|
|
383
|
+
// section titles so omitted CompleteSliceParams requirement fields can be
|
|
384
|
+
// backfilled from previously rendered summary markdown.
|
|
385
|
+
if (effectiveParams.requirementsAdvanced === undefined) {
|
|
386
|
+
const parsed = parseRequirementSection(existingSummaryMd, "Requirements Advanced", "how");
|
|
387
|
+
if (parsed.length > 0) effectiveParams.requirementsAdvanced = parsed as Array<{ id: string; how: string }>;
|
|
388
|
+
}
|
|
389
|
+
if (effectiveParams.requirementsValidated === undefined) {
|
|
390
|
+
const parsed = parseRequirementSection(existingSummaryMd, "Requirements Validated", "proof");
|
|
391
|
+
if (parsed.length > 0) effectiveParams.requirementsValidated = parsed as Array<{ id: string; proof: string }>;
|
|
392
|
+
}
|
|
393
|
+
if (effectiveParams.requirementsInvalidated === undefined) {
|
|
394
|
+
const parsed = parseRequirementSection(existingSummaryMd, "Requirements Invalidated or Re-scoped", "what");
|
|
395
|
+
if (parsed.length > 0) effectiveParams.requirementsInvalidated = parsed as Array<{ id: string; what: string }>;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
352
399
|
// Render summary markdown
|
|
353
|
-
const summaryMd = renderSliceSummaryMarkdown(
|
|
400
|
+
const summaryMd = renderSliceSummaryMarkdown(effectiveParams);
|
|
354
401
|
|
|
355
402
|
// Resolve and write summary to disk
|
|
356
403
|
let summaryPath: string;
|
|
@@ -365,7 +412,7 @@ export async function handleCompleteSlice(
|
|
|
365
412
|
summaryPath = join(manualSliceDir, `${params.sliceId}-SUMMARY.md`);
|
|
366
413
|
}
|
|
367
414
|
|
|
368
|
-
const uatMd = renderUatMarkdown(
|
|
415
|
+
const uatMd = renderUatMarkdown(effectiveParams);
|
|
369
416
|
const uatPath = summaryPath.replace(/-SUMMARY\.md$/, "-UAT.md");
|
|
370
417
|
setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
|
|
371
418
|
let projectionStale = false;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
// GSD
|
|
2
|
-
//
|
|
3
|
-
// Thin wrapper around exec-sandbox.ts that reads effective options from
|
|
4
|
-
// the project preferences (context_mode block) and formats the result
|
|
5
|
-
// for MCP return.
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Executor for the gsd_exec MCP tool.
|
|
6
3
|
|
|
7
4
|
import {
|
|
8
5
|
EXEC_DEFAULTS,
|
|
@@ -11,6 +8,7 @@ import {
|
|
|
11
8
|
type ExecSandboxRequest,
|
|
12
9
|
type ExecSandboxResult,
|
|
13
10
|
} from "../exec-sandbox.js";
|
|
11
|
+
import path from "node:path";
|
|
14
12
|
import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
|
|
15
13
|
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
16
14
|
|
|
@@ -81,6 +79,93 @@ function paramError(message: string): ToolExecutionResult {
|
|
|
81
79
|
};
|
|
82
80
|
}
|
|
83
81
|
|
|
82
|
+
function escapeRegExp(value: string): string {
|
|
83
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizeScanPath(value: string): string {
|
|
87
|
+
return value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function parseWorktreeBase(baseDir: string): { originalRoot: string; worktreeRoot: string } | null {
|
|
91
|
+
const normalizedBase = normalizeScanPath(baseDir);
|
|
92
|
+
const marker = "/.gsd/worktrees/";
|
|
93
|
+
const markerIndex = normalizedBase.indexOf(marker);
|
|
94
|
+
if (markerIndex <= 0) return null;
|
|
95
|
+
return {
|
|
96
|
+
originalRoot: normalizedBase.slice(0, markerIndex),
|
|
97
|
+
worktreeRoot: normalizedBase,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function pathInside(parent: string, target: string): boolean {
|
|
102
|
+
const parentWithSep = parent.endsWith("/") ? parent : `${parent}/`;
|
|
103
|
+
return target === parent || target.startsWith(parentWithSep);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function stripWrappingQuotes(value: string): string {
|
|
107
|
+
const trimmed = value.trim();
|
|
108
|
+
if (trimmed.length < 2) return trimmed;
|
|
109
|
+
const first = trimmed[0];
|
|
110
|
+
const last = trimmed[trimmed.length - 1];
|
|
111
|
+
if ((first === "'" || first === '"' || first === "`") && last === first) {
|
|
112
|
+
return trimmed.slice(1, -1).trim();
|
|
113
|
+
}
|
|
114
|
+
return trimmed;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function extractPathLikeValues(script: string): string[] {
|
|
118
|
+
const values: string[] = [];
|
|
119
|
+
const push = (candidate: string) => {
|
|
120
|
+
const cleaned = stripWrappingQuotes(candidate).trim();
|
|
121
|
+
if (!cleaned) return;
|
|
122
|
+
values.push(cleaned);
|
|
123
|
+
};
|
|
124
|
+
const pushQuotedLiterals = (source: string, depth = 0) => {
|
|
125
|
+
for (const match of source.matchAll(/(["'`])((?:\\.|(?!\1).)*)\1/g)) {
|
|
126
|
+
push(match[2]);
|
|
127
|
+
if (depth < 2 && /["'`]/.test(match[2])) {
|
|
128
|
+
pushQuotedLiterals(match[2], depth + 1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
for (const match of script.matchAll(/(?:^|[;\n\r]|\&\&|\|\|)\s*cd\s+([^\n\r;|&]+)/g)) {
|
|
134
|
+
push(match[1]);
|
|
135
|
+
}
|
|
136
|
+
for (const match of script.matchAll(/process\.chdir\(\s*([^\n\r;]+?)\s*\)/g)) {
|
|
137
|
+
push(match[1]);
|
|
138
|
+
pushQuotedLiterals(match[1]);
|
|
139
|
+
}
|
|
140
|
+
pushQuotedLiterals(script);
|
|
141
|
+
return values;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function resolvesToOriginalRootOutsideWorktree(script: string, baseDir: string): boolean {
|
|
145
|
+
const parsed = parseWorktreeBase(baseDir);
|
|
146
|
+
if (!parsed) return false;
|
|
147
|
+
|
|
148
|
+
const normalizedWorktree = normalizeScanPath(path.resolve(parsed.worktreeRoot));
|
|
149
|
+
const normalizedOriginalRoot = normalizeScanPath(path.resolve(parsed.originalRoot));
|
|
150
|
+
for (const value of extractPathLikeValues(script)) {
|
|
151
|
+
const resolved = normalizeScanPath(path.resolve(normalizedWorktree, value));
|
|
152
|
+
if (pathInside(normalizedOriginalRoot, resolved) && !pathInside(normalizedWorktree, resolved)) {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function scriptReferencesOriginalRootFromWorktree(script: string, baseDir: string): boolean {
|
|
160
|
+
const parsed = parseWorktreeBase(baseDir);
|
|
161
|
+
if (!parsed) return false;
|
|
162
|
+
const normalizedScript = script.replace(/\\/g, "/");
|
|
163
|
+
const originalRootPattern = new RegExp(
|
|
164
|
+
`${escapeRegExp(parsed.originalRoot)}(?=$|[\\s'"\\\`;)&|<>]|/(?!\\.gsd/worktrees(?:/|$)))`,
|
|
165
|
+
);
|
|
166
|
+
return originalRootPattern.test(normalizedScript);
|
|
167
|
+
}
|
|
168
|
+
|
|
84
169
|
export async function executeGsdExec(
|
|
85
170
|
params: ExecToolParams,
|
|
86
171
|
deps: ExecToolDeps,
|
|
@@ -98,6 +183,14 @@ export async function executeGsdExec(
|
|
|
98
183
|
if (Buffer.byteLength(script, "utf8") > 200_000) {
|
|
99
184
|
return paramError("script exceeds the 200 KB length limit");
|
|
100
185
|
}
|
|
186
|
+
if (
|
|
187
|
+
resolvesToOriginalRootOutsideWorktree(script, deps.baseDir)
|
|
188
|
+
|| scriptReferencesOriginalRootFromWorktree(script, deps.baseDir)
|
|
189
|
+
) {
|
|
190
|
+
return paramError(
|
|
191
|
+
"script references the original project root while running inside a milestone worktree; use the active worktree path or relative paths",
|
|
192
|
+
);
|
|
193
|
+
}
|
|
101
194
|
|
|
102
195
|
const opts = buildExecOptions(
|
|
103
196
|
deps.baseDir,
|
|
@@ -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,11 @@ 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";
|
|
31
|
+
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
32
|
+
import { createRepositoryRegistryFromPreferences, type RepositoryRegistry } from "../repository-registry.js";
|
|
22
33
|
|
|
23
34
|
export interface PlanSliceTaskInput {
|
|
24
35
|
taskId: string;
|
|
@@ -31,6 +42,7 @@ export interface PlanSliceTaskInput {
|
|
|
31
42
|
expectedOutput: string[];
|
|
32
43
|
observabilityImpact?: string;
|
|
33
44
|
fullPlanMd?: string;
|
|
45
|
+
targetRepositories?: string[];
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
export interface PlanSliceParams {
|
|
@@ -46,6 +58,7 @@ export interface PlanSliceParams {
|
|
|
46
58
|
integrationClosure?: string;
|
|
47
59
|
/** @optional — omitted fields render as conservative defaults */
|
|
48
60
|
observabilityImpact?: string;
|
|
61
|
+
targetRepositories?: string[];
|
|
49
62
|
/** Optional caller-provided identity for audit trail */
|
|
50
63
|
actorName?: string;
|
|
51
64
|
/** Optional caller-provided reason this action was triggered */
|
|
@@ -59,6 +72,18 @@ export interface PlanSliceResult {
|
|
|
59
72
|
taskPlanPaths: string[];
|
|
60
73
|
}
|
|
61
74
|
|
|
75
|
+
function validateRepositoryTargetIds(
|
|
76
|
+
field: string,
|
|
77
|
+
value: unknown,
|
|
78
|
+
): string[] | null {
|
|
79
|
+
if (value === undefined) return null;
|
|
80
|
+
const ids = validateStringArray(value, field);
|
|
81
|
+
if (ids.length === 0) throw new Error(`${field} must include at least one repository id when provided`);
|
|
82
|
+
const deduped = Array.from(new Set(ids.map((id) => id.trim()).filter(Boolean)));
|
|
83
|
+
if (deduped.length === 0) throw new Error(`${field} must include at least one repository id when provided`);
|
|
84
|
+
return deduped;
|
|
85
|
+
}
|
|
86
|
+
|
|
62
87
|
function validateTasks(value: unknown): PlanSliceTaskInput[] {
|
|
63
88
|
if (!Array.isArray(value) || value.length === 0) {
|
|
64
89
|
throw new Error("tasks must be a non-empty array");
|
|
@@ -79,6 +104,7 @@ function validateTasks(value: unknown): PlanSliceTaskInput[] {
|
|
|
79
104
|
const inputs = obj.inputs;
|
|
80
105
|
const expectedOutput = obj.expectedOutput;
|
|
81
106
|
const observabilityImpact = obj.observabilityImpact;
|
|
107
|
+
const targetRepositories = obj.targetRepositories;
|
|
82
108
|
|
|
83
109
|
if (!isNonEmptyString(taskId)) throw new Error(`tasks[${index}].taskId must be a non-empty string`);
|
|
84
110
|
if (seen.has(taskId)) throw new Error(`tasks[${index}].taskId must be unique`);
|
|
@@ -86,30 +112,29 @@ function validateTasks(value: unknown): PlanSliceTaskInput[] {
|
|
|
86
112
|
if (!isNonEmptyString(title)) throw new Error(`tasks[${index}].title must be a non-empty string`);
|
|
87
113
|
if (!isNonEmptyString(description)) throw new Error(`tasks[${index}].description must be a non-empty string`);
|
|
88
114
|
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
|
-
}
|
|
115
|
+
const validatedFiles = validateStringArray(files, `tasks[${index}].files`);
|
|
92
116
|
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
|
-
}
|
|
117
|
+
const validatedInputs = validateStringArray(inputs, `tasks[${index}].inputs`);
|
|
118
|
+
const validatedExpectedOutput = validateStringArray(expectedOutput, `tasks[${index}].expectedOutput`);
|
|
99
119
|
if (observabilityImpact !== undefined && !isNonEmptyString(observabilityImpact)) {
|
|
100
120
|
throw new Error(`tasks[${index}].observabilityImpact must be a non-empty string when provided`);
|
|
101
121
|
}
|
|
122
|
+
const validatedTargetRepositories = validateRepositoryTargetIds(
|
|
123
|
+
`tasks[${index}].targetRepositories`,
|
|
124
|
+
targetRepositories,
|
|
125
|
+
);
|
|
102
126
|
|
|
103
127
|
return {
|
|
104
128
|
taskId,
|
|
105
129
|
title,
|
|
106
130
|
description,
|
|
107
131
|
estimate,
|
|
108
|
-
files,
|
|
132
|
+
files: validatedFiles,
|
|
109
133
|
verify,
|
|
110
|
-
inputs,
|
|
111
|
-
expectedOutput,
|
|
134
|
+
inputs: validatedInputs,
|
|
135
|
+
expectedOutput: validatedExpectedOutput,
|
|
112
136
|
observabilityImpact: typeof observabilityImpact === "string" ? observabilityImpact : "",
|
|
137
|
+
targetRepositories: validatedTargetRepositories ?? undefined,
|
|
113
138
|
};
|
|
114
139
|
});
|
|
115
140
|
}
|
|
@@ -119,6 +144,11 @@ function validateParams(params: PlanSliceParams): PlanSliceParams {
|
|
|
119
144
|
if (!isNonEmptyString(params?.sliceId)) throw new Error("sliceId is required");
|
|
120
145
|
if (!isNonEmptyString(params?.goal)) throw new Error("goal is required");
|
|
121
146
|
|
|
147
|
+
const validatedTargetRepositories = validateRepositoryTargetIds(
|
|
148
|
+
"targetRepositories",
|
|
149
|
+
params.targetRepositories,
|
|
150
|
+
);
|
|
151
|
+
|
|
122
152
|
return {
|
|
123
153
|
...params,
|
|
124
154
|
// Keep optional enrichment fields empty when omitted. The renderer supplies
|
|
@@ -127,10 +157,97 @@ function validateParams(params: PlanSliceParams): PlanSliceParams {
|
|
|
127
157
|
proofLevel: params.proofLevel ?? "",
|
|
128
158
|
integrationClosure: params.integrationClosure ?? "",
|
|
129
159
|
observabilityImpact: params.observabilityImpact ?? "",
|
|
160
|
+
targetRepositories: validatedTargetRepositories ?? undefined,
|
|
130
161
|
tasks: validateTasks(params.tasks),
|
|
131
162
|
};
|
|
132
163
|
}
|
|
133
164
|
|
|
165
|
+
function loadRepositoryRegistry(basePath: string): RepositoryRegistry {
|
|
166
|
+
const loaded = loadEffectiveGSDPreferences(basePath);
|
|
167
|
+
return createRepositoryRegistryFromPreferences(basePath, loaded?.preferences);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function validateReferencedRepositories(params: PlanSliceParams, registry: RepositoryRegistry): string | null {
|
|
171
|
+
const known = new Set(registry.repositories.map((repo) => repo.id));
|
|
172
|
+
|
|
173
|
+
const missing: string[] = [];
|
|
174
|
+
const noteMissing = (id: string) => {
|
|
175
|
+
if (!known.has(id) && !missing.includes(id)) missing.push(id);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
for (const id of params.targetRepositories ?? []) noteMissing(id);
|
|
179
|
+
for (const task of params.tasks) {
|
|
180
|
+
for (const id of task.targetRepositories ?? []) noteMissing(id);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (missing.length === 0) return null;
|
|
184
|
+
return `unknown targetRepositories: ${missing.join(", ")}. Declared repositories: ${Array.from(known).join(", ")}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function resolveAllowedRootsForPathScope(params: PlanSliceParams, registry: RepositoryRegistry): string[] {
|
|
188
|
+
const requested = new Set<string>();
|
|
189
|
+
for (const id of params.targetRepositories ?? []) requested.add(id);
|
|
190
|
+
for (const task of params.tasks) {
|
|
191
|
+
for (const id of task.targetRepositories ?? []) requested.add(id);
|
|
192
|
+
}
|
|
193
|
+
if (requested.size === 0) return [registry.projectRoot];
|
|
194
|
+
const roots = Array.from(requested)
|
|
195
|
+
.map((id) => registry.byId.get(id)?.root)
|
|
196
|
+
.filter((root): root is string => typeof root === "string");
|
|
197
|
+
return roots.length > 0 ? roots : [registry.projectRoot];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function toTaskRows(params: PlanSliceParams): TaskRow[] {
|
|
201
|
+
return params.tasks.map((task, index) => ({
|
|
202
|
+
milestone_id: params.milestoneId,
|
|
203
|
+
slice_id: params.sliceId,
|
|
204
|
+
id: task.taskId,
|
|
205
|
+
title: task.title,
|
|
206
|
+
status: "pending",
|
|
207
|
+
one_liner: "",
|
|
208
|
+
narrative: "",
|
|
209
|
+
verification_result: "",
|
|
210
|
+
duration: "",
|
|
211
|
+
completed_at: null,
|
|
212
|
+
blocker_discovered: false,
|
|
213
|
+
deviations: "",
|
|
214
|
+
known_issues: "",
|
|
215
|
+
key_files: [],
|
|
216
|
+
key_decisions: [],
|
|
217
|
+
full_summary_md: "",
|
|
218
|
+
description: task.description,
|
|
219
|
+
estimate: task.estimate,
|
|
220
|
+
files: task.files,
|
|
221
|
+
verify: task.verify,
|
|
222
|
+
inputs: task.inputs,
|
|
223
|
+
expected_output: task.expectedOutput,
|
|
224
|
+
observability_impact: task.observabilityImpact ?? "",
|
|
225
|
+
full_plan_md: task.fullPlanMd ?? "",
|
|
226
|
+
target_repositories: task.targetRepositories ?? params.targetRepositories ?? ["project"],
|
|
227
|
+
sequence: index + 1,
|
|
228
|
+
blocker_source: "",
|
|
229
|
+
escalation_pending: 0,
|
|
230
|
+
escalation_awaiting_review: 0,
|
|
231
|
+
escalation_artifact_path: null,
|
|
232
|
+
escalation_override_applied_at: null,
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function validateTaskPathsBeforePersist(params: PlanSliceParams, basePath: string): string | null {
|
|
237
|
+
const taskRows = toTaskRows(params);
|
|
238
|
+
const checks = [
|
|
239
|
+
...checkFilePathConsistency(taskRows, basePath),
|
|
240
|
+
...checkTaskOrdering(taskRows, basePath),
|
|
241
|
+
];
|
|
242
|
+
const blocking = checks.filter((check) => !check.passed && check.blocking);
|
|
243
|
+
|
|
244
|
+
if (blocking.length === 0) return null;
|
|
245
|
+
|
|
246
|
+
return blocking
|
|
247
|
+
.map((check) => `[${check.category}] ${check.target}: ${check.message}`)
|
|
248
|
+
.join("\n");
|
|
249
|
+
}
|
|
250
|
+
|
|
134
251
|
export async function handlePlanSlice(
|
|
135
252
|
rawParams: PlanSliceParams,
|
|
136
253
|
basePath: string,
|
|
@@ -142,6 +259,14 @@ export async function handlePlanSlice(
|
|
|
142
259
|
return { error: `validation failed: ${(err as Error).message}` };
|
|
143
260
|
}
|
|
144
261
|
|
|
262
|
+
const repositoryRegistry = loadRepositoryRegistry(basePath);
|
|
263
|
+
const repoValidationError = validateReferencedRepositories(params, repositoryRegistry);
|
|
264
|
+
if (repoValidationError) {
|
|
265
|
+
return { error: `validation failed: ${repoValidationError}` };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const allowedAbsoluteRoots = resolveAllowedRootsForPathScope(params, repositoryRegistry);
|
|
269
|
+
|
|
145
270
|
const pathScopeError = validatePlanningPathScope(
|
|
146
271
|
basePath,
|
|
147
272
|
params.tasks.flatMap((task, index) => [
|
|
@@ -149,15 +274,22 @@ export async function handlePlanSlice(
|
|
|
149
274
|
{ field: `tasks[${index}].inputs`, values: task.inputs },
|
|
150
275
|
{ field: `tasks[${index}].expectedOutput`, values: task.expectedOutput },
|
|
151
276
|
]),
|
|
277
|
+
allowedAbsoluteRoots,
|
|
152
278
|
);
|
|
153
279
|
if (pathScopeError) {
|
|
154
280
|
return { error: `validation failed: ${pathScopeError}` };
|
|
155
281
|
}
|
|
156
282
|
|
|
283
|
+
const pathError = validateTaskPathsBeforePersist(params, basePath);
|
|
284
|
+
if (pathError) {
|
|
285
|
+
return { error: `pre-execution validation failed:\n${pathError}` };
|
|
286
|
+
}
|
|
287
|
+
|
|
157
288
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
158
289
|
// Guards must be inside the transaction so the state they check cannot
|
|
159
290
|
// change between the read and the write (#2723).
|
|
160
291
|
let guardError: string | null = null;
|
|
292
|
+
let omittedTaskIds: string[] = [];
|
|
161
293
|
|
|
162
294
|
try {
|
|
163
295
|
transaction(() => {
|
|
@@ -181,9 +313,23 @@ export async function handlePlanSlice(
|
|
|
181
313
|
return;
|
|
182
314
|
}
|
|
183
315
|
|
|
316
|
+
const newTaskIds = new Set(params.tasks.map((task) => task.taskId));
|
|
317
|
+
const existingTasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
318
|
+
omittedTaskIds = existingTasks
|
|
319
|
+
.filter((task) => !newTaskIds.has(task.id))
|
|
320
|
+
.map((task) => task.id);
|
|
321
|
+
|
|
322
|
+
for (const task of existingTasks) {
|
|
323
|
+
if (!newTaskIds.has(task.id) && isClosedStatus(task.status)) {
|
|
324
|
+
guardError = `cannot remove completed task ${task.id}`;
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
184
329
|
if (isDeferredStatus(parentSlice.status)) {
|
|
185
330
|
updateSliceStatus(params.milestoneId, params.sliceId, "pending");
|
|
186
331
|
}
|
|
332
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
187
333
|
|
|
188
334
|
upsertSlicePlanning(params.milestoneId, params.sliceId, {
|
|
189
335
|
goal: params.goal,
|
|
@@ -191,8 +337,13 @@ export async function handlePlanSlice(
|
|
|
191
337
|
proofLevel: params.proofLevel,
|
|
192
338
|
integrationClosure: params.integrationClosure,
|
|
193
339
|
observabilityImpact: params.observabilityImpact,
|
|
340
|
+
targetRepositories: params.targetRepositories ?? ["project"],
|
|
194
341
|
});
|
|
195
342
|
|
|
343
|
+
for (const taskId of omittedTaskIds) {
|
|
344
|
+
deleteTask(params.milestoneId, params.sliceId, taskId);
|
|
345
|
+
}
|
|
346
|
+
|
|
196
347
|
for (const task of params.tasks) {
|
|
197
348
|
insertTask({
|
|
198
349
|
id: task.taskId,
|
|
@@ -211,6 +362,7 @@ export async function handlePlanSlice(
|
|
|
211
362
|
expectedOutput: task.expectedOutput,
|
|
212
363
|
observabilityImpact: task.observabilityImpact ?? "",
|
|
213
364
|
fullPlanMd: task.fullPlanMd,
|
|
365
|
+
targetRepositories: task.targetRepositories ?? params.targetRepositories ?? ["project"],
|
|
214
366
|
});
|
|
215
367
|
}
|
|
216
368
|
|
|
@@ -237,6 +389,14 @@ export async function handlePlanSlice(
|
|
|
237
389
|
}
|
|
238
390
|
|
|
239
391
|
try {
|
|
392
|
+
const tasksDir = join(gsdProjectionRoot(basePath), "milestones", params.milestoneId, "slices", params.sliceId, "tasks");
|
|
393
|
+
for (const taskId of omittedTaskIds) {
|
|
394
|
+
const taskPlanPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
395
|
+
if (existsSync(taskPlanPath)) rmSync(taskPlanPath, { force: true });
|
|
396
|
+
const artifactPath = relative(gsdProjectionRoot(basePath), taskPlanPath).replace(/\\/g, "/");
|
|
397
|
+
deleteArtifactByPath(artifactPath);
|
|
398
|
+
}
|
|
399
|
+
|
|
240
400
|
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
241
401
|
invalidateStateCache();
|
|
242
402
|
clearParseCache();
|