@omnicross/daemon 0.1.8 → 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 +1354 -363
- package/dist/cli.js +1336 -340
- package/dist/index.cjs +897 -107
- package/dist/index.d.cts +160 -43
- package/dist/index.d.ts +160 -43
- package/dist/index.js +895 -100
- package/package.json +2 -2
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/
|
|
27
|
-
var
|
|
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/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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 (
|
|
46
|
-
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
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
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
90
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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/
|
|
106
|
-
var
|
|
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
|
|
712
|
+
var import_node_fs4 = require("fs");
|
|
166
713
|
var import_node_os = require("os");
|
|
167
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
200
|
-
(0,
|
|
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,
|
|
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,
|
|
760
|
+
if ((0, import_node_fs4.existsSync)(keyFilePath)) {
|
|
214
761
|
return readKeyFile(keyFilePath);
|
|
215
762
|
}
|
|
216
763
|
return generateKeyFile(keyFilePath);
|
|
@@ -458,7 +1005,234 @@ function decryptTokens(tokens, box) {
|
|
|
458
1005
|
return transformTokens(tokens, (v) => box.decryptMaybe(v));
|
|
459
1006
|
}
|
|
460
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
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
function mapCcrToOmnicross(ccr) {
|
|
1228
|
+
const notes = [];
|
|
1229
|
+
const providers = mapProviders(ccr.Providers ?? [], notes);
|
|
1230
|
+
noteRouterRoles(ccr.Router ?? {}, notes);
|
|
1231
|
+
return { config: { providers }, notes };
|
|
1232
|
+
}
|
|
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;
|
|
@@ -520,6 +1294,35 @@ function validateApiKeys(raw) {
|
|
|
520
1294
|
}
|
|
521
1295
|
return out.length > 0 ? out : void 0;
|
|
522
1296
|
}
|
|
1297
|
+
var THINK_LEVELS = /* @__PURE__ */ new Set([
|
|
1298
|
+
"none",
|
|
1299
|
+
"minimal",
|
|
1300
|
+
"low",
|
|
1301
|
+
"medium",
|
|
1302
|
+
"high",
|
|
1303
|
+
"xhigh",
|
|
1304
|
+
"max"
|
|
1305
|
+
]);
|
|
1306
|
+
function validateThinkingLevels(raw) {
|
|
1307
|
+
if (!Array.isArray(raw)) return void 0;
|
|
1308
|
+
if (!raw.every((level) => typeof level === "string" && THINK_LEVELS.has(level))) {
|
|
1309
|
+
return void 0;
|
|
1310
|
+
}
|
|
1311
|
+
return [...raw];
|
|
1312
|
+
}
|
|
1313
|
+
function validateThinkingTokenLimit(raw) {
|
|
1314
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
1315
|
+
const bounds = raw;
|
|
1316
|
+
const min = bounds["min"];
|
|
1317
|
+
const max = bounds["max"];
|
|
1318
|
+
if (typeof min !== "number" || !Number.isFinite(min) || !Number.isInteger(min) || min < 0) {
|
|
1319
|
+
return void 0;
|
|
1320
|
+
}
|
|
1321
|
+
if (typeof max !== "number" || !Number.isFinite(max) || !Number.isInteger(max) || max < min) {
|
|
1322
|
+
return void 0;
|
|
1323
|
+
}
|
|
1324
|
+
return { min, max };
|
|
1325
|
+
}
|
|
523
1326
|
function validateModelConfigs(raw) {
|
|
524
1327
|
if (!Array.isArray(raw)) return void 0;
|
|
525
1328
|
const out = [];
|
|
@@ -534,6 +1337,10 @@ function validateModelConfigs(raw) {
|
|
|
534
1337
|
if (typeof m["enabled"] === "boolean") entry.enabled = m["enabled"];
|
|
535
1338
|
if (typeof m["vision"] === "boolean") entry.vision = m["vision"];
|
|
536
1339
|
if (typeof m["reasoning"] === "boolean") entry.reasoning = m["reasoning"];
|
|
1340
|
+
const thinkingLevels = validateThinkingLevels(m["thinkingLevels"]);
|
|
1341
|
+
if (thinkingLevels) entry.thinkingLevels = thinkingLevels;
|
|
1342
|
+
const thinkingTokenLimit = validateThinkingTokenLimit(m["thinkingTokenLimit"]);
|
|
1343
|
+
if (thinkingTokenLimit) entry.thinkingTokenLimit = thinkingTokenLimit;
|
|
537
1344
|
out.push(entry);
|
|
538
1345
|
}
|
|
539
1346
|
return out.length > 0 ? out : void 0;
|
|
@@ -718,7 +1525,7 @@ function setSecretBox(box) {
|
|
|
718
1525
|
function loadConfig(path2) {
|
|
719
1526
|
let raw;
|
|
720
1527
|
try {
|
|
721
|
-
raw = (0,
|
|
1528
|
+
raw = (0, import_node_fs6.readFileSync)(path2, "utf8");
|
|
722
1529
|
} catch {
|
|
723
1530
|
throw new Error(`config: cannot read file at '${path2}'`);
|
|
724
1531
|
}
|
|
@@ -733,48 +1540,12 @@ function loadConfig(path2) {
|
|
|
733
1540
|
}
|
|
734
1541
|
function saveConfig(path2, cfg) {
|
|
735
1542
|
const toWrite = secretBox ? encryptConfigSecrets(cfg, secretBox) : cfg;
|
|
736
|
-
(0,
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// src/commands/paths.ts
|
|
740
|
-
var import_node_path2 = require("path");
|
|
741
|
-
function defaultKeysPath(configPath) {
|
|
742
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "keys.json");
|
|
743
|
-
}
|
|
744
|
-
function defaultVouchersPath(configPath) {
|
|
745
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "vouchers.json");
|
|
746
|
-
}
|
|
747
|
-
function defaultTokensPath(configPath) {
|
|
748
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "tokens.json");
|
|
749
|
-
}
|
|
750
|
-
function defaultIntegrationsPath(configPath) {
|
|
751
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "integrations.json");
|
|
752
|
-
}
|
|
753
|
-
function defaultPricingPath(configPath) {
|
|
754
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "pricing.json");
|
|
755
|
-
}
|
|
756
|
-
function defaultPricingRefreshStatePath(configPath) {
|
|
757
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "pricing-refresh.json");
|
|
758
|
-
}
|
|
759
|
-
function defaultAccountAllowancePath(configPath) {
|
|
760
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "allowance-cache.json");
|
|
761
|
-
}
|
|
762
|
-
function defaultUsageEventsPath(configPath) {
|
|
763
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "usage-events.jsonl");
|
|
764
|
-
}
|
|
765
|
-
function defaultAuditDir(configPath) {
|
|
766
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "audit");
|
|
767
|
-
}
|
|
768
|
-
function defaultBillingDir(configPath) {
|
|
769
|
-
return (0, import_node_path2.join)((0, import_node_path2.dirname)(configPath), "billing");
|
|
770
|
-
}
|
|
771
|
-
function resolveSecretBox(masterKeyFilePath) {
|
|
772
|
-
return new SecretBox(() => resolveMasterKey({ keyFilePath: masterKeyFilePath }));
|
|
1543
|
+
(0, import_node_fs6.writeFileSync)(path2, JSON.stringify(toWrite, null, 2) + "\n", "utf8");
|
|
773
1544
|
}
|
|
774
1545
|
|
|
775
1546
|
// src/commands/import-ccr.ts
|
|
776
1547
|
async function runImportCcr(argv) {
|
|
777
|
-
const { values, positionals } = (0,
|
|
1548
|
+
const { values, positionals } = (0, import_node_util2.parseArgs)({
|
|
778
1549
|
args: argv,
|
|
779
1550
|
options: {
|
|
780
1551
|
out: { type: "string", short: "o" },
|
|
@@ -789,7 +1560,7 @@ async function runImportCcr(argv) {
|
|
|
789
1560
|
const outPath = values.out ?? "omnicross.config.json";
|
|
790
1561
|
let raw;
|
|
791
1562
|
try {
|
|
792
|
-
raw = JSON.parse((0,
|
|
1563
|
+
raw = JSON.parse((0, import_node_fs7.readFileSync)(ccrPath, "utf8"));
|
|
793
1564
|
} catch {
|
|
794
1565
|
throw new Error(`import-ccr: cannot read or parse '${ccrPath}'`);
|
|
795
1566
|
}
|
|
@@ -810,19 +1581,19 @@ async function runImportCcr(argv) {
|
|
|
810
1581
|
}
|
|
811
1582
|
|
|
812
1583
|
// src/commands/integrations.ts
|
|
813
|
-
var
|
|
814
|
-
var
|
|
1584
|
+
var import_node_path8 = require("path");
|
|
1585
|
+
var import_node_util3 = require("util");
|
|
815
1586
|
|
|
816
1587
|
// src/integrations/IntegrationManager.ts
|
|
817
1588
|
var import_node_crypto3 = require("crypto");
|
|
818
|
-
var
|
|
1589
|
+
var import_node_fs9 = require("fs");
|
|
819
1590
|
var import_node_os2 = require("os");
|
|
820
|
-
var
|
|
1591
|
+
var import_node_path7 = require("path");
|
|
821
1592
|
var import_core = require("@omnicross/core");
|
|
822
1593
|
|
|
823
1594
|
// src/integrations/IntegrationStateStore.ts
|
|
824
|
-
var
|
|
825
|
-
var
|
|
1595
|
+
var import_node_fs8 = require("fs");
|
|
1596
|
+
var import_node_path6 = require("path");
|
|
826
1597
|
var EMPTY_STATE = { version: 1, clients: {} };
|
|
827
1598
|
var IntegrationStateStore = class {
|
|
828
1599
|
constructor(path2, box) {
|
|
@@ -832,10 +1603,10 @@ var IntegrationStateStore = class {
|
|
|
832
1603
|
path;
|
|
833
1604
|
box;
|
|
834
1605
|
load() {
|
|
835
|
-
if (!(0,
|
|
1606
|
+
if (!(0, import_node_fs8.existsSync)(this.path)) return { ...EMPTY_STATE, clients: {} };
|
|
836
1607
|
let raw;
|
|
837
1608
|
try {
|
|
838
|
-
raw = JSON.parse((0,
|
|
1609
|
+
raw = JSON.parse((0, import_node_fs8.readFileSync)(this.path, "utf8"));
|
|
839
1610
|
} catch {
|
|
840
1611
|
throw new Error(`integration state '${this.path}' is not valid JSON`);
|
|
841
1612
|
}
|
|
@@ -903,21 +1674,21 @@ function isManagedFileRecord(value) {
|
|
|
903
1674
|
return typeof row.path === "string" && typeof row.originalExisted === "boolean" && typeof row.originalContent === "string" && typeof row.originalHash === "string" && typeof row.installedHash === "string";
|
|
904
1675
|
}
|
|
905
1676
|
function atomicWrite(path2, content) {
|
|
906
|
-
(0,
|
|
1677
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path6.dirname)(path2), { recursive: true });
|
|
907
1678
|
const temp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
908
|
-
(0,
|
|
1679
|
+
(0, import_node_fs8.writeFileSync)(temp, content, { encoding: "utf8", mode: 384 });
|
|
909
1680
|
try {
|
|
910
|
-
(0,
|
|
1681
|
+
(0, import_node_fs8.renameSync)(temp, path2);
|
|
911
1682
|
} catch (error) {
|
|
912
1683
|
try {
|
|
913
|
-
(0,
|
|
1684
|
+
(0, import_node_fs8.unlinkSync)(temp);
|
|
914
1685
|
} catch {
|
|
915
1686
|
}
|
|
916
1687
|
throw error;
|
|
917
1688
|
} finally {
|
|
918
|
-
if ((0,
|
|
1689
|
+
if ((0, import_node_fs8.existsSync)(path2)) {
|
|
919
1690
|
try {
|
|
920
|
-
(0,
|
|
1691
|
+
(0, import_node_fs8.chmodSync)(path2, 384);
|
|
921
1692
|
} catch {
|
|
922
1693
|
}
|
|
923
1694
|
}
|
|
@@ -1109,7 +1880,7 @@ var IntegrationManager = class {
|
|
|
1109
1880
|
async plan(client, configPath = this.defaultConfigPath(client)) {
|
|
1110
1881
|
const state = this.options.stateStore.load();
|
|
1111
1882
|
const record = state.clients[client];
|
|
1112
|
-
const target = record?.configPath ?? (0,
|
|
1883
|
+
const target = record?.configPath ?? (0, import_node_path7.resolve)(configPath);
|
|
1113
1884
|
const status = this.statusFor(client, state, await this.isKeyUsable(state));
|
|
1114
1885
|
const changes = client === "codex" ? [
|
|
1115
1886
|
"model_provider",
|
|
@@ -1132,7 +1903,7 @@ var IntegrationManager = class {
|
|
|
1132
1903
|
};
|
|
1133
1904
|
}
|
|
1134
1905
|
async install(client, configPath = this.defaultConfigPath(client)) {
|
|
1135
|
-
const target = (0,
|
|
1906
|
+
const target = (0, import_node_path7.resolve)(configPath);
|
|
1136
1907
|
const state = this.options.stateStore.load();
|
|
1137
1908
|
const existingRecord = state.clients[client];
|
|
1138
1909
|
if (existingRecord) {
|
|
@@ -1409,10 +2180,10 @@ var IntegrationManager = class {
|
|
|
1409
2180
|
};
|
|
1410
2181
|
}
|
|
1411
2182
|
defaultConfigPath(client) {
|
|
1412
|
-
return client === "codex" ? (0,
|
|
2183
|
+
return client === "codex" ? (0, import_node_path7.join)(this.homeDir, ".codex", "config.toml") : (0, import_node_path7.join)(this.homeDir, ".claude", "settings.json");
|
|
1413
2184
|
}
|
|
1414
2185
|
codexAuthPathForConfig(configPath) {
|
|
1415
|
-
return (0,
|
|
2186
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "auth.json");
|
|
1416
2187
|
}
|
|
1417
2188
|
renderInstalled(client, base, secret) {
|
|
1418
2189
|
if (client === "claude") {
|
|
@@ -1425,7 +2196,7 @@ var IntegrationManager = class {
|
|
|
1425
2196
|
}
|
|
1426
2197
|
};
|
|
1427
2198
|
function readOptional(path2) {
|
|
1428
|
-
return (0,
|
|
2199
|
+
return (0, import_node_fs9.existsSync)(path2) ? (0, import_node_fs9.readFileSync)(path2, "utf8") : null;
|
|
1429
2200
|
}
|
|
1430
2201
|
function sha256(value) {
|
|
1431
2202
|
return (0, import_node_crypto3.createHash)("sha256").update(value, "utf8").digest("hex");
|
|
@@ -1489,7 +2260,7 @@ function writeOptional(path2, content) {
|
|
|
1489
2260
|
atomicWrite(path2, content);
|
|
1490
2261
|
return;
|
|
1491
2262
|
}
|
|
1492
|
-
if ((0,
|
|
2263
|
+
if ((0, import_node_fs9.existsSync)(path2)) (0, import_node_fs9.unlinkSync)(path2);
|
|
1493
2264
|
}
|
|
1494
2265
|
function assertLoopbackGatewayUrl(value) {
|
|
1495
2266
|
let url;
|
|
@@ -1506,7 +2277,7 @@ function assertLoopbackGatewayUrl(value) {
|
|
|
1506
2277
|
}
|
|
1507
2278
|
|
|
1508
2279
|
// src/ports/JsonOutboundKeyDb.ts
|
|
1509
|
-
var
|
|
2280
|
+
var import_node_fs10 = require("fs");
|
|
1510
2281
|
var JsonOutboundKeyDb = class {
|
|
1511
2282
|
/**
|
|
1512
2283
|
* @param secretBox OPTIONAL reversible-secret codec. When present, a created
|
|
@@ -1639,16 +2410,16 @@ var JsonOutboundKeyDb = class {
|
|
|
1639
2410
|
}
|
|
1640
2411
|
/** Read the key rows, tolerating a missing/corrupt file (→ empty list). */
|
|
1641
2412
|
readRows() {
|
|
1642
|
-
if (!(0,
|
|
2413
|
+
if (!(0, import_node_fs10.existsSync)(this.keysPath)) return [];
|
|
1643
2414
|
try {
|
|
1644
|
-
const parsed = JSON.parse((0,
|
|
2415
|
+
const parsed = JSON.parse((0, import_node_fs10.readFileSync)(this.keysPath, "utf8"));
|
|
1645
2416
|
return Array.isArray(parsed) ? parsed : [];
|
|
1646
2417
|
} catch {
|
|
1647
2418
|
return [];
|
|
1648
2419
|
}
|
|
1649
2420
|
}
|
|
1650
2421
|
writeRows(rows) {
|
|
1651
|
-
(0,
|
|
2422
|
+
(0, import_node_fs10.writeFileSync)(this.keysPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
|
|
1652
2423
|
}
|
|
1653
2424
|
};
|
|
1654
2425
|
function applyPolicyField(row, field, value) {
|
|
@@ -1659,7 +2430,7 @@ function applyPolicyField(row, field, value) {
|
|
|
1659
2430
|
|
|
1660
2431
|
// src/commands/integrations.ts
|
|
1661
2432
|
async function runIntegrations(argv) {
|
|
1662
|
-
const { values, positionals } = (0,
|
|
2433
|
+
const { values, positionals } = (0, import_node_util3.parseArgs)({
|
|
1663
2434
|
args: argv,
|
|
1664
2435
|
options: {
|
|
1665
2436
|
config: { type: "string", short: "c" },
|
|
@@ -1680,7 +2451,7 @@ async function runIntegrations(argv) {
|
|
|
1680
2451
|
const savedUrl = saved.clients.codex?.gatewayBaseUrl ?? saved.clients.claude?.gatewayBaseUrl;
|
|
1681
2452
|
const gatewayBaseUrl = values["gateway-base-url"] ?? savedUrl ?? "http://127.0.0.1:8765";
|
|
1682
2453
|
const manager = new IntegrationManager({
|
|
1683
|
-
configPath: (0,
|
|
2454
|
+
configPath: (0, import_node_path8.resolve)(values.config),
|
|
1684
2455
|
gatewayBaseUrl,
|
|
1685
2456
|
keyDb: new JsonOutboundKeyDb(defaultKeysPath(values.config)),
|
|
1686
2457
|
stateStore: store
|
|
@@ -1709,10 +2480,10 @@ function isClient(value) {
|
|
|
1709
2480
|
}
|
|
1710
2481
|
|
|
1711
2482
|
// src/commands/keys.ts
|
|
1712
|
-
var
|
|
2483
|
+
var import_node_util4 = require("util");
|
|
1713
2484
|
var import_outbound_api = require("@omnicross/core/outbound-api");
|
|
1714
2485
|
async function runKeys(argv) {
|
|
1715
|
-
const { values, positionals } = (0,
|
|
2486
|
+
const { values, positionals } = (0, import_node_util4.parseArgs)({
|
|
1716
2487
|
args: argv,
|
|
1717
2488
|
options: { config: { type: "string", short: "c" } },
|
|
1718
2489
|
allowPositionals: true
|
|
@@ -1766,14 +2537,14 @@ async function keysRevoke(db, id) {
|
|
|
1766
2537
|
// src/commands/launch.ts
|
|
1767
2538
|
var import_node_child_process2 = require("child_process");
|
|
1768
2539
|
var import_node_crypto15 = require("crypto");
|
|
1769
|
-
var
|
|
1770
|
-
var
|
|
1771
|
-
var
|
|
2540
|
+
var import_node_fs29 = require("fs");
|
|
2541
|
+
var import_node_path20 = require("path");
|
|
2542
|
+
var import_node_util5 = require("util");
|
|
1772
2543
|
var import_cli_launcher3 = require("@omnicross/cli-launcher");
|
|
1773
2544
|
var import_provider_proxy5 = require("@omnicross/core/provider-proxy");
|
|
1774
2545
|
|
|
1775
2546
|
// src/bootstrap.ts
|
|
1776
|
-
var
|
|
2547
|
+
var import_node_fs28 = require("fs");
|
|
1777
2548
|
var import_audit_types = require("@omnicross/contracts/audit-types");
|
|
1778
2549
|
var import_billing_types = require("@omnicross/contracts/billing-types");
|
|
1779
2550
|
var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
|
|
@@ -1789,7 +2560,7 @@ var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-c
|
|
|
1789
2560
|
var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
|
|
1790
2561
|
var import_cli_launcher2 = require("@omnicross/cli-launcher");
|
|
1791
2562
|
var import_outbound_api6 = require("@omnicross/core/outbound-api");
|
|
1792
|
-
var
|
|
2563
|
+
var import_usage2 = require("@omnicross/core/usage");
|
|
1793
2564
|
var import_subscriptions4 = require("@omnicross/subscriptions");
|
|
1794
2565
|
|
|
1795
2566
|
// src/admin/accountsCodexOAuth.ts
|
|
@@ -2282,8 +3053,8 @@ var ClaudeAllowanceRefreshScheduler = class {
|
|
|
2282
3053
|
|
|
2283
3054
|
// src/allowance/JsonAccountAllowancePersistence.ts
|
|
2284
3055
|
var import_node_crypto5 = require("crypto");
|
|
2285
|
-
var
|
|
2286
|
-
var
|
|
3056
|
+
var import_node_fs11 = require("fs");
|
|
3057
|
+
var import_node_path9 = require("path");
|
|
2287
3058
|
var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
2288
3059
|
var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
|
|
2289
3060
|
var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
|
|
@@ -2295,10 +3066,10 @@ var JsonAccountAllowancePersistence = class {
|
|
|
2295
3066
|
cachePath;
|
|
2296
3067
|
/** Read only the `snapshots` payload; all row validation remains defensive. */
|
|
2297
3068
|
load() {
|
|
2298
|
-
if (!(0,
|
|
3069
|
+
if (!(0, import_node_fs11.existsSync)(this.cachePath)) return [];
|
|
2299
3070
|
try {
|
|
2300
|
-
if ((0,
|
|
2301
|
-
const raw = (0,
|
|
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");
|
|
2302
3073
|
if (!raw.trim()) return [];
|
|
2303
3074
|
const parsed = JSON.parse(raw);
|
|
2304
3075
|
if (Array.isArray(parsed)) return parsed;
|
|
@@ -2326,13 +3097,13 @@ var JsonAccountAllowancePersistence = class {
|
|
|
2326
3097
|
if (Buffer.byteLength(serialized, "utf8") > MAX_ALLOWANCE_CACHE_BYTES) {
|
|
2327
3098
|
throw new Error("account allowance cache exceeds its size limit");
|
|
2328
3099
|
}
|
|
2329
|
-
(0,
|
|
3100
|
+
(0, import_node_fs11.mkdirSync)((0, import_node_path9.dirname)(this.cachePath), { recursive: true });
|
|
2330
3101
|
const temporaryPath = `${this.cachePath}.${process.pid}.${(0, import_node_crypto5.randomUUID)()}.tmp`;
|
|
2331
3102
|
try {
|
|
2332
|
-
(0,
|
|
2333
|
-
(0,
|
|
3103
|
+
(0, import_node_fs11.writeFileSync)(temporaryPath, serialized, { encoding: "utf8", flag: "wx" });
|
|
3104
|
+
(0, import_node_fs11.renameSync)(temporaryPath, this.cachePath);
|
|
2334
3105
|
} finally {
|
|
2335
|
-
(0,
|
|
3106
|
+
(0, import_node_fs11.rmSync)(temporaryPath, { force: true });
|
|
2336
3107
|
}
|
|
2337
3108
|
}
|
|
2338
3109
|
};
|
|
@@ -2370,6 +3141,37 @@ function handleAuditQuery(req, res, reader) {
|
|
|
2370
3141
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2371
3142
|
res.end(JSON.stringify({ records }));
|
|
2372
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
|
+
}
|
|
2373
3175
|
async function handleAuditStatsQuery(req, res, reader) {
|
|
2374
3176
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
2375
3177
|
const query2 = {};
|
|
@@ -3100,10 +3902,10 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
|
|
|
3100
3902
|
// src/admin/cliLaunch.ts
|
|
3101
3903
|
var import_node_child_process = require("child_process");
|
|
3102
3904
|
var import_node_crypto6 = require("crypto");
|
|
3103
|
-
var
|
|
3905
|
+
var import_node_fs12 = require("fs");
|
|
3104
3906
|
var import_node_net = require("net");
|
|
3105
3907
|
var import_node_os3 = require("os");
|
|
3106
|
-
var
|
|
3908
|
+
var import_node_path10 = require("path");
|
|
3107
3909
|
var import_cli_launcher = require("@omnicross/cli-launcher");
|
|
3108
3910
|
var import_provider_proxy2 = require("@omnicross/core/provider-proxy");
|
|
3109
3911
|
|
|
@@ -3150,10 +3952,10 @@ function isLaunchCliId(id) {
|
|
|
3150
3952
|
return id !== void 0 && LAUNCHABLE_IDS.has(id);
|
|
3151
3953
|
}
|
|
3152
3954
|
function probeDefault(candidate) {
|
|
3153
|
-
const segments = (process.env["PATH"] ?? "").split(
|
|
3955
|
+
const segments = (process.env["PATH"] ?? "").split(import_node_path10.delimiter).filter(Boolean);
|
|
3154
3956
|
for (const seg of segments) {
|
|
3155
|
-
const full = (0,
|
|
3156
|
-
if ((0,
|
|
3957
|
+
const full = (0, import_node_path10.join)(seg, candidate);
|
|
3958
|
+
if ((0, import_node_fs12.existsSync)(full)) return full;
|
|
3157
3959
|
}
|
|
3158
3960
|
return null;
|
|
3159
3961
|
}
|
|
@@ -3257,10 +4059,10 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
|
|
|
3257
4059
|
const runLine = [command, ...extraArgs].map(shq).join(" ");
|
|
3258
4060
|
const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
|
|
3259
4061
|
if (platform === "darwin") {
|
|
3260
|
-
const launchDir = (0,
|
|
3261
|
-
const commandFile = (0,
|
|
3262
|
-
const bootstrapFile = (0,
|
|
3263
|
-
const socketPath = macIpc.socketPath ?? (0,
|
|
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");
|
|
3264
4066
|
const openerEnv = { ...process.env };
|
|
3265
4067
|
for (const key of Object.keys(env)) delete openerEnv[key];
|
|
3266
4068
|
let claimed = false;
|
|
@@ -3319,7 +4121,7 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
|
|
|
3319
4121
|
if (macIpc.removeArtifacts) {
|
|
3320
4122
|
macIpc.removeArtifacts(launchDir);
|
|
3321
4123
|
} else {
|
|
3322
|
-
(0,
|
|
4124
|
+
(0, import_node_fs12.rmSync)(launchDir, {
|
|
3323
4125
|
recursive: true,
|
|
3324
4126
|
force: true,
|
|
3325
4127
|
maxRetries: 3,
|
|
@@ -3330,23 +4132,23 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
|
|
|
3330
4132
|
}
|
|
3331
4133
|
};
|
|
3332
4134
|
try {
|
|
3333
|
-
(0,
|
|
3334
|
-
(0,
|
|
4135
|
+
(0, import_node_fs12.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
|
|
4136
|
+
(0, import_node_fs12.writeFileSync)(commandFile, `#!/bin/bash
|
|
3335
4137
|
rm -f -- "$0"
|
|
3336
4138
|
exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
|
|
3337
4139
|
`, {
|
|
3338
4140
|
encoding: "utf8",
|
|
3339
4141
|
mode: 448
|
|
3340
4142
|
});
|
|
3341
|
-
(0,
|
|
3342
|
-
(0,
|
|
4143
|
+
(0, import_node_fs12.chmodSync)(commandFile, 448);
|
|
4144
|
+
(0, import_node_fs12.chmodSync)(bootstrapFile, 448);
|
|
3343
4145
|
server.once("error", handleLaunchFailure);
|
|
3344
4146
|
server.listen(socketPath, () => {
|
|
3345
4147
|
if (cleaned) return;
|
|
3346
4148
|
try {
|
|
3347
4149
|
macIpc.onListening?.();
|
|
3348
4150
|
if (cleaned) return;
|
|
3349
|
-
if (process.platform !== "win32") (0,
|
|
4151
|
+
if (process.platform !== "win32") (0, import_node_fs12.chmodSync)(socketPath, 384);
|
|
3350
4152
|
const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
|
|
3351
4153
|
env: openerEnv,
|
|
3352
4154
|
detached: true,
|
|
@@ -3992,6 +4794,7 @@ function applyAuditConfig(config) {
|
|
|
3992
4794
|
} else {
|
|
3993
4795
|
(0, import_auditSink.setAuditCaptureConfig)(null);
|
|
3994
4796
|
(0, import_auditSink.setAuditSink)(null);
|
|
4797
|
+
writer?.reset();
|
|
3995
4798
|
if (sweeper) {
|
|
3996
4799
|
if (config) sweeper.configure(config);
|
|
3997
4800
|
sweeper.dispose();
|
|
@@ -4578,6 +5381,7 @@ async function handleImport(body, deps) {
|
|
|
4578
5381
|
}
|
|
4579
5382
|
|
|
4580
5383
|
// src/admin/usagePricing.ts
|
|
5384
|
+
var import_usage = require("@omnicross/core/usage");
|
|
4581
5385
|
var err4 = (status, message) => ({
|
|
4582
5386
|
status,
|
|
4583
5387
|
body: { error: { type: "admin_api_error", message } }
|
|
@@ -4603,6 +5407,9 @@ var BUCKET_SPAN_MS = {
|
|
|
4603
5407
|
};
|
|
4604
5408
|
var MAX_TIMESERIES_BUCKETS = 2e3;
|
|
4605
5409
|
async function handleUsageGet(view, query2, deps) {
|
|
5410
|
+
if (view === "throughput") {
|
|
5411
|
+
return { status: 200, body: (0, import_usage.getSharedUsageThroughputTracker)().snapshot() };
|
|
5412
|
+
}
|
|
4606
5413
|
const range = parseRange(query2);
|
|
4607
5414
|
if (!isRange(range)) return range;
|
|
4608
5415
|
switch (view) {
|
|
@@ -5405,6 +6212,12 @@ function parseModelConfigsInput(raw, existing) {
|
|
|
5405
6212
|
else if (typeof prior?.vision === "boolean") entry.vision = prior.vision;
|
|
5406
6213
|
if (typeof m["reasoning"] === "boolean") entry.reasoning = m["reasoning"];
|
|
5407
6214
|
else if (typeof prior?.reasoning === "boolean") entry.reasoning = prior.reasoning;
|
|
6215
|
+
const thinkingLevels = validateThinkingLevels(m["thinkingLevels"]);
|
|
6216
|
+
if (thinkingLevels) entry.thinkingLevels = thinkingLevels;
|
|
6217
|
+
else if (prior?.thinkingLevels) entry.thinkingLevels = prior.thinkingLevels;
|
|
6218
|
+
const thinkingTokenLimit = validateThinkingTokenLimit(m["thinkingTokenLimit"]);
|
|
6219
|
+
if (thinkingTokenLimit) entry.thinkingTokenLimit = thinkingTokenLimit;
|
|
6220
|
+
else if (prior?.thinkingTokenLimit) entry.thinkingTokenLimit = prior.thinkingTokenLimit;
|
|
5408
6221
|
out.push(entry);
|
|
5409
6222
|
}
|
|
5410
6223
|
return out.length > 0 ? out : void 0;
|
|
@@ -6230,10 +7043,10 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
|
6230
7043
|
}
|
|
6231
7044
|
|
|
6232
7045
|
// src/admin/uiStatic.ts
|
|
6233
|
-
var
|
|
7046
|
+
var import_node_fs13 = require("fs");
|
|
6234
7047
|
var import_promises = require("fs/promises");
|
|
6235
7048
|
var import_node_module = require("module");
|
|
6236
|
-
var
|
|
7049
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
6237
7050
|
var import_meta = {};
|
|
6238
7051
|
var CONTENT_TYPES = {
|
|
6239
7052
|
".html": "text/html; charset=utf-8",
|
|
@@ -6254,13 +7067,13 @@ var CONTENT_TYPES = {
|
|
|
6254
7067
|
function resolveUiDist() {
|
|
6255
7068
|
const fromEnv = process.env["OMNICROSS_UI_DIST"];
|
|
6256
7069
|
if (fromEnv) {
|
|
6257
|
-
return (0,
|
|
7070
|
+
return (0, import_node_fs13.existsSync)(import_node_path11.default.join(fromEnv, "index.html")) ? import_node_path11.default.resolve(fromEnv) : null;
|
|
6258
7071
|
}
|
|
6259
7072
|
try {
|
|
6260
7073
|
const req = (0, import_node_module.createRequire)(typeof __filename !== "undefined" ? __filename : import_meta.url);
|
|
6261
7074
|
const pkgJson = req.resolve("@omnicross/ui/package.json");
|
|
6262
|
-
const dist =
|
|
6263
|
-
return (0,
|
|
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;
|
|
6264
7077
|
} catch {
|
|
6265
7078
|
return null;
|
|
6266
7079
|
}
|
|
@@ -6302,16 +7115,16 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
6302
7115
|
res.end(JSON.stringify({ error: { type: "bad_request", message: "invalid path" } }));
|
|
6303
7116
|
return true;
|
|
6304
7117
|
}
|
|
6305
|
-
const filePath =
|
|
6306
|
-
if (filePath !== uiDist && !filePath.startsWith(uiDist +
|
|
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)) {
|
|
6307
7120
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
6308
7121
|
res.end(JSON.stringify({ error: { type: "forbidden", message: "path outside ui root" } }));
|
|
6309
7122
|
return true;
|
|
6310
7123
|
}
|
|
6311
7124
|
let target = filePath;
|
|
6312
|
-
if (!(0,
|
|
6313
|
-
if (
|
|
6314
|
-
target =
|
|
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");
|
|
6315
7128
|
} else {
|
|
6316
7129
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
6317
7130
|
res.end(JSON.stringify({ error: { type: "not_found", message: "no such ui asset" } }));
|
|
@@ -6319,14 +7132,14 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
6319
7132
|
}
|
|
6320
7133
|
}
|
|
6321
7134
|
const body = await (0, import_promises.readFile)(target);
|
|
6322
|
-
const type = CONTENT_TYPES[
|
|
7135
|
+
const type = CONTENT_TYPES[import_node_path11.default.extname(target).toLowerCase()] ?? "application/octet-stream";
|
|
6323
7136
|
res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
|
|
6324
7137
|
res.end(req.method === "HEAD" ? void 0 : body);
|
|
6325
7138
|
return true;
|
|
6326
7139
|
}
|
|
6327
7140
|
|
|
6328
7141
|
// src/admin/version.ts
|
|
6329
|
-
var DAEMON_VERSION = true ? "0.1.
|
|
7142
|
+
var DAEMON_VERSION = true ? "0.1.10" : "0.0.0-dev";
|
|
6330
7143
|
|
|
6331
7144
|
// src/admin/AdminServer.ts
|
|
6332
7145
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -6438,6 +7251,14 @@ var AdminServer = class {
|
|
|
6438
7251
|
await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
|
|
6439
7252
|
return;
|
|
6440
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
|
+
}
|
|
6441
7262
|
if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
|
|
6442
7263
|
handleBillingStatus(res, this.deps.billingStatusReader);
|
|
6443
7264
|
return;
|
|
@@ -6867,6 +7688,15 @@ function toLLMProvider(row) {
|
|
|
6867
7688
|
api_base_url: row.baseUrl,
|
|
6868
7689
|
api_key: resolvePreferredApiKey(row),
|
|
6869
7690
|
models,
|
|
7691
|
+
modelConfigs: row.modelConfigs?.map((config) => ({
|
|
7692
|
+
id: config.id,
|
|
7693
|
+
name: config.name ?? config.id,
|
|
7694
|
+
enabled: config.enabled ?? true,
|
|
7695
|
+
vision: config.vision,
|
|
7696
|
+
reasoning: config.reasoning,
|
|
7697
|
+
thinkingLevels: config.thinkingLevels,
|
|
7698
|
+
thinkingTokenLimit: config.thinkingTokenLimit
|
|
7699
|
+
})),
|
|
6870
7700
|
enabled: true,
|
|
6871
7701
|
transformer,
|
|
6872
7702
|
// app-parity-2 child 3: POPULATE the coding-plan endpoint onto the core
|
|
@@ -6893,7 +7723,7 @@ function toLLMProvider(row) {
|
|
|
6893
7723
|
}
|
|
6894
7724
|
|
|
6895
7725
|
// src/ports/ConfigurableLogger.ts
|
|
6896
|
-
var
|
|
7726
|
+
var import_node_fs14 = require("fs");
|
|
6897
7727
|
var LEVEL_ORDER = { error: 0, warn: 1, info: 2, debug: 3 };
|
|
6898
7728
|
var RESERVED_JSON_KEYS = /* @__PURE__ */ new Set(["ts", "level", "msg", "error"]);
|
|
6899
7729
|
var ConfigurableLogger = class {
|
|
@@ -6969,7 +7799,7 @@ var ConfigurableLogger = class {
|
|
|
6969
7799
|
if (this.fileDisabled || !this.filePath) return null;
|
|
6970
7800
|
if (this.fileStream) return this.fileStream;
|
|
6971
7801
|
try {
|
|
6972
|
-
const stream = (0,
|
|
7802
|
+
const stream = (0, import_node_fs14.createWriteStream)(this.filePath, { flags: "a" });
|
|
6973
7803
|
stream.on("error", () => {
|
|
6974
7804
|
this.fileDisabled = true;
|
|
6975
7805
|
this.fileStream = null;
|
|
@@ -7038,7 +7868,7 @@ function safeStringify(value) {
|
|
|
7038
7868
|
}
|
|
7039
7869
|
|
|
7040
7870
|
// src/ports/JsonApiServerSettingsStore.ts
|
|
7041
|
-
var
|
|
7871
|
+
var import_node_fs15 = require("fs");
|
|
7042
7872
|
var import_outbound_api4 = require("@omnicross/core/outbound-api");
|
|
7043
7873
|
var JsonApiServerSettingsStore = class {
|
|
7044
7874
|
/**
|
|
@@ -7065,7 +7895,7 @@ var JsonApiServerSettingsStore = class {
|
|
|
7065
7895
|
if (key !== import_outbound_api4.OUTBOUND_API_SERVER_CONFIG_KEY) return;
|
|
7066
7896
|
const file = this.readFile();
|
|
7067
7897
|
file.server = this.encryptSecrets(value);
|
|
7068
|
-
(0,
|
|
7898
|
+
(0, import_node_fs15.writeFileSync)(this.configPath, JSON.stringify(file, null, 2) + "\n", "utf8");
|
|
7069
7899
|
}
|
|
7070
7900
|
/** Encrypt the proxy passwords + webhook + billing secrets before persisting (no-op without a box). */
|
|
7071
7901
|
encryptSecrets(config) {
|
|
@@ -7088,7 +7918,7 @@ var JsonApiServerSettingsStore = class {
|
|
|
7088
7918
|
/** Read the config.json, tolerating a missing/corrupt file (→ empty shape). */
|
|
7089
7919
|
readFile() {
|
|
7090
7920
|
try {
|
|
7091
|
-
const raw = (0,
|
|
7921
|
+
const raw = (0, import_node_fs15.readFileSync)(this.configPath, "utf8");
|
|
7092
7922
|
const parsed = JSON.parse(raw);
|
|
7093
7923
|
if (parsed && typeof parsed === "object") return parsed;
|
|
7094
7924
|
} catch {
|
|
@@ -7099,7 +7929,7 @@ var JsonApiServerSettingsStore = class {
|
|
|
7099
7929
|
|
|
7100
7930
|
// src/ports/JsonlUsageEventStore.ts
|
|
7101
7931
|
var import_node_crypto11 = require("crypto");
|
|
7102
|
-
var
|
|
7932
|
+
var import_node_fs16 = require("fs");
|
|
7103
7933
|
var JsonlUsageEventStore = class {
|
|
7104
7934
|
constructor(eventsPath, isPriced) {
|
|
7105
7935
|
this.eventsPath = eventsPath;
|
|
@@ -7114,7 +7944,7 @@ var JsonlUsageEventStore = class {
|
|
|
7114
7944
|
id: (0, import_node_crypto11.randomUUID)(),
|
|
7115
7945
|
ts: input.ts ?? Date.now()
|
|
7116
7946
|
};
|
|
7117
|
-
(0,
|
|
7947
|
+
(0, import_node_fs16.appendFileSync)(this.eventsPath, JSON.stringify(row) + "\n", "utf8");
|
|
7118
7948
|
return row.id;
|
|
7119
7949
|
}
|
|
7120
7950
|
async getTotals(range) {
|
|
@@ -7313,10 +8143,10 @@ var JsonlUsageEventStore = class {
|
|
|
7313
8143
|
}
|
|
7314
8144
|
/** Parse every line, skipping malformed/torn lines defensively. */
|
|
7315
8145
|
readAllRows() {
|
|
7316
|
-
if (!(0,
|
|
8146
|
+
if (!(0, import_node_fs16.existsSync)(this.eventsPath)) return [];
|
|
7317
8147
|
let raw;
|
|
7318
8148
|
try {
|
|
7319
|
-
raw = (0,
|
|
8149
|
+
raw = (0, import_node_fs16.readFileSync)(this.eventsPath, "utf8");
|
|
7320
8150
|
} catch {
|
|
7321
8151
|
return [];
|
|
7322
8152
|
}
|
|
@@ -7355,15 +8185,15 @@ function nextBoundary(ts, bucket) {
|
|
|
7355
8185
|
return new Date(d.getFullYear(), d.getMonth() + 1, 1).getTime();
|
|
7356
8186
|
}
|
|
7357
8187
|
}
|
|
7358
|
-
var
|
|
8188
|
+
var pad22 = (n) => String(n).padStart(2, "0");
|
|
7359
8189
|
function bucketLabel(bucketStartTs, bucket) {
|
|
7360
8190
|
const d = new Date(bucketStartTs);
|
|
7361
8191
|
const y = d.getFullYear();
|
|
7362
|
-
const mo =
|
|
7363
|
-
const day =
|
|
8192
|
+
const mo = pad22(d.getMonth() + 1);
|
|
8193
|
+
const day = pad22(d.getDate());
|
|
7364
8194
|
switch (bucket) {
|
|
7365
8195
|
case "hour":
|
|
7366
|
-
return `${mo}-${day} ${
|
|
8196
|
+
return `${mo}-${day} ${pad22(d.getHours())}:00`;
|
|
7367
8197
|
case "day":
|
|
7368
8198
|
return `${y}-${mo}-${day}`;
|
|
7369
8199
|
case "month":
|
|
@@ -7419,7 +8249,7 @@ function median(values) {
|
|
|
7419
8249
|
}
|
|
7420
8250
|
|
|
7421
8251
|
// src/ports/JsonPricingStore.ts
|
|
7422
|
-
var
|
|
8252
|
+
var import_node_fs17 = require("fs");
|
|
7423
8253
|
var import_node_crypto12 = require("crypto");
|
|
7424
8254
|
var JsonPricingStore = class {
|
|
7425
8255
|
constructor(pricingPath) {
|
|
@@ -7434,9 +8264,9 @@ var JsonPricingStore = class {
|
|
|
7434
8264
|
* otherwise unusable pricing table after a crash or manual file edit.
|
|
7435
8265
|
*/
|
|
7436
8266
|
hasUsableSnapshot() {
|
|
7437
|
-
if (!(0,
|
|
8267
|
+
if (!(0, import_node_fs17.existsSync)(this.pricingPath)) return false;
|
|
7438
8268
|
try {
|
|
7439
|
-
const parsed = JSON.parse((0,
|
|
8269
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(this.pricingPath, "utf8"));
|
|
7440
8270
|
return Array.isArray(parsed) && parsed.some(isUsablePricingRow);
|
|
7441
8271
|
} catch {
|
|
7442
8272
|
return false;
|
|
@@ -7549,9 +8379,9 @@ var JsonPricingStore = class {
|
|
|
7549
8379
|
}
|
|
7550
8380
|
/** Read the pricing rows, tolerating a missing/corrupt file (→ empty list). */
|
|
7551
8381
|
readRows() {
|
|
7552
|
-
if (!(0,
|
|
8382
|
+
if (!(0, import_node_fs17.existsSync)(this.pricingPath)) return [];
|
|
7553
8383
|
try {
|
|
7554
|
-
const parsed = JSON.parse((0,
|
|
8384
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(this.pricingPath, "utf8"));
|
|
7555
8385
|
return Array.isArray(parsed) ? parsed : [];
|
|
7556
8386
|
} catch {
|
|
7557
8387
|
return [];
|
|
@@ -7560,18 +8390,18 @@ var JsonPricingStore = class {
|
|
|
7560
8390
|
writeRows(rows) {
|
|
7561
8391
|
const temporaryPath = `${this.pricingPath}.${process.pid}.${(0, import_node_crypto12.randomUUID)()}.tmp`;
|
|
7562
8392
|
try {
|
|
7563
|
-
(0,
|
|
8393
|
+
(0, import_node_fs17.writeFileSync)(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
|
|
7564
8394
|
encoding: "utf8",
|
|
7565
8395
|
flag: "wx"
|
|
7566
8396
|
});
|
|
7567
8397
|
this.replaceFile(temporaryPath);
|
|
7568
8398
|
} finally {
|
|
7569
|
-
(0,
|
|
8399
|
+
(0, import_node_fs17.rmSync)(temporaryPath, { force: true });
|
|
7570
8400
|
}
|
|
7571
8401
|
}
|
|
7572
8402
|
/** Isolated for deterministic failure testing; never removes the target. */
|
|
7573
8403
|
replaceFile(temporaryPath) {
|
|
7574
|
-
(0,
|
|
8404
|
+
(0, import_node_fs17.renameSync)(temporaryPath, this.pricingPath);
|
|
7575
8405
|
}
|
|
7576
8406
|
};
|
|
7577
8407
|
function isUsablePricingRow(value) {
|
|
@@ -7581,7 +8411,7 @@ function isUsablePricingRow(value) {
|
|
|
7581
8411
|
}
|
|
7582
8412
|
|
|
7583
8413
|
// src/pricing/PricingRefreshScheduler.ts
|
|
7584
|
-
var
|
|
8414
|
+
var import_node_fs18 = require("fs");
|
|
7585
8415
|
var EMPTY_STATE2 = {
|
|
7586
8416
|
lastAttemptAt: null,
|
|
7587
8417
|
lastSuccessAt: null,
|
|
@@ -7619,9 +8449,9 @@ var PricingRefreshScheduler = class {
|
|
|
7619
8449
|
this.timer = null;
|
|
7620
8450
|
}
|
|
7621
8451
|
getState() {
|
|
7622
|
-
if (!(0,
|
|
8452
|
+
if (!(0, import_node_fs18.existsSync)(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
|
|
7623
8453
|
try {
|
|
7624
|
-
const value = JSON.parse((0,
|
|
8454
|
+
const value = JSON.parse((0, import_node_fs18.readFileSync)(this.statePath, "utf8"));
|
|
7625
8455
|
return {
|
|
7626
8456
|
lastAttemptAt: finiteOrNull(value.lastAttemptAt),
|
|
7627
8457
|
lastSuccessAt: finiteOrNull(value.lastSuccessAt),
|
|
@@ -7674,9 +8504,9 @@ var PricingRefreshScheduler = class {
|
|
|
7674
8504
|
}
|
|
7675
8505
|
writeState(state) {
|
|
7676
8506
|
const temporaryPath = `${this.statePath}.tmp`;
|
|
7677
|
-
(0,
|
|
8507
|
+
(0, import_node_fs18.writeFileSync)(temporaryPath, `${JSON.stringify(state, null, 2)}
|
|
7678
8508
|
`, "utf8");
|
|
7679
|
-
(0,
|
|
8509
|
+
(0, import_node_fs18.renameSync)(temporaryPath, this.statePath);
|
|
7680
8510
|
}
|
|
7681
8511
|
};
|
|
7682
8512
|
function finiteOrNull(value) {
|
|
@@ -7684,7 +8514,7 @@ function finiteOrNull(value) {
|
|
|
7684
8514
|
}
|
|
7685
8515
|
|
|
7686
8516
|
// src/ports/JsonVoucherDb.ts
|
|
7687
|
-
var
|
|
8517
|
+
var import_node_fs19 = require("fs");
|
|
7688
8518
|
var JsonVoucherDb = class {
|
|
7689
8519
|
constructor(vouchersPath) {
|
|
7690
8520
|
this.vouchersPath = vouchersPath;
|
|
@@ -7762,22 +8592,22 @@ var JsonVoucherDb = class {
|
|
|
7762
8592
|
}
|
|
7763
8593
|
/** Read the voucher rows, tolerating a missing/corrupt file (→ empty list). */
|
|
7764
8594
|
readRows() {
|
|
7765
|
-
if (!(0,
|
|
8595
|
+
if (!(0, import_node_fs19.existsSync)(this.vouchersPath)) return [];
|
|
7766
8596
|
try {
|
|
7767
|
-
const parsed = JSON.parse((0,
|
|
8597
|
+
const parsed = JSON.parse((0, import_node_fs19.readFileSync)(this.vouchersPath, "utf8"));
|
|
7768
8598
|
return Array.isArray(parsed) ? parsed : [];
|
|
7769
8599
|
} catch {
|
|
7770
8600
|
return [];
|
|
7771
8601
|
}
|
|
7772
8602
|
}
|
|
7773
8603
|
writeRows(rows) {
|
|
7774
|
-
(0,
|
|
8604
|
+
(0, import_node_fs19.writeFileSync)(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
|
|
7775
8605
|
}
|
|
7776
8606
|
};
|
|
7777
8607
|
|
|
7778
8608
|
// src/ports/JsonSubscriptionCredentialStore.ts
|
|
7779
|
-
var
|
|
7780
|
-
var
|
|
8609
|
+
var import_node_fs21 = require("fs");
|
|
8610
|
+
var import_node_path13 = require("path");
|
|
7781
8611
|
var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
7782
8612
|
var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
7783
8613
|
var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
@@ -7826,11 +8656,11 @@ function findDuplicateCredentialIds(accounts) {
|
|
|
7826
8656
|
}
|
|
7827
8657
|
|
|
7828
8658
|
// src/ports/external-cli-credentials.ts
|
|
7829
|
-
var
|
|
8659
|
+
var import_node_fs20 = require("fs");
|
|
7830
8660
|
var import_node_os4 = require("os");
|
|
7831
|
-
var
|
|
8661
|
+
var import_node_path12 = require("path");
|
|
7832
8662
|
function externalStorePath(provider, home = (0, import_node_os4.homedir)()) {
|
|
7833
|
-
return provider === "claude" ? (0,
|
|
8663
|
+
return provider === "claude" ? (0, import_node_path12.join)(home, ".claude", ".credentials.json") : (0, import_node_path12.join)(home, ".codex", "auth.json");
|
|
7834
8664
|
}
|
|
7835
8665
|
function decodeJwtExpiryMs(token) {
|
|
7836
8666
|
try {
|
|
@@ -7879,10 +8709,10 @@ function parseCodexTokensEnvelope(raw) {
|
|
|
7879
8709
|
}
|
|
7880
8710
|
function readExternalCliCredentials(provider, home = (0, import_node_os4.homedir)()) {
|
|
7881
8711
|
const path2 = externalStorePath(provider, home);
|
|
7882
|
-
if (!(0,
|
|
8712
|
+
if (!(0, import_node_fs20.existsSync)(path2)) return null;
|
|
7883
8713
|
let raw;
|
|
7884
8714
|
try {
|
|
7885
|
-
const parsed = JSON.parse((0,
|
|
8715
|
+
const parsed = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
|
|
7886
8716
|
raw = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
7887
8717
|
} catch {
|
|
7888
8718
|
return null;
|
|
@@ -8453,9 +9283,9 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
8453
9283
|
* `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
|
|
8454
9284
|
* write incl. child 4's future refresh writes lands encrypted. */
|
|
8455
9285
|
persist(config) {
|
|
8456
|
-
(0,
|
|
9286
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path13.dirname)(this.tokensPath), { recursive: true });
|
|
8457
9287
|
const encrypted = encryptTokens(config, this.box);
|
|
8458
|
-
(0,
|
|
9288
|
+
(0, import_node_fs21.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
|
|
8459
9289
|
}
|
|
8460
9290
|
/**
|
|
8461
9291
|
* Read + parse `tokens.json`, tolerating a missing/corrupt file, then DECRYPT
|
|
@@ -8471,10 +9301,10 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
8471
9301
|
* `config.ts loadConfig`, which decrypts outside its parse try.
|
|
8472
9302
|
*/
|
|
8473
9303
|
readConfig() {
|
|
8474
|
-
if (!(0,
|
|
9304
|
+
if (!(0, import_node_fs21.existsSync)(this.tokensPath)) return { updatedAt: "" };
|
|
8475
9305
|
let parsed;
|
|
8476
9306
|
try {
|
|
8477
|
-
const raw = JSON.parse((0,
|
|
9307
|
+
const raw = JSON.parse((0, import_node_fs21.readFileSync)(this.tokensPath, "utf8"));
|
|
8478
9308
|
parsed = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
|
|
8479
9309
|
} catch {
|
|
8480
9310
|
parsed = null;
|
|
@@ -8991,32 +9821,14 @@ var AccountHealthSweeper = class {
|
|
|
8991
9821
|
};
|
|
8992
9822
|
|
|
8993
9823
|
// src/audit/AuditPruneSweeper.ts
|
|
8994
|
-
var
|
|
8995
|
-
var
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
var AUDIT_FILE_RE = /^audit-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
|
|
8999
|
-
var pad22 = (n) => String(n).padStart(2, "0");
|
|
9000
|
-
function auditFileName(ts) {
|
|
9001
|
-
const d = new Date(ts);
|
|
9002
|
-
return `audit-${d.getFullYear()}-${pad22(d.getMonth() + 1)}-${pad22(d.getDate())}.jsonl`;
|
|
9003
|
-
}
|
|
9004
|
-
function auditFileDateMs(fileName) {
|
|
9005
|
-
const m = AUDIT_FILE_RE.exec(fileName);
|
|
9006
|
-
if (!m) return null;
|
|
9007
|
-
const year = Number(m[1]);
|
|
9008
|
-
const month = Number(m[2]);
|
|
9009
|
-
const day = Number(m[3]);
|
|
9010
|
-
const d = new Date(year, month - 1, day);
|
|
9011
|
-
if (d.getFullYear() !== year || d.getMonth() !== month - 1 || d.getDate() !== day) {
|
|
9012
|
-
return null;
|
|
9013
|
-
}
|
|
9014
|
-
return d.getTime();
|
|
9015
|
-
}
|
|
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");
|
|
9016
9828
|
|
|
9017
9829
|
// src/audit/auditStats.ts
|
|
9018
|
-
var
|
|
9019
|
-
var
|
|
9830
|
+
var import_node_fs22 = require("fs");
|
|
9831
|
+
var import_node_path14 = require("path");
|
|
9020
9832
|
var SIDECAR_VERSION = 1;
|
|
9021
9833
|
var META_PREFIX_BYTES = 64 * 1024;
|
|
9022
9834
|
var READ_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
@@ -9024,9 +9836,9 @@ function auditStatsFileName(auditFile) {
|
|
|
9024
9836
|
return auditFile.replace(/\.jsonl$/, ".stats.json");
|
|
9025
9837
|
}
|
|
9026
9838
|
function readPersisted(path2) {
|
|
9027
|
-
if (!(0,
|
|
9839
|
+
if (!(0, import_node_fs22.existsSync)(path2)) return null;
|
|
9028
9840
|
try {
|
|
9029
|
-
const value = JSON.parse((0,
|
|
9841
|
+
const value = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
9030
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)) {
|
|
9031
9843
|
return null;
|
|
9032
9844
|
}
|
|
@@ -9036,7 +9848,7 @@ function readPersisted(path2) {
|
|
|
9036
9848
|
}
|
|
9037
9849
|
}
|
|
9038
9850
|
function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
|
|
9039
|
-
const statsPath = (0,
|
|
9851
|
+
const statsPath = (0, import_node_path14.join)((0, import_node_path14.dirname)(auditPath), auditStatsFileName((0, import_node_path14.basename)(auditPath)));
|
|
9040
9852
|
const previous = auditBytesBefore === 0 ? {
|
|
9041
9853
|
version: SIDECAR_VERSION,
|
|
9042
9854
|
auditBytes: 0,
|
|
@@ -9056,13 +9868,13 @@ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfte
|
|
|
9056
9868
|
minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
|
|
9057
9869
|
maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
|
|
9058
9870
|
};
|
|
9059
|
-
(0,
|
|
9871
|
+
(0, import_node_fs22.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
|
|
9060
9872
|
}
|
|
9061
9873
|
function queryCovers(stats, from, to) {
|
|
9062
9874
|
return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
|
|
9063
9875
|
}
|
|
9064
|
-
function fileOverlaps(
|
|
9065
|
-
const start = auditFileDateMs(
|
|
9876
|
+
function fileOverlaps(name, from, to) {
|
|
9877
|
+
const start = auditFileDateMs(name);
|
|
9066
9878
|
if (start === null) return false;
|
|
9067
9879
|
const date = new Date(start);
|
|
9068
9880
|
const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
|
|
@@ -9114,7 +9926,7 @@ async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
|
|
|
9114
9926
|
prefixTruncated = false;
|
|
9115
9927
|
};
|
|
9116
9928
|
if (auditBytes > startByte) {
|
|
9117
|
-
const stream = (0,
|
|
9929
|
+
const stream = (0, import_node_fs22.createReadStream)(auditPath, {
|
|
9118
9930
|
start: startByte,
|
|
9119
9931
|
end: auditBytes - 1,
|
|
9120
9932
|
highWaterMark: READ_CHUNK_BYTES
|
|
@@ -9167,21 +9979,27 @@ function mergePersistedStats(previous, appended) {
|
|
|
9167
9979
|
};
|
|
9168
9980
|
}
|
|
9169
9981
|
async function readAuditStats(auditDir, query2 = {}) {
|
|
9170
|
-
if (!(0,
|
|
9982
|
+
if (!(0, import_node_fs22.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
|
|
9171
9983
|
const from = typeof query2.from === "number" ? query2.from : -Infinity;
|
|
9172
9984
|
const to = typeof query2.to === "number" ? query2.to : Infinity;
|
|
9173
|
-
let
|
|
9985
|
+
let sources;
|
|
9174
9986
|
try {
|
|
9175
|
-
|
|
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));
|
|
9176
9996
|
} catch {
|
|
9177
9997
|
return { requestCount: 0, errorCount: 0, complete: false };
|
|
9178
9998
|
}
|
|
9179
9999
|
const total = { requestCount: 0, errorCount: 0, complete: true };
|
|
9180
|
-
for (const
|
|
9181
|
-
const auditPath = (0, import_node_path11.join)(auditDir, file);
|
|
10000
|
+
for (const { auditPath, statsPath } of sources) {
|
|
9182
10001
|
try {
|
|
9183
|
-
const auditBytes = (0,
|
|
9184
|
-
const statsPath = (0, import_node_path11.join)(auditDir, auditStatsFileName(file));
|
|
10002
|
+
const auditBytes = (0, import_node_fs22.statSync)(auditPath).size;
|
|
9185
10003
|
const persisted = readPersisted(statsPath);
|
|
9186
10004
|
if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
|
|
9187
10005
|
total.requestCount += persisted.requestCount;
|
|
@@ -9200,7 +10018,7 @@ async function readAuditStats(auditDir, query2 = {}) {
|
|
|
9200
10018
|
total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
|
|
9201
10019
|
total.complete = total.complete && scanned.filtered.complete;
|
|
9202
10020
|
const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
|
|
9203
|
-
if (current.complete) (0,
|
|
10021
|
+
if (current.complete) (0, import_node_fs22.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
|
|
9204
10022
|
} catch {
|
|
9205
10023
|
total.complete = false;
|
|
9206
10024
|
}
|
|
@@ -9211,6 +10029,7 @@ async function readAuditStats(auditDir, query2 = {}) {
|
|
|
9211
10029
|
// src/audit/AuditPruneSweeper.ts
|
|
9212
10030
|
var DAY_MS = 24 * 60 * 6e4;
|
|
9213
10031
|
var SWEEP_INTERVAL_MS2 = 60 * 6e4;
|
|
10032
|
+
var ARCHIVE_BATCH = 64;
|
|
9214
10033
|
var AuditPruneSweeper = class {
|
|
9215
10034
|
constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
|
|
9216
10035
|
this.auditDir = auditDir;
|
|
@@ -9226,6 +10045,7 @@ var AuditPruneSweeper = class {
|
|
|
9226
10045
|
now;
|
|
9227
10046
|
timer = null;
|
|
9228
10047
|
sweeping = false;
|
|
10048
|
+
archiving = false;
|
|
9229
10049
|
/** Whether pruning is active (audit enabled). */
|
|
9230
10050
|
get enabled() {
|
|
9231
10051
|
return this.config.enabled;
|
|
@@ -9235,13 +10055,13 @@ var AuditPruneSweeper = class {
|
|
|
9235
10055
|
this.config = config;
|
|
9236
10056
|
}
|
|
9237
10057
|
/**
|
|
9238
|
-
* Arm the
|
|
9239
|
-
*
|
|
10058
|
+
* Arm the interval AND run one pass immediately (boot cleanup). No-op when
|
|
10059
|
+
* audit is disabled (zero regression). Idempotent.
|
|
9240
10060
|
*/
|
|
9241
10061
|
start() {
|
|
9242
10062
|
if (this.timer || !this.config.enabled) return;
|
|
9243
|
-
void this.
|
|
9244
|
-
this.timer = setInterval(() => void this.
|
|
10063
|
+
void this.runOnce();
|
|
10064
|
+
this.timer = setInterval(() => void this.runOnce(), this.intervalMs);
|
|
9245
10065
|
this.timer.unref?.();
|
|
9246
10066
|
}
|
|
9247
10067
|
/** Clear the interval (daemon shutdown / test teardown). Idempotent. */
|
|
@@ -9251,31 +10071,43 @@ var AuditPruneSweeper = class {
|
|
|
9251
10071
|
this.timer = null;
|
|
9252
10072
|
}
|
|
9253
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
|
+
}
|
|
9254
10084
|
/**
|
|
9255
|
-
* One prune:
|
|
9256
|
-
*
|
|
9257
|
-
*
|
|
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.
|
|
9258
10088
|
*/
|
|
9259
10089
|
async sweep() {
|
|
9260
10090
|
if (!this.config.enabled || this.sweeping) return 0;
|
|
9261
10091
|
this.sweeping = true;
|
|
9262
10092
|
try {
|
|
9263
|
-
if (!(0,
|
|
9264
|
-
const
|
|
9265
|
-
const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
|
|
9266
|
-
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;
|
|
9267
10095
|
let removed = 0;
|
|
9268
|
-
for (const
|
|
9269
|
-
const dateMs = auditFileDateMs(
|
|
10096
|
+
for (const name of (0, import_node_fs23.readdirSync)(this.auditDir)) {
|
|
10097
|
+
const dateMs = auditFileDateMs(name);
|
|
9270
10098
|
if (dateMs === null || dateMs >= cutoff) continue;
|
|
9271
10099
|
try {
|
|
9272
|
-
|
|
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
|
+
}
|
|
9273
10107
|
removed += 1;
|
|
9274
|
-
const statsPath = (0, import_node_path12.join)(this.auditDir, auditStatsFileName(file));
|
|
9275
|
-
if ((0, import_node_fs19.existsSync)(statsPath)) (0, import_node_fs19.unlinkSync)(statsPath);
|
|
9276
10108
|
} catch (error) {
|
|
9277
|
-
this.logger.warn("[AuditPruneSweeper] failed to
|
|
9278
|
-
|
|
10109
|
+
this.logger.warn("[AuditPruneSweeper] failed to remove expired audit day", {
|
|
10110
|
+
name,
|
|
9279
10111
|
error: error instanceof Error ? error.message : String(error)
|
|
9280
10112
|
});
|
|
9281
10113
|
}
|
|
@@ -9291,59 +10123,158 @@ var AuditPruneSweeper = class {
|
|
|
9291
10123
|
this.sweeping = false;
|
|
9292
10124
|
}
|
|
9293
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
|
+
}
|
|
9294
10209
|
};
|
|
9295
10210
|
|
|
9296
10211
|
// src/audit/auditReader.ts
|
|
9297
|
-
var
|
|
9298
|
-
var
|
|
10212
|
+
var import_node_fs24 = require("fs");
|
|
10213
|
+
var import_node_path16 = require("path");
|
|
9299
10214
|
var DEFAULT_LIMIT = 200;
|
|
9300
10215
|
var MAX_LIMIT = 2e3;
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
let
|
|
10216
|
+
var OVERSCAN = 256;
|
|
10217
|
+
function daySources(auditDir) {
|
|
10218
|
+
let names;
|
|
9304
10219
|
try {
|
|
9305
|
-
|
|
10220
|
+
names = (0, import_node_fs24.readdirSync)(auditDir);
|
|
9306
10221
|
} catch {
|
|
9307
10222
|
return [];
|
|
9308
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 [];
|
|
9309
10249
|
const from = typeof query2.from === "number" ? query2.from : -Infinity;
|
|
9310
10250
|
const to = typeof query2.to === "number" ? query2.to : Infinity;
|
|
9311
10251
|
const limit = Math.min(MAX_LIMIT, Math.max(1, Math.trunc(query2.limit ?? DEFAULT_LIMIT)));
|
|
9312
10252
|
const matched = [];
|
|
9313
|
-
for (const
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
} catch {
|
|
9318
|
-
continue;
|
|
9319
|
-
}
|
|
9320
|
-
for (const line of raw.split("\n")) {
|
|
9321
|
-
const trimmed = line.trim();
|
|
9322
|
-
if (!trimmed) continue;
|
|
9323
|
-
let rec;
|
|
10253
|
+
for (const source of daySources(auditDir)) {
|
|
10254
|
+
const before = matched.length;
|
|
10255
|
+
forEachLineFromTail(source.path, (line) => {
|
|
10256
|
+
let parsed;
|
|
9324
10257
|
try {
|
|
9325
|
-
|
|
10258
|
+
parsed = JSON.parse(line);
|
|
9326
10259
|
} catch {
|
|
9327
|
-
|
|
10260
|
+
return false;
|
|
9328
10261
|
}
|
|
9329
|
-
if (!isAuditRecord(
|
|
9330
|
-
if (query2.keyId !== void 0 &&
|
|
9331
|
-
if (
|
|
9332
|
-
|
|
9333
|
-
|
|
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;
|
|
9334
10270
|
}
|
|
9335
10271
|
matched.sort((a, b) => b.ts - a.ts);
|
|
9336
10272
|
return matched.slice(0, limit);
|
|
9337
10273
|
}
|
|
9338
|
-
function isAuditRecord(value) {
|
|
9339
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
9340
|
-
const r = value;
|
|
9341
|
-
return typeof r["id"] === "string" && typeof r["ts"] === "number" && typeof r["method"] === "string" && typeof r["path"] === "string" && typeof r["status"] === "number";
|
|
9342
|
-
}
|
|
9343
10274
|
|
|
9344
10275
|
// src/audit/AuditWriter.ts
|
|
9345
|
-
var
|
|
9346
|
-
var
|
|
10276
|
+
var import_node_fs25 = require("fs");
|
|
10277
|
+
var import_node_path17 = require("path");
|
|
9347
10278
|
var AuditWriter = class {
|
|
9348
10279
|
constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
|
|
9349
10280
|
this.auditDir = auditDir;
|
|
@@ -9353,10 +10284,13 @@ var AuditWriter = class {
|
|
|
9353
10284
|
auditDir;
|
|
9354
10285
|
logger;
|
|
9355
10286
|
defer;
|
|
9356
|
-
|
|
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();
|
|
9357
10291
|
/**
|
|
9358
|
-
* Enqueue one record
|
|
9359
|
-
*
|
|
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.
|
|
9360
10294
|
*/
|
|
9361
10295
|
record(record) {
|
|
9362
10296
|
this.defer(() => {
|
|
@@ -9369,25 +10303,41 @@ var AuditWriter = class {
|
|
|
9369
10303
|
}
|
|
9370
10304
|
});
|
|
9371
10305
|
}
|
|
10306
|
+
/** Drop all retained encoding bases (config reload / shutdown / test teardown). */
|
|
10307
|
+
reset() {
|
|
10308
|
+
this.bases.clear();
|
|
10309
|
+
this.ensuredDirs.clear();
|
|
10310
|
+
}
|
|
9372
10311
|
/**
|
|
9373
|
-
* Append synchronously — the awaitable form tests use to assert
|
|
9374
|
-
*
|
|
9375
|
-
* 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.
|
|
9376
10314
|
*/
|
|
9377
10315
|
appendNow(record) {
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
(
|
|
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");
|
|
9386
10336
|
try {
|
|
9387
10337
|
updateAuditStatsAfterAppend(
|
|
9388
10338
|
file,
|
|
9389
|
-
|
|
9390
|
-
|
|
10339
|
+
bytesBefore,
|
|
10340
|
+
bytesBefore + Buffer.byteLength(line, "utf8"),
|
|
9391
10341
|
record
|
|
9392
10342
|
);
|
|
9393
10343
|
} catch (error) {
|
|
@@ -9396,12 +10346,39 @@ var AuditWriter = class {
|
|
|
9396
10346
|
});
|
|
9397
10347
|
}
|
|
9398
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
|
+
}
|
|
9399
10376
|
};
|
|
9400
10377
|
|
|
9401
10378
|
// src/billing/BillingPublisher.ts
|
|
9402
|
-
var
|
|
10379
|
+
var import_node_fs26 = require("fs");
|
|
9403
10380
|
var import_node_crypto13 = require("crypto");
|
|
9404
|
-
var
|
|
10381
|
+
var import_node_path18 = require("path");
|
|
9405
10382
|
var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
9406
10383
|
|
|
9407
10384
|
// src/billing/billingFiles.ts
|
|
@@ -9472,8 +10449,8 @@ var BillingPublisher = class {
|
|
|
9472
10449
|
*/
|
|
9473
10450
|
appendNow(event) {
|
|
9474
10451
|
this.ensureDir();
|
|
9475
|
-
const file = (0,
|
|
9476
|
-
(0,
|
|
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");
|
|
9477
10454
|
}
|
|
9478
10455
|
/**
|
|
9479
10456
|
* One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
|
|
@@ -9522,8 +10499,8 @@ var BillingPublisher = class {
|
|
|
9522
10499
|
markDelivered(event) {
|
|
9523
10500
|
try {
|
|
9524
10501
|
this.ensureDir();
|
|
9525
|
-
const file = (0,
|
|
9526
|
-
(0,
|
|
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");
|
|
9527
10504
|
} catch (error) {
|
|
9528
10505
|
this.logger.warn("[BillingPublisher] failed to append delivery marker", {
|
|
9529
10506
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -9532,20 +10509,20 @@ var BillingPublisher = class {
|
|
|
9532
10509
|
}
|
|
9533
10510
|
ensureDir() {
|
|
9534
10511
|
if (this.dirEnsured) return;
|
|
9535
|
-
(0,
|
|
10512
|
+
(0, import_node_fs26.mkdirSync)(this.billingDir, { recursive: true });
|
|
9536
10513
|
this.dirEnsured = true;
|
|
9537
10514
|
}
|
|
9538
10515
|
};
|
|
9539
10516
|
|
|
9540
10517
|
// src/billing/billingReader.ts
|
|
9541
|
-
var
|
|
9542
|
-
var
|
|
10518
|
+
var import_node_fs27 = require("fs");
|
|
10519
|
+
var import_node_path19 = require("path");
|
|
9543
10520
|
function readBillingLedger(billingDir) {
|
|
9544
10521
|
const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
|
|
9545
|
-
if (!(0,
|
|
10522
|
+
if (!(0, import_node_fs27.existsSync)(billingDir)) return view;
|
|
9546
10523
|
let files;
|
|
9547
10524
|
try {
|
|
9548
|
-
files = (0,
|
|
10525
|
+
files = (0, import_node_fs27.readdirSync)(billingDir);
|
|
9549
10526
|
} catch {
|
|
9550
10527
|
return view;
|
|
9551
10528
|
}
|
|
@@ -9576,7 +10553,7 @@ function readBillingStatus(billingDir) {
|
|
|
9576
10553
|
function parseLines(dir, file) {
|
|
9577
10554
|
let raw;
|
|
9578
10555
|
try {
|
|
9579
|
-
raw = (0,
|
|
10556
|
+
raw = (0, import_node_fs27.readFileSync)((0, import_node_path19.join)(dir, file), "utf8");
|
|
9580
10557
|
} catch {
|
|
9581
10558
|
return [];
|
|
9582
10559
|
}
|
|
@@ -10062,7 +11039,7 @@ function buildDaemon(config, paths) {
|
|
|
10062
11039
|
}
|
|
10063
11040
|
);
|
|
10064
11041
|
const pricingStore = new JsonPricingStore(defaultPricingPath(paths.configPath));
|
|
10065
|
-
const pricingEngine = new
|
|
11042
|
+
const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
|
|
10066
11043
|
// Catalog egress follows the same global/env proxy policy as every other
|
|
10067
11044
|
// daemon upstream call; no provider/account override applies here.
|
|
10068
11045
|
fetchImpl: ((input, init) => (0, import_upstreamFetch8.fetchUpstream)(String(input), init ?? {}))
|
|
@@ -10078,8 +11055,10 @@ function buildDaemon(config, paths) {
|
|
|
10078
11055
|
async (providerId, model) => await pricingEngine.getEntry(providerId, model) !== null
|
|
10079
11056
|
);
|
|
10080
11057
|
const keySpendTracker = new import_outbound_api6.KeySpendTracker(usageEventStore);
|
|
10081
|
-
const
|
|
10082
|
-
|
|
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)
|
|
10083
11062
|
});
|
|
10084
11063
|
const providerProxy = (0, import_provider_proxy4.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
|
|
10085
11064
|
const routeLeaseManager = new import_provider_proxy4.RouteLeaseManager(
|
|
@@ -10228,6 +11207,11 @@ function buildDaemon(config, paths) {
|
|
|
10228
11207
|
// NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
|
|
10229
11208
|
auditReader: (query2) => readAuditRecords(auditDir, query2),
|
|
10230
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),
|
|
10231
11215
|
// billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
|
|
10232
11216
|
// secret-free total/delivered/pending counts of the durable ledger.
|
|
10233
11217
|
billingStatusReader: () => readBillingStatus(billingDir)
|
|
@@ -10286,8 +11270,8 @@ function buildDaemon(config, paths) {
|
|
|
10286
11270
|
}
|
|
10287
11271
|
function isTokensStoreReadable(tokensPath) {
|
|
10288
11272
|
try {
|
|
10289
|
-
if (!(0,
|
|
10290
|
-
(0,
|
|
11273
|
+
if (!(0, import_node_fs28.existsSync)(tokensPath)) return true;
|
|
11274
|
+
(0, import_node_fs28.accessSync)(tokensPath, import_node_fs28.constants.R_OK);
|
|
10291
11275
|
return true;
|
|
10292
11276
|
} catch {
|
|
10293
11277
|
return false;
|
|
@@ -10332,10 +11316,10 @@ function buildCliSpawnPlan(opts) {
|
|
|
10332
11316
|
};
|
|
10333
11317
|
}
|
|
10334
11318
|
function resolveInPathDefault(candidate) {
|
|
10335
|
-
const segments = (process.env["PATH"] ?? "").split(
|
|
11319
|
+
const segments = (process.env["PATH"] ?? "").split(import_node_path20.delimiter).filter(Boolean);
|
|
10336
11320
|
for (const seg of segments) {
|
|
10337
|
-
const full = (0,
|
|
10338
|
-
if ((0,
|
|
11321
|
+
const full = (0, import_node_path20.join)(seg, candidate);
|
|
11322
|
+
if ((0, import_node_fs29.existsSync)(full)) return full;
|
|
10339
11323
|
}
|
|
10340
11324
|
return null;
|
|
10341
11325
|
}
|
|
@@ -10343,7 +11327,7 @@ async function runLaunch(argv, deps) {
|
|
|
10343
11327
|
const sep = argv.indexOf("--");
|
|
10344
11328
|
const own = sep === -1 ? argv : argv.slice(0, sep);
|
|
10345
11329
|
const passthrough = sep === -1 ? [] : argv.slice(sep + 1);
|
|
10346
|
-
const { values, positionals } = (0,
|
|
11330
|
+
const { values, positionals } = (0, import_node_util5.parseArgs)({
|
|
10347
11331
|
args: own,
|
|
10348
11332
|
options: {
|
|
10349
11333
|
provider: { type: "string", short: "p" },
|
|
@@ -10513,12 +11497,12 @@ function spawnCliInherit(plan) {
|
|
|
10513
11497
|
// src/commands/login.ts
|
|
10514
11498
|
var import_node_child_process3 = require("child_process");
|
|
10515
11499
|
var import_node_readline = require("readline");
|
|
10516
|
-
var
|
|
11500
|
+
var import_node_util6 = require("util");
|
|
10517
11501
|
var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
10518
11502
|
var import_subscriptions5 = require("@omnicross/subscriptions");
|
|
10519
11503
|
var PROVIDERS2 = ["claude", "codex", "gemini"];
|
|
10520
11504
|
async function runLogin(argv, deps) {
|
|
10521
|
-
const { values, positionals } = (0,
|
|
11505
|
+
const { values, positionals } = (0, import_node_util6.parseArgs)({
|
|
10522
11506
|
args: argv,
|
|
10523
11507
|
options: {
|
|
10524
11508
|
config: { type: "string", short: "c" },
|
|
@@ -10686,9 +11670,9 @@ function promptPaste(prompt) {
|
|
|
10686
11670
|
|
|
10687
11671
|
// src/commands/providers.ts
|
|
10688
11672
|
var import_node_crypto16 = require("crypto");
|
|
10689
|
-
var
|
|
11673
|
+
var import_node_util7 = require("util");
|
|
10690
11674
|
async function runProviders(argv) {
|
|
10691
|
-
const { values, positionals } = (0,
|
|
11675
|
+
const { values, positionals } = (0, import_node_util7.parseArgs)({
|
|
10692
11676
|
args: argv,
|
|
10693
11677
|
options: {
|
|
10694
11678
|
config: { type: "string", short: "c" },
|
|
@@ -10835,10 +11819,10 @@ function providersRmKey(configPath, providerId, keyId) {
|
|
|
10835
11819
|
}
|
|
10836
11820
|
|
|
10837
11821
|
// src/commands/secrets.ts
|
|
10838
|
-
var
|
|
10839
|
-
var
|
|
11822
|
+
var import_node_fs30 = require("fs");
|
|
11823
|
+
var import_node_util8 = require("util");
|
|
10840
11824
|
async function runSecrets(argv) {
|
|
10841
|
-
const { values, positionals } = (0,
|
|
11825
|
+
const { values, positionals } = (0, import_node_util8.parseArgs)({
|
|
10842
11826
|
args: argv,
|
|
10843
11827
|
options: {
|
|
10844
11828
|
config: { type: "string", short: "c" },
|
|
@@ -10908,12 +11892,12 @@ function secretsStatus(args) {
|
|
|
10908
11892
|
reportField("admin.token", cfg.admin.token);
|
|
10909
11893
|
}
|
|
10910
11894
|
const tokensPath = defaultTokensPath(args.config);
|
|
10911
|
-
if ((0,
|
|
11895
|
+
if ((0, import_node_fs30.existsSync)(tokensPath)) {
|
|
10912
11896
|
console.info(`Secret status for ${tokensPath}:`);
|
|
10913
11897
|
reportTokenFields(tokensPath);
|
|
10914
11898
|
}
|
|
10915
11899
|
const integrationsPath = defaultIntegrationsPath(args.config);
|
|
10916
|
-
if ((0,
|
|
11900
|
+
if ((0, import_node_fs30.existsSync)(integrationsPath)) {
|
|
10917
11901
|
const state = readRawJson(integrationsPath);
|
|
10918
11902
|
const key = state.gatewayKey;
|
|
10919
11903
|
if (key && typeof key === "object" && !Array.isArray(key)) {
|
|
@@ -10967,8 +11951,8 @@ async function secretsRotate(args) {
|
|
|
10967
11951
|
const integrationsPath = defaultIntegrationsPath(args.config);
|
|
10968
11952
|
try {
|
|
10969
11953
|
cfg = loadConfig(args.config);
|
|
10970
|
-
if ((0,
|
|
10971
|
-
if ((0,
|
|
11954
|
+
if ((0, import_node_fs30.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
|
|
11955
|
+
if ((0, import_node_fs30.existsSync)(integrationsPath)) {
|
|
10972
11956
|
integrationsPlain = new IntegrationStateStore(integrationsPath, oldBox).load();
|
|
10973
11957
|
}
|
|
10974
11958
|
} finally {
|
|
@@ -11003,20 +11987,20 @@ function secretsDecrypt(args) {
|
|
|
11003
11987
|
let tokensPlain = null;
|
|
11004
11988
|
try {
|
|
11005
11989
|
cfg = loadConfig(args.config);
|
|
11006
|
-
if ((0,
|
|
11990
|
+
if ((0, import_node_fs30.existsSync)(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
|
|
11007
11991
|
} finally {
|
|
11008
11992
|
setSecretBox(null);
|
|
11009
11993
|
}
|
|
11010
11994
|
saveConfig(args.config, cfg);
|
|
11011
11995
|
if (tokensPlain) {
|
|
11012
|
-
(0,
|
|
11996
|
+
(0, import_node_fs30.writeFileSync)(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n", "utf8");
|
|
11013
11997
|
}
|
|
11014
11998
|
console.info(`Decrypted secrets to plaintext in ${args.config}` + tokensSuffix(args.config));
|
|
11015
11999
|
}
|
|
11016
12000
|
function readRawConfig(path2) {
|
|
11017
12001
|
let parsed;
|
|
11018
12002
|
try {
|
|
11019
|
-
parsed = JSON.parse((0,
|
|
12003
|
+
parsed = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
|
|
11020
12004
|
} catch {
|
|
11021
12005
|
throw new Error(`secrets: cannot read or parse '${path2}'`);
|
|
11022
12006
|
}
|
|
@@ -11024,7 +12008,7 @@ function readRawConfig(path2) {
|
|
|
11024
12008
|
}
|
|
11025
12009
|
function readRawJson(path2) {
|
|
11026
12010
|
try {
|
|
11027
|
-
const parsed = JSON.parse((0,
|
|
12011
|
+
const parsed = JSON.parse((0, import_node_fs30.readFileSync)(path2, "utf8"));
|
|
11028
12012
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
11029
12013
|
return parsed;
|
|
11030
12014
|
}
|
|
@@ -11034,13 +12018,13 @@ function readRawJson(path2) {
|
|
|
11034
12018
|
}
|
|
11035
12019
|
function encryptTokensFileInPlace(configPath, box) {
|
|
11036
12020
|
const tokensPath = defaultTokensPath(configPath);
|
|
11037
|
-
if (!(0,
|
|
12021
|
+
if (!(0, import_node_fs30.existsSync)(tokensPath)) return;
|
|
11038
12022
|
const plain = decryptTokensFile(tokensPath, box);
|
|
11039
12023
|
writeTokensEncrypted(tokensPath, plain, box);
|
|
11040
12024
|
}
|
|
11041
12025
|
function rewriteIntegrationState(configPath, readBox, writeBox) {
|
|
11042
12026
|
const path2 = defaultIntegrationsPath(configPath);
|
|
11043
|
-
if (!(0,
|
|
12027
|
+
if (!(0, import_node_fs30.existsSync)(path2)) return;
|
|
11044
12028
|
const state = new IntegrationStateStore(path2, readBox).load();
|
|
11045
12029
|
new IntegrationStateStore(path2, writeBox).save(state);
|
|
11046
12030
|
}
|
|
@@ -11053,7 +12037,7 @@ function writeTokensEncrypted(tokensPath, plain, box) {
|
|
|
11053
12037
|
{ updatedAt: "", ...plain },
|
|
11054
12038
|
box
|
|
11055
12039
|
);
|
|
11056
|
-
(0,
|
|
12040
|
+
(0, import_node_fs30.writeFileSync)(tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
|
|
11057
12041
|
}
|
|
11058
12042
|
var TOKEN_FIELDS2 = {
|
|
11059
12043
|
claude: ["accessToken", "refreshToken"],
|
|
@@ -11076,11 +12060,11 @@ function walkTokens(raw, fn) {
|
|
|
11076
12060
|
return next;
|
|
11077
12061
|
}
|
|
11078
12062
|
function tokensSuffix(configPath) {
|
|
11079
|
-
return (0,
|
|
12063
|
+
return (0, import_node_fs30.existsSync)(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
|
|
11080
12064
|
}
|
|
11081
12065
|
|
|
11082
12066
|
// src/commands/start.ts
|
|
11083
|
-
var
|
|
12067
|
+
var import_node_util9 = require("util");
|
|
11084
12068
|
var import_outbound_api7 = require("@omnicross/core/outbound-api");
|
|
11085
12069
|
var import_SubscriptionAccountHealth5 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
11086
12070
|
var import_AccountAllowanceScheduling6 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
@@ -11119,7 +12103,7 @@ async function seedIdentities(store, credentialStore) {
|
|
|
11119
12103
|
|
|
11120
12104
|
// src/commands/start.ts
|
|
11121
12105
|
async function runStart(argv) {
|
|
11122
|
-
const { values } = (0,
|
|
12106
|
+
const { values } = (0, import_node_util9.parseArgs)({
|
|
11123
12107
|
args: argv,
|
|
11124
12108
|
options: {
|
|
11125
12109
|
config: { type: "string", short: "c" },
|
|
@@ -11259,6 +12243,10 @@ Usage:
|
|
|
11259
12243
|
omnicross secrets encrypt --config <p> Encrypt all at-rest secrets in place.
|
|
11260
12244
|
omnicross secrets status --config <p> Report each secret field (no values shown).
|
|
11261
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.
|
|
11262
12250
|
`;
|
|
11263
12251
|
async function main() {
|
|
11264
12252
|
const [, , subcommand, ...rest] = process.argv;
|
|
@@ -11290,6 +12278,9 @@ async function main() {
|
|
|
11290
12278
|
case "secrets":
|
|
11291
12279
|
await runSecrets(rest);
|
|
11292
12280
|
return;
|
|
12281
|
+
case "audit":
|
|
12282
|
+
await runAudit(rest);
|
|
12283
|
+
return;
|
|
11293
12284
|
case void 0:
|
|
11294
12285
|
case "-h":
|
|
11295
12286
|
case "--help":
|