@tokenfactory/acc-runner 0.41.3 → 0.41.4

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.
@@ -1,16 +1,15 @@
1
+ /** Prepend the EXTRA_PATHS not already present to a given PATH string. */
2
+ export declare function augmentedPathFrom(pathValue: string | undefined): string;
1
3
  /**
2
- * Binary path resolution for launchd-launched acc-runner processes.
3
- *
4
- * launchd strips the shell PATH to /usr/bin:/bin:/usr/sbin:/sbin, omitting
5
- * /opt/homebrew/bin and /usr/local/bin where Homebrew installs git and gh.
6
- * All execa("git"/"gh", ...) calls must use buildEnv() instead of bare
7
- * process.env so the binaries are resolvable under launchd supervision.
8
- */
9
- /**
10
- * Returns process.env with PATH augmented to include Homebrew bin dirs.
11
- * Memoized — safe to call on every execa invocation.
4
+ * Returns process.env with PATH augmented to include the extra bin dirs.
12
5
  *
13
6
  * execa("git", args, { cwd, env: buildEnv() })
14
7
  */
15
8
  export declare function buildEnv(): NodeJS.ProcessEnv;
9
+ /**
10
+ * Like buildEnv(), but augments the PATH of an ARBITRARY base env (preserving
11
+ * every other var). Use when a caller already composed an env — e.g. the claude
12
+ * engine's withAnthropicAuth(...) — and just needs its PATH made launchd-safe.
13
+ */
14
+ export declare function withAugmentedPath(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
16
15
  //# sourceMappingURL=bin-resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bin-resolve.d.ts","sourceRoot":"","sources":["../src/bin-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAqBH;;;;;GAKG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAAC,UAAU,CAE5C"}
1
+ {"version":3,"file":"bin-resolve.d.ts","sourceRoot":"","sources":["../src/bin-resolve.ts"],"names":[],"mappings":"AAyBA,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKvE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAAC,UAAU,CAE5C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAE3E"}
@@ -2,34 +2,46 @@
2
2
  * Binary path resolution for launchd-launched acc-runner processes.
3
3
  *
4
4
  * launchd strips the shell PATH to /usr/bin:/bin:/usr/sbin:/sbin, omitting
5
- * /opt/homebrew/bin and /usr/local/bin where Homebrew installs git and gh.
6
- * All execa("git"/"gh", ...) calls must use buildEnv() instead of bare
7
- * process.env so the binaries are resolvable under launchd supervision.
5
+ * /opt/homebrew/bin and /usr/local/bin where Homebrew installs git and gh, AND
6
+ * ~/.local/bin where the native Claude Code installer puts `claude`. All
7
+ * execa("git"/"gh"/"claude", ...) calls must run with an augmented PATH instead
8
+ * of bare process.env so the binaries are resolvable under launchd supervision.
9
+ *
10
+ * v0.41.4: ~/.local/bin was added after a launchd-supervised runner could not
11
+ * find `claude` at all (its PATH lacked ~/.local/bin), whose health probe then
12
+ * latched a sticky env_broken quarantine.
8
13
  */
14
+ import os from "node:os";
15
+ import path from "node:path";
9
16
  /** Directories prepended when not already in PATH. */
10
17
  const EXTRA_PATHS = [
11
18
  "/opt/homebrew/bin", // Apple Silicon Homebrew
12
19
  "/opt/homebrew/sbin",
13
20
  "/usr/local/bin", // Intel Homebrew / MacPorts
14
21
  "/usr/local/sbin",
22
+ path.join(os.homedir(), ".local", "bin"), // native `claude` install
15
23
  ];
16
- let _augmented = null;
17
- function augmentedPath() {
18
- if (_augmented !== null)
19
- return _augmented;
20
- const existing = process.env.PATH ?? "/usr/bin:/bin:/usr/sbin:/sbin";
24
+ /** Prepend the EXTRA_PATHS not already present to a given PATH string. */
25
+ export function augmentedPathFrom(pathValue) {
26
+ const existing = pathValue ?? "/usr/bin:/bin:/usr/sbin:/sbin";
21
27
  const parts = existing.split(":");
22
28
  const extras = EXTRA_PATHS.filter((p) => !parts.includes(p));
23
- _augmented = extras.length > 0 ? `${extras.join(":")}:${existing}` : existing;
24
- return _augmented;
29
+ return extras.length > 0 ? `${extras.join(":")}:${existing}` : existing;
25
30
  }
26
31
  /**
27
- * Returns process.env with PATH augmented to include Homebrew bin dirs.
28
- * Memoized — safe to call on every execa invocation.
32
+ * Returns process.env with PATH augmented to include the extra bin dirs.
29
33
  *
30
34
  * execa("git", args, { cwd, env: buildEnv() })
31
35
  */
32
36
  export function buildEnv() {
33
- return { ...process.env, PATH: augmentedPath() };
37
+ return { ...process.env, PATH: augmentedPathFrom(process.env.PATH) };
38
+ }
39
+ /**
40
+ * Like buildEnv(), but augments the PATH of an ARBITRARY base env (preserving
41
+ * every other var). Use when a caller already composed an env — e.g. the claude
42
+ * engine's withAnthropicAuth(...) — and just needs its PATH made launchd-safe.
43
+ */
44
+ export function withAugmentedPath(env) {
45
+ return { ...env, PATH: augmentedPathFrom(env.PATH) };
34
46
  }
35
47
  //# sourceMappingURL=bin-resolve.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bin-resolve.js","sourceRoot":"","sources":["../src/bin-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,sDAAsD;AACtD,MAAM,WAAW,GAAG;IAClB,mBAAmB,EAAI,yBAAyB;IAChD,oBAAoB;IACpB,gBAAgB,EAAO,4BAA4B;IACnD,iBAAiB;CAClB,CAAC;AAEF,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC,SAAS,aAAa;IACpB,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,+BAA+B,CAAC;IACrE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,UAAU,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9E,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"bin-resolve.js","sourceRoot":"","sources":["../src/bin-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,sDAAsD;AACtD,MAAM,WAAW,GAAG;IAClB,mBAAmB,EAAI,yBAAyB;IAChD,oBAAoB;IACpB,gBAAgB,EAAO,4BAA4B;IACnD,iBAAiB;IACjB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,0BAA0B;CACrE,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB,CAAC,SAA6B;IAC7D,MAAM,QAAQ,GAAG,SAAS,IAAI,+BAA+B,CAAC;IAC9D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAsB;IACtD,OAAO,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AACvD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/engines/claude-code.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAoC,MAAM,YAAY,CAAC;AAIhF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAKjE;AAoED,eAAO,MAAM,gBAAgB,EAAE,WAU9B,CAAC"}
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/engines/claude-code.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAoC,MAAM,YAAY,CAAC;AAIhF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAKjE;AA0ED,eAAO,MAAM,gBAAgB,EAAE,WAU9B,CAAC"}
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { execa } from "execa";
11
11
  import { withAnthropicAuth } from "../provider-auth.js";
12
+ import { buildEnv, withAugmentedPath } from "../bin-resolve.js";
12
13
  import { classifyClaudeExit } from "../failure-classifier.js";
13
14
  import { parseClaudeJson } from "../cost-pricing.js";
14
15
  const BINARY = "claude";
@@ -24,9 +25,13 @@ export function buildClaudeArgs(modelId) {
24
25
  args.push("--model", trimmed);
25
26
  return args;
26
27
  }
27
- /** withAnthropicAuth forwards ANTHROPIC_API_KEY (trimmed) when set — see src/provider-auth.ts. */
28
+ /**
29
+ * withAnthropicAuth forwards ANTHROPIC_API_KEY (trimmed) when set — see
30
+ * src/provider-auth.ts. v0.41.4: PATH is augmented (withAugmentedPath) so
31
+ * `claude` resolves under launchd, whose PATH omits ~/.local/bin.
32
+ */
28
33
  function claudeCodeEnv(base = process.env) {
29
- return withAnthropicAuth(base);
34
+ return withAugmentedPath(withAnthropicAuth(base));
30
35
  }
31
36
  function spawnClaudeCode(opts) {
32
37
  // --dangerously-skip-permissions: bypass claude's per-edit approval prompts.
@@ -61,7 +66,9 @@ async function claudeCodeHealthProbe() {
61
66
  const res = await execa(BINARY, ["--version"], {
62
67
  reject: false,
63
68
  timeout: 5_000,
64
- env: process.env,
69
+ // v0.41.4: augmented PATH so the probe finds `claude` under launchd
70
+ // (~/.local/bin) — a not-found probe was latching a sticky quarantine.
71
+ env: buildEnv(),
65
72
  });
66
73
  if (res.exitCode === 0) {
67
74
  return { ok: true, detail: (res.stdout || "").trim().slice(0, 200) || "claude --version ok" };
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/engines/claude-code.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/engines/claude-code.ts"],"names":[],"mappings":"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"}
@@ -34,20 +34,24 @@ export declare class SingletonLockHeldError extends Error {
34
34
  */
35
35
  export declare function canonicalRepoPath(repoPath: string): string;
36
36
  /**
37
- * `<cache>/runner.<hash>.lock`. The hash is derived from the canonical repo
38
- * path AND the runner identity (v1.02-A), so two distinct ACC_RUNNER_IDs on
39
- * one repo get distinct lock files and coexist. An empty `runnerId` keeps the
40
- * pre-v1.02 hash (repo path alone) so a runner without ACC_RUNNER_ID still
41
- * detects a pre-upgrade holder for the same repo.
37
+ * `<cache>/runner.<hash>.lock`. v0.41.4: the hash is derived from the runner
38
+ * IDENTITY alone ACC_RUNNER_ID when set, else the shared no-id key — NOT the
39
+ * repo path. Task assignment is per identity, so two processes sharing an
40
+ * identity contend no matter which checkout they run from; keying on identity
41
+ * makes them collide. Distinct ACC_RUNNER_IDs still get distinct lock files
42
+ * (and distinct namespaced cache dirs), so they coexist. `repoPath` is kept in
43
+ * the signature (and stored in the lock file by the caller) purely so doctor
44
+ * and the duplicate banner can name the holder's checkout.
42
45
  */
43
- export declare function singletonLockPath(repoPath: string, runnerId?: string): string;
46
+ export declare function singletonLockPath(_repoPath: string, runnerId?: string): string;
44
47
  /**
45
- * Acquire the single-instance lock for `repoPath` under `runnerId`. Throws
46
- * SingletonLockHeldError when a *live* process already holds the lock for the
47
- * same (canonical repo path, runner identity) pair. A stale lock (dead pid,
48
- * our own pid, or a corrupt file) is reclaimed with a stderr breadcrumb and
49
- * then re-acquired. A different `runnerId` keys a different lock file, so two
50
- * distinct identities on one repo never contend (v1.02-A).
48
+ * Acquire the single-instance lock for `runnerId` (v0.41.4: the key is the
49
+ * identity, not `repoPath`). Throws SingletonLockHeldError when a *live*
50
+ * process already holds the lock for the same identity. A stale lock (dead
51
+ * pid, our own pid, or a corrupt file) is reclaimed with a stderr breadcrumb
52
+ * and then re-acquired. A different `runnerId` keys a different lock file, so
53
+ * two distinct identities on one host never contend; two runners sharing an
54
+ * identity (e.g. both with no ACC_RUNNER_ID) collide regardless of checkout.
51
55
  */
52
56
  export declare function acquireSingletonLock(repoPath: string, pid?: number, runnerId?: string): Promise<SingletonLock>;
53
57
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"singleton.d.ts","sourceRoot":"","sources":["../../src/runtime/singleton.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE9E;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,MAAM,EAAE,iBAAiB;aACzB,QAAQ,EAAE,MAAM;gBADhB,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,MAAM;CAQnC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAA4B,GACrC,MAAM,CAKR;AA4CD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAoB,EACzB,QAAQ,GAAE,MAA4B,GACrC,OAAO,CAAC,aAAa,CAAC,CA+CxB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAoB,EAC7B,QAAQ,GAAE,MAA4B,GACrC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAMnC;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,MAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAqBnB"}
1
+ {"version":3,"file":"singleton.d.ts","sourceRoot":"","sources":["../../src/runtime/singleton.ts"],"names":[],"mappings":"AAwDA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE9E;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,MAAM,EAAE,iBAAiB;aACzB,QAAQ,EAAE,MAAM;gBADhB,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,MAAM;CAQnC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAG/B,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAA4B,GACrC,MAAM,CAIR;AA4CD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAoB,EACzB,QAAQ,GAAE,MAA4B,GACrC,OAAO,CAAC,aAAa,CAAC,CA+CxB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAoB,EAC7B,QAAQ,GAAE,MAA4B,GACrC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAMnC;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,MAAoB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAqBnB"}
@@ -12,21 +12,31 @@
12
12
  * an existing lock whose pid is dead is reclaimed with a log line, while a
13
13
  * live holder for the SAME repo path is rejected loudly.
14
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.
15
+ * v1.02-A concurrent runners per host. The lock is keyed by runner
16
+ * identity so two DISTINCT ACC_RUNNER_IDs can serve work on one machine at
17
+ * the same time (each also gets its own cache dir via `cacheDir()`, so no
18
+ * worktree/ref race). The identity deliberately reads ACC_RUNNER_ID directly
19
+ * (never the minted acc-eph id, which is random per process and would make
20
+ * the lock never collide).
20
21
  *
21
- * v1.02-Aconcurrent runners per host. The lock is now keyed by
22
- * (canonical repo path + runner identity), not the repo path alone, so two
23
- * DISTINCT ACC_RUNNER_IDs can serve the same repo on one machine at the same
24
- * time (each gets its own cache dir via `cacheDir()`, so no worktree/ref
25
- * race). A runner with NO ACC_RUNNER_ID keeps the legacy repo-path-only key
26
- * two un-identified runners on one repo still collide, which is the
27
- * original duplicate-runner footgun the lock exists to catch. The identity
28
- * deliberately reads ACC_RUNNER_ID directly (never the minted acc-eph id,
29
- * which is random per process and would make the lock never collide).
22
+ * v0.41.4 (claim-livelock hardening) the key is the runner IDENTITY, NOT
23
+ * the repo path. Task assignment is per identity: `dispatch` writes
24
+ * `acc.tasks.runner_id`, and the claim scan lists work via
25
+ * `acc.list_assigned_queued_tasks(p_runner_id)`. Two processes that share an
26
+ * identity therefore receive the SAME assigned tasks and fight over the same
27
+ * DB file-locks REGARDLESS of which local checkout each runs from — exactly
28
+ * the incident this hardening addresses (two clones of one repo, both with no
29
+ * ACC_RUNNER_ID, both claiming as the one keychain identity). Keying on the
30
+ * repo *path* let those two coexist and livelock; keying on identity makes
31
+ * them collide. Consequences:
32
+ * - Every runner with NO ACC_RUNNER_ID shares one host-wide lock (they all
33
+ * resolve to the single keychain identity), so at most one un-identified
34
+ * runner runs per host. To run a second runner — for a second project or
35
+ * added throughput — give it a distinct ACC_RUNNER_ID (its cache dir
36
+ * auto-isolates, and it claims its own task stream).
37
+ * - `repoPath` is still recorded in the lock file and surfaced in the
38
+ * duplicate banner / doctor, so the operator can see which checkout the
39
+ * holder serves — it is just no longer part of the key.
30
40
  */
31
41
  import fs from "node:fs";
32
42
  import fsp from "node:fs/promises";
@@ -35,6 +45,13 @@ import crypto from "node:crypto";
35
45
  import { cacheDir } from "./cache-dir.js";
36
46
  import { isProcessAlive } from "./locks.js";
37
47
  import { PACKAGE_VERSION } from "../pkg-version.js";
48
+ /**
49
+ * v0.41.4: the singleton key for a runner with NO ACC_RUNNER_ID. All
50
+ * un-identified runners on a host resolve to the single keychain identity, so
51
+ * they must share ONE lock — the NUL prefix keeps it clear of any real
52
+ * ACC_RUNNER_ID value.
53
+ */
54
+ const NO_ID_SINGLETON_KEY = "\0__acc_runner_no_id_shared__";
38
55
  /**
39
56
  * v1.02-A: the runner identity that keys the singleton lock. ACC_RUNNER_ID
40
57
  * when set, else "" (legacy repo-path-only key). Never the minted acc-eph id.
@@ -68,15 +85,20 @@ export function canonicalRepoPath(repoPath) {
68
85
  }
69
86
  }
70
87
  /**
71
- * `<cache>/runner.<hash>.lock`. The hash is derived from the canonical repo
72
- * path AND the runner identity (v1.02-A), so two distinct ACC_RUNNER_IDs on
73
- * one repo get distinct lock files and coexist. An empty `runnerId` keeps the
74
- * pre-v1.02 hash (repo path alone) so a runner without ACC_RUNNER_ID still
75
- * detects a pre-upgrade holder for the same repo.
88
+ * `<cache>/runner.<hash>.lock`. v0.41.4: the hash is derived from the runner
89
+ * IDENTITY alone ACC_RUNNER_ID when set, else the shared no-id key — NOT the
90
+ * repo path. Task assignment is per identity, so two processes sharing an
91
+ * identity contend no matter which checkout they run from; keying on identity
92
+ * makes them collide. Distinct ACC_RUNNER_IDs still get distinct lock files
93
+ * (and distinct namespaced cache dirs), so they coexist. `repoPath` is kept in
94
+ * the signature (and stored in the lock file by the caller) purely so doctor
95
+ * and the duplicate banner can name the holder's checkout.
76
96
  */
77
- export function singletonLockPath(repoPath, runnerId = singletonRunnerId()) {
78
- const canonical = canonicalRepoPath(repoPath);
79
- const key = runnerId ? `${canonical}\0${runnerId}` : canonical;
97
+ export function singletonLockPath(
98
+ // v0.41.4: retained for signature stability (callers pass repoPath
99
+ // positionally) but no longer part of the key the key is the identity.
100
+ _repoPath, runnerId = singletonRunnerId()) {
101
+ const key = runnerId || NO_ID_SINGLETON_KEY;
80
102
  const hash = crypto.createHash("sha1").update(key).digest("hex").slice(0, 12);
81
103
  return path.join(cacheDir(), `runner.${hash}.lock`);
82
104
  }
@@ -128,12 +150,13 @@ function makeLock(file, repoPath, pid) {
128
150
  };
129
151
  }
130
152
  /**
131
- * Acquire the single-instance lock for `repoPath` under `runnerId`. Throws
132
- * SingletonLockHeldError when a *live* process already holds the lock for the
133
- * same (canonical repo path, runner identity) pair. A stale lock (dead pid,
134
- * our own pid, or a corrupt file) is reclaimed with a stderr breadcrumb and
135
- * then re-acquired. A different `runnerId` keys a different lock file, so two
136
- * distinct identities on one repo never contend (v1.02-A).
153
+ * Acquire the single-instance lock for `runnerId` (v0.41.4: the key is the
154
+ * identity, not `repoPath`). Throws SingletonLockHeldError when a *live*
155
+ * process already holds the lock for the same identity. A stale lock (dead
156
+ * pid, our own pid, or a corrupt file) is reclaimed with a stderr breadcrumb
157
+ * and then re-acquired. A different `runnerId` keys a different lock file, so
158
+ * two distinct identities on one host never contend; two runners sharing an
159
+ * identity (e.g. both with no ACC_RUNNER_ID) collide regardless of checkout.
137
160
  */
138
161
  export async function acquireSingletonLock(repoPath, pid = process.pid, runnerId = singletonRunnerId()) {
139
162
  const canonical = canonicalRepoPath(repoPath);
@@ -1 +1 @@
1
- {"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../src/runtime/singleton.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"singleton.js","sourceRoot":"","sources":["../../src/runtime/singleton.ts"],"names":[],"mappings":"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"}
@@ -69,6 +69,16 @@ export interface RunTaskDeps {
69
69
  * worktree side-effect lands.
70
70
  */
71
71
  acquireLock?: (taskId: string) => Promise<TaskLock>;
72
+ /**
73
+ * v0.41.4 (claim-livelock hardening): given the conflicting task ids from a
74
+ * failed `claim_task_with_locks`, release the file-locks held by holders that
75
+ * are demonstrably dead/stale (non-running, or no `last_runner_signal_at`
76
+ * heartbeat within STALE_LOCK_RECLAIM_MS) and return the ids reclaimed. The
77
+ * caller retries the claim once when this returns a non-empty list. Defaults
78
+ * to `defaultReclaimStaleConflictLocks` (reads `acc.tasks` liveness, calls
79
+ * `acc.release_task_locks`); tests inject a stub.
80
+ */
81
+ reclaimStaleConflictLocks?: (conflicts: string[]) => Promise<string[]>;
72
82
  /**
73
83
  * v0.11-F: provision an isolated git worktree at
74
84
  * `~/.cache/acc-runner/work/<task_id>/`. All subsequent git ops +
@@ -284,6 +294,17 @@ export declare function ensureWorktreeNodeModules(workdir: string, repoPath: str
284
294
  install?: (cwd: string) => Promise<void>;
285
295
  env?: NodeJS.ProcessEnv;
286
296
  }): Promise<EnsureWorktreeDepsResult>;
297
+ /**
298
+ * v0.41.4 default self-heal for a claim conflict: read the conflicting holder
299
+ * tasks' liveness and release the locks of holders that are dead/stale — a
300
+ * holder whose task is no longer `running`, or whose heartbeat
301
+ * (`coalesce(last_runner_signal_at, updated_at)`) is older than
302
+ * STALE_LOCK_RECLAIM_MS. Returns the reclaimed task ids. Best-effort: any read
303
+ * or release error is swallowed (returns what it managed to reclaim) so a claim
304
+ * conflict never turns into a task crash. `release_task_locks` is authorized
305
+ * for the holder lock's bound user, which is the identity the runner holds.
306
+ */
307
+ export declare function defaultReclaimStaleConflictLocks(supabase: RunTaskDeps["supabase"], conflicts: string[], nowMs: number): Promise<string[]>;
287
308
  /**
288
309
  * v0.63 T-63-1: knobs for the silent-claude-unavailability response. Defaults
289
310
  * pause + back off + retry on each silent instant-empty exit, growing the
@@ -1 +1 @@
1
- {"version":3,"file":"task-runner.d.ts","sourceRoot":"","sources":["../src/task-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"task-runner.d.ts","sourceRoot":"","sources":["../src/task-runner.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAS,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAmD,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACrH,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEzD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAS/B,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAIL,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC/B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AAMzB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAI1D,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,OAAO,EAAK,MAAM,CAAC;IACnB,KAAK,EAAO,MAAM,CAAC;IACnB,SAAS,EAAG,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,GAAG,EAAE,YAAY,CAAC;IAClB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd;;;;;;;oDAOgD;IAChD,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,iBAAiB,CAAC;IACnE;;;;0CAIsC;IACtC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D;;;;;;OAMG;IACH,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACtE;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9E;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,aAAa,GAAG,IAAI,CAAC;IACzC;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACzD;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,uBAAuB,EAC7B,IAAI,CAAC,EAAE,uBAAuB,KAC3B,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACxC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/E;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC9F;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;CACpF;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACjC,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GACpB,aAAa,GACb,uBAAuB,GACvB,OAAO,GAIP,OAAO,GACP,eAAe,GACf,KAAK,GACL,aAAa,GAKb,YAAY,GACZ,MAAM,GAIN,QAAQ,GAIR,YAAY,CAAC;AAEjB,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,WAAW,GAAG,iBAAiB,GAAG,UAAU,GAAG,SAAS,CAAC;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;qCAEiC;IACjC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAYD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AA+B3D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIhD;AAsBD,iFAAiF;AACjF,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAC;IACnB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AA0ElE;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IACJ,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACpB,GACL,OAAO,CAAC,wBAAwB,CAAC,CAkEnC;AA4BD;;;;;;;;;GASG;AACH,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,EACjC,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BnB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,cAAc,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;CACtB;AAkBD,8EAA8E;AAC9E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,sBAAsB,CAAC,GAAG,IAAI,CAEzF;AAED,yEAAyE;AACzE,wBAAgB,2BAA2B,IAAI,IAAI,CAIlD;AAED,MAAM,WAAW,yBAAyB;IACxC,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,KAAK,EAAE,OAAO,CAAC;IACf,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,yBAAyB,CAgB9E;AA6DD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAU9D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAM3E;AA8ED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAClC,gBAAgB,CAWlB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB/E;AA+KD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,GAChB,iBAAiB,CA41DnB"}
@@ -252,6 +252,60 @@ export async function ensureWorktreeNodeModules(workdir, repoPath, opts = {}) {
252
252
  * claude-code engine (byte-identical); kept as a thin default so `deps`
253
253
  * overrides still work for tests.
254
254
  */
255
+ /**
256
+ * v0.41.4: staleness floor before the runner will reclaim a conflicting
257
+ * holder's file-lock. MUST be >= the server sweep's floor
258
+ * (`acc.sweep_stale_running`, 15 min on `last_runner_signal_at`) so the runner
259
+ * is NEVER more aggressive than the server — releasing a lock a still-live
260
+ * holder legitimately holds would let two runners edit overlapping paths (the
261
+ * exact 2-writer race the lock prevents). A holder heartbeating within this
262
+ * window is left strictly alone; the runner just keeps waiting.
263
+ */
264
+ const STALE_LOCK_RECLAIM_MS = 15 * 60_000;
265
+ /**
266
+ * v0.41.4 default self-heal for a claim conflict: read the conflicting holder
267
+ * tasks' liveness and release the locks of holders that are dead/stale — a
268
+ * holder whose task is no longer `running`, or whose heartbeat
269
+ * (`coalesce(last_runner_signal_at, updated_at)`) is older than
270
+ * STALE_LOCK_RECLAIM_MS. Returns the reclaimed task ids. Best-effort: any read
271
+ * or release error is swallowed (returns what it managed to reclaim) so a claim
272
+ * conflict never turns into a task crash. `release_task_locks` is authorized
273
+ * for the holder lock's bound user, which is the identity the runner holds.
274
+ */
275
+ export async function defaultReclaimStaleConflictLocks(supabase, conflicts, nowMs) {
276
+ if (conflicts.length === 0)
277
+ return [];
278
+ let rows;
279
+ try {
280
+ const { data, error } = await supabase
281
+ .from("tasks")
282
+ .select("id,status,last_runner_signal_at,updated_at")
283
+ .in("id", conflicts);
284
+ if (error || !data)
285
+ return [];
286
+ rows = data;
287
+ }
288
+ catch {
289
+ return [];
290
+ }
291
+ const reclaimed = [];
292
+ for (const row of rows) {
293
+ const signalAt = row.last_runner_signal_at ?? row.updated_at;
294
+ const ageMs = signalAt ? nowMs - new Date(signalAt).getTime() : Number.POSITIVE_INFINITY;
295
+ const stale = row.status !== "running" || ageMs >= STALE_LOCK_RECLAIM_MS;
296
+ if (!stale)
297
+ continue; // live holder — leave its lock alone and keep waiting.
298
+ try {
299
+ const { error } = await supabase.rpc("release_task_locks", { p_task_id: row.id });
300
+ if (!error)
301
+ reclaimed.push(row.id);
302
+ }
303
+ catch {
304
+ /* best-effort — skip this holder */
305
+ }
306
+ }
307
+ return reclaimed;
308
+ }
255
309
  async function defaultHealthProbe() {
256
310
  return engine.healthProbe();
257
311
  }
@@ -807,23 +861,64 @@ export function runTask(taskId, deps) {
807
861
  });
808
862
  return { taskId, status: "failed", phase: "claim_locks", error: msg };
809
863
  }
810
- const claimResult = (claim.data ?? {});
864
+ let claimResult = (claim.data ?? {});
811
865
  if (claimResult.ok !== true) {
812
- const conflicts = Array.isArray(claimResult.conflicts) ? claimResult.conflicts : [];
813
- await appendEvent(deps.supabase, taskId, "log", {
814
- phase: "claim_locks",
815
- stream: "stderr",
816
- conflicts,
817
- message: `file-lock conflict other tasks hold overlapping paths: ${conflicts.join(", ")}`,
818
- runner_id: deps.session.runnerId,
819
- });
820
- const reason = `file-lock conflict with: ${conflicts.join(", ") || "(unknown)"}`;
821
- return {
822
- taskId,
823
- status: "failed",
824
- phase: "claim_locks",
825
- error: reason,
826
- };
866
+ let conflicts = Array.isArray(claimResult.conflicts) ? claimResult.conflicts : [];
867
+ // v0.41.4 (claim-livelock hardening): a conflict against a DEAD/STALE
868
+ // holder is an orphaned lock row — the holder runner died (or its task
869
+ // is no longer running) without releasing. The server sweep clears these
870
+ // on a 15-min floor, but while the sweep lags or is down the claim loops
871
+ // forever (the incident this addresses). Proactively release the locks
872
+ // of demonstrably-dead/stale holders (never a live, heartbeating one —
873
+ // see STALE_LOCK_RECLAIM_MS) and retry the claim ONCE. Skip our own id
874
+ // (the same-task-race branch reports conflicts=[taskId]).
875
+ const reclaimTargets = conflicts.filter((c) => c && c !== taskId);
876
+ const reclaim = deps.reclaimStaleConflictLocks ??
877
+ ((c) => defaultReclaimStaleConflictLocks(deps.supabase, c, Date.now()));
878
+ const reclaimed = reclaimTargets.length > 0 ? await reclaim(reclaimTargets) : [];
879
+ if (reclaimed.length > 0) {
880
+ await appendEvent(deps.supabase, taskId, "log", {
881
+ phase: "claim_locks",
882
+ stream: "stderr",
883
+ message: `reclaimed ${reclaimed.length} stale/dead lock holder(s) [${reclaimed.join(", ")}] — retrying claim`,
884
+ runner_id: deps.session.runnerId,
885
+ });
886
+ void (async () => {
887
+ try {
888
+ await deps.supabase.rpc("log_activity", {
889
+ p_verb: "runner.claim_lock_reclaim",
890
+ p_target_id: deps.session.runnerId,
891
+ p_payload: { task_id: taskId, reclaimed },
892
+ p_target_type: "runner",
893
+ });
894
+ }
895
+ catch { /* best-effort breadcrumb */ }
896
+ })();
897
+ const retry = await deps.supabase.rpc("claim_task_with_locks", {
898
+ p_task_id: taskId,
899
+ p_runner_id: deps.session.runnerId,
900
+ });
901
+ if (!retry.error) {
902
+ claimResult = (retry.data ?? {});
903
+ }
904
+ }
905
+ if (claimResult.ok !== true) {
906
+ conflicts = Array.isArray(claimResult.conflicts) ? claimResult.conflicts : conflicts;
907
+ await appendEvent(deps.supabase, taskId, "log", {
908
+ phase: "claim_locks",
909
+ stream: "stderr",
910
+ conflicts,
911
+ message: `file-lock conflict — other tasks hold overlapping paths: ${conflicts.join(", ")}`,
912
+ runner_id: deps.session.runnerId,
913
+ });
914
+ const reason = `file-lock conflict with: ${conflicts.join(", ") || "(unknown)"}`;
915
+ return {
916
+ taskId,
917
+ status: "failed",
918
+ phase: "claim_locks",
919
+ error: reason,
920
+ };
921
+ }
827
922
  }
828
923
  // v0.6.1 (v0.11-D): every exit path below the successful claim
829
924
  // must release the lock row so the same paths free up for the