gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00
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 +53 -17
- package/dist/claude-cli-check.js +46 -10
- package/dist/headless.js +49 -4
- package/dist/resource-loader.d.ts +40 -0
- package/dist/resource-loader.js +32 -13
- package/dist/resources/extensions/browser-tools/capture.js +9 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/github-sync/templates.js +103 -0
- package/dist/resources/extensions/google-search/index.js +3 -2
- package/dist/resources/extensions/gsd/auto/loop.js +124 -2
- package/dist/resources/extensions/gsd/auto/phases.js +57 -39
- package/dist/resources/extensions/gsd/auto/session.js +6 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
- package/dist/resources/extensions/gsd/auto-start.js +107 -29
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
- package/dist/resources/extensions/gsd/auto.js +76 -21
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
- package/dist/resources/extensions/gsd/component-loader.js +447 -0
- package/dist/resources/extensions/gsd/component-types.js +69 -0
- package/dist/resources/extensions/gsd/context-store.js +23 -7
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/forensics.js +106 -0
- package/dist/resources/extensions/gsd/gate-registry.js +2 -2
- package/dist/resources/extensions/gsd/git-constants.js +28 -1
- package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
- package/dist/resources/extensions/gsd/git-service.js +126 -2
- package/dist/resources/extensions/gsd/gsd-db.js +6 -3
- package/dist/resources/extensions/gsd/guided-flow.js +39 -13
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
- package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
- package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
- package/dist/resources/extensions/gsd/model-router.js +6 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
- package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/session-lock.js +19 -10
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
- package/dist/resources/extensions/gsd/state.js +69 -58
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
- package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
- package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
- package/dist/resources/extensions/gsd/uok/writer.js +82 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
- package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
- package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
- package/dist/resources/extensions/mcp-client/index.js +3 -1
- package/dist/resources/extensions/ollama/index.js +5 -1
- package/dist/resources/extensions/remote-questions/manager.js +11 -5
- 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 +11 -11
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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/package.json +2 -3
- package/packages/daemon/package.json +2 -2
- package/packages/daemon/src/logger.ts +4 -3
- package/packages/mcp-server/dist/server.d.ts +24 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +88 -87
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +15 -6
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/mcp-server.test.ts +25 -3
- package/packages/mcp-server/src/readers/graph.test.ts +87 -15
- package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
- package/packages/mcp-server/src/server.ts +131 -105
- package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
- package/packages/mcp-server/src/workflow-tools.ts +19 -6
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +2 -2
- package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
- package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
- package/packages/native/src/__tests__/ps.test.mjs +14 -8
- package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
- package/packages/native/src/__tests__/truncate.test.mjs +17 -2
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
- package/packages/pi-agent-core/src/agent.test.ts +96 -102
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.js +9 -2
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
- package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +43 -70
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +36 -11
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +44 -0
- package/packages/pi-ai/src/models/capability-patches.ts +10 -2
- package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
- package/packages/pi-ai/src/models/generated/openai.ts +17 -0
- package/packages/pi-ai/src/models.generated.test.ts +46 -73
- package/packages/pi-ai/src/models.test.ts +48 -11
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
- 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-model-switch.test.js +75 -12
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -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 +61 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
- 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/dynamic-border.test.js +20 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -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 +30 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -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 +105 -13
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
- package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
- package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
- package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
- package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
- package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +14 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +19 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.js.map +1 -1
- package/packages/pi-tui/dist/editor-component.d.ts +2 -0
- package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/packages/pi-tui/dist/editor-component.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
- package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
- package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
- package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
- package/packages/pi-tui/src/components/editor.ts +22 -0
- package/packages/pi-tui/src/components/image.test.ts +10 -5
- package/packages/pi-tui/src/editor-component.ts +3 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/dist/rpc-client.test.js +101 -51
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install.js +15 -1
- package/src/resources/extensions/browser-tools/capture.ts +12 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
- package/src/resources/extensions/github-sync/templates.ts +151 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
- package/src/resources/extensions/google-search/index.ts +3 -2
- package/src/resources/extensions/gsd/auto/loop.ts +142 -2
- package/src/resources/extensions/gsd/auto/phases.ts +62 -38
- package/src/resources/extensions/gsd/auto/session.ts +7 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
- package/src/resources/extensions/gsd/auto-start.ts +127 -9
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
- package/src/resources/extensions/gsd/auto.ts +90 -23
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
- package/src/resources/extensions/gsd/component-loader.ts +598 -0
- package/src/resources/extensions/gsd/component-types.ts +362 -0
- package/src/resources/extensions/gsd/context-store.ts +25 -8
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/forensics.ts +118 -1
- package/src/resources/extensions/gsd/gate-registry.ts +2 -2
- package/src/resources/extensions/gsd/git-constants.ts +30 -1
- package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
- package/src/resources/extensions/gsd/git-service.ts +149 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +57 -14
- package/src/resources/extensions/gsd/journal.ts +11 -1
- package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
- package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
- package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/session-lock.ts +20 -10
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
- package/src/resources/extensions/gsd/state.ts +76 -66
- package/src/resources/extensions/gsd/sync-lock.ts +97 -39
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
- package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
- package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
- package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
- package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
- package/src/resources/extensions/gsd/types.ts +3 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
- package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
- package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
- package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
- package/src/resources/extensions/gsd/uok/writer.ts +113 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
- package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
- package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
- package/src/resources/extensions/mcp-client/index.ts +3 -1
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
- package/src/resources/extensions/ollama/index.ts +5 -1
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
- package/src/resources/extensions/remote-questions/manager.ts +36 -4
- package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
- package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
nativeDiffNameStatus,
|
|
31
31
|
nativeDiffNumstat,
|
|
32
32
|
nativeGetCurrentBranch,
|
|
33
|
+
nativeIsAncestor,
|
|
33
34
|
nativeLogOneline,
|
|
34
35
|
nativeMergeSquash,
|
|
35
36
|
nativeWorktreeAdd,
|
|
@@ -37,6 +38,7 @@ import {
|
|
|
37
38
|
nativeWorktreePrune,
|
|
38
39
|
nativeWorktreeRemove,
|
|
39
40
|
} from "./native-git-bridge.js";
|
|
41
|
+
import { emitCanonicalRootRedirect } from "./worktree-telemetry.js";
|
|
40
42
|
|
|
41
43
|
// ─── Types ─────────────────────────────────────────────────────────────────
|
|
42
44
|
|
|
@@ -132,6 +134,58 @@ export function isInsideWorktreesDir(basePath: string, targetPath: string): bool
|
|
|
132
134
|
return resolved === wtDir || resolved.startsWith(wtDir + sep);
|
|
133
135
|
}
|
|
134
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Return the canonical path from which a milestone's artifacts should be read.
|
|
139
|
+
*
|
|
140
|
+
* If a live git worktree exists for this milestone at `.gsd/worktrees/<MID>/`
|
|
141
|
+
* (directory present AND a `.git` file indicating a registered worktree),
|
|
142
|
+
* returns that worktree path. Otherwise returns `basePath` unchanged.
|
|
143
|
+
*
|
|
144
|
+
* Readers that cross the session/worktree boundary (validators, the bootstrap
|
|
145
|
+
* audit, cross-session state queries) should route through this helper so they
|
|
146
|
+
* don't silently read stale project-root state while live work sits in the
|
|
147
|
+
* worktree. Writers and tools whose contract is "operate on the path I was
|
|
148
|
+
* given" should NOT use this helper — they preserve the legacy behavior.
|
|
149
|
+
*
|
|
150
|
+
* A stale worktree directory (no `.git` file) is treated as absent. The
|
|
151
|
+
* createWorktree() path already cleans these up, but readers must not trust
|
|
152
|
+
* them in the window before cleanup runs.
|
|
153
|
+
*
|
|
154
|
+
* Fixes #4761. Used by the #4762 audit for the pre-completion orphan case.
|
|
155
|
+
*/
|
|
156
|
+
export function resolveCanonicalMilestoneRoot(
|
|
157
|
+
basePath: string,
|
|
158
|
+
milestoneId: string,
|
|
159
|
+
): string {
|
|
160
|
+
if (!milestoneId || /[\/\\]|\.\./.test(milestoneId)) return basePath;
|
|
161
|
+
|
|
162
|
+
const wtPath = worktreePath(basePath, milestoneId);
|
|
163
|
+
if (!existsSync(wtPath)) return basePath;
|
|
164
|
+
|
|
165
|
+
// A registered git worktree has a .git *file* (not directory) containing
|
|
166
|
+
// "gitdir: <path>". A standalone .git directory indicates a copied repo
|
|
167
|
+
// or nested standalone repo — not a worktree registered with this project —
|
|
168
|
+
// and must not be treated as the canonical root.
|
|
169
|
+
const gitPath = join(wtPath, ".git");
|
|
170
|
+
if (!existsSync(gitPath)) return basePath;
|
|
171
|
+
try {
|
|
172
|
+
const stat = lstatSync(gitPath);
|
|
173
|
+
if (!stat.isFile()) return basePath;
|
|
174
|
+
} catch {
|
|
175
|
+
return basePath;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// #4764 — record the redirect so we can measure how often the #4761 fix
|
|
179
|
+
// would have mattered. Best-effort; emit is silent on any failure.
|
|
180
|
+
try {
|
|
181
|
+
emitCanonicalRootRedirect(basePath, milestoneId, wtPath);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
logWarning("worktree", `canonical-root-redirect telemetry failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return wtPath;
|
|
187
|
+
}
|
|
188
|
+
|
|
135
189
|
// ─── Core Operations ───────────────────────────────────────────────────────
|
|
136
190
|
|
|
137
191
|
/**
|
|
@@ -174,6 +228,17 @@ export function createWorktree(basePath: string, name: string, opts: { branch?:
|
|
|
174
228
|
// otherwise fall back to the repo's detected main branch.
|
|
175
229
|
const startPoint = opts.startPoint ?? nativeDetectMainBranch(basePath);
|
|
176
230
|
|
|
231
|
+
// Reject early if startPoint resolves to an empty/invalid ref. On an
|
|
232
|
+
// unborn branch (zero-commit repo) nativeDetectMainBranch returns "",
|
|
233
|
+
// which would flow into `git worktree add ... ""` and crash with
|
|
234
|
+
// `fatal: not a valid object name`. (Issue #4980 HIGH-9)
|
|
235
|
+
if (!startPoint || startPoint.length === 0) {
|
|
236
|
+
throw new GSDError(
|
|
237
|
+
GSD_GIT_ERROR,
|
|
238
|
+
"Repository has no commits yet (unborn branch). Make an initial commit before creating worktrees.",
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
177
242
|
// Check if the branch already exists (leftover from a previous worktree)
|
|
178
243
|
const branchAlreadyExists = nativeBranchExists(basePath, branch);
|
|
179
244
|
|
|
@@ -196,6 +261,21 @@ export function createWorktree(basePath: string, name: string, opts: { branch?:
|
|
|
196
261
|
// from prior sessions that must not be reset.
|
|
197
262
|
nativeWorktreeAdd(basePath, wtPath, branch);
|
|
198
263
|
} else {
|
|
264
|
+
// Ancestry guard: refuse to force-reset a branch that has commits not
|
|
265
|
+
// reachable from startPoint. A crash-then-resume cycle that didn't
|
|
266
|
+
// write the resume file would silently orphan prior-session commits
|
|
267
|
+
// (recoverable from reflog for 90d, then gone — branch is also
|
|
268
|
+
// deleted at teardown). (Issue #4980 HIGH-3)
|
|
269
|
+
const branchIsAncestor = nativeIsAncestor(basePath, branch, startPoint);
|
|
270
|
+
if (!branchIsAncestor) {
|
|
271
|
+
throw new GSDError(
|
|
272
|
+
GSD_GIT_ERROR,
|
|
273
|
+
`Branch "${branch}" already exists with commits not reachable from "${startPoint}". ` +
|
|
274
|
+
`Refusing to force-reset — would orphan prior work. ` +
|
|
275
|
+
`If you intend to keep those commits, retry with reuseExistingBranch=true. ` +
|
|
276
|
+
`If you intend to discard, run \`git branch -D ${branch}\` manually first.`,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
199
279
|
// Reset the stale branch to the start point, then attach worktree to it
|
|
200
280
|
nativeBranchForceReset(basePath, branch, startPoint);
|
|
201
281
|
nativeWorktreeAdd(basePath, wtPath, branch);
|
|
@@ -451,17 +531,38 @@ export function removeWorktree(
|
|
|
451
531
|
(line: string) => line.startsWith("+") || line.startsWith("-"),
|
|
452
532
|
);
|
|
453
533
|
if (hasSubmoduleChanges) {
|
|
454
|
-
//
|
|
455
|
-
//
|
|
534
|
+
// Save submodule changes to a labeled rescue branch instead of the
|
|
535
|
+
// shared stash list. Stash is per-repo (not per-worktree), so an
|
|
536
|
+
// entry created here would appear in the user's main-tree stash
|
|
537
|
+
// list and reference paths that disappear after worktree removal.
|
|
538
|
+
// A branch persists in the shared .git refs after worktree removal
|
|
539
|
+
// and is discoverable via `git branch --list 'gsd/submodule-rescue/*'`.
|
|
540
|
+
// (Issue #4980 HIGH-11)
|
|
541
|
+
const rescueBranch = `gsd/submodule-rescue/${name}-${Date.now()}`;
|
|
456
542
|
try {
|
|
457
543
|
execFileSync(
|
|
458
|
-
"git", ["
|
|
544
|
+
"git", ["add", "-A"],
|
|
545
|
+
{ cwd: resolvedWtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
546
|
+
);
|
|
547
|
+
execFileSync(
|
|
548
|
+
"git", ["commit", "-m", `gsd: rescue submodule changes from worktree ${name}`, "--allow-empty"],
|
|
459
549
|
{ cwd: resolvedWtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
460
550
|
);
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
551
|
+
execFileSync(
|
|
552
|
+
"git", ["branch", rescueBranch, "HEAD"],
|
|
553
|
+
{ cwd: resolvedWtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
554
|
+
);
|
|
555
|
+
logWarning(
|
|
556
|
+
"reconcile",
|
|
557
|
+
`Saved uncommitted submodule changes to rescue branch ${rescueBranch}`,
|
|
558
|
+
{ worktree: name, path: resolvedWtPath, rescueBranch },
|
|
559
|
+
);
|
|
560
|
+
} catch (err) {
|
|
561
|
+
logWarning(
|
|
562
|
+
"reconcile",
|
|
563
|
+
`Submodule rescue branch creation failed — changes may be lost during force removal: ${err instanceof Error ? err.message : String(err)}`,
|
|
564
|
+
{ worktree: name, path: resolvedWtPath },
|
|
565
|
+
);
|
|
465
566
|
}
|
|
466
567
|
}
|
|
467
568
|
} catch (e) {
|
|
@@ -20,6 +20,9 @@ import type { AutoSession } from "./auto/session.js";
|
|
|
20
20
|
import { debugLog } from "./debug-logger.js";
|
|
21
21
|
import { MergeConflictError } from "./git-service.js";
|
|
22
22
|
import { emitJournalEvent } from "./journal.js";
|
|
23
|
+
import { emitWorktreeCreated, emitWorktreeMerged } from "./worktree-telemetry.js";
|
|
24
|
+
import { getCollapseCadence, getMilestoneResquash, resquashMilestoneOnMain } from "./slice-cadence.js";
|
|
25
|
+
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
23
26
|
|
|
24
27
|
// ─── Dependency Interface ──────────────────────────────────────────────────
|
|
25
28
|
|
|
@@ -290,6 +293,19 @@ export class WorktreeResolver {
|
|
|
290
293
|
eventType: "worktree-enter",
|
|
291
294
|
data: { milestoneId, wtPath, created: !existingPath },
|
|
292
295
|
});
|
|
296
|
+
// #4764 — record creation/enter as a lifecycle event so the telemetry
|
|
297
|
+
// aggregator can pair it with the eventual worktree-merged event.
|
|
298
|
+
try {
|
|
299
|
+
emitWorktreeCreated(this.s.originalBasePath || this.s.basePath, milestoneId, {
|
|
300
|
+
reason: existingPath ? "enter-milestone" : "create-milestone",
|
|
301
|
+
});
|
|
302
|
+
} catch (telemetryErr) {
|
|
303
|
+
debugLog("WorktreeResolver", {
|
|
304
|
+
action: "enterMilestone",
|
|
305
|
+
phase: "telemetry-emit",
|
|
306
|
+
error: telemetryErr instanceof Error ? telemetryErr.message : String(telemetryErr),
|
|
307
|
+
});
|
|
308
|
+
}
|
|
293
309
|
ctx.notify(`Entered worktree for ${milestoneId} at ${wtPath}`, "info");
|
|
294
310
|
} catch (err) {
|
|
295
311
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -398,6 +414,10 @@ export class WorktreeResolver {
|
|
|
398
414
|
mergeAndExit(milestoneId: string, ctx: NotifyCtx): void {
|
|
399
415
|
this.validateMilestoneId(milestoneId);
|
|
400
416
|
|
|
417
|
+
// #4764 — telemetry: record start timestamp so we can emit merge duration.
|
|
418
|
+
const mergeStartedAt = new Date().toISOString();
|
|
419
|
+
const mergeStartMs = Date.now();
|
|
420
|
+
|
|
401
421
|
// If worktree creation failed earlier, skip merge — work is on current branch (#2483)
|
|
402
422
|
if (this.s.isolationDegraded) {
|
|
403
423
|
debugLog("WorktreeResolver", {
|
|
@@ -444,17 +464,79 @@ export class WorktreeResolver {
|
|
|
444
464
|
return;
|
|
445
465
|
}
|
|
446
466
|
|
|
467
|
+
let actuallyMerged = false;
|
|
447
468
|
if (
|
|
448
469
|
mode === "worktree" || inWorktree
|
|
449
470
|
) {
|
|
450
|
-
this._mergeWorktreeMode(milestoneId, ctx);
|
|
471
|
+
actuallyMerged = this._mergeWorktreeMode(milestoneId, ctx);
|
|
451
472
|
} else if (mode === "branch") {
|
|
452
|
-
this._mergeBranchMode(milestoneId, ctx);
|
|
473
|
+
actuallyMerged = this._mergeBranchMode(milestoneId, ctx);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// The remainder of this function emits telemetry and runs re-squash.
|
|
477
|
+
// Both are gated on actuallyMerged — if the _merge* helper took a
|
|
478
|
+
// no-merge path (missing originalBase, no roadmap, wrong branch) the
|
|
479
|
+
// milestone branch was intentionally left unmerged and we must not
|
|
480
|
+
// emit a worktree-merged event or collapse commits on main.
|
|
481
|
+
if (!actuallyMerged) {
|
|
482
|
+
// Always clear the start-SHA tracker to avoid leaking across sessions.
|
|
483
|
+
this.s.milestoneStartShas.delete(milestoneId);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// #4765 — when collapse_cadence=slice AND milestone_resquash=true, the
|
|
488
|
+
// N per-slice commits on main should be collapsed into one milestone
|
|
489
|
+
// commit. Done AFTER the primary merge-and-teardown so the branch and
|
|
490
|
+
// worktree are already cleaned up; we operate on main directly.
|
|
491
|
+
try {
|
|
492
|
+
const startSha = this.s.milestoneStartShas.get(milestoneId);
|
|
493
|
+
if (startSha) {
|
|
494
|
+
const prefs = loadEffectiveGSDPreferences(this.s.originalBasePath || this.s.basePath)?.preferences;
|
|
495
|
+
if (getCollapseCadence(prefs) === "slice" && getMilestoneResquash(prefs)) {
|
|
496
|
+
const result = resquashMilestoneOnMain(
|
|
497
|
+
this.s.originalBasePath || this.s.basePath,
|
|
498
|
+
milestoneId,
|
|
499
|
+
startSha,
|
|
500
|
+
);
|
|
501
|
+
if (result.resquashed) {
|
|
502
|
+
ctx.notify(
|
|
503
|
+
`slice-cadence: re-squashed slice commits for ${milestoneId} into a single milestone commit.`,
|
|
504
|
+
"info",
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
this.s.milestoneStartShas.delete(milestoneId);
|
|
509
|
+
}
|
|
510
|
+
} catch (err) {
|
|
511
|
+
debugLog("WorktreeResolver", {
|
|
512
|
+
action: "mergeAndExit",
|
|
513
|
+
milestoneId,
|
|
514
|
+
phase: "resquash",
|
|
515
|
+
error: err instanceof Error ? err.message : String(err),
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// #4764 — record merge completion. Only reaches here when an actual
|
|
520
|
+
// merge ran; failure paths throw out of _merge* before this point and
|
|
521
|
+
// no-merge paths returned above.
|
|
522
|
+
try {
|
|
523
|
+
emitWorktreeMerged(this.s.originalBasePath || this.s.basePath, milestoneId, {
|
|
524
|
+
reason: "milestone-complete",
|
|
525
|
+
startedAt: mergeStartedAt,
|
|
526
|
+
durationMs: Date.now() - mergeStartMs,
|
|
527
|
+
});
|
|
528
|
+
} catch (telemetryErr) {
|
|
529
|
+
debugLog("WorktreeResolver", {
|
|
530
|
+
action: "mergeAndExit",
|
|
531
|
+
phase: "telemetry-emit",
|
|
532
|
+
error: telemetryErr instanceof Error ? telemetryErr.message : String(telemetryErr),
|
|
533
|
+
});
|
|
453
534
|
}
|
|
454
535
|
}
|
|
455
536
|
|
|
456
|
-
/** Worktree-mode merge: read roadmap, merge, teardown, reset paths.
|
|
457
|
-
|
|
537
|
+
/** Worktree-mode merge: read roadmap, merge, teardown, reset paths.
|
|
538
|
+
* Returns true when a squash-merge actually ran (false on skip paths). */
|
|
539
|
+
private _mergeWorktreeMode(milestoneId: string, ctx: NotifyCtx): boolean {
|
|
458
540
|
const originalBase = this.s.originalBasePath;
|
|
459
541
|
if (!originalBase) {
|
|
460
542
|
debugLog("WorktreeResolver", {
|
|
@@ -464,9 +546,10 @@ export class WorktreeResolver {
|
|
|
464
546
|
skipped: true,
|
|
465
547
|
reason: "missing-original-base",
|
|
466
548
|
});
|
|
467
|
-
return;
|
|
549
|
+
return false;
|
|
468
550
|
}
|
|
469
551
|
|
|
552
|
+
let merged = false;
|
|
470
553
|
try {
|
|
471
554
|
const { synced } = this.deps.syncWorktreeStateBack(
|
|
472
555
|
originalBase,
|
|
@@ -515,6 +598,7 @@ export class WorktreeResolver {
|
|
|
515
598
|
milestoneId,
|
|
516
599
|
roadmapContent,
|
|
517
600
|
);
|
|
601
|
+
merged = true;
|
|
518
602
|
|
|
519
603
|
// #2945 Bug 3: mergeMilestoneToMain performs best-effort worktree
|
|
520
604
|
// cleanup internally (step 12), but it can silently fail on Windows
|
|
@@ -618,10 +702,12 @@ export class WorktreeResolver {
|
|
|
618
702
|
result: "done",
|
|
619
703
|
basePath: this.s.basePath,
|
|
620
704
|
});
|
|
705
|
+
return merged;
|
|
621
706
|
}
|
|
622
707
|
|
|
623
|
-
/** Branch-mode merge: check current branch, merge if on milestone branch.
|
|
624
|
-
|
|
708
|
+
/** Branch-mode merge: check current branch, merge if on milestone branch.
|
|
709
|
+
* Returns true when a merge actually ran (false on skip paths). */
|
|
710
|
+
private _mergeBranchMode(milestoneId: string, ctx: NotifyCtx): boolean {
|
|
625
711
|
try {
|
|
626
712
|
const currentBranch = this.deps.getCurrentBranch(this.s.basePath);
|
|
627
713
|
const milestoneBranch = this.deps.autoWorktreeBranch(milestoneId);
|
|
@@ -636,7 +722,7 @@ export class WorktreeResolver {
|
|
|
636
722
|
currentBranch,
|
|
637
723
|
milestoneBranch,
|
|
638
724
|
});
|
|
639
|
-
return;
|
|
725
|
+
return false;
|
|
640
726
|
}
|
|
641
727
|
|
|
642
728
|
const roadmapPath = this.deps.resolveMilestoneFile(
|
|
@@ -652,7 +738,7 @@ export class WorktreeResolver {
|
|
|
652
738
|
skipped: true,
|
|
653
739
|
reason: "no-roadmap",
|
|
654
740
|
});
|
|
655
|
-
return;
|
|
741
|
+
return false;
|
|
656
742
|
}
|
|
657
743
|
|
|
658
744
|
const roadmapContent = this.deps.readFileSync(roadmapPath, "utf-8");
|
|
@@ -683,6 +769,7 @@ export class WorktreeResolver {
|
|
|
683
769
|
mode: "branch",
|
|
684
770
|
result: "success",
|
|
685
771
|
});
|
|
772
|
+
return true;
|
|
686
773
|
} catch (err) {
|
|
687
774
|
const msg = err instanceof Error ? err.message : String(err);
|
|
688
775
|
debugLog("WorktreeResolver", {
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree telemetry — #4764
|
|
3
|
+
*
|
|
4
|
+
* Thin emit helpers + aggregator on top of the existing journal. Separate
|
|
5
|
+
* module so callers import a tiny surface and don't have to assemble
|
|
6
|
+
* JournalEntry records by hand. Kernighan: the underlying emit path
|
|
7
|
+
* (emitJournalEvent) is already battle-tested; this module is just
|
|
8
|
+
* structured call sites + a summarizer.
|
|
9
|
+
*
|
|
10
|
+
* Emitted event types (see journal.ts):
|
|
11
|
+
* - worktree-created worktree entered/created for a milestone
|
|
12
|
+
* - worktree-merged worktree merge back to main completed
|
|
13
|
+
* - worktree-orphaned audit detected an orphaned branch/worktree
|
|
14
|
+
* - auto-exit auto-mode exited (pause/stop/blocked/error)
|
|
15
|
+
* - worktree-sync syncStateToProjectRoot snapshot
|
|
16
|
+
* - canonical-root-redirect resolveCanonicalMilestoneRoot redirected
|
|
17
|
+
*
|
|
18
|
+
* These events are purely observational. They never block, never throw,
|
|
19
|
+
* and never carry code content — only IDs, counts, durations, and reasons.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { randomUUID } from "node:crypto";
|
|
23
|
+
import { emitJournalEvent, queryJournal } from "./journal.js";
|
|
24
|
+
import type { JournalEntry } from "./journal.js";
|
|
25
|
+
|
|
26
|
+
function now(): string {
|
|
27
|
+
return new Date().toISOString();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function baseEntry(eventType: JournalEntry["eventType"], data: Record<string, unknown>): JournalEntry {
|
|
31
|
+
return {
|
|
32
|
+
ts: now(),
|
|
33
|
+
flowId: (typeof data.flowId === "string" ? data.flowId : undefined) ?? randomUUID(),
|
|
34
|
+
seq: typeof data.seq === "number" ? data.seq : 0,
|
|
35
|
+
eventType,
|
|
36
|
+
data,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ─── Reason literal unions ───────────────────────────────────────────────
|
|
41
|
+
// Closed sets so typos at call sites are rejected at compile time and can't
|
|
42
|
+
// silently fragment the telemetry buckets produced by summarizeWorktreeTelemetry.
|
|
43
|
+
|
|
44
|
+
export type WorktreeCreatedReason = "create-milestone" | "enter-milestone";
|
|
45
|
+
export type AutoExitReason =
|
|
46
|
+
| "pause"
|
|
47
|
+
| "stop"
|
|
48
|
+
| "blocked"
|
|
49
|
+
| "merge-conflict"
|
|
50
|
+
| "merge-failed"
|
|
51
|
+
| "slice-merge-conflict"
|
|
52
|
+
| "all-complete"
|
|
53
|
+
| "no-active-milestone"
|
|
54
|
+
| "other";
|
|
55
|
+
|
|
56
|
+
// ─── Emitters ────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
export function emitWorktreeCreated(
|
|
59
|
+
projectRoot: string,
|
|
60
|
+
milestoneId: string,
|
|
61
|
+
meta: { flowId?: string; reason?: WorktreeCreatedReason } = {},
|
|
62
|
+
): void {
|
|
63
|
+
emitJournalEvent(projectRoot, baseEntry("worktree-created", {
|
|
64
|
+
milestoneId,
|
|
65
|
+
startedAt: now(),
|
|
66
|
+
flowId: meta.flowId,
|
|
67
|
+
reason: meta.reason ?? "enter-milestone",
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function emitWorktreeMerged(
|
|
72
|
+
projectRoot: string,
|
|
73
|
+
milestoneId: string,
|
|
74
|
+
meta: {
|
|
75
|
+
flowId?: string;
|
|
76
|
+
reason?: "milestone-complete" | "all-complete" | "stop-fallback" | "transition" | "other";
|
|
77
|
+
startedAt?: string;
|
|
78
|
+
durationMs?: number;
|
|
79
|
+
sliceCount?: number;
|
|
80
|
+
taskCount?: number;
|
|
81
|
+
conflict?: boolean;
|
|
82
|
+
conflictedFiles?: number;
|
|
83
|
+
} = {},
|
|
84
|
+
): void {
|
|
85
|
+
emitJournalEvent(projectRoot, baseEntry("worktree-merged", {
|
|
86
|
+
milestoneId,
|
|
87
|
+
endedAt: now(),
|
|
88
|
+
flowId: meta.flowId,
|
|
89
|
+
reason: meta.reason ?? "other",
|
|
90
|
+
startedAt: meta.startedAt,
|
|
91
|
+
durationMs: meta.durationMs,
|
|
92
|
+
sliceCount: meta.sliceCount,
|
|
93
|
+
taskCount: meta.taskCount,
|
|
94
|
+
conflict: meta.conflict ?? false,
|
|
95
|
+
conflictedFiles: meta.conflictedFiles ?? 0,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function emitWorktreeOrphaned(
|
|
100
|
+
projectRoot: string,
|
|
101
|
+
milestoneId: string,
|
|
102
|
+
meta: {
|
|
103
|
+
flowId?: string;
|
|
104
|
+
reason: "in-progress-unmerged" | "complete-unmerged" | "stale-branch";
|
|
105
|
+
commitsAhead?: number;
|
|
106
|
+
worktreeDirExists?: boolean;
|
|
107
|
+
},
|
|
108
|
+
): void {
|
|
109
|
+
emitJournalEvent(projectRoot, baseEntry("worktree-orphaned", {
|
|
110
|
+
milestoneId,
|
|
111
|
+
flowId: meta.flowId,
|
|
112
|
+
reason: meta.reason,
|
|
113
|
+
commitsAhead: meta.commitsAhead,
|
|
114
|
+
worktreeDirExists: meta.worktreeDirExists ?? false,
|
|
115
|
+
detectedAt: now(),
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function emitAutoExit(
|
|
120
|
+
projectRoot: string,
|
|
121
|
+
meta: {
|
|
122
|
+
flowId?: string;
|
|
123
|
+
/** Must come from the closed AutoExitReason set. Callers with free-form
|
|
124
|
+
* reasons (e.g. stopAuto's `reason?: string` parameter) should map to
|
|
125
|
+
* the closed set before emitting. */
|
|
126
|
+
reason: AutoExitReason;
|
|
127
|
+
milestoneId?: string;
|
|
128
|
+
milestoneMerged: boolean;
|
|
129
|
+
},
|
|
130
|
+
): void {
|
|
131
|
+
emitJournalEvent(projectRoot, baseEntry("auto-exit", {
|
|
132
|
+
reason: meta.reason,
|
|
133
|
+
flowId: meta.flowId,
|
|
134
|
+
milestoneId: meta.milestoneId,
|
|
135
|
+
milestoneMerged: meta.milestoneMerged,
|
|
136
|
+
exitedAt: now(),
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function emitWorktreeSync(
|
|
141
|
+
projectRoot: string,
|
|
142
|
+
milestoneId: string,
|
|
143
|
+
meta: {
|
|
144
|
+
flowId?: string;
|
|
145
|
+
filesCopied?: number;
|
|
146
|
+
bytesCopied?: number;
|
|
147
|
+
commitsAhead?: number;
|
|
148
|
+
worktreeAgeMs?: number;
|
|
149
|
+
},
|
|
150
|
+
): void {
|
|
151
|
+
emitJournalEvent(projectRoot, baseEntry("worktree-sync", {
|
|
152
|
+
milestoneId,
|
|
153
|
+
flowId: meta.flowId,
|
|
154
|
+
filesCopied: meta.filesCopied,
|
|
155
|
+
bytesCopied: meta.bytesCopied,
|
|
156
|
+
commitsAhead: meta.commitsAhead,
|
|
157
|
+
worktreeAgeMs: meta.worktreeAgeMs,
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function emitCanonicalRootRedirect(
|
|
162
|
+
projectRoot: string,
|
|
163
|
+
milestoneId: string,
|
|
164
|
+
redirectedTo: string,
|
|
165
|
+
meta: { flowId?: string } = {},
|
|
166
|
+
): void {
|
|
167
|
+
emitJournalEvent(projectRoot, baseEntry("canonical-root-redirect", {
|
|
168
|
+
milestoneId,
|
|
169
|
+
redirectedTo,
|
|
170
|
+
flowId: meta.flowId,
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// #4765 — slice-cadence collapse events
|
|
175
|
+
|
|
176
|
+
export function emitSliceMerged(
|
|
177
|
+
projectRoot: string,
|
|
178
|
+
milestoneId: string,
|
|
179
|
+
sliceId: string,
|
|
180
|
+
meta: { durationMs?: number; conflict?: boolean; commitSha?: string; flowId?: string } = {},
|
|
181
|
+
): void {
|
|
182
|
+
emitJournalEvent(projectRoot, baseEntry("slice-merged", {
|
|
183
|
+
milestoneId,
|
|
184
|
+
sliceId,
|
|
185
|
+
mergedAt: now(),
|
|
186
|
+
durationMs: meta.durationMs,
|
|
187
|
+
conflict: meta.conflict ?? false,
|
|
188
|
+
commitSha: meta.commitSha,
|
|
189
|
+
flowId: meta.flowId,
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function emitMilestoneResquash(
|
|
194
|
+
projectRoot: string,
|
|
195
|
+
milestoneId: string,
|
|
196
|
+
meta: { sliceCount: number; startSha?: string; endSha?: string; flowId?: string } = { sliceCount: 0 },
|
|
197
|
+
): void {
|
|
198
|
+
emitJournalEvent(projectRoot, baseEntry("milestone-resquash", {
|
|
199
|
+
milestoneId,
|
|
200
|
+
sliceCount: meta.sliceCount,
|
|
201
|
+
startSha: meta.startSha,
|
|
202
|
+
endSha: meta.endSha,
|
|
203
|
+
resquashedAt: now(),
|
|
204
|
+
flowId: meta.flowId,
|
|
205
|
+
}));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ─── Aggregator ──────────────────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
export interface WorktreeTelemetrySummary {
|
|
211
|
+
/** Count of worktrees created within the window */
|
|
212
|
+
worktreesCreated: number;
|
|
213
|
+
/** Count of worktrees merged within the window */
|
|
214
|
+
worktreesMerged: number;
|
|
215
|
+
/** Count of orphan detections within the window */
|
|
216
|
+
orphansDetected: number;
|
|
217
|
+
/** Breakdown by orphan reason */
|
|
218
|
+
orphansByReason: Record<string, number>;
|
|
219
|
+
/** Merge durations in milliseconds, sorted ascending */
|
|
220
|
+
mergeDurationsMs: number[];
|
|
221
|
+
/** Number of merges that hit a conflict */
|
|
222
|
+
mergeConflicts: number;
|
|
223
|
+
/** Auto-exit reasons and their counts */
|
|
224
|
+
exitsByReason: Record<string, number>;
|
|
225
|
+
/** Auto-exits where the milestone was NOT merged before exit — the #4761 producer metric */
|
|
226
|
+
exitsWithUnmergedWork: number;
|
|
227
|
+
/** Count of canonical-root-redirects (how often #4761 validation would have read stale state) */
|
|
228
|
+
canonicalRedirects: number;
|
|
229
|
+
/** #4765 — count of successful slice-level merges (slice-cadence feature) */
|
|
230
|
+
slicesMerged: number;
|
|
231
|
+
/** #4765 — count of slice-level merge conflicts */
|
|
232
|
+
sliceMergeConflicts: number;
|
|
233
|
+
/** #4765 — count of milestone-level re-squash operations */
|
|
234
|
+
milestoneResquashes: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Summarize worktree telemetry across the journal. Optional time window
|
|
239
|
+
* via filters.after / filters.before (ISO-8601).
|
|
240
|
+
*/
|
|
241
|
+
export function summarizeWorktreeTelemetry(
|
|
242
|
+
projectRoot: string,
|
|
243
|
+
filters?: { after?: string; before?: string },
|
|
244
|
+
): WorktreeTelemetrySummary {
|
|
245
|
+
const entries = queryJournal(projectRoot, filters);
|
|
246
|
+
|
|
247
|
+
const summary: WorktreeTelemetrySummary = {
|
|
248
|
+
worktreesCreated: 0,
|
|
249
|
+
worktreesMerged: 0,
|
|
250
|
+
orphansDetected: 0,
|
|
251
|
+
orphansByReason: {},
|
|
252
|
+
mergeDurationsMs: [],
|
|
253
|
+
mergeConflicts: 0,
|
|
254
|
+
exitsByReason: {},
|
|
255
|
+
exitsWithUnmergedWork: 0,
|
|
256
|
+
canonicalRedirects: 0,
|
|
257
|
+
slicesMerged: 0,
|
|
258
|
+
sliceMergeConflicts: 0,
|
|
259
|
+
milestoneResquashes: 0,
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
for (const e of entries) {
|
|
263
|
+
const d = e.data ?? {};
|
|
264
|
+
switch (e.eventType) {
|
|
265
|
+
case "worktree-created":
|
|
266
|
+
summary.worktreesCreated++;
|
|
267
|
+
break;
|
|
268
|
+
case "worktree-merged":
|
|
269
|
+
summary.worktreesMerged++;
|
|
270
|
+
if (typeof d.durationMs === "number") summary.mergeDurationsMs.push(d.durationMs);
|
|
271
|
+
if (d.conflict === true) summary.mergeConflicts++;
|
|
272
|
+
break;
|
|
273
|
+
case "worktree-orphaned": {
|
|
274
|
+
summary.orphansDetected++;
|
|
275
|
+
const reason = typeof d.reason === "string" ? d.reason : "unknown";
|
|
276
|
+
summary.orphansByReason[reason] = (summary.orphansByReason[reason] ?? 0) + 1;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
case "auto-exit": {
|
|
280
|
+
const reason = typeof d.reason === "string" ? d.reason : "unknown";
|
|
281
|
+
summary.exitsByReason[reason] = (summary.exitsByReason[reason] ?? 0) + 1;
|
|
282
|
+
if (d.milestoneMerged === false) summary.exitsWithUnmergedWork++;
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
case "canonical-root-redirect":
|
|
286
|
+
summary.canonicalRedirects++;
|
|
287
|
+
break;
|
|
288
|
+
case "slice-merged":
|
|
289
|
+
summary.slicesMerged++;
|
|
290
|
+
if (d.conflict === true) summary.sliceMergeConflicts++;
|
|
291
|
+
break;
|
|
292
|
+
case "milestone-resquash":
|
|
293
|
+
summary.milestoneResquashes++;
|
|
294
|
+
break;
|
|
295
|
+
default:
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
summary.mergeDurationsMs.sort((a, b) => a - b);
|
|
301
|
+
return summary;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Return the p{quantile} of a sorted array using the nearest-rank method.
|
|
306
|
+
* Quantile in [0,1].
|
|
307
|
+
*
|
|
308
|
+
* Prior implementation used Math.floor(q*n), which overstates exact-rank
|
|
309
|
+
* quantiles by one sample (e.g. p95 of 20 values returned the max instead
|
|
310
|
+
* of the 19th value). The nearest-rank index is ceil(q*n) - 1, clamped to
|
|
311
|
+
* [0, n-1].
|
|
312
|
+
*/
|
|
313
|
+
export function percentile(sortedValues: number[], q: number): number | null {
|
|
314
|
+
if (sortedValues.length === 0) return null;
|
|
315
|
+
if (q <= 0) return sortedValues[0];
|
|
316
|
+
if (q >= 1) return sortedValues[sortedValues.length - 1];
|
|
317
|
+
const idx = Math.min(
|
|
318
|
+
sortedValues.length - 1,
|
|
319
|
+
Math.max(0, Math.ceil(q * sortedValues.length) - 1),
|
|
320
|
+
);
|
|
321
|
+
return sortedValues[idx];
|
|
322
|
+
}
|
|
@@ -203,7 +203,9 @@ async function assertTrustedStdioServer(
|
|
|
203
203
|
return trustKey;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
// Exported for tests (see tests/server-name-spaces.test.ts).
|
|
207
|
+
// Production call sites treat this as module-private.
|
|
208
|
+
export function getServerConfig(name: string): McpServerConfig | undefined {
|
|
207
209
|
const trimmed = name.trim();
|
|
208
210
|
return readConfigs().find((s) =>
|
|
209
211
|
s.name === trimmed ||
|