@opengsd/gsd-pi 1.2.0-dev.e8563f58 → 1.2.0-dev.fbdca60b
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-model-override.d.ts +15 -0
- package/dist/cli-model-override.js +21 -0
- package/dist/cli.js +1 -18
- package/dist/loader.js +6 -4
- package/dist/register-agent-bundles.d.ts +11 -2
- package/dist/register-agent-bundles.js +18 -4
- package/dist/resource-loader.d.ts +10 -5
- package/dist/resource-loader.js +121 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +3 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +447 -215
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +33 -1
- package/dist/resources/extensions/gsd/auto/closeout.js +215 -0
- package/dist/resources/extensions/gsd/auto/dispatch-history.js +21 -6
- package/dist/resources/extensions/gsd/auto/dispatch.js +365 -0
- package/dist/resources/extensions/gsd/auto/finalize.js +347 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -1
- package/dist/resources/extensions/gsd/auto/milestone-lease-reclaim.js +56 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +85 -15
- package/dist/resources/extensions/gsd/auto/phase-helpers.js +146 -0
- package/dist/resources/extensions/gsd/auto/phases.js +17 -2329
- package/dist/resources/extensions/gsd/auto/pre-dispatch.js +534 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto/unit-phase.js +694 -0
- package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto/worktree-safety-phase.js +125 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +18 -6
- package/dist/resources/extensions/gsd/auto-start.js +23 -3
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
- package/dist/resources/extensions/gsd/auto-verification.js +14 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +15 -2
- package/dist/resources/extensions/gsd/auto.js +45 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -7
- package/dist/resources/extensions/gsd/commands/context.js +16 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -2
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +9 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
- package/dist/resources/extensions/gsd/db/engine.js +24 -6
- package/dist/resources/extensions/gsd/db/queries.js +30 -0
- package/dist/resources/extensions/gsd/db-migration-backup.js +51 -8
- package/dist/resources/extensions/gsd/db-transaction.js +27 -23
- package/dist/resources/extensions/gsd/db-writer.js +8 -17
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
- package/dist/resources/extensions/gsd/doctor-environment.js +256 -125
- package/dist/resources/extensions/gsd/gsd-db.js +15 -20
- package/dist/resources/extensions/gsd/guided-flow.js +93 -4
- package/dist/resources/extensions/gsd/health-widget.js +87 -28
- package/dist/resources/extensions/gsd/mcp-bridge.js +10 -0
- package/dist/resources/extensions/gsd/memory-relations.js +1 -1
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
- package/dist/resources/extensions/gsd/milestone-settlement.js +2 -2
- package/dist/resources/extensions/gsd/notifications.js +12 -7
- package/dist/resources/extensions/gsd/projection-flush.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +3 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
- package/dist/resources/extensions/gsd/session-lock.js +1 -1
- package/dist/resources/extensions/gsd/skill-activation.js +3 -6
- package/dist/resources/extensions/gsd/state.js +6 -2
- package/dist/resources/extensions/gsd/tool-contract.js +14 -3
- package/dist/resources/extensions/gsd/tool-surface-readiness.js +83 -31
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +65 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +1 -1
- package/dist/resources/extensions/gsd/unit-registry.js +34 -4
- package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
- package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
- package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
- package/dist/resources/extensions/gsd/workflow-events.js +6 -18
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +2 -0
- package/dist/resources/extensions/gsd/workflow-mcp-readiness-cache.js +105 -0
- package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
- package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
- package/dist/resources/extensions/gsd/worktree-safety.js +28 -26
- package/dist/resources/extensions/gsd/worktree.js +8 -1
- package/dist/resources/extensions/mcp-client/manager.js +6 -1
- package/dist/resources/skills/create-skill/SKILL.md +3 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
- package/dist/runtime-checks.d.ts +10 -0
- package/dist/runtime-checks.js +27 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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.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 +7 -7
- package/dist/web/standalone/.next/server/chunks/{5942.js → 1128.js} +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-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/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +3 -3
- 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/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +6 -4
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +8 -0
- 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 +50 -6
- 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.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +34 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +17 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/README.md +12 -3
- package/packages/mcp-server/dist/cli-runner.d.ts +40 -0
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -0
- package/packages/mcp-server/dist/cli-runner.js +137 -0
- package/packages/mcp-server/dist/cli-runner.js.map +1 -0
- package/packages/mcp-server/dist/cli.js +2 -53
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/pid-registry.d.ts +46 -0
- package/packages/mcp-server/dist/pid-registry.d.ts.map +1 -0
- package/packages/mcp-server/dist/pid-registry.js +459 -0
- package/packages/mcp-server/dist/pid-registry.js.map +1 -0
- package/packages/mcp-server/dist/probe-mode.d.ts +4 -0
- package/packages/mcp-server/dist/probe-mode.d.ts.map +1 -0
- package/packages/mcp-server/dist/probe-mode.js +10 -0
- package/packages/mcp-server/dist/probe-mode.js.map +1 -0
- package/packages/mcp-server/dist/stdio-watchdog.d.ts +8 -0
- package/packages/mcp-server/dist/stdio-watchdog.d.ts.map +1 -0
- package/packages/mcp-server/dist/stdio-watchdog.js +40 -0
- package/packages/mcp-server/dist/stdio-watchdog.js.map +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +62 -43
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +5 -5
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +43 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +45 -17
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/README.md +15 -0
- package/packages/pi-tui/dist/index.d.ts +2 -2
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -2
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/terminal-image.d.ts +33 -0
- package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal-image.js +54 -2
- package/packages/pi-tui/dist/terminal-image.js.map +1 -1
- package/packages/pi-tui/dist/terminal.d.ts +12 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +70 -25
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +15 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +106 -21
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +110 -36
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +45 -17
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +7 -2
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +531 -226
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +672 -7
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +38 -1
- package/src/resources/extensions/gsd/auto/closeout.ts +309 -0
- package/src/resources/extensions/gsd/auto/dispatch-history.ts +22 -6
- package/src/resources/extensions/gsd/auto/dispatch.ts +449 -0
- package/src/resources/extensions/gsd/auto/finalize.ts +445 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -1
- package/src/resources/extensions/gsd/auto/milestone-lease-reclaim.ts +74 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +95 -15
- package/src/resources/extensions/gsd/auto/phase-helpers.ts +199 -0
- package/src/resources/extensions/gsd/auto/phases.ts +58 -3022
- package/src/resources/extensions/gsd/auto/pre-dispatch.ts +704 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto/unit-phase.ts +910 -0
- package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto/worktree-safety-phase.ts +149 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +10 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +11 -10
- package/src/resources/extensions/gsd/auto-post-unit.ts +21 -6
- package/src/resources/extensions/gsd/auto-start.ts +24 -4
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
- package/src/resources/extensions/gsd/auto-verification.ts +18 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +15 -2
- package/src/resources/extensions/gsd/auto.ts +56 -2
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +56 -6
- package/src/resources/extensions/gsd/commands/context.ts +16 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -2
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +11 -4
- package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
- package/src/resources/extensions/gsd/db/engine.ts +26 -6
- package/src/resources/extensions/gsd/db/queries.ts +29 -0
- package/src/resources/extensions/gsd/db-migration-backup.ts +56 -7
- package/src/resources/extensions/gsd/db-transaction.ts +37 -20
- package/src/resources/extensions/gsd/db-writer.ts +11 -19
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
- package/src/resources/extensions/gsd/doctor-environment.ts +267 -142
- package/src/resources/extensions/gsd/gsd-db.ts +15 -19
- package/src/resources/extensions/gsd/guided-flow.ts +145 -24
- package/src/resources/extensions/gsd/health-widget.ts +91 -27
- package/src/resources/extensions/gsd/mcp-bridge.ts +39 -0
- package/src/resources/extensions/gsd/memory-relations.ts +1 -1
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
- package/src/resources/extensions/gsd/milestone-settlement.ts +2 -2
- package/src/resources/extensions/gsd/notifications.ts +13 -6
- package/src/resources/extensions/gsd/projection-flush.ts +20 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +3 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
- package/src/resources/extensions/gsd/session-lock.ts +1 -1
- package/src/resources/extensions/gsd/skill-activation.ts +3 -6
- package/src/resources/extensions/gsd/state.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +206 -22
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +76 -12
- package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +77 -1
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +236 -0
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +169 -1
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +141 -5
- package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +68 -19
- package/src/resources/extensions/gsd/tests/db-transaction.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +8 -0
- package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +117 -91
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +18 -6
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-environment-async.test.ts +104 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +47 -16
- package/src/resources/extensions/gsd/tests/mcp-readiness-preflight.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/milestone-settlement.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/notifications.test.ts +64 -9
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +31 -81
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +26 -2
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +170 -48
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -17
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +184 -10
- package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-readiness-cache.test.ts +119 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/workflow-phase-contract-matrix.test.ts +332 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety-phase.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
- package/src/resources/extensions/gsd/tool-contract.ts +38 -3
- package/src/resources/extensions/gsd/tool-surface-readiness.ts +126 -19
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +90 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
- package/src/resources/extensions/gsd/unit-context-composer.ts +1 -1
- package/src/resources/extensions/gsd/unit-registry.ts +34 -4
- package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
- package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
- package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
- package/src/resources/extensions/gsd/workflow-events.ts +12 -20
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -0
- package/src/resources/extensions/gsd/workflow-mcp-readiness-cache.ts +150 -0
- package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
- package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
- package/src/resources/extensions/gsd/worktree-safety.ts +41 -39
- package/src/resources/extensions/gsd/worktree.ts +7 -1
- package/src/resources/extensions/mcp-client/manager.ts +7 -1
- package/src/resources/skills/create-skill/SKILL.md +3 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
- package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
- package/src/resources/skills/gsd-browser/SKILL.md +0 -41
- /package/dist/web/standalone/.next/static/{LDHRKiRBIVZmiuMjrL1Vy → 2T9IOdiiM3o3gZ4UbPi8E}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{LDHRKiRBIVZmiuMjrL1Vy → 2T9IOdiiM3o3gZ4UbPi8E}/_ssgManifest.js +0 -0
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// gsd-pi - Claude Code stream adapter regression tests
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
+
import { clearGuidedUnitContext, setGuidedUnitContext } from "../../gsd/guided-unit-context.ts";
|
|
3
4
|
import assert from "node:assert/strict";
|
|
4
5
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
5
7
|
import { join, resolve } from "node:path";
|
|
6
8
|
import { tmpdir } from "node:os";
|
|
9
|
+
import { pathToFileURL } from "node:url";
|
|
7
10
|
import {
|
|
11
|
+
streamViaClaudeCode,
|
|
8
12
|
makeStreamExhaustedErrorMessage,
|
|
9
13
|
isClaudeCodeAbortErrorMessage,
|
|
10
14
|
resolveClaudeCodeAbortedMessageText,
|
|
@@ -35,12 +39,20 @@ import {
|
|
|
35
39
|
roundResultToElicitationContent,
|
|
36
40
|
autoInitClaudeCodeWorkflowMcp,
|
|
37
41
|
inferGsdPhaseFromContext,
|
|
42
|
+
resolveGsdPhaseForSdk,
|
|
43
|
+
resolveClaudeCodeToolSurfaceReadinessError,
|
|
44
|
+
resolveClaudeCodeToolSurfaceReadinessRetryDelayMs,
|
|
45
|
+
shouldRetryClaudeCodeToolSurfaceReadiness,
|
|
46
|
+
buildWorkflowMcpReadinessProgressMessage,
|
|
47
|
+
pushWorkflowMcpReadinessProgressEvent,
|
|
38
48
|
} from "../stream-adapter.ts";
|
|
39
49
|
import { CLAUDE_CODE_MODELS } from "../models.ts";
|
|
40
50
|
import type { AssistantMessage, Context, Message } from "@gsd/pi-ai";
|
|
41
51
|
import type { SDKUserMessage } from "../sdk-types.ts";
|
|
42
52
|
import { _setAutoActiveForTest } from "../../gsd/auto.ts";
|
|
43
53
|
import { getInFlightToolCount, hasInteractiveToolInFlight, clearInFlightTools, isInteractiveElicitationInFlight } from "../../gsd/auto-tool-tracking.ts";
|
|
54
|
+
import { clearMcpConfigCache } from "../../mcp-client/manager.ts";
|
|
55
|
+
import { UNIT_TOOL_CONTRACTS } from "../../gsd/unit-tool-contracts.ts";
|
|
44
56
|
|
|
45
57
|
// ---------------------------------------------------------------------------
|
|
46
58
|
// Env helpers — `GSD_WORKFLOW_MCP_*` save/restore
|
|
@@ -356,6 +368,114 @@ describe("stream-adapter — image prompt forwarding (#4183)", () => {
|
|
|
356
368
|
parent_tool_use_id: null,
|
|
357
369
|
});
|
|
358
370
|
});
|
|
371
|
+
|
|
372
|
+
test("buildSdkQueryPrompt image iterable can be consumed for each SDK retry", async () => {
|
|
373
|
+
const context: Context = {
|
|
374
|
+
messages: [
|
|
375
|
+
{
|
|
376
|
+
role: "user",
|
|
377
|
+
content: [
|
|
378
|
+
{ type: "image", data: "ZmFrZQ==", mimeType: "image/jpeg" },
|
|
379
|
+
{ type: "text", text: "Retry with this image." },
|
|
380
|
+
],
|
|
381
|
+
} as Message,
|
|
382
|
+
],
|
|
383
|
+
};
|
|
384
|
+
const textPrompt = buildPromptFromContext(context);
|
|
385
|
+
const prompt = buildSdkQueryPrompt(context, textPrompt);
|
|
386
|
+
|
|
387
|
+
const firstAttempt = [];
|
|
388
|
+
for await (const item of prompt as AsyncIterable<any>) {
|
|
389
|
+
firstAttempt.push(item);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const retryAttempt = [];
|
|
393
|
+
for await (const item of prompt as AsyncIterable<any>) {
|
|
394
|
+
retryAttempt.push(item);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
assert.equal(firstAttempt.length, 1);
|
|
398
|
+
assert.deepEqual(retryAttempt, firstAttempt);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test("SDK readiness retries do not leak partial content into the next attempt", async () => {
|
|
402
|
+
let queryCalls = 0;
|
|
403
|
+
const cwd = mkdtempSync(join(tmpdir(), "claude-sdk-retry-state-"));
|
|
404
|
+
const context: Context = {
|
|
405
|
+
systemPrompt: "UNIT: Run UAT",
|
|
406
|
+
messages: [{ role: "user", content: "Run UAT." } as Message],
|
|
407
|
+
};
|
|
408
|
+
try {
|
|
409
|
+
const stream = streamViaClaudeCode(
|
|
410
|
+
{ id: "claude-sonnet-4-6" } as any,
|
|
411
|
+
context,
|
|
412
|
+
{
|
|
413
|
+
cwd,
|
|
414
|
+
_skipWorkflowMcpPreflightForTest: true,
|
|
415
|
+
async *_sdkQueryForTest() {
|
|
416
|
+
queryCalls += 1;
|
|
417
|
+
if (queryCalls === 1) {
|
|
418
|
+
yield {
|
|
419
|
+
type: "stream_event",
|
|
420
|
+
event: { type: "message_start", message: { model: "claude-sonnet-4-6" } },
|
|
421
|
+
parent_tool_use_id: null,
|
|
422
|
+
uuid: "partial-1",
|
|
423
|
+
session_id: "session-1",
|
|
424
|
+
};
|
|
425
|
+
yield {
|
|
426
|
+
type: "stream_event",
|
|
427
|
+
event: { type: "content_block_start", index: 0, content_block: { type: "text", text: "" } },
|
|
428
|
+
parent_tool_use_id: null,
|
|
429
|
+
uuid: "partial-1",
|
|
430
|
+
session_id: "session-1",
|
|
431
|
+
};
|
|
432
|
+
yield {
|
|
433
|
+
type: "stream_event",
|
|
434
|
+
event: { type: "content_block_delta", index: 0, delta: { type: "text_delta", text: "stale retry text" } },
|
|
435
|
+
parent_tool_use_id: null,
|
|
436
|
+
uuid: "partial-1",
|
|
437
|
+
session_id: "session-1",
|
|
438
|
+
};
|
|
439
|
+
yield {
|
|
440
|
+
type: "system",
|
|
441
|
+
subtype: "init",
|
|
442
|
+
tools: ["Read"],
|
|
443
|
+
mcp_servers: [{ name: "gsd-workflow", status: "connected" }],
|
|
444
|
+
};
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
yield {
|
|
449
|
+
type: "result",
|
|
450
|
+
subtype: "success",
|
|
451
|
+
uuid: "result-2",
|
|
452
|
+
session_id: "session-2",
|
|
453
|
+
duration_ms: 1,
|
|
454
|
+
duration_api_ms: 1,
|
|
455
|
+
is_error: false,
|
|
456
|
+
num_turns: 1,
|
|
457
|
+
result: "fresh retry result",
|
|
458
|
+
stop_reason: "end_turn",
|
|
459
|
+
total_cost_usd: 0,
|
|
460
|
+
usage: {
|
|
461
|
+
input_tokens: 0,
|
|
462
|
+
output_tokens: 0,
|
|
463
|
+
cache_read_input_tokens: 0,
|
|
464
|
+
cache_creation_input_tokens: 0,
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
},
|
|
468
|
+
} as any,
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
const message = await stream.result();
|
|
472
|
+
|
|
473
|
+
assert.equal(queryCalls, 2);
|
|
474
|
+
assert.deepEqual(message.content, [{ type: "text", text: "fresh retry result" }]);
|
|
475
|
+
} finally {
|
|
476
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
477
|
+
}
|
|
478
|
+
});
|
|
359
479
|
});
|
|
360
480
|
|
|
361
481
|
// ---------------------------------------------------------------------------
|
|
@@ -461,6 +581,33 @@ describe("stream-adapter — no transcript fabrication (#4102)", () => {
|
|
|
461
581
|
assert.ok(!prompt.includes("mcp__gsd-workflow__<tool_name>"));
|
|
462
582
|
});
|
|
463
583
|
|
|
584
|
+
test("buildPromptFromContext remaps structured user input to the workflow MCP question tool", () => {
|
|
585
|
+
const context: Context = {
|
|
586
|
+
systemPrompt: "Use ask_user_questions for structured user input.",
|
|
587
|
+
messages: [{ role: "user", content: "Ask the user what comes next" } as Message],
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
const prompt = buildPromptFromContext(context, { workflowMcpServerName: "gsd-workflow" });
|
|
591
|
+
|
|
592
|
+
assert.ok(prompt.includes("mcp__gsd-workflow__ask_user_questions"));
|
|
593
|
+
assert.ok(prompt.includes("Do not call bare ask_user_questions"));
|
|
594
|
+
assert.ok(prompt.includes("Do not call native AskUserQuestion"));
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
test("buildPromptFromContext allows ToolSearch only for deferred workflow MCP hydration", () => {
|
|
598
|
+
const context: Context = {
|
|
599
|
+
messages: [{ role: "user", content: "Plan the slice" } as Message],
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
const prompt = buildPromptFromContext(context, { workflowMcpServerName: "gsd-workflow" });
|
|
603
|
+
|
|
604
|
+
assert.ok(prompt.includes("ToolSearch is available only for Claude Code deferred workflow MCP hydration"));
|
|
605
|
+
assert.ok(prompt.includes("use ToolSearch with select:mcp__gsd-workflow__<tool_name> or the base tool name"));
|
|
606
|
+
assert.ok(prompt.includes("then call the returned MCP tool directly"));
|
|
607
|
+
assert.ok(prompt.includes("Do not use ToolSearch for browser_* tools or general discovery"));
|
|
608
|
+
assert.ok(!prompt.includes("ToolSearch is NOT available"));
|
|
609
|
+
});
|
|
610
|
+
|
|
464
611
|
test("buildPromptFromContext does not advertise workflow MCP tools when unavailable", () => {
|
|
465
612
|
const context: Context = {
|
|
466
613
|
messages: [{ role: "user", content: "Check status" } as Message],
|
|
@@ -760,6 +907,91 @@ describe("stream-adapter — Claude Code external tool results", () => {
|
|
|
760
907
|
assert.deepEqual(finalContent[1], { type: "text", text: "All done." });
|
|
761
908
|
});
|
|
762
909
|
|
|
910
|
+
test("buildFinalAssistantContent suppresses duplicate empty MCP tool-unavailable failures after same-turn success", () => {
|
|
911
|
+
const finalContent = buildFinalAssistantContent({
|
|
912
|
+
intermediateToolBlocks: [
|
|
913
|
+
{
|
|
914
|
+
type: "toolCall",
|
|
915
|
+
id: "tool-empty-uat",
|
|
916
|
+
name: "gsd_uat_exec",
|
|
917
|
+
arguments: {},
|
|
918
|
+
mcpServer: "gsd-workflow",
|
|
919
|
+
} as any,
|
|
920
|
+
{
|
|
921
|
+
type: "toolCall",
|
|
922
|
+
id: "tool-real-uat",
|
|
923
|
+
name: "gsd_uat_exec",
|
|
924
|
+
arguments: {
|
|
925
|
+
milestoneId: "M004",
|
|
926
|
+
sliceId: "S01",
|
|
927
|
+
checkId: "S01-UAT-01-smoke",
|
|
928
|
+
intent: "uat-runtime-check",
|
|
929
|
+
script: "npx playwright test e2e/priority.spec.js --reporter=line",
|
|
930
|
+
},
|
|
931
|
+
mcpServer: "gsd-workflow",
|
|
932
|
+
} as any,
|
|
933
|
+
],
|
|
934
|
+
pendingContent: [{ type: "text", text: "UAT S01 complete." }],
|
|
935
|
+
toolResultsById: new Map([
|
|
936
|
+
[
|
|
937
|
+
"tool-empty-uat",
|
|
938
|
+
{
|
|
939
|
+
content: [{
|
|
940
|
+
type: "text",
|
|
941
|
+
text: "<tool_use_error>Error: No such tool available: mcp__gsd-workflow__gsd_uat_exec</tool_use_error>",
|
|
942
|
+
}],
|
|
943
|
+
isError: true,
|
|
944
|
+
},
|
|
945
|
+
],
|
|
946
|
+
[
|
|
947
|
+
"tool-real-uat",
|
|
948
|
+
{
|
|
949
|
+
content: [{ type: "text", text: "{\"operation\":\"gsd_uat_exec\",\"exit_code\":0}" }],
|
|
950
|
+
isError: false,
|
|
951
|
+
},
|
|
952
|
+
],
|
|
953
|
+
]),
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
assert.equal(finalContent.length, 2);
|
|
957
|
+
assert.equal((finalContent[0] as any).id, "tool-real-uat");
|
|
958
|
+
assert.deepEqual((finalContent[0] as any).externalResult, {
|
|
959
|
+
content: [{ type: "text", text: "{\"operation\":\"gsd_uat_exec\",\"exit_code\":0}" }],
|
|
960
|
+
isError: false,
|
|
961
|
+
});
|
|
962
|
+
assert.deepEqual(finalContent[1], { type: "text", text: "UAT S01 complete." });
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
test("buildFinalAssistantContent keeps lone MCP tool-unavailable failures", () => {
|
|
966
|
+
const finalContent = buildFinalAssistantContent({
|
|
967
|
+
intermediateToolBlocks: [
|
|
968
|
+
{
|
|
969
|
+
type: "toolCall",
|
|
970
|
+
id: "tool-empty-uat",
|
|
971
|
+
name: "gsd_uat_exec",
|
|
972
|
+
arguments: {},
|
|
973
|
+
mcpServer: "gsd-workflow",
|
|
974
|
+
} as any,
|
|
975
|
+
],
|
|
976
|
+
toolResultsById: new Map([
|
|
977
|
+
[
|
|
978
|
+
"tool-empty-uat",
|
|
979
|
+
{
|
|
980
|
+
content: [{
|
|
981
|
+
type: "text",
|
|
982
|
+
text: "<tool_use_error>Error: No such tool available: mcp__gsd-workflow__gsd_uat_exec</tool_use_error>",
|
|
983
|
+
}],
|
|
984
|
+
isError: true,
|
|
985
|
+
},
|
|
986
|
+
],
|
|
987
|
+
]),
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
assert.equal(finalContent.length, 1);
|
|
991
|
+
assert.equal((finalContent[0] as any).id, "tool-empty-uat");
|
|
992
|
+
assert.equal((finalContent[0] as any).externalResult.isError, true);
|
|
993
|
+
});
|
|
994
|
+
|
|
763
995
|
test("buildFinalAssistantContent keeps final-turn tool calls when result arrives without a synthetic user boundary", () => {
|
|
764
996
|
const finalContent = buildFinalAssistantContent({
|
|
765
997
|
intermediateToolBlocks: [],
|
|
@@ -1053,7 +1285,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1053
1285
|
assert.equal(srv.env.GSD_CLI_PATH, "/tmp/gsd");
|
|
1054
1286
|
assert.equal(srv.env.GSD_PERSIST_WRITE_GATE_STATE, "1");
|
|
1055
1287
|
assert.equal(srv.env.GSD_WORKFLOW_PROJECT_ROOT, "/tmp/project");
|
|
1056
|
-
assert.deepEqual(options.disallowedTools, ["
|
|
1288
|
+
assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
|
|
1057
1289
|
assert.deepEqual(options.allowedTools, [
|
|
1058
1290
|
"Read",
|
|
1059
1291
|
"Write",
|
|
@@ -1173,8 +1405,8 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1173
1405
|
"plan-milestone must expose exact milestone status helper before ToolSearch is needed",
|
|
1174
1406
|
);
|
|
1175
1407
|
assert.ok(
|
|
1176
|
-
allowedTools.includes("mcp__gsd-workflow__*"),
|
|
1177
|
-
"
|
|
1408
|
+
!allowedTools.includes("mcp__gsd-workflow__*"),
|
|
1409
|
+
"strict GSD phases must not rely on a workflow wildcard that can mask missing exact tools",
|
|
1178
1410
|
);
|
|
1179
1411
|
assert.ok((options.disallowedTools as string[]).includes("AskUserQuestion"));
|
|
1180
1412
|
assert.equal(options.strictMcpConfig, true);
|
|
@@ -1186,6 +1418,121 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1186
1418
|
}
|
|
1187
1419
|
});
|
|
1188
1420
|
|
|
1421
|
+
test("buildSdkOptions leaves ToolSearch available for complete-milestone workflow MCP hydration", () => {
|
|
1422
|
+
const restore = setWorkflowMcpEnv({
|
|
1423
|
+
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
1424
|
+
GSD_WORKFLOW_MCP_NAME: "gsd-workflow",
|
|
1425
|
+
GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
|
|
1426
|
+
GSD_WORKFLOW_MCP_ENV: JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" }),
|
|
1427
|
+
GSD_WORKFLOW_MCP_CWD: "/tmp/project",
|
|
1428
|
+
});
|
|
1429
|
+
const originalCwd = process.cwd();
|
|
1430
|
+
const emptyDir = mkdtempSync(join(tmpdir(), "claude-mcp-complete-milestone-"));
|
|
1431
|
+
try {
|
|
1432
|
+
process.chdir(emptyDir);
|
|
1433
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { gsdPhase: "complete-milestone" });
|
|
1434
|
+
const disallowedTools = options.disallowedTools as string[];
|
|
1435
|
+
|
|
1436
|
+
assert.ok(!disallowedTools.includes("ToolSearch"));
|
|
1437
|
+
assert.ok(disallowedTools.includes("Skill"));
|
|
1438
|
+
assert.ok(disallowedTools.includes("AskUserQuestion"));
|
|
1439
|
+
assert.equal(options.strictMcpConfig, true);
|
|
1440
|
+
} finally {
|
|
1441
|
+
process.chdir(originalCwd);
|
|
1442
|
+
rmSync(emptyDir, { recursive: true, force: true });
|
|
1443
|
+
restore();
|
|
1444
|
+
}
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1447
|
+
test("buildSdkOptions scopes complete-slice away from native write and shell tools", () => {
|
|
1448
|
+
const restore = setWorkflowMcpEnv({
|
|
1449
|
+
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
1450
|
+
GSD_WORKFLOW_MCP_NAME: "gsd-workflow",
|
|
1451
|
+
GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
|
|
1452
|
+
GSD_WORKFLOW_MCP_ENV: JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" }),
|
|
1453
|
+
GSD_WORKFLOW_MCP_CWD: "/tmp/project",
|
|
1454
|
+
});
|
|
1455
|
+
const originalCwd = process.cwd();
|
|
1456
|
+
const emptyDir = mkdtempSync(join(tmpdir(), "claude-mcp-complete-slice-"));
|
|
1457
|
+
try {
|
|
1458
|
+
process.chdir(emptyDir);
|
|
1459
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { gsdPhase: "complete-slice" });
|
|
1460
|
+
const allowedTools = options.allowedTools as string[];
|
|
1461
|
+
|
|
1462
|
+
assert.ok(allowedTools.includes("Read"));
|
|
1463
|
+
assert.ok(allowedTools.includes("Glob"));
|
|
1464
|
+
assert.ok(allowedTools.includes("Grep"));
|
|
1465
|
+
assert.ok(allowedTools.includes("mcp__gsd-workflow__gsd_exec"));
|
|
1466
|
+
assert.ok(allowedTools.includes("mcp__gsd-workflow__gsd_slice_complete"));
|
|
1467
|
+
assert.ok(!allowedTools.includes("Bash"));
|
|
1468
|
+
assert.ok(!allowedTools.includes("Write"));
|
|
1469
|
+
assert.ok(!allowedTools.includes("Edit"));
|
|
1470
|
+
assert.ok(!allowedTools.includes("mcp__gsd-workflow__*"));
|
|
1471
|
+
} finally {
|
|
1472
|
+
process.chdir(originalCwd);
|
|
1473
|
+
rmSync(emptyDir, { recursive: true, force: true });
|
|
1474
|
+
restore();
|
|
1475
|
+
}
|
|
1476
|
+
});
|
|
1477
|
+
|
|
1478
|
+
test("buildSdkOptions blocks native Skill tool during GSD phases", () => {
|
|
1479
|
+
const restore = setWorkflowMcpEnv({
|
|
1480
|
+
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
1481
|
+
GSD_WORKFLOW_MCP_NAME: "gsd-workflow",
|
|
1482
|
+
GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
|
|
1483
|
+
GSD_WORKFLOW_MCP_ENV: JSON.stringify({ GSD_CLI_PATH: "/tmp/gsd" }),
|
|
1484
|
+
GSD_WORKFLOW_MCP_CWD: "/tmp/project",
|
|
1485
|
+
});
|
|
1486
|
+
const originalCwd = process.cwd();
|
|
1487
|
+
const emptyDir = mkdtempSync(join(tmpdir(), "claude-mcp-no-native-skill-"));
|
|
1488
|
+
try {
|
|
1489
|
+
process.chdir(emptyDir);
|
|
1490
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { gsdPhase: "complete-slice" });
|
|
1491
|
+
const allowedTools = options.allowedTools as string[];
|
|
1492
|
+
const disallowedTools = options.disallowedTools as string[];
|
|
1493
|
+
|
|
1494
|
+
assert.ok(!allowedTools.includes("Skill"));
|
|
1495
|
+
assert.ok(disallowedTools.includes("Skill"));
|
|
1496
|
+
} finally {
|
|
1497
|
+
process.chdir(originalCwd);
|
|
1498
|
+
rmSync(emptyDir, { recursive: true, force: true });
|
|
1499
|
+
restore();
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
|
|
1503
|
+
test("buildSdkOptions presents every unit's required workflow MCP tools", () => {
|
|
1504
|
+
const restore = setWorkflowMcpEnv({
|
|
1505
|
+
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
1506
|
+
GSD_WORKFLOW_MCP_NAME: "gsd-workflow",
|
|
1507
|
+
GSD_WORKFLOW_MCP_ARGS: JSON.stringify(["packages/mcp-server/dist/cli.js"]),
|
|
1508
|
+
GSD_WORKFLOW_MCP_CWD: "/tmp/project",
|
|
1509
|
+
});
|
|
1510
|
+
const originalCwd = process.cwd();
|
|
1511
|
+
const emptyDir = mkdtempSync(join(tmpdir(), "claude-mcp-all-units-"));
|
|
1512
|
+
try {
|
|
1513
|
+
process.chdir(emptyDir);
|
|
1514
|
+
for (const [unitType, contract] of Object.entries(UNIT_TOOL_CONTRACTS)) {
|
|
1515
|
+
const requiredTools = contract.requiredWorkflowTools.filter(
|
|
1516
|
+
(tool) => tool.startsWith("gsd_") || tool === "ask_user_questions",
|
|
1517
|
+
);
|
|
1518
|
+
if (requiredTools.length === 0) continue;
|
|
1519
|
+
|
|
1520
|
+
const options = buildSdkOptions("claude-sonnet-4-20250514", "test", undefined, { gsdPhase: unitType });
|
|
1521
|
+
const allowedTools = options.allowedTools as string[];
|
|
1522
|
+
for (const toolName of requiredTools) {
|
|
1523
|
+
assert.ok(
|
|
1524
|
+
allowedTools.includes(`mcp__gsd-workflow__${toolName}`) || allowedTools.includes("mcp__gsd-workflow__*"),
|
|
1525
|
+
`${unitType} must allow ${toolName}; allowed=${JSON.stringify(allowedTools)}`,
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
} finally {
|
|
1530
|
+
process.chdir(originalCwd);
|
|
1531
|
+
rmSync(emptyDir, { recursive: true, force: true });
|
|
1532
|
+
restore();
|
|
1533
|
+
}
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1189
1536
|
test("inferGsdPhaseFromContext recognizes non-UAT unit prompts", () => {
|
|
1190
1537
|
const context = {
|
|
1191
1538
|
messages: [
|
|
@@ -1196,6 +1543,53 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1196
1543
|
assert.equal(inferGsdPhaseFromContext(context), "plan-milestone");
|
|
1197
1544
|
});
|
|
1198
1545
|
|
|
1546
|
+
test("inferGsdPhaseFromContext recognizes discuss-slice and refine-slice prompts", () => {
|
|
1547
|
+
const discussSlice = {
|
|
1548
|
+
messages: [{ role: "user", content: "Discuss slice S001 in milestone M001." }],
|
|
1549
|
+
} as Context;
|
|
1550
|
+
const refineSlice = {
|
|
1551
|
+
messages: [{ role: "user", content: "## UNIT: Refine Slice S001 (\"Auth\") - Milestone M001" }],
|
|
1552
|
+
} as Context;
|
|
1553
|
+
|
|
1554
|
+
assert.equal(inferGsdPhaseFromContext(discussSlice), "discuss-slice");
|
|
1555
|
+
assert.equal(inferGsdPhaseFromContext(refineSlice), "refine-slice");
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
test("resolveGsdPhaseForSdk prefers guided unit context over prompt inference", () => {
|
|
1559
|
+
const projectRoot = "/tmp/gsd-guided-phase-project";
|
|
1560
|
+
clearGuidedUnitContext();
|
|
1561
|
+
setGuidedUnitContext(projectRoot, "discuss-slice");
|
|
1562
|
+
try {
|
|
1563
|
+
const context = {
|
|
1564
|
+
messages: [{ role: "user", content: "Generic workflow task with no phase slug." }],
|
|
1565
|
+
} as Context;
|
|
1566
|
+
assert.equal(resolveGsdPhaseForSdk(context, projectRoot), "discuss-slice");
|
|
1567
|
+
} finally {
|
|
1568
|
+
clearGuidedUnitContext(projectRoot);
|
|
1569
|
+
}
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
test("resolveGsdPhaseForSdk matches guided context across milestone worktrees", () => {
|
|
1573
|
+
const projectRoot = "/tmp/gsd-guided-phase-root";
|
|
1574
|
+
const worktreeRoot = `${projectRoot}/.gsd/worktrees/m001-wt`;
|
|
1575
|
+
clearGuidedUnitContext();
|
|
1576
|
+
setGuidedUnitContext(worktreeRoot, "refine-slice");
|
|
1577
|
+
try {
|
|
1578
|
+
const context = { messages: [{ role: "user", content: "No UNIT header here." }] } as Context;
|
|
1579
|
+
assert.equal(resolveGsdPhaseForSdk(context, projectRoot), "refine-slice");
|
|
1580
|
+
} finally {
|
|
1581
|
+
clearGuidedUnitContext(worktreeRoot);
|
|
1582
|
+
}
|
|
1583
|
+
});
|
|
1584
|
+
|
|
1585
|
+
test("resolveGsdPhaseForSdk falls back to prompt inference when guided context is absent", () => {
|
|
1586
|
+
clearGuidedUnitContext();
|
|
1587
|
+
const context = {
|
|
1588
|
+
messages: [{ role: "user", content: "## UNIT: Run UAT — M001/S001" }],
|
|
1589
|
+
} as Context;
|
|
1590
|
+
assert.equal(resolveGsdPhaseForSdk(context, "/tmp/unrelated-project"), "run-uat");
|
|
1591
|
+
});
|
|
1592
|
+
|
|
1199
1593
|
test("buildSdkOptions presents ask_user_questions for discuss phases", () => {
|
|
1200
1594
|
const restore = setWorkflowMcpEnv({
|
|
1201
1595
|
GSD_WORKFLOW_MCP_COMMAND: "node",
|
|
@@ -1245,7 +1639,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1245
1639
|
const mcpServers = options.mcpServers as Record<string, any>;
|
|
1246
1640
|
assert.ok(mcpServers?.["custom-workflow"], "expected custom workflow server config");
|
|
1247
1641
|
assert.ok(mcpServers?.["gsd-browser"], "expected gsd-browser server config");
|
|
1248
|
-
assert.deepEqual(options.disallowedTools, ["
|
|
1642
|
+
assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
|
|
1249
1643
|
assert.deepEqual(options.allowedTools, [
|
|
1250
1644
|
"Read",
|
|
1251
1645
|
"Write",
|
|
@@ -1291,7 +1685,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1291
1685
|
if (mcpServers) {
|
|
1292
1686
|
assert.ok(mcpServers["gsd-workflow"], "if present, must include gsd-workflow");
|
|
1293
1687
|
assert.ok(mcpServers["gsd-browser"], "if present, must include gsd-browser");
|
|
1294
|
-
assert.deepEqual((options as any).disallowedTools, ["
|
|
1688
|
+
assert.deepEqual((options as any).disallowedTools, ["AskUserQuestion"]);
|
|
1295
1689
|
} else {
|
|
1296
1690
|
assert.deepEqual((options as any).disallowedTools, ["ToolSearch"]);
|
|
1297
1691
|
}
|
|
@@ -1333,7 +1727,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1333
1727
|
assert.equal(srv.env.GSD_CLI_PATH, "/tmp/gsd");
|
|
1334
1728
|
assert.equal(srv.env.GSD_PERSIST_WRITE_GATE_STATE, "1");
|
|
1335
1729
|
assert.equal(srv.env.GSD_WORKFLOW_PROJECT_ROOT, resolvedRepoDir);
|
|
1336
|
-
assert.deepEqual(options.disallowedTools, ["
|
|
1730
|
+
assert.deepEqual(options.disallowedTools, ["AskUserQuestion"]);
|
|
1337
1731
|
} finally {
|
|
1338
1732
|
process.chdir(originalCwd);
|
|
1339
1733
|
rmSync(repoDir, { recursive: true, force: true });
|
|
@@ -1403,7 +1797,7 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1403
1797
|
const allowedTools = options.allowedTools as string[];
|
|
1404
1798
|
assert.ok(allowedTools.includes("mcp__gsd-workflow__gsd_plan_milestone"));
|
|
1405
1799
|
assert.ok(allowedTools.includes("mcp__gsd-workflow__gsd_milestone_status"));
|
|
1406
|
-
assert.ok(allowedTools.includes("mcp__gsd-workflow__*"));
|
|
1800
|
+
assert.ok(!allowedTools.includes("mcp__gsd-workflow__*"));
|
|
1407
1801
|
} finally {
|
|
1408
1802
|
process.chdir(originalCwd);
|
|
1409
1803
|
rmSync(projectDir, { recursive: true, force: true });
|
|
@@ -1518,6 +1912,277 @@ describe("stream-adapter — session persistence (#2859)", () => {
|
|
|
1518
1912
|
});
|
|
1519
1913
|
});
|
|
1520
1914
|
|
|
1915
|
+
describe("stream-adapter — workflow MCP readiness", () => {
|
|
1916
|
+
test("emits visible progress text before workflow MCP readiness waits", () => {
|
|
1917
|
+
const partial: AssistantMessage = {
|
|
1918
|
+
role: "assistant",
|
|
1919
|
+
content: [],
|
|
1920
|
+
api: "anthropic-messages",
|
|
1921
|
+
provider: "claude-code",
|
|
1922
|
+
model: "claude-sonnet-4-6",
|
|
1923
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
1924
|
+
stopReason: "stop",
|
|
1925
|
+
timestamp: Date.now(),
|
|
1926
|
+
};
|
|
1927
|
+
const events: any[] = [];
|
|
1928
|
+
const state = {};
|
|
1929
|
+
const message = buildWorkflowMcpReadinessProgressMessage({
|
|
1930
|
+
unitType: "complete-milestone",
|
|
1931
|
+
workflowServerName: "gsd-workflow",
|
|
1932
|
+
stage: "preflight",
|
|
1933
|
+
});
|
|
1934
|
+
|
|
1935
|
+
pushWorkflowMcpReadinessProgressEvent({
|
|
1936
|
+
stream: { push: (event: any) => events.push(event) } as any,
|
|
1937
|
+
partial,
|
|
1938
|
+
state,
|
|
1939
|
+
message,
|
|
1940
|
+
});
|
|
1941
|
+
const retryMessage = buildWorkflowMcpReadinessProgressMessage({
|
|
1942
|
+
unitType: "complete-milestone",
|
|
1943
|
+
workflowServerName: "gsd-workflow",
|
|
1944
|
+
stage: "retry",
|
|
1945
|
+
attempt: 1,
|
|
1946
|
+
delayMs: 1_000,
|
|
1947
|
+
});
|
|
1948
|
+
pushWorkflowMcpReadinessProgressEvent({
|
|
1949
|
+
stream: { push: (event: any) => events.push(event) } as any,
|
|
1950
|
+
partial,
|
|
1951
|
+
state,
|
|
1952
|
+
message: retryMessage,
|
|
1953
|
+
});
|
|
1954
|
+
|
|
1955
|
+
assert.deepEqual(events.map((event) => event.type), ["text_start", "text_delta", "text_delta"]);
|
|
1956
|
+
assert.match(events[1].delta, /Starting gsd-workflow MCP/);
|
|
1957
|
+
assert.match(events[1].delta, /complete-milestone/);
|
|
1958
|
+
assert.match(events[2].delta, /Still waiting for gsd-workflow MCP tools/);
|
|
1959
|
+
assert.match(events[2].delta, /Retrying in 1s/);
|
|
1960
|
+
assert.deepEqual(partial.content, [{ type: "text", text: `${message}\n${retryMessage}` }]);
|
|
1961
|
+
});
|
|
1962
|
+
|
|
1963
|
+
test("execute-task requires gsd_exec before the model follows verification guidance", async () => {
|
|
1964
|
+
const error = await resolveClaudeCodeToolSurfaceReadinessError({
|
|
1965
|
+
unitType: "execute-task",
|
|
1966
|
+
workflowServerName: "gsd-workflow",
|
|
1967
|
+
observation: {
|
|
1968
|
+
tools: [
|
|
1969
|
+
"Read",
|
|
1970
|
+
"Bash",
|
|
1971
|
+
"mcp__gsd-workflow__gsd_task_complete",
|
|
1972
|
+
"mcp__gsd-workflow__gsd_exec_search",
|
|
1973
|
+
"mcp__gsd-workflow__gsd_resume",
|
|
1974
|
+
"mcp__gsd-workflow__gsd_capture_thought",
|
|
1975
|
+
],
|
|
1976
|
+
mcpServers: [{ name: "gsd-workflow", status: "connected" }],
|
|
1977
|
+
},
|
|
1978
|
+
});
|
|
1979
|
+
|
|
1980
|
+
assert.match(error ?? "", /gsd_exec/);
|
|
1981
|
+
});
|
|
1982
|
+
|
|
1983
|
+
test("complete-slice requires gsd_exec before the model follows closeout verification guidance", async () => {
|
|
1984
|
+
const error = await resolveClaudeCodeToolSurfaceReadinessError({
|
|
1985
|
+
unitType: "complete-slice",
|
|
1986
|
+
workflowServerName: "gsd-workflow",
|
|
1987
|
+
observation: {
|
|
1988
|
+
tools: [
|
|
1989
|
+
"Read",
|
|
1990
|
+
"mcp__gsd-workflow__gsd_slice_complete",
|
|
1991
|
+
"mcp__gsd-workflow__gsd_task_reopen",
|
|
1992
|
+
"mcp__gsd-workflow__gsd_replan_slice",
|
|
1993
|
+
"mcp__gsd-workflow__gsd_requirement_update",
|
|
1994
|
+
"mcp__gsd-workflow__gsd_summary_save",
|
|
1995
|
+
"mcp__gsd-workflow__gsd_capture_thought",
|
|
1996
|
+
"mcp__gsd-workflow__gsd_exec_search",
|
|
1997
|
+
],
|
|
1998
|
+
mcpServers: [{ name: "gsd-workflow", status: "connected" }],
|
|
1999
|
+
},
|
|
2000
|
+
});
|
|
2001
|
+
|
|
2002
|
+
assert.match(error ?? "", /gsd_exec/);
|
|
2003
|
+
});
|
|
2004
|
+
|
|
2005
|
+
test("complete-slice requires workflow MCP memory capture before closeout guidance can use it", async () => {
|
|
2006
|
+
const error = await resolveClaudeCodeToolSurfaceReadinessError({
|
|
2007
|
+
unitType: "complete-slice",
|
|
2008
|
+
workflowServerName: "gsd-workflow",
|
|
2009
|
+
observation: {
|
|
2010
|
+
tools: [
|
|
2011
|
+
"Read",
|
|
2012
|
+
"capture_thought",
|
|
2013
|
+
"mcp__gsd-workflow__gsd_exec",
|
|
2014
|
+
"mcp__gsd-workflow__gsd_slice_complete",
|
|
2015
|
+
"mcp__gsd-workflow__gsd_task_reopen",
|
|
2016
|
+
"mcp__gsd-workflow__gsd_replan_slice",
|
|
2017
|
+
"mcp__gsd-workflow__gsd_requirement_update",
|
|
2018
|
+
"mcp__gsd-workflow__gsd_summary_save",
|
|
2019
|
+
],
|
|
2020
|
+
mcpServers: [{ name: "gsd-workflow", status: "connected" }],
|
|
2021
|
+
},
|
|
2022
|
+
});
|
|
2023
|
+
|
|
2024
|
+
assert.match(error ?? "", /gsd_capture_thought/);
|
|
2025
|
+
});
|
|
2026
|
+
|
|
2027
|
+
test("terminal init surface remains not ready even when configured workflow MCP probes available", async () => {
|
|
2028
|
+
const previousGsdHome = process.env.GSD_HOME;
|
|
2029
|
+
const projectRoot = realpathSync(mkdtempSync(join(tmpdir(), "claude-sdk-mcp-pending-ready-")));
|
|
2030
|
+
const gsdHomeDir = realpathSync(mkdtempSync(join(tmpdir(), "claude-sdk-mcp-pending-home-")));
|
|
2031
|
+
try {
|
|
2032
|
+
process.env.GSD_HOME = gsdHomeDir;
|
|
2033
|
+
|
|
2034
|
+
const require = createRequire(import.meta.url);
|
|
2035
|
+
const mcpModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/mcp.js")).href;
|
|
2036
|
+
const stdioModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/stdio.js")).href;
|
|
2037
|
+
const serverPath = join(projectRoot, "fake-workflow-mcp-server.mjs");
|
|
2038
|
+
writeFileSync(
|
|
2039
|
+
serverPath,
|
|
2040
|
+
[
|
|
2041
|
+
`const { McpServer } = await import(${JSON.stringify(mcpModuleUrl)});`,
|
|
2042
|
+
`const { StdioServerTransport } = await import(${JSON.stringify(stdioModuleUrl)});`,
|
|
2043
|
+
'const server = new McpServer({ name: "fake", version: "1.0.0" }, { capabilities: { tools: {} } });',
|
|
2044
|
+
'server.tool("gsd_plan_slice", "Plan slice", {}, async () => ({ content: [{ type: "text", text: "ok" }] }));',
|
|
2045
|
+
'server.tool("gsd_reassess_roadmap", "Reassess roadmap", {}, async () => ({ content: [{ type: "text", text: "ok" }] }));',
|
|
2046
|
+
'await server.connect(new StdioServerTransport());',
|
|
2047
|
+
].join("\n"),
|
|
2048
|
+
"utf-8",
|
|
2049
|
+
);
|
|
2050
|
+
writeFileSync(
|
|
2051
|
+
join(projectRoot, ".mcp.json"),
|
|
2052
|
+
JSON.stringify({ mcpServers: { "gsd-workflow": { command: process.execPath, args: [serverPath] } } }),
|
|
2053
|
+
"utf-8",
|
|
2054
|
+
);
|
|
2055
|
+
|
|
2056
|
+
const error = await resolveClaudeCodeToolSurfaceReadinessError({
|
|
2057
|
+
unitType: "plan-slice",
|
|
2058
|
+
workflowServerName: "gsd-workflow",
|
|
2059
|
+
observation: {
|
|
2060
|
+
tools: ["Read", "Bash"],
|
|
2061
|
+
mcpServers: [{ name: "gsd-workflow", status: "failed" }],
|
|
2062
|
+
},
|
|
2063
|
+
});
|
|
2064
|
+
|
|
2065
|
+
assert.match(error ?? "", /status is "failed"/);
|
|
2066
|
+
assert.match(error ?? "", /gsd_plan_slice/);
|
|
2067
|
+
} finally {
|
|
2068
|
+
if (previousGsdHome === undefined) {
|
|
2069
|
+
delete process.env.GSD_HOME;
|
|
2070
|
+
} else {
|
|
2071
|
+
process.env.GSD_HOME = previousGsdHome;
|
|
2072
|
+
}
|
|
2073
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
2074
|
+
rmSync(gsdHomeDir, { recursive: true, force: true });
|
|
2075
|
+
clearMcpConfigCache();
|
|
2076
|
+
}
|
|
2077
|
+
});
|
|
2078
|
+
|
|
2079
|
+
test("pending init surface is not accepted until the live Claude session exposes plan-slice tools", async () => {
|
|
2080
|
+
const projectRoot = realpathSync(mkdtempSync(join(tmpdir(), "claude-sdk-mcp-plan-pending-")));
|
|
2081
|
+
try {
|
|
2082
|
+
const require = createRequire(import.meta.url);
|
|
2083
|
+
const mcpModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/mcp.js")).href;
|
|
2084
|
+
const stdioModuleUrl = pathToFileURL(require.resolve("@modelcontextprotocol/sdk/server/stdio.js")).href;
|
|
2085
|
+
const serverPath = join(projectRoot, "fake-workflow-mcp-server.mjs");
|
|
2086
|
+
writeFileSync(
|
|
2087
|
+
serverPath,
|
|
2088
|
+
[
|
|
2089
|
+
`const { McpServer } = await import(${JSON.stringify(mcpModuleUrl)});`,
|
|
2090
|
+
`const { StdioServerTransport } = await import(${JSON.stringify(stdioModuleUrl)});`,
|
|
2091
|
+
'const server = new McpServer({ name: "fake", version: "1.0.0" }, { capabilities: { tools: {} } });',
|
|
2092
|
+
'server.tool("gsd_plan_slice", "Plan slice", {}, async () => ({ content: [{ type: "text", text: "ok" }] }));',
|
|
2093
|
+
'server.tool("gsd_reassess_roadmap", "Reassess roadmap", {}, async () => ({ content: [{ type: "text", text: "ok" }] }));',
|
|
2094
|
+
'await server.connect(new StdioServerTransport());',
|
|
2095
|
+
].join("\n"),
|
|
2096
|
+
"utf-8",
|
|
2097
|
+
);
|
|
2098
|
+
writeFileSync(
|
|
2099
|
+
join(projectRoot, ".mcp.json"),
|
|
2100
|
+
JSON.stringify({ mcpServers: { "gsd-workflow": { command: process.execPath, args: [serverPath] } } }),
|
|
2101
|
+
"utf-8",
|
|
2102
|
+
);
|
|
2103
|
+
|
|
2104
|
+
const error = await resolveClaudeCodeToolSurfaceReadinessError({
|
|
2105
|
+
unitType: "plan-slice",
|
|
2106
|
+
workflowServerName: "gsd-workflow",
|
|
2107
|
+
projectRoot,
|
|
2108
|
+
observation: {
|
|
2109
|
+
tools: ["Read", "Bash"],
|
|
2110
|
+
mcpServers: [{ name: "gsd-workflow", status: "pending" }],
|
|
2111
|
+
},
|
|
2112
|
+
});
|
|
2113
|
+
|
|
2114
|
+
assert.match(error ?? "", /status is "pending"/);
|
|
2115
|
+
assert.match(error ?? "", /gsd_plan_slice/);
|
|
2116
|
+
} finally {
|
|
2117
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
2118
|
+
clearMcpConfigCache();
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
2121
|
+
|
|
2122
|
+
test("pending init surface can be deferred to Claude Code ToolSearch hydration", async () => {
|
|
2123
|
+
const error = await resolveClaudeCodeToolSurfaceReadinessError({
|
|
2124
|
+
unitType: "plan-slice",
|
|
2125
|
+
workflowServerName: "gsd-workflow",
|
|
2126
|
+
allowPendingToolSearchHydration: true,
|
|
2127
|
+
observation: {
|
|
2128
|
+
tools: ["Read", "Bash"],
|
|
2129
|
+
mcpServers: [{ name: "gsd-workflow", status: "pending" }],
|
|
2130
|
+
},
|
|
2131
|
+
});
|
|
2132
|
+
|
|
2133
|
+
assert.equal(error, null);
|
|
2134
|
+
});
|
|
2135
|
+
|
|
2136
|
+
test("complete-milestone pending init surface defers to Claude Code ToolSearch hydration", async () => {
|
|
2137
|
+
const error = await resolveClaudeCodeToolSurfaceReadinessError({
|
|
2138
|
+
unitType: "complete-milestone",
|
|
2139
|
+
workflowServerName: "gsd-workflow",
|
|
2140
|
+
allowPendingToolSearchHydration: true,
|
|
2141
|
+
observation: {
|
|
2142
|
+
tools: ["Read", "Bash"],
|
|
2143
|
+
mcpServers: [{ name: "gsd-workflow", status: "pending" }],
|
|
2144
|
+
},
|
|
2145
|
+
});
|
|
2146
|
+
|
|
2147
|
+
assert.equal(error, null);
|
|
2148
|
+
});
|
|
2149
|
+
|
|
2150
|
+
test("retries transient readiness errors internally but not terminal MCP failures", () => {
|
|
2151
|
+
const pendingError =
|
|
2152
|
+
'workflow tool surface not ready for run-uat: MCP server "gsd-workflow" status is "pending" (not yet connected): gsd_uat_exec';
|
|
2153
|
+
const partialError =
|
|
2154
|
+
'workflow tool surface not ready for run-uat: MCP server "gsd-workflow" is connected but has not registered: gsd_uat_exec';
|
|
2155
|
+
const terminalError =
|
|
2156
|
+
'workflow tool surface not ready for run-uat: MCP server "gsd-workflow" status is "failed" (terminal) — cannot register: gsd_uat_exec';
|
|
2157
|
+
|
|
2158
|
+
assert.equal(shouldRetryClaudeCodeToolSurfaceReadiness(pendingError), true);
|
|
2159
|
+
assert.equal(shouldRetryClaudeCodeToolSurfaceReadiness(partialError), true);
|
|
2160
|
+
assert.equal(shouldRetryClaudeCodeToolSurfaceReadiness(terminalError), false);
|
|
2161
|
+
assert.equal(
|
|
2162
|
+
resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 0),
|
|
2163
|
+
500,
|
|
2164
|
+
);
|
|
2165
|
+
assert.equal(
|
|
2166
|
+
resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 1),
|
|
2167
|
+
1_000,
|
|
2168
|
+
);
|
|
2169
|
+
assert.equal(
|
|
2170
|
+
resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(partialError, 2),
|
|
2171
|
+
2_000,
|
|
2172
|
+
);
|
|
2173
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 3), 4_000);
|
|
2174
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 4), 8_000);
|
|
2175
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 5), 15_000);
|
|
2176
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 6), 15_000);
|
|
2177
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 7), 15_000);
|
|
2178
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 8), null);
|
|
2179
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 0, true), 1_000);
|
|
2180
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 9, true), 15_000);
|
|
2181
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(pendingError, 10, true), null);
|
|
2182
|
+
assert.equal(resolveClaudeCodeToolSurfaceReadinessRetryDelayMs(terminalError, 0), null);
|
|
2183
|
+
});
|
|
2184
|
+
});
|
|
2185
|
+
|
|
1521
2186
|
describe("stream-adapter — MCP elicitation bridge", () => {
|
|
1522
2187
|
const askUserQuestionsRequest = {
|
|
1523
2188
|
serverName: "gsd-workflow",
|