@opengsd/gsd-pi 1.2.0-dev.b1abb545 → 1.2.0-dev.d6c5343c
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 +14 -34
- 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/GSD-WORKFLOW.md +5 -4
- 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/custom-verify-retry-store.js +17 -2
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
- package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
- package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +94 -48
- package/dist/resources/extensions/gsd/auto/phases.js +8 -3
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +8 -32
- package/dist/resources/extensions/gsd/auto-dispatch.js +40 -57
- package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
- package/dist/resources/extensions/gsd/auto-post-unit.js +31 -14
- package/dist/resources/extensions/gsd/auto-prompts.js +81 -19
- package/dist/resources/extensions/gsd/auto-start.js +24 -26
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +12 -20
- package/dist/resources/extensions/gsd/auto-verification.js +9 -28
- 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 +229 -36
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +319 -71
- 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/consent-question.js +337 -0
- package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
- 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 +398 -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/dispatch-guard.js +10 -35
- 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/engine-hook-contract.js +70 -0
- 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/files.js +33 -19
- 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 +158 -0
- package/dist/resources/extensions/gsd/guided-flow.js +51 -5
- package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
- 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/milestone-closeout.js +13 -23
- 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/parsers-legacy.js +16 -4
- 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 +2 -2
- 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 +6 -4
- 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/reactive-graph.js +8 -1
- 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 +6 -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-presentation-plan.js +4 -4
- package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +44 -53
- 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 +42 -16
- 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/verdict-parser.js +1 -1
- 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 +12 -3
- 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 +8 -8
- 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 +8 -8
- 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/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/README.md +1 -0
- package/packages/pi-ai/dist/models.generated.d.ts +192 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +166 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +3 -2
- 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/GSD-WORKFLOW.md +5 -4
- 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/custom-verify-retry-store.ts +21 -3
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
- package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
- package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
- package/src/resources/extensions/gsd/auto/loop.ts +4 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +109 -51
- package/src/resources/extensions/gsd/auto/phases.ts +12 -3
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -32
- package/src/resources/extensions/gsd/auto-dispatch.ts +38 -52
- package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +37 -13
- package/src/resources/extensions/gsd/auto-prompts.ts +118 -35
- package/src/resources/extensions/gsd/auto-start.ts +24 -29
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +14 -21
- package/src/resources/extensions/gsd/auto-verification.ts +8 -26
- 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 +270 -37
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +368 -78
- 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/consent-question.ts +416 -0
- package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
- 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 +490 -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/dispatch-guard.ts +8 -31
- 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/engine-hook-contract.ts +79 -0
- 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/files.ts +33 -12
- 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 +217 -0
- package/src/resources/extensions/gsd/guided-flow.ts +50 -5
- package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
- 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/milestone-closeout.ts +13 -23
- 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/parsers-legacy.ts +16 -4
- 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 +2 -2
- 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 +6 -4
- 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/reactive-graph.ts +11 -1
- 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 +9 -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 +101 -26
- 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/complete-slice-verification-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/consent-question.test.ts +336 -0
- package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -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/engine-hook-contract.test.ts +148 -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/gsd-db.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/guidance.test.ts +148 -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/integration/run-uat.test.ts +199 -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/parallel-research-dispatch.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
- 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 +112 -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-seam.test.ts +358 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +109 -1
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
- package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +43 -68
- 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 +62 -16
- 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/verdict-parser.ts +1 -1
- 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 +13 -9
- 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/resources/extensions/gsd/user-input-boundary.js +0 -218
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
- package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
- /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → jmTLg6xZmAuq_LIqKOxrH}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → jmTLg6xZmAuq_LIqKOxrH}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// gsd-pi — ADR-032 Unit Closeout module tests (Interactive Closeout adapter path).
|
|
2
|
+
//
|
|
3
|
+
// All git/preference/notification effects go through the injected deps seam —
|
|
4
|
+
// no real repos, no notification store state.
|
|
5
|
+
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
closeUnit,
|
|
11
|
+
isUnitCloseoutTool,
|
|
12
|
+
runInteractiveUnitCloseout,
|
|
13
|
+
type UnitCloseoutDeps,
|
|
14
|
+
} from "../unit-closeout.ts";
|
|
15
|
+
|
|
16
|
+
interface DepsLog {
|
|
17
|
+
commits: Array<{ unitType: string; unitId: string }>;
|
|
18
|
+
notices: Array<{ message: string; severity: string }>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function makeDeps(overrides: {
|
|
22
|
+
isolation?: "none" | "worktree" | "branch";
|
|
23
|
+
branch?: string | null;
|
|
24
|
+
commitResult?: string | null | (() => string | null);
|
|
25
|
+
} = {}): { deps: UnitCloseoutDeps; log: DepsLog } {
|
|
26
|
+
const log: DepsLog = { commits: [], notices: [] };
|
|
27
|
+
const deps: UnitCloseoutDeps = {
|
|
28
|
+
isolationMode: () => overrides.isolation ?? "none",
|
|
29
|
+
currentBranch: () => (overrides.branch === undefined ? "main" : overrides.branch),
|
|
30
|
+
commit: (_basePath, unitType, unitId) => {
|
|
31
|
+
log.commits.push({ unitType, unitId });
|
|
32
|
+
const result = overrides.commitResult;
|
|
33
|
+
if (typeof result === "function") return result();
|
|
34
|
+
return result === undefined ? "chore(gsd): closeout" : result;
|
|
35
|
+
},
|
|
36
|
+
notify: (message, severity) => {
|
|
37
|
+
log.notices.push({ message, severity });
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
return { deps, log };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const BASE = "/tmp/closeout-test-project";
|
|
44
|
+
|
|
45
|
+
test("task boundary commits and stays quiet", () => {
|
|
46
|
+
const { deps, log } = makeDeps({ isolation: "worktree" });
|
|
47
|
+
const result = closeUnit(
|
|
48
|
+
{ basePath: BASE, unitType: "execute-task", unitId: "M001/S01/T01", boundary: "task", outcome: "complete" },
|
|
49
|
+
deps,
|
|
50
|
+
);
|
|
51
|
+
assert.equal(result.gitVerdict, "committed");
|
|
52
|
+
assert.equal(result.notice, undefined);
|
|
53
|
+
assert.deepEqual(log.commits, [{ unitType: "execute-task", unitId: "M001/S01/T01" }]);
|
|
54
|
+
assert.equal(log.notices.length, 0);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("milestone boundary under isolation none commits without a notice", () => {
|
|
58
|
+
const { deps, log } = makeDeps({ isolation: "none" });
|
|
59
|
+
const result = closeUnit(
|
|
60
|
+
{ basePath: BASE, unitType: "complete-milestone", unitId: "M001", boundary: "milestone", outcome: "complete" },
|
|
61
|
+
deps,
|
|
62
|
+
);
|
|
63
|
+
assert.equal(result.gitVerdict, "committed");
|
|
64
|
+
assert.equal(log.notices.length, 0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("milestone boundary off-worktree under isolation worktree fails closed loudly", () => {
|
|
68
|
+
const { deps, log } = makeDeps({ isolation: "worktree", branch: "main" });
|
|
69
|
+
const result = closeUnit(
|
|
70
|
+
{ basePath: BASE, unitType: "complete-milestone", unitId: "M001", boundary: "milestone", outcome: "complete" },
|
|
71
|
+
deps,
|
|
72
|
+
);
|
|
73
|
+
assert.equal(result.gitVerdict, "isolation-bypassed");
|
|
74
|
+
assert.equal(log.notices.length, 1);
|
|
75
|
+
assert.equal(log.notices[0].severity, "warning");
|
|
76
|
+
assert.match(log.notices[0].message, /isolation preference was not honoured/);
|
|
77
|
+
assert.match(log.notices[0].message, /git\.isolation is "worktree"/);
|
|
78
|
+
assert.match(log.notices[0].message, /committed directly on "main"/);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("milestone boundary on a milestone branch defers the merge to worktree tooling", () => {
|
|
82
|
+
const { deps, log } = makeDeps({ isolation: "worktree", branch: "milestone/M001" });
|
|
83
|
+
const result = closeUnit(
|
|
84
|
+
{ basePath: BASE, unitType: "complete-milestone", unitId: "M001", boundary: "milestone", outcome: "complete" },
|
|
85
|
+
deps,
|
|
86
|
+
);
|
|
87
|
+
assert.equal(result.gitVerdict, "milestone-branch");
|
|
88
|
+
assert.equal(log.notices.length, 1);
|
|
89
|
+
assert.equal(log.notices[0].severity, "info");
|
|
90
|
+
assert.match(log.notices[0].message, /worktree merge/);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("clean tree records nothing-to-commit, and the bypass notice says so", () => {
|
|
94
|
+
const { deps, log } = makeDeps({ isolation: "branch", branch: "main", commitResult: null });
|
|
95
|
+
const result = closeUnit(
|
|
96
|
+
{ basePath: BASE, unitType: "complete-milestone", unitId: "M001", boundary: "milestone", outcome: "complete" },
|
|
97
|
+
deps,
|
|
98
|
+
);
|
|
99
|
+
assert.equal(result.gitVerdict, "isolation-bypassed");
|
|
100
|
+
assert.equal(result.commitMessage, null);
|
|
101
|
+
assert.match(log.notices[0].message, /nothing left to commit/);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("commit failure is surfaced, never thrown", () => {
|
|
105
|
+
const { deps, log } = makeDeps({
|
|
106
|
+
commitResult: () => {
|
|
107
|
+
throw new Error("index.lock exists");
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
const result = closeUnit(
|
|
111
|
+
{ basePath: BASE, unitType: "complete-milestone", unitId: "M001", boundary: "milestone", outcome: "complete" },
|
|
112
|
+
deps,
|
|
113
|
+
);
|
|
114
|
+
assert.equal(result.gitVerdict, "commit-failed");
|
|
115
|
+
assert.equal(log.notices[0].severity, "error");
|
|
116
|
+
assert.match(log.notices[0].message, /index\.lock/);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("re-entrancy is safe: a re-fire over an already-clean tree is nothing-to-commit", () => {
|
|
120
|
+
// No result cache — re-entrancy is absorbed by git itself. The second fire
|
|
121
|
+
// sees a clean tree (commit returns null) and records nothing-to-commit.
|
|
122
|
+
let firstFire = true;
|
|
123
|
+
const { deps, log } = makeDeps({
|
|
124
|
+
isolation: "worktree",
|
|
125
|
+
branch: "main",
|
|
126
|
+
commitResult: () => {
|
|
127
|
+
const committed = firstFire;
|
|
128
|
+
firstFire = false;
|
|
129
|
+
return committed ? "chore(gsd): closeout" : null;
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
const request = {
|
|
133
|
+
basePath: BASE,
|
|
134
|
+
unitType: "complete-milestone",
|
|
135
|
+
unitId: "M001",
|
|
136
|
+
boundary: "milestone" as const,
|
|
137
|
+
outcome: "complete" as const,
|
|
138
|
+
};
|
|
139
|
+
const first = closeUnit(request, deps);
|
|
140
|
+
const second = closeUnit(request, deps);
|
|
141
|
+
assert.equal(first.gitVerdict, "isolation-bypassed");
|
|
142
|
+
assert.equal(first.commitMessage, "chore(gsd): closeout");
|
|
143
|
+
assert.equal(second.gitVerdict, "isolation-bypassed");
|
|
144
|
+
assert.equal(second.commitMessage, null);
|
|
145
|
+
assert.match(second.notice ?? "", /nothing left to commit/);
|
|
146
|
+
assert.equal(log.commits.length, 2);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// ─── Interactive adapter mapping ──────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
test("isUnitCloseoutTool recognizes exactly the closeout tools", () => {
|
|
152
|
+
assert.equal(isUnitCloseoutTool("gsd_complete_milestone"), true);
|
|
153
|
+
assert.equal(isUnitCloseoutTool("gsd_save_gate_result"), false);
|
|
154
|
+
assert.equal(isUnitCloseoutTool("read"), false);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("interactive adapter is scoped to milestone boundaries — task/slice tools do not commit", () => {
|
|
158
|
+
const { deps, log } = makeDeps();
|
|
159
|
+
assert.equal(isUnitCloseoutTool("gsd_task_complete"), false);
|
|
160
|
+
assert.equal(isUnitCloseoutTool("gsd_slice_complete"), false);
|
|
161
|
+
assert.equal(
|
|
162
|
+
runInteractiveUnitCloseout(
|
|
163
|
+
{ basePath: BASE, canonicalToolName: "gsd_task_complete", input: { milestoneId: "M001", sliceId: "S02", taskId: "T03" } },
|
|
164
|
+
deps,
|
|
165
|
+
),
|
|
166
|
+
null,
|
|
167
|
+
);
|
|
168
|
+
assert.equal(
|
|
169
|
+
runInteractiveUnitCloseout(
|
|
170
|
+
{ basePath: BASE, canonicalToolName: "gsd_slice_complete", input: { milestoneId: "M001", sliceId: "S02" } },
|
|
171
|
+
deps,
|
|
172
|
+
),
|
|
173
|
+
null,
|
|
174
|
+
);
|
|
175
|
+
assert.equal(log.commits.length, 0);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("interactive adapter maps milestone tool input to canonical unit type", () => {
|
|
179
|
+
const { deps, log } = makeDeps();
|
|
180
|
+
const result = runInteractiveUnitCloseout(
|
|
181
|
+
{ basePath: BASE, canonicalToolName: "gsd_complete_milestone", input: { milestoneId: "M001" } },
|
|
182
|
+
deps,
|
|
183
|
+
);
|
|
184
|
+
assert.equal(result?.gitVerdict, "committed");
|
|
185
|
+
assert.deepEqual(log.commits, [{ unitType: "complete-milestone", unitId: "M001" }]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("interactive adapter accepts snake_case ids and milestone-only input", () => {
|
|
189
|
+
const { deps, log } = makeDeps();
|
|
190
|
+
const result = runInteractiveUnitCloseout(
|
|
191
|
+
{ basePath: BASE, canonicalToolName: "gsd_complete_milestone", input: { milestone_id: "M007" } },
|
|
192
|
+
deps,
|
|
193
|
+
);
|
|
194
|
+
assert.equal(result?.gitVerdict, "committed");
|
|
195
|
+
assert.deepEqual(log.commits, [{ unitType: "complete-milestone", unitId: "M007" }]);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("interactive adapter declines unidentifiable input instead of guessing", () => {
|
|
199
|
+
const { deps, log } = makeDeps();
|
|
200
|
+
assert.equal(
|
|
201
|
+
runInteractiveUnitCloseout({ basePath: BASE, canonicalToolName: "gsd_complete_milestone", input: {} }, deps),
|
|
202
|
+
null,
|
|
203
|
+
);
|
|
204
|
+
assert.equal(
|
|
205
|
+
runInteractiveUnitCloseout({ basePath: BASE, canonicalToolName: "not_a_closeout_tool", input: { milestoneId: "M001" } }, deps),
|
|
206
|
+
null,
|
|
207
|
+
);
|
|
208
|
+
assert.equal(log.commits.length, 0);
|
|
209
|
+
});
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
composeContractedUnitContext,
|
|
12
12
|
composeContextModeInstructions,
|
|
13
13
|
composeInlinedContext,
|
|
14
|
+
composeToolSurfaceInstructions,
|
|
14
15
|
composeUnitContext,
|
|
15
16
|
manifestBudgetChars,
|
|
16
17
|
type ArtifactResolver,
|
|
@@ -24,6 +25,7 @@ import type {
|
|
|
24
25
|
UnitContextManifest,
|
|
25
26
|
} from "../unit-context-manifest.ts";
|
|
26
27
|
import { KNOWN_UNIT_TYPES, UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
28
|
+
import { getUnitToolSurfaceContract } from "../unit-tool-contracts.ts";
|
|
27
29
|
import {
|
|
28
30
|
buildExecuteTaskPrompt,
|
|
29
31
|
buildGateEvaluatePrompt,
|
|
@@ -165,12 +167,32 @@ test("Context Mode composer: every known eligible unit renders its configured la
|
|
|
165
167
|
}
|
|
166
168
|
assert.ok(out.startsWith("## Context Mode"), `${unitType} should render standalone Context Mode heading`);
|
|
167
169
|
assert.match(out, new RegExp(`Lane: \\*\\*${laneLabelByMode[manifest.contextMode]} lane\\*\\*\\.`, "i"));
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
const forbidden = getUnitToolSurfaceContract(unitType)?.forbiddenGsdTools ?? {};
|
|
171
|
+
if ("gsd_exec" in forbidden) {
|
|
172
|
+
// Units that forbid gsd_exec (run-uat) have it stripped from their
|
|
173
|
+
// Claude Code dispatch surface; guidance steering to it produces
|
|
174
|
+
// "No such tool available" loops in the dispatched agent.
|
|
175
|
+
assert.doesNotMatch(out, /`gsd_exec`/, `${unitType} forbids gsd_exec; guidance must not steer to it`);
|
|
176
|
+
assert.doesNotMatch(out, /`gsd_exec_search`/, `${unitType} guidance must not steer to gsd_exec_search`);
|
|
177
|
+
assert.match(out, /`gsd_uat_exec`/, `${unitType} guidance should steer to gsd_uat_exec instead`);
|
|
178
|
+
} else {
|
|
179
|
+
assert.match(out, /`gsd_exec`/, `${unitType} should mention gsd_exec`);
|
|
180
|
+
assert.match(out, /`gsd_exec_search`/, `${unitType} should mention gsd_exec_search`);
|
|
181
|
+
}
|
|
170
182
|
assert.match(out, /`gsd_resume`/, `${unitType} should mention gsd_resume`);
|
|
171
183
|
}
|
|
172
184
|
});
|
|
173
185
|
|
|
186
|
+
test("Context Mode composer: run-uat guidance steers to gsd_uat_exec in both render modes", () => {
|
|
187
|
+
const nested = composeContextModeInstructions("run-uat", { enabled: true, renderMode: "nested" });
|
|
188
|
+
assert.match(nested, /^Context Mode \(verification lane\): /);
|
|
189
|
+
assert.match(nested, /`gsd_uat_exec`/);
|
|
190
|
+
assert.doesNotMatch(nested, /`gsd_exec`/);
|
|
191
|
+
const standalone = composeContextModeInstructions("run-uat", { enabled: true, renderMode: "standalone" });
|
|
192
|
+
assert.match(standalone, /`gsd_uat_exec`/);
|
|
193
|
+
assert.doesNotMatch(standalone, /`gsd_exec`/);
|
|
194
|
+
});
|
|
195
|
+
|
|
174
196
|
test("Context Mode composer: workflow-preferences and research-decision render no Context Mode block", () => {
|
|
175
197
|
assert.strictEqual(
|
|
176
198
|
composeContextModeInstructions("workflow-preferences", { enabled: true, renderMode: "standalone" }),
|
|
@@ -182,6 +204,49 @@ test("Context Mode composer: workflow-preferences and research-decision render n
|
|
|
182
204
|
);
|
|
183
205
|
});
|
|
184
206
|
|
|
207
|
+
test("Tool Surface composer: run-uat forbids gsd_exec and Bash", () => {
|
|
208
|
+
const out = composeToolSurfaceInstructions("run-uat", { renderMode: "standalone" });
|
|
209
|
+
assert.match(out, /^## Tool Surface/);
|
|
210
|
+
assert.match(out, /Do not call `gsd_exec`/);
|
|
211
|
+
assert.match(out, /`Bash`/);
|
|
212
|
+
assert.match(out, /`gsd_uat_exec`/);
|
|
213
|
+
assert.match(out, /`gsd_save_gate_result`/);
|
|
214
|
+
assert.match(out, /`gsd_summary_save`/);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("Tool Surface composer: complete-slice steers verification to gsd_exec", () => {
|
|
218
|
+
const out = composeToolSurfaceInstructions("complete-slice", { renderMode: "standalone" });
|
|
219
|
+
assert.match(out, /`gsd_exec`/);
|
|
220
|
+
assert.match(out, /not direct `bash`/);
|
|
221
|
+
assert.match(out, /`gsd_uat_result_save`/);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("Tool Surface composer: planning units restrict writes to .gsd", () => {
|
|
225
|
+
const out = composeToolSurfaceInstructions("discuss-milestone", { renderMode: "standalone" });
|
|
226
|
+
assert.match(out, /restricted to `\.gsd\/\*\*`/);
|
|
227
|
+
assert.match(out, /`ask_user_questions`/);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("Tool Surface composer: planning-dispatch lists allowed subagents", () => {
|
|
231
|
+
const out = composeToolSurfaceInstructions("plan-slice", { renderMode: "standalone" });
|
|
232
|
+
assert.match(out, /\*\*scout\*\*/);
|
|
233
|
+
assert.match(out, /\*\*planner\*\*/);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test("Tool Surface composer: execute-task warns against slice/milestone closeout tools", () => {
|
|
237
|
+
const out = composeToolSurfaceInstructions("execute-task", { renderMode: "nested" });
|
|
238
|
+
assert.match(out, /^Tool surface: /);
|
|
239
|
+
assert.match(out, /`gsd_task_complete`/);
|
|
240
|
+
assert.match(out, /Do not call `gsd_slice_complete`/);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("Tool Surface composer: unknown unit renders empty block", () => {
|
|
244
|
+
assert.strictEqual(
|
|
245
|
+
composeToolSurfaceInstructions("never-dispatched", { renderMode: "standalone" }),
|
|
246
|
+
"",
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
|
|
185
250
|
// ─── Integration: migrated buildReassessRoadmapPrompt ─────────────────────
|
|
186
251
|
|
|
187
252
|
function makeFixtureBase(): string {
|
|
@@ -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
|
|