iteration-cli 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +589 -55
- package/dist/cursor-hook-entry.js +47 -0
- package/dist/launcher.js +47 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -934,8 +934,8 @@ var require_src = __commonJS({
|
|
|
934
934
|
// src/cli.ts
|
|
935
935
|
import { spawnSync } from "node:child_process";
|
|
936
936
|
import os8 from "node:os";
|
|
937
|
-
import
|
|
938
|
-
import { promises as
|
|
937
|
+
import path21 from "node:path";
|
|
938
|
+
import { promises as fs17 } from "node:fs";
|
|
939
939
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
940
940
|
import { parseArgs } from "node:util";
|
|
941
941
|
|
|
@@ -1175,10 +1175,10 @@ function mergeDefs(...defs) {
|
|
|
1175
1175
|
function cloneDef(schema) {
|
|
1176
1176
|
return mergeDefs(schema._zod.def);
|
|
1177
1177
|
}
|
|
1178
|
-
function getElementAtPath(obj,
|
|
1179
|
-
if (!
|
|
1178
|
+
function getElementAtPath(obj, path22) {
|
|
1179
|
+
if (!path22)
|
|
1180
1180
|
return obj;
|
|
1181
|
-
return
|
|
1181
|
+
return path22.reduce((acc, key) => acc?.[key], obj);
|
|
1182
1182
|
}
|
|
1183
1183
|
function promiseAllObject(promisesObj) {
|
|
1184
1184
|
const keys = Object.keys(promisesObj);
|
|
@@ -1518,11 +1518,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1518
1518
|
}
|
|
1519
1519
|
return false;
|
|
1520
1520
|
}
|
|
1521
|
-
function prefixIssues(
|
|
1521
|
+
function prefixIssues(path22, issues) {
|
|
1522
1522
|
return issues.map((iss) => {
|
|
1523
1523
|
var _a3;
|
|
1524
1524
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1525
|
-
iss.path.unshift(
|
|
1525
|
+
iss.path.unshift(path22);
|
|
1526
1526
|
return iss;
|
|
1527
1527
|
});
|
|
1528
1528
|
}
|
|
@@ -1968,16 +1968,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
|
|
|
1968
1968
|
}
|
|
1969
1969
|
function formatError(error2, mapper = (issue2) => issue2.message) {
|
|
1970
1970
|
const fieldErrors = { _errors: [] };
|
|
1971
|
-
const processError = (error3,
|
|
1971
|
+
const processError = (error3, path22 = []) => {
|
|
1972
1972
|
for (const issue2 of error3.issues) {
|
|
1973
1973
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1974
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1974
|
+
issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
|
|
1975
1975
|
} else if (issue2.code === "invalid_key") {
|
|
1976
|
-
processError({ issues: issue2.issues }, [...
|
|
1976
|
+
processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
|
|
1977
1977
|
} else if (issue2.code === "invalid_element") {
|
|
1978
|
-
processError({ issues: issue2.issues }, [...
|
|
1978
|
+
processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
|
|
1979
1979
|
} else {
|
|
1980
|
-
const fullpath = [...
|
|
1980
|
+
const fullpath = [...path22, ...issue2.path];
|
|
1981
1981
|
if (fullpath.length === 0) {
|
|
1982
1982
|
fieldErrors._errors.push(mapper(issue2));
|
|
1983
1983
|
} else {
|
|
@@ -7557,6 +7557,34 @@ var cursorBillingRequestSchema = object({
|
|
|
7557
7557
|
paidUsd: number2().finite().nonnegative().nullable()
|
|
7558
7558
|
}).strict()).max(5e3)
|
|
7559
7559
|
}).strict();
|
|
7560
|
+
function codexCreditSign(value) {
|
|
7561
|
+
const mantissa = value.split(/[eE]/, 1)[0];
|
|
7562
|
+
if (!/[1-9]/.test(mantissa))
|
|
7563
|
+
return 0;
|
|
7564
|
+
return mantissa.startsWith("-") ? -1 : 1;
|
|
7565
|
+
}
|
|
7566
|
+
var codexBillingRequestSchema = object({
|
|
7567
|
+
accountFingerprint: string2().regex(/^[0-9a-f]{64}$/),
|
|
7568
|
+
reconcile: boolean2(),
|
|
7569
|
+
tasks: array(object({
|
|
7570
|
+
threadId: uuid2(),
|
|
7571
|
+
createdAt: iso_exports.datetime().nullable(),
|
|
7572
|
+
descendantThreadIds: array(uuid2()).max(900),
|
|
7573
|
+
dataStatus: _enum([
|
|
7574
|
+
"available",
|
|
7575
|
+
"partial",
|
|
7576
|
+
"unavailable",
|
|
7577
|
+
"not_queried"
|
|
7578
|
+
]),
|
|
7579
|
+
usageSource: string2().max(100),
|
|
7580
|
+
balanceUsageCredits: string2().regex(/^[+-]?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d{1,3})?$/).max(128).nullable()
|
|
7581
|
+
}).strict()).max(100),
|
|
7582
|
+
authTurns: array(object({
|
|
7583
|
+
threadId: uuid2(),
|
|
7584
|
+
turnId: uuid2(),
|
|
7585
|
+
mode: _enum(["chatgpt", "api_key", "conflicting"])
|
|
7586
|
+
}).strict()).max(5e3)
|
|
7587
|
+
}).strict();
|
|
7560
7588
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7561
7589
|
var TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
7562
7590
|
var unpairedSurrogate = /[\uD800-\uDFFF]/u;
|
|
@@ -11278,11 +11306,11 @@ function requireLodash_sortby() {
|
|
|
11278
11306
|
function baseForOwn(object3, iteratee) {
|
|
11279
11307
|
return object3 && baseFor(object3, iteratee, keys);
|
|
11280
11308
|
}
|
|
11281
|
-
function baseGet(object3,
|
|
11282
|
-
|
|
11283
|
-
var index = 0, length =
|
|
11309
|
+
function baseGet(object3, path22) {
|
|
11310
|
+
path22 = isKey(path22, object3) ? [path22] : castPath(path22);
|
|
11311
|
+
var index = 0, length = path22.length;
|
|
11284
11312
|
while (object3 != null && index < length) {
|
|
11285
|
-
object3 = object3[toKey(
|
|
11313
|
+
object3 = object3[toKey(path22[index++])];
|
|
11286
11314
|
}
|
|
11287
11315
|
return index && index == length ? object3 : void 0;
|
|
11288
11316
|
}
|
|
@@ -11409,13 +11437,13 @@ function requireLodash_sortby() {
|
|
|
11409
11437
|
return object3 === source || baseIsMatch(object3, source, matchData);
|
|
11410
11438
|
};
|
|
11411
11439
|
}
|
|
11412
|
-
function baseMatchesProperty(
|
|
11413
|
-
if (isKey(
|
|
11414
|
-
return matchesStrictComparable(toKey(
|
|
11440
|
+
function baseMatchesProperty(path22, srcValue) {
|
|
11441
|
+
if (isKey(path22) && isStrictComparable(srcValue)) {
|
|
11442
|
+
return matchesStrictComparable(toKey(path22), srcValue);
|
|
11415
11443
|
}
|
|
11416
11444
|
return function(object3) {
|
|
11417
|
-
var objValue = get(object3,
|
|
11418
|
-
return objValue === void 0 && objValue === srcValue ? hasIn(object3,
|
|
11445
|
+
var objValue = get(object3, path22);
|
|
11446
|
+
return objValue === void 0 && objValue === srcValue ? hasIn(object3, path22) : baseIsEqual(srcValue, objValue, void 0, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG);
|
|
11419
11447
|
};
|
|
11420
11448
|
}
|
|
11421
11449
|
function baseOrderBy(collection, iteratees, orders) {
|
|
@@ -11431,9 +11459,9 @@ function requireLodash_sortby() {
|
|
|
11431
11459
|
return compareMultiple(object3, other, orders);
|
|
11432
11460
|
});
|
|
11433
11461
|
}
|
|
11434
|
-
function basePropertyDeep(
|
|
11462
|
+
function basePropertyDeep(path22) {
|
|
11435
11463
|
return function(object3) {
|
|
11436
|
-
return baseGet(object3,
|
|
11464
|
+
return baseGet(object3, path22);
|
|
11437
11465
|
};
|
|
11438
11466
|
}
|
|
11439
11467
|
function baseRest(func, start2) {
|
|
@@ -11688,11 +11716,11 @@ function requireLodash_sortby() {
|
|
|
11688
11716
|
return result;
|
|
11689
11717
|
};
|
|
11690
11718
|
}
|
|
11691
|
-
function hasPath(object3,
|
|
11692
|
-
|
|
11693
|
-
var result, index = -1, length =
|
|
11719
|
+
function hasPath(object3, path22, hasFunc) {
|
|
11720
|
+
path22 = isKey(path22, object3) ? [path22] : castPath(path22);
|
|
11721
|
+
var result, index = -1, length = path22.length;
|
|
11694
11722
|
while (++index < length) {
|
|
11695
|
-
var key = toKey(
|
|
11723
|
+
var key = toKey(path22[index]);
|
|
11696
11724
|
if (!(result = object3 != null && hasFunc(object3, key))) {
|
|
11697
11725
|
break;
|
|
11698
11726
|
}
|
|
@@ -11847,12 +11875,12 @@ function requireLodash_sortby() {
|
|
|
11847
11875
|
function toString(value) {
|
|
11848
11876
|
return value == null ? "" : baseToString(value);
|
|
11849
11877
|
}
|
|
11850
|
-
function get(object3,
|
|
11851
|
-
var result = object3 == null ? void 0 : baseGet(object3,
|
|
11878
|
+
function get(object3, path22, defaultValue) {
|
|
11879
|
+
var result = object3 == null ? void 0 : baseGet(object3, path22);
|
|
11852
11880
|
return result === void 0 ? defaultValue : result;
|
|
11853
11881
|
}
|
|
11854
|
-
function hasIn(object3,
|
|
11855
|
-
return object3 != null && hasPath(object3,
|
|
11882
|
+
function hasIn(object3, path22) {
|
|
11883
|
+
return object3 != null && hasPath(object3, path22, baseHasIn);
|
|
11856
11884
|
}
|
|
11857
11885
|
function keys(object3) {
|
|
11858
11886
|
return isArrayLike(object3) ? arrayLikeKeys(object3) : baseKeys(object3);
|
|
@@ -11860,8 +11888,8 @@ function requireLodash_sortby() {
|
|
|
11860
11888
|
function identity(value) {
|
|
11861
11889
|
return value;
|
|
11862
11890
|
}
|
|
11863
|
-
function property(
|
|
11864
|
-
return isKey(
|
|
11891
|
+
function property(path22) {
|
|
11892
|
+
return isKey(path22) ? baseProperty(toKey(path22)) : basePropertyDeep(path22);
|
|
11865
11893
|
}
|
|
11866
11894
|
module.exports = sortBy;
|
|
11867
11895
|
})(lodash_sortby, lodash_sortby.exports);
|
|
@@ -12292,16 +12320,16 @@ async function reportIfFoundPrivateKeyP12Format({ source, context, t }) {
|
|
|
12292
12320
|
return;
|
|
12293
12321
|
}
|
|
12294
12322
|
try {
|
|
12295
|
-
const
|
|
12296
|
-
const
|
|
12297
|
-
const pfxBytes = new Uint8Array(
|
|
12323
|
+
const fs18 = await import("node:fs");
|
|
12324
|
+
const path22 = await import("node:path");
|
|
12325
|
+
const pfxBytes = new Uint8Array(fs18.readFileSync(source.filePath));
|
|
12298
12326
|
const isGcpServiceAccountP12 = await verifyPkcs12Mac(pfxBytes, GCP_SERVICE_ACCOUNT_P12_PASSWORD);
|
|
12299
12327
|
if (!isGcpServiceAccountP12) {
|
|
12300
12328
|
return;
|
|
12301
12329
|
}
|
|
12302
12330
|
context.report({
|
|
12303
12331
|
message: t("PrivateKeyP12", {
|
|
12304
|
-
FILE_NAME:
|
|
12332
|
+
FILE_NAME: path22.basename(source.filePath)
|
|
12305
12333
|
}),
|
|
12306
12334
|
range: [0, source.content.length]
|
|
12307
12335
|
});
|
|
@@ -15966,11 +15994,11 @@ async function connectedConfig(source) {
|
|
|
15966
15994
|
}
|
|
15967
15995
|
|
|
15968
15996
|
// src/history-import.ts
|
|
15969
|
-
import
|
|
15997
|
+
import path20 from "node:path";
|
|
15970
15998
|
|
|
15971
15999
|
// src/service.ts
|
|
15972
|
-
import { promises as
|
|
15973
|
-
import
|
|
16000
|
+
import { promises as fs16 } from "node:fs";
|
|
16001
|
+
import path19 from "node:path";
|
|
15974
16002
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
15975
16003
|
|
|
15976
16004
|
// src/collector.ts
|
|
@@ -17500,6 +17528,485 @@ async function syncCursorBilling(config2, fetcher = collectorFetch, signal) {
|
|
|
17500
17528
|
};
|
|
17501
17529
|
}
|
|
17502
17530
|
|
|
17531
|
+
// src/codex-billing.ts
|
|
17532
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
17533
|
+
import { promises as fs15 } from "node:fs";
|
|
17534
|
+
import path18 from "node:path";
|
|
17535
|
+
var TASK_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage/thread_usage/query_v2";
|
|
17536
|
+
var UUID3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17537
|
+
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
17538
|
+
var TASK_BATCH_SIZE = 50;
|
|
17539
|
+
var MAX_HEADER_BYTES = 3 * 1024 * 1024;
|
|
17540
|
+
var stateSchema2 = object({
|
|
17541
|
+
accountFingerprint: string2().regex(/^[0-9a-f]{64}$/),
|
|
17542
|
+
lastSyncedAtMs: number2().int().nonnegative(),
|
|
17543
|
+
lastAuditAtMs: number2().int().nonnegative(),
|
|
17544
|
+
unavailableThreadIds: array(uuid2())
|
|
17545
|
+
});
|
|
17546
|
+
var authSchema = object({
|
|
17547
|
+
auth_mode: string2().optional(),
|
|
17548
|
+
tokens: object({
|
|
17549
|
+
access_token: string2().min(1),
|
|
17550
|
+
account_id: string2().min(1)
|
|
17551
|
+
}).optional()
|
|
17552
|
+
});
|
|
17553
|
+
var taskUsageSchema = object({
|
|
17554
|
+
threads: array(
|
|
17555
|
+
object({
|
|
17556
|
+
thread_id: uuid2(),
|
|
17557
|
+
data_status: _enum(["available", "partial", "unavailable"]),
|
|
17558
|
+
usage_source: string2(),
|
|
17559
|
+
balance_usage_credits: string2().nullable().optional()
|
|
17560
|
+
})
|
|
17561
|
+
).max(TASK_BATCH_SIZE)
|
|
17562
|
+
});
|
|
17563
|
+
var sessionMetaSchema = object({
|
|
17564
|
+
type: literal("session_meta"),
|
|
17565
|
+
payload: object({
|
|
17566
|
+
id: uuid2(),
|
|
17567
|
+
timestamp: string2().optional(),
|
|
17568
|
+
creator_account_id: string2().nullable().optional(),
|
|
17569
|
+
model_provider: string2().nullable().optional(),
|
|
17570
|
+
parent_thread_id: string2().nullable().optional(),
|
|
17571
|
+
source: unknown().optional()
|
|
17572
|
+
})
|
|
17573
|
+
});
|
|
17574
|
+
var subagentSourceSchema = object({
|
|
17575
|
+
subagent: object({
|
|
17576
|
+
thread_spawn: object({ parent_thread_id: string2() }).optional()
|
|
17577
|
+
}).optional()
|
|
17578
|
+
});
|
|
17579
|
+
var syncResultSchema = object({ matched: number2().int().nonnegative() });
|
|
17580
|
+
function fingerprint(value) {
|
|
17581
|
+
return createHash8("sha256").update(value).digest("hex");
|
|
17582
|
+
}
|
|
17583
|
+
async function readAuth(codexHome) {
|
|
17584
|
+
let contents;
|
|
17585
|
+
try {
|
|
17586
|
+
contents = await fs15.readFile(path18.join(codexHome, "auth.json"), "utf8");
|
|
17587
|
+
} catch (error2) {
|
|
17588
|
+
if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT")
|
|
17589
|
+
return {
|
|
17590
|
+
accessToken: null,
|
|
17591
|
+
accountId: null,
|
|
17592
|
+
accountFingerprint: fingerprint(
|
|
17593
|
+
"codex-local-auth-logs:no-chatgpt-token"
|
|
17594
|
+
)
|
|
17595
|
+
};
|
|
17596
|
+
throw new Error("Could not read Codex authentication.", { cause: error2 });
|
|
17597
|
+
}
|
|
17598
|
+
let decoded;
|
|
17599
|
+
try {
|
|
17600
|
+
decoded = JSON.parse(contents);
|
|
17601
|
+
} catch (error2) {
|
|
17602
|
+
throw new Error("Codex authentication is not valid JSON.", {
|
|
17603
|
+
cause: error2
|
|
17604
|
+
});
|
|
17605
|
+
}
|
|
17606
|
+
const parsed = authSchema.safeParse(decoded);
|
|
17607
|
+
if (!parsed.success)
|
|
17608
|
+
throw new Error("Codex authentication has an unexpected shape.");
|
|
17609
|
+
const accountId = parsed.data.tokens?.account_id ?? null;
|
|
17610
|
+
return {
|
|
17611
|
+
accessToken: parsed.data.auth_mode === "chatgpt" ? parsed.data.tokens?.access_token ?? null : null,
|
|
17612
|
+
accountId,
|
|
17613
|
+
accountFingerprint: fingerprint(
|
|
17614
|
+
`${accountId ?? "codex-local-auth-logs"}:${parsed.data.auth_mode === "chatgpt" && parsed.data.tokens?.access_token ? "chatgpt" : "no-chatgpt-token"}`
|
|
17615
|
+
)
|
|
17616
|
+
};
|
|
17617
|
+
}
|
|
17618
|
+
async function readState(filename) {
|
|
17619
|
+
let contents;
|
|
17620
|
+
try {
|
|
17621
|
+
contents = await fs15.readFile(filename, "utf8");
|
|
17622
|
+
} catch (error2) {
|
|
17623
|
+
if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT")
|
|
17624
|
+
return null;
|
|
17625
|
+
throw new Error("Could not read Codex billing sync state.", {
|
|
17626
|
+
cause: error2
|
|
17627
|
+
});
|
|
17628
|
+
}
|
|
17629
|
+
let decoded;
|
|
17630
|
+
try {
|
|
17631
|
+
decoded = JSON.parse(contents);
|
|
17632
|
+
} catch (error2) {
|
|
17633
|
+
throw new Error("Codex billing sync state is not valid JSON.", {
|
|
17634
|
+
cause: error2
|
|
17635
|
+
});
|
|
17636
|
+
}
|
|
17637
|
+
const parsed = stateSchema2.safeParse(decoded);
|
|
17638
|
+
if (!parsed.success) throw new Error("Codex billing sync state is invalid.");
|
|
17639
|
+
return parsed.data;
|
|
17640
|
+
}
|
|
17641
|
+
async function saveState2(filename, state) {
|
|
17642
|
+
const temporary = `${filename}.${process.pid}.tmp`;
|
|
17643
|
+
const handle = await fs15.open(temporary, "w", 384);
|
|
17644
|
+
try {
|
|
17645
|
+
await handle.writeFile(`${JSON.stringify(state)}
|
|
17646
|
+
`);
|
|
17647
|
+
await handle.sync();
|
|
17648
|
+
} finally {
|
|
17649
|
+
await handle.close();
|
|
17650
|
+
}
|
|
17651
|
+
await fs15.rename(temporary, filename);
|
|
17652
|
+
}
|
|
17653
|
+
async function localThread(filename) {
|
|
17654
|
+
const stat = await fs15.stat(filename);
|
|
17655
|
+
const handle = await fs15.open(filename, "r");
|
|
17656
|
+
let header = null;
|
|
17657
|
+
try {
|
|
17658
|
+
const buffer = Buffer.alloc(64 * 1024);
|
|
17659
|
+
const chunks = [];
|
|
17660
|
+
let offset = 0;
|
|
17661
|
+
while (offset < Math.min(stat.size, MAX_HEADER_BYTES)) {
|
|
17662
|
+
const read = await handle.read(
|
|
17663
|
+
buffer,
|
|
17664
|
+
0,
|
|
17665
|
+
Math.min(buffer.length, MAX_HEADER_BYTES - offset),
|
|
17666
|
+
offset
|
|
17667
|
+
);
|
|
17668
|
+
if (read.bytesRead === 0) break;
|
|
17669
|
+
const newline = buffer.subarray(0, read.bytesRead).indexOf(10);
|
|
17670
|
+
if (newline >= 0) {
|
|
17671
|
+
chunks.push(Buffer.from(buffer.subarray(0, newline)));
|
|
17672
|
+
header = Buffer.concat(chunks);
|
|
17673
|
+
break;
|
|
17674
|
+
}
|
|
17675
|
+
chunks.push(Buffer.from(buffer.subarray(0, read.bytesRead)));
|
|
17676
|
+
offset += read.bytesRead;
|
|
17677
|
+
}
|
|
17678
|
+
} finally {
|
|
17679
|
+
await handle.close();
|
|
17680
|
+
}
|
|
17681
|
+
if (header === null) return null;
|
|
17682
|
+
let raw;
|
|
17683
|
+
try {
|
|
17684
|
+
raw = JSON.parse(header.toString("utf8"));
|
|
17685
|
+
} catch {
|
|
17686
|
+
return null;
|
|
17687
|
+
}
|
|
17688
|
+
const record3 = sessionMetaSchema.safeParse(raw);
|
|
17689
|
+
if (!record3.success) return null;
|
|
17690
|
+
const payload = record3.data.payload;
|
|
17691
|
+
if (!filename.endsWith(`${payload.id}.jsonl`)) return null;
|
|
17692
|
+
const source = subagentSourceSchema.safeParse(payload.source);
|
|
17693
|
+
const parentThreadId = payload.parent_thread_id ?? (source.success ? source.data.subagent?.thread_spawn?.parent_thread_id : null) ?? null;
|
|
17694
|
+
if (parentThreadId !== null && !UUID3.test(parentThreadId)) return null;
|
|
17695
|
+
return {
|
|
17696
|
+
threadId: payload.id,
|
|
17697
|
+
parentThreadId,
|
|
17698
|
+
createdAt: payload.timestamp && !Number.isNaN(Date.parse(payload.timestamp)) ? new Date(payload.timestamp).toISOString() : null,
|
|
17699
|
+
accountId: payload.creator_account_id ?? null,
|
|
17700
|
+
modelProvider: payload.model_provider ?? null,
|
|
17701
|
+
mtimeMs: stat.mtimeMs
|
|
17702
|
+
};
|
|
17703
|
+
}
|
|
17704
|
+
function groupCodexTasks(threads, accountId) {
|
|
17705
|
+
const byId = new Map(
|
|
17706
|
+
threads.filter(
|
|
17707
|
+
(thread) => thread.accountId === null || thread.accountId === accountId
|
|
17708
|
+
).map((thread) => [thread.threadId, thread])
|
|
17709
|
+
);
|
|
17710
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
17711
|
+
for (const thread of byId.values()) {
|
|
17712
|
+
if (thread.parentThreadId === null)
|
|
17713
|
+
tasks.set(thread.threadId, {
|
|
17714
|
+
threadId: thread.threadId,
|
|
17715
|
+
createdAt: thread.createdAt,
|
|
17716
|
+
descendantThreadIds: [],
|
|
17717
|
+
mtimeMs: thread.mtimeMs
|
|
17718
|
+
});
|
|
17719
|
+
}
|
|
17720
|
+
for (const thread of byId.values()) {
|
|
17721
|
+
if (thread.parentThreadId === null) continue;
|
|
17722
|
+
let ancestor = thread.parentThreadId;
|
|
17723
|
+
const seen = /* @__PURE__ */ new Set([thread.threadId]);
|
|
17724
|
+
while (ancestor !== null && !seen.has(ancestor)) {
|
|
17725
|
+
seen.add(ancestor);
|
|
17726
|
+
const parent = byId.get(ancestor);
|
|
17727
|
+
if (parent === void 0) break;
|
|
17728
|
+
if (parent.parentThreadId === null) {
|
|
17729
|
+
const task = tasks.get(parent.threadId);
|
|
17730
|
+
if (task !== void 0) {
|
|
17731
|
+
task.descendantThreadIds.push(thread.threadId);
|
|
17732
|
+
task.mtimeMs = Math.max(task.mtimeMs, thread.mtimeMs);
|
|
17733
|
+
}
|
|
17734
|
+
break;
|
|
17735
|
+
}
|
|
17736
|
+
ancestor = parent.parentThreadId;
|
|
17737
|
+
}
|
|
17738
|
+
}
|
|
17739
|
+
return [...tasks.values()].map((task) => ({
|
|
17740
|
+
...task,
|
|
17741
|
+
descendantThreadIds: task.descendantThreadIds.sort()
|
|
17742
|
+
}));
|
|
17743
|
+
}
|
|
17744
|
+
function parseCodexAuthLog(threadId, body) {
|
|
17745
|
+
if (threadId === null || !UUID3.test(threadId) || body === null) return null;
|
|
17746
|
+
const turn = /try_run_sampling_request\{turn_id=([0-9a-f-]{36})\b/i.exec(
|
|
17747
|
+
body
|
|
17748
|
+
);
|
|
17749
|
+
const auth = /\bauth_mode=Some\(([^)]+)\)/.exec(body);
|
|
17750
|
+
if (turn === null || auth === null || !UUID3.test(turn[1])) return null;
|
|
17751
|
+
const mode = auth[1] === "Chatgpt" ? "chatgpt" : auth[1] === "ApiKey" || auth[1] === "BedrockApiKey" || auth[1] === "BedrockAccessKeys" ? "api_key" : "conflicting";
|
|
17752
|
+
return { threadId, turnId: turn[1], mode };
|
|
17753
|
+
}
|
|
17754
|
+
async function localAuthTurns(codexHome, modelProviders) {
|
|
17755
|
+
const filename = path18.join(codexHome, "logs_2.sqlite");
|
|
17756
|
+
try {
|
|
17757
|
+
await fs15.access(filename);
|
|
17758
|
+
} catch (error2) {
|
|
17759
|
+
if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT")
|
|
17760
|
+
return [];
|
|
17761
|
+
throw new Error("Could not access Codex's local logs.", { cause: error2 });
|
|
17762
|
+
}
|
|
17763
|
+
const { DatabaseSync } = await import("node:sqlite");
|
|
17764
|
+
let database;
|
|
17765
|
+
try {
|
|
17766
|
+
database = new DatabaseSync(filename, { readOnly: true });
|
|
17767
|
+
} catch (error2) {
|
|
17768
|
+
throw new Error("Could not open Codex's local logs.", { cause: error2 });
|
|
17769
|
+
}
|
|
17770
|
+
const turns = /* @__PURE__ */ new Map();
|
|
17771
|
+
const logRowSchema = object({
|
|
17772
|
+
thread_id: string2().nullable(),
|
|
17773
|
+
feedback_log_body: string2().nullable()
|
|
17774
|
+
});
|
|
17775
|
+
try {
|
|
17776
|
+
const rows = database.prepare(
|
|
17777
|
+
"SELECT thread_id, feedback_log_body FROM logs WHERE target = 'feedback_tags' AND feedback_log_body LIKE '%auth_mode=Some(%'"
|
|
17778
|
+
).iterate();
|
|
17779
|
+
for (const raw of rows) {
|
|
17780
|
+
const row = logRowSchema.safeParse(raw);
|
|
17781
|
+
if (!row.success)
|
|
17782
|
+
throw new Error("Codex's local log row has an invalid shape.");
|
|
17783
|
+
if (row.data.thread_id === null || !modelProviders.has(row.data.thread_id))
|
|
17784
|
+
continue;
|
|
17785
|
+
const parsed = parseCodexAuthLog(
|
|
17786
|
+
row.data.thread_id,
|
|
17787
|
+
row.data.feedback_log_body
|
|
17788
|
+
);
|
|
17789
|
+
if (parsed === null) continue;
|
|
17790
|
+
const mode = parsed.mode === "chatgpt" && modelProviders.get(parsed.threadId) !== "openai" ? "conflicting" : parsed.mode;
|
|
17791
|
+
const key = `${parsed.threadId}:${parsed.turnId}`;
|
|
17792
|
+
const prior = turns.get(key);
|
|
17793
|
+
turns.set(key, {
|
|
17794
|
+
...parsed,
|
|
17795
|
+
mode: prior === void 0 || prior.mode === mode ? mode : "conflicting"
|
|
17796
|
+
});
|
|
17797
|
+
}
|
|
17798
|
+
} finally {
|
|
17799
|
+
database.close();
|
|
17800
|
+
}
|
|
17801
|
+
return [...turns.values()];
|
|
17802
|
+
}
|
|
17803
|
+
async function queryTaskUsage(tasks, accessToken, accountId, signal) {
|
|
17804
|
+
const response = await fetch(TASK_USAGE_URL, {
|
|
17805
|
+
method: "POST",
|
|
17806
|
+
headers: {
|
|
17807
|
+
Authorization: `Bearer ${accessToken}`,
|
|
17808
|
+
"ChatGPT-Account-Id": accountId,
|
|
17809
|
+
"Content-Type": "application/json",
|
|
17810
|
+
"User-Agent": "codex-cli"
|
|
17811
|
+
},
|
|
17812
|
+
body: JSON.stringify({
|
|
17813
|
+
threads: tasks.map((task) => ({
|
|
17814
|
+
thread_id: task.threadId,
|
|
17815
|
+
created_at: task.createdAt,
|
|
17816
|
+
descendant_thread_ids: task.descendantThreadIds
|
|
17817
|
+
}))
|
|
17818
|
+
}),
|
|
17819
|
+
signal: AbortSignal.any([
|
|
17820
|
+
AbortSignal.timeout(2e4),
|
|
17821
|
+
...signal ? [signal] : []
|
|
17822
|
+
])
|
|
17823
|
+
});
|
|
17824
|
+
if (!response.ok)
|
|
17825
|
+
throw new Error(
|
|
17826
|
+
`Codex task usage lookup failed with HTTP ${response.status}.`
|
|
17827
|
+
);
|
|
17828
|
+
const parsed = taskUsageSchema.safeParse(await response.json());
|
|
17829
|
+
if (!parsed.success) throw new Error("Codex returned invalid task usage.");
|
|
17830
|
+
const requested = new Set(tasks.map((task) => task.threadId));
|
|
17831
|
+
const byId = new Map(tasks.map((task) => [task.threadId, task]));
|
|
17832
|
+
const result = /* @__PURE__ */ new Map();
|
|
17833
|
+
for (const row of parsed.data.threads) {
|
|
17834
|
+
if (!requested.has(row.thread_id) || result.has(row.thread_id))
|
|
17835
|
+
throw new Error("Codex returned an unexpected task usage ID.");
|
|
17836
|
+
const task = byId.get(row.thread_id);
|
|
17837
|
+
result.set(row.thread_id, {
|
|
17838
|
+
threadId: row.thread_id,
|
|
17839
|
+
createdAt: task.createdAt,
|
|
17840
|
+
descendantThreadIds: [...task.descendantThreadIds],
|
|
17841
|
+
dataStatus: row.data_status,
|
|
17842
|
+
usageSource: row.usage_source,
|
|
17843
|
+
balanceUsageCredits: row.balance_usage_credits ?? null
|
|
17844
|
+
});
|
|
17845
|
+
}
|
|
17846
|
+
return result;
|
|
17847
|
+
}
|
|
17848
|
+
async function syncCodexBilling(config2, fetcher = collectorFetch, signal) {
|
|
17849
|
+
const auth = await readAuth(config2.codexHome);
|
|
17850
|
+
const stateFile = path18.join(config2.dataDirectory, "codex-billing-sync.json");
|
|
17851
|
+
const prior = await readState(stateFile);
|
|
17852
|
+
const nowMs = Date.now();
|
|
17853
|
+
const history = prior === null || prior.accountFingerprint !== auth.accountFingerprint;
|
|
17854
|
+
const audit = !history && nowMs - prior.lastAuditAtMs >= 7 * DAY_MS2;
|
|
17855
|
+
const cutoff = history ? 0 : Math.min(
|
|
17856
|
+
prior.lastSyncedAtMs - DAY_MS2,
|
|
17857
|
+
nowMs - (audit ? 35 : 7) * DAY_MS2
|
|
17858
|
+
);
|
|
17859
|
+
const filenames = await sourceFiles("codex", config2.codexHome);
|
|
17860
|
+
const threads = [];
|
|
17861
|
+
for (const filename of filenames) {
|
|
17862
|
+
signal?.throwIfAborted();
|
|
17863
|
+
const thread = await localThread(filename);
|
|
17864
|
+
if (thread !== null) threads.push(thread);
|
|
17865
|
+
}
|
|
17866
|
+
const allTasks = groupCodexTasks(threads, auth.accountId);
|
|
17867
|
+
const retryIds = new Set(audit ? prior?.unavailableThreadIds ?? [] : []);
|
|
17868
|
+
const selected = allTasks.filter(
|
|
17869
|
+
(task) => task.mtimeMs >= cutoff || retryIds.has(task.threadId)
|
|
17870
|
+
);
|
|
17871
|
+
if (selected.length === 0)
|
|
17872
|
+
return {
|
|
17873
|
+
tasks: 0,
|
|
17874
|
+
included: 0,
|
|
17875
|
+
creditTasks: 0,
|
|
17876
|
+
apiTurns: 0,
|
|
17877
|
+
skipped: false
|
|
17878
|
+
};
|
|
17879
|
+
const selectedIds = new Set(
|
|
17880
|
+
selected.flatMap((task) => [task.threadId, ...task.descendantThreadIds])
|
|
17881
|
+
);
|
|
17882
|
+
const modelProviders = new Map(
|
|
17883
|
+
threads.filter((thread) => selectedIds.has(thread.threadId)).map((thread) => [thread.threadId, thread.modelProvider])
|
|
17884
|
+
);
|
|
17885
|
+
const authTurns = await localAuthTurns(config2.codexHome, modelProviders);
|
|
17886
|
+
const byThread = /* @__PURE__ */ new Map();
|
|
17887
|
+
for (const turn of authTurns) {
|
|
17888
|
+
const turns = byThread.get(turn.threadId) ?? [];
|
|
17889
|
+
turns.push(turn);
|
|
17890
|
+
byThread.set(turn.threadId, turns);
|
|
17891
|
+
}
|
|
17892
|
+
const localTaskIds = new Set(allTasks.map((task) => task.threadId));
|
|
17893
|
+
const unavailable = new Set(
|
|
17894
|
+
history ? [] : (prior?.unavailableThreadIds ?? []).filter(
|
|
17895
|
+
(id) => localTaskIds.has(id)
|
|
17896
|
+
)
|
|
17897
|
+
);
|
|
17898
|
+
let included = 0;
|
|
17899
|
+
let creditTasks = 0;
|
|
17900
|
+
let apiTurns = 0;
|
|
17901
|
+
const endpoint = new URL(config2.endpoint);
|
|
17902
|
+
endpoint.pathname = "/api/traces/codex-billing";
|
|
17903
|
+
const batches = [];
|
|
17904
|
+
let current = [];
|
|
17905
|
+
let currentIds = 0;
|
|
17906
|
+
let currentTurns = 0;
|
|
17907
|
+
for (const task of selected) {
|
|
17908
|
+
const size = 1 + task.descendantThreadIds.length;
|
|
17909
|
+
const turns = [task.threadId, ...task.descendantThreadIds].reduce(
|
|
17910
|
+
(total, threadId) => total + (byThread.get(threadId)?.length ?? 0),
|
|
17911
|
+
0
|
|
17912
|
+
);
|
|
17913
|
+
if (size > 1e3)
|
|
17914
|
+
throw new Error("Codex task exceeds the billing thread limit.");
|
|
17915
|
+
if (current.length >= TASK_BATCH_SIZE || currentIds + size > 1e3 || currentTurns + turns > 5e3) {
|
|
17916
|
+
if (current.length > 0) batches.push(current);
|
|
17917
|
+
current = [];
|
|
17918
|
+
currentIds = 0;
|
|
17919
|
+
currentTurns = 0;
|
|
17920
|
+
}
|
|
17921
|
+
current.push(task);
|
|
17922
|
+
currentIds += size;
|
|
17923
|
+
currentTurns += turns;
|
|
17924
|
+
if (turns > 5e3) {
|
|
17925
|
+
batches.push(current);
|
|
17926
|
+
current = [];
|
|
17927
|
+
currentIds = 0;
|
|
17928
|
+
currentTurns = 0;
|
|
17929
|
+
}
|
|
17930
|
+
}
|
|
17931
|
+
if (current.length > 0) batches.push(current);
|
|
17932
|
+
for (const batch of batches) {
|
|
17933
|
+
signal?.throwIfAborted();
|
|
17934
|
+
const responseTasks = auth.accessToken === null || auth.accountId === null ? /* @__PURE__ */ new Map() : await queryTaskUsage(batch, auth.accessToken, auth.accountId, signal);
|
|
17935
|
+
const tasks = batch.map((task) => {
|
|
17936
|
+
const response = responseTasks.get(task.threadId);
|
|
17937
|
+
return response ?? {
|
|
17938
|
+
threadId: task.threadId,
|
|
17939
|
+
createdAt: task.createdAt,
|
|
17940
|
+
descendantThreadIds: [...task.descendantThreadIds],
|
|
17941
|
+
dataStatus: auth.accessToken === null || auth.accountId === null ? "not_queried" : "unavailable",
|
|
17942
|
+
usageSource: "",
|
|
17943
|
+
balanceUsageCredits: null
|
|
17944
|
+
};
|
|
17945
|
+
});
|
|
17946
|
+
const batchTurns = batch.flatMap(
|
|
17947
|
+
(task) => [task.threadId, ...task.descendantThreadIds].flatMap(
|
|
17948
|
+
(threadId) => byThread.get(threadId) ?? []
|
|
17949
|
+
)
|
|
17950
|
+
);
|
|
17951
|
+
let serverIncomplete = false;
|
|
17952
|
+
for (let offset = 0; offset < Math.max(1, batchTurns.length); offset += 5e3) {
|
|
17953
|
+
const request2 = codexBillingRequestSchema.parse({
|
|
17954
|
+
accountFingerprint: auth.accountFingerprint,
|
|
17955
|
+
reconcile: offset === 0,
|
|
17956
|
+
tasks,
|
|
17957
|
+
authTurns: batchTurns.slice(offset, offset + 5e3)
|
|
17958
|
+
});
|
|
17959
|
+
const response = await fetcher(endpoint, {
|
|
17960
|
+
method: "POST",
|
|
17961
|
+
headers: {
|
|
17962
|
+
Authorization: `Bearer ${config2.token}`,
|
|
17963
|
+
"Content-Type": "application/json"
|
|
17964
|
+
},
|
|
17965
|
+
body: JSON.stringify(request2),
|
|
17966
|
+
signal: AbortSignal.any([
|
|
17967
|
+
AbortSignal.timeout(9e4),
|
|
17968
|
+
...signal ? [signal] : []
|
|
17969
|
+
])
|
|
17970
|
+
});
|
|
17971
|
+
if (!response.ok)
|
|
17972
|
+
throw new Error(
|
|
17973
|
+
`Codex billing sync failed with HTTP ${response.status}.`
|
|
17974
|
+
);
|
|
17975
|
+
const result = syncResultSchema.safeParse(await response.json());
|
|
17976
|
+
if (!result.success || result.data.matched > tasks.length)
|
|
17977
|
+
throw new Error("Iteration returned an invalid Codex billing result.");
|
|
17978
|
+
if (result.data.matched < tasks.length) serverIncomplete = true;
|
|
17979
|
+
}
|
|
17980
|
+
for (const task of tasks) {
|
|
17981
|
+
if (task.dataStatus === "available" && task.balanceUsageCredits !== null && (task.usageSource === "included_plan" || task.usageSource === "plan_and_credits"))
|
|
17982
|
+
unavailable.delete(task.threadId);
|
|
17983
|
+
else if (task.dataStatus !== "not_queried")
|
|
17984
|
+
unavailable.add(task.threadId);
|
|
17985
|
+
if (serverIncomplete) unavailable.add(task.threadId);
|
|
17986
|
+
if (task.dataStatus === "available" && task.balanceUsageCredits !== null && (task.usageSource === "included_plan" || task.usageSource === "plan_and_credits")) {
|
|
17987
|
+
if (codexCreditSign(task.balanceUsageCredits) === 0 && task.usageSource === "included_plan")
|
|
17988
|
+
included += 1;
|
|
17989
|
+
else if (codexCreditSign(task.balanceUsageCredits) > 0)
|
|
17990
|
+
creditTasks += 1;
|
|
17991
|
+
}
|
|
17992
|
+
}
|
|
17993
|
+
apiTurns += batchTurns.filter((turn) => turn.mode === "api_key").length;
|
|
17994
|
+
}
|
|
17995
|
+
await saveState2(stateFile, {
|
|
17996
|
+
accountFingerprint: auth.accountFingerprint,
|
|
17997
|
+
lastSyncedAtMs: nowMs,
|
|
17998
|
+
lastAuditAtMs: history || audit ? nowMs : prior.lastAuditAtMs,
|
|
17999
|
+
unavailableThreadIds: [...unavailable]
|
|
18000
|
+
});
|
|
18001
|
+
return {
|
|
18002
|
+
tasks: selected.length,
|
|
18003
|
+
included,
|
|
18004
|
+
creditTasks,
|
|
18005
|
+
apiTurns,
|
|
18006
|
+
skipped: false
|
|
18007
|
+
};
|
|
18008
|
+
}
|
|
18009
|
+
|
|
17503
18010
|
// src/service.ts
|
|
17504
18011
|
function errorCode2(error2) {
|
|
17505
18012
|
if (error2 instanceof Error && "code" in error2) return String(error2.code);
|
|
@@ -17541,26 +18048,26 @@ async function persistHealth(health, paths) {
|
|
|
17541
18048
|
}
|
|
17542
18049
|
}
|
|
17543
18050
|
async function acquireCollectorLock(paths) {
|
|
17544
|
-
await ensurePrivateDirectory(
|
|
18051
|
+
await ensurePrivateDirectory(path19.dirname(paths.lock));
|
|
17545
18052
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
17546
18053
|
try {
|
|
17547
|
-
const handle = await
|
|
18054
|
+
const handle = await fs16.open(paths.lock, "wx", 384);
|
|
17548
18055
|
await handle.writeFile(`${process.pid}
|
|
17549
18056
|
`, "utf8");
|
|
17550
18057
|
await handle.sync();
|
|
17551
18058
|
await handle.close();
|
|
17552
18059
|
return async () => {
|
|
17553
|
-
const current = await
|
|
18060
|
+
const current = await fs16.readFile(paths.lock, "utf8").catch(() => "");
|
|
17554
18061
|
if (current.trim() === String(process.pid)) {
|
|
17555
|
-
await
|
|
18062
|
+
await fs16.rm(paths.lock, { force: true });
|
|
17556
18063
|
}
|
|
17557
18064
|
};
|
|
17558
18065
|
} catch (error2) {
|
|
17559
18066
|
if (errorCode2(error2) !== "EEXIST") throw error2;
|
|
17560
|
-
const lockContents = await
|
|
18067
|
+
const lockContents = await fs16.readFile(paths.lock, "utf8").catch(() => "");
|
|
17561
18068
|
const lockPid = Number(lockContents.trim());
|
|
17562
18069
|
if (!Number.isSafeInteger(lockPid) || lockPid < 2) {
|
|
17563
|
-
await
|
|
18070
|
+
await fs16.rm(paths.lock, { force: true });
|
|
17564
18071
|
continue;
|
|
17565
18072
|
}
|
|
17566
18073
|
try {
|
|
@@ -17568,7 +18075,7 @@ async function acquireCollectorLock(paths) {
|
|
|
17568
18075
|
throw new CollectorLockBusyError("Collector is already running.");
|
|
17569
18076
|
} catch (processError) {
|
|
17570
18077
|
if (errorCode2(processError) !== "ESRCH") throw processError;
|
|
17571
|
-
await
|
|
18078
|
+
await fs16.rm(paths.lock, { force: true });
|
|
17572
18079
|
}
|
|
17573
18080
|
}
|
|
17574
18081
|
}
|
|
@@ -17840,6 +18347,33 @@ async function runCollector(directory, expectedSource) {
|
|
|
17840
18347
|
);
|
|
17841
18348
|
}
|
|
17842
18349
|
}
|
|
18350
|
+
if ("codexHome" in config2 && billingReady && Date.now() - lastBillingSyncAt >= 6 * 60 * 60 * 1e3) {
|
|
18351
|
+
try {
|
|
18352
|
+
const billing = await syncCodexBilling(
|
|
18353
|
+
config2,
|
|
18354
|
+
collectorFetch,
|
|
18355
|
+
controller.signal
|
|
18356
|
+
);
|
|
18357
|
+
lastBillingSyncAt = billing.skipped ? Date.now() - 6 * 60 * 60 * 1e3 + 5 * 60 * 1e3 : Date.now();
|
|
18358
|
+
console.info(
|
|
18359
|
+
JSON.stringify({
|
|
18360
|
+
level: "info",
|
|
18361
|
+
operation: "sync_codex_billing",
|
|
18362
|
+
...billing
|
|
18363
|
+
})
|
|
18364
|
+
);
|
|
18365
|
+
} catch (error2) {
|
|
18366
|
+
if (controller.signal.aborted) break;
|
|
18367
|
+
lastBillingSyncAt = Date.now() - 6 * 60 * 60 * 1e3 + 5 * 60 * 1e3;
|
|
18368
|
+
console.error(
|
|
18369
|
+
JSON.stringify({
|
|
18370
|
+
level: "warning",
|
|
18371
|
+
operation: "sync_codex_billing",
|
|
18372
|
+
message: error2 instanceof Error ? error2.message : "Codex billing sync failed."
|
|
18373
|
+
})
|
|
18374
|
+
);
|
|
18375
|
+
}
|
|
18376
|
+
}
|
|
17843
18377
|
try {
|
|
17844
18378
|
await delay3(retryDelayMs, void 0, { signal: controller.signal });
|
|
17845
18379
|
} catch (error2) {
|
|
@@ -17867,7 +18401,7 @@ async function importSourceHistory(config2, paths, confirmed, control = backgrou
|
|
|
17867
18401
|
const source = collectorSource(config2);
|
|
17868
18402
|
const directory = collectorSourceDirectory(config2);
|
|
17869
18403
|
const state = await loadState(paths);
|
|
17870
|
-
if (!state.initialized || state.sourceDirectory !==
|
|
18404
|
+
if (!state.initialized || state.sourceDirectory !== path20.resolve(directory)) {
|
|
17871
18405
|
throw new Error(
|
|
17872
18406
|
`Connect the ${source} source before importing its history.`
|
|
17873
18407
|
);
|
|
@@ -18296,7 +18830,7 @@ function usage(command) {
|
|
|
18296
18830
|
}
|
|
18297
18831
|
async function fileExists(filename) {
|
|
18298
18832
|
try {
|
|
18299
|
-
await
|
|
18833
|
+
await fs17.access(filename);
|
|
18300
18834
|
return true;
|
|
18301
18835
|
} catch (error2) {
|
|
18302
18836
|
if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT") {
|
|
@@ -18346,7 +18880,7 @@ ${missing2.map(collectorSourceLabel).join(" and ")} found on this computer but n
|
|
|
18346
18880
|
await connectAll({});
|
|
18347
18881
|
}
|
|
18348
18882
|
function dataDirectory(source, values) {
|
|
18349
|
-
return
|
|
18883
|
+
return path21.resolve(
|
|
18350
18884
|
optionalString(values, "data-directory") ?? defaultCollectorDirectory(source)
|
|
18351
18885
|
);
|
|
18352
18886
|
}
|
|
@@ -18371,8 +18905,8 @@ async function initialize(source, values) {
|
|
|
18371
18905
|
const organizationId = optionalString(values, "organization-id");
|
|
18372
18906
|
const directory = dataDirectory(source, values);
|
|
18373
18907
|
const paths = collectorPaths(directory);
|
|
18374
|
-
const selectedHome =
|
|
18375
|
-
source === "codex" ? optionalString(values, "codex-home") ?? process.env.CODEX_HOME ??
|
|
18908
|
+
const selectedHome = path21.resolve(
|
|
18909
|
+
source === "codex" ? optionalString(values, "codex-home") ?? process.env.CODEX_HOME ?? path21.join(os8.homedir(), ".codex") : source === "claude" ? optionalString(values, "claude-home") ?? process.env.CLAUDE_CONFIG_DIR ?? path21.join(os8.homedir(), ".claude") : optionalString(values, "cursor-home") ?? path21.join(os8.homedir(), ".cursor")
|
|
18376
18910
|
);
|
|
18377
18911
|
await assertFreshCollectorDirectory(paths, source);
|
|
18378
18912
|
const preparedState = await prepareSourceInitialState(
|
|
@@ -18455,13 +18989,13 @@ async function connectAll(values) {
|
|
|
18455
18989
|
}
|
|
18456
18990
|
const configs = await Promise.all(COLLECTOR_SOURCES.map(connectedConfig));
|
|
18457
18991
|
const sourceHomes = {
|
|
18458
|
-
codex:
|
|
18992
|
+
codex: path21.resolve(
|
|
18459
18993
|
optionalString(values, "codex-home") ?? (configs[0] && "codexHome" in configs[0] ? configs[0].codexHome : sourceHome("codex"))
|
|
18460
18994
|
),
|
|
18461
|
-
claude:
|
|
18995
|
+
claude: path21.resolve(
|
|
18462
18996
|
optionalString(values, "claude-home") ?? (configs[1] && "claudeHome" in configs[1] ? configs[1].claudeHome : sourceHome("claude"))
|
|
18463
18997
|
),
|
|
18464
|
-
cursor:
|
|
18998
|
+
cursor: path21.resolve(
|
|
18465
18999
|
optionalString(values, "cursor-home") ?? (configs[2] && "cursorHome" in configs[2] ? configs[2].cursorHome : sourceHome("cursor"))
|
|
18466
19000
|
)
|
|
18467
19001
|
};
|
|
@@ -7285,6 +7285,31 @@ function superRefine(fn, params) {
|
|
|
7285
7285
|
return _superRefine(fn, params);
|
|
7286
7286
|
}
|
|
7287
7287
|
|
|
7288
|
+
// ../../node_modules/.pnpm/zod@4.6.4/node_modules/zod/v4/classic/iso.js
|
|
7289
|
+
var iso_exports = {};
|
|
7290
|
+
__export(iso_exports, {
|
|
7291
|
+
ZodISODate: () => ZodISODate,
|
|
7292
|
+
ZodISODateTime: () => ZodISODateTime,
|
|
7293
|
+
ZodISODuration: () => ZodISODuration,
|
|
7294
|
+
ZodISOTime: () => ZodISOTime,
|
|
7295
|
+
date: () => date2,
|
|
7296
|
+
datetime: () => datetime2,
|
|
7297
|
+
duration: () => duration2,
|
|
7298
|
+
time: () => time2
|
|
7299
|
+
});
|
|
7300
|
+
function datetime2(params) {
|
|
7301
|
+
return _isoDateTime(ZodISODateTime, params);
|
|
7302
|
+
}
|
|
7303
|
+
function date2(params) {
|
|
7304
|
+
return _isoDate(ZodISODate, params);
|
|
7305
|
+
}
|
|
7306
|
+
function time2(params) {
|
|
7307
|
+
return _isoTime(ZodISOTime, params);
|
|
7308
|
+
}
|
|
7309
|
+
function duration2(params) {
|
|
7310
|
+
return _isoDuration(ZodISODuration, params);
|
|
7311
|
+
}
|
|
7312
|
+
|
|
7288
7313
|
// src/cursor-hooks.ts
|
|
7289
7314
|
import path2 from "node:path";
|
|
7290
7315
|
|
|
@@ -7340,6 +7365,28 @@ var cursorBillingRequestSchema = object({
|
|
|
7340
7365
|
paidUsd: number2().finite().nonnegative().nullable()
|
|
7341
7366
|
}).strict()).max(5e3)
|
|
7342
7367
|
}).strict();
|
|
7368
|
+
var codexBillingRequestSchema = object({
|
|
7369
|
+
accountFingerprint: string2().regex(/^[0-9a-f]{64}$/),
|
|
7370
|
+
reconcile: boolean2(),
|
|
7371
|
+
tasks: array(object({
|
|
7372
|
+
threadId: uuid2(),
|
|
7373
|
+
createdAt: iso_exports.datetime().nullable(),
|
|
7374
|
+
descendantThreadIds: array(uuid2()).max(900),
|
|
7375
|
+
dataStatus: _enum([
|
|
7376
|
+
"available",
|
|
7377
|
+
"partial",
|
|
7378
|
+
"unavailable",
|
|
7379
|
+
"not_queried"
|
|
7380
|
+
]),
|
|
7381
|
+
usageSource: string2().max(100),
|
|
7382
|
+
balanceUsageCredits: string2().regex(/^[+-]?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d{1,3})?$/).max(128).nullable()
|
|
7383
|
+
}).strict()).max(100),
|
|
7384
|
+
authTurns: array(object({
|
|
7385
|
+
threadId: uuid2(),
|
|
7386
|
+
turnId: uuid2(),
|
|
7387
|
+
mode: _enum(["chatgpt", "api_key", "conflicting"])
|
|
7388
|
+
}).strict()).max(5e3)
|
|
7389
|
+
}).strict();
|
|
7343
7390
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7344
7391
|
var TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
7345
7392
|
var unpairedSurrogate = /[\uD800-\uDFFF]/u;
|
package/dist/launcher.js
CHANGED
|
@@ -6364,6 +6364,31 @@ function superRefine(fn, params) {
|
|
|
6364
6364
|
return _superRefine(fn, params);
|
|
6365
6365
|
}
|
|
6366
6366
|
|
|
6367
|
+
// ../../node_modules/.pnpm/zod@4.6.4/node_modules/zod/v4/classic/iso.js
|
|
6368
|
+
var iso_exports = {};
|
|
6369
|
+
__export(iso_exports, {
|
|
6370
|
+
ZodISODate: () => ZodISODate,
|
|
6371
|
+
ZodISODateTime: () => ZodISODateTime,
|
|
6372
|
+
ZodISODuration: () => ZodISODuration,
|
|
6373
|
+
ZodISOTime: () => ZodISOTime,
|
|
6374
|
+
date: () => date2,
|
|
6375
|
+
datetime: () => datetime2,
|
|
6376
|
+
duration: () => duration2,
|
|
6377
|
+
time: () => time2
|
|
6378
|
+
});
|
|
6379
|
+
function datetime2(params) {
|
|
6380
|
+
return _isoDateTime(ZodISODateTime, params);
|
|
6381
|
+
}
|
|
6382
|
+
function date2(params) {
|
|
6383
|
+
return _isoDate(ZodISODate, params);
|
|
6384
|
+
}
|
|
6385
|
+
function time2(params) {
|
|
6386
|
+
return _isoTime(ZodISOTime, params);
|
|
6387
|
+
}
|
|
6388
|
+
function duration2(params) {
|
|
6389
|
+
return _isoDuration(ZodISODuration, params);
|
|
6390
|
+
}
|
|
6391
|
+
|
|
6367
6392
|
// ../trace-contracts/dist/index.js
|
|
6368
6393
|
var TRACE_EVENT_TYPES = [
|
|
6369
6394
|
"user_message",
|
|
@@ -6416,6 +6441,28 @@ var cursorBillingRequestSchema = object({
|
|
|
6416
6441
|
paidUsd: number2().finite().nonnegative().nullable()
|
|
6417
6442
|
}).strict()).max(5e3)
|
|
6418
6443
|
}).strict();
|
|
6444
|
+
var codexBillingRequestSchema = object({
|
|
6445
|
+
accountFingerprint: string2().regex(/^[0-9a-f]{64}$/),
|
|
6446
|
+
reconcile: boolean2(),
|
|
6447
|
+
tasks: array(object({
|
|
6448
|
+
threadId: uuid2(),
|
|
6449
|
+
createdAt: iso_exports.datetime().nullable(),
|
|
6450
|
+
descendantThreadIds: array(uuid2()).max(900),
|
|
6451
|
+
dataStatus: _enum([
|
|
6452
|
+
"available",
|
|
6453
|
+
"partial",
|
|
6454
|
+
"unavailable",
|
|
6455
|
+
"not_queried"
|
|
6456
|
+
]),
|
|
6457
|
+
usageSource: string2().max(100),
|
|
6458
|
+
balanceUsageCredits: string2().regex(/^[+-]?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d{1,3})?$/).max(128).nullable()
|
|
6459
|
+
}).strict()).max(100),
|
|
6460
|
+
authTurns: array(object({
|
|
6461
|
+
threadId: uuid2(),
|
|
6462
|
+
turnId: uuid2(),
|
|
6463
|
+
mode: _enum(["chatgpt", "api_key", "conflicting"])
|
|
6464
|
+
}).strict()).max(5e3)
|
|
6465
|
+
}).strict();
|
|
6419
6466
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
6420
6467
|
var TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
6421
6468
|
var unpairedSurrogate = /[\uD800-\uDFFF]/u;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iteration-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@secretlint/secretlint-rule-preset-recommend": "13.0.6",
|
|
23
23
|
"esbuild": "0.28.2",
|
|
24
24
|
"zod": "4.6.4",
|
|
25
|
-
"iteration-trace-contracts": "0.
|
|
25
|
+
"iteration-trace-contracts": "0.9.0"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "pnpm --filter iteration-trace-contracts build && tsc -p tsconfig.json --noEmit && node build.mjs"
|