iteration-cli 0.12.0 → 0.13.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 +8 -2
- package/dist/cli.js +165 -18
- package/dist/cursor-hook-entry.js +6 -0
- package/dist/launcher.js +6 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
# Iteration CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Connect a computer with the command shown on your Iteration workspace's overview:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npx iteration-cli connect --workspace <workspace ID>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
`--workspace` connects to that workspace without a prompt. The collectors keep running from their own copy of the CLI, so the command does not need a global install. To keep the `iteration` command for status and later changes, install it globally:
|
|
4
10
|
|
|
5
11
|
```sh
|
|
6
12
|
npm install --global iteration-cli
|
|
7
13
|
iteration connect
|
|
8
14
|
```
|
|
9
15
|
|
|
10
|
-
The collectors run on macOS or Linux with Node.js 22 or later. Cursor's local Agents window collector is tested on macOS. Linux needs systemd. The CLI automatically enables background collection after logout and installs a user service that starts at boot and restarts on failure. If server policy does not let the user enable this, an administrator must allow background services for the account. The setting applies to the whole Linux account and remains enabled after `iteration disconnect`; the CLI does not turn off other user services. `iteration connect` finds supported agents with local session directories, asks once before uploading
|
|
16
|
+
The collectors run on macOS or Linux with Node.js 22 or later. Cursor's local Agents window collector is tested on macOS. Linux needs systemd. The CLI automatically enables background collection after logout and installs a user service that starts at boot and restarts on failure. If server policy does not let the user enable this, an administrator must allow background services for the account. The setting applies to the whole Linux account and remains enabled after `iteration disconnect`; the CLI does not turn off other user services. `iteration connect` finds supported agents with local session directories, shows how many saved sessions each one has, asks once before uploading them and future activity, and connects them to one workspace. Saved sessions import newest first, and each collector reports its import progress to Iteration until it completes. A connected collector checks for newly detected supported agents and connects them under that approval. Each source has its own background process, local checkpoint, and upload queue. Run `iteration` to see connected sources, `iteration status cursor` for Cursor details, and `iteration help` for other commands. Source-specific connect commands remain available for advanced setups.
|
|
11
17
|
|
|
12
18
|
Cursor's **This Mac** Agents sessions are read from `~/.cursor/projects/*/agent-transcripts/<conversation>/<conversation>.jsonl`. Connecting Cursor also installs user-level hooks in `~/.cursor/hooks.json` automatically. They capture tool output, thought blocks, model and usage fields, subagent transcripts, and other lifecycle records that the main transcript omits; the collector queues those records locally before upload. Existing hooks are preserved, and `iteration disconnect cursor` removes only Iteration's entries. No Cursor approval or settings step is needed. A custom Cursor directory can be selected with `iteration connect cursor --cursor-home DIR`. Local history predating connection has transcript messages and tool calls, but tool results that Cursor never wrote to its transcript cannot be recovered. Cloud Agents are outside this local collector.
|
|
13
19
|
|
package/dist/cli.js
CHANGED
|
@@ -7633,6 +7633,12 @@ var acknowledgementSchema = object({
|
|
|
7633
7633
|
}).strict();
|
|
7634
7634
|
var episodeCountSchema = number2().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
7635
7635
|
var collectorFrictionSummarySchema = object({ weekEpisodes: episodeCountSchema, dayEpisodes: episodeCountSchema }).strict().refine((summary) => summary.dayEpisodes <= summary.weekEpisodes, "The last day cannot have more friction episodes than the last week.");
|
|
7636
|
+
var sessionCountSchema = number2().int().min(0).max(1e6);
|
|
7637
|
+
var collectorHistoryProgressSchema = object({
|
|
7638
|
+
sessions: sessionCountSchema,
|
|
7639
|
+
readSessions: sessionCountSchema,
|
|
7640
|
+
complete: boolean2()
|
|
7641
|
+
}).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.");
|
|
7636
7642
|
var collectorEnrollmentRequestSchema = object({
|
|
7637
7643
|
deviceName: string2().trim().min(1).max(160),
|
|
7638
7644
|
organizationId: string2().regex(UUID_PATTERN).optional(),
|
|
@@ -7933,7 +7939,7 @@ async function clerkDeviceSignIn(configuration) {
|
|
|
7933
7939
|
);
|
|
7934
7940
|
const verificationUrl = challenge.verification_uri_complete ?? challenge.verification_uri;
|
|
7935
7941
|
process.stdout.write(
|
|
7936
|
-
"Sign in to Iteration
|
|
7942
|
+
"Sign in to Iteration in your browser and confirm this code.\nCode: " + challenge.user_code + "\nLink: " + verificationUrl + "\n"
|
|
7937
7943
|
);
|
|
7938
7944
|
await openBrowser(verificationUrl);
|
|
7939
7945
|
return pollForAccessToken(
|
|
@@ -7981,7 +7987,7 @@ async function chooseOrganization(organizations, hasMore) {
|
|
|
7981
7987
|
);
|
|
7982
7988
|
}
|
|
7983
7989
|
if (process.stdin.isTTY !== true) {
|
|
7984
|
-
throw new Error("Run iteration interactively or pass --
|
|
7990
|
+
throw new Error("Run iteration interactively or pass --workspace.");
|
|
7985
7991
|
}
|
|
7986
7992
|
const prompt = createInterface({
|
|
7987
7993
|
input: process.stdin,
|
|
@@ -15081,6 +15087,38 @@ async function claudeFiles(root) {
|
|
|
15081
15087
|
}
|
|
15082
15088
|
return files.sort();
|
|
15083
15089
|
}
|
|
15090
|
+
function isSessionFile(filename) {
|
|
15091
|
+
return !filename.includes(`${path8.sep}subagents${path8.sep}`);
|
|
15092
|
+
}
|
|
15093
|
+
async function countSavedSessions(source, home) {
|
|
15094
|
+
return (await sourceFiles(source, home)).filter(isSessionFile).length;
|
|
15095
|
+
}
|
|
15096
|
+
async function sourceFilesNewestFirst(source, home) {
|
|
15097
|
+
const files = await sourceFiles(source, home);
|
|
15098
|
+
const listed = [];
|
|
15099
|
+
for (let start2 = 0; start2 < files.length; start2 += 64) {
|
|
15100
|
+
const batch = files.slice(start2, start2 + 64);
|
|
15101
|
+
const stats = await Promise.all(batch.map((filename) => fs8.stat(filename)));
|
|
15102
|
+
for (const [index, stat] of stats.entries()) {
|
|
15103
|
+
const filename = batch[index];
|
|
15104
|
+
if (filename === void 0) continue;
|
|
15105
|
+
listed.push({
|
|
15106
|
+
filename,
|
|
15107
|
+
size: stat.size,
|
|
15108
|
+
modifiedMs: stat.mtimeMs,
|
|
15109
|
+
session: isSessionFile(filename)
|
|
15110
|
+
});
|
|
15111
|
+
}
|
|
15112
|
+
}
|
|
15113
|
+
listed.sort(
|
|
15114
|
+
(left, right) => right.modifiedMs - left.modifiedMs || left.filename.localeCompare(right.filename)
|
|
15115
|
+
);
|
|
15116
|
+
return listed.map(({ filename, size, session }) => ({
|
|
15117
|
+
filename,
|
|
15118
|
+
size,
|
|
15119
|
+
session
|
|
15120
|
+
}));
|
|
15121
|
+
}
|
|
15084
15122
|
function sourceFiles(source, home) {
|
|
15085
15123
|
const directory = path8.resolve(home);
|
|
15086
15124
|
if (source === "codex") return rolloutFiles(path8.join(directory, "sessions"));
|
|
@@ -17021,9 +17059,13 @@ async function scanSourceOnce(config2, paths, signal) {
|
|
|
17021
17059
|
}
|
|
17022
17060
|
const cursors = { ...state.cursors };
|
|
17023
17061
|
const skipping = new Set(state.skipping);
|
|
17062
|
+
const sessionFiles = await sourceFilesNewestFirst(source, sourceDirectory);
|
|
17063
|
+
const listedSizes = new Map(
|
|
17064
|
+
sessionFiles.map((file) => [file.filename, file.size])
|
|
17065
|
+
);
|
|
17024
17066
|
const files = [
|
|
17025
17067
|
...source === "claude" ? await claudeGitHookFiles(config2.dataDirectory) : [],
|
|
17026
|
-
...
|
|
17068
|
+
...sessionFiles.map((file) => file.filename),
|
|
17027
17069
|
...source === "cursor" ? await cursorHookFiles(config2.dataDirectory) : []
|
|
17028
17070
|
];
|
|
17029
17071
|
const completedHooks = [];
|
|
@@ -17039,15 +17081,15 @@ async function scanSourceOnce(config2, paths, signal) {
|
|
|
17039
17081
|
caughtUp = false;
|
|
17040
17082
|
break;
|
|
17041
17083
|
}
|
|
17042
|
-
const
|
|
17084
|
+
const size = listedSizes.get(filename) ?? (await fs13.stat(filename)).size;
|
|
17043
17085
|
let offset = cursors[filename] ?? 0;
|
|
17044
|
-
if (offset >
|
|
17086
|
+
if (offset > size) {
|
|
17045
17087
|
logGap(filename, offset, "rollout_file_shrank_resetting_cursor");
|
|
17046
17088
|
offset = 0;
|
|
17047
17089
|
skipping.delete(filename);
|
|
17048
17090
|
}
|
|
17049
17091
|
const bytesToRead = Math.min(
|
|
17050
|
-
|
|
17092
|
+
size - offset,
|
|
17051
17093
|
MAX_SCAN_BYTES_PER_FILE,
|
|
17052
17094
|
remainingBudget
|
|
17053
17095
|
);
|
|
@@ -17067,7 +17109,7 @@ async function scanSourceOnce(config2, paths, signal) {
|
|
|
17067
17109
|
} finally {
|
|
17068
17110
|
await handle.close();
|
|
17069
17111
|
}
|
|
17070
|
-
if (readEnd <
|
|
17112
|
+
if (readEnd < size) caughtUp = false;
|
|
17071
17113
|
if (skipping.has(filename)) {
|
|
17072
17114
|
const newline = buffer.indexOf(10);
|
|
17073
17115
|
if (newline < 0) {
|
|
@@ -17130,7 +17172,7 @@ async function scanSourceOnce(config2, paths, signal) {
|
|
|
17130
17172
|
lineStart = buffer.length;
|
|
17131
17173
|
}
|
|
17132
17174
|
cursors[filename] = offset + lineStart;
|
|
17133
|
-
if ((source === "cursor" && filename.includes(`${path16.sep}cursor-hooks${path16.sep}`) || source === "claude" && filename.includes(`${path16.sep}git-queue${path16.sep}`)) && cursors[filename] ===
|
|
17175
|
+
if ((source === "cursor" && filename.includes(`${path16.sep}cursor-hooks${path16.sep}`) || source === "claude" && filename.includes(`${path16.sep}git-queue${path16.sep}`)) && cursors[filename] === size)
|
|
17134
17176
|
completedHooks.push(filename);
|
|
17135
17177
|
}
|
|
17136
17178
|
await appendEvents(events, paths);
|
|
@@ -17147,7 +17189,17 @@ async function scanSourceOnce(config2, paths, signal) {
|
|
|
17147
17189
|
},
|
|
17148
17190
|
paths
|
|
17149
17191
|
);
|
|
17150
|
-
|
|
17192
|
+
const sessions = sessionFiles.filter((file) => file.session);
|
|
17193
|
+
return {
|
|
17194
|
+
discovered: events.length,
|
|
17195
|
+
caughtUp,
|
|
17196
|
+
history: {
|
|
17197
|
+
sessions: sessions.length,
|
|
17198
|
+
readSessions: sessions.filter(
|
|
17199
|
+
(file) => (cursors[file.filename] ?? 0) >= file.size
|
|
17200
|
+
).length
|
|
17201
|
+
}
|
|
17202
|
+
};
|
|
17151
17203
|
}
|
|
17152
17204
|
async function uploadPendingOnce(config2, paths, fetcher = collectorFetch, signal, onAcknowledged) {
|
|
17153
17205
|
let uploaded = 0;
|
|
@@ -17217,7 +17269,7 @@ async function collectorTick(config2, paths, fetcher = collectorFetch, signal, o
|
|
|
17217
17269
|
signal,
|
|
17218
17270
|
onAcknowledged
|
|
17219
17271
|
);
|
|
17220
|
-
const scan = await outboxSize(paths) >= SCAN_PAUSE_OUTBOX_BYTES ? { discovered: 0, caughtUp: false } : await scanSourceOnce(config2, paths, signal);
|
|
17272
|
+
const scan = await outboxSize(paths) >= SCAN_PAUSE_OUTBOX_BYTES ? { discovered: 0, caughtUp: false, history: null } : await scanSourceOnce(config2, paths, signal);
|
|
17221
17273
|
uploaded += await uploadPendingOnce(
|
|
17222
17274
|
config2,
|
|
17223
17275
|
paths,
|
|
@@ -17229,10 +17281,66 @@ async function collectorTick(config2, paths, fetcher = collectorFetch, signal, o
|
|
|
17229
17281
|
discovered: scan.discovered,
|
|
17230
17282
|
uploaded,
|
|
17231
17283
|
outboxBytes: await outboxSize(paths),
|
|
17232
|
-
historyCaughtUp: scan.caughtUp
|
|
17284
|
+
historyCaughtUp: scan.caughtUp,
|
|
17285
|
+
history: scan.history
|
|
17233
17286
|
};
|
|
17234
17287
|
}
|
|
17235
17288
|
|
|
17289
|
+
// src/history-progress.ts
|
|
17290
|
+
var REQUEST_TIMEOUT_MS3 = 15e3;
|
|
17291
|
+
var REPORT_INTERVAL_MS = 1e4;
|
|
17292
|
+
var HistoryProgressError = class extends Error {
|
|
17293
|
+
constructor(message, options) {
|
|
17294
|
+
super(message, options);
|
|
17295
|
+
this.name = "HistoryProgressError";
|
|
17296
|
+
}
|
|
17297
|
+
};
|
|
17298
|
+
function unchanged(left, right) {
|
|
17299
|
+
return right !== null && left.sessions === right.sessions && left.readSessions === right.readSessions && left.complete === right.complete;
|
|
17300
|
+
}
|
|
17301
|
+
var HistoryProgressReporter = class {
|
|
17302
|
+
#sent = null;
|
|
17303
|
+
#sentAtMs = Number.NEGATIVE_INFINITY;
|
|
17304
|
+
#completed = false;
|
|
17305
|
+
async report(config2, progress, fetcher, signal, nowMs) {
|
|
17306
|
+
if (this.#completed || unchanged(progress, this.#sent)) return;
|
|
17307
|
+
if (!progress.complete && nowMs - this.#sentAtMs < REPORT_INTERVAL_MS)
|
|
17308
|
+
return;
|
|
17309
|
+
let response;
|
|
17310
|
+
try {
|
|
17311
|
+
response = await fetcher(
|
|
17312
|
+
new URL("/api/traces/collector-progress", config2.endpoint),
|
|
17313
|
+
{
|
|
17314
|
+
method: "POST",
|
|
17315
|
+
headers: {
|
|
17316
|
+
authorization: `Bearer ${config2.token}`,
|
|
17317
|
+
"content-type": "application/json"
|
|
17318
|
+
},
|
|
17319
|
+
body: JSON.stringify(progress),
|
|
17320
|
+
signal: AbortSignal.any([
|
|
17321
|
+
signal,
|
|
17322
|
+
AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
17323
|
+
])
|
|
17324
|
+
}
|
|
17325
|
+
);
|
|
17326
|
+
} catch (error2) {
|
|
17327
|
+
if (signal.aborted) throw error2;
|
|
17328
|
+
throw new HistoryProgressError(
|
|
17329
|
+
"History progress could not reach Iteration.",
|
|
17330
|
+
{ cause: error2 }
|
|
17331
|
+
);
|
|
17332
|
+
}
|
|
17333
|
+
if (response.status !== 204) {
|
|
17334
|
+
throw new HistoryProgressError(
|
|
17335
|
+
`History progress failed with HTTP ${response.status}.`
|
|
17336
|
+
);
|
|
17337
|
+
}
|
|
17338
|
+
this.#sent = progress;
|
|
17339
|
+
this.#sentAtMs = nowMs;
|
|
17340
|
+
this.#completed = progress.complete;
|
|
17341
|
+
}
|
|
17342
|
+
};
|
|
17343
|
+
|
|
17236
17344
|
// src/cursor-billing.ts
|
|
17237
17345
|
import { createHash as createHash7 } from "node:crypto";
|
|
17238
17346
|
import { promises as fs14 } from "node:fs";
|
|
@@ -18172,6 +18280,7 @@ async function runCollector(directory, expectedSource) {
|
|
|
18172
18280
|
const summariesRefreshedAt = /* @__PURE__ */ new Map();
|
|
18173
18281
|
let lastAutoCheckAt = 0;
|
|
18174
18282
|
let lastBillingSyncAt = 0;
|
|
18283
|
+
const historyProgress = new HistoryProgressReporter();
|
|
18175
18284
|
const runtimeVersion = process.env.ITERATION_RUNTIME_VERSION;
|
|
18176
18285
|
let lastRuntimeCheckAt = 0;
|
|
18177
18286
|
let trialSettled = runtimeVersion === void 0;
|
|
@@ -18234,6 +18343,7 @@ async function runCollector(directory, expectedSource) {
|
|
|
18234
18343
|
}
|
|
18235
18344
|
let acknowledgedAtMs = null;
|
|
18236
18345
|
let billingReady = false;
|
|
18346
|
+
let history = null;
|
|
18237
18347
|
try {
|
|
18238
18348
|
const result = await collectorTick(
|
|
18239
18349
|
config2,
|
|
@@ -18245,6 +18355,12 @@ async function runCollector(directory, expectedSource) {
|
|
|
18245
18355
|
}
|
|
18246
18356
|
);
|
|
18247
18357
|
billingReady = result.historyCaughtUp && result.outboxBytes === 0;
|
|
18358
|
+
if (result.history !== null) {
|
|
18359
|
+
history = {
|
|
18360
|
+
...result.history,
|
|
18361
|
+
complete: billingReady && result.history.readSessions === result.history.sessions
|
|
18362
|
+
};
|
|
18363
|
+
}
|
|
18248
18364
|
if (acknowledgedAtMs !== null || health.lastFailure !== null || result.historyCaughtUp && health.historyCaughtUpAtMs === null) {
|
|
18249
18365
|
health = {
|
|
18250
18366
|
lastUploadAtMs: acknowledgedAtMs ?? health.lastUploadAtMs,
|
|
@@ -18297,6 +18413,30 @@ async function runCollector(directory, expectedSource) {
|
|
|
18297
18413
|
await persistHealth(health, paths);
|
|
18298
18414
|
retryDelayMs = Math.min(retryDelayMs * 2, 6e4);
|
|
18299
18415
|
}
|
|
18416
|
+
if (history !== null) {
|
|
18417
|
+
try {
|
|
18418
|
+
await historyProgress.report(
|
|
18419
|
+
config2,
|
|
18420
|
+
history,
|
|
18421
|
+
collectorFetch,
|
|
18422
|
+
controller.signal,
|
|
18423
|
+
Date.now()
|
|
18424
|
+
);
|
|
18425
|
+
} catch (error2) {
|
|
18426
|
+
if (controller.signal.aborted) break;
|
|
18427
|
+
console.error(
|
|
18428
|
+
JSON.stringify({
|
|
18429
|
+
level: "warning",
|
|
18430
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18431
|
+
source,
|
|
18432
|
+
operation: "report_history_progress",
|
|
18433
|
+
errorName: error2 instanceof Error ? error2.name : "UnknownError",
|
|
18434
|
+
causes: errorCauses(error2),
|
|
18435
|
+
message: error2 instanceof Error ? error2.message : "Unknown history progress failure."
|
|
18436
|
+
})
|
|
18437
|
+
);
|
|
18438
|
+
}
|
|
18439
|
+
}
|
|
18300
18440
|
try {
|
|
18301
18441
|
if (source !== "cursor")
|
|
18302
18442
|
await refreshTurnSummaries(
|
|
@@ -18753,7 +18893,7 @@ function argumentsForCli() {
|
|
|
18753
18893
|
help: { type: "boolean" },
|
|
18754
18894
|
endpoint: { type: "string" },
|
|
18755
18895
|
"device-name": { type: "string" },
|
|
18756
|
-
|
|
18896
|
+
workspace: { type: "string" },
|
|
18757
18897
|
"codex-home": { type: "string" },
|
|
18758
18898
|
"claude-home": { type: "string" },
|
|
18759
18899
|
"cursor-home": { type: "string" },
|
|
@@ -18797,7 +18937,7 @@ function usage(command) {
|
|
|
18797
18937
|
"",
|
|
18798
18938
|
"Options for advanced setups:",
|
|
18799
18939
|
" --device-name NAME Name this computer in Iteration",
|
|
18800
|
-
" --
|
|
18940
|
+
" --workspace ID Connect to this workspace without a prompt",
|
|
18801
18941
|
" --codex-home DIR Use a different Codex data directory",
|
|
18802
18942
|
" --claude-home DIR Use a different Claude data directory",
|
|
18803
18943
|
" --cursor-home DIR Use a different Cursor data directory",
|
|
@@ -18902,7 +19042,7 @@ async function initialize(source, values) {
|
|
|
18902
19042
|
const endpoint = optionalString(values, "endpoint") ?? DEFAULT_INGEST_ENDPOINT;
|
|
18903
19043
|
const endpointUrl = validateCollectorEndpoint(endpoint);
|
|
18904
19044
|
const deviceName = optionalString(values, "device-name") ?? os8.hostname();
|
|
18905
|
-
const organizationId = optionalString(values, "
|
|
19045
|
+
const organizationId = optionalString(values, "workspace");
|
|
18906
19046
|
const directory = dataDirectory(source, values);
|
|
18907
19047
|
const paths = collectorPaths(directory);
|
|
18908
19048
|
const selectedHome = path21.resolve(
|
|
@@ -18949,13 +19089,15 @@ async function initialize(source, values) {
|
|
|
18949
19089
|
}
|
|
18950
19090
|
const notice = await turnSummaryNotice(config2);
|
|
18951
19091
|
process.stdout.write(
|
|
18952
|
-
`${collectorSourceLabel(source)} is connected to ${enrollment.organizationName}. Existing sessions are importing and new activity is collected automatically.
|
|
19092
|
+
`${collectorSourceLabel(source)} is connected to ${enrollment.organizationName}. Existing sessions are importing, newest first, and new activity is collected automatically. Iteration shows the import as it runs.${notice}
|
|
18953
19093
|
`
|
|
18954
19094
|
);
|
|
18955
19095
|
return config2;
|
|
18956
19096
|
}
|
|
18957
19097
|
async function approveAllSources(sources, workspaceName, yes) {
|
|
18958
|
-
const names = sources.map(
|
|
19098
|
+
const names = sources.map(
|
|
19099
|
+
({ source, sessions }) => `${collectorSourceLabel(source)} (${sessions.toLocaleString("en-US")} saved ${sessions === 1 ? "session" : "sessions"})`
|
|
19100
|
+
).join(" and ");
|
|
18959
19101
|
const safeName = safeWorkspaceName(workspaceName);
|
|
18960
19102
|
process.stdout.write(
|
|
18961
19103
|
`Detected ${names || "no saved agent sessions"} on this computer.
|
|
@@ -19032,14 +19174,19 @@ async function connectAll(values) {
|
|
|
19032
19174
|
);
|
|
19033
19175
|
}
|
|
19034
19176
|
}
|
|
19035
|
-
const requestedOrganizationId = optionalString(values, "
|
|
19177
|
+
const requestedOrganizationId = optionalString(values, "workspace");
|
|
19036
19178
|
if (requestedOrganizationId && existingScopes[0] && requestedOrganizationId !== existingScopes[0].scope.organizationId) {
|
|
19037
19179
|
throw new Error("The existing collector belongs to a different workspace.");
|
|
19038
19180
|
}
|
|
19039
19181
|
const previousConsent = await loadMachineConsent();
|
|
19040
19182
|
if (previousConsent === null || anchorExisting === null || previousConsent.endpoint !== endpoint || previousConsent.anchorSource !== anchorSource || previousConsent.anchorDataDirectory !== anchorExisting.dataDirectory || previousConsent.organizationId !== existingScopes[0]?.scope.organizationId || previousConsent.sourceHomes.codex !== sourceHomes.codex || previousConsent.sourceHomes.claude !== sourceHomes.claude || previousConsent.sourceHomes.cursor !== sourceHomes.cursor) {
|
|
19041
19183
|
await approveAllSources(
|
|
19042
|
-
|
|
19184
|
+
await Promise.all(
|
|
19185
|
+
detected.map(async (source) => ({
|
|
19186
|
+
source,
|
|
19187
|
+
sessions: await countSavedSessions(source, sourceHomes[source])
|
|
19188
|
+
}))
|
|
19189
|
+
),
|
|
19043
19190
|
existingScopes[0]?.scope.organizationName ?? null,
|
|
19044
19191
|
values.yes === true
|
|
19045
19192
|
);
|
|
@@ -7435,6 +7435,12 @@ var acknowledgementSchema = object({
|
|
|
7435
7435
|
}).strict();
|
|
7436
7436
|
var episodeCountSchema = number2().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
7437
7437
|
var collectorFrictionSummarySchema = object({ weekEpisodes: episodeCountSchema, dayEpisodes: episodeCountSchema }).strict().refine((summary) => summary.dayEpisodes <= summary.weekEpisodes, "The last day cannot have more friction episodes than the last week.");
|
|
7438
|
+
var sessionCountSchema = number2().int().min(0).max(1e6);
|
|
7439
|
+
var collectorHistoryProgressSchema = object({
|
|
7440
|
+
sessions: sessionCountSchema,
|
|
7441
|
+
readSessions: sessionCountSchema,
|
|
7442
|
+
complete: boolean2()
|
|
7443
|
+
}).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.");
|
|
7438
7444
|
var collectorEnrollmentRequestSchema = object({
|
|
7439
7445
|
deviceName: string2().trim().min(1).max(160),
|
|
7440
7446
|
organizationId: string2().regex(UUID_PATTERN).optional(),
|
package/dist/launcher.js
CHANGED
|
@@ -6511,6 +6511,12 @@ var acknowledgementSchema = object({
|
|
|
6511
6511
|
}).strict();
|
|
6512
6512
|
var episodeCountSchema = number2().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
6513
6513
|
var collectorFrictionSummarySchema = object({ weekEpisodes: episodeCountSchema, dayEpisodes: episodeCountSchema }).strict().refine((summary) => summary.dayEpisodes <= summary.weekEpisodes, "The last day cannot have more friction episodes than the last week.");
|
|
6514
|
+
var sessionCountSchema = number2().int().min(0).max(1e6);
|
|
6515
|
+
var collectorHistoryProgressSchema = object({
|
|
6516
|
+
sessions: sessionCountSchema,
|
|
6517
|
+
readSessions: sessionCountSchema,
|
|
6518
|
+
complete: boolean2()
|
|
6519
|
+
}).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.");
|
|
6514
6520
|
var collectorEnrollmentRequestSchema = object({
|
|
6515
6521
|
deviceName: string2().trim().min(1).max(160),
|
|
6516
6522
|
organizationId: string2().regex(UUID_PATTERN).optional(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iteration-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@secretlint/secretlint-rule-preset-recommend": "13.0.6",
|
|
23
23
|
"esbuild": "0.28.2",
|
|
24
24
|
"zod": "4.6.4",
|
|
25
|
-
"iteration-trace-contracts": "0.
|
|
25
|
+
"iteration-trace-contracts": "0.10.0"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "pnpm --filter iteration-trace-contracts build && tsc -p tsconfig.json --noEmit && node build.mjs"
|