claude-discover 1.9.0 → 1.9.1

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.
@@ -557,8 +557,11 @@
557
557
  &:hover { background: var(--bg-elev-2); }
558
558
  &.selected { background: var(--selected); }
559
559
  &.is-subagent-child { padding-left: 20px; }
560
+ &.deep-linked { background: rgba(52, 211, 153, 0.12); } /* last, so it wins over :hover and .selected */
560
561
  }
561
562
 
563
+ .deeplink-note { color: #34d399; }
564
+
562
565
  .session-row-main { flex: 1; min-width: 0; }
563
566
 
564
567
  .session-row-stats {
@@ -733,9 +736,9 @@
733
736
  }
734
737
 
735
738
  .conv-row + .conv-row { margin-top: 15px; }
739
+ /* One instruction row per API call (see groupTurns) — the gap keeps two calls' strips apart. */
736
740
  .conv-row-instruction + .conv-row { margin-top: 20px; }
737
741
  .conv-row-assistant + .conv-row-user { margin-top: 60px; }
738
- .conv-row-instruction + .conv-row-instruction,
739
742
  .conv-row-assistant + .conv-row-assistant { margin-top: 0; }
740
743
 
741
744
 
@@ -1077,6 +1080,18 @@ button.msg-summary:hover { color: var(--text); background: var(--bg-elev-2); bor
1077
1080
  margin-left: -10px;
1078
1081
  }
1079
1082
 
1083
+ /* Full-width toggle so the estimated token count can sit right-aligned, like msg-header-right. */
1084
+ .instruction-file .aux-toggle { display: flex; width: 100%; align-items: center; }
1085
+ .instruction-tokens { margin-left: auto; color: var(--text-faint); }
1086
+
1087
+ /* Summed token total under a run of instruction files: a rule over the right-aligned figure. */
1088
+ .instruction-total { display: flex; font-size: calc(11px * var(--font-scale, 1)); }
1089
+ .instruction-total .instruction-tokens {
1090
+ border-top: 1px solid var(--border);
1091
+ padding-top: 2px;
1092
+ font-weight: 600;
1093
+ }
1094
+
1080
1095
  /* Full path of an expanded memory file, first line of the body — one click selects it for copying. */
1081
1096
  .instruction-path {
1082
1097
  font-family: var(--font-mono), monospace;
@@ -1814,6 +1829,17 @@ button.msg-summary:hover { color: var(--text); background: var(--bg-elev-2); bor
1814
1829
  }
1815
1830
  }
1816
1831
 
1832
+ .session-missing {
1833
+ max-width: 520px;
1834
+ padding: 14px 18px;
1835
+ border: 1px solid rgba(251, 191, 36, 0.35);
1836
+ border-radius: 6px;
1837
+ background: rgba(251, 191, 36, 0.08);
1838
+ color: var(--warn);
1839
+ text-align: center;
1840
+ word-break: break-word;
1841
+ }
1842
+
1817
1843
  .view-body {
1818
1844
  flex: 1;
1819
1845
  display: flex;
@@ -1,4 +1,4 @@
1
- import { r as reactExports, j as jsxRuntimeExports, f as format, s as startOfWeek, a as startOfMonth, b as startOfDay, e as endOfWeek, c as endOfMonth, d as endOfDay, g as addWeeks, h as addMonths, i as addDays, k as isSameWeek, l as isSameMonth, m as isSameDay, n as intervalToDuration, o as getDaysInMonth, p as addHours, H as Hourglass, G as Gauge, M as MessageSquare, C as Clock, Z as Zap, D as DollarSign, R as React, q as Markdown$1, t as rehypeHighlight, u as remarkGfm, T as Terminal, J as JsonView, v as vscodeTheme, w as tippy, x as reactDomExports, y as sn, X as Xt, z as Zt, A as tn, B as delegate, E as clientExports } from "./vendors-D6iOvAG3.js";
1
+ import { r as reactExports, j as jsxRuntimeExports, f as format, s as startOfWeek, a as startOfMonth, b as startOfDay, e as endOfWeek, c as endOfMonth, d as endOfDay, g as addWeeks, h as addMonths, i as addDays, k as isSameWeek, l as isSameMonth, m as isSameDay, n as intervalToDuration, o as getDaysInMonth, p as addHours, q as encode, H as Hourglass, G as Gauge, M as MessageSquare, C as Clock, Z as Zap, D as DollarSign, R as React, t as Markdown$1, u as rehypeHighlight, v as remarkGfm, T as Terminal, J as JsonView, w as vscodeTheme, x as tippy, y as reactDomExports, z as sn, X as Xt, A as Zt, B as tn, E as parse, F as delegate, I as clientExports } from "./vendors-S1fS5xz9.js";
2
2
  const SOURCE_COLORS = {
3
3
  scheduled: "#14b8a6",
4
4
  cli: "#3b82f6",
@@ -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.0") {
38
- const [MAJOR, MINOR, PATCH] = "1.9.0".split(".");
37
+ if (version !== "1.9.1") {
38
+ const [MAJOR, MINOR, PATCH] = "1.9.1".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.0");
43
+ localStorage.setItem(VERSION_KEY, "1.9.1");
44
44
  }
45
45
  }
46
46
  function useMouseFontScale(storageKey) {
@@ -721,8 +721,8 @@ function tone(value, { warn, danger }) {
721
721
  function fmtCompact(n) {
722
722
  if (n == null) return "—";
723
723
  if (n < 0) return `-${fmtCompact(-n)}`;
724
- if (n < 1e3) return `${n}`;
725
- if (n < 1e6) return `${+(n / 1e3).toFixed(1)}k`;
724
+ if (n < 100) return `${n}`;
725
+ if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
726
726
  return `${(n / 1e6).toFixed(1)}M`;
727
727
  }
728
728
  const BAR_MAX_PX = 52;
@@ -872,10 +872,34 @@ function PeriodSummary({ sessions, dayAnchor, granularity = "day" }) {
872
872
  ] })
873
873
  ] });
874
874
  }
875
+ const countTokens = (text, model = "") => {
876
+ if (!text) return 0;
877
+ const LEGACY_CLAUDE = /-(3|4)(-|$)/;
878
+ const scale = LEGACY_CLAUDE.test(model) ? 1.13 : 1.5;
879
+ return Math.round(encode(text).length * scale);
880
+ };
881
+ const queuedPrompt = (it) => it.type === "attachment" && it.attachment?.type === "queued_command" && it.attachment.commandMode === "prompt" && (it.attachment.origin?.kind ?? "human") === "human" && it.attachment.prompt?.trim() ? it.attachment.prompt : null;
875
882
  function flatten(items, instructions = []) {
876
883
  const turns = [];
877
884
  const results = {};
878
885
  for (const it of items) {
886
+ const queued = queuedPrompt(it);
887
+ if (queued) {
888
+ turns.push({
889
+ uuid: it.uuid,
890
+ role: "user",
891
+ isMeta: false,
892
+ queued: true,
893
+ ts: it.timestamp ? Date.parse(it.timestamp) : null,
894
+ model: null,
895
+ msgId: null,
896
+ usage: null,
897
+ tokenDelta: it._tokenDelta ?? null,
898
+ tokenTotal: it._tokenTotal ?? null,
899
+ blocks: [{ type: "text", text: queued }]
900
+ });
901
+ continue;
902
+ }
879
903
  if (it.type === "attachment" && it.attachment) {
880
904
  const block = { type: "attachment", attachment: it.attachment };
881
905
  const last = turns[turns.length - 1];
@@ -1027,7 +1051,9 @@ function groupTurns(turns) {
1027
1051
  else pending.push(t);
1028
1052
  } else if (t.role === "instruction") {
1029
1053
  flush();
1030
- groups.push({ kind: "instruction", turn: t });
1054
+ const prev = groups.at(-1);
1055
+ if (prev?.kind === "instruction" && prev.turns.at(-1).ts === t.ts) prev.turns.push(t);
1056
+ else groups.push({ kind: "instruction", turns: [t] });
1031
1057
  } else if (t.role === "user") {
1032
1058
  flush();
1033
1059
  groups.push({ kind: "user", turns: [...pending, t] });
@@ -1045,7 +1071,7 @@ function groupTurns(turns) {
1045
1071
  function cycleDurations(groups) {
1046
1072
  let prevEnd = null;
1047
1073
  return groups.map((g) => {
1048
- const tss = (g.turns ?? [g.turn]).map((t) => t.ts).filter((ts) => ts != null);
1074
+ const tss = g.turns.map((t) => t.ts).filter((ts) => ts != null);
1049
1075
  const end = tss.length ? tss[tss.length - 1] : null;
1050
1076
  const duration2 = g.kind === "assistant" && end != null && prevEnd != null ? end - prevEnd : null;
1051
1077
  if (end != null) prevEnd = end;
@@ -1055,7 +1081,7 @@ function cycleDurations(groups) {
1055
1081
  function tokenPoints(groups) {
1056
1082
  let prev = 0;
1057
1083
  return groups.map((g) => {
1058
- const turns = g.turns ?? [g.turn];
1084
+ const turns = g.turns;
1059
1085
  let total = null, ctx = null;
1060
1086
  const byMsg = /* @__PURE__ */ new Map();
1061
1087
  for (const t of turns) {
@@ -1076,7 +1102,7 @@ function tokenPoints(groups) {
1076
1102
  usage.cacheCreation5m += u.cache_creation?.ephemeral_5m_input_tokens || 0;
1077
1103
  usage.cacheCreation1h += u.cache_creation?.ephemeral_1h_input_tokens || 0;
1078
1104
  }
1079
- if (total == null || total === prev) return null;
1105
+ if (total == null || total <= prev) return null;
1080
1106
  const delta = total - prev;
1081
1107
  prev = total;
1082
1108
  if (ctx == null && g.kind !== "assistant") ctx = delta;
@@ -1090,7 +1116,7 @@ const TIPS = {
1090
1116
  messages: `Consider sessions below ${fmtCompact(THRESHOLDS.messages.warn)} messages`,
1091
1117
  time: `Consider sessions under ${THRESHOLDS.workTime.warn / 6e4}m`
1092
1118
  };
1093
- function SessionList({ sessions, selectedId, onSelect }) {
1119
+ function SessionList({ sessions, selectedId, deepLink, onSelect }) {
1094
1120
  const selectedRef = reactExports.useRef(null);
1095
1121
  const [sortBy, setSortBy] = useLocalStorage("session-list.sort", "time");
1096
1122
  const [filter, setFilter] = reactExports.useState("");
@@ -1165,12 +1191,15 @@ function SessionList({ sessions, selectedId, onSelect }) {
1165
1191
  const isSubagent = s.sessionId.startsWith("agent-");
1166
1192
  const journal = isJournal(s);
1167
1193
  const isFork = !!s.forkedFrom;
1194
+ const linked = deepLink?.id === s.sessionId;
1195
+ const linkTip = linked && `Opened from deep link
1196
+ claude-discover://session?id=${deepLink.id}${deepLink.date ? `&date=${deepLink.date}` : ""}`;
1168
1197
  const sessionName = s.customTitle && s.agentName && s.customTitle !== s.agentName ? `${s.customTitle} [${s.agentName}]` : s.customTitle || s.agentName || "";
1169
1198
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1170
1199
  "div",
1171
1200
  {
1172
1201
  ref: selectedId === s.sessionId ? selectedRef : null,
1173
- className: `session-row ${selectedId === s.sessionId ? "selected" : ""} ${isChild ? "is-subagent-child" : ""}`,
1202
+ className: `session-row ${selectedId === s.sessionId ? "selected" : ""} ${isChild ? "is-subagent-child" : ""} ${linked ? "deep-linked" : ""}`,
1174
1203
  onClick: () => onSelect(selectedId === s.sessionId ? null : s.sessionId),
1175
1204
  style: { borderLeftColor: SOURCE_COLORS[s.source] || SOURCE_COLORS.other },
1176
1205
  children: [
@@ -1214,7 +1243,8 @@ ${TIPS.time}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { size: 11
1214
1243
  s.models?.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "session-model", children: [
1215
1244
  ", ",
1216
1245
  s.models.map((m) => m.replace(/^claude-/, "")).join(", ")
1217
- ] })
1246
+ ] }),
1247
+ linked && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "deeplink-note", "data-tippy-content": linkTip, "data-tippy-maxWidth": 560, children: ", opened from deep link" })
1218
1248
  ] })
1219
1249
  ] }),
1220
1250
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-row-stats", children: [
@@ -1383,9 +1413,9 @@ function ConversationView({ items, instructions = [], expandAll = null }) {
1383
1413
  const [scale, zoomRef] = useMouseFontScale("font-scale.conversation");
1384
1414
  const hasTimeline = points.some(Boolean);
1385
1415
  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: [
1386
- /* @__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(InstructionFile, { it: g.turn.blocks[0].it, model: currentModel(turns) }) }),
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) }) }),
1387
1417
  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 } })
1388
- ] }, g.kind === "instruction" ? g.turn.uuid : g.turns[0].uuid)) }) });
1418
+ ] }, g.turns[0].uuid)) }) });
1389
1419
  }
1390
1420
  const ClaudeIcon = () => /* @__PURE__ */ jsxRuntimeExports.jsx("img", { className: "msg-icon claude-icon", src: claudeIcon, alt: "" });
1391
1421
  const CTX_LIMIT = THRESHOLDS.context.danger;
@@ -1423,6 +1453,7 @@ function UserRow({ turns, point }) {
1423
1453
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "msg-header", children: [
1424
1454
  /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { className: "msg-icon" }),
1425
1455
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "msg-author", children: "You" }),
1456
+ msg.queued && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "msg-summary", children: "queued during the previous turn" }),
1426
1457
  ctxItems.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "msg-summary", onClick: () => setOpen((v) => !v), children: [
1427
1458
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "aux-chevron", children: open ? "▾" : "▸" }),
1428
1459
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
@@ -1558,11 +1589,43 @@ const ATTACHMENT_RENDERERS = {
1558
1589
  title: `${a.addedNames?.length || 0} deferred tools ${a.removedNames?.length ? `(removed: ${a.removedNames.length})` : ""}`,
1559
1590
  body: safeJson({ added: a.addedNames, removed: a.removedNames }),
1560
1591
  defaultOpen: false
1592
+ }),
1593
+ // The one nested shape the fallback below can't flatten: files → diagnostics → range.
1594
+ diagnostics: (a) => {
1595
+ const lines = (a.files || []).flatMap((f) => (f.diagnostics || []).map((d) => `${f.uri}:${(d.range?.start?.line ?? 0) + 1} ${d.severity}: ${d.message}${d.source ? ` (${d.source})` : ""}`));
1596
+ return { title: `Diagnostics: ${lines.length} in ${a.files?.length || 0} file${a.files?.length === 1 ? "" : "s"}`, body: lines.join("\n") };
1597
+ },
1598
+ // addedLines carry each agent's one-line description; addedTypes is just their names.
1599
+ agent_listing_delta: (a) => ({
1600
+ title: `${a.addedTypes?.length || 0} agent types${a.removedTypes?.length ? ` (removed: ${a.removedTypes.length})` : ""}`,
1601
+ body: (a.addedLines || a.addedTypes || []).join("\n"),
1602
+ defaultOpen: false
1561
1603
  })
1562
1604
  };
1605
+ function genericAttachment(att) {
1606
+ const short = [], long = [];
1607
+ const collect = (v, key) => {
1608
+ if (typeof v === "string") {
1609
+ if (v.trim()) (v.length > 100 ? long : short).push([key, v]);
1610
+ } else if (Array.isArray(v)) {
1611
+ for (const x of v) collect(x, key);
1612
+ } else if (v && typeof v === "object") {
1613
+ for (const [k, x] of Object.entries(v)) collect(x, k);
1614
+ }
1615
+ };
1616
+ for (const [k, v] of Object.entries(att || {})) {
1617
+ if (k !== "type") collect(v, k);
1618
+ }
1619
+ const detail = short.find(([k]) => /path|file|name|dir|uri|url|date/i.test(k))?.[1];
1620
+ const label = (att?.type || "attachment").replace(/_/g, " ").replace(/^./, (c) => c.toUpperCase());
1621
+ return {
1622
+ title: detail ? `${label}: ${detail}` : label,
1623
+ body: long.length ? long.map(([, v]) => v).join("\n\n") : short.length > 1 ? safeJson(att) : null
1624
+ };
1625
+ }
1563
1626
  function Attachment({ att }) {
1564
1627
  const render = ATTACHMENT_RENDERERS[att?.type];
1565
- const { title, body, defaultOpen = false } = render ? render(att) : { title: `Attachment: ${att?.type || "unknown"}`, body: safeJson(att) };
1628
+ const { title, body, defaultOpen = false } = render ? render(att) : genericAttachment(att);
1566
1629
  if (body == null) return /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { title, className: "attachment" });
1567
1630
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Collapsible, { title, className: "attachment", defaultOpen, children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { children: body }) });
1568
1631
  }
@@ -1592,12 +1655,26 @@ function safeJson(x) {
1592
1655
  function JsonBlock({ value }) {
1593
1656
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { className: "block-text", text: "```json\n" + safeJson(value) + "\n```" });
1594
1657
  }
1595
- function InstructionFile({ it, model }) {
1658
+ function InstructionRun({ turns, model }) {
1659
+ const tokens2 = turns.map((t) => countTokens(t.blocks[0].it.content, t.blocks[0].it.model ?? model));
1660
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1661
+ turns.map((t, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(InstructionFile, { it: t.blocks[0].it, model, tokens: tokens2[i] }, t.uuid)),
1662
+ turns.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "aux instruction-total", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "instruction-tokens", children: [
1663
+ "~ ",
1664
+ fmtCompact(tokens2.reduce((a, b) => a + b, 0))
1665
+ ] }) })
1666
+ ] });
1667
+ }
1668
+ function InstructionFile({ it, model, tokens: tokens2 }) {
1596
1669
  const [open, setOpen] = useCollapsed(false);
1597
1670
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "aux instruction-file", children: [
1598
1671
  /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "aux-toggle", onClick: () => setOpen((v) => !v), children: [
1599
1672
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "aux-chevron", children: open ? "▾" : "▸" }),
1600
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: instructionTitle(it, model) })
1673
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: instructionTitle(it, model) }),
1674
+ tokens2 > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "instruction-tokens", title: "Approx. tokens", children: [
1675
+ "~ ",
1676
+ fmtCompact(tokens2)
1677
+ ] })
1601
1678
  ] }),
1602
1679
  open && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "aux-body", children: [
1603
1680
  it.name && it.name !== it.file_path && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "instruction-path", children: it.file_path }),
@@ -1880,7 +1957,7 @@ function renderTurn(t) {
1880
1957
  if (t.role === "instruction") return `**Instructions loaded:**
1881
1958
 
1882
1959
  ${t.blocks.map(renderBlock).join("\n\n")}`;
1883
- const role = t.role === "user" ? "User" : `Assistant`;
1960
+ const role = t.role === "user" ? t.queued ? "User (queued)" : "User" : `Assistant`;
1884
1961
  const tokens2 = t.tokenTotal > 0 && t.tokenDelta != null ? ` (${t.tokenDelta >= 0 ? "+" : ""}${fmtCompact(t.tokenDelta)} / ${fmtCompact(t.tokenTotal)} tokens)` : "";
1885
1962
  return `**${role}${tokens2}:**
1886
1963
 
@@ -2261,7 +2338,7 @@ const TABS = [
2261
2338
  { key: "jsonl", label: "Raw Logs" },
2262
2339
  { key: "requests", label: "API Requests" }
2263
2340
  ];
2264
- function Session({ meta, date, granularity = "day" }) {
2341
+ function Session({ meta, missing, date, granularity = "day" }) {
2265
2342
  const [items, setItems] = reactExports.useState(null);
2266
2343
  const [instructions, setInstructions] = reactExports.useState([]);
2267
2344
  const [mode, setMode] = useLocalStorage("session.view-mode", "conversation");
@@ -2287,7 +2364,10 @@ function Session({ meta, date, granularity = "day" }) {
2287
2364
  };
2288
2365
  }, [sessionId, date, granularity, fileSize]);
2289
2366
  if (!meta) {
2290
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "session-view empty", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Select a session to inspect." }) });
2367
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "session-view empty", children: missing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "session-missing", children: [
2368
+ "⚠ ",
2369
+ missing
2370
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Select a session to inspect." }) });
2291
2371
  }
2292
2372
  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: [
2293
2373
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "view-tab-pane-main", children: [
@@ -2471,6 +2551,7 @@ function App() {
2471
2551
  const [granularity, setGranularity] = useLocalStorage("gantt.granularity", "day");
2472
2552
  const [anchor, setAnchor] = reactExports.useState(() => startOfPeriod(Date.now(), granularity));
2473
2553
  const [selectedId, setSelectedId] = reactExports.useState(null);
2554
+ const [deepLink, setDeepLink] = reactExports.useState(null);
2474
2555
  const [sourceFilter, setSourceFilter] = reactExports.useState(null);
2475
2556
  const [projectFilter, setProjectFilter] = reactExports.useState(null);
2476
2557
  const { defaultLayout, onLayoutChanged } = sn({ id: "app.body", panelIds: ["list", "detail"], storage: localStorage });
@@ -2493,7 +2574,7 @@ function App() {
2493
2574
  setLoading(false);
2494
2575
  }
2495
2576
  });
2496
- }, 120);
2577
+ }, loading ? 0 : 120);
2497
2578
  const off = window.api.onSessionsUpdate((s) => {
2498
2579
  if (!cancelled) setSessions(s || []);
2499
2580
  });
@@ -2514,10 +2595,31 @@ function App() {
2514
2595
  () => sessions.find((s) => s.sessionId === selectedId) || null,
2515
2596
  [sessions, selectedId]
2516
2597
  );
2517
- const selectSession = reactExports.useCallback((id) => {
2598
+ let missing = null;
2599
+ if (!selected && scanProgress?.scanning === false) {
2600
+ 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}.`;
2603
+ }
2604
+ const selectSession = reactExports.useCallback((id, link = null) => {
2518
2605
  closeFind();
2519
2606
  setSelectedId(id);
2607
+ setDeepLink(link);
2520
2608
  }, []);
2609
+ reactExports.useEffect(() => {
2610
+ const open = ({ id, date }) => {
2611
+ const day = date && parse(date, "yyyy-MM-dd", /* @__PURE__ */ new Date());
2612
+ if (day && !isNaN(day)) {
2613
+ setGranularity("day");
2614
+ setAnchor(startOfPeriod(day, "day"));
2615
+ setSourceFilter(null);
2616
+ setProjectFilter(null);
2617
+ }
2618
+ selectSession(id, { id, date });
2619
+ };
2620
+ window.api.takeDeepLink().then((target) => target && open(target));
2621
+ return window.api.onDeepLink(open);
2622
+ }, [selectSession, setGranularity]);
2521
2623
  const shiftPeriod = reactExports.useCallback((delta) => {
2522
2624
  setProjectFilter(null);
2523
2625
  setAnchor((a) => startOfPeriod(addPeriod(a, granularity, delta), granularity));
@@ -2587,11 +2689,12 @@ function App() {
2587
2689
  {
2588
2690
  sessions: dayItems.past,
2589
2691
  selectedId,
2692
+ deepLink,
2590
2693
  onSelect: selectSession
2591
2694
  }
2592
2695
  ) }),
2593
2696
  /* @__PURE__ */ jsxRuntimeExports.jsx(tn, { className: "resize-handle resize-handle-v" }),
2594
- /* @__PURE__ */ jsxRuntimeExports.jsx(Zt, { id: "detail", minSize: 30, className: "body-pane", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Session, { meta: selected, date: format(anchor, "yyyy-MM-dd"), granularity }) })
2697
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Zt, { id: "detail", minSize: 30, className: "body-pane", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Session, { meta: selected, missing, date: format(anchor, "yyyy-MM-dd"), granularity }) })
2595
2698
  ]
2596
2699
  }
2597
2700
  ) })