codesesh 1.0.4 → 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 (59) hide show
  1. package/README.md +5 -4
  2. package/dist/{chunk-W4PZHL2C.js → chunk-4ND6AT6W.js} +154 -92
  3. package/dist/chunk-4ND6AT6W.js.map +1 -0
  4. package/dist/chunk-4QFNZCBR.js +1271 -0
  5. package/dist/chunk-4QFNZCBR.js.map +1 -0
  6. package/dist/{chunk-MBZ4VV4C.js → chunk-A3MT6L6Z.js} +3 -3
  7. package/dist/chunk-COZSWVCH.js +89 -0
  8. package/dist/chunk-COZSWVCH.js.map +1 -0
  9. package/dist/{chunk-YCUN52HA.js → chunk-L3DDWTYV.js} +81 -115
  10. package/dist/chunk-L3DDWTYV.js.map +1 -0
  11. package/dist/{chunk-BYB77UAJ.js → chunk-XQDYKKRC.js} +139 -80
  12. package/dist/chunk-XQDYKKRC.js.map +1 -0
  13. package/dist/{chunk-3SXCTDD6.js → chunk-YZ6XCSVQ.js} +4 -3
  14. package/dist/{discovery-K3GLISI6.js → discovery-ADSQARBV.js} +11 -5
  15. package/dist/index.js +1538 -1030
  16. package/dist/index.js.map +1 -1
  17. package/dist/project-identity-worker.js +4 -4
  18. package/dist/scan-refresh-worker.js +17 -7
  19. package/dist/scan-refresh-worker.js.map +1 -1
  20. package/dist/search-index-worker.js +16 -8
  21. package/dist/search-index-worker.js.map +1 -1
  22. package/dist/session-detail-worker.js +79 -0
  23. package/dist/session-detail-worker.js.map +1 -0
  24. package/dist/smart-tag-worker.js +3 -3
  25. package/dist/web/assets/CustomTimeWindowDialog-D2bx7uDv.js +1 -0
  26. package/dist/web/assets/InteractiveReceipt-BFpIdno8.js +1 -0
  27. package/dist/web/assets/OverviewScreen-D_KXfiJi.js +1 -0
  28. package/dist/web/assets/{PrismHighlighter-B1a2dPJO.js → PrismHighlighter-BgVkYu_S.js} +1 -1
  29. package/dist/web/assets/Projects-CN44UpuR.js +1 -0
  30. package/dist/web/assets/SearchResultsPanel-CWD01v-a.js +1 -0
  31. package/dist/web/assets/SessionDetail-D8taQ6Tl.js +53 -0
  32. package/dist/web/assets/api-B9lJtVbO.js +1 -0
  33. package/dist/web/assets/index-XpolWMY4.js +1423 -0
  34. package/dist/web/assets/index-xbEEMszv.css +1 -0
  35. package/dist/web/assets/session-indexes-fib48ZKn.js +4 -0
  36. package/dist/web/assets/translate-Dmym1ZDl.js +2 -0
  37. package/dist/web/assets/utils-Bk66u8b3.js +1 -0
  38. package/dist/web/index.html +7 -7
  39. package/package.json +3 -3
  40. package/dist/chunk-BYB77UAJ.js.map +0 -1
  41. package/dist/chunk-G4HRD3AR.js +0 -246
  42. package/dist/chunk-G4HRD3AR.js.map +0 -1
  43. package/dist/chunk-W4PZHL2C.js.map +0 -1
  44. package/dist/chunk-YCUN52HA.js.map +0 -1
  45. package/dist/web/assets/InteractiveReceipt-Dk50TBsH.js +0 -1
  46. package/dist/web/assets/OverviewScreen-5hvQVp4H.js +0 -1
  47. package/dist/web/assets/Projects-Cy_v2yep.js +0 -1
  48. package/dist/web/assets/SearchResultsPanel-DfheEwpz.js +0 -1
  49. package/dist/web/assets/SessionDetail-DRI8R3st.js +0 -53
  50. package/dist/web/assets/api-GP9UCedC.js +0 -1
  51. package/dist/web/assets/contract-xJyW5u7a.js +0 -2
  52. package/dist/web/assets/index-Bd-YkWkZ.css +0 -1
  53. package/dist/web/assets/index-DEjvzumm.js +0 -1410
  54. package/dist/web/assets/panel-ND0J63d3.js +0 -1
  55. package/dist/web/assets/session-indexes-BsgjUoc1.js +0 -4
  56. package/dist/web/assets/utils-C7BqyxxV.js +0 -1
  57. /package/dist/{chunk-MBZ4VV4C.js.map → chunk-A3MT6L6Z.js.map} +0 -0
  58. /package/dist/{chunk-3SXCTDD6.js.map → chunk-YZ6XCSVQ.js.map} +0 -0
  59. /package/dist/{discovery-K3GLISI6.js.map → discovery-ADSQARBV.js.map} +0 -0
package/README.md CHANGED
@@ -23,6 +23,7 @@ Your browser will open at `http://localhost:4521` with all your sessions ready t
23
23
  - **Session Aliases** — Give important sessions memorable local names that carry through search, bookmarks, and activity views
24
24
  - **Persistent Themes** — Choose light, dark, or system appearance and keep your UI preferences across sessions
25
25
  - **Structured Global Search** — Search titles, messages, tool output, and file paths with filters for agent, project, smart tag, tool, file activity, and cost
26
+ - **UI languages** — English, Simplified Chinese, and Japanese. Follows your browser language by default; use the language selector in the top toolbar to switch and save your preference. Session content and code stay in their original language.
26
27
  - **Dashboard & Activity Trends** — See totals, daily activity, agent distribution, model usage, token trends, smart tags, bookmarks, and recent sessions
27
28
  - **Project Browse Mode** — Open a dedicated projects view with project-level metrics, sessions, and cross-agent drill-down
28
29
  - **Project & Nested Session Tree** — Group sessions by repository or project identity, while keeping subagent sessions under their parent
@@ -67,7 +68,7 @@ npx codesesh
67
68
  # Choose a custom starting port
68
69
  npx codesesh --port 8080
69
70
 
70
- # Only show sessions active in the last 3 days
71
+ # Only show sessions active in the last 3 local calendar days
71
72
  npx codesesh --days 3
72
73
 
73
74
  # Jump directly to a session
@@ -97,11 +98,11 @@ npx codesesh --trace
97
98
  | `--tls-key` | — | — | Path to the private key matching `--tls-cert` |
98
99
  | `--trust-proxy` | — | `false` | A reverse proxy in front of CodeSesh terminates TLS |
99
100
  | `--public-url` | — | — | Public HTTPS origin used with `--trust-proxy` for startup links |
100
- | `--days` | `-d` | `7` | Only include sessions active in the last N days (`0` = all time) |
101
+ | `--days` | `-d` | `7` | Only include sessions active in the last N local calendar days (`0` = all time) |
101
102
  | `--cwd` | — | — | Filter to sessions from a project directory |
102
103
  | `--agent` | `-a` | all | Filter to specific agent(s), comma-separated |
103
- | `--from` | — | — | Sessions active after this date `YYYY-MM-DD` |
104
- | `--to` | — | — | Sessions active before this date `YYYY-MM-DD` |
104
+ | `--from` | — | — | Sessions active on or after this date `YYYY-MM-DD` |
105
+ | `--to` | — | — | Sessions active on or before this date `YYYY-MM-DD` |
105
106
  | `--session` | `-s` | — | Directly open a session (`agent://session-id`) |
106
107
  | `--json` | `-j` | `false` | Print the session index as JSON and exit (metadata only) |
107
108
  | `--no-open` | — | `false` | Don't auto-open the browser |
@@ -36,7 +36,7 @@ function toPublicReferencedSessionHead(item) {
36
36
  return { ...item, session: toPublicSessionHead(item.session) };
37
37
  }
38
38
 
39
- // ../core/dist/chunk-EY7UDYHJ.mjs
39
+ // ../core/dist/chunk-555L3CTP.mjs
40
40
  var SMART_TAG_CLASSIFIER_REVISION = "smart-tags-v1";
41
41
  var USER_RULES = [
42
42
  ["bugfix", /\b(fix|bug|error|crash|exception|fail(?:ed|ure)?)\b|修复|错误|报错|崩溃|异常/i],
@@ -107,20 +107,27 @@ function hasEditedDocPath(value) {
107
107
  if (typeof value === "string") return DOC_PATH_RE.test(value);
108
108
  if (Array.isArray(value)) return value.some(hasEditedDocPath);
109
109
  if (typeof value !== "object") return false;
110
- const record = value;
110
+ const record2 = value;
111
111
  for (const key of ["path", "file", "filePath", "file_path", "targetPath", "target_path"]) {
112
- const raw = record[key];
112
+ const raw = record2[key];
113
113
  if (typeof raw === "string" && DOC_PATH_RE.test(raw)) return true;
114
114
  }
115
- return Object.values(record).some(hasEditedDocPath);
115
+ return Object.values(record2).some(hasEditedDocPath);
116
116
  }
117
117
  var WORKER_LOG_MESSAGE_TYPE = "codesesh.worker-log";
118
+ var WORKER_LOG_CONTEXT_KEYS = /* @__PURE__ */ new Set(["request_id", "operation_id", "publication_id"]);
118
119
  function isRecord(value) {
119
120
  return value != null && typeof value === "object" && !Array.isArray(value);
120
121
  }
122
+ function isLogContext(value) {
123
+ if (!isRecord(value)) return false;
124
+ return Object.entries(value).every(
125
+ ([key, item]) => WORKER_LOG_CONTEXT_KEYS.has(key) && typeof item === "string" && item.length <= 160
126
+ );
127
+ }
121
128
  function isWorkerLogMessage(value) {
122
129
  if (!isRecord(value) || value.type !== WORKER_LOG_MESSAGE_TYPE) return false;
123
- return typeof value.ts === "string" && value.ts.length > 0 && (value.level === "debug" || value.level === "info" || value.level === "warn" || value.level === "error") && typeof value.event === "string" && value.event.length > 0 && Number.isSafeInteger(value.pid) && Number(value.pid) > 0 && Number.isSafeInteger(value.threadId) && Number(value.threadId) >= 0 && isRecord(value.data);
130
+ return typeof value.ts === "string" && value.ts.length > 0 && (value.level === "debug" || value.level === "info" || value.level === "warn" || value.level === "error") && typeof value.event === "string" && value.event.length > 0 && Number.isSafeInteger(value.pid) && Number(value.pid) > 0 && Number.isSafeInteger(value.threadId) && Number(value.threadId) >= 0 && (value.context === void 0 || isLogContext(value.context)) && isRecord(value.data);
124
131
  }
125
132
 
126
133
  // ../core/dist/chunk-FDGCEOYE.mjs
@@ -165,7 +172,7 @@ function sessionRoutePath(reference) {
165
172
  return `${agentRoutePath(normalized.agentName)}/${encodeURIComponent(normalized.sessionId)}`;
166
173
  }
167
174
 
168
- // ../core/dist/chunk-GHNYETRY.mjs
175
+ // ../core/dist/chunk-665YT5TL.mjs
169
176
  var FILE_TOOL_KINDS = {
170
177
  read: "read",
171
178
  read_file: "read",
@@ -236,8 +243,8 @@ function collectPaths(value, key, paths, depth = 0) {
236
243
  }
237
244
  }
238
245
  function extractPatchOperations(input) {
239
- const record = toRecord(input);
240
- const content = Array.isArray(input) ? input : Array.isArray(record.content) ? record.content : [];
246
+ const record2 = toRecord(input);
247
+ const content = Array.isArray(input) ? input : Array.isArray(record2.content) ? record2.content : [];
241
248
  return content.flatMap((entry) => {
242
249
  const patch = toRecord(entry);
243
250
  const kind = typeof patch.type === "string" ? PATCH_KINDS[patch.type] : void 0;
@@ -324,6 +331,18 @@ function addCalendarDays(timestamp, days) {
324
331
  const date = new Date(timestamp);
325
332
  return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days).getTime();
326
333
  }
334
+ function parseCalendarDayBoundary(value, boundary) {
335
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
336
+ if (!match) return void 0;
337
+ const year = Number(match[1]);
338
+ const month = Number(match[2]) - 1;
339
+ const day = Number(match[3]);
340
+ const start = new Date(year, month, day);
341
+ if (start.getFullYear() !== year || start.getMonth() !== month || start.getDate() !== day) {
342
+ return null;
343
+ }
344
+ return boundary === "start" ? start.getTime() : addCalendarDays(start.getTime(), 1) - 1;
345
+ }
327
346
  function toCalendarDayNumber(timestamp) {
328
347
  const date = new Date(timestamp);
329
348
  return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / 864e5;
@@ -557,9 +576,16 @@ function buildSessionTree(sessions) {
557
576
  }
558
577
  };
559
578
  }
560
- function filterSessionTreeByActivityWindow(sessions, from, to, tree = buildSessionTree(sessions)) {
579
+ function filterSessionTreeByActivityWindow(sessions, from, to, tree) {
561
580
  if (from == null && to == null) return sessions;
562
- const pending2 = filterSessionTreeEntriesByActivityWindow(tree, from, to);
581
+ if (tree === void 0 && sessions.every((session) => hasActivityInWindow(session, from, to))) {
582
+ return [...sessions];
583
+ }
584
+ const pending2 = filterSessionTreeEntriesByActivityWindow(
585
+ tree ?? buildSessionTree(sessions),
586
+ from,
587
+ to
588
+ );
563
589
  const visible = /* @__PURE__ */ new Set();
564
590
  while (pending2.length > 0) {
565
591
  const node = pending2.pop();
@@ -603,11 +629,11 @@ function collectAffectedHierarchyKeys(graph, seedKeys, includeAncestors, collect
603
629
  for (const child of graph.childrenByKey.get(key) ?? []) pending2.push(child);
604
630
  }
605
631
  if (!includeAncestors) return;
632
+ const visitedAncestors = /* @__PURE__ */ new Set();
606
633
  for (const seed of seedKeys) {
607
634
  let key = graph.sessionsByKey.has(seed) ? seed : void 0;
608
- const onPath = /* @__PURE__ */ new Set();
609
- while (key && !onPath.has(key)) {
610
- onPath.add(key);
635
+ while (key && !visitedAncestors.has(key)) {
636
+ visitedAncestors.add(key);
611
637
  collected.add(key);
612
638
  key = graph.parentByKey.get(key);
613
639
  }
@@ -644,8 +670,10 @@ function createSessionProjectionContext(previousSessions, nextSessions, changedS
644
670
  );
645
671
  return { relatedSessionHeads, sessionOrder };
646
672
  }
673
+ var CODESESH_REQUEST_ID_HEADER = "X-CodeSesh-Request-ID";
674
+ var CODESESH_OPERATION_ID_HEADER = "X-CodeSesh-Operation-ID";
647
675
 
648
- // ../core/dist/chunk-3ENBOS4I.mjs
676
+ // ../core/dist/chunk-4COCEPC7.mjs
649
677
  function normalizeToolLabel(part) {
650
678
  if (part.title?.trim()) {
651
679
  return part.title.trim().replace(/^tool:\s*/i, "");
@@ -710,7 +738,7 @@ function extractSessionFileActivity(agentName, sessionId, projectIdentityKey, me
710
738
  );
711
739
  }
712
740
 
713
- // ../core/dist/chunk-WABZHIV5.mjs
741
+ // ../core/dist/chunk-DXASLH4L.mjs
714
742
  import { chmodSync, existsSync, mkdirSync, readdirSync, statSync } from "fs";
715
743
  import { basename, dirname, join } from "path";
716
744
  var diagnostics = null;
@@ -787,12 +815,67 @@ function restrictPrivateDatabase(dbPath) {
787
815
  restrictExistingBackups(dbPath);
788
816
  }
789
817
 
790
- // ../core/dist/chunk-3JGIS7MJ.mjs
818
+ // ../core/dist/chunk-MPV674C3.mjs
791
819
  import { createHash } from "crypto";
792
820
  import { existsSync as existsSync2, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
793
821
  import { homedir } from "os";
794
822
  import { join as join2 } from "path";
795
823
  import { AsyncLocalStorage } from "async_hooks";
824
+ function normalizeModelKey(key) {
825
+ return key.trim().toLowerCase().replaceAll("_", "-");
826
+ }
827
+ var MODELS_DEV_URL = "https://models.dev/api.json";
828
+ var ORIGINAL_PROVIDERS = /* @__PURE__ */ new Set([
829
+ "anthropic",
830
+ "openai",
831
+ "google",
832
+ "deepseek",
833
+ "moonshotai",
834
+ "minimax",
835
+ "mistral",
836
+ "xai",
837
+ "cohere",
838
+ "zai",
839
+ "zhipuai",
840
+ "alibaba",
841
+ "meta",
842
+ "stepfun"
843
+ ]);
844
+ function record(value) {
845
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
846
+ }
847
+ function perToken(value) {
848
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value / 1e6 : void 0;
849
+ }
850
+ function parseModelsDevPricing(data) {
851
+ const providers = Object.entries(record(data) ?? {}).sort(
852
+ ([a], [b]) => Number(ORIGINAL_PROVIDERS.has(b)) - Number(ORIGINAL_PROVIDERS.has(a)) || a.localeCompare(b)
853
+ );
854
+ const qualified = /* @__PURE__ */ new Map();
855
+ const aliases = /* @__PURE__ */ new Map();
856
+ for (const [provider, rawProvider] of providers) {
857
+ const models = record(record(rawProvider)?.["models"]);
858
+ for (const [model, rawModel] of Object.entries(models ?? {})) {
859
+ const cost = record(record(rawModel)?.["cost"]);
860
+ if (!cost) continue;
861
+ const input = perToken(cost["input"]);
862
+ const output = perToken(cost["output"]);
863
+ if (input === void 0 || output === void 0) continue;
864
+ const pricing = {
865
+ inputCostPerToken: input,
866
+ outputCostPerToken: output,
867
+ cacheCreateCostPerToken: perToken(cost["cache_write"]) ?? input,
868
+ cacheReadCostPerToken: perToken(cost["cache_read"]) ?? input,
869
+ reasoningCostPerToken: output,
870
+ webSearchCostPerRequest: 0.01
871
+ };
872
+ qualified.set(normalizeModelKey(`${provider}/${model}`), pricing);
873
+ const name = normalizeModelKey(model);
874
+ if (!aliases.has(name)) aliases.set(name, pricing);
875
+ }
876
+ }
877
+ return new Map([...aliases, ...qualified]);
878
+ }
796
879
  var snapshot_default = {
797
880
  "claude-3-5-haiku": [8e-7, 4e-6, 1e-6, 8e-8],
798
881
  "claude-3-5-sonnet": [3e-6, 15e-6, 375e-8, 3e-7],
@@ -836,16 +919,13 @@ var snapshot_default = {
836
919
  "gemini-2.5-pro": [125e-8, 1e-5, null, 125e-9],
837
920
  "gemini-2.5-flash": [3e-7, 25e-7, null, 3e-8]
838
921
  };
839
- var LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
840
- var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
922
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
841
923
  var WEB_SEARCH_COST = 0.01;
842
924
  var REFRESH_TIMEOUT_MS = 1e4;
843
925
  var published = createPricingGeneration(loadSnapshot());
844
926
  var pending = null;
927
+ var refreshInFlight = null;
845
928
  published = readDiskCache() ?? published;
846
- function normalizeModelKey(key) {
847
- return key.trim().toLowerCase().replaceAll("_", "-");
848
- }
849
929
  function createPricingGeneration(pricing) {
850
930
  const hash = createHash("sha256");
851
931
  const entries = [...pricing.entries()].sort(
@@ -862,14 +942,14 @@ function createPricingGeneration(pricing) {
862
942
  pricing
863
943
  };
864
944
  }
865
- function costNumber(value, fallback) {
866
- return typeof value === "number" && Number.isFinite(value) ? value : fallback;
945
+ function costNumber(value) {
946
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
867
947
  }
868
948
  function getCacheDir() {
869
949
  return join2(homedir(), ".cache", "codesesh");
870
950
  }
871
951
  function getCachePath() {
872
- return join2(getCacheDir(), "litellm-pricing.json");
952
+ return join2(getCacheDir(), "models-dev-pricing.json");
873
953
  }
874
954
  function loadSnapshot() {
875
955
  const map = /* @__PURE__ */ new Map();
@@ -887,33 +967,19 @@ function loadSnapshot() {
887
967
  }
888
968
  return map;
889
969
  }
890
- function parseLiteLLMEntry(entry) {
891
- const input = entry.input_cost_per_token;
892
- const output = entry.output_cost_per_token;
893
- if (typeof input !== "number" || typeof output !== "number") return null;
970
+ function normalizePricing(raw) {
971
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
972
+ const values = raw;
973
+ const input = costNumber(values["inputCostPerToken"]);
974
+ const output = costNumber(values["outputCostPerToken"]);
975
+ if (input === void 0 || output === void 0) return null;
894
976
  return {
895
977
  inputCostPerToken: input,
896
978
  outputCostPerToken: output,
897
- cacheCreateCostPerToken: entry.cache_creation_input_token_cost ?? input * 1.25,
898
- cacheReadCostPerToken: entry.cache_read_input_token_cost ?? input * 0.1,
899
- reasoningCostPerToken: entry.output_reasoning_cost_per_token ?? output,
900
- webSearchCostPerRequest: costNumber(
901
- entry.web_search_cost_per_request ?? entry.search_context_cost_per_query,
902
- WEB_SEARCH_COST
903
- )
904
- };
905
- }
906
- function normalizeCachedPricing(raw) {
907
- const input = costNumber(raw["inputCostPerToken"], 0);
908
- const output = costNumber(raw["outputCostPerToken"], 0);
909
- if (input <= 0 || output <= 0) return null;
910
- return {
911
- inputCostPerToken: input,
912
- outputCostPerToken: output,
913
- cacheCreateCostPerToken: costNumber(raw["cacheCreateCostPerToken"], input * 1.25),
914
- cacheReadCostPerToken: costNumber(raw["cacheReadCostPerToken"], input * 0.1),
915
- reasoningCostPerToken: costNumber(raw["reasoningCostPerToken"], output),
916
- webSearchCostPerRequest: costNumber(raw["webSearchCostPerRequest"], WEB_SEARCH_COST)
979
+ cacheCreateCostPerToken: costNumber(values["cacheCreateCostPerToken"]) ?? input * 1.25,
980
+ cacheReadCostPerToken: costNumber(values["cacheReadCostPerToken"]) ?? input * 0.1,
981
+ reasoningCostPerToken: costNumber(values["reasoningCostPerToken"]) ?? output,
982
+ webSearchCostPerRequest: costNumber(values["webSearchCostPerRequest"]) ?? WEB_SEARCH_COST
917
983
  };
918
984
  }
919
985
  function indexPricing(map, name, pricing) {
@@ -925,30 +991,25 @@ function indexPricing(map, name, pricing) {
925
991
  if (!map.has(stripped)) map.set(stripped, pricing);
926
992
  }
927
993
  }
928
- function parseLiteLLMData(data) {
929
- const map = /* @__PURE__ */ new Map();
930
- for (const [name, entry] of Object.entries(data)) {
931
- const pricing = parseLiteLLMEntry(entry);
932
- if (pricing) indexPricing(map, name, pricing);
933
- }
934
- return map;
935
- }
936
- function readDiskCache() {
994
+ function readDiskCache(requireFresh = false) {
937
995
  const path = getCachePath();
938
996
  if (!existsSync2(path)) return null;
939
997
  try {
940
998
  const cached = JSON.parse(readFileSync(path, "utf-8"));
941
- if (!Number.isFinite(cached.timestamp)) return null;
999
+ if (!Number.isFinite(cached.timestamp) || cached.timestamp > Date.now()) return null;
1000
+ if (requireFresh && Date.now() - cached.timestamp >= CACHE_TTL_MS) return null;
942
1001
  if (cached.data == null || typeof cached.data !== "object" || Array.isArray(cached.data)) {
943
1002
  return null;
944
1003
  }
945
1004
  const next = loadSnapshot();
1005
+ let validEntries = 0;
946
1006
  for (const [name, rawPricing] of Object.entries(cached.data)) {
947
- const pricing = normalizeCachedPricing(rawPricing);
1007
+ const pricing = normalizePricing(rawPricing);
948
1008
  if (!pricing) continue;
949
- indexPricing(next, name, pricing);
1009
+ next.set(normalizeModelKey(name), pricing);
1010
+ validEntries++;
950
1011
  }
951
- return createPricingGeneration(next);
1012
+ return validEntries > 0 ? createPricingGeneration(next) : null;
952
1013
  } catch {
953
1014
  return null;
954
1015
  }
@@ -1011,25 +1072,21 @@ function writeDiskCacheAtomically(path, generation) {
1011
1072
  return false;
1012
1073
  }
1013
1074
  }
1014
- async function refreshPricingCache(options = {}) {
1015
- const path = getCachePath();
1016
- if (existsSync2(path)) {
1017
- try {
1018
- const cached = JSON.parse(readFileSync(path, "utf-8"));
1019
- if (typeof cached.timestamp === "number" && Date.now() - cached.timestamp <= CACHE_TTL_MS) {
1020
- return false;
1021
- }
1022
- } catch {
1023
- }
1024
- }
1075
+ function refreshPricingCache(options = {}) {
1076
+ refreshInFlight ??= fetchPricing(options).finally(() => {
1077
+ refreshInFlight = null;
1078
+ });
1079
+ return refreshInFlight;
1080
+ }
1081
+ async function fetchPricing(options) {
1082
+ if (pending || readDiskCache(true)) return false;
1025
1083
  const timeout = AbortSignal.timeout(options.timeoutMs ?? REFRESH_TIMEOUT_MS);
1026
1084
  const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
1027
1085
  getCoreDiagnostics()?.info?.("pricing.refresh.started", { generation: published.id });
1028
1086
  try {
1029
- const response = await fetch(LITELLM_URL, { signal });
1087
+ const response = await fetch(MODELS_DEV_URL, { signal });
1030
1088
  if (!response.ok) return false;
1031
- const data = await response.json();
1032
- const remote = parseLiteLLMData(data);
1089
+ const remote = parseModelsDevPricing(await response.json());
1033
1090
  if (remote.size === 0) return false;
1034
1091
  const next = loadSnapshot();
1035
1092
  for (const [name, pricing] of remote.entries()) {
@@ -1117,18 +1174,20 @@ function lookupCandidate(model, registry) {
1117
1174
  return null;
1118
1175
  }
1119
1176
  function fuzzyLookup(model, registry) {
1120
- let best = null;
1121
- for (const [key, pricing] of registry.entries()) {
1122
- if (!hasBillablePricing(pricing)) continue;
1123
- if (model.startsWith(`${key}-`) || model.startsWith(`${key}@`) || model === key) {
1124
- if (!best || key.length > best[0].length) best = [key, pricing];
1125
- }
1177
+ const direct = registry.get(model);
1178
+ if (direct && hasBillablePricing(direct)) return direct;
1179
+ for (let index = model.length - 1; index >= 0; index--) {
1180
+ if (model[index] !== "-" && model[index] !== "@") continue;
1181
+ const pricing = registry.get(model.slice(0, index));
1182
+ if (pricing && hasBillablePricing(pricing)) return pricing;
1126
1183
  }
1127
- return best?.[1] ?? null;
1184
+ return null;
1128
1185
  }
1129
1186
  var pricingResolver = {
1130
1187
  resolve(rawModelName) {
1131
1188
  const registry = getPricingRegistry();
1189
+ const exact = registry.get(normalizeModelKey(rawModelName));
1190
+ if (exact && hasBillablePricing(exact)) return exact;
1132
1191
  const candidates = getCandidates(rawModelName);
1133
1192
  for (const candidate of candidates) {
1134
1193
  const pricing = lookupCandidate(candidate, registry);
@@ -1177,7 +1236,7 @@ function estimateCostForTokens(model, usage) {
1177
1236
  return cost > 0 ? { cost: Number(cost.toFixed(8)), source: "estimated" } : null;
1178
1237
  }
1179
1238
 
1180
- // ../core/dist/chunk-326ZXYCY.mjs
1239
+ // ../core/dist/chunk-N65P4J7T.mjs
1181
1240
  import { closeSync, openSync, readSync } from "fs";
1182
1241
  import { StringDecoder } from "string_decoder";
1183
1242
  import { basename as basename2 } from "path";
@@ -1484,7 +1543,8 @@ function cleanMessageParts(parts) {
1484
1543
  }
1485
1544
  function cleanParsedMessage(message) {
1486
1545
  const parts = cleanMessageParts(message.parts);
1487
- if (parts.length === 0) return null;
1546
+ const hasUsage = (message.cost ?? 0) > 0 || Object.values(message.tokens ?? {}).some((value) => value > 0);
1547
+ if (parts.length === 0 && !hasUsage) return null;
1488
1548
  return { ...message, parts };
1489
1549
  }
1490
1550
  function cleanParsedMessages(messages) {
@@ -1505,7 +1565,7 @@ function firstUserMessageTitle(messages) {
1505
1565
  return null;
1506
1566
  }
1507
1567
 
1508
- // ../core/dist/chunk-BAU7ZBXA.mjs
1568
+ // ../core/dist/chunk-HXH76DEE.mjs
1509
1569
  import { existsSync as existsSync3 } from "fs";
1510
1570
  import { basename as basename3, dirname as dirname2, join as join3 } from "path";
1511
1571
  import { createRequire } from "module";
@@ -1793,9 +1853,9 @@ function normalizeToolState(value, legacyPart) {
1793
1853
  }
1794
1854
  function planText(value) {
1795
1855
  if (typeof value === "string") return value;
1796
- const record = toRecord2(value);
1797
- if (!record) return "";
1798
- return planText(record.text ?? record.plan ?? record.content);
1856
+ const record2 = toRecord2(value);
1857
+ if (!record2) return "";
1858
+ return planText(record2.text ?? record2.plan ?? record2.content);
1799
1859
  }
1800
1860
  function normalizePlanPart(value, time_created) {
1801
1861
  const approval_status = value.approval_status === "fail" ? "fail" : "success";
@@ -1974,6 +2034,7 @@ export {
1974
2034
  mergeSessionsUpdatedEvents,
1975
2035
  startOfCalendarDay,
1976
2036
  addCalendarDays,
2037
+ parseCalendarDayBoundary,
1977
2038
  countCalendarDays,
1978
2039
  toCalendarDayKey,
1979
2040
  isProjectIdentityKind,
@@ -1986,12 +2047,13 @@ export {
1986
2047
  filterSessionTreeByActivityWindow,
1987
2048
  filterSessionTreeEntriesByActivityWindow,
1988
2049
  createSessionProjectionContext,
2050
+ CODESESH_REQUEST_ID_HEADER,
2051
+ CODESESH_OPERATION_ID_HEADER,
1989
2052
  extractSessionFileActivity,
1990
2053
  setCoreDiagnostics,
1991
2054
  getCoreDiagnostics,
1992
- ensurePrivateDirectory,
1993
- restrictPrivateFile,
1994
- restrictExistingPrivateFiles,
2055
+ PRIVATE_DIR_MODE,
2056
+ PRIVATE_FILE_MODE,
1995
2057
  getPricingGeneration,
1996
2058
  synchronizePricingGeneration,
1997
2059
  publishPendingPricing,
@@ -2032,4 +2094,4 @@ export {
2032
2094
  AGENT_CATALOG,
2033
2095
  getAgentCatalogEntry
2034
2096
  };
2035
- //# sourceMappingURL=chunk-W4PZHL2C.js.map
2097
+ //# sourceMappingURL=chunk-4ND6AT6W.js.map