@opengsd/gsd-pi 1.2.0-dev.b1abb545 → 1.2.0-dev.fb12b103
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-style.d.ts +17 -0
- package/dist/cli-style.js +28 -0
- package/dist/cli.js +1 -1
- package/dist/headless-events.d.ts +4 -2
- package/dist/headless-events.js +7 -29
- package/dist/models-resolver.d.ts +3 -13
- package/dist/models-resolver.js +3 -22
- package/dist/resource-loader.js +2 -14
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
- package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
- package/dist/resources/extensions/async-jobs/index.js +65 -0
- package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
- package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
- package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
- package/dist/resources/extensions/bg-shell/overlay.js +9 -6
- package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
- package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
- package/dist/resources/extensions/bg-shell/utilities.js +5 -2
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
- package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
- package/dist/resources/extensions/browser-tools/index.js +69 -12
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +38 -6
- package/dist/resources/extensions/gsd/auto/orchestrator.js +40 -9
- package/dist/resources/extensions/gsd/auto/phases.js +6 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +12 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -8
- package/dist/resources/extensions/gsd/auto-prompts.js +15 -10
- package/dist/resources/extensions/gsd/auto-start.js +21 -21
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
- package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
- package/dist/resources/extensions/gsd/auto.js +8 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -12
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +151 -20
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +30 -4
- package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
- package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
- package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
- package/dist/resources/extensions/gsd/captures.js +5 -15
- package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
- package/dist/resources/extensions/gsd/constants.js +0 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
- package/dist/resources/extensions/gsd/db/engine.js +755 -0
- package/dist/resources/extensions/gsd/db/queries.js +372 -0
- package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
- package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
- package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
- package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
- package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
- package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
- package/dist/resources/extensions/gsd/doctor-format.js +9 -6
- package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
- package/dist/resources/extensions/gsd/error-classifier.js +9 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
- package/dist/resources/extensions/gsd/git-service.js +1 -0
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
- package/dist/resources/extensions/gsd/guidance.js +98 -0
- package/dist/resources/extensions/gsd/guided-flow.js +51 -5
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
- package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
- package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
- package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
- package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
- package/dist/resources/extensions/gsd/model-router.js +3 -0
- package/dist/resources/extensions/gsd/notification-store.js +11 -4
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
- package/dist/resources/extensions/gsd/paths.js +37 -24
- package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
- package/dist/resources/extensions/gsd/preferences-models.js +14 -48
- package/dist/resources/extensions/gsd/preferences.js +14 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.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/run-uat.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +5 -2
- package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
- package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
- package/dist/resources/extensions/gsd/publication.js +87 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
- package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
- package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
- package/dist/resources/extensions/gsd/state.js +1 -20
- package/dist/resources/extensions/gsd/status-guards.js +56 -8
- package/dist/resources/extensions/gsd/stop-notice.js +57 -0
- package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
- package/dist/resources/extensions/gsd/tools/exec-tool.js +10 -8
- package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
- package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
- package/dist/resources/extensions/gsd/uat-policy.js +2 -1
- package/dist/resources/extensions/gsd/undo.js +8 -7
- package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
- package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
- package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
- package/dist/resources/extensions/gsd/unit-registry.js +337 -0
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
- package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
- package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
- package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
- package/dist/resources/extensions/gsd/worktree-root.js +28 -6
- package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
- package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
- package/dist/resources/extensions/search-the-web/native-search.js +5 -3
- package/dist/resources/extensions/shared/browser-contract.js +59 -0
- package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
- package/dist/resources/shared/package.json +3 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
- package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
- package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
- package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
- package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
- 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 +10 -10
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.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/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/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 +10 -10
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
- 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/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/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/container.js +18 -26
- package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +14 -47
- 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 +29 -54
- package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +37 -47
- package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +9 -26
- package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +55 -57
- package/dist/web/standalone/node_modules/postcss/lib/node.js +31 -99
- package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
- package/dist/web/standalone/node_modules/postcss/lib/parser.js +9 -10
- package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
- package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +11 -30
- 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 +28 -69
- package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +2 -6
- package/dist/web/standalone/node_modules/postcss/package.json +48 -48
- package/dist/web/standalone/package.json +1 -1
- package/dist/worktree-cli.js +3 -6
- package/dist/worktree-status-banner.js +7 -11
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -0
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +4 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -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 +8 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.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 +7 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/cli.js +6 -3
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +46 -21
- 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/dist/harness/env/nodejs.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
- package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
- package/packages/pi-agent-core/dist/index.d.ts +1 -0
- package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/index.js +3 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
- package/packages/pi-ai/dist/image-models.generated.js +6 -6
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +478 -484
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +500 -533
- 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 +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
- package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
- package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +9 -0
- package/packages/pi-tui/dist/tui.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/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
- package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
- package/src/resources/extensions/async-jobs/index.ts +79 -0
- package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
- package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
- package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
- package/src/resources/extensions/bg-shell/overlay.ts +9 -5
- package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
- package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
- package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
- package/src/resources/extensions/bg-shell/utilities.ts +5 -2
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
- package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
- package/src/resources/extensions/browser-tools/index.ts +71 -13
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +40 -4
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +46 -10
- package/src/resources/extensions/gsd/auto/phases.ts +10 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +12 -0
- package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +25 -7
- package/src/resources/extensions/gsd/auto-prompts.ts +40 -26
- package/src/resources/extensions/gsd/auto-start.ts +21 -22
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
- package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
- package/src/resources/extensions/gsd/auto.ts +20 -24
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +33 -12
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +180 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +29 -3
- package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
- package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
- package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
- package/src/resources/extensions/gsd/captures.ts +5 -16
- package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
- package/src/resources/extensions/gsd/constants.ts +0 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
- package/src/resources/extensions/gsd/db/engine.ts +809 -0
- package/src/resources/extensions/gsd/db/queries.ts +453 -0
- package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
- package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
- package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
- package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
- package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
- package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
- package/src/resources/extensions/gsd/doctor-format.ts +12 -7
- package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
- package/src/resources/extensions/gsd/error-classifier.ts +11 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/git-service.ts +1 -0
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
- package/src/resources/extensions/gsd/guidance.ts +139 -0
- package/src/resources/extensions/gsd/guided-flow.ts +50 -5
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
- package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
- package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
- package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
- package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
- package/src/resources/extensions/gsd/model-router.ts +3 -0
- package/src/resources/extensions/gsd/notification-store.ts +26 -3
- package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
- package/src/resources/extensions/gsd/paths.ts +42 -22
- package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
- package/src/resources/extensions/gsd/preferences-models.ts +12 -47
- package/src/resources/extensions/gsd/preferences.ts +18 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.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/run-uat.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +5 -2
- package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
- package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
- package/src/resources/extensions/gsd/publication.ts +122 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
- package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
- package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
- package/src/resources/extensions/gsd/state.ts +4 -21
- package/src/resources/extensions/gsd/status-guards.ts +59 -8
- package/src/resources/extensions/gsd/stop-notice.ts +75 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +16 -19
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
- package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +58 -15
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +74 -59
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
- package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +24 -29
- package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
- package/src/resources/extensions/gsd/tools/exec-tool.ts +9 -8
- package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
- package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
- package/src/resources/extensions/gsd/uat-policy.ts +2 -1
- package/src/resources/extensions/gsd/undo.ts +9 -8
- package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
- package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
- package/src/resources/extensions/gsd/unit-registry.ts +412 -0
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
- package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
- package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +10 -1
- package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
- package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
- package/src/resources/extensions/gsd/worktree-root.ts +29 -6
- package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
- package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
- package/src/resources/extensions/search-the-web/native-search.ts +5 -3
- package/src/resources/extensions/shared/browser-contract.ts +66 -0
- package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
- package/src/resources/shared/package.json +3 -0
- package/src/resources/skills/create-skill/references/executable-code.md +1 -1
- package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
- package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
- package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
- package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
- package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
- package/src/resources/skills/gsd-browser/SKILL.md +1 -1
- package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
- /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// gsd-pi — ADR-033 Unit Registry parity guard.
|
|
2
|
+
//
|
|
3
|
+
// Pins every view derived from UNIT_REGISTRY to the exact values the
|
|
4
|
+
// hand-maintained tables held before the registry existed. A failure here
|
|
5
|
+
// means a registry edit changed a derived surface — intended changes update
|
|
6
|
+
// the pinned expectation in the same diff.
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
KNOWN_UNIT_TYPES,
|
|
13
|
+
UNIT_REGISTRY,
|
|
14
|
+
EXECUTE_TASK_UNIT_TYPES,
|
|
15
|
+
SECTION_CLOSE_GATE_UNIT_TYPES,
|
|
16
|
+
getUnitDescriptor,
|
|
17
|
+
getUnitPhaseChain,
|
|
18
|
+
} from "../unit-registry.ts";
|
|
19
|
+
import {
|
|
20
|
+
AUTO_UNIT_SCOPED_TOOLS,
|
|
21
|
+
UNIT_TOOL_CONTRACTS,
|
|
22
|
+
getUnitToolSurfaceContract,
|
|
23
|
+
} from "../unit-tool-contracts.ts";
|
|
24
|
+
import { UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
25
|
+
import { phaseChainForUnit } from "../preferences-models.ts";
|
|
26
|
+
|
|
27
|
+
// ─── Pinned pre-registry values ───────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
const EXPECTED_KNOWN_UNIT_TYPES = [
|
|
30
|
+
"research-milestone",
|
|
31
|
+
"plan-milestone",
|
|
32
|
+
"discuss-milestone",
|
|
33
|
+
"validate-milestone",
|
|
34
|
+
"complete-milestone",
|
|
35
|
+
"research-slice",
|
|
36
|
+
"plan-slice",
|
|
37
|
+
"refine-slice",
|
|
38
|
+
"replan-slice",
|
|
39
|
+
"complete-slice",
|
|
40
|
+
"reassess-roadmap",
|
|
41
|
+
"execute-task",
|
|
42
|
+
"reactive-execute",
|
|
43
|
+
"run-uat",
|
|
44
|
+
"gate-evaluate",
|
|
45
|
+
"rewrite-docs",
|
|
46
|
+
"triage-captures",
|
|
47
|
+
"quick-task",
|
|
48
|
+
"workflow-preferences",
|
|
49
|
+
"discuss-project",
|
|
50
|
+
"discuss-requirements",
|
|
51
|
+
"research-decision",
|
|
52
|
+
"research-project",
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// The contract table carried two keys KNOWN_UNIT_TYPES never had (variants)
|
|
56
|
+
// and lacked two it did have (sidecars without contracts).
|
|
57
|
+
const EXPECTED_CONTRACT_ONLY_TYPES = ["discuss-slice", "execute-task-simple"];
|
|
58
|
+
const EXPECTED_CONTRACT_LESS_TYPES = ["triage-captures", "quick-task"];
|
|
59
|
+
|
|
60
|
+
const EXPECTED_EXECUTE_TASK_SET = ["execute-task", "execute-task-simple", "reactive-execute"];
|
|
61
|
+
const EXPECTED_SECTION_CLOSE_SET = [
|
|
62
|
+
...EXPECTED_EXECUTE_TASK_SET,
|
|
63
|
+
"complete-slice",
|
|
64
|
+
"validate-milestone",
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const EXPECTED_PHASE_CHAINS: Record<string, string[] | undefined> = {
|
|
68
|
+
"research-milestone": ["research"],
|
|
69
|
+
"research-slice": ["research"],
|
|
70
|
+
"research-project": ["research"],
|
|
71
|
+
"plan-milestone": ["planning"],
|
|
72
|
+
"plan-slice": ["planning"],
|
|
73
|
+
"refine-slice": ["planning"],
|
|
74
|
+
"replan-slice": ["planning"],
|
|
75
|
+
"discuss-milestone": ["discuss", "planning"],
|
|
76
|
+
"discuss-slice": ["discuss", "planning"],
|
|
77
|
+
"discuss-project": ["discuss", "planning"],
|
|
78
|
+
"discuss-requirements": ["discuss", "planning"],
|
|
79
|
+
"workflow-preferences": ["discuss", "planning"],
|
|
80
|
+
"research-decision": ["discuss", "planning"],
|
|
81
|
+
"execute-task": ["execution"],
|
|
82
|
+
"reactive-execute": ["execution"],
|
|
83
|
+
"execute-task-simple": ["execution_simple", "execution"],
|
|
84
|
+
"complete-slice": ["completion"],
|
|
85
|
+
"complete-milestone": ["completion"],
|
|
86
|
+
"worktree-merge": ["completion"],
|
|
87
|
+
"run-uat": ["uat", "completion"],
|
|
88
|
+
"reassess-roadmap": ["validation", "planning"],
|
|
89
|
+
"rewrite-docs": ["validation", "planning"],
|
|
90
|
+
"gate-evaluate": ["validation", "planning"],
|
|
91
|
+
"validate-milestone": ["validation", "planning"],
|
|
92
|
+
"triage-captures": undefined,
|
|
93
|
+
"quick-task": undefined,
|
|
94
|
+
subagent: ["subagent"],
|
|
95
|
+
"subagent/scout": ["subagent"],
|
|
96
|
+
"no-such-unit": undefined,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// ─── Derived-view parity ──────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
test("KNOWN_UNIT_TYPES derives exactly the pre-registry list, in order", () => {
|
|
102
|
+
assert.deepEqual([...KNOWN_UNIT_TYPES], EXPECTED_KNOWN_UNIT_TYPES);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("UNIT_TOOL_CONTRACTS keeps the pre-registry key set, asymmetries included", () => {
|
|
106
|
+
const contractKeys = Object.keys(UNIT_TOOL_CONTRACTS);
|
|
107
|
+
for (const variant of EXPECTED_CONTRACT_ONLY_TYPES) {
|
|
108
|
+
assert.ok(contractKeys.includes(variant), `variant ${variant} must keep its contract`);
|
|
109
|
+
assert.ok(!KNOWN_UNIT_TYPES.includes(variant as never), `${variant} must stay out of KNOWN_UNIT_TYPES`);
|
|
110
|
+
}
|
|
111
|
+
for (const sidecar of EXPECTED_CONTRACT_LESS_TYPES) {
|
|
112
|
+
assert.ok(!contractKeys.includes(sidecar), `${sidecar} must stay contract-less`);
|
|
113
|
+
assert.equal(getUnitToolSurfaceContract(sidecar), undefined);
|
|
114
|
+
}
|
|
115
|
+
const expectedKeys = [
|
|
116
|
+
...EXPECTED_KNOWN_UNIT_TYPES.filter((t) => !EXPECTED_CONTRACT_LESS_TYPES.includes(t)),
|
|
117
|
+
...EXPECTED_CONTRACT_ONLY_TYPES,
|
|
118
|
+
].sort();
|
|
119
|
+
assert.deepEqual([...contractKeys].sort(), expectedKeys);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("scope-class Sets match the pre-registry hand-maintained Sets", () => {
|
|
123
|
+
assert.deepEqual([...EXECUTE_TASK_UNIT_TYPES].sort(), [...EXPECTED_EXECUTE_TASK_SET].sort());
|
|
124
|
+
assert.deepEqual([...SECTION_CLOSE_GATE_UNIT_TYPES].sort(), [...EXPECTED_SECTION_CLOSE_SET].sort());
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("phaseChainForUnit matches the pre-registry switch for every known input", () => {
|
|
128
|
+
for (const [unitType, expected] of Object.entries(EXPECTED_PHASE_CHAINS)) {
|
|
129
|
+
assert.deepEqual(
|
|
130
|
+
phaseChainForUnit(unitType),
|
|
131
|
+
expected,
|
|
132
|
+
`phase chain for ${unitType}`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("AUTO_UNIT_SCOPED_TOOLS mirrors each contract's allowed tools", () => {
|
|
138
|
+
for (const [unitType, contract] of Object.entries(UNIT_TOOL_CONTRACTS)) {
|
|
139
|
+
assert.deepEqual(AUTO_UNIT_SCOPED_TOOLS[unitType], contract.allowedGsdTools);
|
|
140
|
+
}
|
|
141
|
+
assert.deepEqual(
|
|
142
|
+
Object.keys(AUTO_UNIT_SCOPED_TOOLS).sort(),
|
|
143
|
+
Object.keys(UNIT_TOOL_CONTRACTS).sort(),
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// ─── Registry-internal coherence ──────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
test("every primary unit type has a manifest; manifests cover nothing else", () => {
|
|
150
|
+
const manifestKeys = Object.keys(UNIT_MANIFESTS).sort();
|
|
151
|
+
assert.deepEqual(manifestKeys, [...KNOWN_UNIT_TYPES].sort());
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("every registry row is reachable through the descriptor accessor", () => {
|
|
155
|
+
for (const unitType of Object.keys(UNIT_REGISTRY)) {
|
|
156
|
+
const descriptor = getUnitDescriptor(unitType);
|
|
157
|
+
assert.ok(descriptor, `descriptor for ${unitType}`);
|
|
158
|
+
assert.ok(["primary", "variant"].includes(descriptor.kind));
|
|
159
|
+
assert.ok(["execute-task", "section-close", "standard"].includes(descriptor.scopeClass));
|
|
160
|
+
assert.equal(getUnitPhaseChain(unitType), descriptor.phaseChain);
|
|
161
|
+
}
|
|
162
|
+
assert.equal(getUnitDescriptor("no-such-unit"), undefined);
|
|
163
|
+
});
|
|
@@ -15,6 +15,10 @@ function scaffoldProject(root: string, pkg: Record<string, unknown>): void {
|
|
|
15
15
|
writeFileSync(join(root, "package.json"), JSON.stringify(pkg, null, 2));
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
const LEGACY_ENGINE = { engine: "legacy", source: "probe", reason: "test" } as const;
|
|
19
|
+
const MANAGED_ENGINE = { engine: "gsd-browser", source: "probe", reason: "test" } as const;
|
|
20
|
+
const OFF_ENGINE = { engine: "off", source: "env", reason: "test" } as const;
|
|
21
|
+
|
|
18
22
|
describe("web-app-uat guidance", () => {
|
|
19
23
|
test("returns null for non-web projects", () => {
|
|
20
24
|
const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
|
|
@@ -36,15 +40,54 @@ describe("web-app-uat guidance", () => {
|
|
|
36
40
|
scripts: { dev: "vite" },
|
|
37
41
|
});
|
|
38
42
|
assert.equal(detectWebApp(root), true);
|
|
39
|
-
const block = buildWebAppUatGuidanceBlock(root);
|
|
43
|
+
const block = buildWebAppUatGuidanceBlock(root, LEGACY_ENGINE);
|
|
40
44
|
assert.ok(block);
|
|
41
45
|
assert.match(block!, /browser-executable/);
|
|
46
|
+
assert.match(block!, /Playwright-backed `browser_\*` tools/);
|
|
42
47
|
assert.match(block!, /Playwright scaffolding/);
|
|
43
48
|
} finally {
|
|
44
49
|
rmSync(root, { recursive: true, force: true });
|
|
45
50
|
}
|
|
46
51
|
});
|
|
47
52
|
|
|
53
|
+
test("describes the managed gsd-browser engine when it is the resolved backing", () => {
|
|
54
|
+
const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
|
|
55
|
+
try {
|
|
56
|
+
scaffoldProject(root, {
|
|
57
|
+
dependencies: { react: "19.0.0" },
|
|
58
|
+
scripts: { dev: "vite" },
|
|
59
|
+
});
|
|
60
|
+
const block = buildWebAppUatGuidanceBlock(root, MANAGED_ENGINE);
|
|
61
|
+
assert.ok(block);
|
|
62
|
+
assert.match(block!, /managed gsd-browser engine/);
|
|
63
|
+
assert.match(block!, /browser-executable/);
|
|
64
|
+
assert.doesNotMatch(block!, /Playwright-backed/);
|
|
65
|
+
} finally {
|
|
66
|
+
rmSync(root, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("steers to runtime-executable UAT when browser tools are off", () => {
|
|
71
|
+
const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
|
|
72
|
+
try {
|
|
73
|
+
scaffoldProject(root, {
|
|
74
|
+
dependencies: { react: "19.0.0" },
|
|
75
|
+
scripts: { dev: "vite" },
|
|
76
|
+
});
|
|
77
|
+
const block = buildWebAppUatGuidanceBlock(root, OFF_ENGINE);
|
|
78
|
+
assert.ok(block);
|
|
79
|
+
assert.match(block!, /browser tools are disabled/);
|
|
80
|
+
assert.doesNotMatch(block!, /- `browser-executable`/);
|
|
81
|
+
// mixed/live-runtime require browser tools per UAT_MODE_POLICIES, so the
|
|
82
|
+
// bullet must drop out too — recommending them would dead-end at dispatch.
|
|
83
|
+
assert.doesNotMatch(block!, /- `mixed`/);
|
|
84
|
+
assert.doesNotMatch(block!, /interactive `browser_\*` checks/);
|
|
85
|
+
assert.match(block!, /runtime-executable/);
|
|
86
|
+
} finally {
|
|
87
|
+
rmSync(root, { recursive: true, force: true });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
48
91
|
test("detects existing Playwright and npm script", () => {
|
|
49
92
|
const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
|
|
50
93
|
try {
|
|
@@ -495,8 +495,8 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
|
|
|
495
495
|
estimate: "10m",
|
|
496
496
|
files: ["src/resources/extensions/gsd/workflow-mcp.ts"],
|
|
497
497
|
verify: "node --test",
|
|
498
|
-
inputs: [
|
|
499
|
-
expectedOutput: ["
|
|
498
|
+
inputs: [],
|
|
499
|
+
expectedOutput: ["src/bridge-status.md"],
|
|
500
500
|
},
|
|
501
501
|
],
|
|
502
502
|
},
|
|
@@ -528,8 +528,8 @@ test("executePlanSlice writes task planning state and rendered plan artifacts",
|
|
|
528
528
|
estimate: "15m",
|
|
529
529
|
files: ["src/resources/extensions/gsd/tools/workflow-tool-executors.ts"],
|
|
530
530
|
verify: "node --test",
|
|
531
|
-
inputs: [
|
|
532
|
-
expectedOutput: ["
|
|
531
|
+
inputs: [],
|
|
532
|
+
expectedOutput: ["src/bridge-status.md"],
|
|
533
533
|
},
|
|
534
534
|
],
|
|
535
535
|
}, base));
|
|
@@ -161,13 +161,13 @@ test("enterMilestone returns ok:true mode:worktree on successful create", (t) =>
|
|
|
161
161
|
if (result.ok) {
|
|
162
162
|
assert.equal(result.mode, "worktree");
|
|
163
163
|
assert.ok(
|
|
164
|
-
result.path.endsWith("/.gsd
|
|
165
|
-
`expected path to end with /.gsd
|
|
164
|
+
result.path.endsWith("/.gsd-worktrees/M001"),
|
|
165
|
+
`expected path to end with /.gsd-worktrees/M001, got ${result.path}`,
|
|
166
166
|
);
|
|
167
167
|
}
|
|
168
168
|
assert.ok(
|
|
169
|
-
s.basePath.endsWith("/.gsd
|
|
170
|
-
`expected s.basePath to end with /.gsd
|
|
169
|
+
s.basePath.endsWith("/.gsd-worktrees/M001"),
|
|
170
|
+
`expected s.basePath to end with /.gsd-worktrees/M001, got ${s.basePath}`,
|
|
171
171
|
);
|
|
172
172
|
// After C3 (#5626) `invalidateAllCaches` is inlined; assertion against
|
|
173
173
|
// `deps.calls` for cache invalidation is no longer possible.
|
|
@@ -240,6 +240,43 @@ test("adoptStrandedMilestone forces branch recovery even when normal preferences
|
|
|
240
240
|
assert.equal(currentBranch, "milestone/M001");
|
|
241
241
|
});
|
|
242
242
|
|
|
243
|
+
test("enterMilestone honors stranded branch recovery instead of recreating the worktree", (t) => {
|
|
244
|
+
// Regression: after adoptStrandedMilestone checks out milestone/M001 in
|
|
245
|
+
// the project root, a plain enterMilestone under isolation:worktree used
|
|
246
|
+
// to attempt `git worktree add`, which git refuses ("branch is already in
|
|
247
|
+
// use by another worktree" — the root checkout IS the conflicting
|
|
248
|
+
// worktree), tripping a creation-failed warning and degrading isolation.
|
|
249
|
+
// The recovery override must keep re-entries in branch mode.
|
|
250
|
+
const previousCwd = process.cwd();
|
|
251
|
+
const base = makeGitRepoBase({ isolation: "worktree" });
|
|
252
|
+
t.after(() => cleanupRepoBase(base, previousCwd));
|
|
253
|
+
|
|
254
|
+
const s = makeSession({ basePath: base, originalBasePath: base });
|
|
255
|
+
const deps = makeDeps();
|
|
256
|
+
const ctx = makeCtx();
|
|
257
|
+
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
258
|
+
|
|
259
|
+
const adopted = lifecycle.adoptStrandedMilestone("M001", base, ctx, {
|
|
260
|
+
mode: "branch",
|
|
261
|
+
});
|
|
262
|
+
assert.equal(adopted.ok, true, `expected adopt ok:true, got: ${JSON.stringify(adopted)}`);
|
|
263
|
+
|
|
264
|
+
const result = lifecycle.enterMilestone("M001", ctx);
|
|
265
|
+
|
|
266
|
+
assert.equal(result.ok, true, `expected ok:true, got: ${JSON.stringify(result)}`);
|
|
267
|
+
if (result.ok) {
|
|
268
|
+
assert.equal(result.mode, "branch");
|
|
269
|
+
assert.equal(result.path, base);
|
|
270
|
+
}
|
|
271
|
+
assert.equal(s.basePath, base);
|
|
272
|
+
assert.equal(s.isolationDegraded, false, "intentional branch adoption must not degrade isolation");
|
|
273
|
+
assert.equal(
|
|
274
|
+
ctx.messages.some((m) => m.msg.includes("creation for M001 failed")),
|
|
275
|
+
false,
|
|
276
|
+
"re-entry must not attempt (and fail) canonical worktree creation",
|
|
277
|
+
);
|
|
278
|
+
});
|
|
279
|
+
|
|
243
280
|
test("enterMilestone returns ok:false reason:isolation-degraded when session degraded", () => {
|
|
244
281
|
const s = makeSession({ isolationDegraded: true });
|
|
245
282
|
const deps = makeDeps({ getIsolationMode: () => "branch" });
|
|
@@ -142,6 +142,27 @@ describe("createWorktree", () => {
|
|
|
142
142
|
run("git rev-parse --git-dir", info.path);
|
|
143
143
|
assert.ok(!existsSync(join(info.path, "orphan.txt")), "stale file removed by recovery");
|
|
144
144
|
});
|
|
145
|
+
|
|
146
|
+
test("removes stale canonical directory when legacy orphan is cleaned and canonical target is stale", () => {
|
|
147
|
+
// Scenario: a stale .gsd-worktrees/M020 directory (no .git — aborted prior
|
|
148
|
+
// creation) coexists with an orphaned .gsd/worktrees/M020 dir (.git file not
|
|
149
|
+
// registered with git). worktreePathFor returns the legacy path (canonical has
|
|
150
|
+
// no .git marker), so only the legacy path was previously cleaned — the stale
|
|
151
|
+
// canonical blocked git worktree add. The fix ensures createWorktree also
|
|
152
|
+
// removes the stale canonical before calling git worktree add.
|
|
153
|
+
const canonicalDir = join(base, ".gsd-worktrees", "M020");
|
|
154
|
+
const legacyDir = join(base, ".gsd", "worktrees", "M020");
|
|
155
|
+
|
|
156
|
+
mkdirSync(canonicalDir, { recursive: true }); // stale canonical: exists, no .git
|
|
157
|
+
mkdirSync(legacyDir, { recursive: true });
|
|
158
|
+
writeFileSync(join(legacyDir, ".git"), "gitdir: ../../../../.git/worktrees/M020\n", "utf-8");
|
|
159
|
+
|
|
160
|
+
const info = createWorktree(base, "M020");
|
|
161
|
+
assert.strictEqual(info.name, "M020");
|
|
162
|
+
assert.ok(existsSync(info.path), "worktree path should exist after creation");
|
|
163
|
+
assert.ok(existsSync(join(info.path, ".git")), "new worktree has .git marker");
|
|
164
|
+
run("git rev-parse --git-dir", info.path);
|
|
165
|
+
});
|
|
145
166
|
});
|
|
146
167
|
|
|
147
168
|
describe("createWorktree — duplicate rejection", () => {
|
|
@@ -180,7 +201,7 @@ describe("createWorktree — branch cleanup on add failure", () => {
|
|
|
180
201
|
|
|
181
202
|
// Make the worktrees parent directory non-writable so `git worktree add`
|
|
182
203
|
// fails after the branch has already been force-reset.
|
|
183
|
-
const parentDir = join(base, ".gsd
|
|
204
|
+
const parentDir = join(base, ".gsd-worktrees");
|
|
184
205
|
mkdirSync(parentDir, { recursive: true });
|
|
185
206
|
run(`chmod 555 "${parentDir}"`, base);
|
|
186
207
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for worktreePathFor — the forward seam (project + name → path).
|
|
3
|
+
*
|
|
4
|
+
* Key invariant: a stale canonical directory (no .git marker) must NOT
|
|
5
|
+
* shadow a live legacy worktree (.gsd/worktrees/<name> with .git).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
|
|
15
|
+
import { worktreePathFor, canonicalWorktreesDir, legacyWorktreesDir } from "../worktree-placement.ts";
|
|
16
|
+
|
|
17
|
+
function makeTmpRoot(): string {
|
|
18
|
+
const root = join(tmpdir(), `gsd-placement-test-${randomUUID()}`);
|
|
19
|
+
mkdirSync(root, { recursive: true });
|
|
20
|
+
return root;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function cleanup(root: string): void {
|
|
24
|
+
try { rmSync(root, { recursive: true, force: true }); } catch { /* */ }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function makeCanonicalDir(root: string, name: string): string {
|
|
28
|
+
const p = join(canonicalWorktreesDir(root), name);
|
|
29
|
+
mkdirSync(p, { recursive: true });
|
|
30
|
+
return p;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function makeLiveCanonical(root: string, name: string): string {
|
|
34
|
+
const p = makeCanonicalDir(root, name);
|
|
35
|
+
writeFileSync(join(p, ".git"), `gitdir: ${join(root, ".git", "worktrees", name)}\n`);
|
|
36
|
+
return p;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function makeLiveLegacy(root: string, name: string): string {
|
|
40
|
+
const p = join(legacyWorktreesDir(root), name);
|
|
41
|
+
mkdirSync(p, { recursive: true });
|
|
42
|
+
writeFileSync(join(p, ".git"), `gitdir: ${join(root, ".git", "worktrees", name)}\n`);
|
|
43
|
+
return p;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
test("returns canonical path when canonical has .git marker", () => {
|
|
47
|
+
const root = makeTmpRoot();
|
|
48
|
+
try {
|
|
49
|
+
const canonical = makeLiveCanonical(root, "M001");
|
|
50
|
+
assert.equal(worktreePathFor(root, "M001"), canonical);
|
|
51
|
+
} finally {
|
|
52
|
+
cleanup(root);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("returns legacy path when only legacy exists with .git marker", () => {
|
|
57
|
+
const root = makeTmpRoot();
|
|
58
|
+
try {
|
|
59
|
+
const legacy = makeLiveLegacy(root, "M001");
|
|
60
|
+
assert.equal(worktreePathFor(root, "M001"), legacy);
|
|
61
|
+
} finally {
|
|
62
|
+
cleanup(root);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("returns legacy path when canonical dir exists but has no .git (stale canonical)", () => {
|
|
67
|
+
const root = makeTmpRoot();
|
|
68
|
+
try {
|
|
69
|
+
makeCanonicalDir(root, "M001"); // stale: dir exists, no .git
|
|
70
|
+
const legacy = makeLiveLegacy(root, "M001");
|
|
71
|
+
assert.equal(
|
|
72
|
+
worktreePathFor(root, "M001"),
|
|
73
|
+
legacy,
|
|
74
|
+
"stale canonical must not shadow live legacy worktree",
|
|
75
|
+
);
|
|
76
|
+
} finally {
|
|
77
|
+
cleanup(root);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("returns canonical path for new-worktree creation when neither path exists", () => {
|
|
82
|
+
const root = makeTmpRoot();
|
|
83
|
+
try {
|
|
84
|
+
const expected = join(canonicalWorktreesDir(root), "M001");
|
|
85
|
+
assert.equal(worktreePathFor(root, "M001"), expected);
|
|
86
|
+
} finally {
|
|
87
|
+
cleanup(root);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("prefers live canonical over live legacy when both exist", () => {
|
|
92
|
+
const root = makeTmpRoot();
|
|
93
|
+
try {
|
|
94
|
+
const canonical = makeLiveCanonical(root, "M001");
|
|
95
|
+
makeLiveLegacy(root, "M001");
|
|
96
|
+
assert.equal(worktreePathFor(root, "M001"), canonical);
|
|
97
|
+
} finally {
|
|
98
|
+
cleanup(root);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("returns legacy when canonical is stale and legacy has no .git (both stale)", () => {
|
|
103
|
+
const root = makeTmpRoot();
|
|
104
|
+
try {
|
|
105
|
+
makeCanonicalDir(root, "M001"); // stale canonical
|
|
106
|
+
const legacy = join(legacyWorktreesDir(root), "M001");
|
|
107
|
+
mkdirSync(legacy, { recursive: true }); // stale legacy (no .git)
|
|
108
|
+
// Falls through to legacy existsSync since canonical has no .git
|
|
109
|
+
assert.equal(worktreePathFor(root, "M001"), legacy);
|
|
110
|
+
} finally {
|
|
111
|
+
cleanup(root);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
@@ -65,7 +65,7 @@ describe("reenterActiveWorktreeIfNeeded", () => {
|
|
|
65
65
|
const entered = await reenterActiveWorktreeIfNeeded(dir);
|
|
66
66
|
assert.ok(entered, "re-entry returned a worktree path");
|
|
67
67
|
assert.strictEqual(realpathSync(process.cwd()), realpathSync(entered!), "cwd moved into the worktree");
|
|
68
|
-
assert.strictEqual(entered, join(dir, ".gsd
|
|
68
|
+
assert.strictEqual(entered, join(dir, ".gsd-worktrees", "M001"));
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
test("no-op when already inside a worktree", async (t) => {
|
|
@@ -126,7 +126,9 @@ describe("Worktree Safety module", () => {
|
|
|
126
126
|
assert.equal(result.ok, false);
|
|
127
127
|
assert.equal(result.kind, "invalid-root");
|
|
128
128
|
assert.equal(result.details?.unitRoot, outsideRoot);
|
|
129
|
-
|
|
129
|
+
// The reported expected root is the canonical container; the legacy
|
|
130
|
+
// .gsd/worktrees/ location is also accepted but not surfaced here.
|
|
131
|
+
assert.equal(result.details?.expectedRoot, join(projectRoot, ".gsd-worktrees", "M001"));
|
|
130
132
|
});
|
|
131
133
|
|
|
132
134
|
test("accepts project root for source-writing Unit when isolation mode is none", () => {
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Fix: removeWorktree should query `git worktree list` to find the actual
|
|
10
10
|
* registered path when the computed path doesn't match.
|
|
11
|
+
*
|
|
12
|
+
* New worktrees are created at the canonical `.gsd-worktrees/` sibling and
|
|
13
|
+
* never cross the symlink, so this scenario only applies to LEGACY worktrees
|
|
14
|
+
* (created under `.gsd/worktrees/` by older versions). The test creates the
|
|
15
|
+
* worktree at the legacy location directly to keep that coverage.
|
|
11
16
|
*/
|
|
12
17
|
import { mkdtempSync, mkdirSync, rmSync, symlinkSync, unlinkSync, writeFileSync, existsSync, realpathSync } from "node:fs";
|
|
13
18
|
import { join } from "node:path";
|
|
@@ -15,7 +20,6 @@ import { tmpdir } from "node:os";
|
|
|
15
20
|
import { execSync } from "node:child_process";
|
|
16
21
|
|
|
17
22
|
import {
|
|
18
|
-
createWorktree,
|
|
19
23
|
removeWorktree,
|
|
20
24
|
listWorktrees,
|
|
21
25
|
worktreePath,
|
|
@@ -64,13 +68,15 @@ test('worktree-symlink-removal removes the git-registered symlink target safely'
|
|
|
64
68
|
run("git add .", base);
|
|
65
69
|
run('git commit -m "init"', base);
|
|
66
70
|
|
|
67
|
-
// Create a worktree
|
|
68
|
-
// the worktree at the external path
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
// Create a LEGACY worktree through the symlinked .gsd path — git resolves
|
|
72
|
+
// the symlink and registers the worktree at the external path. (Current
|
|
73
|
+
// createWorktree() uses the canonical .gsd-worktrees/ sibling instead.)
|
|
74
|
+
const legacyPath = join(base, ".gsd", "worktrees", "M002");
|
|
75
|
+
run(`git worktree add -b milestone/M002 "${legacyPath}"`, base);
|
|
76
|
+
assert.ok(existsSync(legacyPath), "worktree created");
|
|
71
77
|
|
|
72
78
|
// Verify worktree was created at the resolved (external) path
|
|
73
|
-
const realWtPath = realpathSync(
|
|
79
|
+
const realWtPath = realpathSync(legacyPath);
|
|
74
80
|
assert.ok(
|
|
75
81
|
realWtPath.startsWith(externalState),
|
|
76
82
|
`worktree real path (${realWtPath}) is under external state dir`,
|
|
@@ -116,8 +116,8 @@ describe("worktree-teardown-safety", () => {
|
|
|
116
116
|
|
|
117
117
|
const wtPathResult = worktreePath(tempDir, "anything");
|
|
118
118
|
assertTrue(
|
|
119
|
-
wtPathResult.startsWith(join(tempDir, ".gsd
|
|
120
|
-
"worktreePath returns path under .gsd
|
|
119
|
+
wtPathResult.startsWith(join(tempDir, ".gsd-worktrees")),
|
|
120
|
+
"worktreePath returns path under the canonical .gsd-worktrees/ container",
|
|
121
121
|
);
|
|
122
122
|
});
|
|
123
123
|
|
|
@@ -803,3 +803,45 @@ test('write-gate: resetWriteGateState persists through dangling .gsd symlink', (
|
|
|
803
803
|
} catch { /* swallow */ }
|
|
804
804
|
}
|
|
805
805
|
});
|
|
806
|
+
|
|
807
|
+
// ─── Scenario 31: hydrate in-memory gate state from persisted snapshot (MCP subprocess) ──
|
|
808
|
+
|
|
809
|
+
test('write-gate: getPendingGate hydrates from disk when workflow MCP verified gate in child process', () => {
|
|
810
|
+
const base = join(tmpdir(), `gsd-write-gate-mcp-hydrate-${randomUUID()}`);
|
|
811
|
+
const stateFilePath = join(base, '.gsd', 'runtime', 'write-gate-state.json');
|
|
812
|
+
const originalEnv = process.env.GSD_PERSIST_WRITE_GATE_STATE;
|
|
813
|
+
const gateId = 'depth_verification_M005_confirm';
|
|
814
|
+
|
|
815
|
+
try {
|
|
816
|
+
process.env.GSD_PERSIST_WRITE_GATE_STATE = '1';
|
|
817
|
+
mkdirSync(join(base, '.gsd', 'runtime'), { recursive: true });
|
|
818
|
+
clearDiscussionFlowState(base);
|
|
819
|
+
setPendingGate(gateId, base);
|
|
820
|
+
|
|
821
|
+
writeFileSync(stateFilePath, JSON.stringify({
|
|
822
|
+
verifiedDepthMilestones: ['M005'],
|
|
823
|
+
verifiedApprovalGates: [gateId],
|
|
824
|
+
activeQueuePhase: false,
|
|
825
|
+
pendingGateId: null,
|
|
826
|
+
}, null, 2), 'utf-8');
|
|
827
|
+
|
|
828
|
+
assert.strictEqual(getPendingGate(base), null, 'stale in-memory pending must refresh from disk');
|
|
829
|
+
assert.strictEqual(isMilestoneDepthVerified('M005', base), true, 'verified milestone must hydrate from disk');
|
|
830
|
+
assert.deepEqual(loadWriteGateSnapshot(base), {
|
|
831
|
+
verifiedDepthMilestones: ['M005'],
|
|
832
|
+
verifiedApprovalGates: [gateId],
|
|
833
|
+
activeQueuePhase: false,
|
|
834
|
+
pendingGateId: null,
|
|
835
|
+
});
|
|
836
|
+
} finally {
|
|
837
|
+
if (originalEnv === undefined) {
|
|
838
|
+
delete process.env.GSD_PERSIST_WRITE_GATE_STATE;
|
|
839
|
+
} else {
|
|
840
|
+
process.env.GSD_PERSIST_WRITE_GATE_STATE = originalEnv;
|
|
841
|
+
}
|
|
842
|
+
clearDiscussionFlowState(base);
|
|
843
|
+
try {
|
|
844
|
+
rmSync(base, { recursive: true, force: true });
|
|
845
|
+
} catch { /* swallow */ }
|
|
846
|
+
}
|
|
847
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Tool Contract module's runtime face — verify the live SDK tool surface covers a Unit's required workflow tools.
|
|
3
|
+
|
|
4
|
+
import { mcpToolMatchesBaseName } from "./mcp-tool-name.js";
|
|
5
|
+
import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
|
|
6
|
+
import { isWorkflowToolSurfaceName } from "./workflow-tool-surface.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Stable phrase recognized as transient by auto-tool-tracking's
|
|
10
|
+
* isToolUnavailableError and error-classifier's transient buckets,
|
|
11
|
+
* which build their matchers from this constant.
|
|
12
|
+
*/
|
|
13
|
+
export const TOOL_SURFACE_NOT_READY = "workflow tool surface not ready";
|
|
14
|
+
|
|
15
|
+
/** MCP server statuses that will not self-heal within the session. */
|
|
16
|
+
const TERMINAL_MCP_SERVER_STATUSES = new Set(["failed", "needs-auth", "disabled"]);
|
|
17
|
+
|
|
18
|
+
export interface LiveToolSurfaceObservation {
|
|
19
|
+
/** Tool names the session reported at init (MCP tools appear as mcp__<server>__<tool>). */
|
|
20
|
+
tools: readonly string[];
|
|
21
|
+
/** MCP server connection statuses the session reported at init. */
|
|
22
|
+
mcpServers: readonly { name: string; status: string }[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Verify the live tool surface observed at SDK session init covers the Unit's
|
|
27
|
+
* required workflow tools. Complements the static pre-dispatch gate
|
|
28
|
+
* (getWorkflowTransportSupportError), which only proves the MCP launch config
|
|
29
|
+
* is discoverable — the workflow server connects asynchronously after session
|
|
30
|
+
* start, so the static gate cannot see whether the tools actually registered.
|
|
31
|
+
*
|
|
32
|
+
* Returns a transient, recovery-classifiable error (kind tool-unavailable →
|
|
33
|
+
* retry) when the workflow server failed or has not yet registered a required
|
|
34
|
+
* tool, so dispatch aborts before the first model turn instead of letting the
|
|
35
|
+
* Unit improvise around "No such tool available". Returns null when no
|
|
36
|
+
* workflow server is part of this session (native tool path), when the Unit
|
|
37
|
+
* requires no workflow tools, or when the surface is ready.
|
|
38
|
+
*/
|
|
39
|
+
export function getToolSurfaceReadinessError(input: {
|
|
40
|
+
unitType: string | undefined;
|
|
41
|
+
workflowServerName: string | undefined;
|
|
42
|
+
observation: LiveToolSurfaceObservation;
|
|
43
|
+
}): string | null {
|
|
44
|
+
const { unitType, workflowServerName, observation } = input;
|
|
45
|
+
if (!unitType || !workflowServerName) return null;
|
|
46
|
+
|
|
47
|
+
const required = getRequiredWorkflowToolsForUnit(unitType).filter(isWorkflowToolSurfaceName);
|
|
48
|
+
if (required.length === 0) return null;
|
|
49
|
+
|
|
50
|
+
const server = observation.mcpServers.find((entry) => entry.name === workflowServerName);
|
|
51
|
+
if (!server) {
|
|
52
|
+
return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" is absent from the init surface (not yet connected): ${required.join(", ")}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The SDK does not wait for MCP servers before init — a still-connecting
|
|
56
|
+
// server reports "pending" there routinely, then registers within seconds,
|
|
57
|
+
// usually well before the Unit's first workflow tool call. Aborting on
|
|
58
|
+
// "pending" would fail the common healthy session, so it passes through;
|
|
59
|
+
// a genuine miss after pass-through still surfaces in-session as
|
|
60
|
+
// "No such tool available" and classifies tool-unavailable → bounded retry.
|
|
61
|
+
// Only statuses that cannot self-heal abort here.
|
|
62
|
+
if (server.status !== "connected" && !TERMINAL_MCP_SERVER_STATUSES.has(server.status)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const missing = required.filter(
|
|
67
|
+
(tool) => !observation.tools.some((name) => name === tool || mcpToolMatchesBaseName(name, tool)),
|
|
68
|
+
);
|
|
69
|
+
if (missing.length === 0) return null;
|
|
70
|
+
|
|
71
|
+
const serverDetail =
|
|
72
|
+
server.status === "connected"
|
|
73
|
+
? `MCP server "${workflowServerName}" is connected but has not registered`
|
|
74
|
+
: `MCP server "${workflowServerName}" status is "${server.status}" and it has not registered`;
|
|
75
|
+
return `${TOOL_SURFACE_NOT_READY} for ${unitType}: ${serverDetail}: ${missing.join(", ")}`;
|
|
76
|
+
}
|