@omnicross/daemon 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +1354 -363
- package/dist/cli.js +1336 -340
- package/dist/index.cjs +897 -107
- package/dist/index.d.cts +160 -43
- package/dist/index.d.ts +160 -43
- package/dist/index.js +895 -100
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,86 +1,633 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/commands/
|
|
4
|
-
import {
|
|
3
|
+
// src/commands/audit.ts
|
|
4
|
+
import { readdirSync as readdirSync3 } from "fs";
|
|
5
|
+
import { join as join5 } from "path";
|
|
5
6
|
import { parseArgs } from "util";
|
|
6
7
|
|
|
7
|
-
// src/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
// src/audit/auditBodyReader.ts
|
|
9
|
+
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
10
|
+
import { join as join2 } from "path";
|
|
11
|
+
import { gunzipSync } from "zlib";
|
|
12
|
+
|
|
13
|
+
// src/audit/auditBodyStore.ts
|
|
14
|
+
var ANCHOR_EVERY = 64;
|
|
15
|
+
var ANCHOR_DELTA_RATIO = 0.75;
|
|
16
|
+
var DIVERGED_PREFIX_RATIO = 0.25;
|
|
17
|
+
var MAX_BASE_CHARS = 4e6;
|
|
18
|
+
var CACHE_BUDGET_CHARS = 16e6;
|
|
19
|
+
var CACHE_MAX_SESSIONS = 32;
|
|
20
|
+
var MAX_BASES_PER_SESSION = 4;
|
|
21
|
+
var isHighSurrogate = (code) => code >= 55296 && code <= 56319;
|
|
22
|
+
var isLowSurrogate = (code) => code >= 56320 && code <= 57343;
|
|
23
|
+
function computeBodyDelta(prev, next) {
|
|
24
|
+
const shortest = Math.min(prev.length, next.length);
|
|
25
|
+
let pre = 0;
|
|
26
|
+
while (pre < shortest && prev.charCodeAt(pre) === next.charCodeAt(pre)) pre += 1;
|
|
27
|
+
if (pre > 0 && isHighSurrogate(prev.charCodeAt(pre - 1))) pre -= 1;
|
|
28
|
+
const maxSuf = shortest - pre;
|
|
29
|
+
let suf = 0;
|
|
30
|
+
while (suf < maxSuf && prev.charCodeAt(prev.length - 1 - suf) === next.charCodeAt(next.length - 1 - suf)) {
|
|
31
|
+
suf += 1;
|
|
32
|
+
}
|
|
33
|
+
if (suf > 0 && isLowSurrogate(prev.charCodeAt(prev.length - suf))) suf -= 1;
|
|
34
|
+
return { pre, suf, ins: next.slice(pre, next.length - suf) };
|
|
35
|
+
}
|
|
36
|
+
function applyBodyDelta(prev, delta) {
|
|
37
|
+
const head = delta.pre > 0 ? prev.slice(0, delta.pre) : "";
|
|
38
|
+
const tail = delta.suf > 0 ? prev.slice(prev.length - delta.suf) : "";
|
|
39
|
+
return head + delta.ins + tail;
|
|
40
|
+
}
|
|
41
|
+
var SessionBaseCache = class {
|
|
42
|
+
constructor(maxSessions = CACHE_MAX_SESSIONS, budgetChars = CACHE_BUDGET_CHARS, maxBaseChars = MAX_BASE_CHARS, maxHeads = MAX_BASES_PER_SESSION) {
|
|
43
|
+
this.maxSessions = maxSessions;
|
|
44
|
+
this.budgetChars = budgetChars;
|
|
45
|
+
this.maxBaseChars = maxBaseChars;
|
|
46
|
+
this.maxHeads = maxHeads;
|
|
47
|
+
}
|
|
48
|
+
maxSessions;
|
|
49
|
+
budgetChars;
|
|
50
|
+
maxBaseChars;
|
|
51
|
+
maxHeads;
|
|
52
|
+
/** Session key to its retained heads, most-recent first. */
|
|
53
|
+
entries = /* @__PURE__ */ new Map();
|
|
54
|
+
chars = 0;
|
|
55
|
+
/** Retained sessions (tests + diagnostics). */
|
|
56
|
+
get size() {
|
|
57
|
+
return this.entries.size;
|
|
58
|
+
}
|
|
59
|
+
/** A session's retained heads, most-recent first. Refreshes LRU recency. */
|
|
60
|
+
get(sessionKey) {
|
|
61
|
+
const found = this.entries.get(sessionKey);
|
|
62
|
+
if (!found) return [];
|
|
63
|
+
this.entries.delete(sessionKey);
|
|
64
|
+
this.entries.set(sessionKey, found);
|
|
65
|
+
return found;
|
|
11
66
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Retain `base` as a head of `sessionKey`.
|
|
69
|
+
*
|
|
70
|
+
* `replacesId` is the head this turn CONTINUES (its body was preserved whole
|
|
71
|
+
* inside the new one), which is swapped out so a linear conversation keeps
|
|
72
|
+
* exactly one head. Omit it when the turn started a distinct stream %s that
|
|
73
|
+
* head is added alongside, which is what keeps a fork's branches apart.
|
|
74
|
+
*
|
|
75
|
+
* A body larger than `maxBaseChars` is not retained: the next turn anchors
|
|
76
|
+
* rather than letting one oversized session monopolize the budget.
|
|
77
|
+
*/
|
|
78
|
+
remember(sessionKey, base, replacesId) {
|
|
79
|
+
const heads = this.entries.get(sessionKey) ?? [];
|
|
80
|
+
if (replacesId !== void 0) {
|
|
81
|
+
const at = heads.findIndex((head) => head.lastId === replacesId);
|
|
82
|
+
if (at >= 0) {
|
|
83
|
+
this.chars -= heads[at].text.length;
|
|
84
|
+
heads.splice(at, 1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (base.text.length <= this.maxBaseChars) {
|
|
88
|
+
heads.unshift(base);
|
|
89
|
+
this.chars += base.text.length;
|
|
90
|
+
}
|
|
91
|
+
while (heads.length > this.maxHeads) {
|
|
92
|
+
const dropped = heads.pop();
|
|
93
|
+
if (dropped) this.chars -= dropped.text.length;
|
|
94
|
+
}
|
|
95
|
+
this.entries.delete(sessionKey);
|
|
96
|
+
if (heads.length > 0) this.entries.set(sessionKey, heads);
|
|
97
|
+
this.evict();
|
|
98
|
+
}
|
|
99
|
+
/** Drop a session's heads (eviction, or a write failure invalidating them). */
|
|
100
|
+
forget(sessionKey) {
|
|
101
|
+
const heads = this.entries.get(sessionKey);
|
|
102
|
+
if (!heads) return;
|
|
103
|
+
for (const head of heads) this.chars -= head.text.length;
|
|
104
|
+
this.entries.delete(sessionKey);
|
|
105
|
+
}
|
|
106
|
+
/** Drop everything (writer disposal / test teardown). */
|
|
107
|
+
clear() {
|
|
108
|
+
this.entries.clear();
|
|
109
|
+
this.chars = 0;
|
|
110
|
+
}
|
|
111
|
+
/** Evict least-recently-used sessions until both bounds hold. */
|
|
112
|
+
evict() {
|
|
113
|
+
while (this.entries.size > this.maxSessions || this.chars > this.budgetChars && this.entries.size > 1) {
|
|
114
|
+
const oldest = this.entries.keys().next();
|
|
115
|
+
if (oldest.done) break;
|
|
116
|
+
this.forget(oldest.value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
function anchorReason(base, dayDir, delta, nextLength) {
|
|
121
|
+
if (!base || !delta) return "new";
|
|
122
|
+
if (base.dayDir !== dayDir) return "day";
|
|
123
|
+
if (base.chainLen >= ANCHOR_EVERY) return "chain";
|
|
124
|
+
if (delta.pre < base.text.length * DIVERGED_PREFIX_RATIO) return "diverged";
|
|
125
|
+
if (delta.ins.length > nextLength * ANCHOR_DELTA_RATIO) return "costly";
|
|
126
|
+
return null;
|
|
16
127
|
}
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
128
|
+
function pickBase(heads, next) {
|
|
129
|
+
let best = null;
|
|
130
|
+
for (const base of heads) {
|
|
131
|
+
const delta = computeBodyDelta(base.text, next);
|
|
132
|
+
if (best !== null && delta.ins.length >= best.delta.ins.length) continue;
|
|
133
|
+
best = { base, delta, continues: delta.pre + delta.suf >= base.text.length };
|
|
134
|
+
}
|
|
135
|
+
return best;
|
|
136
|
+
}
|
|
137
|
+
function encodeBodyEntry(record, sessionKey, dayDir, cache) {
|
|
138
|
+
const requestBody = record.requestBody;
|
|
139
|
+
const responseBody = record.responseBody;
|
|
140
|
+
if (requestBody === void 0 && responseBody === void 0) return null;
|
|
141
|
+
const entry = { id: record.id, ts: record.ts };
|
|
142
|
+
if (requestBody !== void 0) {
|
|
143
|
+
const heads = cache.get(sessionKey);
|
|
144
|
+
const sameDay = heads.filter((head) => head.dayDir === dayDir);
|
|
145
|
+
const chosen = pickBase(sameDay, requestBody);
|
|
146
|
+
const reason = heads.length > 0 && sameDay.length === 0 ? "day" : anchorReason(chosen?.base, dayDir, chosen?.delta ?? null, requestBody.length);
|
|
147
|
+
if (reason !== null) {
|
|
148
|
+
entry.req = { base: null, anchor: reason, pre: 0, suf: 0, ins: requestBody };
|
|
149
|
+
cache.remember(
|
|
150
|
+
sessionKey,
|
|
151
|
+
{ dayDir, lastId: record.id, text: requestBody, chainLen: 0 },
|
|
152
|
+
chosen?.continues === true ? chosen.base.lastId : void 0
|
|
153
|
+
);
|
|
154
|
+
} else {
|
|
155
|
+
const picked = chosen;
|
|
156
|
+
entry.req = {
|
|
157
|
+
base: picked.base.lastId,
|
|
158
|
+
...picked.continues ? { cont: true } : {},
|
|
159
|
+
pre: picked.delta.pre,
|
|
160
|
+
suf: picked.delta.suf,
|
|
161
|
+
ins: picked.delta.ins
|
|
162
|
+
};
|
|
163
|
+
cache.remember(
|
|
164
|
+
sessionKey,
|
|
165
|
+
{ dayDir, lastId: record.id, text: requestBody, chainLen: picked.base.chainLen + 1 },
|
|
166
|
+
picked.continues ? picked.base.lastId : void 0
|
|
167
|
+
);
|
|
168
|
+
}
|
|
21
169
|
}
|
|
22
|
-
if (
|
|
23
|
-
|
|
170
|
+
if (responseBody !== void 0) entry.res = responseBody;
|
|
171
|
+
return JSON.stringify(entry);
|
|
172
|
+
}
|
|
173
|
+
function isAuditBodyEntry(value) {
|
|
174
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
175
|
+
const entry = value;
|
|
176
|
+
if (typeof entry["id"] !== "string" || typeof entry["ts"] !== "number") return false;
|
|
177
|
+
if (entry["res"] !== void 0 && typeof entry["res"] !== "string") return false;
|
|
178
|
+
const req = entry["req"];
|
|
179
|
+
if (req === void 0) return true;
|
|
180
|
+
if (!req || typeof req !== "object" || Array.isArray(req)) return false;
|
|
181
|
+
const delta = req;
|
|
182
|
+
if (delta["anchor"] !== void 0 && typeof delta["anchor"] !== "string") return false;
|
|
183
|
+
if (delta["cont"] !== void 0 && typeof delta["cont"] !== "boolean") return false;
|
|
184
|
+
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";
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/audit/auditDictionary.ts
|
|
188
|
+
import { existsSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
189
|
+
import { join } from "path";
|
|
190
|
+
|
|
191
|
+
// src/audit/auditFiles.ts
|
|
192
|
+
var AUDIT_FILE_RE = /^audit-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
|
|
193
|
+
var AUDIT_DAY_DIR_RE = /^audit-(\d{4})-(\d{2})-(\d{2})$/;
|
|
194
|
+
var AUDIT_META_FILE = "meta.jsonl";
|
|
195
|
+
var AUDIT_BODIES_DIR = "bodies";
|
|
196
|
+
var AUDIT_SESSION_KEY_RE = /^[0-9a-f]{8,64}$/;
|
|
197
|
+
var pad2 = (n) => String(n).padStart(2, "0");
|
|
198
|
+
var localDateStamp = (ts) => {
|
|
199
|
+
const d = new Date(ts);
|
|
200
|
+
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
|
|
201
|
+
};
|
|
202
|
+
function auditDayDirName(ts) {
|
|
203
|
+
return `audit-${localDateStamp(ts)}`;
|
|
204
|
+
}
|
|
205
|
+
function isAuditDayDir(name) {
|
|
206
|
+
return AUDIT_DAY_DIR_RE.test(name);
|
|
207
|
+
}
|
|
208
|
+
function isSafeSessionKey(key) {
|
|
209
|
+
return typeof key === "string" && AUDIT_SESSION_KEY_RE.test(key);
|
|
210
|
+
}
|
|
211
|
+
function auditBodyFileName(sessionKey) {
|
|
212
|
+
return `${sessionKey}.jsonl`;
|
|
213
|
+
}
|
|
214
|
+
function auditFileDateMs(name) {
|
|
215
|
+
const m = AUDIT_FILE_RE.exec(name) ?? AUDIT_DAY_DIR_RE.exec(name);
|
|
216
|
+
if (!m) return null;
|
|
217
|
+
const year = Number(m[1]);
|
|
218
|
+
const month = Number(m[2]);
|
|
219
|
+
const day = Number(m[3]);
|
|
220
|
+
const d = new Date(year, month - 1, day);
|
|
221
|
+
if (d.getFullYear() !== year || d.getMonth() !== month - 1 || d.getDate() !== day) {
|
|
222
|
+
return null;
|
|
24
223
|
}
|
|
25
|
-
|
|
26
|
-
|
|
224
|
+
return d.getTime();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/audit/auditDictionary.ts
|
|
228
|
+
var AUDIT_DICT_FILE = "_dict.jsonl";
|
|
229
|
+
var DICT_BASE_PREFIX = "dict:";
|
|
230
|
+
var DICT_CANDIDATES = 3;
|
|
231
|
+
var MIN_SAVING_RATIO = 0.2;
|
|
232
|
+
function parseEntries(raw) {
|
|
233
|
+
const entries = [];
|
|
234
|
+
for (const line of raw.split("\n")) {
|
|
235
|
+
const trimmed = line.trim();
|
|
236
|
+
if (!trimmed) continue;
|
|
237
|
+
try {
|
|
238
|
+
const parsed = JSON.parse(trimmed);
|
|
239
|
+
if (isAuditBodyEntry(parsed)) entries.push(parsed);
|
|
240
|
+
} catch {
|
|
241
|
+
}
|
|
27
242
|
}
|
|
28
|
-
|
|
29
|
-
|
|
243
|
+
return entries;
|
|
244
|
+
}
|
|
245
|
+
function plainShards(bodiesPath) {
|
|
246
|
+
try {
|
|
247
|
+
return readdirSync(bodiesPath).filter(
|
|
248
|
+
(file) => file.endsWith(".jsonl") && isSafeSessionKey(file.slice(0, -".jsonl".length))
|
|
249
|
+
);
|
|
250
|
+
} catch {
|
|
251
|
+
return [];
|
|
30
252
|
}
|
|
31
|
-
return { format: "openai", ambiguous: true };
|
|
32
253
|
}
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
254
|
+
function chooseDictionary(anchors) {
|
|
255
|
+
if (anchors.length < 2) return null;
|
|
256
|
+
const total = anchors.reduce((sum, body) => sum + body.length, 0);
|
|
257
|
+
const candidates = [...anchors].sort((a, b) => b.length - a.length).slice(0, DICT_CANDIDATES);
|
|
258
|
+
let best = null;
|
|
259
|
+
for (const candidate of candidates) {
|
|
260
|
+
let cost = candidate.length;
|
|
261
|
+
for (const body of anchors) {
|
|
262
|
+
cost += body === candidate ? 0 : computeBodyDelta(candidate, body).ins.length;
|
|
263
|
+
}
|
|
264
|
+
if (best === null || cost < best.cost) best = { body: candidate, cost };
|
|
265
|
+
}
|
|
266
|
+
if (best === null) return null;
|
|
267
|
+
return total - best.cost >= total * MIN_SAVING_RATIO ? best.body : null;
|
|
268
|
+
}
|
|
269
|
+
var EMPTY = { shards: 0, anchors: 0, savedBytes: 0 };
|
|
270
|
+
function compactAuditDay(dayPath) {
|
|
271
|
+
const bodiesPath = join(dayPath, AUDIT_BODIES_DIR);
|
|
272
|
+
if (!existsSync(bodiesPath)) return EMPTY;
|
|
273
|
+
const dictPath = join(bodiesPath, AUDIT_DICT_FILE);
|
|
274
|
+
if (existsSync(dictPath) || existsSync(`${dictPath}.gz`)) return EMPTY;
|
|
275
|
+
const shardFiles = plainShards(bodiesPath);
|
|
276
|
+
if (shardFiles.length < 2) return EMPTY;
|
|
277
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
278
|
+
const anchors = [];
|
|
279
|
+
for (const file of shardFiles) {
|
|
280
|
+
let entries;
|
|
281
|
+
try {
|
|
282
|
+
entries = parseEntries(readFileSync(join(bodiesPath, file), "utf8"));
|
|
283
|
+
} catch {
|
|
39
284
|
continue;
|
|
40
285
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
`Provider '${id}': could not infer apiFormat from base URL \u2014 defaulted to 'openai'. Edit the config if this provider speaks a different wire format.`
|
|
45
|
-
);
|
|
286
|
+
loaded.set(file, entries);
|
|
287
|
+
for (const entry of entries) {
|
|
288
|
+
if (entry.req && entry.req.base === null) anchors.push(entry.req.ins);
|
|
46
289
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
290
|
+
}
|
|
291
|
+
if (anchors.length < 2) return EMPTY;
|
|
292
|
+
const dictionary = chooseDictionary(anchors);
|
|
293
|
+
if (dictionary === null) return EMPTY;
|
|
294
|
+
const dictEntry = {
|
|
295
|
+
id: `${DICT_BASE_PREFIX}0`,
|
|
296
|
+
ts: 0,
|
|
297
|
+
req: { base: null, anchor: "dict", pre: 0, suf: 0, ins: dictionary }
|
|
298
|
+
};
|
|
299
|
+
writeFileSync(dictPath, JSON.stringify(dictEntry) + "\n", "utf8");
|
|
300
|
+
const result = { shards: 0, anchors: 0, savedBytes: 0 };
|
|
301
|
+
for (const [file, entries] of loaded) {
|
|
302
|
+
let changed = false;
|
|
303
|
+
let saved = 0;
|
|
304
|
+
const rewritten = entries.map((entry) => {
|
|
305
|
+
if (!entry.req || entry.req.base !== null || entry.req.ins === dictionary) return entry;
|
|
306
|
+
const delta = computeBodyDelta(dictionary, entry.req.ins);
|
|
307
|
+
if (delta.ins.length >= entry.req.ins.length) return entry;
|
|
308
|
+
changed = true;
|
|
309
|
+
saved += entry.req.ins.length - delta.ins.length;
|
|
310
|
+
return {
|
|
311
|
+
...entry,
|
|
312
|
+
req: { base: dictEntry.id, pre: delta.pre, suf: delta.suf, ins: delta.ins }
|
|
313
|
+
};
|
|
53
314
|
});
|
|
315
|
+
if (!changed) continue;
|
|
316
|
+
const target = join(bodiesPath, file);
|
|
317
|
+
const temp = `${target}.compacting`;
|
|
318
|
+
try {
|
|
319
|
+
writeFileSync(temp, rewritten.map((e) => JSON.stringify(e)).join("\n") + "\n", "utf8");
|
|
320
|
+
renameSync(temp, target);
|
|
321
|
+
} catch {
|
|
322
|
+
try {
|
|
323
|
+
if (existsSync(temp)) unlinkSync(temp);
|
|
324
|
+
} catch {
|
|
325
|
+
}
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
result.shards += 1;
|
|
329
|
+
result.anchors += rewritten.filter((e) => e.req?.base === dictEntry.id).length;
|
|
330
|
+
result.savedBytes += saved;
|
|
54
331
|
}
|
|
55
|
-
|
|
332
|
+
if (result.shards === 0) {
|
|
333
|
+
try {
|
|
334
|
+
unlinkSync(dictPath);
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return result;
|
|
56
339
|
}
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
340
|
+
function compactAllClosedAuditDays(auditDir, now = Date.now) {
|
|
341
|
+
const run = { days: 0, shards: 0, savedBytes: 0 };
|
|
342
|
+
if (!existsSync(auditDir)) return run;
|
|
343
|
+
const today = auditDayDirName(now());
|
|
344
|
+
let names;
|
|
345
|
+
try {
|
|
346
|
+
names = readdirSync(auditDir).filter(isAuditDayDir).sort();
|
|
347
|
+
} catch {
|
|
348
|
+
return run;
|
|
60
349
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
350
|
+
for (const name of names) {
|
|
351
|
+
if (name === today) continue;
|
|
352
|
+
try {
|
|
353
|
+
const result = compactAuditDay(join(auditDir, name));
|
|
354
|
+
if (result.shards === 0) continue;
|
|
355
|
+
run.days += 1;
|
|
356
|
+
run.shards += result.shards;
|
|
357
|
+
run.savedBytes += result.savedBytes;
|
|
358
|
+
} catch {
|
|
359
|
+
}
|
|
65
360
|
}
|
|
66
|
-
|
|
67
|
-
|
|
361
|
+
return run;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/audit/auditJsonl.ts
|
|
365
|
+
import { closeSync, openSync, readSync, statSync } from "fs";
|
|
366
|
+
var WINDOW_BYTES = 1 << 20;
|
|
367
|
+
var MAX_LINE_BYTES = 32 * 1024 * 1024;
|
|
368
|
+
var NEWLINE = 10;
|
|
369
|
+
function forEachLineFromTail(path2, onLine) {
|
|
370
|
+
let fd;
|
|
371
|
+
let end;
|
|
372
|
+
try {
|
|
373
|
+
end = statSync(path2).size;
|
|
374
|
+
if (end === 0) return;
|
|
375
|
+
fd = openSync(path2, "r");
|
|
376
|
+
} catch {
|
|
377
|
+
return;
|
|
68
378
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
379
|
+
try {
|
|
380
|
+
let carry = Buffer.alloc(0);
|
|
381
|
+
while (end > 0) {
|
|
382
|
+
const start = Math.max(0, end - WINDOW_BYTES);
|
|
383
|
+
const window = Buffer.allocUnsafe(end - start);
|
|
384
|
+
let read;
|
|
385
|
+
try {
|
|
386
|
+
read = readSync(fd, window, 0, end - start, start);
|
|
387
|
+
} catch {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const chunk = carry.length > 0 ? Buffer.concat([window.subarray(0, read), carry]) : window.subarray(0, read);
|
|
391
|
+
let lineEnd = chunk.length;
|
|
392
|
+
let nl = lineEnd > 0 ? chunk.lastIndexOf(NEWLINE, lineEnd - 1) : -1;
|
|
393
|
+
while (nl >= 0) {
|
|
394
|
+
if (nl + 1 < lineEnd) {
|
|
395
|
+
const line = chunk.subarray(nl + 1, lineEnd).toString("utf8").trim();
|
|
396
|
+
if (line && onLine(line)) return;
|
|
397
|
+
}
|
|
398
|
+
lineEnd = nl;
|
|
399
|
+
nl = lineEnd > 0 ? chunk.lastIndexOf(NEWLINE, lineEnd - 1) : -1;
|
|
400
|
+
}
|
|
401
|
+
if (start === 0) {
|
|
402
|
+
if (lineEnd > 0) {
|
|
403
|
+
const line = chunk.subarray(0, lineEnd).toString("utf8").trim();
|
|
404
|
+
if (line) onLine(line);
|
|
405
|
+
}
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (lineEnd > MAX_LINE_BYTES) return;
|
|
409
|
+
carry = Buffer.from(chunk.subarray(0, lineEnd));
|
|
410
|
+
end = start;
|
|
411
|
+
}
|
|
412
|
+
} finally {
|
|
413
|
+
try {
|
|
414
|
+
closeSync(fd);
|
|
415
|
+
} catch {
|
|
416
|
+
}
|
|
73
417
|
}
|
|
74
418
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
419
|
+
|
|
420
|
+
// src/audit/auditBodyReader.ts
|
|
421
|
+
function candidateDays(auditDir, ts) {
|
|
422
|
+
if (typeof ts === "number" && Number.isFinite(ts)) {
|
|
423
|
+
const named = auditDayDirName(ts);
|
|
424
|
+
if (existsSync2(join2(auditDir, named))) return [named];
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
return readdirSync2(auditDir).filter(isAuditDayDir).sort().reverse();
|
|
428
|
+
} catch {
|
|
429
|
+
return [];
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function readShard(auditDir, day, sessionKey) {
|
|
433
|
+
const base = join2(auditDir, day, AUDIT_BODIES_DIR, auditBodyFileName(sessionKey));
|
|
434
|
+
try {
|
|
435
|
+
if (existsSync2(base)) return readFileSync2(base, "utf8");
|
|
436
|
+
const gz = `${base}.gz`;
|
|
437
|
+
if (existsSync2(gz)) return gunzipSync(readFileSync2(gz)).toString("utf8");
|
|
438
|
+
} catch {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
function parseShard(raw) {
|
|
444
|
+
const entries = /* @__PURE__ */ new Map();
|
|
445
|
+
for (const line of raw.split("\n")) {
|
|
446
|
+
const trimmed = line.trim();
|
|
447
|
+
if (!trimmed) continue;
|
|
448
|
+
let parsed;
|
|
449
|
+
try {
|
|
450
|
+
parsed = JSON.parse(trimmed);
|
|
451
|
+
} catch {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
if (isAuditBodyEntry(parsed)) entries.set(parsed.id, parsed);
|
|
455
|
+
}
|
|
456
|
+
return entries;
|
|
457
|
+
}
|
|
458
|
+
function withDictionary(auditDir, day, entries) {
|
|
459
|
+
let needed = false;
|
|
460
|
+
for (const entry of entries.values()) {
|
|
461
|
+
if (entry.req?.base?.startsWith(DICT_BASE_PREFIX)) {
|
|
462
|
+
needed = true;
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (!needed) return entries;
|
|
467
|
+
const base = join2(auditDir, day, AUDIT_BODIES_DIR, AUDIT_DICT_FILE);
|
|
468
|
+
let raw = null;
|
|
469
|
+
try {
|
|
470
|
+
if (existsSync2(base)) raw = readFileSync2(base, "utf8");
|
|
471
|
+
else if (existsSync2(`${base}.gz`)) raw = gunzipSync(readFileSync2(`${base}.gz`)).toString("utf8");
|
|
472
|
+
} catch {
|
|
473
|
+
return entries;
|
|
474
|
+
}
|
|
475
|
+
if (raw === null) return entries;
|
|
476
|
+
for (const [id, entry] of parseShard(raw)) entries.set(id, entry);
|
|
477
|
+
return entries;
|
|
478
|
+
}
|
|
479
|
+
function reconstructRequest(entries, entry) {
|
|
480
|
+
if (!entry.req) return void 0;
|
|
481
|
+
const chain = [];
|
|
482
|
+
const visited = /* @__PURE__ */ new Set();
|
|
483
|
+
let cursor = entry;
|
|
484
|
+
while (cursor?.req) {
|
|
485
|
+
if (visited.has(cursor.id)) return void 0;
|
|
486
|
+
visited.add(cursor.id);
|
|
487
|
+
chain.push(cursor);
|
|
488
|
+
if (cursor.req.base === null) break;
|
|
489
|
+
cursor = entries.get(cursor.req.base);
|
|
490
|
+
}
|
|
491
|
+
const anchor = chain[chain.length - 1];
|
|
492
|
+
if (!anchor?.req || anchor.req.base !== null) return void 0;
|
|
493
|
+
let text = anchor.req.ins;
|
|
494
|
+
for (let i = chain.length - 2; i >= 0; i -= 1) {
|
|
495
|
+
const delta = chain[i]?.req;
|
|
496
|
+
if (!delta) return void 0;
|
|
497
|
+
if (delta.pre > text.length || delta.suf > text.length - delta.pre) return void 0;
|
|
498
|
+
text = applyBodyDelta(text, delta);
|
|
499
|
+
}
|
|
500
|
+
return text;
|
|
501
|
+
}
|
|
502
|
+
function assignStreams(entries) {
|
|
503
|
+
const rootOf = /* @__PURE__ */ new Map();
|
|
504
|
+
for (const entry of entries.values()) {
|
|
505
|
+
const seen = /* @__PURE__ */ new Set();
|
|
506
|
+
let cursor = entry;
|
|
507
|
+
while (cursor?.req?.cont === true && cursor.req.base !== null && !seen.has(cursor.id)) {
|
|
508
|
+
seen.add(cursor.id);
|
|
509
|
+
const next = entries.get(cursor.req.base);
|
|
510
|
+
if (!next) break;
|
|
511
|
+
cursor = next;
|
|
512
|
+
}
|
|
513
|
+
rootOf.set(entry.id, cursor?.id ?? entry.id);
|
|
514
|
+
}
|
|
515
|
+
const firstTs = /* @__PURE__ */ new Map();
|
|
516
|
+
for (const entry of entries.values()) {
|
|
517
|
+
const root = rootOf.get(entry.id);
|
|
518
|
+
const known = firstTs.get(root);
|
|
519
|
+
if (known === void 0 || entry.ts < known) firstTs.set(root, entry.ts);
|
|
520
|
+
}
|
|
521
|
+
const order = [...firstTs.entries()].sort((a, b) => a[1] - b[1]).map(([root]) => root);
|
|
522
|
+
const index = new Map(order.map((root, i) => [root, i]));
|
|
523
|
+
const streams = /* @__PURE__ */ new Map();
|
|
524
|
+
for (const entry of entries.values()) {
|
|
525
|
+
streams.set(entry.id, index.get(rootOf.get(entry.id)) ?? 0);
|
|
526
|
+
}
|
|
527
|
+
return streams;
|
|
528
|
+
}
|
|
529
|
+
function readAuditBody(auditDir, query2) {
|
|
530
|
+
if (!isSafeSessionKey(query2.sessionKey) || !query2.id) return {};
|
|
531
|
+
if (!existsSync2(auditDir)) return {};
|
|
532
|
+
for (const day of candidateDays(auditDir, query2.ts)) {
|
|
533
|
+
const raw = readShard(auditDir, day, query2.sessionKey);
|
|
534
|
+
if (raw === null) continue;
|
|
535
|
+
const entries = withDictionary(auditDir, day, parseShard(raw));
|
|
536
|
+
const entry = entries.get(query2.id);
|
|
537
|
+
if (!entry) continue;
|
|
538
|
+
const result = {};
|
|
539
|
+
const requestBody = reconstructRequest(entries, entry);
|
|
540
|
+
if (requestBody !== void 0) result.requestBody = requestBody;
|
|
541
|
+
if (entry.res !== void 0) result.responseBody = entry.res;
|
|
542
|
+
return result;
|
|
543
|
+
}
|
|
544
|
+
return readLegacyInlineBody(auditDir, query2.id);
|
|
545
|
+
}
|
|
546
|
+
function readLegacyInlineBody(auditDir, id) {
|
|
547
|
+
let names;
|
|
548
|
+
try {
|
|
549
|
+
names = readdirSync2(auditDir).filter((name) => AUDIT_FILE_RE.test(name)).sort().reverse();
|
|
550
|
+
} catch {
|
|
551
|
+
return {};
|
|
552
|
+
}
|
|
553
|
+
const needle = JSON.stringify(id);
|
|
554
|
+
let found = {};
|
|
555
|
+
for (const name of names) {
|
|
556
|
+
forEachLineFromTail(join2(auditDir, name), (line) => {
|
|
557
|
+
if (!line.includes(needle)) return false;
|
|
558
|
+
let parsed;
|
|
559
|
+
try {
|
|
560
|
+
parsed = JSON.parse(line);
|
|
561
|
+
} catch {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
const record = parsed;
|
|
565
|
+
if (record.id !== id) return false;
|
|
566
|
+
const result = {};
|
|
567
|
+
if (typeof record.requestBody === "string") result.requestBody = record.requestBody;
|
|
568
|
+
if (typeof record.responseBody === "string") result.responseBody = record.responseBody;
|
|
569
|
+
found = result;
|
|
570
|
+
return true;
|
|
571
|
+
});
|
|
572
|
+
if (found.requestBody !== void 0 || found.responseBody !== void 0) break;
|
|
573
|
+
}
|
|
574
|
+
return found;
|
|
575
|
+
}
|
|
576
|
+
function readAuditSessionTurns(auditDir, sessionKey, ts) {
|
|
577
|
+
if (!isSafeSessionKey(sessionKey) || !existsSync2(auditDir)) return [];
|
|
578
|
+
for (const day of candidateDays(auditDir, ts)) {
|
|
579
|
+
const raw = readShard(auditDir, day, sessionKey);
|
|
580
|
+
if (raw === null) continue;
|
|
581
|
+
const shardEntries = parseShard(raw);
|
|
582
|
+
const streams = assignStreams(shardEntries);
|
|
583
|
+
const entries = withDictionary(auditDir, day, shardEntries);
|
|
584
|
+
const turns = [];
|
|
585
|
+
for (const entry of entries.values()) {
|
|
586
|
+
if (entry.id.startsWith(DICT_BASE_PREFIX)) continue;
|
|
587
|
+
const turn = { id: entry.id, ts: entry.ts, stream: streams.get(entry.id) ?? 0 };
|
|
588
|
+
if (entry.req?.anchor === "diverged") turn.diverged = true;
|
|
589
|
+
const requestBody = reconstructRequest(entries, entry);
|
|
590
|
+
if (requestBody !== void 0) turn.requestBody = requestBody;
|
|
591
|
+
if (entry.res !== void 0) turn.responseBody = entry.res;
|
|
592
|
+
turns.push(turn);
|
|
593
|
+
}
|
|
594
|
+
turns.sort((a, b) => a.stream === b.stream ? a.ts - b.ts : a.stream - b.stream);
|
|
595
|
+
return turns;
|
|
596
|
+
}
|
|
597
|
+
return [];
|
|
598
|
+
}
|
|
599
|
+
function listAuditSessions(auditDir, ts) {
|
|
600
|
+
if (!existsSync2(auditDir)) return [];
|
|
601
|
+
const summaries = [];
|
|
602
|
+
for (const day of candidateDays(auditDir, ts)) {
|
|
603
|
+
const bodiesPath = join2(auditDir, day, AUDIT_BODIES_DIR);
|
|
604
|
+
let files;
|
|
605
|
+
try {
|
|
606
|
+
files = readdirSync2(bodiesPath);
|
|
607
|
+
} catch {
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
for (const file of files) {
|
|
611
|
+
const compressed = file.endsWith(".jsonl.gz");
|
|
612
|
+
const sessionKey = file.replace(/\.jsonl(\.gz)?$/, "");
|
|
613
|
+
if (!isSafeSessionKey(sessionKey) || !compressed && !file.endsWith(".jsonl")) continue;
|
|
614
|
+
let bytes = 0;
|
|
615
|
+
try {
|
|
616
|
+
bytes = statSync2(join2(bodiesPath, file)).size;
|
|
617
|
+
} catch {
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
const raw = readShard(auditDir, day, sessionKey);
|
|
621
|
+
const turns = raw === null ? 0 : parseShard(raw).size;
|
|
622
|
+
summaries.push({ sessionKey, day, turns, bytes, compressed });
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
summaries.sort((a, b) => a.day === b.day ? b.bytes - a.bytes : a.day < b.day ? 1 : -1);
|
|
626
|
+
return summaries;
|
|
80
627
|
}
|
|
81
628
|
|
|
82
|
-
// src/
|
|
83
|
-
import {
|
|
629
|
+
// src/commands/paths.ts
|
|
630
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
84
631
|
|
|
85
632
|
// src/secrets/envelope.ts
|
|
86
633
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
@@ -139,13 +686,13 @@ function decryptValue(envelope, key) {
|
|
|
139
686
|
|
|
140
687
|
// src/secrets/masterKey.ts
|
|
141
688
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
142
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
689
|
+
import { chmodSync, existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
143
690
|
import { homedir } from "os";
|
|
144
|
-
import { dirname, join } from "path";
|
|
691
|
+
import { dirname, join as join3 } from "path";
|
|
145
692
|
var MASTER_KEY_ENV = "OMNICROSS_MASTER_KEY";
|
|
146
693
|
var KEY_BYTES2 = 32;
|
|
147
694
|
function defaultMasterKeyPath() {
|
|
148
|
-
return
|
|
695
|
+
return join3(homedir(), ".omnicross", "master.key");
|
|
149
696
|
}
|
|
150
697
|
function decodeEnvKey(raw) {
|
|
151
698
|
const trimmed = raw.trim();
|
|
@@ -161,7 +708,7 @@ function decodeEnvKey(raw) {
|
|
|
161
708
|
return buf;
|
|
162
709
|
}
|
|
163
710
|
function readKeyFile(path2) {
|
|
164
|
-
const raw =
|
|
711
|
+
const raw = readFileSync3(path2);
|
|
165
712
|
if (raw.length === KEY_BYTES2) return raw;
|
|
166
713
|
const text = raw.toString("utf8").trim();
|
|
167
714
|
if (/^[0-9a-fA-F]{64}$/.test(text)) return Buffer.from(text, "hex");
|
|
@@ -174,7 +721,7 @@ function readKeyFile(path2) {
|
|
|
174
721
|
function generateKeyFile(path2) {
|
|
175
722
|
const key = randomBytes2(KEY_BYTES2);
|
|
176
723
|
mkdirSync(dirname(path2), { recursive: true });
|
|
177
|
-
|
|
724
|
+
writeFileSync2(path2, key, { mode: 384 });
|
|
178
725
|
try {
|
|
179
726
|
chmodSync(path2, 384);
|
|
180
727
|
} catch {
|
|
@@ -187,7 +734,7 @@ function resolveMasterKey(options = {}) {
|
|
|
187
734
|
return decodeEnvKey(envRaw);
|
|
188
735
|
}
|
|
189
736
|
const keyFilePath = options.keyFilePath ?? defaultMasterKeyPath();
|
|
190
|
-
if (
|
|
737
|
+
if (existsSync3(keyFilePath)) {
|
|
191
738
|
return readKeyFile(keyFilePath);
|
|
192
739
|
}
|
|
193
740
|
return generateKeyFile(keyFilePath);
|
|
@@ -426,16 +973,243 @@ function transformTokens(tokens, fn) {
|
|
|
426
973
|
});
|
|
427
974
|
}
|
|
428
975
|
}
|
|
429
|
-
return next;
|
|
976
|
+
return next;
|
|
977
|
+
}
|
|
978
|
+
function encryptTokens(tokens, box) {
|
|
979
|
+
return transformTokens(tokens, (v) => box.encryptMaybe(v));
|
|
980
|
+
}
|
|
981
|
+
function decryptTokens(tokens, box) {
|
|
982
|
+
return transformTokens(tokens, (v) => box.decryptMaybe(v));
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/commands/paths.ts
|
|
986
|
+
function defaultKeysPath(configPath) {
|
|
987
|
+
return join4(dirname2(configPath), "keys.json");
|
|
988
|
+
}
|
|
989
|
+
function defaultVouchersPath(configPath) {
|
|
990
|
+
return join4(dirname2(configPath), "vouchers.json");
|
|
991
|
+
}
|
|
992
|
+
function defaultTokensPath(configPath) {
|
|
993
|
+
return join4(dirname2(configPath), "tokens.json");
|
|
994
|
+
}
|
|
995
|
+
function defaultIntegrationsPath(configPath) {
|
|
996
|
+
return join4(dirname2(configPath), "integrations.json");
|
|
997
|
+
}
|
|
998
|
+
function defaultPricingPath(configPath) {
|
|
999
|
+
return join4(dirname2(configPath), "pricing.json");
|
|
1000
|
+
}
|
|
1001
|
+
function defaultPricingRefreshStatePath(configPath) {
|
|
1002
|
+
return join4(dirname2(configPath), "pricing-refresh.json");
|
|
1003
|
+
}
|
|
1004
|
+
function defaultAccountAllowancePath(configPath) {
|
|
1005
|
+
return join4(dirname2(configPath), "allowance-cache.json");
|
|
1006
|
+
}
|
|
1007
|
+
function defaultUsageEventsPath(configPath) {
|
|
1008
|
+
return join4(dirname2(configPath), "usage-events.jsonl");
|
|
1009
|
+
}
|
|
1010
|
+
function defaultAuditDir(configPath) {
|
|
1011
|
+
return join4(dirname2(configPath), "audit");
|
|
1012
|
+
}
|
|
1013
|
+
function defaultBillingDir(configPath) {
|
|
1014
|
+
return join4(dirname2(configPath), "billing");
|
|
1015
|
+
}
|
|
1016
|
+
function resolveSecretBox(masterKeyFilePath) {
|
|
1017
|
+
return new SecretBox(() => resolveMasterKey({ keyFilePath: masterKeyFilePath }));
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// src/commands/audit.ts
|
|
1021
|
+
function parseDate(value) {
|
|
1022
|
+
if (!value) return void 0;
|
|
1023
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim());
|
|
1024
|
+
if (!m) throw new Error(`audit: --date must be YYYY-MM-DD (got ${value})`);
|
|
1025
|
+
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
1026
|
+
return d.getTime();
|
|
1027
|
+
}
|
|
1028
|
+
function formatBytes(bytes) {
|
|
1029
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1030
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1031
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1032
|
+
}
|
|
1033
|
+
async function runAudit(argv) {
|
|
1034
|
+
const { values, positionals } = parseArgs({
|
|
1035
|
+
args: argv,
|
|
1036
|
+
options: {
|
|
1037
|
+
config: { type: "string", short: "c" },
|
|
1038
|
+
session: { type: "string", short: "s" },
|
|
1039
|
+
date: { type: "string", short: "d" },
|
|
1040
|
+
id: { type: "string" }
|
|
1041
|
+
},
|
|
1042
|
+
allowPositionals: true
|
|
1043
|
+
});
|
|
1044
|
+
const configPath = values.config;
|
|
1045
|
+
if (!configPath) throw new Error("audit: --config <path> is required");
|
|
1046
|
+
const auditDir = defaultAuditDir(configPath);
|
|
1047
|
+
const ts = parseDate(values.date);
|
|
1048
|
+
const action = positionals[0];
|
|
1049
|
+
if (action === "sessions") {
|
|
1050
|
+
const sessions2 = listAuditSessions(auditDir, ts);
|
|
1051
|
+
if (sessions2.length === 0) {
|
|
1052
|
+
console.info("No audit body shards found. Is `captureBodies` enabled?");
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
console.info(["DAY", "SESSION", "TURNS", "SIZE", "ARCHIVED"].join(" "));
|
|
1056
|
+
for (const s of sessions2) {
|
|
1057
|
+
console.info(
|
|
1058
|
+
[s.day, s.sessionKey, String(s.turns), formatBytes(s.bytes), s.compressed ? "gz" : "-"].join(" ")
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
if (action === "show") {
|
|
1064
|
+
const sessionKey = values.session;
|
|
1065
|
+
if (!sessionKey) throw new Error("audit show: --session <key> is required");
|
|
1066
|
+
if (values.id) {
|
|
1067
|
+
const body = readAuditBody(auditDir, { id: values.id, sessionKey, ...ts !== void 0 ? { ts } : {} });
|
|
1068
|
+
if (body.requestBody === void 0 && body.responseBody === void 0) {
|
|
1069
|
+
throw new Error(`audit show: no body found for record ${values.id}`);
|
|
1070
|
+
}
|
|
1071
|
+
if (body.requestBody !== void 0) console.info(`--- request ${values.id} ---
|
|
1072
|
+
${body.requestBody}`);
|
|
1073
|
+
if (body.responseBody !== void 0) console.info(`--- response ${values.id} ---
|
|
1074
|
+
${body.responseBody}`);
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
const turns = readAuditSessionTurns(auditDir, sessionKey, ts);
|
|
1078
|
+
if (turns.length === 0) throw new Error(`audit show: no shard found for session ${sessionKey}`);
|
|
1079
|
+
let stream = -1;
|
|
1080
|
+
for (const turn of turns) {
|
|
1081
|
+
const when = new Date(turn.ts).toISOString();
|
|
1082
|
+
if (turn.stream !== stream) {
|
|
1083
|
+
stream = turn.stream;
|
|
1084
|
+
console.info(`
|
|
1085
|
+
########## stream ${stream} ##########`);
|
|
1086
|
+
}
|
|
1087
|
+
if (turn.diverged) {
|
|
1088
|
+
console.info("=== prefix diverged here (system prompt changed, or a restart reused this session) ===");
|
|
1089
|
+
}
|
|
1090
|
+
if (turn.requestBody !== void 0) {
|
|
1091
|
+
console.info(`--- request ${turn.id} @ ${when} ---
|
|
1092
|
+
${turn.requestBody}`);
|
|
1093
|
+
}
|
|
1094
|
+
if (turn.responseBody !== void 0) {
|
|
1095
|
+
console.info(`--- response ${turn.id} @ ${when} ---
|
|
1096
|
+
${turn.responseBody}`);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
if (action === "compact") {
|
|
1102
|
+
const todayDir = auditDayDirName(Date.now());
|
|
1103
|
+
let names;
|
|
1104
|
+
try {
|
|
1105
|
+
names = readdirSync3(auditDir).filter(isAuditDayDir).sort();
|
|
1106
|
+
} catch {
|
|
1107
|
+
names = [];
|
|
1108
|
+
}
|
|
1109
|
+
const targets = ts !== void 0 ? names.filter((name) => name === auditDayDirName(ts)) : names.filter((name) => name !== todayDir);
|
|
1110
|
+
if (targets.length === 0) {
|
|
1111
|
+
console.info("Nothing to compact (today is skipped; a day is compacted once).");
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
let shards = 0;
|
|
1115
|
+
let saved = 0;
|
|
1116
|
+
for (const name of targets) {
|
|
1117
|
+
if (name === todayDir) {
|
|
1118
|
+
console.info(`Skipping ${name}: the current day is still being written.`);
|
|
1119
|
+
continue;
|
|
1120
|
+
}
|
|
1121
|
+
const result = compactAuditDay(join5(auditDir, name));
|
|
1122
|
+
shards += result.shards;
|
|
1123
|
+
saved += result.savedBytes;
|
|
1124
|
+
console.info(`${name}: ${result.shards} shard(s), ${result.anchors} anchor(s), ${formatBytes(result.savedBytes)} saved`);
|
|
1125
|
+
}
|
|
1126
|
+
console.info(`Done: ${shards} shard(s) rewritten, ${formatBytes(saved)} saved.`);
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
throw new Error("audit: expected `sessions`, `show`, or `compact` (see `omnicross help`)");
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// src/commands/import-ccr.ts
|
|
1133
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
1134
|
+
import { parseArgs as parseArgs2 } from "util";
|
|
1135
|
+
|
|
1136
|
+
// src/ccr-import.ts
|
|
1137
|
+
function parseCcrConfig(raw) {
|
|
1138
|
+
if (!raw || typeof raw !== "object") {
|
|
1139
|
+
throw new Error("CCR config: top-level value must be an object");
|
|
1140
|
+
}
|
|
1141
|
+
const obj = raw;
|
|
1142
|
+
const Providers = Array.isArray(obj["Providers"]) ? obj["Providers"] : [];
|
|
1143
|
+
const Router = obj["Router"] && typeof obj["Router"] === "object" ? obj["Router"] : {};
|
|
1144
|
+
return { Providers, Router };
|
|
1145
|
+
}
|
|
1146
|
+
function inferApiFormat(provider) {
|
|
1147
|
+
const hay = `${provider.api_base_url ?? ""} ${provider.name ?? ""}`.toLowerCase();
|
|
1148
|
+
if (hay.includes("anthropic") || hay.includes("claude")) {
|
|
1149
|
+
return { format: "anthropic", ambiguous: false };
|
|
1150
|
+
}
|
|
1151
|
+
if (hay.includes("generativelanguage") || hay.includes("gemini") || hay.includes("google")) {
|
|
1152
|
+
return { format: "gemini", ambiguous: false };
|
|
1153
|
+
}
|
|
1154
|
+
if (hay.includes("/responses")) {
|
|
1155
|
+
return { format: "openai-response", ambiguous: false };
|
|
1156
|
+
}
|
|
1157
|
+
if (hay.includes("openai") || hay.includes("/v1") || hay.includes("chat/completions")) {
|
|
1158
|
+
return { format: "openai", ambiguous: false };
|
|
1159
|
+
}
|
|
1160
|
+
return { format: "openai", ambiguous: true };
|
|
1161
|
+
}
|
|
1162
|
+
function mapProviders(providers, notes) {
|
|
1163
|
+
const rows = [];
|
|
1164
|
+
for (const [i, p] of providers.entries()) {
|
|
1165
|
+
const id = p.name?.trim();
|
|
1166
|
+
if (!id) {
|
|
1167
|
+
notes.push(`Providers[${i}] has no name \u2014 skipped.`);
|
|
1168
|
+
continue;
|
|
1169
|
+
}
|
|
1170
|
+
const { format, ambiguous } = inferApiFormat(p);
|
|
1171
|
+
if (ambiguous) {
|
|
1172
|
+
notes.push(
|
|
1173
|
+
`Provider '${id}': could not infer apiFormat from base URL \u2014 defaulted to 'openai'. Edit the config if this provider speaks a different wire format.`
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
rows.push({
|
|
1177
|
+
id,
|
|
1178
|
+
apiFormat: format,
|
|
1179
|
+
baseUrl: p.api_base_url ?? "",
|
|
1180
|
+
apiKey: p.api_key ?? "",
|
|
1181
|
+
models: Array.isArray(p.models) ? p.models : void 0
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
return rows;
|
|
430
1185
|
}
|
|
431
|
-
function
|
|
432
|
-
|
|
1186
|
+
function noteRouterRoles(router, notes) {
|
|
1187
|
+
if (router.think) {
|
|
1188
|
+
notes.push(`Router.think \u2192 folded into 'default' (omnicross has no think slot).`);
|
|
1189
|
+
}
|
|
1190
|
+
if (router.longContext) {
|
|
1191
|
+
notes.push(
|
|
1192
|
+
`Router.longContext \u2192 folded into 'default' (no longContext slot; longContextThreshold dropped).`
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
if (router.image) {
|
|
1196
|
+
notes.push(`Router.image \u2192 mapped to 'vision' (CCR forceUseImageAgent dropped).`);
|
|
1197
|
+
}
|
|
1198
|
+
if (router.webSearch) {
|
|
1199
|
+
notes.push(
|
|
1200
|
+
`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.`
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
433
1203
|
}
|
|
434
|
-
function
|
|
435
|
-
|
|
1204
|
+
function mapCcrToOmnicross(ccr) {
|
|
1205
|
+
const notes = [];
|
|
1206
|
+
const providers = mapProviders(ccr.Providers ?? [], notes);
|
|
1207
|
+
noteRouterRoles(ccr.Router ?? {}, notes);
|
|
1208
|
+
return { config: { providers }, notes };
|
|
436
1209
|
}
|
|
437
1210
|
|
|
438
1211
|
// src/config.ts
|
|
1212
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
439
1213
|
var DEFAULT_ADMIN_PORT = 8766;
|
|
440
1214
|
function validateAdmin(raw) {
|
|
441
1215
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -497,6 +1271,35 @@ function validateApiKeys(raw) {
|
|
|
497
1271
|
}
|
|
498
1272
|
return out.length > 0 ? out : void 0;
|
|
499
1273
|
}
|
|
1274
|
+
var THINK_LEVELS = /* @__PURE__ */ new Set([
|
|
1275
|
+
"none",
|
|
1276
|
+
"minimal",
|
|
1277
|
+
"low",
|
|
1278
|
+
"medium",
|
|
1279
|
+
"high",
|
|
1280
|
+
"xhigh",
|
|
1281
|
+
"max"
|
|
1282
|
+
]);
|
|
1283
|
+
function validateThinkingLevels(raw) {
|
|
1284
|
+
if (!Array.isArray(raw)) return void 0;
|
|
1285
|
+
if (!raw.every((level) => typeof level === "string" && THINK_LEVELS.has(level))) {
|
|
1286
|
+
return void 0;
|
|
1287
|
+
}
|
|
1288
|
+
return [...raw];
|
|
1289
|
+
}
|
|
1290
|
+
function validateThinkingTokenLimit(raw) {
|
|
1291
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
1292
|
+
const bounds = raw;
|
|
1293
|
+
const min = bounds["min"];
|
|
1294
|
+
const max = bounds["max"];
|
|
1295
|
+
if (typeof min !== "number" || !Number.isFinite(min) || !Number.isInteger(min) || min < 0) {
|
|
1296
|
+
return void 0;
|
|
1297
|
+
}
|
|
1298
|
+
if (typeof max !== "number" || !Number.isFinite(max) || !Number.isInteger(max) || max < min) {
|
|
1299
|
+
return void 0;
|
|
1300
|
+
}
|
|
1301
|
+
return { min, max };
|
|
1302
|
+
}
|
|
500
1303
|
function validateModelConfigs(raw) {
|
|
501
1304
|
if (!Array.isArray(raw)) return void 0;
|
|
502
1305
|
const out = [];
|
|
@@ -511,6 +1314,10 @@ function validateModelConfigs(raw) {
|
|
|
511
1314
|
if (typeof m["enabled"] === "boolean") entry.enabled = m["enabled"];
|
|
512
1315
|
if (typeof m["vision"] === "boolean") entry.vision = m["vision"];
|
|
513
1316
|
if (typeof m["reasoning"] === "boolean") entry.reasoning = m["reasoning"];
|
|
1317
|
+
const thinkingLevels = validateThinkingLevels(m["thinkingLevels"]);
|
|
1318
|
+
if (thinkingLevels) entry.thinkingLevels = thinkingLevels;
|
|
1319
|
+
const thinkingTokenLimit = validateThinkingTokenLimit(m["thinkingTokenLimit"]);
|
|
1320
|
+
if (thinkingTokenLimit) entry.thinkingTokenLimit = thinkingTokenLimit;
|
|
514
1321
|
out.push(entry);
|
|
515
1322
|
}
|
|
516
1323
|
return out.length > 0 ? out : void 0;
|
|
@@ -695,7 +1502,7 @@ function setSecretBox(box) {
|
|
|
695
1502
|
function loadConfig(path2) {
|
|
696
1503
|
let raw;
|
|
697
1504
|
try {
|
|
698
|
-
raw =
|
|
1505
|
+
raw = readFileSync4(path2, "utf8");
|
|
699
1506
|
} catch {
|
|
700
1507
|
throw new Error(`config: cannot read file at '${path2}'`);
|
|
701
1508
|
}
|
|
@@ -710,48 +1517,12 @@ function loadConfig(path2) {
|
|
|
710
1517
|
}
|
|
711
1518
|
function saveConfig(path2, cfg) {
|
|
712
1519
|
const toWrite = secretBox ? encryptConfigSecrets(cfg, secretBox) : cfg;
|
|
713
|
-
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
// src/commands/paths.ts
|
|
717
|
-
import { dirname as dirname2, join as join2 } from "path";
|
|
718
|
-
function defaultKeysPath(configPath) {
|
|
719
|
-
return join2(dirname2(configPath), "keys.json");
|
|
720
|
-
}
|
|
721
|
-
function defaultVouchersPath(configPath) {
|
|
722
|
-
return join2(dirname2(configPath), "vouchers.json");
|
|
723
|
-
}
|
|
724
|
-
function defaultTokensPath(configPath) {
|
|
725
|
-
return join2(dirname2(configPath), "tokens.json");
|
|
726
|
-
}
|
|
727
|
-
function defaultIntegrationsPath(configPath) {
|
|
728
|
-
return join2(dirname2(configPath), "integrations.json");
|
|
729
|
-
}
|
|
730
|
-
function defaultPricingPath(configPath) {
|
|
731
|
-
return join2(dirname2(configPath), "pricing.json");
|
|
732
|
-
}
|
|
733
|
-
function defaultPricingRefreshStatePath(configPath) {
|
|
734
|
-
return join2(dirname2(configPath), "pricing-refresh.json");
|
|
735
|
-
}
|
|
736
|
-
function defaultAccountAllowancePath(configPath) {
|
|
737
|
-
return join2(dirname2(configPath), "allowance-cache.json");
|
|
738
|
-
}
|
|
739
|
-
function defaultUsageEventsPath(configPath) {
|
|
740
|
-
return join2(dirname2(configPath), "usage-events.jsonl");
|
|
741
|
-
}
|
|
742
|
-
function defaultAuditDir(configPath) {
|
|
743
|
-
return join2(dirname2(configPath), "audit");
|
|
744
|
-
}
|
|
745
|
-
function defaultBillingDir(configPath) {
|
|
746
|
-
return join2(dirname2(configPath), "billing");
|
|
747
|
-
}
|
|
748
|
-
function resolveSecretBox(masterKeyFilePath) {
|
|
749
|
-
return new SecretBox(() => resolveMasterKey({ keyFilePath: masterKeyFilePath }));
|
|
1520
|
+
writeFileSync3(path2, JSON.stringify(toWrite, null, 2) + "\n", "utf8");
|
|
750
1521
|
}
|
|
751
1522
|
|
|
752
1523
|
// src/commands/import-ccr.ts
|
|
753
1524
|
async function runImportCcr(argv) {
|
|
754
|
-
const { values, positionals } =
|
|
1525
|
+
const { values, positionals } = parseArgs2({
|
|
755
1526
|
args: argv,
|
|
756
1527
|
options: {
|
|
757
1528
|
out: { type: "string", short: "o" },
|
|
@@ -766,7 +1537,7 @@ async function runImportCcr(argv) {
|
|
|
766
1537
|
const outPath = values.out ?? "omnicross.config.json";
|
|
767
1538
|
let raw;
|
|
768
1539
|
try {
|
|
769
|
-
raw = JSON.parse(
|
|
1540
|
+
raw = JSON.parse(readFileSync5(ccrPath, "utf8"));
|
|
770
1541
|
} catch {
|
|
771
1542
|
throw new Error(`import-ccr: cannot read or parse '${ccrPath}'`);
|
|
772
1543
|
}
|
|
@@ -788,24 +1559,24 @@ async function runImportCcr(argv) {
|
|
|
788
1559
|
|
|
789
1560
|
// src/commands/integrations.ts
|
|
790
1561
|
import { resolve as resolve2 } from "path";
|
|
791
|
-
import { parseArgs as
|
|
1562
|
+
import { parseArgs as parseArgs3 } from "util";
|
|
792
1563
|
|
|
793
1564
|
// src/integrations/IntegrationManager.ts
|
|
794
1565
|
import { createHash } from "crypto";
|
|
795
|
-
import { existsSync as
|
|
1566
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, unlinkSync as unlinkSync3 } from "fs";
|
|
796
1567
|
import { homedir as homedir2 } from "os";
|
|
797
|
-
import { dirname as dirname4, join as
|
|
1568
|
+
import { dirname as dirname4, join as join6, resolve } from "path";
|
|
798
1569
|
import { createIntegrationKey } from "@omnicross/core";
|
|
799
1570
|
|
|
800
1571
|
// src/integrations/IntegrationStateStore.ts
|
|
801
1572
|
import {
|
|
802
1573
|
chmodSync as chmodSync2,
|
|
803
|
-
existsSync as
|
|
1574
|
+
existsSync as existsSync4,
|
|
804
1575
|
mkdirSync as mkdirSync2,
|
|
805
|
-
readFileSync as
|
|
806
|
-
renameSync,
|
|
807
|
-
unlinkSync,
|
|
808
|
-
writeFileSync as
|
|
1576
|
+
readFileSync as readFileSync6,
|
|
1577
|
+
renameSync as renameSync2,
|
|
1578
|
+
unlinkSync as unlinkSync2,
|
|
1579
|
+
writeFileSync as writeFileSync4
|
|
809
1580
|
} from "fs";
|
|
810
1581
|
import { dirname as dirname3 } from "path";
|
|
811
1582
|
var EMPTY_STATE = { version: 1, clients: {} };
|
|
@@ -817,10 +1588,10 @@ var IntegrationStateStore = class {
|
|
|
817
1588
|
path;
|
|
818
1589
|
box;
|
|
819
1590
|
load() {
|
|
820
|
-
if (!
|
|
1591
|
+
if (!existsSync4(this.path)) return { ...EMPTY_STATE, clients: {} };
|
|
821
1592
|
let raw;
|
|
822
1593
|
try {
|
|
823
|
-
raw = JSON.parse(
|
|
1594
|
+
raw = JSON.parse(readFileSync6(this.path, "utf8"));
|
|
824
1595
|
} catch {
|
|
825
1596
|
throw new Error(`integration state '${this.path}' is not valid JSON`);
|
|
826
1597
|
}
|
|
@@ -890,17 +1661,17 @@ function isManagedFileRecord(value) {
|
|
|
890
1661
|
function atomicWrite(path2, content) {
|
|
891
1662
|
mkdirSync2(dirname3(path2), { recursive: true });
|
|
892
1663
|
const temp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
893
|
-
|
|
1664
|
+
writeFileSync4(temp, content, { encoding: "utf8", mode: 384 });
|
|
894
1665
|
try {
|
|
895
|
-
|
|
1666
|
+
renameSync2(temp, path2);
|
|
896
1667
|
} catch (error) {
|
|
897
1668
|
try {
|
|
898
|
-
|
|
1669
|
+
unlinkSync2(temp);
|
|
899
1670
|
} catch {
|
|
900
1671
|
}
|
|
901
1672
|
throw error;
|
|
902
1673
|
} finally {
|
|
903
|
-
if (
|
|
1674
|
+
if (existsSync4(path2)) {
|
|
904
1675
|
try {
|
|
905
1676
|
chmodSync2(path2, 384);
|
|
906
1677
|
} catch {
|
|
@@ -1394,10 +2165,10 @@ var IntegrationManager = class {
|
|
|
1394
2165
|
};
|
|
1395
2166
|
}
|
|
1396
2167
|
defaultConfigPath(client) {
|
|
1397
|
-
return client === "codex" ?
|
|
2168
|
+
return client === "codex" ? join6(this.homeDir, ".codex", "config.toml") : join6(this.homeDir, ".claude", "settings.json");
|
|
1398
2169
|
}
|
|
1399
2170
|
codexAuthPathForConfig(configPath) {
|
|
1400
|
-
return
|
|
2171
|
+
return join6(dirname4(configPath), "auth.json");
|
|
1401
2172
|
}
|
|
1402
2173
|
renderInstalled(client, base, secret) {
|
|
1403
2174
|
if (client === "claude") {
|
|
@@ -1410,7 +2181,7 @@ var IntegrationManager = class {
|
|
|
1410
2181
|
}
|
|
1411
2182
|
};
|
|
1412
2183
|
function readOptional(path2) {
|
|
1413
|
-
return
|
|
2184
|
+
return existsSync5(path2) ? readFileSync7(path2, "utf8") : null;
|
|
1414
2185
|
}
|
|
1415
2186
|
function sha256(value) {
|
|
1416
2187
|
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
@@ -1474,7 +2245,7 @@ function writeOptional(path2, content) {
|
|
|
1474
2245
|
atomicWrite(path2, content);
|
|
1475
2246
|
return;
|
|
1476
2247
|
}
|
|
1477
|
-
if (
|
|
2248
|
+
if (existsSync5(path2)) unlinkSync3(path2);
|
|
1478
2249
|
}
|
|
1479
2250
|
function assertLoopbackGatewayUrl(value) {
|
|
1480
2251
|
let url;
|
|
@@ -1491,7 +2262,7 @@ function assertLoopbackGatewayUrl(value) {
|
|
|
1491
2262
|
}
|
|
1492
2263
|
|
|
1493
2264
|
// src/ports/JsonOutboundKeyDb.ts
|
|
1494
|
-
import { existsSync as
|
|
2265
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
1495
2266
|
var JsonOutboundKeyDb = class {
|
|
1496
2267
|
/**
|
|
1497
2268
|
* @param secretBox OPTIONAL reversible-secret codec. When present, a created
|
|
@@ -1624,16 +2395,16 @@ var JsonOutboundKeyDb = class {
|
|
|
1624
2395
|
}
|
|
1625
2396
|
/** Read the key rows, tolerating a missing/corrupt file (→ empty list). */
|
|
1626
2397
|
readRows() {
|
|
1627
|
-
if (!
|
|
2398
|
+
if (!existsSync6(this.keysPath)) return [];
|
|
1628
2399
|
try {
|
|
1629
|
-
const parsed = JSON.parse(
|
|
2400
|
+
const parsed = JSON.parse(readFileSync8(this.keysPath, "utf8"));
|
|
1630
2401
|
return Array.isArray(parsed) ? parsed : [];
|
|
1631
2402
|
} catch {
|
|
1632
2403
|
return [];
|
|
1633
2404
|
}
|
|
1634
2405
|
}
|
|
1635
2406
|
writeRows(rows) {
|
|
1636
|
-
|
|
2407
|
+
writeFileSync5(this.keysPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
|
|
1637
2408
|
}
|
|
1638
2409
|
};
|
|
1639
2410
|
function applyPolicyField(row, field, value) {
|
|
@@ -1644,7 +2415,7 @@ function applyPolicyField(row, field, value) {
|
|
|
1644
2415
|
|
|
1645
2416
|
// src/commands/integrations.ts
|
|
1646
2417
|
async function runIntegrations(argv) {
|
|
1647
|
-
const { values, positionals } =
|
|
2418
|
+
const { values, positionals } = parseArgs3({
|
|
1648
2419
|
args: argv,
|
|
1649
2420
|
options: {
|
|
1650
2421
|
config: { type: "string", short: "c" },
|
|
@@ -1694,10 +2465,10 @@ function isClient(value) {
|
|
|
1694
2465
|
}
|
|
1695
2466
|
|
|
1696
2467
|
// src/commands/keys.ts
|
|
1697
|
-
import { parseArgs as
|
|
2468
|
+
import { parseArgs as parseArgs4 } from "util";
|
|
1698
2469
|
import { createNamedKey } from "@omnicross/core/outbound-api";
|
|
1699
2470
|
async function runKeys(argv) {
|
|
1700
|
-
const { values, positionals } =
|
|
2471
|
+
const { values, positionals } = parseArgs4({
|
|
1701
2472
|
args: argv,
|
|
1702
2473
|
options: { config: { type: "string", short: "c" } },
|
|
1703
2474
|
allowPositionals: true
|
|
@@ -1751,9 +2522,9 @@ async function keysRevoke(db, id) {
|
|
|
1751
2522
|
// src/commands/launch.ts
|
|
1752
2523
|
import { spawn as spawn2 } from "child_process";
|
|
1753
2524
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
1754
|
-
import { existsSync as
|
|
1755
|
-
import { delimiter as delimiter2, join as
|
|
1756
|
-
import { parseArgs as
|
|
2525
|
+
import { existsSync as existsSync22 } from "fs";
|
|
2526
|
+
import { delimiter as delimiter2, join as join15 } from "path";
|
|
2527
|
+
import { parseArgs as parseArgs5 } from "util";
|
|
1757
2528
|
import {
|
|
1758
2529
|
buildChatCliLaunchConfig as buildChatCliLaunchConfig2,
|
|
1759
2530
|
buildGeminiCliLaunchConfig as buildGeminiCliLaunchConfig2
|
|
@@ -1761,7 +2532,7 @@ import {
|
|
|
1761
2532
|
import { ROUTE_LEASE_REQUEST_SCHEMA as ROUTE_LEASE_REQUEST_SCHEMA2 } from "@omnicross/core/provider-proxy";
|
|
1762
2533
|
|
|
1763
2534
|
// src/bootstrap.ts
|
|
1764
|
-
import { accessSync, constants as fsConstants, existsSync as
|
|
2535
|
+
import { accessSync, constants as fsConstants, existsSync as existsSync21 } from "fs";
|
|
1765
2536
|
import { DEFAULT_AUDIT_CONFIG } from "@omnicross/contracts/audit-types";
|
|
1766
2537
|
import { DEFAULT_BILLING_CONFIG } from "@omnicross/contracts/billing-types";
|
|
1767
2538
|
import { getGeminiCodeAssistProjectResolver } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
|
|
@@ -1795,7 +2566,12 @@ import {
|
|
|
1795
2566
|
} from "@omnicross/core/provider-proxy";
|
|
1796
2567
|
import { routeLeaseDescriptorPort } from "@omnicross/cli-launcher";
|
|
1797
2568
|
import { KeySpendTracker } from "@omnicross/core/outbound-api";
|
|
1798
|
-
import {
|
|
2569
|
+
import {
|
|
2570
|
+
__resetSharedUsageThroughputTrackerForTests,
|
|
2571
|
+
getSharedUsageThroughputTracker as getSharedUsageThroughputTracker2,
|
|
2572
|
+
PricingEngine,
|
|
2573
|
+
UsageRecorder
|
|
2574
|
+
} from "@omnicross/core/usage";
|
|
1799
2575
|
import {
|
|
1800
2576
|
setSubscriptionAccountService,
|
|
1801
2577
|
setSubscriptionProviderRegistry,
|
|
@@ -2302,13 +3078,13 @@ var ClaudeAllowanceRefreshScheduler = class {
|
|
|
2302
3078
|
// src/allowance/JsonAccountAllowancePersistence.ts
|
|
2303
3079
|
import { randomUUID } from "crypto";
|
|
2304
3080
|
import {
|
|
2305
|
-
existsSync as
|
|
3081
|
+
existsSync as existsSync7,
|
|
2306
3082
|
mkdirSync as mkdirSync3,
|
|
2307
|
-
readFileSync as
|
|
2308
|
-
renameSync as
|
|
3083
|
+
readFileSync as readFileSync9,
|
|
3084
|
+
renameSync as renameSync3,
|
|
2309
3085
|
rmSync,
|
|
2310
|
-
statSync,
|
|
2311
|
-
writeFileSync as
|
|
3086
|
+
statSync as statSync3,
|
|
3087
|
+
writeFileSync as writeFileSync6
|
|
2312
3088
|
} from "fs";
|
|
2313
3089
|
import { dirname as dirname5 } from "path";
|
|
2314
3090
|
import { normalizeAccountAllowanceSnapshot } from "@omnicross/core/pipeline/AccountAllowanceStore";
|
|
@@ -2322,10 +3098,10 @@ var JsonAccountAllowancePersistence = class {
|
|
|
2322
3098
|
cachePath;
|
|
2323
3099
|
/** Read only the `snapshots` payload; all row validation remains defensive. */
|
|
2324
3100
|
load() {
|
|
2325
|
-
if (!
|
|
3101
|
+
if (!existsSync7(this.cachePath)) return [];
|
|
2326
3102
|
try {
|
|
2327
|
-
if (
|
|
2328
|
-
const raw =
|
|
3103
|
+
if (statSync3(this.cachePath).size > MAX_ALLOWANCE_CACHE_BYTES) return [];
|
|
3104
|
+
const raw = readFileSync9(this.cachePath, "utf8");
|
|
2329
3105
|
if (!raw.trim()) return [];
|
|
2330
3106
|
const parsed = JSON.parse(raw);
|
|
2331
3107
|
if (Array.isArray(parsed)) return parsed;
|
|
@@ -2356,8 +3132,8 @@ var JsonAccountAllowancePersistence = class {
|
|
|
2356
3132
|
mkdirSync3(dirname5(this.cachePath), { recursive: true });
|
|
2357
3133
|
const temporaryPath = `${this.cachePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
2358
3134
|
try {
|
|
2359
|
-
|
|
2360
|
-
|
|
3135
|
+
writeFileSync6(temporaryPath, serialized, { encoding: "utf8", flag: "wx" });
|
|
3136
|
+
renameSync3(temporaryPath, this.cachePath);
|
|
2361
3137
|
} finally {
|
|
2362
3138
|
rmSync(temporaryPath, { force: true });
|
|
2363
3139
|
}
|
|
@@ -2399,6 +3175,37 @@ function handleAuditQuery(req, res, reader) {
|
|
|
2399
3175
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2400
3176
|
res.end(JSON.stringify({ records }));
|
|
2401
3177
|
}
|
|
3178
|
+
function handleAuditBodyQuery(req, res, reader) {
|
|
3179
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
3180
|
+
const id = url.searchParams.get("id")?.trim();
|
|
3181
|
+
const sessionKey = url.searchParams.get("session")?.trim();
|
|
3182
|
+
if (!id || !sessionKey) {
|
|
3183
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
3184
|
+
res.end(JSON.stringify({ error: "id and session are required" }));
|
|
3185
|
+
return;
|
|
3186
|
+
}
|
|
3187
|
+
const query2 = { id, sessionKey };
|
|
3188
|
+
const ts = intParam(url.searchParams.get("ts"));
|
|
3189
|
+
if (ts !== void 0) query2.ts = ts;
|
|
3190
|
+
const body = reader ? reader(query2) : {};
|
|
3191
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
3192
|
+
res.end(JSON.stringify(body));
|
|
3193
|
+
}
|
|
3194
|
+
function handleAuditCompact(res, compact) {
|
|
3195
|
+
if (!compact) {
|
|
3196
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
3197
|
+
res.end(JSON.stringify({ days: 0, shards: 0, savedBytes: 0 }));
|
|
3198
|
+
return;
|
|
3199
|
+
}
|
|
3200
|
+
try {
|
|
3201
|
+
const result = compact();
|
|
3202
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
3203
|
+
res.end(JSON.stringify(result));
|
|
3204
|
+
} catch (error) {
|
|
3205
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
3206
|
+
res.end(JSON.stringify({ error: error instanceof Error ? error.message : "compaction failed" }));
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
2402
3209
|
async function handleAuditStatsQuery(req, res, reader) {
|
|
2403
3210
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
2404
3211
|
const query2 = {};
|
|
@@ -3144,10 +3951,10 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
|
|
|
3144
3951
|
// src/admin/cliLaunch.ts
|
|
3145
3952
|
import { exec, spawn } from "child_process";
|
|
3146
3953
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3147
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
3954
|
+
import { chmodSync as chmodSync3, existsSync as existsSync8, mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
3148
3955
|
import { createServer } from "net";
|
|
3149
3956
|
import { tmpdir } from "os";
|
|
3150
|
-
import { delimiter, join as
|
|
3957
|
+
import { delimiter, join as join7 } from "path";
|
|
3151
3958
|
import {
|
|
3152
3959
|
buildChatCliLaunchConfig,
|
|
3153
3960
|
buildClaudeCliLaunchConfig,
|
|
@@ -3204,8 +4011,8 @@ function isLaunchCliId(id) {
|
|
|
3204
4011
|
function probeDefault(candidate) {
|
|
3205
4012
|
const segments = (process.env["PATH"] ?? "").split(delimiter).filter(Boolean);
|
|
3206
4013
|
for (const seg of segments) {
|
|
3207
|
-
const full =
|
|
3208
|
-
if (
|
|
4014
|
+
const full = join7(seg, candidate);
|
|
4015
|
+
if (existsSync8(full)) return full;
|
|
3209
4016
|
}
|
|
3210
4017
|
return null;
|
|
3211
4018
|
}
|
|
@@ -3309,10 +4116,10 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
|
|
|
3309
4116
|
const runLine = [command, ...extraArgs].map(shq).join(" ");
|
|
3310
4117
|
const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
|
|
3311
4118
|
if (platform === "darwin") {
|
|
3312
|
-
const launchDir = mkdtempSync(
|
|
3313
|
-
const commandFile =
|
|
3314
|
-
const bootstrapFile =
|
|
3315
|
-
const socketPath = macIpc.socketPath ??
|
|
4119
|
+
const launchDir = mkdtempSync(join7(tmpdir(), "omnicross-terminal-"));
|
|
4120
|
+
const commandFile = join7(launchDir, "launch.command");
|
|
4121
|
+
const bootstrapFile = join7(launchDir, "bootstrap.cjs");
|
|
4122
|
+
const socketPath = macIpc.socketPath ?? join7(launchDir, "descriptor.sock");
|
|
3316
4123
|
const openerEnv = { ...process.env };
|
|
3317
4124
|
for (const key of Object.keys(env)) delete openerEnv[key];
|
|
3318
4125
|
let claimed = false;
|
|
@@ -3382,8 +4189,8 @@ function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }
|
|
|
3382
4189
|
}
|
|
3383
4190
|
};
|
|
3384
4191
|
try {
|
|
3385
|
-
|
|
3386
|
-
|
|
4192
|
+
writeFileSync7(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
|
|
4193
|
+
writeFileSync7(commandFile, `#!/bin/bash
|
|
3387
4194
|
rm -f -- "$0"
|
|
3388
4195
|
exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
|
|
3389
4196
|
`, {
|
|
@@ -4054,6 +4861,7 @@ function applyAuditConfig(config) {
|
|
|
4054
4861
|
} else {
|
|
4055
4862
|
setAuditCaptureConfig(null);
|
|
4056
4863
|
setAuditSink(null);
|
|
4864
|
+
writer?.reset();
|
|
4057
4865
|
if (sweeper) {
|
|
4058
4866
|
if (config) sweeper.configure(config);
|
|
4059
4867
|
sweeper.dispose();
|
|
@@ -4640,6 +5448,7 @@ async function handleImport(body, deps) {
|
|
|
4640
5448
|
}
|
|
4641
5449
|
|
|
4642
5450
|
// src/admin/usagePricing.ts
|
|
5451
|
+
import { getSharedUsageThroughputTracker } from "@omnicross/core/usage";
|
|
4643
5452
|
var err4 = (status, message) => ({
|
|
4644
5453
|
status,
|
|
4645
5454
|
body: { error: { type: "admin_api_error", message } }
|
|
@@ -4665,6 +5474,9 @@ var BUCKET_SPAN_MS = {
|
|
|
4665
5474
|
};
|
|
4666
5475
|
var MAX_TIMESERIES_BUCKETS = 2e3;
|
|
4667
5476
|
async function handleUsageGet(view, query2, deps) {
|
|
5477
|
+
if (view === "throughput") {
|
|
5478
|
+
return { status: 200, body: getSharedUsageThroughputTracker().snapshot() };
|
|
5479
|
+
}
|
|
4668
5480
|
const range = parseRange(query2);
|
|
4669
5481
|
if (!isRange(range)) return range;
|
|
4670
5482
|
switch (view) {
|
|
@@ -5470,6 +6282,12 @@ function parseModelConfigsInput(raw, existing) {
|
|
|
5470
6282
|
else if (typeof prior?.vision === "boolean") entry.vision = prior.vision;
|
|
5471
6283
|
if (typeof m["reasoning"] === "boolean") entry.reasoning = m["reasoning"];
|
|
5472
6284
|
else if (typeof prior?.reasoning === "boolean") entry.reasoning = prior.reasoning;
|
|
6285
|
+
const thinkingLevels = validateThinkingLevels(m["thinkingLevels"]);
|
|
6286
|
+
if (thinkingLevels) entry.thinkingLevels = thinkingLevels;
|
|
6287
|
+
else if (prior?.thinkingLevels) entry.thinkingLevels = prior.thinkingLevels;
|
|
6288
|
+
const thinkingTokenLimit = validateThinkingTokenLimit(m["thinkingTokenLimit"]);
|
|
6289
|
+
if (thinkingTokenLimit) entry.thinkingTokenLimit = thinkingTokenLimit;
|
|
6290
|
+
else if (prior?.thinkingTokenLimit) entry.thinkingTokenLimit = prior.thinkingTokenLimit;
|
|
5473
6291
|
out.push(entry);
|
|
5474
6292
|
}
|
|
5475
6293
|
return out.length > 0 ? out : void 0;
|
|
@@ -6295,7 +7113,7 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
|
6295
7113
|
}
|
|
6296
7114
|
|
|
6297
7115
|
// src/admin/uiStatic.ts
|
|
6298
|
-
import { existsSync as
|
|
7116
|
+
import { existsSync as existsSync9, statSync as statSync4 } from "fs";
|
|
6299
7117
|
import { readFile } from "fs/promises";
|
|
6300
7118
|
import { createRequire } from "module";
|
|
6301
7119
|
import path from "path";
|
|
@@ -6318,13 +7136,13 @@ var CONTENT_TYPES = {
|
|
|
6318
7136
|
function resolveUiDist() {
|
|
6319
7137
|
const fromEnv = process.env["OMNICROSS_UI_DIST"];
|
|
6320
7138
|
if (fromEnv) {
|
|
6321
|
-
return
|
|
7139
|
+
return existsSync9(path.join(fromEnv, "index.html")) ? path.resolve(fromEnv) : null;
|
|
6322
7140
|
}
|
|
6323
7141
|
try {
|
|
6324
7142
|
const req = createRequire(typeof __filename !== "undefined" ? __filename : import.meta.url);
|
|
6325
7143
|
const pkgJson = req.resolve("@omnicross/ui/package.json");
|
|
6326
7144
|
const dist = path.join(path.dirname(pkgJson), "dist");
|
|
6327
|
-
return
|
|
7145
|
+
return existsSync9(path.join(dist, "index.html")) ? dist : null;
|
|
6328
7146
|
} catch {
|
|
6329
7147
|
return null;
|
|
6330
7148
|
}
|
|
@@ -6373,7 +7191,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
6373
7191
|
return true;
|
|
6374
7192
|
}
|
|
6375
7193
|
let target = filePath;
|
|
6376
|
-
if (!
|
|
7194
|
+
if (!existsSync9(target) || statSync4(target).isDirectory()) {
|
|
6377
7195
|
if (path.extname(rel) === "") {
|
|
6378
7196
|
target = path.join(uiDist, "index.html");
|
|
6379
7197
|
} else {
|
|
@@ -6390,7 +7208,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
6390
7208
|
}
|
|
6391
7209
|
|
|
6392
7210
|
// src/admin/version.ts
|
|
6393
|
-
var DAEMON_VERSION = true ? "0.1.
|
|
7211
|
+
var DAEMON_VERSION = true ? "0.1.10" : "0.0.0-dev";
|
|
6394
7212
|
|
|
6395
7213
|
// src/admin/AdminServer.ts
|
|
6396
7214
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -6502,6 +7320,14 @@ var AdminServer = class {
|
|
|
6502
7320
|
await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
|
|
6503
7321
|
return;
|
|
6504
7322
|
}
|
|
7323
|
+
if (path2 === "/admin/api/audit/body" && (req.method === "GET" || req.method === "HEAD")) {
|
|
7324
|
+
handleAuditBodyQuery(req, res, this.deps.auditBodyReader);
|
|
7325
|
+
return;
|
|
7326
|
+
}
|
|
7327
|
+
if (path2 === "/admin/api/audit/compact" && req.method === "POST") {
|
|
7328
|
+
handleAuditCompact(res, this.deps.auditCompactor);
|
|
7329
|
+
return;
|
|
7330
|
+
}
|
|
6505
7331
|
if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
|
|
6506
7332
|
handleBillingStatus(res, this.deps.billingStatusReader);
|
|
6507
7333
|
return;
|
|
@@ -6934,6 +7760,15 @@ function toLLMProvider(row) {
|
|
|
6934
7760
|
api_base_url: row.baseUrl,
|
|
6935
7761
|
api_key: resolvePreferredApiKey(row),
|
|
6936
7762
|
models,
|
|
7763
|
+
modelConfigs: row.modelConfigs?.map((config) => ({
|
|
7764
|
+
id: config.id,
|
|
7765
|
+
name: config.name ?? config.id,
|
|
7766
|
+
enabled: config.enabled ?? true,
|
|
7767
|
+
vision: config.vision,
|
|
7768
|
+
reasoning: config.reasoning,
|
|
7769
|
+
thinkingLevels: config.thinkingLevels,
|
|
7770
|
+
thinkingTokenLimit: config.thinkingTokenLimit
|
|
7771
|
+
})),
|
|
6937
7772
|
enabled: true,
|
|
6938
7773
|
transformer,
|
|
6939
7774
|
// app-parity-2 child 3: POPULATE the coding-plan endpoint onto the core
|
|
@@ -7105,7 +7940,7 @@ function safeStringify(value) {
|
|
|
7105
7940
|
}
|
|
7106
7941
|
|
|
7107
7942
|
// src/ports/JsonApiServerSettingsStore.ts
|
|
7108
|
-
import { readFileSync as
|
|
7943
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
7109
7944
|
import { OUTBOUND_API_SERVER_CONFIG_KEY } from "@omnicross/core/outbound-api";
|
|
7110
7945
|
var JsonApiServerSettingsStore = class {
|
|
7111
7946
|
/**
|
|
@@ -7132,7 +7967,7 @@ var JsonApiServerSettingsStore = class {
|
|
|
7132
7967
|
if (key !== OUTBOUND_API_SERVER_CONFIG_KEY) return;
|
|
7133
7968
|
const file = this.readFile();
|
|
7134
7969
|
file.server = this.encryptSecrets(value);
|
|
7135
|
-
|
|
7970
|
+
writeFileSync8(this.configPath, JSON.stringify(file, null, 2) + "\n", "utf8");
|
|
7136
7971
|
}
|
|
7137
7972
|
/** Encrypt the proxy passwords + webhook + billing secrets before persisting (no-op without a box). */
|
|
7138
7973
|
encryptSecrets(config) {
|
|
@@ -7155,7 +7990,7 @@ var JsonApiServerSettingsStore = class {
|
|
|
7155
7990
|
/** Read the config.json, tolerating a missing/corrupt file (→ empty shape). */
|
|
7156
7991
|
readFile() {
|
|
7157
7992
|
try {
|
|
7158
|
-
const raw =
|
|
7993
|
+
const raw = readFileSync10(this.configPath, "utf8");
|
|
7159
7994
|
const parsed = JSON.parse(raw);
|
|
7160
7995
|
if (parsed && typeof parsed === "object") return parsed;
|
|
7161
7996
|
} catch {
|
|
@@ -7166,7 +8001,7 @@ var JsonApiServerSettingsStore = class {
|
|
|
7166
8001
|
|
|
7167
8002
|
// src/ports/JsonlUsageEventStore.ts
|
|
7168
8003
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7169
|
-
import { appendFileSync, existsSync as
|
|
8004
|
+
import { appendFileSync, existsSync as existsSync10, readFileSync as readFileSync11 } from "fs";
|
|
7170
8005
|
var JsonlUsageEventStore = class {
|
|
7171
8006
|
constructor(eventsPath, isPriced) {
|
|
7172
8007
|
this.eventsPath = eventsPath;
|
|
@@ -7380,10 +8215,10 @@ var JsonlUsageEventStore = class {
|
|
|
7380
8215
|
}
|
|
7381
8216
|
/** Parse every line, skipping malformed/torn lines defensively. */
|
|
7382
8217
|
readAllRows() {
|
|
7383
|
-
if (!
|
|
8218
|
+
if (!existsSync10(this.eventsPath)) return [];
|
|
7384
8219
|
let raw;
|
|
7385
8220
|
try {
|
|
7386
|
-
raw =
|
|
8221
|
+
raw = readFileSync11(this.eventsPath, "utf8");
|
|
7387
8222
|
} catch {
|
|
7388
8223
|
return [];
|
|
7389
8224
|
}
|
|
@@ -7422,15 +8257,15 @@ function nextBoundary(ts, bucket) {
|
|
|
7422
8257
|
return new Date(d.getFullYear(), d.getMonth() + 1, 1).getTime();
|
|
7423
8258
|
}
|
|
7424
8259
|
}
|
|
7425
|
-
var
|
|
8260
|
+
var pad22 = (n) => String(n).padStart(2, "0");
|
|
7426
8261
|
function bucketLabel(bucketStartTs, bucket) {
|
|
7427
8262
|
const d = new Date(bucketStartTs);
|
|
7428
8263
|
const y = d.getFullYear();
|
|
7429
|
-
const mo =
|
|
7430
|
-
const day =
|
|
8264
|
+
const mo = pad22(d.getMonth() + 1);
|
|
8265
|
+
const day = pad22(d.getDate());
|
|
7431
8266
|
switch (bucket) {
|
|
7432
8267
|
case "hour":
|
|
7433
|
-
return `${mo}-${day} ${
|
|
8268
|
+
return `${mo}-${day} ${pad22(d.getHours())}:00`;
|
|
7434
8269
|
case "day":
|
|
7435
8270
|
return `${y}-${mo}-${day}`;
|
|
7436
8271
|
case "month":
|
|
@@ -7486,7 +8321,7 @@ function median(values) {
|
|
|
7486
8321
|
}
|
|
7487
8322
|
|
|
7488
8323
|
// src/ports/JsonPricingStore.ts
|
|
7489
|
-
import { existsSync as
|
|
8324
|
+
import { existsSync as existsSync11, readFileSync as readFileSync12, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
7490
8325
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
7491
8326
|
var JsonPricingStore = class {
|
|
7492
8327
|
constructor(pricingPath) {
|
|
@@ -7501,9 +8336,9 @@ var JsonPricingStore = class {
|
|
|
7501
8336
|
* otherwise unusable pricing table after a crash or manual file edit.
|
|
7502
8337
|
*/
|
|
7503
8338
|
hasUsableSnapshot() {
|
|
7504
|
-
if (!
|
|
8339
|
+
if (!existsSync11(this.pricingPath)) return false;
|
|
7505
8340
|
try {
|
|
7506
|
-
const parsed = JSON.parse(
|
|
8341
|
+
const parsed = JSON.parse(readFileSync12(this.pricingPath, "utf8"));
|
|
7507
8342
|
return Array.isArray(parsed) && parsed.some(isUsablePricingRow);
|
|
7508
8343
|
} catch {
|
|
7509
8344
|
return false;
|
|
@@ -7616,9 +8451,9 @@ var JsonPricingStore = class {
|
|
|
7616
8451
|
}
|
|
7617
8452
|
/** Read the pricing rows, tolerating a missing/corrupt file (→ empty list). */
|
|
7618
8453
|
readRows() {
|
|
7619
|
-
if (!
|
|
8454
|
+
if (!existsSync11(this.pricingPath)) return [];
|
|
7620
8455
|
try {
|
|
7621
|
-
const parsed = JSON.parse(
|
|
8456
|
+
const parsed = JSON.parse(readFileSync12(this.pricingPath, "utf8"));
|
|
7622
8457
|
return Array.isArray(parsed) ? parsed : [];
|
|
7623
8458
|
} catch {
|
|
7624
8459
|
return [];
|
|
@@ -7627,7 +8462,7 @@ var JsonPricingStore = class {
|
|
|
7627
8462
|
writeRows(rows) {
|
|
7628
8463
|
const temporaryPath = `${this.pricingPath}.${process.pid}.${randomUUID5()}.tmp`;
|
|
7629
8464
|
try {
|
|
7630
|
-
|
|
8465
|
+
writeFileSync9(temporaryPath, JSON.stringify(rows, null, 2) + "\n", {
|
|
7631
8466
|
encoding: "utf8",
|
|
7632
8467
|
flag: "wx"
|
|
7633
8468
|
});
|
|
@@ -7638,7 +8473,7 @@ var JsonPricingStore = class {
|
|
|
7638
8473
|
}
|
|
7639
8474
|
/** Isolated for deterministic failure testing; never removes the target. */
|
|
7640
8475
|
replaceFile(temporaryPath) {
|
|
7641
|
-
|
|
8476
|
+
renameSync4(temporaryPath, this.pricingPath);
|
|
7642
8477
|
}
|
|
7643
8478
|
};
|
|
7644
8479
|
function isUsablePricingRow(value) {
|
|
@@ -7648,7 +8483,7 @@ function isUsablePricingRow(value) {
|
|
|
7648
8483
|
}
|
|
7649
8484
|
|
|
7650
8485
|
// src/pricing/PricingRefreshScheduler.ts
|
|
7651
|
-
import { existsSync as
|
|
8486
|
+
import { existsSync as existsSync12, readFileSync as readFileSync13, renameSync as renameSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
7652
8487
|
var EMPTY_STATE2 = {
|
|
7653
8488
|
lastAttemptAt: null,
|
|
7654
8489
|
lastSuccessAt: null,
|
|
@@ -7686,9 +8521,9 @@ var PricingRefreshScheduler = class {
|
|
|
7686
8521
|
this.timer = null;
|
|
7687
8522
|
}
|
|
7688
8523
|
getState() {
|
|
7689
|
-
if (!
|
|
8524
|
+
if (!existsSync12(this.statePath)) return { ...EMPTY_STATE2, sources: [] };
|
|
7690
8525
|
try {
|
|
7691
|
-
const value = JSON.parse(
|
|
8526
|
+
const value = JSON.parse(readFileSync13(this.statePath, "utf8"));
|
|
7692
8527
|
return {
|
|
7693
8528
|
lastAttemptAt: finiteOrNull(value.lastAttemptAt),
|
|
7694
8529
|
lastSuccessAt: finiteOrNull(value.lastSuccessAt),
|
|
@@ -7741,9 +8576,9 @@ var PricingRefreshScheduler = class {
|
|
|
7741
8576
|
}
|
|
7742
8577
|
writeState(state) {
|
|
7743
8578
|
const temporaryPath = `${this.statePath}.tmp`;
|
|
7744
|
-
|
|
8579
|
+
writeFileSync10(temporaryPath, `${JSON.stringify(state, null, 2)}
|
|
7745
8580
|
`, "utf8");
|
|
7746
|
-
|
|
8581
|
+
renameSync5(temporaryPath, this.statePath);
|
|
7747
8582
|
}
|
|
7748
8583
|
};
|
|
7749
8584
|
function finiteOrNull(value) {
|
|
@@ -7751,7 +8586,7 @@ function finiteOrNull(value) {
|
|
|
7751
8586
|
}
|
|
7752
8587
|
|
|
7753
8588
|
// src/ports/JsonVoucherDb.ts
|
|
7754
|
-
import { existsSync as
|
|
8589
|
+
import { existsSync as existsSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "fs";
|
|
7755
8590
|
var JsonVoucherDb = class {
|
|
7756
8591
|
constructor(vouchersPath) {
|
|
7757
8592
|
this.vouchersPath = vouchersPath;
|
|
@@ -7829,21 +8664,21 @@ var JsonVoucherDb = class {
|
|
|
7829
8664
|
}
|
|
7830
8665
|
/** Read the voucher rows, tolerating a missing/corrupt file (→ empty list). */
|
|
7831
8666
|
readRows() {
|
|
7832
|
-
if (!
|
|
8667
|
+
if (!existsSync13(this.vouchersPath)) return [];
|
|
7833
8668
|
try {
|
|
7834
|
-
const parsed = JSON.parse(
|
|
8669
|
+
const parsed = JSON.parse(readFileSync14(this.vouchersPath, "utf8"));
|
|
7835
8670
|
return Array.isArray(parsed) ? parsed : [];
|
|
7836
8671
|
} catch {
|
|
7837
8672
|
return [];
|
|
7838
8673
|
}
|
|
7839
8674
|
}
|
|
7840
8675
|
writeRows(rows) {
|
|
7841
|
-
|
|
8676
|
+
writeFileSync11(this.vouchersPath, JSON.stringify(rows, null, 2) + "\n", "utf8");
|
|
7842
8677
|
}
|
|
7843
8678
|
};
|
|
7844
8679
|
|
|
7845
8680
|
// src/ports/JsonSubscriptionCredentialStore.ts
|
|
7846
|
-
import { existsSync as
|
|
8681
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync16, writeFileSync as writeFileSync12 } from "fs";
|
|
7847
8682
|
import { dirname as dirname6 } from "path";
|
|
7848
8683
|
import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
|
|
7849
8684
|
import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling3 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
|
|
@@ -7897,11 +8732,11 @@ function findDuplicateCredentialIds(accounts) {
|
|
|
7897
8732
|
}
|
|
7898
8733
|
|
|
7899
8734
|
// src/ports/external-cli-credentials.ts
|
|
7900
|
-
import { existsSync as
|
|
8735
|
+
import { existsSync as existsSync14, readFileSync as readFileSync15 } from "fs";
|
|
7901
8736
|
import { homedir as homedir3 } from "os";
|
|
7902
|
-
import { join as
|
|
8737
|
+
import { join as join8 } from "path";
|
|
7903
8738
|
function externalStorePath(provider, home = homedir3()) {
|
|
7904
|
-
return provider === "claude" ?
|
|
8739
|
+
return provider === "claude" ? join8(home, ".claude", ".credentials.json") : join8(home, ".codex", "auth.json");
|
|
7905
8740
|
}
|
|
7906
8741
|
function decodeJwtExpiryMs(token) {
|
|
7907
8742
|
try {
|
|
@@ -7950,10 +8785,10 @@ function parseCodexTokensEnvelope(raw) {
|
|
|
7950
8785
|
}
|
|
7951
8786
|
function readExternalCliCredentials(provider, home = homedir3()) {
|
|
7952
8787
|
const path2 = externalStorePath(provider, home);
|
|
7953
|
-
if (!
|
|
8788
|
+
if (!existsSync14(path2)) return null;
|
|
7954
8789
|
let raw;
|
|
7955
8790
|
try {
|
|
7956
|
-
const parsed = JSON.parse(
|
|
8791
|
+
const parsed = JSON.parse(readFileSync15(path2, "utf8"));
|
|
7957
8792
|
raw = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
7958
8793
|
} catch {
|
|
7959
8794
|
return null;
|
|
@@ -8526,7 +9361,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
8526
9361
|
persist(config) {
|
|
8527
9362
|
mkdirSync4(dirname6(this.tokensPath), { recursive: true });
|
|
8528
9363
|
const encrypted = encryptTokens(config, this.box);
|
|
8529
|
-
|
|
9364
|
+
writeFileSync12(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
|
|
8530
9365
|
}
|
|
8531
9366
|
/**
|
|
8532
9367
|
* Read + parse `tokens.json`, tolerating a missing/corrupt file, then DECRYPT
|
|
@@ -8542,10 +9377,10 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
8542
9377
|
* `config.ts loadConfig`, which decrypts outside its parse try.
|
|
8543
9378
|
*/
|
|
8544
9379
|
readConfig() {
|
|
8545
|
-
if (!
|
|
9380
|
+
if (!existsSync15(this.tokensPath)) return { updatedAt: "" };
|
|
8546
9381
|
let parsed;
|
|
8547
9382
|
try {
|
|
8548
|
-
const raw = JSON.parse(
|
|
9383
|
+
const raw = JSON.parse(readFileSync16(this.tokensPath, "utf8"));
|
|
8549
9384
|
parsed = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
|
|
8550
9385
|
} catch {
|
|
8551
9386
|
parsed = null;
|
|
@@ -9065,39 +9900,21 @@ var AccountHealthSweeper = class {
|
|
|
9065
9900
|
};
|
|
9066
9901
|
|
|
9067
9902
|
// src/audit/AuditPruneSweeper.ts
|
|
9068
|
-
import { existsSync as
|
|
9069
|
-
import { join as
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
var AUDIT_FILE_RE = /^audit-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
|
|
9073
|
-
var pad22 = (n) => String(n).padStart(2, "0");
|
|
9074
|
-
function auditFileName(ts) {
|
|
9075
|
-
const d = new Date(ts);
|
|
9076
|
-
return `audit-${d.getFullYear()}-${pad22(d.getMonth() + 1)}-${pad22(d.getDate())}.jsonl`;
|
|
9077
|
-
}
|
|
9078
|
-
function auditFileDateMs(fileName) {
|
|
9079
|
-
const m = AUDIT_FILE_RE.exec(fileName);
|
|
9080
|
-
if (!m) return null;
|
|
9081
|
-
const year = Number(m[1]);
|
|
9082
|
-
const month = Number(m[2]);
|
|
9083
|
-
const day = Number(m[3]);
|
|
9084
|
-
const d = new Date(year, month - 1, day);
|
|
9085
|
-
if (d.getFullYear() !== year || d.getMonth() !== month - 1 || d.getDate() !== day) {
|
|
9086
|
-
return null;
|
|
9087
|
-
}
|
|
9088
|
-
return d.getTime();
|
|
9089
|
-
}
|
|
9903
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync17, readdirSync as readdirSync5, rmSync as rmSync4, unlinkSync as unlinkSync4 } from "fs";
|
|
9904
|
+
import { join as join10 } from "path";
|
|
9905
|
+
import { pipeline } from "stream/promises";
|
|
9906
|
+
import { createGzip } from "zlib";
|
|
9090
9907
|
|
|
9091
9908
|
// src/audit/auditStats.ts
|
|
9092
9909
|
import {
|
|
9093
9910
|
createReadStream,
|
|
9094
|
-
existsSync as
|
|
9095
|
-
readFileSync as
|
|
9096
|
-
readdirSync,
|
|
9097
|
-
statSync as
|
|
9098
|
-
writeFileSync as
|
|
9911
|
+
existsSync as existsSync16,
|
|
9912
|
+
readFileSync as readFileSync17,
|
|
9913
|
+
readdirSync as readdirSync4,
|
|
9914
|
+
statSync as statSync5,
|
|
9915
|
+
writeFileSync as writeFileSync13
|
|
9099
9916
|
} from "fs";
|
|
9100
|
-
import { basename, dirname as dirname7, join as
|
|
9917
|
+
import { basename, dirname as dirname7, join as join9 } from "path";
|
|
9101
9918
|
var SIDECAR_VERSION = 1;
|
|
9102
9919
|
var META_PREFIX_BYTES = 64 * 1024;
|
|
9103
9920
|
var READ_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
@@ -9105,9 +9922,9 @@ function auditStatsFileName(auditFile) {
|
|
|
9105
9922
|
return auditFile.replace(/\.jsonl$/, ".stats.json");
|
|
9106
9923
|
}
|
|
9107
9924
|
function readPersisted(path2) {
|
|
9108
|
-
if (!
|
|
9925
|
+
if (!existsSync16(path2)) return null;
|
|
9109
9926
|
try {
|
|
9110
|
-
const value = JSON.parse(
|
|
9927
|
+
const value = JSON.parse(readFileSync17(path2, "utf8"));
|
|
9111
9928
|
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)) {
|
|
9112
9929
|
return null;
|
|
9113
9930
|
}
|
|
@@ -9117,7 +9934,7 @@ function readPersisted(path2) {
|
|
|
9117
9934
|
}
|
|
9118
9935
|
}
|
|
9119
9936
|
function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
|
|
9120
|
-
const statsPath =
|
|
9937
|
+
const statsPath = join9(dirname7(auditPath), auditStatsFileName(basename(auditPath)));
|
|
9121
9938
|
const previous = auditBytesBefore === 0 ? {
|
|
9122
9939
|
version: SIDECAR_VERSION,
|
|
9123
9940
|
auditBytes: 0,
|
|
@@ -9137,13 +9954,13 @@ function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfte
|
|
|
9137
9954
|
minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
|
|
9138
9955
|
maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
|
|
9139
9956
|
};
|
|
9140
|
-
|
|
9957
|
+
writeFileSync13(statsPath, JSON.stringify(next), "utf8");
|
|
9141
9958
|
}
|
|
9142
9959
|
function queryCovers(stats, from, to) {
|
|
9143
9960
|
return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
|
|
9144
9961
|
}
|
|
9145
|
-
function fileOverlaps(
|
|
9146
|
-
const start = auditFileDateMs(
|
|
9962
|
+
function fileOverlaps(name, from, to) {
|
|
9963
|
+
const start = auditFileDateMs(name);
|
|
9147
9964
|
if (start === null) return false;
|
|
9148
9965
|
const date = new Date(start);
|
|
9149
9966
|
const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
|
|
@@ -9248,21 +10065,27 @@ function mergePersistedStats(previous, appended) {
|
|
|
9248
10065
|
};
|
|
9249
10066
|
}
|
|
9250
10067
|
async function readAuditStats(auditDir, query2 = {}) {
|
|
9251
|
-
if (!
|
|
10068
|
+
if (!existsSync16(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
|
|
9252
10069
|
const from = typeof query2.from === "number" ? query2.from : -Infinity;
|
|
9253
10070
|
const to = typeof query2.to === "number" ? query2.to : Infinity;
|
|
9254
|
-
let
|
|
10071
|
+
let sources;
|
|
9255
10072
|
try {
|
|
9256
|
-
|
|
10073
|
+
sources = readdirSync4(auditDir).filter((name) => fileOverlaps(name, from, to)).sort().map(
|
|
10074
|
+
(name) => AUDIT_DAY_DIR_RE.test(name) ? {
|
|
10075
|
+
auditPath: join9(auditDir, name, AUDIT_META_FILE),
|
|
10076
|
+
statsPath: join9(auditDir, name, auditStatsFileName(AUDIT_META_FILE))
|
|
10077
|
+
} : {
|
|
10078
|
+
auditPath: join9(auditDir, name),
|
|
10079
|
+
statsPath: join9(auditDir, auditStatsFileName(name))
|
|
10080
|
+
}
|
|
10081
|
+
).filter((source) => existsSync16(source.auditPath));
|
|
9257
10082
|
} catch {
|
|
9258
10083
|
return { requestCount: 0, errorCount: 0, complete: false };
|
|
9259
10084
|
}
|
|
9260
10085
|
const total = { requestCount: 0, errorCount: 0, complete: true };
|
|
9261
|
-
for (const
|
|
9262
|
-
const auditPath = join6(auditDir, file);
|
|
10086
|
+
for (const { auditPath, statsPath } of sources) {
|
|
9263
10087
|
try {
|
|
9264
|
-
const auditBytes =
|
|
9265
|
-
const statsPath = join6(auditDir, auditStatsFileName(file));
|
|
10088
|
+
const auditBytes = statSync5(auditPath).size;
|
|
9266
10089
|
const persisted = readPersisted(statsPath);
|
|
9267
10090
|
if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
|
|
9268
10091
|
total.requestCount += persisted.requestCount;
|
|
@@ -9281,7 +10104,7 @@ async function readAuditStats(auditDir, query2 = {}) {
|
|
|
9281
10104
|
total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
|
|
9282
10105
|
total.complete = total.complete && scanned.filtered.complete;
|
|
9283
10106
|
const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
|
|
9284
|
-
if (current.complete)
|
|
10107
|
+
if (current.complete) writeFileSync13(statsPath, JSON.stringify(current), "utf8");
|
|
9285
10108
|
} catch {
|
|
9286
10109
|
total.complete = false;
|
|
9287
10110
|
}
|
|
@@ -9292,6 +10115,7 @@ async function readAuditStats(auditDir, query2 = {}) {
|
|
|
9292
10115
|
// src/audit/AuditPruneSweeper.ts
|
|
9293
10116
|
var DAY_MS = 24 * 60 * 6e4;
|
|
9294
10117
|
var SWEEP_INTERVAL_MS2 = 60 * 6e4;
|
|
10118
|
+
var ARCHIVE_BATCH = 64;
|
|
9295
10119
|
var AuditPruneSweeper = class {
|
|
9296
10120
|
constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
|
|
9297
10121
|
this.auditDir = auditDir;
|
|
@@ -9307,6 +10131,7 @@ var AuditPruneSweeper = class {
|
|
|
9307
10131
|
now;
|
|
9308
10132
|
timer = null;
|
|
9309
10133
|
sweeping = false;
|
|
10134
|
+
archiving = false;
|
|
9310
10135
|
/** Whether pruning is active (audit enabled). */
|
|
9311
10136
|
get enabled() {
|
|
9312
10137
|
return this.config.enabled;
|
|
@@ -9316,13 +10141,13 @@ var AuditPruneSweeper = class {
|
|
|
9316
10141
|
this.config = config;
|
|
9317
10142
|
}
|
|
9318
10143
|
/**
|
|
9319
|
-
* Arm the
|
|
9320
|
-
*
|
|
10144
|
+
* Arm the interval AND run one pass immediately (boot cleanup). No-op when
|
|
10145
|
+
* audit is disabled (zero regression). Idempotent.
|
|
9321
10146
|
*/
|
|
9322
10147
|
start() {
|
|
9323
10148
|
if (this.timer || !this.config.enabled) return;
|
|
9324
|
-
void this.
|
|
9325
|
-
this.timer = setInterval(() => void this.
|
|
10149
|
+
void this.runOnce();
|
|
10150
|
+
this.timer = setInterval(() => void this.runOnce(), this.intervalMs);
|
|
9326
10151
|
this.timer.unref?.();
|
|
9327
10152
|
}
|
|
9328
10153
|
/** Clear the interval (daemon shutdown / test teardown). Idempotent. */
|
|
@@ -9332,31 +10157,43 @@ var AuditPruneSweeper = class {
|
|
|
9332
10157
|
this.timer = null;
|
|
9333
10158
|
}
|
|
9334
10159
|
}
|
|
10160
|
+
/** Prune first, then archive — never spend CPU compressing a day about to go. */
|
|
10161
|
+
async runOnce() {
|
|
10162
|
+
await this.sweep();
|
|
10163
|
+
await this.archive();
|
|
10164
|
+
}
|
|
10165
|
+
/** The LOCAL-midnight epoch ms of the current day. */
|
|
10166
|
+
todayMidnight() {
|
|
10167
|
+
const today = new Date(this.now());
|
|
10168
|
+
return new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
|
|
10169
|
+
}
|
|
9335
10170
|
/**
|
|
9336
|
-
* One prune:
|
|
9337
|
-
*
|
|
9338
|
-
*
|
|
10171
|
+
* One prune: remove every audit day strictly OLDER than the retention cutoff
|
|
10172
|
+
* (`now - retentionDays` days, at local-midnight granularity). Exposed for
|
|
10173
|
+
* tests; never throws. Returns the number of days removed.
|
|
9339
10174
|
*/
|
|
9340
10175
|
async sweep() {
|
|
9341
10176
|
if (!this.config.enabled || this.sweeping) return 0;
|
|
9342
10177
|
this.sweeping = true;
|
|
9343
10178
|
try {
|
|
9344
|
-
if (!
|
|
9345
|
-
const
|
|
9346
|
-
const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
|
|
9347
|
-
const cutoff = todayMidnight - (this.config.retentionDays - 1) * DAY_MS;
|
|
10179
|
+
if (!existsSync17(this.auditDir)) return 0;
|
|
10180
|
+
const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS;
|
|
9348
10181
|
let removed = 0;
|
|
9349
|
-
for (const
|
|
9350
|
-
const dateMs = auditFileDateMs(
|
|
10182
|
+
for (const name of readdirSync5(this.auditDir)) {
|
|
10183
|
+
const dateMs = auditFileDateMs(name);
|
|
9351
10184
|
if (dateMs === null || dateMs >= cutoff) continue;
|
|
9352
10185
|
try {
|
|
9353
|
-
|
|
10186
|
+
if (isAuditDayDir(name)) {
|
|
10187
|
+
rmSync4(join10(this.auditDir, name), { recursive: true, force: true });
|
|
10188
|
+
} else {
|
|
10189
|
+
unlinkSync4(join10(this.auditDir, name));
|
|
10190
|
+
const statsPath = join10(this.auditDir, auditStatsFileName(name));
|
|
10191
|
+
if (existsSync17(statsPath)) unlinkSync4(statsPath);
|
|
10192
|
+
}
|
|
9354
10193
|
removed += 1;
|
|
9355
|
-
const statsPath = join7(this.auditDir, auditStatsFileName(file));
|
|
9356
|
-
if (existsSync15(statsPath)) unlinkSync3(statsPath);
|
|
9357
10194
|
} catch (error) {
|
|
9358
|
-
this.logger.warn("[AuditPruneSweeper] failed to
|
|
9359
|
-
|
|
10195
|
+
this.logger.warn("[AuditPruneSweeper] failed to remove expired audit day", {
|
|
10196
|
+
name,
|
|
9360
10197
|
error: error instanceof Error ? error.message : String(error)
|
|
9361
10198
|
});
|
|
9362
10199
|
}
|
|
@@ -9372,59 +10209,158 @@ var AuditPruneSweeper = class {
|
|
|
9372
10209
|
this.sweeping = false;
|
|
9373
10210
|
}
|
|
9374
10211
|
}
|
|
10212
|
+
/**
|
|
10213
|
+
* Gzip the body shards of every CLOSED day (anything before today). Today is
|
|
10214
|
+
* deliberately left as plain text so it stays greppable while it is the day you
|
|
10215
|
+
* are debugging. Exposed for tests; never throws. Returns shards compressed.
|
|
10216
|
+
*/
|
|
10217
|
+
async archive() {
|
|
10218
|
+
if (!this.config.enabled || this.archiving) return 0;
|
|
10219
|
+
this.archiving = true;
|
|
10220
|
+
try {
|
|
10221
|
+
if (!existsSync17(this.auditDir)) return 0;
|
|
10222
|
+
const today = this.todayMidnight();
|
|
10223
|
+
let compressed = 0;
|
|
10224
|
+
for (const name of readdirSync5(this.auditDir)) {
|
|
10225
|
+
if (compressed >= ARCHIVE_BATCH) break;
|
|
10226
|
+
const dateMs = auditFileDateMs(name);
|
|
10227
|
+
if (dateMs === null || dateMs >= today || !isAuditDayDir(name)) continue;
|
|
10228
|
+
const dayPath = join10(this.auditDir, name);
|
|
10229
|
+
try {
|
|
10230
|
+
const compaction = compactAuditDay(dayPath);
|
|
10231
|
+
if (compaction.shards > 0) {
|
|
10232
|
+
this.logger.debug("audit cross-session compaction complete", {
|
|
10233
|
+
day: name,
|
|
10234
|
+
shards: compaction.shards,
|
|
10235
|
+
anchors: compaction.anchors,
|
|
10236
|
+
savedBytes: compaction.savedBytes
|
|
10237
|
+
});
|
|
10238
|
+
}
|
|
10239
|
+
} catch (error) {
|
|
10240
|
+
this.logger.warn("[AuditPruneSweeper] cross-session compaction failed", {
|
|
10241
|
+
day: name,
|
|
10242
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10243
|
+
});
|
|
10244
|
+
}
|
|
10245
|
+
compressed += await this.archiveDay(
|
|
10246
|
+
join10(dayPath, AUDIT_BODIES_DIR),
|
|
10247
|
+
ARCHIVE_BATCH - compressed
|
|
10248
|
+
);
|
|
10249
|
+
}
|
|
10250
|
+
if (compressed > 0) this.logger.debug("audit archive complete", { compressed });
|
|
10251
|
+
return compressed;
|
|
10252
|
+
} catch (error) {
|
|
10253
|
+
this.logger.warn("audit archive pass failed", {
|
|
10254
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10255
|
+
});
|
|
10256
|
+
return 0;
|
|
10257
|
+
} finally {
|
|
10258
|
+
this.archiving = false;
|
|
10259
|
+
}
|
|
10260
|
+
}
|
|
10261
|
+
/** Gzip up to `budget` plain shards in one day's `bodies/` directory. */
|
|
10262
|
+
async archiveDay(bodiesPath, budget) {
|
|
10263
|
+
let shards;
|
|
10264
|
+
try {
|
|
10265
|
+
shards = readdirSync5(bodiesPath).filter((file) => file.endsWith(".jsonl"));
|
|
10266
|
+
} catch {
|
|
10267
|
+
return 0;
|
|
10268
|
+
}
|
|
10269
|
+
let compressed = 0;
|
|
10270
|
+
for (const shard of shards) {
|
|
10271
|
+
if (compressed >= budget) break;
|
|
10272
|
+
const source = join10(bodiesPath, shard);
|
|
10273
|
+
const target = `${source}.gz`;
|
|
10274
|
+
try {
|
|
10275
|
+
if (existsSync17(target)) {
|
|
10276
|
+
unlinkSync4(source);
|
|
10277
|
+
continue;
|
|
10278
|
+
}
|
|
10279
|
+
await pipeline(createReadStream2(source), createGzip(), createWriteStream2(target));
|
|
10280
|
+
unlinkSync4(source);
|
|
10281
|
+
compressed += 1;
|
|
10282
|
+
} catch (error) {
|
|
10283
|
+
try {
|
|
10284
|
+
if (existsSync17(target)) unlinkSync4(target);
|
|
10285
|
+
} catch {
|
|
10286
|
+
}
|
|
10287
|
+
this.logger.warn("[AuditPruneSweeper] failed to archive audit body shard", {
|
|
10288
|
+
shard,
|
|
10289
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10290
|
+
});
|
|
10291
|
+
}
|
|
10292
|
+
}
|
|
10293
|
+
return compressed;
|
|
10294
|
+
}
|
|
9375
10295
|
};
|
|
9376
10296
|
|
|
9377
10297
|
// src/audit/auditReader.ts
|
|
9378
|
-
import { existsSync as
|
|
9379
|
-
import { join as
|
|
10298
|
+
import { existsSync as existsSync18, readdirSync as readdirSync6 } from "fs";
|
|
10299
|
+
import { join as join11 } from "path";
|
|
9380
10300
|
var DEFAULT_LIMIT = 200;
|
|
9381
10301
|
var MAX_LIMIT = 2e3;
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
let
|
|
10302
|
+
var OVERSCAN = 256;
|
|
10303
|
+
function daySources(auditDir) {
|
|
10304
|
+
let names;
|
|
9385
10305
|
try {
|
|
9386
|
-
|
|
10306
|
+
names = readdirSync6(auditDir);
|
|
9387
10307
|
} catch {
|
|
9388
10308
|
return [];
|
|
9389
10309
|
}
|
|
10310
|
+
const sources = [];
|
|
10311
|
+
for (const name of names) {
|
|
10312
|
+
const dateMs = auditFileDateMs(name);
|
|
10313
|
+
if (dateMs === null) continue;
|
|
10314
|
+
if (AUDIT_DAY_DIR_RE.test(name)) {
|
|
10315
|
+
const path2 = join11(auditDir, name, AUDIT_META_FILE);
|
|
10316
|
+
if (existsSync18(path2)) sources.push({ path: path2, dateMs });
|
|
10317
|
+
} else if (AUDIT_FILE_RE.test(name)) {
|
|
10318
|
+
sources.push({ path: join11(auditDir, name), dateMs });
|
|
10319
|
+
}
|
|
10320
|
+
}
|
|
10321
|
+
return sources.sort((a, b) => b.dateMs - a.dateMs);
|
|
10322
|
+
}
|
|
10323
|
+
function isAuditRecord(value) {
|
|
10324
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
10325
|
+
const r = value;
|
|
10326
|
+
return typeof r["id"] === "string" && typeof r["ts"] === "number" && typeof r["method"] === "string" && typeof r["path"] === "string" && typeof r["status"] === "number";
|
|
10327
|
+
}
|
|
10328
|
+
function toMetaRecord(record) {
|
|
10329
|
+
if (record.requestBody === void 0 && record.responseBody === void 0) return record;
|
|
10330
|
+
const { requestBody: _req, responseBody: _res, ...meta } = record;
|
|
10331
|
+
return { ...meta, hasBody: true };
|
|
10332
|
+
}
|
|
10333
|
+
function readAuditRecords(auditDir, query2 = {}) {
|
|
10334
|
+
if (!existsSync18(auditDir)) return [];
|
|
9390
10335
|
const from = typeof query2.from === "number" ? query2.from : -Infinity;
|
|
9391
10336
|
const to = typeof query2.to === "number" ? query2.to : Infinity;
|
|
9392
10337
|
const limit = Math.min(MAX_LIMIT, Math.max(1, Math.trunc(query2.limit ?? DEFAULT_LIMIT)));
|
|
9393
10338
|
const matched = [];
|
|
9394
|
-
for (const
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
} catch {
|
|
9399
|
-
continue;
|
|
9400
|
-
}
|
|
9401
|
-
for (const line of raw.split("\n")) {
|
|
9402
|
-
const trimmed = line.trim();
|
|
9403
|
-
if (!trimmed) continue;
|
|
9404
|
-
let rec;
|
|
10339
|
+
for (const source of daySources(auditDir)) {
|
|
10340
|
+
const before = matched.length;
|
|
10341
|
+
forEachLineFromTail(source.path, (line) => {
|
|
10342
|
+
let parsed;
|
|
9405
10343
|
try {
|
|
9406
|
-
|
|
10344
|
+
parsed = JSON.parse(line);
|
|
9407
10345
|
} catch {
|
|
9408
|
-
|
|
10346
|
+
return false;
|
|
9409
10347
|
}
|
|
9410
|
-
if (!isAuditRecord(
|
|
9411
|
-
if (query2.keyId !== void 0 &&
|
|
9412
|
-
if (
|
|
9413
|
-
|
|
9414
|
-
|
|
10348
|
+
if (!isAuditRecord(parsed)) return false;
|
|
10349
|
+
if (query2.keyId !== void 0 && parsed.keyId !== query2.keyId) return false;
|
|
10350
|
+
if (query2.sessionKey !== void 0 && parsed.sessionKey !== query2.sessionKey) return false;
|
|
10351
|
+
if (parsed.ts < from || parsed.ts > to) return false;
|
|
10352
|
+
matched.push(toMetaRecord(parsed));
|
|
10353
|
+
return matched.length - before >= limit + OVERSCAN;
|
|
10354
|
+
});
|
|
10355
|
+
if (matched.length >= limit) break;
|
|
9415
10356
|
}
|
|
9416
10357
|
matched.sort((a, b) => b.ts - a.ts);
|
|
9417
10358
|
return matched.slice(0, limit);
|
|
9418
10359
|
}
|
|
9419
|
-
function isAuditRecord(value) {
|
|
9420
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
9421
|
-
const r = value;
|
|
9422
|
-
return typeof r["id"] === "string" && typeof r["ts"] === "number" && typeof r["method"] === "string" && typeof r["path"] === "string" && typeof r["status"] === "number";
|
|
9423
|
-
}
|
|
9424
10360
|
|
|
9425
10361
|
// src/audit/AuditWriter.ts
|
|
9426
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
9427
|
-
import { join as
|
|
10362
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync19, mkdirSync as mkdirSync5, statSync as statSync6 } from "fs";
|
|
10363
|
+
import { join as join12 } from "path";
|
|
9428
10364
|
var AuditWriter = class {
|
|
9429
10365
|
constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
|
|
9430
10366
|
this.auditDir = auditDir;
|
|
@@ -9434,10 +10370,13 @@ var AuditWriter = class {
|
|
|
9434
10370
|
auditDir;
|
|
9435
10371
|
logger;
|
|
9436
10372
|
defer;
|
|
9437
|
-
|
|
10373
|
+
/** Day directories already created this process (avoids an mkdir per record). */
|
|
10374
|
+
ensuredDirs = /* @__PURE__ */ new Set();
|
|
10375
|
+
/** Per-session encoding bases. Memory-only; a miss simply writes a full snapshot. */
|
|
10376
|
+
bases = new SessionBaseCache();
|
|
9438
10377
|
/**
|
|
9439
|
-
* Enqueue one record
|
|
9440
|
-
*
|
|
10378
|
+
* Enqueue one record. Returns IMMEDIATELY (fire-and-forget); every fs write and
|
|
10379
|
+
* the delta encoding happen on the deferred tick. A failure is logged, never thrown.
|
|
9441
10380
|
*/
|
|
9442
10381
|
record(record) {
|
|
9443
10382
|
this.defer(() => {
|
|
@@ -9450,25 +10389,41 @@ var AuditWriter = class {
|
|
|
9450
10389
|
}
|
|
9451
10390
|
});
|
|
9452
10391
|
}
|
|
10392
|
+
/** Drop all retained encoding bases (config reload / shutdown / test teardown). */
|
|
10393
|
+
reset() {
|
|
10394
|
+
this.bases.clear();
|
|
10395
|
+
this.ensuredDirs.clear();
|
|
10396
|
+
}
|
|
9453
10397
|
/**
|
|
9454
|
-
* Append synchronously — the awaitable form tests use to assert
|
|
9455
|
-
*
|
|
9456
|
-
* store's lazy file creation).
|
|
10398
|
+
* Append synchronously — the awaitable form tests use to assert a line landed.
|
|
10399
|
+
* Writes the metadata line first (canonical), then the body shard.
|
|
9457
10400
|
*/
|
|
9458
10401
|
appendNow(record) {
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
10402
|
+
const dayDir = auditDayDirName(record.ts);
|
|
10403
|
+
const dayPath = this.ensureDir(join12(this.auditDir, dayDir));
|
|
10404
|
+
this.appendMeta(dayPath, record);
|
|
10405
|
+
this.appendBody(dayPath, dayDir, record);
|
|
10406
|
+
}
|
|
10407
|
+
/** Create a directory once per process and remember it. */
|
|
10408
|
+
ensureDir(path2) {
|
|
10409
|
+
if (!this.ensuredDirs.has(path2)) {
|
|
10410
|
+
mkdirSync5(path2, { recursive: true });
|
|
10411
|
+
this.ensuredDirs.add(path2);
|
|
10412
|
+
}
|
|
10413
|
+
return path2;
|
|
10414
|
+
}
|
|
10415
|
+
/** Write the body-free metadata line + refresh the exact-count sidecar. */
|
|
10416
|
+
appendMeta(dayPath, record) {
|
|
10417
|
+
const { requestBody: _req, responseBody: _res, ...meta } = record;
|
|
10418
|
+
const file = join12(dayPath, AUDIT_META_FILE);
|
|
10419
|
+
const line = JSON.stringify(meta) + "\n";
|
|
10420
|
+
const bytesBefore = existsSync19(file) ? statSync6(file).size : 0;
|
|
9466
10421
|
appendFileSync2(file, line, "utf8");
|
|
9467
10422
|
try {
|
|
9468
10423
|
updateAuditStatsAfterAppend(
|
|
9469
10424
|
file,
|
|
9470
|
-
|
|
9471
|
-
|
|
10425
|
+
bytesBefore,
|
|
10426
|
+
bytesBefore + Buffer.byteLength(line, "utf8"),
|
|
9472
10427
|
record
|
|
9473
10428
|
);
|
|
9474
10429
|
} catch (error) {
|
|
@@ -9477,12 +10432,39 @@ var AuditWriter = class {
|
|
|
9477
10432
|
});
|
|
9478
10433
|
}
|
|
9479
10434
|
}
|
|
10435
|
+
/**
|
|
10436
|
+
* Write the delta-encoded body shard for one record. A no-op when nothing was
|
|
10437
|
+
* captured or when the session key is missing/unsafe — in which case the body
|
|
10438
|
+
* is dropped rather than written to an unvalidated path.
|
|
10439
|
+
*/
|
|
10440
|
+
appendBody(dayPath, dayDir, record) {
|
|
10441
|
+
if (record.requestBody === void 0 && record.responseBody === void 0) return;
|
|
10442
|
+
const sessionKey = record.sessionKey;
|
|
10443
|
+
if (!isSafeSessionKey(sessionKey)) {
|
|
10444
|
+
this.logger.warn("[AuditWriter] dropping audit body with no usable session key", {
|
|
10445
|
+
id: record.id
|
|
10446
|
+
});
|
|
10447
|
+
return;
|
|
10448
|
+
}
|
|
10449
|
+
try {
|
|
10450
|
+
const line = encodeBodyEntry(record, sessionKey, dayDir, this.bases);
|
|
10451
|
+
if (line === null) return;
|
|
10452
|
+
const bodiesPath = this.ensureDir(join12(dayPath, AUDIT_BODIES_DIR));
|
|
10453
|
+
appendFileSync2(join12(bodiesPath, auditBodyFileName(sessionKey)), line + "\n", "utf8");
|
|
10454
|
+
} catch (error) {
|
|
10455
|
+
this.bases.forget(sessionKey);
|
|
10456
|
+
this.logger.warn("[AuditWriter] failed to append audit body shard", {
|
|
10457
|
+
id: record.id,
|
|
10458
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10459
|
+
});
|
|
10460
|
+
}
|
|
10461
|
+
}
|
|
9480
10462
|
};
|
|
9481
10463
|
|
|
9482
10464
|
// src/billing/BillingPublisher.ts
|
|
9483
10465
|
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync6 } from "fs";
|
|
9484
10466
|
import { createHmac } from "crypto";
|
|
9485
|
-
import { join as
|
|
10467
|
+
import { join as join13 } from "path";
|
|
9486
10468
|
import { fetchUpstream as fetchUpstream5 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
9487
10469
|
|
|
9488
10470
|
// src/billing/billingFiles.ts
|
|
@@ -9553,7 +10535,7 @@ var BillingPublisher = class {
|
|
|
9553
10535
|
*/
|
|
9554
10536
|
appendNow(event) {
|
|
9555
10537
|
this.ensureDir();
|
|
9556
|
-
const file =
|
|
10538
|
+
const file = join13(this.billingDir, billingFileName(event.ts));
|
|
9557
10539
|
appendFileSync3(file, JSON.stringify(event) + "\n", "utf8");
|
|
9558
10540
|
}
|
|
9559
10541
|
/**
|
|
@@ -9603,7 +10585,7 @@ var BillingPublisher = class {
|
|
|
9603
10585
|
markDelivered(event) {
|
|
9604
10586
|
try {
|
|
9605
10587
|
this.ensureDir();
|
|
9606
|
-
const file =
|
|
10588
|
+
const file = join13(this.billingDir, deliveredFileName(event.ts));
|
|
9607
10589
|
appendFileSync3(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
|
|
9608
10590
|
} catch (error) {
|
|
9609
10591
|
this.logger.warn("[BillingPublisher] failed to append delivery marker", {
|
|
@@ -9619,14 +10601,14 @@ var BillingPublisher = class {
|
|
|
9619
10601
|
};
|
|
9620
10602
|
|
|
9621
10603
|
// src/billing/billingReader.ts
|
|
9622
|
-
import { existsSync as
|
|
9623
|
-
import { join as
|
|
10604
|
+
import { existsSync as existsSync20, readdirSync as readdirSync7, readFileSync as readFileSync18 } from "fs";
|
|
10605
|
+
import { join as join14 } from "path";
|
|
9624
10606
|
function readBillingLedger(billingDir) {
|
|
9625
10607
|
const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
|
|
9626
|
-
if (!
|
|
10608
|
+
if (!existsSync20(billingDir)) return view;
|
|
9627
10609
|
let files;
|
|
9628
10610
|
try {
|
|
9629
|
-
files =
|
|
10611
|
+
files = readdirSync7(billingDir);
|
|
9630
10612
|
} catch {
|
|
9631
10613
|
return view;
|
|
9632
10614
|
}
|
|
@@ -9657,7 +10639,7 @@ function readBillingStatus(billingDir) {
|
|
|
9657
10639
|
function parseLines(dir, file) {
|
|
9658
10640
|
let raw;
|
|
9659
10641
|
try {
|
|
9660
|
-
raw =
|
|
10642
|
+
raw = readFileSync18(join14(dir, file), "utf8");
|
|
9661
10643
|
} catch {
|
|
9662
10644
|
return [];
|
|
9663
10645
|
}
|
|
@@ -10161,8 +11143,10 @@ function buildDaemon(config, paths) {
|
|
|
10161
11143
|
async (providerId, model) => await pricingEngine.getEntry(providerId, model) !== null
|
|
10162
11144
|
);
|
|
10163
11145
|
const keySpendTracker = new KeySpendTracker(usageEventStore);
|
|
11146
|
+
const usageThroughput = getSharedUsageThroughputTracker2();
|
|
10164
11147
|
const usageRecorder = new UsageRecorder(usageEventStore, pricingEngine, logger, {
|
|
10165
|
-
onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
|
|
11148
|
+
onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at),
|
|
11149
|
+
onEvent: (row, at) => usageThroughput.record(row, at)
|
|
10166
11150
|
});
|
|
10167
11151
|
const providerProxy = getProviderProxy({ llmConfig, apiKeyPool, usageRecorder });
|
|
10168
11152
|
const routeLeaseManager = new RouteLeaseManager(
|
|
@@ -10311,6 +11295,11 @@ function buildDaemon(config, paths) {
|
|
|
10311
11295
|
// NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
|
|
10312
11296
|
auditReader: (query2) => readAuditRecords(auditDir, query2),
|
|
10313
11297
|
auditStatsReader: (query2) => readAuditStats(auditDir, query2),
|
|
11298
|
+
// audit-store-sharding: bodies live in per-session shards, so opening ONE
|
|
11299
|
+
// record's payload is a separate authed call that replays its delta chain.
|
|
11300
|
+
auditBodyReader: (query2) => readAuditBody(auditDir, query2),
|
|
11301
|
+
// audit-store-sharding D8: the manual counterpart to the daily pass.
|
|
11302
|
+
auditCompactor: () => compactAllClosedAuditDays(auditDir),
|
|
10314
11303
|
// billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
|
|
10315
11304
|
// secret-free total/delivered/pending counts of the durable ledger.
|
|
10316
11305
|
billingStatusReader: () => readBillingStatus(billingDir)
|
|
@@ -10369,7 +11358,7 @@ function buildDaemon(config, paths) {
|
|
|
10369
11358
|
}
|
|
10370
11359
|
function isTokensStoreReadable(tokensPath) {
|
|
10371
11360
|
try {
|
|
10372
|
-
if (!
|
|
11361
|
+
if (!existsSync21(tokensPath)) return true;
|
|
10373
11362
|
accessSync(tokensPath, fsConstants.R_OK);
|
|
10374
11363
|
return true;
|
|
10375
11364
|
} catch {
|
|
@@ -10417,8 +11406,8 @@ function buildCliSpawnPlan(opts) {
|
|
|
10417
11406
|
function resolveInPathDefault(candidate) {
|
|
10418
11407
|
const segments = (process.env["PATH"] ?? "").split(delimiter2).filter(Boolean);
|
|
10419
11408
|
for (const seg of segments) {
|
|
10420
|
-
const full =
|
|
10421
|
-
if (
|
|
11409
|
+
const full = join15(seg, candidate);
|
|
11410
|
+
if (existsSync22(full)) return full;
|
|
10422
11411
|
}
|
|
10423
11412
|
return null;
|
|
10424
11413
|
}
|
|
@@ -10426,7 +11415,7 @@ async function runLaunch(argv, deps) {
|
|
|
10426
11415
|
const sep = argv.indexOf("--");
|
|
10427
11416
|
const own = sep === -1 ? argv : argv.slice(0, sep);
|
|
10428
11417
|
const passthrough = sep === -1 ? [] : argv.slice(sep + 1);
|
|
10429
|
-
const { values, positionals } =
|
|
11418
|
+
const { values, positionals } = parseArgs5({
|
|
10430
11419
|
args: own,
|
|
10431
11420
|
options: {
|
|
10432
11421
|
provider: { type: "string", short: "p" },
|
|
@@ -10596,12 +11585,12 @@ function spawnCliInherit(plan) {
|
|
|
10596
11585
|
// src/commands/login.ts
|
|
10597
11586
|
import { spawn as spawn3 } from "child_process";
|
|
10598
11587
|
import { createInterface } from "readline";
|
|
10599
|
-
import { parseArgs as
|
|
11588
|
+
import { parseArgs as parseArgs6 } from "util";
|
|
10600
11589
|
import { fetchUpstream as fetchUpstream8, setUpstreamProxyResolver as setUpstreamProxyResolver2 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
10601
11590
|
import { claudeOAuth as claudeOAuth3, codexOAuth as codexOAuth3, geminiOAuth as geminiOAuth3 } from "@omnicross/subscriptions";
|
|
10602
11591
|
var PROVIDERS2 = ["claude", "codex", "gemini"];
|
|
10603
11592
|
async function runLogin(argv, deps) {
|
|
10604
|
-
const { values, positionals } =
|
|
11593
|
+
const { values, positionals } = parseArgs6({
|
|
10605
11594
|
args: argv,
|
|
10606
11595
|
options: {
|
|
10607
11596
|
config: { type: "string", short: "c" },
|
|
@@ -10769,9 +11758,9 @@ function promptPaste(prompt) {
|
|
|
10769
11758
|
|
|
10770
11759
|
// src/commands/providers.ts
|
|
10771
11760
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
10772
|
-
import { parseArgs as
|
|
11761
|
+
import { parseArgs as parseArgs7 } from "util";
|
|
10773
11762
|
async function runProviders(argv) {
|
|
10774
|
-
const { values, positionals } =
|
|
11763
|
+
const { values, positionals } = parseArgs7({
|
|
10775
11764
|
args: argv,
|
|
10776
11765
|
options: {
|
|
10777
11766
|
config: { type: "string", short: "c" },
|
|
@@ -10918,10 +11907,10 @@ function providersRmKey(configPath, providerId, keyId) {
|
|
|
10918
11907
|
}
|
|
10919
11908
|
|
|
10920
11909
|
// src/commands/secrets.ts
|
|
10921
|
-
import { existsSync as
|
|
10922
|
-
import { parseArgs as
|
|
11910
|
+
import { existsSync as existsSync23, readFileSync as readFileSync19, writeFileSync as writeFileSync14 } from "fs";
|
|
11911
|
+
import { parseArgs as parseArgs8 } from "util";
|
|
10923
11912
|
async function runSecrets(argv) {
|
|
10924
|
-
const { values, positionals } =
|
|
11913
|
+
const { values, positionals } = parseArgs8({
|
|
10925
11914
|
args: argv,
|
|
10926
11915
|
options: {
|
|
10927
11916
|
config: { type: "string", short: "c" },
|
|
@@ -10991,12 +11980,12 @@ function secretsStatus(args) {
|
|
|
10991
11980
|
reportField("admin.token", cfg.admin.token);
|
|
10992
11981
|
}
|
|
10993
11982
|
const tokensPath = defaultTokensPath(args.config);
|
|
10994
|
-
if (
|
|
11983
|
+
if (existsSync23(tokensPath)) {
|
|
10995
11984
|
console.info(`Secret status for ${tokensPath}:`);
|
|
10996
11985
|
reportTokenFields(tokensPath);
|
|
10997
11986
|
}
|
|
10998
11987
|
const integrationsPath = defaultIntegrationsPath(args.config);
|
|
10999
|
-
if (
|
|
11988
|
+
if (existsSync23(integrationsPath)) {
|
|
11000
11989
|
const state = readRawJson(integrationsPath);
|
|
11001
11990
|
const key = state.gatewayKey;
|
|
11002
11991
|
if (key && typeof key === "object" && !Array.isArray(key)) {
|
|
@@ -11050,8 +12039,8 @@ async function secretsRotate(args) {
|
|
|
11050
12039
|
const integrationsPath = defaultIntegrationsPath(args.config);
|
|
11051
12040
|
try {
|
|
11052
12041
|
cfg = loadConfig(args.config);
|
|
11053
|
-
if (
|
|
11054
|
-
if (
|
|
12042
|
+
if (existsSync23(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, oldBox);
|
|
12043
|
+
if (existsSync23(integrationsPath)) {
|
|
11055
12044
|
integrationsPlain = new IntegrationStateStore(integrationsPath, oldBox).load();
|
|
11056
12045
|
}
|
|
11057
12046
|
} finally {
|
|
@@ -11086,20 +12075,20 @@ function secretsDecrypt(args) {
|
|
|
11086
12075
|
let tokensPlain = null;
|
|
11087
12076
|
try {
|
|
11088
12077
|
cfg = loadConfig(args.config);
|
|
11089
|
-
if (
|
|
12078
|
+
if (existsSync23(tokensPath)) tokensPlain = decryptTokensFile(tokensPath, box);
|
|
11090
12079
|
} finally {
|
|
11091
12080
|
setSecretBox(null);
|
|
11092
12081
|
}
|
|
11093
12082
|
saveConfig(args.config, cfg);
|
|
11094
12083
|
if (tokensPlain) {
|
|
11095
|
-
|
|
12084
|
+
writeFileSync14(tokensPath, JSON.stringify(tokensPlain, null, 2) + "\n", "utf8");
|
|
11096
12085
|
}
|
|
11097
12086
|
console.info(`Decrypted secrets to plaintext in ${args.config}` + tokensSuffix(args.config));
|
|
11098
12087
|
}
|
|
11099
12088
|
function readRawConfig(path2) {
|
|
11100
12089
|
let parsed;
|
|
11101
12090
|
try {
|
|
11102
|
-
parsed = JSON.parse(
|
|
12091
|
+
parsed = JSON.parse(readFileSync19(path2, "utf8"));
|
|
11103
12092
|
} catch {
|
|
11104
12093
|
throw new Error(`secrets: cannot read or parse '${path2}'`);
|
|
11105
12094
|
}
|
|
@@ -11107,7 +12096,7 @@ function readRawConfig(path2) {
|
|
|
11107
12096
|
}
|
|
11108
12097
|
function readRawJson(path2) {
|
|
11109
12098
|
try {
|
|
11110
|
-
const parsed = JSON.parse(
|
|
12099
|
+
const parsed = JSON.parse(readFileSync19(path2, "utf8"));
|
|
11111
12100
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
11112
12101
|
return parsed;
|
|
11113
12102
|
}
|
|
@@ -11117,13 +12106,13 @@ function readRawJson(path2) {
|
|
|
11117
12106
|
}
|
|
11118
12107
|
function encryptTokensFileInPlace(configPath, box) {
|
|
11119
12108
|
const tokensPath = defaultTokensPath(configPath);
|
|
11120
|
-
if (!
|
|
12109
|
+
if (!existsSync23(tokensPath)) return;
|
|
11121
12110
|
const plain = decryptTokensFile(tokensPath, box);
|
|
11122
12111
|
writeTokensEncrypted(tokensPath, plain, box);
|
|
11123
12112
|
}
|
|
11124
12113
|
function rewriteIntegrationState(configPath, readBox, writeBox) {
|
|
11125
12114
|
const path2 = defaultIntegrationsPath(configPath);
|
|
11126
|
-
if (!
|
|
12115
|
+
if (!existsSync23(path2)) return;
|
|
11127
12116
|
const state = new IntegrationStateStore(path2, readBox).load();
|
|
11128
12117
|
new IntegrationStateStore(path2, writeBox).save(state);
|
|
11129
12118
|
}
|
|
@@ -11136,7 +12125,7 @@ function writeTokensEncrypted(tokensPath, plain, box) {
|
|
|
11136
12125
|
{ updatedAt: "", ...plain },
|
|
11137
12126
|
box
|
|
11138
12127
|
);
|
|
11139
|
-
|
|
12128
|
+
writeFileSync14(tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
|
|
11140
12129
|
}
|
|
11141
12130
|
var TOKEN_FIELDS2 = {
|
|
11142
12131
|
claude: ["accessToken", "refreshToken"],
|
|
@@ -11159,11 +12148,11 @@ function walkTokens(raw, fn) {
|
|
|
11159
12148
|
return next;
|
|
11160
12149
|
}
|
|
11161
12150
|
function tokensSuffix(configPath) {
|
|
11162
|
-
return
|
|
12151
|
+
return existsSync23(defaultTokensPath(configPath)) ? " (+ tokens.json)" : "";
|
|
11163
12152
|
}
|
|
11164
12153
|
|
|
11165
12154
|
// src/commands/start.ts
|
|
11166
|
-
import { parseArgs as
|
|
12155
|
+
import { parseArgs as parseArgs9 } from "util";
|
|
11167
12156
|
import { loadServerConfig as loadServerConfig3 } from "@omnicross/core/outbound-api";
|
|
11168
12157
|
import { getSharedAccountHealth as getSharedAccountHealth5 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
|
|
11169
12158
|
import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling6 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
|
|
@@ -11202,7 +12191,7 @@ async function seedIdentities(store, credentialStore) {
|
|
|
11202
12191
|
|
|
11203
12192
|
// src/commands/start.ts
|
|
11204
12193
|
async function runStart(argv) {
|
|
11205
|
-
const { values } =
|
|
12194
|
+
const { values } = parseArgs9({
|
|
11206
12195
|
args: argv,
|
|
11207
12196
|
options: {
|
|
11208
12197
|
config: { type: "string", short: "c" },
|
|
@@ -11342,6 +12331,10 @@ Usage:
|
|
|
11342
12331
|
omnicross secrets encrypt --config <p> Encrypt all at-rest secrets in place.
|
|
11343
12332
|
omnicross secrets status --config <p> Report each secret field (no values shown).
|
|
11344
12333
|
omnicross secrets rotate --config <p> --new-master-key-file <p> Re-seal under a new master key.
|
|
12334
|
+
|
|
12335
|
+
omnicross audit sessions --config <p> [--date YYYY-MM-DD] List captured body shards per session.
|
|
12336
|
+
omnicross audit show --config <p> --session <key> [--id <recordId>] Print reconstructed request/response bodies.
|
|
12337
|
+
omnicross audit compact --config <p> [--date YYYY-MM-DD] Run cross-session body compaction now.
|
|
11345
12338
|
`;
|
|
11346
12339
|
async function main() {
|
|
11347
12340
|
const [, , subcommand, ...rest] = process.argv;
|
|
@@ -11373,6 +12366,9 @@ async function main() {
|
|
|
11373
12366
|
case "secrets":
|
|
11374
12367
|
await runSecrets(rest);
|
|
11375
12368
|
return;
|
|
12369
|
+
case "audit":
|
|
12370
|
+
await runAudit(rest);
|
|
12371
|
+
return;
|
|
11376
12372
|
case void 0:
|
|
11377
12373
|
case "-h":
|
|
11378
12374
|
case "--help":
|