iteration-cli 0.17.1 → 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 +581 -324
- 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,
|
|
@@ -16079,10 +16079,10 @@ function mergeDefs2(...defs) {
|
|
|
16079
16079
|
function cloneDef2(schema) {
|
|
16080
16080
|
return mergeDefs2(schema._zod.def);
|
|
16081
16081
|
}
|
|
16082
|
-
function getElementAtPath2(obj,
|
|
16083
|
-
if (!
|
|
16082
|
+
function getElementAtPath2(obj, path32) {
|
|
16083
|
+
if (!path32)
|
|
16084
16084
|
return obj;
|
|
16085
|
-
return
|
|
16085
|
+
return path32.reduce((acc, key) => acc?.[key], obj);
|
|
16086
16086
|
}
|
|
16087
16087
|
function promiseAllObject2(promisesObj) {
|
|
16088
16088
|
const keys = Object.keys(promisesObj);
|
|
@@ -16422,11 +16422,11 @@ function explicitlyAborted2(x, startIndex = 0) {
|
|
|
16422
16422
|
}
|
|
16423
16423
|
return false;
|
|
16424
16424
|
}
|
|
16425
|
-
function prefixIssues2(
|
|
16425
|
+
function prefixIssues2(path32, issues) {
|
|
16426
16426
|
return issues.map((iss) => {
|
|
16427
16427
|
var _a5;
|
|
16428
16428
|
(_a5 = iss).path ?? (_a5.path = []);
|
|
16429
|
-
iss.path.unshift(
|
|
16429
|
+
iss.path.unshift(path32);
|
|
16430
16430
|
return iss;
|
|
16431
16431
|
});
|
|
16432
16432
|
}
|
|
@@ -16884,16 +16884,16 @@ function flattenError2(error3, mapper = (issue3) => issue3.message) {
|
|
|
16884
16884
|
}
|
|
16885
16885
|
function formatError2(error3, mapper = (issue3) => issue3.message) {
|
|
16886
16886
|
const fieldErrors = { _errors: [] };
|
|
16887
|
-
const processError = (error4,
|
|
16887
|
+
const processError = (error4, path32 = []) => {
|
|
16888
16888
|
for (const issue3 of error4.issues) {
|
|
16889
16889
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
16890
|
-
issue3.errors.map((issues) => processError({ issues }, [...
|
|
16890
|
+
issue3.errors.map((issues) => processError({ issues }, [...path32, ...issue3.path]));
|
|
16891
16891
|
} else if (issue3.code === "invalid_key") {
|
|
16892
|
-
processError({ issues: issue3.issues }, [...
|
|
16892
|
+
processError({ issues: issue3.issues }, [...path32, ...issue3.path]);
|
|
16893
16893
|
} else if (issue3.code === "invalid_element") {
|
|
16894
|
-
processError({ issues: issue3.issues }, [...
|
|
16894
|
+
processError({ issues: issue3.issues }, [...path32, ...issue3.path]);
|
|
16895
16895
|
} else {
|
|
16896
|
-
const fullpath = [...
|
|
16896
|
+
const fullpath = [...path32, ...issue3.path];
|
|
16897
16897
|
if (fullpath.length === 0) {
|
|
16898
16898
|
fieldErrors._errors.push(mapper(issue3));
|
|
16899
16899
|
} else {
|
|
@@ -22550,131 +22550,11 @@ function isLaunchDirectory(value) {
|
|
|
22550
22550
|
return true;
|
|
22551
22551
|
}
|
|
22552
22552
|
|
|
22553
|
-
// src/
|
|
22554
|
-
import { createHmac } from "node:crypto";
|
|
22555
|
-
import { promises as fs19 } from "node:fs";
|
|
22556
|
-
import os8 from "node:os";
|
|
22557
|
-
import path24 from "node:path";
|
|
22558
|
-
|
|
22559
|
-
// ../collector-contracts/dist/index.js
|
|
22560
|
-
var cursorBillingRequestSchema = object3({
|
|
22561
|
-
conversationId: uuid5(),
|
|
22562
|
-
reconcileFromMs: number4().int().nonnegative().nullable(),
|
|
22563
|
-
events: array2(object3({
|
|
22564
|
-
timestamp: number4().int().nonnegative(),
|
|
22565
|
-
kind: _enum2([
|
|
22566
|
-
"included",
|
|
22567
|
-
"paid",
|
|
22568
|
-
"byok",
|
|
22569
|
-
"not_charged",
|
|
22570
|
-
"unknown"
|
|
22571
|
-
]),
|
|
22572
|
-
inputTokens: number4().int().nonnegative().nullable(),
|
|
22573
|
-
outputTokens: number4().int().nonnegative().nullable(),
|
|
22574
|
-
cacheReadTokens: number4().int().nonnegative().nullable(),
|
|
22575
|
-
cacheWriteTokens: number4().int().nonnegative().nullable(),
|
|
22576
|
-
paidUsd: number4().finite().nonnegative().nullable()
|
|
22577
|
-
}).strict()).max(5e3)
|
|
22578
|
-
}).strict();
|
|
22579
|
-
function codexCreditSign(value) {
|
|
22580
|
-
const mantissa = value.split(/[eE]/, 1)[0];
|
|
22581
|
-
if (!/[1-9]/.test(mantissa))
|
|
22582
|
-
return 0;
|
|
22583
|
-
return mantissa.startsWith("-") ? -1 : 1;
|
|
22584
|
-
}
|
|
22585
|
-
var codexBillingRequestSchema = object3({
|
|
22586
|
-
accountFingerprint: string5().regex(/^[0-9a-f]{64}$/),
|
|
22587
|
-
reconcile: boolean4(),
|
|
22588
|
-
tasks: array2(object3({
|
|
22589
|
-
threadId: uuid5(),
|
|
22590
|
-
createdAt: iso_exports2.datetime().nullable(),
|
|
22591
|
-
descendantThreadIds: array2(uuid5()).max(900),
|
|
22592
|
-
dataStatus: _enum2([
|
|
22593
|
-
"available",
|
|
22594
|
-
"partial",
|
|
22595
|
-
"unavailable",
|
|
22596
|
-
"not_queried"
|
|
22597
|
-
]),
|
|
22598
|
-
usageSource: string5().max(100),
|
|
22599
|
-
balanceUsageCredits: string5().regex(/^[+-]?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d{1,3})?$/).max(128).nullable()
|
|
22600
|
-
}).strict()).max(100),
|
|
22601
|
-
authTurns: array2(object3({
|
|
22602
|
-
threadId: uuid5(),
|
|
22603
|
-
turnId: uuid5(),
|
|
22604
|
-
mode: _enum2(["chatgpt", "api_key", "conflicting"])
|
|
22605
|
-
}).strict()).max(5e3)
|
|
22606
|
-
}).strict();
|
|
22607
|
-
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}$/;
|
|
22608
|
-
var episodeCountSchema = number4().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
22609
|
-
var collectorFrictionSummarySchema = object3({
|
|
22610
|
-
weekEpisodes: episodeCountSchema,
|
|
22611
|
-
dayEpisodes: episodeCountSchema
|
|
22612
|
-
}).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.");
|
|
22613
|
-
var RECENT_MESSAGE_LIMIT = 400;
|
|
22614
|
-
var sessionCountSchema = number4().int().min(0).max(1e6);
|
|
22615
|
-
var collectorHistoryProgressSchema = object3({
|
|
22616
|
-
sessions: sessionCountSchema,
|
|
22617
|
-
readSessions: sessionCountSchema,
|
|
22618
|
-
complete: boolean4(),
|
|
22619
|
-
recentMessages: object3({
|
|
22620
|
-
sent: number4().int().min(0).max(RECENT_MESSAGE_LIMIT),
|
|
22621
|
-
complete: boolean4()
|
|
22622
|
-
}).strict().optional().describe("The newest messages sent ahead of the rest of the history; collectors before 0.17.0 omit it.")
|
|
22623
|
-
}).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.");
|
|
22624
|
-
var collectorEnrollmentRequestSchema = object3({
|
|
22625
|
-
deviceName: string5().trim().min(1).max(160).describe("Trimmed before length validation."),
|
|
22626
|
-
organizationId: string5().regex(UUID_PATTERN3).optional(),
|
|
22627
|
-
source: _enum2(COLLECTOR_SOURCES2).optional()
|
|
22628
|
-
}).strict();
|
|
22629
|
-
var collectorExpansionRequestSchema = object3({
|
|
22630
|
-
source: _enum2(COLLECTOR_SOURCES2),
|
|
22631
|
-
token: string5().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
22632
|
-
organizationId: string5().regex(UUID_PATTERN3).optional()
|
|
22633
|
-
}).strict();
|
|
22634
|
-
var collectorEnrollmentResponseSchema = discriminatedUnion2("status", [
|
|
22635
|
-
object3({
|
|
22636
|
-
status: literal2("enrolled"),
|
|
22637
|
-
token: string5().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
22638
|
-
deviceId: string5().regex(UUID_PATTERN3),
|
|
22639
|
-
organizationId: string5().regex(UUID_PATTERN3),
|
|
22640
|
-
organizationName: string5().min(1).max(160)
|
|
22641
|
-
}).strict(),
|
|
22642
|
-
object3({
|
|
22643
|
-
status: literal2("choose_organization"),
|
|
22644
|
-
organizations: array2(object3({
|
|
22645
|
-
id: string5().regex(UUID_PATTERN3),
|
|
22646
|
-
name: string5().min(1).max(160)
|
|
22647
|
-
}).strict()).max(20),
|
|
22648
|
-
hasMore: boolean4()
|
|
22649
|
-
}).strict()
|
|
22650
|
-
]);
|
|
22651
|
-
function parseCollectorEnrollmentResponse(input) {
|
|
22652
|
-
const parsed = collectorEnrollmentResponseSchema.safeParse(input);
|
|
22653
|
-
return parsed.success ? { success: true, value: parsed.data } : {
|
|
22654
|
-
success: false,
|
|
22655
|
-
error: parsed.error.issues[0]?.message ?? "Collector enrollment response is invalid."
|
|
22656
|
-
};
|
|
22657
|
-
}
|
|
22658
|
-
function parseCollectorFrictionSummary(input) {
|
|
22659
|
-
const parsed = collectorFrictionSummarySchema.safeParse(input);
|
|
22660
|
-
return parsed.success ? { success: true, value: parsed.data } : {
|
|
22661
|
-
success: false,
|
|
22662
|
-
error: parsed.error.issues[0]?.message ?? "Friction summary is invalid."
|
|
22663
|
-
};
|
|
22664
|
-
}
|
|
22665
|
-
|
|
22666
|
-
// src/background-service.ts
|
|
22667
|
-
import { promises as fs16 } from "node:fs";
|
|
22668
|
-
import os6 from "node:os";
|
|
22669
|
-
import path20 from "node:path";
|
|
22670
|
-
|
|
22671
|
-
// src/launch-agent.ts
|
|
22672
|
-
import { execFile as execFileCallback2 } from "node:child_process";
|
|
22553
|
+
// src/agent-tools.ts
|
|
22673
22554
|
import { promises as fs11 } from "node:fs";
|
|
22674
22555
|
import os3 from "node:os";
|
|
22675
22556
|
import path8 from "node:path";
|
|
22676
|
-
import
|
|
22677
|
-
import { promisify as promisify2 } from "node:util";
|
|
22557
|
+
import readline from "node:readline";
|
|
22678
22558
|
|
|
22679
22559
|
// src/runtime.ts
|
|
22680
22560
|
import { createHash as createHash4 } from "node:crypto";
|
|
@@ -23078,7 +22958,351 @@ async function stableNodePath() {
|
|
|
23078
22958
|
return process.execPath;
|
|
23079
22959
|
}
|
|
23080
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
|
+
|
|
23081
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";
|
|
23082
23306
|
var execFile2 = promisify2(execFileCallback2);
|
|
23083
23307
|
function label(source) {
|
|
23084
23308
|
return `com.iteration.${source}-collector`;
|
|
@@ -23089,16 +23313,16 @@ var RESTART_POLL_MS = 200;
|
|
|
23089
23313
|
function xml(value) {
|
|
23090
23314
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23091
23315
|
}
|
|
23092
|
-
function plistPath(source, homeDirectory =
|
|
23093
|
-
return
|
|
23316
|
+
function plistPath(source, homeDirectory = os4.homedir()) {
|
|
23317
|
+
return path17.join(
|
|
23094
23318
|
homeDirectory,
|
|
23095
23319
|
"Library",
|
|
23096
23320
|
"LaunchAgents",
|
|
23097
23321
|
`${label(source)}.plist`
|
|
23098
23322
|
);
|
|
23099
23323
|
}
|
|
23100
|
-
function launchAgentPlist(launcherPath = runtimePaths().launcher, nodePath = process.execPath, logDirectory =
|
|
23101
|
-
|
|
23324
|
+
function launchAgentPlist(launcherPath = runtimePaths().launcher, nodePath = process.execPath, logDirectory = path17.join(os4.homedir(), "Library", "Logs"), dataDirectory2 = path17.join(
|
|
23325
|
+
os4.homedir(),
|
|
23102
23326
|
".config",
|
|
23103
23327
|
"iteration",
|
|
23104
23328
|
"codex-collector"
|
|
@@ -23121,8 +23345,8 @@ function launchAgentPlist(launcherPath = runtimePaths().launcher, nodePath = pro
|
|
|
23121
23345
|
"<key>RunAtLoad</key><true/>",
|
|
23122
23346
|
"<key>KeepAlive</key><true/>",
|
|
23123
23347
|
"<key>ThrottleInterval</key><integer>10</integer>",
|
|
23124
|
-
`<key>StandardOutPath</key><string>${xml(
|
|
23125
|
-
`<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>`,
|
|
23126
23350
|
"</dict></plist>"
|
|
23127
23351
|
].join("");
|
|
23128
23352
|
}
|
|
@@ -23202,17 +23426,17 @@ async function installLaunchAgent(dataDirectory2, source = "codex") {
|
|
|
23202
23426
|
throw new Error("Automatic startup is currently supported on macOS only.");
|
|
23203
23427
|
}
|
|
23204
23428
|
const file = plistPath(source);
|
|
23205
|
-
const launchAgents =
|
|
23206
|
-
const logs =
|
|
23207
|
-
await
|
|
23208
|
-
await
|
|
23209
|
-
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(
|
|
23210
23434
|
file,
|
|
23211
23435
|
launchAgentPlist(
|
|
23212
23436
|
void 0,
|
|
23213
23437
|
await stableNodePath(),
|
|
23214
23438
|
void 0,
|
|
23215
|
-
dataDirectory2 ??
|
|
23439
|
+
dataDirectory2 ?? path17.join(os4.homedir(), ".config", "iteration", `${source}-collector`),
|
|
23216
23440
|
source
|
|
23217
23441
|
),
|
|
23218
23442
|
{ encoding: "utf8", mode: 420 }
|
|
@@ -23244,7 +23468,7 @@ async function uninstallLaunchAgent(source = "codex") {
|
|
|
23244
23468
|
}
|
|
23245
23469
|
const file = plistPath(source);
|
|
23246
23470
|
await bootoutIfLoaded(launchctlTarget(), source);
|
|
23247
|
-
await
|
|
23471
|
+
await fs12.rm(file, { force: true });
|
|
23248
23472
|
}
|
|
23249
23473
|
async function launchAgentStatus(source = "codex") {
|
|
23250
23474
|
if (process.platform !== "darwin") return false;
|
|
@@ -23265,21 +23489,21 @@ function launchAgentRunning(output) {
|
|
|
23265
23489
|
|
|
23266
23490
|
// src/runtime-install.ts
|
|
23267
23491
|
import { execFile as execFileCallback4 } from "node:child_process";
|
|
23268
|
-
import { promises as
|
|
23492
|
+
import { promises as fs14 } from "node:fs";
|
|
23269
23493
|
import { promisify as promisify4 } from "node:util";
|
|
23270
23494
|
|
|
23271
23495
|
// src/updater.ts
|
|
23272
23496
|
import { execFile as execFileCallback3 } from "node:child_process";
|
|
23273
23497
|
import { createHash as createHash5 } from "node:crypto";
|
|
23274
|
-
import { createWriteStream as createWriteStream2, promises as
|
|
23498
|
+
import { createWriteStream as createWriteStream2, promises as fs13 } from "node:fs";
|
|
23275
23499
|
import http from "node:http";
|
|
23276
23500
|
import https2 from "node:https";
|
|
23277
|
-
import
|
|
23501
|
+
import path18 from "node:path";
|
|
23278
23502
|
import { Transform } from "node:stream";
|
|
23279
23503
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
23280
23504
|
import { promisify as promisify3 } from "node:util";
|
|
23281
23505
|
var execFile3 = promisify3(execFileCallback3);
|
|
23282
|
-
var TAR = process.platform === "win32" ?
|
|
23506
|
+
var TAR = process.platform === "win32" ? path18.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe") : "tar";
|
|
23283
23507
|
var PACKAGE_NAME = "iteration-cli";
|
|
23284
23508
|
var MAX_METADATA_BYTES = 16 * 1024 * 1024;
|
|
23285
23509
|
var MAX_TARBALL_BYTES = 64 * 1024 * 1024;
|
|
@@ -23483,32 +23707,32 @@ async function selfCheck(paths, cliPath, version3) {
|
|
|
23483
23707
|
}
|
|
23484
23708
|
async function installCandidate(paths, candidate, signal) {
|
|
23485
23709
|
await ensureRuntimeDirectory(paths);
|
|
23486
|
-
const staged = await
|
|
23487
|
-
|
|
23710
|
+
const staged = await fs13.mkdtemp(
|
|
23711
|
+
path18.join(paths.staging, `download-${candidate.version}-`)
|
|
23488
23712
|
);
|
|
23489
23713
|
try {
|
|
23490
|
-
const archive =
|
|
23714
|
+
const archive = path18.join(staged, "package.tgz");
|
|
23491
23715
|
await downloadVerified(
|
|
23492
23716
|
candidate.tarball,
|
|
23493
23717
|
candidate.integrity,
|
|
23494
23718
|
archive,
|
|
23495
23719
|
signal
|
|
23496
23720
|
);
|
|
23497
|
-
const extracted =
|
|
23498
|
-
await
|
|
23721
|
+
const extracted = path18.join(staged, "extracted");
|
|
23722
|
+
await fs13.mkdir(extracted, { mode: 448 });
|
|
23499
23723
|
await execFile3(TAR, ["-xzf", archive, "-C", extracted], {
|
|
23500
23724
|
timeout: REQUEST_TIMEOUT_MS,
|
|
23501
23725
|
windowsHide: true
|
|
23502
23726
|
});
|
|
23503
|
-
const packageRoot =
|
|
23727
|
+
const packageRoot = path18.join(extracted, "package");
|
|
23504
23728
|
await selfCheck(
|
|
23505
23729
|
paths,
|
|
23506
|
-
|
|
23730
|
+
path18.join(packageRoot, "dist", "cli.js"),
|
|
23507
23731
|
candidate.version
|
|
23508
23732
|
);
|
|
23509
23733
|
await installVersionDirectory(paths, packageRoot, candidate.version);
|
|
23510
23734
|
} finally {
|
|
23511
|
-
await
|
|
23735
|
+
await fs13.rm(staged, { recursive: true, force: true });
|
|
23512
23736
|
}
|
|
23513
23737
|
}
|
|
23514
23738
|
async function switchVersion(paths, from, version3, previous, expected, nowMs) {
|
|
@@ -23616,7 +23840,7 @@ async function ownVersion() {
|
|
|
23616
23840
|
}
|
|
23617
23841
|
async function exists(filename) {
|
|
23618
23842
|
try {
|
|
23619
|
-
await
|
|
23843
|
+
await fs14.access(filename);
|
|
23620
23844
|
return true;
|
|
23621
23845
|
} catch (error3) {
|
|
23622
23846
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
@@ -23643,7 +23867,7 @@ async function installLauncher(paths, version3) {
|
|
|
23643
23867
|
);
|
|
23644
23868
|
await commitLauncher(paths, staged);
|
|
23645
23869
|
} finally {
|
|
23646
|
-
await
|
|
23870
|
+
await fs14.rm(staged, { force: true });
|
|
23647
23871
|
}
|
|
23648
23872
|
}
|
|
23649
23873
|
async function ensureRuntimeInstalled(expected, paths = runtimePaths()) {
|
|
@@ -23725,9 +23949,9 @@ async function expireRuntimeTrial(nowMs, paths = runtimePaths()) {
|
|
|
23725
23949
|
|
|
23726
23950
|
// src/systemd-user.ts
|
|
23727
23951
|
import { execFile as execFileCallback5 } from "node:child_process";
|
|
23728
|
-
import { promises as
|
|
23729
|
-
import
|
|
23730
|
-
import
|
|
23952
|
+
import { promises as fs15 } from "node:fs";
|
|
23953
|
+
import os5 from "node:os";
|
|
23954
|
+
import path19 from "node:path";
|
|
23731
23955
|
import { promisify as promisify5 } from "node:util";
|
|
23732
23956
|
var execFile5 = promisify5(execFileCallback5);
|
|
23733
23957
|
var SYSTEMCTL_TIMEOUT_MS = 1e4;
|
|
@@ -23797,8 +24021,8 @@ function unitName(source) {
|
|
|
23797
24021
|
return `iteration-${source}-collector.service`;
|
|
23798
24022
|
}
|
|
23799
24023
|
function unitPath(source) {
|
|
23800
|
-
return
|
|
23801
|
-
|
|
24024
|
+
return path19.join(
|
|
24025
|
+
os5.homedir(),
|
|
23802
24026
|
".config",
|
|
23803
24027
|
"systemd",
|
|
23804
24028
|
"user",
|
|
@@ -23806,8 +24030,8 @@ function unitPath(source) {
|
|
|
23806
24030
|
);
|
|
23807
24031
|
}
|
|
23808
24032
|
function systemdLogPath(source) {
|
|
23809
|
-
return
|
|
23810
|
-
|
|
24033
|
+
return path19.join(
|
|
24034
|
+
os5.homedir(),
|
|
23811
24035
|
".config",
|
|
23812
24036
|
"iteration",
|
|
23813
24037
|
"logs",
|
|
@@ -23819,13 +24043,13 @@ function unitValue(value) {
|
|
|
23819
24043
|
throw new Error("Collector paths cannot contain line breaks.");
|
|
23820
24044
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("%", "%%")}"`;
|
|
23821
24045
|
}
|
|
23822
|
-
function systemdUserUnit(launcherPath = runtimePaths().launcher, nodePath = process.execPath, dataDirectory2 =
|
|
23823
|
-
|
|
24046
|
+
function systemdUserUnit(launcherPath = runtimePaths().launcher, nodePath = process.execPath, dataDirectory2 = path19.join(
|
|
24047
|
+
os5.homedir(),
|
|
23824
24048
|
".config",
|
|
23825
24049
|
"iteration",
|
|
23826
24050
|
"codex-collector"
|
|
23827
|
-
), source = "codex", outputPath =
|
|
23828
|
-
|
|
24051
|
+
), source = "codex", outputPath = path19.join(
|
|
24052
|
+
os5.homedir(),
|
|
23829
24053
|
".config",
|
|
23830
24054
|
"iteration",
|
|
23831
24055
|
"logs",
|
|
@@ -23855,10 +24079,10 @@ async function systemctl(...args) {
|
|
|
23855
24079
|
async function installSystemdUserService(dataDirectory2, source) {
|
|
23856
24080
|
await ensureSystemdUserLinger();
|
|
23857
24081
|
const file = unitPath(source);
|
|
23858
|
-
const logDirectory =
|
|
23859
|
-
await
|
|
23860
|
-
await
|
|
23861
|
-
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(
|
|
23862
24086
|
file,
|
|
23863
24087
|
systemdUserUnit(void 0, await stableNodePath(), dataDirectory2, source),
|
|
23864
24088
|
{
|
|
@@ -23874,14 +24098,14 @@ async function installSystemdUserService(dataDirectory2, source) {
|
|
|
23874
24098
|
async function uninstallSystemdUserService(source) {
|
|
23875
24099
|
const file = unitPath(source);
|
|
23876
24100
|
try {
|
|
23877
|
-
await
|
|
24101
|
+
await fs15.access(file);
|
|
23878
24102
|
} catch (error3) {
|
|
23879
24103
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
23880
24104
|
return;
|
|
23881
24105
|
throw error3;
|
|
23882
24106
|
}
|
|
23883
24107
|
await systemctl("disable", "--now", unitName(source));
|
|
23884
|
-
await
|
|
24108
|
+
await fs15.rm(file);
|
|
23885
24109
|
await systemctl("daemon-reload");
|
|
23886
24110
|
}
|
|
23887
24111
|
async function systemdUserServiceStatus(source) {
|
|
@@ -23900,9 +24124,9 @@ async function systemdUserServiceStatus(source) {
|
|
|
23900
24124
|
|
|
23901
24125
|
// src/task-scheduler.ts
|
|
23902
24126
|
import { execFile as execFileCallback6 } from "node:child_process";
|
|
23903
|
-
import { promises as
|
|
23904
|
-
import
|
|
23905
|
-
import
|
|
24127
|
+
import { promises as fs16 } from "node:fs";
|
|
24128
|
+
import os6 from "node:os";
|
|
24129
|
+
import path20 from "node:path";
|
|
23906
24130
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
23907
24131
|
import { promisify as promisify6 } from "node:util";
|
|
23908
24132
|
|
|
@@ -24004,14 +24228,14 @@ function scheduledTaskName(source, sid) {
|
|
|
24004
24228
|
return `iteration-${sid}-${source}-collector`;
|
|
24005
24229
|
}
|
|
24006
24230
|
function servicesDirectory() {
|
|
24007
|
-
return
|
|
24231
|
+
return path20.join(os6.homedir(), ".config", "iteration", "services");
|
|
24008
24232
|
}
|
|
24009
24233
|
function taskDefinitionPath(source) {
|
|
24010
|
-
return
|
|
24234
|
+
return path20.join(servicesDirectory(), `iteration-${source}-collector.xml`);
|
|
24011
24235
|
}
|
|
24012
24236
|
function windowsLogPath(source) {
|
|
24013
|
-
return
|
|
24014
|
-
|
|
24237
|
+
return path20.join(
|
|
24238
|
+
os6.homedir(),
|
|
24015
24239
|
".config",
|
|
24016
24240
|
"iteration",
|
|
24017
24241
|
"logs",
|
|
@@ -24019,8 +24243,8 @@ function windowsLogPath(source) {
|
|
|
24019
24243
|
);
|
|
24020
24244
|
}
|
|
24021
24245
|
function windowsOutputPath(source) {
|
|
24022
|
-
return
|
|
24023
|
-
|
|
24246
|
+
return path20.join(
|
|
24247
|
+
os6.homedir(),
|
|
24024
24248
|
".config",
|
|
24025
24249
|
"iteration",
|
|
24026
24250
|
"logs",
|
|
@@ -24035,7 +24259,7 @@ function scheduledTaskScript(task) {
|
|
|
24035
24259
|
"--data-directory",
|
|
24036
24260
|
task.dataDirectory
|
|
24037
24261
|
].map(windowsArgument).join(" ");
|
|
24038
|
-
const errorLog =
|
|
24262
|
+
const errorLog = path20.join(
|
|
24039
24263
|
task.home,
|
|
24040
24264
|
".config",
|
|
24041
24265
|
"iteration",
|
|
@@ -24155,7 +24379,7 @@ function AccountSid([string]$account) {
|
|
|
24155
24379
|
async function schtasks(source, operation, ...args) {
|
|
24156
24380
|
try {
|
|
24157
24381
|
await execFile6(
|
|
24158
|
-
|
|
24382
|
+
path20.join(
|
|
24159
24383
|
process.env.SystemRoot ?? "C:\\Windows",
|
|
24160
24384
|
"System32",
|
|
24161
24385
|
"schtasks.exe"
|
|
@@ -24199,7 +24423,7 @@ async function desiredTask(dataDirectory2, source) {
|
|
|
24199
24423
|
userSid: await currentUserSid(),
|
|
24200
24424
|
nodePath: await stableNodePath(),
|
|
24201
24425
|
launcher: runtimePaths().launcher,
|
|
24202
|
-
home:
|
|
24426
|
+
home: os6.homedir()
|
|
24203
24427
|
};
|
|
24204
24428
|
}
|
|
24205
24429
|
async function scheduledTaskUsesRuntime(dataDirectory2, source) {
|
|
@@ -24211,10 +24435,10 @@ async function scheduledTaskUsesRuntime(dataDirectory2, source) {
|
|
|
24211
24435
|
async function installScheduledTask(dataDirectory2, source) {
|
|
24212
24436
|
const file = taskDefinitionPath(source);
|
|
24213
24437
|
await ensurePrivateDirectory(servicesDirectory());
|
|
24214
|
-
await ensurePrivateDirectory(
|
|
24438
|
+
await ensurePrivateDirectory(path20.dirname(windowsLogPath(source)));
|
|
24215
24439
|
await stopTask(source);
|
|
24216
24440
|
const xml2 = scheduledTaskXml(await desiredTask(dataDirectory2, source));
|
|
24217
|
-
await
|
|
24441
|
+
await fs16.writeFile(
|
|
24218
24442
|
file,
|
|
24219
24443
|
Buffer.concat([Buffer.from([255, 254]), Buffer.from(xml2, "utf16le")])
|
|
24220
24444
|
);
|
|
@@ -24224,7 +24448,7 @@ async function installScheduledTask(dataDirectory2, source) {
|
|
|
24224
24448
|
}
|
|
24225
24449
|
async function uninstallScheduledTask(source) {
|
|
24226
24450
|
if (await stopTask(source)) await schtasks(source, "/Delete", "/F");
|
|
24227
|
-
await
|
|
24451
|
+
await fs16.rm(taskDefinitionPath(source), { force: true });
|
|
24228
24452
|
}
|
|
24229
24453
|
async function scheduledTaskStatus(source) {
|
|
24230
24454
|
return (await observedTask(source))?.state === 4;
|
|
@@ -24248,8 +24472,8 @@ async function prepareBackgroundPersistence() {
|
|
|
24248
24472
|
function collectorLogPath(source) {
|
|
24249
24473
|
if (process.platform === "linux") return systemdLogPath(source);
|
|
24250
24474
|
if (process.platform === "win32") return windowsLogPath(source);
|
|
24251
|
-
return
|
|
24252
|
-
|
|
24475
|
+
return path21.join(
|
|
24476
|
+
os7.homedir(),
|
|
24253
24477
|
"Library",
|
|
24254
24478
|
"Logs",
|
|
24255
24479
|
`iteration-${source}-collector.error.log`
|
|
@@ -24283,7 +24507,7 @@ async function backgroundServiceDefinition(source) {
|
|
|
24283
24507
|
requireCollectorPlatform();
|
|
24284
24508
|
const file = process.platform === "darwin" ? plistPath(source) : process.platform === "linux" ? unitPath(source) : taskDefinitionPath(source);
|
|
24285
24509
|
try {
|
|
24286
|
-
return await
|
|
24510
|
+
return await fs17.readFile(
|
|
24287
24511
|
file,
|
|
24288
24512
|
process.platform === "win32" ? "utf16le" : "utf8"
|
|
24289
24513
|
);
|
|
@@ -24332,7 +24556,7 @@ function serviceDataDirectory(definition, platform) {
|
|
|
24332
24556
|
(_, slashes) => slashes.slice(0, slashes.length / 2)
|
|
24333
24557
|
);
|
|
24334
24558
|
}
|
|
24335
|
-
if (!directory || !(platform === "win32" ?
|
|
24559
|
+
if (!directory || !(platform === "win32" ? path21.win32 : path21.posix).isAbsolute(directory))
|
|
24336
24560
|
throw new Error("Could not read the collector service data directory.");
|
|
24337
24561
|
return directory;
|
|
24338
24562
|
}
|
|
@@ -24355,15 +24579,15 @@ async function backgroundServiceUsesRuntime(directory, source) {
|
|
|
24355
24579
|
}
|
|
24356
24580
|
|
|
24357
24581
|
// src/config-paths.ts
|
|
24358
|
-
import
|
|
24359
|
-
import
|
|
24582
|
+
import os8 from "node:os";
|
|
24583
|
+
import path22 from "node:path";
|
|
24360
24584
|
function defaultCollectorDirectory(source) {
|
|
24361
|
-
return
|
|
24585
|
+
return path22.join(os8.homedir(), ".config", "iteration", `${source}-collector`);
|
|
24362
24586
|
}
|
|
24363
24587
|
|
|
24364
24588
|
// src/cursor-hooks.ts
|
|
24365
|
-
import { promises as
|
|
24366
|
-
import
|
|
24589
|
+
import { promises as fs18 } from "node:fs";
|
|
24590
|
+
import path23 from "node:path";
|
|
24367
24591
|
function shellQuote(value) {
|
|
24368
24592
|
if (process.platform === "win32") return `"${value}"`;
|
|
24369
24593
|
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
@@ -24398,8 +24622,8 @@ async function readHooks(filename) {
|
|
|
24398
24622
|
let contents;
|
|
24399
24623
|
let mode = 384;
|
|
24400
24624
|
try {
|
|
24401
|
-
contents = await
|
|
24402
|
-
mode = (await
|
|
24625
|
+
contents = await fs18.readFile(filename, "utf8");
|
|
24626
|
+
mode = (await fs18.stat(filename)).mode & 511;
|
|
24403
24627
|
} catch (error3) {
|
|
24404
24628
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24405
24629
|
return { file: {}, mode };
|
|
@@ -24421,14 +24645,14 @@ async function readHooks(filename) {
|
|
|
24421
24645
|
return { file: checked.data, mode };
|
|
24422
24646
|
}
|
|
24423
24647
|
async function writeHooks(filename, file, mode) {
|
|
24424
|
-
await
|
|
24425
|
-
const target = await
|
|
24648
|
+
await fs18.mkdir(path23.dirname(filename), { recursive: true, mode: 448 });
|
|
24649
|
+
const target = await fs18.realpath(filename).catch((error3) => {
|
|
24426
24650
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24427
24651
|
return filename;
|
|
24428
24652
|
throw error3;
|
|
24429
24653
|
});
|
|
24430
24654
|
const temporary = `${target}.iteration-${process.pid}.tmp`;
|
|
24431
|
-
const handle = await
|
|
24655
|
+
const handle = await fs18.open(temporary, "w", mode);
|
|
24432
24656
|
try {
|
|
24433
24657
|
await handle.writeFile(`${JSON.stringify(file, null, 2)}
|
|
24434
24658
|
`, "utf8");
|
|
@@ -24436,14 +24660,14 @@ async function writeHooks(filename, file, mode) {
|
|
|
24436
24660
|
} finally {
|
|
24437
24661
|
await handle.close();
|
|
24438
24662
|
}
|
|
24439
|
-
await
|
|
24663
|
+
await fs18.rename(temporary, target);
|
|
24440
24664
|
}
|
|
24441
24665
|
function entries(value) {
|
|
24442
24666
|
return value ?? [];
|
|
24443
24667
|
}
|
|
24444
24668
|
async function installCursorHooks(cursorHome, dataDirectory2) {
|
|
24445
24669
|
await ensurePrivateDirectory(cursorHookDirectory(dataDirectory2));
|
|
24446
|
-
const filename =
|
|
24670
|
+
const filename = path23.join(cursorHome, "hooks.json");
|
|
24447
24671
|
const { file, mode } = await readHooks(filename);
|
|
24448
24672
|
const hooks = { ...file.hooks };
|
|
24449
24673
|
const nodePath = await stableNodePath();
|
|
@@ -24457,7 +24681,7 @@ async function installCursorHooks(cursorHome, dataDirectory2) {
|
|
|
24457
24681
|
await writeHooks(filename, { ...file, version: 1, hooks }, mode);
|
|
24458
24682
|
}
|
|
24459
24683
|
async function uninstallCursorHooks(cursorHome, dataDirectory2) {
|
|
24460
|
-
const filename =
|
|
24684
|
+
const filename = path23.join(cursorHome, "hooks.json");
|
|
24461
24685
|
const { file, mode } = await readHooks(filename);
|
|
24462
24686
|
const hooks = { ...file.hooks };
|
|
24463
24687
|
let changed = false;
|
|
@@ -24487,8 +24711,8 @@ function silenceCollectorLogs() {
|
|
|
24487
24711
|
// src/turn-summary.ts
|
|
24488
24712
|
import { execFile as execFileCallback7 } from "node:child_process";
|
|
24489
24713
|
import { createHash as createHash6 } from "node:crypto";
|
|
24490
|
-
import { promises as
|
|
24491
|
-
import
|
|
24714
|
+
import { promises as fs19 } from "node:fs";
|
|
24715
|
+
import path24 from "node:path";
|
|
24492
24716
|
import { promisify as promisify7 } from "node:util";
|
|
24493
24717
|
import { crc32 } from "node:zlib";
|
|
24494
24718
|
var execFile7 = promisify7(execFileCallback7);
|
|
@@ -24499,13 +24723,13 @@ var REQUEST_TIMEOUT_MS2 = 1e4;
|
|
|
24499
24723
|
var HOOK_TIMEOUT_SECONDS = 1;
|
|
24500
24724
|
var REQUEST_KEY_PATTERN = /^\d{1,10}$/;
|
|
24501
24725
|
function turnSummaryPaths(dataDirectory2) {
|
|
24502
|
-
const directory =
|
|
24726
|
+
const directory = path24.join(dataDirectory2, "turn-summary");
|
|
24503
24727
|
return {
|
|
24504
24728
|
directory,
|
|
24505
|
-
script:
|
|
24506
|
-
requests:
|
|
24507
|
-
lines:
|
|
24508
|
-
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")
|
|
24509
24733
|
};
|
|
24510
24734
|
}
|
|
24511
24735
|
function shellQuote2(value) {
|
|
@@ -24561,7 +24785,7 @@ async function sessionStartCommand(config3) {
|
|
|
24561
24785
|
function agentHookFile(config3) {
|
|
24562
24786
|
if ("cursorHome" in config3)
|
|
24563
24787
|
throw new Error("Cursor uses its own trace hooks.");
|
|
24564
|
-
return "claudeHome" in config3 ?
|
|
24788
|
+
return "claudeHome" in config3 ? path24.join(config3.claudeHome, "settings.json") : path24.join(config3.codexHome, "hooks.json");
|
|
24565
24789
|
}
|
|
24566
24790
|
var hookEntrySchema2 = object3({
|
|
24567
24791
|
command: string5().optional(),
|
|
@@ -24578,8 +24802,8 @@ async function readHookFile(filename) {
|
|
|
24578
24802
|
let contents;
|
|
24579
24803
|
let mode = 384;
|
|
24580
24804
|
try {
|
|
24581
|
-
contents = await
|
|
24582
|
-
mode = (await
|
|
24805
|
+
contents = await fs19.readFile(filename, "utf8");
|
|
24806
|
+
mode = (await fs19.stat(filename)).mode & 511;
|
|
24583
24807
|
} catch (error3) {
|
|
24584
24808
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT") {
|
|
24585
24809
|
return { file: {}, mode };
|
|
@@ -24605,19 +24829,19 @@ async function readHookFile(filename) {
|
|
|
24605
24829
|
return { file: parsed.data, mode };
|
|
24606
24830
|
}
|
|
24607
24831
|
async function writeHookFile(filename, file, mode) {
|
|
24608
|
-
await
|
|
24609
|
-
const target = await
|
|
24832
|
+
await fs19.mkdir(path24.dirname(filename), { recursive: true });
|
|
24833
|
+
const target = await fs19.realpath(filename).catch((error3) => {
|
|
24610
24834
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24611
24835
|
return filename;
|
|
24612
24836
|
throw error3;
|
|
24613
24837
|
});
|
|
24614
24838
|
const temporary = `${target}.iteration-${process.pid}.tmp`;
|
|
24615
|
-
await
|
|
24839
|
+
await fs19.writeFile(temporary, `${JSON.stringify(file, null, 2)}
|
|
24616
24840
|
`, {
|
|
24617
24841
|
encoding: "utf8",
|
|
24618
24842
|
mode
|
|
24619
24843
|
});
|
|
24620
|
-
await
|
|
24844
|
+
await fs19.rename(temporary, target);
|
|
24621
24845
|
}
|
|
24622
24846
|
function withoutCommand(groups, command) {
|
|
24623
24847
|
return groups.flatMap((group) => {
|
|
@@ -24642,24 +24866,24 @@ async function installTurnSummary(config3) {
|
|
|
24642
24866
|
[paths.requests, paths.lines, paths.shown].map(ensurePrivateDirectory)
|
|
24643
24867
|
);
|
|
24644
24868
|
if (process.platform !== "win32") {
|
|
24645
|
-
await
|
|
24869
|
+
await fs19.writeFile(paths.script, hookScript(paths), {
|
|
24646
24870
|
encoding: "utf8",
|
|
24647
24871
|
mode: 448
|
|
24648
24872
|
});
|
|
24649
|
-
await
|
|
24873
|
+
await fs19.chmod(paths.script, 448);
|
|
24650
24874
|
}
|
|
24651
24875
|
if ("claudeHome" in config3) {
|
|
24652
24876
|
const gitPaths = claudeGitHookPaths(config3.dataDirectory);
|
|
24653
24877
|
await ensurePrivateDirectory(gitPaths.queue);
|
|
24654
24878
|
if (process.platform !== "win32") {
|
|
24655
|
-
await
|
|
24879
|
+
await fs19.writeFile(
|
|
24656
24880
|
gitPaths.script,
|
|
24657
24881
|
`#!/bin/sh
|
|
24658
24882
|
exec ${shellQuote2(await stableNodePath())} ${shellQuote2(runtimePaths().launcher)} claude-git-hook ${shellQuote2(config3.dataDirectory)}
|
|
24659
24883
|
`,
|
|
24660
24884
|
{ encoding: "utf8", mode: 448 }
|
|
24661
24885
|
);
|
|
24662
|
-
await
|
|
24886
|
+
await fs19.chmod(gitPaths.script, 448);
|
|
24663
24887
|
}
|
|
24664
24888
|
}
|
|
24665
24889
|
const filename = agentHookFile(config3);
|
|
@@ -24749,19 +24973,19 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24749
24973
|
windowsHide: true
|
|
24750
24974
|
}
|
|
24751
24975
|
));
|
|
24752
|
-
directory =
|
|
24976
|
+
directory = path24.normalize(directory.trim());
|
|
24753
24977
|
} catch {
|
|
24754
24978
|
quiet();
|
|
24755
24979
|
return;
|
|
24756
24980
|
}
|
|
24757
|
-
if (!
|
|
24981
|
+
if (!path24.isAbsolute(directory)) {
|
|
24758
24982
|
quiet();
|
|
24759
24983
|
return;
|
|
24760
24984
|
}
|
|
24761
24985
|
const key = String(crc32(directory));
|
|
24762
24986
|
const paths = turnSummaryPaths(dataDirectory2);
|
|
24763
24987
|
try {
|
|
24764
|
-
await
|
|
24988
|
+
await fs19.writeFile(path24.join(paths.requests, key), `${directory}
|
|
24765
24989
|
`, {
|
|
24766
24990
|
encoding: "utf8",
|
|
24767
24991
|
mode: 384
|
|
@@ -24770,7 +24994,7 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24770
24994
|
}
|
|
24771
24995
|
let lines;
|
|
24772
24996
|
try {
|
|
24773
|
-
lines = await
|
|
24997
|
+
lines = await fs19.readFile(path24.join(paths.lines, key), "utf8");
|
|
24774
24998
|
} catch {
|
|
24775
24999
|
quiet();
|
|
24776
25000
|
return;
|
|
@@ -24782,7 +25006,7 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24782
25006
|
}
|
|
24783
25007
|
let last;
|
|
24784
25008
|
try {
|
|
24785
|
-
last = (await
|
|
25009
|
+
last = (await fs19.readFile(path24.join(paths.shown, key), "utf8")).split("\n")[0] ?? null;
|
|
24786
25010
|
} catch {
|
|
24787
25011
|
last = null;
|
|
24788
25012
|
}
|
|
@@ -24791,7 +25015,7 @@ async function captureTurnSummary(dataDirectory2) {
|
|
|
24791
25015
|
return;
|
|
24792
25016
|
}
|
|
24793
25017
|
try {
|
|
24794
|
-
await
|
|
25018
|
+
await fs19.writeFile(path24.join(paths.shown, key), `${message}
|
|
24795
25019
|
`, {
|
|
24796
25020
|
encoding: "utf8",
|
|
24797
25021
|
mode: 384
|
|
@@ -24851,7 +25075,7 @@ async function fetchSummary(config3, directory, fetcher, signal) {
|
|
|
24851
25075
|
}
|
|
24852
25076
|
async function readRequest(filename) {
|
|
24853
25077
|
try {
|
|
24854
|
-
const [directory] = (await
|
|
25078
|
+
const [directory] = (await fs19.readFile(filename, "utf8")).split("\n");
|
|
24855
25079
|
return directory ?? null;
|
|
24856
25080
|
} catch (error3) {
|
|
24857
25081
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
@@ -24860,25 +25084,25 @@ async function readRequest(filename) {
|
|
|
24860
25084
|
}
|
|
24861
25085
|
}
|
|
24862
25086
|
async function writeLine(paths, key, directory, message) {
|
|
24863
|
-
const filename =
|
|
25087
|
+
const filename = path24.join(paths.lines, key);
|
|
24864
25088
|
if (message === null) {
|
|
24865
|
-
await
|
|
25089
|
+
await fs19.rm(filename, { force: true });
|
|
24866
25090
|
return;
|
|
24867
25091
|
}
|
|
24868
25092
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
24869
|
-
await
|
|
25093
|
+
await fs19.writeFile(
|
|
24870
25094
|
temporary,
|
|
24871
25095
|
`${directory}
|
|
24872
25096
|
${JSON.stringify({ systemMessage: message })}
|
|
24873
25097
|
`,
|
|
24874
25098
|
{ encoding: "utf8", mode: 384 }
|
|
24875
25099
|
);
|
|
24876
|
-
await
|
|
25100
|
+
await fs19.rename(temporary, filename);
|
|
24877
25101
|
}
|
|
24878
25102
|
async function forget(paths, key) {
|
|
24879
25103
|
await Promise.all(
|
|
24880
25104
|
[paths.requests, paths.lines, paths.shown].map(
|
|
24881
|
-
(directory) =>
|
|
25105
|
+
(directory) => fs19.rm(path24.join(directory, key), { force: true })
|
|
24882
25106
|
)
|
|
24883
25107
|
);
|
|
24884
25108
|
}
|
|
@@ -24886,7 +25110,7 @@ async function refreshTurnSummaries(config3, refreshedAt, nowMs, fetcher = colle
|
|
|
24886
25110
|
const paths = turnSummaryPaths(config3.dataDirectory);
|
|
24887
25111
|
let keys;
|
|
24888
25112
|
try {
|
|
24889
|
-
keys = await
|
|
25113
|
+
keys = await fs19.readdir(paths.requests);
|
|
24890
25114
|
} catch (error3) {
|
|
24891
25115
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24892
25116
|
return 0;
|
|
@@ -24896,8 +25120,8 @@ async function refreshTurnSummaries(config3, refreshedAt, nowMs, fetcher = colle
|
|
|
24896
25120
|
for (const key of keys.sort()) {
|
|
24897
25121
|
signal?.throwIfAborted();
|
|
24898
25122
|
if (!REQUEST_KEY_PATTERN.test(key)) continue;
|
|
24899
|
-
const filename =
|
|
24900
|
-
const stats = await
|
|
25123
|
+
const filename = path24.join(paths.requests, key);
|
|
25124
|
+
const stats = await fs19.stat(filename).catch((error3) => {
|
|
24901
25125
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
24902
25126
|
return null;
|
|
24903
25127
|
throw error3;
|
|
@@ -24964,8 +25188,8 @@ async function codexTurnSummaryApproval(config3) {
|
|
|
24964
25188
|
if (handlerIndex < 0) continue;
|
|
24965
25189
|
let configToml;
|
|
24966
25190
|
try {
|
|
24967
|
-
configToml = await
|
|
24968
|
-
|
|
25191
|
+
configToml = await fs19.readFile(
|
|
25192
|
+
path24.join(config3.codexHome, "config.toml"),
|
|
24969
25193
|
"utf8"
|
|
24970
25194
|
);
|
|
24971
25195
|
} catch (error3) {
|
|
@@ -24992,25 +25216,25 @@ var consentSchema = object3({
|
|
|
24992
25216
|
sourceHomes: object3({
|
|
24993
25217
|
codex: string5(),
|
|
24994
25218
|
claude: string5(),
|
|
24995
|
-
cursor: string5().default(
|
|
25219
|
+
cursor: string5().default(path25.join(os9.homedir(), ".cursor"))
|
|
24996
25220
|
}).strict()
|
|
24997
25221
|
}).strict();
|
|
24998
25222
|
function consentPath() {
|
|
24999
|
-
return
|
|
25223
|
+
return path25.join(os9.homedir(), ".config", "iteration", "auto-connect.json");
|
|
25000
25224
|
}
|
|
25001
25225
|
async function removeMachineConsent() {
|
|
25002
|
-
await
|
|
25226
|
+
await fs20.rm(consentPath(), { force: true });
|
|
25003
25227
|
}
|
|
25004
25228
|
async function detectedSources(sourceHomes) {
|
|
25005
25229
|
const detected = [];
|
|
25006
25230
|
for (const source of COLLECTOR_SOURCES2) {
|
|
25007
|
-
const directory =
|
|
25231
|
+
const directory = path25.join(
|
|
25008
25232
|
sourceHomes[source],
|
|
25009
25233
|
source === "codex" ? "sessions" : "projects"
|
|
25010
25234
|
);
|
|
25011
25235
|
let stats;
|
|
25012
25236
|
try {
|
|
25013
|
-
stats = await
|
|
25237
|
+
stats = await fs20.stat(directory);
|
|
25014
25238
|
} catch (error3) {
|
|
25015
25239
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25016
25240
|
continue;
|
|
@@ -25030,7 +25254,7 @@ async function detectedSources(sourceHomes) {
|
|
|
25030
25254
|
async function loadMachineConsent() {
|
|
25031
25255
|
let text;
|
|
25032
25256
|
try {
|
|
25033
|
-
text = await
|
|
25257
|
+
text = await fs20.readFile(consentPath(), "utf8");
|
|
25034
25258
|
} catch (error3) {
|
|
25035
25259
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25036
25260
|
return null;
|
|
@@ -25056,9 +25280,9 @@ async function saveMachineConsent(consent) {
|
|
|
25056
25280
|
const parsed = consentSchema.parse(consent);
|
|
25057
25281
|
validateCollectorEndpoint(parsed.endpoint);
|
|
25058
25282
|
const filename = consentPath();
|
|
25059
|
-
await ensurePrivateDirectory(
|
|
25283
|
+
await ensurePrivateDirectory(path25.dirname(filename));
|
|
25060
25284
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
25061
|
-
const handle = await
|
|
25285
|
+
const handle = await fs20.open(temporary, "w", 384);
|
|
25062
25286
|
try {
|
|
25063
25287
|
await handle.writeFile(`${JSON.stringify(parsed)}
|
|
25064
25288
|
`, "utf8");
|
|
@@ -25066,7 +25290,7 @@ async function saveMachineConsent(consent) {
|
|
|
25066
25290
|
} finally {
|
|
25067
25291
|
await handle.close();
|
|
25068
25292
|
}
|
|
25069
|
-
await
|
|
25293
|
+
await fs20.rename(temporary, filename);
|
|
25070
25294
|
}
|
|
25071
25295
|
async function readCollectorScope(anchor3) {
|
|
25072
25296
|
const endpoint = validateCollectorEndpoint(anchor3.endpoint);
|
|
@@ -25162,7 +25386,7 @@ async function connectNewDetectedSources(anchor3, consent) {
|
|
|
25162
25386
|
if (source === consent.anchorSource) continue;
|
|
25163
25387
|
const paths = collectorPaths(defaultCollectorDirectory(source));
|
|
25164
25388
|
try {
|
|
25165
|
-
await
|
|
25389
|
+
await fs20.access(paths.config);
|
|
25166
25390
|
continue;
|
|
25167
25391
|
} catch (error3) {
|
|
25168
25392
|
if (!(error3 instanceof Error && "code" in error3 && error3.code === "ENOENT"))
|
|
@@ -25203,7 +25427,7 @@ async function connectNewDetectedSources(anchor3, consent) {
|
|
|
25203
25427
|
async function connectedConfig(source) {
|
|
25204
25428
|
const paths = collectorPaths(defaultCollectorDirectory(source));
|
|
25205
25429
|
try {
|
|
25206
|
-
await
|
|
25430
|
+
await fs20.access(paths.config);
|
|
25207
25431
|
} catch (error3) {
|
|
25208
25432
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25209
25433
|
return null;
|
|
@@ -25697,7 +25921,7 @@ async function authenticateAndEnrollCollector(endpoint, deviceNameValue, organiz
|
|
|
25697
25921
|
}
|
|
25698
25922
|
|
|
25699
25923
|
// src/history-import.ts
|
|
25700
|
-
import
|
|
25924
|
+
import path26 from "node:path";
|
|
25701
25925
|
function backgroundControl(source) {
|
|
25702
25926
|
return {
|
|
25703
25927
|
isRunning: () => backgroundServiceStatus(source),
|
|
@@ -25710,7 +25934,7 @@ async function importSourceHistory(config3, paths, confirmed, control = backgrou
|
|
|
25710
25934
|
const source = collectorSource(config3);
|
|
25711
25935
|
const directory = collectorSourceDirectory(config3);
|
|
25712
25936
|
const state = await loadState(paths);
|
|
25713
|
-
if (!state.initialized || state.sourceDirectory !==
|
|
25937
|
+
if (!state.initialized || state.sourceDirectory !== path26.resolve(directory)) {
|
|
25714
25938
|
throw new Error(
|
|
25715
25939
|
`Connect the ${source} source before importing its history.`
|
|
25716
25940
|
);
|
|
@@ -25759,36 +25983,36 @@ async function importSourceHistory(config3, paths, confirmed, control = backgrou
|
|
|
25759
25983
|
|
|
25760
25984
|
// src/logout.ts
|
|
25761
25985
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
25762
|
-
import { promises as
|
|
25763
|
-
import
|
|
25764
|
-
import
|
|
25986
|
+
import { promises as fs21 } from "node:fs";
|
|
25987
|
+
import os10 from "node:os";
|
|
25988
|
+
import path27 from "node:path";
|
|
25765
25989
|
async function pendingDirectories(filename) {
|
|
25766
25990
|
let contents;
|
|
25767
25991
|
try {
|
|
25768
|
-
contents = await
|
|
25992
|
+
contents = await fs21.readFile(filename, "utf8");
|
|
25769
25993
|
} catch (error3) {
|
|
25770
25994
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25771
25995
|
return [];
|
|
25772
25996
|
throw error3;
|
|
25773
25997
|
}
|
|
25774
|
-
const parsed = array2(string5().refine(
|
|
25998
|
+
const parsed = array2(string5().refine(path27.isAbsolute)).max(64).safeParse(JSON.parse(contents));
|
|
25775
25999
|
if (!parsed.success)
|
|
25776
26000
|
throw new Error("Pending logout directories are invalid.");
|
|
25777
26001
|
return parsed.data;
|
|
25778
26002
|
}
|
|
25779
26003
|
async function savePendingDirectories(filename, directories) {
|
|
25780
|
-
await ensurePrivateDirectory(
|
|
26004
|
+
await ensurePrivateDirectory(path27.dirname(filename));
|
|
25781
26005
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
25782
|
-
await
|
|
26006
|
+
await fs21.writeFile(temporary, JSON.stringify([...directories]), {
|
|
25783
26007
|
mode: 384
|
|
25784
26008
|
});
|
|
25785
|
-
await
|
|
26009
|
+
await fs21.rename(temporary, filename);
|
|
25786
26010
|
}
|
|
25787
26011
|
async function clearConnection(directory) {
|
|
25788
26012
|
const paths = collectorPaths(directory);
|
|
25789
26013
|
let names;
|
|
25790
26014
|
try {
|
|
25791
|
-
names = await
|
|
26015
|
+
names = await fs21.readdir(directory);
|
|
25792
26016
|
} catch (error3) {
|
|
25793
26017
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25794
26018
|
return;
|
|
@@ -25798,14 +26022,15 @@ async function clearConnection(directory) {
|
|
|
25798
26022
|
try {
|
|
25799
26023
|
for (const name of names)
|
|
25800
26024
|
if (/^config\.json\.\d+\.tmp$/.test(name))
|
|
25801
|
-
await
|
|
25802
|
-
if (!names.includes(
|
|
26025
|
+
await fs21.rm(path27.join(directory, name), { force: true });
|
|
26026
|
+
if (!names.includes(path27.basename(paths.config))) return;
|
|
25803
26027
|
const config3 = await loadConfig(paths);
|
|
25804
26028
|
if (config3.destination === "vault")
|
|
25805
26029
|
throw new Error("This directory belongs to Trace Vault, not Iteration.");
|
|
25806
26030
|
if ("cursorHome" in config3)
|
|
25807
26031
|
await uninstallCursorHooks(config3.cursorHome, config3.dataDirectory);
|
|
25808
26032
|
else await uninstallTurnSummary(config3);
|
|
26033
|
+
await uninstallAgentTools(agentHomes(config3));
|
|
25809
26034
|
const retained = [
|
|
25810
26035
|
paths.state,
|
|
25811
26036
|
paths.outbox,
|
|
@@ -25820,27 +26045,27 @@ async function clearConnection(directory) {
|
|
|
25820
26045
|
"turn-summary",
|
|
25821
26046
|
"codex-billing-sync.json",
|
|
25822
26047
|
"cursor-billing-sync.json"
|
|
25823
|
-
].map((name) =>
|
|
26048
|
+
].map((name) => path27.join(directory, name))
|
|
25824
26049
|
];
|
|
25825
|
-
const archive =
|
|
26050
|
+
const archive = path27.join(directory, "logged-out", randomUUID3());
|
|
25826
26051
|
await ensurePrivateDirectory(archive);
|
|
25827
26052
|
for (const filename of retained) {
|
|
25828
26053
|
try {
|
|
25829
|
-
await
|
|
26054
|
+
await fs21.rename(filename, path27.join(archive, path27.basename(filename)));
|
|
25830
26055
|
} catch (error3) {
|
|
25831
26056
|
if (!(error3 instanceof Error && "code" in error3 && error3.code === "ENOENT"))
|
|
25832
26057
|
throw error3;
|
|
25833
26058
|
}
|
|
25834
26059
|
}
|
|
25835
|
-
await
|
|
26060
|
+
await fs21.rm(paths.config);
|
|
25836
26061
|
} finally {
|
|
25837
26062
|
await release();
|
|
25838
26063
|
}
|
|
25839
26064
|
}
|
|
25840
26065
|
async function logout(extraDirectory) {
|
|
25841
26066
|
requireCollectorPlatform();
|
|
25842
|
-
const pending =
|
|
25843
|
-
|
|
26067
|
+
const pending = path27.join(
|
|
26068
|
+
os10.homedir(),
|
|
25844
26069
|
".config",
|
|
25845
26070
|
"iteration",
|
|
25846
26071
|
"logout-pending.json"
|
|
@@ -25850,7 +26075,7 @@ async function logout(extraDirectory) {
|
|
|
25850
26075
|
...await pendingDirectories(pending)
|
|
25851
26076
|
]);
|
|
25852
26077
|
if (extraDirectory !== void 0)
|
|
25853
|
-
directories.add(
|
|
26078
|
+
directories.add(path27.resolve(extraDirectory));
|
|
25854
26079
|
const failures = [];
|
|
25855
26080
|
try {
|
|
25856
26081
|
await removeMachineConsent();
|
|
@@ -25895,7 +26120,7 @@ async function logout(extraDirectory) {
|
|
|
25895
26120
|
`Logout did not finish. Resolve these errors and run iteration logout again:
|
|
25896
26121
|
${failures.join("\n")}`
|
|
25897
26122
|
);
|
|
25898
|
-
await
|
|
26123
|
+
await fs21.rm(pending);
|
|
25899
26124
|
}
|
|
25900
26125
|
|
|
25901
26126
|
// src/runtime-services.ts
|
|
@@ -25926,8 +26151,8 @@ import { setTimeout as delay5 } from "node:timers/promises";
|
|
|
25926
26151
|
|
|
25927
26152
|
// src/codex-billing.ts
|
|
25928
26153
|
import { createHash as createHash7 } from "node:crypto";
|
|
25929
|
-
import { promises as
|
|
25930
|
-
import
|
|
26154
|
+
import { promises as fs22 } from "node:fs";
|
|
26155
|
+
import path28 from "node:path";
|
|
25931
26156
|
var TASK_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage/thread_usage/query_v2";
|
|
25932
26157
|
var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
25933
26158
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -25979,7 +26204,7 @@ function fingerprint(value) {
|
|
|
25979
26204
|
async function readAuth(codexHome) {
|
|
25980
26205
|
let contents;
|
|
25981
26206
|
try {
|
|
25982
|
-
contents = await
|
|
26207
|
+
contents = await fs22.readFile(path28.join(codexHome, "auth.json"), "utf8");
|
|
25983
26208
|
} catch (error3) {
|
|
25984
26209
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
25985
26210
|
return {
|
|
@@ -26014,7 +26239,7 @@ async function readAuth(codexHome) {
|
|
|
26014
26239
|
async function readState(filename) {
|
|
26015
26240
|
let contents;
|
|
26016
26241
|
try {
|
|
26017
|
-
contents = await
|
|
26242
|
+
contents = await fs22.readFile(filename, "utf8");
|
|
26018
26243
|
} catch (error3) {
|
|
26019
26244
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
26020
26245
|
return null;
|
|
@@ -26036,7 +26261,7 @@ async function readState(filename) {
|
|
|
26036
26261
|
}
|
|
26037
26262
|
async function saveState2(filename, state) {
|
|
26038
26263
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
26039
|
-
const handle = await
|
|
26264
|
+
const handle = await fs22.open(temporary, "w", 384);
|
|
26040
26265
|
try {
|
|
26041
26266
|
await handle.writeFile(`${JSON.stringify(state)}
|
|
26042
26267
|
`);
|
|
@@ -26044,11 +26269,11 @@ async function saveState2(filename, state) {
|
|
|
26044
26269
|
} finally {
|
|
26045
26270
|
await handle.close();
|
|
26046
26271
|
}
|
|
26047
|
-
await
|
|
26272
|
+
await fs22.rename(temporary, filename);
|
|
26048
26273
|
}
|
|
26049
26274
|
async function localThread(filename) {
|
|
26050
|
-
const stat = await
|
|
26051
|
-
const handle = await
|
|
26275
|
+
const stat = await fs22.stat(filename);
|
|
26276
|
+
const handle = await fs22.open(filename, "r");
|
|
26052
26277
|
let header = null;
|
|
26053
26278
|
try {
|
|
26054
26279
|
const buffer = Buffer.alloc(64 * 1024);
|
|
@@ -26148,9 +26373,9 @@ function parseCodexAuthLog(threadId, body) {
|
|
|
26148
26373
|
return { threadId, turnId: turn[1], mode };
|
|
26149
26374
|
}
|
|
26150
26375
|
async function localAuthTurns(codexHome, modelProviders) {
|
|
26151
|
-
const filename =
|
|
26376
|
+
const filename = path28.join(codexHome, "logs_2.sqlite");
|
|
26152
26377
|
try {
|
|
26153
|
-
await
|
|
26378
|
+
await fs22.access(filename);
|
|
26154
26379
|
} catch (error3) {
|
|
26155
26380
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
26156
26381
|
return [];
|
|
@@ -26243,7 +26468,7 @@ async function queryTaskUsage(tasks, accessToken, accountId, signal) {
|
|
|
26243
26468
|
}
|
|
26244
26469
|
async function syncCodexBilling(config3, fetcher = collectorFetch, signal) {
|
|
26245
26470
|
const auth = await readAuth(config3.codexHome);
|
|
26246
|
-
const stateFile =
|
|
26471
|
+
const stateFile = path28.join(config3.dataDirectory, "codex-billing-sync.json");
|
|
26247
26472
|
const prior = await readState(stateFile);
|
|
26248
26473
|
const nowMs = Date.now();
|
|
26249
26474
|
const history = prior === null || prior.accountFingerprint !== auth.accountFingerprint;
|
|
@@ -26414,9 +26639,9 @@ async function syncCodexBilling(config3, fetcher = collectorFetch, signal) {
|
|
|
26414
26639
|
|
|
26415
26640
|
// src/cursor-billing.ts
|
|
26416
26641
|
import { createHash as createHash8 } from "node:crypto";
|
|
26417
|
-
import { promises as
|
|
26418
|
-
import
|
|
26419
|
-
import
|
|
26642
|
+
import { promises as fs23 } from "node:fs";
|
|
26643
|
+
import os11 from "node:os";
|
|
26644
|
+
import path29 from "node:path";
|
|
26420
26645
|
var CURSOR_USAGE_URL = "https://api2.cursor.sh/aiserver.v1.DashboardService/GetFilteredUsageEvents";
|
|
26421
26646
|
var PAGE_SIZE = 500;
|
|
26422
26647
|
var MAX_PAGES = 1e3;
|
|
@@ -26447,18 +26672,18 @@ var usagePageSchema = object3({
|
|
|
26447
26672
|
var emptyUsagePageSchema = object3({}).strict();
|
|
26448
26673
|
function cursorAuthDatabase() {
|
|
26449
26674
|
if (process.platform === "darwin")
|
|
26450
|
-
return
|
|
26451
|
-
|
|
26675
|
+
return path29.join(
|
|
26676
|
+
os11.homedir(),
|
|
26452
26677
|
"Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
|
26453
26678
|
);
|
|
26454
26679
|
if (process.platform === "linux")
|
|
26455
|
-
return
|
|
26456
|
-
|
|
26680
|
+
return path29.join(
|
|
26681
|
+
os11.homedir(),
|
|
26457
26682
|
".config/Cursor/User/globalStorage/state.vscdb"
|
|
26458
26683
|
);
|
|
26459
26684
|
if (process.platform === "win32")
|
|
26460
|
-
return
|
|
26461
|
-
process.env.APPDATA ??
|
|
26685
|
+
return path29.join(
|
|
26686
|
+
process.env.APPDATA ?? path29.join(os11.homedir(), "AppData", "Roaming"),
|
|
26462
26687
|
"Cursor/User/globalStorage/state.vscdb"
|
|
26463
26688
|
);
|
|
26464
26689
|
return null;
|
|
@@ -26500,7 +26725,7 @@ async function readCursorAuth() {
|
|
|
26500
26725
|
async function loadBillingState(filename) {
|
|
26501
26726
|
let contents;
|
|
26502
26727
|
try {
|
|
26503
|
-
contents = await
|
|
26728
|
+
contents = await fs23.readFile(filename, "utf8");
|
|
26504
26729
|
} catch (error3) {
|
|
26505
26730
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
26506
26731
|
return null;
|
|
@@ -26516,7 +26741,7 @@ async function loadBillingState(filename) {
|
|
|
26516
26741
|
}
|
|
26517
26742
|
async function saveBillingState(filename, state) {
|
|
26518
26743
|
const temporary = `${filename}.${process.pid}.tmp`;
|
|
26519
|
-
const handle = await
|
|
26744
|
+
const handle = await fs23.open(temporary, "w", 384);
|
|
26520
26745
|
try {
|
|
26521
26746
|
await handle.writeFile(`${JSON.stringify(state)}
|
|
26522
26747
|
`, "utf8");
|
|
@@ -26524,7 +26749,7 @@ async function saveBillingState(filename, state) {
|
|
|
26524
26749
|
} finally {
|
|
26525
26750
|
await handle.close();
|
|
26526
26751
|
}
|
|
26527
|
-
await
|
|
26752
|
+
await fs23.rename(temporary, filename);
|
|
26528
26753
|
}
|
|
26529
26754
|
function planCursorBillingSync(state, accountFingerprint, nowMs) {
|
|
26530
26755
|
if (state === null || state.accountFingerprint !== accountFingerprint)
|
|
@@ -26546,7 +26771,7 @@ function planCursorBillingSync(state, accountFingerprint, nowMs) {
|
|
|
26546
26771
|
}
|
|
26547
26772
|
function cursorConversationIds(filenames) {
|
|
26548
26773
|
return new Set(
|
|
26549
|
-
filenames.map((filename) =>
|
|
26774
|
+
filenames.map((filename) => path29.basename(filename, ".jsonl")).filter((id) => UUID3.test(id))
|
|
26550
26775
|
);
|
|
26551
26776
|
}
|
|
26552
26777
|
function billingKind(kind) {
|
|
@@ -26604,11 +26829,11 @@ async function syncCursorBilling(config3, fetcher = collectorFetch, signal) {
|
|
|
26604
26829
|
if (auth === null)
|
|
26605
26830
|
return { sessions: 0, matched: 0, skipped: true, mode: null };
|
|
26606
26831
|
const localConversations = cursorConversationIds(
|
|
26607
|
-
await cursorFiles(
|
|
26832
|
+
await cursorFiles(path29.join(config3.cursorHome, "projects"))
|
|
26608
26833
|
);
|
|
26609
26834
|
if (localConversations.size === 0)
|
|
26610
26835
|
return { sessions: 0, matched: 0, skipped: true, mode: null };
|
|
26611
|
-
const stateFile =
|
|
26836
|
+
const stateFile = path29.join(config3.dataDirectory, "cursor-billing-sync.json");
|
|
26612
26837
|
const priorState = await loadBillingState(stateFile);
|
|
26613
26838
|
const nowMs = Date.now();
|
|
26614
26839
|
const plan = planCursorBillingSync(
|
|
@@ -27534,26 +27759,26 @@ function renderRuntime(terminal2, summary) {
|
|
|
27534
27759
|
|
|
27535
27760
|
// src/windows-supervisor.ts
|
|
27536
27761
|
import { spawn } from "node:child_process";
|
|
27537
|
-
import { promises as
|
|
27538
|
-
import
|
|
27762
|
+
import { promises as fs24 } from "node:fs";
|
|
27763
|
+
import path30 from "node:path";
|
|
27539
27764
|
import { setTimeout as delay6 } from "node:timers/promises";
|
|
27540
27765
|
var MAX_LOG_BYTES = 8 * 1024 * 1024;
|
|
27541
27766
|
var RESTART_DELAY_MS = 5e3;
|
|
27542
27767
|
async function appendLog(filename, bytes) {
|
|
27543
27768
|
let offset = 0;
|
|
27544
27769
|
while (offset < bytes.length) {
|
|
27545
|
-
const size = await
|
|
27770
|
+
const size = await fs24.stat(filename).then((stat) => stat.size).catch((error3) => {
|
|
27546
27771
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT")
|
|
27547
27772
|
return 0;
|
|
27548
27773
|
throw error3;
|
|
27549
27774
|
});
|
|
27550
27775
|
if (size >= MAX_LOG_BYTES) {
|
|
27551
|
-
await
|
|
27552
|
-
await
|
|
27776
|
+
await fs24.rm(`${filename}.1`, { force: true });
|
|
27777
|
+
await fs24.rename(filename, `${filename}.1`);
|
|
27553
27778
|
continue;
|
|
27554
27779
|
}
|
|
27555
27780
|
const count = Math.min(bytes.length - offset, MAX_LOG_BYTES - size);
|
|
27556
|
-
await
|
|
27781
|
+
await fs24.appendFile(filename, bytes.subarray(offset, offset + count), {
|
|
27557
27782
|
mode: 384
|
|
27558
27783
|
});
|
|
27559
27784
|
offset += count;
|
|
@@ -27569,7 +27794,7 @@ async function copyOutput(stream, filename) {
|
|
|
27569
27794
|
async function superviseCollector(source, dataDirectory2) {
|
|
27570
27795
|
const output = windowsOutputPath(source);
|
|
27571
27796
|
const errors = windowsLogPath(source);
|
|
27572
|
-
await ensurePrivateDirectory(
|
|
27797
|
+
await ensurePrivateDirectory(path30.dirname(output));
|
|
27573
27798
|
const controller = new AbortController();
|
|
27574
27799
|
const stop = () => controller.abort();
|
|
27575
27800
|
process.once("SIGTERM", stop);
|
|
@@ -27781,7 +28006,7 @@ function usage(command) {
|
|
|
27781
28006
|
}
|
|
27782
28007
|
async function fileExists(filename) {
|
|
27783
28008
|
try {
|
|
27784
|
-
await
|
|
28009
|
+
await fs25.access(filename);
|
|
27785
28010
|
return true;
|
|
27786
28011
|
} catch (error3) {
|
|
27787
28012
|
if (error3 instanceof Error && "code" in error3 && error3.code === "ENOENT") {
|
|
@@ -27822,7 +28047,7 @@ async function defaultCommand() {
|
|
|
27822
28047
|
await connectAll({});
|
|
27823
28048
|
}
|
|
27824
28049
|
function dataDirectory(source, values) {
|
|
27825
|
-
return
|
|
28050
|
+
return path31.resolve(
|
|
27826
28051
|
optionalString(values, "data-directory") ?? defaultCollectorDirectory(source)
|
|
27827
28052
|
);
|
|
27828
28053
|
}
|
|
@@ -27902,12 +28127,12 @@ async function initialize(source, values) {
|
|
|
27902
28127
|
requireCollectorPlatform();
|
|
27903
28128
|
const endpoint = optionalString(values, "endpoint") ?? DEFAULT_INGEST_ENDPOINT;
|
|
27904
28129
|
const endpointUrl = validateCollectorEndpoint(endpoint);
|
|
27905
|
-
const deviceName = optionalString(values, "device-name") ??
|
|
28130
|
+
const deviceName = optionalString(values, "device-name") ?? os12.hostname();
|
|
27906
28131
|
const organizationId = optionalString(values, "workspace");
|
|
27907
28132
|
const directory = dataDirectory(source, values);
|
|
27908
28133
|
const paths = collectorPaths(directory);
|
|
27909
|
-
const selectedHome =
|
|
27910
|
-
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")
|
|
27911
28136
|
);
|
|
27912
28137
|
await assertFreshCollectorDirectory(paths, source);
|
|
27913
28138
|
const preparedState = await prepareSourceInitialState(
|
|
@@ -27986,7 +28211,7 @@ async function approveAllSources(sources, workspaceName, yes) {
|
|
|
27986
28211
|
"",
|
|
27987
28212
|
wrap(
|
|
27988
28213
|
terminal,
|
|
27989
|
-
`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." : ""}`
|
|
27990
28215
|
),
|
|
27991
28216
|
""
|
|
27992
28217
|
);
|
|
@@ -28015,13 +28240,13 @@ async function connectAll(values) {
|
|
|
28015
28240
|
}
|
|
28016
28241
|
const configs = await Promise.all(COLLECTOR_SOURCES2.map(connectedConfig));
|
|
28017
28242
|
const resolveSourceHomes = () => ({
|
|
28018
|
-
codex:
|
|
28243
|
+
codex: path31.resolve(
|
|
28019
28244
|
optionalString(values, "codex-home") ?? (configs[0] && "codexHome" in configs[0] ? configs[0].codexHome : sourceHome("codex"))
|
|
28020
28245
|
),
|
|
28021
|
-
claude:
|
|
28246
|
+
claude: path31.resolve(
|
|
28022
28247
|
optionalString(values, "claude-home") ?? (configs[1] && "claudeHome" in configs[1] ? configs[1].claudeHome : sourceHome("claude"))
|
|
28023
28248
|
),
|
|
28024
|
-
cursor:
|
|
28249
|
+
cursor: path31.resolve(
|
|
28025
28250
|
optionalString(values, "cursor-home") ?? (configs[2] && "cursorHome" in configs[2] ? configs[2].cursorHome : sourceHome("cursor"))
|
|
28026
28251
|
)
|
|
28027
28252
|
});
|
|
@@ -28174,8 +28399,33 @@ async function connectAll(values) {
|
|
|
28174
28399
|
)
|
|
28175
28400
|
);
|
|
28176
28401
|
}
|
|
28402
|
+
await addAgentTools(
|
|
28403
|
+
results.map((result) => result.source),
|
|
28404
|
+
sourceHomes
|
|
28405
|
+
);
|
|
28177
28406
|
print(...connectionSummary2(results, results.length > existing.length));
|
|
28178
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
|
+
}
|
|
28179
28429
|
async function importHistory(source, values) {
|
|
28180
28430
|
requireCollectorPlatform();
|
|
28181
28431
|
const directory = dataDirectory(source, values);
|
|
@@ -28505,6 +28755,12 @@ async function runInternalCommand() {
|
|
|
28505
28755
|
}
|
|
28506
28756
|
return true;
|
|
28507
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
|
+
}
|
|
28508
28764
|
if (process.argv[2] === "turn-summary-hook") {
|
|
28509
28765
|
const directory = process.argv[3];
|
|
28510
28766
|
if (!directory || process.argv.length !== 4)
|
|
@@ -28606,6 +28862,7 @@ async function disconnect(selectedSource, values) {
|
|
|
28606
28862
|
if ("cursorHome" in config3)
|
|
28607
28863
|
await uninstallCursorHooks(config3.cursorHome, config3.dataDirectory);
|
|
28608
28864
|
else await uninstallTurnSummary(config3);
|
|
28865
|
+
await uninstallAgentTools(agentHomes(config3));
|
|
28609
28866
|
}
|
|
28610
28867
|
print(
|
|
28611
28868
|
mark(
|