@pdpp/local-collector 0.1.0-beta.6 → 0.1.0-beta.8

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.
Files changed (26) hide show
  1. package/dist/local-collector/bin/pdpp-local-collector.js +580 -22
  2. package/dist/local-collector/src/runner.d.ts +1 -1
  3. package/dist/local-collector/src/runner.js +15 -1
  4. package/dist/polyfill-connectors/connectors/claude_code/index.js +85 -48
  5. package/dist/polyfill-connectors/connectors/codex/index.js +390 -108
  6. package/dist/polyfill-connectors/connectors/codex/parsers.js +5 -3
  7. package/dist/polyfill-connectors/src/bounded-file-preview.js +76 -0
  8. package/dist/polyfill-connectors/src/browser-handoff.js +38 -5
  9. package/dist/polyfill-connectors/src/collector-build-info.d.ts +8 -0
  10. package/dist/polyfill-connectors/src/collector-build-info.js +10 -0
  11. package/dist/polyfill-connectors/src/collector-runner.d.ts +54 -0
  12. package/dist/polyfill-connectors/src/collector-runner.js +250 -18
  13. package/dist/polyfill-connectors/src/connector-exit.js +62 -0
  14. package/dist/polyfill-connectors/src/connector-runtime-protocol.d.ts +41 -21
  15. package/dist/polyfill-connectors/src/connector-runtime.js +241 -30
  16. package/dist/polyfill-connectors/src/fingerprint-cursor.js +107 -0
  17. package/dist/polyfill-connectors/src/local-device-client.d.ts +17 -0
  18. package/dist/polyfill-connectors/src/local-device-client.js +69 -9
  19. package/dist/polyfill-connectors/src/local-device-outbox.d.ts +59 -0
  20. package/dist/polyfill-connectors/src/local-device-outbox.js +394 -5
  21. package/dist/polyfill-connectors/src/local-source-inventory.js +8 -1
  22. package/dist/polyfill-connectors/src/runner/index.d.ts +4 -3
  23. package/dist/polyfill-connectors/src/runner/index.js +4 -3
  24. package/dist/polyfill-connectors/src/safe-text-preview.js +13 -0
  25. package/dist/polyfill-connectors/src/static-secret-injection.js +155 -0
  26. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { type RuntimeCapabilityProfile } from "../../polyfill-connectors/src/runner/index.js";
2
- export { buildCollectorStartMessage, COLLECTOR_PROTOCOL_VERSION, CollectorStateReadError, drainCollectorQueue, emitToStdout, enrollCollector, evaluatePlacement, isMainModule, LocalDeviceClient, LocalDeviceHttpError, LocalDeviceOutbox, LocalDeviceQueue, PROVIDER_RUNTIME_CAPABILITIES, RUNTIME_CAPABILITY_MISMATCH_CODE, RuntimeCapabilityMismatchError, assertPlacementOrThrow, buildLocalDeviceRecordEnvelope, buildLocalDeviceOutboxId, canonicalJson, diffRequiredBindings, hashCanonicalJson, parseJsonlLine, resourceSet, runCollectorConnector, stringifyForJsonl, transformRecordsToCollectorEnvelopes, type CollectorChildContext, type CollectorConnectorSpec, type CollectorEnrollmentConfig, type CollectorRunConfig, type CollectorRunResult, type ConnectorPlacementInput, type ConnectorRuntimeRequirements, type EmittedMessage, type EnrollmentExchangeResponse, type LocalDeviceRecordEnvelope, type BuildLocalDeviceOutboxIdInput, type LocalDeviceOutboxClaimInput, type LocalDeviceOutboxDeadLetterInput, type LocalDeviceOutboxEnqueueInput, type LocalDeviceOutboxFailInput, type LocalDeviceOutboxItem, type LocalDeviceOutboxKind, type LocalDeviceOutboxLeaseInput, type LocalDeviceOutboxOptions, type LocalDeviceOutboxStatus, type LocalDeviceOutboxSummary, type PlacementDecision, type RuntimeBindingName, type RuntimeCapabilityProfile, type StartMessage, type StreamScope, } from "../../polyfill-connectors/src/runner/index.js";
2
+ export { buildCollectorStartMessage, COLLECTOR_COVERAGE_STATUSES, COLLECTOR_PROTOCOL_VERSION, CollectorStateReadError, drainCollectorQueue, emitToStdout, enrollCollector, evaluatePlacement, isMainModule, LocalDeviceClient, LocalDeviceHttpError, LocalDeviceOutbox, LocalDeviceQueue, PROVIDER_RUNTIME_CAPABILITIES, RUNTIME_CAPABILITY_MISMATCH_CODE, RuntimeCapabilityMismatchError, assertPlacementOrThrow, buildLocalDeviceRecordEnvelope, buildLocalDeviceOutboxId, canonicalJson, classifyDeadLetterError, deriveLocalCollectorLifecycleState, diffRequiredBindings, hashCanonicalJson, LOCAL_COLLECTOR_LIFECYCLE_STATES, parseJsonlLine, resourceSet, runCollectorConnector, stringifyForJsonl, summarizeCollectorCompleteness, transformRecordsToCollectorEnvelopes, type CollectorChildContext, type CollectorCompletenessSummary, type CollectorConnectorSpec, type CollectorCoverageStatus, type CollectorEnrollmentConfig, type CollectorRunConfig, type CollectorRunResult, type ConnectorPlacementInput, type ConnectorRuntimeRequirements, type EmittedMessage, type EnrollmentExchangeResponse, type LocalCollectorLifecycleInput, type LocalCollectorLifecycleState, type LocalDeviceRecordEnvelope, type BuildLocalDeviceOutboxIdInput, type LocalDeviceOutboxClaimInput, type LocalDeviceOutboxCompactResult, type LocalDeviceOutboxDeadLetterErrorClass, type LocalDeviceOutboxDeadLetterErrorSummary, type LocalDeviceOutboxDeadLetterErrorSummaryInput, type LocalDeviceOutboxDeadLetterInput, type LocalDeviceOutboxEnqueueInput, type LocalDeviceOutboxFailInput, type LocalDeviceOutboxItem, type LocalDeviceOutboxKind, type LocalDeviceOutboxLeaseInput, type LocalDeviceOutboxOptions, type LocalDeviceOutboxPageStats, type LocalDeviceOutboxPruneSentInput, type LocalDeviceOutboxPruneSentResult, type LocalDeviceOutboxRequeueDeadLettersInput, type LocalDeviceOutboxRequeueDeadLettersResult, type LocalDeviceOutboxStatus, type LocalDeviceOutboxSummary, type PlacementDecision, type RuntimeBindingName, type RuntimeCapabilityProfile, type StartMessage, type StreamScope, } from "../../polyfill-connectors/src/runner/index.js";
3
3
  export declare const COLLECTOR_RUNTIME_CAPABILITIES: RuntimeCapabilityProfile;
4
4
  export interface BundledConnectorEntry {
5
5
  readonly connector_id: string;
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { extname } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { COLLECTOR_PROTOCOL_VERSION as PROTOCOL_VERSION, COLLECTOR_RUNTIME_CAPABILITIES as POLYFILL_COLLECTOR_RUNTIME_CAPABILITIES, } from "../../polyfill-connectors/src/runner/index.js";
5
- export { buildCollectorStartMessage, COLLECTOR_PROTOCOL_VERSION, CollectorStateReadError, drainCollectorQueue, emitToStdout, enrollCollector, evaluatePlacement, isMainModule, LocalDeviceClient, LocalDeviceHttpError, LocalDeviceOutbox, LocalDeviceQueue, PROVIDER_RUNTIME_CAPABILITIES, RUNTIME_CAPABILITY_MISMATCH_CODE, RuntimeCapabilityMismatchError, assertPlacementOrThrow, buildLocalDeviceRecordEnvelope, buildLocalDeviceOutboxId, canonicalJson, diffRequiredBindings, hashCanonicalJson, parseJsonlLine, resourceSet, runCollectorConnector, stringifyForJsonl, transformRecordsToCollectorEnvelopes, } from "../../polyfill-connectors/src/runner/index.js";
5
+ export { buildCollectorStartMessage, COLLECTOR_COVERAGE_STATUSES, COLLECTOR_PROTOCOL_VERSION, CollectorStateReadError, drainCollectorQueue, emitToStdout, enrollCollector, evaluatePlacement, isMainModule, LocalDeviceClient, LocalDeviceHttpError, LocalDeviceOutbox, LocalDeviceQueue, PROVIDER_RUNTIME_CAPABILITIES, RUNTIME_CAPABILITY_MISMATCH_CODE, RuntimeCapabilityMismatchError, assertPlacementOrThrow, buildLocalDeviceRecordEnvelope, buildLocalDeviceOutboxId, canonicalJson, classifyDeadLetterError, deriveLocalCollectorLifecycleState, diffRequiredBindings, hashCanonicalJson, LOCAL_COLLECTOR_LIFECYCLE_STATES, parseJsonlLine, resourceSet, runCollectorConnector, stringifyForJsonl, summarizeCollectorCompleteness, transformRecordsToCollectorEnvelopes, } from "../../polyfill-connectors/src/runner/index.js";
6
6
  export const COLLECTOR_RUNTIME_CAPABILITIES = {
7
7
  id: POLYFILL_COLLECTOR_RUNTIME_CAPABILITIES.id,
8
8
  bindings: new Set(["network", "filesystem", "local_device"]),
@@ -32,6 +32,13 @@ export const BUNDLED_CONNECTORS = Object.freeze({
32
32
  "memory_notes",
33
33
  "skills",
34
34
  "slash_commands",
35
+ "file_history",
36
+ "cache_inventory",
37
+ "coverage_diagnostics",
38
+ "debug_artifacts",
39
+ "downloads",
40
+ "backup_inventory",
41
+ "config_inventory",
35
42
  ]),
36
43
  }),
37
44
  codex: Object.freeze({
@@ -46,6 +53,13 @@ export const BUNDLED_CONNECTORS = Object.freeze({
46
53
  "rules",
47
54
  "prompts",
48
55
  "skills",
56
+ "history",
57
+ "session_index",
58
+ "logs",
59
+ "shell_snapshots",
60
+ "config_inventory",
61
+ "cache_inventory",
62
+ "coverage_diagnostics",
49
63
  ]),
50
64
  }),
51
65
  });
@@ -4,9 +4,10 @@ import { readdir, readFile, stat } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { basename, join } from "node:path";
6
6
  import { createInterface as createFileReader } from "node:readline";
7
+ import { readBoundedFilePreview } from "../../src/bounded-file-preview.js";
7
8
  import { runConnector } from "../../src/connector-runtime.js";
8
9
  import { isMainModule } from "../../src/is-main-module.js";
9
- import { buildLocalSourceInventory, listDirectoryInventory, } from "../../src/local-source-inventory.js";
10
+ import { buildLocalSourceInventory, listDirectoryInventory, openInventoryFingerprintCursor, } from "../../src/local-source-inventory.js";
10
11
  import { safeTextPreview } from "../../src/safe-text-preview.js";
11
12
  import { ATTACHMENT_PREVIEW_CHARS, applyProjectDirScope, BYTES_PER_MB, buildMemoryNoteRecord, buildSkillRecord, buildSlashCommandRecord, extractContent, LINE_PROGRESS_INTERVAL, MESSAGE_CONTENT_PREVIEW_CHARS, makeEmptySessionAccumulator, mergeSessionObservations, parseCsvEnv, parseFrontmatter, SESSION_DIR_PREFIX_RE, TOOL_RESULT_PREVIEW_CHARS, textPreview, widenSessionTimeRange, } from "./parsers.js";
12
13
  import { validateRecord } from "./schemas.js";
@@ -148,6 +149,17 @@ export function observeJsonlFields(obj, obs, forcedSessionId) {
148
149
  }
149
150
  }
150
151
  }
152
+ function updateSessionAccumulatorFromCurrentLine(sessionAccumulators, projectDir, obs, obj, messageCountDelta) {
153
+ if (!obs.sessionId) {
154
+ return;
155
+ }
156
+ updateSessionAccumulator(sessionAccumulators, projectDir, {
157
+ ...obs,
158
+ firstTimestamp: obj.timestamp ?? null,
159
+ lastTimestamp: obj.timestamp ?? null,
160
+ messageCount: messageCountDelta,
161
+ });
162
+ }
151
163
  export function isMessageType(type) {
152
164
  return type === "user" || type === "assistant";
153
165
  }
@@ -211,16 +223,13 @@ export async function emitSessionsFromAccumulators({ emitRecord, requested, sess
211
223
  await emitRecord("sessions", { ...session });
212
224
  }
213
225
  }
214
- async function emitToolResultFile(args) {
215
- let buf;
216
- try {
217
- buf = await readFile(args.full, "utf8");
218
- }
219
- catch {
226
+ export async function emitToolResultFile(args) {
227
+ const bounded = await readBoundedFilePreview(args.full);
228
+ if (bounded === null) {
220
229
  return;
221
230
  }
222
231
  const rel = args.full.slice(args.toolResultsDir.length + 1);
223
- const previewResult = safeTextPreview(buf, TOOL_RESULT_PREVIEW_CHARS);
232
+ const previewResult = safeTextPreview(bounded.buffer, TOOL_RESULT_PREVIEW_CHARS);
224
233
  await args.emitRecord("attachments", {
225
234
  id: `tool_result_file:${args.projectDir}/${args.sessionId}/${rel}`,
226
235
  session_id: args.sessionId,
@@ -354,14 +363,15 @@ async function parseJsonlFile(args) {
354
363
  if (!buildOnly && lineCount % LINE_PROGRESS_INTERVAL === 0) {
355
364
  await emit({
356
365
  type: "PROGRESS",
357
- message: ` ${path}: ${lineCount} lines parsed`,
366
+ message: `Claude Code phase=emit pass=emit lines_parsed=${lineCount}`,
358
367
  });
359
368
  }
369
+ const messageCountBeforeLine = obs.messageCount;
360
370
  observeJsonlFields(obj, obs, forcedSessionId);
361
371
  await processJsonlLine({ buildOnly, deps: { emitRecord, requested }, obj, obs });
362
- }
363
- if (buildOnly) {
364
- updateSessionAccumulator(sessionAccumulators, projectDir, obs);
372
+ if (buildOnly) {
373
+ updateSessionAccumulatorFromCurrentLine(sessionAccumulators, projectDir, obs, obj, obs.messageCount - messageCountBeforeLine);
374
+ }
365
375
  }
366
376
  return obs.sessionId;
367
377
  }
@@ -494,7 +504,7 @@ async function emitProjectMemoryNotes({ emitRecord, fileMtimes, newMtimes, proje
494
504
  await emitRecord("memory_notes", buildMemoryNoteRecord({ projectDir, relPath, frontmatter, body, path: fullPath, mtimeMs: st.mtimeMs }));
495
505
  }
496
506
  }
497
- async function processJsonlFile({ args, forcedSessionId, path, progressLabel, projectDir, }) {
507
+ async function processJsonlFile({ args, forcedSessionId, path, projectDir }) {
498
508
  let st;
499
509
  try {
500
510
  st = statSync(path);
@@ -509,7 +519,7 @@ async function processJsonlFile({ args, forcedSessionId, path, progressLabel, pr
509
519
  }
510
520
  await args.emit({
511
521
  type: "PROGRESS",
512
- message: `${args.buildOnly ? "Indexing" : "Emitting"} ${progressLabel} (${(st.size / BYTES_PER_MB).toFixed(1)}MB)`,
522
+ message: `Claude Code phase=${args.buildOnly ? "index" : "emit"} pass=${args.buildOnly ? "index" : "emit"} file_size_mb=${(st.size / BYTES_PER_MB).toFixed(1)}`,
513
523
  });
514
524
  await parseJsonlFile({
515
525
  buildOnly: args.buildOnly,
@@ -530,7 +540,6 @@ async function processTopLevelJsonl(entries, projectPath, projectDir, args) {
530
540
  args,
531
541
  forcedSessionId: null,
532
542
  path: join(projectPath, f),
533
- progressLabel: `${projectDir}/${f}`,
534
543
  projectDir,
535
544
  });
536
545
  }
@@ -549,7 +558,6 @@ async function processSessionDir(sessEnt, projectPath, projectDir, args) {
549
558
  args,
550
559
  forcedSessionId: sessionId,
551
560
  path: join(subagentsDir, f),
552
- progressLabel: `${projectDir}/${sessionId}/subagents/${f}`,
553
561
  projectDir,
554
562
  });
555
563
  }
@@ -594,13 +602,12 @@ async function listProjectDirs(baseDir, emit) {
594
602
  try {
595
603
  projectDirs = (await readdir(baseDir)).filter((name) => !name.startsWith("."));
596
604
  }
597
- catch (err) {
598
- const errMsg = err instanceof Error ? err.message : String(err);
605
+ catch {
599
606
  await emit({
600
607
  type: "SKIP_RESULT",
601
608
  stream: "sessions",
602
609
  reason: "claude_dir_not_found",
603
- message: `${baseDir} not readable: ${errMsg}`,
610
+ message: "Claude Code projects directory not readable",
604
611
  });
605
612
  return null;
606
613
  }
@@ -613,9 +620,10 @@ export async function scanProjectDirs(args) {
613
620
  if (projectDirs === null) {
614
621
  return;
615
622
  }
623
+ const totalProjectDirs = projectDirs.length;
616
624
  await args.emit({
617
625
  type: "PROGRESS",
618
- message: `${projectDirs.length} project dirs in scope`,
626
+ message: `Claude Code phase=index pass=index total_project_dirs=${totalProjectDirs}`,
619
627
  });
620
628
  for (const projectDir of projectDirs) {
621
629
  await scanProjectDir(projectDir, args);
@@ -649,15 +657,40 @@ async function assertRequestedClaudeSources(input) {
649
657
  throw new Error(`requested Claude Code local source path(s) are missing or unreadable: ${missing.join(", ")}`);
650
658
  }
651
659
  }
660
+ async function emitCoverageDiagnostics(input) {
661
+ if (!input.requested.has("coverage_diagnostics")) {
662
+ return;
663
+ }
664
+ for (const record of input.inventory.coverage) {
665
+ await input.emitRecord("coverage_diagnostics", record);
666
+ }
667
+ }
668
+ async function emitGatedInventoryStream(input) {
669
+ const cursor = openInventoryFingerprintCursor(input.priorState);
670
+ for (const record of input.records) {
671
+ if (cursor.shouldEmit(record)) {
672
+ await input.emitRecord(input.stream, record);
673
+ }
674
+ }
675
+ cursor.pruneStale();
676
+ const inventoryCursor = { fetched_at: nowIso() };
677
+ if (cursor.size() > 0) {
678
+ inventoryCursor.fingerprints = cursor.toState();
679
+ }
680
+ await input.emit({ type: "STATE", stream: input.stream, cursor: inventoryCursor });
681
+ }
652
682
  async function emitLocalInventoryStreams(input) {
653
- const inventory = await buildLocalSourceInventory("claude_code", input.claudeHome, CLAUDE_CODE_KNOWN_LOCAL_STORES);
654
- for (const [stream, records] of inventory.recordsByStream) {
683
+ for (const [stream, records] of input.inventory.recordsByStream) {
655
684
  if (!input.requested.has(stream)) {
656
685
  continue;
657
686
  }
658
- for (const record of records) {
659
- await input.emitRecord(stream, record);
660
- }
687
+ await emitGatedInventoryStream({
688
+ emit: input.emit,
689
+ emitRecord: input.emitRecord,
690
+ priorState: input.state[stream],
691
+ records,
692
+ stream,
693
+ });
661
694
  }
662
695
  if (input.requested.has("file_history")) {
663
696
  const records = await listDirectoryInventory({
@@ -668,14 +701,13 @@ async function emitLocalInventoryStreams(input) {
668
701
  stream: "file_history",
669
702
  reason: "metadata-only until payload contract is approved",
670
703
  });
671
- for (const record of records) {
672
- await input.emitRecord("file_history", record);
673
- }
674
- }
675
- if (input.requested.has("coverage_diagnostics")) {
676
- for (const record of inventory.coverage) {
677
- await input.emitRecord("coverage_diagnostics", record);
678
- }
704
+ await emitGatedInventoryStream({
705
+ emit: input.emit,
706
+ emitRecord: input.emitRecord,
707
+ priorState: input.state.file_history,
708
+ records,
709
+ stream: "file_history",
710
+ });
679
711
  }
680
712
  }
681
713
  async function runSkillsAndCommands(claudeHome, requested, emit, emitRecord, state) {
@@ -688,9 +720,8 @@ async function runSkillsAndCommands(claudeHome, requested, emit, emitRecord, sta
688
720
  newMtimes: state.newSkillsMtimes,
689
721
  });
690
722
  }
691
- catch (err) {
692
- const msg = err instanceof Error ? err.message : String(err);
693
- await emit({ type: "PROGRESS", message: `skills scan skipped: ${msg}` });
723
+ catch {
724
+ await emit({ type: "PROGRESS", message: "Claude Code phase=index pass=index stream=skills scan_skipped=true" });
694
725
  }
695
726
  try {
696
727
  await emitSlashCommands({
@@ -701,9 +732,11 @@ async function runSkillsAndCommands(claudeHome, requested, emit, emitRecord, sta
701
732
  newMtimes: state.newSlashCommandMtimes,
702
733
  });
703
734
  }
704
- catch (err) {
705
- const msg = err instanceof Error ? err.message : String(err);
706
- await emit({ type: "PROGRESS", message: `slash_commands scan skipped: ${msg}` });
735
+ catch {
736
+ await emit({
737
+ type: "PROGRESS",
738
+ message: "Claude Code phase=index pass=index stream=slash_commands scan_skipped=true",
739
+ });
707
740
  }
708
741
  if (requested.has("skills")) {
709
742
  await emit({
@@ -730,16 +763,19 @@ if (isMainModule(import.meta.url)) {
730
763
  async collect({ state, requested, emit, emitRecord }) {
731
764
  const claudeHome = process.env.CLAUDE_CODE_HOME || join(homedir(), ".claude");
732
765
  const baseDir = process.env.CLAUDE_CODE_PROJECTS_DIR || join(claudeHome, "projects");
766
+ const inventory = await buildLocalSourceInventory("claude_code", claudeHome, CLAUDE_CODE_KNOWN_LOCAL_STORES);
767
+ await emitCoverageDiagnostics({ emitRecord, inventory, requested });
733
768
  await assertRequestedClaudeSources({ baseDir, claudeHome, requested });
734
769
  const typedState = state;
735
- const fileMtimes = streamFileMtimes(typedState, "messages") ?? typedState.file_mtimes ?? {};
770
+ const messageFileMtimes = streamFileMtimes(typedState, "messages") ?? typedState.file_mtimes ?? {};
771
+ const sessionFileMtimes = streamFileMtimes(typedState, "sessions") ?? {};
736
772
  const skillsMtimes = streamFileMtimes(typedState, "skills") ?? {};
737
773
  const slashCommandMtimes = streamFileMtimes(typedState, "slash_commands") ?? {};
738
774
  const memoryNoteMtimes = streamFileMtimes(typedState, "memory_notes") ?? {};
739
775
  const newSkillsMtimes = { ...skillsMtimes };
740
776
  const newSlashCommandMtimes = { ...slashCommandMtimes };
741
777
  const newMemoryNoteMtimes = { ...memoryNoteMtimes };
742
- await emitLocalInventoryStreams({ claudeHome, requested, emitRecord });
778
+ await emitLocalInventoryStreams({ claudeHome, emit, emitRecord, inventory, requested, state: typedState });
743
779
  await runSkillsAndCommands(claudeHome, requested, emit, emitRecord, {
744
780
  skillsMtimes,
745
781
  newSkillsMtimes,
@@ -753,15 +789,16 @@ if (isMainModule(import.meta.url)) {
753
789
  if (!needsProjects) {
754
790
  return;
755
791
  }
756
- const newMtimes = { ...fileMtimes };
792
+ const newMessageFileMtimes = { ...messageFileMtimes };
793
+ const newSessionFileMtimes = { ...sessionFileMtimes };
757
794
  const sessionAccumulators = new Map();
758
795
  await scanProjectDirs({
759
796
  baseDir,
760
797
  buildOnly: true,
761
798
  emit,
762
799
  emitRecord,
763
- fileMtimes,
764
- newMtimes,
800
+ fileMtimes: sessionFileMtimes,
801
+ newMtimes: newSessionFileMtimes,
765
802
  memoryNoteMtimes,
766
803
  newMemoryNoteMtimes,
767
804
  requested,
@@ -772,7 +809,7 @@ if (isMainModule(import.meta.url)) {
772
809
  await emit({
773
810
  type: "STATE",
774
811
  stream: "sessions",
775
- cursor: { fetched_at: nowIso() },
812
+ cursor: { file_mtimes: newSessionFileMtimes, fetched_at: nowIso() },
776
813
  });
777
814
  }
778
815
  if (requested.has("memory_notes")) {
@@ -788,8 +825,8 @@ if (isMainModule(import.meta.url)) {
788
825
  buildOnly: false,
789
826
  emit,
790
827
  emitRecord,
791
- fileMtimes,
792
- newMtimes,
828
+ fileMtimes: messageFileMtimes,
829
+ newMtimes: newMessageFileMtimes,
793
830
  requested,
794
831
  sessionAccumulators,
795
832
  });
@@ -798,7 +835,7 @@ if (isMainModule(import.meta.url)) {
798
835
  await emit({
799
836
  type: "STATE",
800
837
  stream: "messages",
801
- cursor: { file_mtimes: newMtimes, fetched_at: nowIso() },
838
+ cursor: { file_mtimes: newMessageFileMtimes, fetched_at: nowIso() },
802
839
  });
803
840
  }
804
841
  },