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