@tokenfactory/acc-runner 0.37.1 → 0.37.3

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 CHANGED
@@ -12,6 +12,7 @@ import { logoutCommand } from "./logout.js";
12
12
  import { watchCommand } from "./watch.js";
13
13
  import { doctorCommand } from "./doctor.js";
14
14
  import { clearQuarantine, getQuarantine } from "./runtime/quarantine.js";
15
+ import { runCommitGuardHook } from "./commit-guard.js";
15
16
  import { PROTOCOL_VERSION } from "./types.js";
16
17
  import { PACKAGE_VERSION } from "./pkg-version.js";
17
18
  const program = new Command();
@@ -115,6 +116,29 @@ quarantineCmd
115
116
  process.exitCode = 1;
116
117
  }
117
118
  });
119
+ // RR-4: the git pre-commit hook the runner installs into a
120
+ // task worktree (see commit-guard.ts) re-invokes this hidden subcommand. It
121
+ // scans the STAGED text files and exits non-zero (with an actionable message on
122
+ // stderr) when a NUL byte / invalid UTF-8 / binary-blob-where-text is found, so
123
+ // git aborts the commit and the agent fixes it in-session. Hidden — it is a hook
124
+ // entry point, not an operator command.
125
+ program
126
+ .command("_precommit-guard", { hidden: true })
127
+ .description("Internal: commit-time mechanical guard (pre-commit hook entry).")
128
+ .action(async () => {
129
+ try {
130
+ const result = await runCommitGuardHook();
131
+ if (!result.ok) {
132
+ console.error(result.message);
133
+ process.exitCode = 1;
134
+ }
135
+ }
136
+ catch (err) {
137
+ // Fail OPEN on an internal error: a guard bug must never wedge the agent's
138
+ // ability to commit. The pre-PR gate (prepr-gate.ts) is the backstop.
139
+ console.error(chalk.yellow(`acc-runner commit-guard skipped (internal error): ${err.message}`));
140
+ }
141
+ });
118
142
  program
119
143
  .command("version")
120
144
  .description("Print CLI + protocol versions.")
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ export type CommitDefectKind = "nul-byte" | "invalid-utf8" | "binary-blob";
2
+ export interface CommitDefect {
3
+ /** Repo-relative staged path. */
4
+ path: string;
5
+ kind: CommitDefectKind;
6
+ /** Log-safe, actionable one-liner naming the exact location + fix. */
7
+ detail: string;
8
+ }
9
+ export interface CommitGuardResult {
10
+ /** True when no staged text file carries a mechanical defect. */
11
+ ok: boolean;
12
+ /** Every defect found (all files scanned — the agent fixes them in one pass). */
13
+ defects: CommitDefect[];
14
+ /** The full task-log message printed to the agent when `ok === false`. */
15
+ message: string;
16
+ }
17
+ export interface CommitGuardDeps {
18
+ /** Staged (added/copied/modified/renamed) text-source paths, repo-relative. */
19
+ listStagedTextFiles?: () => Promise<string[]>;
20
+ /** Raw STAGED blob bytes for a path (`git show :path`) — what is being committed. */
21
+ readStagedBytes?: (file: string) => Promise<Buffer>;
22
+ /** Staged text-source paths git's own `--numstat` reports as binary. */
23
+ listBinaryStagedText?: () => Promise<string[]>;
24
+ /** Working directory for the default git seams. Default: process.cwd(). */
25
+ cwd?: string;
26
+ }
27
+ /**
28
+ * Scan one staged file's bytes for a byte-level defect. Order matters: a NUL is
29
+ * reported as `nul-byte` (the specific, common root cause) rather than folded
30
+ * into the generic UTF-8 check. Returns null when the bytes are clean UTF-8.
31
+ */
32
+ export declare function scanBytesForDefects(file: string, buf: Buffer): CommitDefect | null;
33
+ /**
34
+ * Build the task-log message for a set of defects — actionable, log-safe, and
35
+ * shaped like prepr-gate's formatNulFailure so the two guards read the same. The
36
+ * agent sees this on stderr when its `git commit` is rejected, and fixes the
37
+ * named files IN-SESSION before any PR opens.
38
+ */
39
+ export declare function formatCommitGuardMessage(defects: CommitDefect[]): string;
40
+ /**
41
+ * Scan every staged text-source file for a mechanical defect. `ok === false`
42
+ * means the caller (the pre-commit hook) MUST exit non-zero so git aborts the
43
+ * commit. Unreadable files are skipped, not raised (a deleted-after-stage race is
44
+ * not our failure). git's own binary verdict (`--numstat`) is folded in so a
45
+ * corrupted diff git flags as binary is caught even when the byte scan did not.
46
+ */
47
+ export declare function runCommitGuardHook(deps?: CommitGuardDeps): Promise<CommitGuardResult>;
48
+ /** Escape hatch — matches the truthy convention of preprSkipRequested. */
49
+ export declare function commitGuardSkipRequested(env?: NodeJS.ProcessEnv): boolean;
50
+ /**
51
+ * The per-worktree hooks directory: a SIBLING of the worktree (under the cache
52
+ * work dir), never inside it, so the agent's `git add`/`git add -A` can never
53
+ * stage the hook and pollute the PR. Deterministic from the worktree path so the
54
+ * installer and the spawn-env injector agree without threading a task id.
55
+ */
56
+ export declare function commitHooksDirFor(worktreePath: string): string;
57
+ /**
58
+ * The acc-runner CLI entry the hook re-invokes. `process.argv[1]` is the running
59
+ * CLI in production; the import.meta fallback resolves the sibling dist cli.js
60
+ * when argv[1] is unavailable (e.g. an odd launcher).
61
+ */
62
+ export declare function commitGuardCliEntry(): string;
63
+ /**
64
+ * Write the `pre-commit` hook into the worktree's sibling hooks dir and return
65
+ * that dir. Synchronous so the spawn path (defaultSpawnClaude) can install
66
+ * without becoming async. The hook shells to `node <cli> _precommit-guard`,
67
+ * reusing the same node + CLI that runs the runner. Best-effort at the call
68
+ * site: an install failure must not block the task (the pre-PR gate backstops).
69
+ */
70
+ export declare function installCommitGuardSync(worktreePath: string, entry?: string): string;
71
+ /**
72
+ * Ephemeral git config env that points `core.hooksPath` at `hooksDir` for the
73
+ * spawned agent's git ONLY — never a config-file write, so the operator's git
74
+ * config is untouched (git.ts §1). git reads GIT_CONFIG_COUNT/KEY_n/VALUE_n as
75
+ * transient config. Layered on top of `base` (the caller's env).
76
+ */
77
+ export declare function gitConfigHooksEnv(hooksDir: string, base?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
78
+ //# sourceMappingURL=commit-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-guard.d.ts","sourceRoot":"","sources":["../src/commit-guard.ts"],"names":[],"mappings":"AAkDA,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAC;AAE3E,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,EAAE,EAAE,OAAO,CAAC;IACZ,iFAAiF;IACjF,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,qFAAqF;IACrF,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAsBlF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAYxE;AAMD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAiD5B;AAuDD,0EAA0E;AAC1E,wBAAgB,wBAAwB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAGtF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAI5C;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,MAA8B,GACpC,MAAM,CAWR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAM,CAAC,UAAwB,GACpC,MAAM,CAAC,UAAU,CAOnB"}
@@ -0,0 +1,257 @@
1
+ /**
2
+ * RR-4 — commit-time mechanical guard.
3
+ *
4
+ * EVIDENCE: PR #265 was rejected FOUR times for the SAME NUL-byte-corrupted
5
+ * `normalize.ts`. Each rework cycle re-ran, re-committed, and re-pushed the same
6
+ * byte-level defect because nothing blocked the commit that authored it — tsc +
7
+ * eslint both accept a NUL inside a string literal, so the fast gates stayed
8
+ * green and only the slow LLM reviewer (which sees the file as an "opaque binary
9
+ * blob") caught it, one full review round-trip too late. The task dead-lettered
10
+ * at cycle 3 without ever curing the defect.
11
+ *
12
+ * This guard blocks the defect AT COMMIT TIME, inside the agent's own session,
13
+ * so the agent sees an actionable message and fixes it before a PR ever opens.
14
+ * It is wired as a git `pre-commit` hook (see installCommitGuardSync +
15
+ * gitConfigHooksEnv): the hook is pointed at via an EPHEMERAL `core.hooksPath`
16
+ * injected into the spawned agent's environment (GIT_CONFIG_* env), so the CLI
17
+ * never edits the operator's on-disk git config (git.ts §1) and the hook dir
18
+ * lives OUTSIDE the worktree (a sibling under the cache work dir) so the agent
19
+ * can never accidentally `git add` it.
20
+ *
21
+ * The pre-PR NUL scan in prepr-gate.ts (`runPreprGate`) is the LATER backstop —
22
+ * it fails a PR that already carries a NUL. This guard is the EARLIER, in-session
23
+ * stop that keeps the defect out of the commit in the first place. The two share
24
+ * the byte-level helpers (firstNulOffset / lineColOf / isTextSourcePath) so their
25
+ * verdicts can never diverge.
26
+ *
27
+ * Detected defect classes (all on staged text-extension files — an allowlist so
28
+ * genuine binary assets like images/fonts are never false-positives):
29
+ * - nul-byte — a raw 0x00; git renders the file as an opaque binary blob.
30
+ * - invalid-utf8 — bytes that are not valid UTF-8 (latin1 paste, bad re-save);
31
+ * corrupts the diff the reviewer reads.
32
+ * - binary-blob — git's own `--numstat` reports the staged text file as binary
33
+ * (`-`/`-`), i.e. a corrupted diff where text was expected,
34
+ * even when the first-8KiB byte scan did not trip.
35
+ *
36
+ * Escape hatch: ACC_RUNNER_SKIP_COMMIT_GUARD=1 disables installation entirely
37
+ * (mirrors ACC_RUNNER_SKIP_PREPR). Every I/O boundary is an injectable dep so the
38
+ * scan is unit-testable with fixtures and never shells out in unit tests.
39
+ */
40
+ import fs from "node:fs";
41
+ import path from "node:path";
42
+ import { fileURLToPath } from "node:url";
43
+ import { execa } from "execa";
44
+ import { buildEnv } from "./bin-resolve.js";
45
+ import { firstNulOffset, isTextSourcePath, lineColOf } from "./prepr-gate.js";
46
+ // ─────────────────────────────────────────────────────────────────────────────
47
+ // Pure scan
48
+ // ─────────────────────────────────────────────────────────────────────────────
49
+ /**
50
+ * Scan one staged file's bytes for a byte-level defect. Order matters: a NUL is
51
+ * reported as `nul-byte` (the specific, common root cause) rather than folded
52
+ * into the generic UTF-8 check. Returns null when the bytes are clean UTF-8.
53
+ */
54
+ export function scanBytesForDefects(file, buf) {
55
+ const nul = firstNulOffset(buf);
56
+ if (nul >= 0) {
57
+ const { line, col } = lineColOf(buf, nul);
58
+ return {
59
+ path: file,
60
+ kind: "nul-byte",
61
+ detail: `raw NUL byte at ${file}:${line}:${col} (byte offset ${nul}) — git treats the file as BINARY, so its diff is an opaque blob the reviewer cannot read. Replace the raw NUL with the \\u0000 escape sequence (or a non-control delimiter).`,
62
+ };
63
+ }
64
+ try {
65
+ // fatal:true throws on the first invalid UTF-8 sequence (a lossy toString
66
+ // would silently substitute U+FFFD and hide the defect).
67
+ new TextDecoder("utf-8", { fatal: true }).decode(buf);
68
+ }
69
+ catch {
70
+ return {
71
+ path: file,
72
+ kind: "invalid-utf8",
73
+ detail: `invalid UTF-8 in ${file} — the file is not valid UTF-8 (a latin1 paste or a bad re-save), which corrupts the diff the reviewer reads. Re-save the file as UTF-8.`,
74
+ };
75
+ }
76
+ return null;
77
+ }
78
+ /**
79
+ * Build the task-log message for a set of defects — actionable, log-safe, and
80
+ * shaped like prepr-gate's formatNulFailure so the two guards read the same. The
81
+ * agent sees this on stderr when its `git commit` is rejected, and fixes the
82
+ * named files IN-SESSION before any PR opens.
83
+ */
84
+ export function formatCommitGuardMessage(defects) {
85
+ const lines = [
86
+ "COMMIT BLOCKED — acc-runner commit-time mechanical guard (RR-4).",
87
+ "The following staged source file(s) carry byte-level defects that pass",
88
+ "typecheck/lint/build but make the diff unreviewable (this is the exact defect",
89
+ "that got PR #265 rejected four times). Fix them, re-stage, and commit again:",
90
+ "",
91
+ ];
92
+ for (const d of defects)
93
+ lines.push(` • [${d.kind}] ${d.detail}`);
94
+ lines.push("");
95
+ lines.push("To bypass in an emergency, set ACC_RUNNER_SKIP_COMMIT_GUARD=1 (not recommended).");
96
+ return lines.join("\n");
97
+ }
98
+ // ─────────────────────────────────────────────────────────────────────────────
99
+ // The hook body
100
+ // ─────────────────────────────────────────────────────────────────────────────
101
+ /**
102
+ * Scan every staged text-source file for a mechanical defect. `ok === false`
103
+ * means the caller (the pre-commit hook) MUST exit non-zero so git aborts the
104
+ * commit. Unreadable files are skipped, not raised (a deleted-after-stage race is
105
+ * not our failure). git's own binary verdict (`--numstat`) is folded in so a
106
+ * corrupted diff git flags as binary is caught even when the byte scan did not.
107
+ */
108
+ export async function runCommitGuardHook(deps = {}) {
109
+ const cwd = deps.cwd ?? process.cwd();
110
+ const listStagedTextFiles = deps.listStagedTextFiles ?? (() => defaultListStagedTextFiles(cwd));
111
+ const readStagedBytes = deps.readStagedBytes ?? ((f) => defaultReadStagedBytes(cwd, f));
112
+ const listBinaryStagedText = deps.listBinaryStagedText ?? (() => defaultListBinaryStagedText(cwd));
113
+ const defects = [];
114
+ const seen = new Set();
115
+ const staged = await listStagedTextFiles();
116
+ for (const file of staged) {
117
+ if (!isTextSourcePath(file))
118
+ continue;
119
+ let buf;
120
+ try {
121
+ buf = await readStagedBytes(file);
122
+ }
123
+ catch {
124
+ continue; // unreadable (deleted after stage / partial index) — not our raise
125
+ }
126
+ const defect = scanBytesForDefects(file, buf);
127
+ if (defect) {
128
+ defects.push(defect);
129
+ seen.add(file);
130
+ }
131
+ }
132
+ // git's own binary verdict: a text-extension file it renders as binary is a
133
+ // corrupted diff even if the byte scan missed it. Dedup against byte-scan hits.
134
+ let binaryText = [];
135
+ try {
136
+ binaryText = await listBinaryStagedText();
137
+ }
138
+ catch {
139
+ binaryText = [];
140
+ }
141
+ for (const file of binaryText) {
142
+ if (!isTextSourcePath(file) || seen.has(file))
143
+ continue;
144
+ defects.push({
145
+ path: file,
146
+ kind: "binary-blob",
147
+ detail: `${file} — git renders this text file as a BINARY diff (corrupted / non-text content), so the reviewer sees an opaque blob. Re-save it as clean UTF-8 text.`,
148
+ });
149
+ seen.add(file);
150
+ }
151
+ return defects.length === 0
152
+ ? { ok: true, defects: [], message: "" }
153
+ : { ok: false, defects, message: formatCommitGuardMessage(defects) };
154
+ }
155
+ // ─────────────────────────────────────────────────────────────────────────────
156
+ // Default git I/O
157
+ // ─────────────────────────────────────────────────────────────────────────────
158
+ async function defaultListStagedTextFiles(cwd) {
159
+ const result = await execa("git", ["diff", "--cached", "--name-only", "--diff-filter=ACMR"], { cwd, env: buildEnv(), reject: false });
160
+ if (result.exitCode !== 0)
161
+ return [];
162
+ return (result.stdout ?? "")
163
+ .split("\n")
164
+ .map((s) => s.trim())
165
+ .filter((s) => s.length > 0 && isTextSourcePath(s));
166
+ }
167
+ async function defaultReadStagedBytes(cwd, file) {
168
+ // `git show :<path>` reads the STAGED blob (what is being committed), which can
169
+ // differ from the working tree under a partial `git add`. encoding:"buffer"
170
+ // returns raw bytes so a NUL/invalid-UTF-8 survives intact for the scan.
171
+ const result = await execa("git", ["show", `:${file}`], {
172
+ cwd,
173
+ env: buildEnv(),
174
+ encoding: "buffer",
175
+ });
176
+ return result.stdout;
177
+ }
178
+ async function defaultListBinaryStagedText(cwd) {
179
+ // `--numstat` prints `added\tremoved\tpath`; a binary file shows `-\t-\tpath`.
180
+ const result = await execa("git", ["diff", "--cached", "--numstat", "--diff-filter=ACMR"], { cwd, env: buildEnv(), reject: false });
181
+ if (result.exitCode !== 0)
182
+ return [];
183
+ const out = [];
184
+ for (const raw of (result.stdout ?? "").split("\n")) {
185
+ const line = raw.trim();
186
+ if (!line)
187
+ continue;
188
+ const parts = line.split("\t");
189
+ if (parts.length >= 3 && parts[0] === "-" && parts[1] === "-") {
190
+ out.push(parts.slice(2).join("\t").trim());
191
+ }
192
+ }
193
+ return out;
194
+ }
195
+ // ─────────────────────────────────────────────────────────────────────────────
196
+ // Installation + spawn wiring
197
+ // ─────────────────────────────────────────────────────────────────────────────
198
+ /** Escape hatch — matches the truthy convention of preprSkipRequested. */
199
+ export function commitGuardSkipRequested(env = process.env) {
200
+ const v = env.ACC_RUNNER_SKIP_COMMIT_GUARD?.trim().toLowerCase();
201
+ return v === "1" || v === "true" || v === "yes" || v === "on";
202
+ }
203
+ /**
204
+ * The per-worktree hooks directory: a SIBLING of the worktree (under the cache
205
+ * work dir), never inside it, so the agent's `git add`/`git add -A` can never
206
+ * stage the hook and pollute the PR. Deterministic from the worktree path so the
207
+ * installer and the spawn-env injector agree without threading a task id.
208
+ */
209
+ export function commitHooksDirFor(worktreePath) {
210
+ const parent = path.dirname(worktreePath);
211
+ const base = path.basename(worktreePath);
212
+ return path.join(parent, `.acc-commit-hooks-${base}`);
213
+ }
214
+ /**
215
+ * The acc-runner CLI entry the hook re-invokes. `process.argv[1]` is the running
216
+ * CLI in production; the import.meta fallback resolves the sibling dist cli.js
217
+ * when argv[1] is unavailable (e.g. an odd launcher).
218
+ */
219
+ export function commitGuardCliEntry() {
220
+ const argv1 = process.argv[1];
221
+ if (argv1 && argv1.trim())
222
+ return argv1;
223
+ return fileURLToPath(new URL("./cli.js", import.meta.url));
224
+ }
225
+ /**
226
+ * Write the `pre-commit` hook into the worktree's sibling hooks dir and return
227
+ * that dir. Synchronous so the spawn path (defaultSpawnClaude) can install
228
+ * without becoming async. The hook shells to `node <cli> _precommit-guard`,
229
+ * reusing the same node + CLI that runs the runner. Best-effort at the call
230
+ * site: an install failure must not block the task (the pre-PR gate backstops).
231
+ */
232
+ export function installCommitGuardSync(worktreePath, entry = commitGuardCliEntry()) {
233
+ const dir = commitHooksDirFor(worktreePath);
234
+ fs.mkdirSync(dir, { recursive: true });
235
+ const hookPath = path.join(dir, "pre-commit");
236
+ const body = "#!/bin/sh\n" +
237
+ "# acc-runner RR-4 commit-time mechanical guard — see src/commit-guard.ts\n" +
238
+ `exec node ${JSON.stringify(entry)} _precommit-guard\n`;
239
+ fs.writeFileSync(hookPath, body, { mode: 0o755 });
240
+ fs.chmodSync(hookPath, 0o755);
241
+ return dir;
242
+ }
243
+ /**
244
+ * Ephemeral git config env that points `core.hooksPath` at `hooksDir` for the
245
+ * spawned agent's git ONLY — never a config-file write, so the operator's git
246
+ * config is untouched (git.ts §1). git reads GIT_CONFIG_COUNT/KEY_n/VALUE_n as
247
+ * transient config. Layered on top of `base` (the caller's env).
248
+ */
249
+ export function gitConfigHooksEnv(hooksDir, base = process.env) {
250
+ return {
251
+ ...base,
252
+ GIT_CONFIG_COUNT: "1",
253
+ GIT_CONFIG_KEY_0: "core.hooksPath",
254
+ GIT_CONFIG_VALUE_0: hooksDir,
255
+ };
256
+ }
257
+ //# sourceMappingURL=commit-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-guard.js","sourceRoot":"","sources":["../src/commit-guard.ts"],"names":[],"mappings":"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"}
@@ -47,6 +47,16 @@ export interface PreprGateResult {
47
47
  offending: string[];
48
48
  outputTail: string;
49
49
  };
50
+ /**
51
+ * MIGFIX-01: set when the pre-PR auto-renumber (opt-in) renamed a NEW migration
52
+ * to the next contiguous seq before the seq-lint ran. `output` is the
53
+ * renumber tool's log (which seqs moved, how many refs rewrote) — surfaced so
54
+ * the caller can record that the migration was auto-renumbered. Unset when the
55
+ * step is off or was a no-op (the migration was already contiguous).
56
+ */
57
+ migrationRenumbered?: {
58
+ output: string;
59
+ };
50
60
  }
51
61
  export interface PreprGateDeps {
52
62
  /**
@@ -127,6 +137,33 @@ export interface PreprGateDeps {
127
137
  * NUL fixture without a real file.
128
138
  */
129
139
  readFileBytes?: (workdir: string, file: string) => Promise<Buffer>;
140
+ /**
141
+ * MIGFIX-01 knob (DEFAULT OFF). When ON, a NEW migration this branch adds is
142
+ * auto-renumbered to the next contiguous seq (rewriting every in-repo
143
+ * reference) before the migration-lint seq check runs — so a hand-picked
144
+ * gap/collision no longer forces a manual renumber. Precedence mirrors the
145
+ * other knobs: explicit dep, else `ACC_MIGRATION_AUTO_RENUMBER` env, else
146
+ * `false`. Mirrors an org `migration_auto_renumber` knob the task-runner can
147
+ * resolve and pass here.
148
+ */
149
+ autoRenumber?: boolean;
150
+ /**
151
+ * Run the renumber pass over the changed migration files in `workdir`
152
+ * (`node scripts/ci/migration-lint.mjs --renumber <files>`), then report
153
+ * whether it changed the working tree. Default: spawn node + `git status`.
154
+ * Injectable for tests.
155
+ */
156
+ runMigrationRenumber?: (workdir: string, files: string[]) => Promise<{
157
+ changed: boolean;
158
+ output: string;
159
+ }>;
160
+ /**
161
+ * Commit the renumber result so the subsequent push carries it (the migration
162
+ * was already committed before this gate). Default: `git add -A` + a fresh
163
+ * `chore(acc): auto-renumber …` commit (never an amend — a follow-up commit
164
+ * never rewrites already-pushed history). Injectable for tests.
165
+ */
166
+ commitRenumbered?: (workdir: string) => Promise<void>;
130
167
  }
131
168
  /**
132
169
  * Text-source extensions the NUL/binary check scans. An allowlist (never a
@@ -198,6 +235,17 @@ export declare function preprSkipRequested(env: NodeJS.ProcessEnv): boolean;
198
235
  * un-wired callers get the same effective default as wired ones.
199
236
  */
200
237
  export declare function migrationLintBlockingResolved(explicit: boolean | undefined, env: NodeJS.ProcessEnv): boolean;
238
+ /**
239
+ * MIGFIX-01: resolve whether the pre-PR auto-renumber runs. Precedence:
240
+ * 1. explicit `deps.autoRenumber` (the resolved org knob), else
241
+ * 2. the `ACC_MIGRATION_AUTO_RENUMBER` env (`1/true/yes/on` → on), else
242
+ * 3. `false` — OFF (defaults ship OFF; auto-renumber is an explicit opt-in).
243
+ * When ON and this branch adds a migration whose seq is a gap/collision, the
244
+ * runner renumbers it to the next contiguous seq (and rewrites every in-repo
245
+ * reference) BEFORE the seq-lint could hard-fail it — stopping the manual
246
+ * renumber the operator otherwise had to do by hand.
247
+ */
248
+ export declare function autoRenumberResolved(explicit: boolean | undefined, env: NodeJS.ProcessEnv): boolean;
201
249
  /**
202
250
  * Run the repo's own quality gates in `workdir` before a PR is opened.
203
251
  * `ok === false` means the caller MUST NOT open a PR — fail the task with
@@ -1 +1 @@
1
- {"version":3,"file":"prepr-gate.d.ts","sourceRoot":"","sources":["../src/prepr-gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prepr-gate.d.ts","sourceRoot":"","sources":["../src/prepr-gate.ts"],"names":[],"mappings":"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"}
@@ -193,6 +193,24 @@ export function migrationLintBlockingResolved(explicit, env) {
193
193
  return false;
194
194
  return !(v === "0" || v === "false" || v === "no" || v === "off");
195
195
  }
196
+ /**
197
+ * MIGFIX-01: resolve whether the pre-PR auto-renumber runs. Precedence:
198
+ * 1. explicit `deps.autoRenumber` (the resolved org knob), else
199
+ * 2. the `ACC_MIGRATION_AUTO_RENUMBER` env (`1/true/yes/on` → on), else
200
+ * 3. `false` — OFF (defaults ship OFF; auto-renumber is an explicit opt-in).
201
+ * When ON and this branch adds a migration whose seq is a gap/collision, the
202
+ * runner renumbers it to the next contiguous seq (and rewrites every in-repo
203
+ * reference) BEFORE the seq-lint could hard-fail it — stopping the manual
204
+ * renumber the operator otherwise had to do by hand.
205
+ */
206
+ export function autoRenumberResolved(explicit, env) {
207
+ if (typeof explicit === "boolean")
208
+ return explicit;
209
+ const v = env.ACC_MIGRATION_AUTO_RENUMBER?.trim().toLowerCase();
210
+ if (v === undefined || v === "")
211
+ return false;
212
+ return !(v === "0" || v === "false" || v === "no" || v === "off");
213
+ }
196
214
  // ─────────────────────────────────────────────────────────────────────────────
197
215
  // Default I/O implementations
198
216
  // ─────────────────────────────────────────────────────────────────────────────
@@ -271,6 +289,28 @@ async function defaultRunMigrationLint(workdir, files) {
271
289
  const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim();
272
290
  return { exitCode: result.exitCode ?? null, output };
273
291
  }
292
+ async function defaultRunMigrationRenumber(workdir, files) {
293
+ const script = path.join(workdir, "scripts", "ci", "migration-lint.mjs");
294
+ const result = await execa("node", [script, "--renumber", ...files], {
295
+ cwd: workdir,
296
+ env: buildEnv(),
297
+ reject: false,
298
+ });
299
+ const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`.trim();
300
+ // The tool renames files in the working tree; detect whether it changed
301
+ // anything via git rather than parsing its log.
302
+ const status = await execa("git", ["status", "--porcelain"], {
303
+ cwd: workdir,
304
+ env: buildEnv(),
305
+ reject: false,
306
+ });
307
+ const changed = (status.stdout ?? "").trim().length > 0;
308
+ return { changed, output };
309
+ }
310
+ async function defaultCommitRenumbered(workdir) {
311
+ await execa("git", ["add", "-A"], { cwd: workdir, env: buildEnv(), reject: false });
312
+ await execa("git", ["commit", "-m", "chore(acc): auto-renumber migration to next contiguous seq (MIGFIX-01)"], { cwd: workdir, env: buildEnv(), reject: false });
313
+ }
274
314
  // ─────────────────────────────────────────────────────────────────────────────
275
315
  // The gate
276
316
  // ─────────────────────────────────────────────────────────────────────────────
@@ -381,10 +421,32 @@ export async function runPreprGate(workdir, deps = {}) {
381
421
  // the STRICT-only SQL traps that otherwise surface a full review cycle later
382
422
  // fail the task locally instead. Gated on baseRef / the injected dep so the
383
423
  // unit suite (which provides neither) never shells out to git.
424
+ let migrationRenumbered;
384
425
  if (deps.listChangedMigrations || deps.baseRef) {
385
426
  const listChangedMigrations = deps.listChangedMigrations ?? defaultListChangedMigrations;
386
427
  const runMigrationLint = deps.runMigrationLint ?? defaultRunMigrationLint;
387
- const migrations = await listChangedMigrations(workdir, deps.baseRef);
428
+ let migrations = await listChangedMigrations(workdir, deps.baseRef);
429
+ // MIGFIX-01 (opt-in): renumber a NEW migration to the next contiguous seq
430
+ // BEFORE the seq-lint could hard-fail it. The migration was already
431
+ // committed, so on a rename we commit the renumbered tree (a fresh follow-up
432
+ // commit, never an amend) and re-list — the lint below then runs on the new
433
+ // path. Best-effort: any renumber/commit failure is swallowed so it never
434
+ // blocks a PR (the lint still catches an unresolved seq the normal way).
435
+ if (migrations.length > 0 && autoRenumberResolved(deps.autoRenumber, env)) {
436
+ const runMigrationRenumber = deps.runMigrationRenumber ?? defaultRunMigrationRenumber;
437
+ const commitRenumbered = deps.commitRenumbered ?? defaultCommitRenumbered;
438
+ try {
439
+ const { changed, output } = await runMigrationRenumber(workdir, migrations);
440
+ if (changed) {
441
+ await commitRenumbered(workdir);
442
+ migrations = await listChangedMigrations(workdir, deps.baseRef);
443
+ migrationRenumbered = { output: output.slice(-OUTPUT_TAIL) };
444
+ }
445
+ }
446
+ catch {
447
+ // swallow — the seq-lint below is the backstop.
448
+ }
449
+ }
388
450
  if (migrations.length > 0) {
389
451
  ran.push("migration-lint");
390
452
  const { exitCode, output } = await runMigrationLint(workdir, migrations);
@@ -415,10 +477,11 @@ export async function runPreprGate(workdir, deps = {}) {
415
477
  absent,
416
478
  migrationLintShadow: { exitCode, outputTail: output.slice(-OUTPUT_TAIL) },
417
479
  scopeShadow,
480
+ migrationRenumbered,
418
481
  };
419
482
  }
420
483
  }
421
484
  }
422
- return { ok: true, skipped: false, ran, absent, scopeShadow };
485
+ return { ok: true, skipped: false, ran, absent, scopeShadow, migrationRenumbered };
423
486
  }
424
487
  //# sourceMappingURL=prepr-gate.js.map