@agentproto/worktree 0.4.3 → 0.5.1
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 +6 -3
- package/dist/bin/worktree-agent.mjs +2 -2
- package/dist/{chunk-PKV55ERJ.mjs → chunk-PSNNWGAF.mjs} +3 -3
- package/dist/{chunk-PKV55ERJ.mjs.map → chunk-PSNNWGAF.mjs.map} +1 -1
- package/dist/{chunk-OFO7QHCW.mjs → chunk-S5ARFUTK.mjs} +19 -13
- package/dist/chunk-S5ARFUTK.mjs.map +1 -0
- package/dist/index.d.ts +87 -4
- package/dist/index.mjs +59 -13
- package/dist/index.mjs.map +1 -1
- package/dist/provider/index.mjs +1 -1
- package/package.json +5 -5
- package/dist/chunk-OFO7QHCW.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -375,6 +375,36 @@ declare function serviceEnv(args: {
|
|
|
375
375
|
self: PeerService;
|
|
376
376
|
peers: readonly PeerService[];
|
|
377
377
|
}): Record<string, string>;
|
|
378
|
+
/** Explicit override for {@link resolveWorktreesTurboCacheDir} — a daemon-
|
|
379
|
+
* level pin, same naming shape as `AGENTPROTO_WORKTREES_ROOT`/
|
|
380
|
+
* `AGENTPROTO_WORKTREES_ISOLATION` in `@agentproto/runtime`. */
|
|
381
|
+
declare const WORKTREES_TURBO_CACHE_DIR_ENV = "AGENTPROTO_WORKTREES_TURBO_CACHE_DIR";
|
|
382
|
+
/**
|
|
383
|
+
* Resolve the turbo build-cache directory `runSetup` points every
|
|
384
|
+
* provisioned worktree's setup hooks at (`TURBO_CACHE_DIR` — see turbo's own
|
|
385
|
+
* `--cache-dir` flag, which this env var sets). Measured on a real machine
|
|
386
|
+
* (WP-F): a repo's main checkout carries a turbo cache in the hundreds of MB;
|
|
387
|
+
* a freshly provisioned worktree, with none, pays a full cold `pnpm build`
|
|
388
|
+
* (~103 tasks) instead of a cache restore. `agentproto.json`'s own
|
|
389
|
+
* `worktree.setup` never set this, so every worktree paid that cost
|
|
390
|
+
* independently — this closes it by pointing every worktree at ONE shared
|
|
391
|
+
* directory instead.
|
|
392
|
+
*
|
|
393
|
+
* Deliberately NOT inside any worktree (would die with `worktree rm`) and
|
|
394
|
+
* NOT inside the monorepo checkout being built (would otherwise sit inside
|
|
395
|
+
* pnpm's/turbo's own workspace-relative globs, risking either tool treating
|
|
396
|
+
* its own cache as workspace content). Precedence, matching the rest of this
|
|
397
|
+
* codebase's `worktrees.*` knobs:
|
|
398
|
+
* 1. `AGENTPROTO_WORKTREES_TURBO_CACHE_DIR` — explicit override.
|
|
399
|
+
* 2. a bare `TURBO_CACHE_DIR` already in this process's env — an operator
|
|
400
|
+
* who already exports it (AGENTS.md's own advice, for a *manually*
|
|
401
|
+
* driven worktree) is respected rather than silently redirected.
|
|
402
|
+
* 3. `~/.agentproto/turbo-cache` — a real, single default, mirroring
|
|
403
|
+
* `worktrees.root`'s own reasoning: zero-config still converges every
|
|
404
|
+
* worktree's build cache to one shared place rather than leaving it
|
|
405
|
+
* unset (today's behaviour — each worktree builds cold).
|
|
406
|
+
*/
|
|
407
|
+
declare function resolveWorktreesTurboCacheDir(): string;
|
|
378
408
|
|
|
379
409
|
/** One hook command's result, kept for error reporting / logging. */
|
|
380
410
|
interface HookRun {
|
|
@@ -389,9 +419,14 @@ declare class HookError extends Error {
|
|
|
389
419
|
}
|
|
390
420
|
/**
|
|
391
421
|
* Run the `worktree.setup` hooks sequentially in the worktree, with the
|
|
392
|
-
* `AGENTPROTO_*` context env injected
|
|
393
|
-
*
|
|
394
|
-
*
|
|
422
|
+
* `AGENTPROTO_*` context env injected — plus `TURBO_CACHE_DIR`, pointed at a
|
|
423
|
+
* directory shared across every provisioned worktree (see
|
|
424
|
+
* {@link resolveWorktreesTurboCacheDir}), so a `pnpm build` (or any other
|
|
425
|
+
* turbo-driven build) run BY a setup hook restores from cache instead of
|
|
426
|
+
* paying a full cold build every single time a worktree is provisioned. A
|
|
427
|
+
* setup hook that doesn't use turbo simply never reads the var. The first
|
|
428
|
+
* non-zero exit throws {@link HookError} (setup failure must fail
|
|
429
|
+
* provisioning). No-op when the repo declares no setup.
|
|
395
430
|
*/
|
|
396
431
|
declare function runSetup(config: AgentprotoConfig, ctx: WorktreeEnvContext): Promise<HookRun[]>;
|
|
397
432
|
/**
|
|
@@ -1107,6 +1142,14 @@ declare function makeDaemonAgentSessionHost(client: DaemonClient): DaemonAgentSe
|
|
|
1107
1142
|
* but this module doesn't lean on that as the only guard: the main worktree
|
|
1108
1143
|
* is filtered out before classification even runs, so it can never appear
|
|
1109
1144
|
* in a plan, let alone be attempted.
|
|
1145
|
+
*
|
|
1146
|
+
* One reclassification on top of `classify`'s three classes:
|
|
1147
|
+
* `resolveGcClass` promotes a clean, `unpushed` worktree from `hold` to
|
|
1148
|
+
* `reclaim` when every commit ahead of the default branch is a mechanical
|
|
1149
|
+
* dependency bump (subject AND cumulative diff both checked — see that
|
|
1150
|
+
* function's doc). It's applied identically at plan time and re-verified at
|
|
1151
|
+
* apply time (layer 2), so a worktree that grew a real commit in between is
|
|
1152
|
+
* still caught.
|
|
1110
1153
|
*/
|
|
1111
1154
|
|
|
1112
1155
|
type GcClass = "reclaim" | "salvage" | "hold";
|
|
@@ -1130,6 +1173,43 @@ interface ClassifyForGcOptions {
|
|
|
1130
1173
|
* also depends on.
|
|
1131
1174
|
*/
|
|
1132
1175
|
declare function classifyForGc(tree: TreeState, integration: IntegrationState, liveness: LivenessState, options?: ClassifyForGcOptions): GcClass;
|
|
1176
|
+
/** The only reclaim reason this module can attach today. */
|
|
1177
|
+
type GcReclaimReason = "dep-bump";
|
|
1178
|
+
/**
|
|
1179
|
+
* Layer 3+4 of the exemption: EVERY commit ahead of `baseRef` must have a
|
|
1180
|
+
* dep-bump subject (`git log --format=%s`, two-dot range — exactly the
|
|
1181
|
+
* commits `aheadBy` counts, PLAN-comment on `readUpstreamTrack`), AND the
|
|
1182
|
+
* cumulative diff of that whole range (`git diff`, three-dot/merge-base
|
|
1183
|
+
* range, so it isolates the branch's own changes from anything `baseRef`
|
|
1184
|
+
* did independently in the meantime) must touch nothing but lockfiles and
|
|
1185
|
+
* `package.json`. Both checks run unconditionally together — a subject that
|
|
1186
|
+
* lies is cheap, a diff cannot lie, so the diff is the one that actually
|
|
1187
|
+
* gates. Two extra git spawns, only ever paid for a worktree that would
|
|
1188
|
+
* otherwise be `hold` for exactly `clean ∧ unpushed` — every other class
|
|
1189
|
+
* pays nothing.
|
|
1190
|
+
*/
|
|
1191
|
+
declare function isMechanicalDepBumpRange(repoRoot: string, baseRef: string, tipSha: string): Promise<boolean>;
|
|
1192
|
+
interface ResolveGcClassOptions extends ClassifyForGcOptions {
|
|
1193
|
+
repoRoot: string;
|
|
1194
|
+
/** The tip commit of the worktree being classified — `worktree.head`. */
|
|
1195
|
+
tipSha: string;
|
|
1196
|
+
/** Default `"origin/main"` — matches `reconcileIntegration`'s own default. */
|
|
1197
|
+
defaultBranchRef?: string;
|
|
1198
|
+
}
|
|
1199
|
+
interface ResolvedGcClass {
|
|
1200
|
+
class: GcClass;
|
|
1201
|
+
/** Set only when `class === "reclaim"` via the dep-bump exemption rather than the ordinary merged/fresh path. */
|
|
1202
|
+
reclaimReason?: GcReclaimReason;
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* `classifyForGc` plus the one async, git-touching layer on top: a clean,
|
|
1206
|
+
* `unpushed` worktree whose entire ahead range is a mechanical dep bump is
|
|
1207
|
+
* promoted from `hold` to `reclaim`. Every other class classifyForGc
|
|
1208
|
+
* returns is passed through untouched — this never widens any other hold
|
|
1209
|
+
* reason, and never touches git for a worktree it wouldn't otherwise hold
|
|
1210
|
+
* on `unpushed` alone.
|
|
1211
|
+
*/
|
|
1212
|
+
declare function resolveGcClass(tree: TreeState, integration: IntegrationState, liveness: LivenessState, options: ResolveGcClassOptions): Promise<ResolvedGcClass>;
|
|
1133
1213
|
interface GcPlanEntry {
|
|
1134
1214
|
path: string;
|
|
1135
1215
|
branch: string | null;
|
|
@@ -1139,6 +1219,8 @@ interface GcPlanEntry {
|
|
|
1139
1219
|
liveness: LivenessState;
|
|
1140
1220
|
/** Classification per PLAN.md §5.1, after `--include-detached` (if set). */
|
|
1141
1221
|
class: GcClass;
|
|
1222
|
+
/** Set only when `class === "reclaim"` via the dep-bump exemption — see `resolveGcClass`. */
|
|
1223
|
+
reclaimReason?: GcReclaimReason;
|
|
1142
1224
|
}
|
|
1143
1225
|
interface PlanGcInput {
|
|
1144
1226
|
repoRoot: string;
|
|
@@ -1178,6 +1260,7 @@ type GcApplyOutcome = {
|
|
|
1178
1260
|
path: string;
|
|
1179
1261
|
branch: string | null;
|
|
1180
1262
|
result: "reclaimed";
|
|
1263
|
+
reclaimReason?: GcReclaimReason;
|
|
1181
1264
|
} | {
|
|
1182
1265
|
path: string;
|
|
1183
1266
|
branch: string | null;
|
|
@@ -1224,4 +1307,4 @@ type GcApplyOutcome = {
|
|
|
1224
1307
|
*/
|
|
1225
1308
|
declare function applyGc(plan: readonly GcPlanEntry[], options: ApplyGcOptions): Promise<GcApplyOutcome[]>;
|
|
1226
1309
|
|
|
1227
|
-
export { type AgentprotoConfig, type ApplyGcOptions, CONFIG_FILENAME, type Classification, type ClassifyForGcOptions, type ComputeProvenanceOptions, type ComputeWorktreeStatusInput, ConfigError, DEFAULT_PROXY_PORT, type DaemonAgentSessionHost, type DaemonClient, ENV_VARS, type ExecOptions, type ExecResult, FileVerdictMemoStore, type ForgeClient, type ForgePullRequestRef, ForgeUnavailableError, type GateState, type GcApplyOutcome, type GcClass, type GcPlanEntry, GhCliForgeClient, type GitWorktreeRef, HookError, type HookRun, type HostnameParts, InMemoryVerdictMemoStore, type IntegrationState, type ListWorktreeStatusesInput, type LivenessState, type NamedScript, type PeerService, type PlanGcInput, type ProvenanceConfidence, type ProvenanceInfo, ProxyTable, type ReconcileIntegrationInput, type ResolveSupervisorInput, type ResolvedWorktreeRuntime, RestForgeClient, type RunningProxy, SALVAGE_ROOT, SESSIONS_BUCKETS_ROOT, SESSIONS_FILE_PATH, type SalvageManifest, type SalvageResult, type SalvageWorktreeInput, type ScriptConfig, type ServiceRuntime, type ServiceStatus, ServiceSupervisor, type SessionRef, type SupervisorOptions, type TreeState, UnreachableForgeClient, VERDICT_MEMO_PATH, type VerdictMemoRecord, type VerdictMemoStore, type WorktreeAgentInput, type WorktreeClass, type WorktreeEnvContext, type WorktreeMarker, WorktreeNotRemovableError, type WorktreeStatusEntry, allocatePort, applyGc, classify, classifyForGc, computeLiveness, computeProvenance, computeTreeState, computeWorktreeStatus, connectDaemonAgentSessionHost, createForgeClient, createProxyServer, detectDefaultBranch, disposeSupervisor, ephemeralPort, execArgv, execGit, execShell, expandGlob, getScript, getSupervisor, globToRegExp, hookEnv, isPortFree, listGitWorktrees, listScripts, listServices, listWorktreeStatuses, loadConfigFromBase, makeDaemonAgentSessionHost, normalizeHook, parseConfig, parseGithubOwnerRepo, peerEnv, peerEnvKey, planGc, readSessionsRegistry, readWorktreeMarker, reconcileIntegration, repoLabel, resolveSupervisor, runSetup, runTeardown, salvageWorktree, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, startProxy, stripPort, worktreeAgentInputSchema, worktreeAgentWorkflow, writeWorktreeMarker };
|
|
1310
|
+
export { type AgentprotoConfig, type ApplyGcOptions, CONFIG_FILENAME, type Classification, type ClassifyForGcOptions, type ComputeProvenanceOptions, type ComputeWorktreeStatusInput, ConfigError, DEFAULT_PROXY_PORT, type DaemonAgentSessionHost, type DaemonClient, ENV_VARS, type ExecOptions, type ExecResult, FileVerdictMemoStore, type ForgeClient, type ForgePullRequestRef, ForgeUnavailableError, type GateState, type GcApplyOutcome, type GcClass, type GcPlanEntry, type GcReclaimReason, GhCliForgeClient, type GitWorktreeRef, HookError, type HookRun, type HostnameParts, InMemoryVerdictMemoStore, type IntegrationState, type ListWorktreeStatusesInput, type LivenessState, type NamedScript, type PeerService, type PlanGcInput, type ProvenanceConfidence, type ProvenanceInfo, ProxyTable, type ReconcileIntegrationInput, type ResolveGcClassOptions, type ResolveSupervisorInput, type ResolvedGcClass, type ResolvedWorktreeRuntime, RestForgeClient, type RunningProxy, SALVAGE_ROOT, SESSIONS_BUCKETS_ROOT, SESSIONS_FILE_PATH, type SalvageManifest, type SalvageResult, type SalvageWorktreeInput, type ScriptConfig, type ServiceRuntime, type ServiceStatus, ServiceSupervisor, type SessionRef, type SupervisorOptions, type TreeState, UnreachableForgeClient, VERDICT_MEMO_PATH, type VerdictMemoRecord, type VerdictMemoStore, WORKTREES_TURBO_CACHE_DIR_ENV, type WorktreeAgentInput, type WorktreeClass, type WorktreeEnvContext, type WorktreeMarker, WorktreeNotRemovableError, type WorktreeStatusEntry, allocatePort, applyGc, classify, classifyForGc, computeLiveness, computeProvenance, computeTreeState, computeWorktreeStatus, connectDaemonAgentSessionHost, createForgeClient, createProxyServer, detectDefaultBranch, disposeSupervisor, ephemeralPort, execArgv, execGit, execShell, expandGlob, getScript, getSupervisor, globToRegExp, hookEnv, isMechanicalDepBumpRange, isPortFree, listGitWorktrees, listScripts, listServices, listWorktreeStatuses, loadConfigFromBase, makeDaemonAgentSessionHost, normalizeHook, parseConfig, parseGithubOwnerRepo, peerEnv, peerEnvKey, planGc, readSessionsRegistry, readWorktreeMarker, reconcileIntegration, repoLabel, resolveGcClass, resolveSupervisor, resolveWorktreesTurboCacheDir, runSetup, runTeardown, salvageWorktree, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, startProxy, stripPort, worktreeAgentInputSchema, worktreeAgentWorkflow, writeWorktreeMarker };
|
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-PSNNWGAF.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, 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, runSetup, runTeardown, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, stripPort, worktreeProvider, writeWorktreeMarker } from './chunk-
|
|
3
|
+
import { computeProvenance, execArgv, classify, computeWorktreeStatus, listGitWorktrees, worktreeProvider } from './chunk-S5ARFUTK.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-S5ARFUTK.mjs';
|
|
5
5
|
import { cleanupWorktreeTool } from './chunk-CM3XGWTY.mjs';
|
|
6
6
|
export { cleanupWorktreeTool, listServicesTool, provisionWorktreeTool, runGateTool, runScriptTool, serviceStatusSchema, startServiceTool, stopServiceTool } from './chunk-CM3XGWTY.mjs';
|
|
7
7
|
import { mkdir, copyFile, writeFile, open } from 'fs/promises';
|
|
@@ -428,11 +428,48 @@ function classifyForGc(tree, integration, liveness, options = {}) {
|
|
|
428
428
|
}
|
|
429
429
|
return classify(tree, integration, liveness, options.nowMs).class;
|
|
430
430
|
}
|
|
431
|
+
var DEP_BUMP_SUBJECT_RE = /^(?:chore|fix)\(deps[\w-]*\):\s/;
|
|
432
|
+
function isDepBumpSubject(subject) {
|
|
433
|
+
return DEP_BUMP_SUBJECT_RE.test(subject);
|
|
434
|
+
}
|
|
435
|
+
var DEP_BUMP_ALLOWED_BASENAMES = /* @__PURE__ */ new Set(["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "package.json"]);
|
|
436
|
+
function isDepBumpAllowedPath(path) {
|
|
437
|
+
return DEP_BUMP_ALLOWED_BASENAMES.has(basename(path));
|
|
438
|
+
}
|
|
439
|
+
async function isMechanicalDepBumpRange(repoRoot, baseRef, tipSha) {
|
|
440
|
+
const [subjectsRes, diffRes] = await Promise.all([
|
|
441
|
+
execArgv("git", ["-C", repoRoot, "log", "--format=%s", `${baseRef}..${tipSha}`], repoRoot),
|
|
442
|
+
execArgv("git", ["-C", repoRoot, "diff", "--name-only", `${baseRef}...${tipSha}`], repoRoot)
|
|
443
|
+
]);
|
|
444
|
+
if (subjectsRes.exitCode !== 0 || diffRes.exitCode !== 0) return false;
|
|
445
|
+
const subjects = subjectsRes.stdout.split("\n").filter((line) => line.length > 0);
|
|
446
|
+
if (subjects.length === 0) return false;
|
|
447
|
+
if (!subjects.every(isDepBumpSubject)) return false;
|
|
448
|
+
const files = diffRes.stdout.split("\n").filter((line) => line.length > 0);
|
|
449
|
+
if (files.length === 0) return false;
|
|
450
|
+
return files.every(isDepBumpAllowedPath);
|
|
451
|
+
}
|
|
452
|
+
async function resolveGcClass(tree, integration, liveness, options) {
|
|
453
|
+
const baseClass = classifyForGc(tree, integration, liveness, options);
|
|
454
|
+
if (baseClass !== "hold") return { class: baseClass };
|
|
455
|
+
if (tree.state !== "clean" || integration.state !== "unpushed") return { class: "hold" };
|
|
456
|
+
const baseRef = options.defaultBranchRef ?? "origin/main";
|
|
457
|
+
const isDepBump = await isMechanicalDepBumpRange(options.repoRoot, baseRef, options.tipSha);
|
|
458
|
+
if (!isDepBump) return { class: "hold" };
|
|
459
|
+
return { class: "reclaim", reclaimReason: "dep-bump" };
|
|
460
|
+
}
|
|
431
461
|
async function linkedWorktreesOf(repoRoot) {
|
|
432
462
|
const worktrees = await listGitWorktrees(repoRoot);
|
|
433
463
|
return worktrees.filter((w) => w.path !== repoRoot);
|
|
434
464
|
}
|
|
435
|
-
function toPlanEntry(worktree, status, includeDetached, nowMs) {
|
|
465
|
+
async function toPlanEntry(repoRoot, defaultBranchRef, worktree, status, includeDetached, nowMs) {
|
|
466
|
+
const resolved = await resolveGcClass(status.tree, status.integration, status.liveness, {
|
|
467
|
+
repoRoot,
|
|
468
|
+
tipSha: worktree.head,
|
|
469
|
+
defaultBranchRef,
|
|
470
|
+
includeDetached,
|
|
471
|
+
nowMs
|
|
472
|
+
});
|
|
436
473
|
return {
|
|
437
474
|
path: worktree.path,
|
|
438
475
|
branch: worktree.branch,
|
|
@@ -440,7 +477,8 @@ function toPlanEntry(worktree, status, includeDetached, nowMs) {
|
|
|
440
477
|
tree: status.tree,
|
|
441
478
|
integration: status.integration,
|
|
442
479
|
liveness: status.liveness,
|
|
443
|
-
class:
|
|
480
|
+
class: resolved.class,
|
|
481
|
+
...resolved.reclaimReason ? { reclaimReason: resolved.reclaimReason } : {}
|
|
444
482
|
};
|
|
445
483
|
}
|
|
446
484
|
async function planGc(input) {
|
|
@@ -459,7 +497,7 @@ async function planGc(input) {
|
|
|
459
497
|
sessionsPath: input.sessionsPath,
|
|
460
498
|
now: input.now
|
|
461
499
|
});
|
|
462
|
-
entries.push(toPlanEntry(worktree, status, includeDetached, nowMs));
|
|
500
|
+
entries.push(await toPlanEntry(input.repoRoot, input.defaultBranchRef, worktree, status, includeDetached, nowMs));
|
|
463
501
|
}
|
|
464
502
|
return entries;
|
|
465
503
|
}
|
|
@@ -467,7 +505,7 @@ async function findWorktree(repoRoot, path) {
|
|
|
467
505
|
const worktrees = await linkedWorktreesOf(repoRoot);
|
|
468
506
|
return worktrees.find((w) => w.path === path) ?? null;
|
|
469
507
|
}
|
|
470
|
-
async function reclaimOne(options, worktree) {
|
|
508
|
+
async function reclaimOne(options, worktree, reclaimReason) {
|
|
471
509
|
try {
|
|
472
510
|
await runTool({
|
|
473
511
|
tool: cleanupWorktreeTool,
|
|
@@ -497,7 +535,12 @@ async function reclaimOne(options, worktree) {
|
|
|
497
535
|
message: err instanceof Error ? err.message : String(err)
|
|
498
536
|
};
|
|
499
537
|
}
|
|
500
|
-
return {
|
|
538
|
+
return {
|
|
539
|
+
path: worktree.path,
|
|
540
|
+
branch: worktree.branch,
|
|
541
|
+
result: "reclaimed",
|
|
542
|
+
...reclaimReason ? { reclaimReason } : {}
|
|
543
|
+
};
|
|
501
544
|
}
|
|
502
545
|
async function salvageOne(options, worktree) {
|
|
503
546
|
let salvageDir;
|
|
@@ -569,20 +612,23 @@ async function applyOne(entry, options) {
|
|
|
569
612
|
sessionsPath: options.sessionsPath,
|
|
570
613
|
now: options.now
|
|
571
614
|
});
|
|
572
|
-
const
|
|
615
|
+
const resolved = await resolveGcClass(status.tree, status.integration, status.liveness, {
|
|
616
|
+
repoRoot: options.repoRoot,
|
|
617
|
+
tipSha: fresh.head,
|
|
618
|
+
defaultBranchRef: options.defaultBranchRef,
|
|
573
619
|
includeDetached: Boolean(options.includeDetached),
|
|
574
620
|
nowMs: options.nowMs
|
|
575
621
|
});
|
|
576
|
-
if (
|
|
622
|
+
if (resolved.class !== entry.class) {
|
|
577
623
|
return {
|
|
578
624
|
path: entry.path,
|
|
579
625
|
branch: fresh.branch,
|
|
580
626
|
result: "aborted-reclassified",
|
|
581
627
|
from: entry.class,
|
|
582
|
-
to:
|
|
628
|
+
to: resolved.class
|
|
583
629
|
};
|
|
584
630
|
}
|
|
585
|
-
if (
|
|
631
|
+
if (resolved.class === "reclaim") return reclaimOne(options, fresh, resolved.reclaimReason);
|
|
586
632
|
return salvageOne(options, fresh);
|
|
587
633
|
}
|
|
588
634
|
async function applyGc(plan, options) {
|
|
@@ -593,6 +639,6 @@ async function applyGc(plan, options) {
|
|
|
593
639
|
return outcomes;
|
|
594
640
|
}
|
|
595
641
|
|
|
596
|
-
export { ForgeUnavailableError, GhCliForgeClient, RestForgeClient, SALVAGE_ROOT, UnreachableForgeClient, applyGc, classifyForGc, createForgeClient, createProxyServer, parseGithubOwnerRepo, planGc, salvageWorktree, startProxy };
|
|
642
|
+
export { ForgeUnavailableError, GhCliForgeClient, RestForgeClient, SALVAGE_ROOT, UnreachableForgeClient, applyGc, classifyForGc, createForgeClient, createProxyServer, isMechanicalDepBumpRange, parseGithubOwnerRepo, planGc, resolveGcClass, salvageWorktree, startProxy };
|
|
597
643
|
//# sourceMappingURL=index.mjs.map
|
|
598
644
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/salvage.ts","../src/services/proxy-server.ts","../src/forge.ts","../src/gc.ts"],"names":["netConnect","resolve","fetch"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Salvage-before-discard (PLAN.md §5.2 layer 4). `worktree archive` re-earns\n * its name by snapshotting a worktree's uncommitted state before it removes\n * anything: `git diff HEAD` → `changes.patch`, plus a byte-copy of every\n * unignored untracked file, into\n * `~/.agentproto/worktree-salvage/<repoName>/<slug>-<tipSha7>-<date>/` with a\n * `MANIFEST.json`. Every file is fsynced before this returns — only once the\n * snapshot is durable does the caller proceed to force-remove.\n *\n * Deliberately forge-independent: no PR lookup here. This writer's only job\n * is \"don't lose bytes before deletion,\" not classification — `ls --status`\n * (status.ts) already owns the forge-derived `integration` axis, and gc\n * (PR-D) is where a salvage manifest and a status entry would be cross-\n * referenced, not here.\n */\n\nimport { copyFile, mkdir, open, writeFile } from \"node:fs/promises\"\nimport { homedir } from \"node:os\"\nimport { dirname, join, resolve } from \"node:path\"\nimport { execArgv } from \"./exec.js\"\nimport { computeProvenance, type ProvenanceInfo } from \"./provenance.js\"\n\nexport const SALVAGE_ROOT = (): string => resolve(homedir(), \".agentproto\", \"worktree-salvage\")\n\nexport interface SalvageManifest {\n repo: string\n /** `null` for a detached HEAD. */\n branch: string | null\n tipSha: string\n createdAt: string\n /** Relative paths of every unignored untracked file that was copied in. */\n untrackedFiles: string[]\n /** Whether `changes.patch` has any content (tracked-file changes existed). */\n hasPatch: boolean\n provenance: ProvenanceInfo\n}\n\nexport interface SalvageWorktreeInput {\n /** The main repo root — the stable spawn anchor for this worktree's git reads (see `listUntrackedFiles`'s doc). */\n repoRoot: string\n repoName: string\n worktreePath: string\n branch: string | null\n tipSha: string\n /** Identifies this worktree in the salvage directory name, e.g. its slug or branch. */\n slug: string\n sessionsPath?: string\n /** Injectable clock so tests can freeze `createdAt` / the directory name. */\n now?: () => string\n /** Override for `~/.agentproto/worktree-salvage` — tests use a temp dir. */\n salvageRoot?: string\n}\n\nexport interface SalvageResult {\n dir: string\n manifest: SalvageManifest\n}\n\n/**\n * Untracked, non-ignored files in the worktree — the same class `git\n * worktree remove` refuses without `--force`. Spawn `cwd` is `repoRoot`, not\n * `worktreePath` — a linked worktree can be removed by a concurrent `gc`\n * reap (or a racing status read) while this call is in flight, and a spawn\n * whose `cwd` no longer exists fails `ENOENT` on the COMMAND itself (a\n * Node/libuv quirk), not the directory — see `exec.ts`'s `execGit`, which\n * anchors the same way.\n */\nasync function listUntrackedFiles(repoRoot: string, worktreePath: string): Promise<string[]> {\n const res = await execArgv(\"git\", [\"-C\", worktreePath, \"ls-files\", \"--others\", \"--exclude-standard\"], repoRoot)\n if (res.exitCode !== 0) {\n throw new Error(`git ls-files --others failed in ${worktreePath} (exit ${res.exitCode}): ${res.stderr.trim()}`)\n }\n return res.stdout.split(\"\\n\").filter(Boolean)\n}\n\n/** `git diff HEAD` — staged + unstaged changes to tracked files, uniformly.\n * Empty string on a clean tree. Spawn `cwd` is `repoRoot`, not\n * `worktreePath` — see `listUntrackedFiles`'s doc. */\nasync function diffHead(repoRoot: string, worktreePath: string): Promise<string> {\n const res = await execArgv(\"git\", [\"-C\", worktreePath, \"diff\", \"HEAD\"], repoRoot)\n if (res.exitCode !== 0) {\n throw new Error(`git diff HEAD failed in ${worktreePath} (exit ${res.exitCode}): ${res.stderr.trim()}`)\n }\n return res.stdout\n}\n\n/** Sanitize a path segment for use in the salvage directory name (no slashes, no leading dot-dot). */\nfunction sanitizeSegment(value: string): string {\n return value.replace(/[^a-zA-Z0-9._-]+/g, \"-\").replace(/^-+/, \"\") || \"worktree\"\n}\n\n/** fsync one file by path — the durability guarantee: only after this resolves is the byte \"saved\". */\nasync function fsyncFile(path: string): Promise<void> {\n const handle = await open(path, \"r+\")\n try {\n await handle.sync()\n } finally {\n await handle.close()\n }\n}\n\nasync function writeFileSynced(path: string, content: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, content, \"utf8\")\n await fsyncFile(path)\n}\n\n/**\n * Snapshot `worktreePath`'s uncommitted state into a fresh salvage\n * directory. Safe to call on a clean tree (writes an empty patch, no\n * untracked files, still a manifest) — every path this function returns is\n * fsynced before it resolves.\n */\nexport async function salvageWorktree(input: SalvageWorktreeInput): Promise<SalvageResult> {\n const now = input.now ?? (() => new Date().toISOString())\n const createdAt = now()\n const tipShort = input.tipSha.slice(0, 7)\n const dateStamp = createdAt.slice(0, 10)\n const dirName = `${sanitizeSegment(input.slug)}-${tipShort}-${dateStamp}`\n const dir = resolve(input.salvageRoot ?? SALVAGE_ROOT(), sanitizeSegment(input.repoName), dirName)\n await mkdir(dir, { recursive: true })\n\n const [patch, untrackedFiles, provenance] = await Promise.all([\n diffHead(input.repoRoot, input.worktreePath),\n listUntrackedFiles(input.repoRoot, input.worktreePath),\n computeProvenance(input.repoRoot, input.worktreePath, { sessionsPath: input.sessionsPath }),\n ])\n\n await writeFileSynced(join(dir, \"changes.patch\"), patch)\n\n for (const relPath of untrackedFiles) {\n const dest = join(dir, \"untracked\", relPath)\n await mkdir(dirname(dest), { recursive: true })\n await copyFile(join(input.worktreePath, relPath), dest)\n await fsyncFile(dest)\n }\n\n const manifest: SalvageManifest = {\n repo: input.repoName,\n branch: input.branch,\n tipSha: input.tipSha,\n createdAt,\n untrackedFiles,\n hasPatch: patch.length > 0,\n provenance,\n }\n await writeFileSynced(join(dir, \"MANIFEST.json\"), JSON.stringify(manifest, null, 2) + \"\\n\")\n\n return { dir, manifest }\n}\n","import http from \"node:http\"\nimport { connect as netConnect, type Socket } from \"node:net\"\nimport type { ProxyTable } from \"./proxy-table.js\"\n\n/**\n * A small HTTP reverse proxy over a {@link ProxyTable}. Routes\n * `http://<script>--<branch>--<repo>.localhost:<proxy-port>` to the matched\n * service's local port. Supports WebSocket (and any) `Upgrade` passthrough by\n * splicing raw sockets. Targets are always `127.0.0.1` — services bind\n * locally, the proxy is the only public-ish surface.\n */\n\nconst TARGET_HOST = \"127.0.0.1\"\n\nfunction notFound(table: ProxyTable, host: string | undefined): string {\n const known = table.entries().map(([h]) => h)\n return (\n `worktree-proxy: no service for host \"${host ?? \"(none)\"}\"\\n` +\n (known.length ? `known hosts:\\n${known.map((h) => ` ${h}`).join(\"\\n\")}\\n` : \"no services registered\\n\")\n )\n}\n\n/** Build (but don't start) the proxy HTTP server backed by `table`. */\nexport function createProxyServer(table: ProxyTable): http.Server {\n const server = http.createServer((req, res) => {\n const targetPort = table.lookup(req.headers.host)\n if (targetPort === undefined) {\n res.writeHead(502, { \"content-type\": \"text/plain\" })\n res.end(notFound(table, req.headers.host))\n return\n }\n\n const proxyReq = http.request(\n {\n host: TARGET_HOST,\n port: targetPort,\n method: req.method,\n path: req.url,\n headers: req.headers,\n },\n (proxyRes) => {\n res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers)\n proxyRes.pipe(res)\n },\n )\n proxyReq.on(\"error\", (err) => {\n if (!res.headersSent) res.writeHead(502, { \"content-type\": \"text/plain\" })\n res.end(`worktree-proxy: upstream error: ${err.message}\\n`)\n })\n req.pipe(proxyReq)\n })\n\n // WebSocket / generic Upgrade passthrough: splice the client socket to a\n // fresh TCP connection to the target, replaying the original request line\n // and headers so the upstream completes its own handshake.\n server.on(\"upgrade\", (req, clientSocket: Socket, head: Buffer) => {\n const targetPort = table.lookup(req.headers.host)\n if (targetPort === undefined) {\n clientSocket.end(\"HTTP/1.1 502 Bad Gateway\\r\\n\\r\\n\")\n return\n }\n\n const upstream = netConnect(targetPort, TARGET_HOST, () => {\n const headerLines = [`${req.method} ${req.url} HTTP/1.1`]\n for (let i = 0; i < req.rawHeaders.length; i += 2) {\n headerLines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`)\n }\n upstream.write(headerLines.join(\"\\r\\n\") + \"\\r\\n\\r\\n\")\n if (head && head.length) upstream.write(head)\n upstream.pipe(clientSocket)\n clientSocket.pipe(upstream)\n })\n\n const teardown = (): void => {\n clientSocket.destroy()\n upstream.destroy()\n }\n upstream.on(\"error\", teardown)\n clientSocket.on(\"error\", teardown)\n upstream.on(\"close\", () => clientSocket.destroy())\n clientSocket.on(\"close\", () => upstream.destroy())\n })\n\n return server\n}\n\nexport interface RunningProxy {\n /** The port the proxy is listening on. */\n port: number\n /** The underlying server. */\n server: http.Server\n /** Stop the proxy. */\n close(): Promise<void>\n}\n\n/** Start the proxy server on `port` (0 → OS-assigned). Resolves once listening. */\nexport function startProxy(table: ProxyTable, port = 0): Promise<RunningProxy> {\n const server = createProxyServer(table)\n // Track every accepted socket so shutdown can force-drop them. An upgraded\n // (WebSocket) connection is detached from the server's own tracking, so\n // `server.close()` alone would hang on it — we destroy them explicitly.\n const sockets = new Set<Socket>()\n server.on(\"connection\", (socket: Socket) => {\n sockets.add(socket)\n socket.once(\"close\", () => sockets.delete(socket))\n })\n return new Promise((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(port, () => {\n const address = server.address()\n const boundPort = address && typeof address === \"object\" ? address.port : port\n resolve({\n port: boundPort,\n server,\n close: () =>\n new Promise<void>((res) => {\n for (const socket of sockets) socket.destroy()\n sockets.clear()\n server.close(() => res())\n }),\n })\n })\n })\n}\n","/**\n * `ForgeClient` — the only network-facing surface the reconciliation rule\n * (`status.ts`) depends on. Kept as an interface (not a concrete `gh` call)\n * so:\n * 1. `status.ts` stays testable with a fake — the fixture-repo tests never\n * shell out to a real forge or touch the network.\n * 2. The shape is forge-portable by construction (PLAN.md §7.1): GitLab has\n * the same two facts — \"PRs/MRs whose head is this branch\" and \"PRs/MRs\n * that contain this commit\" — under different verbs\n * (`refs/merge-requests/<n>/head`, `GET /merge_requests?…`). Only\n * GitHub ships today; a `GitlabForgeClient` is a second implementation\n * of this same interface, not a redesign.\n *\n * Two implementations ship: `GhCliForgeClient` (shells out to the `gh` CLI,\n * inheriting the caller's own `gh auth` session — zero config) and\n * `RestForgeClient` (plain `fetch` against the GitHub REST API using\n * `GITHUB_TOKEN` — no new npm dependency). `createForgeClient` picks\n * whichever is usable; when neither is, callers get a client that always\n * reports itself unreachable, which the reconciliation rule already knows\n * how to fall back from (PLAN.md §1.3 step 5: memo, else `unknown(offline)`,\n * never a guess).\n */\n\nimport { z } from \"zod\"\nimport { execArgv } from \"./exec.js\"\n\n/** A pull/merge request as the reconciliation rule needs to see it. */\nexport interface ForgePullRequestRef {\n number: number\n state: \"open\" | \"closed\"\n merged: boolean\n mergedAt: string | null\n headRefName: string\n headRefOid: string\n}\n\n/**\n * Thrown by a `ForgeClient` method when the forge could not be reached or\n * queried at all (network failure, missing/unauthenticated CLI, non-2xx HTTP\n * response). Never thrown for a legitimate empty result (a branch/commit\n * with no PRs is a valid, resolvable answer — `[]`, not an error). Callers\n * treat this as PLAN.md §1.3 step 5: \"never guess.\"\n */\nexport class ForgeUnavailableError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = \"ForgeUnavailableError\"\n }\n}\n\nexport interface ForgeClient {\n /** PRs/MRs (any state) whose head branch is exactly `branch`. */\n pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]>\n /**\n * PRs/MRs associated with a specific commit SHA — the rename/retarget-proof\n * signal (PLAN.md §1.3 step 2b): finds the PR even if the branch was\n * renamed or deleted before merge.\n */\n pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]>\n /**\n * Ensure `oid` (a PR's `headRefOid`) is present in the local object\n * database, fetching `refs/pull/<number>/head` if it isn't. Always\n * fetchable even after the head branch was deleted on the remote\n * (PLAN.md §1.3 step 2, verified for #273/#312/#325/#271).\n */\n ensurePullHeadFetched(prNumber: number, oid: string): Promise<void>\n}\n\n/** A client that always reports itself unreachable — the \"no gh, no token\" case. */\nexport class UnreachableForgeClient implements ForgeClient {\n constructor(private readonly reason: string) {}\n async pullRequestsForBranch(): Promise<ForgePullRequestRef[]> {\n throw new ForgeUnavailableError(this.reason)\n }\n async pullRequestsForCommit(): Promise<ForgePullRequestRef[]> {\n throw new ForgeUnavailableError(this.reason)\n }\n async ensurePullHeadFetched(): Promise<void> {\n throw new ForgeUnavailableError(this.reason)\n }\n}\n\n// ── gh CLI implementation ───────────────────────────────────────────────\n\nconst ghPrListItemSchema = z.object({\n number: z.number(),\n state: z.string(),\n headRefName: z.string(),\n headRefOid: z.string(),\n mergedAt: z.string().nullable(),\n})\ntype GhPrListItem = z.infer<typeof ghPrListItemSchema>\nconst ghPrListSchema = z.array(ghPrListItemSchema)\n\nfunction normalizeGhPrListItem(item: GhPrListItem): ForgePullRequestRef {\n const state = item.state.toUpperCase()\n return {\n number: item.number,\n state: state === \"OPEN\" ? \"open\" : \"closed\",\n merged: state === \"MERGED\" || item.mergedAt !== null,\n mergedAt: item.mergedAt,\n headRefName: item.headRefName,\n headRefOid: item.headRefOid,\n }\n}\n\nconst ghApiCommitPullSchema = z.object({\n number: z.number(),\n state: z.string(),\n merged_at: z.string().nullable(),\n head: z.object({ ref: z.string(), sha: z.string() }),\n})\ntype GhApiCommitPull = z.infer<typeof ghApiCommitPullSchema>\nconst ghApiCommitPullListSchema = z.array(ghApiCommitPullSchema)\n\nfunction normalizeGhApiCommitPull(item: GhApiCommitPull): ForgePullRequestRef {\n return {\n number: item.number,\n state: item.state === \"open\" ? \"open\" : \"closed\",\n merged: item.merged_at !== null,\n mergedAt: item.merged_at,\n headRefName: item.head.ref,\n headRefOid: item.head.sha,\n }\n}\n\n/**\n * GitHub's REST API answers \"commit unknown to this repo\" (e.g. a local\n * commit that was never pushed) with HTTP 422 on `commits/:sha/pulls` —\n * empirically verified against a real unpushed worktree commit, not the 404\n * the endpoint's own docs imply. `gh api` surfaces the status in its stderr\n * as `(HTTP nnn)`. Both 404 and 422 here mean the same legitimate thing:\n * zero associated PRs, not \"the forge is unreachable\" — never guess step 5\n * on a genuinely empty, well-formed answer.\n */\nfunction isCommitNotFoundError(output: string): boolean {\n return /\\(HTTP (404|422)\\)/.test(output)\n}\n\n/** Runs `gh` in `repoRoot` so it auto-detects owner/repo from the `origin` remote there. */\nexport class GhCliForgeClient implements ForgeClient {\n constructor(private readonly repoRoot: string) {}\n\n private async runRaw(args: readonly string[]): Promise<{ exitCode: number; stdout: string; stderr: string }> {\n try {\n return await execArgv(\"gh\", args, this.repoRoot)\n } catch (err) {\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} could not be run: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n )\n }\n }\n\n private async run(args: readonly string[]): Promise<string> {\n const result = await this.runRaw(args)\n if (result.exitCode !== 0) {\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`,\n )\n }\n return result.stdout\n }\n\n private parseOutput<T>(stdout: string, schema: z.ZodType<T[]>, args: readonly string[]): T[] {\n let parsed: unknown\n try {\n parsed = JSON.parse(stdout)\n } catch (err) {\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} produced non-JSON output: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n const result = schema.safeParse(parsed)\n if (!result.success) {\n throw new ForgeUnavailableError(`gh ${args.join(\" \")} output did not match the expected shape`)\n }\n return result.data\n }\n\n async pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]> {\n const args = [\n \"pr\",\n \"list\",\n \"--head\",\n branch,\n \"--state\",\n \"all\",\n \"--json\",\n \"number,state,headRefName,headRefOid,mergedAt\",\n ]\n const stdout = await this.run(args)\n return this.parseOutput(stdout, ghPrListSchema, args).map(normalizeGhPrListItem)\n }\n\n async pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]> {\n const args = [\"api\", `repos/{owner}/{repo}/commits/${sha}/pulls`]\n const result = await this.runRaw(args)\n if (result.exitCode !== 0) {\n if (isCommitNotFoundError(result.stderr) || isCommitNotFoundError(result.stdout)) return []\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`,\n )\n }\n return this.parseOutput(result.stdout, ghApiCommitPullListSchema, args).map(normalizeGhApiCommitPull)\n }\n\n async ensurePullHeadFetched(prNumber: number, oid: string): Promise<void> {\n const check = await execArgv(\"git\", [\"-C\", this.repoRoot, \"cat-file\", \"-e\", `${oid}^{commit}`], this.repoRoot)\n if (check.exitCode === 0) return\n const fetch = await execArgv(\n \"git\",\n [\"-C\", this.repoRoot, \"fetch\", \"origin\", `refs/pull/${prNumber}/head`],\n this.repoRoot,\n )\n if (fetch.exitCode !== 0) {\n throw new ForgeUnavailableError(\n `git fetch origin refs/pull/${prNumber}/head failed: ${fetch.stderr.trim() || fetch.stdout.trim()}`,\n )\n }\n }\n}\n\n// ── GITHUB_TOKEN REST fallback (no new npm dependency — global fetch) ───\n\nconst restPullRequestSchema = z.object({\n number: z.number(),\n state: z.string(),\n merged_at: z.string().nullable(),\n head: z.object({ ref: z.string(), sha: z.string() }),\n})\ntype RestPullRequest = z.infer<typeof restPullRequestSchema>\nconst restPullRequestListSchema = z.array(restPullRequestSchema)\n\nfunction normalizeRestPr(item: RestPullRequest): ForgePullRequestRef {\n return {\n number: item.number,\n state: item.state === \"open\" ? \"open\" : \"closed\",\n merged: item.merged_at !== null,\n mergedAt: item.merged_at,\n headRefName: item.head.ref,\n headRefOid: item.head.sha,\n }\n}\n\n/** Parse `owner/repo` out of a `git remote get-url origin` value (ssh or https form). */\nexport function parseGithubOwnerRepo(remoteUrl: string): { owner: string; repo: string } | null {\n const ssh = remoteUrl.match(/^git@github\\.com:([^/]+)\\/(.+?)(\\.git)?$/)\n if (ssh?.[1] && ssh[2]) return { owner: ssh[1], repo: ssh[2] }\n const https = remoteUrl.match(/^https:\\/\\/github\\.com\\/([^/]+)\\/(.+?)(\\.git)?\\/?$/)\n if (https?.[1] && https[2]) return { owner: https[1], repo: https[2] }\n return null\n}\n\nexport class RestForgeClient implements ForgeClient {\n constructor(\n private readonly owner: string,\n private readonly repo: string,\n private readonly repoRoot: string,\n private readonly token: string,\n private readonly fetchFn: typeof fetch = fetch,\n ) {}\n\n private headers(): Record<string, string> {\n return {\n Authorization: `Bearer ${this.token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n \"User-Agent\": \"agentproto-worktree-status\",\n }\n }\n\n private async get(path: string): Promise<Response> {\n try {\n return await this.fetchFn(`https://api.github.com${path}`, { headers: this.headers() })\n } catch (err) {\n throw new ForgeUnavailableError(\n `GitHub REST request to ${path} failed: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n )\n }\n }\n\n private async pullRequestList(res: Response): Promise<ForgePullRequestRef[]> {\n const body: unknown = await res.json()\n const result = restPullRequestListSchema.safeParse(body)\n if (!result.success) {\n throw new ForgeUnavailableError(`GitHub REST response did not match the expected PR list shape`)\n }\n return result.data.map(normalizeRestPr)\n }\n\n async pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]> {\n const res = await this.get(\n `/repos/${this.owner}/${this.repo}/pulls?head=${this.owner}:${encodeURIComponent(branch)}&state=all&per_page=100`,\n )\n if (!res.ok) {\n throw new ForgeUnavailableError(`GitHub REST pulls?head= failed: ${res.status} ${res.statusText}`)\n }\n return this.pullRequestList(res)\n }\n\n async pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]> {\n const res = await this.get(`/repos/${this.owner}/${this.repo}/commits/${sha}/pulls?per_page=100`)\n // 404 is what the endpoint's docs imply for an unknown commit; 422 is what\n // it empirically returns for one that was never pushed (verified live).\n // Both mean the same legitimate thing: zero associated PRs.\n if (res.status === 404 || res.status === 422) return []\n if (!res.ok) {\n throw new ForgeUnavailableError(`GitHub REST commits/:sha/pulls failed: ${res.status} ${res.statusText}`)\n }\n return this.pullRequestList(res)\n }\n\n async ensurePullHeadFetched(prNumber: number, oid: string): Promise<void> {\n const check = await execArgv(\"git\", [\"-C\", this.repoRoot, \"cat-file\", \"-e\", `${oid}^{commit}`], this.repoRoot)\n if (check.exitCode === 0) return\n const fetch2 = await execArgv(\n \"git\",\n [\"-C\", this.repoRoot, \"fetch\", \"origin\", `refs/pull/${prNumber}/head`],\n this.repoRoot,\n )\n if (fetch2.exitCode !== 0) {\n throw new ForgeUnavailableError(\n `git fetch origin refs/pull/${prNumber}/head failed: ${fetch2.stderr.trim() || fetch2.stdout.trim()}`,\n )\n }\n }\n}\n\n/** Cheap \"is `gh` on PATH and authenticated\" probe — avoids a slow failure per branch. */\nasync function ghIsUsable(repoRoot: string): Promise<boolean> {\n try {\n const res = await execArgv(\"gh\", [\"auth\", \"status\"], repoRoot)\n return res.exitCode === 0\n } catch {\n return false\n }\n}\n\n/**\n * Pick the best available `ForgeClient` for `repoRoot`: `gh` CLI first (zero\n * config, inherits the caller's own auth), else `GITHUB_TOKEN` REST, else a\n * client that always reports unreachable — the reconciliation rule already\n * knows how to fall back from that (memo, else `unknown(offline)`).\n */\nexport async function createForgeClient(repoRoot: string): Promise<ForgeClient> {\n if (await ghIsUsable(repoRoot)) return new GhCliForgeClient(repoRoot)\n\n const token = process.env.GITHUB_TOKEN\n if (token) {\n const remote = await execArgv(\"git\", [\"-C\", repoRoot, \"remote\", \"get-url\", \"origin\"], repoRoot)\n const parsed = remote.exitCode === 0 ? parseGithubOwnerRepo(remote.stdout.trim()) : null\n if (parsed) return new RestForgeClient(parsed.owner, parsed.repo, repoRoot, token)\n }\n\n return new UnreachableForgeClient(\n \"no usable forge client: `gh` is not installed/authenticated and GITHUB_TOKEN is not set (or origin isn't a GitHub remote)\",\n )\n}\n","/**\n * `gc` (PLAN.md §5, PR-D): plan → apply → salvage over the status engine's\n * classification (`status.ts`, PR-A). This module owns no new git knowledge\n * — it reuses `listGitWorktrees` / `computeWorktreeStatus` / `classify` for\n * every fact and `salvageWorktree` / `worktree.cleanup` (PR-C) for every\n * mutation. Its only original logic is sequencing the four safety layers\n * (PLAN.md §5.2):\n *\n * 1. `planGc` is pure read: it classifies every worktree and returns a\n * plan. Nothing is mutated by calling it — the CLI's dry-run default\n * *is* just \"call planGc, print it, stop.\"\n * 2. `applyGc` re-derives each worktree's class from scratch immediately\n * before touching it (a fresh `listGitWorktrees` + `computeWorktreeStatus`,\n * not a reuse of the plan's stale snapshot) and refuses to act if the\n * class changed since the plan was made.\n * 3. The actual removal is `worktree.cleanup` with NO discard flags for a\n * reclaim-class entry — git's own non-`--force` refusal is the backstop\n * this module leans on, never a force flag \"just in case.\"\n * 4. A salvage-class entry is only ever touched via `salvageWorktree`\n * followed by `worktree.cleanup` with both discard flags — snapshot\n * first, removal only after the snapshot is durable (mirrors `worktree\n * archive`'s CLI verb, PR-C).\n *\n * The main worktree (`repoRoot` itself) is never part of the plan: `git\n * worktree list`'s first entry is always the main checkout, and a repo\n * sitting on an up-to-date default branch is trivially `fresh ∧ clean` —\n * exactly what `reclaim` looks for. Git itself refuses to remove\n * the main working tree (\"is a main working tree\", verified empirically),\n * but this module doesn't lean on that as the only guard: the main worktree\n * is filtered out before classification even runs, so it can never appear\n * in a plan, let alone be attempted.\n */\n\nimport { basename } from \"node:path\"\nimport { runTool } from \"@agentproto/driver\"\nimport { cleanupWorktreeTool } from \"./tools/index.js\"\nimport { worktreeProvider } from \"./provider/index.js\"\nimport { salvageWorktree } from \"./salvage.js\"\nimport type { ForgeClient } from \"./forge.js\"\nimport {\n classify,\n listGitWorktrees,\n computeWorktreeStatus,\n type GitWorktreeRef,\n type IntegrationState,\n type LivenessState,\n type TreeState,\n type VerdictMemoStore,\n} from \"./status.js\"\n\nconst candidates = [worktreeProvider]\n\n// ── classification (PLAN.md §5.1) ───────────────────────────────────────\n\nexport type GcClass = \"reclaim\" | \"salvage\" | \"hold\"\n\nexport interface ClassifyForGcOptions {\n /**\n * A clean, idle/daemon-unreachable DETACHED worktree moves from `hold` to\n * `reclaim` (PLAN.md §5.1). This is the only reclassification power any\n * flag has: every other hold reason — partial, open, unknown(offline),\n * gone-unexplained, diverged — is untouched by any flag, ever. Default\n * false.\n */\n includeDetached?: boolean\n /** Threaded straight through to `classify`'s `RECENT_WRITE_HOLD_WINDOW_MS` guard. Defaults to `Date.now()`. */\n nowMs?: number\n}\n\n/**\n * gc's own classifier, layered on top of `classify` (status.ts) rather than\n * reimplementing it — reuse first (AGENTS.md, PLAN.md §0.6). The one thing\n * `classify` cannot know is `--include-detached`, a gc-specific flag; that\n * override lives here, not in the read-only status engine `ls --status`\n * also depends on.\n */\nexport function classifyForGc(\n tree: TreeState,\n integration: IntegrationState,\n liveness: LivenessState,\n options: ClassifyForGcOptions = {},\n): GcClass {\n if (options.includeDetached && integration.state === \"detached\") {\n const idleOrUnreachable = liveness.state === \"idle\" || liveness.state === \"daemon-unreachable\"\n if (tree.state === \"clean\" && idleOrUnreachable) return \"reclaim\"\n }\n return classify(tree, integration, liveness, options.nowMs).class\n}\n\n// ── plan ─────────────────────────────────────────────────────────────\n\nexport interface GcPlanEntry {\n path: string\n branch: string | null\n head: string\n tree: TreeState\n integration: IntegrationState\n liveness: LivenessState\n /** Classification per PLAN.md §5.1, after `--include-detached` (if set). */\n class: GcClass\n}\n\nexport interface PlanGcInput {\n repoRoot: string\n repoName: string\n forge: ForgeClient\n memo: VerdictMemoStore\n defaultBranchRef?: string\n sessionsPath?: string\n includeDetached?: boolean\n now?: () => string\n /** See `ComputeWorktreeStatusInput.nowMs` (status.ts) — kept separate from `now`. Defaults to `Date.now()`. */\n nowMs?: number\n}\n\n/** Every linked worktree of `repoRoot` except the main checkout itself — see the module docblock. */\nasync function linkedWorktreesOf(repoRoot: string): Promise<GitWorktreeRef[]> {\n const worktrees = await listGitWorktrees(repoRoot)\n return worktrees.filter((w) => w.path !== repoRoot)\n}\n\nfunction toPlanEntry(\n worktree: GitWorktreeRef,\n status: { tree: TreeState; integration: IntegrationState; liveness: LivenessState },\n includeDetached: boolean,\n nowMs: number,\n): GcPlanEntry {\n return {\n path: worktree.path,\n branch: worktree.branch,\n head: worktree.head,\n tree: status.tree,\n integration: status.integration,\n liveness: status.liveness,\n class: classifyForGc(status.tree, status.integration, status.liveness, { includeDetached, nowMs }),\n }\n}\n\n/**\n * The dry-run plan (PLAN.md §5.2 layer 1): classify every linked worktree,\n * mutate nothing. This is the human's decision surface — `gc` with no flags\n * is exactly \"call this, print it, stop.\"\n */\nexport async function planGc(input: PlanGcInput): Promise<GcPlanEntry[]> {\n const includeDetached = Boolean(input.includeDetached)\n // One frozen instant for the whole plan's recent-write checks.\n const nowMs = input.nowMs ?? Date.now()\n const worktrees = await linkedWorktreesOf(input.repoRoot)\n const entries: GcPlanEntry[] = []\n for (const worktree of worktrees) {\n const status = await computeWorktreeStatus({\n repoRoot: input.repoRoot,\n repoName: input.repoName,\n worktree,\n forge: input.forge,\n memo: input.memo,\n defaultBranchRef: input.defaultBranchRef,\n sessionsPath: input.sessionsPath,\n now: input.now,\n })\n entries.push(toPlanEntry(worktree, status, includeDetached, nowMs))\n }\n return entries\n}\n\n// ── apply ────────────────────────────────────────────────────────────\n\nexport interface ApplyGcOptions {\n repoRoot: string\n repoName: string\n forge: ForgeClient\n memo: VerdictMemoStore\n defaultBranchRef?: string\n sessionsPath?: string\n includeDetached?: boolean\n /** Archive (salvage-then-remove) every salvage-class entry. Default false — salvage entries are left untouched. */\n salvageDirty?: boolean\n now?: () => string\n /** See `ComputeWorktreeStatusInput.nowMs` (status.ts) — kept separate from `now`. Defaults to `Date.now()`. */\n nowMs?: number\n /** Override for `~/.agentproto/worktree-salvage` — tests use a temp dir. */\n salvageRoot?: string\n}\n\nexport type GcApplyOutcome =\n | { path: string; branch: string | null; result: \"reclaimed\" }\n | { path: string; branch: string | null; result: \"salvaged\"; salvageDir: string }\n | { path: string; branch: string | null; result: \"held\" }\n /** Salvage-class, but `--salvage-dirty` was not passed: left untouched by design. */\n | { path: string; branch: string | null; result: \"skipped-dirty\" }\n /** Layer 2: re-classified at apply time to something other than the plan said — refuses rather than acting on a stale plan. */\n | { path: string; branch: string | null; result: \"aborted-reclassified\"; from: GcClass; to: GcClass }\n /** The worktree named in the plan no longer exists (already removed by something else since the plan was made). */\n | { path: string; branch: string | null; result: \"aborted-vanished\" }\n /** git itself (or the salvage snapshot) refused — the TOCTOU backstop actually firing, or a real I/O failure. */\n | { path: string; branch: string | null; result: \"failed\"; message: string }\n\nasync function findWorktree(repoRoot: string, path: string): Promise<GitWorktreeRef | null> {\n const worktrees = await linkedWorktreesOf(repoRoot)\n return worktrees.find((w) => w.path === path) ?? null\n}\n\nasync function reclaimOne(options: ApplyGcOptions, worktree: GitWorktreeRef): Promise<GcApplyOutcome> {\n try {\n await runTool({\n tool: cleanupWorktreeTool,\n candidates,\n input: {\n repoRoot: options.repoRoot,\n cwd: worktree.path,\n ...(worktree.branch ? { branch: worktree.branch } : {}),\n // Branch deletion only ever runs for a `reclaim`-class entry, which by\n // construction requires `integration ∈ {merged(*), fresh}` and\n // `tree = clean` (PLAN.md's invariant: branch -D only when there's\n // nothing uncommitted to lose, never a hold class).\n deleteBranch: true,\n // No discardUntracked/discardModified, ever, on this path (PLAN.md\n // §5.2 layer 3): `reclaim` means `tree = clean`, so plain `git\n // worktree remove` should succeed on its own; if the tree turned\n // dirty in the instant between the re-check above and this call, git\n // itself refuses and that refusal surfaces below as `failed` — never\n // a force flag \"just in case.\"\n },\n })\n } catch (err) {\n return {\n path: worktree.path,\n branch: worktree.branch,\n result: \"failed\",\n message: err instanceof Error ? err.message : String(err),\n }\n }\n return { path: worktree.path, branch: worktree.branch, result: \"reclaimed\" }\n}\n\nasync function salvageOne(options: ApplyGcOptions, worktree: GitWorktreeRef): Promise<GcApplyOutcome> {\n let salvageDir: string\n try {\n const result = await salvageWorktree({\n repoRoot: options.repoRoot,\n repoName: options.repoName,\n worktreePath: worktree.path,\n branch: worktree.branch,\n tipSha: worktree.head,\n slug: worktree.branch ?? basename(worktree.path),\n sessionsPath: options.sessionsPath,\n now: options.now,\n salvageRoot: options.salvageRoot,\n })\n salvageDir = result.dir\n } catch (err) {\n return {\n path: worktree.path,\n branch: worktree.branch,\n result: \"failed\",\n message: `salvage failed, nothing removed: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n\n try {\n await runTool({\n tool: cleanupWorktreeTool,\n candidates,\n input: {\n repoRoot: options.repoRoot,\n cwd: worktree.path,\n ...(worktree.branch ? { branch: worktree.branch } : {}),\n deleteBranch: true,\n // Both discard flags: the snapshot above is already durable (fsynced)\n // before this call, so nothing on disk is lost by discarding it here\n // (PLAN.md §5.2 layer 4 — salvage before discard).\n discardUntracked: true,\n discardModified: true,\n },\n })\n } catch (err) {\n return {\n path: worktree.path,\n branch: worktree.branch,\n result: \"failed\",\n message: `salvaged to ${salvageDir}, but removal failed: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n\n return { path: worktree.path, branch: worktree.branch, result: \"salvaged\", salvageDir }\n}\n\nasync function applyOne(entry: GcPlanEntry, options: ApplyGcOptions): Promise<GcApplyOutcome> {\n if (entry.class === \"hold\") {\n return { path: entry.path, branch: entry.branch, result: \"held\" }\n }\n if (entry.class === \"salvage\" && !options.salvageDirty) {\n return { path: entry.path, branch: entry.branch, result: \"skipped-dirty\" }\n }\n\n // Layer 2 (PLAN.md §5.2): re-check immediately before touching anything.\n // Re-derive the worktree ref itself, not just its status — a branch can\n // flip between plan and apply (the rendezvous-deploy branch-flip mid-\n // session is the plan's own existence proof for this), so re-listing\n // `git worktree list` is required, not just recomputing against the\n // plan's stale (path, branch, head) tuple.\n const fresh = await findWorktree(options.repoRoot, entry.path)\n if (!fresh) {\n return { path: entry.path, branch: entry.branch, result: \"aborted-vanished\" }\n }\n const status = await computeWorktreeStatus({\n repoRoot: options.repoRoot,\n repoName: options.repoName,\n worktree: fresh,\n forge: options.forge,\n memo: options.memo,\n defaultBranchRef: options.defaultBranchRef,\n sessionsPath: options.sessionsPath,\n now: options.now,\n })\n const freshClass = classifyForGc(status.tree, status.integration, status.liveness, {\n includeDetached: Boolean(options.includeDetached),\n nowMs: options.nowMs,\n })\n if (freshClass !== entry.class) {\n return {\n path: entry.path,\n branch: fresh.branch,\n result: \"aborted-reclassified\",\n from: entry.class,\n to: freshClass,\n }\n }\n\n if (freshClass === \"reclaim\") return reclaimOne(options, fresh)\n // The only other class that reaches this point is \"salvage\" with\n // `options.salvageDirty` true (both earlier guards above already returned\n // for \"hold\" and for \"salvage\" without the flag).\n return salvageOne(options, fresh)\n}\n\n/**\n * Execute a plan (PLAN.md §5.2 layers 2–4). Every entry is re-classified\n * from scratch immediately before it's touched; a `hold` entry is never\n * touched, a `salvage` entry is only touched when `salvageDirty` is true,\n * and every removal goes through `worktree.cleanup` — never a hand-rolled\n * `git worktree remove`.\n */\nexport async function applyGc(plan: readonly GcPlanEntry[], options: ApplyGcOptions): Promise<GcApplyOutcome[]> {\n const outcomes: GcApplyOutcome[] = []\n for (const entry of plan) {\n outcomes.push(await applyOne(entry, options))\n }\n return outcomes\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/salvage.ts","../src/services/proxy-server.ts","../src/forge.ts","../src/gc.ts"],"names":["netConnect","resolve","fetch"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Salvage-before-discard (PLAN.md §5.2 layer 4). `worktree archive` re-earns\n * its name by snapshotting a worktree's uncommitted state before it removes\n * anything: `git diff HEAD` → `changes.patch`, plus a byte-copy of every\n * unignored untracked file, into\n * `~/.agentproto/worktree-salvage/<repoName>/<slug>-<tipSha7>-<date>/` with a\n * `MANIFEST.json`. Every file is fsynced before this returns — only once the\n * snapshot is durable does the caller proceed to force-remove.\n *\n * Deliberately forge-independent: no PR lookup here. This writer's only job\n * is \"don't lose bytes before deletion,\" not classification — `ls --status`\n * (status.ts) already owns the forge-derived `integration` axis, and gc\n * (PR-D) is where a salvage manifest and a status entry would be cross-\n * referenced, not here.\n */\n\nimport { copyFile, mkdir, open, writeFile } from \"node:fs/promises\"\nimport { homedir } from \"node:os\"\nimport { dirname, join, resolve } from \"node:path\"\nimport { execArgv } from \"./exec.js\"\nimport { computeProvenance, type ProvenanceInfo } from \"./provenance.js\"\n\nexport const SALVAGE_ROOT = (): string => resolve(homedir(), \".agentproto\", \"worktree-salvage\")\n\nexport interface SalvageManifest {\n repo: string\n /** `null` for a detached HEAD. */\n branch: string | null\n tipSha: string\n createdAt: string\n /** Relative paths of every unignored untracked file that was copied in. */\n untrackedFiles: string[]\n /** Whether `changes.patch` has any content (tracked-file changes existed). */\n hasPatch: boolean\n provenance: ProvenanceInfo\n}\n\nexport interface SalvageWorktreeInput {\n /** The main repo root — the stable spawn anchor for this worktree's git reads (see `listUntrackedFiles`'s doc). */\n repoRoot: string\n repoName: string\n worktreePath: string\n branch: string | null\n tipSha: string\n /** Identifies this worktree in the salvage directory name, e.g. its slug or branch. */\n slug: string\n sessionsPath?: string\n /** Injectable clock so tests can freeze `createdAt` / the directory name. */\n now?: () => string\n /** Override for `~/.agentproto/worktree-salvage` — tests use a temp dir. */\n salvageRoot?: string\n}\n\nexport interface SalvageResult {\n dir: string\n manifest: SalvageManifest\n}\n\n/**\n * Untracked, non-ignored files in the worktree — the same class `git\n * worktree remove` refuses without `--force`. Spawn `cwd` is `repoRoot`, not\n * `worktreePath` — a linked worktree can be removed by a concurrent `gc`\n * reap (or a racing status read) while this call is in flight, and a spawn\n * whose `cwd` no longer exists fails `ENOENT` on the COMMAND itself (a\n * Node/libuv quirk), not the directory — see `exec.ts`'s `execGit`, which\n * anchors the same way.\n */\nasync function listUntrackedFiles(repoRoot: string, worktreePath: string): Promise<string[]> {\n const res = await execArgv(\"git\", [\"-C\", worktreePath, \"ls-files\", \"--others\", \"--exclude-standard\"], repoRoot)\n if (res.exitCode !== 0) {\n throw new Error(`git ls-files --others failed in ${worktreePath} (exit ${res.exitCode}): ${res.stderr.trim()}`)\n }\n return res.stdout.split(\"\\n\").filter(Boolean)\n}\n\n/** `git diff HEAD` — staged + unstaged changes to tracked files, uniformly.\n * Empty string on a clean tree. Spawn `cwd` is `repoRoot`, not\n * `worktreePath` — see `listUntrackedFiles`'s doc. */\nasync function diffHead(repoRoot: string, worktreePath: string): Promise<string> {\n const res = await execArgv(\"git\", [\"-C\", worktreePath, \"diff\", \"HEAD\"], repoRoot)\n if (res.exitCode !== 0) {\n throw new Error(`git diff HEAD failed in ${worktreePath} (exit ${res.exitCode}): ${res.stderr.trim()}`)\n }\n return res.stdout\n}\n\n/** Sanitize a path segment for use in the salvage directory name (no slashes, no leading dot-dot). */\nfunction sanitizeSegment(value: string): string {\n return value.replace(/[^a-zA-Z0-9._-]+/g, \"-\").replace(/^-+/, \"\") || \"worktree\"\n}\n\n/** fsync one file by path — the durability guarantee: only after this resolves is the byte \"saved\". */\nasync function fsyncFile(path: string): Promise<void> {\n const handle = await open(path, \"r+\")\n try {\n await handle.sync()\n } finally {\n await handle.close()\n }\n}\n\nasync function writeFileSynced(path: string, content: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, content, \"utf8\")\n await fsyncFile(path)\n}\n\n/**\n * Snapshot `worktreePath`'s uncommitted state into a fresh salvage\n * directory. Safe to call on a clean tree (writes an empty patch, no\n * untracked files, still a manifest) — every path this function returns is\n * fsynced before it resolves.\n */\nexport async function salvageWorktree(input: SalvageWorktreeInput): Promise<SalvageResult> {\n const now = input.now ?? (() => new Date().toISOString())\n const createdAt = now()\n const tipShort = input.tipSha.slice(0, 7)\n const dateStamp = createdAt.slice(0, 10)\n const dirName = `${sanitizeSegment(input.slug)}-${tipShort}-${dateStamp}`\n const dir = resolve(input.salvageRoot ?? SALVAGE_ROOT(), sanitizeSegment(input.repoName), dirName)\n await mkdir(dir, { recursive: true })\n\n const [patch, untrackedFiles, provenance] = await Promise.all([\n diffHead(input.repoRoot, input.worktreePath),\n listUntrackedFiles(input.repoRoot, input.worktreePath),\n computeProvenance(input.repoRoot, input.worktreePath, { sessionsPath: input.sessionsPath }),\n ])\n\n await writeFileSynced(join(dir, \"changes.patch\"), patch)\n\n for (const relPath of untrackedFiles) {\n const dest = join(dir, \"untracked\", relPath)\n await mkdir(dirname(dest), { recursive: true })\n await copyFile(join(input.worktreePath, relPath), dest)\n await fsyncFile(dest)\n }\n\n const manifest: SalvageManifest = {\n repo: input.repoName,\n branch: input.branch,\n tipSha: input.tipSha,\n createdAt,\n untrackedFiles,\n hasPatch: patch.length > 0,\n provenance,\n }\n await writeFileSynced(join(dir, \"MANIFEST.json\"), JSON.stringify(manifest, null, 2) + \"\\n\")\n\n return { dir, manifest }\n}\n","import http from \"node:http\"\nimport { connect as netConnect, type Socket } from \"node:net\"\nimport type { ProxyTable } from \"./proxy-table.js\"\n\n/**\n * A small HTTP reverse proxy over a {@link ProxyTable}. Routes\n * `http://<script>--<branch>--<repo>.localhost:<proxy-port>` to the matched\n * service's local port. Supports WebSocket (and any) `Upgrade` passthrough by\n * splicing raw sockets. Targets are always `127.0.0.1` — services bind\n * locally, the proxy is the only public-ish surface.\n */\n\nconst TARGET_HOST = \"127.0.0.1\"\n\nfunction notFound(table: ProxyTable, host: string | undefined): string {\n const known = table.entries().map(([h]) => h)\n return (\n `worktree-proxy: no service for host \"${host ?? \"(none)\"}\"\\n` +\n (known.length ? `known hosts:\\n${known.map((h) => ` ${h}`).join(\"\\n\")}\\n` : \"no services registered\\n\")\n )\n}\n\n/** Build (but don't start) the proxy HTTP server backed by `table`. */\nexport function createProxyServer(table: ProxyTable): http.Server {\n const server = http.createServer((req, res) => {\n const targetPort = table.lookup(req.headers.host)\n if (targetPort === undefined) {\n res.writeHead(502, { \"content-type\": \"text/plain\" })\n res.end(notFound(table, req.headers.host))\n return\n }\n\n const proxyReq = http.request(\n {\n host: TARGET_HOST,\n port: targetPort,\n method: req.method,\n path: req.url,\n headers: req.headers,\n },\n (proxyRes) => {\n res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers)\n proxyRes.pipe(res)\n },\n )\n proxyReq.on(\"error\", (err) => {\n if (!res.headersSent) res.writeHead(502, { \"content-type\": \"text/plain\" })\n res.end(`worktree-proxy: upstream error: ${err.message}\\n`)\n })\n req.pipe(proxyReq)\n })\n\n // WebSocket / generic Upgrade passthrough: splice the client socket to a\n // fresh TCP connection to the target, replaying the original request line\n // and headers so the upstream completes its own handshake.\n server.on(\"upgrade\", (req, clientSocket: Socket, head: Buffer) => {\n const targetPort = table.lookup(req.headers.host)\n if (targetPort === undefined) {\n clientSocket.end(\"HTTP/1.1 502 Bad Gateway\\r\\n\\r\\n\")\n return\n }\n\n const upstream = netConnect(targetPort, TARGET_HOST, () => {\n const headerLines = [`${req.method} ${req.url} HTTP/1.1`]\n for (let i = 0; i < req.rawHeaders.length; i += 2) {\n headerLines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`)\n }\n upstream.write(headerLines.join(\"\\r\\n\") + \"\\r\\n\\r\\n\")\n if (head && head.length) upstream.write(head)\n upstream.pipe(clientSocket)\n clientSocket.pipe(upstream)\n })\n\n const teardown = (): void => {\n clientSocket.destroy()\n upstream.destroy()\n }\n upstream.on(\"error\", teardown)\n clientSocket.on(\"error\", teardown)\n upstream.on(\"close\", () => clientSocket.destroy())\n clientSocket.on(\"close\", () => upstream.destroy())\n })\n\n return server\n}\n\nexport interface RunningProxy {\n /** The port the proxy is listening on. */\n port: number\n /** The underlying server. */\n server: http.Server\n /** Stop the proxy. */\n close(): Promise<void>\n}\n\n/** Start the proxy server on `port` (0 → OS-assigned). Resolves once listening. */\nexport function startProxy(table: ProxyTable, port = 0): Promise<RunningProxy> {\n const server = createProxyServer(table)\n // Track every accepted socket so shutdown can force-drop them. An upgraded\n // (WebSocket) connection is detached from the server's own tracking, so\n // `server.close()` alone would hang on it — we destroy them explicitly.\n const sockets = new Set<Socket>()\n server.on(\"connection\", (socket: Socket) => {\n sockets.add(socket)\n socket.once(\"close\", () => sockets.delete(socket))\n })\n return new Promise((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(port, () => {\n const address = server.address()\n const boundPort = address && typeof address === \"object\" ? address.port : port\n resolve({\n port: boundPort,\n server,\n close: () =>\n new Promise<void>((res) => {\n for (const socket of sockets) socket.destroy()\n sockets.clear()\n server.close(() => res())\n }),\n })\n })\n })\n}\n","/**\n * `ForgeClient` — the only network-facing surface the reconciliation rule\n * (`status.ts`) depends on. Kept as an interface (not a concrete `gh` call)\n * so:\n * 1. `status.ts` stays testable with a fake — the fixture-repo tests never\n * shell out to a real forge or touch the network.\n * 2. The shape is forge-portable by construction (PLAN.md §7.1): GitLab has\n * the same two facts — \"PRs/MRs whose head is this branch\" and \"PRs/MRs\n * that contain this commit\" — under different verbs\n * (`refs/merge-requests/<n>/head`, `GET /merge_requests?…`). Only\n * GitHub ships today; a `GitlabForgeClient` is a second implementation\n * of this same interface, not a redesign.\n *\n * Two implementations ship: `GhCliForgeClient` (shells out to the `gh` CLI,\n * inheriting the caller's own `gh auth` session — zero config) and\n * `RestForgeClient` (plain `fetch` against the GitHub REST API using\n * `GITHUB_TOKEN` — no new npm dependency). `createForgeClient` picks\n * whichever is usable; when neither is, callers get a client that always\n * reports itself unreachable, which the reconciliation rule already knows\n * how to fall back from (PLAN.md §1.3 step 5: memo, else `unknown(offline)`,\n * never a guess).\n */\n\nimport { z } from \"zod\"\nimport { execArgv } from \"./exec.js\"\n\n/** A pull/merge request as the reconciliation rule needs to see it. */\nexport interface ForgePullRequestRef {\n number: number\n state: \"open\" | \"closed\"\n merged: boolean\n mergedAt: string | null\n headRefName: string\n headRefOid: string\n}\n\n/**\n * Thrown by a `ForgeClient` method when the forge could not be reached or\n * queried at all (network failure, missing/unauthenticated CLI, non-2xx HTTP\n * response). Never thrown for a legitimate empty result (a branch/commit\n * with no PRs is a valid, resolvable answer — `[]`, not an error). Callers\n * treat this as PLAN.md §1.3 step 5: \"never guess.\"\n */\nexport class ForgeUnavailableError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = \"ForgeUnavailableError\"\n }\n}\n\nexport interface ForgeClient {\n /** PRs/MRs (any state) whose head branch is exactly `branch`. */\n pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]>\n /**\n * PRs/MRs associated with a specific commit SHA — the rename/retarget-proof\n * signal (PLAN.md §1.3 step 2b): finds the PR even if the branch was\n * renamed or deleted before merge.\n */\n pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]>\n /**\n * Ensure `oid` (a PR's `headRefOid`) is present in the local object\n * database, fetching `refs/pull/<number>/head` if it isn't. Always\n * fetchable even after the head branch was deleted on the remote\n * (PLAN.md §1.3 step 2, verified for #273/#312/#325/#271).\n */\n ensurePullHeadFetched(prNumber: number, oid: string): Promise<void>\n}\n\n/** A client that always reports itself unreachable — the \"no gh, no token\" case. */\nexport class UnreachableForgeClient implements ForgeClient {\n constructor(private readonly reason: string) {}\n async pullRequestsForBranch(): Promise<ForgePullRequestRef[]> {\n throw new ForgeUnavailableError(this.reason)\n }\n async pullRequestsForCommit(): Promise<ForgePullRequestRef[]> {\n throw new ForgeUnavailableError(this.reason)\n }\n async ensurePullHeadFetched(): Promise<void> {\n throw new ForgeUnavailableError(this.reason)\n }\n}\n\n// ── gh CLI implementation ───────────────────────────────────────────────\n\nconst ghPrListItemSchema = z.object({\n number: z.number(),\n state: z.string(),\n headRefName: z.string(),\n headRefOid: z.string(),\n mergedAt: z.string().nullable(),\n})\ntype GhPrListItem = z.infer<typeof ghPrListItemSchema>\nconst ghPrListSchema = z.array(ghPrListItemSchema)\n\nfunction normalizeGhPrListItem(item: GhPrListItem): ForgePullRequestRef {\n const state = item.state.toUpperCase()\n return {\n number: item.number,\n state: state === \"OPEN\" ? \"open\" : \"closed\",\n merged: state === \"MERGED\" || item.mergedAt !== null,\n mergedAt: item.mergedAt,\n headRefName: item.headRefName,\n headRefOid: item.headRefOid,\n }\n}\n\nconst ghApiCommitPullSchema = z.object({\n number: z.number(),\n state: z.string(),\n merged_at: z.string().nullable(),\n head: z.object({ ref: z.string(), sha: z.string() }),\n})\ntype GhApiCommitPull = z.infer<typeof ghApiCommitPullSchema>\nconst ghApiCommitPullListSchema = z.array(ghApiCommitPullSchema)\n\nfunction normalizeGhApiCommitPull(item: GhApiCommitPull): ForgePullRequestRef {\n return {\n number: item.number,\n state: item.state === \"open\" ? \"open\" : \"closed\",\n merged: item.merged_at !== null,\n mergedAt: item.merged_at,\n headRefName: item.head.ref,\n headRefOid: item.head.sha,\n }\n}\n\n/**\n * GitHub's REST API answers \"commit unknown to this repo\" (e.g. a local\n * commit that was never pushed) with HTTP 422 on `commits/:sha/pulls` —\n * empirically verified against a real unpushed worktree commit, not the 404\n * the endpoint's own docs imply. `gh api` surfaces the status in its stderr\n * as `(HTTP nnn)`. Both 404 and 422 here mean the same legitimate thing:\n * zero associated PRs, not \"the forge is unreachable\" — never guess step 5\n * on a genuinely empty, well-formed answer.\n */\nfunction isCommitNotFoundError(output: string): boolean {\n return /\\(HTTP (404|422)\\)/.test(output)\n}\n\n/** Runs `gh` in `repoRoot` so it auto-detects owner/repo from the `origin` remote there. */\nexport class GhCliForgeClient implements ForgeClient {\n constructor(private readonly repoRoot: string) {}\n\n private async runRaw(args: readonly string[]): Promise<{ exitCode: number; stdout: string; stderr: string }> {\n try {\n return await execArgv(\"gh\", args, this.repoRoot)\n } catch (err) {\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} could not be run: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n )\n }\n }\n\n private async run(args: readonly string[]): Promise<string> {\n const result = await this.runRaw(args)\n if (result.exitCode !== 0) {\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`,\n )\n }\n return result.stdout\n }\n\n private parseOutput<T>(stdout: string, schema: z.ZodType<T[]>, args: readonly string[]): T[] {\n let parsed: unknown\n try {\n parsed = JSON.parse(stdout)\n } catch (err) {\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} produced non-JSON output: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n const result = schema.safeParse(parsed)\n if (!result.success) {\n throw new ForgeUnavailableError(`gh ${args.join(\" \")} output did not match the expected shape`)\n }\n return result.data\n }\n\n async pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]> {\n const args = [\n \"pr\",\n \"list\",\n \"--head\",\n branch,\n \"--state\",\n \"all\",\n \"--json\",\n \"number,state,headRefName,headRefOid,mergedAt\",\n ]\n const stdout = await this.run(args)\n return this.parseOutput(stdout, ghPrListSchema, args).map(normalizeGhPrListItem)\n }\n\n async pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]> {\n const args = [\"api\", `repos/{owner}/{repo}/commits/${sha}/pulls`]\n const result = await this.runRaw(args)\n if (result.exitCode !== 0) {\n if (isCommitNotFoundError(result.stderr) || isCommitNotFoundError(result.stdout)) return []\n throw new ForgeUnavailableError(\n `gh ${args.join(\" \")} failed (exit ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`,\n )\n }\n return this.parseOutput(result.stdout, ghApiCommitPullListSchema, args).map(normalizeGhApiCommitPull)\n }\n\n async ensurePullHeadFetched(prNumber: number, oid: string): Promise<void> {\n const check = await execArgv(\"git\", [\"-C\", this.repoRoot, \"cat-file\", \"-e\", `${oid}^{commit}`], this.repoRoot)\n if (check.exitCode === 0) return\n const fetch = await execArgv(\n \"git\",\n [\"-C\", this.repoRoot, \"fetch\", \"origin\", `refs/pull/${prNumber}/head`],\n this.repoRoot,\n )\n if (fetch.exitCode !== 0) {\n throw new ForgeUnavailableError(\n `git fetch origin refs/pull/${prNumber}/head failed: ${fetch.stderr.trim() || fetch.stdout.trim()}`,\n )\n }\n }\n}\n\n// ── GITHUB_TOKEN REST fallback (no new npm dependency — global fetch) ───\n\nconst restPullRequestSchema = z.object({\n number: z.number(),\n state: z.string(),\n merged_at: z.string().nullable(),\n head: z.object({ ref: z.string(), sha: z.string() }),\n})\ntype RestPullRequest = z.infer<typeof restPullRequestSchema>\nconst restPullRequestListSchema = z.array(restPullRequestSchema)\n\nfunction normalizeRestPr(item: RestPullRequest): ForgePullRequestRef {\n return {\n number: item.number,\n state: item.state === \"open\" ? \"open\" : \"closed\",\n merged: item.merged_at !== null,\n mergedAt: item.merged_at,\n headRefName: item.head.ref,\n headRefOid: item.head.sha,\n }\n}\n\n/** Parse `owner/repo` out of a `git remote get-url origin` value (ssh or https form). */\nexport function parseGithubOwnerRepo(remoteUrl: string): { owner: string; repo: string } | null {\n const ssh = remoteUrl.match(/^git@github\\.com:([^/]+)\\/(.+?)(\\.git)?$/)\n if (ssh?.[1] && ssh[2]) return { owner: ssh[1], repo: ssh[2] }\n const https = remoteUrl.match(/^https:\\/\\/github\\.com\\/([^/]+)\\/(.+?)(\\.git)?\\/?$/)\n if (https?.[1] && https[2]) return { owner: https[1], repo: https[2] }\n return null\n}\n\nexport class RestForgeClient implements ForgeClient {\n constructor(\n private readonly owner: string,\n private readonly repo: string,\n private readonly repoRoot: string,\n private readonly token: string,\n private readonly fetchFn: typeof fetch = fetch,\n ) {}\n\n private headers(): Record<string, string> {\n return {\n Authorization: `Bearer ${this.token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n \"User-Agent\": \"agentproto-worktree-status\",\n }\n }\n\n private async get(path: string): Promise<Response> {\n try {\n return await this.fetchFn(`https://api.github.com${path}`, { headers: this.headers() })\n } catch (err) {\n throw new ForgeUnavailableError(\n `GitHub REST request to ${path} failed: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n )\n }\n }\n\n private async pullRequestList(res: Response): Promise<ForgePullRequestRef[]> {\n const body: unknown = await res.json()\n const result = restPullRequestListSchema.safeParse(body)\n if (!result.success) {\n throw new ForgeUnavailableError(`GitHub REST response did not match the expected PR list shape`)\n }\n return result.data.map(normalizeRestPr)\n }\n\n async pullRequestsForBranch(branch: string): Promise<ForgePullRequestRef[]> {\n const res = await this.get(\n `/repos/${this.owner}/${this.repo}/pulls?head=${this.owner}:${encodeURIComponent(branch)}&state=all&per_page=100`,\n )\n if (!res.ok) {\n throw new ForgeUnavailableError(`GitHub REST pulls?head= failed: ${res.status} ${res.statusText}`)\n }\n return this.pullRequestList(res)\n }\n\n async pullRequestsForCommit(sha: string): Promise<ForgePullRequestRef[]> {\n const res = await this.get(`/repos/${this.owner}/${this.repo}/commits/${sha}/pulls?per_page=100`)\n // 404 is what the endpoint's docs imply for an unknown commit; 422 is what\n // it empirically returns for one that was never pushed (verified live).\n // Both mean the same legitimate thing: zero associated PRs.\n if (res.status === 404 || res.status === 422) return []\n if (!res.ok) {\n throw new ForgeUnavailableError(`GitHub REST commits/:sha/pulls failed: ${res.status} ${res.statusText}`)\n }\n return this.pullRequestList(res)\n }\n\n async ensurePullHeadFetched(prNumber: number, oid: string): Promise<void> {\n const check = await execArgv(\"git\", [\"-C\", this.repoRoot, \"cat-file\", \"-e\", `${oid}^{commit}`], this.repoRoot)\n if (check.exitCode === 0) return\n const fetch2 = await execArgv(\n \"git\",\n [\"-C\", this.repoRoot, \"fetch\", \"origin\", `refs/pull/${prNumber}/head`],\n this.repoRoot,\n )\n if (fetch2.exitCode !== 0) {\n throw new ForgeUnavailableError(\n `git fetch origin refs/pull/${prNumber}/head failed: ${fetch2.stderr.trim() || fetch2.stdout.trim()}`,\n )\n }\n }\n}\n\n/** Cheap \"is `gh` on PATH and authenticated\" probe — avoids a slow failure per branch. */\nasync function ghIsUsable(repoRoot: string): Promise<boolean> {\n try {\n const res = await execArgv(\"gh\", [\"auth\", \"status\"], repoRoot)\n return res.exitCode === 0\n } catch {\n return false\n }\n}\n\n/**\n * Pick the best available `ForgeClient` for `repoRoot`: `gh` CLI first (zero\n * config, inherits the caller's own auth), else `GITHUB_TOKEN` REST, else a\n * client that always reports unreachable — the reconciliation rule already\n * knows how to fall back from that (memo, else `unknown(offline)`).\n */\nexport async function createForgeClient(repoRoot: string): Promise<ForgeClient> {\n if (await ghIsUsable(repoRoot)) return new GhCliForgeClient(repoRoot)\n\n const token = process.env.GITHUB_TOKEN\n if (token) {\n const remote = await execArgv(\"git\", [\"-C\", repoRoot, \"remote\", \"get-url\", \"origin\"], repoRoot)\n const parsed = remote.exitCode === 0 ? parseGithubOwnerRepo(remote.stdout.trim()) : null\n if (parsed) return new RestForgeClient(parsed.owner, parsed.repo, repoRoot, token)\n }\n\n return new UnreachableForgeClient(\n \"no usable forge client: `gh` is not installed/authenticated and GITHUB_TOKEN is not set (or origin isn't a GitHub remote)\",\n )\n}\n","/**\n * `gc` (PLAN.md §5, PR-D): plan → apply → salvage over the status engine's\n * classification (`status.ts`, PR-A). This module owns no new git knowledge\n * — it reuses `listGitWorktrees` / `computeWorktreeStatus` / `classify` for\n * every fact and `salvageWorktree` / `worktree.cleanup` (PR-C) for every\n * mutation. Its only original logic is sequencing the four safety layers\n * (PLAN.md §5.2):\n *\n * 1. `planGc` is pure read: it classifies every worktree and returns a\n * plan. Nothing is mutated by calling it — the CLI's dry-run default\n * *is* just \"call planGc, print it, stop.\"\n * 2. `applyGc` re-derives each worktree's class from scratch immediately\n * before touching it (a fresh `listGitWorktrees` + `computeWorktreeStatus`,\n * not a reuse of the plan's stale snapshot) and refuses to act if the\n * class changed since the plan was made.\n * 3. The actual removal is `worktree.cleanup` with NO discard flags for a\n * reclaim-class entry — git's own non-`--force` refusal is the backstop\n * this module leans on, never a force flag \"just in case.\"\n * 4. A salvage-class entry is only ever touched via `salvageWorktree`\n * followed by `worktree.cleanup` with both discard flags — snapshot\n * first, removal only after the snapshot is durable (mirrors `worktree\n * archive`'s CLI verb, PR-C).\n *\n * The main worktree (`repoRoot` itself) is never part of the plan: `git\n * worktree list`'s first entry is always the main checkout, and a repo\n * sitting on an up-to-date default branch is trivially `fresh ∧ clean` —\n * exactly what `reclaim` looks for. Git itself refuses to remove\n * the main working tree (\"is a main working tree\", verified empirically),\n * but this module doesn't lean on that as the only guard: the main worktree\n * is filtered out before classification even runs, so it can never appear\n * in a plan, let alone be attempted.\n *\n * One reclassification on top of `classify`'s three classes:\n * `resolveGcClass` promotes a clean, `unpushed` worktree from `hold` to\n * `reclaim` when every commit ahead of the default branch is a mechanical\n * dependency bump (subject AND cumulative diff both checked — see that\n * function's doc). It's applied identically at plan time and re-verified at\n * apply time (layer 2), so a worktree that grew a real commit in between is\n * still caught.\n */\n\nimport { basename } from \"node:path\"\nimport { runTool } from \"@agentproto/driver\"\nimport { execArgv } from \"./exec.js\"\nimport { cleanupWorktreeTool } from \"./tools/index.js\"\nimport { worktreeProvider } from \"./provider/index.js\"\nimport { salvageWorktree } from \"./salvage.js\"\nimport type { ForgeClient } from \"./forge.js\"\nimport {\n classify,\n listGitWorktrees,\n computeWorktreeStatus,\n type GitWorktreeRef,\n type IntegrationState,\n type LivenessState,\n type TreeState,\n type VerdictMemoStore,\n} from \"./status.js\"\n\nconst candidates = [worktreeProvider]\n\n// ── classification (PLAN.md §5.1) ───────────────────────────────────────\n\nexport type GcClass = \"reclaim\" | \"salvage\" | \"hold\"\n\nexport interface ClassifyForGcOptions {\n /**\n * A clean, idle/daemon-unreachable DETACHED worktree moves from `hold` to\n * `reclaim` (PLAN.md §5.1). This is the only reclassification power any\n * flag has: every other hold reason — partial, open, unknown(offline),\n * gone-unexplained, diverged — is untouched by any flag, ever. Default\n * false.\n */\n includeDetached?: boolean\n /** Threaded straight through to `classify`'s `RECENT_WRITE_HOLD_WINDOW_MS` guard. Defaults to `Date.now()`. */\n nowMs?: number\n}\n\n/**\n * gc's own classifier, layered on top of `classify` (status.ts) rather than\n * reimplementing it — reuse first (AGENTS.md, PLAN.md §0.6). The one thing\n * `classify` cannot know is `--include-detached`, a gc-specific flag; that\n * override lives here, not in the read-only status engine `ls --status`\n * also depends on.\n */\nexport function classifyForGc(\n tree: TreeState,\n integration: IntegrationState,\n liveness: LivenessState,\n options: ClassifyForGcOptions = {},\n): GcClass {\n if (options.includeDetached && integration.state === \"detached\") {\n const idleOrUnreachable = liveness.state === \"idle\" || liveness.state === \"daemon-unreachable\"\n if (tree.state === \"clean\" && idleOrUnreachable) return \"reclaim\"\n }\n return classify(tree, integration, liveness, options.nowMs).class\n}\n\n// ── dep-bump reclaim exemption ──────────────────────────────────────────\n//\n// A worktree whose only unpushed commits are a mechanical dependency bump\n// (`chore(deps): weekly minor/patch bump`, re-run every week by every\n// session that happens to pick it up) is not \"unpushed work to protect\" —\n// it reproduces by re-running the routine, and 25 of these piling up as\n// permanent `hold`s is exactly what emptied a 102GB external SSD of gc\n// coverage. This is deliberately narrow and additive: it only ever promotes\n// a worktree that `classifyForGc` already put in `hold` for the single\n// reason `integration.state === \"unpushed\"` with a clean tree — every other\n// hold reason (partial, open, diverged, gone-unexplained, unknown(offline),\n// a dirty tree, `unpushed` while forge-unreachable — which can't happen, see\n// `reconcileIntegration`) is completely untouched by this and still holds.\n\n/** The only reclaim reason this module can attach today. */\nexport type GcReclaimReason = \"dep-bump\"\n\n/**\n * Mechanical dep-bump commit subjects: `chore(deps)` / `fix(deps)`, with or\n * without a scope (`chore(deps-dev)`, `fix(deps-optional)`, …). A commit\n * message is cheap to type and easy to lie in — this regex alone NEVER\n * licenses anything; `isMechanicalDepBumpRange` below only trusts it in\n * conjunction with the actual cumulative diff.\n */\nconst DEP_BUMP_SUBJECT_RE = /^(?:chore|fix)\\(deps[\\w-]*\\):\\s/\n\nfunction isDepBumpSubject(subject: string): boolean {\n return DEP_BUMP_SUBJECT_RE.test(subject)\n}\n\n/** The only paths a mechanical dep bump is allowed to touch, matched by basename so a nested package's `package.json` counts too. */\nconst DEP_BUMP_ALLOWED_BASENAMES = new Set([\"pnpm-lock.yaml\", \"package-lock.json\", \"yarn.lock\", \"package.json\"])\n\nfunction isDepBumpAllowedPath(path: string): boolean {\n return DEP_BUMP_ALLOWED_BASENAMES.has(basename(path))\n}\n\n/**\n * Layer 3+4 of the exemption: EVERY commit ahead of `baseRef` must have a\n * dep-bump subject (`git log --format=%s`, two-dot range — exactly the\n * commits `aheadBy` counts, PLAN-comment on `readUpstreamTrack`), AND the\n * cumulative diff of that whole range (`git diff`, three-dot/merge-base\n * range, so it isolates the branch's own changes from anything `baseRef`\n * did independently in the meantime) must touch nothing but lockfiles and\n * `package.json`. Both checks run unconditionally together — a subject that\n * lies is cheap, a diff cannot lie, so the diff is the one that actually\n * gates. Two extra git spawns, only ever paid for a worktree that would\n * otherwise be `hold` for exactly `clean ∧ unpushed` — every other class\n * pays nothing.\n */\nexport async function isMechanicalDepBumpRange(repoRoot: string, baseRef: string, tipSha: string): Promise<boolean> {\n const [subjectsRes, diffRes] = await Promise.all([\n execArgv(\"git\", [\"-C\", repoRoot, \"log\", \"--format=%s\", `${baseRef}..${tipSha}`], repoRoot),\n execArgv(\"git\", [\"-C\", repoRoot, \"diff\", \"--name-only\", `${baseRef}...${tipSha}`], repoRoot),\n ])\n if (subjectsRes.exitCode !== 0 || diffRes.exitCode !== 0) return false\n\n const subjects = subjectsRes.stdout.split(\"\\n\").filter((line) => line.length > 0)\n if (subjects.length === 0) return false\n if (!subjects.every(isDepBumpSubject)) return false\n\n const files = diffRes.stdout.split(\"\\n\").filter((line) => line.length > 0)\n if (files.length === 0) return false\n return files.every(isDepBumpAllowedPath)\n}\n\nexport interface ResolveGcClassOptions extends ClassifyForGcOptions {\n repoRoot: string\n /** The tip commit of the worktree being classified — `worktree.head`. */\n tipSha: string\n /** Default `\"origin/main\"` — matches `reconcileIntegration`'s own default. */\n defaultBranchRef?: string\n}\n\nexport interface ResolvedGcClass {\n class: GcClass\n /** Set only when `class === \"reclaim\"` via the dep-bump exemption rather than the ordinary merged/fresh path. */\n reclaimReason?: GcReclaimReason\n}\n\n/**\n * `classifyForGc` plus the one async, git-touching layer on top: a clean,\n * `unpushed` worktree whose entire ahead range is a mechanical dep bump is\n * promoted from `hold` to `reclaim`. Every other class classifyForGc\n * returns is passed through untouched — this never widens any other hold\n * reason, and never touches git for a worktree it wouldn't otherwise hold\n * on `unpushed` alone.\n */\nexport async function resolveGcClass(\n tree: TreeState,\n integration: IntegrationState,\n liveness: LivenessState,\n options: ResolveGcClassOptions,\n): Promise<ResolvedGcClass> {\n const baseClass = classifyForGc(tree, integration, liveness, options)\n if (baseClass !== \"hold\") return { class: baseClass }\n if (tree.state !== \"clean\" || integration.state !== \"unpushed\") return { class: \"hold\" }\n\n const baseRef = options.defaultBranchRef ?? \"origin/main\"\n const isDepBump = await isMechanicalDepBumpRange(options.repoRoot, baseRef, options.tipSha)\n if (!isDepBump) return { class: \"hold\" }\n return { class: \"reclaim\", reclaimReason: \"dep-bump\" }\n}\n\n// ── plan ─────────────────────────────────────────────────────────────\n\nexport interface GcPlanEntry {\n path: string\n branch: string | null\n head: string\n tree: TreeState\n integration: IntegrationState\n liveness: LivenessState\n /** Classification per PLAN.md §5.1, after `--include-detached` (if set). */\n class: GcClass\n /** Set only when `class === \"reclaim\"` via the dep-bump exemption — see `resolveGcClass`. */\n reclaimReason?: GcReclaimReason\n}\n\nexport interface PlanGcInput {\n repoRoot: string\n repoName: string\n forge: ForgeClient\n memo: VerdictMemoStore\n defaultBranchRef?: string\n sessionsPath?: string\n includeDetached?: boolean\n now?: () => string\n /** See `ComputeWorktreeStatusInput.nowMs` (status.ts) — kept separate from `now`. Defaults to `Date.now()`. */\n nowMs?: number\n}\n\n/** Every linked worktree of `repoRoot` except the main checkout itself — see the module docblock. */\nasync function linkedWorktreesOf(repoRoot: string): Promise<GitWorktreeRef[]> {\n const worktrees = await listGitWorktrees(repoRoot)\n return worktrees.filter((w) => w.path !== repoRoot)\n}\n\nasync function toPlanEntry(\n repoRoot: string,\n defaultBranchRef: string | undefined,\n worktree: GitWorktreeRef,\n status: { tree: TreeState; integration: IntegrationState; liveness: LivenessState },\n includeDetached: boolean,\n nowMs: number,\n): Promise<GcPlanEntry> {\n const resolved = await resolveGcClass(status.tree, status.integration, status.liveness, {\n repoRoot,\n tipSha: worktree.head,\n defaultBranchRef,\n includeDetached,\n nowMs,\n })\n return {\n path: worktree.path,\n branch: worktree.branch,\n head: worktree.head,\n tree: status.tree,\n integration: status.integration,\n liveness: status.liveness,\n class: resolved.class,\n ...(resolved.reclaimReason ? { reclaimReason: resolved.reclaimReason } : {}),\n }\n}\n\n/**\n * The dry-run plan (PLAN.md §5.2 layer 1): classify every linked worktree,\n * mutate nothing. This is the human's decision surface — `gc` with no flags\n * is exactly \"call this, print it, stop.\"\n */\nexport async function planGc(input: PlanGcInput): Promise<GcPlanEntry[]> {\n const includeDetached = Boolean(input.includeDetached)\n // One frozen instant for the whole plan's recent-write checks.\n const nowMs = input.nowMs ?? Date.now()\n const worktrees = await linkedWorktreesOf(input.repoRoot)\n const entries: GcPlanEntry[] = []\n for (const worktree of worktrees) {\n const status = await computeWorktreeStatus({\n repoRoot: input.repoRoot,\n repoName: input.repoName,\n worktree,\n forge: input.forge,\n memo: input.memo,\n defaultBranchRef: input.defaultBranchRef,\n sessionsPath: input.sessionsPath,\n now: input.now,\n })\n entries.push(await toPlanEntry(input.repoRoot, input.defaultBranchRef, worktree, status, includeDetached, nowMs))\n }\n return entries\n}\n\n// ── apply ────────────────────────────────────────────────────────────\n\nexport interface ApplyGcOptions {\n repoRoot: string\n repoName: string\n forge: ForgeClient\n memo: VerdictMemoStore\n defaultBranchRef?: string\n sessionsPath?: string\n includeDetached?: boolean\n /** Archive (salvage-then-remove) every salvage-class entry. Default false — salvage entries are left untouched. */\n salvageDirty?: boolean\n now?: () => string\n /** See `ComputeWorktreeStatusInput.nowMs` (status.ts) — kept separate from `now`. Defaults to `Date.now()`. */\n nowMs?: number\n /** Override for `~/.agentproto/worktree-salvage` — tests use a temp dir. */\n salvageRoot?: string\n}\n\nexport type GcApplyOutcome =\n | { path: string; branch: string | null; result: \"reclaimed\"; reclaimReason?: GcReclaimReason }\n | { path: string; branch: string | null; result: \"salvaged\"; salvageDir: string }\n | { path: string; branch: string | null; result: \"held\" }\n /** Salvage-class, but `--salvage-dirty` was not passed: left untouched by design. */\n | { path: string; branch: string | null; result: \"skipped-dirty\" }\n /** Layer 2: re-classified at apply time to something other than the plan said — refuses rather than acting on a stale plan. */\n | { path: string; branch: string | null; result: \"aborted-reclassified\"; from: GcClass; to: GcClass }\n /** The worktree named in the plan no longer exists (already removed by something else since the plan was made). */\n | { path: string; branch: string | null; result: \"aborted-vanished\" }\n /** git itself (or the salvage snapshot) refused — the TOCTOU backstop actually firing, or a real I/O failure. */\n | { path: string; branch: string | null; result: \"failed\"; message: string }\n\nasync function findWorktree(repoRoot: string, path: string): Promise<GitWorktreeRef | null> {\n const worktrees = await linkedWorktreesOf(repoRoot)\n return worktrees.find((w) => w.path === path) ?? null\n}\n\nasync function reclaimOne(\n options: ApplyGcOptions,\n worktree: GitWorktreeRef,\n reclaimReason?: GcReclaimReason,\n): Promise<GcApplyOutcome> {\n try {\n await runTool({\n tool: cleanupWorktreeTool,\n candidates,\n input: {\n repoRoot: options.repoRoot,\n cwd: worktree.path,\n ...(worktree.branch ? { branch: worktree.branch } : {}),\n // Branch deletion only ever runs for a `reclaim`-class entry, which by\n // construction requires `integration ∈ {merged(*), fresh}` and\n // `tree = clean` (PLAN.md's invariant: branch -D only when there's\n // nothing uncommitted to lose, never a hold class).\n deleteBranch: true,\n // No discardUntracked/discardModified, ever, on this path (PLAN.md\n // §5.2 layer 3): `reclaim` means `tree = clean`, so plain `git\n // worktree remove` should succeed on its own; if the tree turned\n // dirty in the instant between the re-check above and this call, git\n // itself refuses and that refusal surfaces below as `failed` — never\n // a force flag \"just in case.\"\n },\n })\n } catch (err) {\n return {\n path: worktree.path,\n branch: worktree.branch,\n result: \"failed\",\n message: err instanceof Error ? err.message : String(err),\n }\n }\n return {\n path: worktree.path,\n branch: worktree.branch,\n result: \"reclaimed\",\n ...(reclaimReason ? { reclaimReason } : {}),\n }\n}\n\nasync function salvageOne(options: ApplyGcOptions, worktree: GitWorktreeRef): Promise<GcApplyOutcome> {\n let salvageDir: string\n try {\n const result = await salvageWorktree({\n repoRoot: options.repoRoot,\n repoName: options.repoName,\n worktreePath: worktree.path,\n branch: worktree.branch,\n tipSha: worktree.head,\n slug: worktree.branch ?? basename(worktree.path),\n sessionsPath: options.sessionsPath,\n now: options.now,\n salvageRoot: options.salvageRoot,\n })\n salvageDir = result.dir\n } catch (err) {\n return {\n path: worktree.path,\n branch: worktree.branch,\n result: \"failed\",\n message: `salvage failed, nothing removed: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n\n try {\n await runTool({\n tool: cleanupWorktreeTool,\n candidates,\n input: {\n repoRoot: options.repoRoot,\n cwd: worktree.path,\n ...(worktree.branch ? { branch: worktree.branch } : {}),\n deleteBranch: true,\n // Both discard flags: the snapshot above is already durable (fsynced)\n // before this call, so nothing on disk is lost by discarding it here\n // (PLAN.md §5.2 layer 4 — salvage before discard).\n discardUntracked: true,\n discardModified: true,\n },\n })\n } catch (err) {\n return {\n path: worktree.path,\n branch: worktree.branch,\n result: \"failed\",\n message: `salvaged to ${salvageDir}, but removal failed: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\n\n return { path: worktree.path, branch: worktree.branch, result: \"salvaged\", salvageDir }\n}\n\nasync function applyOne(entry: GcPlanEntry, options: ApplyGcOptions): Promise<GcApplyOutcome> {\n if (entry.class === \"hold\") {\n return { path: entry.path, branch: entry.branch, result: \"held\" }\n }\n if (entry.class === \"salvage\" && !options.salvageDirty) {\n return { path: entry.path, branch: entry.branch, result: \"skipped-dirty\" }\n }\n\n // Layer 2 (PLAN.md §5.2): re-check immediately before touching anything.\n // Re-derive the worktree ref itself, not just its status — a branch can\n // flip between plan and apply (the rendezvous-deploy branch-flip mid-\n // session is the plan's own existence proof for this), so re-listing\n // `git worktree list` is required, not just recomputing against the\n // plan's stale (path, branch, head) tuple.\n const fresh = await findWorktree(options.repoRoot, entry.path)\n if (!fresh) {\n return { path: entry.path, branch: entry.branch, result: \"aborted-vanished\" }\n }\n const status = await computeWorktreeStatus({\n repoRoot: options.repoRoot,\n repoName: options.repoName,\n worktree: fresh,\n forge: options.forge,\n memo: options.memo,\n defaultBranchRef: options.defaultBranchRef,\n sessionsPath: options.sessionsPath,\n now: options.now,\n })\n // Re-resolved from scratch — including the dep-bump exemption, not just\n // `entry`'s stale plan-time verdict, so a worktree that picked up a real\n // (non-bump) commit between plan and apply is re-caught here, not just at\n // plan time.\n const resolved = await resolveGcClass(status.tree, status.integration, status.liveness, {\n repoRoot: options.repoRoot,\n tipSha: fresh.head,\n defaultBranchRef: options.defaultBranchRef,\n includeDetached: Boolean(options.includeDetached),\n nowMs: options.nowMs,\n })\n if (resolved.class !== entry.class) {\n return {\n path: entry.path,\n branch: fresh.branch,\n result: \"aborted-reclassified\",\n from: entry.class,\n to: resolved.class,\n }\n }\n\n if (resolved.class === \"reclaim\") return reclaimOne(options, fresh, resolved.reclaimReason)\n // The only other class that reaches this point is \"salvage\" with\n // `options.salvageDirty` true (both earlier guards above already returned\n // for \"hold\" and for \"salvage\" without the flag).\n return salvageOne(options, fresh)\n}\n\n/**\n * Execute a plan (PLAN.md §5.2 layers 2–4). Every entry is re-classified\n * from scratch immediately before it's touched; a `hold` entry is never\n * touched, a `salvage` entry is only touched when `salvageDirty` is true,\n * and every removal goes through `worktree.cleanup` — never a hand-rolled\n * `git worktree remove`.\n */\nexport async function applyGc(plan: readonly GcPlanEntry[], options: ApplyGcOptions): Promise<GcApplyOutcome[]> {\n const outcomes: GcApplyOutcome[] = []\n for (const entry of plan) {\n outcomes.push(await applyOne(entry, options))\n }\n return outcomes\n}\n"]}
|
package/dist/provider/index.mjs
CHANGED