iteration-cli 0.16.1 → 0.17.1
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 +2 -2
- package/dist/cli.js +265 -28
- package/dist/cursor-hook-entry.js +11 -0
- package/dist/launcher.js +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Iteration CLI (private source)
|
|
2
2
|
|
|
3
|
-
This package owns the `iteration-cli@0.
|
|
3
|
+
This package owns the `iteration-cli@0.17.1` product executable. Clerk sign-in,
|
|
4
4
|
workspace enrollment and automatic expansion, the default Iteration endpoint,
|
|
5
5
|
commands/status UI, history progress, friction summaries and Codex/Cursor billing
|
|
6
6
|
clients live here, not in the public Trace Vault repository.
|
|
@@ -38,7 +38,7 @@ From the private repository root after workspace initialization:
|
|
|
38
38
|
```sh
|
|
39
39
|
pnpm --filter "iteration-cli..." --recursive --workspace-concurrency=4 run build
|
|
40
40
|
pnpm --filter iteration-cli pack --pack-destination /tmp/iteration-cli-pack
|
|
41
|
-
node packages/cli/smoke.mjs /tmp/iteration-cli-pack/iteration-cli-0.
|
|
41
|
+
node packages/cli/smoke.mjs /tmp/iteration-cli-pack/iteration-cli-0.17.1.tgz
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
The package smoke installs the tarball offline under a disposable home and checks
|
package/dist/cli.js
CHANGED
|
@@ -13037,7 +13037,8 @@ function collectorPaths(directory) {
|
|
|
13037
13037
|
redactionMarker: path4.join(directory, "redaction.json"),
|
|
13038
13038
|
lock: path4.join(directory, "collector.lock"),
|
|
13039
13039
|
historyBackfill: path4.join(directory, "history-backfill.json"),
|
|
13040
|
-
health: path4.join(directory, "health.json")
|
|
13040
|
+
health: path4.join(directory, "health.json"),
|
|
13041
|
+
recentMessages: path4.join(directory, "recent-messages.json")
|
|
13041
13042
|
};
|
|
13042
13043
|
}
|
|
13043
13044
|
async function assertFreshCollectorDirectory(paths, source = "codex") {
|
|
@@ -13294,7 +13295,24 @@ async function redactPendingOutbox(paths) {
|
|
|
13294
13295
|
await ensurePrivateDirectory(path4.dirname(paths.redactionMarker));
|
|
13295
13296
|
await writeJsonAtomic(paths.redactionMarker, { version: 1 });
|
|
13296
13297
|
}
|
|
13297
|
-
|
|
13298
|
+
function queuedEventId(line) {
|
|
13299
|
+
const prefix = '{"eventId":"';
|
|
13300
|
+
if (!line.startsWith(prefix)) return null;
|
|
13301
|
+
const end = line.indexOf('"', prefix.length);
|
|
13302
|
+
return end < 0 ? null : line.slice(prefix.length, end);
|
|
13303
|
+
}
|
|
13304
|
+
async function queuedUserMessageIds(paths, limit2) {
|
|
13305
|
+
const ids = [];
|
|
13306
|
+
if (await outboxSize(paths) === 0) return ids;
|
|
13307
|
+
for await (const line of outboxLines(paths.outbox)) {
|
|
13308
|
+
if (ids.length >= limit2) break;
|
|
13309
|
+
if (!line.includes('"eventType":"user_message"')) continue;
|
|
13310
|
+
const id = queuedEventId(line);
|
|
13311
|
+
if (id !== null) ids.push(id);
|
|
13312
|
+
}
|
|
13313
|
+
return ids;
|
|
13314
|
+
}
|
|
13315
|
+
async function nextBatch(paths, maxBytes, first = /* @__PURE__ */ new Set()) {
|
|
13298
13316
|
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
13299
13317
|
throw new Error("Maximum upload batch size must be a positive integer.");
|
|
13300
13318
|
}
|
|
@@ -13302,9 +13320,19 @@ async function nextBatch(paths, maxBytes) {
|
|
|
13302
13320
|
if (size === 0) return [];
|
|
13303
13321
|
if (size > MAX_OUTBOX_BYTES)
|
|
13304
13322
|
throw new Error("Trace outbox exceeds its configured capacity.");
|
|
13323
|
+
const priority = [];
|
|
13324
|
+
const rest = [];
|
|
13325
|
+
for await (const line of outboxLines(paths.outbox)) {
|
|
13326
|
+
const id = first.size === 0 ? null : queuedEventId(line);
|
|
13327
|
+
if (id !== null && first.has(id)) {
|
|
13328
|
+
if (priority.length < MAX_TRACE_EVENTS_PER_BATCH) priority.push(line);
|
|
13329
|
+
} else if (rest.length < MAX_TRACE_EVENTS_PER_BATCH) rest.push(line);
|
|
13330
|
+
if (first.size === 0 ? rest.length === MAX_TRACE_EVENTS_PER_BATCH : priority.length === MAX_TRACE_EVENTS_PER_BATCH)
|
|
13331
|
+
break;
|
|
13332
|
+
}
|
|
13305
13333
|
const events = [];
|
|
13306
13334
|
let bytes = 0;
|
|
13307
|
-
for
|
|
13335
|
+
for (const line of [...priority, ...rest]) {
|
|
13308
13336
|
const lineBytes = Buffer.byteLength(line, "utf8") + 1;
|
|
13309
13337
|
if (events.length >= MAX_TRACE_EVENTS_PER_BATCH || events.length > 0 && bytes + lineBytes > maxBytes) {
|
|
13310
13338
|
break;
|
|
@@ -13317,6 +13345,45 @@ async function nextBatch(paths, maxBytes) {
|
|
|
13317
13345
|
}
|
|
13318
13346
|
return events;
|
|
13319
13347
|
}
|
|
13348
|
+
var recentMessagesSchema = object({
|
|
13349
|
+
version: literal(1),
|
|
13350
|
+
cursors: record(
|
|
13351
|
+
string2(),
|
|
13352
|
+
number2().int().min(0).max(Number.MAX_SAFE_INTEGER)
|
|
13353
|
+
),
|
|
13354
|
+
// Queued by the pass and not yet acknowledged.
|
|
13355
|
+
queued: array(string2()),
|
|
13356
|
+
sent: number2().int().min(0),
|
|
13357
|
+
scanned: boolean2()
|
|
13358
|
+
}).strict();
|
|
13359
|
+
async function loadRecentMessages(paths) {
|
|
13360
|
+
let contents;
|
|
13361
|
+
try {
|
|
13362
|
+
contents = await fs3.readFile(paths.recentMessages, "utf8");
|
|
13363
|
+
} catch (error22) {
|
|
13364
|
+
if (error22 instanceof Error && "code" in error22 && error22.code === "ENOENT")
|
|
13365
|
+
return null;
|
|
13366
|
+
throw error22;
|
|
13367
|
+
}
|
|
13368
|
+
let decoded;
|
|
13369
|
+
try {
|
|
13370
|
+
decoded = JSON.parse(contents);
|
|
13371
|
+
} catch (error22) {
|
|
13372
|
+
throw new Error("Collector recent message state is not valid JSON.", {
|
|
13373
|
+
cause: error22
|
|
13374
|
+
});
|
|
13375
|
+
}
|
|
13376
|
+
const parsed = recentMessagesSchema.safeParse(decoded);
|
|
13377
|
+
if (!parsed.success)
|
|
13378
|
+
throw new Error("Collector recent message state has an invalid shape.", {
|
|
13379
|
+
cause: parsed.error
|
|
13380
|
+
});
|
|
13381
|
+
return parsed.data;
|
|
13382
|
+
}
|
|
13383
|
+
async function saveRecentMessages(state, paths) {
|
|
13384
|
+
await ensurePrivateDirectory(path4.dirname(paths.recentMessages));
|
|
13385
|
+
await writeJsonAtomic(paths.recentMessages, state);
|
|
13386
|
+
}
|
|
13320
13387
|
async function acknowledgeEvents(acknowledgedIds, paths) {
|
|
13321
13388
|
await rewritePendingEvents(
|
|
13322
13389
|
paths,
|
|
@@ -15353,18 +15420,166 @@ async function scanSourceOnce(config22, paths, signal, policy, accounts) {
|
|
|
15353
15420
|
},
|
|
15354
15421
|
paths
|
|
15355
15422
|
);
|
|
15356
|
-
const sessions = sessionFiles.filter((file) => file.session);
|
|
15357
15423
|
return {
|
|
15358
15424
|
discovered: events.length,
|
|
15359
15425
|
excludedRecords,
|
|
15360
15426
|
caughtUp,
|
|
15361
|
-
history:
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
|
|
15427
|
+
history: historyProgress(sessionFiles, cursors)
|
|
15428
|
+
};
|
|
15429
|
+
}
|
|
15430
|
+
function historyProgress(files, cursors) {
|
|
15431
|
+
const sessions = files.filter((file) => file.session);
|
|
15432
|
+
return {
|
|
15433
|
+
sessions: sessions.length,
|
|
15434
|
+
readSessions: sessions.filter(
|
|
15435
|
+
(file) => (cursors[file.filename] ?? 0) >= file.size
|
|
15436
|
+
).length
|
|
15437
|
+
};
|
|
15438
|
+
}
|
|
15439
|
+
async function savedHistoryProgress(config22, paths) {
|
|
15440
|
+
const files = await sourceFilesNewestFirst(
|
|
15441
|
+
collectorSource(config22),
|
|
15442
|
+
path14.resolve(collectorSourceDirectory(config22))
|
|
15443
|
+
);
|
|
15444
|
+
return historyProgress(files, (await loadState(paths)).cursors);
|
|
15445
|
+
}
|
|
15446
|
+
async function readRange(filename, start2, length) {
|
|
15447
|
+
const handle = await fs9.open(filename, "r");
|
|
15448
|
+
try {
|
|
15449
|
+
const buffer = Buffer.alloc(length);
|
|
15450
|
+
const result = await handle.read(buffer, 0, length, start2);
|
|
15451
|
+
return buffer.subarray(0, result.bytesRead);
|
|
15452
|
+
} finally {
|
|
15453
|
+
await handle.close();
|
|
15454
|
+
}
|
|
15455
|
+
}
|
|
15456
|
+
async function messagesInRecords(source, filename, buffer, start2, room, queuedIds) {
|
|
15457
|
+
const events = [];
|
|
15458
|
+
let lineStart = 0;
|
|
15459
|
+
for (let index = 0; index < buffer.length; index += 1) {
|
|
15460
|
+
if (events.length >= room) break;
|
|
15461
|
+
if (buffer[index] !== 10) continue;
|
|
15462
|
+
let lineBytes = buffer.subarray(lineStart, index);
|
|
15463
|
+
if (lineBytes.at(-1) === 13) lineBytes = lineBytes.subarray(0, -1);
|
|
15464
|
+
const byteOffset = start2 + lineStart;
|
|
15465
|
+
lineStart = index + 1;
|
|
15466
|
+
if (lineBytes.length > MAX_RECORD_BYTES) continue;
|
|
15467
|
+
let line;
|
|
15468
|
+
try {
|
|
15469
|
+
line = UTF8_DECODER.decode(lineBytes);
|
|
15470
|
+
} catch {
|
|
15471
|
+
continue;
|
|
15472
|
+
}
|
|
15473
|
+
const { events: parsed } = parseSourceRecord(
|
|
15474
|
+
source,
|
|
15475
|
+
line,
|
|
15476
|
+
filename,
|
|
15477
|
+
byteOffset
|
|
15478
|
+
);
|
|
15479
|
+
for (const record32 of parsed) {
|
|
15480
|
+
if (record32.eventType !== "user_message" || queuedIds.has(record32.eventId))
|
|
15481
|
+
continue;
|
|
15482
|
+
const event3 = await redactTraceEvent(record32);
|
|
15483
|
+
if (Buffer.byteLength(JSON.stringify(event3), "utf8") <= MAX_EVENT_BYTES)
|
|
15484
|
+
events.push(event3);
|
|
15366
15485
|
}
|
|
15486
|
+
}
|
|
15487
|
+
return { events, consumed: lineStart };
|
|
15488
|
+
}
|
|
15489
|
+
async function queueRecentMessages(config22, paths, limit2, signal) {
|
|
15490
|
+
if (limit2 === void 0) return void 0;
|
|
15491
|
+
const recent = await loadRecentMessages(paths) ?? {
|
|
15492
|
+
version: 1,
|
|
15493
|
+
cursors: {},
|
|
15494
|
+
queued: [...await queuedUserMessageIds(paths, limit2)],
|
|
15495
|
+
sent: 0,
|
|
15496
|
+
scanned: false
|
|
15367
15497
|
};
|
|
15498
|
+
if (recent.scanned) return new Set(recent.queued);
|
|
15499
|
+
const source = collectorSource(config22);
|
|
15500
|
+
const mainCursors = (await loadState(paths)).cursors;
|
|
15501
|
+
const files = await sourceFilesNewestFirst(
|
|
15502
|
+
source,
|
|
15503
|
+
path14.resolve(collectorSourceDirectory(config22))
|
|
15504
|
+
);
|
|
15505
|
+
const queuedIds = await pendingEventIds(paths);
|
|
15506
|
+
const cursors = { ...recent.cursors };
|
|
15507
|
+
const queued = [...recent.queued];
|
|
15508
|
+
const events = [];
|
|
15509
|
+
let budget = MAX_SCAN_BYTES_PER_TICK;
|
|
15510
|
+
let reachedEnd = true;
|
|
15511
|
+
for (const file of files) {
|
|
15512
|
+
signal?.throwIfAborted();
|
|
15513
|
+
const room = limit2 - recent.sent - queued.length;
|
|
15514
|
+
const start2 = Math.max(
|
|
15515
|
+
cursors[file.filename] ?? 0,
|
|
15516
|
+
mainCursors[file.filename] ?? 0
|
|
15517
|
+
);
|
|
15518
|
+
if (room <= 0 || start2 >= file.size) continue;
|
|
15519
|
+
const length = Math.min(file.size - start2, MAX_SCAN_BYTES_PER_FILE, budget);
|
|
15520
|
+
const buffer = await readRange(file.filename, start2, length);
|
|
15521
|
+
budget -= buffer.length;
|
|
15522
|
+
const found = await messagesInRecords(
|
|
15523
|
+
source,
|
|
15524
|
+
file.filename,
|
|
15525
|
+
buffer,
|
|
15526
|
+
start2,
|
|
15527
|
+
room,
|
|
15528
|
+
queuedIds
|
|
15529
|
+
);
|
|
15530
|
+
for (const event3 of found.events) {
|
|
15531
|
+
events.push(event3);
|
|
15532
|
+
queued.push(event3.eventId);
|
|
15533
|
+
queuedIds.add(event3.eventId);
|
|
15534
|
+
}
|
|
15535
|
+
const stuck = found.consumed === 0 && length === MAX_SCAN_BYTES_PER_FILE;
|
|
15536
|
+
cursors[file.filename] = stuck ? file.size : start2 + found.consumed;
|
|
15537
|
+
if (buffer.length < file.size - start2 || budget === 0) {
|
|
15538
|
+
reachedEnd = false;
|
|
15539
|
+
if (budget === 0) break;
|
|
15540
|
+
}
|
|
15541
|
+
}
|
|
15542
|
+
await appendEvents(events, paths);
|
|
15543
|
+
await saveRecentMessages(
|
|
15544
|
+
{
|
|
15545
|
+
version: 1,
|
|
15546
|
+
cursors,
|
|
15547
|
+
queued,
|
|
15548
|
+
sent: recent.sent,
|
|
15549
|
+
scanned: recent.sent + queued.length >= limit2 || reachedEnd
|
|
15550
|
+
},
|
|
15551
|
+
paths
|
|
15552
|
+
);
|
|
15553
|
+
return new Set(queued);
|
|
15554
|
+
}
|
|
15555
|
+
async function settleRecentMessages(paths, limit2) {
|
|
15556
|
+
if (limit2 === void 0) return null;
|
|
15557
|
+
const recent = await loadRecentMessages(paths);
|
|
15558
|
+
if (recent === null) return { sent: 0, complete: false };
|
|
15559
|
+
if (recent.queued.length === 0)
|
|
15560
|
+
return { sent: recent.sent, complete: recent.scanned };
|
|
15561
|
+
const pending = await pendingEventIds(paths);
|
|
15562
|
+
const queued = recent.queued.filter((id) => pending.has(id));
|
|
15563
|
+
const sent = recent.sent + recent.queued.length - queued.length;
|
|
15564
|
+
if (queued.length !== recent.queued.length)
|
|
15565
|
+
await saveRecentMessages(
|
|
15566
|
+
{
|
|
15567
|
+
...recent,
|
|
15568
|
+
queued,
|
|
15569
|
+
sent,
|
|
15570
|
+
cursors: recent.scanned && queued.length === 0 ? {} : recent.cursors
|
|
15571
|
+
},
|
|
15572
|
+
paths
|
|
15573
|
+
);
|
|
15574
|
+
return { sent, complete: recent.scanned && queued.length === 0 };
|
|
15575
|
+
}
|
|
15576
|
+
function checkedRecentLimit(config22, limit2) {
|
|
15577
|
+
if (limit2 === void 0) return void 0;
|
|
15578
|
+
if (!Number.isSafeInteger(limit2) || limit2 < 1)
|
|
15579
|
+
throw new Error("The recent message limit must be a positive integer.");
|
|
15580
|
+
if (config22.destination === "vault")
|
|
15581
|
+
throw new Error("Vault collection does not send recent messages first.");
|
|
15582
|
+
return limit2;
|
|
15368
15583
|
}
|
|
15369
15584
|
function isConsumedHook(source, filename, policy) {
|
|
15370
15585
|
if (policy !== void 0) return false;
|
|
@@ -15379,12 +15594,12 @@ function retryAfterMs(response) {
|
|
|
15379
15594
|
const milliseconds = /^\d+$/.test(header) ? Number(header) * 1e3 : Date.parse(header) - Date.now();
|
|
15380
15595
|
return Number.isFinite(milliseconds) ? Math.max(1e3, Math.min(milliseconds, 3e5)) : 5e3;
|
|
15381
15596
|
}
|
|
15382
|
-
async function uploadPendingOnce(config22, paths, fetcher = collectorFetch, signal, onAcknowledged, policy) {
|
|
15597
|
+
async function uploadPendingOnce(config22, paths, fetcher = collectorFetch, signal, onAcknowledged, policy, first) {
|
|
15383
15598
|
let uploaded = 0;
|
|
15384
15599
|
for (let attempt = 0; attempt < MAX_UPLOADS_PER_TICK; attempt += 1) {
|
|
15385
15600
|
signal?.throwIfAborted();
|
|
15386
15601
|
await recheckQueuedAccounts(config22, paths, policy);
|
|
15387
|
-
const batch = await nextBatch(paths, MAX_UPLOAD_BYTES);
|
|
15602
|
+
const batch = await nextBatch(paths, MAX_UPLOAD_BYTES, first);
|
|
15388
15603
|
if (batch.length === 0) return { uploaded, retryAfterMs: null };
|
|
15389
15604
|
const body = JSON.stringify({ events: batch });
|
|
15390
15605
|
if (Buffer.byteLength(body, "utf8") > MAX_REQUEST_BYTES) {
|
|
@@ -15453,7 +15668,8 @@ async function recheckQueuedAccounts(config22, paths, policy) {
|
|
|
15453
15668
|
(event3) => reauthorizeVaultEvent(policy, event3, accounts)
|
|
15454
15669
|
);
|
|
15455
15670
|
}
|
|
15456
|
-
async function collectorTick(config22, paths, fetcher = collectorFetch, signal, onAcknowledged) {
|
|
15671
|
+
async function collectorTick(config22, paths, fetcher = collectorFetch, signal, onAcknowledged, options = {}) {
|
|
15672
|
+
const recentLimit = checkedRecentLimit(config22, options.recentMessages);
|
|
15457
15673
|
const accounts = await vaultAccountIndex(config22);
|
|
15458
15674
|
const policy = config22.destination === "vault" ? await fetchVaultPolicy(config22.endpoint, config22.token, fetcher, signal) : void 0;
|
|
15459
15675
|
if (policy !== void 0) {
|
|
@@ -15478,15 +15694,22 @@ async function collectorTick(config22, paths, fetcher = collectorFetch, signal,
|
|
|
15478
15694
|
}
|
|
15479
15695
|
}
|
|
15480
15696
|
await redactPendingOutbox(paths);
|
|
15697
|
+
const first = await queueRecentMessages(config22, paths, recentLimit, signal);
|
|
15481
15698
|
let upload = await uploadPendingOnce(
|
|
15482
15699
|
config22,
|
|
15483
15700
|
paths,
|
|
15484
15701
|
fetcher,
|
|
15485
15702
|
signal,
|
|
15486
15703
|
onAcknowledged,
|
|
15487
|
-
policy
|
|
15704
|
+
policy,
|
|
15705
|
+
first
|
|
15488
15706
|
);
|
|
15489
|
-
const scan = await outboxSize(paths) >= SCAN_PAUSE_OUTBOX_BYTES ? {
|
|
15707
|
+
const scan = await outboxSize(paths) >= SCAN_PAUSE_OUTBOX_BYTES ? {
|
|
15708
|
+
discovered: 0,
|
|
15709
|
+
excludedRecords: 0,
|
|
15710
|
+
caughtUp: false,
|
|
15711
|
+
history: await savedHistoryProgress(config22, paths)
|
|
15712
|
+
} : await scanSourceOnce(config22, paths, signal, policy, accounts);
|
|
15490
15713
|
if (policy !== void 0 && scan.caughtUp) {
|
|
15491
15714
|
const state = await loadState(paths);
|
|
15492
15715
|
if (state.captureRecheckAt === void 0)
|
|
@@ -15502,7 +15725,8 @@ async function collectorTick(config22, paths, fetcher = collectorFetch, signal,
|
|
|
15502
15725
|
fetcher,
|
|
15503
15726
|
signal,
|
|
15504
15727
|
onAcknowledged,
|
|
15505
|
-
policy
|
|
15728
|
+
policy,
|
|
15729
|
+
first
|
|
15506
15730
|
);
|
|
15507
15731
|
upload = { ...next, uploaded: upload.uploaded + next.uploaded };
|
|
15508
15732
|
}
|
|
@@ -15513,6 +15737,7 @@ async function collectorTick(config22, paths, fetcher = collectorFetch, signal,
|
|
|
15513
15737
|
outboxBytes: await outboxSize(paths),
|
|
15514
15738
|
historyCaughtUp: scan.caughtUp,
|
|
15515
15739
|
history: scan.history,
|
|
15740
|
+
recentMessages: await settleRecentMessages(paths, recentLimit),
|
|
15516
15741
|
retryAfterMs: upload.retryAfterMs ?? 0
|
|
15517
15742
|
};
|
|
15518
15743
|
}
|
|
@@ -22385,11 +22610,16 @@ var collectorFrictionSummarySchema = object3({
|
|
|
22385
22610
|
weekEpisodes: episodeCountSchema,
|
|
22386
22611
|
dayEpisodes: episodeCountSchema
|
|
22387
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;
|
|
22388
22614
|
var sessionCountSchema = number4().int().min(0).max(1e6);
|
|
22389
22615
|
var collectorHistoryProgressSchema = object3({
|
|
22390
22616
|
sessions: sessionCountSchema,
|
|
22391
22617
|
readSessions: sessionCountSchema,
|
|
22392
|
-
complete: boolean4()
|
|
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.")
|
|
22393
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.");
|
|
22394
22624
|
var collectorEnrollmentRequestSchema = object3({
|
|
22395
22625
|
deviceName: string5().trim().min(1).max(160).describe("Trimmed before length validation."),
|
|
@@ -25582,6 +25812,7 @@ async function clearConnection(directory) {
|
|
|
25582
25812
|
paths.redactionMarker,
|
|
25583
25813
|
paths.historyBackfill,
|
|
25584
25814
|
paths.health,
|
|
25815
|
+
paths.recentMessages,
|
|
25585
25816
|
...[
|
|
25586
25817
|
"cursor-hooks",
|
|
25587
25818
|
"cursor-hook-failure.json",
|
|
@@ -26498,7 +26729,13 @@ var HistoryProgressError = class extends Error {
|
|
|
26498
26729
|
}
|
|
26499
26730
|
};
|
|
26500
26731
|
function unchanged(left, right) {
|
|
26501
|
-
return right !== null && left.sessions === right.sessions && left.readSessions === right.readSessions && left.complete === right.complete;
|
|
26732
|
+
return right !== null && left.sessions === right.sessions && left.readSessions === right.readSessions && left.complete === right.complete && left.recentMessages?.sent === right.recentMessages?.sent && left.recentMessages?.complete === right.recentMessages?.complete;
|
|
26733
|
+
}
|
|
26734
|
+
function settled(progress) {
|
|
26735
|
+
return progress.complete && (progress.recentMessages?.complete ?? true);
|
|
26736
|
+
}
|
|
26737
|
+
function milestone(progress, sent) {
|
|
26738
|
+
return progress.complete || progress.recentMessages?.complete === true && sent?.recentMessages?.complete !== true;
|
|
26502
26739
|
}
|
|
26503
26740
|
var HistoryProgressReporter = class {
|
|
26504
26741
|
#sent = null;
|
|
@@ -26506,7 +26743,7 @@ var HistoryProgressReporter = class {
|
|
|
26506
26743
|
#completed = false;
|
|
26507
26744
|
async report(config3, progress, fetcher, signal, nowMs) {
|
|
26508
26745
|
if (this.#completed || unchanged(progress, this.#sent)) return;
|
|
26509
|
-
if (!progress
|
|
26746
|
+
if (!milestone(progress, this.#sent) && nowMs - this.#sentAtMs < REPORT_INTERVAL_MS)
|
|
26510
26747
|
return;
|
|
26511
26748
|
let response;
|
|
26512
26749
|
try {
|
|
@@ -26539,7 +26776,7 @@ var HistoryProgressReporter = class {
|
|
|
26539
26776
|
}
|
|
26540
26777
|
this.#sent = progress;
|
|
26541
26778
|
this.#sentAtMs = nowMs;
|
|
26542
|
-
this.#completed = progress
|
|
26779
|
+
this.#completed = settled(progress);
|
|
26543
26780
|
}
|
|
26544
26781
|
};
|
|
26545
26782
|
|
|
@@ -26648,7 +26885,7 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
26648
26885
|
const summariesRefreshedAt = /* @__PURE__ */ new Map();
|
|
26649
26886
|
let lastAutoCheckAt = 0;
|
|
26650
26887
|
let lastBillingSyncAt = 0;
|
|
26651
|
-
const
|
|
26888
|
+
const historyProgress2 = new HistoryProgressReporter();
|
|
26652
26889
|
const runtimeVersion = process.env.ITERATION_RUNTIME_VERSION;
|
|
26653
26890
|
let lastRuntimeCheckAt = 0;
|
|
26654
26891
|
let trialSettled = runtimeVersion === void 0;
|
|
@@ -26742,15 +26979,15 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
26742
26979
|
controller.signal,
|
|
26743
26980
|
() => {
|
|
26744
26981
|
acknowledgedAtMs = Date.now();
|
|
26745
|
-
}
|
|
26982
|
+
},
|
|
26983
|
+
{ recentMessages: RECENT_MESSAGE_LIMIT }
|
|
26746
26984
|
);
|
|
26747
26985
|
billingReady = result.historyCaughtUp && result.outboxBytes === 0;
|
|
26748
|
-
|
|
26749
|
-
history
|
|
26750
|
-
|
|
26751
|
-
|
|
26752
|
-
|
|
26753
|
-
}
|
|
26986
|
+
history = {
|
|
26987
|
+
...result.history,
|
|
26988
|
+
complete: billingReady && result.history.readSessions === result.history.sessions,
|
|
26989
|
+
...result.recentMessages === null ? {} : { recentMessages: result.recentMessages }
|
|
26990
|
+
};
|
|
26754
26991
|
await recordTickSuccess(result, acknowledgedAtMs);
|
|
26755
26992
|
} catch (error3) {
|
|
26756
26993
|
if (controller.signal.aborted) return null;
|
|
@@ -26781,7 +27018,7 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
26781
27018
|
const reportHistory = async (history) => {
|
|
26782
27019
|
if (history !== null) {
|
|
26783
27020
|
try {
|
|
26784
|
-
await
|
|
27021
|
+
await historyProgress2.report(
|
|
26785
27022
|
config3,
|
|
26786
27023
|
history,
|
|
26787
27024
|
collectorFetch,
|
|
@@ -11541,6 +11541,17 @@ var healthSchema = object({
|
|
|
11541
11541
|
}).strict().nullable()
|
|
11542
11542
|
}).strict();
|
|
11543
11543
|
var redactionMarkerSchema = object({ version: literal(1) }).strict();
|
|
11544
|
+
var recentMessagesSchema = object({
|
|
11545
|
+
version: literal(1),
|
|
11546
|
+
cursors: record(
|
|
11547
|
+
string2(),
|
|
11548
|
+
number2().int().min(0).max(Number.MAX_SAFE_INTEGER)
|
|
11549
|
+
),
|
|
11550
|
+
// Queued by the pass and not yet acknowledged.
|
|
11551
|
+
queued: array(string2()),
|
|
11552
|
+
sent: number2().int().min(0),
|
|
11553
|
+
scanned: boolean2()
|
|
11554
|
+
}).strict();
|
|
11544
11555
|
var HISTORY_BACKFILL_VERSION = 4;
|
|
11545
11556
|
var historyBackfillMarkerSchema = object({ version: number2().int().min(1).max(HISTORY_BACKFILL_VERSION) }).strict();
|
|
11546
11557
|
var repositoryUrls = /* @__PURE__ */ new Map();
|
package/dist/launcher.js
CHANGED
|
@@ -11666,6 +11666,17 @@ var healthSchema = object({
|
|
|
11666
11666
|
}).strict().nullable()
|
|
11667
11667
|
}).strict();
|
|
11668
11668
|
var redactionMarkerSchema = object({ version: literal(1) }).strict();
|
|
11669
|
+
var recentMessagesSchema = object({
|
|
11670
|
+
version: literal(1),
|
|
11671
|
+
cursors: record(
|
|
11672
|
+
string2(),
|
|
11673
|
+
number2().int().min(0).max(Number.MAX_SAFE_INTEGER)
|
|
11674
|
+
),
|
|
11675
|
+
// Queued by the pass and not yet acknowledged.
|
|
11676
|
+
queued: array(string2()),
|
|
11677
|
+
sent: number2().int().min(0),
|
|
11678
|
+
scanned: boolean2()
|
|
11679
|
+
}).strict();
|
|
11669
11680
|
var HISTORY_BACKFILL_VERSION = 4;
|
|
11670
11681
|
var historyBackfillMarkerSchema = object({ version: number2().int().min(1).max(HISTORY_BACKFILL_VERSION) }).strict();
|
|
11671
11682
|
var scopeRecordSchema = object({
|