@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.
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +169 -8
- package/dist/doctor.js.map +1 -1
- package/dist/engines/claude-code.d.ts +9 -0
- package/dist/engines/claude-code.d.ts.map +1 -0
- package/dist/engines/claude-code.js +95 -0
- package/dist/engines/claude-code.js.map +1 -0
- package/dist/engines/codex.d.ts +27 -0
- package/dist/engines/codex.d.ts.map +1 -0
- package/dist/engines/codex.js +178 -0
- package/dist/engines/codex.js.map +1 -0
- package/dist/engines/registry.d.ts +18 -0
- package/dist/engines/registry.d.ts.map +1 -0
- package/dist/engines/registry.js +26 -0
- package/dist/engines/registry.js.map +1 -0
- package/dist/engines/types.d.ts +73 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +2 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/failure-classifier.d.ts +32 -1
- package/dist/failure-classifier.d.ts.map +1 -1
- package/dist/failure-classifier.js +193 -1
- package/dist/failure-classifier.js.map +1 -1
- package/dist/git.d.ts +10 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +6 -0
- package/dist/git.js.map +1 -1
- package/dist/login.d.ts +17 -0
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +22 -1
- package/dist/login.js.map +1 -1
- package/dist/pr-body.d.ts +53 -0
- package/dist/pr-body.d.ts.map +1 -0
- package/dist/pr-body.js +154 -0
- package/dist/pr-body.js.map +1 -0
- package/dist/prepr-gate.d.ts +132 -2
- package/dist/prepr-gate.d.ts.map +1 -1
- package/dist/prepr-gate.js +260 -9
- package/dist/prepr-gate.js.map +1 -1
- package/dist/provider-auth.d.ts +120 -0
- package/dist/provider-auth.d.ts.map +1 -0
- package/dist/provider-auth.js +184 -0
- package/dist/provider-auth.js.map +1 -0
- package/dist/review-diff-guard.d.ts +12 -0
- package/dist/review-diff-guard.d.ts.map +1 -0
- package/dist/review-diff-guard.js +52 -0
- package/dist/review-diff-guard.js.map +1 -0
- package/dist/review-worktree-cleanup.d.ts +73 -0
- package/dist/review-worktree-cleanup.d.ts.map +1 -0
- package/dist/review-worktree-cleanup.js +103 -0
- package/dist/review-worktree-cleanup.js.map +1 -0
- package/dist/runtime/reviewer.d.ts.map +1 -1
- package/dist/runtime/reviewer.js +72 -29
- package/dist/runtime/reviewer.js.map +1 -1
- package/dist/runtime/worktree.d.ts.map +1 -1
- package/dist/runtime/worktree.js +8 -3
- package/dist/runtime/worktree.js.map +1 -1
- package/dist/task-runner.d.ts +1 -8
- package/dist/task-runner.d.ts.map +1 -1
- package/dist/task-runner.js +65 -66
- package/dist/task-runner.js.map +1 -1
- package/dist/watch.d.ts.map +1 -1
- package/dist/watch.js +30 -3
- package/dist/watch.js.map +1 -1
- package/package.json +1 -1
package/dist/prepr-gate.js
CHANGED
|
@@ -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
|
|
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:
|
|
412
|
+
ok: true,
|
|
159
413
|
skipped: false,
|
|
160
414
|
ran,
|
|
161
415
|
absent,
|
|
162
|
-
|
|
163
|
-
|
|
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
|
package/dist/prepr-gate.js.map
CHANGED
|
@@ -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
|