gsd-pi 2.82.0-dev.ed17d078d → 3.0.0-dev.04f5ccf82
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 +146 -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 +72 -5
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +185 -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 +267 -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 +16 -4
- 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 +74 -3
- package/dist/resources/extensions/gsd/doctor-proactive.js +14 -2
- 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-conflict-state.js +21 -0
- 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-models.js +6 -4
- 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 +35 -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/tui/render-kit.js +33 -0
- 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/watch/header-renderer.js +34 -25
- 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 +8 -8
- 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 +8 -8
- 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/dist/welcome-screen.js +7 -8
- 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/src/__tests__/stream-process.test.mjs +32 -12
- 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/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.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/dynamic-border.test.ts +20 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +3 -0
- 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__/loader.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/loader.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/loader.test.js +24 -0
- package/packages/pi-tui/dist/__tests__/loader.test.js.map +1 -0
- 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 +72 -4
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/loader.js +3 -0
- package/packages/pi-tui/dist/components/loader.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 +1 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +117 -33
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/loader.test.ts +30 -0
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +90 -4
- package/packages/pi-tui/src/components/loader.ts +3 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/src/tui.ts +116 -33
- 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 +172 -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 +78 -5
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +208 -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 +284 -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 +17 -4
- 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 +73 -3
- package/src/resources/extensions/gsd/doctor-proactive.ts +18 -2
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +2 -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-conflict-state.ts +23 -0
- 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-models.ts +6 -4
- 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 +39 -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 +170 -3
- 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 +139 -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-git.test.ts +36 -1
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +33 -1
- 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/milestone-merge-stash-restore.test.ts +60 -0
- 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-missing-models-crash.test.ts +148 -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/tui-render-kit.test.ts +22 -0
- 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/tui/render-kit.ts +44 -0
- 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/watch/header-renderer.ts +35 -24
- 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 → w_ikFkx_-OHxisG9xjz4u}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{YEvjuT-fsFfYQhDSWtueS → w_ikFkx_-OHxisG9xjz4u}/_ssgManifest.js +0 -0
|
@@ -57,6 +57,12 @@ skills_used:
|
|
|
57
57
|
- {{howToVerifyThisTaskIsActuallyDone}}
|
|
58
58
|
- {{commandToRun_OR_behaviorToCheck}}
|
|
59
59
|
|
|
60
|
+
## Verify Rules
|
|
61
|
+
|
|
62
|
+
- Use a real executable check, not prose.
|
|
63
|
+
- If the check needs file-content assertions, write a `node:test` file and run it with `node --test` or a package test script.
|
|
64
|
+
- Do not use inline `node -e` assertions for verification.
|
|
65
|
+
|
|
60
66
|
## Observability Impact
|
|
61
67
|
|
|
62
68
|
<!-- OMIT THIS SECTION ENTIRELY for simple tasks that don't touch runtime boundaries,
|
|
@@ -72,7 +78,8 @@ skills_used:
|
|
|
72
78
|
<!-- Every input MUST be a backtick-wrapped file path. These paths are machine-parsed to
|
|
73
79
|
derive task dependencies — vague descriptions without paths break dependency detection.
|
|
74
80
|
For the first task in a slice with no prior task outputs, list the existing source files
|
|
75
|
-
this task reads or modifies.
|
|
81
|
+
this task reads or modifies.
|
|
82
|
+
Tool field: inputs must be an array of strings, e.g. ["src/index.ts"], never a single string. -->
|
|
76
83
|
|
|
77
84
|
- `{{filePath}}` — {{whatThisTaskNeedsFromPriorWork}}
|
|
78
85
|
|
|
@@ -82,6 +89,7 @@ skills_used:
|
|
|
82
89
|
or modifies. These paths are machine-parsed to derive task dependencies.
|
|
83
90
|
This task should produce a real increment toward making the slice goal/demo true. A full
|
|
84
91
|
slice plan should not be able to mark every task complete while the claimed slice behavior
|
|
85
|
-
still does not work at the stated proof level.
|
|
92
|
+
still does not work at the stated proof level.
|
|
93
|
+
Tool field: expectedOutput must be an array of strings, e.g. ["src/index.ts"], never a single string. -->
|
|
86
94
|
|
|
87
95
|
- `{{filePath}}` — {{whatThisTaskCreatesOrModifies}}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { mkdirSync, existsSync } from "node:fs";
|
|
11
|
-
import { transaction, getMilestone, getMilestoneSlices, getSliceTasks, updateMilestoneStatus, } from "../gsd-db.js";
|
|
11
|
+
import { transaction, getMilestone, getMilestoneSlices, getSliceTasks, getLatestAssessmentByScope, updateMilestoneStatus, } from "../gsd-db.js";
|
|
12
12
|
import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
13
13
|
import { isClosedStatus } from "../status-guards.js";
|
|
14
14
|
import { saveFile, clearParseCache } from "../files.js";
|
|
@@ -24,11 +24,11 @@ function renderMilestoneSummaryMarkdown(params, completedAt) {
|
|
|
24
24
|
const keyFiles = params.keyFiles ?? [];
|
|
25
25
|
const lessonsLearned = params.lessonsLearned ?? [];
|
|
26
26
|
const keyDecisionsYaml = keyDecisions.length > 0
|
|
27
|
-
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
28
|
-
: "
|
|
27
|
+
? `\n${keyDecisions.map(d => ` - ${d}`).join("\n")}`
|
|
28
|
+
: " []";
|
|
29
29
|
const keyFilesYaml = keyFiles.length > 0
|
|
30
|
-
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
31
|
-
: "
|
|
30
|
+
? `\n${keyFiles.map(f => ` - ${f}`).join("\n")}`
|
|
31
|
+
: " []";
|
|
32
32
|
const lessonsYaml = lessonsLearned.length > 0
|
|
33
33
|
? lessonsLearned.map(l => ` - ${l}`).join("\n")
|
|
34
34
|
: " - (none)";
|
|
@@ -37,10 +37,8 @@ id: ${params.milestoneId}
|
|
|
37
37
|
title: "${displayTitle}"
|
|
38
38
|
status: complete
|
|
39
39
|
completed_at: ${completedAt}
|
|
40
|
-
key_decisions
|
|
41
|
-
|
|
42
|
-
key_files:
|
|
43
|
-
${keyFilesYaml}
|
|
40
|
+
key_decisions:${keyDecisionsYaml}
|
|
41
|
+
key_files:${keyFilesYaml}
|
|
44
42
|
lessons_learned:
|
|
45
43
|
${lessonsYaml}
|
|
46
44
|
---
|
|
@@ -101,6 +99,14 @@ export async function handleCompleteMilestone(params, basePath) {
|
|
|
101
99
|
alreadyComplete = true;
|
|
102
100
|
return;
|
|
103
101
|
}
|
|
102
|
+
// Defense-in-depth: only a passing milestone validation permits closeout.
|
|
103
|
+
const validation = getLatestAssessmentByScope(params.milestoneId, "milestone-validation");
|
|
104
|
+
if (validation?.status !== "pass") {
|
|
105
|
+
guardError =
|
|
106
|
+
`Refusing to complete ${params.milestoneId}: latest milestone-validation verdict is ` +
|
|
107
|
+
`"${validation?.status ?? "absent"}". Only verdict=pass permits closeout.`;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
104
110
|
// Verify all slices are complete
|
|
105
111
|
const slices = getMilestoneSlices(params.milestoneId);
|
|
106
112
|
if (slices.length === 0) {
|
|
@@ -65,11 +65,11 @@ function renderSliceSummaryMarkdown(params) {
|
|
|
65
65
|
? affects.map(a => ` - ${a}`).join("\n")
|
|
66
66
|
: " []";
|
|
67
67
|
const keyFilesYaml = keyFiles.length > 0
|
|
68
|
-
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
69
|
-
: "
|
|
68
|
+
? `\n${keyFiles.map(f => ` - ${f}`).join("\n")}`
|
|
69
|
+
: " []";
|
|
70
70
|
const keyDecisionsYaml = keyDecisions.length > 0
|
|
71
|
-
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
72
|
-
: "
|
|
71
|
+
? `\n${keyDecisions.map(d => ` - ${d}`).join("\n")}`
|
|
72
|
+
: " []";
|
|
73
73
|
const patternsYaml = patternsEstablished.length > 0
|
|
74
74
|
? patternsEstablished.map(p => ` - ${p}`).join("\n")
|
|
75
75
|
: " - (none)";
|
|
@@ -106,10 +106,8 @@ requires:
|
|
|
106
106
|
${requiresYaml}
|
|
107
107
|
affects:
|
|
108
108
|
${affectsYaml}
|
|
109
|
-
key_files
|
|
110
|
-
|
|
111
|
-
key_decisions:
|
|
112
|
-
${keyDecisionsYaml}
|
|
109
|
+
key_files:${keyFilesYaml}
|
|
110
|
+
key_decisions:${keyDecisionsYaml}
|
|
113
111
|
patterns_established:
|
|
114
112
|
${patternsYaml}
|
|
115
113
|
observability_surfaces:
|
|
@@ -183,6 +181,31 @@ function renderUatMarkdown(params) {
|
|
|
183
181
|
${params.uatContent}
|
|
184
182
|
`;
|
|
185
183
|
}
|
|
184
|
+
function parseRequirementSection(summaryMd, heading, field) {
|
|
185
|
+
const headingLine = `## ${heading}\n\n`;
|
|
186
|
+
const start = summaryMd.indexOf(headingLine);
|
|
187
|
+
if (start === -1)
|
|
188
|
+
return [];
|
|
189
|
+
const contentStart = start + headingLine.length;
|
|
190
|
+
const nextHeading = summaryMd.indexOf("\n\n## ", contentStart);
|
|
191
|
+
const content = nextHeading === -1
|
|
192
|
+
? summaryMd.slice(contentStart)
|
|
193
|
+
: summaryMd.slice(contentStart, nextHeading);
|
|
194
|
+
return content
|
|
195
|
+
.split("\n")
|
|
196
|
+
.map((line) => line.trim())
|
|
197
|
+
.filter((line) => line.startsWith("- "))
|
|
198
|
+
.map((line) => line.slice(2).trim())
|
|
199
|
+
.map((line) => {
|
|
200
|
+
const pair = line.match(/^(.+?)\s*(?:—|-)\s+(.+)$/);
|
|
201
|
+
const id = pair ? pair[1].trim() : line.trim();
|
|
202
|
+
const detail = pair ? pair[2].trim() : "";
|
|
203
|
+
if (!id || !detail)
|
|
204
|
+
return null;
|
|
205
|
+
return { id, [field]: detail };
|
|
206
|
+
})
|
|
207
|
+
.filter((entry) => entry !== null);
|
|
208
|
+
}
|
|
186
209
|
/**
|
|
187
210
|
* Handle the complete_slice operation end-to-end.
|
|
188
211
|
*
|
|
@@ -218,6 +241,7 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
218
241
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
219
242
|
const completedAt = new Date().toISOString();
|
|
220
243
|
let guardError = null;
|
|
244
|
+
let existingSummaryMd = "";
|
|
221
245
|
transaction(() => {
|
|
222
246
|
// State machine preconditions (inside txn for atomicity).
|
|
223
247
|
// Milestone/slice not existing is OK — insertMilestone/insertSlice below will auto-create.
|
|
@@ -228,6 +252,7 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
228
252
|
return;
|
|
229
253
|
}
|
|
230
254
|
const slice = getSlice(params.milestoneId, params.sliceId);
|
|
255
|
+
existingSummaryMd = slice?.full_summary_md?.trim() ?? "";
|
|
231
256
|
if (slice && isClosedStatus(slice.status)) {
|
|
232
257
|
if (isStaleWrite("complete-slice")) {
|
|
233
258
|
guardError = "__stale_duplicate__";
|
|
@@ -272,8 +297,29 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
272
297
|
if (guardError) {
|
|
273
298
|
return { error: guardError };
|
|
274
299
|
}
|
|
300
|
+
const effectiveParams = { ...params };
|
|
301
|
+
if (existingSummaryMd) {
|
|
302
|
+
// Keep these heading names in lock-step with renderSliceSummaryMarkdown's
|
|
303
|
+
// section titles so omitted CompleteSliceParams requirement fields can be
|
|
304
|
+
// backfilled from previously rendered summary markdown.
|
|
305
|
+
if (effectiveParams.requirementsAdvanced === undefined) {
|
|
306
|
+
const parsed = parseRequirementSection(existingSummaryMd, "Requirements Advanced", "how");
|
|
307
|
+
if (parsed.length > 0)
|
|
308
|
+
effectiveParams.requirementsAdvanced = parsed;
|
|
309
|
+
}
|
|
310
|
+
if (effectiveParams.requirementsValidated === undefined) {
|
|
311
|
+
const parsed = parseRequirementSection(existingSummaryMd, "Requirements Validated", "proof");
|
|
312
|
+
if (parsed.length > 0)
|
|
313
|
+
effectiveParams.requirementsValidated = parsed;
|
|
314
|
+
}
|
|
315
|
+
if (effectiveParams.requirementsInvalidated === undefined) {
|
|
316
|
+
const parsed = parseRequirementSection(existingSummaryMd, "Requirements Invalidated or Re-scoped", "what");
|
|
317
|
+
if (parsed.length > 0)
|
|
318
|
+
effectiveParams.requirementsInvalidated = parsed;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
275
321
|
// Render summary markdown
|
|
276
|
-
const summaryMd = renderSliceSummaryMarkdown(
|
|
322
|
+
const summaryMd = renderSliceSummaryMarkdown(effectiveParams);
|
|
277
323
|
// Resolve and write summary to disk
|
|
278
324
|
let summaryPath;
|
|
279
325
|
const sliceDir = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
@@ -287,7 +333,7 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
287
333
|
mkdirSync(manualSliceDir, { recursive: true });
|
|
288
334
|
summaryPath = join(manualSliceDir, `${params.sliceId}-SUMMARY.md`);
|
|
289
335
|
}
|
|
290
|
-
const uatMd = renderUatMarkdown(
|
|
336
|
+
const uatMd = renderUatMarkdown(effectiveParams);
|
|
291
337
|
const uatPath = summaryPath.replace(/-SUMMARY\.md$/, "-UAT.md");
|
|
292
338
|
setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
|
|
293
339
|
let projectionStale = false;
|
|
@@ -1,9 +1,7 @@
|
|
|
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
|
import { EXEC_DEFAULTS, runExecSandbox, } from "../exec-sandbox.js";
|
|
4
|
+
import path from "node:path";
|
|
7
5
|
import { isContextModeEnabled } from "../preferences-types.js";
|
|
8
6
|
import { contextModeDisabledResult } from "./context-mode-tool-result.js";
|
|
9
7
|
export function buildExecOptions(baseDir, cfg, extras) {
|
|
@@ -41,6 +39,86 @@ function paramError(message) {
|
|
|
41
39
|
isError: true,
|
|
42
40
|
};
|
|
43
41
|
}
|
|
42
|
+
function escapeRegExp(value) {
|
|
43
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
44
|
+
}
|
|
45
|
+
function normalizeScanPath(value) {
|
|
46
|
+
return value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
47
|
+
}
|
|
48
|
+
function parseWorktreeBase(baseDir) {
|
|
49
|
+
const normalizedBase = normalizeScanPath(baseDir);
|
|
50
|
+
const marker = "/.gsd/worktrees/";
|
|
51
|
+
const markerIndex = normalizedBase.indexOf(marker);
|
|
52
|
+
if (markerIndex <= 0)
|
|
53
|
+
return null;
|
|
54
|
+
return {
|
|
55
|
+
originalRoot: normalizedBase.slice(0, markerIndex),
|
|
56
|
+
worktreeRoot: normalizedBase,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function pathInside(parent, target) {
|
|
60
|
+
const parentWithSep = parent.endsWith("/") ? parent : `${parent}/`;
|
|
61
|
+
return target === parent || target.startsWith(parentWithSep);
|
|
62
|
+
}
|
|
63
|
+
function stripWrappingQuotes(value) {
|
|
64
|
+
const trimmed = value.trim();
|
|
65
|
+
if (trimmed.length < 2)
|
|
66
|
+
return trimmed;
|
|
67
|
+
const first = trimmed[0];
|
|
68
|
+
const last = trimmed[trimmed.length - 1];
|
|
69
|
+
if ((first === "'" || first === '"' || first === "`") && last === first) {
|
|
70
|
+
return trimmed.slice(1, -1).trim();
|
|
71
|
+
}
|
|
72
|
+
return trimmed;
|
|
73
|
+
}
|
|
74
|
+
function extractPathLikeValues(script) {
|
|
75
|
+
const values = [];
|
|
76
|
+
const push = (candidate) => {
|
|
77
|
+
const cleaned = stripWrappingQuotes(candidate).trim();
|
|
78
|
+
if (!cleaned)
|
|
79
|
+
return;
|
|
80
|
+
values.push(cleaned);
|
|
81
|
+
};
|
|
82
|
+
const pushQuotedLiterals = (source, depth = 0) => {
|
|
83
|
+
for (const match of source.matchAll(/(["'`])((?:\\.|(?!\1).)*)\1/g)) {
|
|
84
|
+
push(match[2]);
|
|
85
|
+
if (depth < 2 && /["'`]/.test(match[2])) {
|
|
86
|
+
pushQuotedLiterals(match[2], depth + 1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
for (const match of script.matchAll(/(?:^|[;\n\r]|\&\&|\|\|)\s*cd\s+([^\n\r;|&]+)/g)) {
|
|
91
|
+
push(match[1]);
|
|
92
|
+
}
|
|
93
|
+
for (const match of script.matchAll(/process\.chdir\(\s*([^\n\r;]+?)\s*\)/g)) {
|
|
94
|
+
push(match[1]);
|
|
95
|
+
pushQuotedLiterals(match[1]);
|
|
96
|
+
}
|
|
97
|
+
pushQuotedLiterals(script);
|
|
98
|
+
return values;
|
|
99
|
+
}
|
|
100
|
+
function resolvesToOriginalRootOutsideWorktree(script, baseDir) {
|
|
101
|
+
const parsed = parseWorktreeBase(baseDir);
|
|
102
|
+
if (!parsed)
|
|
103
|
+
return false;
|
|
104
|
+
const normalizedWorktree = normalizeScanPath(path.resolve(parsed.worktreeRoot));
|
|
105
|
+
const normalizedOriginalRoot = normalizeScanPath(path.resolve(parsed.originalRoot));
|
|
106
|
+
for (const value of extractPathLikeValues(script)) {
|
|
107
|
+
const resolved = normalizeScanPath(path.resolve(normalizedWorktree, value));
|
|
108
|
+
if (pathInside(normalizedOriginalRoot, resolved) && !pathInside(normalizedWorktree, resolved)) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
function scriptReferencesOriginalRootFromWorktree(script, baseDir) {
|
|
115
|
+
const parsed = parseWorktreeBase(baseDir);
|
|
116
|
+
if (!parsed)
|
|
117
|
+
return false;
|
|
118
|
+
const normalizedScript = script.replace(/\\/g, "/");
|
|
119
|
+
const originalRootPattern = new RegExp(`${escapeRegExp(parsed.originalRoot)}(?=$|[\\s'"\\\`;)&|<>]|/(?!\\.gsd/worktrees(?:/|$)))`);
|
|
120
|
+
return originalRootPattern.test(normalizedScript);
|
|
121
|
+
}
|
|
44
122
|
export async function executeGsdExec(params, deps) {
|
|
45
123
|
if (!isEnabled(deps.preferences))
|
|
46
124
|
return contextModeDisabledResult("gsd_exec");
|
|
@@ -55,6 +133,10 @@ export async function executeGsdExec(params, deps) {
|
|
|
55
133
|
if (Buffer.byteLength(script, "utf8") > 200_000) {
|
|
56
134
|
return paramError("script exceeds the 200 KB length limit");
|
|
57
135
|
}
|
|
136
|
+
if (resolvesToOriginalRootOutsideWorktree(script, deps.baseDir)
|
|
137
|
+
|| scriptReferencesOriginalRootFromWorktree(script, deps.baseDir)) {
|
|
138
|
+
return paramError("script references the original project root while running inside a milestone worktree; use the active worktree path or relative paths");
|
|
139
|
+
}
|
|
58
140
|
const opts = buildExecOptions(deps.baseDir, deps.preferences?.context_mode, { env: deps.env, now: deps.now, generateId: deps.generateId });
|
|
59
141
|
const run = deps.run ?? runExecSandbox;
|
|
60
142
|
try {
|
|
@@ -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 { transaction, getMilestone, getMilestoneSlices, getSlice, insertMilestone, insertSlice, upsertMilestonePlanning, upsertSlicePlanning, } from "../gsd-db.js";
|
|
5
5
|
import { invalidateStateCache } from "../state.js";
|
|
6
6
|
import { renderRoadmapFromDb } from "../markdown-renderer.js";
|
|
@@ -77,6 +77,9 @@ function validateSlices(value) {
|
|
|
77
77
|
seen.add(sliceId);
|
|
78
78
|
if (!isNonEmptyString(title))
|
|
79
79
|
throw new Error(`slices[${index}].title must be a non-empty string`);
|
|
80
|
+
const titleIssue = validateTitle(title);
|
|
81
|
+
if (titleIssue)
|
|
82
|
+
throw new Error(`slices[${index}].title is invalid: ${titleIssue}`);
|
|
80
83
|
if (!isNonEmptyString(risk))
|
|
81
84
|
throw new Error(`slices[${index}].risk must be a non-empty string`);
|
|
82
85
|
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item))) {
|
|
@@ -127,6 +130,9 @@ function validateParams(params) {
|
|
|
127
130
|
throw new Error("title is required");
|
|
128
131
|
if (!isNonEmptyString(params?.vision))
|
|
129
132
|
throw new Error("vision is required");
|
|
133
|
+
const milestoneTitleIssue = validateTitle(params.title);
|
|
134
|
+
if (milestoneTitleIssue)
|
|
135
|
+
throw new Error(`title is invalid: ${milestoneTitleIssue}`);
|
|
130
136
|
return {
|
|
131
137
|
...params,
|
|
132
138
|
dependsOn: params.dependsOn ? validateStringArray(params.dependsOn, "dependsOn") : [],
|
|
@@ -1,7 +1,9 @@
|
|
|
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
|
-
import { isNonEmptyString } from "../validation.js";
|
|
4
|
-
import { transaction, getMilestone, getSlice, insertTask, upsertSlicePlanning, upsertTaskPlanning, insertGateRow, updateSliceStatus, } from "../gsd-db.js";
|
|
5
|
+
import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
6
|
+
import { transaction, getMilestone, getSlice, getSliceTasks, insertTask, upsertSlicePlanning, upsertTaskPlanning, insertGateRow, updateSliceStatus, setSliceSketchFlag, deleteTask, deleteArtifactByPath, } from "../gsd-db.js";
|
|
5
7
|
import { invalidateStateCache } from "../state.js";
|
|
6
8
|
import { renderPlanFromDb } from "../markdown-renderer.js";
|
|
7
9
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
@@ -9,6 +11,21 @@ import { writeManifest } from "../workflow-manifest.js";
|
|
|
9
11
|
import { appendEvent } from "../workflow-events.js";
|
|
10
12
|
import { logWarning } from "../workflow-logger.js";
|
|
11
13
|
import { validatePlanningPathScope } from "../planning-path-scope.js";
|
|
14
|
+
import { checkFilePathConsistency, checkTaskOrdering } from "../pre-execution-checks.js";
|
|
15
|
+
import { buildTaskFileName, gsdProjectionRoot } from "../paths.js";
|
|
16
|
+
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
17
|
+
import { createRepositoryRegistryFromPreferences } from "../repository-registry.js";
|
|
18
|
+
function validateRepositoryTargetIds(field, value) {
|
|
19
|
+
if (value === undefined)
|
|
20
|
+
return null;
|
|
21
|
+
const ids = validateStringArray(value, field);
|
|
22
|
+
if (ids.length === 0)
|
|
23
|
+
throw new Error(`${field} must include at least one repository id when provided`);
|
|
24
|
+
const deduped = Array.from(new Set(ids.map((id) => id.trim()).filter(Boolean)));
|
|
25
|
+
if (deduped.length === 0)
|
|
26
|
+
throw new Error(`${field} must include at least one repository id when provided`);
|
|
27
|
+
return deduped;
|
|
28
|
+
}
|
|
12
29
|
function validateTasks(value) {
|
|
13
30
|
if (!Array.isArray(value) || value.length === 0) {
|
|
14
31
|
throw new Error("tasks must be a non-empty array");
|
|
@@ -28,6 +45,7 @@ function validateTasks(value) {
|
|
|
28
45
|
const inputs = obj.inputs;
|
|
29
46
|
const expectedOutput = obj.expectedOutput;
|
|
30
47
|
const observabilityImpact = obj.observabilityImpact;
|
|
48
|
+
const targetRepositories = obj.targetRepositories;
|
|
31
49
|
if (!isNonEmptyString(taskId))
|
|
32
50
|
throw new Error(`tasks[${index}].taskId must be a non-empty string`);
|
|
33
51
|
if (seen.has(taskId))
|
|
@@ -39,30 +57,26 @@ function validateTasks(value) {
|
|
|
39
57
|
throw new Error(`tasks[${index}].description must be a non-empty string`);
|
|
40
58
|
if (!isNonEmptyString(estimate))
|
|
41
59
|
throw new Error(`tasks[${index}].estimate must be a non-empty string`);
|
|
42
|
-
|
|
43
|
-
throw new Error(`tasks[${index}].files must be an array of non-empty strings`);
|
|
44
|
-
}
|
|
60
|
+
const validatedFiles = validateStringArray(files, `tasks[${index}].files`);
|
|
45
61
|
if (!isNonEmptyString(verify))
|
|
46
62
|
throw new Error(`tasks[${index}].verify must be a non-empty string`);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
if (!Array.isArray(expectedOutput) || expectedOutput.some((item) => !isNonEmptyString(item))) {
|
|
51
|
-
throw new Error(`tasks[${index}].expectedOutput must be an array of non-empty strings`);
|
|
52
|
-
}
|
|
63
|
+
const validatedInputs = validateStringArray(inputs, `tasks[${index}].inputs`);
|
|
64
|
+
const validatedExpectedOutput = validateStringArray(expectedOutput, `tasks[${index}].expectedOutput`);
|
|
53
65
|
if (observabilityImpact !== undefined && !isNonEmptyString(observabilityImpact)) {
|
|
54
66
|
throw new Error(`tasks[${index}].observabilityImpact must be a non-empty string when provided`);
|
|
55
67
|
}
|
|
68
|
+
const validatedTargetRepositories = validateRepositoryTargetIds(`tasks[${index}].targetRepositories`, targetRepositories);
|
|
56
69
|
return {
|
|
57
70
|
taskId,
|
|
58
71
|
title,
|
|
59
72
|
description,
|
|
60
73
|
estimate,
|
|
61
|
-
files,
|
|
74
|
+
files: validatedFiles,
|
|
62
75
|
verify,
|
|
63
|
-
inputs,
|
|
64
|
-
expectedOutput,
|
|
76
|
+
inputs: validatedInputs,
|
|
77
|
+
expectedOutput: validatedExpectedOutput,
|
|
65
78
|
observabilityImpact: typeof observabilityImpact === "string" ? observabilityImpact : "",
|
|
79
|
+
targetRepositories: validatedTargetRepositories ?? undefined,
|
|
66
80
|
};
|
|
67
81
|
});
|
|
68
82
|
}
|
|
@@ -73,6 +87,7 @@ function validateParams(params) {
|
|
|
73
87
|
throw new Error("sliceId is required");
|
|
74
88
|
if (!isNonEmptyString(params?.goal))
|
|
75
89
|
throw new Error("goal is required");
|
|
90
|
+
const validatedTargetRepositories = validateRepositoryTargetIds("targetRepositories", params.targetRepositories);
|
|
76
91
|
return {
|
|
77
92
|
...params,
|
|
78
93
|
// Keep optional enrichment fields empty when omitted. The renderer supplies
|
|
@@ -81,9 +96,94 @@ function validateParams(params) {
|
|
|
81
96
|
proofLevel: params.proofLevel ?? "",
|
|
82
97
|
integrationClosure: params.integrationClosure ?? "",
|
|
83
98
|
observabilityImpact: params.observabilityImpact ?? "",
|
|
99
|
+
targetRepositories: validatedTargetRepositories ?? undefined,
|
|
84
100
|
tasks: validateTasks(params.tasks),
|
|
85
101
|
};
|
|
86
102
|
}
|
|
103
|
+
function loadRepositoryRegistry(basePath) {
|
|
104
|
+
const loaded = loadEffectiveGSDPreferences(basePath);
|
|
105
|
+
return createRepositoryRegistryFromPreferences(basePath, loaded?.preferences);
|
|
106
|
+
}
|
|
107
|
+
function validateReferencedRepositories(params, registry) {
|
|
108
|
+
const known = new Set(registry.repositories.map((repo) => repo.id));
|
|
109
|
+
const missing = [];
|
|
110
|
+
const noteMissing = (id) => {
|
|
111
|
+
if (!known.has(id) && !missing.includes(id))
|
|
112
|
+
missing.push(id);
|
|
113
|
+
};
|
|
114
|
+
for (const id of params.targetRepositories ?? [])
|
|
115
|
+
noteMissing(id);
|
|
116
|
+
for (const task of params.tasks) {
|
|
117
|
+
for (const id of task.targetRepositories ?? [])
|
|
118
|
+
noteMissing(id);
|
|
119
|
+
}
|
|
120
|
+
if (missing.length === 0)
|
|
121
|
+
return null;
|
|
122
|
+
return `unknown targetRepositories: ${missing.join(", ")}. Declared repositories: ${Array.from(known).join(", ")}`;
|
|
123
|
+
}
|
|
124
|
+
function resolveAllowedRootsForPathScope(params, registry) {
|
|
125
|
+
const requested = new Set();
|
|
126
|
+
for (const id of params.targetRepositories ?? [])
|
|
127
|
+
requested.add(id);
|
|
128
|
+
for (const task of params.tasks) {
|
|
129
|
+
for (const id of task.targetRepositories ?? [])
|
|
130
|
+
requested.add(id);
|
|
131
|
+
}
|
|
132
|
+
if (requested.size === 0)
|
|
133
|
+
return [registry.projectRoot];
|
|
134
|
+
const roots = Array.from(requested)
|
|
135
|
+
.map((id) => registry.byId.get(id)?.root)
|
|
136
|
+
.filter((root) => typeof root === "string");
|
|
137
|
+
return roots.length > 0 ? roots : [registry.projectRoot];
|
|
138
|
+
}
|
|
139
|
+
function toTaskRows(params) {
|
|
140
|
+
return params.tasks.map((task, index) => ({
|
|
141
|
+
milestone_id: params.milestoneId,
|
|
142
|
+
slice_id: params.sliceId,
|
|
143
|
+
id: task.taskId,
|
|
144
|
+
title: task.title,
|
|
145
|
+
status: "pending",
|
|
146
|
+
one_liner: "",
|
|
147
|
+
narrative: "",
|
|
148
|
+
verification_result: "",
|
|
149
|
+
duration: "",
|
|
150
|
+
completed_at: null,
|
|
151
|
+
blocker_discovered: false,
|
|
152
|
+
deviations: "",
|
|
153
|
+
known_issues: "",
|
|
154
|
+
key_files: [],
|
|
155
|
+
key_decisions: [],
|
|
156
|
+
full_summary_md: "",
|
|
157
|
+
description: task.description,
|
|
158
|
+
estimate: task.estimate,
|
|
159
|
+
files: task.files,
|
|
160
|
+
verify: task.verify,
|
|
161
|
+
inputs: task.inputs,
|
|
162
|
+
expected_output: task.expectedOutput,
|
|
163
|
+
observability_impact: task.observabilityImpact ?? "",
|
|
164
|
+
full_plan_md: task.fullPlanMd ?? "",
|
|
165
|
+
target_repositories: task.targetRepositories ?? params.targetRepositories ?? ["project"],
|
|
166
|
+
sequence: index + 1,
|
|
167
|
+
blocker_source: "",
|
|
168
|
+
escalation_pending: 0,
|
|
169
|
+
escalation_awaiting_review: 0,
|
|
170
|
+
escalation_artifact_path: null,
|
|
171
|
+
escalation_override_applied_at: null,
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
function validateTaskPathsBeforePersist(params, basePath) {
|
|
175
|
+
const taskRows = toTaskRows(params);
|
|
176
|
+
const checks = [
|
|
177
|
+
...checkFilePathConsistency(taskRows, basePath),
|
|
178
|
+
...checkTaskOrdering(taskRows, basePath),
|
|
179
|
+
];
|
|
180
|
+
const blocking = checks.filter((check) => !check.passed && check.blocking);
|
|
181
|
+
if (blocking.length === 0)
|
|
182
|
+
return null;
|
|
183
|
+
return blocking
|
|
184
|
+
.map((check) => `[${check.category}] ${check.target}: ${check.message}`)
|
|
185
|
+
.join("\n");
|
|
186
|
+
}
|
|
87
187
|
export async function handlePlanSlice(rawParams, basePath) {
|
|
88
188
|
let params;
|
|
89
189
|
try {
|
|
@@ -92,18 +192,29 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
92
192
|
catch (err) {
|
|
93
193
|
return { error: `validation failed: ${err.message}` };
|
|
94
194
|
}
|
|
195
|
+
const repositoryRegistry = loadRepositoryRegistry(basePath);
|
|
196
|
+
const repoValidationError = validateReferencedRepositories(params, repositoryRegistry);
|
|
197
|
+
if (repoValidationError) {
|
|
198
|
+
return { error: `validation failed: ${repoValidationError}` };
|
|
199
|
+
}
|
|
200
|
+
const allowedAbsoluteRoots = resolveAllowedRootsForPathScope(params, repositoryRegistry);
|
|
95
201
|
const pathScopeError = validatePlanningPathScope(basePath, params.tasks.flatMap((task, index) => [
|
|
96
202
|
{ field: `tasks[${index}].files`, values: task.files },
|
|
97
203
|
{ field: `tasks[${index}].inputs`, values: task.inputs },
|
|
98
204
|
{ field: `tasks[${index}].expectedOutput`, values: task.expectedOutput },
|
|
99
|
-
]));
|
|
205
|
+
]), allowedAbsoluteRoots);
|
|
100
206
|
if (pathScopeError) {
|
|
101
207
|
return { error: `validation failed: ${pathScopeError}` };
|
|
102
208
|
}
|
|
209
|
+
const pathError = validateTaskPathsBeforePersist(params, basePath);
|
|
210
|
+
if (pathError) {
|
|
211
|
+
return { error: `pre-execution validation failed:\n${pathError}` };
|
|
212
|
+
}
|
|
103
213
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
104
214
|
// Guards must be inside the transaction so the state they check cannot
|
|
105
215
|
// change between the read and the write (#2723).
|
|
106
216
|
let guardError = null;
|
|
217
|
+
let omittedTaskIds = [];
|
|
107
218
|
try {
|
|
108
219
|
transaction(() => {
|
|
109
220
|
const parentMilestone = getMilestone(params.milestoneId);
|
|
@@ -124,16 +235,32 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
124
235
|
guardError = `cannot re-plan slice ${params.sliceId}: it is already complete — use gsd_slice_reopen first`;
|
|
125
236
|
return;
|
|
126
237
|
}
|
|
238
|
+
const newTaskIds = new Set(params.tasks.map((task) => task.taskId));
|
|
239
|
+
const existingTasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
240
|
+
omittedTaskIds = existingTasks
|
|
241
|
+
.filter((task) => !newTaskIds.has(task.id))
|
|
242
|
+
.map((task) => task.id);
|
|
243
|
+
for (const task of existingTasks) {
|
|
244
|
+
if (!newTaskIds.has(task.id) && isClosedStatus(task.status)) {
|
|
245
|
+
guardError = `cannot remove completed task ${task.id}`;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
127
249
|
if (isDeferredStatus(parentSlice.status)) {
|
|
128
250
|
updateSliceStatus(params.milestoneId, params.sliceId, "pending");
|
|
129
251
|
}
|
|
252
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
130
253
|
upsertSlicePlanning(params.milestoneId, params.sliceId, {
|
|
131
254
|
goal: params.goal,
|
|
132
255
|
successCriteria: params.successCriteria,
|
|
133
256
|
proofLevel: params.proofLevel,
|
|
134
257
|
integrationClosure: params.integrationClosure,
|
|
135
258
|
observabilityImpact: params.observabilityImpact,
|
|
259
|
+
targetRepositories: params.targetRepositories ?? ["project"],
|
|
136
260
|
});
|
|
261
|
+
for (const taskId of omittedTaskIds) {
|
|
262
|
+
deleteTask(params.milestoneId, params.sliceId, taskId);
|
|
263
|
+
}
|
|
137
264
|
for (const task of params.tasks) {
|
|
138
265
|
insertTask({
|
|
139
266
|
id: task.taskId,
|
|
@@ -152,6 +279,7 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
152
279
|
expectedOutput: task.expectedOutput,
|
|
153
280
|
observabilityImpact: task.observabilityImpact ?? "",
|
|
154
281
|
fullPlanMd: task.fullPlanMd,
|
|
282
|
+
targetRepositories: task.targetRepositories ?? params.targetRepositories ?? ["project"],
|
|
155
283
|
});
|
|
156
284
|
}
|
|
157
285
|
// Seed quality gate rows inside the transaction — all-or-nothing with
|
|
@@ -176,6 +304,14 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
176
304
|
return { error: guardError };
|
|
177
305
|
}
|
|
178
306
|
try {
|
|
307
|
+
const tasksDir = join(gsdProjectionRoot(basePath), "milestones", params.milestoneId, "slices", params.sliceId, "tasks");
|
|
308
|
+
for (const taskId of omittedTaskIds) {
|
|
309
|
+
const taskPlanPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
310
|
+
if (existsSync(taskPlanPath))
|
|
311
|
+
rmSync(taskPlanPath, { force: true });
|
|
312
|
+
const artifactPath = relative(gsdProjectionRoot(basePath), taskPlanPath).replace(/\\/g, "/");
|
|
313
|
+
deleteArtifactByPath(artifactPath);
|
|
314
|
+
}
|
|
179
315
|
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
180
316
|
invalidateStateCache();
|
|
181
317
|
clearParseCache();
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* despite passing validation.
|
|
10
10
|
*/
|
|
11
11
|
import { join } from "node:path";
|
|
12
|
-
import { transaction, insertAssessment, getMilestoneSlices, } from "../gsd-db.js";
|
|
12
|
+
import { transaction, insertAssessment, getMilestoneSlices, getMilestone, } from "../gsd-db.js";
|
|
13
13
|
import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
14
14
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
15
15
|
import { saveFile, clearParseCache } from "../files.js";
|
|
@@ -20,6 +20,27 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
20
20
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
21
21
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
22
22
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
23
|
+
function isVerificationNotApplicable(value) {
|
|
24
|
+
const v = (value ?? "").toLowerCase().trim().replace(/[.\s]+$/, "");
|
|
25
|
+
if (!v || v === "none")
|
|
26
|
+
return true;
|
|
27
|
+
return /^(?:none(?:[\s._\u2014-]+[\s\S]*)?|n\/?a(?:[\s._\u2014-]+[\s\S]*)?|not[\s._-]+(?:applicable|required|needed|provided)(?:[\s._\u2014-]+[\s\S]*)?|no[\s._-]+operational[\s\S]*)$/i.test(v);
|
|
28
|
+
}
|
|
29
|
+
function getRequiredVerificationClasses(milestoneId) {
|
|
30
|
+
const milestone = getMilestone(milestoneId);
|
|
31
|
+
if (!milestone)
|
|
32
|
+
return [];
|
|
33
|
+
const required = [];
|
|
34
|
+
if (!isVerificationNotApplicable(milestone.verification_contract))
|
|
35
|
+
required.push("Contract");
|
|
36
|
+
if (!isVerificationNotApplicable(milestone.verification_integration))
|
|
37
|
+
required.push("Integration");
|
|
38
|
+
if (!isVerificationNotApplicable(milestone.verification_operational))
|
|
39
|
+
required.push("Operational");
|
|
40
|
+
if (!isVerificationNotApplicable(milestone.verification_uat))
|
|
41
|
+
required.push("UAT");
|
|
42
|
+
return required;
|
|
43
|
+
}
|
|
23
44
|
function renderValidationMarkdown(params) {
|
|
24
45
|
let md = `---
|
|
25
46
|
verdict: ${params.verdict}
|
|
@@ -59,6 +80,16 @@ export async function handleValidateMilestone(params, basePath, opts) {
|
|
|
59
80
|
if (!isValidMilestoneVerdict(params.verdict)) {
|
|
60
81
|
return { error: `verdict must be one of: ${VALIDATION_VERDICTS.join(", ")}` };
|
|
61
82
|
}
|
|
83
|
+
const requiredClasses = getRequiredVerificationClasses(params.milestoneId);
|
|
84
|
+
if (requiredClasses.length > 0) {
|
|
85
|
+
const verificationClasses = params.verificationClasses ?? "";
|
|
86
|
+
const missingClass = requiredClasses.find((className) => !new RegExp(`\\b${className}\\b`, "i").test(verificationClasses));
|
|
87
|
+
if (missingClass) {
|
|
88
|
+
return {
|
|
89
|
+
error: `verificationClasses must include canonical row "${missingClass}" because this milestone planned ${missingClass.toLowerCase()} verification`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
62
93
|
// ── Resolve paths and render markdown ────────────────────────────────
|
|
63
94
|
// #4761: route through the canonical-root resolver so that when a live
|
|
64
95
|
// worktree exists for this milestone, validation reads/writes the
|