@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
|
@@ -8,25 +8,27 @@
|
|
|
8
8
|
* manages create, enter, detect, and teardown for auto-mode worktrees.
|
|
9
9
|
*/
|
|
10
10
|
import { existsSync, cpSync, readFileSync, readdirSync, mkdirSync, realpathSync, rmSync, unlinkSync, lstatSync as lstatSyncFn, } from "node:fs";
|
|
11
|
-
import { dirname, isAbsolute, join, relative
|
|
11
|
+
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
12
12
|
import { GSDError, GSD_IO_ERROR, GSD_GIT_ERROR } from "./errors.js";
|
|
13
13
|
import { reconcileWorktreeDb, isDbAvailable, getMilestone, getMilestoneSlices, getSliceTasks, } from "./gsd-db.js";
|
|
14
14
|
import { closeWorkflowDatabase, getWorkflowDatabasePath, openWorkflowDatabasePath, } from "./db-workspace.js";
|
|
15
15
|
import { execFileSync } from "node:child_process";
|
|
16
16
|
import { gsdRoot, resolveGsdPathContract } from "./paths.js";
|
|
17
|
-
import { createWorktree, removeWorktree,
|
|
17
|
+
import { createWorktree, removeWorktree, worktreePath, isInsideWorktreesDir, } from "./worktree-manager.js";
|
|
18
|
+
import { worktreePathFor } from "./worktree-placement.js";
|
|
18
19
|
import { detectWorktreeName, nudgeGitBranchCache, } from "./worktree.js";
|
|
19
|
-
import { isGsdWorktreePath, normalizeWorktreePathForCompare, resolveWorktreeProjectRoot, } from "./worktree-root.js";
|
|
20
|
+
import { isGsdWorktreePath, projectRootFromWorktreePath, normalizeWorktreePathForCompare, resolveWorktreeProjectRoot, } from "./worktree-root.js";
|
|
20
21
|
import { autoResolveSafeConflictPaths } from "./git-conflict-resolve.js";
|
|
21
22
|
import { MergeConflictError, readIntegrationBranch, resolveMilestoneIntegrationBranch, RUNTIME_EXCLUSION_PATHS } from "./git-service.js";
|
|
22
|
-
import {
|
|
23
|
+
import { publishMilestone } from "./publication.js";
|
|
23
24
|
import { debugLog } from "./debug-logger.js";
|
|
24
25
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
26
|
+
import { checkoutBranchWithStashGuard, cleanupConflictState, gsdJsonlFilesWithConflictMarkers, hasConflictMarkers, popStashByRef, removeMergeStateFiles, stashAlreadyExistsFilesFromError, stashRefFromError, } from "./worktree-git-recovery.js";
|
|
25
27
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
26
28
|
import { MILESTONE_ID_RE } from "./milestone-ids.js";
|
|
27
29
|
import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
|
|
28
30
|
import { classifyProject } from "./detection.js";
|
|
29
|
-
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeWorkingTreeStatus, nativeAddAllWithExclusions, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeMergeRegular, nativeConflictFiles, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchForceReset, nativeBranchExists, nativeDiffNumstat, nativeUpdateRef, nativeIsAncestor,
|
|
31
|
+
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeWorkingTreeStatus, nativeAddAllWithExclusions, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeMergeRegular, nativeConflictFiles, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchForceReset, nativeBranchExists, nativeDiffNumstat, nativeUpdateRef, nativeIsAncestor, nativeWorktreeList, nativeLsFiles, } from "./native-git-bridge.js";
|
|
30
32
|
import { CLOSEOUT_CONSISTENCY_BLOCKED_REASON, } from "./closeout-consistency-gate.js";
|
|
31
33
|
import { formatCloseoutProofBlock, proveMilestoneCloseout, } from "./milestone-closeout-proof.js";
|
|
32
34
|
import { gsdHome } from "./gsd-home.js";
|
|
@@ -61,111 +63,6 @@ const ROOT_STATE_FILES = [
|
|
|
61
63
|
// Back-sync (worktree → main) must NEVER overwrite the project root's copy
|
|
62
64
|
// because the project root is authoritative for preferences (#2684).
|
|
63
65
|
];
|
|
64
|
-
/**
|
|
65
|
-
* Pop a stash entry by tracking the unique marker embedded in its message so
|
|
66
|
-
* concurrent stash operations against the same project root cannot cause us to
|
|
67
|
-
* pop the wrong entry.
|
|
68
|
-
*
|
|
69
|
-
* If `stashMarker` is null or no longer present in the stash list (e.g. a
|
|
70
|
-
* concurrent process popped/dropped it), leaves the stash list untouched and
|
|
71
|
-
* returns null.
|
|
72
|
-
*
|
|
73
|
-
* Throws on pop failure so callers can handle conflict cases the same way
|
|
74
|
-
* they would with the prior `git stash pop` form. When throwing after a
|
|
75
|
-
* targeted pop attempt, the error is annotated with the targeted stash ref.
|
|
76
|
-
*
|
|
77
|
-
* (Issue #4980 HIGH-6)
|
|
78
|
-
*/
|
|
79
|
-
function popStashByRef(basePath, stashMarker) {
|
|
80
|
-
let popArg = null;
|
|
81
|
-
if (stashMarker) {
|
|
82
|
-
try {
|
|
83
|
-
const list = execFileSync("git", ["stash", "list", "--format=%gd%x00%s"], {
|
|
84
|
-
cwd: basePath,
|
|
85
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
86
|
-
encoding: "utf-8",
|
|
87
|
-
}).trim().split("\n").filter(Boolean);
|
|
88
|
-
for (const entry of list) {
|
|
89
|
-
const [ref, subject] = entry.split("\0");
|
|
90
|
-
if (ref && subject?.includes(stashMarker)) {
|
|
91
|
-
popArg = ref;
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
catch (err) {
|
|
97
|
-
logWarning("worktree", `stash list lookup failed; leaving stash untouched: ${err instanceof Error ? err.message : String(err)}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (!popArg) {
|
|
101
|
-
logWarning("worktree", "recorded stash entry could not be resolved; skipping automatic pop");
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
execFileSync("git", ["stash", "pop", popArg], {
|
|
106
|
-
cwd: basePath,
|
|
107
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
108
|
-
encoding: "utf-8",
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
if (err && typeof err === "object") {
|
|
113
|
-
err.stashRef = popArg;
|
|
114
|
-
}
|
|
115
|
-
throw err;
|
|
116
|
-
}
|
|
117
|
-
return popArg;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Extract a stash ref annotation injected by popStashByRef() when git stash
|
|
121
|
-
* pop fails and we need to conditionally drop the exact stash entry later.
|
|
122
|
-
*/
|
|
123
|
-
function stashRefFromError(err) {
|
|
124
|
-
if (!err || typeof err !== "object")
|
|
125
|
-
return null;
|
|
126
|
-
const stashRef = err.stashRef;
|
|
127
|
-
return typeof stashRef === "string" && stashRef.length > 0 ? stashRef : null;
|
|
128
|
-
}
|
|
129
|
-
function stashAlreadyExistsFilesFromError(err) {
|
|
130
|
-
if (!err || typeof err !== "object")
|
|
131
|
-
return [];
|
|
132
|
-
const stderr = err.stderr;
|
|
133
|
-
const stderrText = typeof stderr === "string"
|
|
134
|
-
? stderr
|
|
135
|
-
: stderr instanceof Uint8Array
|
|
136
|
-
? Buffer.from(stderr).toString("utf-8")
|
|
137
|
-
: "";
|
|
138
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
139
|
-
const text = `${stderrText}\n${message}`;
|
|
140
|
-
const files = new Set();
|
|
141
|
-
for (const line of text.split("\n")) {
|
|
142
|
-
const m = line.match(/^(.*?)\s+already exists, no checkout\s*$/i);
|
|
143
|
-
if (!m)
|
|
144
|
-
continue;
|
|
145
|
-
const filePath = m[1]?.trim();
|
|
146
|
-
if (filePath)
|
|
147
|
-
files.add(filePath);
|
|
148
|
-
}
|
|
149
|
-
return [...files];
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Detect whether an on-disk file still contains unresolved merge conflict
|
|
153
|
-
* markers from a failed stash-pop or merge attempt.
|
|
154
|
-
*
|
|
155
|
-
* Returns false when the file cannot be read.
|
|
156
|
-
*/
|
|
157
|
-
function hasConflictMarkers(filePath) {
|
|
158
|
-
try {
|
|
159
|
-
const content = readFileSync(filePath, "utf-8");
|
|
160
|
-
return content.includes("<<<<<<<") && content.includes("=======") && content.includes(">>>>>>>");
|
|
161
|
-
}
|
|
162
|
-
catch {
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function gsdJsonlFilesWithConflictMarkers(basePath) {
|
|
167
|
-
return nativeLsFiles(basePath, ".gsd/*.jsonl").filter((f) => hasConflictMarkers(join(basePath, f)));
|
|
168
|
-
}
|
|
169
66
|
/**
|
|
170
67
|
* Check if two filesystem paths resolve to the same real location.
|
|
171
68
|
* Returns false if either path cannot be resolved (e.g. doesn't exist).
|
|
@@ -286,19 +183,6 @@ function gitPathspecForWorktreePath(basePath, targetPath) {
|
|
|
286
183
|
export function _gitPathspecForWorktreePath(basePath, targetPath) {
|
|
287
184
|
return gitPathspecForWorktreePath(basePath, targetPath);
|
|
288
185
|
}
|
|
289
|
-
function gitRemoteExists(basePath, remote) {
|
|
290
|
-
try {
|
|
291
|
-
execFileSync("git", ["remote", "get-url", remote], {
|
|
292
|
-
cwd: basePath,
|
|
293
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
294
|
-
encoding: "utf-8",
|
|
295
|
-
});
|
|
296
|
-
return true;
|
|
297
|
-
}
|
|
298
|
-
catch {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
186
|
function findRegularMergeChangedPaths(basePath, milestoneBranch, mainBranch) {
|
|
303
187
|
const changedPaths = new Set();
|
|
304
188
|
let mergeLog = "";
|
|
@@ -421,51 +305,6 @@ export const SAFE_AUTO_RESOLVE_PATTERNS = [
|
|
|
421
305
|
* Covers `.gsd/` state files and common build artifacts. */
|
|
422
306
|
export const isSafeToAutoResolve = (filePath) => filePath.startsWith(".gsd/") ||
|
|
423
307
|
SAFE_AUTO_RESOLVE_PATTERNS.some((re) => re.test(filePath));
|
|
424
|
-
function removeMergeStateFiles(basePath, contextLabel) {
|
|
425
|
-
try {
|
|
426
|
-
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_MODE", "MERGE_HEAD", "AUTO_MERGE"]) {
|
|
427
|
-
const rawPath = execFileSync("git", ["rev-parse", "--git-path", f], {
|
|
428
|
-
cwd: basePath,
|
|
429
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
430
|
-
encoding: "utf-8",
|
|
431
|
-
}).trim();
|
|
432
|
-
const p = rawPath.length > 0
|
|
433
|
-
? (isAbsolute(rawPath) ? rawPath : resolve(basePath, rawPath))
|
|
434
|
-
: join(resolveGitDir(basePath), f);
|
|
435
|
-
if (existsSync(p))
|
|
436
|
-
unlinkSync(p);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
catch (err) {
|
|
440
|
-
logError("worktree", `${contextLabel} merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
function cleanupConflictState(basePath) {
|
|
444
|
-
// Merge conflicts can leave unmerged index entries; merge-abort alone is not
|
|
445
|
-
// enough for squash merges (MERGE_HEAD is never written). Reset the merge
|
|
446
|
-
// index, then remove merge message files that native/libgit2 paths may have
|
|
447
|
-
// created.
|
|
448
|
-
try {
|
|
449
|
-
nativeMergeAbort(basePath);
|
|
450
|
-
}
|
|
451
|
-
catch (err) {
|
|
452
|
-
// MERGE_HEAD absent (squash merge path) — abort is a no-op, which is fine.
|
|
453
|
-
debugLog("conflict-cleanup:merge-abort-skipped", {
|
|
454
|
-
error: err instanceof Error ? err.message : String(err),
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
try {
|
|
458
|
-
execFileSync("git", ["reset", "--merge"], {
|
|
459
|
-
cwd: basePath,
|
|
460
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
461
|
-
encoding: "utf-8",
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
catch (err) {
|
|
465
|
-
logError("worktree", `git reset --merge failed after merge conflict: ${err instanceof Error ? err.message : String(err)}`);
|
|
466
|
-
}
|
|
467
|
-
removeMergeStateFiles(basePath, "conflict");
|
|
468
|
-
}
|
|
469
308
|
// ─── Dispatch-Level Sync (project root ↔ worktree) ──────────────────────────
|
|
470
309
|
/**
|
|
471
310
|
* Sync milestone artifacts from project root INTO worktree before deriveState.
|
|
@@ -539,19 +378,9 @@ export function checkResourcesStale(versionOnStart) {
|
|
|
539
378
|
* Returns the corrected base path.
|
|
540
379
|
*/
|
|
541
380
|
export function escapeStaleWorktree(base) {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
if (idx === -1) {
|
|
546
|
-
// Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/
|
|
547
|
-
const symlinkRe = new RegExp(`\\${pathSep}\\.gsd\\${pathSep}projects\\${pathSep}[a-f0-9]+\\${pathSep}worktrees\\${pathSep}`);
|
|
548
|
-
const match = base.match(symlinkRe);
|
|
549
|
-
if (!match || match.index === undefined)
|
|
550
|
-
return base;
|
|
551
|
-
idx = match.index;
|
|
552
|
-
}
|
|
553
|
-
// base is inside .gsd/worktrees/<something> — extract the project root
|
|
554
|
-
const projectRoot = base.slice(0, idx);
|
|
381
|
+
const projectRoot = projectRootFromWorktreePath(base);
|
|
382
|
+
if (projectRoot === null)
|
|
383
|
+
return base;
|
|
555
384
|
// Guard: If the candidate project root's .gsd IS the user-level ~/.gsd,
|
|
556
385
|
// the string-slice heuristic matched the wrong /.gsd/ boundary. This happens
|
|
557
386
|
// when .gsd is a symlink into ~/.gsd/projects/<hash> and process.cwd()
|
|
@@ -908,109 +737,6 @@ export function enterBranchModeForMilestone(basePath, milestoneId) {
|
|
|
908
737
|
}
|
|
909
738
|
checkoutBranchWithStashGuard(basePath, branch, `enter-branch-mode:${milestoneId}`);
|
|
910
739
|
}
|
|
911
|
-
export function checkoutBranchWithStashGuard(basePath, branch, reason) {
|
|
912
|
-
let stashMarker = null;
|
|
913
|
-
let stashed = false;
|
|
914
|
-
const status = nativeWorkingTreeStatus(basePath).trim();
|
|
915
|
-
if (status.length > 0) {
|
|
916
|
-
stashMarker = `gsd-checkout-stash:${reason}:${process.pid}:${Date.now()}:${process.hrtime.bigint().toString(36)}`;
|
|
917
|
-
const stashListBefore = execFileSync("git", ["stash", "list"], {
|
|
918
|
-
cwd: basePath,
|
|
919
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
920
|
-
encoding: "utf-8",
|
|
921
|
-
});
|
|
922
|
-
execFileSync("git", ["stash", "push", "--include-untracked", "-m", `gsd: checkout stash [${stashMarker}]`], {
|
|
923
|
-
cwd: basePath,
|
|
924
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
925
|
-
encoding: "utf-8",
|
|
926
|
-
});
|
|
927
|
-
const stashListAfter = execFileSync("git", ["stash", "list"], {
|
|
928
|
-
cwd: basePath,
|
|
929
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
930
|
-
encoding: "utf-8",
|
|
931
|
-
});
|
|
932
|
-
stashed = stashListAfter !== stashListBefore;
|
|
933
|
-
}
|
|
934
|
-
// Checkout and stash-restore are split so we can distinguish two failure
|
|
935
|
-
// modes: (a) checkout failed → HEAD did not move, restore stash and rethrow;
|
|
936
|
-
// (b) checkout succeeded but stash pop failed → HEAD moved to `branch` but
|
|
937
|
-
// the working-tree changes remain in the stash list. We surface a distinct
|
|
938
|
-
// error in case (b) so callers don't assume the branch switch was rolled back.
|
|
939
|
-
try {
|
|
940
|
-
nativeCheckoutBranch(basePath, branch);
|
|
941
|
-
}
|
|
942
|
-
catch (checkoutErr) {
|
|
943
|
-
if (stashed) {
|
|
944
|
-
try {
|
|
945
|
-
popStashByRef(basePath, stashMarker);
|
|
946
|
-
}
|
|
947
|
-
catch (restoreErr) {
|
|
948
|
-
logWarning("worktree", `git stash pop failed during checkout restore: ${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)}`);
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
throw checkoutErr;
|
|
952
|
-
}
|
|
953
|
-
if (stashed) {
|
|
954
|
-
try {
|
|
955
|
-
popStashByRef(basePath, stashMarker);
|
|
956
|
-
}
|
|
957
|
-
catch (popErr) {
|
|
958
|
-
const msg = popErr instanceof Error ? popErr.message : String(popErr);
|
|
959
|
-
const stderr = popErr && typeof popErr === "object"
|
|
960
|
-
? popErr.stderr
|
|
961
|
-
: undefined;
|
|
962
|
-
const stderrText = typeof stderr === "string"
|
|
963
|
-
? stderr
|
|
964
|
-
: stderr instanceof Uint8Array
|
|
965
|
-
? Buffer.from(stderr).toString("utf-8")
|
|
966
|
-
: "";
|
|
967
|
-
const stashPopMessage = `${stderrText}\n${msg}`.trim();
|
|
968
|
-
const alreadyExists = stashAlreadyExistsFilesFromError(popErr);
|
|
969
|
-
const gsdAlreadyExists = alreadyExists.filter((f) => f.startsWith(".gsd/"));
|
|
970
|
-
const nonGsdAlreadyExists = alreadyExists.filter((f) => !f.startsWith(".gsd/"));
|
|
971
|
-
const isUntrackedRestoreFailure = stashPopMessage.includes("could not restore untracked files from stash");
|
|
972
|
-
const stashRefForDrop = stashRefFromError(popErr);
|
|
973
|
-
const nonGsdUnmerged = nativeConflictFiles(basePath).filter((f) => !f.startsWith(".gsd/"));
|
|
974
|
-
const gsdContentConflicts = isUntrackedRestoreFailure
|
|
975
|
-
? gsdJsonlFilesWithConflictMarkers(basePath)
|
|
976
|
-
: [];
|
|
977
|
-
const gsdConflictFiles = [...new Set([...gsdAlreadyExists, ...gsdContentConflicts])];
|
|
978
|
-
if (isUntrackedRestoreFailure &&
|
|
979
|
-
gsdConflictFiles.length > 0 &&
|
|
980
|
-
nonGsdAlreadyExists.length === 0 &&
|
|
981
|
-
nonGsdUnmerged.length === 0) {
|
|
982
|
-
for (const f of gsdConflictFiles) {
|
|
983
|
-
execFileSync("git", ["checkout", "HEAD", "--", f], {
|
|
984
|
-
cwd: basePath,
|
|
985
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
986
|
-
encoding: "utf-8",
|
|
987
|
-
});
|
|
988
|
-
nativeAddPaths(basePath, [f]);
|
|
989
|
-
}
|
|
990
|
-
if (stashRefForDrop) {
|
|
991
|
-
try {
|
|
992
|
-
execFileSync("git", ["stash", "drop", stashRefForDrop], {
|
|
993
|
-
cwd: basePath,
|
|
994
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
995
|
-
encoding: "utf-8",
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
|
-
catch (err) { /* stash may already be consumed */
|
|
999
|
-
logWarning("worktree", `git stash drop failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
else {
|
|
1003
|
-
logWarning("worktree", "recorded stash entry could not be resolved; skipping automatic drop");
|
|
1004
|
-
}
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
|
-
const wrapped = new Error(`checkout to '${branch}' succeeded but stash restore failed; working tree changes remain in the stash list. Original error: ${msg}`);
|
|
1008
|
-
if (stashRefForDrop)
|
|
1009
|
-
wrapped.stashRef = stashRefForDrop;
|
|
1010
|
-
throw wrapped;
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
740
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
1015
741
|
/**
|
|
1016
742
|
* Create a new auto-worktree for a milestone, chdir into it, and store
|
|
@@ -1335,7 +1061,9 @@ export function isInAutoWorktree(basePath) {
|
|
|
1335
1061
|
*/
|
|
1336
1062
|
export function getAutoWorktreePath(basePath, milestoneId) {
|
|
1337
1063
|
basePath = resolveWorktreeProjectRoot(basePath);
|
|
1338
|
-
|
|
1064
|
+
// basePath is already the resolved project root — go straight to placement
|
|
1065
|
+
// instead of worktreePath(), which would re-resolve the root.
|
|
1066
|
+
const p = worktreePathFor(basePath, milestoneId);
|
|
1339
1067
|
if (!existsSync(p))
|
|
1340
1068
|
return null;
|
|
1341
1069
|
// Validate this is a real git worktree, not a stray directory.
|
|
@@ -1995,8 +1723,6 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
1995
1723
|
const isUntrackedRestoreFailure = stashPopMessage.includes("could not restore untracked files from stash");
|
|
1996
1724
|
const gsdContentConflicts = [];
|
|
1997
1725
|
const alreadyExists = stashAlreadyExistsFilesFromError(e);
|
|
1998
|
-
const gsdAlreadyExists = alreadyExists.filter((f) => f.startsWith(".gsd/"));
|
|
1999
|
-
const nonGsdAlreadyExists = alreadyExists.filter((f) => !f.startsWith(".gsd/"));
|
|
2000
1726
|
// Untracked-file restore failures can leave marker conflicts in tracked
|
|
2001
1727
|
// .gsd JSONL files without producing `U` status entries.
|
|
2002
1728
|
if (isUntrackedRestoreFailure) {
|
|
@@ -2057,10 +1783,11 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
2057
1783
|
}
|
|
2058
1784
|
else if (gsdUU.length === 0 &&
|
|
2059
1785
|
nonGsdUU.length === 0 &&
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
//
|
|
2063
|
-
//
|
|
1786
|
+
alreadyExists.length > 0) {
|
|
1787
|
+
// Untracked-file restore failure from stash pop where all collided paths
|
|
1788
|
+
// already exist after merge (committed on target). Safe to drop the stash
|
|
1789
|
+
// for the full alreadyExists set — they were untracked on source by
|
|
1790
|
+
// definition of the "already exists, no checkout" failure.
|
|
2064
1791
|
if (stashRefForDrop) {
|
|
2065
1792
|
try {
|
|
2066
1793
|
execFileSync("git", ["stash", "drop", stashRefForDrop], {
|
|
@@ -2083,11 +1810,6 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
2083
1810
|
files: nonGsdUU.join(", "),
|
|
2084
1811
|
});
|
|
2085
1812
|
}
|
|
2086
|
-
else if (nonGsdAlreadyExists.length > 0) {
|
|
2087
|
-
logWarning("reconcile", "Stash pop restore collision on non-.gsd files after merge", {
|
|
2088
|
-
files: nonGsdAlreadyExists.join(", "),
|
|
2089
|
-
});
|
|
2090
|
-
}
|
|
2091
1813
|
else {
|
|
2092
1814
|
logWarning("worktree", "git stash pop failed without resolvable conflict files; leaving stash for manual recovery");
|
|
2093
1815
|
}
|
|
@@ -2182,63 +1904,24 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
2182
1904
|
}
|
|
2183
1905
|
};
|
|
2184
1906
|
let shouldCleanup = false;
|
|
2185
|
-
let pushed = false;
|
|
2186
|
-
let prCreated = false;
|
|
2187
1907
|
try {
|
|
2188
|
-
// 10.
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
}
|
|
2206
|
-
// 9b. Auto-create PR if enabled (#2302: no longer gated on pushed/auto_push)
|
|
2207
|
-
if (prefs.auto_pr === true && !nothingToCommit) {
|
|
2208
|
-
const remote = prefs.remote ?? "origin";
|
|
2209
|
-
const prTarget = prefs.pr_target_branch ?? mainBranch;
|
|
2210
|
-
if (gitRemoteExists(originalBasePath_, remote)) {
|
|
2211
|
-
try {
|
|
2212
|
-
// Push the milestone branch to remote first
|
|
2213
|
-
execFileSync("git", ["push", remote, milestoneBranch], {
|
|
2214
|
-
cwd: originalBasePath_,
|
|
2215
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
2216
|
-
encoding: "utf-8",
|
|
2217
|
-
});
|
|
2218
|
-
const prEvidence = buildPullRequestEvidence({
|
|
2219
|
-
milestoneId,
|
|
2220
|
-
milestoneTitle,
|
|
2221
|
-
changeType: "feat",
|
|
2222
|
-
summaries: completedSlices.map((slice) => `### ${slice.id}\n${slice.title}`),
|
|
2223
|
-
testsRun: ["Auto-created after milestone merge. Run `npm run verify:merge` before marking this draft ready."],
|
|
2224
|
-
rollbackNotes: ["Close the draft PR or revert the merge commit if review finds a behavior regression."],
|
|
2225
|
-
how: "Generated by git.auto_pr after the milestone branch was pushed and merged locally.",
|
|
2226
|
-
});
|
|
2227
|
-
const prUrl = createDraftPullRequestFromEvidence(originalBasePath_, milestoneId, prEvidence, {
|
|
2228
|
-
head: milestoneBranch,
|
|
2229
|
-
base: prTarget,
|
|
2230
|
-
});
|
|
2231
|
-
if (!prUrl) {
|
|
2232
|
-
throw new Error("gh pr create returned no URL");
|
|
2233
|
-
}
|
|
2234
|
-
prCreated = true;
|
|
2235
|
-
}
|
|
2236
|
-
catch (err) {
|
|
2237
|
-
// PR creation failure is non-fatal — gh may not be installed or authenticated
|
|
2238
|
-
logWarning("worktree", `PR creation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2239
|
-
}
|
|
2240
|
-
}
|
|
2241
|
-
}
|
|
1908
|
+
// 10/9b. Publication (auto-push / draft PR) — Publication module seam (ADR-034).
|
|
1909
|
+
const publication = publishMilestone({
|
|
1910
|
+
basePath: originalBasePath_,
|
|
1911
|
+
milestoneId,
|
|
1912
|
+
milestoneTitle,
|
|
1913
|
+
integrationBranch: mainBranch,
|
|
1914
|
+
milestoneBranch,
|
|
1915
|
+
sliceSummaries: completedSlices.map((slice) => `### ${slice.id}\n${slice.title}`),
|
|
1916
|
+
nothingToCommit,
|
|
1917
|
+
prefs: {
|
|
1918
|
+
autoPush: prefs.auto_push === true,
|
|
1919
|
+
autoPr: prefs.auto_pr === true,
|
|
1920
|
+
remote: prefs.remote,
|
|
1921
|
+
prTargetBranch: prefs.pr_target_branch,
|
|
1922
|
+
},
|
|
1923
|
+
});
|
|
1924
|
+
const { pushed, prCreated } = publication;
|
|
2242
1925
|
// 11. Guard removed — step 9b (#1792) now handles this with a smarter check:
|
|
2243
1926
|
// throws only when the milestone has unanchored code changes, passes
|
|
2244
1927
|
// through when the code is genuinely already on the integration branch.
|
|
@@ -25,7 +25,7 @@ import { clearActivityLogState } from "./activity-log.js";
|
|
|
25
25
|
import { synthesizeCrashRecovery, getDeepDiagnostic, readActiveMilestoneId, } from "./session-forensics.js";
|
|
26
26
|
import { writeLock, clearLock, clearStaleWorkerLock, readCrashLock, isLockProcessAlive, formatCrashInfo, emitCrashRecoveredUnitEnd, emitOpenUnitEndForUnit, } from "./crash-recovery.js";
|
|
27
27
|
import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
28
|
-
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, } from "./preferences.js";
|
|
28
|
+
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, resolveEffectiveUnitIsolationMode, } from "./preferences.js";
|
|
29
29
|
import { playNotificationBell, sendDesktopNotification } from "./notifications.js";
|
|
30
30
|
import { getBudgetAlertLevel, getNewBudgetAlertLevel, getBudgetEnforcementAction, resolveCompactionThresholdPercent, shouldRerootStepSessionForContext, } from "./auto-budget.js";
|
|
31
31
|
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, isToolInvocationError, isQueuedUserMessageSkip, isDeterministicPolicyError, } from "./auto-tool-tracking.js";
|
|
@@ -117,6 +117,7 @@ import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
|
117
117
|
import { registerAutoWorker, markWorkerStopping, } from "./db/auto-workers.js";
|
|
118
118
|
import { releaseMilestoneLease } from "./db/milestone-leases.js";
|
|
119
119
|
import { normalizeRealPath } from "./paths.js";
|
|
120
|
+
import { formatStopNoticePrefix, isBlockedStopReason, stopNoticeDisplayReason, } from "./stop-notice.js";
|
|
120
121
|
// ── ENCAPSULATION INVARIANT ─────────────────────────────────────────────────
|
|
121
122
|
// ALL mutable auto-mode state lives in the AutoSession class (auto/session.ts).
|
|
122
123
|
// This file must NOT declare module-level `let` or `var` variables for state.
|
|
@@ -137,17 +138,7 @@ export function formatAutoStopNotification(prefix, totals, unitCount) {
|
|
|
137
138
|
`Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${unitCount} units`,
|
|
138
139
|
].join("\n");
|
|
139
140
|
}
|
|
140
|
-
|
|
141
|
-
return /^Blocked:\s*/i.test(reason ?? "");
|
|
142
|
-
}
|
|
143
|
-
function formatAutoStopDisplayReason(reason) {
|
|
144
|
-
return (reason ?? "").replace(/^Blocked:\s*/i, "").trim();
|
|
145
|
-
}
|
|
146
|
-
export function formatAutoStopNotificationPrefix(reason) {
|
|
147
|
-
const displayReason = formatAutoStopDisplayReason(reason);
|
|
148
|
-
const prefix = isBlockedStopReason(reason) ? "Auto-mode blocked" : "Auto-mode stopped";
|
|
149
|
-
return displayReason ? `${prefix} — ${displayReason}` : prefix;
|
|
150
|
-
}
|
|
141
|
+
export { formatStopNoticePrefix as formatAutoStopNotificationPrefix } from "./stop-notice.js";
|
|
151
142
|
function clearSessionModelOverrideForCommandSession(ctx) {
|
|
152
143
|
const sessionId = s.cmdCtx?.sessionManager?.getSessionId?.() ??
|
|
153
144
|
ctx?.sessionManager?.getSessionId?.();
|
|
@@ -346,14 +337,11 @@ export function startAutoDetached(ctx, pi, base, verboseMode, options) {
|
|
|
346
337
|
export function shouldUseWorktreeIsolation(basePath) {
|
|
347
338
|
return getIsolationMode(basePath) === "worktree";
|
|
348
339
|
}
|
|
349
|
-
function
|
|
350
|
-
return configuredMode
|
|
351
|
-
}
|
|
352
|
-
export function _resolveEffectiveUnitIsolationModeForTest(configuredMode, isolationDegraded) {
|
|
353
|
-
return resolveEffectiveUnitIsolationMode(configuredMode, isolationDegraded);
|
|
340
|
+
export function _resolveEffectiveUnitIsolationModeForTest(configuredMode, isolationDegraded, strandedRecoveryIsolationMode = null) {
|
|
341
|
+
return resolveEffectiveUnitIsolationMode(configuredMode, isolationDegraded, strandedRecoveryIsolationMode);
|
|
354
342
|
}
|
|
355
343
|
function getEffectiveUnitIsolationMode(basePath) {
|
|
356
|
-
return resolveEffectiveUnitIsolationMode(getIsolationMode(basePath), s.isolationDegraded);
|
|
344
|
+
return resolveEffectiveUnitIsolationMode(getIsolationMode(basePath), s.isolationDegraded, s.strandedRecoveryIsolationMode);
|
|
357
345
|
}
|
|
358
346
|
/** Crash recovery prompt — set by startAuto, consumed by the main loop */
|
|
359
347
|
/** Pending verification retry — set when gate fails with retries remaining, consumed by autoLoop */
|
|
@@ -993,8 +981,8 @@ export async function stopAuto(ctx, pi, reason, options = {}) {
|
|
|
993
981
|
if (!s.active && !s.paused)
|
|
994
982
|
return;
|
|
995
983
|
const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
996
|
-
const stopNotificationPrefix =
|
|
997
|
-
const displayReason =
|
|
984
|
+
const stopNotificationPrefix = formatStopNoticePrefix(reason);
|
|
985
|
+
const displayReason = stopNoticeDisplayReason(reason);
|
|
998
986
|
const isHeadlessStop = process.env.GSD_HEADLESS === "1";
|
|
999
987
|
const completionStopRequested = Boolean(options.completionWidget);
|
|
1000
988
|
const preserveCloseoutTranscript = !isHeadlessStop && (options.preserveCloseoutTranscript ?? completionStopRequested);
|
|
@@ -15,7 +15,8 @@ import { resumeAutoAfterProviderDelay } from "./provider-error-resume.js";
|
|
|
15
15
|
import { classifyError, createRetryState, resetRetryState, isTransient, } from "../error-classifier.js";
|
|
16
16
|
import { blockModel, isModelBlocked } from "../blocked-models.js";
|
|
17
17
|
import { getProjectGSDPreferencesPath } from "../preferences.js";
|
|
18
|
-
import {
|
|
18
|
+
import { resolveProviderErrorGuidance } from "../provider-error-guidance.js";
|
|
19
|
+
import { formatGuidance } from "../guidance.js";
|
|
19
20
|
const retryState = createRetryState();
|
|
20
21
|
const MAX_NETWORK_RETRIES = 2;
|
|
21
22
|
function isObjectRecord(value) {
|
|
@@ -486,7 +487,7 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
486
487
|
preferencesPath: dash.basePath ? getProjectGSDPreferencesPath(dash.basePath) : undefined,
|
|
487
488
|
hasConfiguredFallbacks: (modelConfig?.fallbacks.length ?? 0) > 0,
|
|
488
489
|
});
|
|
489
|
-
const guidanceText =
|
|
490
|
+
const guidanceText = formatGuidance(guidance);
|
|
490
491
|
await pauseForProviderModelRejection(ctx, pi, {
|
|
491
492
|
errorDetail,
|
|
492
493
|
rawErrorMsg,
|
|
@@ -9,6 +9,7 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
9
9
|
import { openWorkflowDatabase } from "../db-workspace.js";
|
|
10
10
|
import { getAutoWorktreePath } from "../auto-worktree.js";
|
|
11
11
|
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
12
|
+
import { worktreesDirs } from "../worktree-placement.js";
|
|
12
13
|
export function safeWorkspaceCwd() {
|
|
13
14
|
try {
|
|
14
15
|
return process.cwd();
|
|
@@ -42,19 +43,21 @@ export function resolveWorkflowToolBasePath(ctx, scope) {
|
|
|
42
43
|
return worktree;
|
|
43
44
|
}
|
|
44
45
|
else {
|
|
45
|
-
const
|
|
46
|
-
|
|
46
|
+
const live = [];
|
|
47
|
+
for (const worktreesDir of worktreesDirs(projectRoot)) {
|
|
48
|
+
if (!existsSync(worktreesDir))
|
|
49
|
+
continue;
|
|
47
50
|
try {
|
|
48
|
-
|
|
51
|
+
live.push(...readdirSync(worktreesDir)
|
|
49
52
|
.map((name) => join(worktreesDir, name))
|
|
50
|
-
.filter((p) => existsSync(join(p, ".git")));
|
|
51
|
-
if (live.length === 1)
|
|
52
|
-
return live[0];
|
|
53
|
+
.filter((p) => existsSync(join(p, ".git"))));
|
|
53
54
|
}
|
|
54
55
|
catch (err) {
|
|
55
56
|
logWarning("bootstrap", `resolveWorkflowToolBasePath: failed to scan worktrees: ${err instanceof Error ? err.message : String(err)}`);
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
if (live.length === 1)
|
|
60
|
+
return live[0];
|
|
58
61
|
}
|
|
59
62
|
return cwd;
|
|
60
63
|
}
|