codesesh 1.0.5 → 1.0.6

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 (54) hide show
  1. package/README.md +1 -0
  2. package/dist/{chunk-NBJJGH5P.js → chunk-4ND6AT6W.js} +116 -72
  3. package/dist/chunk-4ND6AT6W.js.map +1 -0
  4. package/dist/{chunk-PAP2Q3WV.js → chunk-4QFNZCBR.js} +2 -2
  5. package/dist/{chunk-FCYCBGEL.js → chunk-A3MT6L6Z.js} +3 -3
  6. package/dist/{chunk-YQFEGFWD.js → chunk-COZSWVCH.js} +2 -2
  7. package/dist/{chunk-WUYSZAYR.js → chunk-L3DDWTYV.js} +9 -4
  8. package/dist/chunk-L3DDWTYV.js.map +1 -0
  9. package/dist/{chunk-TS3IWH5U.js → chunk-XQDYKKRC.js} +30 -14
  10. package/dist/chunk-XQDYKKRC.js.map +1 -0
  11. package/dist/{chunk-XKZSX5BM.js → chunk-YZ6XCSVQ.js} +3 -3
  12. package/dist/{discovery-D23RV7FY.js → discovery-ADSQARBV.js} +5 -5
  13. package/dist/index.js +185 -144
  14. package/dist/index.js.map +1 -1
  15. package/dist/project-identity-worker.js +4 -4
  16. package/dist/scan-refresh-worker.js +6 -6
  17. package/dist/search-index-worker.js +6 -6
  18. package/dist/session-detail-worker.js +6 -6
  19. package/dist/smart-tag-worker.js +3 -3
  20. package/dist/web/assets/CustomTimeWindowDialog-D2bx7uDv.js +1 -0
  21. package/dist/web/assets/InteractiveReceipt-BFpIdno8.js +1 -0
  22. package/dist/web/assets/OverviewScreen-D_KXfiJi.js +1 -0
  23. package/dist/web/assets/{PrismHighlighter-LWITDffT.js → PrismHighlighter-BgVkYu_S.js} +1 -1
  24. package/dist/web/assets/Projects-CN44UpuR.js +1 -0
  25. package/dist/web/assets/SearchResultsPanel-CWD01v-a.js +1 -0
  26. package/dist/web/assets/SessionDetail-D8taQ6Tl.js +53 -0
  27. package/dist/web/assets/api-B9lJtVbO.js +1 -0
  28. package/dist/web/assets/index-XpolWMY4.js +1423 -0
  29. package/dist/web/assets/index-xbEEMszv.css +1 -0
  30. package/dist/web/assets/session-indexes-fib48ZKn.js +4 -0
  31. package/dist/web/assets/translate-Dmym1ZDl.js +2 -0
  32. package/dist/web/assets/utils-Bk66u8b3.js +1 -0
  33. package/dist/web/index.html +7 -7
  34. package/package.json +3 -3
  35. package/dist/chunk-NBJJGH5P.js.map +0 -1
  36. package/dist/chunk-TS3IWH5U.js.map +0 -1
  37. package/dist/chunk-WUYSZAYR.js.map +0 -1
  38. package/dist/web/assets/CustomTimeWindowDialog-C9XTZRm0.js +0 -1
  39. package/dist/web/assets/InteractiveReceipt-Sca1smpv.js +0 -1
  40. package/dist/web/assets/OverviewScreen-Vq6BQR9_.js +0 -1
  41. package/dist/web/assets/Projects-CwicV3Dk.js +0 -1
  42. package/dist/web/assets/SearchResultsPanel-DCO0Ak0c.js +0 -1
  43. package/dist/web/assets/SessionDetail-mdmTQgo1.js +0 -53
  44. package/dist/web/assets/api-CXVT9XcZ.js +0 -1
  45. package/dist/web/assets/contract-BS78VBCV.js +0 -2
  46. package/dist/web/assets/index-C5cyw58A.css +0 -1
  47. package/dist/web/assets/index-H2cT-6c6.js +0 -1423
  48. package/dist/web/assets/session-indexes-yyyWpKLf.js +0 -4
  49. package/dist/web/assets/utils-C7BqyxxV.js +0 -1
  50. /package/dist/{chunk-PAP2Q3WV.js.map → chunk-4QFNZCBR.js.map} +0 -0
  51. /package/dist/{chunk-FCYCBGEL.js.map → chunk-A3MT6L6Z.js.map} +0 -0
  52. /package/dist/{chunk-YQFEGFWD.js.map → chunk-COZSWVCH.js.map} +0 -0
  53. /package/dist/{chunk-XKZSX5BM.js.map → chunk-YZ6XCSVQ.js.map} +0 -0
  54. /package/dist/{discovery-D23RV7FY.js.map → discovery-ADSQARBV.js.map} +0 -0
@@ -4,9 +4,9 @@ import {
4
4
  getProjectIdentityKey,
5
5
  getSessionAgentKey,
6
6
  matchesProjectIdentity
7
- } from "./chunk-NBJJGH5P.js";
7
+ } from "./chunk-4ND6AT6W.js";
8
8
 
9
- // ../core/dist/chunk-SULHDCDQ.mjs
9
+ // ../core/dist/chunk-2AZEUUPW.mjs
10
10
  import * as os from "os";
11
11
  import * as path from "path";
12
12
  import { createHash } from "crypto";
@@ -324,4 +324,4 @@ export {
324
324
  normalizeProjectScopePath,
325
325
  buildProjectGroups
326
326
  };
327
- //# sourceMappingURL=chunk-XKZSX5BM.js.map
327
+ //# sourceMappingURL=chunk-YZ6XCSVQ.js.map
@@ -45,15 +45,15 @@ import {
45
45
  sortSessions,
46
46
  syncSessionSearchIndex,
47
47
  syncSessionSearchIndexChanges
48
- } from "./chunk-TS3IWH5U.js";
49
- import "./chunk-XKZSX5BM.js";
50
- import "./chunk-WUYSZAYR.js";
48
+ } from "./chunk-XQDYKKRC.js";
49
+ import "./chunk-YZ6XCSVQ.js";
50
+ import "./chunk-L3DDWTYV.js";
51
51
  import {
52
52
  SMART_TAGS,
53
53
  filterSessionTreeByActivityWindow,
54
54
  isSmartTag,
55
55
  mergeSortedSessions
56
- } from "./chunk-NBJJGH5P.js";
56
+ } from "./chunk-4ND6AT6W.js";
57
57
  export {
58
58
  SMART_TAGS,
59
59
  attachMissingProjectIdentities,
@@ -105,4 +105,4 @@ export {
105
105
  syncSessionSearchIndex,
106
106
  syncSessionSearchIndexChanges
107
107
  };
108
- //# sourceMappingURL=discovery-D23RV7FY.js.map
108
+ //# sourceMappingURL=discovery-ADSQARBV.js.map
package/dist/index.js CHANGED
@@ -4,19 +4,19 @@ import {
4
4
  buildDashboard,
5
5
  getSessionActivityTime,
6
6
  summarizeProjects
7
- } from "./chunk-FCYCBGEL.js";
7
+ } from "./chunk-A3MT6L6Z.js";
8
8
  import {
9
9
  AGENT_UNAVAILABLE_DURING_SCAN_ERROR_CODE,
10
10
  AgentUnavailableDuringScanError
11
11
  } from "./chunk-RF3EEWPH.js";
12
12
  import {
13
13
  terminateWorkerAfterLogDrain
14
- } from "./chunk-YQFEGFWD.js";
14
+ } from "./chunk-COZSWVCH.js";
15
15
  import "./chunk-QH2HOXJH.js";
16
16
  import {
17
17
  appLogger,
18
18
  logSearchIndexSync
19
- } from "./chunk-PAP2Q3WV.js";
19
+ } from "./chunk-4QFNZCBR.js";
20
20
  import {
21
21
  attachMissingProjectIdentities,
22
22
  beginAgentRefresh,
@@ -50,18 +50,18 @@ import {
50
50
  sessionMatchesSearchCost,
51
51
  sessionSignature,
52
52
  sortSessions
53
- } from "./chunk-TS3IWH5U.js";
53
+ } from "./chunk-XQDYKKRC.js";
54
54
  import {
55
55
  PROJECT_IDENTITY_RESOLVER_REVISION,
56
56
  createProjectScopeMatcher,
57
57
  createProjectScopeMatcherFromIdentity,
58
58
  matchesProjectScope,
59
59
  normalizeProjectDirectory
60
- } from "./chunk-XKZSX5BM.js";
60
+ } from "./chunk-YZ6XCSVQ.js";
61
61
  import {
62
62
  createRegisteredAgents,
63
63
  getAgentInfoMap
64
- } from "./chunk-WUYSZAYR.js";
64
+ } from "./chunk-L3DDWTYV.js";
65
65
  import {
66
66
  CODESESH_OPERATION_ID_HEADER,
67
67
  CODESESH_REQUEST_ID_HEADER,
@@ -96,7 +96,7 @@ import {
96
96
  tableExists,
97
97
  toPublicReferencedSessionHead,
98
98
  toPublicSessionHead
99
- } from "./chunk-NBJJGH5P.js";
99
+ } from "./chunk-4ND6AT6W.js";
100
100
 
101
101
  // src/index.ts
102
102
  import { defineCommand, runMain } from "citty";
@@ -574,14 +574,8 @@ function parseDateWindowRequest(c, endpoint, defaults) {
574
574
 
575
575
  // src/api/snapshot-pagination.ts
576
576
  import { createHash, randomUUID } from "crypto";
577
- var identityVersions = /* @__PURE__ */ new WeakMap();
578
- function identityVersion(identity) {
579
- const existing = identityVersions.get(identity);
580
- if (existing) return existing;
581
- const version = randomUUID();
582
- identityVersions.set(identity, version);
583
- return version;
584
- }
577
+ var SNAPSHOT_TTL_MS = 6e4;
578
+ var SNAPSHOT_LIMIT = 32;
585
579
  function queryFingerprint(params) {
586
580
  const canonical = new URLSearchParams(params);
587
581
  canonical.delete("cursor");
@@ -598,7 +592,7 @@ function decodeCursor(cursor) {
598
592
  const value = JSON.parse(
599
593
  Buffer.from(cursor, "base64url").toString("utf8")
600
594
  );
601
- if (value.version !== 1 || typeof value.snapshot !== "string" || typeof value.view !== "string" || typeof value.query !== "string" || !Number.isSafeInteger(value.offset) || value.offset <= 0) {
595
+ if (value.version !== 1 || typeof value.snapshot !== "string" || !Number.isSafeInteger(value.offset) || value.offset <= 0) {
602
596
  return null;
603
597
  }
604
598
  return value;
@@ -606,26 +600,47 @@ function decodeCursor(cursor) {
606
600
  return null;
607
601
  }
608
602
  }
609
- function paginateSnapshot(items, request) {
610
- const snapshot = identityVersion(request.snapshotIdentity);
611
- const view = identityVersion(request.viewIdentity);
612
- const query = queryFingerprint(request.query);
613
- let offset = 0;
614
- if (request.cursor) {
615
- const cursor = decodeCursor(request.cursor);
616
- if (!cursor || cursor.query !== query) return { kind: "invalid_cursor" };
617
- if (cursor.snapshot !== snapshot || cursor.view !== view) {
618
- return { kind: "stale_snapshot" };
603
+ function createSnapshotPaginator() {
604
+ const snapshotsBySource = /* @__PURE__ */ new WeakMap();
605
+ return function paginateSnapshot(source, request, load) {
606
+ const snapshots = snapshotsBySource.get(source) ?? /* @__PURE__ */ new Map();
607
+ const now = Date.now();
608
+ for (const [id, snapshot2] of snapshots) {
609
+ if (snapshot2.expiresAt <= now) snapshots.delete(id);
610
+ }
611
+ const query = queryFingerprint(request.query);
612
+ let snapshot;
613
+ let snapshotId;
614
+ let offset = 0;
615
+ if (request.cursor) {
616
+ const cursor = decodeCursor(request.cursor);
617
+ if (!cursor) return { kind: "invalid_cursor" };
618
+ const retained = snapshots.get(cursor.snapshot);
619
+ if (!retained) return { kind: "stale_snapshot" };
620
+ if (retained.query !== query || cursor.offset >= retained.items.length) {
621
+ return { kind: "invalid_cursor" };
622
+ }
623
+ snapshot = retained;
624
+ snapshotId = cursor.snapshot;
625
+ offset = cursor.offset;
626
+ } else {
627
+ const loaded = load();
628
+ snapshot = { ...loaded, items: [...loaded.items], query, expiresAt: now + SNAPSHOT_TTL_MS };
629
+ snapshotId = randomUUID();
619
630
  }
620
- if (cursor.offset >= items.length) return { kind: "invalid_cursor" };
621
- offset = cursor.offset;
622
- }
623
- const end = Math.min(offset + request.limit, items.length);
624
- const nextCursor = end < items.length ? encodeCursor({ version: 1, snapshot, view, query, offset: end }) : void 0;
625
- return {
626
- kind: "page",
627
- items: items.slice(offset, end),
628
- ...nextCursor ? { nextCursor } : {}
631
+ const end = Math.min(offset + request.limit, snapshot.items.length);
632
+ const nextCursor = end < snapshot.items.length ? encodeCursor({ version: 1, snapshot: snapshotId, offset: end }) : void 0;
633
+ if (!request.cursor && nextCursor) {
634
+ if (snapshots.size >= SNAPSHOT_LIMIT) snapshots.delete(snapshots.keys().next().value);
635
+ snapshots.set(snapshotId, snapshot);
636
+ snapshotsBySource.set(source, snapshots);
637
+ }
638
+ return {
639
+ kind: "page",
640
+ items: snapshot.items.slice(offset, end),
641
+ view: snapshot.view,
642
+ ...nextCursor ? { nextCursor } : {}
643
+ };
629
644
  };
630
645
  }
631
646
 
@@ -663,13 +678,14 @@ function getSnapshotSessionTree(source, sessions) {
663
678
  const cache = getSnapshotAggregationCache(source, sessions);
664
679
  return cache.sessionTree ??= buildSessionTree(sessions);
665
680
  }
666
- function getDashboardCostFacts(source, sessions, from, to, cacheTo, analyticsRevision) {
667
- const build = () => listDashboardCostFacts({ from, to });
681
+ function getSnapshotCostFacts(source, sessions, from, to, cacheTo, analyticsRevision) {
682
+ const costFrom = from === 0 ? void 0 : from;
683
+ const build = () => listDashboardCostFacts({ from: costFrom, to });
668
684
  if (analyticsRevision === null) return build();
669
685
  return getSnapshotAggregation(
670
686
  source,
671
687
  sessions,
672
- ["dashboard-cost-facts", from, cacheTo, analyticsRevision],
688
+ ["cost-facts", costFrom, cacheTo, analyticsRevision],
673
689
  build
674
690
  );
675
691
  }
@@ -718,6 +734,7 @@ function getDashboardStorageAggregation(source, sessions, scope, from, to, cache
718
734
  }
719
735
 
720
736
  // src/api/catalog-handlers.ts
737
+ var paginateProjects = createSnapshotPaginator();
721
738
  function handleGetConfig(c, defaults) {
722
739
  const payload = {
723
740
  window: {
@@ -770,46 +787,54 @@ function handleGetProjects(c, scanSource, defaults = {}) {
770
787
  const window = parseDateWindowRequest(c, "projects", defaults);
771
788
  if (window.kind === "rejected") return window.response;
772
789
  const { from, to } = window;
773
- const analyticsRevision = getAnalyticsRevision();
774
- const catalog = getSnapshotAggregation(
790
+ const loadSnapshot = () => {
791
+ const analyticsRevision = getAnalyticsRevision();
792
+ const catalog = getSnapshotAggregation(
793
+ scanSource,
794
+ scanResult.sessions,
795
+ ["projects", from, to, analyticsRevision],
796
+ () => {
797
+ const tree = getSnapshotSessionTree(scanSource, scanResult.sessions);
798
+ const costFacts = (from == null || from === 0) && to == null ? getSnapshotCostFacts(scanSource, scanResult.sessions, from, to, to, analyticsRevision) : listDashboardCostFacts({ from, to, includeModelCosts: false });
799
+ const projects2 = attachProjectMetricsFromTree(
800
+ listCachedProjectGroups(scanResult.sessions),
801
+ tree,
802
+ from,
803
+ to,
804
+ costFacts
805
+ ).filter(
806
+ (project) => project.sessionCount > 0 || project.messages > 0 || project.tokens > 0 || project.cost > 0
807
+ );
808
+ return { projects: projects2, summary: summarizeProjects(projects2) };
809
+ }
810
+ );
811
+ const projects = projectIdentity ? catalog.projects.filter(
812
+ (project) => project.identityKind === projectIdentity.kind && project.identityKey === projectIdentity.key
813
+ ) : catalog.projects;
814
+ return {
815
+ items: projects,
816
+ view: projectIdentity ? summarizeProjects(projects) : catalog.summary
817
+ };
818
+ };
819
+ const page = paginateProjects(
775
820
  scanSource,
776
- scanResult.sessions,
777
- ["projects", from, to, analyticsRevision],
778
- () => {
779
- const tree = getSnapshotSessionTree(scanSource, scanResult.sessions);
780
- const costFacts = listDashboardCostFacts({ from, to, includeModelCosts: false });
781
- const projects2 = attachProjectMetricsFromTree(
782
- listCachedProjectGroups(scanResult.sessions),
783
- tree,
784
- from,
785
- to,
786
- costFacts
787
- ).filter(
788
- (project) => project.sessionCount > 0 || project.messages > 0 || project.tokens > 0 || project.cost > 0
789
- );
790
- return { projects: projects2, summary: summarizeProjects(projects2) };
791
- }
821
+ {
822
+ cursor: params.get("cursor") ?? void 0,
823
+ limit: limit.value,
824
+ query: params
825
+ },
826
+ loadSnapshot
792
827
  );
793
- const projects = projectIdentity ? catalog.projects.filter(
794
- (project) => project.identityKind === projectIdentity.kind && project.identityKey === projectIdentity.key
795
- ) : catalog.projects;
796
- const page = paginateSnapshot(projects, {
797
- cursor: params.get("cursor") ?? void 0,
798
- limit: limit.value,
799
- query: params,
800
- snapshotIdentity: scanResult.sessions,
801
- viewIdentity: catalog.projects
802
- });
803
828
  if (page.kind === "invalid_cursor") {
804
829
  reportInvalidQueryParameter("projects", "cursor", "rejected");
805
830
  return c.json({ error: "cursor is invalid for this request" }, 400);
806
831
  }
807
832
  if (page.kind === "stale_snapshot") {
808
- return c.json({ error: "project snapshot changed; restart pagination" }, 409);
833
+ return c.json({ error: "project snapshot expired; restart pagination" }, 409);
809
834
  }
810
835
  return c.json({
811
836
  projects: page.items,
812
- summary: projectIdentity ? summarizeProjects(projects) : catalog.summary,
837
+ summary: page.view,
813
838
  ...page.nextCursor ? { nextCursor: page.nextCursor } : {}
814
839
  });
815
840
  }
@@ -1543,12 +1568,12 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
1543
1568
  const fixedTo = dateWindow.to;
1544
1569
  const cacheTo = fixedTo ?? startOfCalendarDay(to);
1545
1570
  const analyticsRevision = getAnalyticsRevision();
1546
- const costFacts = getDashboardCostFacts(
1571
+ const costFacts = getSnapshotCostFacts(
1547
1572
  scanSource,
1548
1573
  scanResult.sessions,
1549
1574
  compare?.from ?? from,
1550
- to,
1551
- cacheTo,
1575
+ from == null && fixedTo == null ? void 0 : to,
1576
+ from == null && fixedTo == null ? void 0 : cacheTo,
1552
1577
  analyticsRevision
1553
1578
  );
1554
1579
  const aggregate = getSnapshotAggregation(
@@ -1932,6 +1957,7 @@ function createSessionDetailJsonResponse(data, messages) {
1932
1957
  }
1933
1958
 
1934
1959
  // src/api/session-handlers.ts
1960
+ var paginateSessions = createSnapshotPaginator();
1935
1961
  function getSessionHeadReference(session) {
1936
1962
  return session.reference;
1937
1963
  }
@@ -1973,64 +1999,72 @@ async function handleGetSessions(c, scanSource, defaults = {}, resolver) {
1973
1999
  if (sessionQuery.agent.kind === "unknown") {
1974
2000
  reportInvalidQueryParameter("sessions", "agent", "empty_result");
1975
2001
  }
1976
- const agentFilter = sessionQuery.agent.kind === "known" ? sessionQuery.agent.agentName : sessionQuery.agent.kind;
1977
- let sessions = getSnapshotAggregation(
1978
- scanSource,
1979
- scanResult.sessions,
1980
- [
1981
- "sessions",
1982
- agentFilter,
1983
- projectIdentity?.kind,
1984
- projectIdentity?.key,
1985
- projectScope?.identity.kind,
1986
- projectScope?.identity.key,
1987
- projectScope?.path,
1988
- tag,
1989
- from,
1990
- to
1991
- ],
1992
- () => {
1993
- let filtered = sessionQuery.agent.kind === "all" ? scanResult.sessions : sessionQuery.agent.kind === "known" ? scanResult.byAgent[sessionQuery.agent.agentName] ?? [] : [];
1994
- if (projectIdentity) {
1995
- filtered = filtered.filter(
1996
- (session) => matchesProjectIdentity(session.project_identity, projectIdentity)
1997
- );
1998
- } else if (projectScope) {
1999
- filtered = filtered.filter((session) => matchesProjectScope(session, projectScope));
2002
+ const loadSnapshot = () => {
2003
+ const agentFilter = sessionQuery.agent.kind === "known" ? sessionQuery.agent.agentName : sessionQuery.agent.kind;
2004
+ let sessions2 = getSnapshotAggregation(
2005
+ scanSource,
2006
+ scanResult.sessions,
2007
+ [
2008
+ "sessions",
2009
+ agentFilter,
2010
+ projectIdentity?.kind,
2011
+ projectIdentity?.key,
2012
+ projectScope?.identity.kind,
2013
+ projectScope?.identity.key,
2014
+ projectScope?.path,
2015
+ tag,
2016
+ from,
2017
+ to
2018
+ ],
2019
+ () => {
2020
+ let filtered = sessionQuery.agent.kind === "all" ? scanResult.sessions : sessionQuery.agent.kind === "known" ? scanResult.byAgent[sessionQuery.agent.agentName] ?? [] : [];
2021
+ if (projectIdentity) {
2022
+ filtered = filtered.filter(
2023
+ (session) => matchesProjectIdentity(session.project_identity, projectIdentity)
2024
+ );
2025
+ } else if (projectScope) {
2026
+ filtered = filtered.filter(
2027
+ (session) => matchesProjectScope(session, projectScope)
2028
+ );
2029
+ }
2030
+ filtered = filterSessionsByActivityWindow(filtered, from, to);
2031
+ return tag ? filtered.filter((session) => session.smart_tags?.includes(tag)) : filtered;
2000
2032
  }
2001
- filtered = filterSessionsByActivityWindow(filtered, from, to);
2002
- return tag ? filtered.filter((session) => session.smart_tags?.includes(tag)) : filtered;
2033
+ );
2034
+ const aliases2 = loadAliasView();
2035
+ if (q) {
2036
+ sessions2 = sessions2.filter((session) => {
2037
+ const alias = aliases2.get(getSessionHeadReference(session));
2038
+ return session.title.toLowerCase().includes(q) || alias?.toLowerCase().includes(q);
2039
+ });
2003
2040
  }
2004
- );
2005
- const aliases = loadAliasView();
2006
- if (q) {
2007
- sessions = sessions.filter((session) => {
2008
- const alias = aliases.get(getSessionHeadReference(session));
2009
- return session.title.toLowerCase().includes(q) || alias?.toLowerCase().includes(q);
2010
- });
2011
- }
2041
+ return { items: sessions2, view: aliases2 };
2042
+ };
2012
2043
  if (paginationRequested) {
2013
- const page = paginateSnapshot(sessions, {
2014
- cursor: params.get("cursor") ?? void 0,
2015
- limit: sessionQuery.limit.value,
2016
- query: params,
2017
- snapshotIdentity: scanResult.sessions,
2018
- viewIdentity: aliases
2019
- });
2044
+ const page = paginateSessions(
2045
+ scanSource,
2046
+ {
2047
+ cursor: params.get("cursor") ?? void 0,
2048
+ limit: sessionQuery.limit.value,
2049
+ query: params
2050
+ },
2051
+ loadSnapshot
2052
+ );
2020
2053
  if (page.kind === "invalid_cursor") {
2021
2054
  reportInvalidQueryParameter("sessions", "cursor", "rejected");
2022
2055
  return c.json({ error: "cursor is invalid for this request" }, 400);
2023
2056
  }
2024
2057
  if (page.kind === "stale_snapshot") {
2025
- return c.json({ error: "session snapshot changed; restart pagination" }, 409);
2058
+ return c.json({ error: "session snapshot expired; restart pagination" }, 409);
2026
2059
  }
2027
2060
  return c.json({
2028
2061
  sessions: page.items.map(
2029
- (session) => toPublicSessionHead(aliases.decorate(session, getSessionHeadReference(session)))
2062
+ (session) => toPublicSessionHead(page.view.decorate(session, getSessionHeadReference(session)))
2030
2063
  ),
2031
2064
  ...page.nextCursor ? { nextCursor: page.nextCursor } : {}
2032
2065
  });
2033
2066
  }
2067
+ const { items: sessions, view: aliases } = loadSnapshot();
2034
2068
  return c.json({
2035
2069
  sessions: sessions.map(
2036
2070
  (session) => toPublicSessionHead(aliases.decorate(session, getSessionHeadReference(session)))
@@ -2248,7 +2282,7 @@ function handleGetBookmarks(c, scanSource) {
2248
2282
  storageAvailable: true
2249
2283
  });
2250
2284
  },
2251
- () => c.json({ bookmarks: [], storageAvailable: false })
2285
+ () => c.json({ error: "Bookmark storage is unavailable" }, 503)
2252
2286
  );
2253
2287
  }
2254
2288
  function isKnownAgentKey(agentKey) {
@@ -5588,31 +5622,31 @@ var AgentSyncEngine = class {
5588
5622
  try {
5589
5623
  const { result } = workerRun;
5590
5624
  const sessions2 = attachMissingProjectIdentities(result.sessions);
5625
+ const persistenceDiff = buildSessionPersistenceDiff(baseline, sessions2, {
5626
+ // Worker-reported IDs also preserve metadata-only pricing repairs.
5627
+ candidateChangedIds: result.changedIds ?? [],
5628
+ completeness: result.completeness,
5629
+ explicitRemovedSessionIds: result.explicitRemovedSessionIds
5630
+ });
5631
+ const strategy = this.refreshStrategyBase(sessions2, result.completeness, scope, {
5632
+ checkDuration,
5633
+ scanDuration: performance.now() - scanStartedAt,
5634
+ sourceFailures: result.sourceFailures ?? [],
5635
+ workerRun,
5636
+ pendingAgentState: {
5637
+ meta: result.meta,
5638
+ refreshedAt: checkResult.timestamp,
5639
+ refreshTransaction
5640
+ }
5641
+ });
5642
+ if (persistenceDiff.changedSessions.length === 0 && persistenceDiff.removedSessionIds.length === 0 && (result.sourceFailures?.length ?? 0) === 0) {
5643
+ this.logUnchangedRefresh(agent.name, refreshStartedAt);
5644
+ return { ...strategy, status: "unchanged" };
5645
+ }
5591
5646
  return {
5592
- ...this.refreshStrategyBase(sessions2, result.completeness, scope, {
5593
- checkDuration,
5594
- scanDuration: performance.now() - scanStartedAt,
5595
- sourceFailures: result.sourceFailures ?? [],
5596
- workerRun,
5597
- pendingAgentState: {
5598
- meta: result.meta,
5599
- refreshedAt: checkResult.timestamp,
5600
- refreshTransaction
5601
- }
5602
- }),
5647
+ ...strategy,
5603
5648
  status: "continue",
5604
- publication: {
5605
- kind: "changes",
5606
- // Meta-only changes (e.g. a pricing capture epoch bump) leave the head
5607
- // signature intact; without the worker-reported ids they would never
5608
- // persist and checkForChanges would rescan on every startup.
5609
- diff: buildSessionPersistenceDiff(baseline, sessions2, {
5610
- candidateChangedIds: result.changedIds ?? [],
5611
- completeness: result.completeness,
5612
- explicitRemovedSessionIds: result.explicitRemovedSessionIds
5613
- }),
5614
- candidateChangedIds: []
5615
- }
5649
+ publication: { kind: "changes", diff: persistenceDiff, candidateChangedIds: [] }
5616
5650
  };
5617
5651
  } catch (error) {
5618
5652
  workerRun.discard();
@@ -5835,7 +5869,7 @@ var AgentSyncEngine = class {
5835
5869
 
5836
5870
  // src/session-watcher.ts
5837
5871
  import { existsSync as existsSync3, readdirSync, statSync, watch } from "fs";
5838
- import { dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
5872
+ import { basename, dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
5839
5873
  var WRITE_STABILITY_THRESHOLD_MS = 250;
5840
5874
  var WRITE_STABILITY_POLL_MS = 100;
5841
5875
  function toAbsolutePath(path) {
@@ -5941,7 +5975,11 @@ var SessionWatcher = class {
5941
5975
  const targetPath = toAbsolutePath(target.path);
5942
5976
  const scopes = scopesByRoot.get(rootPath) ?? [];
5943
5977
  if (!scopes.some((scope) => scope.agentName === agent.name && scope.targetPath === targetPath)) {
5944
- scopes.push({ agentName: agent.name, targetPath });
5978
+ scopes.push({
5979
+ agentName: agent.name,
5980
+ targetPath,
5981
+ ignoredFileNames: target.ignoredFileNames
5982
+ });
5945
5983
  }
5946
5984
  scopesByRoot.set(rootPath, scopes);
5947
5985
  }
@@ -6060,7 +6098,9 @@ var SessionWatcher = class {
6060
6098
  handleWatchEvent(watchPath, scopes, eventType, filename) {
6061
6099
  const changedPath = resolveWatchEventPath(watchPath, filename);
6062
6100
  const agentNames = new Set(
6063
- scopes.filter((scope) => isRelatedPath(changedPath, scope.targetPath)).map((scope) => scope.agentName)
6101
+ scopes.filter(
6102
+ (scope) => isRelatedPath(changedPath, scope.targetPath) && !(scope.ignoredFileNames?.includes(basename(changedPath)) && changedPath !== scope.targetPath && isSameOrChildPath(scope.targetPath, changedPath))
6103
+ ).map((scope) => scope.agentName)
6064
6104
  );
6065
6105
  if (agentNames.size === 0) {
6066
6106
  return;
@@ -6712,7 +6752,8 @@ function startPricingRefresh(timeoutMs = REFRESH_TIMEOUT_MS) {
6712
6752
  }
6713
6753
  );
6714
6754
  return {
6715
- publish() {
6755
+ async ready() {
6756
+ await completion;
6716
6757
  if (publishPendingPricing()) appLogger.info("pricing.refresh.published", {});
6717
6758
  },
6718
6759
  async cancel() {
@@ -6886,7 +6927,7 @@ var main = defineCommand({
6886
6927
  log_path: appLogger.getLogPath()
6887
6928
  });
6888
6929
  if (clearCache) {
6889
- const { clearCache: clear } = await import("./discovery-D23RV7FY.js");
6930
+ const { clearCache: clear } = await import("./discovery-ADSQARBV.js");
6890
6931
  clear();
6891
6932
  appLogger.info("cache.clear");
6892
6933
  console.log("Cache cleared.");
@@ -6915,6 +6956,7 @@ var main = defineCommand({
6915
6956
  { currentWorkingDirectory: process.cwd() }
6916
6957
  );
6917
6958
  const { from: listDefaultFrom, to: listDefaultTo, days: listDefaultDays } = listWindow;
6959
+ await pricingRefresh.ready();
6918
6960
  const store = new LiveScanStore({
6919
6961
  watchEnabled: !jsonOnly,
6920
6962
  scanOptions,
@@ -6978,7 +7020,6 @@ var main = defineCommand({
6978
7020
  }
6979
7021
  const { url } = app;
6980
7022
  if (!jsonOnly) {
6981
- pricingRefresh.publish();
6982
7023
  store.startBackgroundRefresh();
6983
7024
  }
6984
7025
  let shuttingDown = false;