@kynver-app/runtime 0.1.108 → 0.1.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cleanup-git-rev-cache.d.ts +5 -0
- package/dist/cleanup-git-status-cache.d.ts +5 -0
- package/dist/cleanup-guards.d.ts +2 -0
- package/dist/cleanup-index-status.d.ts +8 -1
- package/dist/cleanup-run-liveness.d.ts +8 -1
- package/dist/cli.js +372 -73
- package/dist/cli.js.map +4 -4
- package/dist/daemon-platform-guard.d.ts +2 -0
- package/dist/index.js +364 -65
- package/dist/index.js.map +4 -4
- package/dist/landing/cli-auth.d.ts +5 -1
- package/dist/landing/land-pr.d.ts +8 -0
- package/dist/server/cleanup.js +185 -38
- package/dist/server/cleanup.js.map +3 -3
- package/dist/server/default-repo.js +11 -1
- package/dist/server/default-repo.js.map +3 -3
- package/dist/server/memory-cost-enforce.js +11 -1
- package/dist/server/memory-cost-enforce.js.map +3 -3
- package/dist/server/monitor.js +14 -2
- package/dist/server/monitor.js.map +2 -2
- package/dist/worker-ops.d.ts +4 -0
- package/package.json +1 -1
|
@@ -3,5 +3,9 @@ export interface EnsureGitHubCliAuthResult {
|
|
|
3
3
|
configured: boolean;
|
|
4
4
|
reason: string;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Intentional duplicate of `src/modules/agent-os/ready-pr-landing/ready-pr-landing.cli-auth.ts`.
|
|
8
|
+
* The runtime package cannot import `@/src` server modules (standalone esbuild bundle), so gh
|
|
9
|
+
* token resolution is mirrored here. Keep both copies in sync when auth probe logic changes.
|
|
10
|
+
*/
|
|
7
11
|
export declare function ensureGitHubTokenFromCliAuth(): EnsureGitHubCliAuthResult;
|
|
@@ -14,6 +14,14 @@ export interface ExecuteLandPrMergeInput {
|
|
|
14
14
|
skipNotReady?: boolean;
|
|
15
15
|
exec?: PrHandoffExec;
|
|
16
16
|
}
|
|
17
|
+
/** Parse `owner/repo` from a GitHub PR URL, e.g. https://github.com/acme/app/pull/42 -> "acme/app". Returns null on non-match. */
|
|
18
|
+
export declare function repoFromPrUrl(prUrl: string): string | null;
|
|
19
|
+
/** Pure predicate form of the runtime verification-evidence gate (for tests). */
|
|
20
|
+
export declare function runtimeVerificationEvidenceSufficient(input: {
|
|
21
|
+
title?: string | null;
|
|
22
|
+
body?: string | null;
|
|
23
|
+
vercelCheckSuccess?: boolean;
|
|
24
|
+
}): boolean;
|
|
17
25
|
/**
|
|
18
26
|
* Daemon-local PR merge — live readiness, squash merge, branch delete, worktree cleanup.
|
|
19
27
|
*/
|
package/dist/server/cleanup.js
CHANGED
|
@@ -21,6 +21,10 @@ function fail(message) {
|
|
|
21
21
|
console.error(message);
|
|
22
22
|
process.exit(1);
|
|
23
23
|
}
|
|
24
|
+
function hiddenSpawnOptions(opts) {
|
|
25
|
+
if (process.platform !== "win32") return opts;
|
|
26
|
+
return { windowsHide: true, ...opts };
|
|
27
|
+
}
|
|
24
28
|
function safeJson(line) {
|
|
25
29
|
try {
|
|
26
30
|
return JSON.parse(line);
|
|
@@ -126,7 +130,11 @@ var FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
|
|
|
126
130
|
|
|
127
131
|
// src/git.ts
|
|
128
132
|
function git(cwd, args, options = {}) {
|
|
129
|
-
const res = spawnSync(
|
|
133
|
+
const res = spawnSync(
|
|
134
|
+
"git",
|
|
135
|
+
args,
|
|
136
|
+
hiddenSpawnOptions({ cwd, encoding: "utf8" })
|
|
137
|
+
);
|
|
130
138
|
if (res.status !== 0 && !options.allowFailure) {
|
|
131
139
|
const message = `git ${args.join(" ")} failed: ${res.stderr || res.stdout}`;
|
|
132
140
|
if (options.throwError) throw new Error(message);
|
|
@@ -139,7 +147,11 @@ function gitStatusShort(worktreePath) {
|
|
|
139
147
|
}
|
|
140
148
|
function gitCapture(cwd, args) {
|
|
141
149
|
try {
|
|
142
|
-
const res = spawnSync(
|
|
150
|
+
const res = spawnSync(
|
|
151
|
+
"git",
|
|
152
|
+
args,
|
|
153
|
+
hiddenSpawnOptions({ cwd, encoding: "utf8" })
|
|
154
|
+
);
|
|
143
155
|
return {
|
|
144
156
|
status: res.status,
|
|
145
157
|
stdout: res.stdout || "",
|
|
@@ -1735,6 +1747,32 @@ function materialWorktreeChanges(changedFiles) {
|
|
|
1735
1747
|
});
|
|
1736
1748
|
}
|
|
1737
1749
|
|
|
1750
|
+
// src/cleanup-worktree-salvage.ts
|
|
1751
|
+
function prUrlFromFinalResult(finalResult) {
|
|
1752
|
+
if (typeof finalResult === "string") {
|
|
1753
|
+
const match = finalResult.match(/https:\/\/github\.com\/[^\s]+\/pull\/\d+/i);
|
|
1754
|
+
return match?.[0] ?? null;
|
|
1755
|
+
}
|
|
1756
|
+
if (finalResult && typeof finalResult === "object") {
|
|
1757
|
+
const obj = finalResult;
|
|
1758
|
+
for (const key of ["prUrl", "pr_url", "pullRequestUrl"]) {
|
|
1759
|
+
const value = obj[key];
|
|
1760
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
return null;
|
|
1764
|
+
}
|
|
1765
|
+
function isPrOrUnmergedWork(status) {
|
|
1766
|
+
const relation = status.gitAncestry?.relation;
|
|
1767
|
+
if (relation === "merged" || relation === "synced") {
|
|
1768
|
+
return materialWorktreeChanges(status.changedFiles).length > 0;
|
|
1769
|
+
}
|
|
1770
|
+
if (prUrlFromFinalResult(status.finalResult)) return true;
|
|
1771
|
+
if (relation === "ahead" || relation === "diverged") return true;
|
|
1772
|
+
if (status.changedFiles.length > 0 && status.finalResult) return true;
|
|
1773
|
+
return false;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1738
1776
|
// src/cleanup-index-status.ts
|
|
1739
1777
|
function indexedWorktreeStatus(entry) {
|
|
1740
1778
|
if (!entry.status) {
|
|
@@ -1745,11 +1783,71 @@ function indexedWorktreeStatus(entry) {
|
|
|
1745
1783
|
}
|
|
1746
1784
|
return entry.status;
|
|
1747
1785
|
}
|
|
1748
|
-
function indexedWorktreeHasMaterialChanges(entry) {
|
|
1786
|
+
function indexedWorktreeHasMaterialChanges(entry, gitStatusCache) {
|
|
1749
1787
|
if (entry.status) {
|
|
1750
1788
|
return materialWorktreeChanges(entry.status.changedFiles).length > 0;
|
|
1751
1789
|
}
|
|
1752
|
-
|
|
1790
|
+
const porcelain = gitStatusCache ? gitStatusCache.porcelain(entry.worktreePath) : gitStatusShort(entry.worktreePath);
|
|
1791
|
+
return materialWorktreeChanges(porcelain).length > 0;
|
|
1792
|
+
}
|
|
1793
|
+
function finalResultFromWorkerJson(entry) {
|
|
1794
|
+
const snapshot = entry.worker.completionSnapshot?.finalResult;
|
|
1795
|
+
if (snapshot !== void 0 && snapshot !== null) return snapshot;
|
|
1796
|
+
if (entry.worker.taskPrUrl) {
|
|
1797
|
+
return { prUrl: entry.worker.taskPrUrl };
|
|
1798
|
+
}
|
|
1799
|
+
return null;
|
|
1800
|
+
}
|
|
1801
|
+
function resolveWorktreeGuardStatus(entry, ctx) {
|
|
1802
|
+
if (entry.status) return entry.status;
|
|
1803
|
+
const worker = entry.worker;
|
|
1804
|
+
const completionAcknowledged = typeof worker.completionReportedAt === "string" && worker.completionReportedAt.trim().length > 0;
|
|
1805
|
+
const workerJsonTerminal = Boolean(worker.status && ["done", "exited", "blocked", "failed", "abandoned"].includes(worker.status)) || completionAcknowledged;
|
|
1806
|
+
const finalResult = finalResultFromWorkerJson(entry);
|
|
1807
|
+
if (workerJsonTerminal && !isPidAlive(worker.pid)) {
|
|
1808
|
+
const changedFiles = ctx?.gitStatusCache ? ctx.gitStatusCache.porcelain(entry.worktreePath) : gitStatusShort(entry.worktreePath);
|
|
1809
|
+
const baseLabel = entry.run.baseCommit?.trim() || entry.run.base?.trim() || "origin/main";
|
|
1810
|
+
const ahead = ctx?.gitRevCache?.countAheadOfMain(entry.worktreePath, baseLabel);
|
|
1811
|
+
const gitAncestry = ahead === 0 ? {
|
|
1812
|
+
checked: true,
|
|
1813
|
+
base: baseLabel,
|
|
1814
|
+
relation: "synced"
|
|
1815
|
+
} : computeGitAncestry(entry.worktreePath, {
|
|
1816
|
+
base: entry.run.base,
|
|
1817
|
+
baseCommit: entry.run.baseCommit
|
|
1818
|
+
});
|
|
1819
|
+
const status = {
|
|
1820
|
+
runId: entry.runId,
|
|
1821
|
+
worker: entry.workerName,
|
|
1822
|
+
pid: worker.pid,
|
|
1823
|
+
alive: false,
|
|
1824
|
+
status: worker.status ?? (completionAcknowledged ? "done" : "exited"),
|
|
1825
|
+
attention: { state: completionAcknowledged ? "done" : "stale" },
|
|
1826
|
+
branch: worker.branch,
|
|
1827
|
+
worktreePath: entry.worktreePath,
|
|
1828
|
+
ownedPaths: worker.ownedPaths,
|
|
1829
|
+
stdoutBytes: 0,
|
|
1830
|
+
stderrBytes: 0,
|
|
1831
|
+
heartbeatBytes: 0,
|
|
1832
|
+
firstEventAt: null,
|
|
1833
|
+
lastEventAt: null,
|
|
1834
|
+
lastActivityAt: worker.completionReportedAt ?? null,
|
|
1835
|
+
currentTool: null,
|
|
1836
|
+
heartbeatCount: 0,
|
|
1837
|
+
lastHeartbeatAt: null,
|
|
1838
|
+
lastHeartbeatPhase: null,
|
|
1839
|
+
lastHeartbeatSummary: null,
|
|
1840
|
+
heartbeatBlocker: null,
|
|
1841
|
+
changedFiles,
|
|
1842
|
+
gitAncestry,
|
|
1843
|
+
finalResult,
|
|
1844
|
+
completionBlocker: typeof worker.completionBlocker === "string" ? worker.completionBlocker.trim() || null : null,
|
|
1845
|
+
prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? prUrlFromFinalResult(finalResult)
|
|
1846
|
+
};
|
|
1847
|
+
entry.status = status;
|
|
1848
|
+
return status;
|
|
1849
|
+
}
|
|
1850
|
+
return indexedWorktreeStatus(entry);
|
|
1753
1851
|
}
|
|
1754
1852
|
|
|
1755
1853
|
// src/finalize.ts
|
|
@@ -1810,32 +1908,6 @@ function finalizeStaleRuns() {
|
|
|
1810
1908
|
return finalized;
|
|
1811
1909
|
}
|
|
1812
1910
|
|
|
1813
|
-
// src/cleanup-worktree-salvage.ts
|
|
1814
|
-
function prUrlFromFinalResult(finalResult) {
|
|
1815
|
-
if (typeof finalResult === "string") {
|
|
1816
|
-
const match = finalResult.match(/https:\/\/github\.com\/[^\s]+\/pull\/\d+/i);
|
|
1817
|
-
return match?.[0] ?? null;
|
|
1818
|
-
}
|
|
1819
|
-
if (finalResult && typeof finalResult === "object") {
|
|
1820
|
-
const obj = finalResult;
|
|
1821
|
-
for (const key of ["prUrl", "pr_url", "pullRequestUrl"]) {
|
|
1822
|
-
const value = obj[key];
|
|
1823
|
-
if (typeof value === "string" && value.trim()) return value.trim();
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
return null;
|
|
1827
|
-
}
|
|
1828
|
-
function isPrOrUnmergedWork(status) {
|
|
1829
|
-
const relation = status.gitAncestry?.relation;
|
|
1830
|
-
if (relation === "merged" || relation === "synced") {
|
|
1831
|
-
return materialWorktreeChanges(status.changedFiles).length > 0;
|
|
1832
|
-
}
|
|
1833
|
-
if (prUrlFromFinalResult(status.finalResult)) return true;
|
|
1834
|
-
if (relation === "ahead" || relation === "diverged") return true;
|
|
1835
|
-
if (status.changedFiles.length > 0 && status.finalResult) return true;
|
|
1836
|
-
return false;
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
1911
|
// src/cleanup-completion-blocker.ts
|
|
1840
1912
|
function completionBlockerBlocksWorktreeRemoval(indexed, status) {
|
|
1841
1913
|
const blocker = typeof indexed.worker.completionBlocker === "string" ? indexed.worker.completionBlocker.trim() : "";
|
|
@@ -1856,13 +1928,28 @@ function completionBlockerBlocksWorktreeRemoval(indexed, status) {
|
|
|
1856
1928
|
}
|
|
1857
1929
|
|
|
1858
1930
|
// src/cleanup-run-liveness.ts
|
|
1931
|
+
var TERMINAL_WORKER_JSON_STATUSES = /* @__PURE__ */ new Set([
|
|
1932
|
+
"done",
|
|
1933
|
+
"exited",
|
|
1934
|
+
"blocked",
|
|
1935
|
+
"failed",
|
|
1936
|
+
"abandoned"
|
|
1937
|
+
]);
|
|
1859
1938
|
function deriveRunTerminal(indexed, ctx) {
|
|
1860
1939
|
if (ctx) return ctx.runTerminalCache.derive(indexed.run);
|
|
1861
1940
|
return deriveTerminalRunStatus(indexed.run);
|
|
1862
1941
|
}
|
|
1863
1942
|
function isWorkerProcessLive(indexed) {
|
|
1864
1943
|
if (isPidAlive(indexed.worker.pid)) return true;
|
|
1865
|
-
if (
|
|
1944
|
+
if (typeof indexed.worker.completionReportedAt === "string" && indexed.worker.completionReportedAt.trim().length > 0) {
|
|
1945
|
+
return false;
|
|
1946
|
+
}
|
|
1947
|
+
const workerStatus = indexed.worker.status;
|
|
1948
|
+
if (workerStatus && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus)) return false;
|
|
1949
|
+
if (!indexed.worker.pid) {
|
|
1950
|
+
if (workerStatus !== "running") return false;
|
|
1951
|
+
return indexedWorktreeStatus(indexed).alive;
|
|
1952
|
+
}
|
|
1866
1953
|
return false;
|
|
1867
1954
|
}
|
|
1868
1955
|
function isRunStaleActive(indexed, ctx) {
|
|
@@ -1871,6 +1958,10 @@ function isRunStaleActive(indexed, ctx) {
|
|
|
1871
1958
|
}
|
|
1872
1959
|
function runBlocksWorktreeRemoval(indexed, ctx) {
|
|
1873
1960
|
if (isWorkerProcessLive(indexed)) return true;
|
|
1961
|
+
const workerStatus = indexed.worker.status;
|
|
1962
|
+
if (workerStatus && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus) && !indexed.worker.completionBlocker) {
|
|
1963
|
+
return false;
|
|
1964
|
+
}
|
|
1874
1965
|
const status = indexedWorktreeStatus(indexed);
|
|
1875
1966
|
if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return true;
|
|
1876
1967
|
if (isFinishedWorkerStatus(status)) return false;
|
|
@@ -1889,7 +1980,7 @@ function effectiveWorktreeAgeMs(input) {
|
|
|
1889
1980
|
if (input.liveness && isRunStaleActive(indexed, input.liveness)) {
|
|
1890
1981
|
return terminalWorktreesAgeMs;
|
|
1891
1982
|
}
|
|
1892
|
-
if (input.liveness && isFinishedWorkerStatus(
|
|
1983
|
+
if (input.liveness && isFinishedWorkerStatus(resolveWorktreeGuardStatus(indexed, input.liveness)) && !isWorkerProcessLive(indexed)) {
|
|
1893
1984
|
return terminalWorktreesAgeMs;
|
|
1894
1985
|
}
|
|
1895
1986
|
return worktreesAgeMs;
|
|
@@ -1903,8 +1994,13 @@ function skipWorktreeRemoval(input) {
|
|
|
1903
1994
|
const ageThresholdMs = effectiveWorktreeAgeMs(input);
|
|
1904
1995
|
if (worktreesAgeMs <= 0 && !includeOrphans && ageThresholdMs <= 0) return "worktrees_disabled";
|
|
1905
1996
|
if (ageThresholdMs > 0 && ageMs < ageThresholdMs) return "below_age_threshold";
|
|
1906
|
-
const status = indexedWorktreeStatus(indexed);
|
|
1907
1997
|
if (isWorkerProcessLive(indexed)) return "active_worker";
|
|
1998
|
+
if (indexedWorktreeHasMaterialChanges(indexed, input.liveness?.gitStatusCache)) {
|
|
1999
|
+
return "dirty_worktree";
|
|
2000
|
+
}
|
|
2001
|
+
const ahead = input.liveness?.gitRevCache?.countAheadOfMain(input.worktreePath);
|
|
2002
|
+
if (ahead !== null && ahead !== void 0 && ahead > 0) return "pr_or_unmerged_commits";
|
|
2003
|
+
const status = resolveWorktreeGuardStatus(indexed, input.liveness);
|
|
1908
2004
|
if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return "completion_blocked";
|
|
1909
2005
|
if (runBlocksWorktreeRemoval(indexed, input.liveness)) return "run_still_active";
|
|
1910
2006
|
if (!isFinishedWorkerStatus(status)) return "run_still_active";
|
|
@@ -1935,7 +2031,9 @@ function skipDependencyCacheRemoval(input) {
|
|
|
1935
2031
|
if (!diskPressure && ageMs < nodeModulesAgeMs) return "below_age_threshold";
|
|
1936
2032
|
if (activeWorktreePaths.has(path8.resolve(worktreePath))) return "active_worker";
|
|
1937
2033
|
if (indexed && isWorkerProcessLive(indexed)) return "active_worker";
|
|
1938
|
-
if (indexed && indexedWorktreeHasMaterialChanges(indexed))
|
|
2034
|
+
if (indexed && indexedWorktreeHasMaterialChanges(indexed, input.gitStatusCache)) {
|
|
2035
|
+
return "dirty_worktree";
|
|
2036
|
+
}
|
|
1939
2037
|
return null;
|
|
1940
2038
|
}
|
|
1941
2039
|
function skipBuildCacheRemoval(input) {
|
|
@@ -3119,6 +3217,37 @@ function emitCleanupProgress(phase, detail) {
|
|
|
3119
3217
|
console.error(`[kynver cleanup] ${phase}${suffix}`);
|
|
3120
3218
|
}
|
|
3121
3219
|
|
|
3220
|
+
// src/cleanup-git-rev-cache.ts
|
|
3221
|
+
var CleanupGitRevCache = class {
|
|
3222
|
+
aheadOfMain = /* @__PURE__ */ new Map();
|
|
3223
|
+
countAheadOfMain(worktreePath, base = "origin/main") {
|
|
3224
|
+
const key = `${worktreePath}\0${base}`;
|
|
3225
|
+
if (this.aheadOfMain.has(key)) return this.aheadOfMain.get(key) ?? null;
|
|
3226
|
+
const result = gitCapture(worktreePath, ["rev-list", "--count", `${base}..HEAD`]);
|
|
3227
|
+
if (result.status !== 0) {
|
|
3228
|
+
this.aheadOfMain.set(key, null);
|
|
3229
|
+
return null;
|
|
3230
|
+
}
|
|
3231
|
+
const count = Number(result.stdout.trim());
|
|
3232
|
+
const parsed = Number.isFinite(count) ? count : null;
|
|
3233
|
+
this.aheadOfMain.set(key, parsed);
|
|
3234
|
+
return parsed;
|
|
3235
|
+
}
|
|
3236
|
+
};
|
|
3237
|
+
|
|
3238
|
+
// src/cleanup-git-status-cache.ts
|
|
3239
|
+
var CleanupGitStatusCache = class {
|
|
3240
|
+
cache = /* @__PURE__ */ new Map();
|
|
3241
|
+
porcelain(worktreePath) {
|
|
3242
|
+
const resolved = worktreePath;
|
|
3243
|
+
const cached = this.cache.get(resolved);
|
|
3244
|
+
if (cached !== void 0) return cached;
|
|
3245
|
+
const lines = gitStatusShort(resolved);
|
|
3246
|
+
this.cache.set(resolved, lines);
|
|
3247
|
+
return lines;
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
|
|
3122
3251
|
// src/cleanup-run-terminal-cache.ts
|
|
3123
3252
|
var CleanupRunTerminalCache = class {
|
|
3124
3253
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -3236,7 +3365,11 @@ function runHarnessCleanup(options = {}) {
|
|
|
3236
3365
|
emitCleanupProgress("index", "building worktree index");
|
|
3237
3366
|
const index = mergeWorktreeIndexes(paths.scanRoots);
|
|
3238
3367
|
emitCleanupProgress("index", `${index.size} indexed worktree(s)`);
|
|
3239
|
-
const liveness = {
|
|
3368
|
+
const liveness = {
|
|
3369
|
+
runTerminalCache: new CleanupRunTerminalCache(),
|
|
3370
|
+
gitStatusCache: new CleanupGitStatusCache(),
|
|
3371
|
+
gitRevCache: new CleanupGitRevCache()
|
|
3372
|
+
};
|
|
3240
3373
|
const skips = [];
|
|
3241
3374
|
const actions = [];
|
|
3242
3375
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
@@ -3256,8 +3389,15 @@ function runHarnessCleanup(options = {}) {
|
|
|
3256
3389
|
index,
|
|
3257
3390
|
now: paths.now
|
|
3258
3391
|
};
|
|
3259
|
-
|
|
3392
|
+
const dependencyCandidates = scanDependencyCacheCandidates(scanOpts);
|
|
3393
|
+
emitCleanupProgress("dependency", `${dependencyCandidates.length} cache candidate(s) at ${harnessRoot}`);
|
|
3394
|
+
let dependencyProcessed = 0;
|
|
3395
|
+
for (const raw of dependencyCandidates) {
|
|
3260
3396
|
if (atSweepCap()) break;
|
|
3397
|
+
dependencyProcessed += 1;
|
|
3398
|
+
if (dependencyProcessed % 50 === 0) {
|
|
3399
|
+
emitCleanupProgress("dependency", `${dependencyProcessed}/${dependencyCandidates.length} evaluated`);
|
|
3400
|
+
}
|
|
3261
3401
|
const resolved = path23.resolve(raw.path);
|
|
3262
3402
|
if (processedPaths.has(resolved)) continue;
|
|
3263
3403
|
processedPaths.add(resolved);
|
|
@@ -3277,7 +3417,8 @@ function runHarnessCleanup(options = {}) {
|
|
|
3277
3417
|
ageMs: candidate.ageMs,
|
|
3278
3418
|
worktreePath,
|
|
3279
3419
|
activeWorktreePaths: activeGuards.activeWorktreePaths,
|
|
3280
|
-
diskPressure: retention.diskPressure
|
|
3420
|
+
diskPressure: retention.diskPressure,
|
|
3421
|
+
gitStatusCache: liveness.gitStatusCache
|
|
3281
3422
|
});
|
|
3282
3423
|
if (guardReason) {
|
|
3283
3424
|
recordSkip(skips, candidate.path, guardReason);
|
|
@@ -3312,7 +3453,8 @@ function runHarnessCleanup(options = {}) {
|
|
|
3312
3453
|
ageMs: candidate.ageMs,
|
|
3313
3454
|
worktreePath,
|
|
3314
3455
|
activeWorktreePaths: activeGuards.activeWorktreePaths,
|
|
3315
|
-
diskPressure: retention.diskPressure
|
|
3456
|
+
diskPressure: retention.diskPressure,
|
|
3457
|
+
gitStatusCache: liveness.gitStatusCache
|
|
3316
3458
|
});
|
|
3317
3459
|
if (guardReason) {
|
|
3318
3460
|
recordSkip(skips, candidate.path, guardReason);
|
|
@@ -3332,8 +3474,13 @@ function runHarnessCleanup(options = {}) {
|
|
|
3332
3474
|
];
|
|
3333
3475
|
emitCleanupProgress("worktrees", `${worktreeCandidates.length} candidate(s) at ${harnessRoot}`);
|
|
3334
3476
|
const worktreeSeen = /* @__PURE__ */ new Set();
|
|
3477
|
+
let worktreeProcessed = 0;
|
|
3335
3478
|
for (const raw of worktreeCandidates) {
|
|
3336
3479
|
if (atSweepCap()) break;
|
|
3480
|
+
worktreeProcessed += 1;
|
|
3481
|
+
if (worktreeProcessed % 50 === 0) {
|
|
3482
|
+
emitCleanupProgress("worktrees", `${worktreeProcessed}/${worktreeCandidates.length} evaluated`);
|
|
3483
|
+
}
|
|
3337
3484
|
const resolved = path23.resolve(raw.path);
|
|
3338
3485
|
if (worktreeSeen.has(resolved)) continue;
|
|
3339
3486
|
worktreeSeen.add(resolved);
|