@tokenfactory/acc-runner 0.25.1 → 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.
Files changed (162) hide show
  1. package/README.md +77 -4
  2. package/package.json +1 -1
  3. package/dist/anthropic-auth.d.ts +0 -53
  4. package/dist/anthropic-auth.d.ts.map +0 -1
  5. package/dist/anthropic-auth.js +0 -89
  6. package/dist/anthropic-auth.js.map +0 -1
  7. package/dist/bin-resolve.d.ts +0 -16
  8. package/dist/bin-resolve.d.ts.map +0 -1
  9. package/dist/bin-resolve.js +0 -35
  10. package/dist/bin-resolve.js.map +0 -1
  11. package/dist/cli.d.ts +0 -3
  12. package/dist/cli.d.ts.map +0 -1
  13. package/dist/cli.js +0 -128
  14. package/dist/cli.js.map +0 -1
  15. package/dist/config.d.ts +0 -121
  16. package/dist/config.d.ts.map +0 -1
  17. package/dist/config.js +0 -396
  18. package/dist/config.js.map +0 -1
  19. package/dist/cost-pricing.d.ts +0 -130
  20. package/dist/cost-pricing.d.ts.map +0 -1
  21. package/dist/cost-pricing.js +0 -191
  22. package/dist/cost-pricing.js.map +0 -1
  23. package/dist/doctor.d.ts +0 -37
  24. package/dist/doctor.d.ts.map +0 -1
  25. package/dist/doctor.js +0 -658
  26. package/dist/doctor.js.map +0 -1
  27. package/dist/failure-classifier.d.ts +0 -112
  28. package/dist/failure-classifier.d.ts.map +0 -1
  29. package/dist/failure-classifier.js +0 -353
  30. package/dist/failure-classifier.js.map +0 -1
  31. package/dist/gh.d.ts +0 -22
  32. package/dist/gh.d.ts.map +0 -1
  33. package/dist/gh.js +0 -48
  34. package/dist/gh.js.map +0 -1
  35. package/dist/git.d.ts +0 -50
  36. package/dist/git.d.ts.map +0 -1
  37. package/dist/git.js +0 -127
  38. package/dist/git.js.map +0 -1
  39. package/dist/github-client.d.ts +0 -133
  40. package/dist/github-client.d.ts.map +0 -1
  41. package/dist/github-client.js +0 -234
  42. package/dist/github-client.js.map +0 -1
  43. package/dist/keychain.d.ts +0 -21
  44. package/dist/keychain.d.ts.map +0 -1
  45. package/dist/keychain.js +0 -45
  46. package/dist/keychain.js.map +0 -1
  47. package/dist/login.d.ts +0 -12
  48. package/dist/login.d.ts.map +0 -1
  49. package/dist/login.js +0 -133
  50. package/dist/login.js.map +0 -1
  51. package/dist/logout.d.ts +0 -2
  52. package/dist/logout.d.ts.map +0 -1
  53. package/dist/logout.js +0 -31
  54. package/dist/logout.js.map +0 -1
  55. package/dist/mcp-spawn.d.ts +0 -30
  56. package/dist/mcp-spawn.d.ts.map +0 -1
  57. package/dist/mcp-spawn.js +0 -145
  58. package/dist/mcp-spawn.js.map +0 -1
  59. package/dist/messaging.d.ts +0 -49
  60. package/dist/messaging.d.ts.map +0 -1
  61. package/dist/messaging.js +0 -36
  62. package/dist/messaging.js.map +0 -1
  63. package/dist/pkg-version.d.ts +0 -3
  64. package/dist/pkg-version.d.ts.map +0 -1
  65. package/dist/pkg-version.js +0 -20
  66. package/dist/pkg-version.js.map +0 -1
  67. package/dist/profiles/designer-prompt.d.ts +0 -18
  68. package/dist/profiles/designer-prompt.d.ts.map +0 -1
  69. package/dist/profiles/designer-prompt.js +0 -172
  70. package/dist/profiles/designer-prompt.js.map +0 -1
  71. package/dist/profiles/developer-prompt.d.ts +0 -24
  72. package/dist/profiles/developer-prompt.d.ts.map +0 -1
  73. package/dist/profiles/developer-prompt.js +0 -24
  74. package/dist/profiles/developer-prompt.js.map +0 -1
  75. package/dist/profiles/manager-prompt.d.ts +0 -34
  76. package/dist/profiles/manager-prompt.d.ts.map +0 -1
  77. package/dist/profiles/manager-prompt.js +0 -93
  78. package/dist/profiles/manager-prompt.js.map +0 -1
  79. package/dist/profiles/tester-prompt.d.ts +0 -28
  80. package/dist/profiles/tester-prompt.d.ts.map +0 -1
  81. package/dist/profiles/tester-prompt.js +0 -165
  82. package/dist/profiles/tester-prompt.js.map +0 -1
  83. package/dist/prompt.d.ts +0 -38
  84. package/dist/prompt.d.ts.map +0 -1
  85. package/dist/prompt.js +0 -78
  86. package/dist/prompt.js.map +0 -1
  87. package/dist/runtime/cache-dir.d.ts +0 -2
  88. package/dist/runtime/cache-dir.d.ts.map +0 -1
  89. package/dist/runtime/cache-dir.js +0 -15
  90. package/dist/runtime/cache-dir.js.map +0 -1
  91. package/dist/runtime/conflict-resolver.d.ts +0 -65
  92. package/dist/runtime/conflict-resolver.d.ts.map +0 -1
  93. package/dist/runtime/conflict-resolver.js +0 -477
  94. package/dist/runtime/conflict-resolver.js.map +0 -1
  95. package/dist/runtime/expand-args.d.ts +0 -28
  96. package/dist/runtime/expand-args.d.ts.map +0 -1
  97. package/dist/runtime/expand-args.js +0 -50
  98. package/dist/runtime/expand-args.js.map +0 -1
  99. package/dist/runtime/locks.d.ts +0 -21
  100. package/dist/runtime/locks.d.ts.map +0 -1
  101. package/dist/runtime/locks.js +0 -97
  102. package/dist/runtime/locks.js.map +0 -1
  103. package/dist/runtime/provision-mutex.d.ts +0 -37
  104. package/dist/runtime/provision-mutex.d.ts.map +0 -1
  105. package/dist/runtime/provision-mutex.js +0 -67
  106. package/dist/runtime/provision-mutex.js.map +0 -1
  107. package/dist/runtime/quarantine.d.ts +0 -26
  108. package/dist/runtime/quarantine.d.ts.map +0 -1
  109. package/dist/runtime/quarantine.js +0 -50
  110. package/dist/runtime/quarantine.js.map +0 -1
  111. package/dist/runtime/resolution-integrity.d.ts +0 -86
  112. package/dist/runtime/resolution-integrity.d.ts.map +0 -1
  113. package/dist/runtime/resolution-integrity.js +0 -248
  114. package/dist/runtime/resolution-integrity.js.map +0 -1
  115. package/dist/runtime/reviewer.d.ts +0 -81
  116. package/dist/runtime/reviewer.d.ts.map +0 -1
  117. package/dist/runtime/reviewer.js +0 -374
  118. package/dist/runtime/reviewer.js.map +0 -1
  119. package/dist/runtime/rework.d.ts +0 -48
  120. package/dist/runtime/rework.d.ts.map +0 -1
  121. package/dist/runtime/rework.js +0 -136
  122. package/dist/runtime/rework.js.map +0 -1
  123. package/dist/runtime/singleton.d.ts +0 -47
  124. package/dist/runtime/singleton.d.ts.map +0 -1
  125. package/dist/runtime/singleton.js +0 -200
  126. package/dist/runtime/singleton.js.map +0 -1
  127. package/dist/runtime/version-drift.d.ts +0 -31
  128. package/dist/runtime/version-drift.d.ts.map +0 -1
  129. package/dist/runtime/version-drift.js +0 -114
  130. package/dist/runtime/version-drift.js.map +0 -1
  131. package/dist/runtime/worktree.d.ts +0 -74
  132. package/dist/runtime/worktree.d.ts.map +0 -1
  133. package/dist/runtime/worktree.js +0 -206
  134. package/dist/runtime/worktree.js.map +0 -1
  135. package/dist/secrets/inject.d.ts +0 -70
  136. package/dist/secrets/inject.d.ts.map +0 -1
  137. package/dist/secrets/inject.js +0 -102
  138. package/dist/secrets/inject.js.map +0 -1
  139. package/dist/supabase.d.ts +0 -4
  140. package/dist/supabase.d.ts.map +0 -1
  141. package/dist/supabase.js +0 -36
  142. package/dist/supabase.js.map +0 -1
  143. package/dist/task-runner.d.ts +0 -313
  144. package/dist/task-runner.d.ts.map +0 -1
  145. package/dist/task-runner.js +0 -1766
  146. package/dist/task-runner.js.map +0 -1
  147. package/dist/token-provider.d.ts +0 -50
  148. package/dist/token-provider.d.ts.map +0 -1
  149. package/dist/token-provider.js +0 -177
  150. package/dist/token-provider.js.map +0 -1
  151. package/dist/types.d.ts +0 -120
  152. package/dist/types.d.ts.map +0 -1
  153. package/dist/types.js +0 -16
  154. package/dist/types.js.map +0 -1
  155. package/dist/version-check.d.ts +0 -17
  156. package/dist/version-check.d.ts.map +0 -1
  157. package/dist/version-check.js +0 -56
  158. package/dist/version-check.js.map +0 -1
  159. package/dist/watch.d.ts +0 -295
  160. package/dist/watch.d.ts.map +0 -1
  161. package/dist/watch.js +0 -1532
  162. 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"}
@@ -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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"}