codesesh 0.18.0 → 1.0.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.
Files changed (68) hide show
  1. package/README.md +5 -2
  2. package/dist/{chunk-HIYT2ZJL.js → chunk-BEF6LLRG.js} +2982 -473
  3. package/dist/chunk-BEF6LLRG.js.map +1 -0
  4. package/dist/{chunk-DHNP33L4.js → chunk-TIHF4T3K.js} +2 -2
  5. package/dist/{dist-DMGLFBW6.js → dist-3F467V44.js} +16 -2
  6. package/dist/index.js +218 -52
  7. package/dist/index.js.map +1 -1
  8. package/dist/scan-refresh-worker.js +243 -24
  9. package/dist/scan-refresh-worker.js.map +1 -1
  10. package/dist/search-index-worker.js +9 -11
  11. package/dist/search-index-worker.js.map +1 -1
  12. package/dist/smart-tag-worker.js +2 -2
  13. package/dist/web/assets/ErrorBoundary-BY-N1QzJ.js +1 -0
  14. package/dist/web/assets/InteractiveReceipt-DYGyHeZd.js +1 -0
  15. package/dist/web/assets/OverviewScreen-_ZaVjhxN.js +1 -0
  16. package/dist/web/assets/PrismHighlighter-BZkkX0AU.js +6 -0
  17. package/dist/web/assets/Projects-q6cEm2dc.js +1 -0
  18. package/dist/web/assets/SearchFilterBar-CrVBpo40.js +1 -0
  19. package/dist/web/assets/SearchResultsPanel-Cg5V8Ia6.js +1 -0
  20. package/dist/web/assets/SessionDetail-BSSuddsZ.js +54 -0
  21. package/dist/web/assets/{session-title-CNhapdPJ.js → SmartTagChips-ux6idUGJ.js} +1 -1
  22. package/dist/web/assets/chunk-62JRHF6Z-BWRsEBnL.js +4 -0
  23. package/dist/web/assets/code-metrics-UYFsCC7E.js +1 -0
  24. package/dist/web/assets/ibm-plex-sans-cyrillic-ext-wght-normal-d45eAU9y.woff2 +0 -0
  25. package/dist/web/assets/ibm-plex-sans-cyrillic-wght-normal-BAAhND-U.woff2 +0 -0
  26. package/dist/web/assets/ibm-plex-sans-greek-wght-normal-CmyJS8uq.woff2 +0 -0
  27. package/dist/web/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
  28. package/dist/web/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
  29. package/dist/web/assets/ibm-plex-sans-vietnamese-wght-normal-Dg1JeJN0.woff2 +0 -0
  30. package/dist/web/assets/index-C3KgxGwE.js +1410 -0
  31. package/dist/web/assets/index-DQX42cFQ.css +1 -0
  32. package/dist/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  33. package/dist/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  34. package/dist/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  35. package/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  36. package/dist/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  37. package/dist/web/assets/jsx-runtime-B-hcVAMW.js +1 -0
  38. package/dist/web/assets/panel-B7kuE60V.js +1 -0
  39. package/dist/web/assets/session-indexes-DmnjZ_JL.js +1 -0
  40. package/dist/web/assets/session-title-DdtlxtlR.js +1 -0
  41. package/dist/web/assets/space-grotesk-latin-ext-wght-normal-D9tNdqV9.woff2 +0 -0
  42. package/dist/web/assets/space-grotesk-latin-wght-normal-BhU9QXUp.woff2 +0 -0
  43. package/dist/web/assets/space-grotesk-vietnamese-wght-normal-D0rl6rjA.woff2 +0 -0
  44. package/dist/web/assets/utils-t2u9IbNT.js +1 -0
  45. package/dist/web/icon/agent/grok.svg +1 -0
  46. package/dist/web/index.html +43 -31
  47. package/package.json +8 -8
  48. package/dist/chunk-HIYT2ZJL.js.map +0 -1
  49. package/dist/web/assets/AgentIcon-DcUJM198.js +0 -1
  50. package/dist/web/assets/BookmarkButton-CJjTjyae.js +0 -1
  51. package/dist/web/assets/Dashboard-wjTLT17d.js +0 -39
  52. package/dist/web/assets/DialogTitle-Bz0eXTGu.js +0 -1
  53. package/dist/web/assets/InteractiveReceipt-xnRqJvfd.js +0 -1
  54. package/dist/web/assets/PrismHighlighter-C7OfXHq2.js +0 -6
  55. package/dist/web/assets/Projects-DBxubQuM.js +0 -1
  56. package/dist/web/assets/SearchFilterBar-BG9ah_Po.js +0 -1
  57. package/dist/web/assets/SearchResultsPanel-Clmf2xKw.js +0 -1
  58. package/dist/web/assets/SessionDetail-CgR7ipmi.js +0 -54
  59. package/dist/web/assets/index-DR07vs5V.js +0 -1890
  60. package/dist/web/assets/index-DuB6tGoe.css +0 -2
  61. package/dist/web/assets/index.dom-CCLJ9_FR.js +0 -1
  62. package/dist/web/assets/jsx-runtime-n5LQ9ujS.js +0 -1
  63. package/dist/web/assets/preload-helper-CmKXJxR3.js +0 -1
  64. package/dist/web/assets/session-indexes-EHJdYE4j.js +0 -4
  65. package/dist/web/assets/useTheme-CwDcVdGz.js +0 -1
  66. package/dist/web/assets/utils-B6KiDbIe.js +0 -1
  67. /package/dist/{chunk-DHNP33L4.js.map → chunk-TIHF4T3K.js.map} +0 -0
  68. /package/dist/{dist-DMGLFBW6.js.map → dist-3F467V44.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  restrictExistingPrivateFiles,
5
5
  restrictPrivateFile,
6
6
  setCoreDiagnostics
7
- } from "./chunk-HIYT2ZJL.js";
7
+ } from "./chunk-BEF6LLRG.js";
8
8
 
9
9
  // src/logging.ts
10
10
  import { appendFileSync, existsSync, readdirSync, renameSync, statSync, unlinkSync } from "fs";
@@ -174,4 +174,4 @@ export {
174
174
  appLogger,
175
175
  logSearchIndexSync
176
176
  };
177
- //# sourceMappingURL=chunk-DHNP33L4.js.map
177
+ //# sourceMappingURL=chunk-TIHF4T3K.js.map
@@ -20,24 +20,31 @@ import {
20
20
  ensureSessionTagsSync,
21
21
  executeSessionSearch,
22
22
  filterSessionSearchCandidates,
23
+ filterSessionTreeByActivityWindow,
24
+ getAgentFullSyncCursor,
23
25
  getAgentInfoMap,
24
26
  getAgentLastFullSyncAt,
25
27
  getCachePath2,
26
28
  getPricingGeneration,
27
29
  getRegisteredAgents,
30
+ getRootSessions,
28
31
  getSessionActivityTime,
29
32
  getSmartTagSourceTimestamp,
30
33
  hasPendingPricing,
31
34
  importBookmarks,
32
35
  isAgentCacheInitialized,
36
+ isChildSession,
33
37
  isProjectIdentityKind,
34
38
  listBookmarks,
35
39
  listCachedProjectGroups,
36
40
  listFileActivity,
41
+ listModelCostDistribution,
37
42
  listSessionAliases,
38
43
  loadCachedSessions,
39
44
  markAgentCacheInitialized,
40
45
  markAgentFullSyncCompleted,
46
+ markAgentFullSyncProgress,
47
+ markAgentFullSyncStarted,
41
48
  matchesProjectIdentity,
42
49
  matchesProjectScope,
43
50
  materializeSessionDetailResponse,
@@ -59,7 +66,7 @@ import {
59
66
  syncSessionSearchIndexChanges,
60
67
  upsertBookmark,
61
68
  upsertSessionAlias
62
- } from "./chunk-HIYT2ZJL.js";
69
+ } from "./chunk-BEF6LLRG.js";
63
70
  export {
64
71
  BaseAgent,
65
72
  StateStorageUnavailableError as BookmarkStorageUnavailableError,
@@ -82,24 +89,31 @@ export {
82
89
  ensureSessionTagsSync,
83
90
  executeSessionSearch,
84
91
  filterSessionSearchCandidates,
92
+ filterSessionTreeByActivityWindow,
93
+ getAgentFullSyncCursor,
85
94
  getAgentInfoMap,
86
95
  getAgentLastFullSyncAt,
87
96
  getCachePath2 as getCachePath,
88
97
  getPricingGeneration,
89
98
  getRegisteredAgents,
99
+ getRootSessions,
90
100
  getSessionActivityTime,
91
101
  getSmartTagSourceTimestamp,
92
102
  hasPendingPricing,
93
103
  importBookmarks,
94
104
  isAgentCacheInitialized,
105
+ isChildSession,
95
106
  isProjectIdentityKind,
96
107
  listBookmarks,
97
108
  listCachedProjectGroups,
98
109
  listFileActivity,
110
+ listModelCostDistribution,
99
111
  listSessionAliases,
100
112
  loadCachedSessions,
101
113
  markAgentCacheInitialized,
102
114
  markAgentFullSyncCompleted,
115
+ markAgentFullSyncProgress,
116
+ markAgentFullSyncStarted,
103
117
  matchesProjectIdentity,
104
118
  matchesProjectScope,
105
119
  materializeSessionDetailResponse,
@@ -122,4 +136,4 @@ export {
122
136
  upsertBookmark,
123
137
  upsertSessionAlias
124
138
  };
125
- //# sourceMappingURL=dist-DMGLFBW6.js.map
139
+ //# sourceMappingURL=dist-3F467V44.js.map
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  appLogger,
4
4
  logSearchIndexSync
5
- } from "./chunk-DHNP33L4.js";
5
+ } from "./chunk-TIHF4T3K.js";
6
6
  import {
7
7
  FileSystemSessionSource,
8
8
  SessionAliasValidationError,
@@ -20,20 +20,27 @@ import {
20
20
  deleteSessionAlias,
21
21
  executeSessionSearch,
22
22
  filterSessionSearchCandidates,
23
+ filterSessionTreeByActivityWindow,
23
24
  formatSessionReference,
25
+ getAgentFullSyncCursor,
24
26
  getAgentInfoMap,
25
27
  getAgentLastFullSyncAt,
26
28
  getSessionActivityTime,
27
29
  getSessionAgentKey,
30
+ getSessionRouteKey,
28
31
  importBookmarks,
29
32
  isAgentCacheInitialized,
30
33
  isProjectIdentityKind,
31
34
  listBookmarks,
32
35
  listCachedProjectGroups,
33
36
  listFileActivity,
37
+ listModelCostDistribution,
34
38
  listSessionAliases,
35
39
  loadCachedSessions,
40
+ markAgentCacheInitialized,
36
41
  markAgentFullSyncCompleted,
42
+ markAgentFullSyncProgress,
43
+ markAgentFullSyncStarted,
37
44
  matchesProjectIdentity,
38
45
  matchesProjectScope,
39
46
  materializeSessionDetailResponse,
@@ -44,6 +51,8 @@ import {
44
51
  perf,
45
52
  publishPendingPricing,
46
53
  refreshPricingCache,
54
+ saveCachedSessionChanges,
55
+ saveCachedSessions,
47
56
  scanSessions,
48
57
  sessionRoutePath,
49
58
  sessionSignature,
@@ -51,7 +60,7 @@ import {
51
60
  startOfCalendarDay,
52
61
  upsertBookmark,
53
62
  upsertSessionAlias
54
- } from "./chunk-HIYT2ZJL.js";
63
+ } from "./chunk-BEF6LLRG.js";
55
64
 
56
65
  // src/index.ts
57
66
  import { defineCommand, runMain } from "citty";
@@ -206,13 +215,7 @@ function parseSearchOptions(c, defaults, projectIdentity) {
206
215
  };
207
216
  }
208
217
  function filterSessionsByActivityWindow(sessions, from, to) {
209
- if (from == null && to == null) return sessions;
210
- return sessions.filter((session) => {
211
- const activity = getSessionActivityTime(session);
212
- if (from != null && activity < from) return false;
213
- if (to != null && activity > to) return false;
214
- return true;
215
- });
218
+ return filterSessionTreeByActivityWindow(sessions, from, to);
216
219
  }
217
220
 
218
221
  // src/api/session-aliases-view.ts
@@ -538,6 +541,23 @@ function handleGetSessions(c, scanSource, defaults = {}) {
538
541
  )
539
542
  });
540
543
  }
544
+ function withParentContext(results, sessions, aliases) {
545
+ if (!results.some((result) => result.session.parent_reference)) return results;
546
+ const byRouteKey = new Map(
547
+ sessions.map((session) => [
548
+ getSessionRouteKey(getSessionAgentKey(session), session.id),
549
+ session
550
+ ])
551
+ );
552
+ return results.map((result) => {
553
+ const parentReference = result.session.parent_reference;
554
+ if (!parentReference) return result;
555
+ const parent = byRouteKey.get(formatSessionReference(parentReference));
556
+ if (!parent) return result;
557
+ const reference = normalizeSessionReference(parentReference);
558
+ return { ...result, parent: { reference, title: aliases.get(reference) ?? parent.title } };
559
+ });
560
+ }
541
561
  function handleSearchSessions(c, scanSource, defaults = {}) {
542
562
  const query = c.req.query("q")?.trim() ?? "";
543
563
  const scanResult = scanSource.getSnapshot();
@@ -559,7 +579,13 @@ function handleSearchSessions(c, scanSource, defaults = {}) {
559
579
  for (const result of [...aliasResults, ...results]) {
560
580
  deduped.set(`${result.reference.agentName}\0${result.reference.sessionId}`, result);
561
581
  }
562
- return c.json({ results: [...deduped.values()].slice(0, searchOptions.limit ?? 50) });
582
+ return c.json({
583
+ results: withParentContext(
584
+ [...deduped.values()].slice(0, searchOptions.limit ?? 50),
585
+ scanResult.sessions,
586
+ aliases
587
+ )
588
+ });
563
589
  }
564
590
  function handleGetFileActivity(c, defaults = {}) {
565
591
  const limitValue = Number(c.req.query("limit"));
@@ -761,6 +787,7 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
761
787
  projectKind: projectIdentity?.kind,
762
788
  projectKey: projectIdentity?.key
763
789
  };
790
+ const compare = from == null ? void 0 : { from: addCalendarDays(from, -(days ?? countCalendarDays(from, to))), to: from - 1 };
764
791
  const fixedTo = parseDateParam(c.req.query("to"), defaults.to);
765
792
  const aggregate = getSnapshotAggregation(
766
793
  scanSource,
@@ -771,7 +798,9 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
771
798
  scope.projectKind,
772
799
  scope.projectKey,
773
800
  from,
774
- fixedTo ?? startOfCalendarDay(to)
801
+ fixedTo ?? startOfCalendarDay(to),
802
+ compare?.from,
803
+ compare?.to
775
804
  ],
776
805
  () => {
777
806
  const agentInfo = getAgentInfoMap({});
@@ -781,7 +810,8 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
781
810
  scope,
782
811
  from,
783
812
  to,
784
- agentInfoMap
813
+ agentInfoMap,
814
+ compare
785
815
  });
786
816
  }
787
817
  );
@@ -795,7 +825,14 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
795
825
  to,
796
826
  limit: 12
797
827
  }),
798
- window: { from, to, days }
828
+ modelCost: listModelCostDistribution({
829
+ agent: scope.agent,
830
+ projectKind: scope.projectKind,
831
+ projectKey: scope.projectKey,
832
+ from,
833
+ to
834
+ }),
835
+ window: { from, to, days, compareFrom: compare?.from, compareTo: compare?.to }
799
836
  };
800
837
  const aliases = loadAliasView();
801
838
  return c.json({
@@ -1382,6 +1419,11 @@ import { existsSync as existsSync2 } from "fs";
1382
1419
  import { fileURLToPath as fileURLToPath2 } from "url";
1383
1420
  import { Worker } from "worker_threads";
1384
1421
 
1422
+ // src/errors.ts
1423
+ function toError(value) {
1424
+ return value instanceof Error ? value : new Error(String(value));
1425
+ }
1426
+
1385
1427
  // src/pending-search-index-jobs.ts
1386
1428
  var PendingSearchIndexJobBatch = class {
1387
1429
  constructor(id, context, jobs, waiter) {
@@ -1637,7 +1679,7 @@ var SearchIndexJobRunner = class {
1637
1679
  });
1638
1680
  worker.on("error", (error) => {
1639
1681
  appLogger.error("search_index.worker_error", { context: batch.context, error });
1640
- this.settle(batch, error);
1682
+ this.settle(batch, toError(error));
1641
1683
  });
1642
1684
  worker.on("exit", (code) => this.finishWorker(worker, batch, code));
1643
1685
  }
@@ -1684,6 +1726,17 @@ var ScanStatusModel = class {
1684
1726
  backfill: { active: false, pendingAgents: [], completedAgents: [], failedAgents: [] }
1685
1727
  };
1686
1728
  snapshot() {
1729
+ const backfill = {
1730
+ ...this.status.backfill,
1731
+ pendingAgents: [...this.status.backfill.pendingAgents],
1732
+ completedAgents: [...this.status.backfill.completedAgents],
1733
+ failedAgents: [...this.status.backfill.failedAgents]
1734
+ };
1735
+ if (this.status.backfill.progress) {
1736
+ backfill.progress = { ...this.status.backfill.progress };
1737
+ } else {
1738
+ delete backfill.progress;
1739
+ }
1687
1740
  return {
1688
1741
  type: "scan-status",
1689
1742
  ...this.status,
@@ -1696,12 +1749,7 @@ var ScanStatusModel = class {
1696
1749
  { ...status }
1697
1750
  ])
1698
1751
  ),
1699
- backfill: {
1700
- ...this.status.backfill,
1701
- pendingAgents: [...this.status.backfill.pendingAgents],
1702
- completedAgents: [...this.status.backfill.completedAgents],
1703
- failedAgents: [...this.status.backfill.failedAgents]
1704
- }
1752
+ backfill
1705
1753
  };
1706
1754
  }
1707
1755
  startBatch(agentNames, phase, sessionCounts) {
@@ -1771,26 +1819,34 @@ var ScanStatusModel = class {
1771
1819
  }
1772
1820
  updateAgent(agentName, progress) {
1773
1821
  const status = this.status.agentStatuses[agentName];
1774
- if (!status || status.status !== "scanning") return null;
1822
+ if (!status || status.status === "pending" || status.status === "complete" || status.status === "indexing" && progress.phase !== "finalizing") {
1823
+ return null;
1824
+ }
1775
1825
  const now = Date.now();
1826
+ const nextStatus = progress.phase === "finalizing" ? "finalizing" : "scanning";
1827
+ const agentStatuses = {
1828
+ ...this.status.agentStatuses,
1829
+ [agentName]: {
1830
+ ...status,
1831
+ status: nextStatus,
1832
+ total: progress.total ?? status.total,
1833
+ processed: progress.processed ?? status.processed,
1834
+ sessions: progress.sessions ?? status.sessions,
1835
+ updatedAt: now
1836
+ }
1837
+ };
1776
1838
  return this.set({
1777
1839
  ...this.status,
1778
- agentStatuses: {
1779
- ...this.status.agentStatuses,
1780
- [agentName]: {
1781
- ...status,
1782
- total: progress.total ?? status.total,
1783
- processed: progress.processed ?? status.processed,
1784
- sessions: progress.sessions ?? status.sessions,
1785
- updatedAt: now
1786
- }
1787
- },
1840
+ phase: this.activePhase(this.status.pendingAgents, this.status.scanningAgents, agentStatuses),
1841
+ agentStatuses,
1788
1842
  updatedAt: now
1789
1843
  });
1790
1844
  }
1791
1845
  indexAgent(agentName) {
1792
1846
  const status = this.status.agentStatuses[agentName];
1793
- if (!this.status.active || !status || status.status !== "scanning") return null;
1847
+ if (!this.status.active || !status || status.status !== "scanning" && status.status !== "finalizing") {
1848
+ return null;
1849
+ }
1794
1850
  const now = Date.now();
1795
1851
  const agentStatuses = {
1796
1852
  ...this.status.agentStatuses,
@@ -1862,7 +1918,10 @@ var ScanStatusModel = class {
1862
1918
  });
1863
1919
  }
1864
1920
  activePhase(pendingAgents, scanningAgents, agentStatuses) {
1865
- if (pendingAgents.length === 0 && scanningAgents.length > 0 && scanningAgents.every((agentName) => agentStatuses[agentName]?.status === "indexing")) {
1921
+ if (pendingAgents.length === 0 && scanningAgents.length > 0 && scanningAgents.every((agentName) => {
1922
+ const status = agentStatuses[agentName]?.status;
1923
+ return status === "finalizing" || status === "indexing";
1924
+ })) {
1866
1925
  return "indexing";
1867
1926
  }
1868
1927
  return this.status.phase === "initializing" ? "initializing" : "scanning";
@@ -1878,6 +1937,7 @@ var REFRESH_DEBOUNCE_MS = 200;
1878
1937
  var EMPTY_AGENT_REFRESH_DEBOUNCE_MS = 3e4;
1879
1938
  var SEARCH_INDEX_BULK_PENDING_PATH_THRESHOLD = 100;
1880
1939
  var BACKFILL_INTERVAL_MS = 24 * 60 * 60 * 1e3;
1940
+ var CACHE_TRUNCATION_COVERAGE = 0.5;
1881
1941
  function buildPersistenceDiff(previousSessions, nextSessions, candidateChangedIds = []) {
1882
1942
  const { changes, removedSessionIds } = computeSessionDiff(
1883
1943
  previousSessions,
@@ -1901,6 +1961,8 @@ var AgentSyncEngine = class {
1901
1961
  sessionIndex = new LiveSessionIndex();
1902
1962
  backfillQueue = [];
1903
1963
  currentBackfillAgent;
1964
+ currentBackfillProgress;
1965
+ cacheIntegrityCheckedAgents = /* @__PURE__ */ new Set();
1904
1966
  completedBackfillAgents = [];
1905
1967
  failedBackfillAgents = [];
1906
1968
  sessionsChangedListeners = /* @__PURE__ */ new Set();
@@ -1980,6 +2042,8 @@ var AgentSyncEngine = class {
1980
2042
  }
1981
2043
  this.backfillQueue.length = 0;
1982
2044
  this.currentBackfillAgent = void 0;
2045
+ this.currentBackfillProgress = void 0;
2046
+ this.cacheIntegrityCheckedAgents.clear();
1983
2047
  const searchIndexSnapshot = this.searchIndexJobs.snapshot();
1984
2048
  appLogger.info("search_index.shutdown.started", {
1985
2049
  active_batch_id: searchIndexSnapshot.activeBatchId,
@@ -2012,6 +2076,16 @@ var AgentSyncEngine = class {
2012
2076
  );
2013
2077
  }
2014
2078
  updateAgentScanProgress(agentName, progress) {
2079
+ if (this.currentBackfillAgent === agentName) {
2080
+ this.currentBackfillProgress = {
2081
+ phase: progress.phase,
2082
+ total: progress.total,
2083
+ processed: progress.processed,
2084
+ sessions: progress.sessions
2085
+ };
2086
+ this.publishBackfillStatus();
2087
+ return;
2088
+ }
2015
2089
  this.publishStatus(this.scanStatus.updateAgent(agentName, progress));
2016
2090
  }
2017
2091
  beginAgentIndexing(agentName) {
@@ -2157,7 +2231,9 @@ var AgentSyncEngine = class {
2157
2231
  async initializeAgent(agent, previousSessions) {
2158
2232
  this.setScanPhase("initializing");
2159
2233
  const scanStartedAt = performance.now();
2160
- const result = await this.runWorker(agent, previousSessions, null, this.startupScanOptions());
2234
+ const result = await this.runWorker(agent, previousSessions, null, this.startupScanOptions(), {
2235
+ checkpoint: true
2236
+ });
2161
2237
  agent.setSessionMetaMap(new Map(Object.entries(result.meta)));
2162
2238
  const sessions = attachMissingProjectIdentities(result.sessions);
2163
2239
  this.lastRefreshAtByAgent.set(agent.name, Date.now());
@@ -2202,7 +2278,7 @@ var AgentSyncEngine = class {
2202
2278
  const preciseChangedIds = checkResult.changedIds ?? null;
2203
2279
  const scanStartedAt = performance.now();
2204
2280
  if (preciseChangedIds === null) {
2205
- const result = await this.runWorker(agent, baseline, null, {});
2281
+ const result = await this.runWorker(agent, baseline, null, {}, { checkpoint: true });
2206
2282
  agent.setSessionMetaMap(new Map(Object.entries(result.meta)));
2207
2283
  const sessions2 = attachMissingProjectIdentities(result.sessions);
2208
2284
  return this.refreshStrategyResult(sessions2, {
@@ -2223,7 +2299,7 @@ var AgentSyncEngine = class {
2223
2299
  }
2224
2300
  async scanAgentFully(agent, previousSessions) {
2225
2301
  const scanStartedAt = performance.now();
2226
- const result = await this.runWorker(agent, previousSessions, null, {});
2302
+ const result = await this.runWorker(agent, previousSessions, null, {}, { checkpoint: true });
2227
2303
  agent.setSessionMetaMap(new Map(Object.entries(result.meta)));
2228
2304
  const sessions = attachMissingProjectIdentities(result.sessions);
2229
2305
  this.lastRefreshAtByAgent.set(agent.name, Date.now());
@@ -2250,8 +2326,63 @@ var AgentSyncEngine = class {
2250
2326
  changedIds,
2251
2327
  scanOptions,
2252
2328
  sourceSync: workerOptions.sourceSync,
2329
+ backfill: workerOptions.backfill,
2330
+ backfillCursor: workerOptions.backfillCursor,
2331
+ checkpoint: workerOptions.checkpoint,
2253
2332
  meta: workerOptions.meta ?? buildAgentCacheMeta(agent),
2254
- onProgress: (progress) => this.updateAgentScanProgress(agent.name, progress)
2333
+ onProgress: (progress) => this.updateAgentScanProgress(agent.name, progress),
2334
+ onCheckpoint: (checkpoint) => this.handleWorkerCheckpoint(agent, checkpoint)
2335
+ });
2336
+ }
2337
+ handleWorkerCheckpoint(agent, checkpoint) {
2338
+ if (this.isShuttingDown) return;
2339
+ if (checkpoint.stage === "scanned") {
2340
+ let persisted2 = false;
2341
+ try {
2342
+ persisted2 = saveCachedSessions(agent.name, checkpoint.sessions, checkpoint.meta);
2343
+ if (persisted2) markAgentCacheInitialized(agent.name);
2344
+ } catch (error) {
2345
+ appLogger.error("scan.checkpoint.failed", {
2346
+ agent: agent.name,
2347
+ stage: checkpoint.stage,
2348
+ error
2349
+ });
2350
+ }
2351
+ agent.setSessionMetaMap(new Map(Object.entries(checkpoint.meta)));
2352
+ const event = this.sessionIndex.commitAgentSessions(agent.name, checkpoint.sessions);
2353
+ this.emitSessionsChanged({
2354
+ agentName: agent.name,
2355
+ sessions: this.sessionIndex.snapshot().byAgent[agent.name] ?? [],
2356
+ event
2357
+ });
2358
+ appLogger.info("scan.checkpoint.persisted", {
2359
+ agent: agent.name,
2360
+ stage: checkpoint.stage,
2361
+ sessions: checkpoint.sessions.length,
2362
+ persisted: persisted2
2363
+ });
2364
+ return;
2365
+ }
2366
+ let persisted = false;
2367
+ try {
2368
+ persisted = saveCachedSessionChanges(agent.name, checkpoint.changes, [], checkpoint.meta);
2369
+ } catch (error) {
2370
+ appLogger.error("scan.checkpoint.failed", {
2371
+ agent: agent.name,
2372
+ stage: checkpoint.stage,
2373
+ sessions: checkpoint.changes.length,
2374
+ error
2375
+ });
2376
+ }
2377
+ if (persisted && checkpoint.backfillCursor) {
2378
+ markAgentFullSyncProgress(agent.name, checkpoint.backfillCursor);
2379
+ }
2380
+ appLogger.debug("scan.checkpoint.persisted", {
2381
+ agent: agent.name,
2382
+ stage: checkpoint.stage,
2383
+ sessions: checkpoint.changes.length,
2384
+ backfill_cursor: checkpoint.backfillCursor,
2385
+ persisted
2255
2386
  });
2256
2387
  }
2257
2388
  needsBackfill(agent) {
@@ -2259,7 +2390,23 @@ var AgentSyncEngine = class {
2259
2390
  if (startupScanOptions.from == null && startupScanOptions.to == null) return false;
2260
2391
  if (!agent.isAvailable()) return false;
2261
2392
  const lastSyncAt = getAgentLastFullSyncAt(agent.name);
2262
- return lastSyncAt == null || Date.now() - lastSyncAt > BACKFILL_INTERVAL_MS;
2393
+ if (lastSyncAt == null || Date.now() - lastSyncAt > BACKFILL_INTERVAL_MS) return true;
2394
+ if (!(agent instanceof FileSystemSessionSource)) return false;
2395
+ if (this.cacheIntegrityCheckedAgents.has(agent.name)) return false;
2396
+ const cached = loadCachedSessions(agent.name);
2397
+ const sourceCount = agent.listSessionSources().length;
2398
+ const cachedCount = cached?.sessions.length ?? 0;
2399
+ this.cacheIntegrityCheckedAgents.add(agent.name);
2400
+ if (sourceCount > 0 && cachedCount / sourceCount < CACHE_TRUNCATION_COVERAGE) {
2401
+ appLogger.warn("scan.backfill.cache_truncated", {
2402
+ agent: agent.name,
2403
+ cached_sessions: cachedCount,
2404
+ source_files: sourceCount,
2405
+ last_sync_at: lastSyncAt
2406
+ });
2407
+ return true;
2408
+ }
2409
+ return false;
2263
2410
  }
2264
2411
  enqueueBackfill(agentName) {
2265
2412
  if (this.isShuttingDown || this.currentBackfillAgent === agentName || this.backfillQueue.includes(agentName)) {
@@ -2274,10 +2421,12 @@ var AgentSyncEngine = class {
2274
2421
  const agentName = this.backfillQueue.shift();
2275
2422
  if (!agentName) return;
2276
2423
  this.currentBackfillAgent = agentName;
2424
+ this.currentBackfillProgress = void 0;
2277
2425
  this.publishBackfillStatus();
2278
2426
  void this.runBackfill(agentName).then((result) => {
2279
2427
  if (this.isShuttingDown) return;
2280
2428
  this.currentBackfillAgent = void 0;
2429
+ this.currentBackfillProgress = void 0;
2281
2430
  if (result === "committed") {
2282
2431
  if (!this.completedBackfillAgents.includes(agentName)) {
2283
2432
  this.completedBackfillAgents.push(agentName);
@@ -2287,6 +2436,7 @@ var AgentSyncEngine = class {
2287
2436
  );
2288
2437
  } else if (!this.failedBackfillAgents.includes(agentName)) {
2289
2438
  this.failedBackfillAgents.push(agentName);
2439
+ this.cacheIntegrityCheckedAgents.delete(agentName);
2290
2440
  }
2291
2441
  this.publishBackfillStatus();
2292
2442
  this.pumpBackfillQueue();
@@ -2303,8 +2453,10 @@ var AgentSyncEngine = class {
2303
2453
  const cached = loadCachedSessions(agentName);
2304
2454
  const baseline = cached?.sessions ?? snapshot.byAgent[agentName] ?? [];
2305
2455
  const meta = cached?.meta ?? buildAgentCacheMeta(agent);
2456
+ const backfillCursor = getAgentFullSyncCursor(agentName);
2306
2457
  if (cached) restoreAgentCacheMeta(agent, cached);
2307
2458
  try {
2459
+ markAgentFullSyncStarted(agentName);
2308
2460
  const result = await this.runWorker(
2309
2461
  agent,
2310
2462
  baseline,
@@ -2312,11 +2464,16 @@ var AgentSyncEngine = class {
2312
2464
  {},
2313
2465
  {
2314
2466
  sourceSync: agent instanceof FileSystemSessionSource,
2315
- meta
2467
+ backfill: true,
2468
+ backfillCursor,
2469
+ meta,
2470
+ checkpoint: true
2316
2471
  }
2317
2472
  );
2318
2473
  agent.setSessionMetaMap(new Map(Object.entries(result.meta)));
2319
2474
  const fullSessions = attachMissingProjectIdentities(result.sessions);
2475
+ this.currentBackfillProgress = { phase: "indexing", sessions: fullSessions.length };
2476
+ this.publishBackfillStatus();
2320
2477
  await this.commitSessionPublication({
2321
2478
  context: "scan.backfill",
2322
2479
  agentName,
@@ -2350,6 +2507,7 @@ var AgentSyncEngine = class {
2350
2507
  active: this.currentBackfillAgent != null || this.backfillQueue.length > 0,
2351
2508
  pendingAgents: [...this.backfillQueue],
2352
2509
  currentAgent: this.currentBackfillAgent,
2510
+ progress: this.currentBackfillProgress,
2353
2511
  completedAgents: [...this.completedBackfillAgents],
2354
2512
  failedAgents: [...this.failedBackfillAgents]
2355
2513
  };
@@ -2783,6 +2941,9 @@ var ThreadWorkerRunner = class {
2783
2941
  previousSessions: payload.previousSessions,
2784
2942
  changedIds: payload.changedIds,
2785
2943
  sourceSync: payload.sourceSync,
2944
+ backfill: payload.backfill,
2945
+ backfillCursor: payload.backfillCursor,
2946
+ checkpoint: payload.checkpoint,
2786
2947
  scanOptions: payload.scanOptions,
2787
2948
  meta: payload.meta
2788
2949
  };
@@ -2793,7 +2954,7 @@ var ThreadWorkerRunner = class {
2793
2954
  try {
2794
2955
  slot = this.createWorker(agentName, request);
2795
2956
  } catch (error) {
2796
- reject(error instanceof Error ? error : new Error(String(error)));
2957
+ reject(toError(error));
2797
2958
  return;
2798
2959
  }
2799
2960
  }
@@ -2801,14 +2962,15 @@ var ThreadWorkerRunner = class {
2801
2962
  resolve: resolve4,
2802
2963
  reject,
2803
2964
  payload,
2804
- onProgress: payload.onProgress
2965
+ onProgress: payload.onProgress,
2966
+ onCheckpoint: payload.onCheckpoint
2805
2967
  });
2806
2968
  if (!isNewWorker) {
2807
2969
  try {
2808
2970
  slot.worker.postMessage(request);
2809
2971
  } catch (error) {
2810
2972
  slot.pending.delete(request.requestId);
2811
- reject(error instanceof Error ? error : new Error(String(error)));
2973
+ reject(toError(error));
2812
2974
  }
2813
2975
  }
2814
2976
  });
@@ -2834,7 +2996,7 @@ var ThreadWorkerRunner = class {
2834
2996
  this.handleMessage(slot, message);
2835
2997
  });
2836
2998
  worker.on("error", (error) => {
2837
- this.closeWorker(agentName, slot, error);
2999
+ this.closeWorker(agentName, slot, toError(error));
2838
3000
  });
2839
3001
  worker.on("exit", (code) => {
2840
3002
  if (slot.closed) return;
@@ -2853,6 +3015,10 @@ var ThreadWorkerRunner = class {
2853
3015
  pending.onProgress?.(message.progress);
2854
3016
  return;
2855
3017
  }
3018
+ if (message.type === "checkpoint") {
3019
+ pending.onCheckpoint?.(message.checkpoint);
3020
+ return;
3021
+ }
2856
3022
  slot.pending.delete(message.requestId);
2857
3023
  if (message.type === "error") {
2858
3024
  pending.reject(new Error(message.error));
@@ -2872,7 +3038,7 @@ var ThreadWorkerRunner = class {
2872
3038
  changedIds: pending.payload.sourceSync ? replacedSessionIds : void 0
2873
3039
  });
2874
3040
  } catch (error) {
2875
- pending.reject(error instanceof Error ? error : new Error(String(error)));
3041
+ pending.reject(toError(error));
2876
3042
  }
2877
3043
  }
2878
3044
  closeWorker(agentName, slot, error) {
@@ -3068,14 +3234,14 @@ function printScanResults(agents) {
3068
3234
 
3069
3235
  // src/session-index-output.ts
3070
3236
  function buildSessionIndexOutput(snapshot, window = {}) {
3071
- const sessions = snapshot.sessions.filter((session) => {
3072
- const activity = session.time_updated ?? session.time_created;
3073
- if (window.from != null && activity < window.from) return false;
3074
- if (window.to != null && activity > window.to) return false;
3075
- return true;
3076
- });
3237
+ const sessions = filterSessionTreeByActivityWindow(snapshot.sessions, window.from, window.to);
3077
3238
  const agents = getAgentInfoMap(
3078
- Object.fromEntries(Object.entries(snapshot.byAgent).map(([name, list]) => [name, list.length]))
3239
+ Object.fromEntries(
3240
+ Object.entries(snapshot.byAgent).map(([name, list]) => [
3241
+ name,
3242
+ filterSessionTreeByActivityWindow(list, window.from, window.to).length
3243
+ ])
3244
+ )
3079
3245
  ).map(({ name, displayName, count }) => ({
3080
3246
  name,
3081
3247
  displayName,
@@ -3293,7 +3459,7 @@ var main = defineCommand({
3293
3459
  log_path: appLogger.getLogPath()
3294
3460
  });
3295
3461
  if (clearCache) {
3296
- const { clearCache: clear } = await import("./dist-DMGLFBW6.js");
3462
+ const { clearCache: clear } = await import("./dist-3F467V44.js");
3297
3463
  clear();
3298
3464
  appLogger.info("cache.clear");
3299
3465
  console.log("Cache cleared.");