@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
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Recover guided-unit completion signals that did not produce expected tool/file evidence.
|
|
3
|
+
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import {
|
|
7
|
+
clearPathCache,
|
|
8
|
+
relMilestoneFile,
|
|
9
|
+
resolveMilestoneFile,
|
|
10
|
+
resolveMilestonePath,
|
|
11
|
+
} from "./paths.js";
|
|
12
|
+
import {
|
|
13
|
+
_getPendingAutoStart,
|
|
14
|
+
deletePendingAutoStart,
|
|
15
|
+
hasPendingAutoStart,
|
|
16
|
+
} from "./pending-auto-start.js";
|
|
17
|
+
import { logWarning } from "./workflow-logger.js";
|
|
18
|
+
|
|
19
|
+
// #4573: cap for how many times we nudge the LLM after a premature ready
|
|
20
|
+
// phrase before giving up and asking the user to re-run /gsd.
|
|
21
|
+
const MAX_READY_REJECTS = 2;
|
|
22
|
+
|
|
23
|
+
// #4573: matches the canonical ready phrase the discuss prompt asks the LLM
|
|
24
|
+
// to emit. Accepts any M-prefixed milestone ID (three digits + optional
|
|
25
|
+
// suffix) with optional trailing punctuation.
|
|
26
|
+
const READY_PHRASE_RE = /\bMilestone\s+M\d{3}[A-Z0-9-]*\s+ready\.?/i;
|
|
27
|
+
|
|
28
|
+
const emptyTurnCounterByBase = new Map<string, number>();
|
|
29
|
+
const MAX_EMPTY_TURN_RETRIES = 2;
|
|
30
|
+
|
|
31
|
+
// Phrases that indicate the LLM is about to do something but has not yet.
|
|
32
|
+
// Kept tight to avoid flagging legitimate narration like "I'll wait for your answer."
|
|
33
|
+
//
|
|
34
|
+
// "make" was previously in the verb list but matches conversational meta phrases
|
|
35
|
+
// like "Let me make sure I understand…" which are NOT action announcements —
|
|
36
|
+
// removed to prevent the empty-turn nudge from auto-replying to user questions
|
|
37
|
+
// in discuss flows.
|
|
38
|
+
const COMMIT_INTENT_RE =
|
|
39
|
+
/\b(?:I['’]ll|I will|Next,? I['’]ll|Now I['’]ll|Let me|I['’]m going to|I am going to)\s+(?:now\s+)?(?:write|create|call|invoke|update|add|run|execute|generate|produce|emit|compose|implement|save|apply|commit)\b/i;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extract the concatenated text content from an assistant message, whether it
|
|
43
|
+
* stores content as a string or as an array of text blocks.
|
|
44
|
+
*/
|
|
45
|
+
function extractAssistantText(msg: any): string {
|
|
46
|
+
if (!msg) return "";
|
|
47
|
+
const content = msg.content;
|
|
48
|
+
if (typeof content === "string") return content;
|
|
49
|
+
if (!Array.isArray(content)) return "";
|
|
50
|
+
const parts: string[] = [];
|
|
51
|
+
for (const block of content) {
|
|
52
|
+
if (!block || typeof block !== "object") continue;
|
|
53
|
+
if (block.type === "text" && typeof block.text === "string") parts.push(block.text);
|
|
54
|
+
}
|
|
55
|
+
return parts.join("\n");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Return true if the assistant message contains any tool-use block.
|
|
60
|
+
*
|
|
61
|
+
* The canonical pi-ai `AssistantMessage.content` (see packages/pi-ai/src/types.ts)
|
|
62
|
+
* uses `type: "toolCall"` and `type: "serverToolUse"` for tool invocations —
|
|
63
|
+
* every provider (anthropic-direct, claude-code-cli, openai, etc.) normalizes
|
|
64
|
+
* incoming tool blocks into these two shapes before they reach guided-flow.
|
|
65
|
+
*
|
|
66
|
+
* The Anthropic API wire shape `"tool_use"` / `"server_tool_use"` does NOT appear
|
|
67
|
+
* in the internal AssistantMessage — those literals are only used when sending
|
|
68
|
+
* messages back out to the Anthropic API. Matching them here was a latent bug:
|
|
69
|
+
* `hasToolUse` returned `false` for every real tool call, which let the
|
|
70
|
+
* empty-turn nudge fire and pre-empt MCP tools that block on the user
|
|
71
|
+
* (e.g. `ask_user_questions`). See investigation in PR for #4658.
|
|
72
|
+
*/
|
|
73
|
+
function hasToolUse(msg: any): boolean {
|
|
74
|
+
if (!msg) return false;
|
|
75
|
+
const content = msg.content;
|
|
76
|
+
if (!Array.isArray(content)) return false;
|
|
77
|
+
return content.some(
|
|
78
|
+
(b: any) =>
|
|
79
|
+
b &&
|
|
80
|
+
typeof b === "object" &&
|
|
81
|
+
(b.type === "toolCall" || b.type === "serverToolUse"),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* #4573 — Detect and recover from the "ready phrase without files" failure mode.
|
|
87
|
+
*
|
|
88
|
+
* When the LLM emits "Milestone {{id}} ready." but has not written the
|
|
89
|
+
* milestone CONTEXT/ROADMAP artifacts, `checkAutoStartAfterDiscuss()` silently
|
|
90
|
+
* returns false and the next /gsd invocation loops into the "All milestones
|
|
91
|
+
* complete" warning.
|
|
92
|
+
*
|
|
93
|
+
* This function, called from `handleAgentEnd` after `checkAutoStartAfterDiscuss`
|
|
94
|
+
* returns false, pattern-matches the ready phrase on the last assistant message.
|
|
95
|
+
* If it fired AND neither the canonical M###-CONTEXT.md/M###-ROADMAP.md nor
|
|
96
|
+
* legacy CONTEXT.md/ROADMAP.md files exist, it:
|
|
97
|
+
* 1. Notifies the user that the signal was rejected.
|
|
98
|
+
* 2. Injects a system message via `pi.sendMessage(..., {triggerTurn:true})`
|
|
99
|
+
* telling the LLM the signal was premature and to emit the writes now.
|
|
100
|
+
* 3. Caps at `MAX_READY_REJECTS` per-entry; beyond that, gives up and asks
|
|
101
|
+
* the user to re-run /gsd.
|
|
102
|
+
*
|
|
103
|
+
* Returns true when a nudge (or give-up) was emitted, signaling the caller to
|
|
104
|
+
* skip `resolveAgentEnd`.
|
|
105
|
+
*/
|
|
106
|
+
export function maybeHandleReadyPhraseWithoutFiles(
|
|
107
|
+
event: { messages: any[] },
|
|
108
|
+
lookupBasePath?: string,
|
|
109
|
+
): boolean {
|
|
110
|
+
const entry = _getPendingAutoStart(lookupBasePath);
|
|
111
|
+
if (!entry) return false;
|
|
112
|
+
const { ctx, pi, basePath, milestoneId } = entry;
|
|
113
|
+
|
|
114
|
+
// Gate: last assistant message must contain the ready phrase
|
|
115
|
+
const lastMsg = event.messages[event.messages.length - 1];
|
|
116
|
+
const text = extractAssistantText(lastMsg);
|
|
117
|
+
if (!READY_PHRASE_RE.test(text)) return false;
|
|
118
|
+
|
|
119
|
+
// Bust paths.ts cached dir listings before checking for fresh writes. The
|
|
120
|
+
// LLM's Write tool calls do not invalidate paths.ts caches, so a stale
|
|
121
|
+
// listing taken before the milestone dir or its CONTEXT/ROADMAP files
|
|
122
|
+
// existed would falsely report the artifacts as missing and trigger the
|
|
123
|
+
// 3-strike "ready without files" abort even though the writes succeeded.
|
|
124
|
+
clearPathCache();
|
|
125
|
+
|
|
126
|
+
// Gate: artifacts must still be missing — if they exist, the happy path
|
|
127
|
+
// already fired and we have nothing to do.
|
|
128
|
+
const contextFile = resolveMilestoneFile(basePath, milestoneId, "CONTEXT");
|
|
129
|
+
const roadmapFile = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
130
|
+
if (contextFile || roadmapFile) return false;
|
|
131
|
+
|
|
132
|
+
// Diagnostic: when the cached resolver reports both files missing, also probe
|
|
133
|
+
// the canonical paths with uncached existsSync so we can tell whether the
|
|
134
|
+
// recovery is firing on real-missing files or a path-resolution miss
|
|
135
|
+
// (basePath/symlink mismatch, stale cache despite agent-end-recovery flush,
|
|
136
|
+
// legacy descriptor dir not matching, etc.).
|
|
137
|
+
try {
|
|
138
|
+
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
139
|
+
const canonicalCtx = mDir ? join(mDir, `${milestoneId}-CONTEXT.md`) : null;
|
|
140
|
+
const canonicalRoadmap = mDir ? join(mDir, `${milestoneId}-ROADMAP.md`) : null;
|
|
141
|
+
logWarning(
|
|
142
|
+
"guided",
|
|
143
|
+
`ready-phrase-reject diagnostic mid=${milestoneId} basePath=${basePath} ` +
|
|
144
|
+
`mDir=${mDir ?? "null"} ` +
|
|
145
|
+
`canonical-ctx=${canonicalCtx ?? "null"} ctx-exists=${canonicalCtx ? existsSync(canonicalCtx) : "n/a"} ` +
|
|
146
|
+
`canonical-roadmap=${canonicalRoadmap ?? "null"} roadmap-exists=${canonicalRoadmap ? existsSync(canonicalRoadmap) : "n/a"}`,
|
|
147
|
+
);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
logWarning("guided", `ready-phrase-reject diagnostic failed: ${(e as Error).message}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
entry.readyRejectCount = (entry.readyRejectCount ?? 0) + 1;
|
|
153
|
+
|
|
154
|
+
if (entry.readyRejectCount > MAX_READY_REJECTS) {
|
|
155
|
+
// Give up: clear state and tell the user to re-run /gsd. Avoids an
|
|
156
|
+
// infinite nudge loop when the LLM never produces the writes.
|
|
157
|
+
deletePendingAutoStart(basePath);
|
|
158
|
+
ctx.ui.notify(
|
|
159
|
+
`Milestone ${milestoneId}: LLM signaled "ready" ${entry.readyRejectCount} times without writing files. ` +
|
|
160
|
+
`Stopping auto-nudge. Run /gsd to try again.`,
|
|
161
|
+
"error",
|
|
162
|
+
);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const contextRel = relMilestoneFile(basePath, milestoneId, "CONTEXT");
|
|
167
|
+
const roadmapRel = relMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
168
|
+
ctx.ui.notify(
|
|
169
|
+
`Milestone ${milestoneId}: "ready" signal rejected — ${contextRel} and ${roadmapRel} are missing. Asking the LLM to complete the writes.`,
|
|
170
|
+
"warning",
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const nudge =
|
|
174
|
+
`You emitted "Milestone ${milestoneId} ready." but neither ` +
|
|
175
|
+
`${contextRel} nor ${roadmapRel} exists on disk. ` +
|
|
176
|
+
`The ready phrase is a POST-WRITE signal and has been rejected. ` +
|
|
177
|
+
`In this turn: (1) write PROJECT.md, REQUIREMENTS.md, and the milestone ` +
|
|
178
|
+
`CONTEXT.md, (2) call gsd_plan_milestone, then (3) emit the ready phrase. ` +
|
|
179
|
+
`Do not describe these steps — execute them as tool calls. ` +
|
|
180
|
+
`This is retry ${entry.readyRejectCount}/${MAX_READY_REJECTS}; further ` +
|
|
181
|
+
`premature signals will clear the session.`;
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
pi.sendMessage(
|
|
185
|
+
{ customType: "gsd-ready-no-files", content: nudge, display: false },
|
|
186
|
+
{ triggerTurn: true },
|
|
187
|
+
);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
logWarning("guided", `ready-phrase nudge sendMessage failed: ${(e as Error).message}`);
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Reset the empty-turn counter for a basePath after a successful tool-use turn.
|
|
197
|
+
* Called from handleAgentEnd when the last message contains tool_use blocks.
|
|
198
|
+
*/
|
|
199
|
+
export function resetEmptyTurnCounter(basePath?: string): void {
|
|
200
|
+
if (basePath) emptyTurnCounterByBase.delete(basePath);
|
|
201
|
+
else emptyTurnCounterByBase.clear();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function maybeHandleEmptyIntentTurn(
|
|
205
|
+
event: { messages: any[] },
|
|
206
|
+
isAuto: boolean,
|
|
207
|
+
lookupBasePath?: string,
|
|
208
|
+
): boolean {
|
|
209
|
+
// Gate: only fire when there is system-driven work in flight. Interactive
|
|
210
|
+
// /gsd discuss (user-driven) produces legitimate text-only turns.
|
|
211
|
+
if (!isAuto && !hasPendingAutoStart(lookupBasePath)) return false;
|
|
212
|
+
|
|
213
|
+
const lastMsg = event.messages[event.messages.length - 1];
|
|
214
|
+
if (!lastMsg) return false;
|
|
215
|
+
if (hasToolUse(lastMsg)) return false;
|
|
216
|
+
|
|
217
|
+
const text = extractAssistantText(lastMsg).trim();
|
|
218
|
+
if (!text) return false;
|
|
219
|
+
|
|
220
|
+
// Skip if the LLM is emitting the ready phrase — that is the ready-no-files
|
|
221
|
+
// path, handled by maybeHandleReadyPhraseWithoutFiles.
|
|
222
|
+
if (READY_PHRASE_RE.test(text)) return false;
|
|
223
|
+
|
|
224
|
+
// Skip if the LLM is clearly handing back to the user. Discuss flows
|
|
225
|
+
// often pose a question and follow it with a conditional intent on the
|
|
226
|
+
// same line ("Did I capture that correctly? If so, I'll write the
|
|
227
|
+
// requirements."). A line-trailing `?` check misses these because the
|
|
228
|
+
// line ends in `.`. Match any sentence-terminating `?` (followed by
|
|
229
|
+
// whitespace or end-of-text) — false negatives here auto-reply to the
|
|
230
|
+
// user, which is a much worse failure mode than a missed nudge.
|
|
231
|
+
if (/\?(?:\s|$)/.test(text)) return false;
|
|
232
|
+
|
|
233
|
+
// Must contain a commit-intent phrase — this is the stall we care about.
|
|
234
|
+
if (!COMMIT_INTENT_RE.test(text)) return false;
|
|
235
|
+
|
|
236
|
+
// Resolve the target basePath + pi for injection. Prefer the pending
|
|
237
|
+
// autostart entry (discuss flow); otherwise we cannot inject.
|
|
238
|
+
const entry = _getPendingAutoStart(lookupBasePath);
|
|
239
|
+
if (!entry) return false;
|
|
240
|
+
const { ctx, pi, basePath } = entry;
|
|
241
|
+
|
|
242
|
+
const count = (emptyTurnCounterByBase.get(basePath) ?? 0) + 1;
|
|
243
|
+
emptyTurnCounterByBase.set(basePath, count);
|
|
244
|
+
|
|
245
|
+
if (count > MAX_EMPTY_TURN_RETRIES) {
|
|
246
|
+
ctx.ui.notify(
|
|
247
|
+
`Empty-turn recovery: LLM announced intent ${count} times without calling any tool. ` +
|
|
248
|
+
`Stopping auto-nudge.`,
|
|
249
|
+
"error",
|
|
250
|
+
);
|
|
251
|
+
return false; // let the normal flow resolve/pause the unit
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
ctx.ui.notify(
|
|
255
|
+
`Empty-turn detected: LLM announced intent but called no tool. Prompting it to execute.`,
|
|
256
|
+
"info",
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const nudge =
|
|
260
|
+
`Your last turn announced an action (e.g. "I'll write…" or "Let me call…") ` +
|
|
261
|
+
`but contained no tool call. The system records zero tool-use blocks for ` +
|
|
262
|
+
`that turn. Execute the announced action NOW as a tool call in this turn. ` +
|
|
263
|
+
`Do not describe it again. Retry ${count}/${MAX_EMPTY_TURN_RETRIES}.`;
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
pi.sendMessage(
|
|
267
|
+
{ customType: "gsd-empty-turn-recovery", content: nudge, display: false },
|
|
268
|
+
{ triggerTurn: true },
|
|
269
|
+
);
|
|
270
|
+
} catch (e) {
|
|
271
|
+
logWarning("guided", `empty-turn nudge sendMessage failed: ${(e as Error).message}`);
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
// Critical invariant: rendered markdown must round-trip through
|
|
10
10
|
// parseRoadmap(), parsePlan(), parseSummary() in files.ts.
|
|
11
11
|
|
|
12
|
-
import { readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
12
|
+
import { readFileSync, existsSync, mkdirSync, statSync } from "node:fs";
|
|
13
13
|
import { logWarning } from "./workflow-logger.js";
|
|
14
14
|
import { isClosedStatus } from "./status-guards.js";
|
|
15
15
|
import { dirname, join, relative } from "node:path";
|
|
16
|
-
import { createRequire } from "node:module";
|
|
17
16
|
import {
|
|
18
17
|
getAllMilestones,
|
|
19
18
|
getMilestone,
|
|
@@ -38,7 +37,8 @@ import {
|
|
|
38
37
|
buildTaskFileName,
|
|
39
38
|
buildSliceFileName,
|
|
40
39
|
} from "./paths.js";
|
|
41
|
-
import { saveFile, clearParseCache } from "./files.js";
|
|
40
|
+
import { saveFile, clearParseCache, registerCacheClearCallback } from "./files.js";
|
|
41
|
+
import { parseRoadmap, parsePlan } from "./parsers-legacy.js";
|
|
42
42
|
import { invalidateStateCache } from "./state.js";
|
|
43
43
|
import { clearPathCache } from "./paths.js";
|
|
44
44
|
import type { RiskLevel } from "./types.js";
|
|
@@ -171,7 +171,8 @@ function renderRoadmapMarkdown(milestone: MilestoneRow, slices: SliceRow[]): str
|
|
|
171
171
|
lines.push("");
|
|
172
172
|
for (const slice of slices) {
|
|
173
173
|
const done = isClosedStatus(slice.status) ? "x" : " ";
|
|
174
|
-
const
|
|
174
|
+
const cleanDepends = (slice.depends ?? []).map(d => d.replace(/^\[|\]$/g, '')).filter(d => /^[A-Za-z0-9][A-Za-z0-9-]*$/.test(d));
|
|
175
|
+
const depends = `[${cleanDepends.join(",")}]`;
|
|
175
176
|
const safeTitle = sanitizeInlineRoadmapText(slice.title || slice.id) || slice.id;
|
|
176
177
|
const safeRisk = normalizeRiskLevel(slice.risk);
|
|
177
178
|
// ADR-011: sketch slices get a `[sketch]` badge so the roadmap shows at a
|
|
@@ -738,20 +739,41 @@ export interface StaleEntry {
|
|
|
738
739
|
* Returns a list of stale entries with file path and reason.
|
|
739
740
|
* Logs to stderr when stale files are detected.
|
|
740
741
|
*/
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
742
|
+
// #442 Phase 1.5: cache parsed ROADMAP/PLAN projections by file identity
|
|
743
|
+
// (path + mtimeMs + size) so an unchanged projection skips readFileSync AND
|
|
744
|
+
// the parse entirely on repeated dispatches. The DB-vs-disk comparison below
|
|
745
|
+
// still runs every call against fresh DB rows — only the disk-parse half is
|
|
746
|
+
// memoized, and parsed output depends solely on file bytes, so this is
|
|
747
|
+
// behavior-preserving. Invalidation rides the existing clearParseCache()
|
|
748
|
+
// callback chain (fired by invalidateCaches() after every projection write and
|
|
749
|
+
// by reconcileBeforeDispatch repairs), so a changed file always re-parses.
|
|
750
|
+
interface CachedProjection { mtimeMs: number; size: number; parsed: unknown }
|
|
751
|
+
const _projectionParseCache = new Map<string, CachedProjection>();
|
|
752
|
+
registerCacheClearCallback(() => _projectionParseCache.clear());
|
|
753
|
+
|
|
754
|
+
function parseProjectionByIdentity(path: string, parse: (content: string) => unknown): unknown {
|
|
755
|
+
let st: ReturnType<typeof statSync> | null = null;
|
|
756
|
+
try { st = statSync(path); } catch { st = null; }
|
|
757
|
+
if (st) {
|
|
758
|
+
const hit = _projectionParseCache.get(path);
|
|
759
|
+
if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) {
|
|
760
|
+
return hit.parsed;
|
|
761
|
+
}
|
|
762
|
+
const parsed = parse(readFileSync(path, "utf-8"));
|
|
763
|
+
_projectionParseCache.set(path, { mtimeMs: st.mtimeMs, size: st.size, parsed });
|
|
764
|
+
return parsed;
|
|
753
765
|
}
|
|
766
|
+
// stat failed (e.g. file vanished between existsSync and here) — fall back to
|
|
767
|
+
// the original plain read+parse so error handling is unchanged.
|
|
768
|
+
return parse(readFileSync(path, "utf-8"));
|
|
769
|
+
}
|
|
754
770
|
|
|
771
|
+
export function detectStaleRenders(basePath: string): StaleEntry[] {
|
|
772
|
+
// parseRoadmap/parsePlan are statically imported (#442 Phase 1.4): the
|
|
773
|
+
// per-call createRequire("./parsers-legacy") that used to live here ran on
|
|
774
|
+
// every dispatch. The static `./parsers-legacy.js` specifier resolves in
|
|
775
|
+
// both packaged (.js) and source (.ts via the strip-types loader) contexts —
|
|
776
|
+
// the same form a dozen other modules already use.
|
|
755
777
|
const stale: StaleEntry[] = [];
|
|
756
778
|
const milestones = getAllMilestones();
|
|
757
779
|
|
|
@@ -762,8 +784,7 @@ export function detectStaleRenders(basePath: string): StaleEntry[] {
|
|
|
762
784
|
const roadmapPath = resolveRoadmapProjectionPath(basePath, milestone.id);
|
|
763
785
|
if (existsSync(roadmapPath)) {
|
|
764
786
|
try {
|
|
765
|
-
const
|
|
766
|
-
const parsed = parseRoadmap(content);
|
|
787
|
+
const parsed = parseProjectionByIdentity(roadmapPath, parseRoadmap) as ReturnType<typeof parseRoadmap>;
|
|
767
788
|
|
|
768
789
|
for (const slice of slices) {
|
|
769
790
|
const isCompleteInDb = isClosedStatus(slice.status);
|
|
@@ -795,8 +816,7 @@ export function detectStaleRenders(basePath: string): StaleEntry[] {
|
|
|
795
816
|
const planPath = resolveSliceFile(basePath, milestone.id, slice.id, "PLAN");
|
|
796
817
|
if (planPath && existsSync(planPath)) {
|
|
797
818
|
try {
|
|
798
|
-
const
|
|
799
|
-
const parsed = parsePlan(content);
|
|
819
|
+
const parsed = parseProjectionByIdentity(planPath, parsePlan) as ReturnType<typeof parsePlan>;
|
|
800
820
|
|
|
801
821
|
for (const task of tasks) {
|
|
802
822
|
const isDoneInDb = isClosedStatus(task.status);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
2
3
|
import { resolve } from "node:path";
|
|
3
4
|
|
|
4
5
|
import type { ClaudeCodeMcpConfig } from "./preferences-types.js";
|
|
6
|
+
import { toMcpWildcardToolName } from "./mcp-tool-name.js";
|
|
5
7
|
import { resolveModelMcpConfig } from "./preferences-mcp.js";
|
|
6
8
|
|
|
7
9
|
interface McpJsonFile {
|
|
@@ -115,6 +117,12 @@ export function discoverMcpServerNames(projectDir: string): string[] {
|
|
|
115
117
|
return discoverMcpServers(projectDir).map((server) => server.name);
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
export function discoverUserMcpServerNames(): string[] {
|
|
121
|
+
const userSettingsPath = resolve(homedir(), ".claude", "settings.json");
|
|
122
|
+
const userSettings = readJsonFile(userSettingsPath, true) as ClaudeSettingsFile | undefined;
|
|
123
|
+
return collectServerEntries(userSettings?.mcpServers).map((s) => s.name);
|
|
124
|
+
}
|
|
125
|
+
|
|
118
126
|
export function computeMcpDisallowedTools(
|
|
119
127
|
modelId: string,
|
|
120
128
|
mcpConfig: ClaudeCodeMcpConfig | undefined,
|
|
@@ -152,5 +160,5 @@ export function computeMcpDisallowedTools(
|
|
|
152
160
|
blocked.delete(workflowServerName);
|
|
153
161
|
}
|
|
154
162
|
|
|
155
|
-
return [...blocked].map(
|
|
163
|
+
return [...blocked].map(toMcpWildcardToolName);
|
|
156
164
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Shared parsing and formatting helpers for MCP-scoped tool names.
|
|
3
|
+
|
|
4
|
+
const MCP_TOOL_PREFIX = "mcp__";
|
|
5
|
+
|
|
6
|
+
export interface ParsedMcpToolName {
|
|
7
|
+
serverName: string;
|
|
8
|
+
toolName: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function parseMcpToolName(toolName: string): ParsedMcpToolName | null {
|
|
12
|
+
if (!toolName.startsWith(MCP_TOOL_PREFIX)) return null;
|
|
13
|
+
const toolSeparator = toolName.indexOf("__", MCP_TOOL_PREFIX.length);
|
|
14
|
+
if (toolSeparator < 0) return null;
|
|
15
|
+
return {
|
|
16
|
+
serverName: toolName.slice(MCP_TOOL_PREFIX.length, toolSeparator),
|
|
17
|
+
toolName: toolName.slice(toolSeparator + 2),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function stripMcpToolPrefix(toolName: string): string {
|
|
22
|
+
return parseMcpToolName(toolName)?.toolName ?? toolName;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function toMcpToolName(serverName: string, toolName: string): string {
|
|
26
|
+
return `${MCP_TOOL_PREFIX}${serverName}__${toolName}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function toMcpWildcardToolName(serverName: string): string {
|
|
30
|
+
return toMcpToolName(serverName, "*");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function mcpToolMatchesBaseName(toolName: string, baseName: string): boolean {
|
|
34
|
+
return parseMcpToolName(toolName)?.toolName === baseName;
|
|
35
|
+
}
|
|
@@ -14,12 +14,12 @@ import {
|
|
|
14
14
|
insertMilestone,
|
|
15
15
|
insertSlice,
|
|
16
16
|
insertTask,
|
|
17
|
-
openDatabase,
|
|
18
17
|
transaction,
|
|
19
18
|
updateMilestoneStatus,
|
|
20
19
|
updateSliceStatus,
|
|
21
20
|
_getAdapter,
|
|
22
21
|
} from './gsd-db.js';
|
|
22
|
+
import { openWorkflowDatabasePath } from './db-workspace.js';
|
|
23
23
|
import {
|
|
24
24
|
resolveGsdRootFile,
|
|
25
25
|
resolveMilestoneFile,
|
|
@@ -641,7 +641,7 @@ export function migrateHierarchyToDb(basePath: string): {
|
|
|
641
641
|
title: sliceEntry.title,
|
|
642
642
|
status: sliceStatus,
|
|
643
643
|
risk: sliceEntry.risk,
|
|
644
|
-
depends: sliceEntry.depends,
|
|
644
|
+
depends: (sliceEntry.depends ?? []).map(d => d.replace(/^\[|\]$/g, '')).filter(d => /^[A-Za-z0-9][A-Za-z0-9-]*$/.test(d)),
|
|
645
645
|
demo: sliceEntry.demo,
|
|
646
646
|
sequence: si + 1, // Preserve roadmap parse order (#3356)
|
|
647
647
|
isSketch: sliceEntry.isSketch ?? false, // ADR-011: preserve the `[sketch]` flag on re-import
|
|
@@ -753,7 +753,7 @@ export function migrateFromMarkdown(gsdDir: string): {
|
|
|
753
753
|
|
|
754
754
|
// Open DB if not already open
|
|
755
755
|
if (!_getAdapter()) {
|
|
756
|
-
|
|
756
|
+
openWorkflowDatabasePath(dbPath);
|
|
757
757
|
}
|
|
758
758
|
|
|
759
759
|
let decisions = 0;
|
|
@@ -7,7 +7,7 @@ import { homedir } from "node:os";
|
|
|
7
7
|
|
|
8
8
|
import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
|
|
9
9
|
import { readCrashLock, isLockProcessAlive } from "../crash-recovery.js";
|
|
10
|
-
import {
|
|
10
|
+
import { closeWorkflowDatabase } from "../db-workspace.js";
|
|
11
11
|
import { readPausedSessionMetadata } from "../interrupted-session.js";
|
|
12
12
|
import { gsdRoot } from "../paths.js";
|
|
13
13
|
import type { MigrationPreview } from "./writer.js";
|
|
@@ -144,6 +144,6 @@ export async function assertMigrationTargetAvailable(targetRoot: string): Promis
|
|
|
144
144
|
);
|
|
145
145
|
}
|
|
146
146
|
} finally {
|
|
147
|
-
|
|
147
|
+
closeWorkflowDatabase();
|
|
148
148
|
}
|
|
149
149
|
}
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
getMilestoneSlices,
|
|
7
7
|
getSliceTasks,
|
|
8
8
|
isDbAvailable,
|
|
9
|
-
refreshOpenDatabaseFromDisk,
|
|
10
9
|
} from "./gsd-db.js";
|
|
10
|
+
import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
|
|
11
11
|
import { parsePlan, parseRoadmap } from "./parsers-legacy.js";
|
|
12
12
|
import {
|
|
13
13
|
milestonesDir,
|
|
@@ -179,7 +179,7 @@ export async function checkMarkdownHierarchyAgainstDb(
|
|
|
179
179
|
// The markdown projections may have just been written by a workflow/MCP
|
|
180
180
|
// server in another process. Reopen before comparing so startup does not
|
|
181
181
|
// warn from a stale long-lived SQLite handle.
|
|
182
|
-
|
|
182
|
+
refreshWorkflowDatabaseFromDisk();
|
|
183
183
|
|
|
184
184
|
const dbScan = scanDbHierarchy();
|
|
185
185
|
const beforeDb = dbScan.counts;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Single proof surface for milestone closeout readiness/finality.
|
|
3
|
+
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
|
|
8
|
+
checkCloseoutConsistencyGate,
|
|
9
|
+
type CloseoutConsistencyFailureReason,
|
|
10
|
+
type CloseoutConsistencyResult,
|
|
11
|
+
} from "./closeout-consistency-gate.js";
|
|
12
|
+
import { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
|
|
13
|
+
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
14
|
+
import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
|
|
15
|
+
|
|
16
|
+
export type CloseoutProofFailureReason =
|
|
17
|
+
| CloseoutConsistencyFailureReason
|
|
18
|
+
| "summary-artifact-missing"
|
|
19
|
+
| "summary-artifact-failed"
|
|
20
|
+
| "implementation-evidence-missing";
|
|
21
|
+
|
|
22
|
+
export type ImplementationEvidenceRequirement = "present" | "not-absent";
|
|
23
|
+
|
|
24
|
+
export type CloseoutProofResult =
|
|
25
|
+
| { ok: true }
|
|
26
|
+
| {
|
|
27
|
+
ok: false;
|
|
28
|
+
reason: CloseoutProofFailureReason;
|
|
29
|
+
recoveryReason: typeof CLOSEOUT_CONSISTENCY_BLOCKED_REASON;
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export interface CloseoutProofOptions {
|
|
34
|
+
refreshFromDisk?: boolean;
|
|
35
|
+
allowOpenMilestone?: boolean;
|
|
36
|
+
summaryArtifactBasePath?: string;
|
|
37
|
+
implementationEvidence?: {
|
|
38
|
+
basePath: string;
|
|
39
|
+
requirement: ImplementationEvidenceRequirement;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function blocked(reason: CloseoutProofFailureReason, message: string): CloseoutProofResult {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
reason,
|
|
47
|
+
recoveryReason: CLOSEOUT_CONSISTENCY_BLOCKED_REASON,
|
|
48
|
+
message,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function fromConsistencyResult(result: CloseoutConsistencyResult): CloseoutProofResult {
|
|
53
|
+
if (result.ok) return result;
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
reason: result.reason,
|
|
57
|
+
recoveryReason: result.recoveryReason,
|
|
58
|
+
message: result.message,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function checkSummaryArtifact(milestoneId: string, basePath: string): CloseoutProofResult {
|
|
63
|
+
const summaryPath = resolveExpectedArtifactPath("complete-milestone", milestoneId, basePath);
|
|
64
|
+
if (!summaryPath || !existsSync(summaryPath)) {
|
|
65
|
+
return blocked(
|
|
66
|
+
"summary-artifact-missing",
|
|
67
|
+
`Closeout proof blocked for ${milestoneId}: milestone summary artifact is missing.`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const summaryOutcome = classifyMilestoneSummaryContent(readFileSync(summaryPath, "utf-8"));
|
|
72
|
+
if (summaryOutcome === "failure") {
|
|
73
|
+
return blocked(
|
|
74
|
+
"summary-artifact-failed",
|
|
75
|
+
`Closeout proof blocked for ${milestoneId}: milestone summary records failed closeout.`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { ok: true };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function checkImplementationEvidence(
|
|
83
|
+
milestoneId: string,
|
|
84
|
+
basePath: string,
|
|
85
|
+
requirement: ImplementationEvidenceRequirement,
|
|
86
|
+
): CloseoutProofResult {
|
|
87
|
+
const evidence = hasImplementationArtifacts(basePath, milestoneId);
|
|
88
|
+
if (requirement === "present" && evidence === "present") return { ok: true };
|
|
89
|
+
if (requirement === "not-absent" && evidence !== "absent") return { ok: true };
|
|
90
|
+
|
|
91
|
+
return blocked(
|
|
92
|
+
"implementation-evidence-missing",
|
|
93
|
+
`Closeout proof blocked for ${milestoneId}: implementation evidence is ${evidence}.`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function proveMilestoneCloseout(
|
|
98
|
+
milestoneId: string,
|
|
99
|
+
options: CloseoutProofOptions = {},
|
|
100
|
+
): CloseoutProofResult {
|
|
101
|
+
const consistency = checkCloseoutConsistencyGate(milestoneId, {
|
|
102
|
+
refreshFromDisk: options.refreshFromDisk,
|
|
103
|
+
allowOpenMilestone: options.allowOpenMilestone,
|
|
104
|
+
artifactBasePath: options.summaryArtifactBasePath,
|
|
105
|
+
});
|
|
106
|
+
if (!consistency.ok) return fromConsistencyResult(consistency);
|
|
107
|
+
|
|
108
|
+
if (options.summaryArtifactBasePath) {
|
|
109
|
+
const summary = checkSummaryArtifact(milestoneId, options.summaryArtifactBasePath);
|
|
110
|
+
if (!summary.ok) return summary;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (options.implementationEvidence) {
|
|
114
|
+
const implementation = checkImplementationEvidence(
|
|
115
|
+
milestoneId,
|
|
116
|
+
options.implementationEvidence.basePath,
|
|
117
|
+
options.implementationEvidence.requirement,
|
|
118
|
+
);
|
|
119
|
+
if (!implementation.ok) return implementation;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return { ok: true };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function formatCloseoutProofBlock(result: CloseoutProofResult): string {
|
|
126
|
+
if (result.ok) return "";
|
|
127
|
+
if (result.reason.startsWith("summary-") || result.reason.startsWith("implementation-")) {
|
|
128
|
+
return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the closeout evidence and run /gsd auto to retry.`;
|
|
129
|
+
}
|
|
130
|
+
return `${result.message} Recovery reason: ${result.recoveryReason}. Resolve the canonical DB state and run /gsd auto to retry.`;
|
|
131
|
+
}
|