@opengsd/gsd-pi 1.1.1-dev.b2556262 → 1.2.0-dev.4813ead6
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/dist/cli-web-branch.d.ts +2 -0
- package/dist/cli-web-branch.js +9 -2
- package/dist/help-text.js +5 -0
- package/dist/project-sessions.js +4 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +78 -23
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +101 -237
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
- package/dist/resources/extensions/github-sync/templates.js +3 -3
- package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
- package/dist/resources/extensions/gsd/auto/contracts.js +8 -1
- package/dist/resources/extensions/gsd/auto/loop.js +74 -56
- package/dist/resources/extensions/gsd/auto/orchestrator.js +763 -63
- package/dist/resources/extensions/gsd/auto/phases.js +28 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
- package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +191 -9
- package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
- package/dist/resources/extensions/gsd/auto-runtime-state.js +17 -0
- package/dist/resources/extensions/gsd/auto-start.js +12 -23
- package/dist/resources/extensions/gsd/auto-timers.js +16 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +37 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +33 -29
- package/dist/resources/extensions/gsd/auto-verification.js +7 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +45 -36
- package/dist/resources/extensions/gsd/auto.js +73 -471
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +103 -138
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
- package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
- package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
- package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
- package/dist/resources/extensions/gsd/db-workspace.js +103 -0
- package/dist/resources/extensions/gsd/debug-logger.js +10 -0
- package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
- package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/dist/resources/extensions/gsd/doctor-proactive.js +7 -2
- package/dist/resources/extensions/gsd/doctor.js +16 -9
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
- package/dist/resources/extensions/gsd/gsd-db.js +12 -0
- package/dist/resources/extensions/gsd/guided-flow.js +36 -470
- package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +33 -33
- package/dist/resources/extensions/gsd/mcp-filter.js +8 -1
- package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
- package/dist/resources/extensions/gsd/md-importer.js +4 -3
- package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
- package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
- package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
- package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
- package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
- package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
- package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
- package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +45 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
- package/dist/resources/extensions/gsd/preferences.js +147 -29
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +6 -7
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
- package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
- package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
- package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
- package/dist/resources/extensions/gsd/question-transport.js +86 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
- package/dist/resources/extensions/gsd/schemas/parsers.js +6 -1
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
- package/dist/resources/extensions/gsd/state.js +13 -5
- package/dist/resources/extensions/gsd/templates/plan.md +7 -0
- package/dist/resources/extensions/gsd/templates/project.md +1 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/dist/resources/extensions/gsd/templates/uat.md +5 -1
- package/dist/resources/extensions/gsd/tool-contract.js +52 -8
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
- package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +169 -20
- package/dist/resources/extensions/gsd/uat-policy.js +16 -10
- package/dist/resources/extensions/gsd/uat-run.js +9 -14
- package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
- package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
- package/dist/resources/extensions/gsd/user-input-boundary.js +65 -4
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
- package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
- package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
- package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
- package/dist/resources/extensions/shared/interview-ui.js +2 -2
- package/dist/resources/shared/claude-runtime-floor.js +182 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -0
- package/dist/update-cmd.js +20 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- 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 +8 -8
- 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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- 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 +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
- package/dist/web/standalone/.next/server/chunks/5047.js +2 -0
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- 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/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/2659.b7b129ee6a769448.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
- package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
- package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
- package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
- package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
- package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
- package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
- package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
- package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
- package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
- package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
- package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
- package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
- package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
- package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
- package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
- package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
- package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
- package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
- package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
- package/dist/web/standalone/node_modules/postcss/package.json +48 -48
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +20 -8
- package/package.json +17 -11
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +10 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +8 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +2 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +8 -127
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +47 -166
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +11 -3
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/components/input.js +1 -1
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/keys.d.ts.map +1 -1
- package/packages/pi-tui/dist/keys.js +39 -30
- package/packages/pi-tui/dist/keys.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +22 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/install/deps.js +10 -0
- package/scripts/link-workspace-packages.cjs +7 -40
- package/src/resources/extensions/ask-user-questions.ts +87 -24
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +126 -289
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +242 -2
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
- package/src/resources/extensions/github-sync/templates.ts +3 -3
- package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
- package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +40 -121
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
- package/src/resources/extensions/gsd/auto/loop.ts +83 -61
- package/src/resources/extensions/gsd/auto/orchestrator.ts +913 -64
- package/src/resources/extensions/gsd/auto/phases.ts +35 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +220 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
- package/src/resources/extensions/gsd/auto-runtime-state.ts +30 -0
- package/src/resources/extensions/gsd/auto-start.ts +17 -20
- package/src/resources/extensions/gsd/auto-timers.ts +16 -2
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +40 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +42 -30
- package/src/resources/extensions/gsd/auto-verification.ts +7 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +57 -42
- package/src/resources/extensions/gsd/auto.ts +96 -508
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +120 -151
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
- package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
- package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
- package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
- package/src/resources/extensions/gsd/db-workspace.ts +170 -0
- package/src/resources/extensions/gsd/debug-logger.ts +11 -0
- package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
- package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +8 -2
- package/src/resources/extensions/gsd/doctor.ts +15 -5
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
- package/src/resources/extensions/gsd/gsd-db.ts +12 -0
- package/src/resources/extensions/gsd/guided-flow.ts +49 -560
- package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +40 -20
- package/src/resources/extensions/gsd/mcp-filter.ts +9 -1
- package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -3
- package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
- package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
- package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
- package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
- package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
- package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
- package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +48 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +173 -28
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +6 -7
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
- package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
- package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
- package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
- package/src/resources/extensions/gsd/question-transport.ts +138 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
- package/src/resources/extensions/gsd/schemas/parsers.ts +6 -1
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
- package/src/resources/extensions/gsd/state.ts +15 -5
- package/src/resources/extensions/gsd/templates/plan.md +7 -0
- package/src/resources/extensions/gsd/templates/project.md +1 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/src/resources/extensions/gsd/templates/uat.md +5 -1
- package/src/resources/extensions/gsd/tests/artifact-db-drift-memo.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-dispatch-baseline-harness.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +709 -845
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +38 -10
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/native-merge-regular.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +21 -6
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
- package/src/resources/extensions/gsd/tool-contract.ts +86 -8
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
- package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +183 -21
- package/src/resources/extensions/gsd/uat-policy.ts +19 -10
- package/src/resources/extensions/gsd/uat-run.ts +10 -14
- package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
- package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
- package/src/resources/extensions/gsd/user-input-boundary.ts +55 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
- package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
- package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
- package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
- package/src/resources/extensions/shared/interview-ui.ts +15 -2
- package/src/resources/shared/claude-runtime-floor.ts +248 -0
- package/dist/web/standalone/.next/server/chunks/678.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
- package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
- package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
- package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +0 -21
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +0 -213
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts +0 -28
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js +0 -249
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts +0 -19
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts.map +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js +0 -797
- package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js.map +0 -1
- package/scripts/ensure-workspace-builds.cjs +0 -129
- /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_ssgManifest.js +0 -0
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Plans milestone roadmap state through DB-backed workflow tools.
|
|
3
|
-
import { clearParseCache } from "../files.js";
|
|
4
|
-
import { isClosedStatus } from "../status-guards.js";
|
|
5
3
|
import { isNonEmptyString, validateStringArray, validateTitle } from "../validation.js";
|
|
6
|
-
import {
|
|
7
|
-
import { invalidateStateCache } from "../state.js";
|
|
8
|
-
import { renderRoadmapFromDb } from "../markdown-renderer.js";
|
|
9
|
-
import { renderAllProjections } from "../workflow-projections.js";
|
|
10
|
-
import { writeManifest } from "../workflow-manifest.js";
|
|
11
|
-
import { appendEvent } from "../workflow-events.js";
|
|
12
|
-
import { logWarning } from "../workflow-logger.js";
|
|
4
|
+
import { persistMilestonePlan } from "../milestone-planning-persistence.js";
|
|
13
5
|
function validateRiskEntries(value) {
|
|
14
6
|
if (!Array.isArray(value)) {
|
|
15
7
|
throw new Error("keyRisks must be an array");
|
|
@@ -43,10 +35,16 @@ function validateProofStrategy(value) {
|
|
|
43
35
|
return { riskOrUnknown, retireIn, whatWillBeProven };
|
|
44
36
|
});
|
|
45
37
|
}
|
|
38
|
+
const SLICE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
46
39
|
function validateSlices(value) {
|
|
47
40
|
if (!Array.isArray(value) || value.length === 0) {
|
|
48
41
|
throw new Error("slices must be a non-empty array");
|
|
49
42
|
}
|
|
43
|
+
// Pre-collect all slice IDs so depends cross-validation can reference the full set.
|
|
44
|
+
const allSliceIds = new Set(value
|
|
45
|
+
.filter((e) => !!e && typeof e === "object")
|
|
46
|
+
.map(e => e.sliceId)
|
|
47
|
+
.filter((id) => isNonEmptyString(id)));
|
|
50
48
|
const seen = new Set();
|
|
51
49
|
return value.map((entry, index) => {
|
|
52
50
|
if (!entry || typeof entry !== "object") {
|
|
@@ -84,8 +82,13 @@ function validateSlices(value) {
|
|
|
84
82
|
throw new Error(`slices[${index}].title is invalid: ${titleIssue}`);
|
|
85
83
|
if (!isNonEmptyString(risk))
|
|
86
84
|
throw new Error(`slices[${index}].risk must be a non-empty string`);
|
|
87
|
-
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item))) {
|
|
88
|
-
throw new Error(`slices[${index}].depends must be an array of
|
|
85
|
+
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item))) {
|
|
86
|
+
throw new Error(`slices[${index}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
87
|
+
}
|
|
88
|
+
for (const dep of depends) {
|
|
89
|
+
if (!allSliceIds.has(dep)) {
|
|
90
|
+
throw new Error(`slices[${index}].depends references unknown slice "${dep}" — check that it is defined in the same milestone`);
|
|
91
|
+
}
|
|
89
92
|
}
|
|
90
93
|
if (!isNonEmptyString(demo))
|
|
91
94
|
throw new Error(`slices[${index}].demo must be a non-empty string`);
|
|
@@ -160,136 +163,5 @@ export async function handlePlanMilestone(rawParams, basePath) {
|
|
|
160
163
|
catch (err) {
|
|
161
164
|
return { error: `validation failed: ${err.message}` };
|
|
162
165
|
}
|
|
163
|
-
|
|
164
|
-
// Guards must be inside the transaction so the state they check cannot
|
|
165
|
-
// change between the read and the write (#2723).
|
|
166
|
-
let guardError = null;
|
|
167
|
-
try {
|
|
168
|
-
transaction(() => {
|
|
169
|
-
const existingMilestone = getMilestone(params.milestoneId);
|
|
170
|
-
if (existingMilestone && isClosedStatus(existingMilestone.status)) {
|
|
171
|
-
guardError = `cannot re-plan milestone ${params.milestoneId}: it is already complete`;
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
// Guard: refuse to re-plan a milestone that would drop completed slices (#2960).
|
|
175
|
-
// Allow re-planning when all completed slices are still present in the
|
|
176
|
-
// incoming plan — their status is preserved below (#2558). Block only when
|
|
177
|
-
// the new plan omits a completed slice, which could shadow completed work.
|
|
178
|
-
const existingSlices = getMilestoneSlices(params.milestoneId);
|
|
179
|
-
const completedSlices = existingSlices.filter(s => isClosedStatus(s.status));
|
|
180
|
-
if (completedSlices.length > 0) {
|
|
181
|
-
const incomingSliceIds = new Set(params.slices.map(s => s.sliceId));
|
|
182
|
-
const droppedCompleted = completedSlices.filter(s => !incomingSliceIds.has(s.id));
|
|
183
|
-
if (droppedCompleted.length > 0) {
|
|
184
|
-
guardError = `cannot re-plan milestone ${params.milestoneId}: ${droppedCompleted.length} completed slice(s) would be dropped (${droppedCompleted.map(s => s.id).join(", ")}). Use gsd_reassess_roadmap to modify the roadmap.`;
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
// Validate depends_on: all dependencies must exist and be complete
|
|
189
|
-
if (params.dependsOn && params.dependsOn.length > 0) {
|
|
190
|
-
for (const depId of params.dependsOn) {
|
|
191
|
-
const dep = getMilestone(depId);
|
|
192
|
-
if (!dep) {
|
|
193
|
-
guardError = `depends_on references unknown milestone: ${depId}`;
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
if (!isClosedStatus(dep.status)) {
|
|
197
|
-
guardError = `depends_on milestone ${depId} is not yet complete (status: ${dep.status})`;
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
insertMilestone({
|
|
203
|
-
id: params.milestoneId,
|
|
204
|
-
title: params.title,
|
|
205
|
-
status: params.status ?? "active",
|
|
206
|
-
depends_on: params.dependsOn ?? [],
|
|
207
|
-
});
|
|
208
|
-
upsertMilestonePlanning(params.milestoneId, {
|
|
209
|
-
title: params.title,
|
|
210
|
-
status: params.status ?? "active",
|
|
211
|
-
depends_on: params.dependsOn ?? [],
|
|
212
|
-
vision: params.vision,
|
|
213
|
-
successCriteria: params.successCriteria,
|
|
214
|
-
keyRisks: params.keyRisks,
|
|
215
|
-
proofStrategy: params.proofStrategy,
|
|
216
|
-
verificationContract: params.verificationContract,
|
|
217
|
-
verificationIntegration: params.verificationIntegration,
|
|
218
|
-
verificationOperational: params.verificationOperational,
|
|
219
|
-
verificationUat: params.verificationUat,
|
|
220
|
-
definitionOfDone: params.definitionOfDone,
|
|
221
|
-
requirementCoverage: params.requirementCoverage,
|
|
222
|
-
boundaryMapMarkdown: params.boundaryMapMarkdown,
|
|
223
|
-
});
|
|
224
|
-
for (let i = 0; i < params.slices.length; i++) {
|
|
225
|
-
const slice = params.slices[i];
|
|
226
|
-
// Preserve completed/done status on re-plan (#2558).
|
|
227
|
-
// Without this, a re-plan after milestone transition would reset
|
|
228
|
-
// already-completed slices back to "pending".
|
|
229
|
-
const existing = getSlice(params.milestoneId, slice.sliceId);
|
|
230
|
-
const status = existing && (existing.status === "complete" || existing.status === "done")
|
|
231
|
-
? existing.status
|
|
232
|
-
: "pending";
|
|
233
|
-
insertSlice({
|
|
234
|
-
id: slice.sliceId,
|
|
235
|
-
milestoneId: params.milestoneId,
|
|
236
|
-
title: slice.title,
|
|
237
|
-
status,
|
|
238
|
-
risk: slice.risk,
|
|
239
|
-
depends: slice.depends,
|
|
240
|
-
demo: slice.demo,
|
|
241
|
-
sequence: i + 1, // Preserve agent-ordered sequence (#3356)
|
|
242
|
-
// ADR-011: pass undefined through so ON CONFLICT preserves existing values
|
|
243
|
-
// when the caller omitted the fields on a re-plan.
|
|
244
|
-
isSketch: slice.isSketch,
|
|
245
|
-
sketchScope: slice.sketchScope,
|
|
246
|
-
});
|
|
247
|
-
upsertSlicePlanning(params.milestoneId, slice.sliceId, {
|
|
248
|
-
goal: slice.goal,
|
|
249
|
-
successCriteria: slice.successCriteria,
|
|
250
|
-
proofLevel: slice.proofLevel,
|
|
251
|
-
integrationClosure: slice.integrationClosure,
|
|
252
|
-
observabilityImpact: slice.observabilityImpact,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
catch (err) {
|
|
258
|
-
return { error: `db write failed: ${err.message}` };
|
|
259
|
-
}
|
|
260
|
-
if (guardError) {
|
|
261
|
-
return { error: guardError };
|
|
262
|
-
}
|
|
263
|
-
let roadmapPath;
|
|
264
|
-
try {
|
|
265
|
-
const renderResult = await renderRoadmapFromDb(basePath, params.milestoneId);
|
|
266
|
-
roadmapPath = renderResult.roadmapPath;
|
|
267
|
-
}
|
|
268
|
-
catch (renderErr) {
|
|
269
|
-
logWarning("tool", `plan_milestone — render failed (DB rows preserved for debugging): ${renderErr.message}`);
|
|
270
|
-
invalidateStateCache();
|
|
271
|
-
return { error: `render failed: ${renderErr.message}` };
|
|
272
|
-
}
|
|
273
|
-
invalidateStateCache();
|
|
274
|
-
clearParseCache();
|
|
275
|
-
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
276
|
-
try {
|
|
277
|
-
await renderAllProjections(basePath, params.milestoneId);
|
|
278
|
-
writeManifest(basePath);
|
|
279
|
-
appendEvent(basePath, {
|
|
280
|
-
cmd: "plan-milestone",
|
|
281
|
-
params: { milestoneId: params.milestoneId },
|
|
282
|
-
ts: new Date().toISOString(),
|
|
283
|
-
actor: "agent",
|
|
284
|
-
actor_name: params.actorName,
|
|
285
|
-
trigger_reason: params.triggerReason,
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
catch (hookErr) {
|
|
289
|
-
logWarning("tool", `plan-milestone post-mutation hook warning: ${hookErr.message}`);
|
|
290
|
-
}
|
|
291
|
-
return {
|
|
292
|
-
milestoneId: params.milestoneId,
|
|
293
|
-
roadmapPath,
|
|
294
|
-
};
|
|
166
|
+
return persistMilestonePlan(params, basePath);
|
|
295
167
|
}
|
|
@@ -31,6 +31,7 @@ function validateParams(params) {
|
|
|
31
31
|
if (!Array.isArray(params.sliceChanges.removed)) {
|
|
32
32
|
throw new Error("sliceChanges.removed must be an array");
|
|
33
33
|
}
|
|
34
|
+
const SLICE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
34
35
|
// Validate each modified slice
|
|
35
36
|
for (let i = 0; i < params.sliceChanges.modified.length; i++) {
|
|
36
37
|
const s = params.sliceChanges.modified[i];
|
|
@@ -40,6 +41,11 @@ function validateParams(params) {
|
|
|
40
41
|
throw new Error(`sliceChanges.modified[${i}].sliceId is required`);
|
|
41
42
|
if (!isNonEmptyString(s.title))
|
|
42
43
|
throw new Error(`sliceChanges.modified[${i}].title is required`);
|
|
44
|
+
if (s.depends !== undefined) {
|
|
45
|
+
if (!Array.isArray(s.depends) || s.depends.some((item) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item))) {
|
|
46
|
+
throw new Error(`sliceChanges.modified[${i}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
43
49
|
}
|
|
44
50
|
// Validate each added slice
|
|
45
51
|
for (let i = 0; i < params.sliceChanges.added.length; i++) {
|
|
@@ -50,6 +56,11 @@ function validateParams(params) {
|
|
|
50
56
|
throw new Error(`sliceChanges.added[${i}].sliceId is required`);
|
|
51
57
|
if (!isNonEmptyString(s.title))
|
|
52
58
|
throw new Error(`sliceChanges.added[${i}].title is required`);
|
|
59
|
+
if (s.depends !== undefined) {
|
|
60
|
+
if (!Array.isArray(s.depends) || s.depends.some((item) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item))) {
|
|
61
|
+
throw new Error(`sliceChanges.added[${i}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
53
64
|
}
|
|
54
65
|
return params;
|
|
55
66
|
}
|
|
@@ -111,6 +122,34 @@ export async function handleReassessRoadmap(rawParams, basePath) {
|
|
|
111
122
|
return;
|
|
112
123
|
}
|
|
113
124
|
}
|
|
125
|
+
// Cross-milestone depends validation — effective slice ID set after this reassessment
|
|
126
|
+
const removedIds = new Set(params.sliceChanges.removed);
|
|
127
|
+
const effectiveSliceIds = new Set(existingSlices.map(s => s.id).filter(id => !removedIds.has(id)));
|
|
128
|
+
for (const added of params.sliceChanges.added) {
|
|
129
|
+
effectiveSliceIds.add(added.sliceId);
|
|
130
|
+
}
|
|
131
|
+
for (let i = 0; i < params.sliceChanges.modified.length; i++) {
|
|
132
|
+
const mod = params.sliceChanges.modified[i];
|
|
133
|
+
if (mod.depends !== undefined) {
|
|
134
|
+
for (const dep of mod.depends) {
|
|
135
|
+
if (!effectiveSliceIds.has(dep)) {
|
|
136
|
+
guardError = `sliceChanges.modified[${i}].depends references unknown slice "${dep}" — check that it is defined in this milestone`;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (let i = 0; i < params.sliceChanges.added.length; i++) {
|
|
143
|
+
const added = params.sliceChanges.added[i];
|
|
144
|
+
if (added.depends !== undefined) {
|
|
145
|
+
for (const dep of added.depends) {
|
|
146
|
+
if (!effectiveSliceIds.has(dep)) {
|
|
147
|
+
guardError = `sliceChanges.added[${i}].depends references unknown slice "${dep}" — check that it is defined in this milestone`;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
114
153
|
// Record assessment
|
|
115
154
|
insertAssessment({
|
|
116
155
|
path: assessmentRelPath,
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
* despite passing validation.
|
|
12
12
|
*/
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
-
import { transaction, insertAssessment, getMilestoneSlices, getMilestone,
|
|
15
|
-
import { gsdProjectionRoot, clearPathCache
|
|
14
|
+
import { transaction, insertAssessment, getMilestoneSlices, getMilestone, } from "../gsd-db.js";
|
|
15
|
+
import { gsdProjectionRoot, clearPathCache } from "../paths.js";
|
|
16
16
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
17
|
-
import {
|
|
17
|
+
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
18
|
+
import { saveFile, clearParseCache } from "../files.js";
|
|
18
19
|
import { invalidateStateCache } from "../state.js";
|
|
19
20
|
import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
|
|
20
21
|
import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
|
|
@@ -22,7 +23,7 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
22
23
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
23
24
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
24
25
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
25
|
-
import {
|
|
26
|
+
import { applyBrowserEvidenceGate, browserEvidenceGateRequiresAttention, } from "../milestone-validation-evidence.js";
|
|
26
27
|
function isVerificationNotApplicable(value) {
|
|
27
28
|
const v = (value ?? "").toLowerCase().trim().replace(/[.\s]+$/, "");
|
|
28
29
|
if (!v || v === "none")
|
|
@@ -44,80 +45,6 @@ function getRequiredVerificationClasses(milestoneId) {
|
|
|
44
45
|
required.push("UAT");
|
|
45
46
|
return required;
|
|
46
47
|
}
|
|
47
|
-
function hasRuntimeExecutableUatEvidenceText(text) {
|
|
48
|
-
if (!/\buatType:\s*runtime-executable\b/i.test(text))
|
|
49
|
-
return false;
|
|
50
|
-
if (!/\bverdict:\s*PASS\b/i.test(text))
|
|
51
|
-
return false;
|
|
52
|
-
return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
|
|
53
|
-
}
|
|
54
|
-
async function browserEvidenceGateRequiresAttention(params, basePath) {
|
|
55
|
-
if (params.verdict !== "pass")
|
|
56
|
-
return false;
|
|
57
|
-
const milestone = getMilestone(params.milestoneId);
|
|
58
|
-
const slices = getMilestoneSlices(params.milestoneId);
|
|
59
|
-
const requirementText = compactTextParts([
|
|
60
|
-
milestone?.vision,
|
|
61
|
-
milestone?.success_criteria,
|
|
62
|
-
milestone?.verification_uat,
|
|
63
|
-
params.successCriteriaChecklist,
|
|
64
|
-
params.verificationClasses,
|
|
65
|
-
...slices.flatMap((slice) => [
|
|
66
|
-
slice.demo,
|
|
67
|
-
slice.goal,
|
|
68
|
-
slice.success_criteria,
|
|
69
|
-
]),
|
|
70
|
-
]);
|
|
71
|
-
if (!hasBrowserRequiredText(requirementText))
|
|
72
|
-
return false;
|
|
73
|
-
// Collect per-slice evidence so the runtime bypass is checked independently
|
|
74
|
-
// for each slice. Concatenating all slices before checking would allow runtime
|
|
75
|
-
// evidence from one slice to cover another slice's browser requirements.
|
|
76
|
-
const sliceEvidencePairs = [];
|
|
77
|
-
for (const slice of slices) {
|
|
78
|
-
const chunks = [];
|
|
79
|
-
const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
|
|
80
|
-
const artifact = getArtifact(artifactPath);
|
|
81
|
-
if (artifact?.full_content)
|
|
82
|
-
chunks.push(artifact.full_content);
|
|
83
|
-
const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
|
|
84
|
-
const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
|
|
85
|
-
if (assessmentContent)
|
|
86
|
-
chunks.push(assessmentContent);
|
|
87
|
-
sliceEvidencePairs.push({
|
|
88
|
-
sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
|
|
89
|
-
evidenceText: chunks.join("\n\n"),
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
const persistedEvidence = sliceEvidencePairs.map((s) => s.evidenceText).join("\n\n");
|
|
93
|
-
// Runtime bypass: each slice whose own requirement text has browser-observable
|
|
94
|
-
// criteria must have its own runtime-executable UAT evidence. When no individual
|
|
95
|
-
// slice has slice-level browser requirements (e.g., they come from milestone-level
|
|
96
|
-
// fields only), fall back to checking whether any slice has runtime evidence.
|
|
97
|
-
const browserRequiringSlices = sliceEvidencePairs.filter((s) => hasBrowserRequiredText(s.sliceRequirementText));
|
|
98
|
-
const runtimeBypasses = browserRequiringSlices.length > 0
|
|
99
|
-
? browserRequiringSlices.every((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText))
|
|
100
|
-
: sliceEvidencePairs.some((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText));
|
|
101
|
-
if (runtimeBypasses)
|
|
102
|
-
return false;
|
|
103
|
-
const validationEvidence = compactTextParts([
|
|
104
|
-
params.successCriteriaChecklist,
|
|
105
|
-
params.verificationClasses,
|
|
106
|
-
params.verdictRationale,
|
|
107
|
-
params.remediationPlan,
|
|
108
|
-
]);
|
|
109
|
-
return !hasBrowserEvidenceText(`${persistedEvidence}\n\n${validationEvidence}`);
|
|
110
|
-
}
|
|
111
|
-
function applyBrowserEvidenceGate(params) {
|
|
112
|
-
const note = "Browser evidence gate: Browser-observable acceptance criteria were detected, but no persisted ASSESSMENT or validation evidence recorded browser actions with assertions. Downgraded from pass to needs-attention.";
|
|
113
|
-
return {
|
|
114
|
-
...params,
|
|
115
|
-
verdict: "needs-attention",
|
|
116
|
-
verdictRationale: params.verdictRationale.trim()
|
|
117
|
-
? `${params.verdictRationale.trim()}\n\n${note}`
|
|
118
|
-
: note,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
48
|
function renderValidationMarkdown(params) {
|
|
122
49
|
let md = `---
|
|
123
50
|
verdict: ${params.verdict}
|
|
@@ -214,6 +141,16 @@ export async function handleValidateMilestone(params, basePath, opts) {
|
|
|
214
141
|
let projectionStale = false;
|
|
215
142
|
try {
|
|
216
143
|
await saveFile(validationPath, validationMd);
|
|
144
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath);
|
|
145
|
+
if (projectRoot !== artifactBasePath) {
|
|
146
|
+
const projectValidationPath = join(gsdProjectionRoot(projectRoot), "milestones", effectiveParams.milestoneId, `${effectiveParams.milestoneId}-VALIDATION.md`);
|
|
147
|
+
try {
|
|
148
|
+
await saveFile(projectValidationPath, validationMd);
|
|
149
|
+
}
|
|
150
|
+
catch (mirrorErr) {
|
|
151
|
+
logWarning("projection", `validate_milestone project-root VALIDATION mirror failed for ${effectiveParams.milestoneId}`, { error: mirrorErr.message });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
217
154
|
}
|
|
218
155
|
catch (renderErr) {
|
|
219
156
|
projectionStale = true;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
|
|
4
4
|
import { sanitizeCompleteMilestoneParams } from "../bootstrap/sanitize-complete-milestone.js";
|
|
5
5
|
import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, shouldBlockRootArtifactSaveInSnapshot } from "../bootstrap/write-gate.js";
|
|
6
|
-
import { getActiveRequirements,
|
|
6
|
+
import { getActiveRequirements, getAllMilestones, getMilestone, getSliceStatusSummary, getSliceTaskCounts, insertMilestone, insertAssessment, insertGateRun, readTransaction, saveGateResult, upsertQualityGate, } from "../gsd-db.js";
|
|
7
7
|
import { GATE_REGISTRY } from "../gate-registry.js";
|
|
8
8
|
import { generateRequirementsMd, saveArtifactToDb } from "../db-writer.js";
|
|
9
9
|
import { clearPathCache, relSliceFile, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
@@ -74,6 +74,103 @@ function registerProjectMilestoneSequence(content) {
|
|
|
74
74
|
}
|
|
75
75
|
return registered;
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Best-effort recovery of the human one-liner for each milestone id from a
|
|
79
|
+
* (possibly malformed) Milestone Sequence body. Deliberately lenient: tolerates
|
|
80
|
+
* any separator the canonical MILESTONE_LINE_RE rejects (en-dash, " : ", a
|
|
81
|
+
* missing checkbox, etc.) so a model formatting slip does not discard the prose.
|
|
82
|
+
*/
|
|
83
|
+
function recoverMilestoneTails(sequenceBody) {
|
|
84
|
+
const out = new Map();
|
|
85
|
+
const lenient = /^\s*(?:-\s*)?(?:\[[ xX]\]\s*)?(M\d{3})\b\s*[:.\-–—]*\s*(.*)$/;
|
|
86
|
+
for (const rawLine of sequenceBody.split("\n")) {
|
|
87
|
+
const m = rawLine.match(lenient);
|
|
88
|
+
if (m)
|
|
89
|
+
out.set(m[1], m[2].trim());
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
function firstSentence(text) {
|
|
94
|
+
const trimmed = text.trim();
|
|
95
|
+
if (!trimmed)
|
|
96
|
+
return "";
|
|
97
|
+
const idx = trimmed.search(/[.!?](\s|$)/);
|
|
98
|
+
return (idx >= 0 ? trimmed.slice(0, idx + 1) : trimmed).trim();
|
|
99
|
+
}
|
|
100
|
+
/** Render one canonical, parseable milestone line for the given DB row. */
|
|
101
|
+
function renderMilestoneLine(m, recoveredTail) {
|
|
102
|
+
const done = m.status === "complete";
|
|
103
|
+
let oneLiner = recoveredTail;
|
|
104
|
+
// The recovered tail often still carries the title (e.g. "Foo — bar" or
|
|
105
|
+
// "Foo : bar"). Strip a leading repetition of the title, then any separator.
|
|
106
|
+
if (oneLiner.toLowerCase().startsWith(m.title.toLowerCase())) {
|
|
107
|
+
oneLiner = oneLiner.slice(m.title.length).replace(/^\s*[:.\-–—]+\s*/, "").trim();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
const sep = oneLiner.match(/\s+(?:—|–|--|-|:)\s+/);
|
|
111
|
+
if (sep && sep.index !== undefined)
|
|
112
|
+
oneLiner = oneLiner.slice(sep.index + sep[0].length).trim();
|
|
113
|
+
}
|
|
114
|
+
// MILESTONE_LINE_RE requires non-empty prose after the separator.
|
|
115
|
+
if (!oneLiner)
|
|
116
|
+
oneLiner = firstSentence(m.vision) || (done ? "Completed." : "Planned.");
|
|
117
|
+
return `- [${done ? "x" : " "}] ${m.id}: ${m.title} — ${oneLiner}`;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Rebuild the "## Milestone Sequence" section from authoritative DB rows when a
|
|
121
|
+
* model-authored PROJECT.md projection parsed to zero milestone lines but the DB
|
|
122
|
+
* already holds milestones. The DB is the source of truth (markdown is a
|
|
123
|
+
* projection), so this repairs the projection rather than failing the save.
|
|
124
|
+
* Preserves a leading HTML comment in the section and recovers one-liners
|
|
125
|
+
* best-effort. The returned content parses cleanly under MILESTONE_LINE_RE.
|
|
126
|
+
*/
|
|
127
|
+
function rebuildMilestoneSequenceSection(content, milestones) {
|
|
128
|
+
const lines = content.split("\n");
|
|
129
|
+
const headerIdx = lines.findIndex(l => /^##\s+Milestone Sequence\s*$/.test(l));
|
|
130
|
+
const canonicalLines = (() => {
|
|
131
|
+
// Recover tails from the existing (malformed) body when the section exists.
|
|
132
|
+
let body = "";
|
|
133
|
+
if (headerIdx !== -1) {
|
|
134
|
+
let end = headerIdx + 1;
|
|
135
|
+
while (end < lines.length && !/^##\s+/.test(lines[end]))
|
|
136
|
+
end++;
|
|
137
|
+
body = lines.slice(headerIdx + 1, end).join("\n");
|
|
138
|
+
}
|
|
139
|
+
const tails = recoverMilestoneTails(body);
|
|
140
|
+
return milestones.map(m => renderMilestoneLine(m, tails.get(m.id) ?? ""));
|
|
141
|
+
})();
|
|
142
|
+
if (headerIdx === -1) {
|
|
143
|
+
// No section at all — append a fresh, canonical one.
|
|
144
|
+
const sep = content.endsWith("\n") ? "" : "\n";
|
|
145
|
+
return `${content}${sep}\n## Milestone Sequence\n\n${canonicalLines.join("\n")}\n`;
|
|
146
|
+
}
|
|
147
|
+
let bodyEnd = headerIdx + 1;
|
|
148
|
+
while (bodyEnd < lines.length && !/^##\s+/.test(lines[bodyEnd]))
|
|
149
|
+
bodyEnd++;
|
|
150
|
+
const existingBody = lines.slice(headerIdx + 1, bodyEnd);
|
|
151
|
+
// Preserve a contiguous leading HTML comment block (the "Check off…" hint).
|
|
152
|
+
let i = 0;
|
|
153
|
+
while (i < existingBody.length && existingBody[i].trim() === "")
|
|
154
|
+
i++;
|
|
155
|
+
const preserved = [];
|
|
156
|
+
if (i < existingBody.length && existingBody[i].trim().startsWith("<!--")) {
|
|
157
|
+
while (i < existingBody.length) {
|
|
158
|
+
preserved.push(existingBody[i]);
|
|
159
|
+
const closed = existingBody[i].includes("-->");
|
|
160
|
+
i++;
|
|
161
|
+
if (closed)
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return [
|
|
166
|
+
...lines.slice(0, headerIdx + 1),
|
|
167
|
+
"",
|
|
168
|
+
...(preserved.length ? [...preserved, ""] : []),
|
|
169
|
+
...canonicalLines,
|
|
170
|
+
"",
|
|
171
|
+
...lines.slice(bodyEnd),
|
|
172
|
+
].join("\n");
|
|
173
|
+
}
|
|
77
174
|
async function mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, content) {
|
|
78
175
|
const contract = resolveGsdPathContract(basePath);
|
|
79
176
|
if (!contract.worktreeGsd)
|
|
@@ -192,6 +289,7 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
192
289
|
}, basePath);
|
|
193
290
|
await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, contentToSave);
|
|
194
291
|
let registeredMilestones = [];
|
|
292
|
+
let milestoneSequenceSelfHealed = false;
|
|
195
293
|
if (params.artifact_type === "PROJECT") {
|
|
196
294
|
try {
|
|
197
295
|
registeredMilestones = registerProjectMilestoneSequence(contentToSave);
|
|
@@ -227,28 +325,78 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
227
325
|
};
|
|
228
326
|
}
|
|
229
327
|
if (registeredMilestones.length === 0) {
|
|
230
|
-
|
|
328
|
+
const existingMilestones = getAllMilestones();
|
|
329
|
+
if (existingMilestones.length === 0) {
|
|
330
|
+
// Genuine first-save failure: no milestones parsed AND none in the DB.
|
|
331
|
+
// /gsd really would report "No Active Milestone" — hard-fail so the
|
|
332
|
+
// caller rewrites the sequence before proceeding.
|
|
333
|
+
logError("tool", `gsd_summary_save: PROJECT.md saved to ${relativePath} but parsed zero milestones — registration produced no DB rows`, {
|
|
334
|
+
tool: "gsd_summary_save",
|
|
335
|
+
});
|
|
336
|
+
// PROJECT.md was persisted; invalidate so subsequent reads see the new
|
|
337
|
+
// artifacts row even though no milestones registered.
|
|
338
|
+
invalidateStateCache();
|
|
339
|
+
return {
|
|
340
|
+
content: [{
|
|
341
|
+
type: "text",
|
|
342
|
+
text: `Error: PROJECT.md was saved to ${relativePath} but contains zero parseable milestone lines, ` +
|
|
343
|
+
`so no milestones were registered in the DB. /gsd will report "No Active Milestone". ` +
|
|
344
|
+
`Rewrite PROJECT.md so the "Milestone Sequence" section uses canonical lines: ` +
|
|
345
|
+
`\`- [ ] M001: <Title> — <One-liner>\` (em-dash, double-dash \`--\`, or single-dash \`-\` separator), then re-call gsd_summary_save(PROJECT).`,
|
|
346
|
+
}],
|
|
347
|
+
details: {
|
|
348
|
+
operation: "save_summary",
|
|
349
|
+
path: relativePath,
|
|
350
|
+
artifact_type: params.artifact_type,
|
|
351
|
+
error: "milestone_registration_empty_parse",
|
|
352
|
+
},
|
|
353
|
+
isError: true,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
// Existing DB rows mean this is projection drift, not data loss. Rebuild
|
|
357
|
+
// the section from DB state and re-persist a parseable projection.
|
|
358
|
+
logWarning("tool", `gsd_summary_save: PROJECT.md parsed zero milestone lines but DB has ${existingMilestones.length} — rebuilding Milestone Sequence from DB (projection self-heal)`, {
|
|
231
359
|
tool: "gsd_summary_save",
|
|
360
|
+
path: relativePath,
|
|
232
361
|
});
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
362
|
+
try {
|
|
363
|
+
const healed = rebuildMilestoneSequenceSection(contentToSave, existingMilestones);
|
|
364
|
+
await saveArtifactToDb({ path: relativePath, artifact_type: params.artifact_type, content: healed }, basePath);
|
|
365
|
+
await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, healed);
|
|
366
|
+
const healedRegisteredMilestones = registerProjectMilestoneSequence(healed);
|
|
367
|
+
if (healedRegisteredMilestones.length === 0) {
|
|
368
|
+
throw new Error("self-healed PROJECT.md still parsed zero milestone lines");
|
|
369
|
+
}
|
|
370
|
+
registeredMilestones = healedRegisteredMilestones;
|
|
371
|
+
milestoneSequenceSelfHealed = true;
|
|
372
|
+
}
|
|
373
|
+
catch (healErr) {
|
|
374
|
+
const msg = healErr instanceof Error ? healErr.message : String(healErr);
|
|
375
|
+
logError("tool", `gsd_summary_save: Milestone Sequence self-heal failed: ${msg}`, {
|
|
376
|
+
tool: "gsd_summary_save",
|
|
246
377
|
path: relativePath,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
378
|
+
error: msg,
|
|
379
|
+
});
|
|
380
|
+
invalidateStateCache();
|
|
381
|
+
return {
|
|
382
|
+
content: [{
|
|
383
|
+
type: "text",
|
|
384
|
+
text: `Error: PROJECT.md was saved to ${relativePath} but contains zero parseable milestone lines, ` +
|
|
385
|
+
`and automatic DB-backed Milestone Sequence repair failed: ${msg}. ` +
|
|
386
|
+
`Rewrite PROJECT.md so the "Milestone Sequence" section uses canonical lines: ` +
|
|
387
|
+
`\`- [ ] M001: <Title> — <One-liner>\`, then re-call gsd_summary_save(PROJECT).`,
|
|
388
|
+
}],
|
|
389
|
+
details: {
|
|
390
|
+
operation: "save_summary",
|
|
391
|
+
path: relativePath,
|
|
392
|
+
artifact_type: params.artifact_type,
|
|
393
|
+
error: "milestone_sequence_self_heal_failed",
|
|
394
|
+
self_heal_error: msg,
|
|
395
|
+
},
|
|
396
|
+
isError: true,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
invalidateStateCache();
|
|
252
400
|
}
|
|
253
401
|
}
|
|
254
402
|
if (params.artifact_type === "CONTEXT" && !params.task_id) {
|
|
@@ -271,6 +419,7 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
271
419
|
artifact_type: params.artifact_type,
|
|
272
420
|
content_source: contentSource,
|
|
273
421
|
...(registeredMilestones.length > 0 ? { registeredMilestones } : {}),
|
|
422
|
+
...(milestoneSequenceSelfHealed ? { milestoneSequenceSelfHealed: true } : {}),
|
|
274
423
|
},
|
|
275
424
|
};
|
|
276
425
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// File Purpose: Central UAT mode policy for dispatch, tool presentation, and result validation.
|
|
3
3
|
import { extractUatType } from "./files.js";
|
|
4
4
|
import { hasBrowserRequiredText } from "./browser-evidence.js";
|
|
5
|
+
import { parseMcpToolName } from "./mcp-tool-name.js";
|
|
5
6
|
export const UAT_TYPES = [
|
|
6
7
|
"artifact-driven",
|
|
7
8
|
"browser-executable",
|
|
@@ -80,26 +81,31 @@ export function shouldDispatchUatForContent(content, prefs) {
|
|
|
80
81
|
export function uatTypeIncludesBrowser(uatType) {
|
|
81
82
|
return isUatType(uatType) && UAT_MODE_POLICIES[uatType].browserTools;
|
|
82
83
|
}
|
|
83
|
-
function canonicalPresentedToolName(toolName) {
|
|
84
|
-
if (!toolName.startsWith("mcp__"))
|
|
85
|
-
return toolName;
|
|
86
|
-
const toolSeparator = toolName.indexOf("__", "mcp__".length);
|
|
87
|
-
return toolSeparator >= 0 ? toolName.slice(toolSeparator + 2) : toolName;
|
|
88
|
-
}
|
|
89
84
|
export function isUatBrowserToolName(toolName) {
|
|
90
|
-
|
|
85
|
+
const parsed = parseMcpToolName(toolName);
|
|
86
|
+
const canonicalName = parsed?.toolName ?? toolName;
|
|
87
|
+
if (canonicalName.startsWith("browser_"))
|
|
88
|
+
return true;
|
|
89
|
+
return parsed?.toolName === "*" && parsed.serverName.toLowerCase().includes("browser");
|
|
91
90
|
}
|
|
92
91
|
export function hasUatBrowserToolSurface(activeTools) {
|
|
93
92
|
return Array.isArray(activeTools) && activeTools.some(isUatBrowserToolName);
|
|
94
93
|
}
|
|
94
|
+
export function resolveUatBrowserToolSurface(options) {
|
|
95
|
+
const surfaces = [options.activeTools, options.registeredTools].filter(Array.isArray);
|
|
96
|
+
if (surfaces.length === 0)
|
|
97
|
+
return undefined;
|
|
98
|
+
return [...new Set(surfaces.flat())];
|
|
99
|
+
}
|
|
95
100
|
export function getUatBrowserToolSupportError(options) {
|
|
96
101
|
if (!uatTypeIncludesBrowser(options.uatType))
|
|
97
102
|
return null;
|
|
98
|
-
|
|
103
|
+
const toolSurface = resolveUatBrowserToolSurface(options);
|
|
104
|
+
if (!toolSurface)
|
|
99
105
|
return null;
|
|
100
|
-
if (hasUatBrowserToolSurface(
|
|
106
|
+
if (hasUatBrowserToolSurface(toolSurface))
|
|
101
107
|
return null;
|
|
102
|
-
return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the
|
|
108
|
+
return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the run-uat tool surface has none. Enable browser tools or change the UAT to a runtime-executable Playwright command, then rerun /gsd auto.`;
|
|
103
109
|
}
|
|
104
110
|
export function isPartialEligibleUatType(uatType) {
|
|
105
111
|
return !!uatType && UAT_MODE_POLICIES[uatType].partialEligible;
|