iteration-cli 0.16.0 → 0.17.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 +2 -2
- package/dist/cli.js +256 -31
- 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.0` 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.0.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,
|
|
@@ -15366,6 +15433,144 @@ async function scanSourceOnce(config22, paths, signal, policy, accounts) {
|
|
|
15366
15433
|
}
|
|
15367
15434
|
};
|
|
15368
15435
|
}
|
|
15436
|
+
async function readRange(filename, start2, length) {
|
|
15437
|
+
const handle = await fs9.open(filename, "r");
|
|
15438
|
+
try {
|
|
15439
|
+
const buffer = Buffer.alloc(length);
|
|
15440
|
+
const result = await handle.read(buffer, 0, length, start2);
|
|
15441
|
+
return buffer.subarray(0, result.bytesRead);
|
|
15442
|
+
} finally {
|
|
15443
|
+
await handle.close();
|
|
15444
|
+
}
|
|
15445
|
+
}
|
|
15446
|
+
async function messagesInRecords(source, filename, buffer, start2, room, queuedIds) {
|
|
15447
|
+
const events = [];
|
|
15448
|
+
let lineStart = 0;
|
|
15449
|
+
for (let index = 0; index < buffer.length; index += 1) {
|
|
15450
|
+
if (events.length >= room) break;
|
|
15451
|
+
if (buffer[index] !== 10) continue;
|
|
15452
|
+
let lineBytes = buffer.subarray(lineStart, index);
|
|
15453
|
+
if (lineBytes.at(-1) === 13) lineBytes = lineBytes.subarray(0, -1);
|
|
15454
|
+
const byteOffset = start2 + lineStart;
|
|
15455
|
+
lineStart = index + 1;
|
|
15456
|
+
if (lineBytes.length > MAX_RECORD_BYTES) continue;
|
|
15457
|
+
let line;
|
|
15458
|
+
try {
|
|
15459
|
+
line = UTF8_DECODER.decode(lineBytes);
|
|
15460
|
+
} catch {
|
|
15461
|
+
continue;
|
|
15462
|
+
}
|
|
15463
|
+
const { events: parsed } = parseSourceRecord(
|
|
15464
|
+
source,
|
|
15465
|
+
line,
|
|
15466
|
+
filename,
|
|
15467
|
+
byteOffset
|
|
15468
|
+
);
|
|
15469
|
+
for (const record32 of parsed) {
|
|
15470
|
+
if (record32.eventType !== "user_message" || queuedIds.has(record32.eventId))
|
|
15471
|
+
continue;
|
|
15472
|
+
const event3 = await redactTraceEvent(record32);
|
|
15473
|
+
if (Buffer.byteLength(JSON.stringify(event3), "utf8") <= MAX_EVENT_BYTES)
|
|
15474
|
+
events.push(event3);
|
|
15475
|
+
}
|
|
15476
|
+
}
|
|
15477
|
+
return { events, consumed: lineStart };
|
|
15478
|
+
}
|
|
15479
|
+
async function queueRecentMessages(config22, paths, limit2, signal) {
|
|
15480
|
+
if (limit2 === void 0) return void 0;
|
|
15481
|
+
const recent = await loadRecentMessages(paths) ?? {
|
|
15482
|
+
version: 1,
|
|
15483
|
+
cursors: {},
|
|
15484
|
+
queued: [...await queuedUserMessageIds(paths, limit2)],
|
|
15485
|
+
sent: 0,
|
|
15486
|
+
scanned: false
|
|
15487
|
+
};
|
|
15488
|
+
if (recent.scanned) return new Set(recent.queued);
|
|
15489
|
+
const source = collectorSource(config22);
|
|
15490
|
+
const mainCursors = (await loadState(paths)).cursors;
|
|
15491
|
+
const files = await sourceFilesNewestFirst(
|
|
15492
|
+
source,
|
|
15493
|
+
path14.resolve(collectorSourceDirectory(config22))
|
|
15494
|
+
);
|
|
15495
|
+
const queuedIds = await pendingEventIds(paths);
|
|
15496
|
+
const cursors = { ...recent.cursors };
|
|
15497
|
+
const queued = [...recent.queued];
|
|
15498
|
+
const events = [];
|
|
15499
|
+
let budget = MAX_SCAN_BYTES_PER_TICK;
|
|
15500
|
+
let reachedEnd = true;
|
|
15501
|
+
for (const file of files) {
|
|
15502
|
+
signal?.throwIfAborted();
|
|
15503
|
+
const room = limit2 - recent.sent - queued.length;
|
|
15504
|
+
const start2 = Math.max(
|
|
15505
|
+
cursors[file.filename] ?? 0,
|
|
15506
|
+
mainCursors[file.filename] ?? 0
|
|
15507
|
+
);
|
|
15508
|
+
if (room <= 0 || start2 >= file.size) continue;
|
|
15509
|
+
const length = Math.min(file.size - start2, MAX_SCAN_BYTES_PER_FILE, budget);
|
|
15510
|
+
const buffer = await readRange(file.filename, start2, length);
|
|
15511
|
+
budget -= buffer.length;
|
|
15512
|
+
const found = await messagesInRecords(
|
|
15513
|
+
source,
|
|
15514
|
+
file.filename,
|
|
15515
|
+
buffer,
|
|
15516
|
+
start2,
|
|
15517
|
+
room,
|
|
15518
|
+
queuedIds
|
|
15519
|
+
);
|
|
15520
|
+
for (const event3 of found.events) {
|
|
15521
|
+
events.push(event3);
|
|
15522
|
+
queued.push(event3.eventId);
|
|
15523
|
+
queuedIds.add(event3.eventId);
|
|
15524
|
+
}
|
|
15525
|
+
const stuck = found.consumed === 0 && length === MAX_SCAN_BYTES_PER_FILE;
|
|
15526
|
+
cursors[file.filename] = stuck ? file.size : start2 + found.consumed;
|
|
15527
|
+
if (buffer.length < file.size - start2 || budget === 0) {
|
|
15528
|
+
reachedEnd = false;
|
|
15529
|
+
if (budget === 0) break;
|
|
15530
|
+
}
|
|
15531
|
+
}
|
|
15532
|
+
await appendEvents(events, paths);
|
|
15533
|
+
await saveRecentMessages(
|
|
15534
|
+
{
|
|
15535
|
+
version: 1,
|
|
15536
|
+
cursors,
|
|
15537
|
+
queued,
|
|
15538
|
+
sent: recent.sent,
|
|
15539
|
+
scanned: recent.sent + queued.length >= limit2 || reachedEnd
|
|
15540
|
+
},
|
|
15541
|
+
paths
|
|
15542
|
+
);
|
|
15543
|
+
return new Set(queued);
|
|
15544
|
+
}
|
|
15545
|
+
async function settleRecentMessages(paths, limit2) {
|
|
15546
|
+
if (limit2 === void 0) return null;
|
|
15547
|
+
const recent = await loadRecentMessages(paths);
|
|
15548
|
+
if (recent === null) return { sent: 0, complete: false };
|
|
15549
|
+
if (recent.queued.length === 0)
|
|
15550
|
+
return { sent: recent.sent, complete: recent.scanned };
|
|
15551
|
+
const pending = await pendingEventIds(paths);
|
|
15552
|
+
const queued = recent.queued.filter((id) => pending.has(id));
|
|
15553
|
+
const sent = recent.sent + recent.queued.length - queued.length;
|
|
15554
|
+
if (queued.length !== recent.queued.length)
|
|
15555
|
+
await saveRecentMessages(
|
|
15556
|
+
{
|
|
15557
|
+
...recent,
|
|
15558
|
+
queued,
|
|
15559
|
+
sent,
|
|
15560
|
+
cursors: recent.scanned && queued.length === 0 ? {} : recent.cursors
|
|
15561
|
+
},
|
|
15562
|
+
paths
|
|
15563
|
+
);
|
|
15564
|
+
return { sent, complete: recent.scanned && queued.length === 0 };
|
|
15565
|
+
}
|
|
15566
|
+
function checkedRecentLimit(config22, limit2) {
|
|
15567
|
+
if (limit2 === void 0) return void 0;
|
|
15568
|
+
if (!Number.isSafeInteger(limit2) || limit2 < 1)
|
|
15569
|
+
throw new Error("The recent message limit must be a positive integer.");
|
|
15570
|
+
if (config22.destination === "vault")
|
|
15571
|
+
throw new Error("Vault collection does not send recent messages first.");
|
|
15572
|
+
return limit2;
|
|
15573
|
+
}
|
|
15369
15574
|
function isConsumedHook(source, filename, policy) {
|
|
15370
15575
|
if (policy !== void 0) return false;
|
|
15371
15576
|
return isCursorHookFile(source, filename) || source === "claude" && filename.includes(`${path14.sep}git-queue${path14.sep}`);
|
|
@@ -15379,12 +15584,12 @@ function retryAfterMs(response) {
|
|
|
15379
15584
|
const milliseconds = /^\d+$/.test(header) ? Number(header) * 1e3 : Date.parse(header) - Date.now();
|
|
15380
15585
|
return Number.isFinite(milliseconds) ? Math.max(1e3, Math.min(milliseconds, 3e5)) : 5e3;
|
|
15381
15586
|
}
|
|
15382
|
-
async function uploadPendingOnce(config22, paths, fetcher = collectorFetch, signal, onAcknowledged, policy) {
|
|
15587
|
+
async function uploadPendingOnce(config22, paths, fetcher = collectorFetch, signal, onAcknowledged, policy, first) {
|
|
15383
15588
|
let uploaded = 0;
|
|
15384
15589
|
for (let attempt = 0; attempt < MAX_UPLOADS_PER_TICK; attempt += 1) {
|
|
15385
15590
|
signal?.throwIfAborted();
|
|
15386
15591
|
await recheckQueuedAccounts(config22, paths, policy);
|
|
15387
|
-
const batch = await nextBatch(paths, MAX_UPLOAD_BYTES);
|
|
15592
|
+
const batch = await nextBatch(paths, MAX_UPLOAD_BYTES, first);
|
|
15388
15593
|
if (batch.length === 0) return { uploaded, retryAfterMs: null };
|
|
15389
15594
|
const body = JSON.stringify({ events: batch });
|
|
15390
15595
|
if (Buffer.byteLength(body, "utf8") > MAX_REQUEST_BYTES) {
|
|
@@ -15453,7 +15658,8 @@ async function recheckQueuedAccounts(config22, paths, policy) {
|
|
|
15453
15658
|
(event3) => reauthorizeVaultEvent(policy, event3, accounts)
|
|
15454
15659
|
);
|
|
15455
15660
|
}
|
|
15456
|
-
async function collectorTick(config22, paths, fetcher = collectorFetch, signal, onAcknowledged) {
|
|
15661
|
+
async function collectorTick(config22, paths, fetcher = collectorFetch, signal, onAcknowledged, options = {}) {
|
|
15662
|
+
const recentLimit = checkedRecentLimit(config22, options.recentMessages);
|
|
15457
15663
|
const accounts = await vaultAccountIndex(config22);
|
|
15458
15664
|
const policy = config22.destination === "vault" ? await fetchVaultPolicy(config22.endpoint, config22.token, fetcher, signal) : void 0;
|
|
15459
15665
|
if (policy !== void 0) {
|
|
@@ -15478,13 +15684,15 @@ async function collectorTick(config22, paths, fetcher = collectorFetch, signal,
|
|
|
15478
15684
|
}
|
|
15479
15685
|
}
|
|
15480
15686
|
await redactPendingOutbox(paths);
|
|
15687
|
+
const first = await queueRecentMessages(config22, paths, recentLimit, signal);
|
|
15481
15688
|
let upload = await uploadPendingOnce(
|
|
15482
15689
|
config22,
|
|
15483
15690
|
paths,
|
|
15484
15691
|
fetcher,
|
|
15485
15692
|
signal,
|
|
15486
15693
|
onAcknowledged,
|
|
15487
|
-
policy
|
|
15694
|
+
policy,
|
|
15695
|
+
first
|
|
15488
15696
|
);
|
|
15489
15697
|
const scan = await outboxSize(paths) >= SCAN_PAUSE_OUTBOX_BYTES ? { discovered: 0, excludedRecords: 0, caughtUp: false, history: null } : await scanSourceOnce(config22, paths, signal, policy, accounts);
|
|
15490
15698
|
if (policy !== void 0 && scan.caughtUp) {
|
|
@@ -15502,7 +15710,8 @@ async function collectorTick(config22, paths, fetcher = collectorFetch, signal,
|
|
|
15502
15710
|
fetcher,
|
|
15503
15711
|
signal,
|
|
15504
15712
|
onAcknowledged,
|
|
15505
|
-
policy
|
|
15713
|
+
policy,
|
|
15714
|
+
first
|
|
15506
15715
|
);
|
|
15507
15716
|
upload = { ...next, uploaded: upload.uploaded + next.uploaded };
|
|
15508
15717
|
}
|
|
@@ -15513,6 +15722,7 @@ async function collectorTick(config22, paths, fetcher = collectorFetch, signal,
|
|
|
15513
15722
|
outboxBytes: await outboxSize(paths),
|
|
15514
15723
|
historyCaughtUp: scan.caughtUp,
|
|
15515
15724
|
history: scan.history,
|
|
15725
|
+
recentMessages: await settleRecentMessages(paths, recentLimit),
|
|
15516
15726
|
retryAfterMs: upload.retryAfterMs ?? 0
|
|
15517
15727
|
};
|
|
15518
15728
|
}
|
|
@@ -22385,11 +22595,16 @@ var collectorFrictionSummarySchema = object3({
|
|
|
22385
22595
|
weekEpisodes: episodeCountSchema,
|
|
22386
22596
|
dayEpisodes: episodeCountSchema
|
|
22387
22597
|
}).strict().refine((summary) => summary.dayEpisodes <= summary.weekEpisodes, "The last day cannot have more friction episodes than the last week.").describe("dayEpisodes must not exceed weekEpisodes.");
|
|
22598
|
+
var RECENT_MESSAGE_LIMIT = 400;
|
|
22388
22599
|
var sessionCountSchema = number4().int().min(0).max(1e6);
|
|
22389
22600
|
var collectorHistoryProgressSchema = object3({
|
|
22390
22601
|
sessions: sessionCountSchema,
|
|
22391
22602
|
readSessions: sessionCountSchema,
|
|
22392
|
-
complete: boolean4()
|
|
22603
|
+
complete: boolean4(),
|
|
22604
|
+
recentMessages: object3({
|
|
22605
|
+
sent: number4().int().min(0).max(RECENT_MESSAGE_LIMIT),
|
|
22606
|
+
complete: boolean4()
|
|
22607
|
+
}).strict().optional().describe("The newest messages sent ahead of the rest of the history; collectors before 0.17.0 omit it.")
|
|
22393
22608
|
}).strict().refine((progress) => progress.readSessions <= progress.sessions, "Read sessions cannot exceed listed sessions.").refine((progress) => !progress.complete || progress.readSessions === progress.sessions, "A complete import has read every listed session.").describe("readSessions must not exceed sessions; complete requires equal counts.");
|
|
22394
22609
|
var collectorEnrollmentRequestSchema = object3({
|
|
22395
22610
|
deviceName: string5().trim().min(1).max(160).describe("Trimmed before length validation."),
|
|
@@ -23950,12 +24165,14 @@ ${detail}` : ""}`,
|
|
|
23950
24165
|
}
|
|
23951
24166
|
async function stopTask(source) {
|
|
23952
24167
|
const task = await observedTask(source);
|
|
23953
|
-
if (task === null
|
|
24168
|
+
if (task === null) return false;
|
|
24169
|
+
if (task.state === 1 || task.state === 3) return true;
|
|
23954
24170
|
await schtasks(source, "/End");
|
|
23955
24171
|
const deadline = Date.now() + TASK_TIMEOUT_MS;
|
|
23956
24172
|
while (Date.now() < deadline) {
|
|
23957
24173
|
const current = await observedTask(source);
|
|
23958
|
-
if (current === null
|
|
24174
|
+
if (current === null) return false;
|
|
24175
|
+
if (current.state === 1 || current.state === 3) return true;
|
|
23959
24176
|
await delay3(100);
|
|
23960
24177
|
}
|
|
23961
24178
|
throw new Error(`Windows did not stop the ${source} collector task.`);
|
|
@@ -23991,9 +24208,7 @@ async function installScheduledTask(dataDirectory2, source) {
|
|
|
23991
24208
|
return file;
|
|
23992
24209
|
}
|
|
23993
24210
|
async function uninstallScheduledTask(source) {
|
|
23994
|
-
await stopTask(source);
|
|
23995
|
-
if (await observedTask(source) !== null)
|
|
23996
|
-
await schtasks(source, "/Delete", "/F");
|
|
24211
|
+
if (await stopTask(source)) await schtasks(source, "/Delete", "/F");
|
|
23997
24212
|
await fs15.rm(taskDefinitionPath(source), { force: true });
|
|
23998
24213
|
}
|
|
23999
24214
|
async function scheduledTaskStatus(source) {
|
|
@@ -25582,6 +25797,7 @@ async function clearConnection(directory) {
|
|
|
25582
25797
|
paths.redactionMarker,
|
|
25583
25798
|
paths.historyBackfill,
|
|
25584
25799
|
paths.health,
|
|
25800
|
+
paths.recentMessages,
|
|
25585
25801
|
...[
|
|
25586
25802
|
"cursor-hooks",
|
|
25587
25803
|
"cursor-hook-failure.json",
|
|
@@ -25641,16 +25857,15 @@ async function logout(extraDirectory) {
|
|
|
25641
25857
|
}
|
|
25642
25858
|
}
|
|
25643
25859
|
await savePendingDirectories(pending, directories);
|
|
25644
|
-
|
|
25645
|
-
|
|
25646
|
-
|
|
25647
|
-
|
|
25648
|
-
|
|
25649
|
-
|
|
25650
|
-
|
|
25651
|
-
|
|
25652
|
-
|
|
25653
|
-
}
|
|
25860
|
+
const stopped = await Promise.all(
|
|
25861
|
+
COLLECTOR_SOURCES2.filter((source) => !unreadableServices.has(source)).map(
|
|
25862
|
+
(source) => uninstallBackgroundService(source).then(
|
|
25863
|
+
() => null,
|
|
25864
|
+
(error3) => `${source}: ${error3 instanceof Error ? error3.message : "Could not stop collector startup."}`
|
|
25865
|
+
)
|
|
25866
|
+
)
|
|
25867
|
+
);
|
|
25868
|
+
for (const failure3 of stopped) if (failure3 !== null) failures.push(failure3);
|
|
25654
25869
|
for (const directory of directories) {
|
|
25655
25870
|
try {
|
|
25656
25871
|
await clearConnection(directory);
|
|
@@ -26499,7 +26714,13 @@ var HistoryProgressError = class extends Error {
|
|
|
26499
26714
|
}
|
|
26500
26715
|
};
|
|
26501
26716
|
function unchanged(left, right) {
|
|
26502
|
-
return right !== null && left.sessions === right.sessions && left.readSessions === right.readSessions && left.complete === right.complete;
|
|
26717
|
+
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;
|
|
26718
|
+
}
|
|
26719
|
+
function settled(progress) {
|
|
26720
|
+
return progress.complete && (progress.recentMessages?.complete ?? true);
|
|
26721
|
+
}
|
|
26722
|
+
function milestone(progress, sent) {
|
|
26723
|
+
return progress.complete || progress.recentMessages?.complete === true && sent?.recentMessages?.complete !== true;
|
|
26503
26724
|
}
|
|
26504
26725
|
var HistoryProgressReporter = class {
|
|
26505
26726
|
#sent = null;
|
|
@@ -26507,7 +26728,7 @@ var HistoryProgressReporter = class {
|
|
|
26507
26728
|
#completed = false;
|
|
26508
26729
|
async report(config3, progress, fetcher, signal, nowMs) {
|
|
26509
26730
|
if (this.#completed || unchanged(progress, this.#sent)) return;
|
|
26510
|
-
if (!progress
|
|
26731
|
+
if (!milestone(progress, this.#sent) && nowMs - this.#sentAtMs < REPORT_INTERVAL_MS)
|
|
26511
26732
|
return;
|
|
26512
26733
|
let response;
|
|
26513
26734
|
try {
|
|
@@ -26540,7 +26761,7 @@ var HistoryProgressReporter = class {
|
|
|
26540
26761
|
}
|
|
26541
26762
|
this.#sent = progress;
|
|
26542
26763
|
this.#sentAtMs = nowMs;
|
|
26543
|
-
this.#completed = progress
|
|
26764
|
+
this.#completed = settled(progress);
|
|
26544
26765
|
}
|
|
26545
26766
|
};
|
|
26546
26767
|
|
|
@@ -26650,6 +26871,7 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
26650
26871
|
let lastAutoCheckAt = 0;
|
|
26651
26872
|
let lastBillingSyncAt = 0;
|
|
26652
26873
|
const historyProgress = new HistoryProgressReporter();
|
|
26874
|
+
let scanned = null;
|
|
26653
26875
|
const runtimeVersion = process.env.ITERATION_RUNTIME_VERSION;
|
|
26654
26876
|
let lastRuntimeCheckAt = 0;
|
|
26655
26877
|
let trialSettled = runtimeVersion === void 0;
|
|
@@ -26743,13 +26965,16 @@ async function runCollector(directory = defaultCollectorDirectory("codex"), expe
|
|
|
26743
26965
|
controller.signal,
|
|
26744
26966
|
() => {
|
|
26745
26967
|
acknowledgedAtMs = Date.now();
|
|
26746
|
-
}
|
|
26968
|
+
},
|
|
26969
|
+
{ recentMessages: RECENT_MESSAGE_LIMIT }
|
|
26747
26970
|
);
|
|
26748
26971
|
billingReady = result.historyCaughtUp && result.outboxBytes === 0;
|
|
26749
|
-
|
|
26972
|
+
scanned = result.history ?? scanned;
|
|
26973
|
+
if (scanned !== null) {
|
|
26750
26974
|
history = {
|
|
26751
|
-
...
|
|
26752
|
-
complete: billingReady &&
|
|
26975
|
+
...scanned,
|
|
26976
|
+
complete: billingReady && scanned.readSessions === scanned.sessions,
|
|
26977
|
+
...result.recentMessages === null ? {} : { recentMessages: result.recentMessages }
|
|
26753
26978
|
};
|
|
26754
26979
|
}
|
|
26755
26980
|
await recordTickSuccess(result, acknowledgedAtMs);
|
|
@@ -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({
|