iteration-cli 0.17.0 → 0.18.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/README.md +5 -4
- package/dist/cli.js +611 -343
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7,9 +7,9 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { spawnSync } from "node:child_process";
|
|
10
|
-
import { promises as
|
|
11
|
-
import
|
|
12
|
-
import
|
|
10
|
+
import { promises as fs25 } from "node:fs";
|
|
11
|
+
import os12 from "node:os";
|
|
12
|
+
import path31 from "node:path";
|
|
13
13
|
import { parseArgs } from "node:util";
|
|
14
14
|
|
|
15
15
|
// ../trace-vault/packages/cli/dist/index.js
|
|
@@ -7973,16 +7973,16 @@ function consoleWriter(line, level) {
|
|
|
7973
7973
|
}
|
|
7974
7974
|
var loggingContext = () => ({});
|
|
7975
7975
|
var logWriter = consoleWriter;
|
|
7976
|
-
function configureCollectorLogging(context2,
|
|
7976
|
+
function configureCollectorLogging(context2, write2 = consoleWriter) {
|
|
7977
7977
|
loggingContext = context2;
|
|
7978
|
-
logWriter =
|
|
7978
|
+
logWriter = write2;
|
|
7979
7979
|
}
|
|
7980
7980
|
function writeLog(line, level) {
|
|
7981
7981
|
logWriter(line, level);
|
|
7982
7982
|
}
|
|
7983
|
-
function createLogger(context2,
|
|
7983
|
+
function createLogger(context2, write2 = writeLog) {
|
|
7984
7984
|
return (entry) => {
|
|
7985
|
-
|
|
7985
|
+
write2(
|
|
7986
7986
|
JSON.stringify({
|
|
7987
7987
|
...entry,
|
|
7988
7988
|
...context2,
|
|
@@ -15420,19 +15420,29 @@ async function scanSourceOnce(config22, paths, signal, policy, accounts) {
|
|
|
15420
15420
|
},
|
|
15421
15421
|
paths
|
|
15422
15422
|
);
|
|
15423
|
-
const sessions = sessionFiles.filter((file) => file.session);
|
|
15424
15423
|
return {
|
|
15425
15424
|
discovered: events.length,
|
|
15426
15425
|
excludedRecords,
|
|
15427
15426
|
caughtUp,
|
|
15428
|
-
history:
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15432
|
-
|
|
15433
|
-
|
|
15427
|
+
history: historyProgress(sessionFiles, cursors)
|
|
15428
|
+
};
|
|
15429
|
+
}
|
|
15430
|
+
function historyProgress(files, cursors) {
|
|
15431
|
+
const sessions = files.filter((file) => file.session);
|
|
15432
|
+
return {
|
|
15433
|
+
sessions: sessions.length,
|
|
15434
|
+
readSessions: sessions.filter(
|
|
15435
|
+
(file) => (cursors[file.filename] ?? 0) >= file.size
|
|
15436
|
+
).length
|
|
15434
15437
|
};
|
|
15435
15438
|
}
|
|
15439
|
+
async function savedHistoryProgress(config22, paths) {
|
|
15440
|
+
const files = await sourceFilesNewestFirst(
|
|
15441
|
+
collectorSource(config22),
|
|
15442
|
+
path14.resolve(collectorSourceDirectory(config22))
|
|
15443
|
+
);
|
|
15444
|
+
return historyProgress(files, (await loadState(paths)).cursors);
|
|
15445
|
+
}
|
|
15436
15446
|
async function readRange(filename, start2, length) {
|
|
15437
15447
|
const handle = await fs9.open(filename, "r");
|
|
15438
15448
|
try {
|
|
@@ -15694,7 +15704,12 @@ async function collectorTick(config22, paths, fetcher = collectorFetch, signal,
|
|
|
15694
15704
|
policy,
|
|
15695
15705
|
first
|
|
15696
15706
|
);
|
|
15697
|
-
const scan = await outboxSize(paths) >= SCAN_PAUSE_OUTBOX_BYTES ? {
|
|
15707
|
+
const scan = await outboxSize(paths) >= SCAN_PAUSE_OUTBOX_BYTES ? {
|
|
15708
|
+
discovered: 0,
|
|
15709
|
+
excludedRecords: 0,
|
|
15710
|
+
caughtUp: false,
|
|
15711
|
+
history: await savedHistoryProgress(config22, paths)
|
|
15712
|
+
} : await scanSourceOnce(config22, paths, signal, policy, accounts);
|
|
15698
15713
|
if (policy !== void 0 && scan.caughtUp) {
|
|
15699
15714
|
const state = await loadState(paths);
|
|
15700
15715
|
if (state.captureRecheckAt === void 0)
|
|
@@ -16064,10 +16079,10 @@ function mergeDefs2(...defs) {
|
|
|
16064
16079
|
function cloneDef2(schema) {
|
|
16065
16080
|
return mergeDefs2(schema._zod.def);
|
|
16066
16081
|
}
|
|
16067
|
-
function getElementAtPath2(obj,
|
|
16068
|
-
if (!
|
|
16082
|
+
function getElementAtPath2(obj, path32) {
|
|
16083
|
+
if (!path32)
|
|
16069
16084
|
return obj;
|
|
16070
|
-
return
|
|
16085
|
+
return path32.reduce((acc, key) => acc?.[key], obj);
|
|
16071
16086
|
}
|
|
16072
16087
|
function promiseAllObject2(promisesObj) {
|
|
16073
16088
|
const keys = Object.keys(promisesObj);
|
|
@@ -16407,11 +16422,11 @@ function explicitlyAborted2(x, startIndex = 0) {
|
|
|
16407
16422
|
}
|
|
16408
16423
|
return false;
|
|
16409
16424
|
}
|
|
16410
|
-
function prefixIssues2(
|
|
16425
|
+
function prefixIssues2(path32, issues) {
|
|
16411
16426
|
return issues.map((iss) => {
|
|
16412
16427
|
var _a5;
|
|
16413
16428
|
(_a5 = iss).path ?? (_a5.path = []);
|
|
16414
|
-
iss.path.unshift(
|
|
16429
|
+
iss.path.unshift(path32);
|
|
16415
16430
|
return iss;
|
|
16416
16431
|
});
|
|
16417
16432
|
}
|
|
@@ -16869,16 +16884,16 @@ function flattenError2(error3, mapper = (issue3) => issue3.message) {
|
|
|
16869
16884
|
}
|
|
16870
16885
|
function formatError2(error3, mapper = (issue3) => issue3.message) {
|
|
16871
16886
|
const fieldErrors = { _errors: [] };
|
|
16872
|
-
const processError = (error4,
|
|
16887
|
+
const processError = (error4, path32 = []) => {
|
|
16873
16888
|
for (const issue3 of error4.issues) {
|
|
16874
16889
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
16875
|
-
issue3.errors.map((issues) => processError({ issues }, [...
|
|
16890
|
+
issue3.errors.map((issues) => processError({ issues }, [...path32, ...issue3.path]));
|
|
16876
16891
|
} else if (issue3.code === "invalid_key") {
|
|
16877
|
-
processError({ issues: issue3.issues }, [...
|
|
16892
|
+
processError({ issues: issue3.issues }, [...path32, ...issue3.path]);
|
|
16878
16893
|
} else if (issue3.code === "invalid_element") {
|
|
16879
|
-
processError({ issues: issue3.issues }, [...
|
|
16894
|
+
processError({ issues: issue3.issues }, [...path32, ...issue3.path]);
|
|
16880
16895
|
} else {
|
|
16881
|
-
const fullpath = [...
|
|
16896
|
+
const fullpath = [...path32, ...issue3.path];
|
|
16882
16897
|
if (fullpath.length === 0) {
|
|
16883
16898
|
fieldErrors._errors.push(mapper(issue3));
|
|
16884
16899
|
} else {
|
|
@@ -22535,131 +22550,11 @@ function isLaunchDirectory(value) {
|
|
|
22535
22550
|
return true;
|
|
22536
22551
|
}
|
|
22537
22552
|
|
|
22538
|
-
// src/
|
|
22539
|
-
import { createHmac } from "node:crypto";
|
|
22540
|
-
import { promises as fs19 } from "node:fs";
|
|
22541
|
-
import os8 from "node:os";
|
|
22542
|
-
import path24 from "node:path";
|
|
22543
|
-
|
|
22544
|
-
// ../collector-contracts/dist/index.js
|
|
22545
|
-
var cursorBillingRequestSchema = object3({
|
|
22546
|
-
conversationId: uuid5(),
|
|
22547
|
-
reconcileFromMs: number4().int().nonnegative().nullable(),
|
|
22548
|
-
events: array2(object3({
|
|
22549
|
-
timestamp: number4().int().nonnegative(),
|
|
22550
|
-
kind: _enum2([
|
|
22551
|
-
"included",
|
|
22552
|
-
"paid",
|
|
22553
|
-
"byok",
|
|
22554
|
-
"not_charged",
|
|
22555
|
-
"unknown"
|
|
22556
|
-
]),
|
|
22557
|
-
inputTokens: number4().int().nonnegative().nullable(),
|
|
22558
|
-
outputTokens: number4().int().nonnegative().nullable(),
|
|
22559
|
-
cacheReadTokens: number4().int().nonnegative().nullable(),
|
|
22560
|
-
cacheWriteTokens: number4().int().nonnegative().nullable(),
|
|
22561
|
-
paidUsd: number4().finite().nonnegative().nullable()
|
|
22562
|
-
}).strict()).max(5e3)
|
|
22563
|
-
}).strict();
|
|
22564
|
-
function codexCreditSign(value) {
|
|
22565
|
-
const mantissa = value.split(/[eE]/, 1)[0];
|
|
22566
|
-
if (!/[1-9]/.test(mantissa))
|
|
22567
|
-
return 0;
|
|
22568
|
-
return mantissa.startsWith("-") ? -1 : 1;
|
|
22569
|
-
}
|
|
22570
|
-
var codexBillingRequestSchema = object3({
|
|
22571
|
-
accountFingerprint: string5().regex(/^[0-9a-f]{64}$/),
|
|
22572
|
-
reconcile: boolean4(),
|
|
22573
|
-
tasks: array2(object3({
|
|
22574
|
-
threadId: uuid5(),
|
|
22575
|
-
createdAt: iso_exports2.datetime().nullable(),
|
|
22576
|
-
descendantThreadIds: array2(uuid5()).max(900),
|
|
22577
|
-
dataStatus: _enum2([
|
|
22578
|
-
"available",
|
|
22579
|
-
"partial",
|
|
22580
|
-
"unavailable",
|
|
22581
|
-
"not_queried"
|
|
22582
|
-
]),
|
|
22583
|
-
usageSource: string5().max(100),
|
|
22584
|
-
balanceUsageCredits: string5().regex(/^[+-]?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d{1,3})?$/).max(128).nullable()
|
|
22585
|
-
}).strict()).max(100),
|
|
22586
|
-
authTurns: array2(object3({
|
|
22587
|
-
threadId: uuid5(),
|
|
22588
|
-
turnId: uuid5(),
|
|
22589
|
-
mode: _enum2(["chatgpt", "api_key", "conflicting"])
|
|
22590
|
-
}).strict()).max(5e3)
|
|
22591
|
-
}).strict();
|
|
22592
|
-
var UUID_PATTERN3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
|
|
22593
|
-
var episodeCountSchema = number4().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
22594
|
-
var collectorFrictionSummarySchema = object3({
|
|
22595
|
-
weekEpisodes: episodeCountSchema,
|
|
22596
|
-
dayEpisodes: episodeCountSchema
|
|
22597
|
-
}).strict().refine((summary) => summary.dayEpisodes <= summary.weekEpisodes, "The last day cannot have more friction episodes than the last week.").describe("dayEpisodes must not exceed weekEpisodes.");
|
|
22598
|
-
var RECENT_MESSAGE_LIMIT = 400;
|
|
22599
|
-
var sessionCountSchema = number4().int().min(0).max(1e6);
|
|
22600
|
-
var collectorHistoryProgressSchema = object3({
|
|
22601
|
-
sessions: sessionCountSchema,
|
|
22602
|
-
readSessions: sessionCountSchema,
|
|
22603
|
-
complete: boolean4(),
|
|
22604
|
-
recentMessages: object3({
|
|
22605
|
-
sent: number4().int().min(0).max(RECENT_MESSAGE_LIMIT),
|
|
22606
|
-
complete: boolean4()
|
|
22607
|
-
}).strict().optional().describe("The newest messages sent ahead of the rest of the history; collectors before 0.17.0 omit it.")
|
|
22608
|
-
}).strict().refine((progress) => progress.readSessions <= progress.sessions, "Read sessions cannot exceed listed sessions.").refine((progress) => !progress.complete || progress.readSessions === progress.sessions, "A complete import has read every listed session.").describe("readSessions must not exceed sessions; complete requires equal counts.");
|
|
22609
|
-
var collectorEnrollmentRequestSchema = object3({
|
|
22610
|
-
deviceName: string5().trim().min(1).max(160).describe("Trimmed before length validation."),
|
|
22611
|
-
organizationId: string5().regex(UUID_PATTERN3).optional(),
|
|
22612
|
-
source: _enum2(COLLECTOR_SOURCES2).optional()
|
|
22613
|
-
}).strict();
|
|
22614
|
-
var collectorExpansionRequestSchema = object3({
|
|
22615
|
-
source: _enum2(COLLECTOR_SOURCES2),
|
|
22616
|
-
token: string5().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
22617
|
-
organizationId: string5().regex(UUID_PATTERN3).optional()
|
|
22618
|
-
}).strict();
|
|
22619
|
-
var collectorEnrollmentResponseSchema = discriminatedUnion2("status", [
|
|
22620
|
-
object3({
|
|
22621
|
-
status: literal2("enrolled"),
|
|
22622
|
-
token: string5().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
22623
|
-
deviceId: string5().regex(UUID_PATTERN3),
|
|
22624
|
-
organizationId: string5().regex(UUID_PATTERN3),
|
|
22625
|
-
organizationName: string5().min(1).max(160)
|
|
22626
|
-
}).strict(),
|
|
22627
|
-
object3({
|
|
22628
|
-
status: literal2("choose_organization"),
|
|
22629
|
-
organizations: array2(object3({
|
|
22630
|
-
id: string5().regex(UUID_PATTERN3),
|
|
22631
|
-
name: string5().min(1).max(160)
|
|
22632
|
-
}).strict()).max(20),
|
|
22633
|
-
hasMore: boolean4()
|
|
22634
|
-
}).strict()
|
|
22635
|
-
]);
|
|
22636
|
-
function parseCollectorEnrollmentResponse(input) {
|
|
22637
|
-
const parsed = collectorEnrollmentResponseSchema.safeParse(input);
|
|
22638
|
-
return parsed.success ? { success: true, value: parsed.data } : {
|
|
22639
|
-
success: false,
|
|
22640
|
-
error: parsed.error.issues[0]?.message ?? "Collector enrollment response is invalid."
|
|
22641
|
-
};
|
|
22642
|
-
}
|
|
22643
|
-
function parseCollectorFrictionSummary(input) {
|
|
22644
|
-
const parsed = collectorFrictionSummarySchema.safeParse(input);
|
|
22645
|
-
return parsed.success ? { success: true, value: parsed.data } : {
|
|
22646
|
-
success: false,
|
|
22647
|
-
error: parsed.error.issues[0]?.message ?? "Friction summary is invalid."
|
|
22648
|
-
};
|
|
22649
|
-
}
|
|
22650
|
-
|
|
22651
|
-
// src/background-service.ts
|
|
22652
|
-
import { promises as fs16 } from "node:fs";
|
|
22653
|
-
import os6 from "node:os";
|
|
22654
|
-
import path20 from "node:path";
|
|
22655
|
-
|
|
22656
|
-
// src/launch-agent.ts
|
|
22657
|
-
import { execFile as execFileCallback2 } from "node:child_process";
|
|
22553
|
+
// src/agent-tools.ts
|
|
22658
22554
|
import { promises as fs11 } from "node:fs";
|
|
22659
22555
|
import os3 from "node:os";
|
|
22660
22556
|
import path8 from "node:path";
|
|
22661
|
-
import
|
|
22662
|
-
import { promisify as promisify2 } from "node:util";
|
|
22557
|
+
import readline from "node:readline";
|
|
22663
22558
|
|
|
22664
22559
|
// src/runtime.ts
|
|
22665
22560
|
import { createHash as createHash4 } from "node:crypto";
|
|
@@ -23063,7 +22958,351 @@ async function stableNodePath() {
|
|
|
23063
22958
|
return process.execPath;
|
|
23064
22959
|
}
|
|
23065
22960
|
|
|
22961
|
+
// src/agent-tools.ts
|
|
22962
|
+
var SERVER_NAME = "iteration";
|
|
22963
|
+
var RENEW_BEFORE_MS = 5 * 60 * 1e3;
|
|
22964
|
+
var accessSchema = object3({
|
|
22965
|
+
url: url(),
|
|
22966
|
+
token: string5().min(1),
|
|
22967
|
+
expiresAt: iso_exports2.datetime()
|
|
22968
|
+
});
|
|
22969
|
+
var versioned = object3({ protocolVersion: string5().optional() }).loose().optional();
|
|
22970
|
+
var messageSchema = object3({
|
|
22971
|
+
id: union2([string5(), number4()]).optional(),
|
|
22972
|
+
method: string5().optional(),
|
|
22973
|
+
params: versioned,
|
|
22974
|
+
result: versioned
|
|
22975
|
+
}).loose();
|
|
22976
|
+
function write(message) {
|
|
22977
|
+
process.stdout.write(`${JSON.stringify(message)}
|
|
22978
|
+
`);
|
|
22979
|
+
}
|
|
22980
|
+
async function serveAgentTools(config3) {
|
|
22981
|
+
let access = null;
|
|
22982
|
+
let version3;
|
|
22983
|
+
let renewing = null;
|
|
22984
|
+
const fetchAccess = async () => {
|
|
22985
|
+
if (config3 === null)
|
|
22986
|
+
throw new Error(
|
|
22987
|
+
"This computer is not connected to Iteration. Run iteration connect."
|
|
22988
|
+
);
|
|
22989
|
+
const response = await collectorFetch(
|
|
22990
|
+
new URL("./tool-access", validateCollectorEndpoint(config3.endpoint)),
|
|
22991
|
+
{
|
|
22992
|
+
method: "POST",
|
|
22993
|
+
headers: { Authorization: `Bearer ${config3.token}` },
|
|
22994
|
+
signal: AbortSignal.timeout(15e3)
|
|
22995
|
+
}
|
|
22996
|
+
);
|
|
22997
|
+
const payload = await response.json().catch(() => null);
|
|
22998
|
+
if (!response.ok) {
|
|
22999
|
+
const error3 = object3({ error: string5() }).safeParse(payload);
|
|
23000
|
+
throw new Error(
|
|
23001
|
+
`Iteration's tools are unavailable: ${error3.success ? error3.data.error : `HTTP ${response.status}`}`
|
|
23002
|
+
);
|
|
23003
|
+
}
|
|
23004
|
+
const parsed = accessSchema.parse(payload);
|
|
23005
|
+
access = { ...parsed, expiresAt: Date.parse(parsed.expiresAt) };
|
|
23006
|
+
return access;
|
|
23007
|
+
};
|
|
23008
|
+
const renew = (force) => {
|
|
23009
|
+
if (!force && access !== null && access.expiresAt - Date.now() > RENEW_BEFORE_MS)
|
|
23010
|
+
return Promise.resolve(access);
|
|
23011
|
+
renewing ??= fetchAccess().finally(() => {
|
|
23012
|
+
renewing = null;
|
|
23013
|
+
});
|
|
23014
|
+
return renewing;
|
|
23015
|
+
};
|
|
23016
|
+
const post = async (body, method, force) => {
|
|
23017
|
+
const current = await renew(force);
|
|
23018
|
+
return fetch(current.url, {
|
|
23019
|
+
method: "POST",
|
|
23020
|
+
headers: {
|
|
23021
|
+
Authorization: `Bearer ${current.token}`,
|
|
23022
|
+
"Content-Type": "application/json",
|
|
23023
|
+
Accept: "application/json, text/event-stream",
|
|
23024
|
+
...version3 !== void 0 && method !== "initialize" ? { "MCP-Protocol-Version": version3 } : {},
|
|
23025
|
+
...method === void 0 ? {} : { "MCP-Method": method }
|
|
23026
|
+
},
|
|
23027
|
+
body,
|
|
23028
|
+
signal: AbortSignal.timeout(31e4)
|
|
23029
|
+
});
|
|
23030
|
+
};
|
|
23031
|
+
const relay = (text) => {
|
|
23032
|
+
const message = messageSchema.safeParse(JSON.parse(text));
|
|
23033
|
+
const negotiated = message.success ? message.data.result?.protocolVersion : void 0;
|
|
23034
|
+
if (negotiated !== void 0) version3 = negotiated;
|
|
23035
|
+
write(JSON.parse(text));
|
|
23036
|
+
};
|
|
23037
|
+
const forward = async (line) => {
|
|
23038
|
+
const message = messageSchema.parse(JSON.parse(line));
|
|
23039
|
+
if (message.method === "initialize")
|
|
23040
|
+
version3 = message.params?.protocolVersion ?? version3;
|
|
23041
|
+
try {
|
|
23042
|
+
let response = await post(line, message.method, false);
|
|
23043
|
+
if (response.status === 401)
|
|
23044
|
+
response = await post(line, message.method, true);
|
|
23045
|
+
if (response.status === 202 || message.id === void 0) return;
|
|
23046
|
+
const type = response.headers.get("content-type") ?? "";
|
|
23047
|
+
if (type.includes("text/event-stream")) {
|
|
23048
|
+
const text2 = await response.text();
|
|
23049
|
+
for (const event3 of text2.split(/\r?\n\r?\n/)) {
|
|
23050
|
+
const data = event3.split(/\r?\n/).filter((row) => row.startsWith("data:")).map((row) => row.slice(5).trimStart()).join("\n");
|
|
23051
|
+
if (data.trim()) relay(data);
|
|
23052
|
+
}
|
|
23053
|
+
return;
|
|
23054
|
+
}
|
|
23055
|
+
const text = await response.text();
|
|
23056
|
+
if (text.trim()) relay(text);
|
|
23057
|
+
else if (!response.ok)
|
|
23058
|
+
throw new Error(`Iteration's tools answered HTTP ${response.status}.`);
|
|
23059
|
+
} catch (error3) {
|
|
23060
|
+
if (message.id === void 0) return;
|
|
23061
|
+
write({
|
|
23062
|
+
jsonrpc: "2.0",
|
|
23063
|
+
id: message.id,
|
|
23064
|
+
error: {
|
|
23065
|
+
code: -32603,
|
|
23066
|
+
message: error3 instanceof Error ? error3.message : "Iteration's tools are unavailable."
|
|
23067
|
+
}
|
|
23068
|
+
});
|
|
23069
|
+
}
|
|
23070
|
+
};
|
|
23071
|
+
const pending = /* @__PURE__ */ new Set();
|
|
23072
|
+
for await (const line of readline.createInterface({
|
|
23073
|
+
input: process.stdin
|
|
23074
|
+
})) {
|
|
23075
|
+
if (!line.trim()) continue;
|
|
23076
|
+
const task = forward(line).catch(() => void 0);
|
|
23077
|
+
pending.add(task);
|
|
23078
|
+
void task.finally(() => pending.delete(task));
|
|
23079
|
+
}
|
|
23080
|
+
await Promise.allSettled(pending);
|
|
23081
|
+
}
|
|
23082
|
+
async function writeAtomically(filename, content) {
|
|
23083
|
+
await fs11.mkdir(path8.dirname(filename), { recursive: true });
|
|
23084
|
+
const mode = await fs11.stat(filename).then((stat) => stat.mode & 511).catch(() => 384);
|
|
23085
|
+
const temporary = `${filename}.${process.pid}.${Date.now()}.tmp`;
|
|
23086
|
+
await fs11.writeFile(temporary, content, { mode });
|
|
23087
|
+
await fs11.rename(temporary, filename);
|
|
23088
|
+
}
|
|
23089
|
+
async function readText2(filename) {
|
|
23090
|
+
try {
|
|
23091
|
+
return await fs11.readFile(filename, "utf8");
|
|
23092
|
+
} catch (error3) {
|
|
23093
|
+
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
23094
|
+
return null;
|
|
23095
|
+
throw error3;
|
|
23096
|
+
}
|
|
23097
|
+
}
|
|
23098
|
+
var jsonServersSchema = object3({
|
|
23099
|
+
mcpServers: record3(string5(), unknown2()).optional()
|
|
23100
|
+
}).loose();
|
|
23101
|
+
async function updateJsonServers(filename, server) {
|
|
23102
|
+
const text = await readText2(filename);
|
|
23103
|
+
if (text === null && server === null) return;
|
|
23104
|
+
let parsed;
|
|
23105
|
+
try {
|
|
23106
|
+
parsed = jsonServersSchema.parse(text === null ? {} : JSON.parse(text));
|
|
23107
|
+
} catch (error3) {
|
|
23108
|
+
throw new Error(`Could not read MCP settings at ${filename}.`, {
|
|
23109
|
+
cause: error3
|
|
23110
|
+
});
|
|
23111
|
+
}
|
|
23112
|
+
const { [SERVER_NAME]: existing, ...others } = parsed.mcpServers ?? {};
|
|
23113
|
+
if (server === null && existing === void 0) return;
|
|
23114
|
+
if (server !== null && JSON.stringify(existing) === JSON.stringify(server))
|
|
23115
|
+
return;
|
|
23116
|
+
const mcpServers = server === null ? others : { ...others, [SERVER_NAME]: server };
|
|
23117
|
+
await writeAtomically(
|
|
23118
|
+
filename,
|
|
23119
|
+
`${JSON.stringify({ ...parsed, mcpServers }, null, 2)}
|
|
23120
|
+
`
|
|
23121
|
+
);
|
|
23122
|
+
}
|
|
23123
|
+
var CODEX_TABLE = `[mcp_servers.${SERVER_NAME}]`;
|
|
23124
|
+
function withoutCodexServer(text) {
|
|
23125
|
+
const lines = text.split(/\r?\n/);
|
|
23126
|
+
const kept = [];
|
|
23127
|
+
let skipping = false;
|
|
23128
|
+
for (const line of lines) {
|
|
23129
|
+
const table = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/.exec(line)?.[1]?.trim();
|
|
23130
|
+
if (table !== void 0)
|
|
23131
|
+
skipping = table === `mcp_servers.${SERVER_NAME}` || table.startsWith(`mcp_servers.${SERVER_NAME}.`);
|
|
23132
|
+
if (!skipping) kept.push(line);
|
|
23133
|
+
}
|
|
23134
|
+
return kept.join("\n").replace(/\n{3,}$/, "\n\n");
|
|
23135
|
+
}
|
|
23136
|
+
async function updateCodexServer(filename, command) {
|
|
23137
|
+
const text = await readText2(filename);
|
|
23138
|
+
if (text === null && command === null) return;
|
|
23139
|
+
const base = withoutCodexServer(text ?? "");
|
|
23140
|
+
const [program, ...args] = command ?? [];
|
|
23141
|
+
const next = command === null ? base : `${base.trimEnd()}${base.trim() ? "\n\n" : ""}${CODEX_TABLE}
|
|
23142
|
+
command = ${JSON.stringify(program)}
|
|
23143
|
+
args = ${JSON.stringify(args)}
|
|
23144
|
+
`;
|
|
23145
|
+
if (next === text) return;
|
|
23146
|
+
await writeAtomically(filename, next);
|
|
23147
|
+
}
|
|
23148
|
+
function claudeSettingsFile(claudeHome) {
|
|
23149
|
+
return path8.resolve(claudeHome) === path8.join(os3.homedir(), ".claude") ? path8.join(os3.homedir(), ".claude.json") : path8.join(claudeHome, ".claude.json");
|
|
23150
|
+
}
|
|
23151
|
+
var cursorSettingsFile = () => path8.join(os3.homedir(), ".cursor", "mcp.json");
|
|
23152
|
+
async function installAgentTools(homes) {
|
|
23153
|
+
const command = [
|
|
23154
|
+
await stableNodePath(),
|
|
23155
|
+
runtimePaths().launcher,
|
|
23156
|
+
"mcp"
|
|
23157
|
+
];
|
|
23158
|
+
const [program, ...args] = command;
|
|
23159
|
+
if (homes.claude !== void 0)
|
|
23160
|
+
await updateJsonServers(claudeSettingsFile(homes.claude), {
|
|
23161
|
+
type: "stdio",
|
|
23162
|
+
command: program,
|
|
23163
|
+
args
|
|
23164
|
+
});
|
|
23165
|
+
if (homes.codex !== void 0)
|
|
23166
|
+
await updateCodexServer(path8.join(homes.codex, "config.toml"), command);
|
|
23167
|
+
if (homes.cursor)
|
|
23168
|
+
await updateJsonServers(cursorSettingsFile(), { command: program, args });
|
|
23169
|
+
}
|
|
23170
|
+
async function uninstallAgentTools(homes) {
|
|
23171
|
+
if (homes.claude !== void 0)
|
|
23172
|
+
await updateJsonServers(claudeSettingsFile(homes.claude), null);
|
|
23173
|
+
if (homes.codex !== void 0)
|
|
23174
|
+
await updateCodexServer(path8.join(homes.codex, "config.toml"), null);
|
|
23175
|
+
if (homes.cursor) await updateJsonServers(cursorSettingsFile(), null);
|
|
23176
|
+
}
|
|
23177
|
+
function agentHomes(config3) {
|
|
23178
|
+
return "cursorHome" in config3 ? { cursor: true } : "claudeHome" in config3 ? { claude: config3.claudeHome } : { codex: config3.codexHome };
|
|
23179
|
+
}
|
|
23180
|
+
|
|
23181
|
+
// src/auto-connect.ts
|
|
23182
|
+
import { createHmac } from "node:crypto";
|
|
23183
|
+
import { promises as fs20 } from "node:fs";
|
|
23184
|
+
import os9 from "node:os";
|
|
23185
|
+
import path25 from "node:path";
|
|
23186
|
+
|
|
23187
|
+
// ../collector-contracts/dist/index.js
|
|
23188
|
+
var cursorBillingRequestSchema = object3({
|
|
23189
|
+
conversationId: uuid5(),
|
|
23190
|
+
reconcileFromMs: number4().int().nonnegative().nullable(),
|
|
23191
|
+
events: array2(object3({
|
|
23192
|
+
timestamp: number4().int().nonnegative(),
|
|
23193
|
+
kind: _enum2([
|
|
23194
|
+
"included",
|
|
23195
|
+
"paid",
|
|
23196
|
+
"byok",
|
|
23197
|
+
"not_charged",
|
|
23198
|
+
"unknown"
|
|
23199
|
+
]),
|
|
23200
|
+
inputTokens: number4().int().nonnegative().nullable(),
|
|
23201
|
+
outputTokens: number4().int().nonnegative().nullable(),
|
|
23202
|
+
cacheReadTokens: number4().int().nonnegative().nullable(),
|
|
23203
|
+
cacheWriteTokens: number4().int().nonnegative().nullable(),
|
|
23204
|
+
paidUsd: number4().finite().nonnegative().nullable()
|
|
23205
|
+
}).strict()).max(5e3)
|
|
23206
|
+
}).strict();
|
|
23207
|
+
function codexCreditSign(value) {
|
|
23208
|
+
const mantissa = value.split(/[eE]/, 1)[0];
|
|
23209
|
+
if (!/[1-9]/.test(mantissa))
|
|
23210
|
+
return 0;
|
|
23211
|
+
return mantissa.startsWith("-") ? -1 : 1;
|
|
23212
|
+
}
|
|
23213
|
+
var codexBillingRequestSchema = object3({
|
|
23214
|
+
accountFingerprint: string5().regex(/^[0-9a-f]{64}$/),
|
|
23215
|
+
reconcile: boolean4(),
|
|
23216
|
+
tasks: array2(object3({
|
|
23217
|
+
threadId: uuid5(),
|
|
23218
|
+
createdAt: iso_exports2.datetime().nullable(),
|
|
23219
|
+
descendantThreadIds: array2(uuid5()).max(900),
|
|
23220
|
+
dataStatus: _enum2([
|
|
23221
|
+
"available",
|
|
23222
|
+
"partial",
|
|
23223
|
+
"unavailable",
|
|
23224
|
+
"not_queried"
|
|
23225
|
+
]),
|
|
23226
|
+
usageSource: string5().max(100),
|
|
23227
|
+
balanceUsageCredits: string5().regex(/^[+-]?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d{1,3})?$/).max(128).nullable()
|
|
23228
|
+
}).strict()).max(100),
|
|
23229
|
+
authTurns: array2(object3({
|
|
23230
|
+
threadId: uuid5(),
|
|
23231
|
+
turnId: uuid5(),
|
|
23232
|
+
mode: _enum2(["chatgpt", "api_key", "conflicting"])
|
|
23233
|
+
}).strict()).max(5e3)
|
|
23234
|
+
}).strict();
|
|
23235
|
+
var UUID_PATTERN3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
|
|
23236
|
+
var episodeCountSchema = number4().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
23237
|
+
var collectorFrictionSummarySchema = object3({
|
|
23238
|
+
weekEpisodes: episodeCountSchema,
|
|
23239
|
+
dayEpisodes: episodeCountSchema
|
|
23240
|
+
}).strict().refine((summary) => summary.dayEpisodes <= summary.weekEpisodes, "The last day cannot have more friction episodes than the last week.").describe("dayEpisodes must not exceed weekEpisodes.");
|
|
23241
|
+
var RECENT_MESSAGE_LIMIT = 400;
|
|
23242
|
+
var sessionCountSchema = number4().int().min(0).max(1e6);
|
|
23243
|
+
var collectorHistoryProgressSchema = object3({
|
|
23244
|
+
sessions: sessionCountSchema,
|
|
23245
|
+
readSessions: sessionCountSchema,
|
|
23246
|
+
complete: boolean4(),
|
|
23247
|
+
recentMessages: object3({
|
|
23248
|
+
sent: number4().int().min(0).max(RECENT_MESSAGE_LIMIT),
|
|
23249
|
+
complete: boolean4()
|
|
23250
|
+
}).strict().optional().describe("The newest messages sent ahead of the rest of the history; collectors before 0.17.0 omit it.")
|
|
23251
|
+
}).strict().refine((progress) => progress.readSessions <= progress.sessions, "Read sessions cannot exceed listed sessions.").refine((progress) => !progress.complete || progress.readSessions === progress.sessions, "A complete import has read every listed session.").describe("readSessions must not exceed sessions; complete requires equal counts.");
|
|
23252
|
+
var collectorEnrollmentRequestSchema = object3({
|
|
23253
|
+
deviceName: string5().trim().min(1).max(160).describe("Trimmed before length validation."),
|
|
23254
|
+
organizationId: string5().regex(UUID_PATTERN3).optional(),
|
|
23255
|
+
source: _enum2(COLLECTOR_SOURCES2).optional()
|
|
23256
|
+
}).strict();
|
|
23257
|
+
var collectorExpansionRequestSchema = object3({
|
|
23258
|
+
source: _enum2(COLLECTOR_SOURCES2),
|
|
23259
|
+
token: string5().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
23260
|
+
organizationId: string5().regex(UUID_PATTERN3).optional()
|
|
23261
|
+
}).strict();
|
|
23262
|
+
var collectorEnrollmentResponseSchema = discriminatedUnion2("status", [
|
|
23263
|
+
object3({
|
|
23264
|
+
status: literal2("enrolled"),
|
|
23265
|
+
token: string5().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
23266
|
+
deviceId: string5().regex(UUID_PATTERN3),
|
|
23267
|
+
organizationId: string5().regex(UUID_PATTERN3),
|
|
23268
|
+
organizationName: string5().min(1).max(160)
|
|
23269
|
+
}).strict(),
|
|
23270
|
+
object3({
|
|
23271
|
+
status: literal2("choose_organization"),
|
|
23272
|
+
organizations: array2(object3({
|
|
23273
|
+
id: string5().regex(UUID_PATTERN3),
|
|
23274
|
+
name: string5().min(1).max(160)
|
|
23275
|
+
}).strict()).max(20),
|
|
23276
|
+
hasMore: boolean4()
|
|
23277
|
+
}).strict()
|
|
23278
|
+
]);
|
|
23279
|
+
function parseCollectorEnrollmentResponse(input) {
|
|
23280
|
+
const parsed = collectorEnrollmentResponseSchema.safeParse(input);
|
|
23281
|
+
return parsed.success ? { success: true, value: parsed.data } : {
|
|
23282
|
+
success: false,
|
|
23283
|
+
error: parsed.error.issues[0]?.message ?? "Collector enrollment response is invalid."
|
|
23284
|
+
};
|
|
23285
|
+
}
|
|
23286
|
+
function parseCollectorFrictionSummary(input) {
|
|
23287
|
+
const parsed = collectorFrictionSummarySchema.safeParse(input);
|
|
23288
|
+
return parsed.success ? { success: true, value: parsed.data } : {
|
|
23289
|
+
success: false,
|
|
23290
|
+
error: parsed.error.issues[0]?.message ?? "Friction summary is invalid."
|
|
23291
|
+
};
|
|
23292
|
+
}
|
|
23293
|
+
|
|
23294
|
+
// src/background-service.ts
|
|
23295
|
+
import { promises as fs17 } from "node:fs";
|
|
23296
|
+
import os7 from "node:os";
|
|
23297
|
+
import path21 from "node:path";
|
|
23298
|
+
|
|
23066
23299
|
// src/launch-agent.ts
|
|
23300
|
+
import { execFile as execFileCallback2 } from "node:child_process";
|
|
23301
|
+
import { promises as fs12 } from "node:fs";
|
|
23302
|
+
import os4 from "node:os";
|
|
23303
|
+
import path17 from "node:path";
|
|
23304
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
23305
|
+
import { promisify as promisify2 } from "node:util";
|
|
23067
23306
|
var execFile2 = promisify2(execFileCallback2);
|
|
23068
23307
|
function label(source) {
|
|
23069
23308
|
return `com.iteration.${source}-collector`;
|
|
@@ -23074,16 +23313,16 @@ var RESTART_POLL_MS = 200;
|
|
|
23074
23313
|
function xml(value) {
|
|
23075
23314
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23076
23315
|
}
|
|
23077
|
-
function plistPath(source, homeDirectory =
|
|
23078
|
-
return
|
|
23316
|
+
function plistPath(source, homeDirectory = os4.homedir()) {
|
|
23317
|
+
return path17.join(
|
|
23079
23318
|
homeDirectory,
|
|
23080
23319
|
"Library",
|
|
23081
23320
|
"LaunchAgents",
|
|
23082
23321
|
`${label(source)}.plist`
|
|
23083
23322
|
);
|
|
23084
23323
|
}
|
|
23085
|
-
function launchAgentPlist(launcherPath = runtimePaths().launcher, nodePath = process.execPath, logDirectory =
|
|
23086
|
-
|
|
23324
|
+
function launchAgentPlist(launcherPath = runtimePaths().launcher, nodePath = process.execPath, logDirectory = path17.join(os4.homedir(), "Library", "Logs"), dataDirectory2 = path17.join(
|
|
23325
|
+
os4.homedir(),
|
|
23087
23326
|
".config",
|
|
23088
23327
|
"iteration",
|
|
23089
23328
|
"codex-collector"
|
|
@@ -23106,8 +23345,8 @@ function launchAgentPlist(launcherPath = runtimePaths().launcher, nodePath = pro
|
|
|
23106
23345
|
"<key>RunAtLoad</key><true/>",
|
|
23107
23346
|
"<key>KeepAlive</key><true/>",
|
|
23108
23347
|
"<key>ThrottleInterval</key><integer>10</integer>",
|
|
23109
|
-
`<key>StandardOutPath</key><string>${xml(
|
|
23110
|
-
`<key>StandardErrorPath</key><string>${xml(
|
|
23348
|
+
`<key>StandardOutPath</key><string>${xml(path17.join(logDirectory, `iteration-${source}-collector.log`))}</string>`,
|
|
23349
|
+
`<key>StandardErrorPath</key><string>${xml(path17.join(logDirectory, `iteration-${source}-collector.error.log`))}</string>`,
|
|
23111
23350
|
"</dict></plist>"
|
|
23112
23351
|
].join("");
|
|
23113
23352
|
}
|
|
@@ -23187,17 +23426,17 @@ async function installLaunchAgent(dataDirectory2, source = "codex") {
|
|
|
23187
23426
|
throw new Error("Automatic startup is currently supported on macOS only.");
|
|
23188
23427
|
}
|
|
23189
23428
|
const file = plistPath(source);
|
|
23190
|
-
const launchAgents =
|
|
23191
|
-
const logs =
|
|
23192
|
-
await
|
|
23193
|
-
await
|
|
23194
|
-
await
|
|
23429
|
+
const launchAgents = path17.dirname(file);
|
|
23430
|
+
const logs = path17.join(os4.homedir(), "Library", "Logs");
|
|
23431
|
+
await fs12.mkdir(launchAgents, { recursive: true, mode: 493 });
|
|
23432
|
+
await fs12.mkdir(logs, { recursive: true, mode: 493 });
|
|
23433
|
+
await fs12.writeFile(
|
|
23195
23434
|
file,
|
|
23196
23435
|
launchAgentPlist(
|
|
23197
23436
|
void 0,
|
|
23198
23437
|
await stableNodePath(),
|
|
23199
23438
|
void 0,
|
|
23200
|
-
dataDirectory2 ??
|
|
23439
|
+
dataDirectory2 ?? path17.join(os4.homedir(), ".config", "iteration", `${source}-collector`),
|
|
23201
23440
|
source
|
|
23202
23441
|
),
|
|
23203
23442
|
{ encoding: "utf8", mode: 420 }
|
|
@@ -23229,7 +23468,7 @@ async function uninstallLaunchAgent(source = "codex") {
|
|
|
23229
23468
|
}
|
|
23230
23469
|
const file = plistPath(source);
|
|
23231
23470
|
await bootoutIfLoaded(launchctlTarget(), source);
|
|
23232
|
-
await
|
|
23471
|
+
await fs12.rm(file, { force: true });
|
|
23233
23472
|
}
|
|
23234
23473
|
async function launchAgentStatus(source = "codex") {
|
|
23235
23474
|
if (process.platform !== "darwin") return false;
|
|
@@ -23250,21 +23489,21 @@ function launchAgentRunning(output) {
|
|
|
23250
23489
|
|
|
23251
23490
|
// src/runtime-install.ts
|
|
23252
23491
|
import { execFile as execFileCallback4 } from "node:child_process";
|
|
23253
|
-
import { promises as
|
|
23492
|
+
import { promises as fs14 } from "node:fs";
|
|
23254
23493
|
import { promisify as promisify4 } from "node:util";
|
|
23255
23494
|
|
|
23256
23495
|
// src/updater.ts
|
|
23257
23496
|
import { execFile as execFileCallback3 } from "node:child_process";
|
|
23258
23497
|
import { createHash as createHash5 } from "node:crypto";
|
|
23259
|
-
import { createWriteStream as createWriteStream2, promises as
|
|
23498
|
+
import { createWriteStream as createWriteStream2, promises as fs13 } from "node:fs";
|
|
23260
23499
|
import http from "node:http";
|
|
23261
23500
|
import https2 from "node:https";
|
|
23262
|
-
import
|
|
23501
|
+
import path18 from "node:path";
|
|
23263
23502
|
import { Transform } from "node:stream";
|
|
23264
23503
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
23265
23504
|
import { promisify as promisify3 } from "node:util";
|
|
23266
23505
|
var execFile3 = promisify3(execFileCallback3);
|
|
23267
|
-
var TAR = process.platform === "win32" ?
|
|
23506
|
+
var TAR = process.platform === "win32" ? path18.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe") : "tar";
|
|
23268
23507
|
var PACKAGE_NAME = "iteration-cli";
|
|
23269
23508
|
var MAX_METADATA_BYTES = 16 * 1024 * 1024;
|
|
23270
23509
|
var MAX_TARBALL_BYTES = 64 * 1024 * 1024;
|
|
@@ -23468,32 +23707,32 @@ async function selfCheck(paths, cliPath, version3) {
|
|
|
23468
23707
|
}
|
|
23469
23708
|
async function installCandidate(paths, candidate, signal) {
|
|
23470
23709
|
await ensureRuntimeDirectory(paths);
|
|
23471
|
-
const staged = await
|
|
23472
|
-
|
|
23710
|
+
const staged = await fs13.mkdtemp(
|
|
23711
|
+
path18.join(paths.staging, `download-${candidate.version}-`)
|
|
23473
23712
|
);
|
|
23474
23713
|
try {
|
|
23475
|
-
const archive =
|
|
23714
|
+
const archive = path18.join(staged, "package.tgz");
|
|
23476
23715
|
await downloadVerified(
|
|
23477
23716
|
candidate.tarball,
|
|
23478
23717
|
candidate.integrity,
|
|
23479
23718
|
archive,
|
|
23480
23719
|
signal
|
|
23481
23720
|
);
|
|
23482
|
-
const extracted =
|
|
23483
|
-
await
|
|
23721
|
+
const extracted = path18.join(staged, "extracted");
|
|
23722
|
+
await fs13.mkdir(extracted, { mode: 448 });
|
|
23484
23723
|
await execFile3(TAR, ["-xzf", archive, "-C", extracted], {
|
|
23485
23724
|
timeout: REQUEST_TIMEOUT_MS,
|
|
23486
23725
|
windowsHide: true
|
|
23487
23726
|
});
|
|
23488
|
-
const packageRoot =
|
|
23727
|
+
const packageRoot = path18.join(extracted, "package");
|
|
23489
23728
|
await selfCheck(
|
|
23490
23729
|
paths,
|
|
23491
|
-
|
|
23730
|
+
path18.join(packageRoot, "dist", "cli.js"),
|
|
23492
23731
|
candidate.version
|
|
23493
23732
|
);
|
|
23494
23733
|
await installVersionDirectory(paths, packageRoot, candidate.version);
|
|
23495
23734
|
} finally {
|
|
23496
|
-
await
|
|
23735
|
+
await fs13.rm(staged, { recursive: true, force: true });
|
|
23497
23736
|
}
|
|
23498
23737
|
}
|
|
23499
23738
|
async function switchVersion(paths, from, version3, previous, expected, nowMs) {
|
|
@@ -23601,7 +23840,7 @@ async function ownVersion() {
|
|
|
23601
23840
|
}
|
|
23602
23841
|
async function exists(filename) {
|
|
23603
23842
|
try {
|
|
23604
|
-
await
|
|
23843
|
+
await fs14.access(filename);
|
|
23605
23844
|
return true;
|
|
23606
23845
|
} catch (error3) {
|
|
23607
23846
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
@@ -23628,7 +23867,7 @@ async function installLauncher(paths, version3) {
|
|
|
23628
23867
|
);
|
|
23629
23868
|
await commitLauncher(paths, staged);
|
|
23630
23869
|
} finally {
|
|
23631
|
-
await
|
|
23870
|
+
await fs14.rm(staged, { force: true });
|
|
23632
23871
|
}
|
|
23633
23872
|
}
|
|
23634
23873
|
async function ensureRuntimeInstalled(expected, paths = runtimePaths()) {
|
|
@@ -23710,9 +23949,9 @@ async function expireRuntimeTrial(nowMs, paths = runtimePaths()) {
|
|
|
23710
23949
|
|
|
23711
23950
|
// src/systemd-user.ts
|
|
23712
23951
|
import { execFile as execFileCallback5 } from "node:child_process";
|
|
23713
|
-
import { promises as
|
|
23714
|
-
import
|
|
23715
|
-
import
|
|
23952
|
+
import { promises as fs15 } from "node:fs";
|
|
23953
|
+
import os5 from "node:os";
|
|
23954
|
+
import path19 from "node:path";
|
|
23716
23955
|
import { promisify as promisify5 } from "node:util";
|
|
23717
23956
|
var execFile5 = promisify5(execFileCallback5);
|
|
23718
23957
|
var SYSTEMCTL_TIMEOUT_MS = 1e4;
|
|
@@ -23782,8 +24021,8 @@ function unitName(source) {
|
|
|
23782
24021
|
return `iteration-${source}-collector.service`;
|
|
23783
24022
|
}
|
|
23784
24023
|
function unitPath(source) {
|
|
23785
|
-
return
|
|
23786
|
-
|
|
24024
|
+
return path19.join(
|
|
24025
|
+
os5.homedir(),
|
|
23787
24026
|
".config",
|
|
23788
24027
|
"systemd",
|
|
23789
24028
|
"user",
|
|
@@ -23791,8 +24030,8 @@ function unitPath(source) {
|
|
|
23791
24030
|
);
|
|
23792
24031
|
}
|
|
23793
24032
|
function systemdLogPath(source) {
|
|
23794
|
-
return
|
|
23795
|
-
|
|
24033
|
+
return path19.join(
|
|
24034
|
+
os5.homedir(),
|
|
23796
24035
|
".config",
|
|
23797
24036
|
"iteration",
|
|
23798
24037
|
"logs",
|
|
@@ -23804,13 +24043,13 @@ function unitValue(value) {
|
|
|
23804
24043
|
throw new Error("Collector paths cannot contain line breaks.");
|
|
23805
24044
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("%", "%%")}"`;
|
|
23806
24045
|
}
|
|
23807
|
-
function systemdUserUnit(launcherPath = runtimePaths().launcher, nodePath = process.execPath, dataDirectory2 =
|
|
23808
|
-
|
|
24046
|
+
function systemdUserUnit(launcherPath = runtimePaths().launcher, nodePath = process.execPath, dataDirectory2 = path19.join(
|
|
24047
|
+
os5.homedir(),
|
|
23809
24048
|
".config",
|
|
23810
24049
|
"iteration",
|
|
23811
24050
|
"codex-collector"
|
|
23812
|
-
), source = "codex", outputPath =
|
|
23813
|
-
|
|
24051
|
+
), source = "codex", outputPath = path19.join(
|
|
24052
|
+
os5.homedir(),
|
|
23814
24053
|
".config",
|
|
23815
24054
|
"iteration",
|
|
23816
24055
|
"logs",
|
|
@@ -23840,10 +24079,10 @@ async function systemctl(...args) {
|
|
|
23840
24079
|
async function installSystemdUserService(dataDirectory2, source) {
|
|
23841
24080
|
await ensureSystemdUserLinger();
|
|
23842
24081
|
const file = unitPath(source);
|
|
23843
|
-
const logDirectory =
|
|
23844
|
-
await
|
|
23845
|
-
await
|
|
23846
|
-
await
|
|
24082
|
+
const logDirectory = path19.dirname(systemdLogPath(source));
|
|
24083
|
+
await fs15.mkdir(path19.dirname(file), { recursive: true, mode: 448 });
|
|
24084
|
+
await fs15.mkdir(logDirectory, { recursive: true, mode: 448 });
|
|
24085
|
+
await fs15.writeFile(
|
|
23847
24086
|
file,
|
|
23848
24087
|
systemdUserUnit(void 0, await stableNodePath(), dataDirectory2, source),
|
|
23849
24088
|
{
|
|
@@ -23859,14 +24098,14 @@ async function installSystemdUserService(dataDirectory2, source) {
|
|
|
23859
24098
|
async function uninstallSystemdUserService(source) {
|
|
23860
24099
|
const file = unitPath(source);
|
|
23861
24100
|
try {
|
|
23862
|
-
await
|
|
24101
|
+
await fs15.access(file);
|
|
23863
24102
|
} catch (error3) {
|
|
23864
24103
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
23865
24104
|
return;
|
|
23866
24105
|
throw error3;
|
|
23867
24106
|
}
|
|
23868
24107
|
await systemctl("disable", "--now", unitName(source));
|
|
23869
|
-
await
|
|
24108
|
+
await fs15.rm(file);
|
|
23870
24109
|
await systemctl("daemon-reload");
|
|
23871
24110
|
}
|
|
23872
24111
|
async function systemdUserServiceStatus(source) {
|
|
@@ -23885,9 +24124,9 @@ async function systemdUserServiceStatus(source) {
|
|
|
23885
24124
|
|
|
23886
24125
|
// src/task-scheduler.ts
|
|
23887
24126
|
import { execFile as execFileCallback6 } from "node:child_process";
|
|
23888
|
-
import { promises as
|
|
23889
|
-
import
|
|
23890
|
-
import
|
|
24127
|
+
import { promises as fs16 } from "node:fs";
|
|
24128
|
+
import os6 from "node:os";
|
|
24129
|
+
import path20 from "node:path";
|
|
23891
24130
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
23892
24131
|
import { promisify as promisify6 } from "node:util";
|
|
23893
24132
|
|
|
@@ -23989,14 +24228,14 @@ function scheduledTaskName(source, sid) {
|
|
|
23989
24228
|
return `iteration-${sid}-${source}-collector`;
|
|
23990
24229
|
}
|
|
23991
24230
|
function servicesDirectory() {
|
|
23992
|
-
return
|
|
24231
|
+
return path20.join(os6.homedir(), ".config", "iteration", "services");
|
|
23993
24232
|
}
|
|
23994
24233
|
function taskDefinitionPath(source) {
|
|
23995
|
-
return
|
|
24234
|
+
return path20.join(servicesDirectory(), `iteration-${source}-collector.xml`);
|
|
23996
24235
|
}
|
|
23997
24236
|
function windowsLogPath(source) {
|
|
23998
|
-
return
|
|
23999
|
-
|
|
24237
|
+
return path20.join(
|
|
24238
|
+
os6.homedir(),
|
|
24000
24239
|
".config",
|
|
24001
24240
|
"iteration",
|
|
24002
24241
|
"logs",
|
|
@@ -24004,8 +24243,8 @@ function windowsLogPath(source) {
|
|
|
24004
24243
|
);
|
|
24005
24244
|
}
|
|
24006
24245
|
function windowsOutputPath(source) {
|
|
24007
|
-
return
|
|
24008
|
-
|
|
24246
|
+
return path20.join(
|
|
24247
|
+
os6.homedir(),
|
|
24009
24248
|
".config",
|
|
24010
24249
|
"iteration",
|
|
24011
24250
|
"logs",
|
|
@@ -24020,7 +24259,7 @@ function scheduledTaskScript(task) {
|
|
|
24020
24259
|
"--data-directory",
|
|
24021
24260
|
task.dataDirectory
|
|
24022
24261
|
].map(windowsArgument).join(" ");
|
|
24023
|
-
const errorLog =
|
|
24262
|
+
const errorLog = path20.join(
|
|
24024
24263
|
task.home,
|
|
24025
24264
|
".config",
|
|
24026
24265
|
"iteration",
|
|
@@ -24140,7 +24379,7 @@ function AccountSid([string]$account) {
|
|
|
24140
24379
|
async function schtasks(source, operation, ...args) {
|
|
24141
24380
|
try {
|
|
24142
24381
|
await execFile6(
|
|
24143
|
-
|
|
24382
|
+
path20.join(
|
|
24144
24383
|
process.env.SystemRoot ?? "C:\\Windows",
|
|
24145
24384
|
"System32",
|
|
24146
24385
|
"schtasks.exe"
|
|
@@ -24184,7 +24423,7 @@ async function desiredTask(dataDirectory2, source) {
|
|
|
24184
24423
|
userSid: await currentUserSid(),
|
|
24185
24424
|
nodePath: await stableNodePath(),
|
|
24186
24425
|
launcher: runtimePaths().launcher,
|
|
24187
|
-
home:
|
|
24426
|
+
home: os6.homedir()
|
|
24188
24427
|
};
|
|
24189
24428
|
}
|
|
24190
24429
|
async function scheduledTaskUsesRuntime(dataDirectory2, source) {
|
|
@@ -24196,10 +24435,10 @@ async function scheduledTaskUsesRuntime(dataDirectory2, source) {
|
|
|
24196
24435
|
async function installScheduledTask(dataDirectory2, source) {
|
|
24197
24436
|
const file = taskDefinitionPath(source);
|
|
24198
24437
|
await ensurePrivateDirectory(servicesDirectory());
|
|
24199
|
-
await ensurePrivateDirectory(
|
|
24438
|
+
await ensurePrivateDirectory(path20.dirname(windowsLogPath(source)));
|
|
24200
24439
|
await stopTask(source);
|
|
24201
24440
|
const xml2 = scheduledTaskXml(await desiredTask(dataDirectory2, source));
|
|
24202
|
-
await
|
|
24441
|
+
await fs16.writeFile(
|
|
24203
24442
|
file,
|
|
24204
24443
|
Buffer.concat([Buffer.from([255, 254]), Buffer.from(xml2, "utf16le")])
|
|
24205
24444
|
);
|
|
@@ -24209,7 +24448,7 @@ async function installScheduledTask(dataDirectory2, source) {
|
|
|
24209
24448
|
}
|
|
24210
24449
|
async function uninstallScheduledTask(source) {
|
|
24211
24450
|
if (await stopTask(source)) await schtasks(source, "/Delete", "/F");
|
|
24212
|
-
await
|
|
24451
|
+
await fs16.rm(taskDefinitionPath(source), { force: true });
|
|
24213
24452
|
}
|
|
24214
24453
|
async function scheduledTaskStatus(source) {
|
|
24215
24454
|
return (await observedTask(source))?.state === 4;
|
|
@@ -24233,8 +24472,8 @@ async function prepareBackgroundPersistence() {
|
|
|
24233
24472
|
function collectorLogPath(source) {
|
|
24234
24473
|
if (process.platform === "linux") return systemdLogPath(source);
|
|
24235
24474
|
if (process.platform === "win32") return windowsLogPath(source);
|
|
24236
|
-
return
|
|
24237
|
-
|
|
24475
|
+
return path21.join(
|
|
24476
|
+
os7.homedir(),
|
|
24238
24477
|
"Library",
|
|
24239
24478
|
"Logs",
|
|
24240
24479
|
`iteration-${source}-collector.error.log`
|
|
@@ -24268,7 +24507,7 @@ async function backgroundServiceDefinition(source) {
|
|
|
24268
24507
|
requireCollectorPlatform();
|
|
24269
24508
|
const file = process.platform === "darwin" ? plistPath(source) : process.platform === "linux" ? unitPath(source) : taskDefinitionPath(source);
|
|
24270
24509
|
try {
|
|
24271
|
-
return await
|
|
24510
|
+
return await fs17.readFile(
|
|
24272
24511
|
file,
|
|
24273
24512
|
process.platform === "win32" ? "utf16le" : "utf8"
|
|
24274
24513
|
);
|
|
@@ -24317,7 +24556,7 @@ function serviceDataDirectory(definition, platform) {
|
|
|
24317
24556
|
(_, slashes) => slashes.slice(0, slashes.length / 2)
|
|
24318
24557
|
);
|
|
24319
24558
|
}
|
|
24320
|
-
if (!directory || !(platform === "win32" ?
|
|
24559
|
+
if (!directory || !(platform === "win32" ? path21.win32 : path21.posix).isAbsolute(directory))
|
|
24321
24560
|
throw new Error("Could not read the collector service data directory.");
|
|
24322
24561
|
return directory;
|
|
24323
24562
|
}
|
|
@@ -24340,15 +24579,15 @@ async function backgroundServiceUsesRuntime(directory, source) {
|
|
|
24340
24579
|
}
|
|
24341
24580
|
|
|
24342
24581
|
// src/config-paths.ts
|
|
24343
|
-
import
|
|
24344
|
-
import
|
|
24582
|
+
import os8 from "node:os";
|
|
24583
|
+
import path22 from "node:path";
|
|
24345
24584
|
function defaultCollectorDirectory(source) {
|
|
24346
|
-
return
|
|
24585
|
+
return path22.join(os8.homedir(), ".config", "iteration", `${source}-collector`);
|
|
24347
24586
|
}
|
|
24348
24587
|
|
|
24349
24588
|
// src/cursor-hooks.ts
|
|
24350
|
-
import { promises as
|
|
24351
|
-
import
|
|
24589
|
+
import { promises as fs18 } from "node:fs";
|
|
24590
|
+
import path23 from "node:path";
|
|
24352
24591
|
function shellQuote(value) {
|
|
24353
24592
|
if (process.platform === "win32") return `"${value}"`;
|
|
24354
24593
|
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
@@ -24383,8 +24622,8 @@ async function readHooks(filename) {
|
|
|
24383
24622
|
let contents;
|
|
24384
24623
|
let mode = 384;
|
|
24385
24624
|
try {
|
|
24386
|
-
contents = await
|
|
24387
|
-
mode = (await
|
|
24625
|
+
contents = await fs18.readFile(filename, "utf8");
|
|
24626
|
+
mode = (await fs18.stat(filename)).mode & 511;
|
|
24388
24627
|
} catch (error3) {
|
|
24389
24628
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24390
24629
|
return { file: {}, mode };
|
|
@@ -24406,14 +24645,14 @@ async function readHooks(filename) {
|
|
|
24406
24645
|
return { file: checked.data, mode };
|
|
24407
24646
|
}
|
|
24408
24647
|
async function writeHooks(filename, file, mode) {
|
|
24409
|
-
await
|
|
24410
|
-
const target = await
|
|
24648
|
+
await fs18.mkdir(path23.dirname(filename), { recursive: true, mode: 448 });
|
|
24649
|
+
const target = await fs18.realpath(filename).catch((error3) => {
|
|
24411
24650
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24412
24651
|
return filename;
|
|
24413
24652
|
throw error3;
|
|
24414
24653
|
});
|
|
24415
24654
|
const temporary = `${target}.iteration-${process.pid}.tmp`;
|
|
24416
|
-
const handle = await
|
|
24655
|
+
const handle = await fs18.open(temporary, "w", mode);
|
|
24417
24656
|
try {
|
|
24418
24657
|
await handle.writeFile(`${JSON.stringify(file, null, 2)}
|
|
24419
24658
|
`, "utf8");
|
|
@@ -24421,14 +24660,14 @@ async function writeHooks(filename, file, mode) {
|
|
|
24421
24660
|
} finally {
|
|
24422
24661
|
await handle.close();
|
|
24423
24662
|
}
|
|
24424
|
-
await
|
|
24663
|
+
await fs18.rename(temporary, target);
|
|
24425
24664
|
}
|
|
24426
24665
|
function entries(value) {
|
|
24427
24666
|
return value ?? [];
|
|
24428
24667
|
}
|
|
24429
24668
|
async function installCursorHooks(cursorHome, dataDirectory2) {
|
|
24430
24669
|
await ensurePrivateDirectory(cursorHookDirectory(dataDirectory2));
|
|
24431
|
-
const filename =
|
|
24670
|
+
const filename = path23.join(cursorHome, "hooks.json");
|
|
24432
24671
|
const { file, mode } = await readHooks(filename);
|
|
24433
24672
|
const hooks = { ...file.hooks };
|
|
24434
24673
|
const nodePath = await stableNodePath();
|
|
@@ -24442,7 +24681,7 @@ async function installCursorHooks(cursorHome, dataDirectory2) {
|
|
|
24442
24681
|
await writeHooks(filename, { ...file, version: 1, hooks }, mode);
|
|
24443
24682
|
}
|
|
24444
24683
|
async function uninstallCursorHooks(cursorHome, dataDirectory2) {
|
|
24445
|
-
const filename =
|
|
24684
|
+
const filename = path23.join(cursorHome, "hooks.json");
|
|
24446
24685
|
const { file, mode } = await readHooks(filename);
|
|
24447
24686
|
const hooks = { ...file.hooks };
|
|
24448
24687
|
let changed = false;
|
|
@@ -24472,8 +24711,8 @@ function silenceCollectorLogs() {
|
|
|
24472
24711
|
// src/turn-summary.ts
|
|
24473
24712
|
import { execFile as execFileCallback7 } from "node:child_process";
|
|
24474
24713
|
import { createHash as createHash6 } from "node:crypto";
|
|
24475
|
-
import { promises as
|
|
24476
|
-
import
|
|
24714
|
+
import { promises as fs19 } from "node:fs";
|
|
24715
|
+
import path24 from "node:path";
|
|
24477
24716
|
import { promisify as promisify7 } from "node:util";
|
|
24478
24717
|
import { crc32 } from "node:zlib";
|
|
24479
24718
|
var execFile7 = promisify7(execFileCallback7);
|
|
@@ -24484,13 +24723,13 @@ var REQUEST_TIMEOUT_MS2 = 1e4;
|
|
|
24484
24723
|
var HOOK_TIMEOUT_SECONDS = 1;
|
|
24485
24724
|
var REQUEST_KEY_PATTERN = /^\d{1,10}$/;
|
|
24486
24725
|
function turnSummaryPaths(dataDirectory2) {
|
|
24487
|
-
const directory =
|
|
24726
|
+
const directory = path24.join(dataDirectory2, "turn-summary");
|
|
24488
24727
|
return {
|
|
24489
24728
|
directory,
|
|
24490
|
-
script:
|
|
24491
|
-
requests:
|
|
24492
|
-
lines:
|
|
24493
|
-
shown:
|
|
24729
|
+
script: path24.join(directory, "stop-hook.sh"),
|
|
24730
|
+
requests: path24.join(directory, "requests"),
|
|
24731
|
+
lines: path24.join(directory, "lines"),
|
|
24732
|
+
shown: path24.join(directory, "shown")
|
|
24494
24733
|
};
|
|
24495
24734
|
}
|
|
24496
24735
|
function shellQuote2(value) {
|
|
@@ -24546,7 +24785,7 @@ async function sessionStartCommand(config3) {
|
|
|
24546
24785
|
function agentHookFile(config3) {
|
|
24547
24786
|
if ("cursorHome" in config3)
|
|
24548
24787
|
throw new Error("Cursor uses its own trace hooks.");
|
|
24549
|
-
return "claudeHome" in config3 ?
|
|
24788
|
+
return "claudeHome" in config3 ? path24.join(config3.claudeHome, "settings.json") : path24.join(config3.codexHome, "hooks.json");
|
|
24550
24789
|
}
|
|
24551
24790
|
var hookEntrySchema2 = object3({
|
|
24552
24791
|
command: string5().optional(),
|
|
@@ -24563,8 +24802,8 @@ async function readHookFile(filename) {
|
|
|
24563
24802
|
let contents;
|
|
24564
24803
|
let mode = 384;
|
|
24565
24804
|
try {
|
|
24566
|
-
contents = await
|
|
24567
|
-
mode = (await
|
|
24805
|
+
contents = await fs19.readFile(filename, "utf8");
|
|
24806
|
+
mode = (await fs19.stat(filename)).mode & 511;
|
|
24568
24807
|
} catch (error3) {
|
|
24569
24808
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT") {
|
|
24570
24809
|
return { file: {}, mode };
|
|
@@ -24590,19 +24829,19 @@ async function readHookFile(filename) {
|
|
|
24590
24829
|
return { file: parsed.data, mode };
|
|
24591
24830
|
}
|
|
24592
24831
|
async function writeHookFile(filename, file, mode) {
|
|
24593
|
-
await
|
|
24594
|
-
const target = await
|
|
24832
|
+
await fs19.mkdir(path24.dirname(filename), { recursive: true });
|
|
24833
|
+
const target = await fs19.realpath(filename).catch((error3) => {
|
|
24595
24834
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24596
24835
|
return filename;
|
|
24597
24836
|
throw error3;
|
|
24598
24837
|
});
|
|
24599
24838
|
const temporary = `${target}.iteration-${process.pid}.tmp`;
|
|
24600
|
-
await
|
|
24839
|
+
await fs19.writeFile(temporary, `${JSON.stringify(file, null, 2)}
|
|
24601
24840
|
`, {
|
|
24602
24841
|
encoding: "utf8",
|
|
24603
24842
|
mode
|
|
24604
24843
|
});
|
|
24605
|
-
await
|
|
24844
|
+
await fs19.rename(temporary, target);
|
|
24606
24845
|
}
|
|
24607
24846
|
function withoutCommand(groups, command) {
|
|
24608
24847
|
return groups.flatMap((group) => {
|
|
@@ -24627,24 +24866,24 @@ async function installTurnSummary(config3) {
|
|
|
24627
24866
|
[paths.requests, paths.lines, paths.shown].map(ensurePrivateDirectory)
|
|
24628
24867
|
);
|
|
24629
24868
|
if (process.platform !== "win32") {
|
|
24630
|
-
await
|
|
24869
|
+
await fs19.writeFile(paths.script, hookScript(paths), {
|
|
24631
24870
|
encoding: "utf8",
|
|
24632
24871
|
mode: 448
|
|
24633
24872
|
});
|
|
24634
|
-
await
|
|
24873
|
+
await fs19.chmod(paths.script, 448);
|
|
24635
24874
|
}
|
|
24636
24875
|
if ("claudeHome" in config3) {
|
|
24637
24876
|
const gitPaths = claudeGitHookPaths(config3.dataDirectory);
|
|
24638
24877
|
await ensurePrivateDirectory(gitPaths.queue);
|
|
24639
24878
|
if (process.platform !== "win32") {
|
|
24640
|
-
await
|
|
24879
|
+
await fs19.writeFile(
|
|
24641
24880
|
gitPaths.script,
|
|
24642
24881
|
`#!/bin/sh
|
|
24643
24882
|
exec ${shellQuote2(await stableNodePath())} ${shellQuote2(runtimePaths().launcher)} claude-git-hook ${shellQuote2(config3.dataDirectory)}
|
|
24644
24883
|
`,
|
|
24645
24884
|
{ encoding: "utf8", mode: 448 }
|
|
24646
24885
|
);
|
|
24647
|
-
await
|
|
24886
|
+
await fs19.chmod(gitPaths.script, 448);
|
|
24648
24887
|
}
|
|
24649
24888
|
}
|
|
24650
24889
|
const filename = agentHookFile(config3);
|
|
@@ -24734,19 +24973,19 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24734
24973
|
windowsHide: true
|
|
24735
24974
|
}
|
|
24736
24975
|
));
|
|
24737
|
-
directory =
|
|
24976
|
+
directory = path24.normalize(directory.trim());
|
|
24738
24977
|
} catch {
|
|
24739
24978
|
quiet();
|
|
24740
24979
|
return;
|
|
24741
24980
|
}
|
|
24742
|
-
if (!
|
|
24981
|
+
if (!path24.isAbsolute(directory)) {
|
|
24743
24982
|
quiet();
|
|
24744
24983
|
return;
|
|
24745
24984
|
}
|
|
24746
24985
|
const key = String(crc32(directory));
|
|
24747
24986
|
const paths = turnSummaryPaths(dataDirectory2);
|
|
24748
24987
|
try {
|
|
24749
|
-
await
|
|
24988
|
+
await fs19.writeFile(path24.join(paths.requests, key), `${directory}
|
|
24750
24989
|
`, {
|
|
24751
24990
|
encoding: "utf8",
|
|
24752
24991
|
mode: 384
|
|
@@ -24755,7 +24994,7 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24755
24994
|
}
|
|
24756
24995
|
let lines;
|
|
24757
24996
|
try {
|
|
24758
|
-
lines = await
|
|
24997
|
+
lines = await fs19.readFile(path24.join(paths.lines, key), "utf8");
|
|
24759
24998
|
} catch {
|
|
24760
24999
|
quiet();
|
|
24761
25000
|
return;
|
|
@@ -24767,7 +25006,7 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24767
25006
|
}
|
|
24768
25007
|
let last;
|
|
24769
25008
|
try {
|
|
24770
|
-
last = (await
|
|
25009
|
+
last = (await fs19.readFile(path24.join(paths.shown, key), "utf8")).split("\n")[0] ?? null;
|
|
24771
25010
|
} catch {
|
|
24772
25011
|
last = null;
|
|
24773
25012
|
}
|
|
@@ -24776,7 +25015,7 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24776
25015
|
return;
|
|
24777
25016
|
}
|
|
24778
25017
|
try {
|
|
24779
|
-
await
|
|
25018
|
+
await fs19.writeFile(path24.join(paths.shown, key), `${message}
|
|
24780
25019
|
`, {
|
|
24781
25020
|
encoding: "utf8",
|
|
24782
25021
|
mode: 384
|
|
@@ -24836,7 +25075,7 @@ async function fetchSummary(config3, directory, fetcher, signal) {
|
|
|
24836
25075
|
}
|
|
24837
25076
|
async function readRequest(filename) {
|
|
24838
25077
|
try {
|
|
24839
|
-
const [directory] = (await
|
|
25078
|
+
const [directory] = (await fs19.readFile(filename, "utf8")).split("\n");
|
|
24840
25079
|
return directory ?? null;
|
|
24841
25080
|
} catch (error3) {
|
|
24842
25081
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
@@ -24845,25 +25084,25 @@ async function readRequest(filename) {
|
|
|
24845
25084
|
}
|
|
24846
25085
|
}
|
|
24847
25086
|
async function writeLine(paths, key, directory, message) {
|
|
24848
|
-
const filename =
|
|
25087
|
+
const filename = path24.join(paths.lines, key);
|
|
24849
25088
|
if (message === null) {
|
|
24850
|
-
await
|
|
25089
|
+
await fs19.rm(filename, { force: true });
|
|
24851
25090
|
return;
|
|
24852
25091
|
}
|
|
24853
25092
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
24854
|
-
await
|
|
25093
|
+
await fs19.writeFile(
|
|
24855
25094
|
temporary,
|
|
24856
25095
|
`${directory}
|
|
24857
25096
|
${JSON.stringify({ systemMessage: message })}
|
|
24858
25097
|
`,
|
|
24859
25098
|
{ encoding: "utf8", mode: 384 }
|
|
24860
25099
|
);
|
|
24861
|
-
await
|
|
25100
|
+
await fs19.rename(temporary, filename);
|
|
24862
25101
|
}
|
|
24863
25102
|
async function forget(paths, key) {
|
|
24864
25103
|
await Promise.all(
|
|
24865
25104
|
[paths.requests, paths.lines, paths.shown].map(
|
|
24866
|
-
(directory) =>
|
|
25105
|
+
(directory) => fs19.rm(path24.join(directory, key), { force: true })
|
|
24867
25106
|
)
|
|
24868
25107
|
);
|
|
24869
25108
|
}
|
|
@@ -24871,7 +25110,7 @@ async function refreshTurnSummaries(config3, refreshedAt, nowMs, fetcher = colle
|
|
|
24871
25110
|
const paths = turnSummaryPaths(config3.dataDirectory);
|
|
24872
25111
|
let keys;
|
|
24873
25112
|
try {
|
|
24874
|
-
keys = await
|
|
25113
|
+
keys = await fs19.readdir(paths.requests);
|
|
24875
25114
|
} catch (error3) {
|
|
24876
25115
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24877
25116
|
return 0;
|
|
@@ -24881,8 +25120,8 @@ async function refreshTurnSummaries(config3, refreshedAt, nowMs, fetcher = colle
|
|
|
24881
25120
|
for (const key of keys.sort()) {
|
|
24882
25121
|
signal?.throwIfAborted();
|
|
24883
25122
|
if (!REQUEST_KEY_PATTERN.test(key)) continue;
|
|
24884
|
-
const filename =
|
|
24885
|
-
const stats = await
|
|
25123
|
+
const filename = path24.join(paths.requests, key);
|
|
25124
|
+
const stats = await fs19.stat(filename).catch((error3) => {
|
|
24886
25125
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24887
25126
|
return null;
|
|
24888
25127
|
throw error3;
|
|
@@ -24949,8 +25188,8 @@ async function codexTurnSummaryApproval(config3) {
|
|
|
24949
25188
|
if (handlerIndex < 0) continue;
|
|
24950
25189
|
let configToml;
|
|
24951
25190
|
try {
|
|
24952
|
-
configToml = await
|
|
24953
|
-
|
|
25191
|
+
configToml = await fs19.readFile(
|
|
25192
|
+
path24.join(config3.codexHome, "config.toml"),
|
|
24954
25193
|
"utf8"
|
|
24955
25194
|
);
|
|
24956
25195
|
} catch (error3) {
|
|
@@ -24977,25 +25216,25 @@ var consentSchema = object3({
|
|
|
24977
25216
|
sourceHomes: object3({
|
|
24978
25217
|
codex: string5(),
|
|
24979
25218
|
claude: string5(),
|
|
24980
|
-
cursor: string5().default(
|
|
25219
|
+
cursor: string5().default(path25.join(os9.homedir(), ".cursor"))
|
|
24981
25220
|
}).strict()
|
|
24982
25221
|
}).strict();
|
|
24983
25222
|
function consentPath() {
|
|
24984
|
-
return
|
|
25223
|
+
return path25.join(os9.homedir(), ".config", "iteration", "auto-connect.json");
|
|
24985
25224
|
}
|
|
24986
25225
|
async function removeMachineConsent() {
|
|
24987
|
-
await
|
|
25226
|
+
await fs20.rm(consentPath(), { force: true });
|
|
24988
25227
|
}
|
|
24989
25228
|
async function detectedSources(sourceHomes) {
|
|
24990
25229
|
const detected = [];
|
|
24991
25230
|
for (const source of COLLECTOR_SOURCES2) {
|
|
24992
|
-
const directory =
|
|
25231
|
+
const directory = path25.join(
|
|
24993
25232
|
sourceHomes[source],
|
|
24994
25233
|
source === "codex" ? "sessions" : "projects"
|
|
24995
25234
|
);
|
|
24996
25235
|
let stats;
|
|
24997
25236
|
try {
|
|
24998
|
-
stats = await
|
|
25237
|
+
stats = await fs20.stat(directory);
|
|
24999
25238
|
} catch (error3) {
|
|
25000
25239
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25001
25240
|
continue;
|
|
@@ -25015,7 +25254,7 @@ async function detectedSources(sourceHomes) {
|
|
|
25015
25254
|
async function loadMachineConsent() {
|
|
25016
25255
|
let text;
|
|
25017
25256
|
try {
|
|
25018
|
-
text = await
|
|
25257
|
+
text = await fs20.readFile(consentPath(), "utf8");
|
|
25019
25258
|
} catch (error3) {
|
|
25020
25259
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25021
25260
|
return null;
|
|
@@ -25041,9 +25280,9 @@ async function saveMachineConsent(consent) {
|
|
|
25041
25280
|
const parsed = consentSchema.parse(consent);
|
|
25042
25281
|
validateCollectorEndpoint(parsed.endpoint);
|
|
25043
25282
|
const filename = consentPath();
|
|
25044
|
-
await ensurePrivateDirectory(
|
|
25283
|
+
await ensurePrivateDirectory(path25.dirname(filename));
|
|
25045
25284
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
25046
|
-
const handle = await
|
|
25285
|
+
const handle = await fs20.open(temporary, "w", 384);
|
|
25047
25286
|
try {
|
|
25048
25287
|
await handle.writeFile(`${JSON.stringify(parsed)}
|
|
25049
25288
|
`, "utf8");
|
|
@@ -25051,7 +25290,7 @@ async function saveMachineConsent(consent) {
|
|
|
25051
25290
|
} finally {
|
|
25052
25291
|
await handle.close();
|
|
25053
25292
|
}
|
|
25054
|
-
await
|
|
25293
|
+
await fs20.rename(temporary, filename);
|
|
25055
25294
|
}
|
|
25056
25295
|
async function readCollectorScope(anchor3) {
|
|
25057
25296
|
const endpoint = validateCollectorEndpoint(anchor3.endpoint);
|
|
@@ -25147,7 +25386,7 @@ async function connectNewDetectedSources(anchor3, consent) {
|
|
|
25147
25386
|
if (source === consent.anchorSource) continue;
|
|
25148
25387
|
const paths = collectorPaths(defaultCollectorDirectory(source));
|
|
25149
25388
|
try {
|
|
25150
|
-
await
|
|
25389
|
+
await fs20.access(paths.config);
|
|
25151
25390
|
continue;
|
|
25152
25391
|
} catch (error3) {
|
|
25153
25392
|
if (!(error3 instanceof Error && "code" in error3 && error3.code === "ENOENT"))
|
|
@@ -25188,7 +25427,7 @@ async function connectNewDetectedSources(anchor3, consent) {
|
|
|
25188
25427
|
async function connectedConfig(source) {
|
|
25189
25428
|
const paths = collectorPaths(defaultCollectorDirectory(source));
|
|
25190
25429
|
try {
|
|
25191
|
-
await
|
|
25430
|
+
await fs20.access(paths.config);
|
|
25192
25431
|
} catch (error3) {
|
|
25193
25432
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25194
25433
|
return null;
|
|
@@ -25682,7 +25921,7 @@ async function authenticateAndEnrollCollector(endpoint, deviceNameValue, organiz
|
|
|
25682
25921
|
}
|
|
25683
25922
|
|
|
25684
25923
|
// src/history-import.ts
|
|
25685
|
-
import
|
|
25924
|
+
import path26 from "node:path";
|
|
25686
25925
|
function backgroundControl(source) {
|
|
25687
25926
|
return {
|
|
25688
25927
|
isRunning: () => backgroundServiceStatus(source),
|
|
@@ -25695,7 +25934,7 @@ async function importSourceHistory(config3, paths, confirmed, control = backgrou
|
|
|
25695
25934
|
const source = collectorSource(config3);
|
|
25696
25935
|
const directory = collectorSourceDirectory(config3);
|
|
25697
25936
|
const state = await loadState(paths);
|
|
25698
|
-
if (!state.initialized || state.sourceDirectory !==
|
|
25937
|
+
if (!state.initialized || state.sourceDirectory !== path26.resolve(directory)) {
|
|
25699
25938
|
throw new Error(
|
|
25700
25939
|
`Connect the ${source} source before importing its history.`
|
|
25701
25940
|
);
|
|
@@ -25744,36 +25983,36 @@ async function importSourceHistory(config3, paths, confirmed, control = backgrou
|
|
|
25744
25983
|
|
|
25745
25984
|
// src/logout.ts
|
|
25746
25985
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
25747
|
-
import { promises as
|
|
25748
|
-
import
|
|
25749
|
-
import
|
|
25986
|
+
import { promises as fs21 } from "node:fs";
|
|
25987
|
+
import os10 from "node:os";
|
|
25988
|
+
import path27 from "node:path";
|
|
25750
25989
|
async function pendingDirectories(filename) {
|
|
25751
25990
|
let contents;
|
|
25752
25991
|
try {
|
|
25753
|
-
contents = await
|
|
25992
|
+
contents = await fs21.readFile(filename, "utf8");
|
|
25754
25993
|
} catch (error3) {
|
|
25755
25994
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25756
25995
|
return [];
|
|
25757
25996
|
throw error3;
|
|
25758
25997
|
}
|
|
25759
|
-
const parsed = array2(string5().refine(
|
|
25998
|
+
const parsed = array2(string5().refine(path27.isAbsolute)).max(64).safeParse(JSON.parse(contents));
|
|
25760
25999
|
if (!parsed.success)
|
|
25761
26000
|
throw new Error("Pending logout directories are invalid.");
|
|
25762
26001
|
return parsed.data;
|
|
25763
26002
|
}
|
|
25764
26003
|
async function savePendingDirectories(filename, directories) {
|
|
25765
|
-
await ensurePrivateDirectory(
|
|
26004
|
+
await ensurePrivateDirectory(path27.dirname(filename));
|
|
25766
26005
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
25767
|
-
await
|
|
26006
|
+
await fs21.writeFile(temporary, JSON.stringify([...directories]), {
|
|
25768
26007
|
mode: 384
|
|
25769
26008
|
});
|
|
25770
|
-
await
|
|
26009
|
+
await fs21.rename(temporary, filename);
|
|
25771
26010
|
}
|
|
25772
26011
|
async function clearConnection(directory) {
|
|
25773
26012
|
const paths = collectorPaths(directory);
|
|
25774
26013
|
let names;
|
|
25775
26014
|
try {
|
|
25776
|
-
names = await
|
|
26015
|
+
names = await fs21.readdir(directory);
|
|
25777
26016
|
} catch (error3) {
|
|
25778
26017
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25779
26018
|
return;
|
|
@@ -25783,14 +26022,15 @@ async function clearConnection(directory) {
|
|
|
25783
26022
|
try {
|
|
25784
26023
|
for (const name of names)
|
|
25785
26024
|
if (/^config\.json\.\d+\.tmp$/.test(name))
|
|
25786
|
-
await
|
|
25787
|
-
if (!names.includes(
|
|
26025
|
+
await fs21.rm(path27.join(directory, name), { force: true });
|
|
26026
|
+
if (!names.includes(path27.basename(paths.config))) return;
|
|
25788
26027
|
const config3 = await loadConfig(paths);
|
|
25789
26028
|
if (config3.destination === "vault")
|
|
25790
26029
|
throw new Error("This directory belongs to Trace Vault, not Iteration.");
|
|
25791
26030
|
if ("cursorHome" in config3)
|
|
25792
26031
|
await uninstallCursorHooks(config3.cursorHome, config3.dataDirectory);
|
|
25793
26032
|
else await uninstallTurnSummary(config3);
|
|
26033
|
+
await uninstallAgentTools(agentHomes(config3));
|
|
25794
26034
|
const retained = [
|
|
25795
26035
|
paths.state,
|
|
25796
26036
|
paths.outbox,
|
|
@@ -25805,27 +26045,27 @@ async function clearConnection(directory) {
|
|
|
25805
26045
|
"turn-summary",
|
|
25806
26046
|
"codex-billing-sync.json",
|
|
25807
26047
|
"cursor-billing-sync.json"
|
|
25808
|
-
].map((name) =>
|
|
26048
|
+
].map((name) => path27.join(directory, name))
|
|
25809
26049
|
];
|
|
25810
|
-
const archive =
|
|
26050
|
+
const archive = path27.join(directory, "logged-out", randomUUID3());
|
|
25811
26051
|
await ensurePrivateDirectory(archive);
|
|
25812
26052
|
for (const filename of retained) {
|
|
25813
26053
|
try {
|
|
25814
|
-
await
|
|
26054
|
+
await fs21.rename(filename, path27.join(archive, path27.basename(filename)));
|
|
25815
26055
|
} catch (error3) {
|
|
25816
26056
|
if (!(error3 instanceof Error && "code" in error3 && error3.code === "ENOENT"))
|
|
25817
26057
|
throw error3;
|
|
25818
26058
|
}
|
|
25819
26059
|
}
|
|
25820
|
-
await
|
|
26060
|
+
await fs21.rm(paths.config);
|
|
25821
26061
|
} finally {
|
|
25822
26062
|
await release();
|
|
25823
26063
|
}
|
|
25824
26064
|
}
|
|
25825
26065
|
async function logout(extraDirectory) {
|
|
25826
26066
|
requireCollectorPlatform();
|
|
25827
|
-
const pending =
|
|
25828
|
-
|
|
26067
|
+
const pending = path27.join(
|
|
26068
|
+
os10.homedir(),
|
|
25829
26069
|
".config",
|
|
25830
26070
|
"iteration",
|
|
25831
26071
|
"logout-pending.json"
|
|
@@ -25835,7 +26075,7 @@ async function logout(extraDirectory) {
|
|
|
25835
26075
|
...await pendingDirectories(pending)
|
|
25836
26076
|
]);
|
|
25837
26077
|
if (extraDirectory !== void 0)
|
|
25838
|
-
directories.add(
|
|
26078
|
+
directories.add(path27.resolve(extraDirectory));
|
|
25839
26079
|
const failures = [];
|
|
25840
26080
|
try {
|
|
25841
26081
|
await removeMachineConsent();
|
|
@@ -25880,7 +26120,7 @@ async function logout(extraDirectory) {
|
|
|
25880
26120
|
`Logout did not finish. Resolve these errors and run iteration logout again:
|
|
25881
26121
|
${failures.join("\n")}`
|
|
25882
26122
|
);
|
|
25883
|
-
await
|
|
26123
|
+
await fs21.rm(pending);
|
|
25884
26124
|
}
|
|
25885
26125
|
|
|
25886
26126
|
// src/runtime-services.ts
|
|
@@ -25911,8 +26151,8 @@ import { setTimeout as delay5 } from "node:timers/promises";
|
|
|
25911
26151
|
|
|
25912
26152
|
// src/codex-billing.ts
|
|
25913
26153
|
import { createHash as createHash7 } from "node:crypto";
|
|
25914
|
-
import { promises as
|
|
25915
|
-
import
|
|
26154
|
+
import { promises as fs22 } from "node:fs";
|
|
26155
|
+
import path28 from "node:path";
|
|
25916
26156
|
var TASK_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage/thread_usage/query_v2";
|
|
25917
26157
|
var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
25918
26158
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -25964,7 +26204,7 @@ function fingerprint(value) {
|
|
|
25964
26204
|
async function readAuth(codexHome) {
|
|
25965
26205
|
let contents;
|
|
25966
26206
|
try {
|
|
25967
|
-
contents = await
|
|
26207
|
+
contents = await fs22.readFile(path28.join(codexHome, "auth.json"), "utf8");
|
|
25968
26208
|
} catch (error3) {
|
|
25969
26209
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25970
26210
|
return {
|
|
@@ -25999,7 +26239,7 @@ async function readAuth(codexHome) {
|
|
|
25999
26239
|
async function readState(filename) {
|
|
26000
26240
|
let contents;
|
|
26001
26241
|
try {
|
|
26002
|
-
contents = await
|
|
26242
|
+
contents = await fs22.readFile(filename, "utf8");
|
|
26003
26243
|
} catch (error3) {
|
|
26004
26244
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
26005
26245
|
return null;
|
|
@@ -26021,7 +26261,7 @@ async function readState(filename) {
|
|
|
26021
26261
|
}
|
|
26022
26262
|
async function saveState2(filename, state) {
|
|
26023
26263
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
26024
|
-
const handle = await
|
|
26264
|
+
const handle = await fs22.open(temporary, "w", 384);
|
|
26025
26265
|
try {
|
|
26026
26266
|
await handle.writeFile(`${JSON.stringify(state)}
|
|
26027
26267
|
`);
|
|
@@ -26029,11 +26269,11 @@ async function saveState2(filename, state) {
|
|
|
26029
26269
|
} finally {
|
|
26030
26270
|
await handle.close();
|
|
26031
26271
|
}
|
|
26032
|
-
await
|
|
26272
|
+
await fs22.rename(temporary, filename);
|
|
26033
26273
|
}
|
|
26034
26274
|
async function localThread(filename) {
|
|
26035
|
-
const stat = await
|
|
26036
|
-
const handle = await
|
|
26275
|
+
const stat = await fs22.stat(filename);
|
|
26276
|
+
const handle = await fs22.open(filename, "r");
|
|
26037
26277
|
let header = null;
|
|
26038
26278
|
try {
|
|
26039
26279
|
const buffer = Buffer.alloc(64 * 1024);
|
|
@@ -26133,9 +26373,9 @@ function parseCodexAuthLog(threadId, body) {
|
|
|
26133
26373
|
return { threadId, turnId: turn[1], mode };
|
|
26134
26374
|
}
|
|
26135
26375
|
async function localAuthTurns(codexHome, modelProviders) {
|
|
26136
|
-
const filename =
|
|
26376
|
+
const filename = path28.join(codexHome, "logs_2.sqlite");
|
|
26137
26377
|
try {
|
|
26138
|
-
await
|
|
26378
|
+
await fs22.access(filename);
|
|
26139
26379
|
} catch (error3) {
|
|
26140
26380
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
26141
26381
|
return [];
|
|
@@ -26228,7 +26468,7 @@ async function queryTaskUsage(tasks, accessToken, accountId, signal) {
|
|
|
26228
26468
|
}
|
|
26229
26469
|
async function syncCodexBilling(config3, fetcher = collectorFetch, signal) {
|
|
26230
26470
|
const auth = await readAuth(config3.codexHome);
|
|
26231
|
-
const stateFile =
|
|
26471
|
+
const stateFile = path28.join(config3.dataDirectory, "codex-billing-sync.json");
|
|
26232
26472
|
const prior = await readState(stateFile);
|
|
26233
26473
|
const nowMs = Date.now();
|
|
26234
26474
|
const history = prior === null || prior.accountFingerprint !== auth.accountFingerprint;
|
|
@@ -26399,9 +26639,9 @@ async function syncCodexBilling(config3, fetcher = collectorFetch, signal) {
|
|
|
26399
26639
|
|
|
26400
26640
|
// src/cursor-billing.ts
|
|
26401
26641
|
import { createHash as createHash8 } from "node:crypto";
|
|
26402
|
-
import { promises as
|
|
26403
|
-
import
|
|
26404
|
-
import
|
|
26642
|
+
import { promises as fs23 } from "node:fs";
|
|
26643
|
+
import os11 from "node:os";
|
|
26644
|
+
import path29 from "node:path";
|
|
26405
26645
|
var CURSOR_USAGE_URL = "https://api2.cursor.sh/aiserver.v1.DashboardService/GetFilteredUsageEvents";
|
|
26406
26646
|
var PAGE_SIZE = 500;
|
|
26407
26647
|
var MAX_PAGES = 1e3;
|
|
@@ -26432,18 +26672,18 @@ var usagePageSchema = object3({
|
|
|
26432
26672
|
var emptyUsagePageSchema = object3({}).strict();
|
|
26433
26673
|
function cursorAuthDatabase() {
|
|
26434
26674
|
if (process.platform === "darwin")
|
|
26435
|
-
return
|
|
26436
|
-
|
|
26675
|
+
return path29.join(
|
|
26676
|
+
os11.homedir(),
|
|
26437
26677
|
"Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
|
26438
26678
|
);
|
|
26439
26679
|
if (process.platform === "linux")
|
|
26440
|
-
return
|
|
26441
|
-
|
|
26680
|
+
return path29.join(
|
|
26681
|
+
os11.homedir(),
|
|
26442
26682
|
".config/Cursor/User/globalStorage/state.vscdb"
|
|
26443
26683
|
);
|
|
26444
26684
|
if (process.platform === "win32")
|
|
26445
|
-
return
|
|
26446
|
-
process.env.APPDATA ??
|
|
26685
|
+
return path29.join(
|
|
26686
|
+
process.env.APPDATA ?? path29.join(os11.homedir(), "AppData", "Roaming"),
|
|
26447
26687
|
"Cursor/User/globalStorage/state.vscdb"
|
|
26448
26688
|
);
|
|
26449
26689
|
return null;
|
|
@@ -26485,7 +26725,7 @@ async function readCursorAuth() {
|
|
|
26485
26725
|
async function loadBillingState(filename) {
|
|
26486
26726
|
let contents;
|
|
26487
26727
|
try {
|
|
26488
|
-
contents = await
|
|
26728
|
+
contents = await fs23.readFile(filename, "utf8");
|
|
26489
26729
|
} catch (error3) {
|
|
26490
26730
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
26491
26731
|
return null;
|
|
@@ -26501,7 +26741,7 @@ async function loadBillingState(filename) {
|
|
|
26501
26741
|
}
|
|
26502
26742
|
async function saveBillingState(filename, state) {
|
|
26503
26743
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
26504
|
-
const handle = await
|
|
26744
|
+
const handle = await fs23.open(temporary, "w", 384);
|
|
26505
26745
|
try {
|
|
26506
26746
|
await handle.writeFile(`${JSON.stringify(state)}
|
|
26507
26747
|
`, "utf8");
|
|
@@ -26509,7 +26749,7 @@ async function saveBillingState(filename, state) {
|
|
|
26509
26749
|
} finally {
|
|
26510
26750
|
await handle.close();
|
|
26511
26751
|
}
|
|
26512
|
-
await
|
|
26752
|
+
await fs23.rename(temporary, filename);
|
|
26513
26753
|
}
|
|
26514
26754
|
function planCursorBillingSync(state, accountFingerprint, nowMs) {
|
|
26515
26755
|
if (state === null || state.accountFingerprint !== accountFingerprint)
|
|
@@ -26531,7 +26771,7 @@ function planCursorBillingSync(state, accountFingerprint, nowMs) {
|
|
|
26531
26771
|
}
|
|
26532
26772
|
function cursorConversationIds(filenames) {
|
|
26533
26773
|
return new Set(
|
|
26534
|
-
filenames.map((filename) =>
|
|
26774
|
+
filenames.map((filename) => path29.basename(filename, ".jsonl")).filter((id) => UUID3.test(id))
|
|
26535
26775
|
);
|
|
26536
26776
|
}
|
|
26537
26777
|
function billingKind(kind) {
|
|
@@ -26589,11 +26829,11 @@ async function syncCursorBilling(config3, fetcher = collectorFetch, signal) {
|
|
|
26589
26829
|
if (auth === null)
|
|
26590
26830
|
return { sessions: 0, matched: 0, skipped: true, mode: null };
|
|
26591
26831
|
const localConversations = cursorConversationIds(
|
|
26592
|
-
await cursorFiles(
|
|
26832
|
+
await cursorFiles(path29.join(config3.cursorHome, "projects"))
|
|
26593
26833
|
);
|
|
26594
26834
|
if (localConversations.size === 0)
|
|
26595
26835
|
return { sessions: 0, matched: 0, skipped: true, mode: null };
|
|
26596
|
-
const stateFile =
|
|
26836
|
+
const stateFile = path29.join(config3.dataDirectory, "cursor-billing-sync.json");
|
|
26597
26837
|
const priorState = await loadBillingState(stateFile);
|
|
26598
26838
|
const nowMs = Date.now();
|
|
26599
26839
|
const plan = planCursorBillingSync(
|
|
@@ -26870,8 +27110,7 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
26870
27110
|
const summariesRefreshedAt = /* @__PURE__ */ new Map();
|
|
26871
27111
|
let lastAutoCheckAt = 0;
|
|
26872
27112
|
let lastBillingSyncAt = 0;
|
|
26873
|
-
const
|
|
26874
|
-
let scanned = null;
|
|
27113
|
+
const historyProgress2 = new HistoryProgressReporter();
|
|
26875
27114
|
const runtimeVersion = process.env.ITERATION_RUNTIME_VERSION;
|
|
26876
27115
|
let lastRuntimeCheckAt = 0;
|
|
26877
27116
|
let trialSettled = runtimeVersion === void 0;
|
|
@@ -26969,14 +27208,11 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
26969
27208
|
{ recentMessages: RECENT_MESSAGE_LIMIT }
|
|
26970
27209
|
);
|
|
26971
27210
|
billingReady = result.historyCaughtUp && result.outboxBytes === 0;
|
|
26972
|
-
|
|
26973
|
-
|
|
26974
|
-
history
|
|
26975
|
-
|
|
26976
|
-
|
|
26977
|
-
...result.recentMessages === null ? {} : { recentMessages: result.recentMessages }
|
|
26978
|
-
};
|
|
26979
|
-
}
|
|
27211
|
+
history = {
|
|
27212
|
+
...result.history,
|
|
27213
|
+
complete: billingReady && result.history.readSessions === result.history.sessions,
|
|
27214
|
+
...result.recentMessages === null ? {} : { recentMessages: result.recentMessages }
|
|
27215
|
+
};
|
|
26980
27216
|
await recordTickSuccess(result, acknowledgedAtMs);
|
|
26981
27217
|
} catch (error3) {
|
|
26982
27218
|
if (controller.signal.aborted) return null;
|
|
@@ -27007,7 +27243,7 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
27007
27243
|
const reportHistory = async (history) => {
|
|
27008
27244
|
if (history !== null) {
|
|
27009
27245
|
try {
|
|
27010
|
-
await
|
|
27246
|
+
await historyProgress2.report(
|
|
27011
27247
|
config3,
|
|
27012
27248
|
history,
|
|
27013
27249
|
collectorFetch,
|
|
@@ -27523,26 +27759,26 @@ function renderRuntime(terminal2, summary) {
|
|
|
27523
27759
|
|
|
27524
27760
|
// src/windows-supervisor.ts
|
|
27525
27761
|
import { spawn } from "node:child_process";
|
|
27526
|
-
import { promises as
|
|
27527
|
-
import
|
|
27762
|
+
import { promises as fs24 } from "node:fs";
|
|
27763
|
+
import path30 from "node:path";
|
|
27528
27764
|
import { setTimeout as delay6 } from "node:timers/promises";
|
|
27529
27765
|
var MAX_LOG_BYTES = 8 * 1024 * 1024;
|
|
27530
27766
|
var RESTART_DELAY_MS = 5e3;
|
|
27531
27767
|
async function appendLog(filename, bytes) {
|
|
27532
27768
|
let offset = 0;
|
|
27533
27769
|
while (offset < bytes.length) {
|
|
27534
|
-
const size = await
|
|
27770
|
+
const size = await fs24.stat(filename).then((stat) => stat.size).catch((error3) => {
|
|
27535
27771
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
27536
27772
|
return 0;
|
|
27537
27773
|
throw error3;
|
|
27538
27774
|
});
|
|
27539
27775
|
if (size >= MAX_LOG_BYTES) {
|
|
27540
|
-
await
|
|
27541
|
-
await
|
|
27776
|
+
await fs24.rm(`${filename}.1`, { force: true });
|
|
27777
|
+
await fs24.rename(filename, `${filename}.1`);
|
|
27542
27778
|
continue;
|
|
27543
27779
|
}
|
|
27544
27780
|
const count = Math.min(bytes.length - offset, MAX_LOG_BYTES - size);
|
|
27545
|
-
await
|
|
27781
|
+
await fs24.appendFile(filename, bytes.subarray(offset, offset + count), {
|
|
27546
27782
|
mode: 384
|
|
27547
27783
|
});
|
|
27548
27784
|
offset += count;
|
|
@@ -27558,7 +27794,7 @@ async function copyOutput(stream, filename) {
|
|
|
27558
27794
|
async function superviseCollector(source, dataDirectory2) {
|
|
27559
27795
|
const output = windowsOutputPath(source);
|
|
27560
27796
|
const errors = windowsLogPath(source);
|
|
27561
|
-
await ensurePrivateDirectory(
|
|
27797
|
+
await ensurePrivateDirectory(path30.dirname(output));
|
|
27562
27798
|
const controller = new AbortController();
|
|
27563
27799
|
const stop = () => controller.abort();
|
|
27564
27800
|
process.once("SIGTERM", stop);
|
|
@@ -27770,7 +28006,7 @@ function usage(command) {
|
|
|
27770
28006
|
}
|
|
27771
28007
|
async function fileExists(filename) {
|
|
27772
28008
|
try {
|
|
27773
|
-
await
|
|
28009
|
+
await fs25.access(filename);
|
|
27774
28010
|
return true;
|
|
27775
28011
|
} catch (error3) {
|
|
27776
28012
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT") {
|
|
@@ -27811,7 +28047,7 @@ async function defaultCommand() {
|
|
|
27811
28047
|
await connectAll({});
|
|
27812
28048
|
}
|
|
27813
28049
|
function dataDirectory(source, values) {
|
|
27814
|
-
return
|
|
28050
|
+
return path31.resolve(
|
|
27815
28051
|
optionalString(values, "data-directory") ?? defaultCollectorDirectory(source)
|
|
27816
28052
|
);
|
|
27817
28053
|
}
|
|
@@ -27891,12 +28127,12 @@ async function initialize(source, values) {
|
|
|
27891
28127
|
requireCollectorPlatform();
|
|
27892
28128
|
const endpoint = optionalString(values, "endpoint") ?? DEFAULT_INGEST_ENDPOINT;
|
|
27893
28129
|
const endpointUrl = validateCollectorEndpoint(endpoint);
|
|
27894
|
-
const deviceName = optionalString(values, "device-name") ??
|
|
28130
|
+
const deviceName = optionalString(values, "device-name") ?? os12.hostname();
|
|
27895
28131
|
const organizationId = optionalString(values, "workspace");
|
|
27896
28132
|
const directory = dataDirectory(source, values);
|
|
27897
28133
|
const paths = collectorPaths(directory);
|
|
27898
|
-
const selectedHome =
|
|
27899
|
-
source === "codex" ? optionalString(values, "codex-home") ?? process.env.CODEX_HOME ??
|
|
28134
|
+
const selectedHome = path31.resolve(
|
|
28135
|
+
source === "codex" ? optionalString(values, "codex-home") ?? process.env.CODEX_HOME ?? path31.join(os12.homedir(), ".codex") : source === "claude" ? optionalString(values, "claude-home") ?? process.env.CLAUDE_CONFIG_DIR ?? path31.join(os12.homedir(), ".claude") : optionalString(values, "cursor-home") ?? path31.join(os12.homedir(), ".cursor")
|
|
27900
28136
|
);
|
|
27901
28137
|
await assertFreshCollectorDirectory(paths, source);
|
|
27902
28138
|
const preparedState = await prepareSourceInitialState(
|
|
@@ -27975,7 +28211,7 @@ async function approveAllSources(sources, workspaceName, yes) {
|
|
|
27975
28211
|
"",
|
|
27976
28212
|
wrap(
|
|
27977
28213
|
terminal,
|
|
27978
|
-
`Existing sessions and new activity, including prompts, code and tool output, upload to ${safeName ?? "your workspace"}, where its members can read them. Supported agents you install later connect automatically.${process.platform === "linux" ? " Collection continues after you log out." : ""}`
|
|
28214
|
+
`Existing sessions and new activity, including prompts, code and tool output, upload to ${safeName ?? "your workspace"}, where its members can read them. Your agents also get the workspace's tools. Supported agents you install later connect automatically.${process.platform === "linux" ? " Collection continues after you log out." : ""}`
|
|
27979
28215
|
),
|
|
27980
28216
|
""
|
|
27981
28217
|
);
|
|
@@ -28004,13 +28240,13 @@ async function connectAll(values) {
|
|
|
28004
28240
|
}
|
|
28005
28241
|
const configs = await Promise.all(COLLECTOR_SOURCES2.map(connectedConfig));
|
|
28006
28242
|
const resolveSourceHomes = () => ({
|
|
28007
|
-
codex:
|
|
28243
|
+
codex: path31.resolve(
|
|
28008
28244
|
optionalString(values, "codex-home") ?? (configs[0] && "codexHome" in configs[0] ? configs[0].codexHome : sourceHome("codex"))
|
|
28009
28245
|
),
|
|
28010
|
-
claude:
|
|
28246
|
+
claude: path31.resolve(
|
|
28011
28247
|
optionalString(values, "claude-home") ?? (configs[1] && "claudeHome" in configs[1] ? configs[1].claudeHome : sourceHome("claude"))
|
|
28012
28248
|
),
|
|
28013
|
-
cursor:
|
|
28249
|
+
cursor: path31.resolve(
|
|
28014
28250
|
optionalString(values, "cursor-home") ?? (configs[2] && "cursorHome" in configs[2] ? configs[2].cursorHome : sourceHome("cursor"))
|
|
28015
28251
|
)
|
|
28016
28252
|
});
|
|
@@ -28163,8 +28399,33 @@ async function connectAll(values) {
|
|
|
28163
28399
|
)
|
|
28164
28400
|
);
|
|
28165
28401
|
}
|
|
28402
|
+
await addAgentTools(
|
|
28403
|
+
results.map((result) => result.source),
|
|
28404
|
+
sourceHomes
|
|
28405
|
+
);
|
|
28166
28406
|
print(...connectionSummary2(results, results.length > existing.length));
|
|
28167
28407
|
}
|
|
28408
|
+
async function addAgentTools(sources, sourceHomes) {
|
|
28409
|
+
for (const source of new Set(sources)) {
|
|
28410
|
+
try {
|
|
28411
|
+
await installAgentTools(
|
|
28412
|
+
source === "cursor" ? { cursor: true } : source === "claude" ? { claude: sourceHomes.claude } : { codex: sourceHomes.codex }
|
|
28413
|
+
);
|
|
28414
|
+
} catch (error3) {
|
|
28415
|
+
print(
|
|
28416
|
+
mark(
|
|
28417
|
+
terminal,
|
|
28418
|
+
"warning",
|
|
28419
|
+
`Could not add Iteration's tools to ${collectorSourceLabel(source)}`
|
|
28420
|
+
),
|
|
28421
|
+
wrap(
|
|
28422
|
+
terminal,
|
|
28423
|
+
error3 instanceof Error ? error3.message : "Its settings could not be updated."
|
|
28424
|
+
)
|
|
28425
|
+
);
|
|
28426
|
+
}
|
|
28427
|
+
}
|
|
28428
|
+
}
|
|
28168
28429
|
async function importHistory(source, values) {
|
|
28169
28430
|
requireCollectorPlatform();
|
|
28170
28431
|
const directory = dataDirectory(source, values);
|
|
@@ -28494,6 +28755,12 @@ async function runInternalCommand() {
|
|
|
28494
28755
|
}
|
|
28495
28756
|
return true;
|
|
28496
28757
|
}
|
|
28758
|
+
if (process.argv[2] === "mcp") {
|
|
28759
|
+
if (process.argv.length !== 3) throw new Error("Invalid mcp command.");
|
|
28760
|
+
const configs = await Promise.all(COLLECTOR_SOURCES2.map(connectedConfig));
|
|
28761
|
+
await serveAgentTools(configs.find((config3) => config3 !== null) ?? null);
|
|
28762
|
+
return true;
|
|
28763
|
+
}
|
|
28497
28764
|
if (process.argv[2] === "turn-summary-hook") {
|
|
28498
28765
|
const directory = process.argv[3];
|
|
28499
28766
|
if (!directory || process.argv.length !== 4)
|
|
@@ -28595,6 +28862,7 @@ async function disconnect(selectedSource, values) {
|
|
|
28595
28862
|
if ("cursorHome" in config3)
|
|
28596
28863
|
await uninstallCursorHooks(config3.cursorHome, config3.dataDirectory);
|
|
28597
28864
|
else await uninstallTurnSummary(config3);
|
|
28865
|
+
await uninstallAgentTools(agentHomes(config3));
|
|
28598
28866
|
}
|
|
28599
28867
|
print(
|
|
28600
28868
|
mark(
|