@tokenfactory/acc-runner 0.41.7 → 0.43.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 (114) hide show
  1. package/README.md +87 -4
  2. package/dist/acc.d.ts +3 -0
  3. package/dist/acc.d.ts.map +1 -0
  4. package/dist/acc.js +21 -0
  5. package/dist/acc.js.map +1 -0
  6. package/dist/cli-name.d.ts +29 -0
  7. package/dist/cli-name.d.ts.map +1 -0
  8. package/dist/cli-name.js +17 -0
  9. package/dist/cli-name.js.map +1 -0
  10. package/dist/cli.d.ts +20 -2
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +45 -289
  13. package/dist/cli.js.map +1 -1
  14. package/dist/engines/account-probe.d.ts +24 -0
  15. package/dist/engines/account-probe.d.ts.map +1 -1
  16. package/dist/engines/account-probe.js +18 -1
  17. package/dist/engines/account-probe.js.map +1 -1
  18. package/dist/keychain.d.ts +17 -0
  19. package/dist/keychain.d.ts.map +1 -1
  20. package/dist/keychain.js +36 -0
  21. package/dist/keychain.js.map +1 -1
  22. package/dist/login.d.ts +45 -1
  23. package/dist/login.d.ts.map +1 -1
  24. package/dist/login.js +91 -4
  25. package/dist/login.js.map +1 -1
  26. package/dist/machine-capabilities/index.d.ts +21 -0
  27. package/dist/machine-capabilities/index.d.ts.map +1 -0
  28. package/dist/machine-capabilities/index.js +21 -0
  29. package/dist/machine-capabilities/index.js.map +1 -0
  30. package/dist/machine-capabilities/probe.d.ts +61 -0
  31. package/dist/machine-capabilities/probe.d.ts.map +1 -0
  32. package/dist/machine-capabilities/probe.js +243 -0
  33. package/dist/machine-capabilities/probe.js.map +1 -0
  34. package/dist/machine-capabilities/redact.d.ts +42 -0
  35. package/dist/machine-capabilities/redact.d.ts.map +1 -0
  36. package/dist/machine-capabilities/redact.js +160 -0
  37. package/dist/machine-capabilities/redact.js.map +1 -0
  38. package/dist/machine-capabilities/report.d.ts +107 -0
  39. package/dist/machine-capabilities/report.d.ts.map +1 -0
  40. package/dist/machine-capabilities/report.js +211 -0
  41. package/dist/machine-capabilities/report.js.map +1 -0
  42. package/dist/machine-capabilities/types.d.ts +115 -0
  43. package/dist/machine-capabilities/types.d.ts.map +1 -0
  44. package/dist/machine-capabilities/types.js +11 -0
  45. package/dist/machine-capabilities/types.js.map +1 -0
  46. package/dist/migration-seq-guard.d.ts +78 -0
  47. package/dist/migration-seq-guard.d.ts.map +1 -0
  48. package/dist/migration-seq-guard.js +304 -0
  49. package/dist/migration-seq-guard.js.map +1 -0
  50. package/dist/node-version.d.ts +132 -0
  51. package/dist/node-version.d.ts.map +1 -0
  52. package/dist/node-version.js +318 -0
  53. package/dist/node-version.js.map +1 -0
  54. package/dist/prepr-gate.d.ts +120 -0
  55. package/dist/prepr-gate.d.ts.map +1 -1
  56. package/dist/prepr-gate.js +202 -3
  57. package/dist/prepr-gate.js.map +1 -1
  58. package/dist/program.d.ts +16 -0
  59. package/dist/program.d.ts.map +1 -0
  60. package/dist/program.js +355 -0
  61. package/dist/program.js.map +1 -0
  62. package/dist/runtime/review-chunking.d.ts +101 -0
  63. package/dist/runtime/review-chunking.d.ts.map +1 -0
  64. package/dist/runtime/review-chunking.js +192 -0
  65. package/dist/runtime/review-chunking.js.map +1 -0
  66. package/dist/runtime/review-diff.d.ts +30 -0
  67. package/dist/runtime/review-diff.d.ts.map +1 -0
  68. package/dist/runtime/review-diff.js +59 -0
  69. package/dist/runtime/review-diff.js.map +1 -0
  70. package/dist/runtime/reviewer.d.ts +40 -19
  71. package/dist/runtime/reviewer.d.ts.map +1 -1
  72. package/dist/runtime/reviewer.js +252 -51
  73. package/dist/runtime/reviewer.js.map +1 -1
  74. package/dist/serve-scope/command.d.ts +12 -0
  75. package/dist/serve-scope/command.d.ts.map +1 -0
  76. package/dist/serve-scope/command.js +89 -0
  77. package/dist/serve-scope/command.js.map +1 -0
  78. package/dist/serve-scope/index.d.ts +130 -0
  79. package/dist/serve-scope/index.d.ts.map +1 -0
  80. package/dist/serve-scope/index.js +148 -0
  81. package/dist/serve-scope/index.js.map +1 -0
  82. package/dist/task-runner.d.ts +11 -0
  83. package/dist/task-runner.d.ts.map +1 -1
  84. package/dist/task-runner.js +69 -0
  85. package/dist/task-runner.js.map +1 -1
  86. package/dist/user-auth/device-login.d.ts +47 -0
  87. package/dist/user-auth/device-login.d.ts.map +1 -0
  88. package/dist/user-auth/device-login.js +189 -0
  89. package/dist/user-auth/device-login.js.map +1 -0
  90. package/dist/user-auth/liveness.d.ts +27 -0
  91. package/dist/user-auth/liveness.d.ts.map +1 -0
  92. package/dist/user-auth/liveness.js +128 -0
  93. package/dist/user-auth/liveness.js.map +1 -0
  94. package/dist/user-auth/session.d.ts +82 -0
  95. package/dist/user-auth/session.d.ts.map +1 -0
  96. package/dist/user-auth/session.js +172 -0
  97. package/dist/user-auth/session.js.map +1 -0
  98. package/dist/user-cli/chat.d.ts +44 -0
  99. package/dist/user-cli/chat.d.ts.map +1 -0
  100. package/dist/user-cli/chat.js +199 -0
  101. package/dist/user-cli/chat.js.map +1 -0
  102. package/dist/user-cli/client.d.ts +20 -0
  103. package/dist/user-cli/client.d.ts.map +1 -0
  104. package/dist/user-cli/client.js +60 -0
  105. package/dist/user-cli/client.js.map +1 -0
  106. package/dist/user-cli/tasks.d.ts +37 -0
  107. package/dist/user-cli/tasks.d.ts.map +1 -0
  108. package/dist/user-cli/tasks.js +131 -0
  109. package/dist/user-cli/tasks.js.map +1 -0
  110. package/dist/watch.d.ts +8 -0
  111. package/dist/watch.d.ts.map +1 -1
  112. package/dist/watch.js +28 -0
  113. package/dist/watch.js.map +1 -1
  114. package/package.json +3 -2
@@ -0,0 +1,211 @@
1
+ /**
2
+ * AX-H1 (MACHINE-CAPABILITIES): the reporter — decide WHETHER to probe on this
3
+ * AS-1 cadence tick, and record the result.
4
+ *
5
+ * WHY A GATE AND NOT JUST "PROBE EVERY TICK". AX-H1 rides the AS-1 cadence
6
+ * (account-probe.ts) rather than adding a loop of its own, and that cadence ticks
7
+ * every ~60s while the runner is capacity-paused. An account probe is a config
8
+ * read; a capability probe shells out to gh, git and every engine — four to six
9
+ * subprocesses. Firing that every minute forever would make a cheap loop
10
+ * expensive and would rewrite an unchanged row all day.
11
+ *
12
+ * So the gate has three rules, in priority order:
13
+ *
14
+ * 1. FIRST TICK always probes. A machine that never reports is a machine ACC
15
+ * cannot describe, which is the whole gap.
16
+ * 2. AN ACCOUNT CHANGE always probes. A login swap is precisely when the engine
17
+ * rows went stale, and it is the AS-1 signal that already exists.
18
+ * 3. Otherwise probe at most once per `probeMinIntervalMs` (default 15 min).
19
+ *
20
+ * …and the WRITE has one more: an unchanged snapshot is only re-recorded once per
21
+ * `refreshMinIntervalMs` (default 6 h), so `probed_at` still proves liveness
22
+ * without an unchanged row being written 96 times a day. `snapshotFingerprint`
23
+ * decides "unchanged" over the whole sanitized document, so a version bump or a
24
+ * lost gh login is a change and a reordered scope list is not.
25
+ *
26
+ * FULLY injectable (probe / rpc / clock) so both gates are asserted with a fake
27
+ * clock and zero subprocesses.
28
+ */
29
+ import { sanitizeSnapshot } from "./redact.js";
30
+ /** Minimum gap between host probes on the shared AS-1 cadence. */
31
+ export const DEFAULT_PROBE_MIN_INTERVAL_MS = 15 * 60_000;
32
+ /** Minimum gap between re-recording an UNCHANGED snapshot (liveness refresh). */
33
+ export const DEFAULT_REFRESH_MIN_INTERVAL_MS = 6 * 60 * 60_000;
34
+ /**
35
+ * A stable content fingerprint of a snapshot. Deliberately excludes nothing:
36
+ * every field that reaches the server is in it, so "unchanged" means the recorded
37
+ * row would be byte-identical. Sorted keys, so JSON key order cannot make an
38
+ * unchanged machine look changed.
39
+ */
40
+ export function snapshotFingerprint(snapshot) {
41
+ return JSON.stringify(snapshot, (_key, value) => {
42
+ if (value && typeof value === "object" && !Array.isArray(value)) {
43
+ const obj = value;
44
+ return Object.fromEntries(Object.keys(obj).sort().map((k) => [k, obj[k]]));
45
+ }
46
+ return value;
47
+ });
48
+ }
49
+ /**
50
+ * Drives the capability probe on somebody else's cadence. Holds only the last
51
+ * fingerprint + two timestamps, so it is cheap to keep for the process lifetime
52
+ * and has no timer of its own — which is what makes "there is exactly one probe
53
+ * loop on this host" structurally true rather than a claim in a comment.
54
+ */
55
+ export class MachineCapabilityReporter {
56
+ deps;
57
+ probeMinIntervalMs;
58
+ refreshMinIntervalMs;
59
+ now;
60
+ lastProbeAt = null;
61
+ lastRecordAt = null;
62
+ lastFingerprint = null;
63
+ lastAccountKey = null;
64
+ seq = 0;
65
+ /** Serial chain so two triggers never probe concurrently or record out of order. */
66
+ tail = Promise.resolve();
67
+ constructor(deps) {
68
+ this.deps = deps;
69
+ this.probeMinIntervalMs = Math.max(0, deps.probeMinIntervalMs ?? DEFAULT_PROBE_MIN_INTERVAL_MS);
70
+ this.refreshMinIntervalMs = Math.max(0, deps.refreshMinIntervalMs ?? DEFAULT_REFRESH_MIN_INTERVAL_MS);
71
+ this.now = deps.now ?? Date.now;
72
+ }
73
+ /** The last recorded fingerprint (null before the first successful probe). */
74
+ fingerprint() {
75
+ return this.lastFingerprint;
76
+ }
77
+ /** Resolve once every queued tick has settled (test seam). */
78
+ async settle() {
79
+ await this.tail;
80
+ }
81
+ /**
82
+ * Note one AS-1 cadence tick. `accountKey` is the AS-1 `synthetic_account` of
83
+ * the identity that tick resolved: when it moves, the engine rows are stale by
84
+ * definition and the throttle is bypassed.
85
+ *
86
+ * Returns the outcome and never rejects — a capability report is
87
+ * best-effort telemetry and must never be able to fail a cadence tick.
88
+ */
89
+ onProbeTick(args) {
90
+ const run = this.tail.then(() => this.tick(args));
91
+ // Keep the chain alive even if a tick rejects (it should not — tick catches).
92
+ this.tail = run.then(() => undefined, () => undefined);
93
+ return run;
94
+ }
95
+ shouldProbe(accountKey) {
96
+ if (this.lastProbeAt === null)
97
+ return { probe: true, reason: "first-probe" };
98
+ if (accountKey !== null && accountKey !== this.lastAccountKey) {
99
+ return { probe: true, reason: "account-changed" };
100
+ }
101
+ const age = this.now() - this.lastProbeAt;
102
+ if (age >= this.probeMinIntervalMs)
103
+ return { probe: true, reason: "interval-elapsed" };
104
+ return { probe: false, reason: "throttled" };
105
+ }
106
+ async tick(args) {
107
+ const accountKey = args.accountKey ?? null;
108
+ const decision = this.shouldProbe(accountKey);
109
+ // A skip is only ever reached when the account is UNCHANGED (rule 2 above
110
+ // outranks the throttle), so nothing is lost by not tracking the key here.
111
+ if (!decision.probe) {
112
+ return { action: "skipped", reason: "throttled" };
113
+ }
114
+ let snapshot;
115
+ try {
116
+ // Sanitized again here even though probe.ts already sanitizes: this class
117
+ // accepts an INJECTED probe, and the redaction boundary must not depend on
118
+ // which probe was injected.
119
+ snapshot = sanitizeSnapshot(await this.deps.probe());
120
+ }
121
+ catch (err) {
122
+ this.deps.onLog?.(`[acc-runner] machine-capability probe (${args.trigger}) failed: ${err?.message ?? String(err)}`);
123
+ return { action: "failed", reason: "probe-threw" };
124
+ }
125
+ const at = this.now();
126
+ this.lastProbeAt = at;
127
+ if (accountKey !== null)
128
+ this.lastAccountKey = accountKey;
129
+ const fingerprint = snapshotFingerprint(snapshot);
130
+ const changed = fingerprint !== this.lastFingerprint;
131
+ const refreshDue = this.lastRecordAt === null || at - this.lastRecordAt >= this.refreshMinIntervalMs;
132
+ if (!changed && !refreshDue) {
133
+ return {
134
+ action: "probed",
135
+ recorded: false,
136
+ changed: false,
137
+ reason: "unchanged",
138
+ probeReason: decision.reason,
139
+ };
140
+ }
141
+ if (!this.deps.transport) {
142
+ this.lastFingerprint = fingerprint;
143
+ return {
144
+ action: "probed",
145
+ recorded: false,
146
+ changed,
147
+ reason: "no-transport",
148
+ probeReason: decision.reason,
149
+ };
150
+ }
151
+ const report = {
152
+ snapshot,
153
+ trigger: args.trigger,
154
+ seq: ++this.seq,
155
+ };
156
+ const recorded = await recordMachineCapabilities(this.deps.transport, report, {
157
+ runnerId: this.deps.runnerId ?? null,
158
+ onLog: this.deps.onLog,
159
+ });
160
+ if (recorded) {
161
+ this.lastRecordAt = at;
162
+ this.lastFingerprint = fingerprint;
163
+ }
164
+ return {
165
+ action: "probed",
166
+ recorded,
167
+ changed,
168
+ reason: changed ? "changed" : "liveness-refresh",
169
+ probeReason: decision.reason,
170
+ };
171
+ }
172
+ }
173
+ /**
174
+ * Send one report to `acc.record_machine_capabilities`. Returns false (and logs)
175
+ * on any failure rather than throwing: a pre-0310 server 404s this RPC, and an
176
+ * operator on an older deploy must not have their runner wedged by a telemetry
177
+ * write — the same non-fatal contract `set_runner_capabilities` uses in watch.ts.
178
+ *
179
+ * The snapshot is sanitized ONE more time on the way out. That is not paranoia
180
+ * theatre: this function is exported and callable with an arbitrary snapshot, and
181
+ * the invariant it has to hold is "nothing that leaves this process carries
182
+ * credential material", not "nothing that leaves this class does".
183
+ */
184
+ export async function recordMachineCapabilities(transport, report, opts = {}) {
185
+ const snapshot = sanitizeSnapshot(report.snapshot);
186
+ try {
187
+ const { error } = await transport.rpc("record_machine_capabilities", {
188
+ p_machine: snapshot.machine,
189
+ p_runner_id: opts.runnerId ?? null,
190
+ p_platform: snapshot.platform,
191
+ p_arch: snapshot.arch,
192
+ p_runner_version: snapshot.runner_version || null,
193
+ p_tools: snapshot.tools,
194
+ p_engines: snapshot.engines,
195
+ p_probe_trigger: report.trigger,
196
+ p_probe_seq: report.seq,
197
+ // No timestamp argument by design: probed_at is server time (0310 §4), so a
198
+ // host with a wrong clock cannot win last-writer-wins forever.
199
+ });
200
+ if (error) {
201
+ opts.onLog?.(`[acc-runner] record_machine_capabilities failed (continuing): ${error.message}`);
202
+ return false;
203
+ }
204
+ return true;
205
+ }
206
+ catch (err) {
207
+ opts.onLog?.(`[acc-runner] record_machine_capabilities threw (continuing): ${err?.message ?? String(err)}`);
208
+ return false;
209
+ }
210
+ }
211
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/machine-capabilities/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * AX-H1 (MACHINE-CAPABILITIES): the shapes a host reports about ITSELF.
3
+ *
4
+ * The one rule these types exist to encode (AUTH_APPROVAL_BRIEF.md §7.1 + the
5
+ * MLSA plan): NO CREDENTIAL EVER TRANSITS ACC. Every field below is either
6
+ *
7
+ * - PRESENCE — is the tool installed, does it authenticate, which version;
8
+ * - IDENTITY — which login / email / plan / scope-set it resolves to;
9
+ * - PROVENANCE — which host, which runner, which AS-1 probe trigger.
10
+ *
11
+ * There is deliberately no field that could hold a token, and the field set is
12
+ * CLOSED on three sides: `sanitizeSnapshot` (redact.ts) rebuilds every record
13
+ * from these fields before it leaves the host,
14
+ * `acc._normalize_machine_capability_{tools,engines}` (migration 0310) rebuilds
15
+ * it again from the same whitelist server-side, and two CHECK constraints reject
16
+ * anything shaped like a credential at rest. Adding a field here without adding
17
+ * it to BOTH whitelists means the field is silently dropped, which is the
18
+ * intended failure direction.
19
+ *
20
+ * DECLARATIONS ONLY — no behaviour, no I/O, so the contract can be asserted
21
+ * against the SQL mirror in a unit test.
22
+ */
23
+ import type { EngineAuthMode, EnginePlanHint } from "../engines/types.js";
24
+ /**
25
+ * The host tools ACC probes. Mirrors `acc.machine_capability_tools()` (0310 §1)
26
+ * and `HOST_TOOLS` in api/_lib/machine-capabilities.ts — the unit suite asserts
27
+ * all three agree, so a tool added on one side cannot silently be dropped by
28
+ * the writer's whitelist on another.
29
+ *
30
+ * Deliberately NOT the `acc.runners.capabilities` vocabulary (0114/0115): those
31
+ * are routing tags an operator DECLARES; these are tools ACC PROBES.
32
+ */
33
+ export declare const HOST_TOOLS: readonly ["gh", "git"];
34
+ export type HostTool = (typeof HOST_TOOLS)[number];
35
+ /** What one host tool offers. Presence + identity only. */
36
+ export interface ToolCapability {
37
+ /** Which tool this row describes. */
38
+ tool: HostTool;
39
+ /** The binary resolved on the (launchd-augmented) PATH. */
40
+ present: boolean;
41
+ /** Reported version, e.g. "2.62.0". Null when absent or unparseable. */
42
+ version: string | null;
43
+ /**
44
+ * The tool holds a working credential. For `gh` this is `gh auth status`
45
+ * exiting 0; `git` has no host-level login of its own, so it reports false.
46
+ */
47
+ authenticated: boolean;
48
+ /**
49
+ * WHO the tool acts as: the gh account login, or git's `user.email`. An
50
+ * identity, never a credential — and null rather than guessed when unknown.
51
+ */
52
+ identity: string | null;
53
+ /** The host the credential is for (gh: github.com / a GHES hostname). */
54
+ host: string | null;
55
+ /**
56
+ * The AUTHORITY LABELS a gh token carries ("repo", "read:org"). These are what
57
+ * make "can this machine open a PR" answerable. The token itself is never
58
+ * read: `gh auth status --show-token` is never invoked anywhere in this
59
+ * package, and the unit suite asserts that.
60
+ */
61
+ scopes: string[];
62
+ /** Masked, credential-safe one-line summary — safe to log, store and display. */
63
+ detail: string;
64
+ }
65
+ /** What one coding engine offers on this host. */
66
+ export interface EngineCapability {
67
+ /** Engine registry id (claude-code | codex | gemini). */
68
+ engine_id: string;
69
+ /** The engine's binary resolved on PATH. */
70
+ present: boolean;
71
+ /** Reported version. Null when absent or unparseable. */
72
+ version: string | null;
73
+ /** The engine resolved a real, named account (not the honest-unknown identity). */
74
+ logged_in: boolean;
75
+ /** Which auth channel the identity resolved through (AS-1 `channel`). */
76
+ channel: EngineAuthMode;
77
+ /** The account the engine is logged in as, or null when unintrospectable. */
78
+ account_email: string | null;
79
+ /** Coarse plan hint; "unknown" when the engine cannot detect one. */
80
+ plan_hint: EnginePlanHint;
81
+ /** The AS-1 stable synthetic account id. Always set. */
82
+ synthetic_account: string;
83
+ /** Masked, credential-safe one-line summary. */
84
+ detail: string;
85
+ }
86
+ /** Everything one host reports about itself in a single probe. */
87
+ export interface MachineCapabilitySnapshot {
88
+ /** os.hostname() — the operator-facing name of the machine. */
89
+ machine: string;
90
+ /** process.platform. */
91
+ platform: string;
92
+ /** process.arch. */
93
+ arch: string;
94
+ /** The acc-runner version that produced this snapshot. */
95
+ runner_version: string;
96
+ /** One row per probed host tool, in HOST_TOOLS order. */
97
+ tools: ToolCapability[];
98
+ /** One row per registered chat engine. */
99
+ engines: EngineCapability[];
100
+ }
101
+ /**
102
+ * A snapshot plus the AS-1 provenance of the probe that produced it. This is
103
+ * what `recordMachineCapabilities` sends to
104
+ * `acc.record_machine_capabilities` — note there is no timestamp: `probed_at` is
105
+ * server time, because a host with a wrong clock would otherwise win every
106
+ * last-writer-wins comparison forever (0310 §4).
107
+ */
108
+ export interface MachineCapabilityReport {
109
+ snapshot: MachineCapabilitySnapshot;
110
+ /** Which AS-1 cadence trigger fired this probe. */
111
+ trigger: string;
112
+ /** The probing process's monotonic probe sequence. */
113
+ seq: number;
114
+ }
115
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/machine-capabilities/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1E;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,wBAAyB,CAAC;AAEjD,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,IAAI,EAAE,QAAQ,CAAC;IACf,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,kDAAkD;AAClD,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,yDAAyD;IACzD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,mFAAmF;IACnF,SAAS,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,OAAO,EAAE,cAAc,CAAC;IACxB,6EAA6E;IAC7E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qEAAqE;IACrE,SAAS,EAAE,cAAc,CAAC;IAC1B,wDAAwD;IACxD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,kEAAkE;AAClE,MAAM,WAAW,yBAAyB;IACxC,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,0CAA0C;IAC1C,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,yBAAyB,CAAC;IACpC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;CACb"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The host tools ACC probes. Mirrors `acc.machine_capability_tools()` (0310 §1)
3
+ * and `HOST_TOOLS` in api/_lib/machine-capabilities.ts — the unit suite asserts
4
+ * all three agree, so a tool added on one side cannot silently be dropped by
5
+ * the writer's whitelist on another.
6
+ *
7
+ * Deliberately NOT the `acc.runners.capabilities` vocabulary (0114/0115): those
8
+ * are routing tags an operator DECLARES; these are tools ACC PROBES.
9
+ */
10
+ export const HOST_TOOLS = ["gh", "git"];
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/machine-capabilities/types.ts"],"names":[],"mappings":"AAwBA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,KAAK,CAAU,CAAC"}
@@ -0,0 +1,78 @@
1
+ /** Kill switch. Set to `0`/`false` to skip the pre-push re-validation entirely. */
2
+ export declare const SEQ_GUARD_ENV = "ACC_MIGRATION_SEQ_GUARD";
3
+ /** Every reason the guard can decline to renumber, for the runner log. */
4
+ export type SeqGuardSkipReason = "disabled" | "no-base-ref" | "no-new-migrations" | "no-remote-seqs" | "seq-free" | "renumber-noop" | "renumber-failed";
5
+ export interface SeqGuardRenumber {
6
+ /** Repo-relative path the migration had before the guard ran. */
7
+ file: string;
8
+ /** Repo-relative path it now has. */
9
+ newFile: string;
10
+ /** Numeric seq before → after. */
11
+ fromSeq: number;
12
+ toSeq: number;
13
+ /** Tail of the renumber tool's own log (which refs it rewrote). */
14
+ output: string;
15
+ }
16
+ export interface SeqGuardResult {
17
+ /** True iff a migration was renumbered AND the rename was committed. */
18
+ renumbered: boolean;
19
+ /** Why nothing happened. Unset when `renumbered` is true. */
20
+ skipped?: SeqGuardSkipReason;
21
+ /** Human-readable one-liner for the runner log — always set. */
22
+ detail: string;
23
+ /** Highest seq seen on the freshly-fetched integration head (null if unread). */
24
+ remoteMaxSeq?: number | null;
25
+ /** The move, when one happened. */
26
+ move?: SeqGuardRenumber;
27
+ }
28
+ export interface SeqGuardOptions {
29
+ /** Integration branch this task will target, e.g. `acc/integration`. */
30
+ integrationBranch: string;
31
+ /** Merge-base ref the new-migration diff is taken against. */
32
+ baseRef?: string;
33
+ /** Remote to re-fetch. Defaults to `origin`. */
34
+ remote?: string;
35
+ /**
36
+ * Live `acc.applied_migrations` seqs, when the caller can read them. Unioned
37
+ * with the fresh remote head so a migration applied out-of-band still counts
38
+ * as claimed. Omitted → the remote head alone is the baseline.
39
+ */
40
+ appliedSeqs?: number[] | null;
41
+ }
42
+ export interface SeqGuardDeps {
43
+ env?: NodeJS.ProcessEnv;
44
+ /** `git fetch <remote> <branch>`. Rejects → treated as "no fresh head". */
45
+ fetchRef?: (workdir: string, remote: string, branch: string) => Promise<void>;
46
+ /**
47
+ * Migration paths present on the freshly-fetched head, repo-relative. Returns
48
+ * `null` when the ref could not be read (the guard then stands down).
49
+ */
50
+ listRemoteMigrations?: (workdir: string, ref: string) => Promise<string[] | null>;
51
+ /** Migration files this branch ADDED vs `baseRef`, repo-relative. */
52
+ listAddedMigrations?: (workdir: string, baseRef?: string) => Promise<string[]>;
53
+ /** Run the renumber pass with an out-of-tree baseline roster. */
54
+ runRenumber?: (workdir: string, files: string[], baselineSeqs: number[]) => Promise<{
55
+ output: string;
56
+ }>;
57
+ /** True when the working tree has uncommitted changes (did the renumber act?). */
58
+ isDirty?: (workdir: string) => Promise<boolean>;
59
+ /** Commit the rename so the push carries it. */
60
+ commit?: (workdir: string, message: string) => Promise<void>;
61
+ }
62
+ /**
63
+ * The numeric sequence prefix of a migration path (`…/0315_acc_x.sql` → 315),
64
+ * or null when the filename does not carry one. Mirrors `parseSeq` in
65
+ * scripts/ci/migration-lint.mjs — the two must agree on what counts as a
66
+ * migration, so both accept `_` and `-` after the digits.
67
+ */
68
+ export declare function migrationSeq(file: string): number | null;
69
+ /** Whether the guard is enabled. ON by default; `0`/`false`/`no` turns it off. */
70
+ export declare function seqGuardEnabled(env?: NodeJS.ProcessEnv): boolean;
71
+ /**
72
+ * Re-validate this branch's NEW migration seq against a freshly-fetched
73
+ * integration head and auto-renumber it when a sibling has since taken the
74
+ * number. Returns what happened; NEVER throws (a crash inside the guard is
75
+ * reported as `renumber-failed` and the push proceeds).
76
+ */
77
+ export declare function revalidateMigrationSeq(workdir: string, opts: SeqGuardOptions, deps?: SeqGuardDeps): Promise<SeqGuardResult>;
78
+ //# sourceMappingURL=migration-seq-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-seq-guard.d.ts","sourceRoot":"","sources":["../src/migration-seq-guard.ts"],"names":[],"mappings":"AAkDA,mFAAmF;AACnF,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAIvD,0EAA0E;AAC1E,MAAM,MAAM,kBAAkB,GAC1B,UAAU,GACV,aAAa,GACb,mBAAmB,GACnB,gBAAgB,GAChB,UAAU,GACV,eAAe,GACf,iBAAiB,CAAC;AAEtB,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,UAAU,EAAE,OAAO,CAAC;IACpB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mCAAmC;IACnC,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E;;;OAGG;IACH,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;IAClF,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/E,iEAAiE;IACjE,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EAAE,EACf,YAAY,EAAE,MAAM,EAAE,KACnB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjC,kFAAkF;IAClF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,gDAAgD;IAChD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMxD;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAI7E;AAwGD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,EACrB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,cAAc,CAAC,CAgKzB"}