@tokenfactory/acc-runner 0.30.0 → 0.33.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 (68) hide show
  1. package/dist/cli.js +3 -2
  2. package/dist/cli.js.map +1 -1
  3. package/dist/doctor.d.ts +19 -0
  4. package/dist/doctor.d.ts.map +1 -1
  5. package/dist/doctor.js +169 -8
  6. package/dist/doctor.js.map +1 -1
  7. package/dist/engines/claude-code.d.ts +9 -0
  8. package/dist/engines/claude-code.d.ts.map +1 -0
  9. package/dist/engines/claude-code.js +95 -0
  10. package/dist/engines/claude-code.js.map +1 -0
  11. package/dist/engines/codex.d.ts +27 -0
  12. package/dist/engines/codex.d.ts.map +1 -0
  13. package/dist/engines/codex.js +178 -0
  14. package/dist/engines/codex.js.map +1 -0
  15. package/dist/engines/registry.d.ts +18 -0
  16. package/dist/engines/registry.d.ts.map +1 -0
  17. package/dist/engines/registry.js +26 -0
  18. package/dist/engines/registry.js.map +1 -0
  19. package/dist/engines/types.d.ts +73 -0
  20. package/dist/engines/types.d.ts.map +1 -0
  21. package/dist/engines/types.js +2 -0
  22. package/dist/engines/types.js.map +1 -0
  23. package/dist/failure-classifier.d.ts +32 -1
  24. package/dist/failure-classifier.d.ts.map +1 -1
  25. package/dist/failure-classifier.js +193 -1
  26. package/dist/failure-classifier.js.map +1 -1
  27. package/dist/git.d.ts +10 -0
  28. package/dist/git.d.ts.map +1 -1
  29. package/dist/git.js +6 -0
  30. package/dist/git.js.map +1 -1
  31. package/dist/login.d.ts +17 -0
  32. package/dist/login.d.ts.map +1 -1
  33. package/dist/login.js +22 -1
  34. package/dist/login.js.map +1 -1
  35. package/dist/pr-body.d.ts +53 -0
  36. package/dist/pr-body.d.ts.map +1 -0
  37. package/dist/pr-body.js +154 -0
  38. package/dist/pr-body.js.map +1 -0
  39. package/dist/prepr-gate.d.ts +132 -2
  40. package/dist/prepr-gate.d.ts.map +1 -1
  41. package/dist/prepr-gate.js +260 -9
  42. package/dist/prepr-gate.js.map +1 -1
  43. package/dist/provider-auth.d.ts +120 -0
  44. package/dist/provider-auth.d.ts.map +1 -0
  45. package/dist/provider-auth.js +184 -0
  46. package/dist/provider-auth.js.map +1 -0
  47. package/dist/review-diff-guard.d.ts +12 -0
  48. package/dist/review-diff-guard.d.ts.map +1 -0
  49. package/dist/review-diff-guard.js +52 -0
  50. package/dist/review-diff-guard.js.map +1 -0
  51. package/dist/review-worktree-cleanup.d.ts +73 -0
  52. package/dist/review-worktree-cleanup.d.ts.map +1 -0
  53. package/dist/review-worktree-cleanup.js +103 -0
  54. package/dist/review-worktree-cleanup.js.map +1 -0
  55. package/dist/runtime/reviewer.d.ts.map +1 -1
  56. package/dist/runtime/reviewer.js +72 -29
  57. package/dist/runtime/reviewer.js.map +1 -1
  58. package/dist/runtime/worktree.d.ts.map +1 -1
  59. package/dist/runtime/worktree.js +8 -3
  60. package/dist/runtime/worktree.js.map +1 -1
  61. package/dist/task-runner.d.ts +1 -8
  62. package/dist/task-runner.d.ts.map +1 -1
  63. package/dist/task-runner.js +65 -66
  64. package/dist/task-runner.js.map +1 -1
  65. package/dist/watch.d.ts.map +1 -1
  66. package/dist/watch.js +30 -3
  67. package/dist/watch.js.map +1 -1
  68. package/package.json +1 -1
@@ -32,14 +32,167 @@ import { buildEnv } from "./bin-resolve.js";
32
32
  */
33
33
  export const PREPR_GATES = ["typecheck", "lint", "build", "test"];
34
34
  // ─────────────────────────────────────────────────────────────────────────────
35
+ // V96 (R4/R5): scope + binary/NUL pure helpers
36
+ // ─────────────────────────────────────────────────────────────────────────────
37
+ /**
38
+ * Text-source extensions the NUL/binary check scans. An allowlist (never a
39
+ * binary denylist) so genuine binary assets — images, fonts, the design export —
40
+ * are never false-positives. Kept in sync with scripts/ci/check-no-binary-source.mjs
41
+ * (the CI backstop for the SAME defect class); the runner package cannot import
42
+ * that .mjs, so the list is duplicated per the standing cross-package convention.
43
+ */
44
+ export const TEXT_EXTENSIONS = new Set([
45
+ ".ts", ".tsx", ".mts", ".cts",
46
+ ".js", ".jsx", ".mjs", ".cjs",
47
+ ".json", ".jsonc",
48
+ ".sql",
49
+ ".md", ".mdx", ".txt",
50
+ ".css", ".scss", ".html",
51
+ ".yml", ".yaml", ".toml",
52
+ ".sh", ".env",
53
+ ]);
54
+ /** True when `p` has a text-source extension the NUL check scans. */
55
+ export function isTextSourcePath(p) {
56
+ return TEXT_EXTENSIONS.has(path.extname(p).toLowerCase());
57
+ }
58
+ /** Offset of the first NUL byte in `buf`, or -1 if there is none. */
59
+ export function firstNulOffset(buf) {
60
+ return buf.indexOf(0);
61
+ }
62
+ /** 1-based {line, col} of byte `offset` within `buf` (col counts bytes). */
63
+ export function lineColOf(buf, offset) {
64
+ let line = 1;
65
+ let lineStart = 0;
66
+ for (let i = 0; i < offset && i < buf.length; i++) {
67
+ if (buf[i] === 0x0a) {
68
+ line++;
69
+ lineStart = i + 1;
70
+ }
71
+ }
72
+ return { line, col: offset - lineStart + 1 };
73
+ }
74
+ /**
75
+ * Build the log-safe failure message for a NUL hit. Names the file, the byte
76
+ * offset, and the 1-based line:col — the exact pointer the reviewer needed for
77
+ * PR #1059 (a single NUL byte burned two review cycles).
78
+ */
79
+ export function formatNulFailure(hit) {
80
+ return [
81
+ `raw NUL byte in staged text source: ${hit.path}:${hit.line}:${hit.col} (byte offset ${hit.offset})`,
82
+ "git treats a file with a NUL byte as BINARY, so the diff renders as an opaque",
83
+ "blob and the reviewer cannot review it (this blocked V82 / PR #1059). tsc +",
84
+ "eslint accept a NUL inside a string, so typecheck/lint/build will NOT catch it.",
85
+ "Fix: replace the raw NUL byte with the \\u0000 escape sequence (or a non-control",
86
+ "delimiter). UTF-16-encoded files trip this too — re-save as UTF-8.",
87
+ ].join("\n");
88
+ }
89
+ /**
90
+ * Convert one `allowed`-list glob into a RegExp anchored to a full repo-relative
91
+ * path. Semantics:
92
+ * - `**` matches any run of chars INCLUDING `/`;
93
+ * - `*` matches any run of chars EXCLUDING `/` (within one path segment);
94
+ * - `?` matches a single non-`/` char;
95
+ * - a pattern ending in `/` (or a bare directory with no wildcard) matches
96
+ * everything beneath that directory prefix;
97
+ * - every other char is matched literally.
98
+ */
99
+ export function globToRegExp(glob) {
100
+ const g = glob.trim();
101
+ // Directory-prefix form: `foo/bar/` → everything under it.
102
+ if (g.endsWith("/")) {
103
+ return new RegExp("^" + escapeRegexLiteral(g) + ".*$");
104
+ }
105
+ let re = "";
106
+ for (let i = 0; i < g.length; i++) {
107
+ const c = g[i];
108
+ if (c === "*") {
109
+ if (g[i + 1] === "*") {
110
+ re += ".*";
111
+ i++;
112
+ }
113
+ else {
114
+ re += "[^/]*";
115
+ }
116
+ }
117
+ else if (c === "?") {
118
+ re += "[^/]";
119
+ }
120
+ else {
121
+ re += escapeRegexLiteral(c);
122
+ }
123
+ }
124
+ return new RegExp("^" + re + "$");
125
+ }
126
+ function escapeRegexLiteral(s) {
127
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
128
+ }
129
+ /**
130
+ * True when `file` (repo-relative) matches ANY of `globs`, OR when a wildcard-free
131
+ * glob names a directory that `file` sits beneath (`api/_lib` matches
132
+ * `api/_lib/x.ts`). Fail-open on an empty glob list — a task that declares no
133
+ * scope is treated as "everything allowed" (the caller gates on non-empty).
134
+ */
135
+ export function matchesAllowedGlobs(file, globs) {
136
+ const f = file.trim();
137
+ if (globs.length === 0)
138
+ return true;
139
+ for (const raw of globs) {
140
+ const g = raw.trim();
141
+ if (!g)
142
+ continue;
143
+ if (globToRegExp(g).test(f))
144
+ return true;
145
+ // Wildcard-free directory prefix: `api/_lib` allows `api/_lib/**`.
146
+ if (!/[*?]/.test(g) && f.startsWith(g.endsWith("/") ? g : `${g}/`))
147
+ return true;
148
+ }
149
+ return false;
150
+ }
151
+ /** Repo-relative staged paths that match NONE of the allowed globs. */
152
+ export function scopeViolations(files, globs) {
153
+ if (globs.length === 0)
154
+ return [];
155
+ return files.filter((f) => f && !matchesAllowedGlobs(f, globs));
156
+ }
157
+ /**
158
+ * Resolve whether a scope violation BLOCKS the PR. Precedence:
159
+ * 1. explicit `deps.scopeEnforce`, else
160
+ * 2. the `ACC_PREPR_SCOPE_ENFORCE` env (`1/true/yes/on` → enforce), else
161
+ * 3. `false` — advisory/shadow (defaults ship OFF; enforcement is opt-in).
162
+ */
163
+ export function scopeEnforceResolved(explicit, env) {
164
+ if (typeof explicit === "boolean")
165
+ return explicit;
166
+ const v = env.ACC_PREPR_SCOPE_ENFORCE?.trim().toLowerCase();
167
+ if (v === undefined || v === "")
168
+ return false;
169
+ return !(v === "0" || v === "false" || v === "no" || v === "off");
170
+ }
171
+ // ─────────────────────────────────────────────────────────────────────────────
35
172
  // Pure helpers
36
173
  // ─────────────────────────────────────────────────────────────────────────────
37
174
  const OUTPUT_TAIL = 4000;
38
- /** Escape-hatch flag. Matches the truthy convention in anthropic-auth.ts. */
175
+ /** Escape-hatch flag. Matches the truthy convention in provider-auth.ts. */
39
176
  export function preprSkipRequested(env) {
40
177
  const v = env.ACC_RUNNER_SKIP_PREPR?.trim().toLowerCase();
41
178
  return v === "1" || v === "true" || v === "yes" || v === "on";
42
179
  }
180
+ /**
181
+ * Resolve whether a migration-lint ERROR blocks the PR. Precedence:
182
+ * 1. explicit `deps.migrationLintBlocking` (the resolved org knob), else
183
+ * 2. the `ACC_MIGRATION_LINT_BLOCKING` env (`1/true/yes/on` → blocking), else
184
+ * 3. `false` — shadow (defaults ship OFF; blocking is an explicit opt-in).
185
+ * Matches the org `migration_lint_blocking` default of `false` (shadow), so
186
+ * un-wired callers get the same effective default as wired ones.
187
+ */
188
+ export function migrationLintBlockingResolved(explicit, env) {
189
+ if (typeof explicit === "boolean")
190
+ return explicit;
191
+ const v = env.ACC_MIGRATION_LINT_BLOCKING?.trim().toLowerCase();
192
+ if (v === undefined || v === "")
193
+ return false;
194
+ return !(v === "0" || v === "false" || v === "no" || v === "off");
195
+ }
43
196
  // ─────────────────────────────────────────────────────────────────────────────
44
197
  // Default I/O implementations
45
198
  // ─────────────────────────────────────────────────────────────────────────────
@@ -91,6 +244,23 @@ async function defaultListChangedMigrations(workdir, baseRef) {
91
244
  .map((s) => s.trim())
92
245
  .filter((s) => s.endsWith(".sql"));
93
246
  }
247
+ async function defaultListStagedFiles(workdir, baseRef) {
248
+ if (!baseRef)
249
+ return [];
250
+ // `<base>...HEAD` (merge-base range) so only files THIS branch added/changed
251
+ // are checked — never files the base already carried. reject:false + exitCode
252
+ // guard: a missing base ref yields no files rather than throwing.
253
+ const result = await execa("git", ["diff", "--name-only", "--diff-filter=ACMR", `${baseRef}...HEAD`], { cwd: workdir, env: buildEnv(), reject: false });
254
+ if (result.exitCode !== 0)
255
+ return [];
256
+ return (result.stdout ?? "")
257
+ .split("\n")
258
+ .map((s) => s.trim())
259
+ .filter((s) => s.length > 0);
260
+ }
261
+ async function defaultReadFileBytes(workdir, file) {
262
+ return fs.readFile(path.join(workdir, file));
263
+ }
94
264
  async function defaultRunMigrationLint(workdir, files) {
95
265
  const script = path.join(workdir, "scripts", "ci", "migration-lint.mjs");
96
266
  const result = await execa("node", [script, ...files], {
@@ -120,9 +290,74 @@ export async function runPreprGate(workdir, deps = {}) {
120
290
  }
121
291
  const readScripts = deps.readScripts ?? defaultReadScripts;
122
292
  const runGate = deps.runGate ?? defaultRunGate;
123
- const scripts = await readScripts(workdir);
124
293
  const ran = [];
125
294
  const absent = [];
295
+ let scopeShadow;
296
+ // V96 (R4/R5): staged-file checks run FIRST — they are cheap and catch the
297
+ // exact classes typecheck/lint/build cannot (a NUL byte tsc accepts inside a
298
+ // string; an out-of-scope edit). Gated on baseRef / injected dep so the unit
299
+ // suite (which provides neither) never shells out to git.
300
+ if (deps.listStagedFiles || deps.baseRef) {
301
+ const listStagedFiles = deps.listStagedFiles ?? defaultListStagedFiles;
302
+ const readFileBytes = deps.readFileBytes ?? defaultReadFileBytes;
303
+ const staged = await listStagedFiles(workdir, deps.baseRef);
304
+ // (a) BINARY/NUL check — always-on structural guard (not a knob). Any staged
305
+ // text-extension file that git will treat as binary (a raw NUL byte, or
306
+ // UTF-16 which is riddled with NULs) FAILS the gate with file + byte offset.
307
+ ran.push("nul-check");
308
+ for (const file of staged) {
309
+ if (!isTextSourcePath(file))
310
+ continue;
311
+ let buf;
312
+ try {
313
+ buf = await readFileBytes(workdir, file);
314
+ }
315
+ catch {
316
+ continue; // unreadable (e.g. deleted after diff) — not our failure to raise
317
+ }
318
+ const offset = firstNulOffset(buf);
319
+ if (offset >= 0) {
320
+ const { line, col } = lineColOf(buf, offset);
321
+ const hit = { path: file, offset, line, col };
322
+ return {
323
+ ok: false,
324
+ skipped: false,
325
+ ran,
326
+ absent,
327
+ failure: {
328
+ gate: "nul-check",
329
+ exitCode: 1,
330
+ outputTail: formatNulFailure(hit),
331
+ },
332
+ };
333
+ }
334
+ }
335
+ // (b) SCOPE check — staged files vs the task's `allowed` globs. Only when the
336
+ // task declares a scope (non-empty globs). Enforcement is a DEFAULT-OFF knob:
337
+ // ON → HALT (fail gate); OFF → advisory (scopeShadow, PR still opens).
338
+ const globs = (deps.allowedGlobs ?? []).filter((g) => g && g.trim().length > 0);
339
+ if (globs.length > 0) {
340
+ const offending = scopeViolations(staged, globs);
341
+ if (offending.length > 0) {
342
+ ran.push("scope");
343
+ const detail = `staged file(s) outside the task's allowed scope:\n` +
344
+ offending.map((f) => ` - ${f}`).join("\n") +
345
+ `\nallowed globs:\n` +
346
+ globs.map((g) => ` - ${g}`).join("\n");
347
+ if (scopeEnforceResolved(deps.scopeEnforce, env)) {
348
+ return {
349
+ ok: false,
350
+ skipped: false,
351
+ ran,
352
+ absent,
353
+ failure: { gate: "scope", exitCode: 1, outputTail: detail.slice(-OUTPUT_TAIL) },
354
+ };
355
+ }
356
+ scopeShadow = { offending, outputTail: detail.slice(-OUTPUT_TAIL) };
357
+ }
358
+ }
359
+ }
360
+ const scripts = await readScripts(workdir);
126
361
  for (const gate of PREPR_GATES) {
127
362
  if (!scripts[gate]) {
128
363
  absent.push(gate);
@@ -154,20 +389,36 @@ export async function runPreprGate(workdir, deps = {}) {
154
389
  ran.push("migration-lint");
155
390
  const { exitCode, output } = await runMigrationLint(workdir, migrations);
156
391
  if (exitCode !== 0) {
392
+ const blocking = migrationLintBlockingResolved(deps.migrationLintBlocking, env);
393
+ if (blocking) {
394
+ // Blocking mode: a lint ERROR fails the gate — no PR is opened and the
395
+ // linter output lands in the runner log via failure.outputTail.
396
+ return {
397
+ ok: false,
398
+ skipped: false,
399
+ ran,
400
+ absent,
401
+ failure: {
402
+ gate: "migration-lint",
403
+ exitCode,
404
+ outputTail: output.slice(-OUTPUT_TAIL),
405
+ },
406
+ };
407
+ }
408
+ // Shadow mode: advisory only — surface the findings for logging but do
409
+ // NOT block the PR. (The linter itself exits 0 on warning-only findings,
410
+ // so reaching here means a genuine lint ERROR that shadow week tolerates.)
157
411
  return {
158
- ok: false,
412
+ ok: true,
159
413
  skipped: false,
160
414
  ran,
161
415
  absent,
162
- failure: {
163
- gate: "migration-lint",
164
- exitCode,
165
- outputTail: output.slice(-OUTPUT_TAIL),
166
- },
416
+ migrationLintShadow: { exitCode, outputTail: output.slice(-OUTPUT_TAIL) },
417
+ scopeShadow,
167
418
  };
168
419
  }
169
420
  }
170
421
  }
171
- return { ok: true, skipped: false, ran, absent };
422
+ return { ok: true, skipped: false, ran, absent, scopeShadow };
172
423
  }
173
424
  //# sourceMappingURL=prepr-gate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepr-gate.js","sourceRoot":"","sources":["../src/prepr-gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prepr-gate.js","sourceRoot":"","sources":["../src/prepr-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Centralised resolution of how the spawned
3
+ * `claude` CLI authenticates with Anthropic.
4
+ *
5
+ * Claude Code authenticates *strictly* via the `ANTHROPIC_API_KEY`
6
+ * environment variable (or an apiKeyHelper) — it has no `--api-key` flag;
7
+ * passing one fails with `error: unknown option '--api-key'`. So "passing
8
+ * the API key to claude" means making sure the variable is present in the
9
+ * spawned subprocess's environment.
10
+ *
11
+ * When ANTHROPIC_API_KEY is set the CLI bills against the API account, which
12
+ * has no per-session usage cap. When it is absent the CLI falls back to the
13
+ * operator's interactive OAuth session, which is subject to the 429 session
14
+ * caps this change exists to avoid.
15
+ *
16
+ * M4 (ENGINE-CODEX): this module was renamed anthropic-auth.ts →
17
+ * provider-auth.ts and extended to cover the OpenAI Codex CLI as well, which
18
+ * has TWO auth channels (see §0.1.5 of the multi-model plan): an `api-key`
19
+ * mode driven by `OPENAI_API_KEY` (keychain/env) and a `subscription` mode
20
+ * driven by a stored ChatGPT login session. The Anthropic helpers are
21
+ * unchanged (byte-identical) so existing call sites keep their behaviour.
22
+ */
23
+ export type AnthropicAuthMode = "api-key" | "interactive-session";
24
+ /** Trimmed ANTHROPIC_API_KEY from `env`, or "" when unset/blank. */
25
+ export declare function anthropicApiKey(env?: NodeJS.ProcessEnv): string;
26
+ /**
27
+ * Opt-in claude-config isolation. Even with ANTHROPIC_API_KEY
28
+ * set, the Claude CLI prefers a stored claude.ai OAuth login when one exists —
29
+ * the observed cause of 429 session caps on a key-configured runner. Pointing
30
+ * the spawned claude at an isolated CLAUDE_CONFIG_DIR (no stored login) leaves
31
+ * the env key as the only credential, forcing API-key auth. Opt-in via
32
+ * ACC_RUNNER_ISOLATE_CLAUDE_CONFIG because the behaviour needs live-runner
33
+ * validation before becoming default.
34
+ */
35
+ export declare function claudeConfigIsolationEnabled(env?: NodeJS.ProcessEnv): boolean;
36
+ /** Runner-owned claude config dir used when isolation is enabled. */
37
+ export declare function isolatedClaudeConfigDir(env?: NodeJS.ProcessEnv): string;
38
+ /**
39
+ * `"api-key"` when ANTHROPIC_API_KEY is set (non-blank), else
40
+ * `"interactive-session"`.
41
+ */
42
+ export declare function resolveAuthMode(env?: NodeJS.ProcessEnv): AnthropicAuthMode;
43
+ /**
44
+ * Returns `base` with ANTHROPIC_API_KEY explicitly forwarded (trimmed) when
45
+ * set, so every claude spawn site authenticates identically regardless of how
46
+ * `base` was assembled. A passthrough of `base` when the key is absent — the
47
+ * CLI then uses the operator's interactive OAuth session.
48
+ */
49
+ export declare function withAnthropicAuth(base?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
50
+ /** One-line, human-readable description of an auth mode for banners/checks. */
51
+ export declare function describeAuthMode(mode: AnthropicAuthMode): string;
52
+ /**
53
+ * Precedence hint for the banner / doctor. Returns null when
54
+ * there's nothing to add (interactive-session mode is already self-explanatory
55
+ * via describeAuthMode). In api-key mode it tells the operator either that
56
+ * isolation is forcing the key, or — if not isolated — how to stop a claude.ai
57
+ * login from shadowing the key and causing 429s.
58
+ */
59
+ export declare function authPrecedenceHint(env?: NodeJS.ProcessEnv): string | null;
60
+ /** How the codex CLI authenticates for a given spawn. */
61
+ export type CodexAuthMode = "api-key" | "subscription";
62
+ /**
63
+ * Preference resolved from `auth_preference` (plan §0.1.5). `subscription_first`
64
+ * starts on the subscription session and spills to the api-key on a cap-hit;
65
+ * `api_key_first` starts on the key. Defaults to `subscription_first` — the
66
+ * program's cost-saving default — so an unset preference behaves as the plan
67
+ * specifies.
68
+ */
69
+ export type CodexAuthPreference = "subscription_first" | "api_key_first";
70
+ /**
71
+ * The per-provider keychain account under the frozen `acc-runner` service.
72
+ * FROZEN-CONTRACT EXTENSION (Track-A note): this ADDS a namespaced account
73
+ * (`provider:openai`) alongside the existing `default` session entry — the
74
+ * session schema in keychain.ts is untouched, so a Track-A review only needs
75
+ * to bless the new account name, not a shape change. The value is the raw
76
+ * OPENAI_API_KEY string (never a JSON blob), so it round-trips through keytar
77
+ * without colliding with the StoredSession JSON at `default`.
78
+ */
79
+ export declare const OPENAI_KEYCHAIN_ACCOUNT: "provider:openai";
80
+ /** Trimmed OPENAI_API_KEY from `env`, or "" when unset/blank. */
81
+ export declare function openaiApiKey(env?: NodeJS.ProcessEnv): string;
82
+ /**
83
+ * Read the OPENAI_API_KEY from the OS keychain (per-provider account). Returns
84
+ * "" when absent, keytar is unavailable (headless Linux without libsecret), or
85
+ * the entry is empty. Async because keychain access is — the sync spawn path
86
+ * (`withOpenAiAuth`) only ever reads the env-present key, exactly like the
87
+ * Anthropic path; the keychain is consulted by startup/doctor which can await.
88
+ */
89
+ export declare function openaiApiKeyFromKeychain(): Promise<string>;
90
+ /**
91
+ * Resolve the `auth_preference` string into a typed preference. Accepts the
92
+ * env-string forms and the DB spelling; anything unknown/blank falls back to
93
+ * the `subscription_first` default.
94
+ */
95
+ export declare function resolveCodexAuthPreference(raw: string | null | undefined): CodexAuthPreference;
96
+ /**
97
+ * The auth mode a codex spawn should START in, given the preference and whether
98
+ * an api key is present. `subscription_first` uses subscription; `api_key_first`
99
+ * uses the key when one is available (else subscription). This is the FIRST
100
+ * attempt only — the spill to api-key on a `subscription_exhausted` cap-hit is
101
+ * driven by the (future, M5) task-runner orchestration, which re-invokes with
102
+ * mode "api-key" explicitly.
103
+ */
104
+ export declare function initialCodexAuthMode(preference: CodexAuthPreference, hasApiKey: boolean): CodexAuthMode;
105
+ /** One-line, human-readable description of a codex auth mode for banners/checks. */
106
+ export declare function describeCodexAuthMode(mode: CodexAuthMode): string;
107
+ /**
108
+ * Augment `base` for a codex spawn in the given auth mode:
109
+ * - "api-key": OPENAI_API_KEY is forwarded (trimmed) so codex bills the
110
+ * key. A passthrough when the key is absent — codex then
111
+ * errors on missing auth, surfaced as `auth_expired`.
112
+ * - "subscription": OPENAI_API_KEY is REMOVED from the environment so codex
113
+ * cannot silently bill the key and instead uses the stored
114
+ * ChatGPT login (the mirror of the claude config-isolation
115
+ * concern: a stray key must not shadow the subscription we
116
+ * deliberately chose to try first).
117
+ * Never mutates `base`; returns a shallow copy.
118
+ */
119
+ export declare function withOpenAiAuth(mode: CodexAuthMode, base?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
120
+ //# sourceMappingURL=provider-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-auth.d.ts","sourceRoot":"","sources":["../src/provider-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,qBAAqB,CAAC;AAElE,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAGT;AAED,qEAAqE;AACrE,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,iBAAiB,CAEvF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAAC,UAAU,CAc1F;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAIhE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,IAAI,CASf;AAiBD,yDAAyD;AACzD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,cAAc,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,GAAG,eAAe,CAAC;AAEzE;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,EAAG,iBAA0B,CAAC;AAElE,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAEzE;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAYhE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7B,mBAAmB,CAMrB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,mBAAmB,EAC/B,SAAS,EAAE,OAAO,GACjB,aAAa,CAGf;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAIjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,aAAa,EACnB,IAAI,GAAE,MAAM,CAAC,UAAwB,GACpC,MAAM,CAAC,UAAU,CAUnB"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Centralised resolution of how the spawned
3
+ * `claude` CLI authenticates with Anthropic.
4
+ *
5
+ * Claude Code authenticates *strictly* via the `ANTHROPIC_API_KEY`
6
+ * environment variable (or an apiKeyHelper) — it has no `--api-key` flag;
7
+ * passing one fails with `error: unknown option '--api-key'`. So "passing
8
+ * the API key to claude" means making sure the variable is present in the
9
+ * spawned subprocess's environment.
10
+ *
11
+ * When ANTHROPIC_API_KEY is set the CLI bills against the API account, which
12
+ * has no per-session usage cap. When it is absent the CLI falls back to the
13
+ * operator's interactive OAuth session, which is subject to the 429 session
14
+ * caps this change exists to avoid.
15
+ *
16
+ * M4 (ENGINE-CODEX): this module was renamed anthropic-auth.ts →
17
+ * provider-auth.ts and extended to cover the OpenAI Codex CLI as well, which
18
+ * has TWO auth channels (see §0.1.5 of the multi-model plan): an `api-key`
19
+ * mode driven by `OPENAI_API_KEY` (keychain/env) and a `subscription` mode
20
+ * driven by a stored ChatGPT login session. The Anthropic helpers are
21
+ * unchanged (byte-identical) so existing call sites keep their behaviour.
22
+ */
23
+ import os from "node:os";
24
+ import path from "node:path";
25
+ import { RUNNER_KEYCHAIN_SERVICE } from "./types.js";
26
+ /** Trimmed ANTHROPIC_API_KEY from `env`, or "" when unset/blank. */
27
+ export function anthropicApiKey(env = process.env) {
28
+ return (env.ANTHROPIC_API_KEY ?? "").trim();
29
+ }
30
+ /**
31
+ * Opt-in claude-config isolation. Even with ANTHROPIC_API_KEY
32
+ * set, the Claude CLI prefers a stored claude.ai OAuth login when one exists —
33
+ * the observed cause of 429 session caps on a key-configured runner. Pointing
34
+ * the spawned claude at an isolated CLAUDE_CONFIG_DIR (no stored login) leaves
35
+ * the env key as the only credential, forcing API-key auth. Opt-in via
36
+ * ACC_RUNNER_ISOLATE_CLAUDE_CONFIG because the behaviour needs live-runner
37
+ * validation before becoming default.
38
+ */
39
+ export function claudeConfigIsolationEnabled(env = process.env) {
40
+ const v = (env.ACC_RUNNER_ISOLATE_CLAUDE_CONFIG ?? "").trim().toLowerCase();
41
+ return v === "1" || v === "true" || v === "yes" || v === "on";
42
+ }
43
+ /** Runner-owned claude config dir used when isolation is enabled. */
44
+ export function isolatedClaudeConfigDir(env = process.env) {
45
+ const override = (env.ACC_RUNNER_CLAUDE_CONFIG_DIR ?? "").trim();
46
+ return override || path.join(os.homedir(), ".acc-runner", "claude-config");
47
+ }
48
+ /**
49
+ * `"api-key"` when ANTHROPIC_API_KEY is set (non-blank), else
50
+ * `"interactive-session"`.
51
+ */
52
+ export function resolveAuthMode(env = process.env) {
53
+ return anthropicApiKey(env) ? "api-key" : "interactive-session";
54
+ }
55
+ /**
56
+ * Returns `base` with ANTHROPIC_API_KEY explicitly forwarded (trimmed) when
57
+ * set, so every claude spawn site authenticates identically regardless of how
58
+ * `base` was assembled. A passthrough of `base` when the key is absent — the
59
+ * CLI then uses the operator's interactive OAuth session.
60
+ */
61
+ export function withAnthropicAuth(base = process.env) {
62
+ const key = anthropicApiKey(base);
63
+ if (!key)
64
+ return base;
65
+ const next = { ...base, ANTHROPIC_API_KEY: key };
66
+ // When isolation is opted in and the operator hasn't already
67
+ // pinned a config dir, point claude at a runner-owned dir so a stored
68
+ // claude.ai login can't shadow the API key. Never clobber an explicit value.
69
+ if (claudeConfigIsolationEnabled(base) &&
70
+ !(base.CLAUDE_CONFIG_DIR ?? "").trim()) {
71
+ next.CLAUDE_CONFIG_DIR = isolatedClaudeConfigDir(base);
72
+ }
73
+ return next;
74
+ }
75
+ /** One-line, human-readable description of an auth mode for banners/checks. */
76
+ export function describeAuthMode(mode) {
77
+ return mode === "api-key"
78
+ ? "api-key (ANTHROPIC_API_KEY set — no session cap)"
79
+ : "interactive-session (no ANTHROPIC_API_KEY — subject to 429 session caps)";
80
+ }
81
+ /**
82
+ * Precedence hint for the banner / doctor. Returns null when
83
+ * there's nothing to add (interactive-session mode is already self-explanatory
84
+ * via describeAuthMode). In api-key mode it tells the operator either that
85
+ * isolation is forcing the key, or — if not isolated — how to stop a claude.ai
86
+ * login from shadowing the key and causing 429s.
87
+ */
88
+ export function authPrecedenceHint(env = process.env) {
89
+ if (resolveAuthMode(env) !== "api-key")
90
+ return null;
91
+ if (claudeConfigIsolationEnabled(env)) {
92
+ return `claude config isolated at ${isolatedClaudeConfigDir(env)} — API key forced`;
93
+ }
94
+ return ("if you still hit 429 session caps, a claude.ai login is shadowing the API key — " +
95
+ "run `claude /logout` or set ACC_RUNNER_ISOLATE_CLAUDE_CONFIG=1");
96
+ }
97
+ /**
98
+ * The per-provider keychain account under the frozen `acc-runner` service.
99
+ * FROZEN-CONTRACT EXTENSION (Track-A note): this ADDS a namespaced account
100
+ * (`provider:openai`) alongside the existing `default` session entry — the
101
+ * session schema in keychain.ts is untouched, so a Track-A review only needs
102
+ * to bless the new account name, not a shape change. The value is the raw
103
+ * OPENAI_API_KEY string (never a JSON blob), so it round-trips through keytar
104
+ * without colliding with the StoredSession JSON at `default`.
105
+ */
106
+ export const OPENAI_KEYCHAIN_ACCOUNT = "provider:openai";
107
+ /** Trimmed OPENAI_API_KEY from `env`, or "" when unset/blank. */
108
+ export function openaiApiKey(env = process.env) {
109
+ return (env.OPENAI_API_KEY ?? "").trim();
110
+ }
111
+ /**
112
+ * Read the OPENAI_API_KEY from the OS keychain (per-provider account). Returns
113
+ * "" when absent, keytar is unavailable (headless Linux without libsecret), or
114
+ * the entry is empty. Async because keychain access is — the sync spawn path
115
+ * (`withOpenAiAuth`) only ever reads the env-present key, exactly like the
116
+ * Anthropic path; the keychain is consulted by startup/doctor which can await.
117
+ */
118
+ export async function openaiApiKeyFromKeychain() {
119
+ try {
120
+ const mod = (await import("keytar"));
121
+ const k = mod.default ?? mod;
122
+ const raw = await k.getPassword(RUNNER_KEYCHAIN_SERVICE, OPENAI_KEYCHAIN_ACCOUNT);
123
+ return (raw ?? "").trim();
124
+ }
125
+ catch {
126
+ return "";
127
+ }
128
+ }
129
+ /**
130
+ * Resolve the `auth_preference` string into a typed preference. Accepts the
131
+ * env-string forms and the DB spelling; anything unknown/blank falls back to
132
+ * the `subscription_first` default.
133
+ */
134
+ export function resolveCodexAuthPreference(raw) {
135
+ const v = (raw ?? "").trim().toLowerCase();
136
+ if (v === "api_key_first" || v === "api-key-first" || v === "api_key") {
137
+ return "api_key_first";
138
+ }
139
+ return "subscription_first";
140
+ }
141
+ /**
142
+ * The auth mode a codex spawn should START in, given the preference and whether
143
+ * an api key is present. `subscription_first` uses subscription; `api_key_first`
144
+ * uses the key when one is available (else subscription). This is the FIRST
145
+ * attempt only — the spill to api-key on a `subscription_exhausted` cap-hit is
146
+ * driven by the (future, M5) task-runner orchestration, which re-invokes with
147
+ * mode "api-key" explicitly.
148
+ */
149
+ export function initialCodexAuthMode(preference, hasApiKey) {
150
+ if (preference === "api_key_first")
151
+ return hasApiKey ? "api-key" : "subscription";
152
+ return "subscription";
153
+ }
154
+ /** One-line, human-readable description of a codex auth mode for banners/checks. */
155
+ export function describeCodexAuthMode(mode) {
156
+ return mode === "api-key"
157
+ ? "api-key (OPENAI_API_KEY set — billed to the platform key, no session cap)"
158
+ : "subscription (ChatGPT login session — subject to plan session/usage caps)";
159
+ }
160
+ /**
161
+ * Augment `base` for a codex spawn in the given auth mode:
162
+ * - "api-key": OPENAI_API_KEY is forwarded (trimmed) so codex bills the
163
+ * key. A passthrough when the key is absent — codex then
164
+ * errors on missing auth, surfaced as `auth_expired`.
165
+ * - "subscription": OPENAI_API_KEY is REMOVED from the environment so codex
166
+ * cannot silently bill the key and instead uses the stored
167
+ * ChatGPT login (the mirror of the claude config-isolation
168
+ * concern: a stray key must not shadow the subscription we
169
+ * deliberately chose to try first).
170
+ * Never mutates `base`; returns a shallow copy.
171
+ */
172
+ export function withOpenAiAuth(mode, base = process.env) {
173
+ const next = { ...base };
174
+ if (mode === "api-key") {
175
+ const key = openaiApiKey(base);
176
+ if (key)
177
+ next.OPENAI_API_KEY = key;
178
+ return next;
179
+ }
180
+ // subscription: strip the key so codex uses the ChatGPT login session.
181
+ delete next.OPENAI_API_KEY;
182
+ return next;
183
+ }
184
+ //# sourceMappingURL=provider-auth.js.map