gsd-pi 2.80.0-dev.fbe7c8c6f → 2.81.0-dev.3cddbbba2
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/README.md +47 -59
- package/dist/claude-cli-check.d.ts +30 -0
- package/dist/claude-cli-check.js +18 -7
- package/dist/cli.js +0 -19
- package/dist/headless-query.d.ts +10 -0
- package/dist/headless-query.js +6 -4
- package/dist/loader-entrypoint.d.ts +8 -0
- package/dist/loader-entrypoint.js +27 -0
- package/dist/loader.js +2 -11
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.js +6 -3
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +40 -3
- package/dist/resources/extensions/github-sync/sync.js +4 -1
- package/dist/resources/extensions/gsd/auto/contracts.js +2 -0
- package/dist/resources/extensions/gsd/auto/loop.js +214 -17
- package/dist/resources/extensions/gsd/auto/orchestrator.js +48 -4
- package/dist/resources/extensions/gsd/auto/phases.js +372 -134
- package/dist/resources/extensions/gsd/auto/resolve.js +29 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +88 -33
- package/dist/resources/extensions/gsd/auto/session.js +18 -1
- package/dist/resources/extensions/gsd/auto/unit-runner-events.js +7 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
- package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
- package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +199 -177
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
- package/dist/resources/extensions/gsd/auto-dispatch.js +30 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +119 -79
- package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
- package/dist/resources/extensions/gsd/auto-start.js +251 -16
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
- package/dist/resources/extensions/gsd/auto-verification.js +12 -6
- package/dist/resources/extensions/gsd/auto-worktree.js +237 -336
- package/dist/resources/extensions/gsd/auto.js +493 -129
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +133 -12
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +44 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +30 -20
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +337 -55
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
- package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +19 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
- package/dist/resources/extensions/gsd/commands-config.js +1 -1
- package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
- package/dist/resources/extensions/gsd/context-budget.js +37 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +92 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
- package/dist/resources/extensions/gsd/git-service.js +75 -6
- package/dist/resources/extensions/gsd/gsd-db.js +46 -13
- package/dist/resources/extensions/gsd/guided-flow.js +119 -42
- package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +6 -9
- package/dist/resources/extensions/gsd/init-wizard.js +4 -1
- package/dist/resources/extensions/gsd/memory-store.js +69 -12
- package/dist/resources/extensions/gsd/migrate/command.js +40 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +46 -22
- package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
- package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +22 -17
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/recovery-classification.js +94 -0
- package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
- package/dist/resources/extensions/gsd/state-reconciliation.js +27 -0
- package/dist/resources/extensions/gsd/tool-contract.js +50 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
- package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
- package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
- package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
- package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +1364 -0
- package/dist/resources/extensions/gsd/worktree-safety.js +119 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +317 -0
- package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
- package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
- 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 +13 -13
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +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/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +3 -3
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
- package/dist/welcome-screen.d.ts +2 -7
- package/dist/welcome-screen.js +68 -75
- package/package.json +3 -3
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +9 -2
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +43 -11
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/index.d.ts +1 -0
- package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/index.js +2 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
- package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
- package/packages/pi-agent-core/dist/token-audit.js +221 -0
- package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
- package/packages/pi-agent-core/dist/types.d.ts +31 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-agent-core/src/agent.ts +52 -11
- package/packages/pi-agent-core/src/index.ts +2 -0
- package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
- package/packages/pi-agent-core/src/token-audit.ts +287 -0
- package/packages/pi-agent-core/src/types.ts +26 -10
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
- package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +9 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
- package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
- package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
- package/packages/pi-ai/src/providers/anthropic.ts +22 -9
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
- package/packages/pi-ai/src/types.ts +3 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
- package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
- package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +36 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +30 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +21 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +94 -16
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +6 -2
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +6 -6
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +60 -4
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +81 -4
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
- package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
- package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
- package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
- package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
- package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +161 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +6 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +225 -73
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +31 -6
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +71 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +28 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +40 -1
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +40 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +102 -16
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +6 -2
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
- package/packages/pi-coding-agent/src/core/extensions/types.ts +63 -2
- package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +92 -4
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
- package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
- package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
- package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
- package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
- package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
- package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
- package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
- package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
- package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
- package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
- package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
- package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
- package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +228 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +247 -94
- package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +75 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +39 -8
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +27 -3
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +31 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.js +9 -6
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +18 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
- package/packages/pi-tui/src/overlay-layout.ts +10 -7
- package/packages/pi-tui/src/tui.ts +20 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/README.md +7 -0
- package/packages/rpc-client/package.json +1 -1
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +105 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +27 -26
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +42 -3
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +67 -0
- package/src/resources/extensions/github-sync/sync.ts +8 -1
- package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
- package/src/resources/extensions/gsd/auto/contracts.ts +19 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +19 -16
- package/src/resources/extensions/gsd/auto/loop.ts +247 -25
- package/src/resources/extensions/gsd/auto/orchestrator.ts +52 -4
- package/src/resources/extensions/gsd/auto/phases.ts +512 -202
- package/src/resources/extensions/gsd/auto/resolve.ts +42 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +97 -34
- package/src/resources/extensions/gsd/auto/session.ts +19 -1
- package/src/resources/extensions/gsd/auto/types.ts +3 -0
- package/src/resources/extensions/gsd/auto/unit-runner-events.ts +15 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
- package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
- package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +249 -182
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
- package/src/resources/extensions/gsd/auto-dispatch.ts +31 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +131 -81
- package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +321 -21
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
- package/src/resources/extensions/gsd/auto-verification.ts +12 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +267 -360
- package/src/resources/extensions/gsd/auto.ts +578 -126
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +166 -12
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +45 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +32 -19
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +384 -55
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
- package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -2
- package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
- package/src/resources/extensions/gsd/commands-config.ts +1 -1
- package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
- package/src/resources/extensions/gsd/context-budget.ts +44 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +107 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
- package/src/resources/extensions/gsd/git-service.ts +89 -10
- package/src/resources/extensions/gsd/gsd-db.ts +50 -13
- package/src/resources/extensions/gsd/guided-flow.ts +148 -49
- package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +8 -9
- package/src/resources/extensions/gsd/init-wizard.ts +5 -1
- package/src/resources/extensions/gsd/journal.ts +2 -0
- package/src/resources/extensions/gsd/memory-store.ts +77 -12
- package/src/resources/extensions/gsd/migrate/command.ts +47 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +53 -19
- package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
- package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +22 -17
- package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/recovery-classification.ts +122 -0
- package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
- package/src/resources/extensions/gsd/state-reconciliation.ts +57 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +134 -9
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1125 -215
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +119 -2
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +363 -18
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +175 -11
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
- package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
- package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +160 -0
- package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
- package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
- package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
- package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +90 -31
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +46 -11
- package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
- package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +24 -11
- package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +100 -38
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
- package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
- package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +248 -11
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +77 -12
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +267 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +88 -98
- package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -182
- package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +95 -75
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -106
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
- package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +36 -164
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +222 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
- package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -77
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
- package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
- package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -56
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +35 -40
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
- package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +295 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +330 -0
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +80 -1
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
- package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -57
- package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +197 -78
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +888 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
- package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +327 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
- package/src/resources/extensions/gsd/tool-contract.ts +82 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
- package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
- package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
- package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
- package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +1882 -0
- package/src/resources/extensions/gsd/worktree-safety.ts +282 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +404 -0
- package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
- package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
- package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +0 -733
- package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
- package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +0 -434
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1247
- package/src/resources/extensions/gsd/worktree-resolver.ts +0 -909
- /package/dist/web/standalone/.next/static/{yTuahMMuJzVnsov5PreWl → F5x9E6H9k_52fjqyql93y}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{yTuahMMuJzVnsov5PreWl → F5x9E6H9k_52fjqyql93y}/_ssgManifest.js +0 -0
|
@@ -1,1247 +0,0 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { mkdtempSync, rmSync, mkdirSync, realpathSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
WorktreeResolver,
|
|
8
|
-
type WorktreeResolverDeps,
|
|
9
|
-
type NotifyCtx,
|
|
10
|
-
} from "../worktree-resolver.js";
|
|
11
|
-
import { AutoSession } from "../auto/session.js";
|
|
12
|
-
|
|
13
|
-
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
14
|
-
|
|
15
|
-
/** Track calls to mock deps for assertion. */
|
|
16
|
-
interface CallLog {
|
|
17
|
-
fn: string;
|
|
18
|
-
args: unknown[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function makeSession(
|
|
22
|
-
overrides?: Partial<{ basePath: string; originalBasePath: string }>,
|
|
23
|
-
): AutoSession {
|
|
24
|
-
const s = new AutoSession();
|
|
25
|
-
s.basePath = overrides?.basePath ?? "/project";
|
|
26
|
-
s.originalBasePath = overrides?.originalBasePath ?? "/project";
|
|
27
|
-
return s;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function makeDeps(
|
|
31
|
-
overrides?: Partial<WorktreeResolverDeps>,
|
|
32
|
-
): WorktreeResolverDeps & { calls: CallLog[] } {
|
|
33
|
-
const calls: CallLog[] = [];
|
|
34
|
-
|
|
35
|
-
const deps: WorktreeResolverDeps & { calls: CallLog[] } = {
|
|
36
|
-
calls,
|
|
37
|
-
isInAutoWorktree: (basePath: string) => {
|
|
38
|
-
calls.push({ fn: "isInAutoWorktree", args: [basePath] });
|
|
39
|
-
return false;
|
|
40
|
-
},
|
|
41
|
-
shouldUseWorktreeIsolation: () => {
|
|
42
|
-
calls.push({ fn: "shouldUseWorktreeIsolation", args: [] });
|
|
43
|
-
return true;
|
|
44
|
-
},
|
|
45
|
-
getIsolationMode: () => {
|
|
46
|
-
calls.push({ fn: "getIsolationMode", args: [] });
|
|
47
|
-
return "worktree";
|
|
48
|
-
},
|
|
49
|
-
mergeMilestoneToMain: (
|
|
50
|
-
basePath: string,
|
|
51
|
-
milestoneId: string,
|
|
52
|
-
roadmapContent: string,
|
|
53
|
-
) => {
|
|
54
|
-
calls.push({
|
|
55
|
-
fn: "mergeMilestoneToMain",
|
|
56
|
-
args: [basePath, milestoneId, roadmapContent],
|
|
57
|
-
});
|
|
58
|
-
return { pushed: false, codeFilesChanged: true };
|
|
59
|
-
},
|
|
60
|
-
syncWorktreeStateBack: (
|
|
61
|
-
mainBasePath: string,
|
|
62
|
-
worktreePath: string,
|
|
63
|
-
milestoneId: string,
|
|
64
|
-
) => {
|
|
65
|
-
calls.push({
|
|
66
|
-
fn: "syncWorktreeStateBack",
|
|
67
|
-
args: [mainBasePath, worktreePath, milestoneId],
|
|
68
|
-
});
|
|
69
|
-
return { synced: [] };
|
|
70
|
-
},
|
|
71
|
-
teardownAutoWorktree: (
|
|
72
|
-
basePath: string,
|
|
73
|
-
milestoneId: string,
|
|
74
|
-
opts?: { preserveBranch?: boolean },
|
|
75
|
-
) => {
|
|
76
|
-
calls.push({
|
|
77
|
-
fn: "teardownAutoWorktree",
|
|
78
|
-
args: [basePath, milestoneId, opts],
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
createAutoWorktree: (basePath: string, milestoneId: string) => {
|
|
82
|
-
calls.push({ fn: "createAutoWorktree", args: [basePath, milestoneId] });
|
|
83
|
-
return `/project/.gsd/worktrees/${milestoneId}`;
|
|
84
|
-
},
|
|
85
|
-
enterAutoWorktree: (basePath: string, milestoneId: string) => {
|
|
86
|
-
calls.push({ fn: "enterAutoWorktree", args: [basePath, milestoneId] });
|
|
87
|
-
return `/project/.gsd/worktrees/${milestoneId}`;
|
|
88
|
-
},
|
|
89
|
-
getAutoWorktreePath: (basePath: string, milestoneId: string) => {
|
|
90
|
-
calls.push({ fn: "getAutoWorktreePath", args: [basePath, milestoneId] });
|
|
91
|
-
return null;
|
|
92
|
-
},
|
|
93
|
-
autoCommitCurrentBranch: (
|
|
94
|
-
basePath: string,
|
|
95
|
-
reason: string,
|
|
96
|
-
milestoneId: string,
|
|
97
|
-
) => {
|
|
98
|
-
calls.push({
|
|
99
|
-
fn: "autoCommitCurrentBranch",
|
|
100
|
-
args: [basePath, reason, milestoneId],
|
|
101
|
-
});
|
|
102
|
-
},
|
|
103
|
-
getCurrentBranch: (basePath: string) => {
|
|
104
|
-
calls.push({ fn: "getCurrentBranch", args: [basePath] });
|
|
105
|
-
return "main";
|
|
106
|
-
},
|
|
107
|
-
autoWorktreeBranch: (milestoneId: string) => {
|
|
108
|
-
calls.push({ fn: "autoWorktreeBranch", args: [milestoneId] });
|
|
109
|
-
return `milestone/${milestoneId}`;
|
|
110
|
-
},
|
|
111
|
-
resolveMilestoneFile: (
|
|
112
|
-
basePath: string,
|
|
113
|
-
milestoneId: string,
|
|
114
|
-
fileType: string,
|
|
115
|
-
) => {
|
|
116
|
-
calls.push({
|
|
117
|
-
fn: "resolveMilestoneFile",
|
|
118
|
-
args: [basePath, milestoneId, fileType],
|
|
119
|
-
});
|
|
120
|
-
return `/project/.gsd/milestones/${milestoneId}/${milestoneId}-ROADMAP.md`;
|
|
121
|
-
},
|
|
122
|
-
readFileSync: (path: string, _encoding: string) => {
|
|
123
|
-
calls.push({ fn: "readFileSync", args: [path] });
|
|
124
|
-
return "# Roadmap\n- [x] S01: Slice one\n";
|
|
125
|
-
},
|
|
126
|
-
GitServiceImpl: class MockGitServiceImpl {
|
|
127
|
-
basePath: string;
|
|
128
|
-
gitConfig: unknown;
|
|
129
|
-
constructor(basePath: string, gitConfig: unknown) {
|
|
130
|
-
calls.push({ fn: "GitServiceImpl", args: [basePath, gitConfig] });
|
|
131
|
-
this.basePath = basePath;
|
|
132
|
-
this.gitConfig = gitConfig;
|
|
133
|
-
}
|
|
134
|
-
} as unknown as WorktreeResolverDeps["GitServiceImpl"],
|
|
135
|
-
loadEffectiveGSDPreferences: () => {
|
|
136
|
-
calls.push({ fn: "loadEffectiveGSDPreferences", args: [] });
|
|
137
|
-
return { preferences: { git: {} } };
|
|
138
|
-
},
|
|
139
|
-
invalidateAllCaches: () => {
|
|
140
|
-
calls.push({ fn: "invalidateAllCaches", args: [] });
|
|
141
|
-
},
|
|
142
|
-
captureIntegrationBranch: (
|
|
143
|
-
basePath: string,
|
|
144
|
-
mid: string | undefined,
|
|
145
|
-
) => {
|
|
146
|
-
calls.push({
|
|
147
|
-
fn: "captureIntegrationBranch",
|
|
148
|
-
args: [basePath, mid],
|
|
149
|
-
});
|
|
150
|
-
},
|
|
151
|
-
enterBranchModeForMilestone: (basePath: string, milestoneId: string) => {
|
|
152
|
-
calls.push({ fn: "enterBranchModeForMilestone", args: [basePath, milestoneId] });
|
|
153
|
-
},
|
|
154
|
-
...overrides,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// Re-apply overrides that add the call tracking
|
|
158
|
-
if (overrides) {
|
|
159
|
-
for (const [key, val] of Object.entries(overrides)) {
|
|
160
|
-
if (key !== "calls") {
|
|
161
|
-
(deps as unknown as Record<string, unknown>)[key] = val;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return deps;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function makeNotifyCtx(): NotifyCtx & {
|
|
170
|
-
messages: Array<{ msg: string; level?: string }>;
|
|
171
|
-
} {
|
|
172
|
-
const messages: Array<{ msg: string; level?: string }> = [];
|
|
173
|
-
return {
|
|
174
|
-
messages,
|
|
175
|
-
notify: (msg: string, level?: "info" | "warning" | "error" | "success") => {
|
|
176
|
-
messages.push({ msg, level });
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function findCalls(calls: CallLog[], fn: string): CallLog[] {
|
|
182
|
-
return calls.filter((c) => c.fn === fn);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ─── Getter Tests ────────────────────────────────────────────────────────────
|
|
186
|
-
|
|
187
|
-
test("workPath returns s.basePath", () => {
|
|
188
|
-
const s = makeSession({ basePath: "/project/.gsd/worktrees/M001" });
|
|
189
|
-
const resolver = new WorktreeResolver(s, makeDeps());
|
|
190
|
-
assert.equal(resolver.workPath, "/project/.gsd/worktrees/M001");
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
test("projectRoot returns originalBasePath when set", () => {
|
|
194
|
-
const s = makeSession({
|
|
195
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
196
|
-
originalBasePath: "/project",
|
|
197
|
-
});
|
|
198
|
-
const resolver = new WorktreeResolver(s, makeDeps());
|
|
199
|
-
assert.equal(resolver.projectRoot, "/project");
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
test("projectRoot falls back to basePath when originalBasePath is empty", () => {
|
|
203
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "" });
|
|
204
|
-
const resolver = new WorktreeResolver(s, makeDeps());
|
|
205
|
-
assert.equal(resolver.projectRoot, "/project");
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
test("lockPath returns originalBasePath when set (same as lockBase)", () => {
|
|
209
|
-
const s = makeSession({
|
|
210
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
211
|
-
originalBasePath: "/project",
|
|
212
|
-
});
|
|
213
|
-
const resolver = new WorktreeResolver(s, makeDeps());
|
|
214
|
-
assert.equal(resolver.lockPath, "/project");
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
test("lockPath falls back to basePath when originalBasePath is empty", () => {
|
|
218
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "" });
|
|
219
|
-
const resolver = new WorktreeResolver(s, makeDeps());
|
|
220
|
-
assert.equal(resolver.lockPath, "/project");
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// ─── enterMilestone Tests ────────────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
test("enterMilestone creates new worktree when none exists", () => {
|
|
226
|
-
const s = makeSession();
|
|
227
|
-
const deps = makeDeps({
|
|
228
|
-
getAutoWorktreePath: () => null,
|
|
229
|
-
});
|
|
230
|
-
const ctx = makeNotifyCtx();
|
|
231
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
232
|
-
|
|
233
|
-
resolver.enterMilestone("M001", ctx);
|
|
234
|
-
|
|
235
|
-
assert.equal(s.basePath, "/project/.gsd/worktrees/M001");
|
|
236
|
-
assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 1);
|
|
237
|
-
assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
|
|
238
|
-
assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
|
|
239
|
-
assert.ok(
|
|
240
|
-
ctx.messages.some(
|
|
241
|
-
(m) => m.level === "info" && m.msg.includes("Entered worktree"),
|
|
242
|
-
),
|
|
243
|
-
);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
test("enterMilestone enters existing worktree instead of creating", () => {
|
|
247
|
-
const s = makeSession();
|
|
248
|
-
const deps = makeDeps({
|
|
249
|
-
getAutoWorktreePath: () => "/project/.gsd/worktrees/M001",
|
|
250
|
-
});
|
|
251
|
-
const ctx = makeNotifyCtx();
|
|
252
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
253
|
-
|
|
254
|
-
resolver.enterMilestone("M001", ctx);
|
|
255
|
-
|
|
256
|
-
assert.equal(s.basePath, "/project/.gsd/worktrees/M001");
|
|
257
|
-
assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 1);
|
|
258
|
-
assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
test("enterMilestone is no-op when isolation mode is none", () => {
|
|
262
|
-
const s = makeSession();
|
|
263
|
-
const deps = makeDeps({
|
|
264
|
-
getIsolationMode: () => "none",
|
|
265
|
-
});
|
|
266
|
-
const ctx = makeNotifyCtx();
|
|
267
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
268
|
-
|
|
269
|
-
resolver.enterMilestone("M001", ctx);
|
|
270
|
-
|
|
271
|
-
assert.equal(s.basePath, "/project"); // unchanged
|
|
272
|
-
assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
|
|
273
|
-
assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
|
|
274
|
-
assert.equal(findCalls(deps.calls, "enterBranchModeForMilestone").length, 0);
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
test("enterMilestone passes project root to isolation mode guard", () => {
|
|
278
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
279
|
-
let checkedBasePath: string | undefined;
|
|
280
|
-
const deps = makeDeps({
|
|
281
|
-
getIsolationMode: (basePath?: string) => {
|
|
282
|
-
checkedBasePath = basePath;
|
|
283
|
-
return "none";
|
|
284
|
-
},
|
|
285
|
-
});
|
|
286
|
-
const ctx = makeNotifyCtx();
|
|
287
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
288
|
-
|
|
289
|
-
resolver.enterMilestone("M001", ctx);
|
|
290
|
-
|
|
291
|
-
assert.equal(checkedBasePath, "/project");
|
|
292
|
-
assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
test("enterMilestone does NOT update basePath on creation failure", () => {
|
|
296
|
-
const s = makeSession();
|
|
297
|
-
const deps = makeDeps({
|
|
298
|
-
getAutoWorktreePath: () => null,
|
|
299
|
-
createAutoWorktree: () => {
|
|
300
|
-
throw new Error("disk full");
|
|
301
|
-
},
|
|
302
|
-
});
|
|
303
|
-
const ctx = makeNotifyCtx();
|
|
304
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
305
|
-
|
|
306
|
-
resolver.enterMilestone("M001", ctx);
|
|
307
|
-
|
|
308
|
-
assert.equal(s.basePath, "/project"); // unchanged — error recovery
|
|
309
|
-
assert.ok(
|
|
310
|
-
ctx.messages.some(
|
|
311
|
-
(m) => m.level === "warning" && m.msg.includes("disk full"),
|
|
312
|
-
),
|
|
313
|
-
);
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
test("enterMilestone uses originalBasePath as base for worktree ops", () => {
|
|
317
|
-
const s = makeSession({
|
|
318
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
319
|
-
originalBasePath: "/project",
|
|
320
|
-
});
|
|
321
|
-
let createdFrom = "";
|
|
322
|
-
const deps = makeDeps({
|
|
323
|
-
getAutoWorktreePath: () => null,
|
|
324
|
-
createAutoWorktree: (basePath: string, _mid: string) => {
|
|
325
|
-
createdFrom = basePath;
|
|
326
|
-
return "/project/.gsd/worktrees/M002";
|
|
327
|
-
},
|
|
328
|
-
});
|
|
329
|
-
const ctx = makeNotifyCtx();
|
|
330
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
331
|
-
|
|
332
|
-
resolver.enterMilestone("M002", ctx);
|
|
333
|
-
|
|
334
|
-
assert.equal(createdFrom, "/project"); // uses originalBasePath, not current basePath
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
test("enterMilestone does not create double-nested worktree when originalBasePath is empty and basePath is a worktree path", () => {
|
|
338
|
-
// Regression test for #3729: when s.originalBasePath is "" (falsy) and
|
|
339
|
-
// s.basePath is already a worktree path, the expression
|
|
340
|
-
// `this.s.originalBasePath || this.s.basePath` evaluates to the worktree
|
|
341
|
-
// path. Passing that to createAutoWorktree produces a doubly-nested path
|
|
342
|
-
// like /project/.gsd/worktrees/M001/.gsd/worktrees/M002.
|
|
343
|
-
const wtPath = "/project/.gsd/worktrees/M001";
|
|
344
|
-
const s = makeSession({
|
|
345
|
-
basePath: wtPath,
|
|
346
|
-
originalBasePath: "/project", // will be overwritten below to simulate the bug
|
|
347
|
-
});
|
|
348
|
-
// Simulate the real bug: originalBasePath is "" (falsy) as it is when AutoSession
|
|
349
|
-
// is constructed fresh or reset() is called without auto-start re-setting it.
|
|
350
|
-
s.originalBasePath = "";
|
|
351
|
-
|
|
352
|
-
let createdFromPath = "";
|
|
353
|
-
const deps = makeDeps({
|
|
354
|
-
getAutoWorktreePath: () => null,
|
|
355
|
-
createAutoWorktree: (basePath: string, _mid: string) => {
|
|
356
|
-
createdFromPath = basePath;
|
|
357
|
-
return `/project/.gsd/worktrees/M002`;
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
const ctx = makeNotifyCtx();
|
|
361
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
362
|
-
|
|
363
|
-
resolver.enterMilestone("M002", ctx);
|
|
364
|
-
|
|
365
|
-
// The path passed to createAutoWorktree must be the project root, NOT the
|
|
366
|
-
// worktree path. If it equals wtPath the worktree would be created at
|
|
367
|
-
// /project/.gsd/worktrees/M001/.gsd/worktrees/M002 (double-nesting).
|
|
368
|
-
assert.ok(
|
|
369
|
-
!createdFromPath.includes("/.gsd/worktrees/"),
|
|
370
|
-
`createAutoWorktree must be called with project root, got: "${createdFromPath}"`,
|
|
371
|
-
);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
// ─── enterMilestone Tests (branch mode) ──────────────────────────────────────
|
|
375
|
-
|
|
376
|
-
test("enterMilestone in branch mode calls enterBranchModeForMilestone and rebuilds GitService", () => {
|
|
377
|
-
const s = makeSession();
|
|
378
|
-
const deps = makeDeps({
|
|
379
|
-
getIsolationMode: () => "branch",
|
|
380
|
-
});
|
|
381
|
-
const ctx = makeNotifyCtx();
|
|
382
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
383
|
-
|
|
384
|
-
resolver.enterMilestone("M001", ctx);
|
|
385
|
-
|
|
386
|
-
// Branch mode: no worktree created, basePath unchanged
|
|
387
|
-
assert.equal(s.basePath, "/project");
|
|
388
|
-
assert.equal(findCalls(deps.calls, "enterBranchModeForMilestone").length, 1);
|
|
389
|
-
assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
|
|
390
|
-
assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
|
|
391
|
-
assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
|
|
392
|
-
assert.ok(ctx.messages.some((m) => m.level === "info" && m.msg.includes("milestone/M001")));
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
test("enterMilestone in branch mode uses originalBasePath as base", () => {
|
|
396
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
397
|
-
let calledWith = "";
|
|
398
|
-
const deps = makeDeps({
|
|
399
|
-
getIsolationMode: () => "branch",
|
|
400
|
-
enterBranchModeForMilestone: (basePath: string, _mid: string) => {
|
|
401
|
-
calledWith = basePath;
|
|
402
|
-
},
|
|
403
|
-
});
|
|
404
|
-
const ctx = makeNotifyCtx();
|
|
405
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
406
|
-
|
|
407
|
-
resolver.enterMilestone("M001", ctx);
|
|
408
|
-
|
|
409
|
-
assert.equal(calledWith, "/project");
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
test("enterMilestone in branch mode degrades isolation on failure", () => {
|
|
413
|
-
const s = makeSession();
|
|
414
|
-
const deps = makeDeps({
|
|
415
|
-
getIsolationMode: () => "branch",
|
|
416
|
-
enterBranchModeForMilestone: () => {
|
|
417
|
-
throw new Error("checkout failed");
|
|
418
|
-
},
|
|
419
|
-
});
|
|
420
|
-
const ctx = makeNotifyCtx();
|
|
421
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
422
|
-
|
|
423
|
-
resolver.enterMilestone("M001", ctx);
|
|
424
|
-
|
|
425
|
-
assert.equal(s.basePath, "/project"); // unchanged
|
|
426
|
-
assert.ok(s.isolationDegraded);
|
|
427
|
-
assert.ok(ctx.messages.some((m) => m.level === "warning" && m.msg.includes("checkout failed")));
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
test("enterMilestone branch mode is skipped when isolationDegraded", () => {
|
|
431
|
-
const s = makeSession();
|
|
432
|
-
s.isolationDegraded = true;
|
|
433
|
-
const deps = makeDeps({
|
|
434
|
-
getIsolationMode: () => "branch",
|
|
435
|
-
});
|
|
436
|
-
const ctx = makeNotifyCtx();
|
|
437
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
438
|
-
|
|
439
|
-
resolver.enterMilestone("M001", ctx);
|
|
440
|
-
|
|
441
|
-
assert.equal(findCalls(deps.calls, "enterBranchModeForMilestone").length, 0);
|
|
442
|
-
assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
// ─── exitMilestone Tests ─────────────────────────────────────────────────────
|
|
446
|
-
|
|
447
|
-
test("exitMilestone commits, tears down, and resets basePath", () => {
|
|
448
|
-
const s = makeSession({
|
|
449
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
450
|
-
originalBasePath: "/project",
|
|
451
|
-
});
|
|
452
|
-
const deps = makeDeps({
|
|
453
|
-
isInAutoWorktree: () => true,
|
|
454
|
-
});
|
|
455
|
-
const ctx = makeNotifyCtx();
|
|
456
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
457
|
-
|
|
458
|
-
resolver.exitMilestone("M001", ctx);
|
|
459
|
-
|
|
460
|
-
assert.equal(s.basePath, "/project"); // reset to originalBasePath
|
|
461
|
-
assert.equal(findCalls(deps.calls, "autoCommitCurrentBranch").length, 1);
|
|
462
|
-
assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 1);
|
|
463
|
-
assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1); // rebuilt
|
|
464
|
-
assert.equal(findCalls(deps.calls, "invalidateAllCaches").length, 1);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
test("exitMilestone is no-op when not in worktree", () => {
|
|
468
|
-
const s = makeSession();
|
|
469
|
-
const deps = makeDeps({
|
|
470
|
-
isInAutoWorktree: () => false,
|
|
471
|
-
});
|
|
472
|
-
const ctx = makeNotifyCtx();
|
|
473
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
474
|
-
|
|
475
|
-
resolver.exitMilestone("M001", ctx);
|
|
476
|
-
|
|
477
|
-
assert.equal(s.basePath, "/project"); // unchanged
|
|
478
|
-
assert.equal(findCalls(deps.calls, "autoCommitCurrentBranch").length, 0);
|
|
479
|
-
assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 0);
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
test("exitMilestone passes preserveBranch option", () => {
|
|
483
|
-
const s = makeSession({
|
|
484
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
485
|
-
originalBasePath: "/project",
|
|
486
|
-
});
|
|
487
|
-
let preserveOpts: unknown = null;
|
|
488
|
-
const deps = makeDeps({
|
|
489
|
-
isInAutoWorktree: () => true,
|
|
490
|
-
teardownAutoWorktree: (
|
|
491
|
-
_basePath: string,
|
|
492
|
-
_mid: string,
|
|
493
|
-
opts?: { preserveBranch?: boolean },
|
|
494
|
-
) => {
|
|
495
|
-
preserveOpts = opts;
|
|
496
|
-
},
|
|
497
|
-
});
|
|
498
|
-
const ctx = makeNotifyCtx();
|
|
499
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
500
|
-
|
|
501
|
-
resolver.exitMilestone("M001", ctx, { preserveBranch: true });
|
|
502
|
-
|
|
503
|
-
assert.deepEqual(preserveOpts, { preserveBranch: true });
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
test("exitMilestone still resets basePath even if auto-commit fails", () => {
|
|
507
|
-
const s = makeSession({
|
|
508
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
509
|
-
originalBasePath: "/project",
|
|
510
|
-
});
|
|
511
|
-
const deps = makeDeps({
|
|
512
|
-
isInAutoWorktree: () => true,
|
|
513
|
-
autoCommitCurrentBranch: () => {
|
|
514
|
-
throw new Error("commit error");
|
|
515
|
-
},
|
|
516
|
-
});
|
|
517
|
-
const ctx = makeNotifyCtx();
|
|
518
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
519
|
-
|
|
520
|
-
resolver.exitMilestone("M001", ctx);
|
|
521
|
-
|
|
522
|
-
// Should still complete: reset basePath, rebuild git service
|
|
523
|
-
assert.equal(s.basePath, "/project");
|
|
524
|
-
assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
// ─── mergeAndExit Tests (worktree mode) ──────────────────────────────────────
|
|
528
|
-
|
|
529
|
-
test("mergeAndExit in worktree mode reads roadmap and merges", () => {
|
|
530
|
-
const s = makeSession({
|
|
531
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
532
|
-
originalBasePath: "/project",
|
|
533
|
-
});
|
|
534
|
-
const deps = makeDeps({
|
|
535
|
-
isInAutoWorktree: () => true,
|
|
536
|
-
getIsolationMode: () => "worktree",
|
|
537
|
-
});
|
|
538
|
-
const ctx = makeNotifyCtx();
|
|
539
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
540
|
-
|
|
541
|
-
resolver.mergeAndExit("M001", ctx);
|
|
542
|
-
|
|
543
|
-
assert.equal(findCalls(deps.calls, "syncWorktreeStateBack").length, 1);
|
|
544
|
-
assert.equal(findCalls(deps.calls, "resolveMilestoneFile").length, 1);
|
|
545
|
-
assert.equal(findCalls(deps.calls, "readFileSync").length, 1);
|
|
546
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
|
|
547
|
-
assert.equal(s.basePath, "/project"); // restored
|
|
548
|
-
assert.ok(ctx.messages.some((m) => m.msg.includes("merged to main")));
|
|
549
|
-
});
|
|
550
|
-
|
|
551
|
-
test("mergeAndExit in worktree mode shows pushed status", () => {
|
|
552
|
-
const s = makeSession({
|
|
553
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
554
|
-
originalBasePath: "/project",
|
|
555
|
-
});
|
|
556
|
-
const deps = makeDeps({
|
|
557
|
-
isInAutoWorktree: () => true,
|
|
558
|
-
getIsolationMode: () => "worktree",
|
|
559
|
-
mergeMilestoneToMain: () => ({ pushed: true, codeFilesChanged: true }),
|
|
560
|
-
});
|
|
561
|
-
const ctx = makeNotifyCtx();
|
|
562
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
563
|
-
|
|
564
|
-
resolver.mergeAndExit("M001", ctx);
|
|
565
|
-
|
|
566
|
-
assert.ok(ctx.messages.some((m) => m.msg.includes("Pushed to remote")));
|
|
567
|
-
});
|
|
568
|
-
|
|
569
|
-
test("mergeAndExit falls back to teardown with preserveBranch when roadmap is missing (#1573)", () => {
|
|
570
|
-
const s = makeSession({
|
|
571
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
572
|
-
originalBasePath: "/project",
|
|
573
|
-
});
|
|
574
|
-
const deps = makeDeps({
|
|
575
|
-
isInAutoWorktree: () => true,
|
|
576
|
-
getIsolationMode: () => "worktree",
|
|
577
|
-
resolveMilestoneFile: () => null,
|
|
578
|
-
});
|
|
579
|
-
const ctx = makeNotifyCtx();
|
|
580
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
581
|
-
|
|
582
|
-
resolver.mergeAndExit("M001", ctx);
|
|
583
|
-
|
|
584
|
-
const teardownCalls = findCalls(deps.calls, "teardownAutoWorktree");
|
|
585
|
-
assert.equal(teardownCalls.length, 1);
|
|
586
|
-
// Branch must be preserved so commits are not orphaned (#1573)
|
|
587
|
-
assert.deepEqual(teardownCalls[0].args[2], { preserveBranch: true });
|
|
588
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
|
|
589
|
-
assert.equal(s.basePath, "/project"); // restored
|
|
590
|
-
assert.ok(ctx.messages.some((m) => m.msg.includes("branch preserved")));
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
test("mergeAndExit resolves roadmap from worktree when missing at project root (#1573)", () => {
|
|
594
|
-
const s = makeSession({
|
|
595
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
596
|
-
originalBasePath: "/project",
|
|
597
|
-
});
|
|
598
|
-
// resolveMilestoneFile returns null for project root, returns path for worktree
|
|
599
|
-
const deps = makeDeps({
|
|
600
|
-
isInAutoWorktree: () => true,
|
|
601
|
-
getIsolationMode: () => "worktree",
|
|
602
|
-
resolveMilestoneFile: (basePath: string) => {
|
|
603
|
-
if (basePath === "/project") return null; // missing at project root
|
|
604
|
-
if (basePath === "/project/.gsd/worktrees/M001") {
|
|
605
|
-
return "/project/.gsd/worktrees/M001/.gsd/milestones/M001/M001-ROADMAP.md";
|
|
606
|
-
}
|
|
607
|
-
return null;
|
|
608
|
-
},
|
|
609
|
-
});
|
|
610
|
-
const ctx = makeNotifyCtx();
|
|
611
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
612
|
-
|
|
613
|
-
resolver.mergeAndExit("M001", ctx);
|
|
614
|
-
|
|
615
|
-
// Should have called mergeMilestoneToMain, not bare teardown
|
|
616
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
|
|
617
|
-
// #2945 Bug 3: secondary teardown is now called after merge for cleanup
|
|
618
|
-
assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 1);
|
|
619
|
-
assert.equal(s.basePath, "/project"); // restored
|
|
620
|
-
assert.ok(ctx.messages.some((m) => m.msg.includes("merged to main")));
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
test("mergeAndExit in worktree mode restores to project root on merge failure", () => {
|
|
624
|
-
const s = makeSession({
|
|
625
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
626
|
-
originalBasePath: "/project",
|
|
627
|
-
});
|
|
628
|
-
const deps = makeDeps({
|
|
629
|
-
isInAutoWorktree: () => true,
|
|
630
|
-
getIsolationMode: () => "worktree",
|
|
631
|
-
mergeMilestoneToMain: () => {
|
|
632
|
-
throw new Error("conflict in main");
|
|
633
|
-
},
|
|
634
|
-
});
|
|
635
|
-
const ctx = makeNotifyCtx();
|
|
636
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
637
|
-
|
|
638
|
-
// Error propagates (#4380) — callers handle recovery. restoreToProjectRoot()
|
|
639
|
-
// still runs before re-throw so state is consistent for the caller.
|
|
640
|
-
assert.throws(() => resolver.mergeAndExit("M001", ctx), /conflict in main/);
|
|
641
|
-
|
|
642
|
-
assert.equal(s.basePath, "/project"); // error recovery — restored before re-throw
|
|
643
|
-
assert.ok(
|
|
644
|
-
ctx.messages.some(
|
|
645
|
-
(m) => m.level === "warning" && m.msg.includes("conflict in main"),
|
|
646
|
-
),
|
|
647
|
-
);
|
|
648
|
-
assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1); // rebuilt after recovery
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
test("mergeAndExit failure message tells user worktree and branch are preserved (#1668)", () => {
|
|
652
|
-
// Regression test: before the fix, the failure message was a bare
|
|
653
|
-
// "Milestone merge failed: <reason>" with no recovery guidance. Users were
|
|
654
|
-
// left confused about whether their code had been deleted. The new message
|
|
655
|
-
// explicitly states that the worktree and branch are preserved and what to do.
|
|
656
|
-
const s = makeSession({
|
|
657
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
658
|
-
originalBasePath: "/project",
|
|
659
|
-
});
|
|
660
|
-
const deps = makeDeps({
|
|
661
|
-
isInAutoWorktree: () => true,
|
|
662
|
-
getIsolationMode: () => "worktree",
|
|
663
|
-
mergeMilestoneToMain: () => {
|
|
664
|
-
throw new Error("pathspec 'main' did not match any file(s) known to git");
|
|
665
|
-
},
|
|
666
|
-
});
|
|
667
|
-
const ctx = makeNotifyCtx();
|
|
668
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
669
|
-
|
|
670
|
-
// Error propagates (#4380) — notification is still emitted before re-throw
|
|
671
|
-
assert.throws(() => resolver.mergeAndExit("M001", ctx), /pathspec 'main' did not match/);
|
|
672
|
-
|
|
673
|
-
const warning = ctx.messages.find((m) => m.level === "warning");
|
|
674
|
-
assert.ok(warning, "a warning message is emitted");
|
|
675
|
-
// Must contain the original error
|
|
676
|
-
assert.ok(warning!.msg.includes("pathspec 'main' did not match"), "warning includes the original error");
|
|
677
|
-
// Must tell the user their work is safe
|
|
678
|
-
assert.ok(
|
|
679
|
-
warning!.msg.includes("preserved"),
|
|
680
|
-
"warning tells user the worktree and branch are preserved",
|
|
681
|
-
);
|
|
682
|
-
// Must suggest a recovery action
|
|
683
|
-
assert.ok(
|
|
684
|
-
warning!.msg.includes("retry") || warning!.msg.includes("manually"),
|
|
685
|
-
"warning suggests a recovery action",
|
|
686
|
-
);
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
test("mergeAndExit failure message references /gsd dispatch complete-milestone, not /complete-milestone (#1891)", () => {
|
|
690
|
-
// Regression test: the failure notification previously told users to
|
|
691
|
-
// "retry /complete-milestone" — a command that does not exist. The correct
|
|
692
|
-
// recovery command is "/gsd dispatch complete-milestone".
|
|
693
|
-
const s = makeSession({
|
|
694
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
695
|
-
originalBasePath: "/project",
|
|
696
|
-
});
|
|
697
|
-
const deps = makeDeps({
|
|
698
|
-
isInAutoWorktree: () => true,
|
|
699
|
-
getIsolationMode: () => "worktree",
|
|
700
|
-
mergeMilestoneToMain: () => {
|
|
701
|
-
throw new Error("dirty working tree");
|
|
702
|
-
},
|
|
703
|
-
});
|
|
704
|
-
const ctx = makeNotifyCtx();
|
|
705
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
706
|
-
|
|
707
|
-
// Error propagates (#4380) — notification is still emitted before re-throw
|
|
708
|
-
assert.throws(() => resolver.mergeAndExit("M001", ctx), /dirty working tree/);
|
|
709
|
-
|
|
710
|
-
const warning = ctx.messages.find((m) => m.level === "warning");
|
|
711
|
-
assert.ok(warning, "a warning message is emitted");
|
|
712
|
-
// Must reference the correct dispatch command
|
|
713
|
-
assert.ok(
|
|
714
|
-
warning!.msg.includes("/gsd dispatch complete-milestone"),
|
|
715
|
-
"warning references /gsd dispatch complete-milestone, not bare /complete-milestone",
|
|
716
|
-
);
|
|
717
|
-
// Must NOT contain the bare (incorrect) command without the dispatch prefix
|
|
718
|
-
assert.ok(
|
|
719
|
-
!warning!.msg.match(/retry\s+\/complete-milestone(?!\S)/),
|
|
720
|
-
"warning must not reference the non-existent /complete-milestone command",
|
|
721
|
-
);
|
|
722
|
-
});
|
|
723
|
-
|
|
724
|
-
// ─── mergeAndExit Tests (branch mode) ────────────────────────────────────────
|
|
725
|
-
|
|
726
|
-
test("mergeAndExit in branch mode merges when on milestone branch", () => {
|
|
727
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
728
|
-
const deps = makeDeps({
|
|
729
|
-
isInAutoWorktree: () => false,
|
|
730
|
-
getIsolationMode: () => "branch",
|
|
731
|
-
getCurrentBranch: () => "milestone/M001",
|
|
732
|
-
autoWorktreeBranch: () => "milestone/M001",
|
|
733
|
-
});
|
|
734
|
-
const ctx = makeNotifyCtx();
|
|
735
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
736
|
-
|
|
737
|
-
resolver.mergeAndExit("M001", ctx);
|
|
738
|
-
|
|
739
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1);
|
|
740
|
-
assert.ok(ctx.messages.some((m) => m.msg.includes("branch mode")));
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
test("mergeAndExit in branch mode skips when not on milestone branch", () => {
|
|
744
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
745
|
-
const deps = makeDeps({
|
|
746
|
-
isInAutoWorktree: () => false,
|
|
747
|
-
getIsolationMode: () => "branch",
|
|
748
|
-
getCurrentBranch: () => "main",
|
|
749
|
-
autoWorktreeBranch: () => "milestone/M001",
|
|
750
|
-
});
|
|
751
|
-
const ctx = makeNotifyCtx();
|
|
752
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
753
|
-
|
|
754
|
-
resolver.mergeAndExit("M001", ctx);
|
|
755
|
-
|
|
756
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
|
|
757
|
-
assert.equal(ctx.messages.length, 0);
|
|
758
|
-
});
|
|
759
|
-
|
|
760
|
-
test("mergeAndExit in branch mode handles merge failure gracefully", () => {
|
|
761
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
762
|
-
const deps = makeDeps({
|
|
763
|
-
isInAutoWorktree: () => false,
|
|
764
|
-
getIsolationMode: () => "branch",
|
|
765
|
-
getCurrentBranch: () => "milestone/M001",
|
|
766
|
-
autoWorktreeBranch: () => "milestone/M001",
|
|
767
|
-
mergeMilestoneToMain: () => {
|
|
768
|
-
throw new Error("branch merge conflict");
|
|
769
|
-
},
|
|
770
|
-
});
|
|
771
|
-
const ctx = makeNotifyCtx();
|
|
772
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
773
|
-
|
|
774
|
-
// Error propagates (#4380) — notification is still emitted before re-throw
|
|
775
|
-
assert.throws(() => resolver.mergeAndExit("M001", ctx), /branch merge conflict/);
|
|
776
|
-
|
|
777
|
-
assert.ok(
|
|
778
|
-
ctx.messages.some(
|
|
779
|
-
(m) => m.level === "warning" && m.msg.includes("branch merge conflict"),
|
|
780
|
-
),
|
|
781
|
-
);
|
|
782
|
-
});
|
|
783
|
-
|
|
784
|
-
test("mergeAndExit in branch mode skips when no roadmap", () => {
|
|
785
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
786
|
-
const deps = makeDeps({
|
|
787
|
-
isInAutoWorktree: () => false,
|
|
788
|
-
getIsolationMode: () => "branch",
|
|
789
|
-
getCurrentBranch: () => "milestone/M001",
|
|
790
|
-
autoWorktreeBranch: () => "milestone/M001",
|
|
791
|
-
resolveMilestoneFile: () => null,
|
|
792
|
-
});
|
|
793
|
-
const ctx = makeNotifyCtx();
|
|
794
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
795
|
-
|
|
796
|
-
resolver.mergeAndExit("M001", ctx);
|
|
797
|
-
|
|
798
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
|
|
799
|
-
});
|
|
800
|
-
|
|
801
|
-
test("mergeAndExit in branch mode rebuilds GitService after merge", () => {
|
|
802
|
-
const s = makeSession({ basePath: "/project", originalBasePath: "/project" });
|
|
803
|
-
const deps = makeDeps({
|
|
804
|
-
isInAutoWorktree: () => false,
|
|
805
|
-
getIsolationMode: () => "branch",
|
|
806
|
-
getCurrentBranch: () => "milestone/M001",
|
|
807
|
-
autoWorktreeBranch: () => "milestone/M001",
|
|
808
|
-
});
|
|
809
|
-
const ctx = makeNotifyCtx();
|
|
810
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
811
|
-
|
|
812
|
-
resolver.mergeAndExit("M001", ctx);
|
|
813
|
-
|
|
814
|
-
assert.equal(findCalls(deps.calls, "GitServiceImpl").length, 1);
|
|
815
|
-
});
|
|
816
|
-
|
|
817
|
-
// ─── mergeAndExit Tests (none mode) ──────────────────────────────────────────
|
|
818
|
-
|
|
819
|
-
test("mergeAndExit in none mode is a no-op", () => {
|
|
820
|
-
const s = makeSession();
|
|
821
|
-
const deps = makeDeps({
|
|
822
|
-
getIsolationMode: () => "none",
|
|
823
|
-
});
|
|
824
|
-
const ctx = makeNotifyCtx();
|
|
825
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
826
|
-
|
|
827
|
-
resolver.mergeAndExit("M001", ctx);
|
|
828
|
-
|
|
829
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
|
|
830
|
-
assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 0);
|
|
831
|
-
assert.equal(ctx.messages.length, 0);
|
|
832
|
-
});
|
|
833
|
-
|
|
834
|
-
// ─── #1906 — metadata-only merge warning ────────────────────────────────────
|
|
835
|
-
|
|
836
|
-
test("mergeAndExit warns when merge contains no code changes (#1906)", () => {
|
|
837
|
-
const s = makeSession({
|
|
838
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
839
|
-
originalBasePath: "/project",
|
|
840
|
-
});
|
|
841
|
-
const deps = makeDeps({
|
|
842
|
-
isInAutoWorktree: () => true,
|
|
843
|
-
getIsolationMode: () => "worktree",
|
|
844
|
-
mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: false }),
|
|
845
|
-
});
|
|
846
|
-
const ctx = makeNotifyCtx();
|
|
847
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
848
|
-
|
|
849
|
-
resolver.mergeAndExit("M001", ctx);
|
|
850
|
-
|
|
851
|
-
assert.ok(
|
|
852
|
-
ctx.messages.some((m) => m.msg.includes("NO code changes") && m.level === "warning"),
|
|
853
|
-
"must emit warning when only .gsd/ metadata was merged",
|
|
854
|
-
);
|
|
855
|
-
assert.ok(
|
|
856
|
-
!ctx.messages.some((m) => m.msg.includes("merged to main") && m.level === "info"),
|
|
857
|
-
"must NOT emit success-style info notification for metadata-only merge",
|
|
858
|
-
);
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
test("mergeAndExit emits info when merge contains code changes (#1906)", () => {
|
|
862
|
-
const s = makeSession({
|
|
863
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
864
|
-
originalBasePath: "/project",
|
|
865
|
-
});
|
|
866
|
-
const deps = makeDeps({
|
|
867
|
-
isInAutoWorktree: () => true,
|
|
868
|
-
getIsolationMode: () => "worktree",
|
|
869
|
-
mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: true }),
|
|
870
|
-
});
|
|
871
|
-
const ctx = makeNotifyCtx();
|
|
872
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
873
|
-
|
|
874
|
-
resolver.mergeAndExit("M001", ctx);
|
|
875
|
-
|
|
876
|
-
assert.ok(
|
|
877
|
-
ctx.messages.some((m) => m.msg.includes("merged to main") && m.level === "info"),
|
|
878
|
-
"must emit info notification when code files were merged",
|
|
879
|
-
);
|
|
880
|
-
assert.ok(
|
|
881
|
-
!ctx.messages.some((m) => m.msg.includes("NO code changes")),
|
|
882
|
-
"must NOT emit metadata-only warning when code files were merged",
|
|
883
|
-
);
|
|
884
|
-
});
|
|
885
|
-
|
|
886
|
-
test("mergeAndExit branch mode warns when merge contains no code changes (#1906)", () => {
|
|
887
|
-
const s = makeSession({
|
|
888
|
-
basePath: "/project",
|
|
889
|
-
originalBasePath: "/project",
|
|
890
|
-
});
|
|
891
|
-
const deps = makeDeps({
|
|
892
|
-
isInAutoWorktree: () => false,
|
|
893
|
-
getIsolationMode: () => "branch",
|
|
894
|
-
getCurrentBranch: () => "milestone/M001",
|
|
895
|
-
autoWorktreeBranch: () => "milestone/M001",
|
|
896
|
-
mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: false }),
|
|
897
|
-
});
|
|
898
|
-
const ctx = makeNotifyCtx();
|
|
899
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
900
|
-
|
|
901
|
-
resolver.mergeAndExit("M001", ctx);
|
|
902
|
-
|
|
903
|
-
assert.ok(
|
|
904
|
-
ctx.messages.some((m) => m.msg.includes("NO code changes") && m.level === "warning"),
|
|
905
|
-
"branch mode must emit warning when only .gsd/ metadata was merged",
|
|
906
|
-
);
|
|
907
|
-
});
|
|
908
|
-
|
|
909
|
-
// ─── mergeAndEnterNext Tests ─────────────────────────────────────────────────
|
|
910
|
-
|
|
911
|
-
test("mergeAndEnterNext calls mergeAndExit then enterMilestone", () => {
|
|
912
|
-
const s = makeSession({
|
|
913
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
914
|
-
originalBasePath: "/project",
|
|
915
|
-
});
|
|
916
|
-
const callOrder: string[] = [];
|
|
917
|
-
const deps = makeDeps({
|
|
918
|
-
isInAutoWorktree: () => true,
|
|
919
|
-
getIsolationMode: () => "worktree",
|
|
920
|
-
shouldUseWorktreeIsolation: () => true,
|
|
921
|
-
mergeMilestoneToMain: (
|
|
922
|
-
basePath: string,
|
|
923
|
-
milestoneId: string,
|
|
924
|
-
_roadmap: string,
|
|
925
|
-
) => {
|
|
926
|
-
callOrder.push(`merge:${milestoneId}`);
|
|
927
|
-
return { pushed: false, codeFilesChanged: true };
|
|
928
|
-
},
|
|
929
|
-
getAutoWorktreePath: () => null,
|
|
930
|
-
createAutoWorktree: (basePath: string, milestoneId: string) => {
|
|
931
|
-
callOrder.push(`create:${milestoneId}`);
|
|
932
|
-
return `/project/.gsd/worktrees/${milestoneId}`;
|
|
933
|
-
},
|
|
934
|
-
});
|
|
935
|
-
const ctx = makeNotifyCtx();
|
|
936
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
937
|
-
|
|
938
|
-
resolver.mergeAndEnterNext("M001", "M002", ctx);
|
|
939
|
-
|
|
940
|
-
assert.deepEqual(callOrder, ["merge:M001", "create:M002"]);
|
|
941
|
-
assert.equal(s.basePath, "/project/.gsd/worktrees/M002");
|
|
942
|
-
});
|
|
943
|
-
|
|
944
|
-
test("mergeAndEnterNext enters next milestone even if merge fails", () => {
|
|
945
|
-
const s = makeSession({
|
|
946
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
947
|
-
originalBasePath: "/project",
|
|
948
|
-
});
|
|
949
|
-
const deps = makeDeps({
|
|
950
|
-
isInAutoWorktree: (basePath: string) => basePath.includes("worktrees"),
|
|
951
|
-
getIsolationMode: () => "worktree",
|
|
952
|
-
shouldUseWorktreeIsolation: () => true,
|
|
953
|
-
mergeMilestoneToMain: () => {
|
|
954
|
-
throw new Error("merge failed");
|
|
955
|
-
},
|
|
956
|
-
getAutoWorktreePath: () => null,
|
|
957
|
-
createAutoWorktree: (_basePath: string, milestoneId: string) => {
|
|
958
|
-
return `/project/.gsd/worktrees/${milestoneId}`;
|
|
959
|
-
},
|
|
960
|
-
});
|
|
961
|
-
const ctx = makeNotifyCtx();
|
|
962
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
963
|
-
|
|
964
|
-
resolver.mergeAndEnterNext("M001", "M002", ctx);
|
|
965
|
-
|
|
966
|
-
// Merge failed but enter should still happen
|
|
967
|
-
assert.equal(s.basePath, "/project/.gsd/worktrees/M002");
|
|
968
|
-
assert.ok(
|
|
969
|
-
ctx.messages.some(
|
|
970
|
-
(m) => m.level === "warning" && m.msg.includes("merge failed"),
|
|
971
|
-
),
|
|
972
|
-
);
|
|
973
|
-
assert.ok(
|
|
974
|
-
ctx.messages.some(
|
|
975
|
-
(m) => m.level === "info" && m.msg.includes("Entered worktree"),
|
|
976
|
-
),
|
|
977
|
-
);
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
// ─── GitService Rebuild Atomicity ────────────────────────────────────────────
|
|
981
|
-
|
|
982
|
-
test("GitService is rebuilt with the NEW basePath after enterMilestone", () => {
|
|
983
|
-
const s = makeSession();
|
|
984
|
-
let gitServiceBasePath = "";
|
|
985
|
-
const deps = makeDeps({
|
|
986
|
-
getAutoWorktreePath: () => null,
|
|
987
|
-
GitServiceImpl: class {
|
|
988
|
-
constructor(basePath: string, _config: unknown) {
|
|
989
|
-
gitServiceBasePath = basePath;
|
|
990
|
-
}
|
|
991
|
-
} as unknown as WorktreeResolverDeps["GitServiceImpl"],
|
|
992
|
-
});
|
|
993
|
-
const ctx = makeNotifyCtx();
|
|
994
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
995
|
-
|
|
996
|
-
resolver.enterMilestone("M001", ctx);
|
|
997
|
-
|
|
998
|
-
assert.equal(gitServiceBasePath, "/project/.gsd/worktrees/M001"); // new path, not old
|
|
999
|
-
});
|
|
1000
|
-
|
|
1001
|
-
test("GitService is rebuilt with originalBasePath after exitMilestone", () => {
|
|
1002
|
-
const s = makeSession({
|
|
1003
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
1004
|
-
originalBasePath: "/project",
|
|
1005
|
-
});
|
|
1006
|
-
let gitServiceBasePath = "";
|
|
1007
|
-
const deps = makeDeps({
|
|
1008
|
-
isInAutoWorktree: () => true,
|
|
1009
|
-
GitServiceImpl: class {
|
|
1010
|
-
constructor(basePath: string, _config: unknown) {
|
|
1011
|
-
gitServiceBasePath = basePath;
|
|
1012
|
-
}
|
|
1013
|
-
} as unknown as WorktreeResolverDeps["GitServiceImpl"],
|
|
1014
|
-
});
|
|
1015
|
-
const ctx = makeNotifyCtx();
|
|
1016
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1017
|
-
|
|
1018
|
-
resolver.exitMilestone("M001", ctx);
|
|
1019
|
-
|
|
1020
|
-
assert.equal(gitServiceBasePath, "/project"); // project root, not worktree
|
|
1021
|
-
});
|
|
1022
|
-
|
|
1023
|
-
// ─── Isolation Degradation Tests (#2483) ──────────────────────────────────
|
|
1024
|
-
|
|
1025
|
-
test("enterMilestone sets isolationDegraded when worktree creation throws (#2483)", () => {
|
|
1026
|
-
const s = makeSession();
|
|
1027
|
-
const deps = makeDeps({
|
|
1028
|
-
getAutoWorktreePath: () => null,
|
|
1029
|
-
createAutoWorktree: () => {
|
|
1030
|
-
throw new Error("empty repo");
|
|
1031
|
-
},
|
|
1032
|
-
});
|
|
1033
|
-
const ctx = makeNotifyCtx();
|
|
1034
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1035
|
-
|
|
1036
|
-
resolver.enterMilestone("M001", ctx);
|
|
1037
|
-
|
|
1038
|
-
assert.equal(s.isolationDegraded, true);
|
|
1039
|
-
assert.equal(s.basePath, "/project"); // unchanged — error recovery
|
|
1040
|
-
});
|
|
1041
|
-
|
|
1042
|
-
test("enterMilestone is no-op when isolationDegraded is true (#2483)", () => {
|
|
1043
|
-
const s = makeSession();
|
|
1044
|
-
s.isolationDegraded = true;
|
|
1045
|
-
const deps = makeDeps();
|
|
1046
|
-
const ctx = makeNotifyCtx();
|
|
1047
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1048
|
-
|
|
1049
|
-
resolver.enterMilestone("M001", ctx);
|
|
1050
|
-
|
|
1051
|
-
assert.equal(s.basePath, "/project"); // unchanged
|
|
1052
|
-
assert.equal(findCalls(deps.calls, "createAutoWorktree").length, 0);
|
|
1053
|
-
assert.equal(findCalls(deps.calls, "enterAutoWorktree").length, 0);
|
|
1054
|
-
assert.equal(findCalls(deps.calls, "shouldUseWorktreeIsolation").length, 0);
|
|
1055
|
-
});
|
|
1056
|
-
|
|
1057
|
-
test("mergeAndExit is no-op when isolationDegraded is true (#2483)", () => {
|
|
1058
|
-
const s = makeSession({
|
|
1059
|
-
basePath: "/project",
|
|
1060
|
-
originalBasePath: "/project",
|
|
1061
|
-
});
|
|
1062
|
-
s.isolationDegraded = true;
|
|
1063
|
-
const deps = makeDeps({
|
|
1064
|
-
getIsolationMode: () => "worktree",
|
|
1065
|
-
});
|
|
1066
|
-
const ctx = makeNotifyCtx();
|
|
1067
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1068
|
-
|
|
1069
|
-
resolver.mergeAndExit("M001", ctx);
|
|
1070
|
-
|
|
1071
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0);
|
|
1072
|
-
assert.equal(findCalls(deps.calls, "teardownAutoWorktree").length, 0);
|
|
1073
|
-
assert.equal(findCalls(deps.calls, "getIsolationMode").length, 0);
|
|
1074
|
-
assert.ok(
|
|
1075
|
-
ctx.messages.some(
|
|
1076
|
-
(m) => m.level === "info" && m.msg.includes("isolation was degraded"),
|
|
1077
|
-
),
|
|
1078
|
-
);
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
test("isolationDegraded is reset by session.reset() (#2483)", () => {
|
|
1082
|
-
const s = new AutoSession();
|
|
1083
|
-
s.isolationDegraded = true;
|
|
1084
|
-
|
|
1085
|
-
s.reset();
|
|
1086
|
-
|
|
1087
|
-
assert.equal(s.isolationDegraded, false);
|
|
1088
|
-
});
|
|
1089
|
-
|
|
1090
|
-
// ─── #2625 — Default isolation mode change must not orphan worktree commits ──
|
|
1091
|
-
|
|
1092
|
-
test("mergeAndExit still merges when mode is 'none' but session is in a worktree (#2625)", () => {
|
|
1093
|
-
// Scenario: user upgraded from a version where default was "worktree" to one
|
|
1094
|
-
// where default is "none". They have an active worktree with committed work.
|
|
1095
|
-
// mergeAndExit must detect the active worktree and merge regardless of config.
|
|
1096
|
-
const s = makeSession({
|
|
1097
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
1098
|
-
originalBasePath: "/project",
|
|
1099
|
-
});
|
|
1100
|
-
const deps = makeDeps({
|
|
1101
|
-
isInAutoWorktree: () => true,
|
|
1102
|
-
getIsolationMode: () => "none", // config says "none" — but we ARE in a worktree
|
|
1103
|
-
});
|
|
1104
|
-
const ctx = makeNotifyCtx();
|
|
1105
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1106
|
-
|
|
1107
|
-
resolver.mergeAndExit("M001", ctx);
|
|
1108
|
-
|
|
1109
|
-
// Must still merge — not skip silently
|
|
1110
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 1,
|
|
1111
|
-
"must call mergeMilestoneToMain even when isolation mode is 'none' but we are in a worktree");
|
|
1112
|
-
assert.equal(s.basePath, "/project", "basePath must be restored to project root");
|
|
1113
|
-
assert.ok(ctx.messages.some((m) => m.msg.includes("merged to main")),
|
|
1114
|
-
"must notify about the merge");
|
|
1115
|
-
});
|
|
1116
|
-
|
|
1117
|
-
test("mergeAndExit in none mode remains a no-op when NOT in a worktree (#2625)", () => {
|
|
1118
|
-
// When mode is "none" and we are genuinely not in a worktree, it should still be a no-op.
|
|
1119
|
-
const s = makeSession({
|
|
1120
|
-
basePath: "/project",
|
|
1121
|
-
originalBasePath: "/project",
|
|
1122
|
-
});
|
|
1123
|
-
const deps = makeDeps({
|
|
1124
|
-
isInAutoWorktree: () => false,
|
|
1125
|
-
getIsolationMode: () => "none",
|
|
1126
|
-
});
|
|
1127
|
-
const ctx = makeNotifyCtx();
|
|
1128
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1129
|
-
|
|
1130
|
-
resolver.mergeAndExit("M001", ctx);
|
|
1131
|
-
|
|
1132
|
-
assert.equal(findCalls(deps.calls, "mergeMilestoneToMain").length, 0,
|
|
1133
|
-
"must NOT merge when not in a worktree and mode is none");
|
|
1134
|
-
});
|
|
1135
|
-
|
|
1136
|
-
// ─── #4380 — Non-MergeConflictError must not be swallowed ────────────────────
|
|
1137
|
-
|
|
1138
|
-
test("mergeAndExit propagates non-MergeConflictError to caller (#4380)", () => {
|
|
1139
|
-
// Regression test: previously the catch block in _mergeWorktreeMode only
|
|
1140
|
-
// re-threw MergeConflictError. Permission errors, filesystem errors, and other
|
|
1141
|
-
// non-conflict failures were swallowed silently, making broken states impossible
|
|
1142
|
-
// to diagnose and preventing callers (phases.ts) from applying their own
|
|
1143
|
-
// error-recovery logic.
|
|
1144
|
-
const permissionError = new Error("EACCES: permission denied, open '/project/.git/SQUASH_MSG'");
|
|
1145
|
-
const s = makeSession({
|
|
1146
|
-
basePath: "/project/.gsd/worktrees/M001",
|
|
1147
|
-
originalBasePath: "/project",
|
|
1148
|
-
});
|
|
1149
|
-
const deps = makeDeps({
|
|
1150
|
-
isInAutoWorktree: () => true,
|
|
1151
|
-
getIsolationMode: () => "worktree",
|
|
1152
|
-
mergeMilestoneToMain: () => {
|
|
1153
|
-
throw permissionError;
|
|
1154
|
-
},
|
|
1155
|
-
});
|
|
1156
|
-
const ctx = makeNotifyCtx();
|
|
1157
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1158
|
-
|
|
1159
|
-
// The error must propagate — callers need it to apply their own recovery logic
|
|
1160
|
-
assert.throws(
|
|
1161
|
-
() => resolver.mergeAndExit("M001", ctx),
|
|
1162
|
-
(err: unknown) => err === permissionError,
|
|
1163
|
-
"non-MergeConflictError must propagate to the caller, not be swallowed",
|
|
1164
|
-
);
|
|
1165
|
-
});
|
|
1166
|
-
|
|
1167
|
-
// ─── Regression: mergeAndExit anchors cwd at project root before merge work ─
|
|
1168
|
-
// (de73fb43d headless `gsd auto` exits-on-task regression)
|
|
1169
|
-
//
|
|
1170
|
-
// Background: the auto loop runs tasks inside the milestone worktree
|
|
1171
|
-
// (process.cwd() === worktreePath). When the milestone completes, the
|
|
1172
|
-
// worktree dir is torn down. If cwd was still inside it at that moment,
|
|
1173
|
-
// every subsequent process.cwd() throws ENOENT — and after de73fb43d
|
|
1174
|
-
// auto/run-unit.ts:50 turns that ENOENT into a session-failed cancel,
|
|
1175
|
-
// which in headless mode bubbles up to a "Auto-mode stopped" notify
|
|
1176
|
-
// and process.exit(0). mergeAndExit must therefore guarantee cwd is
|
|
1177
|
-
// anchored at the project root regardless of which merge path runs.
|
|
1178
|
-
|
|
1179
|
-
test("mergeAndExit chdirs to project root before merge work (regression: headless gsd auto exit)", () => {
|
|
1180
|
-
// Set up real dirs so process.chdir actually succeeds. realpathSync
|
|
1181
|
-
// canonicalizes the macOS /var → /private/var symlink so equality holds.
|
|
1182
|
-
const projectRoot = realpathSync(mkdtempSync(join(tmpdir(), "gsd-resolver-cwd-")));
|
|
1183
|
-
const worktreePath = join(projectRoot, ".gsd/worktrees/M001");
|
|
1184
|
-
mkdirSync(worktreePath, { recursive: true });
|
|
1185
|
-
const previousCwd = process.cwd();
|
|
1186
|
-
|
|
1187
|
-
try {
|
|
1188
|
-
process.chdir(worktreePath);
|
|
1189
|
-
assert.equal(process.cwd(), worktreePath, "precondition: cwd is in worktree");
|
|
1190
|
-
|
|
1191
|
-
const s = makeSession({
|
|
1192
|
-
basePath: worktreePath,
|
|
1193
|
-
originalBasePath: projectRoot,
|
|
1194
|
-
});
|
|
1195
|
-
const deps = makeDeps({
|
|
1196
|
-
isInAutoWorktree: () => true,
|
|
1197
|
-
getIsolationMode: () => "worktree",
|
|
1198
|
-
});
|
|
1199
|
-
const ctx = makeNotifyCtx();
|
|
1200
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1201
|
-
|
|
1202
|
-
resolver.mergeAndExit("M001", ctx);
|
|
1203
|
-
|
|
1204
|
-
assert.equal(
|
|
1205
|
-
process.cwd(),
|
|
1206
|
-
projectRoot,
|
|
1207
|
-
"mergeAndExit must leave cwd at the project root, not the (about-to-be-removed) worktree",
|
|
1208
|
-
);
|
|
1209
|
-
} finally {
|
|
1210
|
-
try { process.chdir(previousCwd); } catch { /* best-effort */ }
|
|
1211
|
-
rmSync(projectRoot, { recursive: true, force: true });
|
|
1212
|
-
}
|
|
1213
|
-
});
|
|
1214
|
-
|
|
1215
|
-
test("mergeAndExit anchors cwd even on isolation-degraded skip path", () => {
|
|
1216
|
-
// The skip paths (isolation-degraded, mode-none, missing-original-base)
|
|
1217
|
-
// bypass the per-mode merge helpers entirely. They must still leave cwd
|
|
1218
|
-
// at the project root so a subsequent worktree teardown elsewhere does
|
|
1219
|
-
// not strand cwd in a deleted dir.
|
|
1220
|
-
const projectRoot = realpathSync(mkdtempSync(join(tmpdir(), "gsd-resolver-cwd-degraded-")));
|
|
1221
|
-
const worktreePath = join(projectRoot, ".gsd/worktrees/M001");
|
|
1222
|
-
mkdirSync(worktreePath, { recursive: true });
|
|
1223
|
-
const previousCwd = process.cwd();
|
|
1224
|
-
|
|
1225
|
-
try {
|
|
1226
|
-
process.chdir(worktreePath);
|
|
1227
|
-
const s = makeSession({
|
|
1228
|
-
basePath: worktreePath,
|
|
1229
|
-
originalBasePath: projectRoot,
|
|
1230
|
-
});
|
|
1231
|
-
s.isolationDegraded = true;
|
|
1232
|
-
const deps = makeDeps({ getIsolationMode: () => "worktree" });
|
|
1233
|
-
const ctx = makeNotifyCtx();
|
|
1234
|
-
const resolver = new WorktreeResolver(s, deps);
|
|
1235
|
-
|
|
1236
|
-
resolver.mergeAndExit("M001", ctx);
|
|
1237
|
-
|
|
1238
|
-
assert.equal(
|
|
1239
|
-
process.cwd(),
|
|
1240
|
-
projectRoot,
|
|
1241
|
-
"isolation-degraded skip must still anchor cwd at project root",
|
|
1242
|
-
);
|
|
1243
|
-
} finally {
|
|
1244
|
-
try { process.chdir(previousCwd); } catch { /* best-effort */ }
|
|
1245
|
-
rmSync(projectRoot, { recursive: true, force: true });
|
|
1246
|
-
}
|
|
1247
|
-
});
|