@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
|
@@ -6,10 +6,11 @@ import { sanitizeCompleteMilestoneParams } from "../bootstrap/sanitize-complete-
|
|
|
6
6
|
import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, shouldBlockRootArtifactSaveInSnapshot } from "../bootstrap/write-gate.js";
|
|
7
7
|
import {
|
|
8
8
|
getActiveRequirements,
|
|
9
|
-
|
|
9
|
+
getAllMilestones,
|
|
10
10
|
getMilestone,
|
|
11
11
|
getSliceStatusSummary,
|
|
12
12
|
getSliceTaskCounts,
|
|
13
|
+
insertMilestone,
|
|
13
14
|
insertAssessment,
|
|
14
15
|
insertGateRun,
|
|
15
16
|
readTransaction,
|
|
@@ -126,6 +127,111 @@ function registerProjectMilestoneSequence(content: string): string[] {
|
|
|
126
127
|
return registered;
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
/** Minimal shape of a DB milestone row needed to re-render the sequence section. */
|
|
131
|
+
interface MilestoneSeqRow {
|
|
132
|
+
id: string;
|
|
133
|
+
title: string;
|
|
134
|
+
status: string;
|
|
135
|
+
vision: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Best-effort recovery of the human one-liner for each milestone id from a
|
|
140
|
+
* (possibly malformed) Milestone Sequence body. Deliberately lenient: tolerates
|
|
141
|
+
* any separator the canonical MILESTONE_LINE_RE rejects (en-dash, " : ", a
|
|
142
|
+
* missing checkbox, etc.) so a model formatting slip does not discard the prose.
|
|
143
|
+
*/
|
|
144
|
+
function recoverMilestoneTails(sequenceBody: string): Map<string, string> {
|
|
145
|
+
const out = new Map<string, string>();
|
|
146
|
+
const lenient = /^\s*(?:-\s*)?(?:\[[ xX]\]\s*)?(M\d{3})\b\s*[:.\-–—]*\s*(.*)$/;
|
|
147
|
+
for (const rawLine of sequenceBody.split("\n")) {
|
|
148
|
+
const m = rawLine.match(lenient);
|
|
149
|
+
if (m) out.set(m[1], m[2].trim());
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function firstSentence(text: string): string {
|
|
155
|
+
const trimmed = text.trim();
|
|
156
|
+
if (!trimmed) return "";
|
|
157
|
+
const idx = trimmed.search(/[.!?](\s|$)/);
|
|
158
|
+
return (idx >= 0 ? trimmed.slice(0, idx + 1) : trimmed).trim();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Render one canonical, parseable milestone line for the given DB row. */
|
|
162
|
+
function renderMilestoneLine(m: MilestoneSeqRow, recoveredTail: string): string {
|
|
163
|
+
const done = m.status === "complete";
|
|
164
|
+
let oneLiner = recoveredTail;
|
|
165
|
+
// The recovered tail often still carries the title (e.g. "Foo — bar" or
|
|
166
|
+
// "Foo : bar"). Strip a leading repetition of the title, then any separator.
|
|
167
|
+
if (oneLiner.toLowerCase().startsWith(m.title.toLowerCase())) {
|
|
168
|
+
oneLiner = oneLiner.slice(m.title.length).replace(/^\s*[:.\-–—]+\s*/, "").trim();
|
|
169
|
+
} else {
|
|
170
|
+
const sep = oneLiner.match(/\s+(?:—|–|--|-|:)\s+/);
|
|
171
|
+
if (sep && sep.index !== undefined) oneLiner = oneLiner.slice(sep.index + sep[0].length).trim();
|
|
172
|
+
}
|
|
173
|
+
// MILESTONE_LINE_RE requires non-empty prose after the separator.
|
|
174
|
+
if (!oneLiner) oneLiner = firstSentence(m.vision) || (done ? "Completed." : "Planned.");
|
|
175
|
+
return `- [${done ? "x" : " "}] ${m.id}: ${m.title} — ${oneLiner}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Rebuild the "## Milestone Sequence" section from authoritative DB rows when a
|
|
180
|
+
* model-authored PROJECT.md projection parsed to zero milestone lines but the DB
|
|
181
|
+
* already holds milestones. The DB is the source of truth (markdown is a
|
|
182
|
+
* projection), so this repairs the projection rather than failing the save.
|
|
183
|
+
* Preserves a leading HTML comment in the section and recovers one-liners
|
|
184
|
+
* best-effort. The returned content parses cleanly under MILESTONE_LINE_RE.
|
|
185
|
+
*/
|
|
186
|
+
function rebuildMilestoneSequenceSection(content: string, milestones: MilestoneSeqRow[]): string {
|
|
187
|
+
const lines = content.split("\n");
|
|
188
|
+
const headerIdx = lines.findIndex(l => /^##\s+Milestone Sequence\s*$/.test(l));
|
|
189
|
+
|
|
190
|
+
const canonicalLines = (() => {
|
|
191
|
+
// Recover tails from the existing (malformed) body when the section exists.
|
|
192
|
+
let body = "";
|
|
193
|
+
if (headerIdx !== -1) {
|
|
194
|
+
let end = headerIdx + 1;
|
|
195
|
+
while (end < lines.length && !/^##\s+/.test(lines[end])) end++;
|
|
196
|
+
body = lines.slice(headerIdx + 1, end).join("\n");
|
|
197
|
+
}
|
|
198
|
+
const tails = recoverMilestoneTails(body);
|
|
199
|
+
return milestones.map(m => renderMilestoneLine(m, tails.get(m.id) ?? ""));
|
|
200
|
+
})();
|
|
201
|
+
|
|
202
|
+
if (headerIdx === -1) {
|
|
203
|
+
// No section at all — append a fresh, canonical one.
|
|
204
|
+
const sep = content.endsWith("\n") ? "" : "\n";
|
|
205
|
+
return `${content}${sep}\n## Milestone Sequence\n\n${canonicalLines.join("\n")}\n`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let bodyEnd = headerIdx + 1;
|
|
209
|
+
while (bodyEnd < lines.length && !/^##\s+/.test(lines[bodyEnd])) bodyEnd++;
|
|
210
|
+
const existingBody = lines.slice(headerIdx + 1, bodyEnd);
|
|
211
|
+
|
|
212
|
+
// Preserve a contiguous leading HTML comment block (the "Check off…" hint).
|
|
213
|
+
let i = 0;
|
|
214
|
+
while (i < existingBody.length && existingBody[i].trim() === "") i++;
|
|
215
|
+
const preserved: string[] = [];
|
|
216
|
+
if (i < existingBody.length && existingBody[i].trim().startsWith("<!--")) {
|
|
217
|
+
while (i < existingBody.length) {
|
|
218
|
+
preserved.push(existingBody[i]);
|
|
219
|
+
const closed = existingBody[i].includes("-->");
|
|
220
|
+
i++;
|
|
221
|
+
if (closed) break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return [
|
|
226
|
+
...lines.slice(0, headerIdx + 1),
|
|
227
|
+
"",
|
|
228
|
+
...(preserved.length ? [...preserved, ""] : []),
|
|
229
|
+
...canonicalLines,
|
|
230
|
+
"",
|
|
231
|
+
...lines.slice(bodyEnd),
|
|
232
|
+
].join("\n");
|
|
233
|
+
}
|
|
234
|
+
|
|
129
235
|
async function mirrorArtifactToActiveWorktreeProjection(
|
|
130
236
|
basePath: string,
|
|
131
237
|
relativePath: string,
|
|
@@ -260,6 +366,7 @@ export async function executeSummarySave(
|
|
|
260
366
|
await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, contentToSave);
|
|
261
367
|
|
|
262
368
|
let registeredMilestones: string[] = [];
|
|
369
|
+
let milestoneSequenceSelfHealed = false;
|
|
263
370
|
if (params.artifact_type === "PROJECT") {
|
|
264
371
|
try {
|
|
265
372
|
registeredMilestones = registerProjectMilestoneSequence(contentToSave);
|
|
@@ -294,29 +401,83 @@ export async function executeSummarySave(
|
|
|
294
401
|
};
|
|
295
402
|
}
|
|
296
403
|
if (registeredMilestones.length === 0) {
|
|
297
|
-
|
|
404
|
+
const existingMilestones = getAllMilestones();
|
|
405
|
+
if (existingMilestones.length === 0) {
|
|
406
|
+
// Genuine first-save failure: no milestones parsed AND none in the DB.
|
|
407
|
+
// /gsd really would report "No Active Milestone" — hard-fail so the
|
|
408
|
+
// caller rewrites the sequence before proceeding.
|
|
409
|
+
logError("tool", `gsd_summary_save: PROJECT.md saved to ${relativePath} but parsed zero milestones — registration produced no DB rows`, {
|
|
410
|
+
tool: "gsd_summary_save",
|
|
411
|
+
});
|
|
412
|
+
// PROJECT.md was persisted; invalidate so subsequent reads see the new
|
|
413
|
+
// artifacts row even though no milestones registered.
|
|
414
|
+
invalidateStateCache();
|
|
415
|
+
return {
|
|
416
|
+
content: [{
|
|
417
|
+
type: "text",
|
|
418
|
+
text:
|
|
419
|
+
`Error: PROJECT.md was saved to ${relativePath} but contains zero parseable milestone lines, ` +
|
|
420
|
+
`so no milestones were registered in the DB. /gsd will report "No Active Milestone". ` +
|
|
421
|
+
`Rewrite PROJECT.md so the "Milestone Sequence" section uses canonical lines: ` +
|
|
422
|
+
`\`- [ ] M001: <Title> — <One-liner>\` (em-dash, double-dash \`--\`, or single-dash \`-\` separator), then re-call gsd_summary_save(PROJECT).`,
|
|
423
|
+
}],
|
|
424
|
+
details: {
|
|
425
|
+
operation: "save_summary",
|
|
426
|
+
path: relativePath,
|
|
427
|
+
artifact_type: params.artifact_type,
|
|
428
|
+
error: "milestone_registration_empty_parse",
|
|
429
|
+
},
|
|
430
|
+
isError: true,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Existing DB rows mean this is projection drift, not data loss. Rebuild
|
|
435
|
+
// the section from DB state and re-persist a parseable projection.
|
|
436
|
+
logWarning("tool", `gsd_summary_save: PROJECT.md parsed zero milestone lines but DB has ${existingMilestones.length} — rebuilding Milestone Sequence from DB (projection self-heal)`, {
|
|
298
437
|
tool: "gsd_summary_save",
|
|
438
|
+
path: relativePath,
|
|
299
439
|
});
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
440
|
+
try {
|
|
441
|
+
const healed = rebuildMilestoneSequenceSection(contentToSave, existingMilestones);
|
|
442
|
+
await saveArtifactToDb(
|
|
443
|
+
{ path: relativePath, artifact_type: params.artifact_type, content: healed },
|
|
444
|
+
basePath,
|
|
445
|
+
);
|
|
446
|
+
await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, healed);
|
|
447
|
+
const healedRegisteredMilestones = registerProjectMilestoneSequence(healed);
|
|
448
|
+
if (healedRegisteredMilestones.length === 0) {
|
|
449
|
+
throw new Error("self-healed PROJECT.md still parsed zero milestone lines");
|
|
450
|
+
}
|
|
451
|
+
registeredMilestones = healedRegisteredMilestones;
|
|
452
|
+
milestoneSequenceSelfHealed = true;
|
|
453
|
+
} catch (healErr) {
|
|
454
|
+
const msg = healErr instanceof Error ? healErr.message : String(healErr);
|
|
455
|
+
logError("tool", `gsd_summary_save: Milestone Sequence self-heal failed: ${msg}`, {
|
|
456
|
+
tool: "gsd_summary_save",
|
|
314
457
|
path: relativePath,
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
458
|
+
error: msg,
|
|
459
|
+
});
|
|
460
|
+
invalidateStateCache();
|
|
461
|
+
return {
|
|
462
|
+
content: [{
|
|
463
|
+
type: "text",
|
|
464
|
+
text:
|
|
465
|
+
`Error: PROJECT.md was saved to ${relativePath} but contains zero parseable milestone lines, ` +
|
|
466
|
+
`and automatic DB-backed Milestone Sequence repair failed: ${msg}. ` +
|
|
467
|
+
`Rewrite PROJECT.md so the "Milestone Sequence" section uses canonical lines: ` +
|
|
468
|
+
`\`- [ ] M001: <Title> — <One-liner>\`, then re-call gsd_summary_save(PROJECT).`,
|
|
469
|
+
}],
|
|
470
|
+
details: {
|
|
471
|
+
operation: "save_summary",
|
|
472
|
+
path: relativePath,
|
|
473
|
+
artifact_type: params.artifact_type,
|
|
474
|
+
error: "milestone_sequence_self_heal_failed",
|
|
475
|
+
self_heal_error: msg,
|
|
476
|
+
},
|
|
477
|
+
isError: true,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
invalidateStateCache();
|
|
320
481
|
}
|
|
321
482
|
}
|
|
322
483
|
|
|
@@ -339,6 +500,7 @@ export async function executeSummarySave(
|
|
|
339
500
|
artifact_type: params.artifact_type,
|
|
340
501
|
content_source: contentSource,
|
|
341
502
|
...(registeredMilestones.length > 0 ? { registeredMilestones } : {}),
|
|
503
|
+
...(milestoneSequenceSelfHealed ? { milestoneSequenceSelfHealed: true } : {}),
|
|
342
504
|
},
|
|
343
505
|
};
|
|
344
506
|
} catch (err) {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { extractUatType } from "./files.js";
|
|
5
5
|
import type { UatType } from "./files.js";
|
|
6
6
|
import { hasBrowserRequiredText } from "./browser-evidence.js";
|
|
7
|
+
import { parseMcpToolName } from "./mcp-tool-name.js";
|
|
7
8
|
|
|
8
9
|
export type { UatType } from "./files.js";
|
|
9
10
|
|
|
@@ -122,31 +123,39 @@ export function uatTypeIncludesBrowser(uatType: string | undefined): boolean {
|
|
|
122
123
|
return isUatType(uatType) && UAT_MODE_POLICIES[uatType].browserTools;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
function canonicalPresentedToolName(toolName: string): string {
|
|
126
|
-
if (!toolName.startsWith("mcp__")) return toolName;
|
|
127
|
-
const toolSeparator = toolName.indexOf("__", "mcp__".length);
|
|
128
|
-
return toolSeparator >= 0 ? toolName.slice(toolSeparator + 2) : toolName;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
126
|
export function isUatBrowserToolName(toolName: string): boolean {
|
|
132
|
-
|
|
127
|
+
const parsed = parseMcpToolName(toolName);
|
|
128
|
+
const canonicalName = parsed?.toolName ?? toolName;
|
|
129
|
+
if (canonicalName.startsWith("browser_")) return true;
|
|
130
|
+
return parsed?.toolName === "*" && parsed.serverName.toLowerCase().includes("browser");
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
export function hasUatBrowserToolSurface(activeTools: readonly string[] | undefined): boolean {
|
|
136
134
|
return Array.isArray(activeTools) && activeTools.some(isUatBrowserToolName);
|
|
137
135
|
}
|
|
138
136
|
|
|
137
|
+
export function resolveUatBrowserToolSurface(options: {
|
|
138
|
+
activeTools: readonly string[] | undefined;
|
|
139
|
+
registeredTools?: readonly string[] | undefined;
|
|
140
|
+
}): readonly string[] | undefined {
|
|
141
|
+
const surfaces = [options.activeTools, options.registeredTools].filter(Array.isArray);
|
|
142
|
+
if (surfaces.length === 0) return undefined;
|
|
143
|
+
return [...new Set(surfaces.flat())];
|
|
144
|
+
}
|
|
145
|
+
|
|
139
146
|
export function getUatBrowserToolSupportError(options: {
|
|
140
147
|
uatType: UatType;
|
|
141
148
|
activeTools: readonly string[] | undefined;
|
|
149
|
+
registeredTools?: readonly string[] | undefined;
|
|
142
150
|
milestoneId: string;
|
|
143
151
|
sliceId: string;
|
|
144
152
|
}): string | null {
|
|
145
153
|
if (!uatTypeIncludesBrowser(options.uatType)) return null;
|
|
146
|
-
|
|
147
|
-
if (
|
|
154
|
+
const toolSurface = resolveUatBrowserToolSurface(options);
|
|
155
|
+
if (!toolSurface) return null;
|
|
156
|
+
if (hasUatBrowserToolSurface(toolSurface)) return null;
|
|
148
157
|
|
|
149
|
-
return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the
|
|
158
|
+
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.`;
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
export function isPartialEligibleUatType(uatType: UatType | undefined): boolean {
|
|
@@ -103,7 +103,7 @@ function mergeBlockedTools(
|
|
|
103
103
|
): UatPresentationInput["blockedTools"] {
|
|
104
104
|
const merged = new Map<string, { name: string; reason: string }>();
|
|
105
105
|
for (const entry of [...(current ?? []), ...canonical]) {
|
|
106
|
-
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.
|
|
106
|
+
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name), entry);
|
|
107
107
|
}
|
|
108
108
|
return [...merged.values()];
|
|
109
109
|
}
|
|
@@ -299,22 +299,18 @@ function quoteToolNames(toolNames: readonly string[]): string {
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
function validateCanonicalPresentation(params: UatResultSaveParams): string | null {
|
|
302
|
-
const aliasHints: Record<string, string> = {
|
|
303
|
-
gsd_save_summary: "gsd_summary_save",
|
|
304
|
-
gsd_complete_task: "gsd_task_complete",
|
|
305
|
-
gsd_complete_slice: "gsd_slice_complete",
|
|
306
|
-
gsd_milestone_complete: "gsd_complete_milestone",
|
|
307
|
-
};
|
|
308
302
|
const errors: string[] = [];
|
|
309
303
|
for (const toolName of params.presentation.presentedTools) {
|
|
310
|
-
const baseName = parseMcpToolName(toolName)?.
|
|
311
|
-
const canonical =
|
|
312
|
-
if (canonical
|
|
304
|
+
const baseName = parseMcpToolName(toolName)?.toolName ?? toolName;
|
|
305
|
+
const canonical = canonicalWorkflowToolName(baseName);
|
|
306
|
+
if (canonical !== baseName) {
|
|
307
|
+
errors.push(`presentation tool "${toolName}" uses an alias; use canonical "${canonical}"`);
|
|
308
|
+
}
|
|
313
309
|
}
|
|
314
310
|
|
|
315
311
|
const presentedCanonical = new Set(
|
|
316
312
|
params.presentation.presentedTools.map((toolName) =>
|
|
317
|
-
canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
313
|
+
canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)
|
|
318
314
|
),
|
|
319
315
|
);
|
|
320
316
|
const missingRequiredTools = RUN_UAT_WORKFLOW_TOOL_NAMES.filter(
|
|
@@ -329,11 +325,11 @@ function validateCanonicalPresentation(params: UatResultSaveParams): string | nu
|
|
|
329
325
|
const forbiddenCanonical = new Set(
|
|
330
326
|
RUN_UAT_FORBIDDEN_TOOL_NAMES
|
|
331
327
|
.filter((toolName) => !toolName.includes("*"))
|
|
332
|
-
.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
328
|
+
.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)),
|
|
333
329
|
);
|
|
334
330
|
const forbiddenPresentedTools: string[] = [];
|
|
335
331
|
for (const toolName of params.presentation.presentedTools) {
|
|
336
|
-
const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.
|
|
332
|
+
const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName);
|
|
337
333
|
if (toolName === "mcp__gsd-workflow__*" || forbiddenCanonical.has(canonical)) {
|
|
338
334
|
forbiddenPresentedTools.push(toolName);
|
|
339
335
|
}
|
|
@@ -346,7 +342,7 @@ function validateCanonicalPresentation(params: UatResultSaveParams): string | nu
|
|
|
346
342
|
|
|
347
343
|
const blockedCanonical = new Set(
|
|
348
344
|
params.presentation.blockedTools.map((entry) =>
|
|
349
|
-
canonicalWorkflowToolName(parseMcpToolName(entry.name)?.
|
|
345
|
+
canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name)
|
|
350
346
|
),
|
|
351
347
|
);
|
|
352
348
|
const missingBlockedTools = ["gsd_exec", "gsd_summary_save", "gsd_save_gate_result"].filter(
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
type ContextModePolicy,
|
|
46
46
|
type UnitContextManifest,
|
|
47
47
|
} from "./unit-context-manifest.js";
|
|
48
|
+
import type { UnitPromptContextContract } from "./tool-contract.js";
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Async function mapping an artifact key to its inlined-content string,
|
|
@@ -195,8 +196,32 @@ export interface ComposedUnitContext {
|
|
|
195
196
|
readonly inline: string;
|
|
196
197
|
}
|
|
197
198
|
|
|
199
|
+
export type UnitContextBlockMode = "prepend" | "inline" | "excerpt" | "computed";
|
|
200
|
+
|
|
201
|
+
export interface ComposedUnitContextBlock {
|
|
202
|
+
readonly key: string;
|
|
203
|
+
readonly mode: UnitContextBlockMode;
|
|
204
|
+
readonly body: string;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface ComposedContractedUnitContext extends ComposedUnitContext {
|
|
208
|
+
readonly blocks: readonly ComposedUnitContextBlock[];
|
|
209
|
+
readonly onDemand: readonly ArtifactKey[];
|
|
210
|
+
}
|
|
211
|
+
|
|
198
212
|
const SECTION_SEPARATOR = "\n\n---\n\n";
|
|
199
213
|
|
|
214
|
+
interface UnitContextCompositionContract {
|
|
215
|
+
readonly unitType: string;
|
|
216
|
+
readonly artifacts: {
|
|
217
|
+
readonly inline: readonly ArtifactKey[];
|
|
218
|
+
readonly excerpt: readonly ArtifactKey[];
|
|
219
|
+
readonly onDemand: readonly ArtifactKey[];
|
|
220
|
+
readonly computed: readonly ComputedArtifactId[];
|
|
221
|
+
readonly prepend: readonly ComputedArtifactId[];
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
200
225
|
/**
|
|
201
226
|
* Compose all manifest-declared context for a unit type using the v2
|
|
202
227
|
* surface. Walks `prepend` first (computed-only), then the `inline` list
|
|
@@ -220,36 +245,73 @@ export async function composeUnitContext(
|
|
|
220
245
|
const manifest: UnitContextManifest | null = resolveManifest(unitType);
|
|
221
246
|
if (!manifest) return { prepend: "", inline: "" };
|
|
222
247
|
|
|
223
|
-
|
|
248
|
+
const composed = await composeDeclaredUnitContext({
|
|
249
|
+
unitType,
|
|
250
|
+
artifacts: {
|
|
251
|
+
inline: manifest.artifacts.inline,
|
|
252
|
+
excerpt: manifest.artifacts.excerpt,
|
|
253
|
+
onDemand: manifest.artifacts.onDemand,
|
|
254
|
+
computed: manifest.artifacts.computed ?? [],
|
|
255
|
+
prepend: manifest.prepend ?? [],
|
|
256
|
+
},
|
|
257
|
+
}, opts);
|
|
258
|
+
return {
|
|
259
|
+
prepend: composed.prepend,
|
|
260
|
+
inline: composed.inline,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export async function composeContractedUnitContext(
|
|
265
|
+
contract: UnitPromptContextContract,
|
|
266
|
+
opts: ComposeUnitContextOptions,
|
|
267
|
+
): Promise<ComposedContractedUnitContext> {
|
|
268
|
+
return composeDeclaredUnitContext(contract, opts);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async function composeDeclaredUnitContext(
|
|
272
|
+
contract: UnitContextCompositionContract,
|
|
273
|
+
opts: ComposeUnitContextOptions,
|
|
274
|
+
): Promise<ComposedContractedUnitContext> {
|
|
275
|
+
// Single-source `unitType`: contract/manifest selection comes from the
|
|
224
276
|
// function arg, but computed builders read it from `base.unitType`.
|
|
225
|
-
//
|
|
226
|
-
// but a different one in opts.base), the composer would silently
|
|
227
|
-
// mix one unit's manifest with another unit's computed context.
|
|
228
|
-
// Normalize here so the composer dispatches a consistent identity
|
|
229
|
-
// through to every builder.
|
|
277
|
+
// Normalize here so every builder sees the same Unit identity.
|
|
230
278
|
const normalizedOpts: ComposeUnitContextOptions = {
|
|
231
279
|
...opts,
|
|
232
|
-
base: { ...opts.base, unitType },
|
|
280
|
+
base: { ...opts.base, unitType: contract.unitType },
|
|
233
281
|
};
|
|
234
282
|
|
|
235
|
-
const prependBlocks = await
|
|
236
|
-
|
|
283
|
+
const prependBlocks = await runComputedBlocks(
|
|
284
|
+
contract.artifacts.prepend,
|
|
285
|
+
normalizedOpts,
|
|
286
|
+
"prepend",
|
|
287
|
+
);
|
|
288
|
+
const inlineBlocks: ComposedUnitContextBlock[] = [];
|
|
237
289
|
|
|
238
|
-
for (const key of
|
|
290
|
+
for (const key of contract.artifacts.inline) {
|
|
239
291
|
if (!normalizedOpts.resolveArtifact) break;
|
|
240
292
|
const body = await normalizedOpts.resolveArtifact(key);
|
|
241
|
-
if (body && body.length > 0)
|
|
293
|
+
if (body && body.length > 0) {
|
|
294
|
+
inlineBlocks.push({ key, mode: "inline", body });
|
|
295
|
+
}
|
|
242
296
|
}
|
|
243
|
-
for (const key of
|
|
297
|
+
for (const key of contract.artifacts.excerpt) {
|
|
244
298
|
if (!normalizedOpts.resolveExcerpt) break;
|
|
245
299
|
const body = await normalizedOpts.resolveExcerpt(key);
|
|
246
|
-
if (body && body.length > 0)
|
|
300
|
+
if (body && body.length > 0) {
|
|
301
|
+
inlineBlocks.push({ key, mode: "excerpt", body });
|
|
302
|
+
}
|
|
247
303
|
}
|
|
248
|
-
inlineBlocks.push(...await
|
|
304
|
+
inlineBlocks.push(...await runComputedBlocks(
|
|
305
|
+
contract.artifacts.computed,
|
|
306
|
+
normalizedOpts,
|
|
307
|
+
"computed",
|
|
308
|
+
));
|
|
249
309
|
|
|
250
310
|
return {
|
|
251
|
-
prepend: prependBlocks.join(SECTION_SEPARATOR),
|
|
252
|
-
inline: inlineBlocks.join(SECTION_SEPARATOR),
|
|
311
|
+
prepend: prependBlocks.map((block) => block.body).join(SECTION_SEPARATOR),
|
|
312
|
+
inline: inlineBlocks.map((block) => block.body).join(SECTION_SEPARATOR),
|
|
313
|
+
blocks: [...prependBlocks, ...inlineBlocks],
|
|
314
|
+
onDemand: contract.artifacts.onDemand,
|
|
253
315
|
};
|
|
254
316
|
}
|
|
255
317
|
|
|
@@ -258,10 +320,11 @@ export async function composeUnitContext(
|
|
|
258
320
|
* Missing registry entries (manifest declares the id but caller didn't
|
|
259
321
|
* register it) are skipped silently — see composeUnitContext rationale.
|
|
260
322
|
*/
|
|
261
|
-
async function
|
|
323
|
+
async function runComputedBlocks(
|
|
262
324
|
ids: readonly ComputedArtifactId[],
|
|
263
325
|
opts: ComposeUnitContextOptions,
|
|
264
|
-
|
|
326
|
+
mode: Extract<UnitContextBlockMode, "prepend" | "computed">,
|
|
327
|
+
): Promise<ComposedUnitContextBlock[]> {
|
|
265
328
|
if (ids.length === 0 || !opts.computed) return [];
|
|
266
329
|
// Type safety lives at the registration boundary (caller-supplied
|
|
267
330
|
// `computed` is typed against ComputedArtifactInputs[K] per id). Inside
|
|
@@ -274,12 +337,14 @@ async function runComputed(
|
|
|
274
337
|
inputs: unknown;
|
|
275
338
|
};
|
|
276
339
|
const registry = opts.computed as Record<string, AnyEntry | undefined>;
|
|
277
|
-
const out:
|
|
340
|
+
const out: ComposedUnitContextBlock[] = [];
|
|
278
341
|
for (const id of ids) {
|
|
279
342
|
const entry = registry[id];
|
|
280
343
|
if (!entry) continue;
|
|
281
344
|
const body = await entry.build(entry.inputs, opts.base);
|
|
282
|
-
if (body && body.length > 0)
|
|
345
|
+
if (body && body.length > 0) {
|
|
346
|
+
out.push({ key: id, mode, body });
|
|
347
|
+
}
|
|
283
348
|
}
|
|
284
349
|
return out;
|
|
285
350
|
}
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
} from "./paths.js";
|
|
11
11
|
import { loadFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
|
|
12
12
|
import { parseUnitId } from "./unit-id.js";
|
|
13
|
-
import { getTask, isDbAvailable
|
|
13
|
+
import { getTask, isDbAvailable } from "./gsd-db.js";
|
|
14
|
+
import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
|
|
14
15
|
import { isClosedStatus } from "./status-guards.js";
|
|
15
16
|
|
|
16
17
|
// Per-record advisory lock — prevents read-modify-write races between
|
|
@@ -218,7 +219,7 @@ export async function inspectExecuteTaskDurability(
|
|
|
218
219
|
const nextActionAdvanced = !new RegExp(`Execute ${tid}\\b`).test(stateContent);
|
|
219
220
|
let dbComplete = false;
|
|
220
221
|
if (isDbAvailable()) {
|
|
221
|
-
|
|
222
|
+
refreshWorkflowDatabaseFromDisk();
|
|
222
223
|
const task = getTask(mid, sid, tid);
|
|
223
224
|
dbComplete = !!task && isClosedStatus(task.status);
|
|
224
225
|
}
|
|
@@ -71,6 +71,7 @@ export const UNIT_TOOL_CONTRACTS: Record<string, UnitToolSurfaceContract> = {
|
|
|
71
71
|
"gsd_milestone_generate_id",
|
|
72
72
|
],
|
|
73
73
|
requiredWorkflowTools: [
|
|
74
|
+
"ask_user_questions",
|
|
74
75
|
"gsd_summary_save",
|
|
75
76
|
"gsd_requirement_save",
|
|
76
77
|
"gsd_requirement_update",
|
|
@@ -80,7 +81,7 @@ export const UNIT_TOOL_CONTRACTS: Record<string, UnitToolSurfaceContract> = {
|
|
|
80
81
|
},
|
|
81
82
|
"discuss-slice": {
|
|
82
83
|
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
83
|
-
requiredWorkflowTools: ["gsd_summary_save"],
|
|
84
|
+
requiredWorkflowTools: ["ask_user_questions", "gsd_summary_save"],
|
|
84
85
|
},
|
|
85
86
|
"validate-milestone": {
|
|
86
87
|
allowedGsdTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
|
|
@@ -23,7 +23,7 @@ const APPROVAL_CHANGE_QUESTION_RE =
|
|
|
23
23
|
const RESEARCH_DECISION_QUESTION_RE =
|
|
24
24
|
/\b(?:research|skip)\b/i;
|
|
25
25
|
|
|
26
|
-
function
|
|
26
|
+
function extractVisibleTextFromMessage(msg: unknown): string {
|
|
27
27
|
if (!msg || typeof msg !== "object") return "";
|
|
28
28
|
const content = (msg as { content?: unknown }).content;
|
|
29
29
|
if (typeof content === "string") return content;
|
|
@@ -35,6 +35,26 @@ function extractTextFromMessage(msg: unknown): string {
|
|
|
35
35
|
if (typed.type === "text" && typeof typed.text === "string") {
|
|
36
36
|
parts.push(typed.text);
|
|
37
37
|
}
|
|
38
|
+
// thinking blocks intentionally excluded — they are internal reasoning, not user-visible
|
|
39
|
+
}
|
|
40
|
+
return parts.join("\n");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function extractTextFromMessage(msg: unknown): string {
|
|
44
|
+
if (!msg || typeof msg !== "object") return "";
|
|
45
|
+
const content = (msg as { content?: unknown }).content;
|
|
46
|
+
if (typeof content === "string") return content;
|
|
47
|
+
if (!Array.isArray(content)) return "";
|
|
48
|
+
const parts: string[] = [];
|
|
49
|
+
for (const block of content) {
|
|
50
|
+
if (!block || typeof block !== "object") continue;
|
|
51
|
+
const typed = block as { type?: unknown; text?: unknown; thinking?: unknown };
|
|
52
|
+
if (typed.type === "text" && typeof typed.text === "string") {
|
|
53
|
+
parts.push(typed.text);
|
|
54
|
+
}
|
|
55
|
+
if (typed.type === "thinking" && typeof typed.thinking === "string") {
|
|
56
|
+
parts.push(typed.thinking);
|
|
57
|
+
}
|
|
38
58
|
}
|
|
39
59
|
return parts.join("\n");
|
|
40
60
|
}
|
|
@@ -51,12 +71,24 @@ export function lastAssistantText(messages: unknown[] | null | undefined): strin
|
|
|
51
71
|
return "";
|
|
52
72
|
}
|
|
53
73
|
|
|
74
|
+
function lastAssistantVisibleText(messages: unknown[] | null | undefined): string {
|
|
75
|
+
if (!Array.isArray(messages)) return "";
|
|
76
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
77
|
+
const msg = messages[i];
|
|
78
|
+
if (!msg || typeof msg !== "object") continue;
|
|
79
|
+
if ((msg as { role?: unknown }).role !== "assistant") continue;
|
|
80
|
+
const text = extractVisibleTextFromMessage(msg).trim();
|
|
81
|
+
if (text) return text;
|
|
82
|
+
}
|
|
83
|
+
return "";
|
|
84
|
+
}
|
|
85
|
+
|
|
54
86
|
function anyMessageMatches(messages: unknown[] | undefined, pattern: RegExp): boolean {
|
|
55
87
|
if (!Array.isArray(messages)) return false;
|
|
56
88
|
return messages.some((msg) => {
|
|
57
89
|
if (!msg || typeof msg !== "object") return false;
|
|
58
90
|
if ((msg as { role?: unknown }).role === "user") return false;
|
|
59
|
-
return pattern.test(
|
|
91
|
+
return pattern.test(extractVisibleTextFromMessage(msg));
|
|
60
92
|
});
|
|
61
93
|
}
|
|
62
94
|
|
|
@@ -134,7 +166,7 @@ export function isExplicitApprovalResponse(
|
|
|
134
166
|
export function isAwaitingUserInput(messages: unknown[] | undefined): boolean {
|
|
135
167
|
if (anyMessageMatches(messages, /ask_user_questions was cancelled before receiving a response/i)) return true;
|
|
136
168
|
if (anyMessageMatches(messages, REMOTE_QUESTION_FAILURE_RE)) return true;
|
|
137
|
-
const text =
|
|
169
|
+
const text = lastAssistantVisibleText(messages);
|
|
138
170
|
if (!text) return false;
|
|
139
171
|
if (APPROVAL_WAIT_RE.test(text)) return true;
|
|
140
172
|
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
@@ -145,12 +177,30 @@ export function isAwaitingUserInput(messages: unknown[] | undefined): boolean {
|
|
|
145
177
|
export function isAwaitingApprovalBoundary(messages: unknown[] | undefined): boolean {
|
|
146
178
|
if (anyMessageMatches(messages, /ask_user_questions was cancelled before receiving a response/i)) return true;
|
|
147
179
|
if (anyMessageMatches(messages, REMOTE_QUESTION_FAILURE_RE)) return true;
|
|
148
|
-
const text =
|
|
180
|
+
const text = lastAssistantVisibleText(messages);
|
|
149
181
|
if (!text) return false;
|
|
150
182
|
if (APPROVAL_WAIT_RE.test(text)) return true;
|
|
151
183
|
return hasApprovalQuestion(text);
|
|
152
184
|
}
|
|
153
185
|
|
|
186
|
+
/** True when an assistant message already has an in-flight ask_user_questions tool call. */
|
|
187
|
+
export function messageHasPendingAskUserQuestionsTool(message: unknown): boolean {
|
|
188
|
+
if (!message || typeof message !== "object") return false;
|
|
189
|
+
const content = (message as { content?: unknown }).content;
|
|
190
|
+
if (!Array.isArray(content)) return false;
|
|
191
|
+
return content.some((block) => {
|
|
192
|
+
if (!block || typeof block !== "object") return false;
|
|
193
|
+
// Claude Code marks completion by attaching externalResult, not by setting state.
|
|
194
|
+
// Streaming blocks often carry no state; serverToolUse is the claude-code-cli MCP path.
|
|
195
|
+
const tool = block as { type?: string; name?: string; state?: string; externalResult?: unknown };
|
|
196
|
+
if (tool.type !== "toolCall" && tool.type !== "serverToolUse") return false;
|
|
197
|
+
const name = String(tool.name ?? "").toLowerCase();
|
|
198
|
+
if (!name.includes("ask_user_questions")) return false;
|
|
199
|
+
if (tool.externalResult !== undefined) return false;
|
|
200
|
+
return tool.state !== "completed" && tool.state !== "done";
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
154
204
|
export function shouldPauseForUserApprovalQuestion(
|
|
155
205
|
unitType: string | undefined,
|
|
156
206
|
messages: unknown[] | undefined,
|
|
@@ -158,7 +208,7 @@ export function shouldPauseForUserApprovalQuestion(
|
|
|
158
208
|
if (!unitType || !USER_APPROVAL_UNIT_TYPES.has(unitType)) return false;
|
|
159
209
|
if (anyMessageMatches(messages, /ask_user_questions was cancelled before receiving a response/i)) return true;
|
|
160
210
|
if (anyMessageMatches(messages, REMOTE_QUESTION_FAILURE_RE)) return true;
|
|
161
|
-
const text =
|
|
211
|
+
const text = lastAssistantVisibleText(messages);
|
|
162
212
|
if (!text) return false;
|
|
163
213
|
if (APPROVAL_WAIT_RE.test(text)) return true;
|
|
164
214
|
if (unitType === "research-decision") return hasResearchDecisionQuestion(text);
|