@tokenfactory/acc-runner 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -4
- package/package.json +1 -1
- package/dist/anthropic-auth.d.ts +0 -53
- package/dist/anthropic-auth.d.ts.map +0 -1
- package/dist/anthropic-auth.js +0 -89
- package/dist/anthropic-auth.js.map +0 -1
- package/dist/bin-resolve.d.ts +0 -16
- package/dist/bin-resolve.d.ts.map +0 -1
- package/dist/bin-resolve.js +0 -35
- package/dist/bin-resolve.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -128
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts +0 -121
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -396
- package/dist/config.js.map +0 -1
- package/dist/cost-pricing.d.ts +0 -130
- package/dist/cost-pricing.d.ts.map +0 -1
- package/dist/cost-pricing.js +0 -191
- package/dist/cost-pricing.js.map +0 -1
- package/dist/doctor.d.ts +0 -37
- package/dist/doctor.d.ts.map +0 -1
- package/dist/doctor.js +0 -658
- package/dist/doctor.js.map +0 -1
- package/dist/failure-classifier.d.ts +0 -112
- package/dist/failure-classifier.d.ts.map +0 -1
- package/dist/failure-classifier.js +0 -353
- package/dist/failure-classifier.js.map +0 -1
- package/dist/gh.d.ts +0 -22
- package/dist/gh.d.ts.map +0 -1
- package/dist/gh.js +0 -48
- package/dist/gh.js.map +0 -1
- package/dist/git.d.ts +0 -50
- package/dist/git.d.ts.map +0 -1
- package/dist/git.js +0 -127
- package/dist/git.js.map +0 -1
- package/dist/github-client.d.ts +0 -133
- package/dist/github-client.d.ts.map +0 -1
- package/dist/github-client.js +0 -234
- package/dist/github-client.js.map +0 -1
- package/dist/keychain.d.ts +0 -21
- package/dist/keychain.d.ts.map +0 -1
- package/dist/keychain.js +0 -45
- package/dist/keychain.js.map +0 -1
- package/dist/login.d.ts +0 -12
- package/dist/login.d.ts.map +0 -1
- package/dist/login.js +0 -133
- package/dist/login.js.map +0 -1
- package/dist/logout.d.ts +0 -2
- package/dist/logout.d.ts.map +0 -1
- package/dist/logout.js +0 -31
- package/dist/logout.js.map +0 -1
- package/dist/mcp-spawn.d.ts +0 -30
- package/dist/mcp-spawn.d.ts.map +0 -1
- package/dist/mcp-spawn.js +0 -145
- package/dist/mcp-spawn.js.map +0 -1
- package/dist/messaging.d.ts +0 -49
- package/dist/messaging.d.ts.map +0 -1
- package/dist/messaging.js +0 -36
- package/dist/messaging.js.map +0 -1
- package/dist/pkg-version.d.ts +0 -3
- package/dist/pkg-version.d.ts.map +0 -1
- package/dist/pkg-version.js +0 -20
- package/dist/pkg-version.js.map +0 -1
- package/dist/profiles/designer-prompt.d.ts +0 -18
- package/dist/profiles/designer-prompt.d.ts.map +0 -1
- package/dist/profiles/designer-prompt.js +0 -172
- package/dist/profiles/designer-prompt.js.map +0 -1
- package/dist/profiles/developer-prompt.d.ts +0 -24
- package/dist/profiles/developer-prompt.d.ts.map +0 -1
- package/dist/profiles/developer-prompt.js +0 -24
- package/dist/profiles/developer-prompt.js.map +0 -1
- package/dist/profiles/manager-prompt.d.ts +0 -34
- package/dist/profiles/manager-prompt.d.ts.map +0 -1
- package/dist/profiles/manager-prompt.js +0 -93
- package/dist/profiles/manager-prompt.js.map +0 -1
- package/dist/profiles/tester-prompt.d.ts +0 -28
- package/dist/profiles/tester-prompt.d.ts.map +0 -1
- package/dist/profiles/tester-prompt.js +0 -165
- package/dist/profiles/tester-prompt.js.map +0 -1
- package/dist/prompt.d.ts +0 -38
- package/dist/prompt.d.ts.map +0 -1
- package/dist/prompt.js +0 -78
- package/dist/prompt.js.map +0 -1
- package/dist/runtime/cache-dir.d.ts +0 -2
- package/dist/runtime/cache-dir.d.ts.map +0 -1
- package/dist/runtime/cache-dir.js +0 -15
- package/dist/runtime/cache-dir.js.map +0 -1
- package/dist/runtime/conflict-resolver.d.ts +0 -65
- package/dist/runtime/conflict-resolver.d.ts.map +0 -1
- package/dist/runtime/conflict-resolver.js +0 -477
- package/dist/runtime/conflict-resolver.js.map +0 -1
- package/dist/runtime/expand-args.d.ts +0 -28
- package/dist/runtime/expand-args.d.ts.map +0 -1
- package/dist/runtime/expand-args.js +0 -50
- package/dist/runtime/expand-args.js.map +0 -1
- package/dist/runtime/locks.d.ts +0 -21
- package/dist/runtime/locks.d.ts.map +0 -1
- package/dist/runtime/locks.js +0 -97
- package/dist/runtime/locks.js.map +0 -1
- package/dist/runtime/provision-mutex.d.ts +0 -37
- package/dist/runtime/provision-mutex.d.ts.map +0 -1
- package/dist/runtime/provision-mutex.js +0 -67
- package/dist/runtime/provision-mutex.js.map +0 -1
- package/dist/runtime/quarantine.d.ts +0 -26
- package/dist/runtime/quarantine.d.ts.map +0 -1
- package/dist/runtime/quarantine.js +0 -50
- package/dist/runtime/quarantine.js.map +0 -1
- package/dist/runtime/resolution-integrity.d.ts +0 -86
- package/dist/runtime/resolution-integrity.d.ts.map +0 -1
- package/dist/runtime/resolution-integrity.js +0 -248
- package/dist/runtime/resolution-integrity.js.map +0 -1
- package/dist/runtime/reviewer.d.ts +0 -81
- package/dist/runtime/reviewer.d.ts.map +0 -1
- package/dist/runtime/reviewer.js +0 -374
- package/dist/runtime/reviewer.js.map +0 -1
- package/dist/runtime/rework.d.ts +0 -48
- package/dist/runtime/rework.d.ts.map +0 -1
- package/dist/runtime/rework.js +0 -136
- package/dist/runtime/rework.js.map +0 -1
- package/dist/runtime/singleton.d.ts +0 -47
- package/dist/runtime/singleton.d.ts.map +0 -1
- package/dist/runtime/singleton.js +0 -200
- package/dist/runtime/singleton.js.map +0 -1
- package/dist/runtime/version-drift.d.ts +0 -31
- package/dist/runtime/version-drift.d.ts.map +0 -1
- package/dist/runtime/version-drift.js +0 -114
- package/dist/runtime/version-drift.js.map +0 -1
- package/dist/runtime/worktree.d.ts +0 -74
- package/dist/runtime/worktree.d.ts.map +0 -1
- package/dist/runtime/worktree.js +0 -206
- package/dist/runtime/worktree.js.map +0 -1
- package/dist/secrets/inject.d.ts +0 -70
- package/dist/secrets/inject.d.ts.map +0 -1
- package/dist/secrets/inject.js +0 -102
- package/dist/secrets/inject.js.map +0 -1
- package/dist/supabase.d.ts +0 -4
- package/dist/supabase.d.ts.map +0 -1
- package/dist/supabase.js +0 -36
- package/dist/supabase.js.map +0 -1
- package/dist/task-runner.d.ts +0 -313
- package/dist/task-runner.d.ts.map +0 -1
- package/dist/task-runner.js +0 -1766
- package/dist/task-runner.js.map +0 -1
- package/dist/token-provider.d.ts +0 -50
- package/dist/token-provider.d.ts.map +0 -1
- package/dist/token-provider.js +0 -177
- package/dist/token-provider.js.map +0 -1
- package/dist/types.d.ts +0 -120
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -16
- package/dist/types.js.map +0 -1
- package/dist/version-check.d.ts +0 -17
- package/dist/version-check.d.ts.map +0 -1
- package/dist/version-check.js +0 -56
- package/dist/version-check.js.map +0 -1
- package/dist/watch.d.ts +0 -295
- package/dist/watch.d.ts.map +0 -1
- package/dist/watch.js +0 -1532
- package/dist/watch.js.map +0 -1
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* v0.14.0 (T-54-2, GA-3): single-instance runner lock.
|
|
3
|
-
*
|
|
4
|
-
* On 2026-06-05 two `acc-runner watch` processes came up on one machine
|
|
5
|
-
* sharing the same repo path. They collided on per-task worktree locks and
|
|
6
|
-
* raced git refs, double-failing an entire batch in under a second
|
|
7
|
-
* (CURRENT_CYCLE.md v0.53 incident (b)). No startup guard existed.
|
|
8
|
-
*
|
|
9
|
-
* This module gives any task-executing entrypoint (today: `watch`) an
|
|
10
|
-
* exclusive lock keyed by the *canonical repo path* it serves. Acquisition
|
|
11
|
-
* uses O_EXCL (`fs.openSync(file, "wx")`) so the create-or-fail is atomic;
|
|
12
|
-
* an existing lock whose pid is dead is reclaimed with a log line, while a
|
|
13
|
-
* live holder for the SAME repo path is rejected loudly.
|
|
14
|
-
*
|
|
15
|
-
* Different repo paths coexist (future multi-repo): the lock file name is
|
|
16
|
-
* derived from a hash of the canonical repo path, so one machine can run
|
|
17
|
-
* one runner per repo without contention. The conceptual name in the spec
|
|
18
|
-
* is `<cache>/runner.lock`; the per-repo hash suffix is what makes
|
|
19
|
-
* coexistence possible.
|
|
20
|
-
*/
|
|
21
|
-
import fs from "node:fs";
|
|
22
|
-
import fsp from "node:fs/promises";
|
|
23
|
-
import path from "node:path";
|
|
24
|
-
import crypto from "node:crypto";
|
|
25
|
-
import { cacheDir } from "./cache-dir.js";
|
|
26
|
-
import { isProcessAlive } from "./locks.js";
|
|
27
|
-
import { PACKAGE_VERSION } from "../pkg-version.js";
|
|
28
|
-
export class SingletonLockHeldError extends Error {
|
|
29
|
-
holder;
|
|
30
|
-
lockFile;
|
|
31
|
-
constructor(holder, lockFile) {
|
|
32
|
-
super(`another acc-runner (pid ${holder.pid}) is already serving repo ${holder.repoPath}`);
|
|
33
|
-
this.holder = holder;
|
|
34
|
-
this.lockFile = lockFile;
|
|
35
|
-
this.name = "SingletonLockHeldError";
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Resolve a repo path to a stable canonical form so two spellings of the
|
|
40
|
-
* same directory (trailing slash, symlink, `./`) map to one lock file.
|
|
41
|
-
* realpath fails if the path does not exist yet — fall back to resolve().
|
|
42
|
-
*/
|
|
43
|
-
export function canonicalRepoPath(repoPath) {
|
|
44
|
-
const resolved = path.resolve(repoPath);
|
|
45
|
-
try {
|
|
46
|
-
return fs.realpathSync(resolved);
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
return resolved;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/** `<cache>/runner.<hash>.lock`, hash derived from the canonical repo path. */
|
|
53
|
-
export function singletonLockPath(repoPath) {
|
|
54
|
-
const hash = crypto
|
|
55
|
-
.createHash("sha1")
|
|
56
|
-
.update(canonicalRepoPath(repoPath))
|
|
57
|
-
.digest("hex")
|
|
58
|
-
.slice(0, 12);
|
|
59
|
-
return path.join(cacheDir(), `runner.${hash}.lock`);
|
|
60
|
-
}
|
|
61
|
-
async function readLockInfo(file) {
|
|
62
|
-
let raw;
|
|
63
|
-
try {
|
|
64
|
-
raw = await fsp.readFile(file, "utf8");
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
if (err.code === "ENOENT")
|
|
68
|
-
return null;
|
|
69
|
-
throw err;
|
|
70
|
-
}
|
|
71
|
-
try {
|
|
72
|
-
const parsed = JSON.parse(raw);
|
|
73
|
-
if (typeof parsed.pid !== "number" || !Number.isFinite(parsed.pid))
|
|
74
|
-
return null;
|
|
75
|
-
return {
|
|
76
|
-
pid: parsed.pid,
|
|
77
|
-
repoPath: typeof parsed.repoPath === "string" ? parsed.repoPath : "<unknown>",
|
|
78
|
-
acquiredAt: typeof parsed.acquiredAt === "string" ? parsed.acquiredAt : "<unknown>",
|
|
79
|
-
version: typeof parsed.version === "string" ? parsed.version : "<unknown>",
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
// Corrupt/partial lock file — treat as reclaimable rather than fatal.
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function makeLock(file, repoPath, pid) {
|
|
88
|
-
return {
|
|
89
|
-
lockFile: file,
|
|
90
|
-
repoPath,
|
|
91
|
-
async release() {
|
|
92
|
-
try {
|
|
93
|
-
const holder = await readLockInfo(file);
|
|
94
|
-
// Only unlink if we still own it — never stomp a lock another
|
|
95
|
-
// process reclaimed after we exited uncleanly.
|
|
96
|
-
if (holder && holder.pid === pid)
|
|
97
|
-
await fsp.unlink(file);
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
if (err.code !== "ENOENT")
|
|
101
|
-
throw err;
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Acquire the single-instance lock for `repoPath`. Throws
|
|
108
|
-
* SingletonLockHeldError when a *live* process already holds the lock for
|
|
109
|
-
* the same canonical repo path. A stale lock (dead pid, our own pid, or a
|
|
110
|
-
* corrupt file) is reclaimed with a stderr breadcrumb and then re-acquired.
|
|
111
|
-
*/
|
|
112
|
-
export async function acquireSingletonLock(repoPath, pid = process.pid) {
|
|
113
|
-
const canonical = canonicalRepoPath(repoPath);
|
|
114
|
-
const file = singletonLockPath(repoPath);
|
|
115
|
-
await fsp.mkdir(path.dirname(file), { recursive: true });
|
|
116
|
-
const payload = `${JSON.stringify({
|
|
117
|
-
pid,
|
|
118
|
-
repoPath: canonical,
|
|
119
|
-
acquiredAt: new Date().toISOString(),
|
|
120
|
-
version: PACKAGE_VERSION,
|
|
121
|
-
}, null, 2)}\n`;
|
|
122
|
-
// Two attempts: the second only runs after we reclaim a stale lock, which
|
|
123
|
-
// closes the (tiny) window between the failed create and the unlink.
|
|
124
|
-
for (let attempt = 0; attempt < 2; attempt++) {
|
|
125
|
-
try {
|
|
126
|
-
// "wx" === O_CREAT | O_EXCL | O_WRONLY: atomic create-or-fail.
|
|
127
|
-
const fd = fs.openSync(file, "wx");
|
|
128
|
-
try {
|
|
129
|
-
fs.writeSync(fd, payload);
|
|
130
|
-
}
|
|
131
|
-
finally {
|
|
132
|
-
fs.closeSync(fd);
|
|
133
|
-
}
|
|
134
|
-
return makeLock(file, canonical, pid);
|
|
135
|
-
}
|
|
136
|
-
catch (err) {
|
|
137
|
-
if (err.code !== "EEXIST")
|
|
138
|
-
throw err;
|
|
139
|
-
const holder = await readLockInfo(file);
|
|
140
|
-
if (holder && holder.pid !== pid && isProcessAlive(holder.pid)) {
|
|
141
|
-
throw new SingletonLockHeldError(holder, file);
|
|
142
|
-
}
|
|
143
|
-
// Stale: dead holder, our own leftover pid, or unparseable. Reclaim.
|
|
144
|
-
process.stderr.write(`[acc-runner] reclaiming stale runner lock ${file} ` +
|
|
145
|
-
`(held by pid ${holder?.pid ?? "?"}, not alive)\n`);
|
|
146
|
-
try {
|
|
147
|
-
fs.unlinkSync(file);
|
|
148
|
-
}
|
|
149
|
-
catch (unlinkErr) {
|
|
150
|
-
if (unlinkErr.code !== "ENOENT")
|
|
151
|
-
throw unlinkErr;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
throw new Error(`could not acquire singleton lock at ${file}`);
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Inspect the lock file for `repoPath` and return its holder iff a *live*
|
|
159
|
-
* process other than `selfPid` owns it. Used by `acc-runner doctor` to
|
|
160
|
-
* report a duplicate runner without trying to acquire the lock.
|
|
161
|
-
*/
|
|
162
|
-
export async function findLiveLockHolder(repoPath, selfPid = process.pid) {
|
|
163
|
-
const holder = await readLockInfo(singletonLockPath(repoPath));
|
|
164
|
-
if (holder && holder.pid !== selfPid && isProcessAlive(holder.pid)) {
|
|
165
|
-
return holder;
|
|
166
|
-
}
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* pgrep-style scan for other `acc-runner watch` processes. Best-effort and
|
|
171
|
-
* offline of the lock file — used by doctor to catch a runner that predates
|
|
172
|
-
* the singleton lock (no lock file) or one whose lock was hand-deleted.
|
|
173
|
-
* Returns foreign pids; never throws (returns [] on any failure).
|
|
174
|
-
*/
|
|
175
|
-
export async function listForeignRunnerPids(selfPid = process.pid) {
|
|
176
|
-
try {
|
|
177
|
-
const { execa } = await import("execa");
|
|
178
|
-
const { stdout } = await execa("ps", ["-axo", "pid=,args="]);
|
|
179
|
-
const pids = [];
|
|
180
|
-
for (const line of stdout.split(/\r?\n/)) {
|
|
181
|
-
const m = line.trim().match(/^(\d+)\s+(.*)$/);
|
|
182
|
-
if (!m)
|
|
183
|
-
continue;
|
|
184
|
-
const pid = Number.parseInt(m[1], 10);
|
|
185
|
-
const args = m[2];
|
|
186
|
-
if (pid === selfPid)
|
|
187
|
-
continue;
|
|
188
|
-
// Match the runner's watch command without matching this doctor run
|
|
189
|
-
// (which is `acc-runner doctor`) or a grep of the word.
|
|
190
|
-
if (/acc-runner\b.*\bwatch\b/.test(args) || /\bacc-runner-watch\b/.test(args)) {
|
|
191
|
-
pids.push(pid);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return pids;
|
|
195
|
-
}
|
|
196
|
-
catch {
|
|
197
|
-
return [];
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
//# sourceMappingURL=singleton.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../src/runtime/singleton.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export declare const NPM_PACKAGE = "@tokenfactory/acc-runner";
|
|
2
|
-
export interface TaskEnvRecord {
|
|
3
|
-
/** `claude --version` first line at the last successful task, or null. */
|
|
4
|
-
claudeVersion: string | null;
|
|
5
|
-
recordedAt: string;
|
|
6
|
-
}
|
|
7
|
-
export declare function taskEnvFile(): string;
|
|
8
|
-
export interface NpmLatestDeps {
|
|
9
|
-
/** Fetch the latest published version string, or null on failure. */
|
|
10
|
-
fetchLatest?: () => Promise<string | null>;
|
|
11
|
-
/** Now, ms since epoch — injectable for cache-freshness tests. */
|
|
12
|
-
now?: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Latest published version, via a cached registry lookup. Returns the
|
|
16
|
-
* cached value while it is fresh; refetches once it goes stale. On a
|
|
17
|
-
* network failure with no usable cache, returns null so the caller skips
|
|
18
|
-
* the drift check silently (offline-safe).
|
|
19
|
-
*/
|
|
20
|
-
export declare function npmLatestVersion(deps?: NpmLatestDeps): Promise<string | null>;
|
|
21
|
-
/**
|
|
22
|
-
* First line of `claude --version`, or null when the binary is missing or
|
|
23
|
-
* errors. Shared by the watch success-recorder and doctor's drift check so
|
|
24
|
-
* both compare the exact same string.
|
|
25
|
-
*/
|
|
26
|
-
export declare function getClaudeVersion(): Promise<string | null>;
|
|
27
|
-
/** Persist the claude CLI version seen at a successful task. Best-effort. */
|
|
28
|
-
export declare function recordTaskClaudeVersion(claudeVersion: string | null): Promise<void>;
|
|
29
|
-
/** Read the last recorded task-env, or null when no task has succeeded yet. */
|
|
30
|
-
export declare function readTaskEnv(): Promise<TaskEnvRecord | null>;
|
|
31
|
-
//# sourceMappingURL=version-drift.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"version-drift.d.ts","sourceRoot":"","sources":["../../src/runtime/version-drift.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,WAAW,6BAA6B,CAAC;AAQtD,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAgBD,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAiBD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuBxB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAO/D;AAED,6EAA6E;AAC7E,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,+EAA+E;AAC/E,wBAAsB,WAAW,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAEjE"}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* v0.14.0 (T-54-2, GA-6 runner-side): version-drift detection inputs.
|
|
3
|
-
*
|
|
4
|
-
* Two silent drifts double-failed the v0.53 batch's blast radius: this
|
|
5
|
-
* machine ran acc-runner 0.11.0 while 0.12.0 was on npm, and the claude
|
|
6
|
-
* CLI auto-updated mid-cycle without anyone noticing. `acc-runner doctor`
|
|
7
|
-
* now surfaces both as WARNs. This module owns the two data sources:
|
|
8
|
-
*
|
|
9
|
-
* 1. npmLatestVersion() — one *cached* registry lookup (default 6h TTL),
|
|
10
|
-
* offline-safe (returns null on any network failure so doctor skips
|
|
11
|
-
* the check silently rather than failing).
|
|
12
|
-
* 2. recordTaskClaudeVersion() / readTaskEnv() — the claude CLI version
|
|
13
|
-
* observed at the last successful task, persisted in the cache so
|
|
14
|
-
* doctor can flag "claude changed under you since the last green run".
|
|
15
|
-
*
|
|
16
|
-
* Both use additive cache files under the runner cache dir — no existing
|
|
17
|
-
* cache schema is touched.
|
|
18
|
-
*/
|
|
19
|
-
import fs from "node:fs/promises";
|
|
20
|
-
import path from "node:path";
|
|
21
|
-
import { execa } from "execa";
|
|
22
|
-
import { buildEnv } from "../bin-resolve.js";
|
|
23
|
-
import { cacheDir } from "./cache-dir.js";
|
|
24
|
-
export const NPM_PACKAGE = "@tokenfactory/acc-runner";
|
|
25
|
-
const REGISTRY_TTL_MS = 6 * 60 * 60 * 1000; // 6h — "one cached lookup", not per-run.
|
|
26
|
-
function registryCacheFile() {
|
|
27
|
-
return path.join(cacheDir(), "npm-latest.json");
|
|
28
|
-
}
|
|
29
|
-
export function taskEnvFile() {
|
|
30
|
-
return path.join(cacheDir(), "last-task-env.json");
|
|
31
|
-
}
|
|
32
|
-
async function readJson(file) {
|
|
33
|
-
try {
|
|
34
|
-
return JSON.parse(await fs.readFile(file, "utf8"));
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
if (err.code === "ENOENT")
|
|
38
|
-
return null;
|
|
39
|
-
return null; // corrupt cache is non-fatal — treat as a miss
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
async function writeJson(file, value) {
|
|
43
|
-
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
44
|
-
await fs.writeFile(file, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
45
|
-
}
|
|
46
|
-
/** Default network fetch of the registry "latest" dist-tag. */
|
|
47
|
-
async function fetchLatestFromRegistry() {
|
|
48
|
-
try {
|
|
49
|
-
const res = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE}/latest`, { headers: { Accept: "application/json" } });
|
|
50
|
-
if (!res.ok)
|
|
51
|
-
return null;
|
|
52
|
-
const body = (await res.json());
|
|
53
|
-
return typeof body.version === "string" ? body.version : null;
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Latest published version, via a cached registry lookup. Returns the
|
|
61
|
-
* cached value while it is fresh; refetches once it goes stale. On a
|
|
62
|
-
* network failure with no usable cache, returns null so the caller skips
|
|
63
|
-
* the drift check silently (offline-safe).
|
|
64
|
-
*/
|
|
65
|
-
export async function npmLatestVersion(deps = {}) {
|
|
66
|
-
const now = deps.now ?? Date.now();
|
|
67
|
-
const fetchLatest = deps.fetchLatest ?? fetchLatestFromRegistry;
|
|
68
|
-
const file = registryCacheFile();
|
|
69
|
-
const cached = await readJson(file);
|
|
70
|
-
if (cached?.latest) {
|
|
71
|
-
const age = now - Date.parse(cached.checkedAt);
|
|
72
|
-
if (Number.isFinite(age) && age >= 0 && age < REGISTRY_TTL_MS) {
|
|
73
|
-
return cached.latest;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
const latest = await fetchLatest();
|
|
77
|
-
if (!latest) {
|
|
78
|
-
// Offline / registry down: fall back to a stale cache if we have one.
|
|
79
|
-
return cached?.latest ?? null;
|
|
80
|
-
}
|
|
81
|
-
await writeJson(file, {
|
|
82
|
-
latest,
|
|
83
|
-
checkedAt: new Date(now).toISOString(),
|
|
84
|
-
}).catch(() => {
|
|
85
|
-
/* cache write is best-effort */
|
|
86
|
-
});
|
|
87
|
-
return latest;
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* First line of `claude --version`, or null when the binary is missing or
|
|
91
|
-
* errors. Shared by the watch success-recorder and doctor's drift check so
|
|
92
|
-
* both compare the exact same string.
|
|
93
|
-
*/
|
|
94
|
-
export async function getClaudeVersion() {
|
|
95
|
-
try {
|
|
96
|
-
const { stdout } = await execa("claude", ["--version"], { env: buildEnv() });
|
|
97
|
-
return stdout.split(/\r?\n/)[0]?.trim() || null;
|
|
98
|
-
}
|
|
99
|
-
catch {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
/** Persist the claude CLI version seen at a successful task. Best-effort. */
|
|
104
|
-
export async function recordTaskClaudeVersion(claudeVersion) {
|
|
105
|
-
await writeJson(taskEnvFile(), {
|
|
106
|
-
claudeVersion,
|
|
107
|
-
recordedAt: new Date().toISOString(),
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
/** Read the last recorded task-env, or null when no task has succeeded yet. */
|
|
111
|
-
export async function readTaskEnv() {
|
|
112
|
-
return readJson(taskEnvFile());
|
|
113
|
-
}
|
|
114
|
-
//# sourceMappingURL=version-drift.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"version-drift.js","sourceRoot":"","sources":["../../src/runtime/version-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
export declare function workDir(): string;
|
|
2
|
-
export interface PreparedWorktree {
|
|
3
|
-
path: string;
|
|
4
|
-
/**
|
|
5
|
-
* v0.12-RESUME — true when a pre-existing registered worktree on
|
|
6
|
-
* the expected branch was reused instead of force-recreated. The
|
|
7
|
-
* caller logs this so an operator can audit how often the resume
|
|
8
|
-
* path actually fires vs. force-recreate (which is the path taken
|
|
9
|
-
* on every fresh task and on every stale/mismatched leftover).
|
|
10
|
-
* Optional so v0.11-F-era test stubs that omit the flag remain
|
|
11
|
-
* valid; absent or false both mean "fresh-recreate path".
|
|
12
|
-
*/
|
|
13
|
-
resumed?: boolean;
|
|
14
|
-
cleanup(): Promise<void>;
|
|
15
|
-
}
|
|
16
|
-
export type GitExec = (args: string[], cwd: string) => Promise<void>;
|
|
17
|
-
export type WorktreeInspector = (repoPath: string, taskId: string) => Promise<WorktreeInspection | null>;
|
|
18
|
-
export interface PrepareWorktreeOptions {
|
|
19
|
-
repoPath: string;
|
|
20
|
-
/**
|
|
21
|
-
* v0.41-B: optional mirror clone path used exclusively for `git
|
|
22
|
-
* worktree` sub-commands (add/remove/prune). `git fetch` still runs
|
|
23
|
-
* against `repoPath` (which has credentials + the full ref history),
|
|
24
|
-
* so when this is set the runner reads from the operator's clone and
|
|
25
|
-
* writes worktree registrations against a separate path — sidestepping
|
|
26
|
-
* the virtiofs lock conflicts that arise when another process (e.g.
|
|
27
|
-
* Cowork) holds `repoPath` open. Undefined preserves v0.40 byte-for-
|
|
28
|
-
* byte behaviour: every git op runs against `repoPath`.
|
|
29
|
-
*/
|
|
30
|
-
worktreeRepoPath?: string;
|
|
31
|
-
taskId: string;
|
|
32
|
-
branch: string;
|
|
33
|
-
baseBranch: string;
|
|
34
|
-
git?: GitExec;
|
|
35
|
-
/**
|
|
36
|
-
* v0.12-RESUME — override worktree-state inspection for tests.
|
|
37
|
-
* Defaults to the real `inspectExistingWorktree` which shells out
|
|
38
|
-
* via `execa`. Tests inject a stub so the resume-vs-fresh branch is
|
|
39
|
-
* exercisable without standing up a real git repo on disk.
|
|
40
|
-
*/
|
|
41
|
-
inspect?: WorktreeInspector;
|
|
42
|
-
}
|
|
43
|
-
export declare function worktreePath(taskId: string): string;
|
|
44
|
-
/**
|
|
45
|
-
* v0.12-RESUME — capture the state of `worktreePath(taskId)` so the
|
|
46
|
-
* caller can decide between resume (reuse the dir + branch) and
|
|
47
|
-
* force-recreate (the legacy v0.11-F behaviour). Returns null when
|
|
48
|
-
* the directory does not exist.
|
|
49
|
-
*
|
|
50
|
-
* `dirty` is set when `git status --porcelain` inside the worktree
|
|
51
|
-
* lists at least one entry — meaning the prior (crashed) runner left
|
|
52
|
-
* uncommitted edits Claude can pick up from. `branch` is the result
|
|
53
|
-
* of `git rev-parse --abbrev-ref HEAD` — when it matches the
|
|
54
|
-
* task's expected branch the worktree is a valid resume candidate.
|
|
55
|
-
*
|
|
56
|
-
* Best-effort: failures (corrupt worktree, missing .git/worktrees
|
|
57
|
-
* entry, etc.) return `registered: false, branch: null` so the
|
|
58
|
-
* caller falls back to force-recreate rather than crashing.
|
|
59
|
-
*/
|
|
60
|
-
export interface WorktreeInspection {
|
|
61
|
-
path: string;
|
|
62
|
-
registered: boolean;
|
|
63
|
-
branch: string | null;
|
|
64
|
-
dirty: boolean;
|
|
65
|
-
}
|
|
66
|
-
export declare function inspectExistingWorktree(repoPath: string, taskId: string): Promise<WorktreeInspection | null>;
|
|
67
|
-
export declare function prepareTaskWorktree(opts: PrepareWorktreeOptions): Promise<PreparedWorktree>;
|
|
68
|
-
export interface OrphanWorktree {
|
|
69
|
-
path: string;
|
|
70
|
-
taskId: string;
|
|
71
|
-
}
|
|
72
|
-
/** Doctor helper: dirs under workDir() not registered in `git worktree list`. */
|
|
73
|
-
export declare function listOrphanWorktrees(repoPath: string): Promise<OrphanWorktree[]>;
|
|
74
|
-
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/runtime/worktree.ts"],"names":[],"mappings":"AAmCA,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;AAExC,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAMD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAyBD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAgDpC;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CA8D3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,iFAAiF;AACjF,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,EAAE,CAAC,CA+B3B"}
|
package/dist/runtime/worktree.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-task isolated `git worktree` at `~/.cache/acc-runner/work/<task_id>/`
|
|
3
|
-
* so parallel runners on the same machine don't race on the shared
|
|
4
|
-
* clone's branch checkout. Cleaned up on every task completion path.
|
|
5
|
-
*
|
|
6
|
-
* v0.19-T64 — start-point contract. A FRESH task branch MUST be cut from
|
|
7
|
-
* the LATEST integration tip, not a stale local ref. `git fetch` is driven
|
|
8
|
-
* by the caller (task-runner.ts), which fetches origin and passes the
|
|
9
|
-
* freshly-fetched remote-tracking ref (`origin/<integration>`) as
|
|
10
|
-
* `baseBranch`. T-63-1 shipped a PR that conflicted against the real
|
|
11
|
-
* integration because a 13-commit-stale LOCAL ref was used as the base;
|
|
12
|
-
* forking from `origin/<integration>` is the fix. On a caller-side fetch
|
|
13
|
-
* failure the caller falls back to the local ref and emits
|
|
14
|
-
* `runner.stale_base_fallback` — the worktree still starts from whatever
|
|
15
|
-
* `baseBranch` it is handed, so this module never aborts for staleness.
|
|
16
|
-
*
|
|
17
|
-
* v0.12-RESUME — when a prior runner crashed mid-task and the
|
|
18
|
-
* v0.12 stale-running sweep returned the task to queued, a fresh
|
|
19
|
-
* runner that picks the same task back up will find a leftover
|
|
20
|
-
* worktree directory + git registration. The pre-v0.12 behaviour
|
|
21
|
-
* was to force-remove and recreate, throwing away the dead
|
|
22
|
-
* runner's in-progress edits. We now detect this case
|
|
23
|
-
* (`inspectExistingWorktree`), preserve the directory when it is
|
|
24
|
-
* still a valid registration on the expected task branch, and
|
|
25
|
-
* mark the returned `PreparedWorktree` as `resumed: true` so the
|
|
26
|
-
* task-runner can log the resume and Claude picks up from the
|
|
27
|
-
* partially-committed state instead of restarting from baseBranch.
|
|
28
|
-
*/
|
|
29
|
-
import fs from "node:fs/promises";
|
|
30
|
-
import os from "node:os";
|
|
31
|
-
import path from "node:path";
|
|
32
|
-
import { execa } from "execa";
|
|
33
|
-
import { buildEnv } from "../bin-resolve.js";
|
|
34
|
-
// Lazy so tests can override HOME between cases.
|
|
35
|
-
export function workDir() {
|
|
36
|
-
return path.join(os.homedir(), ".cache", "acc-runner", "work");
|
|
37
|
-
}
|
|
38
|
-
function defaultGitExec(args, cwd) {
|
|
39
|
-
return execa("git", args, { cwd, env: buildEnv() }).then(() => undefined);
|
|
40
|
-
}
|
|
41
|
-
export function worktreePath(taskId) {
|
|
42
|
-
return path.join(workDir(), taskId);
|
|
43
|
-
}
|
|
44
|
-
async function pathExists(p) {
|
|
45
|
-
try {
|
|
46
|
-
await fs.access(p);
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
async function removeWorktree(repoPath, target, git) {
|
|
54
|
-
if (await pathExists(target)) {
|
|
55
|
-
// Best-effort: deregister, then nuke residue. Partial cleanup
|
|
56
|
-
// shouldn't fail the surrounding task lifecycle.
|
|
57
|
-
try {
|
|
58
|
-
await git(["worktree", "remove", "--force", target], repoPath);
|
|
59
|
-
}
|
|
60
|
-
catch { /* noop */ }
|
|
61
|
-
await fs.rm(target, { recursive: true, force: true });
|
|
62
|
-
}
|
|
63
|
-
try {
|
|
64
|
-
await git(["worktree", "prune"], repoPath);
|
|
65
|
-
}
|
|
66
|
-
catch { /* noop */ }
|
|
67
|
-
}
|
|
68
|
-
export async function inspectExistingWorktree(repoPath, taskId) {
|
|
69
|
-
const target = worktreePath(taskId);
|
|
70
|
-
if (!(await pathExists(target)))
|
|
71
|
-
return null;
|
|
72
|
-
// `git worktree list --porcelain` runs from the *parent* clone so
|
|
73
|
-
// the registration check sees the canonical list. A target dir
|
|
74
|
-
// that exists on disk but is absent here is an orphan — the
|
|
75
|
-
// caller will treat it as not-registered and force-recreate.
|
|
76
|
-
let registered = false;
|
|
77
|
-
try {
|
|
78
|
-
const { stdout } = await execa("git", ["worktree", "list", "--porcelain"], { cwd: repoPath, env: buildEnv() });
|
|
79
|
-
for (const line of stdout.split(/\r?\n/)) {
|
|
80
|
-
const m = /^worktree (.+)$/.exec(line);
|
|
81
|
-
if (m && path.resolve(m[1]) === path.resolve(target)) {
|
|
82
|
-
registered = true;
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
registered = false;
|
|
89
|
-
}
|
|
90
|
-
let branch = null;
|
|
91
|
-
try {
|
|
92
|
-
const { stdout } = await execa("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: target, env: buildEnv() });
|
|
93
|
-
branch = stdout.trim() || null;
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
branch = null;
|
|
97
|
-
}
|
|
98
|
-
let dirty = false;
|
|
99
|
-
try {
|
|
100
|
-
const { stdout } = await execa("git", ["status", "--porcelain"], { cwd: target, env: buildEnv() });
|
|
101
|
-
dirty = stdout.trim().length > 0;
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
dirty = false;
|
|
105
|
-
}
|
|
106
|
-
return { path: target, registered, branch, dirty };
|
|
107
|
-
}
|
|
108
|
-
export async function prepareTaskWorktree(opts) {
|
|
109
|
-
const git = opts.git ?? defaultGitExec;
|
|
110
|
-
await fs.mkdir(workDir(), { recursive: true });
|
|
111
|
-
const target = worktreePath(opts.taskId);
|
|
112
|
-
// v0.41-B: every `git worktree` sub-command runs against this base,
|
|
113
|
-
// which is the mirror clone when configured and the operator's
|
|
114
|
-
// working clone otherwise. `git fetch` (driven by the caller) stays
|
|
115
|
-
// on opts.repoPath so credentials and ref history come from the
|
|
116
|
-
// working clone; only worktree registration/removal/prune relocate.
|
|
117
|
-
const worktreeBase = opts.worktreeRepoPath ?? opts.repoPath;
|
|
118
|
-
// v0.12-RESUME — if a leftover worktree is registered on the
|
|
119
|
-
// expected branch, preserve it so Claude can pick up where the
|
|
120
|
-
// dead runner left off. Otherwise (orphan dir, wrong branch,
|
|
121
|
-
// corrupt state) fall through to the v0.11-F force-recreate
|
|
122
|
-
// path so the new task starts from a known baseBranch tip.
|
|
123
|
-
//
|
|
124
|
-
// We only enter the resume path when the inspector reports
|
|
125
|
-
// registered=true on the expected branch. The real inspector
|
|
126
|
-
// shells to `git worktree list --porcelain`; tests inject a stub.
|
|
127
|
-
// When `opts.repoPath` is not a real git checkout (test fixtures
|
|
128
|
-
// like "/repo"), the default inspector swallows the `git` error
|
|
129
|
-
// and returns registered=false, preserving v0.11-F's force-
|
|
130
|
-
// recreate semantics for the existing test suite.
|
|
131
|
-
const inspect = opts.inspect ?? inspectExistingWorktree;
|
|
132
|
-
const existing = await inspect(worktreeBase, opts.taskId);
|
|
133
|
-
if (existing && existing.registered && existing.branch === opts.branch) {
|
|
134
|
-
let cleaned = false;
|
|
135
|
-
return {
|
|
136
|
-
path: target,
|
|
137
|
-
resumed: true,
|
|
138
|
-
async cleanup() {
|
|
139
|
-
if (cleaned)
|
|
140
|
-
return;
|
|
141
|
-
cleaned = true;
|
|
142
|
-
await removeWorktree(worktreeBase, target, git);
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
await removeWorktree(worktreeBase, target, git);
|
|
147
|
-
// `-B <branch> <path> <baseBranch>` force-creates the task branch at
|
|
148
|
-
// baseBranch's tip, overwriting a stale ref from a prior crashed run.
|
|
149
|
-
// v0.19 T-64-1: for a FRESH task the caller passes the freshly-fetched
|
|
150
|
-
// origin tip (`origin/<integration>`) as baseBranch — NOT a stale local
|
|
151
|
-
// ref — so the branch starts at the latest integration HEAD. The resume
|
|
152
|
-
// path above returns before reaching here, so a resumed partial branch
|
|
153
|
-
// is never reset to this base.
|
|
154
|
-
await git(["worktree", "add", "-B", opts.branch, target, opts.baseBranch], worktreeBase);
|
|
155
|
-
let cleaned = false;
|
|
156
|
-
return {
|
|
157
|
-
path: target,
|
|
158
|
-
resumed: false,
|
|
159
|
-
async cleanup() {
|
|
160
|
-
if (cleaned)
|
|
161
|
-
return;
|
|
162
|
-
cleaned = true;
|
|
163
|
-
await removeWorktree(worktreeBase, target, git);
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
/** Doctor helper: dirs under workDir() not registered in `git worktree list`. */
|
|
168
|
-
export async function listOrphanWorktrees(repoPath) {
|
|
169
|
-
let entries;
|
|
170
|
-
try {
|
|
171
|
-
entries = await fs.readdir(workDir());
|
|
172
|
-
}
|
|
173
|
-
catch (err) {
|
|
174
|
-
if (err.code === "ENOENT")
|
|
175
|
-
return [];
|
|
176
|
-
throw err;
|
|
177
|
-
}
|
|
178
|
-
const registered = new Set();
|
|
179
|
-
try {
|
|
180
|
-
const { stdout } = await execa("git", ["worktree", "list", "--porcelain"], { cwd: repoPath, env: buildEnv() });
|
|
181
|
-
for (const line of stdout.split(/\r?\n/)) {
|
|
182
|
-
const m = /^worktree (.+)$/.exec(line);
|
|
183
|
-
if (m)
|
|
184
|
-
registered.add(path.resolve(m[1]));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
// Without a usable repo we can't distinguish; surface everything.
|
|
189
|
-
}
|
|
190
|
-
const orphans = [];
|
|
191
|
-
for (const name of entries) {
|
|
192
|
-
const p = path.join(workDir(), name);
|
|
193
|
-
try {
|
|
194
|
-
const stat = await fs.stat(p);
|
|
195
|
-
if (!stat.isDirectory())
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (!registered.has(p))
|
|
202
|
-
orphans.push({ path: p, taskId: name });
|
|
203
|
-
}
|
|
204
|
-
return orphans;
|
|
205
|
-
}
|
|
206
|
-
//# sourceMappingURL=worktree.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/runtime/worktree.ts"],"names":[],"mappings":"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"}
|