claude-discover 1.9.1 → 1.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/main/main.js CHANGED
@@ -432,13 +432,14 @@ class RequestParser {
432
432
  return files;
433
433
  }
434
434
  }
435
+ const agentKey = (id) => id?.includes("@") ? id.slice(0, id.indexOf("@")) : id?.replace(/^a/, "").replace(/-[0-9a-f]{16}$/, "") ?? null;
435
436
  class RequestFile {
436
437
  constructor(sessionId, { dir = REQUESTS_DIR, agentId = null } = {}) {
437
438
  this.filePath = join(dir, `${sessionId}.requests.jsonl`);
438
- this.agentId = agentId;
439
+ this.agentKey = agentKey(agentId);
439
440
  }
440
441
  #mine(rec) {
441
- return (rec.requestHeaders?.["x-claude-code-agent-id"] ?? null) === this.agentId;
442
+ return agentKey(rec.requestHeaders?.["x-claude-code-agent-id"] ?? null) === this.agentKey;
442
443
  }
443
444
  async lines() {
444
445
  const raw = await fsp.readFile(this.filePath, "utf8").catch(() => "");
@@ -1126,7 +1127,7 @@ class SessionsService extends EventEmitter {
1126
1127
  }
1127
1128
  // Subagents send the parent's session id, so the proxy logs their requests into the parent's
1128
1129
  // file, tagged x-claude-code-agent-id — route their reads there. The transcript filename is
1129
- // `agent-<id>` while the header carries the bare <id>.
1130
+ // `agent-<id>`; RequestFile normalizes that id against the header's own spelling.
1130
1131
  #requestFile(sessionId, parentSessionId) {
1131
1132
  const agentId = parentSessionId && sessionId.startsWith("agent-") ? sessionId.slice("agent-".length) : null;
1132
1133
  return agentId ? new RequestFile(parentSessionId, { agentId }) : new RequestFile(sessionId);
@@ -34,13 +34,13 @@ function useLocalStorage(key, initial) {
34
34
  }
35
35
  function clearOutdatedLocalStorage() {
36
36
  const version = localStorage.getItem(VERSION_KEY);
37
- if (version !== "1.9.1") {
38
- const [MAJOR, MINOR, PATCH] = "1.9.1".split(".");
37
+ if (version !== "1.9.2") {
38
+ const [MAJOR, MINOR, PATCH] = "1.9.2".split(".");
39
39
  const [major, minor, patch] = (version ?? "").split(".");
40
40
  if (MAJOR !== major || MINOR !== minor) {
41
41
  localStorage.clear();
42
42
  }
43
- localStorage.setItem(VERSION_KEY, "1.9.1");
43
+ localStorage.setItem(VERSION_KEY, "1.9.2");
44
44
  }
45
45
  }
46
46
  function useMouseFontScale(storageKey) {
@@ -983,6 +983,26 @@ ${text}` }]
983
983
  return out;
984
984
  }
985
985
  const currentModel = (turns) => turns.findLast((t) => t.model && t.model !== "<synthetic>")?.model;
986
+ const SMALL_CONTEXT = /* @__PURE__ */ new Set([
987
+ "claude-3-opus",
988
+ "claude-3-sonnet",
989
+ "claude-3-haiku",
990
+ "claude-3-5-sonnet",
991
+ "claude-3-5-haiku",
992
+ "claude-3-7-sonnet",
993
+ "claude-haiku-4-5",
994
+ "claude-opus-4",
995
+ "claude-opus-4-1",
996
+ "claude-opus-4-5",
997
+ "claude-opus-4-6",
998
+ "claude-sonnet-4",
999
+ "claude-sonnet-4-5",
1000
+ "claude-sonnet-4-6"
1001
+ ]);
1002
+ function contextWindow(models = []) {
1003
+ const is200k = (model) => SMALL_CONTEXT.has(model.replace(/[-@]\d{8}.*$/, ""));
1004
+ return models.some((m) => m && !is200k(m)) ? 1e6 : 2e5;
1005
+ }
986
1006
  function normalizeContent(content) {
987
1007
  if (typeof content === "string") return [{ type: "text", text: content }];
988
1008
  if (!Array.isArray(content)) return [];
@@ -1411,22 +1431,23 @@ function ConversationView({ items, instructions = [], expandAll = null }) {
1411
1431
  const durations = reactExports.useMemo(() => cycleDurations(groups), [groups]);
1412
1432
  const findOpen = useFindActive();
1413
1433
  const [scale, zoomRef] = useMouseFontScale("font-scale.conversation");
1434
+ const model = currentModel(turns);
1435
+ const ctxLimit = contextWindow([model]);
1414
1436
  const hasTimeline = points.some(Boolean);
1415
1437
  return /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandAllContext.Provider, { value: expandAll, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: zoomRef, className: `conversation${hasTimeline ? " has-token-timeline" : ""}`, style: { "--font-scale": scale }, children: groups.map((g, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `conv-row conv-row-${g.kind}`, children: [
1416
- /* @__PURE__ */ jsxRuntimeExports.jsx(LazyMount, { eager: i < 8, forceMount: findOpen, placeholderMinHeight: 80, children: g.kind === "user" ? /* @__PURE__ */ jsxRuntimeExports.jsx(UserRow, { turns: g.turns, point: points[i] }) : g.kind === "assistant" ? /* @__PURE__ */ jsxRuntimeExports.jsx(AssistantCard, { turns: g.turns, point: points[i], duration: durations[i], showAuthor: groups[i - 1]?.kind !== "assistant" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(InstructionRun, { turns: g.turns, model: currentModel(turns) }) }),
1438
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LazyMount, { eager: i < 8, forceMount: findOpen, placeholderMinHeight: 80, children: g.kind === "user" ? /* @__PURE__ */ jsxRuntimeExports.jsx(UserRow, { turns: g.turns, point: points[i], ctxLimit }) : g.kind === "assistant" ? /* @__PURE__ */ jsxRuntimeExports.jsx(AssistantCard, { turns: g.turns, point: points[i], ctxLimit, duration: durations[i], showAuthor: groups[i - 1]?.kind !== "assistant" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(InstructionRun, { turns: g.turns, model }) }),
1417
1439
  points[i] ? /* @__PURE__ */ jsxRuntimeExports.jsx(TokenPoint, { point: points[i] }) : hasTimeline && g.kind === "user" && g.turns.some(isCommandTurn) && /* @__PURE__ */ jsxRuntimeExports.jsx(TokenPoint, { point: { role: "command", delta: 0 } })
1418
1440
  ] }, g.turns[0].uuid)) }) });
1419
1441
  }
1420
1442
  const ClaudeIcon = () => /* @__PURE__ */ jsxRuntimeExports.jsx("img", { className: "msg-icon claude-icon", src: claudeIcon, alt: "" });
1421
- const CTX_LIMIT = THRESHOLDS.context.danger;
1422
1443
  function TokenPoint({ point: p }) {
1423
1444
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `token-point token-point-${p.role}${p.delta < 0 ? " negative" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "token-point-dot" }) });
1424
1445
  }
1425
- function TokenStats({ point }) {
1446
+ function TokenStats({ point, ctxLimit }) {
1426
1447
  if (!point) return null;
1427
1448
  const rows = [];
1428
1449
  if (point.ctx != null) {
1429
- const width = Math.min(point.ctx / CTX_LIMIT, 1) * 100;
1450
+ const width = Math.min(point.ctx / ctxLimit, 1) * 100;
1430
1451
  rows.push(`<div class="token-tooltip-ctx">Context <span class="token-point-ctx-bar"><span style="width:${width}%"></span></span> <span class="token-tooltip-ctx-val">${fmtCompact(point.ctx)}</span></div>`);
1431
1452
  }
1432
1453
  const u = point.usage;
@@ -1444,7 +1465,7 @@ function TokenStats({ point }) {
1444
1465
  rows.push(`<div class="token-tooltip-total"><span>Accumulated tokens</span><span>${fmtCompact(point.total)}</span></div>`);
1445
1466
  return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "msg-tokens", "data-tippy-html": `<div class="token-tooltip">${rows.join("")}</div>`, children: fmtCompact(point.total) });
1446
1467
  }
1447
- function UserRow({ turns, point }) {
1468
+ function UserRow({ turns, point, ctxLimit }) {
1448
1469
  const [open, setOpen] = useCollapsed(false);
1449
1470
  const msg = turns.find((t) => !isContextTurn(t));
1450
1471
  const ctxItems = turns.filter(isContextTurn).flatMap((t) => t.blocks);
@@ -1464,7 +1485,7 @@ function UserRow({ turns, point }) {
1464
1485
  ] })
1465
1486
  ] }),
1466
1487
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "msg-header-right", children: [
1467
- /* @__PURE__ */ jsxRuntimeExports.jsx(TokenStats, { point }),
1488
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TokenStats, { point, ctxLimit }),
1468
1489
  msg.ts != null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "msg-time", children: format(msg.ts, "HH:mm:ss") })
1469
1490
  ] })
1470
1491
  ] }),
@@ -1472,7 +1493,7 @@ function UserRow({ turns, point }) {
1472
1493
  /* @__PURE__ */ jsxRuntimeExports.jsx(TurnRow, { turn: msg })
1473
1494
  ] });
1474
1495
  }
1475
- function AssistantCard({ turns, point, duration: duration2, showAuthor = true }) {
1496
+ function AssistantCard({ turns, point, ctxLimit, duration: duration2, showAuthor = true }) {
1476
1497
  const [open, setOpen] = useCollapsed(false);
1477
1498
  const toolBlocks = turns.flatMap((t) => t.blocks.filter((b) => b.type === "tool_use"));
1478
1499
  const errorCount = toolBlocks.filter((b) => b.result?.is_error).length;
@@ -1506,7 +1527,7 @@ function AssistantCard({ turns, point, duration: duration2, showAuthor = true })
1506
1527
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: summary })
1507
1528
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "msg-summary", children: summary })),
1508
1529
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "msg-header-right", children: [
1509
- /* @__PURE__ */ jsxRuntimeExports.jsx(TokenStats, { point }),
1530
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TokenStats, { point, ctxLimit }),
1510
1531
  end != null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "msg-time", title: duration2 > 0 ? `Response time: ${fmtDuration(duration2)}` : null, children: format(end, "HH:mm:ss") })
1511
1532
  ] })
1512
1533
  ] }),
@@ -1908,7 +1929,6 @@ function RequestsView({ sessionId, date, granularity = "day", fileSize = 0, expa
1908
1929
  ] })
1909
1930
  ] });
1910
1931
  }
1911
- const CONTEXT_WINDOW$1 = THRESHOLDS.context.danger;
1912
1932
  let MAX_LINES = 10;
1913
1933
  let MAX_LINE_CHARS = 200;
1914
1934
  let MODEL = null;
@@ -1971,7 +1991,8 @@ function markdownSession(meta, items, truncated, instructions = []) {
1971
1991
  const t = meta.tokens;
1972
1992
  const stu = meta.serverToolUse;
1973
1993
  const wallDuration = meta.lastActivityAt - meta.startedAt;
1974
- const contextPct = Math.round(meta.lastContextTokens / CONTEXT_WINDOW$1 * 100);
1994
+ const ctxLimit = contextWindow(meta.models);
1995
+ const contextPct = Math.round(meta.lastContextTokens / ctxLimit * 100);
1975
1996
  const cacheHitPct = (meta.cacheHitRatio * 100).toFixed(0);
1976
1997
  const turns = items ? flatten(items, instructions) : null;
1977
1998
  MODEL = turns ? currentModel(turns) : null;
@@ -1987,7 +2008,7 @@ ${transcript}`;
1987
2008
  - Estimated cost: ${fmtUSD(meta.cost)}
1988
2009
  - Total tokens: ${fmtCompact(meta.totalTokens)}
1989
2010
  - Working time: ${fmtDuration(meta.activeMs)}
1990
- - Context size: ${fmtCompact(meta.lastContextTokens)} / ${fmtCompact(CONTEXT_WINDOW$1)} (${contextPct}%)${meta.savings.using5mCache > 0 ? `
2011
+ - Context size: ${fmtCompact(meta.lastContextTokens)} / ${fmtCompact(ctxLimit)} (${contextPct}%)${meta.savings.using5mCache > 0 ? `
1991
2012
 
1992
2013
  ## Potential savings
1993
2014
  - with 5m cache: ${meta.cost > 0 ? `(${(meta.savings.using5mCache / meta.cost * 100).toFixed(0)}%) ` : ""}−${fmtUSD(meta.savings.using5mCache)}` : ""}
@@ -2155,7 +2176,6 @@ ${body}`;
2155
2176
  ] })
2156
2177
  ] });
2157
2178
  }
2158
- const CONTEXT_WINDOW = THRESHOLDS.context.danger;
2159
2179
  function SessionSummary({ meta, items, instructions, agent, onOpenAgent, granularity = "day" }) {
2160
2180
  const timeFormat = granularity === "day" ? "pp" : "MMM d, pp";
2161
2181
  const onAnalyze = () => {
@@ -2174,7 +2194,8 @@ ${body}`);
2174
2194
  const stu = meta.serverToolUse;
2175
2195
  const hasServerTools = stu.webSearch > 0 || stu.webFetch > 0;
2176
2196
  const modelLabel = meta.models.join(", ") || "—";
2177
- const contextRatio = meta.lastContextTokens / CONTEXT_WINDOW;
2197
+ const ctxLimit = contextWindow(meta.models);
2198
+ const ctxTone = tone(meta.lastContextTokens, THRESHOLDS.context);
2178
2199
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-summary", children: [
2179
2200
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "summary-ai", children: [
2180
2201
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "summary-ai-row", children: [
@@ -2209,7 +2230,7 @@ ${body}`);
2209
2230
  ] }) }),
2210
2231
  /* @__PURE__ */ jsxRuntimeExports.jsx(Field, { label: "Total tokens", value: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: tone(totalTokens2, THRESHOLDS.tokens), children: fmtCompact(totalTokens2) }) }),
2211
2232
  /* @__PURE__ */ jsxRuntimeExports.jsx(Field, { label: "Working time", value: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: tone(activeDuration, THRESHOLDS.workTime), children: fmtDuration(activeDuration) }) }),
2212
- /* @__PURE__ */ jsxRuntimeExports.jsx(Field, { label: "Context size", value: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: tone(meta.lastContextTokens, THRESHOLDS.context), children: `${fmtCompact(meta.lastContextTokens)} / ${fmtCompact(CONTEXT_WINDOW)}` }), below: /* @__PURE__ */ jsxRuntimeExports.jsx(Bar, { ratio: contextRatio, tone: tone(meta.lastContextTokens, THRESHOLDS.context) }) })
2233
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Field, { label: "Context size", value: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: ctxTone, children: `${fmtCompact(meta.lastContextTokens)} / ${fmtCompact(ctxLimit)}` }), below: /* @__PURE__ */ jsxRuntimeExports.jsx(Bar, { ratio: meta.lastContextTokens / ctxLimit, tone: ctxTone }) })
2213
2234
  ] }),
2214
2235
  meta.savings.using5mCache > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Section, { title: "Potential savings", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2215
2236
  Field,
@@ -2364,10 +2385,10 @@ function Session({ meta, missing, date, granularity = "day" }) {
2364
2385
  };
2365
2386
  }, [sessionId, date, granularity, fileSize]);
2366
2387
  if (!meta) {
2367
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "session-view empty", children: missing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-missing", children: [
2388
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "session-view empty", children: missing?.warn ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-missing", children: [
2368
2389
  "⚠ ",
2369
- missing
2370
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Select a session to inspect." }) });
2390
+ missing.text
2391
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: missing?.text || "Select a session to inspect." }) });
2371
2392
  }
2372
2393
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "session-view", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "view-body", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "view-conversation", children: agentOpen ? /* @__PURE__ */ jsxRuntimeExports.jsx(AgentView, { meta, items, instructions, agent, onClose: () => setAgentOpen(false) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "view-tab-pane", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "view-tab-pane-row", children: [
2373
2394
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "view-tab-pane-main", children: [
@@ -2598,8 +2619,8 @@ function App() {
2598
2619
  let missing = null;
2599
2620
  if (!selected && scanProgress?.scanning === false) {
2600
2621
  const when = granularity === "day" ? `on ${format(anchor, "MMM d, yyyy")}` : `in this ${granularity}`;
2601
- if (!sessions.length) missing = `No sessions recorded ${when}.`;
2602
- else if (deepLink?.date === format(anchor, "yyyy-MM-dd")) missing = `Session ${selectedId} has no records ${when}.`;
2622
+ if (!sessions.length) missing = { text: `No sessions recorded ${when}.` };
2623
+ else if (deepLink?.date === format(anchor, "yyyy-MM-dd")) missing = { text: `Session ${selectedId} has no records ${when}.`, warn: true };
2603
2624
  }
2604
2625
  const selectSession = reactExports.useCallback((id, link = null) => {
2605
2626
  closeFind();
@@ -6,7 +6,7 @@
6
6
  <meta charset="UTF-8" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <title>Discover</title>
9
- <script type="module" crossorigin src="./assets/index-BKTnG3v8.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-BugPzqD2.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="./assets/vendors-S1fS5xz9.js">
11
11
  <link rel="stylesheet" crossorigin href="./assets/vendors-B4XMnGdr.css">
12
12
  <link rel="stylesheet" crossorigin href="./assets/index-03LlBvFr.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-discover",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "type": "module",
5
5
  "description": "Claude Discover — a desktop tool to browse your local Claude Code sessions: conversations, token costs, and captured API traffic",
6
6
  "license": "MIT",