@chances-ai/engine 24.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/discover.d.ts +30 -0
- package/dist/agents/discover.d.ts.map +1 -0
- package/dist/agents/discover.js +183 -0
- package/dist/agents/discover.js.map +1 -0
- package/dist/agents/index.d.ts +20 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +52 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/parse.d.ts +61 -0
- package/dist/agents/parse.d.ts.map +1 -0
- package/dist/agents/parse.js +527 -0
- package/dist/agents/parse.js.map +1 -0
- package/dist/agents/types.d.ts +52 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +8 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/ai/adapters/ai-sdk-stream.d.ts +19 -0
- package/dist/ai/adapters/ai-sdk-stream.d.ts.map +1 -0
- package/dist/ai/adapters/ai-sdk-stream.js +125 -0
- package/dist/ai/adapters/ai-sdk-stream.js.map +1 -0
- package/dist/ai/adapters/ai-sdk.d.ts +56 -0
- package/dist/ai/adapters/ai-sdk.d.ts.map +1 -0
- package/dist/ai/adapters/ai-sdk.js +112 -0
- package/dist/ai/adapters/ai-sdk.js.map +1 -0
- package/dist/ai/adapters/mock.d.ts +13 -0
- package/dist/ai/adapters/mock.d.ts.map +1 -0
- package/dist/ai/adapters/mock.js +54 -0
- package/dist/ai/adapters/mock.js.map +1 -0
- package/dist/ai/adapters/openai-compatible.d.ts +23 -0
- package/dist/ai/adapters/openai-compatible.d.ts.map +1 -0
- package/dist/ai/adapters/openai-compatible.js +45 -0
- package/dist/ai/adapters/openai-compatible.js.map +1 -0
- package/dist/ai/cost.d.ts +3 -0
- package/dist/ai/cost.d.ts.map +1 -0
- package/dist/ai/cost.js +5 -0
- package/dist/ai/cost.js.map +1 -0
- package/dist/ai/index.d.ts +12 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +11 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/known-models.d.ts +20 -0
- package/dist/ai/known-models.d.ts.map +1 -0
- package/dist/ai/known-models.js +129 -0
- package/dist/ai/known-models.js.map +1 -0
- package/dist/ai/registry.d.ts +12 -0
- package/dist/ai/registry.d.ts.map +1 -0
- package/dist/ai/registry.js +24 -0
- package/dist/ai/registry.js.map +1 -0
- package/dist/ai/retry.d.ts +11 -0
- package/dist/ai/retry.d.ts.map +1 -0
- package/dist/ai/retry.js +14 -0
- package/dist/ai/retry.js.map +1 -0
- package/dist/ai/router.d.ts +25 -0
- package/dist/ai/router.d.ts.map +1 -0
- package/dist/ai/router.js +36 -0
- package/dist/ai/router.js.map +1 -0
- package/dist/ai/setup.d.ts +23 -0
- package/dist/ai/setup.d.ts.map +1 -0
- package/dist/ai/setup.js +47 -0
- package/dist/ai/setup.js.map +1 -0
- package/dist/ai/summarizer.d.ts +24 -0
- package/dist/ai/summarizer.d.ts.map +1 -0
- package/dist/ai/summarizer.js +56 -0
- package/dist/ai/summarizer.js.map +1 -0
- package/dist/ai/types.d.ts +83 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/core/compaction/circuit-breaker.d.ts +32 -0
- package/dist/core/compaction/circuit-breaker.d.ts.map +1 -0
- package/dist/core/compaction/circuit-breaker.js +42 -0
- package/dist/core/compaction/circuit-breaker.js.map +1 -0
- package/dist/core/compaction/compactor.d.ts +75 -0
- package/dist/core/compaction/compactor.d.ts.map +1 -0
- package/dist/core/compaction/compactor.js +261 -0
- package/dist/core/compaction/compactor.js.map +1 -0
- package/dist/core/compaction/estimate.d.ts +39 -0
- package/dist/core/compaction/estimate.d.ts.map +1 -0
- package/dist/core/compaction/estimate.js +74 -0
- package/dist/core/compaction/estimate.js.map +1 -0
- package/dist/core/compaction/index.d.ts +5 -0
- package/dist/core/compaction/index.d.ts.map +1 -0
- package/dist/core/compaction/index.js +5 -0
- package/dist/core/compaction/index.js.map +1 -0
- package/dist/core/compaction/prune.d.ts +43 -0
- package/dist/core/compaction/prune.d.ts.map +1 -0
- package/dist/core/compaction/prune.js +51 -0
- package/dist/core/compaction/prune.js.map +1 -0
- package/dist/core/engine.d.ts +268 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +767 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/task-tool.d.ts +175 -0
- package/dist/core/task-tool.d.ts.map +1 -0
- package/dist/core/task-tool.js +901 -0
- package/dist/core/task-tool.js.map +1 -0
- package/dist/core/workspace-query.d.ts +83 -0
- package/dist/core/workspace-query.d.ts.map +1 -0
- package/dist/core/workspace-query.js +217 -0
- package/dist/core/workspace-query.js.map +1 -0
- package/dist/core/worktree/active-marker.d.ts +31 -0
- package/dist/core/worktree/active-marker.d.ts.map +1 -0
- package/dist/core/worktree/active-marker.js +109 -0
- package/dist/core/worktree/active-marker.js.map +1 -0
- package/dist/core/worktree/create.d.ts +40 -0
- package/dist/core/worktree/create.d.ts.map +1 -0
- package/dist/core/worktree/create.js +121 -0
- package/dist/core/worktree/create.js.map +1 -0
- package/dist/core/worktree/errors.d.ts +7 -0
- package/dist/core/worktree/errors.d.ts.map +1 -0
- package/dist/core/worktree/errors.js +11 -0
- package/dist/core/worktree/errors.js.map +1 -0
- package/dist/core/worktree/gc.d.ts +39 -0
- package/dist/core/worktree/gc.d.ts.map +1 -0
- package/dist/core/worktree/gc.js +146 -0
- package/dist/core/worktree/gc.js.map +1 -0
- package/dist/core/worktree/git.d.ts +53 -0
- package/dist/core/worktree/git.d.ts.map +1 -0
- package/dist/core/worktree/git.js +166 -0
- package/dist/core/worktree/git.js.map +1 -0
- package/dist/core/worktree/index.d.ts +8 -0
- package/dist/core/worktree/index.d.ts.map +1 -0
- package/dist/core/worktree/index.js +8 -0
- package/dist/core/worktree/index.js.map +1 -0
- package/dist/core/worktree/paths.d.ts +26 -0
- package/dist/core/worktree/paths.d.ts.map +1 -0
- package/dist/core/worktree/paths.js +57 -0
- package/dist/core/worktree/paths.js.map +1 -0
- package/dist/core/worktree/slug.d.ts +6 -0
- package/dist/core/worktree/slug.d.ts.map +1 -0
- package/dist/core/worktree/slug.js +21 -0
- package/dist/core/worktree/slug.js.map +1 -0
- package/dist/local-vault/file-store.d.ts +64 -0
- package/dist/local-vault/file-store.d.ts.map +1 -0
- package/dist/local-vault/file-store.js +225 -0
- package/dist/local-vault/file-store.js.map +1 -0
- package/dist/local-vault/index.d.ts +57 -0
- package/dist/local-vault/index.d.ts.map +1 -0
- package/dist/local-vault/index.js +68 -0
- package/dist/local-vault/index.js.map +1 -0
- package/dist/local-vault/keychain.d.ts +58 -0
- package/dist/local-vault/keychain.d.ts.map +1 -0
- package/dist/local-vault/keychain.js +200 -0
- package/dist/local-vault/keychain.js.map +1 -0
- package/dist/local-vault/mutex.d.ts +20 -0
- package/dist/local-vault/mutex.d.ts.map +1 -0
- package/dist/local-vault/mutex.js +44 -0
- package/dist/local-vault/mutex.js.map +1 -0
- package/dist/local-vault/passphrase.d.ts +30 -0
- package/dist/local-vault/passphrase.d.ts.map +1 -0
- package/dist/local-vault/passphrase.js +72 -0
- package/dist/local-vault/passphrase.js.map +1 -0
- package/dist/lsp/config.d.ts +34 -0
- package/dist/lsp/config.d.ts.map +1 -0
- package/dist/lsp/config.js +68 -0
- package/dist/lsp/config.js.map +1 -0
- package/dist/lsp/detect.d.ts +7 -0
- package/dist/lsp/detect.d.ts.map +1 -0
- package/dist/lsp/detect.js +78 -0
- package/dist/lsp/detect.js.map +1 -0
- package/dist/lsp/errors.d.ts +11 -0
- package/dist/lsp/errors.d.ts.map +1 -0
- package/dist/lsp/errors.js +11 -0
- package/dist/lsp/errors.js.map +1 -0
- package/dist/lsp/formatters.d.ts +147 -0
- package/dist/lsp/formatters.d.ts.map +1 -0
- package/dist/lsp/formatters.js +259 -0
- package/dist/lsp/formatters.js.map +1 -0
- package/dist/lsp/index.d.ts +31 -0
- package/dist/lsp/index.d.ts.map +1 -0
- package/dist/lsp/index.js +31 -0
- package/dist/lsp/index.js.map +1 -0
- package/dist/lsp/instance.d.ts +72 -0
- package/dist/lsp/instance.d.ts.map +1 -0
- package/dist/lsp/instance.js +489 -0
- package/dist/lsp/instance.js.map +1 -0
- package/dist/lsp/lazy-load.d.ts +27 -0
- package/dist/lsp/lazy-load.d.ts.map +1 -0
- package/dist/lsp/lazy-load.js +57 -0
- package/dist/lsp/lazy-load.js.map +1 -0
- package/dist/lsp/manager.d.ts +59 -0
- package/dist/lsp/manager.d.ts.map +1 -0
- package/dist/lsp/manager.js +242 -0
- package/dist/lsp/manager.js.map +1 -0
- package/dist/lsp/ops.d.ts +13 -0
- package/dist/lsp/ops.d.ts.map +1 -0
- package/dist/lsp/ops.js +225 -0
- package/dist/lsp/ops.js.map +1 -0
- package/dist/lsp/rpc.d.ts +47 -0
- package/dist/lsp/rpc.d.ts.map +1 -0
- package/dist/lsp/rpc.js +134 -0
- package/dist/lsp/rpc.js.map +1 -0
- package/dist/lsp/safe-uri.d.ts +18 -0
- package/dist/lsp/safe-uri.d.ts.map +1 -0
- package/dist/lsp/safe-uri.js +96 -0
- package/dist/lsp/safe-uri.js.map +1 -0
- package/dist/lsp/types.d.ts +70 -0
- package/dist/lsp/types.d.ts.map +1 -0
- package/dist/lsp/types.js +16 -0
- package/dist/lsp/types.js.map +1 -0
- package/dist/mcp/bridge.d.ts +57 -0
- package/dist/mcp/bridge.d.ts.map +1 -0
- package/dist/mcp/bridge.js +98 -0
- package/dist/mcp/bridge.js.map +1 -0
- package/dist/mcp/category.d.ts +22 -0
- package/dist/mcp/category.d.ts.map +1 -0
- package/dist/mcp/category.js +11 -0
- package/dist/mcp/category.js.map +1 -0
- package/dist/mcp/client.d.ts +228 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +352 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/content.d.ts +86 -0
- package/dist/mcp/content.d.ts.map +1 -0
- package/dist/mcp/content.js +147 -0
- package/dist/mcp/content.js.map +1 -0
- package/dist/mcp/env.d.ts +19 -0
- package/dist/mcp/env.d.ts.map +1 -0
- package/dist/mcp/env.js +50 -0
- package/dist/mcp/env.js.map +1 -0
- package/dist/mcp/host.d.ts +199 -0
- package/dist/mcp/host.d.ts.map +1 -0
- package/dist/mcp/host.js +530 -0
- package/dist/mcp/host.js.map +1 -0
- package/dist/mcp/index.d.ts +18 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +17 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/load-mcp-host.d.ts +32 -0
- package/dist/mcp/load-mcp-host.d.ts.map +1 -0
- package/dist/mcp/load-mcp-host.js +49 -0
- package/dist/mcp/load-mcp-host.js.map +1 -0
- package/dist/mcp/oauth/callback-server.d.ts +73 -0
- package/dist/mcp/oauth/callback-server.d.ts.map +1 -0
- package/dist/mcp/oauth/callback-server.js +280 -0
- package/dist/mcp/oauth/callback-server.js.map +1 -0
- package/dist/mcp/oauth/config-hash.d.ts +24 -0
- package/dist/mcp/oauth/config-hash.d.ts.map +1 -0
- package/dist/mcp/oauth/config-hash.js +55 -0
- package/dist/mcp/oauth/config-hash.js.map +1 -0
- package/dist/mcp/oauth/error-normalize.d.ts +39 -0
- package/dist/mcp/oauth/error-normalize.d.ts.map +1 -0
- package/dist/mcp/oauth/error-normalize.js +91 -0
- package/dist/mcp/oauth/error-normalize.js.map +1 -0
- package/dist/mcp/oauth/provider.d.ts +190 -0
- package/dist/mcp/oauth/provider.d.ts.map +1 -0
- package/dist/mcp/oauth/provider.js +305 -0
- package/dist/mcp/oauth/provider.js.map +1 -0
- package/dist/mcp/oauth/refresh-coalescer.d.ts +46 -0
- package/dist/mcp/oauth/refresh-coalescer.d.ts.map +1 -0
- package/dist/mcp/oauth/refresh-coalescer.js +77 -0
- package/dist/mcp/oauth/refresh-coalescer.js.map +1 -0
- package/dist/mcp/oauth/sdk-shapes.d.ts +77 -0
- package/dist/mcp/oauth/sdk-shapes.d.ts.map +1 -0
- package/dist/mcp/oauth/sdk-shapes.js +21 -0
- package/dist/mcp/oauth/sdk-shapes.js.map +1 -0
- package/dist/mcp/parse.d.ts +28 -0
- package/dist/mcp/parse.d.ts.map +1 -0
- package/dist/mcp/parse.js +209 -0
- package/dist/mcp/parse.js.map +1 -0
- package/dist/mcp/prompts.d.ts +31 -0
- package/dist/mcp/prompts.d.ts.map +1 -0
- package/dist/mcp/prompts.js +71 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/redact.d.ts +62 -0
- package/dist/mcp/redact.d.ts.map +1 -0
- package/dist/mcp/redact.js +87 -0
- package/dist/mcp/redact.js.map +1 -0
- package/dist/mcp/resources.d.ts +70 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +170 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/types.d.ts +123 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +2 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/memory/frontmatter.d.ts +18 -0
- package/dist/memory/frontmatter.d.ts.map +1 -0
- package/dist/memory/frontmatter.js +81 -0
- package/dist/memory/frontmatter.js.map +1 -0
- package/dist/memory/index.d.ts +5 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +5 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/store.d.ts +44 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +237 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/tools.d.ts +11 -0
- package/dist/memory/tools.d.ts.map +1 -0
- package/dist/memory/tools.js +159 -0
- package/dist/memory/tools.js.map +1 -0
- package/dist/memory/types.d.ts +32 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +20 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/plugin-api/index.d.ts +167 -0
- package/dist/plugin-api/index.d.ts.map +1 -0
- package/dist/plugin-api/index.js +151 -0
- package/dist/plugin-api/index.js.map +1 -0
- package/dist/plugin-logger/index.d.ts +21 -0
- package/dist/plugin-logger/index.d.ts.map +1 -0
- package/dist/plugin-logger/index.js +59 -0
- package/dist/plugin-logger/index.js.map +1 -0
- package/dist/session/index.d.ts +125 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +202 -0
- package/dist/session/index.js.map +1 -0
- package/dist/tools/approval.d.ts +33 -0
- package/dist/tools/approval.d.ts.map +1 -0
- package/dist/tools/approval.js +53 -0
- package/dist/tools/approval.js.map +1 -0
- package/dist/tools/builtins/_shared.d.ts +94 -0
- package/dist/tools/builtins/_shared.d.ts.map +1 -0
- package/dist/tools/builtins/_shared.js +246 -0
- package/dist/tools/builtins/_shared.js.map +1 -0
- package/dist/tools/builtins/ask-user-question.d.ts +27 -0
- package/dist/tools/builtins/ask-user-question.d.ts.map +1 -0
- package/dist/tools/builtins/ask-user-question.js +191 -0
- package/dist/tools/builtins/ask-user-question.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts +3 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -0
- package/dist/tools/builtins/bash.js +158 -0
- package/dist/tools/builtins/bash.js.map +1 -0
- package/dist/tools/builtins/diff.d.ts +3 -0
- package/dist/tools/builtins/diff.d.ts.map +1 -0
- package/dist/tools/builtins/diff.js +83 -0
- package/dist/tools/builtins/diff.js.map +1 -0
- package/dist/tools/builtins/edit.d.ts +3 -0
- package/dist/tools/builtins/edit.d.ts.map +1 -0
- package/dist/tools/builtins/edit.js +40 -0
- package/dist/tools/builtins/edit.js.map +1 -0
- package/dist/tools/builtins/glob.d.ts +3 -0
- package/dist/tools/builtins/glob.d.ts.map +1 -0
- package/dist/tools/builtins/glob.js +37 -0
- package/dist/tools/builtins/glob.js.map +1 -0
- package/dist/tools/builtins/grep.d.ts +3 -0
- package/dist/tools/builtins/grep.d.ts.map +1 -0
- package/dist/tools/builtins/grep.js +81 -0
- package/dist/tools/builtins/grep.js.map +1 -0
- package/dist/tools/builtins/lsp.d.ts +3 -0
- package/dist/tools/builtins/lsp.d.ts.map +1 -0
- package/dist/tools/builtins/lsp.js +102 -0
- package/dist/tools/builtins/lsp.js.map +1 -0
- package/dist/tools/builtins/pty.d.ts +64 -0
- package/dist/tools/builtins/pty.d.ts.map +1 -0
- package/dist/tools/builtins/pty.js +536 -0
- package/dist/tools/builtins/pty.js.map +1 -0
- package/dist/tools/builtins/read.d.ts +3 -0
- package/dist/tools/builtins/read.d.ts.map +1 -0
- package/dist/tools/builtins/read.js +18 -0
- package/dist/tools/builtins/read.js.map +1 -0
- package/dist/tools/builtins/web-fetch.d.ts +4 -0
- package/dist/tools/builtins/web-fetch.d.ts.map +1 -0
- package/dist/tools/builtins/web-fetch.js +353 -0
- package/dist/tools/builtins/web-fetch.js.map +1 -0
- package/dist/tools/builtins/write.d.ts +3 -0
- package/dist/tools/builtins/write.d.ts.map +1 -0
- package/dist/tools/builtins/write.js +48 -0
- package/dist/tools/builtins/write.js.map +1 -0
- package/dist/tools/builtins.d.ts +9 -0
- package/dist/tools/builtins.d.ts.map +1 -0
- package/dist/tools/builtins.js +29 -0
- package/dist/tools/builtins.js.map +1 -0
- package/dist/tools/diff.d.ts +18 -0
- package/dist/tools/diff.d.ts.map +1 -0
- package/dist/tools/diff.js +57 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/permission.d.ts +120 -0
- package/dist/tools/permission.d.ts.map +1 -0
- package/dist/tools/permission.js +208 -0
- package/dist/tools/permission.js.map +1 -0
- package/dist/tools/registry.d.ts +12 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +19 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +244 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +15 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { mkdir, stat } from "node:fs/promises";
|
|
2
|
+
import { ensureChancesExcludeEntry, findCanonicalRoot, gitBranchDelete, gitWorktreeAdd, gitWorktreeRemove, } from "./git.js";
|
|
3
|
+
import { branchNameFor, isAgentSlug, newAgentSlug } from "./slug.js";
|
|
4
|
+
import { writeActiveMarker } from "./active-marker.js";
|
|
5
|
+
import { worktreePathFor, worktreesDir } from "./paths.js";
|
|
6
|
+
import { WorktreeError } from "./errors.js";
|
|
7
|
+
/**
|
|
8
|
+
* Creates a fresh `.chances/worktrees/<slug>` worktree for an isolated
|
|
9
|
+
* subagent. Per Round-1:
|
|
10
|
+
*
|
|
11
|
+
* - AbortSignal-aware: cancellation kills the in-flight `git worktree add`
|
|
12
|
+
* and runs idempotent cleanup before rethrowing (MUST-FIX #3).
|
|
13
|
+
* - Slug-collision retry up to `maxSlugAttempts` (NICE #2).
|
|
14
|
+
* - Canonical-root resolution so `chances`-from-inside-a-user-worktree
|
|
15
|
+
* doesn't nest a new worktree under the user's (SHOULD-FIX #3).
|
|
16
|
+
* - `.git/info/exclude` ensured for `.chances/worktrees/` so the parent's
|
|
17
|
+
* `git status` stays clean (SHOULD-FIX #1).
|
|
18
|
+
* - Writes the `.chances-active` heartbeat marker so cross-process GC can
|
|
19
|
+
* detect a live owner (MUST-FIX #4 + SHOULD-FIX #5).
|
|
20
|
+
*/
|
|
21
|
+
export async function createAgentWorktree(cwd, opts = {}) {
|
|
22
|
+
const { signal } = opts;
|
|
23
|
+
const maxAttempts = Math.max(1, opts.maxSlugAttempts ?? 5);
|
|
24
|
+
if (signal?.aborted) {
|
|
25
|
+
throw new WorktreeError("CREATE_FAILED", "cancelled before start");
|
|
26
|
+
}
|
|
27
|
+
const canonicalRoot = await findCanonicalRoot(cwd, signal);
|
|
28
|
+
await ensureChancesExcludeEntry(canonicalRoot);
|
|
29
|
+
await mkdir(worktreesDir(canonicalRoot), { recursive: true });
|
|
30
|
+
let lastErr;
|
|
31
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
32
|
+
if (signal?.aborted) {
|
|
33
|
+
throw new WorktreeError("CREATE_FAILED", "cancelled mid-create");
|
|
34
|
+
}
|
|
35
|
+
const slug = newAgentSlug();
|
|
36
|
+
if (!isAgentSlug(slug)) {
|
|
37
|
+
// Defensive: random hex generation should always satisfy the regex,
|
|
38
|
+
// but if a future change loosens entropy we want to fail loud rather
|
|
39
|
+
// than push a malformed branch into git.
|
|
40
|
+
throw new WorktreeError("CREATE_FAILED", `generated slug rejected: ${slug}`);
|
|
41
|
+
}
|
|
42
|
+
const branch = branchNameFor(slug);
|
|
43
|
+
const path = worktreePathFor(canonicalRoot, slug);
|
|
44
|
+
// Slug-collision pre-check: if the path already exists, regenerate.
|
|
45
|
+
if (await pathExists(path)) {
|
|
46
|
+
lastErr = new WorktreeError("CREATE_FAILED", `path collision: ${path}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
await gitWorktreeAdd(canonicalRoot, path, branch, signal);
|
|
51
|
+
await writeActiveMarker(path);
|
|
52
|
+
return {
|
|
53
|
+
canonicalRoot,
|
|
54
|
+
path,
|
|
55
|
+
branch,
|
|
56
|
+
slug,
|
|
57
|
+
cleanup: makeCleanup(canonicalRoot, path, branch),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
lastErr = e;
|
|
62
|
+
// Best-effort cleanup in case `git worktree add` left a partial
|
|
63
|
+
// directory or branch behind. Errors here are swallowed — we're
|
|
64
|
+
// already on the failure path and the next stale-GC pass will mop
|
|
65
|
+
// up. We do NOT re-check `signal` here because cleanup is the
|
|
66
|
+
// promise we made to the caller; honouring it dominates the abort.
|
|
67
|
+
try {
|
|
68
|
+
await gitWorktreeRemove(canonicalRoot, path);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
/* ignore */
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
await gitBranchDelete(canonicalRoot, branch);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
/* ignore */
|
|
78
|
+
}
|
|
79
|
+
// If the error looks like a transient collision, retry. Otherwise
|
|
80
|
+
// propagate immediately to avoid masking real failures (e.g.
|
|
81
|
+
// permission denied on `.chances/`).
|
|
82
|
+
if (e instanceof WorktreeError && /collision|already exists/i.test(e.message)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
throw e;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw new WorktreeError("SLUG_EXHAUSTED", `could not create a unique worktree slug after ${maxAttempts} attempts`, lastErr);
|
|
89
|
+
}
|
|
90
|
+
function makeCleanup(canonicalRoot, path, branch) {
|
|
91
|
+
let done = false;
|
|
92
|
+
return async () => {
|
|
93
|
+
if (done)
|
|
94
|
+
return;
|
|
95
|
+
done = true;
|
|
96
|
+
try {
|
|
97
|
+
await gitWorktreeRemove(canonicalRoot, path);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
/* best-effort; stale-GC handles the rest */
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await gitBranchDelete(canonicalRoot, branch);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* best-effort */
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async function pathExists(p) {
|
|
111
|
+
try {
|
|
112
|
+
await stat(p);
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
if (e.code === "ENOENT")
|
|
117
|
+
return false;
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/core/worktree/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type WorktreeErrorCode = "NOT_A_GIT_REPO" | "GIT_CLI_MISSING" | "CREATE_FAILED" | "REMOVE_FAILED" | "GC_FAILED" | "SLUG_EXHAUSTED" | "NESTED_RESOLVE_FAILED";
|
|
2
|
+
export declare class WorktreeError extends Error {
|
|
3
|
+
readonly code: WorktreeErrorCode;
|
|
4
|
+
readonly cause?: unknown | undefined;
|
|
5
|
+
constructor(code: WorktreeErrorCode, message: string, cause?: unknown | undefined);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/worktree/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GACzB,gBAAgB,GAChB,iBAAiB,GACjB,eAAe,GACf,eAAe,GACf,WAAW,GACX,gBAAgB,GAChB,uBAAuB,CAAC;AAE5B,qBAAa,aAAc,SAAQ,KAAK;IAEpC,QAAQ,CAAC,IAAI,EAAE,iBAAiB;aAEd,KAAK,CAAC,EAAE,OAAO;gBAFxB,IAAI,EAAE,iBAAiB,EAChC,OAAO,EAAE,MAAM,EACG,KAAK,CAAC,EAAE,OAAO,YAAA;CAKpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/worktree/errors.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,aAAc,SAAQ,KAAK;IAE3B;IAES;IAHpB,YACW,IAAuB,EAChC,OAAe,EACG,KAAe;QAEjC,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAJpB,SAAI,GAAJ,IAAI,CAAmB;QAEd,UAAK,GAAL,KAAK,CAAU;QAGjC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface GcOptions {
|
|
2
|
+
/** Worktrees older than this are eligible. Default 30, matches
|
|
3
|
+
* claude-code. */
|
|
4
|
+
cutoffDays?: number;
|
|
5
|
+
/** Heartbeat freshness window. If the active marker's `lastHeartbeat`
|
|
6
|
+
* is within this window (and the PID is alive), the worktree is
|
|
7
|
+
* conservatively retained. Default 600 s = 10 min. */
|
|
8
|
+
heartbeatStaleSeconds?: number;
|
|
9
|
+
/** Upper bound on the number of entries the GC scans in one pass.
|
|
10
|
+
* Matches 3.3's catalog cap pattern — bounds the cost so a pathological
|
|
11
|
+
* `.chances/worktrees/` (thousands of leaked dirs) can't blow the
|
|
12
|
+
* cold-start budget. Default 256. */
|
|
13
|
+
maxEntries?: number;
|
|
14
|
+
/** Cap on the wallclock the GC pass may spend before giving up the
|
|
15
|
+
* rest of the entries (the remaining cleanup falls to the next boot).
|
|
16
|
+
* Default 2 000 ms. */
|
|
17
|
+
maxWallclockMs?: number;
|
|
18
|
+
/** Injected `now` for tests. */
|
|
19
|
+
now?: () => number;
|
|
20
|
+
}
|
|
21
|
+
export interface GcResult {
|
|
22
|
+
scanned: number;
|
|
23
|
+
removed: string[];
|
|
24
|
+
skipped: {
|
|
25
|
+
path: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
}[];
|
|
28
|
+
}
|
|
29
|
+
/** Best-effort sweep of stale agent worktrees under
|
|
30
|
+
* `<canonicalRoot>/.chances/worktrees/`. Fail-closed: any error on a
|
|
31
|
+
* single entry skips that entry rather than deleting on uncertainty.
|
|
32
|
+
* Returns a summary so the boot path can log a one-line "removed N
|
|
33
|
+
* stale worktrees" without spamming. */
|
|
34
|
+
export declare function cleanupStaleWorktrees(canonicalRoot: string, opts?: GcOptions): Promise<GcResult>;
|
|
35
|
+
/** Active-marker path expose for tests/diagnostics — kept here so the
|
|
36
|
+
* gc module's surface stays self-contained without re-exporting from
|
|
37
|
+
* `paths.ts`. */
|
|
38
|
+
export { activeMarkerPathFor } from "./paths.js";
|
|
39
|
+
//# sourceMappingURL=gc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gc.d.ts","sourceRoot":"","sources":["../../../src/core/worktree/gc.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,SAAS;IACxB;sBACkB;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;0DAEsD;IACtD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;yCAGqC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;2BAEuB;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7C;AAED;;;;wCAIwC;AACxC,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,MAAM,EACrB,IAAI,GAAE,SAAc,GACnB,OAAO,CAAC,QAAQ,CAAC,CA0EnB;AA+ED;;iBAEiB;AACjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { gitBranchDelete, gitDiffShortstat, gitStatusEmpty, gitUnmergedCommitCount, gitWorktreeRemove, } from "./git.js";
|
|
4
|
+
import { branchNameFor, isAgentSlug } from "./slug.js";
|
|
5
|
+
import { worktreesDir } from "./paths.js";
|
|
6
|
+
import { isProcessAlive, readActiveMarker } from "./active-marker.js";
|
|
7
|
+
/** Best-effort sweep of stale agent worktrees under
|
|
8
|
+
* `<canonicalRoot>/.chances/worktrees/`. Fail-closed: any error on a
|
|
9
|
+
* single entry skips that entry rather than deleting on uncertainty.
|
|
10
|
+
* Returns a summary so the boot path can log a one-line "removed N
|
|
11
|
+
* stale worktrees" without spamming. */
|
|
12
|
+
export async function cleanupStaleWorktrees(canonicalRoot, opts = {}) {
|
|
13
|
+
const cutoffDays = opts.cutoffDays ?? 30;
|
|
14
|
+
const heartbeatStaleSeconds = opts.heartbeatStaleSeconds ?? 600;
|
|
15
|
+
const maxEntries = Math.max(1, opts.maxEntries ?? 256);
|
|
16
|
+
const maxWallclockMs = Math.max(100, opts.maxWallclockMs ?? 2_000);
|
|
17
|
+
const now = opts.now ?? Date.now;
|
|
18
|
+
const startedAt = now();
|
|
19
|
+
const cutoffMs = cutoffDays * 24 * 60 * 60 * 1000;
|
|
20
|
+
const heartbeatStaleMs = heartbeatStaleSeconds * 1000;
|
|
21
|
+
const dir = worktreesDir(canonicalRoot);
|
|
22
|
+
let entries;
|
|
23
|
+
try {
|
|
24
|
+
entries = await readdir(dir);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
if (e.code === "ENOENT") {
|
|
28
|
+
return { scanned: 0, removed: [], skipped: [] };
|
|
29
|
+
}
|
|
30
|
+
return { scanned: 0, removed: [], skipped: [{ path: dir, reason: "readdir failed" }] };
|
|
31
|
+
}
|
|
32
|
+
const result = { scanned: 0, removed: [], skipped: [] };
|
|
33
|
+
for (const name of entries.sort()) {
|
|
34
|
+
if (result.scanned >= maxEntries) {
|
|
35
|
+
result.skipped.push({ path: name, reason: "max-entries cap reached" });
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (now() - startedAt > maxWallclockMs) {
|
|
39
|
+
result.skipped.push({ path: name, reason: "wallclock cap reached" });
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
result.scanned++;
|
|
43
|
+
if (!isAgentSlug(name)) {
|
|
44
|
+
result.skipped.push({ path: name, reason: "slug shape mismatch" });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const worktreePath = join(dir, name);
|
|
48
|
+
try {
|
|
49
|
+
const verdict = await evaluateEntry(canonicalRoot, worktreePath, name, {
|
|
50
|
+
now: now(),
|
|
51
|
+
cutoffMs,
|
|
52
|
+
heartbeatStaleMs,
|
|
53
|
+
});
|
|
54
|
+
if (verdict === "delete") {
|
|
55
|
+
try {
|
|
56
|
+
await gitWorktreeRemove(canonicalRoot, worktreePath);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
// (Round-2 SHOULD-FIX #1) Real removal failures must NOT be
|
|
60
|
+
// reported as successful removal. Skip this entry; the user
|
|
61
|
+
// can investigate / next pass will retry.
|
|
62
|
+
result.skipped.push({
|
|
63
|
+
path: name,
|
|
64
|
+
reason: `remove failed: ${e.message || String(e)}`,
|
|
65
|
+
});
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
// Branch deletion is best-effort — the worktree directory is
|
|
69
|
+
// already gone so leaving an orphan branch is benign.
|
|
70
|
+
await gitBranchDelete(canonicalRoot, branchNameFor(name));
|
|
71
|
+
result.removed.push(name);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
result.skipped.push({ path: name, reason: verdict });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
// Fail-closed: ANY git error on a probe skips this entry.
|
|
79
|
+
result.skipped.push({
|
|
80
|
+
path: name,
|
|
81
|
+
reason: `error: ${e.message || String(e)}`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
async function evaluateEntry(canonicalRoot, worktreePath, slug, ctx) {
|
|
88
|
+
// (1) `.git` pointer file exists — if not, this is a stale leftover
|
|
89
|
+
// dir that git no longer tracks; let regular FS cleanup handle it
|
|
90
|
+
// (deleted via `git worktree remove --force` against the path is
|
|
91
|
+
// typically a no-op, but we keep that path off the happy path so the
|
|
92
|
+
// operator can investigate orphans).
|
|
93
|
+
const dotGitPath = join(worktreePath, ".git");
|
|
94
|
+
let dotGitStat;
|
|
95
|
+
try {
|
|
96
|
+
dotGitStat = await stat(dotGitPath);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return "missing-dotgit-pointer";
|
|
100
|
+
}
|
|
101
|
+
// (2) Age gate: created < cutoffDays ago → kept. Use the `.git`
|
|
102
|
+
// pointer's mtime (claude-code pattern) since the worktree dir itself
|
|
103
|
+
// can be touched by tools.
|
|
104
|
+
const ageMs = ctx.now - dotGitStat.mtimeMs;
|
|
105
|
+
if (ageMs < ctx.cutoffMs)
|
|
106
|
+
return "too-recent";
|
|
107
|
+
// (3) Active marker liveness check. Marker missing → eligible
|
|
108
|
+
// (continues to dirty/unmerged probes). Marker present + fresh
|
|
109
|
+
// heartbeat + alive PID → conservatively retained.
|
|
110
|
+
const marker = await readActiveMarker(worktreePath);
|
|
111
|
+
if (marker) {
|
|
112
|
+
const heartbeatAge = ctx.now - marker.lastHeartbeat;
|
|
113
|
+
if (heartbeatAge < ctx.heartbeatStaleMs) {
|
|
114
|
+
// Marker is fresh — owner is almost certainly alive, hands off.
|
|
115
|
+
return "active-marker-fresh";
|
|
116
|
+
}
|
|
117
|
+
if (isProcessAlive(marker.pid, marker.hostname)) {
|
|
118
|
+
// Heartbeat is stale but the PID is alive (or remote-host); the
|
|
119
|
+
// owner may be paused (debugger, SIGSTOP) or just slow. Stay
|
|
120
|
+
// conservative.
|
|
121
|
+
return "active-marker-live-pid";
|
|
122
|
+
}
|
|
123
|
+
// Marker is stale AND owner is dead → fall through to git probes.
|
|
124
|
+
}
|
|
125
|
+
// (4) Worktree must be clean (no untracked, no staged, no modified).
|
|
126
|
+
const clean = await gitStatusEmpty(worktreePath);
|
|
127
|
+
if (!clean)
|
|
128
|
+
return "git-dirty";
|
|
129
|
+
// (5) Branch must have no commits unreachable from HEAD.
|
|
130
|
+
const unmerged = await gitUnmergedCommitCount(canonicalRoot, branchNameFor(slug));
|
|
131
|
+
if (unmerged > 0)
|
|
132
|
+
return "unmerged-commits";
|
|
133
|
+
// (6) Extra defensive belt: a `--shortstat` diff against HEAD that's
|
|
134
|
+
// non-empty also keeps it. `gitStatusEmpty` already covers this, but
|
|
135
|
+
// catching the second observable is cheap and matches claude-code's
|
|
136
|
+
// belt-and-suspenders pattern.
|
|
137
|
+
const shortstat = await gitDiffShortstat(worktreePath);
|
|
138
|
+
if (shortstat.length > 0)
|
|
139
|
+
return "git-dirty";
|
|
140
|
+
return "delete";
|
|
141
|
+
}
|
|
142
|
+
/** Active-marker path expose for tests/diagnostics — kept here so the
|
|
143
|
+
* gc module's surface stays self-contained without re-exporting from
|
|
144
|
+
* `paths.ts`. */
|
|
145
|
+
export { activeMarkerPathFor } from "./paths.js";
|
|
146
|
+
//# sourceMappingURL=gc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gc.js","sourceRoot":"","sources":["../../../src/core/worktree/gc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AA6BtE;;;;wCAIwC;AACxC,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,aAAqB,EACrB,OAAkB,EAAE;IAEpB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IACzC,MAAM,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,IAAI,GAAG,CAAC;IAChE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACjC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC;IACxB,MAAM,QAAQ,GAAG,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAClD,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,IAAI,CAAC;IAEtD,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IACxC,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAK,CAA2B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAClD,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC;IACzF,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAElE,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAClC,IAAI,MAAM,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC;YACjC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,CAAC;YACvE,SAAS;QACX,CAAC;QACD,IAAI,GAAG,EAAE,GAAG,SAAS,GAAG,cAAc,EAAE,CAAC;YACvC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC,CAAC;YACrE,MAAM;QACR,CAAC;QACD,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;YACnE,SAAS;QACX,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE;gBACrE,GAAG,EAAE,GAAG,EAAE;gBACV,QAAQ;gBACR,gBAAgB;aACjB,CAAC,CAAC;YACH,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACzB,IAAI,CAAC;oBACH,MAAM,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;gBACvD,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,4DAA4D;oBAC5D,4DAA4D;oBAC5D,0CAA0C;oBAC1C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;wBAClB,IAAI,EAAE,IAAI;wBACV,MAAM,EAAE,kBAAmB,CAAW,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE;qBAC9D,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBACD,6DAA6D;gBAC7D,sDAAsD;gBACtD,MAAM,eAAe,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,0DAA0D;YAC1D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClB,IAAI,EAAE,IAAI;gBACV,MAAM,EAAE,UAAW,CAAW,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE;aACtD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAiBD,KAAK,UAAU,aAAa,CAC1B,aAAqB,EACrB,YAAoB,EACpB,IAAY,EACZ,GAAY;IAEZ,oEAAoE;IACpE,kEAAkE;IAClE,iEAAiE;IACjE,qEAAqE;IACrE,qCAAqC;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,UAAU,CAAC;IACf,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,wBAAwB,CAAC;IAClC,CAAC;IAED,gEAAgE;IAChE,sEAAsE;IACtE,2BAA2B;IAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC;IAC3C,IAAI,KAAK,GAAG,GAAG,CAAC,QAAQ;QAAE,OAAO,YAAY,CAAC;IAE9C,8DAA8D;IAC9D,+DAA+D;IAC/D,mDAAmD;IACnD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,YAAY,GAAG,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,aAAa,CAAC;QACpD,IAAI,YAAY,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACxC,gEAAgE;YAChE,OAAO,qBAAqB,CAAC;QAC/B,CAAC;QACD,IAAI,cAAc,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChD,gEAAgE;YAChE,6DAA6D;YAC7D,gBAAgB;YAChB,OAAO,wBAAwB,CAAC;QAClC,CAAC;QACD,kEAAkE;IACpE,CAAC;IAED,qEAAqE;IACrE,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK;QAAE,OAAO,WAAW,CAAC;IAE/B,yDAAyD;IACzD,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAClF,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,kBAAkB,CAAC;IAE5C,qEAAqE;IACrE,qEAAqE;IACrE,oEAAoE;IACpE,+BAA+B;IAC/B,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAC;IACvD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,WAAW,CAAC;IAE7C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;iBAEiB;AACjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface GitRunOptions {
|
|
2
|
+
cwd?: string;
|
|
3
|
+
signal?: AbortSignal;
|
|
4
|
+
/** When true, a non-zero exit is returned as `{ ok: false, ... }`
|
|
5
|
+
* instead of throwing. Callers that care about specific codes (e.g.
|
|
6
|
+
* `git status` returning 0/non-zero meaningfully) opt into this. */
|
|
7
|
+
allowNonZero?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface GitResult {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
stdout: string;
|
|
12
|
+
stderr: string;
|
|
13
|
+
code: number | null;
|
|
14
|
+
}
|
|
15
|
+
/** Spawn `git ARGS...` with stdout/stderr captured. Resolves with the result;
|
|
16
|
+
* throws WorktreeError on signal failures or when the git binary is missing.
|
|
17
|
+
* Cancellation via AbortSignal kills the child with SIGTERM. */
|
|
18
|
+
export declare function runGit(args: string[], opts?: GitRunOptions): Promise<GitResult>;
|
|
19
|
+
/** Resolves the canonical git repo root for `cwd`. When inside a nested
|
|
20
|
+
* worktree, `--show-superproject-working-tree` returns the parent superproject;
|
|
21
|
+
* we fall back to `--show-toplevel` for regular repos. (Round-1 SHOULD-FIX #3.) */
|
|
22
|
+
export declare function findCanonicalRoot(cwd: string, signal?: AbortSignal): Promise<string>;
|
|
23
|
+
/** `git worktree add -b <branch> <path> HEAD` against `canonicalRoot`. */
|
|
24
|
+
export declare function gitWorktreeAdd(canonicalRoot: string, path: string, branch: string, signal?: AbortSignal): Promise<void>;
|
|
25
|
+
/** `git worktree remove --force <path>` then `git worktree prune`.
|
|
26
|
+
*
|
|
27
|
+
* Idempotency: "worktree is not registered" / "no such directory"
|
|
28
|
+
* exits are treated as success (the post-condition "the path is not
|
|
29
|
+
* registered as a worktree" already holds). REAL failures (permission
|
|
30
|
+
* denied, locked, FS error) throw `REMOVE_FAILED` so callers can
|
|
31
|
+
* distinguish "removed" from "could not remove" — Round-2 SHOULD-FIX
|
|
32
|
+
* #1.
|
|
33
|
+
*/
|
|
34
|
+
export declare function gitWorktreeRemove(canonicalRoot: string, path: string, signal?: AbortSignal): Promise<void>;
|
|
35
|
+
/** `git branch -D <branch>`. Best-effort; returns silently if the branch
|
|
36
|
+
* doesn't exist. */
|
|
37
|
+
export declare function gitBranchDelete(canonicalRoot: string, branch: string, signal?: AbortSignal): Promise<void>;
|
|
38
|
+
/** `git status --porcelain` parser: returns true when the worktree has no
|
|
39
|
+
* untracked, modified, or staged files. */
|
|
40
|
+
export declare function gitStatusEmpty(worktreePath: string, signal?: AbortSignal): Promise<boolean>;
|
|
41
|
+
/** `git rev-list <branch> ^HEAD --count`. Number of commits on `branch` not
|
|
42
|
+
* reachable from `HEAD`. Used by GC to detect worktrees holding unmerged
|
|
43
|
+
* work. */
|
|
44
|
+
export declare function gitUnmergedCommitCount(canonicalRoot: string, branch: string, signal?: AbortSignal): Promise<number>;
|
|
45
|
+
/** `git diff --shortstat HEAD` invoked inside the worktree. Returns the
|
|
46
|
+
* trimmed shortstat ("3 files changed, 47 insertions(+), 12 deletions(-)")
|
|
47
|
+
* or the empty string when the worktree matches HEAD. */
|
|
48
|
+
export declare function gitDiffShortstat(worktreePath: string, signal?: AbortSignal): Promise<string>;
|
|
49
|
+
/** Ensures `.git/info/exclude` contains `.chances/worktrees/`. Idempotent. We
|
|
50
|
+
* append a labelled section so a re-run doesn't duplicate the entry, and we
|
|
51
|
+
* never touch the user's tracked `.gitignore`. (Round-1 SHOULD-FIX #1.) */
|
|
52
|
+
export declare function ensureChancesExcludeEntry(canonicalRoot: string): Promise<void>;
|
|
53
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/core/worktree/git.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;wEAEoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED;;gEAEgE;AAChE,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,SAAS,CAAC,CA+BzF;AAED;;mFAEmF;AACnF,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB1F;AAED,0EAA0E;AAC1E,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;oBACoB;AACpB,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;2CAC2C;AAC3C,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CASjG;AAED;;WAEW;AACX,wBAAsB,sBAAsB,CAC1C,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;yDAEyD;AACzD,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAQlG;AAED;;2EAE2E;AAC3E,wBAAsB,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBpF"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { WorktreeError } from "./errors.js";
|
|
5
|
+
/** Spawn `git ARGS...` with stdout/stderr captured. Resolves with the result;
|
|
6
|
+
* throws WorktreeError on signal failures or when the git binary is missing.
|
|
7
|
+
* Cancellation via AbortSignal kills the child with SIGTERM. */
|
|
8
|
+
export async function runGit(args, opts = {}) {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
const child = spawn("git", args, {
|
|
11
|
+
cwd: opts.cwd,
|
|
12
|
+
signal: opts.signal,
|
|
13
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
14
|
+
});
|
|
15
|
+
let stdout = "";
|
|
16
|
+
let stderr = "";
|
|
17
|
+
child.stdout?.on("data", (b) => (stdout += b.toString("utf8")));
|
|
18
|
+
child.stderr?.on("data", (b) => (stderr += b.toString("utf8")));
|
|
19
|
+
child.on("error", (e) => {
|
|
20
|
+
if (e.code === "ENOENT") {
|
|
21
|
+
reject(new WorktreeError("GIT_CLI_MISSING", "git binary not found on PATH", e));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (e.name === "AbortError") {
|
|
25
|
+
reject(new WorktreeError("CREATE_FAILED", `git ${args[0]} aborted`, e));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
reject(new WorktreeError("CREATE_FAILED", `git ${args[0]} spawn failed: ${e.message}`, e));
|
|
29
|
+
});
|
|
30
|
+
child.on("close", (code) => {
|
|
31
|
+
const ok = code === 0;
|
|
32
|
+
if (!ok && !opts.allowNonZero) {
|
|
33
|
+
resolve({ ok, stdout, stderr, code });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
resolve({ ok, stdout, stderr, code });
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** Resolves the canonical git repo root for `cwd`. When inside a nested
|
|
41
|
+
* worktree, `--show-superproject-working-tree` returns the parent superproject;
|
|
42
|
+
* we fall back to `--show-toplevel` for regular repos. (Round-1 SHOULD-FIX #3.) */
|
|
43
|
+
export async function findCanonicalRoot(cwd, signal) {
|
|
44
|
+
const superRes = await runGit(["rev-parse", "--show-superproject-working-tree"], {
|
|
45
|
+
cwd,
|
|
46
|
+
signal,
|
|
47
|
+
allowNonZero: true,
|
|
48
|
+
});
|
|
49
|
+
if (superRes.ok) {
|
|
50
|
+
const trimmed = superRes.stdout.trim();
|
|
51
|
+
if (trimmed.length > 0)
|
|
52
|
+
return trimmed;
|
|
53
|
+
}
|
|
54
|
+
const topRes = await runGit(["rev-parse", "--show-toplevel"], {
|
|
55
|
+
cwd,
|
|
56
|
+
signal,
|
|
57
|
+
allowNonZero: true,
|
|
58
|
+
});
|
|
59
|
+
if (!topRes.ok) {
|
|
60
|
+
throw new WorktreeError("NOT_A_GIT_REPO", `not a git repository (or any parent): ${cwd}${topRes.stderr.trim() ? " — " + topRes.stderr.trim() : ""}`);
|
|
61
|
+
}
|
|
62
|
+
return topRes.stdout.trim();
|
|
63
|
+
}
|
|
64
|
+
/** `git worktree add -b <branch> <path> HEAD` against `canonicalRoot`. */
|
|
65
|
+
export async function gitWorktreeAdd(canonicalRoot, path, branch, signal) {
|
|
66
|
+
const res = await runGit(["worktree", "add", "-b", branch, path, "HEAD"], {
|
|
67
|
+
cwd: canonicalRoot,
|
|
68
|
+
signal,
|
|
69
|
+
allowNonZero: true,
|
|
70
|
+
});
|
|
71
|
+
if (!res.ok) {
|
|
72
|
+
throw new WorktreeError("CREATE_FAILED", `git worktree add failed${res.stderr.trim() ? ": " + res.stderr.trim() : ""}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** `git worktree remove --force <path>` then `git worktree prune`.
|
|
76
|
+
*
|
|
77
|
+
* Idempotency: "worktree is not registered" / "no such directory"
|
|
78
|
+
* exits are treated as success (the post-condition "the path is not
|
|
79
|
+
* registered as a worktree" already holds). REAL failures (permission
|
|
80
|
+
* denied, locked, FS error) throw `REMOVE_FAILED` so callers can
|
|
81
|
+
* distinguish "removed" from "could not remove" — Round-2 SHOULD-FIX
|
|
82
|
+
* #1.
|
|
83
|
+
*/
|
|
84
|
+
export async function gitWorktreeRemove(canonicalRoot, path, signal) {
|
|
85
|
+
const res = await runGit(["worktree", "remove", "--force", path], {
|
|
86
|
+
cwd: canonicalRoot,
|
|
87
|
+
signal,
|
|
88
|
+
allowNonZero: true,
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
const err = res.stderr.toLowerCase();
|
|
92
|
+
const idempotentMiss = /is not a working tree/.test(err) ||
|
|
93
|
+
/no such (file or directory|working tree)/.test(err) ||
|
|
94
|
+
/is not a working tree/.test(err) ||
|
|
95
|
+
/not a working tree/.test(err);
|
|
96
|
+
if (!idempotentMiss) {
|
|
97
|
+
throw new WorktreeError("REMOVE_FAILED", `git worktree remove failed${res.stderr.trim() ? ": " + res.stderr.trim() : ""}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
await runGit(["worktree", "prune"], { cwd: canonicalRoot, signal, allowNonZero: true });
|
|
101
|
+
}
|
|
102
|
+
/** `git branch -D <branch>`. Best-effort; returns silently if the branch
|
|
103
|
+
* doesn't exist. */
|
|
104
|
+
export async function gitBranchDelete(canonicalRoot, branch, signal) {
|
|
105
|
+
await runGit(["branch", "-D", branch], { cwd: canonicalRoot, signal, allowNonZero: true });
|
|
106
|
+
}
|
|
107
|
+
/** `git status --porcelain` parser: returns true when the worktree has no
|
|
108
|
+
* untracked, modified, or staged files. */
|
|
109
|
+
export async function gitStatusEmpty(worktreePath, signal) {
|
|
110
|
+
const res = await runGit(["status", "--porcelain"], { cwd: worktreePath, signal });
|
|
111
|
+
if (!res.ok) {
|
|
112
|
+
throw new WorktreeError("GC_FAILED", `git status failed at ${worktreePath}${res.stderr.trim() ? ": " + res.stderr.trim() : ""}`);
|
|
113
|
+
}
|
|
114
|
+
return res.stdout.trim().length === 0;
|
|
115
|
+
}
|
|
116
|
+
/** `git rev-list <branch> ^HEAD --count`. Number of commits on `branch` not
|
|
117
|
+
* reachable from `HEAD`. Used by GC to detect worktrees holding unmerged
|
|
118
|
+
* work. */
|
|
119
|
+
export async function gitUnmergedCommitCount(canonicalRoot, branch, signal) {
|
|
120
|
+
const res = await runGit(["rev-list", "--count", branch, "^HEAD"], {
|
|
121
|
+
cwd: canonicalRoot,
|
|
122
|
+
signal,
|
|
123
|
+
allowNonZero: true,
|
|
124
|
+
});
|
|
125
|
+
if (!res.ok) {
|
|
126
|
+
throw new WorktreeError("GC_FAILED", `git rev-list failed for ${branch}${res.stderr.trim() ? ": " + res.stderr.trim() : ""}`);
|
|
127
|
+
}
|
|
128
|
+
const n = parseInt(res.stdout.trim(), 10);
|
|
129
|
+
return Number.isFinite(n) ? n : 0;
|
|
130
|
+
}
|
|
131
|
+
/** `git diff --shortstat HEAD` invoked inside the worktree. Returns the
|
|
132
|
+
* trimmed shortstat ("3 files changed, 47 insertions(+), 12 deletions(-)")
|
|
133
|
+
* or the empty string when the worktree matches HEAD. */
|
|
134
|
+
export async function gitDiffShortstat(worktreePath, signal) {
|
|
135
|
+
const res = await runGit(["diff", "--shortstat", "HEAD"], {
|
|
136
|
+
cwd: worktreePath,
|
|
137
|
+
signal,
|
|
138
|
+
allowNonZero: true,
|
|
139
|
+
});
|
|
140
|
+
if (!res.ok)
|
|
141
|
+
return "";
|
|
142
|
+
return res.stdout.trim();
|
|
143
|
+
}
|
|
144
|
+
/** Ensures `.git/info/exclude` contains `.chances/worktrees/`. Idempotent. We
|
|
145
|
+
* append a labelled section so a re-run doesn't duplicate the entry, and we
|
|
146
|
+
* never touch the user's tracked `.gitignore`. (Round-1 SHOULD-FIX #1.) */
|
|
147
|
+
export async function ensureChancesExcludeEntry(canonicalRoot) {
|
|
148
|
+
const excludePath = join(canonicalRoot, ".git", "info", "exclude");
|
|
149
|
+
let existing = "";
|
|
150
|
+
try {
|
|
151
|
+
existing = await readFile(excludePath, "utf8");
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
const err = e;
|
|
155
|
+
if (err.code !== "ENOENT")
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
158
|
+
if (existing.includes(".chances/worktrees/"))
|
|
159
|
+
return;
|
|
160
|
+
await mkdir(dirname(excludePath), { recursive: true });
|
|
161
|
+
const block = (existing.endsWith("\n") || existing.length === 0 ? "" : "\n") +
|
|
162
|
+
"# chances-cli — agent worktrees (auto-managed, see docs/4.1-design.md)\n" +
|
|
163
|
+
".chances/worktrees/\n";
|
|
164
|
+
await writeFile(excludePath, existing + block, "utf8");
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/core/worktree/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createAgentWorktree, type AgentWorktreeHandle, type CreateAgentWorktreeOptions, } from "./create.js";
|
|
2
|
+
export { cleanupStaleWorktrees, type GcOptions, type GcResult, } from "./gc.js";
|
|
3
|
+
export { WorktreeError, type WorktreeErrorCode } from "./errors.js";
|
|
4
|
+
export { refreshActiveMarker } from "./active-marker.js";
|
|
5
|
+
export { gitDiffShortstat, findCanonicalRoot } from "./git.js";
|
|
6
|
+
export { worktreePathFor, worktreesDir, activeMarkerPathFor } from "./paths.js";
|
|
7
|
+
export { branchNameFor, isAgentSlug, newAgentSlug } from "./slug.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/worktree/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,GAChC,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,KAAK,SAAS,EACd,KAAK,QAAQ,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createAgentWorktree, } from "./create.js";
|
|
2
|
+
export { cleanupStaleWorktrees, } from "./gc.js";
|
|
3
|
+
export { WorktreeError } from "./errors.js";
|
|
4
|
+
export { refreshActiveMarker } from "./active-marker.js";
|
|
5
|
+
export { gitDiffShortstat, findCanonicalRoot } from "./git.js";
|
|
6
|
+
export { worktreePathFor, worktreesDir, activeMarkerPathFor } from "./paths.js";
|
|
7
|
+
export { branchNameFor, isAgentSlug, newAgentSlug } from "./slug.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/worktree/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,GAGpB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,GAGtB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAA0B,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|