@opengsd/gsd-pi 1.2.0-dev.4c756166 → 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 +9 -9
- 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 +9 -9
- 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/models.generated.d.ts +294 -239
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +260 -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/{DUFWcMFRH3iXh7d2fbrOF → 2p9Rv9pQflAxCBbGVI2vb}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{DUFWcMFRH3iXh7d2fbrOF → 2p9Rv9pQflAxCBbGVI2vb}/_ssgManifest.js +0 -0
|
@@ -43,10 +43,8 @@ import {
|
|
|
43
43
|
} from "../error-classifier.js";
|
|
44
44
|
import { blockModel, isModelBlocked } from "../blocked-models.js";
|
|
45
45
|
import { getProjectGSDPreferencesPath } from "../preferences.js";
|
|
46
|
-
import {
|
|
47
|
-
|
|
48
|
-
resolveProviderErrorGuidance,
|
|
49
|
-
} from "../provider-error-guidance.js";
|
|
46
|
+
import { resolveProviderErrorGuidance } from "../provider-error-guidance.js";
|
|
47
|
+
import { formatGuidance } from "../guidance.js";
|
|
50
48
|
|
|
51
49
|
const retryState = createRetryState();
|
|
52
50
|
const MAX_NETWORK_RETRIES = 2;
|
|
@@ -627,7 +625,7 @@ export async function handleAgentEnd(
|
|
|
627
625
|
preferencesPath: dash.basePath ? getProjectGSDPreferencesPath(dash.basePath) : undefined,
|
|
628
626
|
hasConfiguredFallbacks: (modelConfig?.fallbacks.length ?? 0) > 0,
|
|
629
627
|
});
|
|
630
|
-
const guidanceText =
|
|
628
|
+
const guidanceText = formatGuidance(guidance);
|
|
631
629
|
|
|
632
630
|
await pauseForProviderModelRejection(ctx, pi, {
|
|
633
631
|
errorDetail,
|
|
@@ -12,6 +12,7 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
12
12
|
import { openWorkflowDatabase } from "../db-workspace.js";
|
|
13
13
|
import { getAutoWorktreePath } from "../auto-worktree.js";
|
|
14
14
|
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
15
|
+
import { worktreesDirs } from "../worktree-placement.js";
|
|
15
16
|
|
|
16
17
|
export function safeWorkspaceCwd(): string {
|
|
17
18
|
try {
|
|
@@ -46,13 +47,15 @@ export function resolveWorkflowToolBasePath(
|
|
|
46
47
|
const worktree = getAutoWorktreePath(projectRoot, milestoneId);
|
|
47
48
|
if (worktree) return worktree;
|
|
48
49
|
} else {
|
|
49
|
-
const
|
|
50
|
-
|
|
50
|
+
const live: string[] = [];
|
|
51
|
+
for (const worktreesDir of worktreesDirs(projectRoot)) {
|
|
52
|
+
if (!existsSync(worktreesDir)) continue;
|
|
51
53
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
live.push(
|
|
55
|
+
...readdirSync(worktreesDir)
|
|
56
|
+
.map((name) => join(worktreesDir, name))
|
|
57
|
+
.filter((p) => existsSync(join(p, ".git"))),
|
|
58
|
+
);
|
|
56
59
|
} catch (err) {
|
|
57
60
|
logWarning(
|
|
58
61
|
"bootstrap",
|
|
@@ -60,6 +63,7 @@ export function resolveWorkflowToolBasePath(
|
|
|
60
63
|
);
|
|
61
64
|
}
|
|
62
65
|
}
|
|
66
|
+
if (live.length === 1) return live[0]!;
|
|
63
67
|
}
|
|
64
68
|
return cwd;
|
|
65
69
|
}
|
|
@@ -13,7 +13,7 @@ import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-exten
|
|
|
13
13
|
import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
|
|
14
14
|
|
|
15
15
|
import { buildMilestoneFileName, clearPathCache, milestonesDir, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
|
|
16
|
-
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";
|
|
16
|
+
import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, loadWriteGateSnapshot, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
|
|
17
17
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
18
18
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
19
19
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
@@ -40,6 +40,7 @@ import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecor
|
|
|
40
40
|
import { parseUnitId } from "../unit-id.js";
|
|
41
41
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
42
42
|
import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
43
|
+
import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
|
|
43
44
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
44
45
|
import { initNotificationStore } from "../notification-store.js";
|
|
45
46
|
import { initNotificationWidget } from "../notification-widget.js";
|
|
@@ -61,6 +62,8 @@ import { filterToolsForProvider } from "../model-router.js";
|
|
|
61
62
|
import { mcpToolMatchesBaseName } from "../mcp-tool-name.js";
|
|
62
63
|
import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
|
|
63
64
|
import { supportsSourceObservationsForUnit } from "../source-observations.js";
|
|
65
|
+
import { clearPendingAutoStart } from "../pending-auto-start.js";
|
|
66
|
+
import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
|
|
64
67
|
|
|
65
68
|
let approvalQuestionAbortInFlight = false;
|
|
66
69
|
|
|
@@ -572,8 +575,13 @@ function isShellExecutionTool(canonicalName: string): boolean {
|
|
|
572
575
|
|
|
573
576
|
function activateDeferredApprovalGate(basePath: string): void {
|
|
574
577
|
if (deferredApprovalGate?.basePath !== basePath) return;
|
|
575
|
-
|
|
578
|
+
const gateId = deferredApprovalGate.gateId;
|
|
576
579
|
deferredApprovalGate = null;
|
|
580
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
581
|
+
const milestoneId = extractDepthVerificationMilestoneId(gateId);
|
|
582
|
+
if (isApprovalGateVerifiedInSnapshot(snapshot, gateId)) return;
|
|
583
|
+
if (milestoneId && isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId)) return;
|
|
584
|
+
setPendingGate(gateId, basePath);
|
|
577
585
|
}
|
|
578
586
|
|
|
579
587
|
function extractGateQuestionId(input: unknown): string | undefined {
|
|
@@ -593,6 +601,26 @@ function isContextDraftSummarySave(toolName: string, input: unknown): boolean {
|
|
|
593
601
|
return (input as { artifact_type?: unknown }).artifact_type === "CONTEXT-DRAFT";
|
|
594
602
|
}
|
|
595
603
|
|
|
604
|
+
/**
|
|
605
|
+
* External engines (claude-code-cli) deliver ask_user_questions results as
|
|
606
|
+
* relayed MCP tool results: the structured round payload arrives in
|
|
607
|
+
* `result.structuredContent`, not in pi-native `event.details`. Without this
|
|
608
|
+
* fallback, applyAskUserQuestionsGateResult sees no response for an answered
|
|
609
|
+
* gate question and lands in the "waiting" branch — leaving a re-armed gate
|
|
610
|
+
* permanently pending and the discuss→auto handoff blocked.
|
|
611
|
+
*/
|
|
612
|
+
function resolveAskUserQuestionsGateDetails(event: { details?: unknown; result?: unknown }): any {
|
|
613
|
+
const hasRoundShape = (value: any): boolean =>
|
|
614
|
+
!!value && typeof value === "object" &&
|
|
615
|
+
(value.cancelled !== undefined || value.response !== undefined);
|
|
616
|
+
|
|
617
|
+
const details = event.details as any;
|
|
618
|
+
if (hasRoundShape(details)) return details;
|
|
619
|
+
const structured = (event.result as { structuredContent?: unknown } | undefined)?.structuredContent;
|
|
620
|
+
if (hasRoundShape(structured)) return structured;
|
|
621
|
+
return details ?? {};
|
|
622
|
+
}
|
|
623
|
+
|
|
596
624
|
type StructuredQuestion = {
|
|
597
625
|
id?: string;
|
|
598
626
|
header?: string;
|
|
@@ -802,7 +830,7 @@ export function registerHooks(
|
|
|
802
830
|
}
|
|
803
831
|
});
|
|
804
832
|
|
|
805
|
-
pi.on("session_switch", async (
|
|
833
|
+
pi.on("session_switch", async (event, ctx) => {
|
|
806
834
|
const basePath = contextBasePath(ctx);
|
|
807
835
|
const preserveCloseoutSurface = isAutoCompletionStopInProgress();
|
|
808
836
|
initSessionNotifications(ctx);
|
|
@@ -811,6 +839,13 @@ export function registerHooks(
|
|
|
811
839
|
clearDeferredApprovalGate();
|
|
812
840
|
await resetAskUserQuestionsTurnCache();
|
|
813
841
|
clearDiscussionFlowState(basePath);
|
|
842
|
+
// /clear or /new destroys the conversation holding a discuss interview, so
|
|
843
|
+
// its pending discuss→auto handoff can never be answered — clear it. Resume
|
|
844
|
+
// restores the interview transcript, so the entry survives. Auto-mode's own
|
|
845
|
+
// newSession() calls are safe: the handoff consumes the entry on agent_end.
|
|
846
|
+
if (event.reason === "new") {
|
|
847
|
+
clearPendingAutoStart(basePath);
|
|
848
|
+
}
|
|
814
849
|
await syncServiceTierStatus(ctx);
|
|
815
850
|
await applyDisabledModelProviderPolicy(ctx);
|
|
816
851
|
await applyCompactionThresholdOverride(ctx);
|
|
@@ -1368,13 +1403,27 @@ export function registerHooks(
|
|
|
1368
1403
|
} else if (isAutoActive()) {
|
|
1369
1404
|
clearToolInvocationError();
|
|
1370
1405
|
}
|
|
1406
|
+
// Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
|
|
1407
|
+
// own units; interactive completions get the durable git subset (commit +
|
|
1408
|
+
// Closeout Git Verdict) instead of silently bypassing git.isolation.
|
|
1409
|
+
if (!event.isError && !isAutoActive() && isUnitCloseoutTool(toolName)) {
|
|
1410
|
+
try {
|
|
1411
|
+
runInteractiveUnitCloseout({
|
|
1412
|
+
basePath: resolveWorkflowToolBasePath(ctx, event.input as { milestone_id?: string }),
|
|
1413
|
+
canonicalToolName: toolName,
|
|
1414
|
+
input: event.input,
|
|
1415
|
+
});
|
|
1416
|
+
} catch (err) {
|
|
1417
|
+
safetyLogWarning("engine", `interactive unit closeout failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1371
1420
|
if (toolName !== "ask_user_questions") return;
|
|
1372
1421
|
const basePath = contextBasePath(ctx);
|
|
1373
1422
|
const milestoneId = await getDiscussionMilestoneIdFor(basePath);
|
|
1374
1423
|
|
|
1375
|
-
const details = event
|
|
1424
|
+
const details = resolveAskUserQuestionsGateDetails(event);
|
|
1376
1425
|
|
|
1377
|
-
const questions: any[] = (event.input as any)?.questions ?? [];
|
|
1426
|
+
const questions: any[] = (event.input as any)?.questions ?? details?.questions ?? [];
|
|
1378
1427
|
const gateResult = applyAskUserQuestionsGateResult({
|
|
1379
1428
|
basePath,
|
|
1380
1429
|
questions,
|
|
@@ -1415,10 +1464,42 @@ export function registerHooks(
|
|
|
1415
1464
|
if (toolName === "ask_user_questions") {
|
|
1416
1465
|
const questionId = extractGateQuestionId(event.args);
|
|
1417
1466
|
if (typeof questionId === "string") {
|
|
1418
|
-
|
|
1467
|
+
// External engines (claude-code-cli) ingest the SDK turn's tool blocks
|
|
1468
|
+
// post-hoc, so this event can fire AFTER the workflow MCP child already
|
|
1469
|
+
// verified this gate and allowed the CONTEXT save. setPendingGate also
|
|
1470
|
+
// revokes verifiedDepthMilestones/verifiedApprovalGates, so an
|
|
1471
|
+
// unconditional re-arm here wipes the child's verification and leaves
|
|
1472
|
+
// the discuss→auto handoff permanently blocked. Skip the re-arm when
|
|
1473
|
+
// the snapshot already records this exact gate as verified — mirrors
|
|
1474
|
+
// activateDeferredApprovalGate's guard. Stale verified state cannot
|
|
1475
|
+
// leak into a later re-discussion: a successful handoff deletes the
|
|
1476
|
+
// snapshot via clearDiscussionFlowState.
|
|
1477
|
+
const snapshot = refreshWriteGateStateFromDisk(basePath);
|
|
1478
|
+
const gateMilestoneId = extractDepthVerificationMilestoneId(questionId);
|
|
1479
|
+
const alreadyVerified =
|
|
1480
|
+
isApprovalGateVerifiedInSnapshot(snapshot, questionId) ||
|
|
1481
|
+
isMilestoneDepthVerifiedInSnapshot(snapshot, gateMilestoneId);
|
|
1482
|
+
if (!alreadyVerified) {
|
|
1483
|
+
setPendingGate(questionId, basePath);
|
|
1484
|
+
}
|
|
1419
1485
|
clearDeferredApprovalGate(basePath);
|
|
1420
1486
|
}
|
|
1421
1487
|
}
|
|
1488
|
+
|
|
1489
|
+
// Safety harness: record evidence here, not only in tool_call. External
|
|
1490
|
+
// engines (claude-code-cli) pre-execute tools, so the agent loop skips
|
|
1491
|
+
// beforeToolCall/tool_call for them — tool_execution_start is the only
|
|
1492
|
+
// event that fires for every tool call. recordToolCall dedupes by
|
|
1493
|
+
// toolCallId, so native tools (which hit both events) record once.
|
|
1494
|
+
safetyRecordToolCall(event.toolCallId, event.toolName, (event.args ?? {}) as Record<string, unknown>);
|
|
1495
|
+
const execDash = getAutoRuntimeSnapshot();
|
|
1496
|
+
if (execDash.basePath && execDash.currentUnit?.type === "execute-task") {
|
|
1497
|
+
const { milestone: xMid, slice: xSid, task: xTid } = parseUnitId(execDash.currentUnit.id);
|
|
1498
|
+
if (xMid && xSid && xTid) {
|
|
1499
|
+
saveEvidenceToDisk(execDash.basePath, xMid, xSid, xTid);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1422
1503
|
if (!isAutoActive()) return;
|
|
1423
1504
|
markToolStart(event.toolCallId, event.toolName);
|
|
1424
1505
|
});
|
|
@@ -10,6 +10,7 @@ import { getIsolationMode } from "../preferences.js";
|
|
|
10
10
|
import { compileSubagentPermissionContract, type ToolsPolicy } from "../unit-context-manifest.js";
|
|
11
11
|
import { logWarning } from "../workflow-logger.js";
|
|
12
12
|
import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
13
|
+
import { worktreesDirs } from "../worktree-placement.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Regex matching milestone CONTEXT.md file names in both legacy M001
|
|
@@ -244,6 +245,27 @@ export function loadWriteGateSnapshot(basePath: string): WriteGateSnapshot {
|
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Merge the persisted write-gate snapshot into the in-process Map entry.
|
|
250
|
+
* The workflow MCP server runs in a child process and records depth
|
|
251
|
+
* verification there; without this refresh the extension host keeps stale
|
|
252
|
+
* pending-gate memory and `activateDeferredApprovalGate` can re-arm a gate
|
|
253
|
+
* that the subprocess already cleared on disk.
|
|
254
|
+
*
|
|
255
|
+
* Returns the snapshot used for the refresh so callers that need to inspect
|
|
256
|
+
* it (e.g. re-arm guards) avoid a second disk read.
|
|
257
|
+
*/
|
|
258
|
+
export function refreshWriteGateStateFromDisk(basePath: string): WriteGateSnapshot {
|
|
259
|
+
const snapshot = loadWriteGateSnapshot(basePath);
|
|
260
|
+
if (!shouldPersistWriteGateSnapshot()) return snapshot;
|
|
261
|
+
const state = getWriteGateState(basePath);
|
|
262
|
+
state.pendingGateId = snapshot.pendingGateId;
|
|
263
|
+
state.activeQueuePhase = snapshot.activeQueuePhase;
|
|
264
|
+
state.verifiedDepthMilestones = new Set(snapshot.verifiedDepthMilestones);
|
|
265
|
+
state.verifiedApprovalGates = new Set(snapshot.verifiedApprovalGates ?? []);
|
|
266
|
+
return snapshot;
|
|
267
|
+
}
|
|
268
|
+
|
|
247
269
|
export function isDepthVerified(basePath: string = process.cwd()): boolean {
|
|
248
270
|
return getWriteGateState(basePath).verifiedDepthMilestones.size > 0;
|
|
249
271
|
}
|
|
@@ -256,6 +278,7 @@ export function isMilestoneDepthVerified(
|
|
|
256
278
|
basePath: string = process.cwd(),
|
|
257
279
|
): boolean {
|
|
258
280
|
if (!milestoneId) return false;
|
|
281
|
+
refreshWriteGateStateFromDisk(basePath);
|
|
259
282
|
return getWriteGateState(basePath).verifiedDepthMilestones.has(milestoneId);
|
|
260
283
|
}
|
|
261
284
|
|
|
@@ -357,6 +380,7 @@ export function clearPendingGate(basePath: string): void {
|
|
|
357
380
|
* Get the currently pending gate, if any.
|
|
358
381
|
*/
|
|
359
382
|
export function getPendingGate(basePath: string = process.cwd()): string | null {
|
|
383
|
+
refreshWriteGateStateFromDisk(basePath);
|
|
360
384
|
return getWriteGateState(basePath).pendingGateId;
|
|
361
385
|
}
|
|
362
386
|
|
|
@@ -1138,10 +1162,12 @@ export function shouldBlockWorktreeWrite(
|
|
|
1138
1162
|
const realTarget = realpathOrResolve(absTarget);
|
|
1139
1163
|
const realRoot = realpathOrResolve(projectRoot);
|
|
1140
1164
|
const realGsd = realpathOrResolve(join(projectRoot, ".gsd"));
|
|
1141
|
-
const realWorktreesDir = realpathOrResolve(join(projectRoot, ".gsd", "worktrees"));
|
|
1142
1165
|
|
|
1143
|
-
// Allow writes inside
|
|
1144
|
-
|
|
1166
|
+
// Allow writes inside a legitimate worktrees subtree (canonical
|
|
1167
|
+
// .gsd-worktrees/ or legacy .gsd/worktrees/).
|
|
1168
|
+
for (const container of worktreesDirs(projectRoot)) {
|
|
1169
|
+
if (isPathContained(realTarget, realpathOrResolve(container))) return { block: false };
|
|
1170
|
+
}
|
|
1145
1171
|
|
|
1146
1172
|
// Allow writes to .gsd/ planning artifacts, but reject siblings whose name
|
|
1147
1173
|
// starts with "worktrees" (the worktrees-extra prefix trick — case 4).
|
|
@@ -14,3 +14,6 @@ export const QUICK_BRANCH_RE = /^gsd\/quick\//;
|
|
|
14
14
|
|
|
15
15
|
/** Matches GSD-generated workflow template branches, not arbitrary user gsd/* branches. */
|
|
16
16
|
export const WORKFLOW_BRANCH_RE = /^gsd\/(?:hotfix|bugfix|small-feature|refactor|spike|security-audit|dep-upgrade|full-project)\//;
|
|
17
|
+
|
|
18
|
+
/** Auto-mode milestone branch prefix: milestone/<MID>. */
|
|
19
|
+
export const MILESTONE_BRANCH_PREFIX = "milestone/";
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
12
|
-
import { join, resolve
|
|
12
|
+
import { join, resolve } from "node:path";
|
|
13
13
|
import { randomUUID } from "node:crypto";
|
|
14
14
|
import { gsdRoot } from "./paths.js";
|
|
15
|
+
import { projectRootFromWorktreePath } from "./worktree-root.js";
|
|
15
16
|
|
|
16
17
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
17
18
|
|
|
@@ -59,21 +60,9 @@ const VALID_CLASSIFICATIONS: readonly string[] = [
|
|
|
59
60
|
* directory that contains `.gsd/worktrees/` — that's the project root.
|
|
60
61
|
*/
|
|
61
62
|
export function resolveCapturesPath(basePath: string): string {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let idx = resolved.indexOf(worktreeMarker);
|
|
66
|
-
if (idx === -1) {
|
|
67
|
-
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/
|
|
68
|
-
const symlinkRe = new RegExp(
|
|
69
|
-
`\\${sep}\\.gsd\\${sep}projects\\${sep}[a-f0-9]+\\${sep}worktrees\\${sep}`,
|
|
70
|
-
);
|
|
71
|
-
const match = resolved.match(symlinkRe);
|
|
72
|
-
if (match && match.index !== undefined) idx = match.index;
|
|
73
|
-
}
|
|
74
|
-
if (idx !== -1) {
|
|
75
|
-
// basePath is inside a worktree — resolve to project root
|
|
76
|
-
const projectRoot = resolved.slice(0, idx);
|
|
63
|
+
// If basePath is inside a worktree, resolve to the project root.
|
|
64
|
+
const projectRoot = projectRootFromWorktreePath(resolve(basePath));
|
|
65
|
+
if (projectRoot) {
|
|
77
66
|
return join(projectRoot, ".gsd", CAPTURES_FILENAME);
|
|
78
67
|
}
|
|
79
68
|
return join(gsdRoot(basePath), CAPTURES_FILENAME);
|
|
@@ -10,6 +10,7 @@ import { runTurnGitAction, type TurnGitActionMode, type TurnGitActionResult } fr
|
|
|
10
10
|
import { _getAdapter, upsertTurnGitTransaction } from "./gsd-db.js";
|
|
11
11
|
import { probeGitConflictState } from "./git-conflict-state.js";
|
|
12
12
|
import { parseUnitId } from "./unit-id.js";
|
|
13
|
+
import { worktreePathFor } from "./worktree-placement.js";
|
|
13
14
|
|
|
14
15
|
export interface CloseoutFailureRecord {
|
|
15
16
|
traceId: string;
|
|
@@ -156,7 +157,7 @@ export function resolveCloseoutRecoveryBasePath(projectRoot: string, record: Clo
|
|
|
156
157
|
const parsed = parseUnitId(record.unitId);
|
|
157
158
|
const milestoneId = parsed.milestone ?? (/^M\d+(?:-[a-z0-9]{6})?/.exec(record.unitId)?.[0] ?? "");
|
|
158
159
|
if (milestoneId) {
|
|
159
|
-
const worktreePath = existingRealPath(
|
|
160
|
+
const worktreePath = existingRealPath(worktreePathFor(projectRoot, milestoneId));
|
|
160
161
|
if (worktreePath) return worktreePath;
|
|
161
162
|
}
|
|
162
163
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
-
import { join
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
|
|
4
4
|
import { loadRegistry } from "../workflow-templates.js";
|
|
5
5
|
import { gsdHome } from "../gsd-home.js";
|
|
6
|
+
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
6
7
|
import { VISUAL_BRIEF_MODES } from "../../visual-brief/prompts.js";
|
|
7
8
|
|
|
8
9
|
|
|
@@ -396,75 +397,12 @@ function getExtensionCompletions(prefix: string, action: string) {
|
|
|
396
397
|
}
|
|
397
398
|
}
|
|
398
399
|
|
|
399
|
-
function normalizePathForCompare(path: string): string {
|
|
400
|
-
return path.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
function findWorktreeSegment(normalizedPath: string): { gsdIdx: number; afterWorktrees: number } | null {
|
|
404
|
-
const directMarker = "/.gsd/worktrees/";
|
|
405
|
-
const directIdx = normalizedPath.indexOf(directMarker);
|
|
406
|
-
if (directIdx !== -1) {
|
|
407
|
-
return { gsdIdx: directIdx, afterWorktrees: directIdx + directMarker.length };
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const symlinkMatch = normalizedPath.match(/\/\.gsd\/projects\/[a-f0-9]+\/worktrees\//);
|
|
411
|
-
if (symlinkMatch?.index !== undefined) {
|
|
412
|
-
return { gsdIdx: symlinkMatch.index, afterWorktrees: symlinkMatch.index + symlinkMatch[0].length };
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
return null;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function resolveProjectRootFromGitFile(worktreePath: string): string | null {
|
|
419
|
-
try {
|
|
420
|
-
let dir = worktreePath;
|
|
421
|
-
for (let i = 0; i < 30; i++) {
|
|
422
|
-
const gitPath = join(dir, ".git");
|
|
423
|
-
if (existsSync(gitPath)) {
|
|
424
|
-
const content = readFileSync(gitPath, "utf8").trim();
|
|
425
|
-
if (content.startsWith("gitdir: ")) {
|
|
426
|
-
const gitDir = resolve(dir, content.slice(8));
|
|
427
|
-
const dotGitDir = resolve(gitDir, "..", "..");
|
|
428
|
-
if (dotGitDir.endsWith(".git") || dotGitDir.endsWith(".git/") || dotGitDir.endsWith(".git\\")) {
|
|
429
|
-
return resolve(dotGitDir, "..");
|
|
430
|
-
}
|
|
431
|
-
const commonDirPath = join(gitDir, "commondir");
|
|
432
|
-
if (existsSync(commonDirPath)) {
|
|
433
|
-
const commonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
434
|
-
return resolve(resolve(gitDir, commonDir), "..");
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
break;
|
|
438
|
-
}
|
|
439
|
-
const parent = resolve(dir, "..");
|
|
440
|
-
if (parent === dir) break;
|
|
441
|
-
dir = parent;
|
|
442
|
-
}
|
|
443
|
-
} catch {
|
|
444
|
-
// Completion must stay best-effort.
|
|
445
|
-
}
|
|
446
|
-
return null;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
400
|
function resolveProjectRootForCompletion(basePath: string): string {
|
|
401
|
+
// Completion honors GSD_PROJECT_ROOT unconditionally (worker processes may
|
|
402
|
+
// complete from any cwd); resolveWorktreeProjectRoot only honors it for
|
|
403
|
+
// worktree paths.
|
|
450
404
|
if (process.env.GSD_PROJECT_ROOT) return process.env.GSD_PROJECT_ROOT;
|
|
451
|
-
|
|
452
|
-
const normalizedPath = normalizePathForCompare(basePath);
|
|
453
|
-
const segment = findWorktreeSegment(normalizedPath);
|
|
454
|
-
if (!segment) return basePath;
|
|
455
|
-
|
|
456
|
-
const separator = basePath.includes("\\") ? "\\" : "/";
|
|
457
|
-
const gsdMarker = `${separator}.gsd${separator}`;
|
|
458
|
-
const gsdIdx = basePath.indexOf(gsdMarker);
|
|
459
|
-
const candidate = gsdIdx !== -1 ? basePath.slice(0, gsdIdx) : basePath.slice(0, segment.gsdIdx);
|
|
460
|
-
|
|
461
|
-
const normalizedGsdHome = normalizePathForCompare(gsdHome());
|
|
462
|
-
const candidateGsdPath = normalizePathForCompare(join(candidate, ".gsd"));
|
|
463
|
-
if (candidateGsdPath === normalizedGsdHome || candidateGsdPath.startsWith(`${normalizedGsdHome}/`)) {
|
|
464
|
-
return resolveProjectRootFromGitFile(basePath) ?? basePath;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
return candidate;
|
|
405
|
+
return resolveWorktreeProjectRoot(basePath);
|
|
468
406
|
}
|
|
469
407
|
|
|
470
408
|
export function getGsdArgumentCompletions(prefix: string) {
|
|
@@ -39,6 +39,7 @@ import { markLatestActiveForWorkerCanceled, type DispatchStatus } from "./db/uni
|
|
|
39
39
|
import { getRuntimeKv, setRuntimeKv, deleteRuntimeKv } from "./db/runtime-kv.js";
|
|
40
40
|
import { _getAdapter, isDbAvailable } from "./gsd-db.js";
|
|
41
41
|
import { gsdRoot, normalizeRealPath } from "./paths.js";
|
|
42
|
+
import { crashResumeHint } from "./guidance.js";
|
|
42
43
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
43
44
|
import { effectiveLockFile } from "./session-lock.js";
|
|
44
45
|
import { isInFlightRuntimePhase, listUnitRuntimeRecords, type AutoUnitRuntimeRecord } from "./unit-runtime.js";
|
|
@@ -321,15 +322,8 @@ export function formatCrashInfo(lock: LockData): string {
|
|
|
321
322
|
` PID: ${lock.pid}`,
|
|
322
323
|
];
|
|
323
324
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
} else if (lock.unitType.includes("research") || lock.unitType.includes("plan")) {
|
|
327
|
-
lines.push(`The ${lock.unitType} unit may be incomplete. Run /gsd auto to re-run it.`);
|
|
328
|
-
} else if (lock.unitType.includes("execute")) {
|
|
329
|
-
lines.push(`Task execution was interrupted. Run /gsd auto to resume — completed work is preserved.`);
|
|
330
|
-
} else if (lock.unitType.includes("complete")) {
|
|
331
|
-
lines.push(`Slice/milestone completion was interrupted. Run /gsd auto to finish.`);
|
|
332
|
-
}
|
|
325
|
+
const hint = crashResumeHint(lock.unitType, lock.unitId);
|
|
326
|
+
if (hint) lines.push(hint);
|
|
333
327
|
|
|
334
328
|
return lines.join("\n");
|
|
335
329
|
}
|