@opengsd/gsd-pi 1.2.0-dev.4813ead6 → 1.2.0-dev.5457a158
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-style.d.ts +17 -0
- package/dist/cli-style.js +28 -0
- package/dist/cli.js +1 -1
- package/dist/headless-events.d.ts +4 -2
- package/dist/headless-events.js +7 -29
- package/dist/models-resolver.d.ts +3 -13
- package/dist/models-resolver.js +3 -22
- package/dist/resource-loader.js +2 -14
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/bg-shell/utilities.js +5 -2
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +35 -4
- package/dist/resources/extensions/gsd/auto/orchestrator.js +33 -4
- package/dist/resources/extensions/gsd/auto/phases.js +6 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -8
- package/dist/resources/extensions/gsd/auto-prompts.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +12 -14
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
- package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
- package/dist/resources/extensions/gsd/auto.js +8 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +86 -6
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +30 -4
- package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
- package/dist/resources/extensions/gsd/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/crash-recovery.js +4 -12
- package/dist/resources/extensions/gsd/db/engine.js +755 -0
- package/dist/resources/extensions/gsd/db/queries.js +372 -0
- package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
- package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
- package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
- package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
- package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
- package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
- package/dist/resources/extensions/gsd/doctor-format.js +9 -6
- package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
- package/dist/resources/extensions/gsd/error-classifier.js +9 -0
- package/dist/resources/extensions/gsd/git-service.js +1 -0
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
- package/dist/resources/extensions/gsd/guidance.js +98 -0
- package/dist/resources/extensions/gsd/guided-flow.js +51 -5
- package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
- package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
- package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
- package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
- package/dist/resources/extensions/gsd/model-router.js +3 -0
- package/dist/resources/extensions/gsd/notification-store.js +11 -4
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
- package/dist/resources/extensions/gsd/paths.js +37 -24
- package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
- package/dist/resources/extensions/gsd/preferences-models.js +12 -46
- package/dist/resources/extensions/gsd/preferences.js +14 -0
- 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/provider-error-guidance.js +1 -5
- package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
- package/dist/resources/extensions/gsd/publication.js +87 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
- package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
- package/dist/resources/extensions/gsd/state.js +1 -20
- package/dist/resources/extensions/gsd/status-guards.js +56 -8
- package/dist/resources/extensions/gsd/stop-notice.js +57 -0
- package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
- package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -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/undo.js +8 -7
- package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
- package/dist/resources/extensions/gsd/unit-context-composer.js +9 -1
- package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
- package/dist/resources/extensions/gsd/unit-registry.js +350 -0
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
- package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
- package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
- package/dist/resources/extensions/gsd/worktree-root.js +28 -6
- package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
- package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
- package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
- 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 +6 -6
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
- 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/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/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/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/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/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +0 -30
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +0 -30
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +361 -255
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +311 -256
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/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/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/bg-shell/utilities.ts +5 -2
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +37 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +39 -5
- package/src/resources/extensions/gsd/auto/phases.ts +10 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +25 -7
- package/src/resources/extensions/gsd/auto-prompts.ts +3 -0
- package/src/resources/extensions/gsd/auto-start.ts +12 -15
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
- package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
- package/src/resources/extensions/gsd/auto.ts +20 -24
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -6
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +87 -6
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +29 -3
- package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
- package/src/resources/extensions/gsd/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/crash-recovery.ts +3 -9
- package/src/resources/extensions/gsd/db/engine.ts +809 -0
- package/src/resources/extensions/gsd/db/queries.ts +453 -0
- package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
- package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
- package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
- package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
- package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
- package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
- package/src/resources/extensions/gsd/doctor-format.ts +12 -7
- package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
- package/src/resources/extensions/gsd/error-classifier.ts +11 -0
- package/src/resources/extensions/gsd/git-service.ts +1 -0
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
- package/src/resources/extensions/gsd/guidance.ts +139 -0
- package/src/resources/extensions/gsd/guided-flow.ts +50 -5
- package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
- package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
- package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
- package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
- package/src/resources/extensions/gsd/model-router.ts +3 -0
- package/src/resources/extensions/gsd/notification-store.ts +26 -3
- package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
- package/src/resources/extensions/gsd/paths.ts +42 -22
- package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
- package/src/resources/extensions/gsd/preferences-models.ts +10 -46
- package/src/resources/extensions/gsd/preferences.ts +18 -0
- 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/provider-error-guidance.ts +4 -9
- package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
- package/src/resources/extensions/gsd/publication.ts +122 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
- package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
- package/src/resources/extensions/gsd/state.ts +4 -21
- package/src/resources/extensions/gsd/status-guards.ts +59 -8
- package/src/resources/extensions/gsd/stop-notice.ts +75 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-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/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/evidence-xref-gsd-exec.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +51 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +54 -1
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
- package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
- package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/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/unit-closeout.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +23 -2
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +42 -0
- package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
- package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -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/undo.ts +9 -8
- package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
- package/src/resources/extensions/gsd/unit-context-composer.ts +12 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
- package/src/resources/extensions/gsd/unit-registry.ts +425 -0
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
- package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +10 -1
- package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
- package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
- package/src/resources/extensions/gsd/worktree-root.ts +29 -6
- package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
- package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
- package/src/resources/skills/gsd-browser/SKILL.md +1 -1
- /package/dist/web/standalone/.next/static/{tkLHUSzPA2kMmWz4DmGwI → 2p9Rv9pQflAxCBbGVI2vb}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{tkLHUSzPA2kMmWz4DmGwI → 2p9Rv9pQflAxCBbGVI2vb}/_ssgManifest.js +0 -0
|
@@ -7,7 +7,7 @@ import { isToolCallEventType } from "@gsd/pi-coding-agent";
|
|
|
7
7
|
import { ALWAYS_PRESERVED_SHIM_TOOL_NAMES } from "@gsd/pi-ai";
|
|
8
8
|
import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
|
|
9
9
|
import { buildMilestoneFileName, clearPathCache, milestonesDir, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
|
|
10
|
-
import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isMilestoneDepthVerified, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
10
|
+
import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
11
11
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
12
12
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
13
13
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
@@ -20,6 +20,7 @@ import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecor
|
|
|
20
20
|
import { parseUnitId } from "../unit-id.js";
|
|
21
21
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
22
22
|
import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
23
|
+
import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
|
|
23
24
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
24
25
|
import { initNotificationStore } from "../notification-store.js";
|
|
25
26
|
import { initNotificationWidget } from "../notification-widget.js";
|
|
@@ -35,6 +36,8 @@ import { filterToolsForProvider } from "../model-router.js";
|
|
|
35
36
|
import { mcpToolMatchesBaseName } from "../mcp-tool-name.js";
|
|
36
37
|
import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
37
38
|
import { supportsSourceObservationsForUnit } from "../source-observations.js";
|
|
39
|
+
import { clearPendingAutoStart } from "../pending-auto-start.js";
|
|
40
|
+
import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
|
|
38
41
|
let approvalQuestionAbortInFlight = false;
|
|
39
42
|
async function loadWelcomeScreenModule() {
|
|
40
43
|
const candidates = [];
|
|
@@ -444,8 +447,15 @@ function isShellExecutionTool(canonicalName) {
|
|
|
444
447
|
function activateDeferredApprovalGate(basePath) {
|
|
445
448
|
if (deferredApprovalGate?.basePath !== basePath)
|
|
446
449
|
return;
|
|
447
|
-
|
|
450
|
+
const gateId = deferredApprovalGate.gateId;
|
|
448
451
|
deferredApprovalGate = null;
|
|
452
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
453
|
+
const milestoneId = extractDepthVerificationMilestoneId(gateId);
|
|
454
|
+
if (isApprovalGateVerifiedInSnapshot(snapshot, gateId))
|
|
455
|
+
return;
|
|
456
|
+
if (milestoneId && isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId))
|
|
457
|
+
return;
|
|
458
|
+
setPendingGate(gateId, basePath);
|
|
449
459
|
}
|
|
450
460
|
function extractGateQuestionId(input) {
|
|
451
461
|
const questions = input?.questions ?? [];
|
|
@@ -463,6 +473,25 @@ function isContextDraftSummarySave(toolName, input) {
|
|
|
463
473
|
return false;
|
|
464
474
|
return input.artifact_type === "CONTEXT-DRAFT";
|
|
465
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* External engines (claude-code-cli) deliver ask_user_questions results as
|
|
478
|
+
* relayed MCP tool results: the structured round payload arrives in
|
|
479
|
+
* `result.structuredContent`, not in pi-native `event.details`. Without this
|
|
480
|
+
* fallback, applyAskUserQuestionsGateResult sees no response for an answered
|
|
481
|
+
* gate question and lands in the "waiting" branch — leaving a re-armed gate
|
|
482
|
+
* permanently pending and the discuss→auto handoff blocked.
|
|
483
|
+
*/
|
|
484
|
+
function resolveAskUserQuestionsGateDetails(event) {
|
|
485
|
+
const hasRoundShape = (value) => !!value && typeof value === "object" &&
|
|
486
|
+
(value.cancelled !== undefined || value.response !== undefined);
|
|
487
|
+
const details = event.details;
|
|
488
|
+
if (hasRoundShape(details))
|
|
489
|
+
return details;
|
|
490
|
+
const structured = event.result?.structuredContent;
|
|
491
|
+
if (hasRoundShape(structured))
|
|
492
|
+
return structured;
|
|
493
|
+
return details ?? {};
|
|
494
|
+
}
|
|
466
495
|
function selectedAnswerLabel(selected) {
|
|
467
496
|
if (Array.isArray(selected))
|
|
468
497
|
return selected.map(String).join(", ");
|
|
@@ -626,7 +655,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
626
655
|
catch { /* non-fatal */ }
|
|
627
656
|
}
|
|
628
657
|
});
|
|
629
|
-
pi.on("session_switch", async (
|
|
658
|
+
pi.on("session_switch", async (event, ctx) => {
|
|
630
659
|
const basePath = contextBasePath(ctx);
|
|
631
660
|
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
632
661
|
initSessionNotifications(ctx);
|
|
@@ -635,6 +664,13 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
635
664
|
clearDeferredApprovalGate();
|
|
636
665
|
await resetAskUserQuestionsTurnCache();
|
|
637
666
|
clearDiscussionFlowState(basePath);
|
|
667
|
+
// /clear or /new destroys the conversation holding a discuss interview, so
|
|
668
|
+
// its pending discuss→auto handoff can never be answered — clear it. Resume
|
|
669
|
+
// restores the interview transcript, so the entry survives. Auto-mode's own
|
|
670
|
+
// newSession() calls are safe: the handoff consumes the entry on agent_end.
|
|
671
|
+
if (event.reason === "new") {
|
|
672
|
+
clearPendingAutoStart(basePath);
|
|
673
|
+
}
|
|
638
674
|
await syncServiceTierStatus(ctx);
|
|
639
675
|
await applyDisabledModelProviderPolicy(ctx);
|
|
640
676
|
await applyCompactionThresholdOverride(ctx);
|
|
@@ -1105,12 +1141,27 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1105
1141
|
else if (isAutoActive()) {
|
|
1106
1142
|
clearToolInvocationError();
|
|
1107
1143
|
}
|
|
1144
|
+
// Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
|
|
1145
|
+
// own units; interactive completions get the durable git subset (commit +
|
|
1146
|
+
// Closeout Git Verdict) instead of silently bypassing git.isolation.
|
|
1147
|
+
if (!event.isError && !isAutoActive() && isUnitCloseoutTool(toolName)) {
|
|
1148
|
+
try {
|
|
1149
|
+
runInteractiveUnitCloseout({
|
|
1150
|
+
basePath: resolveWorkflowToolBasePath(ctx, event.input),
|
|
1151
|
+
canonicalToolName: toolName,
|
|
1152
|
+
input: event.input,
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
catch (err) {
|
|
1156
|
+
safetyLogWarning("engine", `interactive unit closeout failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1108
1159
|
if (toolName !== "ask_user_questions")
|
|
1109
1160
|
return;
|
|
1110
1161
|
const basePath = contextBasePath(ctx);
|
|
1111
1162
|
const milestoneId = await getDiscussionMilestoneIdFor(basePath);
|
|
1112
|
-
const details = event
|
|
1113
|
-
const questions = event.input?.questions ?? [];
|
|
1163
|
+
const details = resolveAskUserQuestionsGateDetails(event);
|
|
1164
|
+
const questions = event.input?.questions ?? details?.questions ?? [];
|
|
1114
1165
|
const gateResult = applyAskUserQuestionsGateResult({
|
|
1115
1166
|
basePath,
|
|
1116
1167
|
questions,
|
|
@@ -1146,10 +1197,39 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1146
1197
|
if (toolName === "ask_user_questions") {
|
|
1147
1198
|
const questionId = extractGateQuestionId(event.args);
|
|
1148
1199
|
if (typeof questionId === "string") {
|
|
1149
|
-
|
|
1200
|
+
// External engines (claude-code-cli) ingest the SDK turn's tool blocks
|
|
1201
|
+
// post-hoc, so this event can fire AFTER the workflow MCP child already
|
|
1202
|
+
// verified this gate and allowed the CONTEXT save. setPendingGate also
|
|
1203
|
+
// revokes verifiedDepthMilestones/verifiedApprovalGates, so an
|
|
1204
|
+
// unconditional re-arm here wipes the child's verification and leaves
|
|
1205
|
+
// the discuss→auto handoff permanently blocked. Skip the re-arm when
|
|
1206
|
+
// the snapshot already records this exact gate as verified — mirrors
|
|
1207
|
+
// activateDeferredApprovalGate's guard. Stale verified state cannot
|
|
1208
|
+
// leak into a later re-discussion: a successful handoff deletes the
|
|
1209
|
+
// snapshot via clearDiscussionFlowState.
|
|
1210
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
1211
|
+
const gateMilestoneId = extractDepthVerificationMilestoneId(questionId);
|
|
1212
|
+
const alreadyVerified = isApprovalGateVerifiedInSnapshot(snapshot, questionId) ||
|
|
1213
|
+
isMilestoneDepthVerifiedInSnapshot(snapshot, gateMilestoneId);
|
|
1214
|
+
if (!alreadyVerified) {
|
|
1215
|
+
setPendingGate(questionId, basePath);
|
|
1216
|
+
}
|
|
1150
1217
|
clearDeferredApprovalGate(basePath);
|
|
1151
1218
|
}
|
|
1152
1219
|
}
|
|
1220
|
+
// Safety harness: record evidence here, not only in tool_call. External
|
|
1221
|
+
// engines (claude-code-cli) pre-execute tools, so the agent loop skips
|
|
1222
|
+
// beforeToolCall/tool_call for them — tool_execution_start is the only
|
|
1223
|
+
// event that fires for every tool call. recordToolCall dedupes by
|
|
1224
|
+
// toolCallId, so native tools (which hit both events) record once.
|
|
1225
|
+
safetyRecordToolCall(event.toolCallId, event.toolName, (event.args ?? {}));
|
|
1226
|
+
const execDash = getAutoRuntimeSnapshot();
|
|
1227
|
+
if (execDash.basePath && execDash.currentUnit?.type === "execute-task") {
|
|
1228
|
+
const { milestone: xMid, slice: xSid, task: xTid } = parseUnitId(execDash.currentUnit.id);
|
|
1229
|
+
if (xMid && xSid && xTid) {
|
|
1230
|
+
saveEvidenceToDisk(execDash.basePath, xMid, xSid, xTid);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1153
1233
|
if (!isAutoActive())
|
|
1154
1234
|
return;
|
|
1155
1235
|
markToolStart(event.toolCallId, event.toolName);
|
|
@@ -8,6 +8,7 @@ import { getIsolationMode } from "../preferences.js";
|
|
|
8
8
|
import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
|
|
9
9
|
import { logWarning } from "../workflow-logger.js";
|
|
10
10
|
import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
11
|
+
import { worktreesDirs } from "../worktree-placement.js";
|
|
11
12
|
/**
|
|
12
13
|
* Regex matching milestone CONTEXT.md file names in both legacy M001
|
|
13
14
|
* and unique M001-abc123 formats. Exported so regex-hardening tests
|
|
@@ -214,6 +215,27 @@ export function loadWriteGateSnapshot(basePath) {
|
|
|
214
215
|
return currentWriteGateSnapshot(basePath);
|
|
215
216
|
}
|
|
216
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Merge the persisted write-gate snapshot into the in-process Map entry.
|
|
220
|
+
* The workflow MCP server runs in a child process and records depth
|
|
221
|
+
* verification there; without this refresh the extension host keeps stale
|
|
222
|
+
* pending-gate memory and `activateDeferredApprovalGate` can re-arm a gate
|
|
223
|
+
* that the subprocess already cleared on disk.
|
|
224
|
+
*
|
|
225
|
+
* Returns the snapshot used for the refresh so callers that need to inspect
|
|
226
|
+
* it (e.g. re-arm guards) avoid a second disk read.
|
|
227
|
+
*/
|
|
228
|
+
export function refreshWriteGateStateFromDisk(basePath) {
|
|
229
|
+
const snapshot = loadWriteGateSnapshot(basePath);
|
|
230
|
+
if (!shouldPersistWriteGateSnapshot())
|
|
231
|
+
return snapshot;
|
|
232
|
+
const state = getWriteGateState(basePath);
|
|
233
|
+
state.pendingGateId = snapshot.pendingGateId;
|
|
234
|
+
state.activeQueuePhase = snapshot.activeQueuePhase;
|
|
235
|
+
state.verifiedDepthMilestones = new Set(snapshot.verifiedDepthMilestones);
|
|
236
|
+
state.verifiedApprovalGates = new Set(snapshot.verifiedApprovalGates ?? []);
|
|
237
|
+
return snapshot;
|
|
238
|
+
}
|
|
217
239
|
export function isDepthVerified(basePath = process.cwd()) {
|
|
218
240
|
return getWriteGateState(basePath).verifiedDepthMilestones.size > 0;
|
|
219
241
|
}
|
|
@@ -223,6 +245,7 @@ export function isDepthVerified(basePath = process.cwd()) {
|
|
|
223
245
|
export function isMilestoneDepthVerified(milestoneId, basePath = process.cwd()) {
|
|
224
246
|
if (!milestoneId)
|
|
225
247
|
return false;
|
|
248
|
+
refreshWriteGateStateFromDisk(basePath);
|
|
226
249
|
return getWriteGateState(basePath).verifiedDepthMilestones.has(milestoneId);
|
|
227
250
|
}
|
|
228
251
|
export function isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId) {
|
|
@@ -309,6 +332,7 @@ export function clearPendingGate(basePath) {
|
|
|
309
332
|
* Get the currently pending gate, if any.
|
|
310
333
|
*/
|
|
311
334
|
export function getPendingGate(basePath = process.cwd()) {
|
|
335
|
+
refreshWriteGateStateFromDisk(basePath);
|
|
312
336
|
return getWriteGateState(basePath).pendingGateId;
|
|
313
337
|
}
|
|
314
338
|
/**
|
|
@@ -919,10 +943,12 @@ export function shouldBlockWorktreeWrite(toolName, targetPath, effectiveBasePath
|
|
|
919
943
|
const realTarget = realpathOrResolve(absTarget);
|
|
920
944
|
const realRoot = realpathOrResolve(projectRoot);
|
|
921
945
|
const realGsd = realpathOrResolve(join(projectRoot, ".gsd"));
|
|
922
|
-
|
|
923
|
-
//
|
|
924
|
-
|
|
925
|
-
|
|
946
|
+
// Allow writes inside a legitimate worktrees subtree (canonical
|
|
947
|
+
// .gsd-worktrees/ or legacy .gsd/worktrees/).
|
|
948
|
+
for (const container of worktreesDirs(projectRoot)) {
|
|
949
|
+
if (isPathContained(realTarget, realpathOrResolve(container)))
|
|
950
|
+
return { block: false };
|
|
951
|
+
}
|
|
926
952
|
// Allow writes to .gsd/ planning artifacts, but reject siblings whose name
|
|
927
953
|
// starts with "worktrees" (the worktrees-extra prefix trick — case 4).
|
|
928
954
|
if (isPathContained(realTarget, realGsd)) {
|
|
@@ -11,3 +11,5 @@ export const SLICE_BRANCH_RE = /^gsd\/(?:([a-zA-Z0-9_-]+)\/)?(M\d+(?:-[a-z0-9]{6
|
|
|
11
11
|
export const QUICK_BRANCH_RE = /^gsd\/quick\//;
|
|
12
12
|
/** Matches GSD-generated workflow template branches, not arbitrary user gsd/* branches. */
|
|
13
13
|
export const WORKFLOW_BRANCH_RE = /^gsd\/(?:hotfix|bugfix|small-feature|refactor|spike|security-audit|dep-upgrade|full-project)\//;
|
|
14
|
+
/** Auto-mode milestone branch prefix: milestone/<MID>. */
|
|
15
|
+
export const MILESTONE_BRANCH_PREFIX = "milestone/";
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
* `.gsd/CAPTURES.md`, not the worktree's local `.gsd/`.
|
|
9
9
|
*/
|
|
10
10
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
11
|
-
import { join, resolve
|
|
11
|
+
import { join, resolve } from "node:path";
|
|
12
12
|
import { randomUUID } from "node:crypto";
|
|
13
13
|
import { gsdRoot } from "./paths.js";
|
|
14
|
+
import { projectRootFromWorktreePath } from "./worktree-root.js";
|
|
14
15
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
15
16
|
const CAPTURES_FILENAME = "CAPTURES.md";
|
|
16
17
|
const VALID_CLASSIFICATIONS = [
|
|
@@ -29,20 +30,9 @@ const VALID_CLASSIFICATIONS = [
|
|
|
29
30
|
* directory that contains `.gsd/worktrees/` — that's the project root.
|
|
30
31
|
*/
|
|
31
32
|
export function resolveCapturesPath(basePath) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let idx = resolved.indexOf(worktreeMarker);
|
|
36
|
-
if (idx === -1) {
|
|
37
|
-
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/
|
|
38
|
-
const symlinkRe = new RegExp(`\\${sep}\\.gsd\\${sep}projects\\${sep}[a-f0-9]+\\${sep}worktrees\\${sep}`);
|
|
39
|
-
const match = resolved.match(symlinkRe);
|
|
40
|
-
if (match && match.index !== undefined)
|
|
41
|
-
idx = match.index;
|
|
42
|
-
}
|
|
43
|
-
if (idx !== -1) {
|
|
44
|
-
// basePath is inside a worktree — resolve to project root
|
|
45
|
-
const projectRoot = resolved.slice(0, idx);
|
|
33
|
+
// If basePath is inside a worktree, resolve to the project root.
|
|
34
|
+
const projectRoot = projectRootFromWorktreePath(resolve(basePath));
|
|
35
|
+
if (projectRoot) {
|
|
46
36
|
return join(projectRoot, ".gsd", CAPTURES_FILENAME);
|
|
47
37
|
}
|
|
48
38
|
return join(gsdRoot(basePath), CAPTURES_FILENAME);
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// File Purpose: Closeout git failure discovery, retry, and manual resolution helpers.
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
4
|
import { existsSync, realpathSync } from "node:fs";
|
|
5
|
-
import { isAbsolute,
|
|
5
|
+
import { isAbsolute, resolve } from "node:path";
|
|
6
6
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
7
7
|
import { runTurnGitAction } from "./git-service.js";
|
|
8
8
|
import { _getAdapter, upsertTurnGitTransaction } from "./gsd-db.js";
|
|
9
9
|
import { probeGitConflictState } from "./git-conflict-state.js";
|
|
10
10
|
import { parseUnitId } from "./unit-id.js";
|
|
11
|
+
import { worktreePathFor } from "./worktree-placement.js";
|
|
11
12
|
function parseMetadata(value) {
|
|
12
13
|
if (typeof value !== "string" || !value.trim())
|
|
13
14
|
return {};
|
|
@@ -121,7 +122,7 @@ export function resolveCloseoutRecoveryBasePath(projectRoot, record) {
|
|
|
121
122
|
const parsed = parseUnitId(record.unitId);
|
|
122
123
|
const milestoneId = parsed.milestone ?? (/^M\d+(?:-[a-z0-9]{6})?/.exec(record.unitId)?.[0] ?? "");
|
|
123
124
|
if (milestoneId) {
|
|
124
|
-
const worktreePath = existingRealPath(
|
|
125
|
+
const worktreePath = existingRealPath(worktreePathFor(projectRoot, milestoneId));
|
|
125
126
|
if (worktreePath)
|
|
126
127
|
return worktreePath;
|
|
127
128
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
-
import { join
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
import { loadRegistry } from "../workflow-templates.js";
|
|
4
4
|
import { gsdHome } from "../gsd-home.js";
|
|
5
|
+
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
5
6
|
import { VISUAL_BRIEF_MODES } from "../../visual-brief/prompts.js";
|
|
6
7
|
export const GSD_COMMAND_DESCRIPTION = "GSD — Git Ship Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|brief|report|queue|quick|discuss|capture|triage|dispatch|verdict|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|closeout|rebuild|model|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|debug|logs|forensics|changelog|migrate|remote|steer|knowledge|memory|new-milestone|new-project|parallel|cmux|park|unpark|init|setup|onboarding|inspect|extensions|update|upgrade|fast|mcp|rethink|workflow|codebase|notifications|ship|do|usage|context|session-report|backlog|pr-branch|add-tests|scan|language|worktree|eval-review";
|
|
7
8
|
export const TOP_LEVEL_SUBCOMMANDS = [
|
|
@@ -380,70 +381,13 @@ function getExtensionCompletions(prefix, action) {
|
|
|
380
381
|
return [];
|
|
381
382
|
}
|
|
382
383
|
}
|
|
383
|
-
function normalizePathForCompare(path) {
|
|
384
|
-
return path.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
385
|
-
}
|
|
386
|
-
function findWorktreeSegment(normalizedPath) {
|
|
387
|
-
const directMarker = "/.gsd/worktrees/";
|
|
388
|
-
const directIdx = normalizedPath.indexOf(directMarker);
|
|
389
|
-
if (directIdx !== -1) {
|
|
390
|
-
return { gsdIdx: directIdx, afterWorktrees: directIdx + directMarker.length };
|
|
391
|
-
}
|
|
392
|
-
const symlinkMatch = normalizedPath.match(/\/\.gsd\/projects\/[a-f0-9]+\/worktrees\//);
|
|
393
|
-
if (symlinkMatch?.index !== undefined) {
|
|
394
|
-
return { gsdIdx: symlinkMatch.index, afterWorktrees: symlinkMatch.index + symlinkMatch[0].length };
|
|
395
|
-
}
|
|
396
|
-
return null;
|
|
397
|
-
}
|
|
398
|
-
function resolveProjectRootFromGitFile(worktreePath) {
|
|
399
|
-
try {
|
|
400
|
-
let dir = worktreePath;
|
|
401
|
-
for (let i = 0; i < 30; i++) {
|
|
402
|
-
const gitPath = join(dir, ".git");
|
|
403
|
-
if (existsSync(gitPath)) {
|
|
404
|
-
const content = readFileSync(gitPath, "utf8").trim();
|
|
405
|
-
if (content.startsWith("gitdir: ")) {
|
|
406
|
-
const gitDir = resolve(dir, content.slice(8));
|
|
407
|
-
const dotGitDir = resolve(gitDir, "..", "..");
|
|
408
|
-
if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
|
|
409
|
-
return resolve(dotGitDir, "..");
|
|
410
|
-
}
|
|
411
|
-
const commonDirPath = join(gitDir, "commondir");
|
|
412
|
-
if (existsSync(commonDirPath)) {
|
|
413
|
-
const commonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
414
|
-
return resolve(resolve(gitDir, commonDir), "..");
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
break;
|
|
418
|
-
}
|
|
419
|
-
const parent = resolve(dir, "..");
|
|
420
|
-
if (parent === dir)
|
|
421
|
-
break;
|
|
422
|
-
dir = parent;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
catch {
|
|
426
|
-
// Completion must stay best-effort.
|
|
427
|
-
}
|
|
428
|
-
return null;
|
|
429
|
-
}
|
|
430
384
|
function resolveProjectRootForCompletion(basePath) {
|
|
385
|
+
// Completion honors GSD_PROJECT_ROOT unconditionally (worker processes may
|
|
386
|
+
// complete from any cwd); resolveWorktreeProjectRoot only honors it for
|
|
387
|
+
// worktree paths.
|
|
431
388
|
if (process.env.GSD_PROJECT_ROOT)
|
|
432
389
|
return process.env.GSD_PROJECT_ROOT;
|
|
433
|
-
|
|
434
|
-
const segment = findWorktreeSegment(normalizedPath);
|
|
435
|
-
if (!segment)
|
|
436
|
-
return basePath;
|
|
437
|
-
const separator = basePath.includes("\\") ? "\\" : "/";
|
|
438
|
-
const gsdMarker = `${separator}.gsd${separator}`;
|
|
439
|
-
const gsdIdx = basePath.indexOf(gsdMarker);
|
|
440
|
-
const candidate = gsdIdx !== -1 ? basePath.slice(0, gsdIdx) : basePath.slice(0, segment.gsdIdx);
|
|
441
|
-
const normalizedGsdHome = normalizePathForCompare(gsdHome());
|
|
442
|
-
const candidateGsdPath = normalizePathForCompare(join(candidate, ".gsd"));
|
|
443
|
-
if (candidateGsdPath === normalizedGsdHome || candidateGsdPath.startsWith(`${normalizedGsdHome}/`)) {
|
|
444
|
-
return resolveProjectRootFromGitFile(basePath) ?? basePath;
|
|
445
|
-
}
|
|
446
|
-
return candidate;
|
|
390
|
+
return resolveWorktreeProjectRoot(basePath);
|
|
447
391
|
}
|
|
448
392
|
export function getGsdArgumentCompletions(prefix) {
|
|
449
393
|
const hasTrailingSpace = prefix.endsWith(" ");
|
|
@@ -29,6 +29,7 @@ import { markLatestActiveForWorkerCanceled } from "./db/unit-dispatches.js";
|
|
|
29
29
|
import { getRuntimeKv, setRuntimeKv, deleteRuntimeKv } from "./db/runtime-kv.js";
|
|
30
30
|
import { _getAdapter, isDbAvailable } from "./gsd-db.js";
|
|
31
31
|
import { gsdRoot, normalizeRealPath } from "./paths.js";
|
|
32
|
+
import { crashResumeHint } from "./guidance.js";
|
|
32
33
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
33
34
|
import { effectiveLockFile } from "./session-lock.js";
|
|
34
35
|
import { isInFlightRuntimePhase, listUnitRuntimeRecords } from "./unit-runtime.js";
|
|
@@ -289,18 +290,9 @@ export function formatCrashInfo(lock) {
|
|
|
289
290
|
` Started at: ${lock.unitStartedAt}`,
|
|
290
291
|
` PID: ${lock.pid}`,
|
|
291
292
|
];
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
else if (lock.unitType.includes("research") || lock.unitType.includes("plan")) {
|
|
296
|
-
lines.push(`The ${lock.unitType} unit may be incomplete. Run /gsd auto to re-run it.`);
|
|
297
|
-
}
|
|
298
|
-
else if (lock.unitType.includes("execute")) {
|
|
299
|
-
lines.push(`Task execution was interrupted. Run /gsd auto to resume — completed work is preserved.`);
|
|
300
|
-
}
|
|
301
|
-
else if (lock.unitType.includes("complete")) {
|
|
302
|
-
lines.push(`Slice/milestone completion was interrupted. Run /gsd auto to finish.`);
|
|
303
|
-
}
|
|
293
|
+
const hint = crashResumeHint(lock.unitType, lock.unitId);
|
|
294
|
+
if (hint)
|
|
295
|
+
lines.push(hint);
|
|
304
296
|
return lines.join("\n");
|
|
305
297
|
}
|
|
306
298
|
/**
|