@agentproto/worktree 0.6.2 → 0.7.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/bin/worktree-agent.mjs +2 -2
- package/dist/{chunk-5TEU6UGY.mjs → chunk-MKZ7BDGG.mjs} +3 -3
- package/dist/{chunk-5TEU6UGY.mjs.map → chunk-MKZ7BDGG.mjs.map} +1 -1
- package/dist/{chunk-Y337JFBG.mjs → chunk-RQUJW75P.mjs} +10 -5
- package/dist/chunk-RQUJW75P.mjs.map +1 -0
- package/dist/index.d.ts +39 -12
- package/dist/index.mjs +46 -3
- package/dist/index.mjs.map +1 -1
- package/dist/provider/index.mjs +1 -1
- package/package.json +3 -3
- package/dist/chunk-Y337JFBG.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -956,6 +956,15 @@ interface GitWorktreeRef {
|
|
|
956
956
|
/** `null` for a detached HEAD. */
|
|
957
957
|
branch: string | null;
|
|
958
958
|
head: string;
|
|
959
|
+
/**
|
|
960
|
+
* Set to git's own reason string (e.g. `"gitdir file points to
|
|
961
|
+
* non-existent location"`) when `git worktree list --porcelain` itself
|
|
962
|
+
* marks this entry prunable — its working directory is gone, so no git
|
|
963
|
+
* command can be run with it as `-C` target. `undefined` for every
|
|
964
|
+
* ordinary, live entry. This is git's own signal, not re-derived via
|
|
965
|
+
* `existsSync` or any other filesystem check of our own.
|
|
966
|
+
*/
|
|
967
|
+
prunable?: string;
|
|
959
968
|
}
|
|
960
969
|
/** Parses `git worktree list --porcelain` — every linked worktree of `repoRoot`, wherever it lives. */
|
|
961
970
|
declare function listGitWorktrees(repoRoot: string): Promise<GitWorktreeRef[]>;
|
|
@@ -1205,14 +1214,22 @@ interface ClassifyForGcOptions {
|
|
|
1205
1214
|
declare function classifyForGc(tree: TreeState, integration: IntegrationState, liveness: LivenessState, options?: ClassifyForGcOptions): GcClass;
|
|
1206
1215
|
/**
|
|
1207
1216
|
* The reclaim reasons this module can attach. `dep-bump` promotes a `hold`
|
|
1208
|
-
* to `reclaim` (see above). `orphan`
|
|
1209
|
-
* from a `hold` verdict
|
|
1210
|
-
*
|
|
1211
|
-
* physically present under the repo's worktree
|
|
1212
|
-
* list` no longer knows about
|
|
1213
|
-
*
|
|
1217
|
+
* to `reclaim` (see above). `orphan` and `prunable` are both different in
|
|
1218
|
+
* kind — neither ever starts from a `hold` verdict, because neither was
|
|
1219
|
+
* classified via `classify`'s three axes in the first place:
|
|
1220
|
+
* - `orphan`: a directory physically present under the repo's worktree
|
|
1221
|
+
* pool that `git worktree list` no longer knows about at all (see the
|
|
1222
|
+
* "orphan reclaim" section below).
|
|
1223
|
+
* - `prunable`: the mirror image — `git worktree list` still has a
|
|
1224
|
+
* registration, but git itself already reports it `prunable` because
|
|
1225
|
+
* the working directory is gone. Distinct from `orphan` on purpose: an
|
|
1226
|
+
* orphan's directory is still there to lose (it just failed removal),
|
|
1227
|
+
* so `reclaimOrphan` does `rm -rf`; a prunable entry's directory is
|
|
1228
|
+
* already gone, so there's nothing to inspect and nothing to `rm` — the
|
|
1229
|
+
* only irreversible thing history nearly did to it (deleting the branch)
|
|
1230
|
+
* must not happen either. See "prunable reclaim" below.
|
|
1214
1231
|
*/
|
|
1215
|
-
type GcReclaimReason = "dep-bump" | "orphan";
|
|
1232
|
+
type GcReclaimReason = "dep-bump" | "orphan" | "prunable";
|
|
1216
1233
|
/** The hold reasons this module can attach, distinct from `classify`'s snapshot-based holds. */
|
|
1217
1234
|
type GcHoldReason = "live-session-cwd";
|
|
1218
1235
|
/**
|
|
@@ -1255,17 +1272,19 @@ interface GcPlanEntry {
|
|
|
1255
1272
|
branch: string | null;
|
|
1256
1273
|
head: string;
|
|
1257
1274
|
/**
|
|
1258
|
-
* Absent
|
|
1259
|
-
* answer the tree/integration/
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1275
|
+
* Absent for an orphan entry (`orphan: true`) or a prunable entry
|
|
1276
|
+
* (`prunable: true`) — git itself cannot answer the tree/integration/
|
|
1277
|
+
* liveness questions for a directory it no longer recognizes as a
|
|
1278
|
+
* worktree (orphan) or whose working directory is simply gone (prunable),
|
|
1279
|
+
* so this module never fabricates a value for them rather than reporting
|
|
1280
|
+
* a fact it can't actually check.
|
|
1262
1281
|
*/
|
|
1263
1282
|
tree?: TreeState;
|
|
1264
1283
|
integration?: IntegrationState;
|
|
1265
1284
|
liveness?: LivenessState;
|
|
1266
1285
|
/** Classification per PLAN.md §5.1, after `--include-detached` (if set). */
|
|
1267
1286
|
class: GcClass;
|
|
1268
|
-
/** Set only when `class === "reclaim"` via the dep-bump exemption or the
|
|
1287
|
+
/** Set only when `class === "reclaim"` via the dep-bump exemption, the orphan reclaim path, or the prunable reclaim path — see `resolveGcClass` / `scanOrphanWorktreePaths` / `toPlanEntry`. */
|
|
1269
1288
|
reclaimReason?: GcReclaimReason;
|
|
1270
1289
|
/** Set only when `class === "hold"` via `protectedPaths` (`isProtectedPath`) — distinguishes this from an ordinary snapshot-based hold. */
|
|
1271
1290
|
holdReason?: GcHoldReason;
|
|
@@ -1278,6 +1297,14 @@ interface GcPlanEntry {
|
|
|
1278
1297
|
* it classifies.
|
|
1279
1298
|
*/
|
|
1280
1299
|
orphan?: boolean;
|
|
1300
|
+
/**
|
|
1301
|
+
* `true` only for a linked worktree `git worktree list --porcelain` itself
|
|
1302
|
+
* already marked `prunable` — its working directory is gone, so none of
|
|
1303
|
+
* `classify`'s three axes were computed (no git command was ever run
|
|
1304
|
+
* against the dead path). Always paired with `class: "reclaim"` and
|
|
1305
|
+
* `reclaimReason: "prunable"` — see "prunable reclaim" below `toPlanEntry`.
|
|
1306
|
+
*/
|
|
1307
|
+
prunable?: boolean;
|
|
1281
1308
|
}
|
|
1282
1309
|
interface PlanGcInput {
|
|
1283
1310
|
repoRoot: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { connectDaemonAgentSessionHost, makeDaemonAgentSessionHost, worktreeAgentInputSchema, worktreeAgentWorkflow } from './chunk-
|
|
1
|
+
export { connectDaemonAgentSessionHost, makeDaemonAgentSessionHost, worktreeAgentInputSchema, worktreeAgentWorkflow } from './chunk-MKZ7BDGG.mjs';
|
|
2
2
|
import './chunk-E3EM24BS.mjs';
|
|
3
|
-
import { computeProvenance, execArgv, classify, computeWorktreeStatus, listGitWorktrees, worktreeProvider } from './chunk-
|
|
4
|
-
export { CONFIG_FILENAME, ConfigError, DEFAULT_PROXY_PORT, ENV_VARS, FileVerdictMemoStore, HookError, InMemoryVerdictMemoStore, ProxyTable, SESSIONS_BUCKETS_ROOT, SESSIONS_FILE_PATH, ServiceSupervisor, VERDICT_MEMO_PATH, WORKTREES_TURBO_CACHE_DIR_ENV, WorktreeNotRemovableError, allocatePort, classify, computeLiveness, computeProvenance, computeTreeState, computeWorktreeStatus, detectDefaultBranch, disposeSupervisor, ephemeralPort, execArgv, execGit, execShell, expandGlob, getScript, getSupervisor, globToRegExp, hookEnv, isPortFree, listGitWorktrees, listScripts, listServices, listWorktreeStatuses, loadConfigFromBase, normalizeHook, parseConfig, peerEnv, peerEnvKey, readSessionsRegistry, readWorktreeMarker, reconcileIntegration, repoLabel, resolveSupervisor, resolveWorktreesTurboCacheDir, runSetup, runTeardown, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, stripPort, worktreeProvider, writeWorktreeMarker } from './chunk-
|
|
3
|
+
import { computeProvenance, execArgv, classify, computeWorktreeStatus, listGitWorktrees, execGit, worktreeProvider } from './chunk-RQUJW75P.mjs';
|
|
4
|
+
export { CONFIG_FILENAME, ConfigError, DEFAULT_PROXY_PORT, ENV_VARS, FileVerdictMemoStore, HookError, InMemoryVerdictMemoStore, ProxyTable, SESSIONS_BUCKETS_ROOT, SESSIONS_FILE_PATH, ServiceSupervisor, VERDICT_MEMO_PATH, WORKTREES_TURBO_CACHE_DIR_ENV, WorktreeNotRemovableError, allocatePort, classify, computeLiveness, computeProvenance, computeTreeState, computeWorktreeStatus, detectDefaultBranch, disposeSupervisor, ephemeralPort, execArgv, execGit, execShell, expandGlob, getScript, getSupervisor, globToRegExp, hookEnv, isPortFree, listGitWorktrees, listScripts, listServices, listWorktreeStatuses, loadConfigFromBase, normalizeHook, parseConfig, peerEnv, peerEnvKey, readSessionsRegistry, readWorktreeMarker, reconcileIntegration, repoLabel, resolveSupervisor, resolveWorktreesTurboCacheDir, runSetup, runTeardown, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, stripPort, worktreeProvider, writeWorktreeMarker } from './chunk-RQUJW75P.mjs';
|
|
5
5
|
import { cleanupWorktreeTool } from './chunk-BBDKRTJK.mjs';
|
|
6
6
|
export { cleanupWorktreeTool, listServicesTool, provisionWorktreeTool, runGateTool, runScriptTool, serviceStatusSchema, startServiceTool, stopServiceTool } from './chunk-BBDKRTJK.mjs';
|
|
7
7
|
import { mkdir, copyFile, writeFile, open, readdir, realpath, rm, readFile, stat } from 'fs/promises';
|
|
@@ -563,6 +563,39 @@ async function reclaimOrphan(entry, options) {
|
|
|
563
563
|
}
|
|
564
564
|
return { path: entry.path, branch: null, result: "reclaimed", reclaimReason: "orphan" };
|
|
565
565
|
}
|
|
566
|
+
function makePrunablePlanEntry(worktree, protectedPaths) {
|
|
567
|
+
if (isProtectedPath(worktree.path, protectedPaths)) {
|
|
568
|
+
return { path: worktree.path, branch: worktree.branch, head: worktree.head, class: "hold", holdReason: "live-session-cwd" };
|
|
569
|
+
}
|
|
570
|
+
return {
|
|
571
|
+
path: worktree.path,
|
|
572
|
+
branch: worktree.branch,
|
|
573
|
+
head: worktree.head,
|
|
574
|
+
class: "reclaim",
|
|
575
|
+
reclaimReason: "prunable",
|
|
576
|
+
prunable: true
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
async function reclaimPrunable(entry, options) {
|
|
580
|
+
const fresh = await listGitWorktrees(options.repoRoot);
|
|
581
|
+
const stillThere = fresh.find((w) => w.path === entry.path);
|
|
582
|
+
if (stillThere && !stillThere.prunable) {
|
|
583
|
+
return { path: entry.path, branch: stillThere.branch, result: "aborted-reclassified", from: "reclaim", to: "hold" };
|
|
584
|
+
}
|
|
585
|
+
if (stillThere) {
|
|
586
|
+
try {
|
|
587
|
+
await execGit(options.repoRoot, ["worktree", "prune"]);
|
|
588
|
+
} catch (err) {
|
|
589
|
+
return {
|
|
590
|
+
path: entry.path,
|
|
591
|
+
branch: entry.branch,
|
|
592
|
+
result: "failed",
|
|
593
|
+
message: err instanceof Error ? err.message : String(err)
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return { path: entry.path, branch: entry.branch, result: "reclaimed", reclaimReason: "prunable" };
|
|
598
|
+
}
|
|
566
599
|
async function toPlanEntry(repoRoot, defaultBranchRef, worktree, status, includeDetached, nowMs, protectedPaths) {
|
|
567
600
|
if (isProtectedPath(worktree.path, protectedPaths)) {
|
|
568
601
|
return {
|
|
@@ -600,6 +633,10 @@ async function planGc(input) {
|
|
|
600
633
|
const worktrees = await linkedWorktreesOf(input.repoRoot);
|
|
601
634
|
const entries = [];
|
|
602
635
|
for (const worktree of worktrees) {
|
|
636
|
+
if (worktree.prunable) {
|
|
637
|
+
entries.push(makePrunablePlanEntry(worktree, input.protectedPaths));
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
603
640
|
const status = await computeWorktreeStatus({
|
|
604
641
|
repoRoot: input.repoRoot,
|
|
605
642
|
repoName: input.repoName,
|
|
@@ -735,6 +772,9 @@ async function applyOne(entry, options) {
|
|
|
735
772
|
if (entry.orphan) {
|
|
736
773
|
return reclaimOrphan(entry, options);
|
|
737
774
|
}
|
|
775
|
+
if (entry.prunable) {
|
|
776
|
+
return reclaimPrunable(entry, options);
|
|
777
|
+
}
|
|
738
778
|
if (entry.class === "hold") {
|
|
739
779
|
return { path: entry.path, branch: entry.branch, result: "held" };
|
|
740
780
|
}
|
|
@@ -784,6 +824,9 @@ async function applyGc(plan, options) {
|
|
|
784
824
|
async function reclaimOneWorktree(worktreePath, options) {
|
|
785
825
|
const worktree = await findWorktree(options.repoRoot, worktreePath);
|
|
786
826
|
if (!worktree) return null;
|
|
827
|
+
if (worktree.prunable) {
|
|
828
|
+
return applyOne(makePrunablePlanEntry(worktree, options.protectedPaths), options);
|
|
829
|
+
}
|
|
787
830
|
const status = await computeWorktreeStatus({
|
|
788
831
|
repoRoot: options.repoRoot,
|
|
789
832
|
repoName: options.repoName,
|