@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
|
@@ -131,6 +131,48 @@ export function findTransition(
|
|
|
131
131
|
);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Edge-keyed legality check for the Phase Transition Invariant (ADR-030).
|
|
136
|
+
* `advance()` derives the next Phase and asserts the (from → to) edge here.
|
|
137
|
+
*
|
|
138
|
+
* The matrix is an assertion, not a decision-maker — `deriveState` already
|
|
139
|
+
* chose the Phase. A self-edge is trivially legal (no transition to assert). An
|
|
140
|
+
* edge is legal when some matrix entry permits it, honoring the `*` wildcard
|
|
141
|
+
* rows (e.g. any → blocked via manual-block, any → executing via
|
|
142
|
+
* retryable-failure).
|
|
143
|
+
*
|
|
144
|
+
* Note: the matrix is currently a sparse hardening spec, not a complete
|
|
145
|
+
* legal-edge graph, so `advance()` consumes this in advisory mode (telemetry
|
|
146
|
+
* only). It must be expanded to cover every edge `deriveState` emits before
|
|
147
|
+
* enforcement flips on.
|
|
148
|
+
*/
|
|
149
|
+
export function isLegalEdge(from: Phase, to: Phase): boolean {
|
|
150
|
+
if (from === to) return true;
|
|
151
|
+
return STATE_TRANSITION_MATRIX.some(
|
|
152
|
+
(entry) => (entry.from === from || entry.from === "*") && entry.to === to,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Thrown when an illegal derived Phase edge survives reconciliation. Carries
|
|
158
|
+
* both endpoints so Recovery Classification can report them. Recognized by
|
|
159
|
+
* class in `classifyFailure` and mapped to the `illegal-transition` kind.
|
|
160
|
+
*/
|
|
161
|
+
export class IllegalPhaseTransitionError extends Error {
|
|
162
|
+
// Explicit fields, not constructor parameter properties — strip-types
|
|
163
|
+
// consumers (workspace-index subprocess, integration tests) reject the
|
|
164
|
+
// parameter-property syntax with ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX.
|
|
165
|
+
readonly from: Phase;
|
|
166
|
+
readonly to: Phase;
|
|
167
|
+
|
|
168
|
+
constructor(from: Phase, to: Phase) {
|
|
169
|
+
super(`Illegal phase transition ${from} -> ${to} survived reconciliation`);
|
|
170
|
+
this.name = "IllegalPhaseTransitionError";
|
|
171
|
+
this.from = from;
|
|
172
|
+
this.to = to;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
134
176
|
export function validateTransitionMatrix(requiredEvents: readonly string[]): MatrixValidationResult {
|
|
135
177
|
const seen = new Set<string>();
|
|
136
178
|
const duplicateKeys: string[] = [];
|
|
@@ -13,6 +13,11 @@ import type {
|
|
|
13
13
|
MilestoneRegistryEntry,
|
|
14
14
|
} from './types.js';
|
|
15
15
|
|
|
16
|
+
// Pre-migration fallback ONLY (ADR-017): deriveState must work on projects
|
|
17
|
+
// whose DB does not exist yet (before md-importer runs), so it parses markdown
|
|
18
|
+
// projections when `isDbAvailable()` is false or the DB has no rows. Once the
|
|
19
|
+
// DB is populated, decision reads go through gsd-db queries — these parsers
|
|
20
|
+
// must never be consulted when DB data is present.
|
|
16
21
|
import {
|
|
17
22
|
parseRoadmap,
|
|
18
23
|
parsePlan,
|
|
@@ -71,27 +76,10 @@ import {
|
|
|
71
76
|
readinessNeedsDiscussion,
|
|
72
77
|
} from './milestone-readiness.js';
|
|
73
78
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`1. Review the validation details: \`/gsd status\``,
|
|
79
|
-
`2. If you fixed the missing evidence or issue, re-run milestone validation: \`/gsd validate-milestone\``,
|
|
80
|
-
`3. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
|
|
81
|
-
`4. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
|
|
82
|
-
`After validation or override passes, run \`/gsd auto\` to complete and merge the milestone.`,
|
|
83
|
-
].join("\n");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function formatNeedsRemediationBlocker(milestoneId: string): string {
|
|
87
|
-
return [
|
|
88
|
-
`Milestone ${milestoneId} is blocked because milestone validation returned needs-remediation, but all slices are complete.`,
|
|
89
|
-
`Fix options:`,
|
|
90
|
-
`1. Run \`/gsd dispatch reassess\` to add remediation slices, then run \`/gsd auto\``,
|
|
91
|
-
`2. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
|
|
92
|
-
`3. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
|
|
93
|
-
].join("\n");
|
|
94
|
-
}
|
|
79
|
+
import {
|
|
80
|
+
needsAttentionBlockerGuidance as formatNeedsAttentionBlocker,
|
|
81
|
+
needsRemediationBlockerGuidance as formatNeedsRemediationBlocker,
|
|
82
|
+
} from './guidance.js';
|
|
95
83
|
|
|
96
84
|
/**
|
|
97
85
|
* A "ghost" milestone directory contains only META.json (and no substantive
|
|
@@ -1,17 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Status predicates for GSD state-machine
|
|
2
|
+
* Status predicates and the canonical status vocabulary for GSD state-machine
|
|
3
|
+
* guards (ADR-030).
|
|
3
4
|
*
|
|
4
|
-
* The DB
|
|
5
|
-
*
|
|
6
|
-
* "closed" (legacy/imported), and
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* The DB column is free-form `string` so legacy/imported rows still load. Three
|
|
6
|
+
* raw values besides canonical "complete"/"skipped" indicate "closed": "done"
|
|
7
|
+
* (legacy alias), "closed" (legacy/imported), and "skipped" (user-directed skip
|
|
8
|
+
* via rethink or backtrack). `RAW_CLOSED_STATUSES` is the single source for both
|
|
9
|
+
* `isClosedStatus()` and the SQL terminal-status fragment
|
|
10
|
+
* (`db/sql-constants.ts` derives `TERMINAL_STATUS_SQL` from it), replacing the
|
|
11
|
+
* prior independent definitions.
|
|
12
|
+
*
|
|
13
|
+
* `toStatus()` is the single seam where a free-form string becomes the canonical
|
|
14
|
+
* `Status` vocabulary; the Status Transition Core writes canonical, so the store
|
|
15
|
+
* converges over time without a forced migration.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Canonical, normalized entity-status vocabulary across milestones, slices, and
|
|
20
|
+
* tasks — the single source for both the `Status` type and the runtime
|
|
21
|
+
* membership set. The in-memory domain speaks `Status`; the DB column stays
|
|
22
|
+
* free-form.
|
|
23
|
+
*/
|
|
24
|
+
export const CANONICAL_STATUSES = [
|
|
25
|
+
"pending", "queued", "active", "parked", "in_progress", "blocked", "complete", "skipped", "deferred",
|
|
26
|
+
] as const;
|
|
27
|
+
export type Status = (typeof CANONICAL_STATUSES)[number];
|
|
28
|
+
const CANONICAL_STATUS_SET: ReadonlySet<string> = new Set(CANONICAL_STATUSES);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Raw status values that mean a unit is closed — the single source of truth.
|
|
32
|
+
* Includes legacy/imported aliases ("done", "closed") alongside canonical
|
|
33
|
+
* "complete"/"skipped" because the DB column is free-form and older rows /
|
|
34
|
+
* imports still carry them. Order matters: `TERMINAL_STATUS_SQL` is derived
|
|
35
|
+
* from this array verbatim.
|
|
36
|
+
*/
|
|
37
|
+
export const RAW_CLOSED_STATUSES = ["complete", "done", "skipped", "closed"] as const;
|
|
38
|
+
const RAW_CLOSED_SET: ReadonlySet<string> = new Set(RAW_CLOSED_STATUSES);
|
|
39
|
+
|
|
40
|
+
/** Free-form aliases mapped to their canonical Status on read. */
|
|
41
|
+
const ALIAS_TO_CANONICAL: Readonly<Record<string, Status>> = {
|
|
42
|
+
done: "complete",
|
|
43
|
+
closed: "complete",
|
|
44
|
+
planned: "pending",
|
|
45
|
+
"in-progress": "in_progress",
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Normalize a free-form DB status string into the canonical `Status`
|
|
50
|
+
* vocabulary. Maps known aliases (done/closed → complete, planned → pending,
|
|
51
|
+
* in-progress → in_progress). An unrecognized/legacy value is **quarantined** —
|
|
52
|
+
* preserved verbatim rather than silently remapped to a wrong canonical state —
|
|
53
|
+
* so reads never fail and reconciliation/telemetry can surface it.
|
|
10
54
|
*/
|
|
55
|
+
export function toStatus(raw: string): Status {
|
|
56
|
+
const value = raw.trim();
|
|
57
|
+
if (CANONICAL_STATUS_SET.has(value)) return value as Status;
|
|
58
|
+
const alias = ALIAS_TO_CANONICAL[value];
|
|
59
|
+
if (alias) return alias;
|
|
60
|
+
return value as Status;
|
|
61
|
+
}
|
|
11
62
|
|
|
12
63
|
/** Returns true when a milestone, slice, or task status indicates closure. */
|
|
13
64
|
export function isClosedStatus(status: string): boolean {
|
|
14
|
-
return status
|
|
65
|
+
return RAW_CLOSED_SET.has(status);
|
|
15
66
|
}
|
|
16
67
|
|
|
17
68
|
/** Returns true when a slice status indicates it was deferred by a decision. */
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Stop Notice module — single owner of the auto/step-mode
|
|
3
|
+
// stop/pause notice vocabulary. Both sides of the wire live here: the
|
|
4
|
+
// formatters that produce the canonical prefixes (used by stopAuto/pauseAuto)
|
|
5
|
+
// and the classifiers that recognize them (used by the headless host to pick
|
|
6
|
+
// exit codes). Wording changes in this file keep emitter and detector in
|
|
7
|
+
// lockstep; round-trip tests enforce it.
|
|
8
|
+
|
|
9
|
+
export type StopNoticeKind = "stopped" | "blocked";
|
|
10
|
+
|
|
11
|
+
/** A reason string of the form "Blocked: …" marks a blocked stop. */
|
|
12
|
+
export function isBlockedStopReason(reason?: string | null): boolean {
|
|
13
|
+
return /^Blocked:\s*/i.test(reason ?? "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Strip the "Blocked: " marker for display. */
|
|
17
|
+
export function stopNoticeDisplayReason(reason?: string | null): string {
|
|
18
|
+
return (reason ?? "").replace(/^Blocked:\s*/i, "").trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function stopNoticeKind(reason?: string | null): StopNoticeKind {
|
|
22
|
+
return isBlockedStopReason(reason) ? "blocked" : "stopped";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Canonical stop-notice prefix: "Auto-mode blocked — reason" / "Auto-mode stopped". */
|
|
26
|
+
export function formatStopNoticePrefix(reason?: string | null): string {
|
|
27
|
+
const displayReason = stopNoticeDisplayReason(reason);
|
|
28
|
+
const prefix = stopNoticeKind(reason) === "blocked" ? "Auto-mode blocked" : "Auto-mode stopped";
|
|
29
|
+
return displayReason ? `${prefix} — ${displayReason}` : prefix;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─── Classification (headless host side) ────────────────────────────────
|
|
33
|
+
// The canonical lowercase prefixes the headless event loop recognizes in
|
|
34
|
+
// notify messages. Emitters above and ad-hoc emitters elsewhere must start
|
|
35
|
+
// their terminal notices with one of these.
|
|
36
|
+
|
|
37
|
+
export const PAUSED_NOTICE_PREFIXES = ["auto-mode paused", "step-mode paused"] as const;
|
|
38
|
+
|
|
39
|
+
export const TERMINAL_NOTICE_PREFIXES = [
|
|
40
|
+
"auto-mode stopped",
|
|
41
|
+
"step-mode stopped",
|
|
42
|
+
"auto-mode complete",
|
|
43
|
+
"no active milestone",
|
|
44
|
+
"auto-mode idle",
|
|
45
|
+
] as const;
|
|
46
|
+
|
|
47
|
+
/** Manual-resolution notices emitted before auto-mode can formally pause/stop. */
|
|
48
|
+
export function isManualResolutionNotice(message: string): boolean {
|
|
49
|
+
return (
|
|
50
|
+
message.includes("resolve manually and re-run /gsd auto") ||
|
|
51
|
+
message.includes("resolve conflicts manually and run /gsd auto to resume") ||
|
|
52
|
+
message.includes("resolve and run /gsd auto to resume")
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function isPauseNotice(message: string): boolean {
|
|
57
|
+
return PAUSED_NOTICE_PREFIXES.some((prefix) => message.startsWith(prefix));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isTerminalNotice(message: string): boolean {
|
|
61
|
+
return TERMINAL_NOTICE_PREFIXES.some((prefix) => message.startsWith(prefix));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Pauses that do not require operator intervention in headless mode. */
|
|
65
|
+
export function isNonBlockingPauseNotice(message: string): boolean {
|
|
66
|
+
return message.includes("idempotent advance: unit already active");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function isBlockedNoticeMessage(message: string): boolean {
|
|
70
|
+
return (
|
|
71
|
+
message.includes("blocked:") ||
|
|
72
|
+
(isPauseNotice(message) && !isNonBlockingPauseNotice(message)) ||
|
|
73
|
+
isManualResolutionNotice(message)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -5517,6 +5517,129 @@ test("dispatch Worktree Safety wins before stuck detection for execute-task with
|
|
|
5517
5517
|
);
|
|
5518
5518
|
});
|
|
5519
5519
|
|
|
5520
|
+
test("dispatch Worktree Safety honors degraded branch fallback instead of demanding the canonical worktree root", async (t) => {
|
|
5521
|
+
_resetPendingResolve();
|
|
5522
|
+
|
|
5523
|
+
const ctx = makeMockCtx();
|
|
5524
|
+
const pi = makeMockPi();
|
|
5525
|
+
const notifications: string[] = [];
|
|
5526
|
+
ctx.ui.notify = (msg: string) => { notifications.push(msg); };
|
|
5527
|
+
|
|
5528
|
+
// Worktree creation failed and the lifecycle fell back to the milestone
|
|
5529
|
+
// branch in the project root. The safety gate must validate against that
|
|
5530
|
+
// effective branch mode, not the configured worktree mode.
|
|
5531
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-degraded-"));
|
|
5532
|
+
t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
|
|
5533
|
+
|
|
5534
|
+
const s = makeLoopSession({
|
|
5535
|
+
basePath: projectRoot,
|
|
5536
|
+
originalBasePath: projectRoot,
|
|
5537
|
+
canonicalProjectRoot: projectRoot,
|
|
5538
|
+
isolationDegraded: true,
|
|
5539
|
+
});
|
|
5540
|
+
const deps = makeMockDeps({
|
|
5541
|
+
getIsolationMode: () => "worktree",
|
|
5542
|
+
});
|
|
5543
|
+
const result = await runDispatch(
|
|
5544
|
+
{
|
|
5545
|
+
ctx,
|
|
5546
|
+
pi,
|
|
5547
|
+
s,
|
|
5548
|
+
deps,
|
|
5549
|
+
prefs: undefined,
|
|
5550
|
+
iteration: 1,
|
|
5551
|
+
flowId: "test-flow",
|
|
5552
|
+
nextSeq: () => 1,
|
|
5553
|
+
},
|
|
5554
|
+
{
|
|
5555
|
+
state: {
|
|
5556
|
+
phase: "executing",
|
|
5557
|
+
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
5558
|
+
activeSlice: { id: "S01", title: "Slice 1" },
|
|
5559
|
+
activeTask: { id: "T01" },
|
|
5560
|
+
registry: [{ id: "M001", status: "active" }],
|
|
5561
|
+
blockers: [],
|
|
5562
|
+
} as any,
|
|
5563
|
+
mid: "M001",
|
|
5564
|
+
midTitle: "Test",
|
|
5565
|
+
},
|
|
5566
|
+
{
|
|
5567
|
+
recentUnits: [],
|
|
5568
|
+
stuckRecoveryAttempts: 0,
|
|
5569
|
+
consecutiveFinalizeTimeouts: 0,
|
|
5570
|
+
},
|
|
5571
|
+
);
|
|
5572
|
+
|
|
5573
|
+
assert.equal(result.action, "next", "dispatch must proceed under degraded branch isolation");
|
|
5574
|
+
assert.ok(
|
|
5575
|
+
!notifications.some((n) => n.includes("Worktree Safety failed")),
|
|
5576
|
+
"degraded branch fallback must not trip a false invalid-root",
|
|
5577
|
+
);
|
|
5578
|
+
assert.ok(!deps.callLog.includes("stopAuto"), "auto-mode must not stop on the degraded fallback");
|
|
5579
|
+
});
|
|
5580
|
+
|
|
5581
|
+
test("dispatch Worktree Safety honors stranded branch recovery instead of demanding the canonical worktree root", async (t) => {
|
|
5582
|
+
_resetPendingResolve();
|
|
5583
|
+
|
|
5584
|
+
const ctx = makeMockCtx();
|
|
5585
|
+
const pi = makeMockPi();
|
|
5586
|
+
const notifications: string[] = [];
|
|
5587
|
+
ctx.ui.notify = (msg: string) => { notifications.push(msg); };
|
|
5588
|
+
|
|
5589
|
+
// Bootstrap adopted stranded work by checking out the milestone branch in
|
|
5590
|
+
// the project root (strandedRecoveryIsolationMode = "branch"). Isolation is
|
|
5591
|
+
// NOT degraded — the adoption is intentional. The safety gate must validate
|
|
5592
|
+
// against the effective branch mode, not the configured worktree mode.
|
|
5593
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-stranded-"));
|
|
5594
|
+
t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
|
|
5595
|
+
|
|
5596
|
+
const s = makeLoopSession({
|
|
5597
|
+
basePath: projectRoot,
|
|
5598
|
+
originalBasePath: projectRoot,
|
|
5599
|
+
canonicalProjectRoot: projectRoot,
|
|
5600
|
+
strandedRecoveryIsolationMode: "branch",
|
|
5601
|
+
});
|
|
5602
|
+
const deps = makeMockDeps({
|
|
5603
|
+
getIsolationMode: () => "worktree",
|
|
5604
|
+
});
|
|
5605
|
+
const result = await runDispatch(
|
|
5606
|
+
{
|
|
5607
|
+
ctx,
|
|
5608
|
+
pi,
|
|
5609
|
+
s,
|
|
5610
|
+
deps,
|
|
5611
|
+
prefs: undefined,
|
|
5612
|
+
iteration: 1,
|
|
5613
|
+
flowId: "test-flow",
|
|
5614
|
+
nextSeq: () => 1,
|
|
5615
|
+
},
|
|
5616
|
+
{
|
|
5617
|
+
state: {
|
|
5618
|
+
phase: "executing",
|
|
5619
|
+
activeMilestone: { id: "M001", title: "Test", status: "active" },
|
|
5620
|
+
activeSlice: { id: "S01", title: "Slice 1" },
|
|
5621
|
+
activeTask: { id: "T01" },
|
|
5622
|
+
registry: [{ id: "M001", status: "active" }],
|
|
5623
|
+
blockers: [],
|
|
5624
|
+
} as any,
|
|
5625
|
+
mid: "M001",
|
|
5626
|
+
midTitle: "Test",
|
|
5627
|
+
},
|
|
5628
|
+
{
|
|
5629
|
+
recentUnits: [],
|
|
5630
|
+
stuckRecoveryAttempts: 0,
|
|
5631
|
+
consecutiveFinalizeTimeouts: 0,
|
|
5632
|
+
},
|
|
5633
|
+
);
|
|
5634
|
+
|
|
5635
|
+
assert.equal(result.action, "next", "dispatch must proceed under stranded branch recovery");
|
|
5636
|
+
assert.ok(
|
|
5637
|
+
!notifications.some((n) => n.includes("Worktree Safety failed")),
|
|
5638
|
+
"stranded branch recovery must not trip a false invalid-root",
|
|
5639
|
+
);
|
|
5640
|
+
assert.ok(!deps.callLog.includes("stopAuto"), "auto-mode must not stop on stranded branch recovery");
|
|
5641
|
+
});
|
|
5642
|
+
|
|
5520
5643
|
test("runDispatch runs stuck detection while artifact verification retry is pending (#5719)", async (t) => {
|
|
5521
5644
|
_resetPendingResolve();
|
|
5522
5645
|
|
|
@@ -857,3 +857,25 @@ test("resolveModelId: claude-code wins when session is claude-code regardless of
|
|
|
857
857
|
assert.ok(result, "should resolve a model");
|
|
858
858
|
assert.equal(result.provider, "claude-code", "claude-code must win when it is the session provider");
|
|
859
859
|
});
|
|
860
|
+
|
|
861
|
+
test("resolveModelId: openai-codex wins over openai for bare GPT IDs when both are available", () => {
|
|
862
|
+
const availableModels = [
|
|
863
|
+
{ id: "gpt-5.5", provider: "openai" },
|
|
864
|
+
{ id: "gpt-5.5", provider: "openai-codex" },
|
|
865
|
+
];
|
|
866
|
+
|
|
867
|
+
const result = resolveModelId("gpt-5.5", availableModels, undefined);
|
|
868
|
+
assert.ok(result, "should resolve a model");
|
|
869
|
+
assert.equal(result.provider, "openai-codex", "ChatGPT OAuth must win over platform API for bare IDs");
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
test("resolveModelId: github-copilot wins over openai when both offer the same GPT model", () => {
|
|
873
|
+
const availableModels = [
|
|
874
|
+
{ id: "gpt-5.5", provider: "openai" },
|
|
875
|
+
{ id: "gpt-5.5", provider: "github-copilot" },
|
|
876
|
+
];
|
|
877
|
+
|
|
878
|
+
const result = resolveModelId("gpt-5.5", availableModels, undefined);
|
|
879
|
+
assert.ok(result);
|
|
880
|
+
assert.equal(result.provider, "github-copilot");
|
|
881
|
+
});
|
|
@@ -22,8 +22,8 @@ import {
|
|
|
22
22
|
createAutoOrchestrator,
|
|
23
23
|
decideOrchestratorDispatch,
|
|
24
24
|
resolveLiveOrchestratorBasePath,
|
|
25
|
-
STUCK_WINDOW_SIZE,
|
|
26
25
|
} from "../auto/orchestrator.js";
|
|
26
|
+
import { STUCK_WINDOW_SIZE } from "../auto/dispatch-history.js";
|
|
27
27
|
import type { OrchestratorContext } from "../auto/orchestrator.js";
|
|
28
28
|
import type { AutoOrchestrationModule, AutoSessionContext } from "../auto/contracts.js";
|
|
29
29
|
import type { GSDState } from "../types.js";
|
|
@@ -41,6 +41,10 @@ import {
|
|
|
41
41
|
openDatabase,
|
|
42
42
|
} from "../gsd-db.js";
|
|
43
43
|
import { AutoSession } from "../auto/session.js";
|
|
44
|
+
import { registerAutoWorker } from "../db/auto-workers.js";
|
|
45
|
+
import { claimMilestoneLease } from "../db/milestone-leases.js";
|
|
46
|
+
import { recordDispatchClaim, markFailed } from "../db/unit-dispatches.js";
|
|
47
|
+
import { normalizeRealPath } from "../paths.js";
|
|
44
48
|
import { acquireSessionLock, releaseSessionLock } from "../session-lock.js";
|
|
45
49
|
import { queryJournal } from "../journal.js";
|
|
46
50
|
import { invalidateAllCaches } from "../cache.js";
|
|
@@ -518,13 +522,12 @@ test("advance() is idempotent for the same active unit", async (t) => {
|
|
|
518
522
|
if (first.kind === "advanced") {
|
|
519
523
|
assert.deepEqual(first.unit, { unitType: "execute-task", unitId: "M001/S01/T01" });
|
|
520
524
|
}
|
|
521
|
-
assert.equal(second.kind, "
|
|
522
|
-
if (second.kind !== "
|
|
525
|
+
assert.equal(second.kind, "skipped");
|
|
526
|
+
if (second.kind !== "skipped") return;
|
|
523
527
|
assert.equal(second.reason, "idempotent advance: unit already active");
|
|
524
|
-
assert.equal(second.action, "pause");
|
|
525
528
|
});
|
|
526
529
|
|
|
527
|
-
test("idempotency
|
|
530
|
+
test("idempotency skip fires with its own reason before saturation", async (t) => {
|
|
528
531
|
const f = makeFixture();
|
|
529
532
|
t.after(() => f.cleanup());
|
|
530
533
|
|
|
@@ -532,10 +535,9 @@ test("idempotency block fires with its own reason before saturation", async (t)
|
|
|
532
535
|
const second = await f.orchestrator.advance();
|
|
533
536
|
|
|
534
537
|
assert.equal(first.kind, "advanced");
|
|
535
|
-
assert.equal(second.kind, "
|
|
536
|
-
if (second.kind !== "
|
|
538
|
+
assert.equal(second.kind, "skipped");
|
|
539
|
+
if (second.kind !== "skipped") return;
|
|
537
540
|
assert.equal(second.reason, "idempotent advance: unit already active");
|
|
538
|
-
assert.equal(second.action, "pause");
|
|
539
541
|
});
|
|
540
542
|
|
|
541
543
|
test("completeActiveUnit clears in-flight idempotency and stops stale same-unit advance", async (t) => {
|
|
@@ -671,12 +673,12 @@ test("resume() clears idempotent lock and allows re-advance", async (t) => {
|
|
|
671
673
|
t.after(() => f.cleanup());
|
|
672
674
|
|
|
673
675
|
const first = await f.orchestrator.advance();
|
|
674
|
-
const
|
|
676
|
+
const idempotent = await f.orchestrator.advance();
|
|
675
677
|
const resumed = await f.orchestrator.resume();
|
|
676
678
|
const next = await f.orchestrator.advance();
|
|
677
679
|
|
|
678
680
|
assert.equal(first.kind, "advanced");
|
|
679
|
-
assert.equal(
|
|
681
|
+
assert.equal(idempotent.kind, "skipped");
|
|
680
682
|
assert.equal(resumed.kind, "resumed");
|
|
681
683
|
assert.equal(next.kind, "advanced");
|
|
682
684
|
});
|
|
@@ -686,11 +688,11 @@ test("start() clears prior idempotent lock", async (t) => {
|
|
|
686
688
|
t.after(() => f.cleanup());
|
|
687
689
|
|
|
688
690
|
await f.orchestrator.advance();
|
|
689
|
-
const
|
|
691
|
+
const idempotent = await f.orchestrator.advance();
|
|
690
692
|
const restarted = await f.orchestrator.start(SESSION_CONTEXT);
|
|
691
693
|
const next = await f.orchestrator.advance();
|
|
692
694
|
|
|
693
|
-
assert.equal(
|
|
695
|
+
assert.equal(idempotent.kind, "skipped");
|
|
694
696
|
assert.equal(restarted.kind, "started");
|
|
695
697
|
assert.equal(next.kind, "advanced");
|
|
696
698
|
});
|
|
@@ -700,32 +702,28 @@ test("stop() clears idempotent unit lock so advance can run again", async (t) =>
|
|
|
700
702
|
t.after(() => f.cleanup());
|
|
701
703
|
|
|
702
704
|
const first = await f.orchestrator.advance();
|
|
703
|
-
const
|
|
705
|
+
const idempotent = await f.orchestrator.advance();
|
|
704
706
|
const stopped = await f.orchestrator.stop("reset");
|
|
705
707
|
const second = await f.orchestrator.advance();
|
|
706
708
|
|
|
707
709
|
assert.equal(first.kind, "advanced");
|
|
708
|
-
assert.equal(
|
|
710
|
+
assert.equal(idempotent.kind, "skipped");
|
|
709
711
|
assert.equal(stopped.kind, "stopped");
|
|
710
712
|
assert.equal(second.kind, "advanced");
|
|
711
713
|
});
|
|
712
714
|
|
|
713
|
-
test("
|
|
715
|
+
test("idempotent path journals advance-skipped and records a health snapshot", async (t) => {
|
|
714
716
|
const f = makeFixture();
|
|
715
717
|
t.after(() => f.cleanup());
|
|
716
718
|
|
|
717
719
|
await f.orchestrator.advance();
|
|
718
720
|
await f.orchestrator.advance();
|
|
719
721
|
|
|
720
|
-
assert.ok(f.journalNames().includes("advance-
|
|
722
|
+
assert.ok(f.journalNames().includes("advance-skipped"));
|
|
721
723
|
});
|
|
722
724
|
|
|
723
725
|
// ─── Stuck-loop ring buffer (issue #5787) ──────────────────────────────────
|
|
724
726
|
|
|
725
|
-
test("STUCK_WINDOW_SIZE matches the legacy auto/phases.ts constant", () => {
|
|
726
|
-
assert.equal(STUCK_WINDOW_SIZE, 6);
|
|
727
|
-
});
|
|
728
|
-
|
|
729
727
|
test("stuck-loop: empty ring on a freshly constructed orchestrator advances normally", async (t) => {
|
|
730
728
|
const f = makeFixture();
|
|
731
729
|
t.after(() => f.cleanup());
|
|
@@ -761,21 +759,24 @@ test("stuck-loop: ring saturated with same unit blocks with action 'stop' and st
|
|
|
761
759
|
// First call advances.
|
|
762
760
|
assert.equal(results[0].kind, "advanced");
|
|
763
761
|
|
|
764
|
-
// Intermediate calls are
|
|
762
|
+
// Intermediate calls are skipped by idempotency (not stuck-loop yet).
|
|
765
763
|
for (let i = 1; i < STUCK_WINDOW_SIZE - 1; i++) {
|
|
766
764
|
const r = results[i];
|
|
767
|
-
assert.equal(r.kind, "
|
|
768
|
-
if (r.kind !== "
|
|
765
|
+
assert.equal(r.kind, "skipped", `round ${i} should be skipped`);
|
|
766
|
+
if (r.kind !== "skipped") return;
|
|
769
767
|
assert.equal(r.reason, "idempotent advance: unit already active");
|
|
770
|
-
assert.equal(r.action, "pause");
|
|
771
768
|
}
|
|
772
769
|
|
|
773
|
-
// The final call (ring now holds STUCK_WINDOW_SIZE copies) returns stuck-loop
|
|
770
|
+
// The final call (ring now holds STUCK_WINDOW_SIZE copies) returns stuck-loop
|
|
771
|
+
// with the detect-stuck rule verdict in the reason.
|
|
774
772
|
const last = results[STUCK_WINDOW_SIZE - 1];
|
|
775
773
|
assert.equal(last.kind, "blocked");
|
|
776
774
|
if (last.kind !== "blocked") return;
|
|
777
775
|
assert.equal(last.action, "stop");
|
|
778
|
-
assert.
|
|
776
|
+
assert.ok(
|
|
777
|
+
last.reason.startsWith("stuck-loop: execute-task:M001/S01/T01 derived"),
|
|
778
|
+
`expected detect-stuck verdict reason, got: ${last.reason}`,
|
|
779
|
+
);
|
|
779
780
|
});
|
|
780
781
|
|
|
781
782
|
test("stuck-loop: start() resets the ring so a fresh saturation cycle is required", async (t) => {
|
|
@@ -855,6 +856,80 @@ test("stuck-loop: stop('user-request') resets the ring (hard stop)", async (t) =
|
|
|
855
856
|
assert.equal(next.kind, "advanced");
|
|
856
857
|
});
|
|
857
858
|
|
|
859
|
+
test("stuck-loop #482 regression: start() rehydrates the window from the dispatch ledger so cross-session re-dispatch loops are detected", async (t) => {
|
|
860
|
+
const f = makeFixture();
|
|
861
|
+
t.after(() => f.cleanup());
|
|
862
|
+
|
|
863
|
+
// Simulate a PRIOR session: the dispatch ledger recorded the same unit
|
|
864
|
+
// being re-dispatched repeatedly without progress. The orchestrator under test is a
|
|
865
|
+
// fresh instance (as it would be after a session restart) — before the
|
|
866
|
+
// Dispatch History module, start() reset the window to [] and the loop
|
|
867
|
+
// would silently re-dispatch the unit forever (#482: 146 re-dispatches).
|
|
868
|
+
const worker = registerAutoWorker({ projectRootRealpath: normalizeRealPath(f.base) });
|
|
869
|
+
const lease = claimMilestoneLease(worker, "M001");
|
|
870
|
+
assert.equal(lease.ok, true);
|
|
871
|
+
if (!lease.ok) return;
|
|
872
|
+
for (let i = 0; i < STUCK_WINDOW_SIZE - 1; i++) {
|
|
873
|
+
const claim = recordDispatchClaim({
|
|
874
|
+
traceId: `prior-session-${i}`,
|
|
875
|
+
workerId: worker,
|
|
876
|
+
milestoneLeaseToken: lease.token,
|
|
877
|
+
milestoneId: "M001",
|
|
878
|
+
unitType: "execute-task",
|
|
879
|
+
unitId: "M001/S01/T01",
|
|
880
|
+
});
|
|
881
|
+
assert.equal(claim.ok, true);
|
|
882
|
+
if (!claim.ok) return;
|
|
883
|
+
markFailed(claim.dispatchId, { errorSummary: "" });
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
const started = await f.orchestrator.start(SESSION_CONTEXT);
|
|
887
|
+
assert.equal(started.kind, "started");
|
|
888
|
+
|
|
889
|
+
// The very next decision for the same unit must trip the stuck verdict
|
|
890
|
+
// instead of advancing.
|
|
891
|
+
const result = await f.orchestrator.advance();
|
|
892
|
+
assert.equal(result.kind, "blocked");
|
|
893
|
+
if (result.kind !== "blocked") return;
|
|
894
|
+
assert.equal(result.action, "stop");
|
|
895
|
+
assert.ok(result.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${result.reason}`);
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
test("stuck-loop #482: resume() with an empty window rehydrates from the dispatch ledger", async (t) => {
|
|
899
|
+
const f = makeFixture();
|
|
900
|
+
t.after(() => f.cleanup());
|
|
901
|
+
|
|
902
|
+
const worker = registerAutoWorker({ projectRootRealpath: normalizeRealPath(f.base) });
|
|
903
|
+
const lease = claimMilestoneLease(worker, "M001");
|
|
904
|
+
assert.equal(lease.ok, true);
|
|
905
|
+
if (!lease.ok) return;
|
|
906
|
+
for (let i = 0; i < STUCK_WINDOW_SIZE - 1; i++) {
|
|
907
|
+
const claim = recordDispatchClaim({
|
|
908
|
+
traceId: `prior-session-resume-${i}`,
|
|
909
|
+
workerId: worker,
|
|
910
|
+
milestoneLeaseToken: lease.token,
|
|
911
|
+
milestoneId: "M001",
|
|
912
|
+
unitType: "execute-task",
|
|
913
|
+
unitId: "M001/S01/T01",
|
|
914
|
+
});
|
|
915
|
+
assert.equal(claim.ok, true);
|
|
916
|
+
if (!claim.ok) return;
|
|
917
|
+
markFailed(claim.dispatchId, { errorSummary: "" });
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// Fresh orchestrator resuming a prior session: window starts empty, so
|
|
921
|
+
// resume() must rehydrate (while in-process resume keeps the live window —
|
|
922
|
+
// see the #572 preservation tests above).
|
|
923
|
+
const resumed = await f.orchestrator.resume();
|
|
924
|
+
assert.equal(resumed.kind, "resumed");
|
|
925
|
+
|
|
926
|
+
const result = await f.orchestrator.advance();
|
|
927
|
+
assert.equal(result.kind, "blocked");
|
|
928
|
+
if (result.kind !== "blocked") return;
|
|
929
|
+
assert.equal(result.action, "stop");
|
|
930
|
+
assert.ok(result.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${result.reason}`);
|
|
931
|
+
});
|
|
932
|
+
|
|
858
933
|
test("stuck-loop: journal records the stuck-loop reason on advance-blocked", async (t) => {
|
|
859
934
|
const f = makeFixture();
|
|
860
935
|
t.after(() => f.cleanup());
|
|
@@ -306,7 +306,9 @@ test("pauseAuto records the expected worktree path when paused from project root
|
|
|
306
306
|
|
|
307
307
|
const meta = readPausedSessionMetadata(base);
|
|
308
308
|
assert.ok(meta);
|
|
309
|
-
|
|
309
|
+
// No worktree exists yet, so the recorded path is the canonical
|
|
310
|
+
// .gsd-worktrees/ creation location (worktree-placement seam).
|
|
311
|
+
assert.equal(meta.worktreePath, join(base, ".gsd-worktrees", "M001"));
|
|
310
312
|
} finally {
|
|
311
313
|
autoSession.reset();
|
|
312
314
|
try {
|