@omnicross/daemon 0.1.9 → 0.1.10

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.cjs CHANGED
@@ -23,87 +23,634 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  mod
24
24
  ));
25
25
 
26
- // src/commands/import-ccr.ts
27
- var import_node_fs3 = require("fs");
26
+ // src/commands/audit.ts
27
+ var import_node_fs5 = require("fs");
28
+ var import_node_path5 = require("path");
28
29
  var import_node_util = require("util");
29
30
 
30
- // src/ccr-import.ts
31
- function parseCcrConfig(raw) {
32
- if (!raw || typeof raw !== "object") {
33
- throw new Error("CCR config: top-level value must be an object");
31
+ // src/audit/auditBodyReader.ts
32
+ var import_node_fs3 = require("fs");
33
+ var import_node_path2 = require("path");
34
+ var import_node_zlib = require("zlib");
35
+
36
+ // src/audit/auditBodyStore.ts
37
+ var ANCHOR_EVERY = 64;
38
+ var ANCHOR_DELTA_RATIO = 0.75;
39
+ var DIVERGED_PREFIX_RATIO = 0.25;
40
+ var MAX_BASE_CHARS = 4e6;
41
+ var CACHE_BUDGET_CHARS = 16e6;
42
+ var CACHE_MAX_SESSIONS = 32;
43
+ var MAX_BASES_PER_SESSION = 4;
44
+ var isHighSurrogate = (code) => code >= 55296 && code <= 56319;
45
+ var isLowSurrogate = (code) => code >= 56320 && code <= 57343;
46
+ function computeBodyDelta(prev, next) {
47
+ const shortest = Math.min(prev.length, next.length);
48
+ let pre = 0;
49
+ while (pre < shortest && prev.charCodeAt(pre) === next.charCodeAt(pre)) pre += 1;
50
+ if (pre > 0 && isHighSurrogate(prev.charCodeAt(pre - 1))) pre -= 1;
51
+ const maxSuf = shortest - pre;
52
+ let suf = 0;
53
+ while (suf < maxSuf && prev.charCodeAt(prev.length - 1 - suf) === next.charCodeAt(next.length - 1 - suf)) {
54
+ suf += 1;
55
+ }
56
+ if (suf > 0 && isLowSurrogate(prev.charCodeAt(prev.length - suf))) suf -= 1;
57
+ return { pre, suf, ins: next.slice(pre, next.length - suf) };
58
+ }
59
+ function applyBodyDelta(prev, delta) {
60
+ const head = delta.pre > 0 ? prev.slice(0, delta.pre) : "";
61
+ const tail = delta.suf > 0 ? prev.slice(prev.length - delta.suf) : "";
62
+ return head + delta.ins + tail;
63
+ }
64
+ var SessionBaseCache = class {
65
+ constructor(maxSessions = CACHE_MAX_SESSIONS, budgetChars = CACHE_BUDGET_CHARS, maxBaseChars = MAX_BASE_CHARS, maxHeads = MAX_BASES_PER_SESSION) {
66
+ this.maxSessions = maxSessions;
67
+ this.budgetChars = budgetChars;
68
+ this.maxBaseChars = maxBaseChars;
69
+ this.maxHeads = maxHeads;
70
+ }
71
+ maxSessions;
72
+ budgetChars;
73
+ maxBaseChars;
74
+ maxHeads;
75
+ /** Session key to its retained heads, most-recent first. */
76
+ entries = /* @__PURE__ */ new Map();
77
+ chars = 0;
78
+ /** Retained sessions (tests + diagnostics). */
79
+ get size() {
80
+ return this.entries.size;
81
+ }
82
+ /** A session's retained heads, most-recent first. Refreshes LRU recency. */
83
+ get(sessionKey) {
84
+ const found = this.entries.get(sessionKey);
85
+ if (!found) return [];
86
+ this.entries.delete(sessionKey);
87
+ this.entries.set(sessionKey, found);
88
+ return found;
34
89
  }
35
- const obj = raw;
36
- const Providers = Array.isArray(obj["Providers"]) ? obj["Providers"] : [];
37
- const Router = obj["Router"] && typeof obj["Router"] === "object" ? obj["Router"] : {};
38
- return { Providers, Router };
90
+ /**
91
+ * Retain `base` as a head of `sessionKey`.
92
+ *
93
+ * `replacesId` is the head this turn CONTINUES (its body was preserved whole
94
+ * inside the new one), which is swapped out so a linear conversation keeps
95
+ * exactly one head. Omit it when the turn started a distinct stream %s that
96
+ * head is added alongside, which is what keeps a fork's branches apart.
97
+ *
98
+ * A body larger than `maxBaseChars` is not retained: the next turn anchors
99
+ * rather than letting one oversized session monopolize the budget.
100
+ */
101
+ remember(sessionKey, base, replacesId) {
102
+ const heads = this.entries.get(sessionKey) ?? [];
103
+ if (replacesId !== void 0) {
104
+ const at = heads.findIndex((head) => head.lastId === replacesId);
105
+ if (at >= 0) {
106
+ this.chars -= heads[at].text.length;
107
+ heads.splice(at, 1);
108
+ }
109
+ }
110
+ if (base.text.length <= this.maxBaseChars) {
111
+ heads.unshift(base);
112
+ this.chars += base.text.length;
113
+ }
114
+ while (heads.length > this.maxHeads) {
115
+ const dropped = heads.pop();
116
+ if (dropped) this.chars -= dropped.text.length;
117
+ }
118
+ this.entries.delete(sessionKey);
119
+ if (heads.length > 0) this.entries.set(sessionKey, heads);
120
+ this.evict();
121
+ }
122
+ /** Drop a session's heads (eviction, or a write failure invalidating them). */
123
+ forget(sessionKey) {
124
+ const heads = this.entries.get(sessionKey);
125
+ if (!heads) return;
126
+ for (const head of heads) this.chars -= head.text.length;
127
+ this.entries.delete(sessionKey);
128
+ }
129
+ /** Drop everything (writer disposal / test teardown). */
130
+ clear() {
131
+ this.entries.clear();
132
+ this.chars = 0;
133
+ }
134
+ /** Evict least-recently-used sessions until both bounds hold. */
135
+ evict() {
136
+ while (this.entries.size > this.maxSessions || this.chars > this.budgetChars && this.entries.size > 1) {
137
+ const oldest = this.entries.keys().next();
138
+ if (oldest.done) break;
139
+ this.forget(oldest.value);
140
+ }
141
+ }
142
+ };
143
+ function anchorReason(base, dayDir, delta, nextLength) {
144
+ if (!base || !delta) return "new";
145
+ if (base.dayDir !== dayDir) return "day";
146
+ if (base.chainLen >= ANCHOR_EVERY) return "chain";
147
+ if (delta.pre < base.text.length * DIVERGED_PREFIX_RATIO) return "diverged";
148
+ if (delta.ins.length > nextLength * ANCHOR_DELTA_RATIO) return "costly";
149
+ return null;
39
150
  }
40
- function inferApiFormat(provider) {
41
- const hay = `${provider.api_base_url ?? ""} ${provider.name ?? ""}`.toLowerCase();
42
- if (hay.includes("anthropic") || hay.includes("claude")) {
43
- return { format: "anthropic", ambiguous: false };
151
+ function pickBase(heads, next) {
152
+ let best = null;
153
+ for (const base of heads) {
154
+ const delta = computeBodyDelta(base.text, next);
155
+ if (best !== null && delta.ins.length >= best.delta.ins.length) continue;
156
+ best = { base, delta, continues: delta.pre + delta.suf >= base.text.length };
157
+ }
158
+ return best;
159
+ }
160
+ function encodeBodyEntry(record, sessionKey, dayDir, cache) {
161
+ const requestBody = record.requestBody;
162
+ const responseBody = record.responseBody;
163
+ if (requestBody === void 0 && responseBody === void 0) return null;
164
+ const entry = { id: record.id, ts: record.ts };
165
+ if (requestBody !== void 0) {
166
+ const heads = cache.get(sessionKey);
167
+ const sameDay = heads.filter((head) => head.dayDir === dayDir);
168
+ const chosen = pickBase(sameDay, requestBody);
169
+ const reason = heads.length > 0 && sameDay.length === 0 ? "day" : anchorReason(chosen?.base, dayDir, chosen?.delta ?? null, requestBody.length);
170
+ if (reason !== null) {
171
+ entry.req = { base: null, anchor: reason, pre: 0, suf: 0, ins: requestBody };
172
+ cache.remember(
173
+ sessionKey,
174
+ { dayDir, lastId: record.id, text: requestBody, chainLen: 0 },
175
+ chosen?.continues === true ? chosen.base.lastId : void 0
176
+ );
177
+ } else {
178
+ const picked = chosen;
179
+ entry.req = {
180
+ base: picked.base.lastId,
181
+ ...picked.continues ? { cont: true } : {},
182
+ pre: picked.delta.pre,
183
+ suf: picked.delta.suf,
184
+ ins: picked.delta.ins
185
+ };
186
+ cache.remember(
187
+ sessionKey,
188
+ { dayDir, lastId: record.id, text: requestBody, chainLen: picked.base.chainLen + 1 },
189
+ picked.continues ? picked.base.lastId : void 0
190
+ );
191
+ }
44
192
  }
45
- if (hay.includes("generativelanguage") || hay.includes("gemini") || hay.includes("google")) {
46
- return { format: "gemini", ambiguous: false };
193
+ if (responseBody !== void 0) entry.res = responseBody;
194
+ return JSON.stringify(entry);
195
+ }
196
+ function isAuditBodyEntry(value) {
197
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
198
+ const entry = value;
199
+ if (typeof entry["id"] !== "string" || typeof entry["ts"] !== "number") return false;
200
+ if (entry["res"] !== void 0 && typeof entry["res"] !== "string") return false;
201
+ const req = entry["req"];
202
+ if (req === void 0) return true;
203
+ if (!req || typeof req !== "object" || Array.isArray(req)) return false;
204
+ const delta = req;
205
+ if (delta["anchor"] !== void 0 && typeof delta["anchor"] !== "string") return false;
206
+ if (delta["cont"] !== void 0 && typeof delta["cont"] !== "boolean") return false;
207
+ return (delta["base"] === null || typeof delta["base"] === "string") && Number.isSafeInteger(delta["pre"]) && delta["pre"] >= 0 && Number.isSafeInteger(delta["suf"]) && delta["suf"] >= 0 && typeof delta["ins"] === "string";
208
+ }
209
+
210
+ // src/audit/auditDictionary.ts
211
+ var import_node_fs = require("fs");
212
+ var import_node_path = require("path");
213
+
214
+ // src/audit/auditFiles.ts
215
+ var AUDIT_FILE_RE = /^audit-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
216
+ var AUDIT_DAY_DIR_RE = /^audit-(\d{4})-(\d{2})-(\d{2})$/;
217
+ var AUDIT_META_FILE = "meta.jsonl";
218
+ var AUDIT_BODIES_DIR = "bodies";
219
+ var AUDIT_SESSION_KEY_RE = /^[0-9a-f]{8,64}$/;
220
+ var pad2 = (n) => String(n).padStart(2, "0");
221
+ var localDateStamp = (ts) => {
222
+ const d = new Date(ts);
223
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
224
+ };
225
+ function auditDayDirName(ts) {
226
+ return `audit-${localDateStamp(ts)}`;
227
+ }
228
+ function isAuditDayDir(name) {
229
+ return AUDIT_DAY_DIR_RE.test(name);
230
+ }
231
+ function isSafeSessionKey(key) {
232
+ return typeof key === "string" && AUDIT_SESSION_KEY_RE.test(key);
233
+ }
234
+ function auditBodyFileName(sessionKey) {
235
+ return `${sessionKey}.jsonl`;
236
+ }
237
+ function auditFileDateMs(name) {
238
+ const m = AUDIT_FILE_RE.exec(name) ?? AUDIT_DAY_DIR_RE.exec(name);
239
+ if (!m) return null;
240
+ const year = Number(m[1]);
241
+ const month = Number(m[2]);
242
+ const day = Number(m[3]);
243
+ const d = new Date(year, month - 1, day);
244
+ if (d.getFullYear() !== year || d.getMonth() !== month - 1 || d.getDate() !== day) {
245
+ return null;
47
246
  }
48
- if (hay.includes("/responses")) {
49
- return { format: "openai-response", ambiguous: false };
247
+ return d.getTime();
248
+ }
249
+
250
+ // src/audit/auditDictionary.ts
251
+ var AUDIT_DICT_FILE = "_dict.jsonl";
252
+ var DICT_BASE_PREFIX = "dict:";
253
+ var DICT_CANDIDATES = 3;
254
+ var MIN_SAVING_RATIO = 0.2;
255
+ function parseEntries(raw) {
256
+ const entries = [];
257
+ for (const line of raw.split("\n")) {
258
+ const trimmed = line.trim();
259
+ if (!trimmed) continue;
260
+ try {
261
+ const parsed = JSON.parse(trimmed);
262
+ if (isAuditBodyEntry(parsed)) entries.push(parsed);
263
+ } catch {
264
+ }
50
265
  }
51
- if (hay.includes("openai") || hay.includes("/v1") || hay.includes("chat/completions")) {
52
- return { format: "openai", ambiguous: false };
266
+ return entries;
267
+ }
268
+ function plainShards(bodiesPath) {
269
+ try {
270
+ return (0, import_node_fs.readdirSync)(bodiesPath).filter(
271
+ (file) => file.endsWith(".jsonl") && isSafeSessionKey(file.slice(0, -".jsonl".length))
272
+ );
273
+ } catch {
274
+ return [];
53
275
  }
54
- return { format: "openai", ambiguous: true };
55
276
  }
56
- function mapProviders(providers, notes) {
57
- const rows = [];
58
- for (const [i, p] of providers.entries()) {
59
- const id = p.name?.trim();
60
- if (!id) {
61
- notes.push(`Providers[${i}] has no name \u2014 skipped.`);
277
+ function chooseDictionary(anchors) {
278
+ if (anchors.length < 2) return null;
279
+ const total = anchors.reduce((sum, body) => sum + body.length, 0);
280
+ const candidates = [...anchors].sort((a, b) => b.length - a.length).slice(0, DICT_CANDIDATES);
281
+ let best = null;
282
+ for (const candidate of candidates) {
283
+ let cost = candidate.length;
284
+ for (const body of anchors) {
285
+ cost += body === candidate ? 0 : computeBodyDelta(candidate, body).ins.length;
286
+ }
287
+ if (best === null || cost < best.cost) best = { body: candidate, cost };
288
+ }
289
+ if (best === null) return null;
290
+ return total - best.cost >= total * MIN_SAVING_RATIO ? best.body : null;
291
+ }
292
+ var EMPTY = { shards: 0, anchors: 0, savedBytes: 0 };
293
+ function compactAuditDay(dayPath) {
294
+ const bodiesPath = (0, import_node_path.join)(dayPath, AUDIT_BODIES_DIR);
295
+ if (!(0, import_node_fs.existsSync)(bodiesPath)) return EMPTY;
296
+ const dictPath = (0, import_node_path.join)(bodiesPath, AUDIT_DICT_FILE);
297
+ if ((0, import_node_fs.existsSync)(dictPath) || (0, import_node_fs.existsSync)(`${dictPath}.gz`)) return EMPTY;
298
+ const shardFiles = plainShards(bodiesPath);
299
+ if (shardFiles.length < 2) return EMPTY;
300
+ const loaded = /* @__PURE__ */ new Map();
301
+ const anchors = [];
302
+ for (const file of shardFiles) {
303
+ let entries;
304
+ try {
305
+ entries = parseEntries((0, import_node_fs.readFileSync)((0, import_node_path.join)(bodiesPath, file), "utf8"));
306
+ } catch {
62
307
  continue;
63
308
  }
64
- const { format, ambiguous } = inferApiFormat(p);
65
- if (ambiguous) {
66
- notes.push(
67
- `Provider '${id}': could not infer apiFormat from base URL \u2014 defaulted to 'openai'. Edit the config if this provider speaks a different wire format.`
68
- );
309
+ loaded.set(file, entries);
310
+ for (const entry of entries) {
311
+ if (entry.req && entry.req.base === null) anchors.push(entry.req.ins);
69
312
  }
70
- rows.push({
71
- id,
72
- apiFormat: format,
73
- baseUrl: p.api_base_url ?? "",
74
- apiKey: p.api_key ?? "",
75
- models: Array.isArray(p.models) ? p.models : void 0
313
+ }
314
+ if (anchors.length < 2) return EMPTY;
315
+ const dictionary = chooseDictionary(anchors);
316
+ if (dictionary === null) return EMPTY;
317
+ const dictEntry = {
318
+ id: `${DICT_BASE_PREFIX}0`,
319
+ ts: 0,
320
+ req: { base: null, anchor: "dict", pre: 0, suf: 0, ins: dictionary }
321
+ };
322
+ (0, import_node_fs.writeFileSync)(dictPath, JSON.stringify(dictEntry) + "\n", "utf8");
323
+ const result = { shards: 0, anchors: 0, savedBytes: 0 };
324
+ for (const [file, entries] of loaded) {
325
+ let changed = false;
326
+ let saved = 0;
327
+ const rewritten = entries.map((entry) => {
328
+ if (!entry.req || entry.req.base !== null || entry.req.ins === dictionary) return entry;
329
+ const delta = computeBodyDelta(dictionary, entry.req.ins);
330
+ if (delta.ins.length >= entry.req.ins.length) return entry;
331
+ changed = true;
332
+ saved += entry.req.ins.length - delta.ins.length;
333
+ return {
334
+ ...entry,
335
+ req: { base: dictEntry.id, pre: delta.pre, suf: delta.suf, ins: delta.ins }
336
+ };
76
337
  });
338
+ if (!changed) continue;
339
+ const target = (0, import_node_path.join)(bodiesPath, file);
340
+ const temp = `${target}.compacting`;
341
+ try {
342
+ (0, import_node_fs.writeFileSync)(temp, rewritten.map((e) => JSON.stringify(e)).join("\n") + "\n", "utf8");
343
+ (0, import_node_fs.renameSync)(temp, target);
344
+ } catch {
345
+ try {
346
+ if ((0, import_node_fs.existsSync)(temp)) (0, import_node_fs.unlinkSync)(temp);
347
+ } catch {
348
+ }
349
+ continue;
350
+ }
351
+ result.shards += 1;
352
+ result.anchors += rewritten.filter((e) => e.req?.base === dictEntry.id).length;
353
+ result.savedBytes += saved;
77
354
  }
78
- return rows;
355
+ if (result.shards === 0) {
356
+ try {
357
+ (0, import_node_fs.unlinkSync)(dictPath);
358
+ } catch {
359
+ }
360
+ }
361
+ return result;
79
362
  }
80
- function noteRouterRoles(router, notes) {
81
- if (router.think) {
82
- notes.push(`Router.think \u2192 folded into 'default' (omnicross has no think slot).`);
363
+ function compactAllClosedAuditDays(auditDir, now = Date.now) {
364
+ const run = { days: 0, shards: 0, savedBytes: 0 };
365
+ if (!(0, import_node_fs.existsSync)(auditDir)) return run;
366
+ const today = auditDayDirName(now());
367
+ let names;
368
+ try {
369
+ names = (0, import_node_fs.readdirSync)(auditDir).filter(isAuditDayDir).sort();
370
+ } catch {
371
+ return run;
83
372
  }
84
- if (router.longContext) {
85
- notes.push(
86
- `Router.longContext \u2192 folded into 'default' (no longContext slot; longContextThreshold dropped).`
87
- );
373
+ for (const name of names) {
374
+ if (name === today) continue;
375
+ try {
376
+ const result = compactAuditDay((0, import_node_path.join)(auditDir, name));
377
+ if (result.shards === 0) continue;
378
+ run.days += 1;
379
+ run.shards += result.shards;
380
+ run.savedBytes += result.savedBytes;
381
+ } catch {
382
+ }
88
383
  }
89
- if (router.image) {
90
- notes.push(`Router.image \u2192 mapped to 'vision' (CCR forceUseImageAgent dropped).`);
384
+ return run;
385
+ }
386
+
387
+ // src/audit/auditJsonl.ts
388
+ var import_node_fs2 = require("fs");
389
+ var WINDOW_BYTES = 1 << 20;
390
+ var MAX_LINE_BYTES = 32 * 1024 * 1024;
391
+ var NEWLINE = 10;
392
+ function forEachLineFromTail(path2, onLine) {
393
+ let fd;
394
+ let end;
395
+ try {
396
+ end = (0, import_node_fs2.statSync)(path2).size;
397
+ if (end === 0) return;
398
+ fd = (0, import_node_fs2.openSync)(path2, "r");
399
+ } catch {
400
+ return;
91
401
  }
92
- if (router.webSearch) {
93
- notes.push(
94
- `Router.webSearch \u2192 DROPPED. omnicross injects web search via an interception port rather than routing to a natively-online model; the CCR webSearch model ('${router.webSearch}') was not carried over.`
95
- );
402
+ try {
403
+ let carry = Buffer.alloc(0);
404
+ while (end > 0) {
405
+ const start = Math.max(0, end - WINDOW_BYTES);
406
+ const window = Buffer.allocUnsafe(end - start);
407
+ let read;
408
+ try {
409
+ read = (0, import_node_fs2.readSync)(fd, window, 0, end - start, start);
410
+ } catch {
411
+ return;
412
+ }
413
+ const chunk = carry.length > 0 ? Buffer.concat([window.subarray(0, read), carry]) : window.subarray(0, read);
414
+ let lineEnd = chunk.length;
415
+ let nl = lineEnd > 0 ? chunk.lastIndexOf(NEWLINE, lineEnd - 1) : -1;
416
+ while (nl >= 0) {
417
+ if (nl + 1 < lineEnd) {
418
+ const line = chunk.subarray(nl + 1, lineEnd).toString("utf8").trim();
419
+ if (line && onLine(line)) return;
420
+ }
421
+ lineEnd = nl;
422
+ nl = lineEnd > 0 ? chunk.lastIndexOf(NEWLINE, lineEnd - 1) : -1;
423
+ }
424
+ if (start === 0) {
425
+ if (lineEnd > 0) {
426
+ const line = chunk.subarray(0, lineEnd).toString("utf8").trim();
427
+ if (line) onLine(line);
428
+ }
429
+ return;
430
+ }
431
+ if (lineEnd > MAX_LINE_BYTES) return;
432
+ carry = Buffer.from(chunk.subarray(0, lineEnd));
433
+ end = start;
434
+ }
435
+ } finally {
436
+ try {
437
+ (0, import_node_fs2.closeSync)(fd);
438
+ } catch {
439
+ }
96
440
  }
97
441
  }
98
- function mapCcrToOmnicross(ccr) {
99
- const notes = [];
100
- const providers = mapProviders(ccr.Providers ?? [], notes);
101
- noteRouterRoles(ccr.Router ?? {}, notes);
102
- return { config: { providers }, notes };
442
+
443
+ // src/audit/auditBodyReader.ts
444
+ function candidateDays(auditDir, ts) {
445
+ if (typeof ts === "number" && Number.isFinite(ts)) {
446
+ const named = auditDayDirName(ts);
447
+ if ((0, import_node_fs3.existsSync)((0, import_node_path2.join)(auditDir, named))) return [named];
448
+ }
449
+ try {
450
+ return (0, import_node_fs3.readdirSync)(auditDir).filter(isAuditDayDir).sort().reverse();
451
+ } catch {
452
+ return [];
453
+ }
454
+ }
455
+ function readShard(auditDir, day, sessionKey) {
456
+ const base = (0, import_node_path2.join)(auditDir, day, AUDIT_BODIES_DIR, auditBodyFileName(sessionKey));
457
+ try {
458
+ if ((0, import_node_fs3.existsSync)(base)) return (0, import_node_fs3.readFileSync)(base, "utf8");
459
+ const gz = `${base}.gz`;
460
+ if ((0, import_node_fs3.existsSync)(gz)) return (0, import_node_zlib.gunzipSync)((0, import_node_fs3.readFileSync)(gz)).toString("utf8");
461
+ } catch {
462
+ return null;
463
+ }
464
+ return null;
465
+ }
466
+ function parseShard(raw) {
467
+ const entries = /* @__PURE__ */ new Map();
468
+ for (const line of raw.split("\n")) {
469
+ const trimmed = line.trim();
470
+ if (!trimmed) continue;
471
+ let parsed;
472
+ try {
473
+ parsed = JSON.parse(trimmed);
474
+ } catch {
475
+ continue;
476
+ }
477
+ if (isAuditBodyEntry(parsed)) entries.set(parsed.id, parsed);
478
+ }
479
+ return entries;
480
+ }
481
+ function withDictionary(auditDir, day, entries) {
482
+ let needed = false;
483
+ for (const entry of entries.values()) {
484
+ if (entry.req?.base?.startsWith(DICT_BASE_PREFIX)) {
485
+ needed = true;
486
+ break;
487
+ }
488
+ }
489
+ if (!needed) return entries;
490
+ const base = (0, import_node_path2.join)(auditDir, day, AUDIT_BODIES_DIR, AUDIT_DICT_FILE);
491
+ let raw = null;
492
+ try {
493
+ if ((0, import_node_fs3.existsSync)(base)) raw = (0, import_node_fs3.readFileSync)(base, "utf8");
494
+ else if ((0, import_node_fs3.existsSync)(`${base}.gz`)) raw = (0, import_node_zlib.gunzipSync)((0, import_node_fs3.readFileSync)(`${base}.gz`)).toString("utf8");
495
+ } catch {
496
+ return entries;
497
+ }
498
+ if (raw === null) return entries;
499
+ for (const [id, entry] of parseShard(raw)) entries.set(id, entry);
500
+ return entries;
501
+ }
502
+ function reconstructRequest(entries, entry) {
503
+ if (!entry.req) return void 0;
504
+ const chain = [];
505
+ const visited = /* @__PURE__ */ new Set();
506
+ let cursor = entry;
507
+ while (cursor?.req) {
508
+ if (visited.has(cursor.id)) return void 0;
509
+ visited.add(cursor.id);
510
+ chain.push(cursor);
511
+ if (cursor.req.base === null) break;
512
+ cursor = entries.get(cursor.req.base);
513
+ }
514
+ const anchor = chain[chain.length - 1];
515
+ if (!anchor?.req || anchor.req.base !== null) return void 0;
516
+ let text = anchor.req.ins;
517
+ for (let i = chain.length - 2; i >= 0; i -= 1) {
518
+ const delta = chain[i]?.req;
519
+ if (!delta) return void 0;
520
+ if (delta.pre > text.length || delta.suf > text.length - delta.pre) return void 0;
521
+ text = applyBodyDelta(text, delta);
522
+ }
523
+ return text;
524
+ }
525
+ function assignStreams(entries) {
526
+ const rootOf = /* @__PURE__ */ new Map();
527
+ for (const entry of entries.values()) {
528
+ const seen = /* @__PURE__ */ new Set();
529
+ let cursor = entry;
530
+ while (cursor?.req?.cont === true && cursor.req.base !== null && !seen.has(cursor.id)) {
531
+ seen.add(cursor.id);
532
+ const next = entries.get(cursor.req.base);
533
+ if (!next) break;
534
+ cursor = next;
535
+ }
536
+ rootOf.set(entry.id, cursor?.id ?? entry.id);
537
+ }
538
+ const firstTs = /* @__PURE__ */ new Map();
539
+ for (const entry of entries.values()) {
540
+ const root = rootOf.get(entry.id);
541
+ const known = firstTs.get(root);
542
+ if (known === void 0 || entry.ts < known) firstTs.set(root, entry.ts);
543
+ }
544
+ const order = [...firstTs.entries()].sort((a, b) => a[1] - b[1]).map(([root]) => root);
545
+ const index = new Map(order.map((root, i) => [root, i]));
546
+ const streams = /* @__PURE__ */ new Map();
547
+ for (const entry of entries.values()) {
548
+ streams.set(entry.id, index.get(rootOf.get(entry.id)) ?? 0);
549
+ }
550
+ return streams;
551
+ }
552
+ function readAuditBody(auditDir, query2) {
553
+ if (!isSafeSessionKey(query2.sessionKey) || !query2.id) return {};
554
+ if (!(0, import_node_fs3.existsSync)(auditDir)) return {};
555
+ for (const day of candidateDays(auditDir, query2.ts)) {
556
+ const raw = readShard(auditDir, day, query2.sessionKey);
557
+ if (raw === null) continue;
558
+ const entries = withDictionary(auditDir, day, parseShard(raw));
559
+ const entry = entries.get(query2.id);
560
+ if (!entry) continue;
561
+ const result = {};
562
+ const requestBody = reconstructRequest(entries, entry);
563
+ if (requestBody !== void 0) result.requestBody = requestBody;
564
+ if (entry.res !== void 0) result.responseBody = entry.res;
565
+ return result;
566
+ }
567
+ return readLegacyInlineBody(auditDir, query2.id);
568
+ }
569
+ function readLegacyInlineBody(auditDir, id) {
570
+ let names;
571
+ try {
572
+ names = (0, import_node_fs3.readdirSync)(auditDir).filter((name) => AUDIT_FILE_RE.test(name)).sort().reverse();
573
+ } catch {
574
+ return {};
575
+ }
576
+ const needle = JSON.stringify(id);
577
+ let found = {};
578
+ for (const name of names) {
579
+ forEachLineFromTail((0, import_node_path2.join)(auditDir, name), (line) => {
580
+ if (!line.includes(needle)) return false;
581
+ let parsed;
582
+ try {
583
+ parsed = JSON.parse(line);
584
+ } catch {
585
+ return false;
586
+ }
587
+ const record = parsed;
588
+ if (record.id !== id) return false;
589
+ const result = {};
590
+ if (typeof record.requestBody === "string") result.requestBody = record.requestBody;
591
+ if (typeof record.responseBody === "string") result.responseBody = record.responseBody;
592
+ found = result;
593
+ return true;
594
+ });
595
+ if (found.requestBody !== void 0 || found.responseBody !== void 0) break;
596
+ }
597
+ return found;
598
+ }
599
+ function readAuditSessionTurns(auditDir, sessionKey, ts) {
600
+ if (!isSafeSessionKey(sessionKey) || !(0, import_node_fs3.existsSync)(auditDir)) return [];
601
+ for (const day of candidateDays(auditDir, ts)) {
602
+ const raw = readShard(auditDir, day, sessionKey);
603
+ if (raw === null) continue;
604
+ const shardEntries = parseShard(raw);
605
+ const streams = assignStreams(shardEntries);
606
+ const entries = withDictionary(auditDir, day, shardEntries);
607
+ const turns = [];
608
+ for (const entry of entries.values()) {
609
+ if (entry.id.startsWith(DICT_BASE_PREFIX)) continue;
610
+ const turn = { id: entry.id, ts: entry.ts, stream: streams.get(entry.id) ?? 0 };
611
+ if (entry.req?.anchor === "diverged") turn.diverged = true;
612
+ const requestBody = reconstructRequest(entries, entry);
613
+ if (requestBody !== void 0) turn.requestBody = requestBody;
614
+ if (entry.res !== void 0) turn.responseBody = entry.res;
615
+ turns.push(turn);
616
+ }
617
+ turns.sort((a, b) => a.stream === b.stream ? a.ts - b.ts : a.stream - b.stream);
618
+ return turns;
619
+ }
620
+ return [];
621
+ }
622
+ function listAuditSessions(auditDir, ts) {
623
+ if (!(0, import_node_fs3.existsSync)(auditDir)) return [];
624
+ const summaries = [];
625
+ for (const day of candidateDays(auditDir, ts)) {
626
+ const bodiesPath = (0, import_node_path2.join)(auditDir, day, AUDIT_BODIES_DIR);
627
+ let files;
628
+ try {
629
+ files = (0, import_node_fs3.readdirSync)(bodiesPath);
630
+ } catch {
631
+ continue;
632
+ }
633
+ for (const file of files) {
634
+ const compressed = file.endsWith(".jsonl.gz");
635
+ const sessionKey = file.replace(/\.jsonl(\.gz)?$/, "");
636
+ if (!isSafeSessionKey(sessionKey) || !compressed && !file.endsWith(".jsonl")) continue;
637
+ let bytes = 0;
638
+ try {
639
+ bytes = (0, import_node_fs3.statSync)((0, import_node_path2.join)(bodiesPath, file)).size;
640
+ } catch {
641
+ continue;
642
+ }
643
+ const raw = readShard(auditDir, day, sessionKey);
644
+ const turns = raw === null ? 0 : parseShard(raw).size;
645
+ summaries.push({ sessionKey, day, turns, bytes, compressed });
646
+ }
647
+ }
648
+ summaries.sort((a, b) => a.day === b.day ? b.bytes - a.bytes : a.day < b.day ? 1 : -1);
649
+ return summaries;
103
650
  }
104
651
 
105
- // src/config.ts
106
- var import_node_fs2 = require("fs");
652
+ // src/commands/paths.ts
653
+ var import_node_path4 = require("path");
107
654
 
108
655
  // src/secrets/envelope.ts
109
656
  var import_node_crypto = require("crypto");
@@ -162,13 +709,13 @@ function decryptValue(envelope, key) {
162
709
 
163
710
  // src/secrets/masterKey.ts
164
711
  var import_node_crypto2 = require("crypto");
165
- var import_node_fs = require("fs");
712
+ var import_node_fs4 = require("fs");
166
713
  var import_node_os = require("os");
167
- var import_node_path = require("path");
714
+ var import_node_path3 = require("path");
168
715
  var MASTER_KEY_ENV = "OMNICROSS_MASTER_KEY";
169
716
  var KEY_BYTES2 = 32;
170
717
  function defaultMasterKeyPath() {
171
- return (0, import_node_path.join)((0, import_node_os.homedir)(), ".omnicross", "master.key");
718
+ return (0, import_node_path3.join)((0, import_node_os.homedir)(), ".omnicross", "master.key");
172
719
  }
173
720
  function decodeEnvKey(raw) {
174
721
  const trimmed = raw.trim();
@@ -184,7 +731,7 @@ function decodeEnvKey(raw) {
184
731
  return buf;
185
732
  }
186
733
  function readKeyFile(path2) {
187
- const raw = (0, import_node_fs.readFileSync)(path2);
734
+ const raw = (0, import_node_fs4.readFileSync)(path2);
188
735
  if (raw.length === KEY_BYTES2) return raw;
189
736
  const text = raw.toString("utf8").trim();
190
737
  if (/^[0-9a-fA-F]{64}$/.test(text)) return Buffer.from(text, "hex");
@@ -196,10 +743,10 @@ function readKeyFile(path2) {
196
743
  }
197
744
  function generateKeyFile(path2) {
198
745
  const key = (0, import_node_crypto2.randomBytes)(KEY_BYTES2);
199
- (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(path2), { recursive: true });
200
- (0, import_node_fs.writeFileSync)(path2, key, { mode: 384 });
746
+ (0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(path2), { recursive: true });
747
+ (0, import_node_fs4.writeFileSync)(path2, key, { mode: 384 });
201
748
  try {
202
- (0, import_node_fs.chmodSync)(path2, 384);
749
+ (0, import_node_fs4.chmodSync)(path2, 384);
203
750
  } catch {
204
751
  }
205
752
  return key;
@@ -210,7 +757,7 @@ function resolveMasterKey(options = {}) {
210
757
  return decodeEnvKey(envRaw);
211
758
  }
212
759
  const keyFilePath = options.keyFilePath ?? defaultMasterKeyPath();
213
- if ((0, import_node_fs.existsSync)(keyFilePath)) {
760
+ if ((0, import_node_fs4.existsSync)(keyFilePath)) {
214
761
  return readKeyFile(keyFilePath);
215
762
  }
216
763
  return generateKeyFile(keyFilePath);
@@ -449,16 +996,243 @@ function transformTokens(tokens, fn) {
449
996
  });
450
997
  }
451
998
  }
452
- return next;
453
- }
454
- function encryptTokens(tokens, box) {
455
- return transformTokens(tokens, (v) => box.encryptMaybe(v));
999
+ return next;
1000
+ }
1001
+ function encryptTokens(tokens, box) {
1002
+ return transformTokens(tokens, (v) => box.encryptMaybe(v));
1003
+ }
1004
+ function decryptTokens(tokens, box) {
1005
+ return transformTokens(tokens, (v) => box.decryptMaybe(v));
1006
+ }
1007
+
1008
+ // src/commands/paths.ts
1009
+ function defaultKeysPath(configPath) {
1010
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "keys.json");
1011
+ }
1012
+ function defaultVouchersPath(configPath) {
1013
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "vouchers.json");
1014
+ }
1015
+ function defaultTokensPath(configPath) {
1016
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "tokens.json");
1017
+ }
1018
+ function defaultIntegrationsPath(configPath) {
1019
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "integrations.json");
1020
+ }
1021
+ function defaultPricingPath(configPath) {
1022
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "pricing.json");
1023
+ }
1024
+ function defaultPricingRefreshStatePath(configPath) {
1025
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "pricing-refresh.json");
1026
+ }
1027
+ function defaultAccountAllowancePath(configPath) {
1028
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "allowance-cache.json");
1029
+ }
1030
+ function defaultUsageEventsPath(configPath) {
1031
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "usage-events.jsonl");
1032
+ }
1033
+ function defaultAuditDir(configPath) {
1034
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "audit");
1035
+ }
1036
+ function defaultBillingDir(configPath) {
1037
+ return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "billing");
1038
+ }
1039
+ function resolveSecretBox(masterKeyFilePath) {
1040
+ return new SecretBox(() => resolveMasterKey({ keyFilePath: masterKeyFilePath }));
1041
+ }
1042
+
1043
+ // src/commands/audit.ts
1044
+ function parseDate(value) {
1045
+ if (!value) return void 0;
1046
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim());
1047
+ if (!m) throw new Error(`audit: --date must be YYYY-MM-DD (got ${value})`);
1048
+ const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
1049
+ return d.getTime();
1050
+ }
1051
+ function formatBytes(bytes) {
1052
+ if (bytes < 1024) return `${bytes} B`;
1053
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1054
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1055
+ }
1056
+ async function runAudit(argv) {
1057
+ const { values, positionals } = (0, import_node_util.parseArgs)({
1058
+ args: argv,
1059
+ options: {
1060
+ config: { type: "string", short: "c" },
1061
+ session: { type: "string", short: "s" },
1062
+ date: { type: "string", short: "d" },
1063
+ id: { type: "string" }
1064
+ },
1065
+ allowPositionals: true
1066
+ });
1067
+ const configPath = values.config;
1068
+ if (!configPath) throw new Error("audit: --config <path> is required");
1069
+ const auditDir = defaultAuditDir(configPath);
1070
+ const ts = parseDate(values.date);
1071
+ const action = positionals[0];
1072
+ if (action === "sessions") {
1073
+ const sessions2 = listAuditSessions(auditDir, ts);
1074
+ if (sessions2.length === 0) {
1075
+ console.info("No audit body shards found. Is `captureBodies` enabled?");
1076
+ return;
1077
+ }
1078
+ console.info(["DAY", "SESSION", "TURNS", "SIZE", "ARCHIVED"].join(" "));
1079
+ for (const s of sessions2) {
1080
+ console.info(
1081
+ [s.day, s.sessionKey, String(s.turns), formatBytes(s.bytes), s.compressed ? "gz" : "-"].join(" ")
1082
+ );
1083
+ }
1084
+ return;
1085
+ }
1086
+ if (action === "show") {
1087
+ const sessionKey = values.session;
1088
+ if (!sessionKey) throw new Error("audit show: --session <key> is required");
1089
+ if (values.id) {
1090
+ const body = readAuditBody(auditDir, { id: values.id, sessionKey, ...ts !== void 0 ? { ts } : {} });
1091
+ if (body.requestBody === void 0 && body.responseBody === void 0) {
1092
+ throw new Error(`audit show: no body found for record ${values.id}`);
1093
+ }
1094
+ if (body.requestBody !== void 0) console.info(`--- request ${values.id} ---
1095
+ ${body.requestBody}`);
1096
+ if (body.responseBody !== void 0) console.info(`--- response ${values.id} ---
1097
+ ${body.responseBody}`);
1098
+ return;
1099
+ }
1100
+ const turns = readAuditSessionTurns(auditDir, sessionKey, ts);
1101
+ if (turns.length === 0) throw new Error(`audit show: no shard found for session ${sessionKey}`);
1102
+ let stream = -1;
1103
+ for (const turn of turns) {
1104
+ const when = new Date(turn.ts).toISOString();
1105
+ if (turn.stream !== stream) {
1106
+ stream = turn.stream;
1107
+ console.info(`
1108
+ ########## stream ${stream} ##########`);
1109
+ }
1110
+ if (turn.diverged) {
1111
+ console.info("=== prefix diverged here (system prompt changed, or a restart reused this session) ===");
1112
+ }
1113
+ if (turn.requestBody !== void 0) {
1114
+ console.info(`--- request ${turn.id} @ ${when} ---
1115
+ ${turn.requestBody}`);
1116
+ }
1117
+ if (turn.responseBody !== void 0) {
1118
+ console.info(`--- response ${turn.id} @ ${when} ---
1119
+ ${turn.responseBody}`);
1120
+ }
1121
+ }
1122
+ return;
1123
+ }
1124
+ if (action === "compact") {
1125
+ const todayDir = auditDayDirName(Date.now());
1126
+ let names;
1127
+ try {
1128
+ names = (0, import_node_fs5.readdirSync)(auditDir).filter(isAuditDayDir).sort();
1129
+ } catch {
1130
+ names = [];
1131
+ }
1132
+ const targets = ts !== void 0 ? names.filter((name) => name === auditDayDirName(ts)) : names.filter((name) => name !== todayDir);
1133
+ if (targets.length === 0) {
1134
+ console.info("Nothing to compact (today is skipped; a day is compacted once).");
1135
+ return;
1136
+ }
1137
+ let shards = 0;
1138
+ let saved = 0;
1139
+ for (const name of targets) {
1140
+ if (name === todayDir) {
1141
+ console.info(`Skipping ${name}: the current day is still being written.`);
1142
+ continue;
1143
+ }
1144
+ const result = compactAuditDay((0, import_node_path5.join)(auditDir, name));
1145
+ shards += result.shards;
1146
+ saved += result.savedBytes;
1147
+ console.info(`${name}: ${result.shards} shard(s), ${result.anchors} anchor(s), ${formatBytes(result.savedBytes)} saved`);
1148
+ }
1149
+ console.info(`Done: ${shards} shard(s) rewritten, ${formatBytes(saved)} saved.`);
1150
+ return;
1151
+ }
1152
+ throw new Error("audit: expected `sessions`, `show`, or `compact` (see `omnicross help`)");
1153
+ }
1154
+
1155
+ // src/commands/import-ccr.ts
1156
+ var import_node_fs7 = require("fs");
1157
+ var import_node_util2 = require("util");
1158
+
1159
+ // src/ccr-import.ts
1160
+ function parseCcrConfig(raw) {
1161
+ if (!raw || typeof raw !== "object") {
1162
+ throw new Error("CCR config: top-level value must be an object");
1163
+ }
1164
+ const obj = raw;
1165
+ const Providers = Array.isArray(obj["Providers"]) ? obj["Providers"] : [];
1166
+ const Router = obj["Router"] && typeof obj["Router"] === "object" ? obj["Router"] : {};
1167
+ return { Providers, Router };
1168
+ }
1169
+ function inferApiFormat(provider) {
1170
+ const hay = `${provider.api_base_url ?? ""} ${provider.name ?? ""}`.toLowerCase();
1171
+ if (hay.includes("anthropic") || hay.includes("claude")) {
1172
+ return { format: "anthropic", ambiguous: false };
1173
+ }
1174
+ if (hay.includes("generativelanguage") || hay.includes("gemini") || hay.includes("google")) {
1175
+ return { format: "gemini", ambiguous: false };
1176
+ }
1177
+ if (hay.includes("/responses")) {
1178
+ return { format: "openai-response", ambiguous: false };
1179
+ }
1180
+ if (hay.includes("openai") || hay.includes("/v1") || hay.includes("chat/completions")) {
1181
+ return { format: "openai", ambiguous: false };
1182
+ }
1183
+ return { format: "openai", ambiguous: true };
1184
+ }
1185
+ function mapProviders(providers, notes) {
1186
+ const rows = [];
1187
+ for (const [i, p] of providers.entries()) {
1188
+ const id = p.name?.trim();
1189
+ if (!id) {
1190
+ notes.push(`Providers[${i}] has no name \u2014 skipped.`);
1191
+ continue;
1192
+ }
1193
+ const { format, ambiguous } = inferApiFormat(p);
1194
+ if (ambiguous) {
1195
+ notes.push(
1196
+ `Provider '${id}': could not infer apiFormat from base URL \u2014 defaulted to 'openai'. Edit the config if this provider speaks a different wire format.`
1197
+ );
1198
+ }
1199
+ rows.push({
1200
+ id,
1201
+ apiFormat: format,
1202
+ baseUrl: p.api_base_url ?? "",
1203
+ apiKey: p.api_key ?? "",
1204
+ models: Array.isArray(p.models) ? p.models : void 0
1205
+ });
1206
+ }
1207
+ return rows;
1208
+ }
1209
+ function noteRouterRoles(router, notes) {
1210
+ if (router.think) {
1211
+ notes.push(`Router.think \u2192 folded into 'default' (omnicross has no think slot).`);
1212
+ }
1213
+ if (router.longContext) {
1214
+ notes.push(
1215
+ `Router.longContext \u2192 folded into 'default' (no longContext slot; longContextThreshold dropped).`
1216
+ );
1217
+ }
1218
+ if (router.image) {
1219
+ notes.push(`Router.image \u2192 mapped to 'vision' (CCR forceUseImageAgent dropped).`);
1220
+ }
1221
+ if (router.webSearch) {
1222
+ notes.push(
1223
+ `Router.webSearch \u2192 DROPPED. omnicross injects web search via an interception port rather than routing to a natively-online model; the CCR webSearch model ('${router.webSearch}') was not carried over.`
1224
+ );
1225
+ }
456
1226
  }
457
- function decryptTokens(tokens, box) {
458
- return transformTokens(tokens, (v) => box.decryptMaybe(v));
1227
+ function mapCcrToOmnicross(ccr) {
1228
+ const notes = [];
1229
+ const providers = mapProviders(ccr.Providers ?? [], notes);
1230
+ noteRouterRoles(ccr.Router ?? {}, notes);
1231
+ return { config: { providers }, notes };
459
1232
  }
460
1233
 
461
1234
  // src/config.ts
1235
+ var import_node_fs6 = require("fs");
462
1236
  var DEFAULT_ADMIN_PORT = 8766;
463
1237
  function validateAdmin(raw) {
464
1238
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
@@ -751,7 +1525,7 @@ function setSecretBox(box) {
751
1525
  function loadConfig(path2) {
752
1526
  let raw;
753
1527
  try {
754
- raw = (0, import_node_fs2.readFileSync)(path2, "utf8");
1528
+ raw = (0, import_node_fs6.readFileSync)(path2, "utf8");
755
1529
  } catch {
756
1530
  throw new Error(`config: cannot read file at '${path2}'`);
757
1531
  }
@@ -766,48 +1540,12 @@ function loadConfig(path2) {
766
1540
  }
767
1541
  function saveConfig(path2, cfg) {
768
1542
  const toWrite = secretBox ? encryptConfigSecrets(cfg, secretBox) : cfg;
769
- (0, import_node_fs2.writeFileSync)(path2, JSON.stringify(toWrite, null, 2) + "\n", "utf8");
770
- }
771
-
772
- // src/commands/paths.ts
773
- var import_node_path2 = require("path");
774
- function defaultKeysPath(configPath) {
775
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "keys.json");
776
- }
777
- function defaultVouchersPath(configPath) {
778
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "vouchers.json");
779
- }
780
- function defaultTokensPath(configPath) {
781
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "tokens.json");
782
- }
783
- function defaultIntegrationsPath(configPath) {
784
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "integrations.json");
785
- }
786
- function defaultPricingPath(configPath) {
787
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "pricing.json");
788
- }
789
- function defaultPricingRefreshStatePath(configPath) {
790
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "pricing-refresh.json");
791
- }
792
- function defaultAccountAllowancePath(configPath) {
793
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "allowance-cache.json");
794
- }
795
- function defaultUsageEventsPath(configPath) {
796
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "usage-events.jsonl");
797
- }
798
- function defaultAuditDir(configPath) {
799
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "audit");
800
- }
801
- function defaultBillingDir(configPath) {
802
- return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "billing");
803
- }
804
- function resolveSecretBox(masterKeyFilePath) {
805
- return new SecretBox(() => resolveMasterKey({ keyFilePath: masterKeyFilePath }));
1543
+ (0, import_node_fs6.writeFileSync)(path2, JSON.stringify(toWrite, null, 2) + "\n", "utf8");
806
1544
  }
807
1545
 
808
1546
  // src/commands/import-ccr.ts
809
1547
  async function runImportCcr(argv) {
810
- const { values, positionals } = (0, import_node_util.parseArgs)({
1548
+ const { values, positionals } = (0, import_node_util2.parseArgs)({
811
1549
  args: argv,
812
1550
  options: {
813
1551
  out: { type: "string", short: "o" },
@@ -822,7 +1560,7 @@ async function runImportCcr(argv) {
822
1560
  const outPath = values.out ?? "omnicross.config.json";
823
1561
  let raw;
824
1562
  try {
825
- raw = JSON.parse((0, import_node_fs3.readFileSync)(ccrPath, "utf8"));
1563
+ raw = JSON.parse((0, import_node_fs7.readFileSync)(ccrPath, "utf8"));
826
1564
  } catch {
827
1565
  throw new Error(`import-ccr: cannot read or parse '${ccrPath}'`);
828
1566
  }
@@ -843,19 +1581,19 @@ async function runImportCcr(argv) {
843
1581
  }
844
1582
 
845
1583
  // src/commands/integrations.ts
846
- var import_node_path5 = require("path");
847
- var import_node_util2 = require("util");
1584
+ var import_node_path8 = require("path");
1585
+ var import_node_util3 = require("util");
848
1586
 
849
1587
  // src/integrations/IntegrationManager.ts
850
1588
  var import_node_crypto3 = require("crypto");
851
- var import_node_fs5 = require("fs");
1589
+ var import_node_fs9 = require("fs");
852
1590
  var import_node_os2 = require("os");
853
- var import_node_path4 = require("path");
1591
+ var import_node_path7 = require("path");
854
1592
  var import_core = require("@omnicross/core");
855
1593
 
856
1594
  // src/integrations/IntegrationStateStore.ts
857
- var import_node_fs4 = require("fs");
858
- var import_node_path3 = require("path");
1595
+ var import_node_fs8 = require("fs");
1596
+ var import_node_path6 = require("path");
859
1597
  var EMPTY_STATE = { version: 1, clients: {} };
860
1598
  var IntegrationStateStore = class {
861
1599
  constructor(path2, box) {
@@ -865,10 +1603,10 @@ var IntegrationStateStore = class {
865
1603
  path;
866
1604
  box;
867
1605
  load() {
868
- if (!(0, import_node_fs4.existsSync)(this.path)) return { ...EMPTY_STATE, clients: {} };
1606
+ if (!(0, import_node_fs8.existsSync)(this.path)) return { ...EMPTY_STATE, clients: {} };
869
1607
  let raw;
870
1608
  try {
871
- raw = JSON.parse((0, import_node_fs4.readFileSync)(this.path, "utf8"));
1609
+ raw = JSON.parse((0, import_node_fs8.readFileSync)(this.path, "utf8"));
872
1610
  } catch {
873
1611
  throw new Error(`integration state '${this.path}' is not valid JSON`);
874
1612
  }
@@ -936,21 +1674,21 @@ function isManagedFileRecord(value) {
936
1674
  return typeof row.path === "string" && typeof row.originalExisted === "boolean" && typeof row.originalContent === "string" && typeof row.originalHash === "string" && typeof row.installedHash === "string";
937
1675
  }
938
1676
  function atomicWrite(path2, content) {
939
- (0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(path2), { recursive: true });
1677
+ (0, import_node_fs8.mkdirSync)((0, import_node_path6.dirname)(path2), { recursive: true });
940
1678
  const temp = `${path2}.tmp-${process.pid}-${Date.now()}`;
941
- (0, import_node_fs4.writeFileSync)(temp, content, { encoding: "utf8", mode: 384 });
1679
+ (0, import_node_fs8.writeFileSync)(temp, content, { encoding: "utf8", mode: 384 });
942
1680
  try {
943
- (0, import_node_fs4.renameSync)(temp, path2);
1681
+ (0, import_node_fs8.renameSync)(temp, path2);
944
1682
  } catch (error) {
945
1683
  try {
946
- (0, import_node_fs4.unlinkSync)(temp);
1684
+ (0, import_node_fs8.unlinkSync)(temp);
947
1685
  } catch {
948
1686
  }
949
1687
  throw error;
950
1688
  } finally {
951
- if ((0, import_node_fs4.existsSync)(path2)) {
1689
+ if ((0, import_node_fs8.existsSync)(path2)) {
952
1690
  try {
953
- (0, import_node_fs4.chmodSync)(path2, 384);
1691
+ (0, import_node_fs8.chmodSync)(path2, 384);
954
1692
  } catch {
955
1693
  }
956
1694
  }
@@ -1142,7 +1880,7 @@ var IntegrationManager = class {
1142
1880
  async plan(client, configPath = this.defaultConfigPath(client)) {
1143
1881
  const state = this.options.stateStore.load();
1144
1882
  const record = state.clients[client];
1145
- const target = record?.configPath ?? (0, import_node_path4.resolve)(configPath);
1883
+ const target = record?.configPath ?? (0, import_node_path7.resolve)(configPath);
1146
1884
  const status = this.statusFor(client, state, await this.isKeyUsable(state));
1147
1885
  const changes = client === "codex" ? [
1148
1886
  "model_provider",
@@ -1165,7 +1903,7 @@ var IntegrationManager = class {
1165
1903
  };
1166
1904
  }
1167
1905
  async install(client, configPath = this.defaultConfigPath(client)) {
1168
- const target = (0, import_node_path4.resolve)(configPath);
1906
+ const target = (0, import_node_path7.resolve)(configPath);
1169
1907
  const state = this.options.stateStore.load();
1170
1908
  const existingRecord = state.clients[client];
1171
1909
  if (existingRecord) {
@@ -1442,10 +2180,10 @@ var IntegrationManager = class {
1442
2180
  };
1443
2181
  }
1444
2182
  defaultConfigPath(client) {
1445
- return client === "codex" ? (0, import_node_path4.join)(this.homeDir, ".codex", "config.toml") : (0, import_node_path4.join)(this.homeDir, ".claude", "settings.json");
2183
+ return client === "codex" ? (0, import_node_path7.join)(this.homeDir, ".codex", "config.toml") : (0, import_node_path7.join)(this.homeDir, ".claude", "settings.json");
1446
2184
  }
1447
2185
  codexAuthPathForConfig(configPath) {
1448
- return (0, import_node_path4.join)((0, import_node_path4.dirname)(configPath), "auth.json");
2186
+ return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "auth.json");
1449
2187
  }
1450
2188
  renderInstalled(client, base, secret) {
1451
2189
  if (client === "claude") {
@@ -1458,7 +2196,7 @@ var IntegrationManager = class {
1458
2196
  }
1459
2197
  };
1460
2198
  function readOptional(path2) {
1461
- return (0, import_node_fs5.existsSync)(path2) ? (0, import_node_fs5.readFileSync)(path2, "utf8") : null;
2199
+ return (0, import_node_fs9.existsSync)(path2) ? (0, import_node_fs9.readFileSync)(path2, "utf8") : null;
1462
2200
  }
1463
2201
  function sha256(value) {
1464
2202
  return (0, import_node_crypto3.createHash)("sha256").update(value, "utf8").digest("hex");
@@ -1522,7 +2260,7 @@ function writeOptional(path2, content) {
1522
2260
  atomicWrite(path2, content);
1523
2261
  return;
1524
2262
  }
1525
- if ((0, import_node_fs5.existsSync)(path2)) (0, import_node_fs5.unlinkSync)(path2);
2263
+ if ((0, import_node_fs9.existsSync)(path2)) (0, import_node_fs9.unlinkSync)(path2);
1526
2264
  }
1527
2265
  function assertLoopbackGatewayUrl(value) {
1528
2266
  let url;
@@ -1539,7 +2277,7 @@ function assertLoopbackGatewayUrl(value) {
1539
2277
  }
1540
2278
 
1541
2279
  // src/ports/JsonOutboundKeyDb.ts
1542
- var import_node_fs6 = require("fs");
2280
+ var import_node_fs10 = require("fs");
1543
2281
  var JsonOutboundKeyDb = class {
1544
2282
  /**
1545
2283
  * @param secretBox OPTIONAL reversible-secret codec. When present, a created
@@ -1672,16 +2410,16 @@ var JsonOutboundKeyDb = class {
1672
2410
  }
1673
2411
  /** Read the key rows, tolerating a missing/corrupt file (→ empty list). */
1674
2412
  readRows() {
1675
- if (!(0, import_node_fs6.existsSync)(this.keysPath)) return [];
2413
+ if (!(0, import_node_fs10.existsSync)(this.keysPath)) return [];
1676
2414
  try {
1677
- const parsed = JSON.parse((0, import_node_fs6.readFileSync)(this.keysPath, "utf8"));
2415
+ const parsed = JSON.parse((0, import_node_fs10.readFileSync)(this.keysPath, "utf8"));
1678
2416
  return Array.isArray(parsed) ? parsed : [];
1679
2417
  } catch {
1680
2418
  return [];
1681
2419
  }
1682
2420
  }
1683
2421
  writeRows(rows) {
1684
- (0, import_node_fs6.writeFileSync)(this.keysPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
2422
+ (0, import_node_fs10.writeFileSync)(this.keysPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
1685
2423
  }
1686
2424
  };
1687
2425
  function applyPolicyField(row, field, value) {
@@ -1692,7 +2430,7 @@ function applyPolicyField(row, field, value) {
1692
2430
 
1693
2431
  // src/commands/integrations.ts
1694
2432
  async function runIntegrations(argv) {
1695
- const { values, positionals } = (0, import_node_util2.parseArgs)({
2433
+ const { values, positionals } = (0, import_node_util3.parseArgs)({
1696
2434
  args: argv,
1697
2435
  options: {
1698
2436
  config: { type: "string", short: "c" },
@@ -1713,7 +2451,7 @@ async function runIntegrations(argv) {
1713
2451
  const savedUrl = saved.clients.codex?.gatewayBaseUrl ?? saved.clients.claude?.gatewayBaseUrl;
1714
2452
  const gatewayBaseUrl = values["gateway-base-url"] ?? savedUrl ?? "http://127.0.0.1:8765";
1715
2453
  const manager = new IntegrationManager({
1716
- configPath: (0, import_node_path5.resolve)(values.config),
2454
+ configPath: (0, import_node_path8.resolve)(values.config),
1717
2455
  gatewayBaseUrl,
1718
2456
  keyDb: new JsonOutboundKeyDb(defaultKeysPath(values.config)),
1719
2457
  stateStore: store
@@ -1742,10 +2480,10 @@ function isClient(value) {
1742
2480
  }
1743
2481
 
1744
2482
  // src/commands/keys.ts
1745
- var import_node_util3 = require("util");
2483
+ var import_node_util4 = require("util");
1746
2484
  var import_outbound_api = require("@omnicross/core/outbound-api");
1747
2485
  async function runKeys(argv) {
1748
- const { values, positionals } = (0, import_node_util3.parseArgs)({
2486
+ const { values, positionals } = (0, import_node_util4.parseArgs)({
1749
2487
  args: argv,
1750
2488
  options: { config: { type: "string", short: "c" } },
1751
2489
  allowPositionals: true
@@ -1799,14 +2537,14 @@ async function keysRevoke(db, id) {
1799
2537
  // src/commands/launch.ts
1800
2538
  var import_node_child_process2 = require("child_process");
1801
2539
  var import_node_crypto15 = require("crypto");
1802
- var import_node_fs25 = require("fs");
1803
- var import_node_path17 = require("path");
1804
- var import_node_util4 = require("util");
2540
+ var import_node_fs29 = require("fs");
2541
+ var import_node_path20 = require("path");
2542
+ var import_node_util5 = require("util");
1805
2543
  var import_cli_launcher3 = require("@omnicross/cli-launcher");
1806
2544
  var import_provider_proxy5 = require("@omnicross/core/provider-proxy");
1807
2545
 
1808
2546
  // src/bootstrap.ts
1809
- var import_node_fs24 = require("fs");
2547
+ var import_node_fs28 = require("fs");
1810
2548
  var import_audit_types = require("@omnicross/contracts/audit-types");
1811
2549
  var import_billing_types = require("@omnicross/contracts/billing-types");
1812
2550
  var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
@@ -1822,7 +2560,7 @@ var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-c
1822
2560
  var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
1823
2561
  var import_cli_launcher2 = require("@omnicross/cli-launcher");
1824
2562
  var import_outbound_api6 = require("@omnicross/core/outbound-api");
1825
- var import_usage = require("@omnicross/core/usage");
2563
+ var import_usage2 = require("@omnicross/core/usage");
1826
2564
  var import_subscriptions4 = require("@omnicross/subscriptions");
1827
2565
 
1828
2566
  // src/admin/accountsCodexOAuth.ts
@@ -2315,8 +3053,8 @@ var ClaudeAllowanceRefreshScheduler = class {
2315
3053
 
2316
3054
  // src/allowance/JsonAccountAllowancePersistence.ts
2317
3055
  var import_node_crypto5 = require("crypto");
2318
- var import_node_fs7 = require("fs");
2319
- var import_node_path6 = require("path");
3056
+ var import_node_fs11 = require("fs");
3057
+ var import_node_path9 = require("path");
2320
3058
  var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2321
3059
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
2322
3060
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
@@ -2328,10 +3066,10 @@ var JsonAccountAllowancePersistence = class {
2328
3066
  cachePath;
2329
3067
  /** Read only the `snapshots` payload; all row validation remains defensive. */
2330
3068
  load() {
2331
- if (!(0, import_node_fs7.existsSync)(this.cachePath)) return [];
3069
+ if (!(0, import_node_fs11.existsSync)(this.cachePath)) return [];
2332
3070
  try {
2333
- if ((0, import_node_fs7.statSync)(this.cachePath).size > MAX_ALLOWANCE_CACHE_BYTES) return [];
2334
- const raw = (0, import_node_fs7.readFileSync)(this.cachePath, "utf8");
3071
+ if ((0, import_node_fs11.statSync)(this.cachePath).size > MAX_ALLOWANCE_CACHE_BYTES) return [];
3072
+ const raw = (0, import_node_fs11.readFileSync)(this.cachePath, "utf8");
2335
3073
  if (!raw.trim()) return [];
2336
3074
  const parsed = JSON.parse(raw);
2337
3075
  if (Array.isArray(parsed)) return parsed;
@@ -2359,13 +3097,13 @@ var JsonAccountAllowancePersistence = class {
2359
3097
  if (Buffer.byteLength(serialized, "utf8") > MAX_ALLOWANCE_CACHE_BYTES) {
2360
3098
  throw new Error("account allowance cache exceeds its size limit");
2361
3099
  }
2362
- (0, import_node_fs7.mkdirSync)((0, import_node_path6.dirname)(this.cachePath), { recursive: true });
3100
+ (0, import_node_fs11.mkdirSync)((0, import_node_path9.dirname)(this.cachePath), { recursive: true });
2363
3101
  const temporaryPath = `${this.cachePath}.${process.pid}.${(0, import_node_crypto5.randomUUID)()}.tmp`;
2364
3102
  try {
2365
- (0, import_node_fs7.writeFileSync)(temporaryPath, serialized, { encoding: "utf8", flag: "wx" });
2366
- (0, import_node_fs7.renameSync)(temporaryPath, this.cachePath);
3103
+ (0, import_node_fs11.writeFileSync)(temporaryPath, serialized, { encoding: "utf8", flag: "wx" });
3104
+ (0, import_node_fs11.renameSync)(temporaryPath, this.cachePath);
2367
3105
  } finally {
2368
- (0, import_node_fs7.rmSync)(temporaryPath, { force: true });
3106
+ (0, import_node_fs11.rmSync)(temporaryPath, { force: true });
2369
3107
  }
2370
3108
  }
2371
3109
  };
@@ -2403,6 +3141,37 @@ function handleAuditQuery(req, res, reader) {
2403
3141
  res.writeHead(200, { "Content-Type": "application/json" });
2404
3142
  res.end(JSON.stringify({ records }));
2405
3143
  }
3144
+ function handleAuditBodyQuery(req, res, reader) {
3145
+ const url = new URL(req.url ?? "/", "http://localhost");
3146
+ const id = url.searchParams.get("id")?.trim();
3147
+ const sessionKey = url.searchParams.get("session")?.trim();
3148
+ if (!id || !sessionKey) {
3149
+ res.writeHead(400, { "Content-Type": "application/json" });
3150
+ res.end(JSON.stringify({ error: "id and session are required" }));
3151
+ return;
3152
+ }
3153
+ const query2 = { id, sessionKey };
3154
+ const ts = intParam(url.searchParams.get("ts"));
3155
+ if (ts !== void 0) query2.ts = ts;
3156
+ const body = reader ? reader(query2) : {};
3157
+ res.writeHead(200, { "Content-Type": "application/json" });
3158
+ res.end(JSON.stringify(body));
3159
+ }
3160
+ function handleAuditCompact(res, compact) {
3161
+ if (!compact) {
3162
+ res.writeHead(200, { "Content-Type": "application/json" });
3163
+ res.end(JSON.stringify({ days: 0, shards: 0, savedBytes: 0 }));
3164
+ return;
3165
+ }
3166
+ try {
3167
+ const result = compact();
3168
+ res.writeHead(200, { "Content-Type": "application/json" });
3169
+ res.end(JSON.stringify(result));
3170
+ } catch (error) {
3171
+ res.writeHead(500, { "Content-Type": "application/json" });
3172
+ res.end(JSON.stringify({ error: error instanceof Error ? error.message : "compaction failed" }));
3173
+ }
3174
+ }
2406
3175
  async function handleAuditStatsQuery(req, res, reader) {
2407
3176
  const url = new URL(req.url ?? "/", "http://localhost");
2408
3177
  const query2 = {};
@@ -3133,10 +3902,10 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
3133
3902
  // src/admin/cliLaunch.ts
3134
3903
  var import_node_child_process = require("child_process");
3135
3904
  var import_node_crypto6 = require("crypto");
3136
- var import_node_fs8 = require("fs");
3905
+ var import_node_fs12 = require("fs");
3137
3906
  var import_node_net = require("net");
3138
3907
  var import_node_os3 = require("os");
3139
- var import_node_path7 = require("path");
3908
+ var import_node_path10 = require("path");
3140
3909
  var import_cli_launcher = require("@omnicross/cli-launcher");
3141
3910
  var import_provider_proxy2 = require("@omnicross/core/provider-proxy");
3142
3911
 
@@ -3183,10 +3952,10 @@ function isLaunchCliId(id) {
3183
3952
  return id !== void 0 && LAUNCHABLE_IDS.has(id);
3184
3953
  }
3185
3954
  function probeDefault(candidate) {
3186
- const segments = (process.env["PATH"] ?? "").split(import_node_path7.delimiter).filter(Boolean);
3955
+ const segments = (process.env["PATH"] ?? "").split(import_node_path10.delimiter).filter(Boolean);
3187
3956
  for (const seg of segments) {
3188
- const full = (0, import_node_path7.join)(seg, candidate);
3189
- if ((0, import_node_fs8.existsSync)(full)) return full;
3957
+ const full = (0, import_node_path10.join)(seg, candidate);
3958
+ if ((0, import_node_fs12.existsSync)(full)) return full;
3190
3959
  }
3191
3960
  return null;
3192
3961
  }
@@ -3290,10 +4059,10 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
3290
4059
  const runLine = [command, ...extraArgs].map(shq).join(" ");
3291
4060
  const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
3292
4061
  if (platform === "darwin") {
3293
- const launchDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path7.join)((0, import_node_os3.tmpdir)(), "omnicross-terminal-"));
3294
- const commandFile = (0, import_node_path7.join)(launchDir, "launch.command");
3295
- const bootstrapFile = (0, import_node_path7.join)(launchDir, "bootstrap.cjs");
3296
- const socketPath = macIpc.socketPath ?? (0, import_node_path7.join)(launchDir, "descriptor.sock");
4062
+ const launchDir = (0, import_node_fs12.mkdtempSync)((0, import_node_path10.join)((0, import_node_os3.tmpdir)(), "omnicross-terminal-"));
4063
+ const commandFile = (0, import_node_path10.join)(launchDir, "launch.command");
4064
+ const bootstrapFile = (0, import_node_path10.join)(launchDir, "bootstrap.cjs");
4065
+ const socketPath = macIpc.socketPath ?? (0, import_node_path10.join)(launchDir, "descriptor.sock");
3297
4066
  const openerEnv = { ...process.env };
3298
4067
  for (const key of Object.keys(env)) delete openerEnv[key];
3299
4068
  let claimed = false;
@@ -3352,7 +4121,7 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
3352
4121
  if (macIpc.removeArtifacts) {
3353
4122
  macIpc.removeArtifacts(launchDir);
3354
4123
  } else {
3355
- (0, import_node_fs8.rmSync)(launchDir, {
4124
+ (0, import_node_fs12.rmSync)(launchDir, {
3356
4125
  recursive: true,
3357
4126
  force: true,
3358
4127
  maxRetries: 3,
@@ -3363,23 +4132,23 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
3363
4132
  }
3364
4133
  };
3365
4134
  try {
3366
- (0, import_node_fs8.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
3367
- (0, import_node_fs8.writeFileSync)(commandFile, `#!/bin/bash
4135
+ (0, import_node_fs12.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
4136
+ (0, import_node_fs12.writeFileSync)(commandFile, `#!/bin/bash
3368
4137
  rm -f -- "$0"
3369
4138
  exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
3370
4139
  `, {
3371
4140
  encoding: "utf8",
3372
4141
  mode: 448
3373
4142
  });
3374
- (0, import_node_fs8.chmodSync)(commandFile, 448);
3375
- (0, import_node_fs8.chmodSync)(bootstrapFile, 448);
4143
+ (0, import_node_fs12.chmodSync)(commandFile, 448);
4144
+ (0, import_node_fs12.chmodSync)(bootstrapFile, 448);
3376
4145
  server.once("error", handleLaunchFailure);
3377
4146
  server.listen(socketPath, () => {
3378
4147
  if (cleaned) return;
3379
4148
  try {
3380
4149
  macIpc.onListening?.();
3381
4150
  if (cleaned) return;
3382
- if (process.platform !== "win32") (0, import_node_fs8.chmodSync)(socketPath, 384);
4151
+ if (process.platform !== "win32") (0, import_node_fs12.chmodSync)(socketPath, 384);
3383
4152
  const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
3384
4153
  env: openerEnv,
3385
4154
  detached: true,
@@ -4025,6 +4794,7 @@ function applyAuditConfig(config) {
4025
4794
  } else {
4026
4795
  (0, import_auditSink.setAuditCaptureConfig)(null);
4027
4796
  (0, import_auditSink.setAuditSink)(null);
4797
+ writer?.reset();
4028
4798
  if (sweeper) {
4029
4799
  if (config) sweeper.configure(config);
4030
4800
  sweeper.dispose();
@@ -4611,6 +5381,7 @@ async function handleImport(body, deps) {
4611
5381
  }
4612
5382
 
4613
5383
  // src/admin/usagePricing.ts
5384
+ var import_usage = require("@omnicross/core/usage");
4614
5385
  var err4 = (status, message) => ({
4615
5386
  status,
4616
5387
  body: { error: { type: "admin_api_error", message } }
@@ -4636,6 +5407,9 @@ var BUCKET_SPAN_MS = {
4636
5407
  };
4637
5408
  var MAX_TIMESERIES_BUCKETS = 2e3;
4638
5409
  async function handleUsageGet(view, query2, deps) {
5410
+ if (view === "throughput") {
5411
+ return { status: 200, body: (0, import_usage.getSharedUsageThroughputTracker)().snapshot() };
5412
+ }
4639
5413
  const range = parseRange(query2);
4640
5414
  if (!isRange(range)) return range;
4641
5415
  switch (view) {
@@ -6269,10 +7043,10 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
6269
7043
  }
6270
7044
 
6271
7045
  // src/admin/uiStatic.ts
6272
- var import_node_fs9 = require("fs");
7046
+ var import_node_fs13 = require("fs");
6273
7047
  var import_promises = require("fs/promises");
6274
7048
  var import_node_module = require("module");
6275
- var import_node_path8 = __toESM(require("path"), 1);
7049
+ var import_node_path11 = __toESM(require("path"), 1);
6276
7050
  var import_meta = {};
6277
7051
  var CONTENT_TYPES = {
6278
7052
  ".html": "text/html; charset=utf-8",
@@ -6293,13 +7067,13 @@ var CONTENT_TYPES = {
6293
7067
  function resolveUiDist() {
6294
7068
  const fromEnv = process.env["OMNICROSS_UI_DIST"];
6295
7069
  if (fromEnv) {
6296
- return (0, import_node_fs9.existsSync)(import_node_path8.default.join(fromEnv, "index.html")) ? import_node_path8.default.resolve(fromEnv) : null;
7070
+ return (0, import_node_fs13.existsSync)(import_node_path11.default.join(fromEnv, "index.html")) ? import_node_path11.default.resolve(fromEnv) : null;
6297
7071
  }
6298
7072
  try {
6299
7073
  const req = (0, import_node_module.createRequire)(typeof __filename !== "undefined" ? __filename : import_meta.url);
6300
7074
  const pkgJson = req.resolve("@omnicross/ui/package.json");
6301
- const dist = import_node_path8.default.join(import_node_path8.default.dirname(pkgJson), "dist");
6302
- return (0, import_node_fs9.existsSync)(import_node_path8.default.join(dist, "index.html")) ? dist : null;
7075
+ const dist = import_node_path11.default.join(import_node_path11.default.dirname(pkgJson), "dist");
7076
+ return (0, import_node_fs13.existsSync)(import_node_path11.default.join(dist, "index.html")) ? dist : null;
6303
7077
  } catch {
6304
7078
  return null;
6305
7079
  }
@@ -6341,16 +7115,16 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
6341
7115
  res.end(JSON.stringify({ error: { type: "bad_request", message: "invalid path" } }));
6342
7116
  return true;
6343
7117
  }
6344
- const filePath = import_node_path8.default.resolve(uiDist, rel === "" ? "index.html" : rel);
6345
- if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path8.default.sep)) {
7118
+ const filePath = import_node_path11.default.resolve(uiDist, rel === "" ? "index.html" : rel);
7119
+ if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path11.default.sep)) {
6346
7120
  res.writeHead(403, { "Content-Type": "application/json" });
6347
7121
  res.end(JSON.stringify({ error: { type: "forbidden", message: "path outside ui root" } }));
6348
7122
  return true;
6349
7123
  }
6350
7124
  let target = filePath;
6351
- if (!(0, import_node_fs9.existsSync)(target) || (0, import_node_fs9.statSync)(target).isDirectory()) {
6352
- if (import_node_path8.default.extname(rel) === "") {
6353
- target = import_node_path8.default.join(uiDist, "index.html");
7125
+ if (!(0, import_node_fs13.existsSync)(target) || (0, import_node_fs13.statSync)(target).isDirectory()) {
7126
+ if (import_node_path11.default.extname(rel) === "") {
7127
+ target = import_node_path11.default.join(uiDist, "index.html");
6354
7128
  } else {
6355
7129
  res.writeHead(404, { "Content-Type": "application/json" });
6356
7130
  res.end(JSON.stringify({ error: { type: "not_found", message: "no such ui asset" } }));
@@ -6358,14 +7132,14 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
6358
7132
  }
6359
7133
  }
6360
7134
  const body = await (0, import_promises.readFile)(target);
6361
- const type = CONTENT_TYPES[import_node_path8.default.extname(target).toLowerCase()] ?? "application/octet-stream";
7135
+ const type = CONTENT_TYPES[import_node_path11.default.extname(target).toLowerCase()] ?? "application/octet-stream";
6362
7136
  res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
6363
7137
  res.end(req.method === "HEAD" ? void 0 : body);
6364
7138
  return true;
6365
7139
  }
6366
7140
 
6367
7141
  // src/admin/version.ts
6368
- var DAEMON_VERSION = true ? "0.1.9" : "0.0.0-dev";
7142
+ var DAEMON_VERSION = true ? "0.1.10" : "0.0.0-dev";
6369
7143
 
6370
7144
  // src/admin/AdminServer.ts
6371
7145
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -6477,6 +7251,14 @@ var AdminServer = class {
6477
7251
  await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
6478
7252
  return;
6479
7253
  }
7254
+ if (path2 === "/admin/api/audit/body" && (req.method === "GET" || req.method === "HEAD")) {
7255
+ handleAuditBodyQuery(req, res, this.deps.auditBodyReader);
7256
+ return;
7257
+ }
7258
+ if (path2 === "/admin/api/audit/compact" && req.method === "POST") {
7259
+ handleAuditCompact(res, this.deps.auditCompactor);
7260
+ return;
7261
+ }
6480
7262
  if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
6481
7263
  handleBillingStatus(res, this.deps.billingStatusReader);
6482
7264
  return;
@@ -6941,7 +7723,7 @@ function toLLMProvider(row) {
6941
7723
  }
6942
7724
 
6943
7725
  // src/ports/ConfigurableLogger.ts
6944
- var import_node_fs10 = require("fs");
7726
+ var import_node_fs14 = require("fs");
6945
7727
  var LEVEL_ORDER = { error: 0, warn: 1, info: 2, debug: 3 };
6946
7728
  var RESERVED_JSON_KEYS = /* @__PURE__ */ new Set(["ts", "level", "msg", "error"]);
6947
7729
  var ConfigurableLogger = class {
@@ -7017,7 +7799,7 @@ var ConfigurableLogger = class {
7017
7799
  if (this.fileDisabled || !this.filePath) return null;
7018
7800
  if (this.fileStream) return this.fileStream;
7019
7801
  try {
7020
- const stream = (0, import_node_fs10.createWriteStream)(this.filePath, { flags: "a" });
7802
+ const stream = (0, import_node_fs14.createWriteStream)(this.filePath, { flags: "a" });
7021
7803
  stream.on("error", () => {
7022
7804
  this.fileDisabled = true;
7023
7805
  this.fileStream = null;
@@ -7086,7 +7868,7 @@ function safeStringify(value) {
7086
7868
  }
7087
7869
 
7088
7870
  // src/ports/JsonApiServerSettingsStore.ts
7089
- var import_node_fs11 = require("fs");
7871
+ var import_node_fs15 = require("fs");
7090
7872
  var import_outbound_api4 = require("@omnicross/core/outbound-api");
7091
7873
  var JsonApiServerSettingsStore = class {
7092
7874
  /**
@@ -7113,7 +7895,7 @@ var JsonApiServerSettingsStore = class {
7113
7895
  if (key !== import_outbound_api4.OUTBOUND_API_SERVER_CONFIG_KEY) return;
7114
7896
  const file = this.readFile();
7115
7897
  file.server = this.encryptSecrets(value);
7116
- (0, import_node_fs11.writeFileSync)(this.configPath, JSON.stringify(file, null, 2) + "\n", "utf8");
7898
+ (0, import_node_fs15.writeFileSync)(this.configPath, JSON.stringify(file, null, 2) + "\n", "utf8");
7117
7899
  }
7118
7900
  /** Encrypt the proxy passwords + webhook + billing secrets before persisting (no-op without a box). */
7119
7901
  encryptSecrets(config) {
@@ -7136,7 +7918,7 @@ var JsonApiServerSettingsStore = class {
7136
7918
  /** Read the config.json, tolerating a missing/corrupt file (→ empty shape). */
7137
7919
  readFile() {
7138
7920
  try {
7139
- const raw = (0, import_node_fs11.readFileSync)(this.configPath, "utf8");
7921
+ const raw = (0, import_node_fs15.readFileSync)(this.configPath, "utf8");
7140
7922
  const parsed = JSON.parse(raw);
7141
7923
  if (parsed && typeof parsed === "object") return parsed;
7142
7924
  } catch {
@@ -7147,7 +7929,7 @@ var JsonApiServerSettingsStore = class {
7147
7929
 
7148
7930
  // src/ports/JsonlUsageEventStore.ts
7149
7931
  var import_node_crypto11 = require("crypto");
7150
- var import_node_fs12 = require("fs");
7932
+ var import_node_fs16 = require("fs");
7151
7933
  var JsonlUsageEventStore = class {
7152
7934
  constructor(eventsPath, isPriced) {
7153
7935
  this.eventsPath = eventsPath;
@@ -7162,7 +7944,7 @@ var JsonlUsageEventStore = class {
7162
7944
  id: (0, import_node_crypto11.randomUUID)(),
7163
7945
  ts: input.ts ?? Date.now()
7164
7946
  };
7165
- (0, import_node_fs12.appendFileSync)(this.eventsPath, JSON.stringify(row) + "\n", "utf8");
7947
+ (0, import_node_fs16.appendFileSync)(this.eventsPath, JSON.stringify(row) + "\n", "utf8");
7166
7948
  return row.id;
7167
7949
  }
7168
7950
  async getTotals(range) {
@@ -7361,10 +8143,10 @@ var JsonlUsageEventStore = class {
7361
8143
  }
7362
8144
  /** Parse every line, skipping malformed/torn lines defensively. */
7363
8145
  readAllRows() {
7364
- if (!(0, import_node_fs12.existsSync)(this.eventsPath)) return [];
8146
+ if (!(0, import_node_fs16.existsSync)(this.eventsPath)) return [];
7365
8147
  let raw;
7366
8148
  try {
7367
- raw = (0, import_node_fs12.readFileSync)(this.eventsPath, "utf8");
8149
+ raw = (0, import_node_fs16.readFileSync)(this.eventsPath, "utf8");
7368
8150
  } catch {
7369
8151
  return [];
7370
8152
  }
@@ -7403,15 +8185,15 @@ function nextBoundary(ts, bucket) {
7403
8185
  return new Date(d.getFullYear(), d.getMonth() + 1, 1).getTime();
7404
8186
  }
7405
8187
  }
7406
- var pad2 = (n) => String(n).padStart(2, "0");
8188
+ var pad22 = (n) => String(n).padStart(2, "0");
7407
8189
  function bucketLabel(bucketStartTs, bucket) {
7408
8190
  const d = new Date(bucketStartTs);
7409
8191
  const y = d.getFullYear();
7410
- const mo = pad2(d.getMonth() + 1);
7411
- const day = pad2(d.getDate());
8192
+ const mo = pad22(d.getMonth() + 1);
8193
+ const day = pad22(d.getDate());
7412
8194
  switch (bucket) {
7413
8195
  case "hour":
7414
- return `${mo}-${day} ${pad2(d.getHours())}:00`;
8196
+ return `${mo}-${day} ${pad22(d.getHours())}:00`;
7415
8197
  case "day":
7416
8198
  return `${y}-${mo}-${day}`;
7417
8199
  case "month":
@@ -7467,7 +8249,7 @@ function median(values) {
7467
8249
  }
7468
8250
 
7469
8251
  // src/ports/JsonPricingStore.ts
7470
- var import_node_fs13 = require("fs");
8252
+ var import_node_fs17 = require("fs");
7471
8253
  var import_node_crypto12 = require("crypto");
7472
8254
  var JsonPricingStore = class {
7473
8255
  constructor(pricingPath) {
@@ -7482,9 +8264,9 @@ var JsonPricingStore = class {
7482
8264
  * otherwise unusable pricing table after a crash or manual file edit.
7483
8265
  */
7484
8266
  hasUsableSnapshot() {
7485
- if (!(0, import_node_fs13.existsSync)(this.pricingPath)) return false;
8267
+ if (!(0, import_node_fs17.existsSync)(this.pricingPath)) return false;
7486
8268
  try {
7487
- const parsed = JSON.parse((0, import_node_fs13.readFileSync)(this.pricingPath, "utf8"));
8269
+ const parsed = JSON.parse((0, import_node_fs17.readFileSync)(this.pricingPath, "utf8"));
7488
8270
  return Array.isArray(parsed) && parsed.some(isUsablePricingRow);
7489
8271
  } catch {
7490
8272
  return false;
@@ -7597,9 +8379,9 @@ var JsonPricingStore = class {
7597
8379
  }
7598
8380
  /** Read the pricing rows, tolerating a missing/corrupt file (→ empty list). */
7599
8381
  readRows() {
7600
- if (!(0, import_node_fs13.existsSync)(this.pricingPath)) return [];
8382
+ if (!(0, import_node_fs17.existsSync)(this.pricingPath)) return [];
7601
8383
  try {
7602
- const parsed = JSON.parse((0, import_node_fs13.readFileSync)(this.pricingPath, "utf8"));
8384
+ const parsed = JSON.parse((0, import_node_fs17.readFileSync)(this.pricingPath, "utf8"));
7603
8385
  return Array.isArray(parsed) ? parsed : [];
7604
8386
  } catch {
7605
8387
  return [];
@@ -7608,18 +8390,18 @@ var JsonPricingStore = class {
7608
8390
  writeRows(rows) {
7609
8391
  const temporaryPath = `${this.pricingPath}.${process.pid}.${(0, import_node_crypto12.randomUUID)()}.tmp`;
7610
8392
  try {
7611
- (0, import_node_fs13.writeFileSync)(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
8393
+ (0, import_node_fs17.writeFileSync)(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
7612
8394
  encoding: "utf8",
7613
8395
  flag: "wx"
7614
8396
  });
7615
8397
  this.replaceFile(temporaryPath);
7616
8398
  } finally {
7617
- (0, import_node_fs13.rmSync)(temporaryPath, { force: true });
8399
+ (0, import_node_fs17.rmSync)(temporaryPath, { force: true });
7618
8400
  }
7619
8401
  }
7620
8402
  /** Isolated for deterministic failure testing; never removes the target. */
7621
8403
  replaceFile(temporaryPath) {
7622
- (0, import_node_fs13.renameSync)(temporaryPath, this.pricingPath);
8404
+ (0, import_node_fs17.renameSync)(temporaryPath, this.pricingPath);
7623
8405
  }
7624
8406
  };
7625
8407
  function isUsablePricingRow(value) {
@@ -7629,7 +8411,7 @@ function isUsablePricingRow(value) {
7629
8411
  }
7630
8412
 
7631
8413
  // src/pricing/PricingRefreshScheduler.ts
7632
- var import_node_fs14 = require("fs");
8414
+ var import_node_fs18 = require("fs");
7633
8415
  var EMPTY_STATE2 = {
7634
8416
  lastAttemptAt: null,
7635
8417
  lastSuccessAt: null,
@@ -7667,9 +8449,9 @@ var PricingRefreshScheduler = class {
7667
8449
  this.timer = null;
7668
8450
  }
7669
8451
  getState() {
7670
- if (!(0, import_node_fs14.existsSync)(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
8452
+ if (!(0, import_node_fs18.existsSync)(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
7671
8453
  try {
7672
- const value = JSON.parse((0, import_node_fs14.readFileSync)(this.statePath, "utf8"));
8454
+ const value = JSON.parse((0, import_node_fs18.readFileSync)(this.statePath, "utf8"));
7673
8455
  return {
7674
8456
  lastAttemptAt: finiteOrNull(value.lastAttemptAt),
7675
8457
  lastSuccessAt: finiteOrNull(value.lastSuccessAt),
@@ -7722,9 +8504,9 @@ var PricingRefreshScheduler = class {
7722
8504
  }
7723
8505
  writeState(state) {
7724
8506
  const temporaryPath = `${this.statePath}.tmp`;
7725
- (0, import_node_fs14.writeFileSync)(temporaryPath, `${JSON.stringify(state, null, 2)}
8507
+ (0, import_node_fs18.writeFileSync)(temporaryPath, `${JSON.stringify(state, null, 2)}
7726
8508
  `, "utf8");
7727
- (0, import_node_fs14.renameSync)(temporaryPath, this.statePath);
8509
+ (0, import_node_fs18.renameSync)(temporaryPath, this.statePath);
7728
8510
  }
7729
8511
  };
7730
8512
  function finiteOrNull(value) {
@@ -7732,7 +8514,7 @@ function finiteOrNull(value) {
7732
8514
  }
7733
8515
 
7734
8516
  // src/ports/JsonVoucherDb.ts
7735
- var import_node_fs15 = require("fs");
8517
+ var import_node_fs19 = require("fs");
7736
8518
  var JsonVoucherDb = class {
7737
8519
  constructor(vouchersPath) {
7738
8520
  this.vouchersPath = vouchersPath;
@@ -7810,22 +8592,22 @@ var JsonVoucherDb = class {
7810
8592
  }
7811
8593
  /** Read the voucher rows, tolerating a missing/corrupt file (→ empty list). */
7812
8594
  readRows() {
7813
- if (!(0, import_node_fs15.existsSync)(this.vouchersPath)) return [];
8595
+ if (!(0, import_node_fs19.existsSync)(this.vouchersPath)) return [];
7814
8596
  try {
7815
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(this.vouchersPath, "utf8"));
8597
+ const parsed = JSON.parse((0, import_node_fs19.readFileSync)(this.vouchersPath, "utf8"));
7816
8598
  return Array.isArray(parsed) ? parsed : [];
7817
8599
  } catch {
7818
8600
  return [];
7819
8601
  }
7820
8602
  }
7821
8603
  writeRows(rows) {
7822
- (0, import_node_fs15.writeFileSync)(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
8604
+ (0, import_node_fs19.writeFileSync)(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
7823
8605
  }
7824
8606
  };
7825
8607
 
7826
8608
  // src/ports/JsonSubscriptionCredentialStore.ts
7827
- var import_node_fs17 = require("fs");
7828
- var import_node_path10 = require("path");
8609
+ var import_node_fs21 = require("fs");
8610
+ var import_node_path13 = require("path");
7829
8611
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
7830
8612
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
7831
8613
  var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
@@ -7874,11 +8656,11 @@ function findDuplicateCredentialIds(accounts) {
7874
8656
  }
7875
8657
 
7876
8658
  // src/ports/external-cli-credentials.ts
7877
- var import_node_fs16 = require("fs");
8659
+ var import_node_fs20 = require("fs");
7878
8660
  var import_node_os4 = require("os");
7879
- var import_node_path9 = require("path");
8661
+ var import_node_path12 = require("path");
7880
8662
  function externalStorePath(provider, home = (0, import_node_os4.homedir)()) {
7881
- return provider === "claude" ? (0, import_node_path9.join)(home, ".claude", ".credentials.json") : (0, import_node_path9.join)(home, ".codex", "auth.json");
8663
+ return provider === "claude" ? (0, import_node_path12.join)(home, ".claude", ".credentials.json") : (0, import_node_path12.join)(home, ".codex", "auth.json");
7882
8664
  }
7883
8665
  function decodeJwtExpiryMs(token) {
7884
8666
  try {
@@ -7927,10 +8709,10 @@ function parseCodexTokensEnvelope(raw) {
7927
8709
  }
7928
8710
  function readExternalCliCredentials(provider, home = (0, import_node_os4.homedir)()) {
7929
8711
  const path2 = externalStorePath(provider, home);
7930
- if (!(0, import_node_fs16.existsSync)(path2)) return null;
8712
+ if (!(0, import_node_fs20.existsSync)(path2)) return null;
7931
8713
  let raw;
7932
8714
  try {
7933
- const parsed = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
8715
+ const parsed = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
7934
8716
  raw = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
7935
8717
  } catch {
7936
8718
  return null;
@@ -8501,9 +9283,9 @@ var JsonSubscriptionCredentialStore = class {
8501
9283
  * `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
8502
9284
  * write incl. child 4's future refresh writes lands encrypted. */
8503
9285
  persist(config) {
8504
- (0, import_node_fs17.mkdirSync)((0, import_node_path10.dirname)(this.tokensPath), { recursive: true });
9286
+ (0, import_node_fs21.mkdirSync)((0, import_node_path13.dirname)(this.tokensPath), { recursive: true });
8505
9287
  const encrypted = encryptTokens(config, this.box);
8506
- (0, import_node_fs17.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
9288
+ (0, import_node_fs21.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
8507
9289
  }
8508
9290
  /**
8509
9291
  * Read + parse `tokens.json`, tolerating a missing/corrupt file, then DECRYPT
@@ -8519,10 +9301,10 @@ var JsonSubscriptionCredentialStore = class {
8519
9301
  * `config.ts loadConfig`, which decrypts outside its parse try.
8520
9302
  */
8521
9303
  readConfig() {
8522
- if (!(0, import_node_fs17.existsSync)(this.tokensPath)) return { updatedAt: "" };
9304
+ if (!(0, import_node_fs21.existsSync)(this.tokensPath)) return { updatedAt: "" };
8523
9305
  let parsed;
8524
9306
  try {
8525
- const raw = JSON.parse((0, import_node_fs17.readFileSync)(this.tokensPath, "utf8"));
9307
+ const raw = JSON.parse((0, import_node_fs21.readFileSync)(this.tokensPath, "utf8"));
8526
9308
  parsed = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
8527
9309
  } catch {
8528
9310
  parsed = null;
@@ -9039,32 +9821,14 @@ var AccountHealthSweeper = class {
9039
9821
  };
9040
9822
 
9041
9823
  // src/audit/AuditPruneSweeper.ts
9042
- var import_node_fs19 = require("fs");
9043
- var import_node_path12 = require("path");
9044
-
9045
- // src/audit/auditFiles.ts
9046
- var AUDIT_FILE_RE = /^audit-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
9047
- var pad22 = (n) => String(n).padStart(2, "0");
9048
- function auditFileName(ts) {
9049
- const d = new Date(ts);
9050
- return `audit-${d.getFullYear()}-${pad22(d.getMonth() + 1)}-${pad22(d.getDate())}.jsonl`;
9051
- }
9052
- function auditFileDateMs(fileName) {
9053
- const m = AUDIT_FILE_RE.exec(fileName);
9054
- if (!m) return null;
9055
- const year = Number(m[1]);
9056
- const month = Number(m[2]);
9057
- const day = Number(m[3]);
9058
- const d = new Date(year, month - 1, day);
9059
- if (d.getFullYear() !== year || d.getMonth() !== month - 1 || d.getDate() !== day) {
9060
- return null;
9061
- }
9062
- return d.getTime();
9063
- }
9824
+ var import_node_fs23 = require("fs");
9825
+ var import_node_path15 = require("path");
9826
+ var import_promises2 = require("stream/promises");
9827
+ var import_node_zlib2 = require("zlib");
9064
9828
 
9065
9829
  // src/audit/auditStats.ts
9066
- var import_node_fs18 = require("fs");
9067
- var import_node_path11 = require("path");
9830
+ var import_node_fs22 = require("fs");
9831
+ var import_node_path14 = require("path");
9068
9832
  var SIDECAR_VERSION = 1;
9069
9833
  var META_PREFIX_BYTES = 64 * 1024;
9070
9834
  var READ_CHUNK_BYTES = 4 * 1024 * 1024;
@@ -9072,9 +9836,9 @@ function auditStatsFileName(auditFile) {
9072
9836
  return auditFile.replace(/\.jsonl$/, ".stats.json");
9073
9837
  }
9074
9838
  function readPersisted(path2) {
9075
- if (!(0, import_node_fs18.existsSync)(path2)) return null;
9839
+ if (!(0, import_node_fs22.existsSync)(path2)) return null;
9076
9840
  try {
9077
- const value = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
9841
+ const value = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
9078
9842
  if (value.version !== SIDECAR_VERSION || !Number.isSafeInteger(value.auditBytes) || (value.auditBytes ?? -1) < 0 || !Number.isSafeInteger(value.requestCount) || (value.requestCount ?? -1) < 0 || !Number.isSafeInteger(value.errorCount) || (value.errorCount ?? -1) < 0 || (value.errorCount ?? 0) > (value.requestCount ?? -1) || typeof value.complete !== "boolean" || value.minTs !== null && !Number.isFinite(value.minTs) || value.maxTs !== null && !Number.isFinite(value.maxTs)) {
9079
9843
  return null;
9080
9844
  }
@@ -9084,7 +9848,7 @@ function readPersisted(path2) {
9084
9848
  }
9085
9849
  }
9086
9850
  function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
9087
- const statsPath = (0, import_node_path11.join)((0, import_node_path11.dirname)(auditPath), auditStatsFileName((0, import_node_path11.basename)(auditPath)));
9851
+ const statsPath = (0, import_node_path14.join)((0, import_node_path14.dirname)(auditPath), auditStatsFileName((0, import_node_path14.basename)(auditPath)));
9088
9852
  const previous = auditBytesBefore === 0 ? {
9089
9853
  version: SIDECAR_VERSION,
9090
9854
  auditBytes: 0,
@@ -9104,13 +9868,13 @@ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfte
9104
9868
  minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
9105
9869
  maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
9106
9870
  };
9107
- (0, import_node_fs18.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
9871
+ (0, import_node_fs22.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
9108
9872
  }
9109
9873
  function queryCovers(stats, from, to) {
9110
9874
  return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
9111
9875
  }
9112
- function fileOverlaps(file, from, to) {
9113
- const start = auditFileDateMs(file);
9876
+ function fileOverlaps(name, from, to) {
9877
+ const start = auditFileDateMs(name);
9114
9878
  if (start === null) return false;
9115
9879
  const date = new Date(start);
9116
9880
  const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
@@ -9162,7 +9926,7 @@ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
9162
9926
  prefixTruncated = false;
9163
9927
  };
9164
9928
  if (auditBytes > startByte) {
9165
- const stream = (0, import_node_fs18.createReadStream)(auditPath, {
9929
+ const stream = (0, import_node_fs22.createReadStream)(auditPath, {
9166
9930
  start: startByte,
9167
9931
  end: auditBytes - 1,
9168
9932
  highWaterMark: READ_CHUNK_BYTES
@@ -9215,21 +9979,27 @@ function mergePersistedStats(previous, appended) {
9215
9979
  };
9216
9980
  }
9217
9981
  async function readAuditStats(auditDir, query2 = {}) {
9218
- if (!(0, import_node_fs18.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
9982
+ if (!(0, import_node_fs22.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
9219
9983
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
9220
9984
  const to = typeof query2.to === "number" ? query2.to : Infinity;
9221
- let files;
9985
+ let sources;
9222
9986
  try {
9223
- files = (0, import_node_fs18.readdirSync)(auditDir).filter((file) => AUDIT_FILE_RE.test(file) && fileOverlaps(file, from, to)).sort();
9987
+ sources = (0, import_node_fs22.readdirSync)(auditDir).filter((name) => fileOverlaps(name, from, to)).sort().map(
9988
+ (name) => AUDIT_DAY_DIR_RE.test(name) ? {
9989
+ auditPath: (0, import_node_path14.join)(auditDir, name, AUDIT_META_FILE),
9990
+ statsPath: (0, import_node_path14.join)(auditDir, name, auditStatsFileName(AUDIT_META_FILE))
9991
+ } : {
9992
+ auditPath: (0, import_node_path14.join)(auditDir, name),
9993
+ statsPath: (0, import_node_path14.join)(auditDir, auditStatsFileName(name))
9994
+ }
9995
+ ).filter((source) => (0, import_node_fs22.existsSync)(source.auditPath));
9224
9996
  } catch {
9225
9997
  return { requestCount: 0, errorCount: 0, complete: false };
9226
9998
  }
9227
9999
  const total = { requestCount: 0, errorCount: 0, complete: true };
9228
- for (const file of files) {
9229
- const auditPath = (0, import_node_path11.join)(auditDir, file);
10000
+ for (const { auditPath, statsPath } of sources) {
9230
10001
  try {
9231
- const auditBytes = (0, import_node_fs18.statSync)(auditPath).size;
9232
- const statsPath = (0, import_node_path11.join)(auditDir, auditStatsFileName(file));
10002
+ const auditBytes = (0, import_node_fs22.statSync)(auditPath).size;
9233
10003
  const persisted = readPersisted(statsPath);
9234
10004
  if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
9235
10005
  total.requestCount += persisted.requestCount;
@@ -9248,7 +10018,7 @@ async function readAuditStats(auditDir, query2 = {}) {
9248
10018
  total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
9249
10019
  total.complete = total.complete && scanned.filtered.complete;
9250
10020
  const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
9251
- if (current.complete) (0, import_node_fs18.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
10021
+ if (current.complete) (0, import_node_fs22.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
9252
10022
  } catch {
9253
10023
  total.complete = false;
9254
10024
  }
@@ -9259,6 +10029,7 @@ async function readAuditStats(auditDir, query2 = {}) {
9259
10029
  // src/audit/AuditPruneSweeper.ts
9260
10030
  var DAY_MS = 24 * 60 * 6e4;
9261
10031
  var SWEEP_INTERVAL_MS2 = 60 * 6e4;
10032
+ var ARCHIVE_BATCH = 64;
9262
10033
  var AuditPruneSweeper = class {
9263
10034
  constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
9264
10035
  this.auditDir = auditDir;
@@ -9274,6 +10045,7 @@ var AuditPruneSweeper = class {
9274
10045
  now;
9275
10046
  timer = null;
9276
10047
  sweeping = false;
10048
+ archiving = false;
9277
10049
  /** Whether pruning is active (audit enabled). */
9278
10050
  get enabled() {
9279
10051
  return this.config.enabled;
@@ -9283,13 +10055,13 @@ var AuditPruneSweeper = class {
9283
10055
  this.config = config;
9284
10056
  }
9285
10057
  /**
9286
- * Arm the prune interval AND run one prune immediately (boot cleanup). No-op
9287
- * when audit is disabled (zero regression). Idempotent.
10058
+ * Arm the interval AND run one pass immediately (boot cleanup). No-op when
10059
+ * audit is disabled (zero regression). Idempotent.
9288
10060
  */
9289
10061
  start() {
9290
10062
  if (this.timer || !this.config.enabled) return;
9291
- void this.sweep();
9292
- this.timer = setInterval(() => void this.sweep(), this.intervalMs);
10063
+ void this.runOnce();
10064
+ this.timer = setInterval(() => void this.runOnce(), this.intervalMs);
9293
10065
  this.timer.unref?.();
9294
10066
  }
9295
10067
  /** Clear the interval (daemon shutdown / test teardown). Idempotent. */
@@ -9299,31 +10071,43 @@ var AuditPruneSweeper = class {
9299
10071
  this.timer = null;
9300
10072
  }
9301
10073
  }
10074
+ /** Prune first, then archive — never spend CPU compressing a day about to go. */
10075
+ async runOnce() {
10076
+ await this.sweep();
10077
+ await this.archive();
10078
+ }
10079
+ /** The LOCAL-midnight epoch ms of the current day. */
10080
+ todayMidnight() {
10081
+ const today = new Date(this.now());
10082
+ return new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
10083
+ }
9302
10084
  /**
9303
- * One prune: unlink every audit date file strictly OLDER than the retention
9304
- * cutoff (`now - retentionDays` days, at local-midnight granularity). Exposed
9305
- * for tests; never throws. Returns the number of files removed.
10085
+ * One prune: remove every audit day strictly OLDER than the retention cutoff
10086
+ * (`now - retentionDays` days, at local-midnight granularity). Exposed for
10087
+ * tests; never throws. Returns the number of days removed.
9306
10088
  */
9307
10089
  async sweep() {
9308
10090
  if (!this.config.enabled || this.sweeping) return 0;
9309
10091
  this.sweeping = true;
9310
10092
  try {
9311
- if (!(0, import_node_fs19.existsSync)(this.auditDir)) return 0;
9312
- const today = new Date(this.now());
9313
- const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
9314
- const cutoff = todayMidnight - (this.config.retentionDays - 1) * DAY_MS;
10093
+ if (!(0, import_node_fs23.existsSync)(this.auditDir)) return 0;
10094
+ const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS;
9315
10095
  let removed = 0;
9316
- for (const file of (0, import_node_fs19.readdirSync)(this.auditDir)) {
9317
- const dateMs = auditFileDateMs(file);
10096
+ for (const name of (0, import_node_fs23.readdirSync)(this.auditDir)) {
10097
+ const dateMs = auditFileDateMs(name);
9318
10098
  if (dateMs === null || dateMs >= cutoff) continue;
9319
10099
  try {
9320
- (0, import_node_fs19.unlinkSync)((0, import_node_path12.join)(this.auditDir, file));
10100
+ if (isAuditDayDir(name)) {
10101
+ (0, import_node_fs23.rmSync)((0, import_node_path15.join)(this.auditDir, name), { recursive: true, force: true });
10102
+ } else {
10103
+ (0, import_node_fs23.unlinkSync)((0, import_node_path15.join)(this.auditDir, name));
10104
+ const statsPath = (0, import_node_path15.join)(this.auditDir, auditStatsFileName(name));
10105
+ if ((0, import_node_fs23.existsSync)(statsPath)) (0, import_node_fs23.unlinkSync)(statsPath);
10106
+ }
9321
10107
  removed += 1;
9322
- const statsPath = (0, import_node_path12.join)(this.auditDir, auditStatsFileName(file));
9323
- if ((0, import_node_fs19.existsSync)(statsPath)) (0, import_node_fs19.unlinkSync)(statsPath);
9324
10108
  } catch (error) {
9325
- this.logger.warn("[AuditPruneSweeper] failed to unlink expired audit file", {
9326
- file,
10109
+ this.logger.warn("[AuditPruneSweeper] failed to remove expired audit day", {
10110
+ name,
9327
10111
  error: error instanceof Error ? error.message : String(error)
9328
10112
  });
9329
10113
  }
@@ -9339,59 +10123,158 @@ var AuditPruneSweeper = class {
9339
10123
  this.sweeping = false;
9340
10124
  }
9341
10125
  }
10126
+ /**
10127
+ * Gzip the body shards of every CLOSED day (anything before today). Today is
10128
+ * deliberately left as plain text so it stays greppable while it is the day you
10129
+ * are debugging. Exposed for tests; never throws. Returns shards compressed.
10130
+ */
10131
+ async archive() {
10132
+ if (!this.config.enabled || this.archiving) return 0;
10133
+ this.archiving = true;
10134
+ try {
10135
+ if (!(0, import_node_fs23.existsSync)(this.auditDir)) return 0;
10136
+ const today = this.todayMidnight();
10137
+ let compressed = 0;
10138
+ for (const name of (0, import_node_fs23.readdirSync)(this.auditDir)) {
10139
+ if (compressed >= ARCHIVE_BATCH) break;
10140
+ const dateMs = auditFileDateMs(name);
10141
+ if (dateMs === null || dateMs >= today || !isAuditDayDir(name)) continue;
10142
+ const dayPath = (0, import_node_path15.join)(this.auditDir, name);
10143
+ try {
10144
+ const compaction = compactAuditDay(dayPath);
10145
+ if (compaction.shards > 0) {
10146
+ this.logger.debug("audit cross-session compaction complete", {
10147
+ day: name,
10148
+ shards: compaction.shards,
10149
+ anchors: compaction.anchors,
10150
+ savedBytes: compaction.savedBytes
10151
+ });
10152
+ }
10153
+ } catch (error) {
10154
+ this.logger.warn("[AuditPruneSweeper] cross-session compaction failed", {
10155
+ day: name,
10156
+ error: error instanceof Error ? error.message : String(error)
10157
+ });
10158
+ }
10159
+ compressed += await this.archiveDay(
10160
+ (0, import_node_path15.join)(dayPath, AUDIT_BODIES_DIR),
10161
+ ARCHIVE_BATCH - compressed
10162
+ );
10163
+ }
10164
+ if (compressed > 0) this.logger.debug("audit archive complete", { compressed });
10165
+ return compressed;
10166
+ } catch (error) {
10167
+ this.logger.warn("audit archive pass failed", {
10168
+ error: error instanceof Error ? error.message : String(error)
10169
+ });
10170
+ return 0;
10171
+ } finally {
10172
+ this.archiving = false;
10173
+ }
10174
+ }
10175
+ /** Gzip up to `budget` plain shards in one day's `bodies/` directory. */
10176
+ async archiveDay(bodiesPath, budget) {
10177
+ let shards;
10178
+ try {
10179
+ shards = (0, import_node_fs23.readdirSync)(bodiesPath).filter((file) => file.endsWith(".jsonl"));
10180
+ } catch {
10181
+ return 0;
10182
+ }
10183
+ let compressed = 0;
10184
+ for (const shard of shards) {
10185
+ if (compressed >= budget) break;
10186
+ const source = (0, import_node_path15.join)(bodiesPath, shard);
10187
+ const target = `${source}.gz`;
10188
+ try {
10189
+ if ((0, import_node_fs23.existsSync)(target)) {
10190
+ (0, import_node_fs23.unlinkSync)(source);
10191
+ continue;
10192
+ }
10193
+ await (0, import_promises2.pipeline)((0, import_node_fs23.createReadStream)(source), (0, import_node_zlib2.createGzip)(), (0, import_node_fs23.createWriteStream)(target));
10194
+ (0, import_node_fs23.unlinkSync)(source);
10195
+ compressed += 1;
10196
+ } catch (error) {
10197
+ try {
10198
+ if ((0, import_node_fs23.existsSync)(target)) (0, import_node_fs23.unlinkSync)(target);
10199
+ } catch {
10200
+ }
10201
+ this.logger.warn("[AuditPruneSweeper] failed to archive audit body shard", {
10202
+ shard,
10203
+ error: error instanceof Error ? error.message : String(error)
10204
+ });
10205
+ }
10206
+ }
10207
+ return compressed;
10208
+ }
9342
10209
  };
9343
10210
 
9344
10211
  // src/audit/auditReader.ts
9345
- var import_node_fs20 = require("fs");
9346
- var import_node_path13 = require("path");
10212
+ var import_node_fs24 = require("fs");
10213
+ var import_node_path16 = require("path");
9347
10214
  var DEFAULT_LIMIT = 200;
9348
10215
  var MAX_LIMIT = 2e3;
9349
- function readAuditRecords(auditDir, query2 = {}) {
9350
- if (!(0, import_node_fs20.existsSync)(auditDir)) return [];
9351
- let files;
10216
+ var OVERSCAN = 256;
10217
+ function daySources(auditDir) {
10218
+ let names;
9352
10219
  try {
9353
- files = (0, import_node_fs20.readdirSync)(auditDir).filter((f) => AUDIT_FILE_RE.test(f));
10220
+ names = (0, import_node_fs24.readdirSync)(auditDir);
9354
10221
  } catch {
9355
10222
  return [];
9356
10223
  }
10224
+ const sources = [];
10225
+ for (const name of names) {
10226
+ const dateMs = auditFileDateMs(name);
10227
+ if (dateMs === null) continue;
10228
+ if (AUDIT_DAY_DIR_RE.test(name)) {
10229
+ const path2 = (0, import_node_path16.join)(auditDir, name, AUDIT_META_FILE);
10230
+ if ((0, import_node_fs24.existsSync)(path2)) sources.push({ path: path2, dateMs });
10231
+ } else if (AUDIT_FILE_RE.test(name)) {
10232
+ sources.push({ path: (0, import_node_path16.join)(auditDir, name), dateMs });
10233
+ }
10234
+ }
10235
+ return sources.sort((a, b) => b.dateMs - a.dateMs);
10236
+ }
10237
+ function isAuditRecord(value) {
10238
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
10239
+ const r = value;
10240
+ return typeof r["id"] === "string" && typeof r["ts"] === "number" && typeof r["method"] === "string" && typeof r["path"] === "string" && typeof r["status"] === "number";
10241
+ }
10242
+ function toMetaRecord(record) {
10243
+ if (record.requestBody === void 0 && record.responseBody === void 0) return record;
10244
+ const { requestBody: _req, responseBody: _res, ...meta } = record;
10245
+ return { ...meta, hasBody: true };
10246
+ }
10247
+ function readAuditRecords(auditDir, query2 = {}) {
10248
+ if (!(0, import_node_fs24.existsSync)(auditDir)) return [];
9357
10249
  const from = typeof query2.from === "number" ? query2.from : -Infinity;
9358
10250
  const to = typeof query2.to === "number" ? query2.to : Infinity;
9359
10251
  const limit = Math.min(MAX_LIMIT, Math.max(1, Math.trunc(query2.limit ?? DEFAULT_LIMIT)));
9360
10252
  const matched = [];
9361
- for (const file of files.sort().reverse()) {
9362
- let raw;
9363
- try {
9364
- raw = (0, import_node_fs20.readFileSync)((0, import_node_path13.join)(auditDir, file), "utf8");
9365
- } catch {
9366
- continue;
9367
- }
9368
- for (const line of raw.split("\n")) {
9369
- const trimmed = line.trim();
9370
- if (!trimmed) continue;
9371
- let rec;
10253
+ for (const source of daySources(auditDir)) {
10254
+ const before = matched.length;
10255
+ forEachLineFromTail(source.path, (line) => {
10256
+ let parsed;
9372
10257
  try {
9373
- rec = JSON.parse(trimmed);
10258
+ parsed = JSON.parse(line);
9374
10259
  } catch {
9375
- continue;
10260
+ return false;
9376
10261
  }
9377
- if (!isAuditRecord(rec)) continue;
9378
- if (query2.keyId !== void 0 && rec.keyId !== query2.keyId) continue;
9379
- if (rec.ts < from || rec.ts > to) continue;
9380
- matched.push(rec);
9381
- }
10262
+ if (!isAuditRecord(parsed)) return false;
10263
+ if (query2.keyId !== void 0 && parsed.keyId !== query2.keyId) return false;
10264
+ if (query2.sessionKey !== void 0 && parsed.sessionKey !== query2.sessionKey) return false;
10265
+ if (parsed.ts < from || parsed.ts > to) return false;
10266
+ matched.push(toMetaRecord(parsed));
10267
+ return matched.length - before >= limit + OVERSCAN;
10268
+ });
10269
+ if (matched.length >= limit) break;
9382
10270
  }
9383
10271
  matched.sort((a, b) => b.ts - a.ts);
9384
10272
  return matched.slice(0, limit);
9385
10273
  }
9386
- function isAuditRecord(value) {
9387
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
9388
- const r = value;
9389
- return typeof r["id"] === "string" && typeof r["ts"] === "number" && typeof r["method"] === "string" && typeof r["path"] === "string" && typeof r["status"] === "number";
9390
- }
9391
10274
 
9392
10275
  // src/audit/AuditWriter.ts
9393
- var import_node_fs21 = require("fs");
9394
- var import_node_path14 = require("path");
10276
+ var import_node_fs25 = require("fs");
10277
+ var import_node_path17 = require("path");
9395
10278
  var AuditWriter = class {
9396
10279
  constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
9397
10280
  this.auditDir = auditDir;
@@ -9401,10 +10284,13 @@ var AuditWriter = class {
9401
10284
  auditDir;
9402
10285
  logger;
9403
10286
  defer;
9404
- dirEnsured = false;
10287
+ /** Day directories already created this process (avoids an mkdir per record). */
10288
+ ensuredDirs = /* @__PURE__ */ new Set();
10289
+ /** Per-session encoding bases. Memory-only; a miss simply writes a full snapshot. */
10290
+ bases = new SessionBaseCache();
9405
10291
  /**
9406
- * Enqueue one record for append. Returns IMMEDIATELY (fire-and-forget); the fs
9407
- * write happens on the deferred tick. A failure is logged, never thrown.
10292
+ * Enqueue one record. Returns IMMEDIATELY (fire-and-forget); every fs write and
10293
+ * the delta encoding happen on the deferred tick. A failure is logged, never thrown.
9408
10294
  */
9409
10295
  record(record) {
9410
10296
  this.defer(() => {
@@ -9417,25 +10303,41 @@ var AuditWriter = class {
9417
10303
  }
9418
10304
  });
9419
10305
  }
10306
+ /** Drop all retained encoding bases (config reload / shutdown / test teardown). */
10307
+ reset() {
10308
+ this.bases.clear();
10309
+ this.ensuredDirs.clear();
10310
+ }
9420
10311
  /**
9421
- * Append synchronously — the awaitable form tests use to assert the line landed.
9422
- * Ensures the `audit/` directory exists on first write (lazy, like the usage
9423
- * store's lazy file creation).
10312
+ * Append synchronously — the awaitable form tests use to assert a line landed.
10313
+ * Writes the metadata line first (canonical), then the body shard.
9424
10314
  */
9425
10315
  appendNow(record) {
9426
- if (!this.dirEnsured) {
9427
- (0, import_node_fs21.mkdirSync)(this.auditDir, { recursive: true });
9428
- this.dirEnsured = true;
9429
- }
9430
- const file = (0, import_node_path14.join)(this.auditDir, auditFileName(record.ts));
9431
- const line = JSON.stringify(record) + "\n";
9432
- const auditBytesBefore = (0, import_node_fs21.existsSync)(file) ? (0, import_node_fs21.statSync)(file).size : 0;
9433
- (0, import_node_fs21.appendFileSync)(file, line, "utf8");
10316
+ const dayDir = auditDayDirName(record.ts);
10317
+ const dayPath = this.ensureDir((0, import_node_path17.join)(this.auditDir, dayDir));
10318
+ this.appendMeta(dayPath, record);
10319
+ this.appendBody(dayPath, dayDir, record);
10320
+ }
10321
+ /** Create a directory once per process and remember it. */
10322
+ ensureDir(path2) {
10323
+ if (!this.ensuredDirs.has(path2)) {
10324
+ (0, import_node_fs25.mkdirSync)(path2, { recursive: true });
10325
+ this.ensuredDirs.add(path2);
10326
+ }
10327
+ return path2;
10328
+ }
10329
+ /** Write the body-free metadata line + refresh the exact-count sidecar. */
10330
+ appendMeta(dayPath, record) {
10331
+ const { requestBody: _req, responseBody: _res, ...meta } = record;
10332
+ const file = (0, import_node_path17.join)(dayPath, AUDIT_META_FILE);
10333
+ const line = JSON.stringify(meta) + "\n";
10334
+ const bytesBefore = (0, import_node_fs25.existsSync)(file) ? (0, import_node_fs25.statSync)(file).size : 0;
10335
+ (0, import_node_fs25.appendFileSync)(file, line, "utf8");
9434
10336
  try {
9435
10337
  updateAuditStatsAfterAppend(
9436
10338
  file,
9437
- auditBytesBefore,
9438
- auditBytesBefore + Buffer.byteLength(line, "utf8"),
10339
+ bytesBefore,
10340
+ bytesBefore + Buffer.byteLength(line, "utf8"),
9439
10341
  record
9440
10342
  );
9441
10343
  } catch (error) {
@@ -9444,12 +10346,39 @@ var AuditWriter = class {
9444
10346
  });
9445
10347
  }
9446
10348
  }
10349
+ /**
10350
+ * Write the delta-encoded body shard for one record. A no-op when nothing was
10351
+ * captured or when the session key is missing/unsafe — in which case the body
10352
+ * is dropped rather than written to an unvalidated path.
10353
+ */
10354
+ appendBody(dayPath, dayDir, record) {
10355
+ if (record.requestBody === void 0 && record.responseBody === void 0) return;
10356
+ const sessionKey = record.sessionKey;
10357
+ if (!isSafeSessionKey(sessionKey)) {
10358
+ this.logger.warn("[AuditWriter] dropping audit body with no usable session key", {
10359
+ id: record.id
10360
+ });
10361
+ return;
10362
+ }
10363
+ try {
10364
+ const line = encodeBodyEntry(record, sessionKey, dayDir, this.bases);
10365
+ if (line === null) return;
10366
+ const bodiesPath = this.ensureDir((0, import_node_path17.join)(dayPath, AUDIT_BODIES_DIR));
10367
+ (0, import_node_fs25.appendFileSync)((0, import_node_path17.join)(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
10368
+ } catch (error) {
10369
+ this.bases.forget(sessionKey);
10370
+ this.logger.warn("[AuditWriter] failed to append audit body shard", {
10371
+ id: record.id,
10372
+ error: error instanceof Error ? error.message : String(error)
10373
+ });
10374
+ }
10375
+ }
9447
10376
  };
9448
10377
 
9449
10378
  // src/billing/BillingPublisher.ts
9450
- var import_node_fs22 = require("fs");
10379
+ var import_node_fs26 = require("fs");
9451
10380
  var import_node_crypto13 = require("crypto");
9452
- var import_node_path15 = require("path");
10381
+ var import_node_path18 = require("path");
9453
10382
  var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
9454
10383
 
9455
10384
  // src/billing/billingFiles.ts
@@ -9520,8 +10449,8 @@ var BillingPublisher = class {
9520
10449
  */
9521
10450
  appendNow(event) {
9522
10451
  this.ensureDir();
9523
- const file = (0, import_node_path15.join)(this.billingDir, billingFileName(event.ts));
9524
- (0, import_node_fs22.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
10452
+ const file = (0, import_node_path18.join)(this.billingDir, billingFileName(event.ts));
10453
+ (0, import_node_fs26.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
9525
10454
  }
9526
10455
  /**
9527
10456
  * One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
@@ -9570,8 +10499,8 @@ var BillingPublisher = class {
9570
10499
  markDelivered(event) {
9571
10500
  try {
9572
10501
  this.ensureDir();
9573
- const file = (0, import_node_path15.join)(this.billingDir, deliveredFileName(event.ts));
9574
- (0, import_node_fs22.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
10502
+ const file = (0, import_node_path18.join)(this.billingDir, deliveredFileName(event.ts));
10503
+ (0, import_node_fs26.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
9575
10504
  } catch (error) {
9576
10505
  this.logger.warn("[BillingPublisher] failed to append delivery marker", {
9577
10506
  error: error instanceof Error ? error.message : String(error)
@@ -9580,20 +10509,20 @@ var BillingPublisher = class {
9580
10509
  }
9581
10510
  ensureDir() {
9582
10511
  if (this.dirEnsured) return;
9583
- (0, import_node_fs22.mkdirSync)(this.billingDir, { recursive: true });
10512
+ (0, import_node_fs26.mkdirSync)(this.billingDir, { recursive: true });
9584
10513
  this.dirEnsured = true;
9585
10514
  }
9586
10515
  };
9587
10516
 
9588
10517
  // src/billing/billingReader.ts
9589
- var import_node_fs23 = require("fs");
9590
- var import_node_path16 = require("path");
10518
+ var import_node_fs27 = require("fs");
10519
+ var import_node_path19 = require("path");
9591
10520
  function readBillingLedger(billingDir) {
9592
10521
  const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
9593
- if (!(0, import_node_fs23.existsSync)(billingDir)) return view;
10522
+ if (!(0, import_node_fs27.existsSync)(billingDir)) return view;
9594
10523
  let files;
9595
10524
  try {
9596
- files = (0, import_node_fs23.readdirSync)(billingDir);
10525
+ files = (0, import_node_fs27.readdirSync)(billingDir);
9597
10526
  } catch {
9598
10527
  return view;
9599
10528
  }
@@ -9624,7 +10553,7 @@ function readBillingStatus(billingDir) {
9624
10553
  function parseLines(dir, file) {
9625
10554
  let raw;
9626
10555
  try {
9627
- raw = (0, import_node_fs23.readFileSync)((0, import_node_path16.join)(dir, file), "utf8");
10556
+ raw = (0, import_node_fs27.readFileSync)((0, import_node_path19.join)(dir, file), "utf8");
9628
10557
  } catch {
9629
10558
  return [];
9630
10559
  }
@@ -10110,7 +11039,7 @@ function buildDaemon(config, paths) {
10110
11039
  }
10111
11040
  );
10112
11041
  const pricingStore = new JsonPricingStore(defaultPricingPath(paths.configPath));
10113
- const pricingEngine = new import_usage.PricingEngine(pricingStore, logger, {
11042
+ const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
10114
11043
  // Catalog egress follows the same global/env proxy policy as every other
10115
11044
  // daemon upstream call; no provider/account override applies here.
10116
11045
  fetchImpl: ((input, init) => (0, import_upstreamFetch8.fetchUpstream)(String(input), init ?? {}))
@@ -10126,8 +11055,10 @@ function buildDaemon(config, paths) {
10126
11055
  async (providerId, model) => await pricingEngine.getEntry(providerId, model) !== null
10127
11056
  );
10128
11057
  const keySpendTracker = new import_outbound_api6.KeySpendTracker(usageEventStore);
10129
- const usageRecorder = new import_usage.UsageRecorder(usageEventStore, pricingEngine, logger, {
10130
- onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
11058
+ const usageThroughput = (0, import_usage2.getSharedUsageThroughputTracker)();
11059
+ const usageRecorder = new import_usage2.UsageRecorder(usageEventStore, pricingEngine, logger, {
11060
+ onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at),
11061
+ onEvent: (row, at) => usageThroughput.record(row, at)
10131
11062
  });
10132
11063
  const providerProxy = (0, import_provider_proxy4.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
10133
11064
  const routeLeaseManager = new import_provider_proxy4.RouteLeaseManager(
@@ -10276,6 +11207,11 @@ function buildDaemon(config, paths) {
10276
11207
  // NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
10277
11208
  auditReader: (query2) => readAuditRecords(auditDir, query2),
10278
11209
  auditStatsReader: (query2) => readAuditStats(auditDir, query2),
11210
+ // audit-store-sharding: bodies live in per-session shards, so opening ONE
11211
+ // record's payload is a separate authed call that replays its delta chain.
11212
+ auditBodyReader: (query2) => readAuditBody(auditDir, query2),
11213
+ // audit-store-sharding D8: the manual counterpart to the daily pass.
11214
+ auditCompactor: () => compactAllClosedAuditDays(auditDir),
10279
11215
  // billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
10280
11216
  // secret-free total/delivered/pending counts of the durable ledger.
10281
11217
  billingStatusReader: () => readBillingStatus(billingDir)
@@ -10334,8 +11270,8 @@ function buildDaemon(config, paths) {
10334
11270
  }
10335
11271
  function isTokensStoreReadable(tokensPath) {
10336
11272
  try {
10337
- if (!(0, import_node_fs24.existsSync)(tokensPath)) return true;
10338
- (0, import_node_fs24.accessSync)(tokensPath, import_node_fs24.constants.R_OK);
11273
+ if (!(0, import_node_fs28.existsSync)(tokensPath)) return true;
11274
+ (0, import_node_fs28.accessSync)(tokensPath, import_node_fs28.constants.R_OK);
10339
11275
  return true;
10340
11276
  } catch {
10341
11277
  return false;
@@ -10380,10 +11316,10 @@ function buildCliSpawnPlan(opts) {
10380
11316
  };
10381
11317
  }
10382
11318
  function resolveInPathDefault(candidate) {
10383
- const segments = (process.env["PATH"] ?? "").split(import_node_path17.delimiter).filter(Boolean);
11319
+ const segments = (process.env["PATH"] ?? "").split(import_node_path20.delimiter).filter(Boolean);
10384
11320
  for (const seg of segments) {
10385
- const full = (0, import_node_path17.join)(seg, candidate);
10386
- if ((0, import_node_fs25.existsSync)(full)) return full;
11321
+ const full = (0, import_node_path20.join)(seg, candidate);
11322
+ if ((0, import_node_fs29.existsSync)(full)) return full;
10387
11323
  }
10388
11324
  return null;
10389
11325
  }
@@ -10391,7 +11327,7 @@ async function runLaunch(argv, deps) {
10391
11327
  const sep = argv.indexOf("--");
10392
11328
  const own = sep === -1 ? argv : argv.slice(0, sep);
10393
11329
  const passthrough = sep === -1 ? [] : argv.slice(sep + 1);
10394
- const { values, positionals } = (0, import_node_util4.parseArgs)({
11330
+ const { values, positionals } = (0, import_node_util5.parseArgs)({
10395
11331
  args: own,
10396
11332
  options: {
10397
11333
  provider: { type: "string", short: "p" },
@@ -10561,12 +11497,12 @@ function spawnCliInherit(plan) {
10561
11497
  // src/commands/login.ts
10562
11498
  var import_node_child_process3 = require("child_process");
10563
11499
  var import_node_readline = require("readline");
10564
- var import_node_util5 = require("util");
11500
+ var import_node_util6 = require("util");
10565
11501
  var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
10566
11502
  var import_subscriptions5 = require("@omnicross/subscriptions");
10567
11503
  var PROVIDERS2 = ["claude", "codex", "gemini"];
10568
11504
  async function runLogin(argv, deps) {
10569
- const { values, positionals } = (0, import_node_util5.parseArgs)({
11505
+ const { values, positionals } = (0, import_node_util6.parseArgs)({
10570
11506
  args: argv,
10571
11507
  options: {
10572
11508
  config: { type: "string", short: "c" },
@@ -10734,9 +11670,9 @@ function promptPaste(prompt) {
10734
11670
 
10735
11671
  // src/commands/providers.ts
10736
11672
  var import_node_crypto16 = require("crypto");
10737
- var import_node_util6 = require("util");
11673
+ var import_node_util7 = require("util");
10738
11674
  async function runProviders(argv) {
10739
- const { values, positionals } = (0, import_node_util6.parseArgs)({
11675
+ const { values, positionals } = (0, import_node_util7.parseArgs)({
10740
11676
  args: argv,
10741
11677
  options: {
10742
11678
  config: { type: "string", short: "c" },
@@ -10883,10 +11819,10 @@ function providersRmKey(configPath, providerId, keyId) {
10883
11819
  }
10884
11820
 
10885
11821
  // src/commands/secrets.ts
10886
- var import_node_fs26 = require("fs");
10887
- var import_node_util7 = require("util");
11822
+ var import_node_fs30 = require("fs");
11823
+ var import_node_util8 = require("util");
10888
11824
  async function runSecrets(argv) {
10889
- const { values, positionals } = (0, import_node_util7.parseArgs)({
11825
+ const { values, positionals } = (0, import_node_util8.parseArgs)({
10890
11826
  args: argv,
10891
11827
  options: {
10892
11828
  config: { type: "string", short: "c" },
@@ -10956,12 +11892,12 @@ function secretsStatus(args) {
10956
11892
  reportField("admin.token", cfg.admin.token);
10957
11893
  }
10958
11894
  const tokensPath = defaultTokensPath(args.config);
10959
- if ((0, import_node_fs26.existsSync)(tokensPath)) {
11895
+ if ((0, import_node_fs30.existsSync)(tokensPath)) {
10960
11896
  console.info(`Secret status for ${tokensPath}:`);
10961
11897
  reportTokenFields(tokensPath);
10962
11898
  }
10963
11899
  const integrationsPath = defaultIntegrationsPath(args.config);
10964
- if ((0, import_node_fs26.existsSync)(integrationsPath)) {
11900
+ if ((0, import_node_fs30.existsSync)(integrationsPath)) {
10965
11901
  const state = readRawJson(integrationsPath);
10966
11902
  const key = state.gatewayKey;
10967
11903
  if (key && typeof key === "object" && !Array.isArray(key)) {
@@ -11015,8 +11951,8 @@ async function secretsRotate(args) {
11015
11951
  const integrationsPath = defaultIntegrationsPath(args.config);
11016
11952
  try {
11017
11953
  cfg = loadConfig(args.config);
11018
- if ((0, import_node_fs26.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
11019
- if ((0, import_node_fs26.existsSync)(integrationsPath)) {
11954
+ if ((0, import_node_fs30.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
11955
+ if ((0, import_node_fs30.existsSync)(integrationsPath)) {
11020
11956
  integrationsPlain = new IntegrationStateStore(integrationsPath, oldBox).load();
11021
11957
  }
11022
11958
  } finally {
@@ -11051,20 +11987,20 @@ function secretsDecrypt(args) {
11051
11987
  let tokensPlain = null;
11052
11988
  try {
11053
11989
  cfg = loadConfig(args.config);
11054
- if ((0, import_node_fs26.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
11990
+ if ((0, import_node_fs30.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
11055
11991
  } finally {
11056
11992
  setSecretBox(null);
11057
11993
  }
11058
11994
  saveConfig(args.config, cfg);
11059
11995
  if (tokensPlain) {
11060
- (0, import_node_fs26.writeFileSync)(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n", "utf8");
11996
+ (0, import_node_fs30.writeFileSync)(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n", "utf8");
11061
11997
  }
11062
11998
  console.info(`Decrypted secrets to plaintext in ${args.config}` + tokensSuffix(args.config));
11063
11999
  }
11064
12000
  function readRawConfig(path2) {
11065
12001
  let parsed;
11066
12002
  try {
11067
- parsed = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
12003
+ parsed = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
11068
12004
  } catch {
11069
12005
  throw new Error(`secrets: cannot read or parse '${path2}'`);
11070
12006
  }
@@ -11072,7 +12008,7 @@ function readRawConfig(path2) {
11072
12008
  }
11073
12009
  function readRawJson(path2) {
11074
12010
  try {
11075
- const parsed = JSON.parse((0, import_node_fs26.readFileSync)(path2, "utf8"));
12011
+ const parsed = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
11076
12012
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
11077
12013
  return parsed;
11078
12014
  }
@@ -11082,13 +12018,13 @@ function readRawJson(path2) {
11082
12018
  }
11083
12019
  function encryptTokensFileInPlace(configPath, box) {
11084
12020
  const tokensPath = defaultTokensPath(configPath);
11085
- if (!(0, import_node_fs26.existsSync)(tokensPath)) return;
12021
+ if (!(0, import_node_fs30.existsSync)(tokensPath)) return;
11086
12022
  const plain = decryptTokensFile(tokensPath, box);
11087
12023
  writeTokensEncrypted(tokensPath, plain, box);
11088
12024
  }
11089
12025
  function rewriteIntegrationState(configPath, readBox, writeBox) {
11090
12026
  const path2 = defaultIntegrationsPath(configPath);
11091
- if (!(0, import_node_fs26.existsSync)(path2)) return;
12027
+ if (!(0, import_node_fs30.existsSync)(path2)) return;
11092
12028
  const state = new IntegrationStateStore(path2, readBox).load();
11093
12029
  new IntegrationStateStore(path2, writeBox).save(state);
11094
12030
  }
@@ -11101,7 +12037,7 @@ function writeTokensEncrypted(tokensPath, plain, box) {
11101
12037
  { updatedAt: "", ...plain },
11102
12038
  box
11103
12039
  );
11104
- (0, import_node_fs26.writeFileSync)(tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
12040
+ (0, import_node_fs30.writeFileSync)(tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
11105
12041
  }
11106
12042
  var TOKEN_FIELDS2 = {
11107
12043
  claude: ["accessToken", "refreshToken"],
@@ -11124,11 +12060,11 @@ function walkTokens(raw, fn) {
11124
12060
  return next;
11125
12061
  }
11126
12062
  function tokensSuffix(configPath) {
11127
- return (0, import_node_fs26.existsSync)(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
12063
+ return (0, import_node_fs30.existsSync)(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
11128
12064
  }
11129
12065
 
11130
12066
  // src/commands/start.ts
11131
- var import_node_util8 = require("util");
12067
+ var import_node_util9 = require("util");
11132
12068
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
11133
12069
  var import_SubscriptionAccountHealth5 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
11134
12070
  var import_AccountAllowanceScheduling6 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
@@ -11167,7 +12103,7 @@ async function seedIdentities(store, credentialStore) {
11167
12103
 
11168
12104
  // src/commands/start.ts
11169
12105
  async function runStart(argv) {
11170
- const { values } = (0, import_node_util8.parseArgs)({
12106
+ const { values } = (0, import_node_util9.parseArgs)({
11171
12107
  args: argv,
11172
12108
  options: {
11173
12109
  config: { type: "string", short: "c" },
@@ -11307,6 +12243,10 @@ Usage:
11307
12243
  omnicross secrets encrypt --config <p> Encrypt all at-rest secrets in place.
11308
12244
  omnicross secrets status --config <p> Report each secret field (no values shown).
11309
12245
  omnicross secrets rotate --config <p> --new-master-key-file <p> Re-seal under a new master key.
12246
+
12247
+ omnicross audit sessions --config <p> [--date YYYY-MM-DD] List captured body shards per session.
12248
+ omnicross audit show --config <p> --session <key> [--id <recordId>] Print reconstructed request/response bodies.
12249
+ omnicross audit compact --config <p> [--date YYYY-MM-DD] Run cross-session body compaction now.
11310
12250
  `;
11311
12251
  async function main() {
11312
12252
  const [, , subcommand, ...rest] = process.argv;
@@ -11338,6 +12278,9 @@ async function main() {
11338
12278
  case "secrets":
11339
12279
  await runSecrets(rest);
11340
12280
  return;
12281
+ case "audit":
12282
+ await runAudit(rest);
12283
+ return;
11341
12284
  case void 0:
11342
12285
  case "-h":
11343
12286
  case "--help":