gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.20138ae42
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 +50 -31
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +30 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +85 -12
- package/dist/resources/extensions/gsd/auto-verification.js +28 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +158 -55
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +25 -6
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +38 -1
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +39 -1
- package/dist/resources/extensions/gsd/gsd-db.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +93 -111
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/api/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 +12 -12
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +6 -5
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +14 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +36 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +92 -9
- package/src/resources/extensions/gsd/auto-verification.ts +36 -34
- package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +167 -53
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +33 -6
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +41 -1
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- 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/git-service.ts +45 -1
- package/src/resources/extensions/gsd/gsd-db.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +126 -128
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +129 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// GSD-2 — ADR-005 Phase 3b: surface ProviderSwitchReport from pi-ai.
|
|
2
|
+
//
|
|
3
|
+
// pi-ai builds a ProviderSwitchReport on every cross-provider transform but
|
|
4
|
+
// only logs it to stderr when GSD_VERBOSE=1. This module installs a
|
|
5
|
+
// single-subscriber observer that surfaces non-empty reports through GSD's
|
|
6
|
+
// three usual telemetry surfaces:
|
|
7
|
+
//
|
|
8
|
+
// 1. UOK audit event (category model-policy, type provider-switch) — only
|
|
9
|
+
// when an auto trace is active.
|
|
10
|
+
// 2. Persistent notification (.gsd/notifications.jsonl, severity warning) —
|
|
11
|
+
// whenever the GSD basePath is known, so users see the loss in the
|
|
12
|
+
// dashboard / status surface without GSD_VERBOSE.
|
|
13
|
+
// 3. In-memory counter, exposed via getProviderSwitchStats() so any
|
|
14
|
+
// caller (dashboard, doctor, tests) can read the rollup.
|
|
15
|
+
import { setProviderSwitchObserver } from "@gsd/pi-ai";
|
|
16
|
+
import { autoSession } from "./auto-runtime-state.js";
|
|
17
|
+
import { appendNotification } from "./notification-store.js";
|
|
18
|
+
import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
|
|
19
|
+
const INTERACTIVE_TRACE_KEY = "interactive";
|
|
20
|
+
let installed = false;
|
|
21
|
+
let totalSwitches = 0;
|
|
22
|
+
const totals = {
|
|
23
|
+
thinkingBlocksDropped: 0,
|
|
24
|
+
thinkingBlocksDowngraded: 0,
|
|
25
|
+
toolCallIdsRemapped: 0,
|
|
26
|
+
syntheticToolResultsInserted: 0,
|
|
27
|
+
thoughtSignaturesDropped: 0,
|
|
28
|
+
};
|
|
29
|
+
const byTrace = new Map();
|
|
30
|
+
let lastReport = null;
|
|
31
|
+
let lastAt = null;
|
|
32
|
+
/** Format a one-line summary suitable for a notification message. */
|
|
33
|
+
function summarize(report) {
|
|
34
|
+
const parts = [];
|
|
35
|
+
if (report.thinkingBlocksDropped > 0)
|
|
36
|
+
parts.push(`${report.thinkingBlocksDropped} thinking dropped`);
|
|
37
|
+
if (report.thinkingBlocksDowngraded > 0)
|
|
38
|
+
parts.push(`${report.thinkingBlocksDowngraded} thinking downgraded`);
|
|
39
|
+
if (report.toolCallIdsRemapped > 0)
|
|
40
|
+
parts.push(`${report.toolCallIdsRemapped} tool ids remapped`);
|
|
41
|
+
if (report.syntheticToolResultsInserted > 0)
|
|
42
|
+
parts.push(`${report.syntheticToolResultsInserted} synthetic tool results`);
|
|
43
|
+
if (report.thoughtSignaturesDropped > 0)
|
|
44
|
+
parts.push(`${report.thoughtSignaturesDropped} thought signatures dropped`);
|
|
45
|
+
return `Provider switch ${report.fromApi} → ${report.toApi}: ${parts.join(", ")}`;
|
|
46
|
+
}
|
|
47
|
+
function recordReport(report) {
|
|
48
|
+
const now = new Date().toISOString();
|
|
49
|
+
totalSwitches += 1;
|
|
50
|
+
totals.thinkingBlocksDropped += report.thinkingBlocksDropped;
|
|
51
|
+
totals.thinkingBlocksDowngraded += report.thinkingBlocksDowngraded;
|
|
52
|
+
totals.toolCallIdsRemapped += report.toolCallIdsRemapped;
|
|
53
|
+
totals.syntheticToolResultsInserted += report.syntheticToolResultsInserted;
|
|
54
|
+
totals.thoughtSignaturesDropped += report.thoughtSignaturesDropped;
|
|
55
|
+
lastReport = report;
|
|
56
|
+
lastAt = now;
|
|
57
|
+
const traceKey = autoSession.currentTraceId ?? INTERACTIVE_TRACE_KEY;
|
|
58
|
+
const existing = byTrace.get(traceKey);
|
|
59
|
+
if (existing) {
|
|
60
|
+
existing.switches += 1;
|
|
61
|
+
existing.lastReport = report;
|
|
62
|
+
existing.lastAt = now;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
byTrace.set(traceKey, { switches: 1, lastReport: report, lastAt: now });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function emitAudit(report) {
|
|
69
|
+
const traceId = autoSession.currentTraceId;
|
|
70
|
+
const basePath = autoSession.basePath;
|
|
71
|
+
if (!traceId || !basePath)
|
|
72
|
+
return;
|
|
73
|
+
try {
|
|
74
|
+
emitUokAuditEvent(basePath, buildAuditEnvelope({
|
|
75
|
+
traceId,
|
|
76
|
+
category: "model-policy",
|
|
77
|
+
type: "provider-switch",
|
|
78
|
+
payload: {
|
|
79
|
+
fromApi: report.fromApi,
|
|
80
|
+
toApi: report.toApi,
|
|
81
|
+
thinkingBlocksDropped: report.thinkingBlocksDropped,
|
|
82
|
+
thinkingBlocksDowngraded: report.thinkingBlocksDowngraded,
|
|
83
|
+
toolCallIdsRemapped: report.toolCallIdsRemapped,
|
|
84
|
+
syntheticToolResultsInserted: report.syntheticToolResultsInserted,
|
|
85
|
+
thoughtSignaturesDropped: report.thoughtSignaturesDropped,
|
|
86
|
+
},
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Audit emission is best-effort. Counter + notification still fire.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function emitNotification(report) {
|
|
94
|
+
try {
|
|
95
|
+
appendNotification(summarize(report), "warning", "workflow-logger");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Notification persistence is best-effort.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function handleReport(report) {
|
|
102
|
+
recordReport(report);
|
|
103
|
+
emitAudit(report);
|
|
104
|
+
emitNotification(report);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Install the pi-ai observer. Idempotent — calling more than once is a no-op
|
|
108
|
+
* after the first install.
|
|
109
|
+
*/
|
|
110
|
+
export function installProviderSwitchObserver() {
|
|
111
|
+
if (installed)
|
|
112
|
+
return;
|
|
113
|
+
setProviderSwitchObserver(handleReport);
|
|
114
|
+
installed = true;
|
|
115
|
+
}
|
|
116
|
+
/** Uninstall the observer. Intended for tests. */
|
|
117
|
+
export function uninstallProviderSwitchObserver() {
|
|
118
|
+
setProviderSwitchObserver(undefined);
|
|
119
|
+
installed = false;
|
|
120
|
+
}
|
|
121
|
+
/** Read-only snapshot of the in-memory rollup. */
|
|
122
|
+
export function getProviderSwitchStats() {
|
|
123
|
+
const trace = {};
|
|
124
|
+
for (const [key, value] of byTrace) {
|
|
125
|
+
trace[key] = { switches: value.switches, lastReport: { ...value.lastReport }, lastAt: value.lastAt };
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
totalSwitches,
|
|
129
|
+
totals: { ...totals },
|
|
130
|
+
byTrace: trace,
|
|
131
|
+
lastReport: lastReport ? { ...lastReport } : null,
|
|
132
|
+
lastAt,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/** Reset the in-memory rollup. Intended for tests. */
|
|
136
|
+
export function _resetProviderSwitchStats() {
|
|
137
|
+
totalSwitches = 0;
|
|
138
|
+
totals.thinkingBlocksDropped = 0;
|
|
139
|
+
totals.thinkingBlocksDowngraded = 0;
|
|
140
|
+
totals.toolCallIdsRemapped = 0;
|
|
141
|
+
totals.syntheticToolResultsInserted = 0;
|
|
142
|
+
totals.thoughtSignaturesDropped = 0;
|
|
143
|
+
byTrace.clear();
|
|
144
|
+
lastReport = null;
|
|
145
|
+
lastAt = null;
|
|
146
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// GSD-2 — Smart entry routing decisions.
|
|
2
|
+
// Pure route selection for /gsd guided wizard choices.
|
|
3
|
+
export function resolveGuidedExecuteLaunchMode(isolationMode) {
|
|
4
|
+
return isolationMode === "worktree" ? "auto-step" : "guided-dispatch";
|
|
5
|
+
}
|
|
6
|
+
export function resolveActiveTaskChoiceRoute(input) {
|
|
7
|
+
if (input.choice === "auto") {
|
|
8
|
+
return {
|
|
9
|
+
kind: "auto-bootstrap",
|
|
10
|
+
verboseMode: false,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
if (input.choice === "execute") {
|
|
14
|
+
if (resolveGuidedExecuteLaunchMode(input.isolationMode) === "auto-step") {
|
|
15
|
+
return {
|
|
16
|
+
kind: "auto-bootstrap",
|
|
17
|
+
verboseMode: false,
|
|
18
|
+
options: {
|
|
19
|
+
step: true,
|
|
20
|
+
milestoneLock: input.milestoneId,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
kind: "guided-dispatch",
|
|
26
|
+
unitType: "execute-task",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (input.choice === "status") {
|
|
30
|
+
return { kind: "status" };
|
|
31
|
+
}
|
|
32
|
+
if (input.choice === "milestone_actions") {
|
|
33
|
+
return { kind: "milestone-actions" };
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`Invalid ActiveTaskChoice: ${input.choice}`);
|
|
36
|
+
}
|
|
@@ -10,6 +10,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
10
10
|
import { getErrorMessage } from "../../error-utils.js";
|
|
11
11
|
import { nativeAddPaths, nativeCheckoutTheirs, nativeCommit, nativeConflictFiles, nativeMergeAbort, nativeRebaseAbort, nativeResetHard, } from "../../native-git-bridge.js";
|
|
12
12
|
import { logError, logWarning } from "../../workflow-logger.js";
|
|
13
|
+
import { isGsdWorktreePath } from "../../worktree-root.js";
|
|
13
14
|
const SILENT_NOTIFY = () => { };
|
|
14
15
|
function resolveGitDir(basePath) {
|
|
15
16
|
try {
|
|
@@ -23,7 +24,11 @@ function resolveGitDir(basePath) {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
catch (err) {
|
|
26
|
-
|
|
27
|
+
const message = getErrorMessage(err);
|
|
28
|
+
logWarning("recovery", `gitdir resolution failed: ${message}`);
|
|
29
|
+
if (isGsdWorktreePath(basePath)) {
|
|
30
|
+
throw new Error(`Worktree integrity failure: ${basePath} is not a valid git worktree (git rev-parse failed: ${message.split("\n")[0]}). Repair or recreate the worktree before retrying.`);
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
return join(basePath, ".git");
|
|
29
34
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
// Project/App: GSD-2
|
|
2
2
|
// File Purpose: ADR-017 unregistered-milestone drift handler. Detects
|
|
3
3
|
// milestones whose on-disk directory has meaningful content (ROADMAP/
|
|
4
|
-
// CONTEXT/SUMMARY) but no DB row, then
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// CONTEXT/SUMMARY) but no DB row, then fails closed with an explicit recovery
|
|
5
|
+
// instruction. Markdown hierarchy import is reserved for operator-controlled
|
|
6
|
+
// migration/recovery commands, not automatic runtime reconciliation.
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
8
|
import { getMilestone, isDbAvailable } from "../../gsd-db.js";
|
|
9
|
-
import { migrateHierarchyToDb } from "../../md-importer.js";
|
|
10
9
|
import { findMilestoneIds } from "../../milestone-ids.js";
|
|
11
10
|
import { resolveMilestoneFile } from "../../paths.js";
|
|
12
11
|
function milestoneHasContent(basePath, milestoneId) {
|
|
@@ -31,17 +30,13 @@ export function detectUnregisteredMilestoneDrift(_state, ctx) {
|
|
|
31
30
|
return drifts;
|
|
32
31
|
}
|
|
33
32
|
/**
|
|
34
|
-
* Repair
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* Note: even though we receive one record at a time, the importer is a
|
|
39
|
-
* project-wide operation. Repeated invocation across multiple drift records
|
|
40
|
-
* in the same pass is wasteful but safe; a future optimization could
|
|
41
|
-
* coalesce by checking whether the importer has already run this pass.
|
|
33
|
+
* Repair intentionally fails closed. The project-root DB is authoritative at
|
|
34
|
+
* runtime; markdown-only milestones must be imported through an explicit
|
|
35
|
+
* migration/recovery command so operators opt into changing canonical state.
|
|
42
36
|
*/
|
|
43
|
-
export function repairUnregisteredMilestone(
|
|
44
|
-
|
|
37
|
+
export function repairUnregisteredMilestone(record, _ctx) {
|
|
38
|
+
throw new Error(`Milestone ${record.milestoneId} exists only as markdown projection. ` +
|
|
39
|
+
"Runtime reconciliation will not import markdown into the authoritative DB; run explicit GSD recovery/migration if this markdown should repopulate the database.");
|
|
45
40
|
}
|
|
46
41
|
export const unregisteredMilestoneHandler = {
|
|
47
42
|
kind: "unregistered-milestone",
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
// Project/App: GSD-2
|
|
2
2
|
// File Purpose: ADR-017 roadmap-divergence drift handler. Detects mismatches
|
|
3
|
-
// between ROADMAP.md (parsed slice sequence
|
|
4
|
-
// DB slice rows for that milestone, then
|
|
5
|
-
//
|
|
3
|
+
// between ROADMAP.md (parsed slice sequence, depends declarations, and
|
|
4
|
+
// checkboxes) and the DB slice rows for that milestone, then re-renders the
|
|
5
|
+
// ROADMAP projection from the authoritative DB rows.
|
|
6
6
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
-
import { getMilestone, getMilestoneSlices, isDbAvailable,
|
|
8
|
-
import {
|
|
7
|
+
import { getMilestone, getMilestoneSlices, isDbAvailable, } from "../../gsd-db.js";
|
|
8
|
+
import { renderRoadmapFromDb } from "../../markdown-renderer.js";
|
|
9
9
|
import { findMilestoneIds } from "../../milestone-ids.js";
|
|
10
10
|
import { parseRoadmap } from "../../parsers-legacy.js";
|
|
11
11
|
import { resolveMilestoneFile } from "../../paths.js";
|
|
12
|
+
import { isClosedStatus } from "../../status-guards.js";
|
|
12
13
|
function arraysEqual(a, b) {
|
|
13
14
|
if (a.length !== b.length)
|
|
14
15
|
return false;
|
|
@@ -30,8 +31,10 @@ function milestoneHasDivergence(basePath, milestoneId) {
|
|
|
30
31
|
}
|
|
31
32
|
const dbSlices = getMilestoneSlices(milestoneId);
|
|
32
33
|
const dbSliceMap = new Map(dbSlices.map((s) => [s.id, s]));
|
|
34
|
+
const roadmapSliceIds = new Set();
|
|
33
35
|
for (let i = 0; i < roadmap.slices.length; i++) {
|
|
34
36
|
const roadmapSlice = roadmap.slices[i];
|
|
37
|
+
roadmapSliceIds.add(roadmapSlice.id);
|
|
35
38
|
const expectedSequence = i + 1;
|
|
36
39
|
const dbSlice = dbSliceMap.get(roadmapSlice.id);
|
|
37
40
|
if (!dbSlice)
|
|
@@ -40,6 +43,12 @@ function milestoneHasDivergence(basePath, milestoneId) {
|
|
|
40
43
|
return true;
|
|
41
44
|
if (!arraysEqual(dbSlice.depends, roadmapSlice.depends))
|
|
42
45
|
return true;
|
|
46
|
+
if (isClosedStatus(dbSlice.status) !== roadmapSlice.done)
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
for (const dbSlice of dbSlices) {
|
|
50
|
+
if (!roadmapSliceIds.has(dbSlice.id))
|
|
51
|
+
return true;
|
|
43
52
|
}
|
|
44
53
|
return false;
|
|
45
54
|
}
|
|
@@ -59,26 +68,12 @@ export function detectRoadmapDivergenceDrift(_state, ctx) {
|
|
|
59
68
|
return drifts;
|
|
60
69
|
}
|
|
61
70
|
/**
|
|
62
|
-
* Repair a milestone's roadmap divergence
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* 2. syncSliceDependencies updates the junction table per slice — the
|
|
66
|
-
* importer only writes the JSON column, not the relational view.
|
|
71
|
+
* Repair a milestone's roadmap divergence by regenerating the projection from
|
|
72
|
+
* DB rows. ROADMAP.md is a projection; runtime reconciliation must not import
|
|
73
|
+
* slice presence, sequence, dependencies, or checkbox state from markdown.
|
|
67
74
|
*/
|
|
68
|
-
export function repairRoadmapDivergence(record, ctx) {
|
|
69
|
-
|
|
70
|
-
const roadmapPath = resolveMilestoneFile(ctx.basePath, record.milestoneId, "ROADMAP");
|
|
71
|
-
if (!roadmapPath || !existsSync(roadmapPath))
|
|
72
|
-
return;
|
|
73
|
-
try {
|
|
74
|
-
const roadmap = parseRoadmap(readFileSync(roadmapPath, "utf-8"));
|
|
75
|
-
for (const slice of roadmap.slices) {
|
|
76
|
-
syncSliceDependencies(record.milestoneId, slice.id, slice.depends);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
/* parse failure: detector will fire again next pass */
|
|
81
|
-
}
|
|
75
|
+
export async function repairRoadmapDivergence(record, ctx) {
|
|
76
|
+
await renderRoadmapFromDb(ctx.basePath, record.milestoneId);
|
|
82
77
|
}
|
|
83
78
|
export const roadmapDivergenceHandler = {
|
|
84
79
|
kind: "roadmap-divergence",
|
|
@@ -22,3 +22,7 @@ export function isDeferredStatus(status) {
|
|
|
22
22
|
export function isInactiveStatus(status) {
|
|
23
23
|
return isClosedStatus(status) || isDeferredStatus(status);
|
|
24
24
|
}
|
|
25
|
+
/** Returns true when a prior milestone should not block dispatch ordering. */
|
|
26
|
+
export function isSkippedForDispatch(status) {
|
|
27
|
+
return isClosedStatus(status) || status === "parked" || isDeferredStatus(status);
|
|
28
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Project Knowledge
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Project-specific rules plus projected patterns and lessons learned.
|
|
4
|
+
Rules are maintained in this file. Patterns and lessons are persisted to the memories table and rendered here on the next session-start projection.
|
|
5
5
|
|
|
6
6
|
## Rules
|
|
7
7
|
|
|
@@ -99,11 +99,11 @@
|
|
|
99
99
|
- "Improve UI"
|
|
100
100
|
|
|
101
101
|
Each task should usually include:
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
102
|
+
- description: why this task exists, concrete steps, and done-when acceptance
|
|
103
|
+
- files: JSON array of likely touched paths
|
|
104
|
+
- verify: the command, test, or runtime check that proves it worked
|
|
105
|
+
- inputs: JSON array of existing paths or prior task outputs this task consumes
|
|
106
|
+
- expectedOutput: JSON array of paths this task creates or overwrites
|
|
107
107
|
|
|
108
108
|
Keep the checkbox line format exactly:
|
|
109
109
|
- [ ] **T01: Title** `est:30m`
|
|
@@ -131,10 +131,13 @@
|
|
|
131
131
|
|
|
132
132
|
Verify field rules:
|
|
133
133
|
- MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
|
|
134
|
+
- MUST NOT use shell pipes, redirects, semicolons, backticks, command substitution, or output trimming
|
|
134
135
|
- For content/document tasks: verify file existence, section count, YAML validity, or word count
|
|
135
136
|
NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
|
|
136
137
|
- If no command can verify the output, write: "Manual review — file exists and is non-empty"
|
|
138
|
+
- BAD: `python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5`
|
|
137
139
|
- BAD: "Sections 3.1 and 3.2 exist with exact formulas. Zero TBD/TODO."
|
|
140
|
+
- GOOD: `python3 -m pytest tests/ -q --tb=short`
|
|
138
141
|
- GOOD: `grep -c "^## " doc.md` returns >= 4 (4+ sections), `! grep -q "TBD\|TODO" doc.md`
|
|
139
142
|
|
|
140
143
|
Integration closure rule:
|
|
@@ -72,7 +72,8 @@ skills_used:
|
|
|
72
72
|
<!-- Every input MUST be a backtick-wrapped file path. These paths are machine-parsed to
|
|
73
73
|
derive task dependencies — vague descriptions without paths break dependency detection.
|
|
74
74
|
For the first task in a slice with no prior task outputs, list the existing source files
|
|
75
|
-
this task reads or modifies.
|
|
75
|
+
this task reads or modifies.
|
|
76
|
+
Tool field: inputs must be an array of strings, e.g. ["src/index.ts"], never a single string. -->
|
|
76
77
|
|
|
77
78
|
- `{{filePath}}` — {{whatThisTaskNeedsFromPriorWork}}
|
|
78
79
|
|
|
@@ -82,6 +83,7 @@ skills_used:
|
|
|
82
83
|
or modifies. These paths are machine-parsed to derive task dependencies.
|
|
83
84
|
This task should produce a real increment toward making the slice goal/demo true. A full
|
|
84
85
|
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.
|
|
86
|
+
still does not work at the stated proof level.
|
|
87
|
+
Tool field: expectedOutput must be an array of strings, e.g. ["src/index.ts"], never a single string. -->
|
|
86
88
|
|
|
87
89
|
- `{{filePath}}` — {{whatThisTaskCreatesOrModifies}}
|
|
@@ -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
|
---
|
|
@@ -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:
|
|
@@ -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,8 @@ 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, gsdRoot, resolveTasksDir } from "../paths.js";
|
|
12
16
|
function validateTasks(value) {
|
|
13
17
|
if (!Array.isArray(value) || value.length === 0) {
|
|
14
18
|
throw new Error("tasks must be a non-empty array");
|
|
@@ -39,17 +43,11 @@ function validateTasks(value) {
|
|
|
39
43
|
throw new Error(`tasks[${index}].description must be a non-empty string`);
|
|
40
44
|
if (!isNonEmptyString(estimate))
|
|
41
45
|
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
|
-
}
|
|
46
|
+
const validatedFiles = validateStringArray(files, `tasks[${index}].files`);
|
|
45
47
|
if (!isNonEmptyString(verify))
|
|
46
48
|
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
|
-
}
|
|
49
|
+
const validatedInputs = validateStringArray(inputs, `tasks[${index}].inputs`);
|
|
50
|
+
const validatedExpectedOutput = validateStringArray(expectedOutput, `tasks[${index}].expectedOutput`);
|
|
53
51
|
if (observabilityImpact !== undefined && !isNonEmptyString(observabilityImpact)) {
|
|
54
52
|
throw new Error(`tasks[${index}].observabilityImpact must be a non-empty string when provided`);
|
|
55
53
|
}
|
|
@@ -58,10 +56,10 @@ function validateTasks(value) {
|
|
|
58
56
|
title,
|
|
59
57
|
description,
|
|
60
58
|
estimate,
|
|
61
|
-
files,
|
|
59
|
+
files: validatedFiles,
|
|
62
60
|
verify,
|
|
63
|
-
inputs,
|
|
64
|
-
expectedOutput,
|
|
61
|
+
inputs: validatedInputs,
|
|
62
|
+
expectedOutput: validatedExpectedOutput,
|
|
65
63
|
observabilityImpact: typeof observabilityImpact === "string" ? observabilityImpact : "",
|
|
66
64
|
};
|
|
67
65
|
});
|
|
@@ -84,6 +82,53 @@ function validateParams(params) {
|
|
|
84
82
|
tasks: validateTasks(params.tasks),
|
|
85
83
|
};
|
|
86
84
|
}
|
|
85
|
+
function toTaskRows(params) {
|
|
86
|
+
return params.tasks.map((task, index) => ({
|
|
87
|
+
milestone_id: params.milestoneId,
|
|
88
|
+
slice_id: params.sliceId,
|
|
89
|
+
id: task.taskId,
|
|
90
|
+
title: task.title,
|
|
91
|
+
status: "pending",
|
|
92
|
+
one_liner: "",
|
|
93
|
+
narrative: "",
|
|
94
|
+
verification_result: "",
|
|
95
|
+
duration: "",
|
|
96
|
+
completed_at: null,
|
|
97
|
+
blocker_discovered: false,
|
|
98
|
+
deviations: "",
|
|
99
|
+
known_issues: "",
|
|
100
|
+
key_files: [],
|
|
101
|
+
key_decisions: [],
|
|
102
|
+
full_summary_md: "",
|
|
103
|
+
description: task.description,
|
|
104
|
+
estimate: task.estimate,
|
|
105
|
+
files: task.files,
|
|
106
|
+
verify: task.verify,
|
|
107
|
+
inputs: task.inputs,
|
|
108
|
+
expected_output: task.expectedOutput,
|
|
109
|
+
observability_impact: task.observabilityImpact ?? "",
|
|
110
|
+
full_plan_md: task.fullPlanMd ?? "",
|
|
111
|
+
sequence: index + 1,
|
|
112
|
+
blocker_source: "",
|
|
113
|
+
escalation_pending: 0,
|
|
114
|
+
escalation_awaiting_review: 0,
|
|
115
|
+
escalation_artifact_path: null,
|
|
116
|
+
escalation_override_applied_at: null,
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
function validateTaskPathsBeforePersist(params, basePath) {
|
|
120
|
+
const taskRows = toTaskRows(params);
|
|
121
|
+
const checks = [
|
|
122
|
+
...checkFilePathConsistency(taskRows, basePath),
|
|
123
|
+
...checkTaskOrdering(taskRows, basePath),
|
|
124
|
+
];
|
|
125
|
+
const blocking = checks.filter((check) => !check.passed && check.blocking);
|
|
126
|
+
if (blocking.length === 0)
|
|
127
|
+
return null;
|
|
128
|
+
return blocking
|
|
129
|
+
.map((check) => `[${check.category}] ${check.target}: ${check.message}`)
|
|
130
|
+
.join("\n");
|
|
131
|
+
}
|
|
87
132
|
export async function handlePlanSlice(rawParams, basePath) {
|
|
88
133
|
let params;
|
|
89
134
|
try {
|
|
@@ -100,10 +145,15 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
100
145
|
if (pathScopeError) {
|
|
101
146
|
return { error: `validation failed: ${pathScopeError}` };
|
|
102
147
|
}
|
|
148
|
+
const pathError = validateTaskPathsBeforePersist(params, basePath);
|
|
149
|
+
if (pathError) {
|
|
150
|
+
return { error: `pre-execution validation failed:\n${pathError}` };
|
|
151
|
+
}
|
|
103
152
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
104
153
|
// Guards must be inside the transaction so the state they check cannot
|
|
105
154
|
// change between the read and the write (#2723).
|
|
106
155
|
let guardError = null;
|
|
156
|
+
let omittedTaskIds = [];
|
|
107
157
|
try {
|
|
108
158
|
transaction(() => {
|
|
109
159
|
const parentMilestone = getMilestone(params.milestoneId);
|
|
@@ -124,9 +174,21 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
124
174
|
guardError = `cannot re-plan slice ${params.sliceId}: it is already complete — use gsd_slice_reopen first`;
|
|
125
175
|
return;
|
|
126
176
|
}
|
|
177
|
+
const newTaskIds = new Set(params.tasks.map((task) => task.taskId));
|
|
178
|
+
const existingTasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
179
|
+
omittedTaskIds = existingTasks
|
|
180
|
+
.filter((task) => !newTaskIds.has(task.id))
|
|
181
|
+
.map((task) => task.id);
|
|
182
|
+
for (const task of existingTasks) {
|
|
183
|
+
if (!newTaskIds.has(task.id) && isClosedStatus(task.status)) {
|
|
184
|
+
guardError = `cannot remove completed task ${task.id}`;
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
127
188
|
if (isDeferredStatus(parentSlice.status)) {
|
|
128
189
|
updateSliceStatus(params.milestoneId, params.sliceId, "pending");
|
|
129
190
|
}
|
|
191
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
130
192
|
upsertSlicePlanning(params.milestoneId, params.sliceId, {
|
|
131
193
|
goal: params.goal,
|
|
132
194
|
successCriteria: params.successCriteria,
|
|
@@ -134,6 +196,9 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
134
196
|
integrationClosure: params.integrationClosure,
|
|
135
197
|
observabilityImpact: params.observabilityImpact,
|
|
136
198
|
});
|
|
199
|
+
for (const taskId of omittedTaskIds) {
|
|
200
|
+
deleteTask(params.milestoneId, params.sliceId, taskId);
|
|
201
|
+
}
|
|
137
202
|
for (const task of params.tasks) {
|
|
138
203
|
insertTask({
|
|
139
204
|
id: task.taskId,
|
|
@@ -176,6 +241,16 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
176
241
|
return { error: guardError };
|
|
177
242
|
}
|
|
178
243
|
try {
|
|
244
|
+
const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
245
|
+
for (const taskId of omittedTaskIds) {
|
|
246
|
+
if (!tasksDir)
|
|
247
|
+
continue;
|
|
248
|
+
const taskPlanPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
249
|
+
if (existsSync(taskPlanPath))
|
|
250
|
+
rmSync(taskPlanPath, { force: true });
|
|
251
|
+
const artifactPath = relative(gsdRoot(basePath), taskPlanPath).replace(/\\/g, "/");
|
|
252
|
+
deleteArtifactByPath(artifactPath);
|
|
253
|
+
}
|
|
179
254
|
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
180
255
|
invalidateStateCache();
|
|
181
256
|
clearParseCache();
|