research-copilot 0.1.3 → 0.2.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.
Files changed (67) hide show
  1. package/app/out/main/index.mjs +1281 -282
  2. package/app/out/preload/index.js +5 -0
  3. package/app/out/renderer/assets/{MilkdownMarkdownEditor-CCiFOpuq.js → MilkdownMarkdownEditor-D7GYpVZn.js} +50 -50
  4. package/app/out/renderer/assets/{arc-BR5G9xaE.js → arc-Kp4J_Jd7.js} +1 -1
  5. package/app/out/renderer/assets/{blockDiagram-c4efeb88-JmvDTsGU.js → blockDiagram-c4efeb88-DkMSdn8j.js} +8 -8
  6. package/app/out/renderer/assets/{c4Diagram-c83219d4-Daf_3gE1.js → c4Diagram-c83219d4-DqAGxrYw.js} +3 -3
  7. package/app/out/renderer/assets/{channel-xtutyETs.js → channel-S4GQrISQ.js} +1 -1
  8. package/app/out/renderer/assets/{classDiagram-beda092f-BFWEqrCW.js → classDiagram-beda092f-B7AsTCEg.js} +6 -6
  9. package/app/out/renderer/assets/{classDiagram-v2-2358418a-BQw7RI0A.js → classDiagram-v2-2358418a-B4oFy-In.js} +10 -10
  10. package/app/out/renderer/assets/{clone-uoV60hcB.js → clone-Dv1e6zYr.js} +1 -1
  11. package/app/out/renderer/assets/{createText-1719965b-BaRII2sm.js → createText-1719965b-HBXHvWlI.js} +2 -2
  12. package/app/out/renderer/assets/{edges-96097737-CL7Yc4hz.js → edges-96097737-B6X5lcC0.js} +3 -3
  13. package/app/out/renderer/assets/{erDiagram-0228fc6a-B9hgyxu6.js → erDiagram-0228fc6a-BmBmTBlH.js} +5 -5
  14. package/app/out/renderer/assets/{flowDb-c6c81e3f-b_RS-jIJ.js → flowDb-c6c81e3f-CObz36ob.js} +1 -1
  15. package/app/out/renderer/assets/{flowDiagram-50d868cf-CPB3IueC.js → flowDiagram-50d868cf-C2hFHxwF.js} +12 -12
  16. package/app/out/renderer/assets/{flowDiagram-v2-4f6560a1-DM8cFvdZ.js → flowDiagram-v2-4f6560a1-DEe8EygW.js} +12 -12
  17. package/app/out/renderer/assets/{flowchart-elk-definition-6af322e1-BsxABHy9.js → flowchart-elk-definition-6af322e1-CgTtfYKk.js} +6 -6
  18. package/app/out/renderer/assets/{ganttDiagram-a2739b55-DpMib95K.js → ganttDiagram-a2739b55-C5Pq4zEy.js} +3 -3
  19. package/app/out/renderer/assets/{gitGraphDiagram-82fe8481-C0OtwErh.js → gitGraphDiagram-82fe8481-oLp0f8Ll.js} +2 -2
  20. package/app/out/renderer/assets/{graph-CXef_RHM.js → graph-51iZ6wgR.js} +1 -1
  21. package/app/out/renderer/assets/{index-Bg4LHaeu.js → index-32eUzqVW.js} +3 -3
  22. package/app/out/renderer/assets/{index-5325376f-0FtzFTBH.js → index-5325376f-yLvOW-Os.js} +6 -6
  23. package/app/out/renderer/assets/{index-tz7ZKjP9.js → index-AuZa-hTj.js} +3 -3
  24. package/app/out/renderer/assets/{index-uZnv8lTU.js → index-B9a4DKM-.js} +3 -3
  25. package/app/out/renderer/assets/{index-CabfPYgf.js → index-BMsuFGn6.js} +3 -3
  26. package/app/out/renderer/assets/{index-CFaiDIr7.js → index-BQA_Kvr6.js} +3 -3
  27. package/app/out/renderer/assets/{index-D9-3cc7l.js → index-BSd80-j9.js} +4 -4
  28. package/app/out/renderer/assets/{index-C1Hf3CJw.js → index-BfWWn8B_.js} +6 -6
  29. package/app/out/renderer/assets/{index-CTF1A-5m.js → index-Bscx_5dF.js} +3 -3
  30. package/app/out/renderer/assets/{index-BBH0Chbw.js → index-CAOQIqEc.js} +6 -6
  31. package/app/out/renderer/assets/{index-Cx3Vwh3q.js → index-CTmGCKqa.js} +4 -4
  32. package/app/out/renderer/assets/{index-DRyElXV-.js → index-CmpSV9Ld.js} +5 -5
  33. package/app/out/renderer/assets/{index-BohTbJeP.js → index-Cn2e13ja.js} +6 -6
  34. package/app/out/renderer/assets/{index-BE4XBnng.js → index-D_Y7v6pE.js} +3 -3
  35. package/app/out/renderer/assets/{index-vGIhunyU.js → index-DjqJjt6u.js} +6 -6
  36. package/app/out/renderer/assets/{index-Crf9Pipm.js → index-DppxBL77.js} +3 -3
  37. package/app/out/renderer/assets/{index-C_cgOzmt.js → index-Du-Z3sl4.js} +952 -90
  38. package/app/out/renderer/assets/{index-CMDsy41q.js → index-FGsCVYSr.js} +1 -1
  39. package/app/out/renderer/assets/{index-C-_uCjZJ.css → index-L4DJn7cw.css} +14 -18
  40. package/app/out/renderer/assets/{index-DuAPj57k.js → index-UajPJYNV.js} +3 -3
  41. package/app/out/renderer/assets/{index-DeVfJmHc.js → index-_Z53hJps.js} +3 -3
  42. package/app/out/renderer/assets/{index-BHo8axTp.js → index-_iFRQTkA.js} +6 -6
  43. package/app/out/renderer/assets/{index-CKjCQ1EB.js → index-ohN9yRWw.js} +6 -6
  44. package/app/out/renderer/assets/{index-Dy2bySYF.js → index-shoMWskw.js} +3 -3
  45. package/app/out/renderer/assets/{index-OqY0JVi2.js → index-y1Od1ed6.js} +3 -3
  46. package/app/out/renderer/assets/{infoDiagram-8eee0895-CPFVhSvg.js → infoDiagram-8eee0895-Cm0Hm5ZX.js} +2 -2
  47. package/app/out/renderer/assets/{journeyDiagram-c64418c1-PKaxJ2mn.js → journeyDiagram-c64418c1-A2Gw9bVu.js} +4 -4
  48. package/app/out/renderer/assets/{layout-CawlN23W.js → layout-C5N2nTfF.js} +2 -2
  49. package/app/out/renderer/assets/{line-C_cMMDTP.js → line-Dn6BEQAK.js} +1 -1
  50. package/app/out/renderer/assets/{linear-CnzgpVoT.js → linear-8wk0rPUX.js} +1 -1
  51. package/app/out/renderer/assets/{mindmap-definition-8da855dc-2dVBAm3g.js → mindmap-definition-8da855dc-BVy6ISnb.js} +3 -3
  52. package/app/out/renderer/assets/{pieDiagram-a8764435-p6hNN8aY.js → pieDiagram-a8764435-B9_axIHE.js} +3 -3
  53. package/app/out/renderer/assets/{quadrantDiagram-1e28029f-JJT_eOsi.js → quadrantDiagram-1e28029f-B1kmkDFg.js} +3 -3
  54. package/app/out/renderer/assets/{requirementDiagram-08caed73-Ck4auzva.js → requirementDiagram-08caed73-C_bNWUtT.js} +5 -5
  55. package/app/out/renderer/assets/{sankeyDiagram-a04cb91d-DICtg7Jw.js → sankeyDiagram-a04cb91d-CD2h1LiI.js} +2 -2
  56. package/app/out/renderer/assets/{sequenceDiagram-c5b8d532-Bv7njQoz.js → sequenceDiagram-c5b8d532-B6d6cuqi.js} +3 -3
  57. package/app/out/renderer/assets/{stateDiagram-1ecb1508-CmuiBQ0q.js → stateDiagram-1ecb1508-CkuNj_3H.js} +6 -6
  58. package/app/out/renderer/assets/{stateDiagram-v2-c2b004d7-DErEMYcv.js → stateDiagram-v2-c2b004d7-CevZ3tno.js} +10 -10
  59. package/app/out/renderer/assets/{styles-b4e223ce-CEjXkOYY.js → styles-b4e223ce-DAe5WQrg.js} +1 -1
  60. package/app/out/renderer/assets/{styles-ca3715f6-BJWKCKia.js → styles-ca3715f6-BDSX88bY.js} +1 -1
  61. package/app/out/renderer/assets/{styles-d45a18b0-BrhRky7i.js → styles-d45a18b0-SE9h7les.js} +4 -4
  62. package/app/out/renderer/assets/{svgDrawCommon-b86b1483-RWkoQoOd.js → svgDrawCommon-b86b1483-D1mpNbDQ.js} +1 -1
  63. package/app/out/renderer/assets/{timeline-definition-faaaa080-25xmyyis.js → timeline-definition-faaaa080-7Ha-nm4M.js} +3 -3
  64. package/app/out/renderer/assets/{xychartDiagram-f5964ef8-DwBkod9W.js → xychartDiagram-f5964ef8-DLy7iyZW.js} +5 -5
  65. package/app/out/renderer/index.html +2 -2
  66. package/app/package.json +1 -1
  67. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./MilkdownMarkdownEditor-CCiFOpuq.js","./MilkdownMarkdownEditor-tTNRIB2K.css"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./MilkdownMarkdownEditor-D7GYpVZn.js","./MilkdownMarkdownEditor-tTNRIB2K.css"])))=>i.map(i=>d[i]);
2
2
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
3
3
  function getDefaultExportFromCjs(x) {
4
4
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -12641,6 +12641,27 @@ const ChevronRight = createLucideIcon("ChevronRight", [
12641
12641
  * See the LICENSE file in the root directory of this source tree.
12642
12642
  */
12643
12643
  const ChevronUp = createLucideIcon("ChevronUp", [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]]);
12644
+ /**
12645
+ * @license lucide-react v0.469.0 - ISC
12646
+ *
12647
+ * This source code is licensed under the ISC license.
12648
+ * See the LICENSE file in the root directory of this source tree.
12649
+ */
12650
+ const CircleAlert = createLucideIcon("CircleAlert", [
12651
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
12652
+ ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
12653
+ ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
12654
+ ]);
12655
+ /**
12656
+ * @license lucide-react v0.469.0 - ISC
12657
+ *
12658
+ * This source code is licensed under the ISC license.
12659
+ * See the LICENSE file in the root directory of this source tree.
12660
+ */
12661
+ const CircleCheck = createLucideIcon("CircleCheck", [
12662
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
12663
+ ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
12664
+ ]);
12644
12665
  /**
12645
12666
  * @license lucide-react v0.469.0 - ISC
12646
12667
  *
@@ -12883,6 +12904,17 @@ const GitBranch = createLucideIcon("GitBranch", [
12883
12904
  ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
12884
12905
  ["path", { d: "M18 9a9 9 0 0 1-9 9", key: "n2h4wq" }]
12885
12906
  ]);
12907
+ /**
12908
+ * @license lucide-react v0.469.0 - ISC
12909
+ *
12910
+ * This source code is licensed under the ISC license.
12911
+ * See the LICENSE file in the root directory of this source tree.
12912
+ */
12913
+ const Globe = createLucideIcon("Globe", [
12914
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
12915
+ ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
12916
+ ["path", { d: "M2 12h20", key: "9i4pu4" }]
12917
+ ]);
12886
12918
  /**
12887
12919
  * @license lucide-react v0.469.0 - ISC
12888
12920
  *
@@ -13182,6 +13214,21 @@ const Upload = createLucideIcon("Upload", [
13182
13214
  ["polyline", { points: "17 8 12 3 7 8", key: "t8dd8p" }],
13183
13215
  ["line", { x1: "12", x2: "12", y1: "3", y2: "15", key: "widbto" }]
13184
13216
  ]);
13217
+ /**
13218
+ * @license lucide-react v0.469.0 - ISC
13219
+ *
13220
+ * This source code is licensed under the ISC license.
13221
+ * See the LICENSE file in the root directory of this source tree.
13222
+ */
13223
+ const Wrench = createLucideIcon("Wrench", [
13224
+ [
13225
+ "path",
13226
+ {
13227
+ d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z",
13228
+ key: "cbrjhi"
13229
+ }
13230
+ ]
13231
+ ]);
13185
13232
  /**
13186
13233
  * @license lucide-react v0.469.0 - ISC
13187
13234
  *
@@ -26215,6 +26262,65 @@ const __vitePreload = function preload2(baseModule, deps, importerUrl) {
26215
26262
  return baseModule().catch(handlePreloadError);
26216
26263
  });
26217
26264
  };
26265
+ function extractProgress(tool, data) {
26266
+ if (!data?.partialResult) return void 0;
26267
+ const text2 = data.partialResult?.content?.[0]?.text;
26268
+ if (typeof text2 === "string" && text2.length > 0) {
26269
+ const lines = text2.split("\n").filter(Boolean);
26270
+ const maxLines = tool === "bash" ? 5 : 3;
26271
+ return lines.slice(-maxLines).join("\n");
26272
+ }
26273
+ return void 0;
26274
+ }
26275
+ const useToolEventsStore = create$1((set, get) => ({
26276
+ currentRunEvents: [],
26277
+ onToolCall: (event) => {
26278
+ const toolCallId = event.toolCallId || `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
26279
+ const newEvent = {
26280
+ id: toolCallId,
26281
+ toolCallId,
26282
+ tool: event.tool,
26283
+ status: "running",
26284
+ summary: event.summary,
26285
+ detail: event.detail,
26286
+ startedAt: Date.now()
26287
+ };
26288
+ set((state) => ({
26289
+ currentRunEvents: [...state.currentRunEvents, newEvent]
26290
+ }));
26291
+ },
26292
+ onToolResult: (event) => {
26293
+ set((state) => {
26294
+ const events = [...state.currentRunEvents];
26295
+ const idx = event.toolCallId ? events.findLastIndex((e) => e.toolCallId === event.toolCallId && e.status === "running") : events.findLastIndex((e) => e.tool === event.tool && e.status === "running");
26296
+ if (idx !== -1) {
26297
+ events[idx] = {
26298
+ ...events[idx],
26299
+ status: event.success !== false ? "success" : "error",
26300
+ resultSummary: event.summary,
26301
+ resultDetail: event.resultDetail,
26302
+ durationMs: event.durationMs,
26303
+ completedAt: Date.now()
26304
+ };
26305
+ }
26306
+ return { currentRunEvents: events };
26307
+ });
26308
+ },
26309
+ onToolProgress: (event) => {
26310
+ if (event.phase === "end") return;
26311
+ set((state) => {
26312
+ const events = [...state.currentRunEvents];
26313
+ const idx = events.findLastIndex((e) => e.toolCallId === event.toolCallId);
26314
+ if (idx !== -1) {
26315
+ const progress = extractProgress(event.tool, event.data) ?? events[idx].progress;
26316
+ events[idx] = { ...events[idx], progress };
26317
+ }
26318
+ return { currentRunEvents: events };
26319
+ });
26320
+ },
26321
+ snapshot: () => [...get().currentRunEvents],
26322
+ clearRun: () => set({ currentRunEvents: [] })
26323
+ }));
26218
26324
  const PAGE_SIZE = 20;
26219
26325
  const api$8 = window.api;
26220
26326
  let _sessionId = "";
@@ -26223,6 +26329,9 @@ const useChatStore = create$1((set, get) => ({
26223
26329
  streamingText: "",
26224
26330
  isStreaming: false,
26225
26331
  savedMessageIds: /* @__PURE__ */ new Set(),
26332
+ turnToolEvents: /* @__PURE__ */ new Map(),
26333
+ draftText: "",
26334
+ setDraftText: (text2) => set({ draftText: text2 }),
26226
26335
  hasMore: false,
26227
26336
  isLoadingHistory: false,
26228
26337
  _offset: 0,
@@ -26274,11 +26383,20 @@ const useChatStore = create$1((set, get) => ({
26274
26383
  images: result.images?.map((i) => `data:${i.mimeType};base64,${i.base64}`),
26275
26384
  timestamp: Date.now()
26276
26385
  };
26277
- set((s15) => ({
26278
- messages: [...s15.messages, assistantMsg],
26279
- streamingText: "",
26280
- isStreaming: false
26281
- }));
26386
+ const toolEventsSnapshot = useToolEventsStore.getState().snapshot();
26387
+ useToolEventsStore.getState().clearRun();
26388
+ set((s15) => {
26389
+ const nextToolEvents = new Map(s15.turnToolEvents);
26390
+ if (toolEventsSnapshot.length > 0) {
26391
+ nextToolEvents.set(assistantMsg.id, toolEventsSnapshot);
26392
+ }
26393
+ return {
26394
+ messages: [...s15.messages, assistantMsg],
26395
+ streamingText: "",
26396
+ isStreaming: false,
26397
+ turnToolEvents: nextToolEvents
26398
+ };
26399
+ });
26282
26400
  if (_sessionId) {
26283
26401
  api$8.saveMessage(_sessionId, assistantMsg).catch(() => {
26284
26402
  });
@@ -26291,6 +26409,8 @@ const useChatStore = create$1((set, get) => ({
26291
26409
  streamingText: "",
26292
26410
  isStreaming: false,
26293
26411
  savedMessageIds: /* @__PURE__ */ new Set(),
26412
+ turnToolEvents: /* @__PURE__ */ new Map(),
26413
+ draftText: "",
26294
26414
  hasMore: false,
26295
26415
  isLoadingHistory: false,
26296
26416
  _offset: 0,
@@ -26377,16 +26497,19 @@ const useActivityStore = create$1((set) => ({
26377
26497
  push: (event) => set((state) => {
26378
26498
  if (event.tool && event.tool.startsWith("todo-")) return state;
26379
26499
  if (event.type === "tool-result") {
26380
- const idx = findLastIndex(state.events, (e) => e.type === "tool-call" && e.tool === event.tool);
26500
+ const idx = event.toolCallId ? findLastIndex(state.events, (e) => e.type === "tool-call" && e.toolCallId === event.toolCallId) : findLastIndex(state.events, (e) => e.type === "tool-call" && e.tool === event.tool);
26381
26501
  if (idx !== -1) {
26382
26502
  const updated = [...state.events];
26383
26503
  updated[idx] = {
26384
26504
  ...updated[idx],
26505
+ // preserve original detail (tool-call params)
26385
26506
  type: "tool-result",
26386
26507
  summary: event.summary,
26387
26508
  success: event.success,
26388
26509
  error: event.error,
26389
- timestamp: event.timestamp
26510
+ timestamp: event.timestamp,
26511
+ resultDetail: event.resultDetail,
26512
+ durationMs: event.durationMs
26390
26513
  };
26391
26514
  return { events: updated };
26392
26515
  }
@@ -26415,6 +26538,10 @@ async function loadFromFramework() {
26415
26538
  const useUsageStore = create$1((set, get) => {
26416
26539
  return {
26417
26540
  // Current run
26541
+ runPromptTokens: 0,
26542
+ runCompletionTokens: 0,
26543
+ runCachedTokens: 0,
26544
+ runCacheWriteTokens: 0,
26418
26545
  runTokens: 0,
26419
26546
  runCost: 0,
26420
26547
  runCacheHitRate: 0,
@@ -26426,37 +26553,54 @@ const useUsageStore = create$1((set, get) => {
26426
26553
  // All-time totals (from framework persistence)
26427
26554
  allTimeTokens: 0,
26428
26555
  allTimePromptTokens: 0,
26556
+ allTimeCompletionTokens: 0,
26429
26557
  allTimeCachedTokens: 0,
26558
+ allTimeCacheWriteTokens: 0,
26430
26559
  allTimeCost: 0,
26431
26560
  allTimeBillableCost: 0,
26432
26561
  allTimeCalls: 0,
26433
26562
  billingSource: "none",
26434
26563
  recordCall: (event) => set((state) => {
26435
- const newTokens = event.promptTokens + event.completionTokens;
26564
+ const callTokens = event.promptTokens + event.completionTokens + event.cachedTokens;
26565
+ const cacheWrite = event.cacheWriteTokens ?? 0;
26436
26566
  const billableCost = event.billableCost ?? event.cost;
26437
- const newState = {
26438
- runTokens: state.runTokens + newTokens,
26567
+ const newRunPrompt = state.runPromptTokens + event.promptTokens;
26568
+ const newRunCached = state.runCachedTokens + event.cachedTokens;
26569
+ const totalRunInput = newRunPrompt + newRunCached;
26570
+ const runCacheHitRate = totalRunInput > 0 ? newRunCached / totalRunInput : 0;
26571
+ return {
26572
+ runPromptTokens: newRunPrompt,
26573
+ runCompletionTokens: state.runCompletionTokens + event.completionTokens,
26574
+ runCachedTokens: newRunCached,
26575
+ runCacheWriteTokens: state.runCacheWriteTokens + cacheWrite,
26576
+ runTokens: state.runTokens + callTokens,
26439
26577
  runCost: state.runCost + event.cost,
26440
- runCacheHitRate: event.cacheHitRate,
26578
+ runCacheHitRate,
26441
26579
  runCallCount: state.runCallCount + 1,
26442
- // Also accumulate to session/all-time
26443
- sessionTokens: state.sessionTokens + newTokens,
26580
+ // Session
26581
+ sessionTokens: state.sessionTokens + callTokens,
26444
26582
  sessionCost: state.sessionCost + event.cost,
26445
26583
  sessionCalls: state.sessionCalls + 1,
26446
- allTimeTokens: state.allTimeTokens + newTokens,
26584
+ // All-time
26585
+ allTimeTokens: state.allTimeTokens + callTokens,
26447
26586
  allTimePromptTokens: state.allTimePromptTokens + event.promptTokens,
26587
+ allTimeCompletionTokens: state.allTimeCompletionTokens + event.completionTokens,
26448
26588
  allTimeCachedTokens: state.allTimeCachedTokens + event.cachedTokens,
26589
+ allTimeCacheWriteTokens: state.allTimeCacheWriteTokens + cacheWrite,
26449
26590
  allTimeCost: state.allTimeCost + event.cost,
26450
26591
  allTimeBillableCost: state.allTimeBillableCost + billableCost,
26451
26592
  allTimeCalls: state.allTimeCalls + 1,
26452
26593
  billingSource: event.billingSource ?? state.billingSource
26453
26594
  };
26454
- return newState;
26455
26595
  }),
26456
26596
  completeRun: (_summary) => {
26457
26597
  },
26458
26598
  // Reset run stats - called when a NEW run starts (not when old one ends)
26459
26599
  resetRun: () => set({
26600
+ runPromptTokens: 0,
26601
+ runCompletionTokens: 0,
26602
+ runCachedTokens: 0,
26603
+ runCacheWriteTokens: 0,
26460
26604
  runTokens: 0,
26461
26605
  runCost: 0,
26462
26606
  runCacheHitRate: 0,
@@ -26464,6 +26608,10 @@ const useUsageStore = create$1((set, get) => {
26464
26608
  }),
26465
26609
  // Reset session stats (but keep all-time)
26466
26610
  resetSession: () => set({
26611
+ runPromptTokens: 0,
26612
+ runCompletionTokens: 0,
26613
+ runCachedTokens: 0,
26614
+ runCacheWriteTokens: 0,
26467
26615
  runTokens: 0,
26468
26616
  runCost: 0,
26469
26617
  runCacheHitRate: 0,
@@ -26476,18 +26624,21 @@ const useUsageStore = create$1((set, get) => {
26476
26624
  loadPersisted: async () => {
26477
26625
  const persisted = await loadFromFramework();
26478
26626
  if (persisted?.totals) {
26627
+ const t = persisted.totals;
26479
26628
  set({
26480
- allTimeTokens: persisted.totals.tokens ?? 0,
26481
- allTimePromptTokens: persisted.totals.promptTokens ?? 0,
26482
- allTimeCachedTokens: persisted.totals.cachedTokens ?? 0,
26483
- allTimeCost: persisted.totals.cost ?? 0,
26484
- allTimeBillableCost: persisted.totals.cost ?? 0,
26485
- allTimeCalls: persisted.totals.calls ?? 0,
26629
+ allTimeTokens: t.tokens ?? 0,
26630
+ allTimePromptTokens: t.promptTokens ?? 0,
26631
+ allTimeCompletionTokens: t.completionTokens ?? 0,
26632
+ allTimeCachedTokens: t.cachedTokens ?? 0,
26633
+ allTimeCacheWriteTokens: t.cacheWriteTokens ?? 0,
26634
+ allTimeCost: t.cost ?? 0,
26635
+ allTimeBillableCost: t.cost ?? 0,
26636
+ allTimeCalls: t.calls ?? 0,
26486
26637
  billingSource: "api-key",
26487
26638
  // Also restore to session totals
26488
- sessionTokens: persisted.totals.tokens ?? 0,
26489
- sessionCost: persisted.totals.cost ?? 0,
26490
- sessionCalls: persisted.totals.calls ?? 0
26639
+ sessionTokens: t.tokens ?? 0,
26640
+ sessionCost: t.cost ?? 0,
26641
+ sessionCalls: t.calls ?? 0
26491
26642
  });
26492
26643
  }
26493
26644
  },
@@ -26496,6 +26647,10 @@ const useUsageStore = create$1((set, get) => {
26496
26647
  api$7?.resetUsageTotals?.().catch?.(() => {
26497
26648
  });
26498
26649
  set({
26650
+ runPromptTokens: 0,
26651
+ runCompletionTokens: 0,
26652
+ runCachedTokens: 0,
26653
+ runCacheWriteTokens: 0,
26499
26654
  runTokens: 0,
26500
26655
  runCost: 0,
26501
26656
  runCacheHitRate: 0,
@@ -26505,7 +26660,9 @@ const useUsageStore = create$1((set, get) => {
26505
26660
  sessionCalls: 0,
26506
26661
  allTimeTokens: 0,
26507
26662
  allTimePromptTokens: 0,
26663
+ allTimeCompletionTokens: 0,
26508
26664
  allTimeCachedTokens: 0,
26665
+ allTimeCacheWriteTokens: 0,
26509
26666
  allTimeCost: 0,
26510
26667
  allTimeBillableCost: 0,
26511
26668
  billingSource: "none",
@@ -28402,6 +28559,630 @@ function HeroIdle() {
28402
28559
  )) })
28403
28560
  ] });
28404
28561
  }
28562
+ function getFileName(path2) {
28563
+ if (!path2) return "";
28564
+ const parts = path2.replace(/\\/g, "/").split("/");
28565
+ return parts[parts.length - 1] || path2;
28566
+ }
28567
+ function truncStr(s15, max) {
28568
+ if (!s15) return "";
28569
+ return s15.length > max ? s15.slice(0, max - 3) + "..." : s15;
28570
+ }
28571
+ function safeRecord(obj) {
28572
+ return obj && typeof obj === "object" ? obj : {};
28573
+ }
28574
+ function extractResultText(result) {
28575
+ const r = safeRecord(result);
28576
+ const content2 = r.content;
28577
+ return content2?.[0]?.text || "";
28578
+ }
28579
+ function lastNLines$1(text2, n) {
28580
+ const lines = text2.split("\n").filter(Boolean);
28581
+ return lines.slice(-n).join("\n");
28582
+ }
28583
+ const configs = [
28584
+ // ── File tools ────────────────────────
28585
+ {
28586
+ name: "read",
28587
+ displayName: "Read",
28588
+ icon: "FileText",
28589
+ category: "file",
28590
+ formatCallSummary: (a) => {
28591
+ const path2 = a.path || "";
28592
+ const offset = a.offset;
28593
+ const limit = a.limit;
28594
+ const suffix2 = offset ? ` · lines ${offset}-${offset + (limit || 2e3)}` : "";
28595
+ return `${getFileName(path2)}${suffix2}`;
28596
+ },
28597
+ formatCallDetail: (a) => ({ path: a.path, offset: a.offset, limit: a.limit }),
28598
+ formatResultSummary: (result) => {
28599
+ const text2 = extractResultText(result);
28600
+ const lineCount = text2 ? text2.split("\n").length : 0;
28601
+ return lineCount ? `${lineCount} lines` : "Read completed";
28602
+ },
28603
+ formatResultDetail: (result) => {
28604
+ const text2 = extractResultText(result);
28605
+ return { lineCount: text2 ? text2.split("\n").length : 0 };
28606
+ }
28607
+ },
28608
+ {
28609
+ name: "write",
28610
+ displayName: "Write",
28611
+ icon: "FileText",
28612
+ category: "file",
28613
+ formatCallSummary: (a) => getFileName(a.path || ""),
28614
+ formatCallDetail: (a) => ({ path: a.path }),
28615
+ formatResultSummary: (_2, a) => `Written: ${getFileName(a?.path || "")}`,
28616
+ formatResultDetail: (_2, a) => ({ path: a?.path })
28617
+ },
28618
+ {
28619
+ name: "edit",
28620
+ displayName: "Edit",
28621
+ icon: "FileText",
28622
+ category: "file",
28623
+ formatCallSummary: (a) => getFileName(a.path || ""),
28624
+ formatCallDetail: (a) => ({ path: a.path }),
28625
+ formatResultSummary: (_2, a) => `Edited: ${getFileName(a?.path || "")}`,
28626
+ formatResultDetail: (_2, a) => ({ path: a?.path })
28627
+ },
28628
+ // ── Code tools ────────────────────────
28629
+ {
28630
+ name: "bash",
28631
+ displayName: "Bash",
28632
+ icon: "Terminal",
28633
+ category: "code",
28634
+ formatCallSummary: (a) => {
28635
+ const cmd = a.command || "";
28636
+ return cmd.length > 60 ? `$ ${cmd.slice(0, 57)}...` : `$ ${cmd}`;
28637
+ },
28638
+ formatCallDetail: (a) => ({ command: truncStr(a.command, 200) }),
28639
+ formatResultSummary: () => "Command completed",
28640
+ formatResultDetail: (result) => {
28641
+ const text2 = extractResultText(result);
28642
+ const lines = text2.split("\n").filter(Boolean);
28643
+ return { outputLines: lines.length, outputPreview: truncStr(lastNLines$1(text2, 3), 200) };
28644
+ },
28645
+ formatProgress: (partial) => {
28646
+ const text2 = partial?.content?.[0]?.text;
28647
+ if (typeof text2 === "string" && text2.length > 0) {
28648
+ return lastNLines$1(text2, 5);
28649
+ }
28650
+ return void 0;
28651
+ }
28652
+ },
28653
+ // ── Search tools ────────────────────────
28654
+ {
28655
+ name: "grep",
28656
+ displayName: "Search",
28657
+ icon: "Search",
28658
+ category: "search",
28659
+ formatCallSummary: (a) => `"${truncStr(a.pattern, 30)}"${a.path ? ` in ${a.path}` : ""}`,
28660
+ formatCallDetail: (a) => ({ pattern: a.pattern, path: a.path, glob: a.glob }),
28661
+ formatResultSummary: (result) => {
28662
+ const text2 = extractResultText(result);
28663
+ const count = text2.split("\n").filter(Boolean).length;
28664
+ return `${count} results`;
28665
+ },
28666
+ formatResultDetail: (result) => {
28667
+ const text2 = extractResultText(result);
28668
+ return { matchCount: text2.split("\n").filter(Boolean).length };
28669
+ }
28670
+ },
28671
+ {
28672
+ name: "glob",
28673
+ displayName: "Find Files",
28674
+ icon: "Search",
28675
+ category: "search",
28676
+ formatCallSummary: (a) => a.pattern || "",
28677
+ formatCallDetail: (a) => ({ pattern: a.pattern, path: a.path }),
28678
+ formatResultSummary: (result) => {
28679
+ const text2 = extractResultText(result);
28680
+ const count = text2.split("\n").filter(Boolean).length;
28681
+ return `${count} files`;
28682
+ },
28683
+ formatResultDetail: (result) => {
28684
+ const text2 = extractResultText(result);
28685
+ return { fileCount: text2.split("\n").filter(Boolean).length };
28686
+ }
28687
+ },
28688
+ {
28689
+ name: "find",
28690
+ displayName: "Find",
28691
+ icon: "Search",
28692
+ category: "search",
28693
+ formatCallSummary: (a) => truncStr(a.pattern || a.path, 40),
28694
+ formatCallDetail: (a) => ({ pattern: a.pattern, path: a.path }),
28695
+ formatResultSummary: () => "Find completed",
28696
+ formatResultDetail: () => ({})
28697
+ },
28698
+ {
28699
+ name: "ls",
28700
+ displayName: "List",
28701
+ icon: "FileText",
28702
+ category: "file",
28703
+ formatCallSummary: (a) => a.path || ".",
28704
+ formatCallDetail: (a) => ({ path: a.path }),
28705
+ formatResultSummary: () => "Listed",
28706
+ formatResultDetail: () => ({})
28707
+ },
28708
+ // ── Web tools ────────────────────────
28709
+ {
28710
+ name: "fetch",
28711
+ displayName: "Fetch",
28712
+ icon: "Globe",
28713
+ category: "web",
28714
+ formatCallSummary: (a) => truncStr(a.url, 50),
28715
+ formatCallDetail: (a) => ({ url: a.url }),
28716
+ formatResultSummary: (result) => {
28717
+ const text2 = extractResultText(result);
28718
+ const kb = (text2.length / 1024).toFixed(1);
28719
+ return `${kb}KB received`;
28720
+ },
28721
+ formatResultDetail: (result) => {
28722
+ const text2 = extractResultText(result);
28723
+ return { sizeKB: parseFloat((text2.length / 1024).toFixed(1)) };
28724
+ }
28725
+ },
28726
+ {
28727
+ name: "web_fetch",
28728
+ displayName: "Web Fetch",
28729
+ icon: "Globe",
28730
+ category: "web",
28731
+ formatCallSummary: (a) => truncStr(a.url, 50),
28732
+ formatCallDetail: (a) => ({ url: a.url }),
28733
+ formatResultSummary: (result) => {
28734
+ const r = safeRecord(result);
28735
+ const data = safeRecord(r.data);
28736
+ const charCount = data.charCount;
28737
+ if (charCount) return `${(charCount / 1024).toFixed(1)}KB received`;
28738
+ return "Fetch completed";
28739
+ },
28740
+ formatResultDetail: (result) => {
28741
+ const r = safeRecord(result);
28742
+ const data = safeRecord(r.data);
28743
+ return { charCount: data.charCount, url: data.url };
28744
+ }
28745
+ },
28746
+ {
28747
+ name: "web_search",
28748
+ displayName: "Web Search",
28749
+ icon: "Globe",
28750
+ category: "web",
28751
+ formatCallSummary: (a) => truncStr(a.query, 50),
28752
+ formatCallDetail: (a) => ({ query: a.query }),
28753
+ formatResultSummary: () => "Search completed",
28754
+ formatResultDetail: () => ({})
28755
+ },
28756
+ // ── Research tools ────────────────────────
28757
+ {
28758
+ name: "literature-search",
28759
+ displayName: "Literature Search",
28760
+ icon: "BookOpen",
28761
+ category: "research",
28762
+ formatCallSummary: (a) => truncStr(a.query, 40),
28763
+ formatCallDetail: (a) => ({ query: a.query, maxResults: a.max_results }),
28764
+ formatResultSummary: (result) => {
28765
+ const r = safeRecord(result);
28766
+ const data = safeRecord(r.data);
28767
+ const totalFound = data.totalPapersFound ?? 0;
28768
+ const saved = data.papersAutoSaved ?? 0;
28769
+ const coverage = data.coverage;
28770
+ if (totalFound > 0) {
28771
+ let s15 = `Found ${totalFound} papers`;
28772
+ if (coverage?.score != null) s15 += ` (${Math.round(coverage.score * 100)}%)`;
28773
+ if (saved > 0) s15 += `, saved ${saved}`;
28774
+ return s15;
28775
+ }
28776
+ const local = data.localPapersUsed ?? 0;
28777
+ const external = data.externalPapersUsed ?? 0;
28778
+ return `Found ${local + external} papers`;
28779
+ },
28780
+ formatResultDetail: (result) => {
28781
+ const r = safeRecord(result);
28782
+ const data = safeRecord(r.data);
28783
+ return {
28784
+ papersFound: data.totalPapersFound ?? 0,
28785
+ papersSaved: data.papersAutoSaved ?? 0,
28786
+ coverage: data.coverage?.score
28787
+ };
28788
+ }
28789
+ },
28790
+ {
28791
+ name: "lit-subtopic",
28792
+ displayName: "Sub-topic Search",
28793
+ icon: "BookOpen",
28794
+ category: "research",
28795
+ formatCallSummary: (a) => a._summary || "Searching sub-topic",
28796
+ formatCallDetail: (a) => ({ summary: a._summary }),
28797
+ formatResultSummary: (result) => safeRecord(result).data || "Search completed",
28798
+ formatResultDetail: () => ({})
28799
+ },
28800
+ {
28801
+ name: "lit-enrich",
28802
+ displayName: "Enrich Papers",
28803
+ icon: "BookOpen",
28804
+ category: "research",
28805
+ formatCallSummary: (a) => a._summary || "Enriching paper metadata",
28806
+ formatCallDetail: (a) => ({ summary: a._summary }),
28807
+ formatResultSummary: (result) => safeRecord(result).data || "Enriched metadata",
28808
+ formatResultDetail: () => ({})
28809
+ },
28810
+ {
28811
+ name: "lit-autosave",
28812
+ displayName: "Save Papers",
28813
+ icon: "BookOpen",
28814
+ category: "research",
28815
+ formatCallSummary: (a) => a._summary || "Saving papers",
28816
+ formatCallDetail: (a) => ({ summary: a._summary }),
28817
+ formatResultSummary: (result) => safeRecord(result).data || "Saved papers",
28818
+ formatResultDetail: () => ({})
28819
+ },
28820
+ {
28821
+ name: "data_analyze",
28822
+ displayName: "Data Analysis",
28823
+ icon: "Database",
28824
+ category: "research",
28825
+ formatCallSummary: (a) => getFileName(a.file_path || "") || "data",
28826
+ formatCallDetail: (a) => ({ file_path: a.file_path }),
28827
+ formatResultSummary: () => "Analysis completed",
28828
+ formatResultDetail: () => ({})
28829
+ },
28830
+ // ── Artifact tools ────────────────────────
28831
+ {
28832
+ name: "artifact-create",
28833
+ displayName: "Create Artifact",
28834
+ icon: "Sparkles",
28835
+ category: "memory",
28836
+ formatCallSummary: (a) => {
28837
+ const type = (a.type || "artifact").toLowerCase();
28838
+ const title = truncStr(a.title, 35);
28839
+ return `${type}: ${title}`;
28840
+ },
28841
+ formatCallDetail: (a) => ({ type: a.type, title: a.title }),
28842
+ formatResultSummary: (result) => {
28843
+ const data = safeRecord(safeRecord(result).data);
28844
+ const type = data.type || "artifact";
28845
+ const title = truncStr(data.title, 30);
28846
+ return title ? `Created ${type}: ${title}` : `Created ${type}`;
28847
+ },
28848
+ formatResultDetail: (result) => {
28849
+ const data = safeRecord(safeRecord(result).data);
28850
+ return { type: data.type, title: data.title };
28851
+ }
28852
+ },
28853
+ {
28854
+ name: "artifact-update",
28855
+ displayName: "Update Artifact",
28856
+ icon: "Sparkles",
28857
+ category: "memory",
28858
+ formatCallSummary: (a) => truncStr(a.id, 30),
28859
+ formatCallDetail: (a) => ({ id: a.id }),
28860
+ formatResultSummary: () => "Updated",
28861
+ formatResultDetail: () => ({})
28862
+ },
28863
+ {
28864
+ name: "artifact-search",
28865
+ displayName: "Search Artifacts",
28866
+ icon: "Search",
28867
+ category: "memory",
28868
+ formatCallSummary: (a) => truncStr(a.query, 40),
28869
+ formatCallDetail: (a) => ({ query: a.query, types: a.types }),
28870
+ formatResultSummary: () => "Search completed",
28871
+ formatResultDetail: () => ({})
28872
+ },
28873
+ // ── System tools ────────────────────────
28874
+ {
28875
+ name: "convert_document",
28876
+ displayName: "Convert Document",
28877
+ icon: "FileText",
28878
+ category: "system",
28879
+ formatCallSummary: (a) => getFileName(a.source || ""),
28880
+ formatCallDetail: (a) => ({ source: a.source }),
28881
+ formatResultSummary: (result, a) => {
28882
+ const data = safeRecord(safeRecord(result).data);
28883
+ const skill = data.converterSkill;
28884
+ const sourceName = getFileName(a?.source || "");
28885
+ return skill ? `Converted ${sourceName} via ${skill}` : `Converted ${sourceName}`;
28886
+ },
28887
+ formatResultDetail: (result) => {
28888
+ const data = safeRecord(safeRecord(result).data);
28889
+ return { converterSkill: data.converterSkill, outputFile: data.outputFile };
28890
+ }
28891
+ },
28892
+ {
28893
+ name: "load_skill",
28894
+ displayName: "Load Skill",
28895
+ icon: "Sparkles",
28896
+ category: "system",
28897
+ formatCallSummary: (a) => a.name || "skill",
28898
+ formatCallDetail: (a) => ({ name: a.name }),
28899
+ formatResultSummary: (_2, a) => `Loaded: ${a?.name || "skill"}`,
28900
+ formatResultDetail: () => ({})
28901
+ }
28902
+ ];
28903
+ const registry = /* @__PURE__ */ new Map();
28904
+ for (const config of configs) {
28905
+ registry.set(config.name, config);
28906
+ }
28907
+ function getToolDisplayName(toolName) {
28908
+ return registry.get(toolName)?.displayName || toolName;
28909
+ }
28910
+ function getToolIcon(toolName) {
28911
+ return registry.get(toolName)?.icon || "Wrench";
28912
+ }
28913
+ const ICON_MAP = {
28914
+ FileText,
28915
+ Terminal,
28916
+ Search,
28917
+ Globe,
28918
+ Wrench,
28919
+ BookOpen,
28920
+ Database,
28921
+ Sparkles
28922
+ };
28923
+ function getToolMeta(tool) {
28924
+ return {
28925
+ name: getToolDisplayName(tool),
28926
+ Icon: ICON_MAP[getToolIcon(tool)] || Wrench
28927
+ };
28928
+ }
28929
+ function StatusIcon({ status, size = 13 }) {
28930
+ switch (status) {
28931
+ case "running":
28932
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size, className: "animate-spin t-text-accent-soft" });
28933
+ case "success":
28934
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { size, className: "t-text-success" });
28935
+ case "error":
28936
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { size, className: "t-text-error" });
28937
+ }
28938
+ }
28939
+ function formatDuration(ms2) {
28940
+ if (ms2 < 1e3) return `${ms2}ms`;
28941
+ if (ms2 < 6e4) return `${(ms2 / 1e3).toFixed(1)}s`;
28942
+ return `${(ms2 / 6e4).toFixed(1)}m`;
28943
+ }
28944
+ function ElapsedTimer({ startedAt }) {
28945
+ const [elapsed, setElapsed] = reactExports.useState(Date.now() - startedAt);
28946
+ reactExports.useEffect(() => {
28947
+ const interval = setInterval(() => setElapsed(Date.now() - startedAt), 100);
28948
+ return () => clearInterval(interval);
28949
+ }, [startedAt]);
28950
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted tabular-nums", children: formatDuration(elapsed) });
28951
+ }
28952
+ const CompactToolLine = React$2.memo(function CompactToolLine2({ event }) {
28953
+ const [expanded, setExpanded] = reactExports.useState(false);
28954
+ const { name: name2, Icon: Icon2 } = getToolMeta(event.tool);
28955
+ const displaySummary = event.resultSummary || event.summary;
28956
+ const detailItems = buildDetailItems(event.tool, event.detail, event.resultDetail);
28957
+ const hasExpandable = detailItems.length > 0;
28958
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
28959
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28960
+ "button",
28961
+ {
28962
+ onClick: () => hasExpandable && setExpanded(!expanded),
28963
+ className: `w-full flex items-center gap-1.5 px-2 py-[3px] text-[11px] rounded transition-colors ${hasExpandable ? "hover:t-bg-hover cursor-pointer" : "cursor-default"}`,
28964
+ children: [
28965
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StatusIcon, { status: event.status, size: 11 }),
28966
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 10, className: "t-text-muted shrink-0" }),
28967
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium t-text-secondary shrink-0", children: name2 }),
28968
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted select-none", children: "·" }),
28969
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted truncate flex-1 text-left", children: displaySummary }),
28970
+ event.durationMs != null && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted tabular-nums shrink-0", children: formatDuration(event.durationMs) }),
28971
+ hasExpandable && /* @__PURE__ */ jsxRuntimeExports.jsx(
28972
+ "span",
28973
+ {
28974
+ className: "t-text-muted shrink-0 transition-transform duration-150",
28975
+ style: { transform: expanded ? "rotate(90deg)" : "rotate(0deg)" },
28976
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 9 })
28977
+ }
28978
+ )
28979
+ ]
28980
+ }
28981
+ ),
28982
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-5 mr-2 mb-1 mt-0.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandedDetail, { event }) })
28983
+ ] });
28984
+ });
28985
+ const RunningToolCard = React$2.memo(function RunningToolCard2({ event }) {
28986
+ const [expanded, setExpanded] = reactExports.useState(false);
28987
+ const { name: name2, Icon: Icon2 } = getToolMeta(event.tool);
28988
+ const displaySummary = event.summary;
28989
+ const detailItems = buildDetailItems(event.tool, event.detail, event.resultDetail);
28990
+ const hasExpandable = detailItems.length > 0 || event.progress;
28991
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border t-border t-bg-surface shadow-sm overflow-hidden", children: [
28992
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28993
+ "button",
28994
+ {
28995
+ onClick: () => hasExpandable && setExpanded(!expanded),
28996
+ className: `w-full flex items-center gap-2 px-3 py-2 text-xs transition-colors ${hasExpandable ? "hover:t-bg-hover cursor-pointer" : "cursor-default"}`,
28997
+ children: [
28998
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StatusIcon, { status: event.status }),
28999
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 12, className: "t-text-accent-soft shrink-0" }),
29000
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium t-text shrink-0", children: name2 }),
29001
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted select-none", children: "·" }),
29002
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-secondary truncate flex-1 text-left", children: displaySummary }),
29003
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ElapsedTimer, { startedAt: event.startedAt }),
29004
+ hasExpandable && /* @__PURE__ */ jsxRuntimeExports.jsx(
29005
+ "span",
29006
+ {
29007
+ className: "t-text-muted shrink-0 transition-transform duration-150",
29008
+ style: { transform: expanded ? "rotate(90deg)" : "rotate(0deg)" },
29009
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 10 })
29010
+ }
29011
+ )
29012
+ ]
29013
+ }
29014
+ ),
29015
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border px-3 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandedDetail, { event }) }),
29016
+ !expanded && event.progress && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border px-3 py-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-[10px] font-mono t-text-muted overflow-hidden max-h-14 leading-relaxed whitespace-pre-wrap", children: event.progress }) })
29017
+ ] });
29018
+ });
29019
+ const ToolUseCard = React$2.memo(function ToolUseCard2({ event, compact }) {
29020
+ if (compact || event.status !== "running") {
29021
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CompactToolLine, { event });
29022
+ }
29023
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(RunningToolCard, { event });
29024
+ });
29025
+ function ExpandedDetail({ event }) {
29026
+ const items = buildDetailItems(event.tool, event.detail, event.resultDetail);
29027
+ const hasProgress = !!event.progress;
29028
+ if (items.length === 0 && !hasProgress) return null;
29029
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
29030
+ items.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1", children: items.map((item, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(DetailItem, { ...item }, i)) }),
29031
+ hasProgress && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "p-2 rounded t-bg-base text-[10px] font-mono t-text-secondary overflow-x-auto max-h-28 overflow-y-auto leading-relaxed whitespace-pre-wrap border t-border-subtle", children: event.progress })
29032
+ ] });
29033
+ }
29034
+ function DetailItem({ type, label, value }) {
29035
+ switch (type) {
29036
+ case "path":
29037
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-[11px]", children: [
29038
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { size: 10, className: "t-text-muted shrink-0" }),
29039
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono t-text-secondary truncate", title: value, children: value })
29040
+ ] });
29041
+ case "code":
29042
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "p-2 rounded t-bg-base text-[10px] font-mono t-text-secondary overflow-x-auto leading-relaxed whitespace-pre-wrap border t-border-subtle", children: value });
29043
+ case "stat":
29044
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-[10px]", children: [
29045
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: label }),
29046
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium t-text-secondary tabular-nums", children: value })
29047
+ ] });
29048
+ case "kv":
29049
+ default:
29050
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-2 text-[11px]", children: [
29051
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted shrink-0 text-[10px]", children: label }),
29052
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-secondary font-mono truncate", title: value, children: value })
29053
+ ] });
29054
+ }
29055
+ }
29056
+ function buildDetailItems(tool, detail, resultDetail) {
29057
+ const items = [];
29058
+ if (!detail && !resultDetail) return items;
29059
+ switch (tool) {
29060
+ case "read": {
29061
+ const path2 = detail?.path;
29062
+ if (path2) items.push({ type: "path", value: path2 });
29063
+ const lineCount = resultDetail?.lineCount;
29064
+ if (lineCount) items.push({ type: "stat", label: "Lines read", value: String(lineCount) });
29065
+ break;
29066
+ }
29067
+ case "write":
29068
+ case "edit": {
29069
+ const path2 = detail?.path || resultDetail?.path;
29070
+ if (path2) items.push({ type: "path", value: path2 });
29071
+ break;
29072
+ }
29073
+ case "bash": {
29074
+ const cmd = detail?.command;
29075
+ if (cmd) items.push({ type: "code", value: `$ ${cmd}` });
29076
+ const preview = resultDetail?.outputPreview;
29077
+ if (preview) items.push({ type: "code", value: preview });
29078
+ const lines = resultDetail?.outputLines;
29079
+ if (lines && !preview) items.push({ type: "stat", label: "Output", value: `${lines} lines` });
29080
+ break;
29081
+ }
29082
+ case "grep": {
29083
+ const pattern = detail?.pattern;
29084
+ const path2 = detail?.path;
29085
+ if (pattern) items.push({ type: "kv", label: "Pattern", value: pattern });
29086
+ if (path2) items.push({ type: "kv", label: "Path", value: path2 });
29087
+ const count = resultDetail?.matchCount;
29088
+ if (count != null) items.push({ type: "stat", label: "Matches", value: String(count) });
29089
+ break;
29090
+ }
29091
+ case "glob": {
29092
+ const pattern = detail?.pattern;
29093
+ if (pattern) items.push({ type: "kv", label: "Pattern", value: pattern });
29094
+ const count = resultDetail?.fileCount;
29095
+ if (count != null) items.push({ type: "stat", label: "Files found", value: String(count) });
29096
+ break;
29097
+ }
29098
+ case "fetch":
29099
+ case "web_fetch": {
29100
+ const url = detail?.url;
29101
+ if (url) items.push({ type: "kv", label: "URL", value: url });
29102
+ const size = resultDetail?.sizeKB || resultDetail?.charCount;
29103
+ if (size) items.push({ type: "stat", label: "Received", value: size > 1024 ? `${(size / 1024).toFixed(1)}MB` : `${size}KB` });
29104
+ break;
29105
+ }
29106
+ case "web_search": {
29107
+ const query = detail?.query;
29108
+ if (query) items.push({ type: "kv", label: "Query", value: query });
29109
+ break;
29110
+ }
29111
+ case "literature-search": {
29112
+ const query = detail?.query;
29113
+ if (query) items.push({ type: "kv", label: "Query", value: query });
29114
+ const found = resultDetail?.papersFound;
29115
+ const saved = resultDetail?.papersSaved;
29116
+ const coverage = resultDetail?.coverage;
29117
+ if (found != null) items.push({ type: "stat", label: "Papers found", value: String(found) });
29118
+ if (saved != null && saved > 0) items.push({ type: "stat", label: "Saved", value: String(saved) });
29119
+ if (coverage != null) items.push({ type: "stat", label: "Coverage", value: `${Math.round(coverage * 100)}%` });
29120
+ break;
29121
+ }
29122
+ case "artifact-create":
29123
+ case "artifact-update": {
29124
+ const type = detail?.type || resultDetail?.type;
29125
+ const title = detail?.title || resultDetail?.title;
29126
+ if (type) items.push({ type: "kv", label: "Type", value: type });
29127
+ if (title) items.push({ type: "kv", label: "Title", value: title });
29128
+ break;
29129
+ }
29130
+ case "artifact-search": {
29131
+ const query = detail?.query;
29132
+ if (query) items.push({ type: "kv", label: "Query", value: query });
29133
+ break;
29134
+ }
29135
+ default: {
29136
+ const skipKeys = /* @__PURE__ */ new Set(["success", "path"]);
29137
+ const source = { ...detail, ...resultDetail };
29138
+ for (const [key, val] of Object.entries(source)) {
29139
+ if (val == null || skipKeys.has(key)) continue;
29140
+ const strVal = typeof val === "string" ? val : JSON.stringify(val);
29141
+ if (strVal.length === 0 || strVal === "true" || strVal === "false") continue;
29142
+ items.push({ type: "kv", label: key, value: strVal });
29143
+ }
29144
+ break;
29145
+ }
29146
+ }
29147
+ return items;
29148
+ }
29149
+ const VISIBLE_COMPLETED = 3;
29150
+ function ToolUseStream({ events: propEvents }) {
29151
+ const liveEvents = useToolEventsStore((s15) => s15.currentRunEvents);
29152
+ const events = propEvents ?? liveEvents;
29153
+ const [showAll, setShowAll] = reactExports.useState(false);
29154
+ const { running, completed } = reactExports.useMemo(() => {
29155
+ const running2 = [];
29156
+ const completed2 = [];
29157
+ for (const e of events) {
29158
+ if (e.status === "running") running2.push(e);
29159
+ else completed2.push(e);
29160
+ }
29161
+ return { running: running2, completed: completed2 };
29162
+ }, [events]);
29163
+ if (events.length === 0) return null;
29164
+ const hiddenCount = showAll ? 0 : Math.max(0, completed.length - VISIBLE_COMPLETED);
29165
+ const visibleCompleted = showAll ? completed : completed.slice(-VISIBLE_COMPLETED);
29166
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "my-2 max-w-[80%]", children: [
29167
+ hiddenCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
29168
+ "button",
29169
+ {
29170
+ onClick: () => setShowAll(true),
29171
+ className: "flex items-center gap-1.5 px-2 py-1 mb-1 text-[10px] t-text-muted hover:t-text-accent-soft transition-colors rounded",
29172
+ children: [
29173
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 10 }),
29174
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
29175
+ hiddenCount,
29176
+ " more tool ",
29177
+ hiddenCount === 1 ? "call" : "calls"
29178
+ ] })
29179
+ ]
29180
+ }
29181
+ ),
29182
+ visibleCompleted.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-0", children: visibleCompleted.map((event) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseCard, { event, compact: true }, event.id)) }),
29183
+ running.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 mt-1", children: running.map((event) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseCard, { event }, event.id)) })
29184
+ ] });
29185
+ }
28405
29186
  const api$4 = window.api;
28406
29187
  const remarkPlugins$1 = [remarkGfm];
28407
29188
  function SelectionBookmark() {
@@ -28583,37 +29364,12 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
28583
29364
  }
28584
29365
  ) });
28585
29366
  });
28586
- function ThinkingDots() {
28587
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex gap-1 items-center", children: [
28588
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full t-bg-accent-soft animate-bounce", style: { animationDelay: "0ms" } }),
28589
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full t-bg-accent-soft animate-bounce", style: { animationDelay: "150ms" } }),
28590
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full t-bg-accent-soft animate-bounce", style: { animationDelay: "300ms" } })
28591
- ] });
28592
- }
28593
- function ThinkingBubble() {
28594
- const events = useActivityStore((s15) => s15.events);
28595
- const activity = reactExports.useMemo(() => {
28596
- const latest = [...events].reverse().find((e) => e.type === "tool-call") || events[events.length - 1];
28597
- return latest?.summary || "";
28598
- }, [events]);
28599
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
28600
- /* @__PURE__ */ jsxRuntimeExports.jsx(
28601
- "div",
28602
- {
28603
- className: "rounded-2xl px-4 py-3 text-sm t-text-secondary shrink-0",
28604
- style: { background: "var(--color-bubble-assistant)" },
28605
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
28606
- /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingDots, {}),
28607
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Thinking" })
28608
- ] })
28609
- }
28610
- ),
28611
- activity && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex items-center gap-2 min-w-0", children: [
28612
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 h-px border-t t-border" }),
28613
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs t-text-muted whitespace-nowrap truncate max-w-[60%] animate-pulse", children: activity }),
28614
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 h-px border-t t-border" })
28615
- ] })
28616
- ] });
29367
+ function ThinkingIndicator() {
29368
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-1.5 mt-3 ml-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex gap-[3px] items-center", children: [
29369
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-[5px] h-[5px] rounded-full t-bg-accent-soft animate-bounce", style: { animationDelay: "0ms" } }),
29370
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-[5px] h-[5px] rounded-full t-bg-accent-soft animate-bounce", style: { animationDelay: "150ms" } }),
29371
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-[5px] h-[5px] rounded-full t-bg-accent-soft animate-bounce", style: { animationDelay: "300ms" } })
29372
+ ] }) });
28617
29373
  }
28618
29374
  function StreamingBubble() {
28619
29375
  const text2 = useChatStore((s15) => s15.streamingText);
@@ -28635,10 +29391,13 @@ function ChatMessages() {
28635
29391
  const isStreaming = useChatStore((s15) => s15.isStreaming);
28636
29392
  const streamingText = useChatStore((s15) => s15.streamingText);
28637
29393
  const savedMessageIds = useChatStore((s15) => s15.savedMessageIds);
29394
+ const turnToolEvents = useChatStore((s15) => s15.turnToolEvents);
28638
29395
  const hasMore = useChatStore((s15) => s15.hasMore);
28639
29396
  const isLoadingHistory = useChatStore((s15) => s15.isLoadingHistory);
28640
29397
  const loadHistory = useChatStore((s15) => s15.loadHistory);
28641
29398
  const scrollToMessageId = useChatStore((s15) => s15.scrollToMessageId);
29399
+ const toolEventsCount = useToolEventsStore((s15) => s15.currentRunEvents.length);
29400
+ const hasRunningTools = useToolEventsStore((s15) => s15.currentRunEvents.some((e) => e.status === "running"));
28642
29401
  const bottomRef = reactExports.useRef(null);
28643
29402
  const scrollContainerRef = reactExports.useRef(null);
28644
29403
  const [autoScroll, setAutoScroll] = reactExports.useState(true);
@@ -28671,7 +29430,7 @@ function ChatMessages() {
28671
29430
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
28672
29431
  }
28673
29432
  }
28674
- }, [messages, streamingText, autoScroll]);
29433
+ }, [messages, streamingText, toolEventsCount, autoScroll]);
28675
29434
  reactExports.useEffect(() => {
28676
29435
  if (!scrollToMessageId || !scrollContainerRef.current) return;
28677
29436
  const el2 = scrollContainerRef.current.querySelector(`[data-msg-id="${scrollToMessageId}"]`);
@@ -28697,15 +29456,26 @@ function ChatMessages() {
28697
29456
  messages.map((msg, i) => {
28698
29457
  const prev = messages[i - 1];
28699
29458
  const gap = prev && prev.role !== msg.role ? "mt-5" : "mt-3";
28700
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: i === 0 ? "" : gap, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
28701
- MessageBubble,
28702
- {
28703
- msg,
28704
- isSaved: savedMessageIds.has(msg.id)
28705
- }
28706
- ) }, msg.id);
29459
+ const toolEvents = msg.role === "assistant" ? turnToolEvents.get(msg.id) : void 0;
29460
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: i === 0 ? "" : gap, children: [
29461
+ toolEvents && toolEvents.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseStream, { events: toolEvents }),
29462
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29463
+ MessageBubble,
29464
+ {
29465
+ msg,
29466
+ isSaved: savedMessageIds.has(msg.id)
29467
+ }
29468
+ )
29469
+ ] }, msg.id);
28707
29470
  }),
28708
- isStreaming && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-5", children: streamingText ? /* @__PURE__ */ jsxRuntimeExports.jsx(StreamingBubble, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingBubble, {}) }),
29471
+ isStreaming && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-5", children: [
29472
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseStream, {}),
29473
+ streamingText ? /* @__PURE__ */ jsxRuntimeExports.jsx(StreamingBubble, {}) : !hasRunningTools ? (
29474
+ /* Show thinking dots only when no tools are running —
29475
+ running tool cards already have spinners as progress indicator */
29476
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingIndicator, {})
29477
+ ) : null
29478
+ ] }),
28709
29479
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: bottomRef })
28710
29480
  ]
28711
29481
  }
@@ -28730,6 +29500,16 @@ function formatMention(c) {
28730
29500
  const needsQuotes = c.value.includes(" ");
28731
29501
  return needsQuotes ? `@${c.type}:"${c.value}"` : `@${c.type}:${c.value}`;
28732
29502
  }
29503
+ function truncatePath(path2, maxLen = 60) {
29504
+ const lastSlash = path2.lastIndexOf("/");
29505
+ if (lastSlash === -1) return { dir: "", file: path2 };
29506
+ const file = path2.slice(lastSlash + 1);
29507
+ const dir = path2.slice(0, lastSlash);
29508
+ if (path2.length <= maxLen) return { dir: dir + "/", file };
29509
+ const budget = maxLen - file.length - 2;
29510
+ if (budget <= 0) return { dir: "…/", file };
29511
+ return { dir: "…" + dir.slice(dir.length - budget) + "/", file };
29512
+ }
28733
29513
  function MentionPopover({ query, onSelect, onClose }) {
28734
29514
  const [candidates, setCandidates] = reactExports.useState([]);
28735
29515
  const [selectedIdx, setSelectedIdx] = reactExports.useState(0);
@@ -28745,24 +29525,26 @@ function MentionPopover({ query, onSelect, onClose }) {
28745
29525
  const flatList = reactExports.useMemo(() => {
28746
29526
  return grouped.flatMap((g2) => g2.items);
28747
29527
  }, [grouped]);
29528
+ const debounceRef = reactExports.useRef();
28748
29529
  reactExports.useEffect(() => {
28749
29530
  let stale = false;
28750
29531
  setLoading(true);
28751
- console.log(`[MentionPopover] fetching candidates for query="${query}"`);
28752
- api$3.getCandidates(query).then((result) => {
28753
- if (stale) return;
28754
- console.log(`[MentionPopover] got ${result?.length ?? 0} candidates for query="${query}"`);
28755
- setCandidates(result || []);
28756
- setSelectedIdx(0);
28757
- setLoading(false);
28758
- }).catch((err) => {
28759
- if (stale) return;
28760
- console.error("[MentionPopover] getCandidates error:", err);
28761
- setCandidates([]);
28762
- setLoading(false);
28763
- });
29532
+ clearTimeout(debounceRef.current);
29533
+ debounceRef.current = setTimeout(() => {
29534
+ api$3.getCandidates(query).then((result) => {
29535
+ if (stale) return;
29536
+ setCandidates(result || []);
29537
+ setSelectedIdx(0);
29538
+ setLoading(false);
29539
+ }).catch(() => {
29540
+ if (stale) return;
29541
+ setCandidates([]);
29542
+ setLoading(false);
29543
+ });
29544
+ }, 50);
28764
29545
  return () => {
28765
29546
  stale = true;
29547
+ clearTimeout(debounceRef.current);
28766
29548
  };
28767
29549
  }, [query]);
28768
29550
  reactExports.useEffect(() => {
@@ -28795,7 +29577,7 @@ function MentionPopover({ query, onSelect, onClose }) {
28795
29577
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
28796
29578
  "div",
28797
29579
  {
28798
- className: "absolute z-50 w-96 max-h-64 overflow-y-auto rounded-xl border t-border t-bg-surface shadow-xl",
29580
+ className: "absolute z-50 w-[32rem] max-h-80 overflow-y-auto rounded-xl border t-border t-bg-surface shadow-xl",
28799
29581
  style: { bottom: "100%", left: 48, marginBottom: 8 },
28800
29582
  children: [
28801
29583
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1.5 border-b t-border flex items-center gap-2 text-xs t-text-secondary", children: [
@@ -28827,9 +29609,16 @@ function MentionPopover({ query, onSelect, onClose }) {
28827
29609
  },
28828
29610
  onMouseEnter: () => setSelectedIdx(idx),
28829
29611
  className: `flex items-center gap-1.5 w-full px-3 py-1 text-xs text-left transition-colors ${idx === selectedIdx ? "t-bg-elevated t-text" : "t-text-secondary t-bg-hover"}`,
29612
+ title: c.label,
28830
29613
  children: [
28831
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1", children: c.label }),
28832
- c.detail && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted truncate max-w-[100px]", children: c.detail })
29614
+ c.type === "file" ? (() => {
29615
+ const { dir, file } = truncatePath(c.label);
29616
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate flex-1 min-w-0", children: [
29617
+ dir && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: dir }),
29618
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: file })
29619
+ ] });
29620
+ })() : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1 min-w-0", children: c.label }),
29621
+ c.detail && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted shrink-0 ml-2", children: c.detail })
28833
29622
  ]
28834
29623
  },
28835
29624
  `${c.type}-${c.value}`
@@ -28974,7 +29763,8 @@ function parseFlagArgs(raw) {
28974
29763
  return { cleaned: cleaned.trim(), flags };
28975
29764
  }
28976
29765
  function ChatInput() {
28977
- const [text2, setText] = reactExports.useState("");
29766
+ const text2 = useChatStore((s15) => s15.draftText);
29767
+ const setText = useChatStore((s15) => s15.setDraftText);
28978
29768
  const [showMention, setShowMention] = reactExports.useState(false);
28979
29769
  const [mentionQuery, setMentionQuery] = reactExports.useState("");
28980
29770
  const [showCommand, setShowCommand] = reactExports.useState(false);
@@ -28991,7 +29781,6 @@ function ChatInput() {
28991
29781
  const hasProject = useSessionStore((s15) => s15.hasProject);
28992
29782
  const refreshEntities = useEntityStore((s15) => s15.refreshAll);
28993
29783
  reactExports.useEffect(() => {
28994
- setText("");
28995
29784
  setShowMention(false);
28996
29785
  setShowCommand(false);
28997
29786
  setPendingImages([]);
@@ -29340,7 +30129,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
29340
30129
  setText(val);
29341
30130
  const cursor = e.target.selectionStart;
29342
30131
  const before = val.slice(0, cursor);
29343
- const mentionMatch = before.match(/@([\w./-]*)$/);
30132
+ const mentionMatch = before.match(/@([\p{L}\p{N}\p{M}_\-./()\[\]~:]*)$/u);
29344
30133
  if (mentionMatch) {
29345
30134
  setShowMention(true);
29346
30135
  setMentionQuery(mentionMatch[1]);
@@ -29360,7 +30149,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
29360
30149
  const cursor = textareaRef.current?.selectionStart ?? text2.length;
29361
30150
  const before = text2.slice(0, cursor);
29362
30151
  const after = text2.slice(cursor);
29363
- const replaced = before.replace(/@[\w./-]*$/, value + " ");
30152
+ const replaced = before.replace(/@[\p{L}\p{N}\p{M}_\-./()\[\]~:]*$/u, value + " ");
29364
30153
  setText(replaced + after);
29365
30154
  setShowMention(false);
29366
30155
  textareaRef.current?.focus();
@@ -29969,7 +30758,7 @@ function CenterPanel() {
29969
30758
  }
29970
30759
  const remarkPlugins = [remarkGfm];
29971
30760
  const LazyMilkdownMarkdownEditor = reactExports.lazy(async () => {
29972
- const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-CCiFOpuq.js").then((n) => n.bL), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
30761
+ const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-D7GYpVZn.js").then((n) => n.bL), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
29973
30762
  return { default: mod.MilkdownMarkdownEditor };
29974
30763
  });
29975
30764
  const typeIcons = {
@@ -30566,6 +31355,9 @@ function StatusBar() {
30566
31355
  const events = useActivityStore((s15) => s15.events);
30567
31356
  const activeSkills = useActivityStore((s15) => s15.activeSkills);
30568
31357
  const runTokens = useUsageStore((s15) => s15.runTokens);
31358
+ const runPromptTokens = useUsageStore((s15) => s15.runPromptTokens);
31359
+ const runCompletionTokens = useUsageStore((s15) => s15.runCompletionTokens);
31360
+ const runCachedTokens = useUsageStore((s15) => s15.runCachedTokens);
30569
31361
  const runCost = useUsageStore((s15) => s15.runCost);
30570
31362
  const runCacheHitRate = useUsageStore((s15) => s15.runCacheHitRate);
30571
31363
  const allTimeTokens = useUsageStore((s15) => s15.allTimeTokens);
@@ -30607,12 +31399,12 @@ function StatusBar() {
30607
31399
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
30608
31400
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 whitespace-nowrap", children: [
30609
31401
  hasRunUsage && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30610
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
31402
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { title: `In: ${formatTokens(runPromptTokens)} · Cache: ${formatTokens(runCachedTokens)} · Out: ${formatTokens(runCompletionTokens)}`, children: [
30611
31403
  formatTokens(runTokens),
30612
31404
  " tokens"
30613
31405
  ] }),
30614
31406
  runCost > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-success", children: formatCost(runCost) }),
30615
- runCacheHitRate > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-accent-soft", children: [
31407
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: runCacheHitRate > 0.5 ? "t-text-accent" : "t-text-accent-soft", children: [
30616
31408
  Math.round(runCacheHitRate * 100),
30617
31409
  "% cache"
30618
31410
  ] })
@@ -39371,6 +40163,53 @@ class ErrorBoundary extends reactExports.Component {
39371
40163
  ] }) });
39372
40164
  }
39373
40165
  }
40166
+ function lastNLines(text2, n) {
40167
+ const lines = text2.split("\n").filter(Boolean);
40168
+ return lines.slice(-n).join("\n");
40169
+ }
40170
+ function extractPartialOutput(tool, data) {
40171
+ if (!data?.partialResult) return void 0;
40172
+ const pr = data.partialResult;
40173
+ const text2 = pr?.content?.[0]?.text;
40174
+ if (typeof text2 === "string" && text2.length > 0) {
40175
+ const maxLines = tool === "bash" ? 5 : 3;
40176
+ return lastNLines(text2, maxLines);
40177
+ }
40178
+ return void 0;
40179
+ }
40180
+ const useToolProgressStore = create$1((set) => ({
40181
+ inFlight: /* @__PURE__ */ new Map(),
40182
+ reportProgress: (event) => {
40183
+ set((state) => {
40184
+ const next = new Map(state.inFlight);
40185
+ const phase = event.phase;
40186
+ if (phase === "start") {
40187
+ next.set(event.toolCallId, {
40188
+ tool: event.tool,
40189
+ toolCallId: event.toolCallId,
40190
+ phase,
40191
+ startedAt: event.timestamp,
40192
+ updatedAt: event.timestamp
40193
+ });
40194
+ } else if (phase === "update") {
40195
+ const existing = next.get(event.toolCallId);
40196
+ const partialOutput = extractPartialOutput(event.tool, event.data);
40197
+ next.set(event.toolCallId, {
40198
+ tool: event.tool,
40199
+ toolCallId: event.toolCallId,
40200
+ phase,
40201
+ partialOutput: partialOutput ?? existing?.partialOutput,
40202
+ startedAt: existing?.startedAt ?? event.timestamp,
40203
+ updatedAt: event.timestamp
40204
+ });
40205
+ } else if (phase === "end") {
40206
+ next.delete(event.toolCallId);
40207
+ }
40208
+ return { inFlight: next };
40209
+ });
40210
+ },
40211
+ clearAll: () => set({ inFlight: /* @__PURE__ */ new Map() })
40212
+ }));
39374
40213
  const api = window.api;
39375
40214
  function FolderGate({ onOpenSettings }) {
39376
40215
  const pickFolder = useSessionStore((s15) => s15.pickFolder);
@@ -39502,6 +40341,16 @@ function App() {
39502
40341
  });
39503
40342
  }
39504
40343
  }
40344
+ if (snapshot && snapshot.toolEvents?.length > 0) {
40345
+ const toolStore = useToolEventsStore.getState();
40346
+ for (const evt of snapshot.toolEvents) {
40347
+ if (evt.type === "tool-call") {
40348
+ toolStore.onToolCall(evt);
40349
+ } else if (evt.type === "tool-result") {
40350
+ toolStore.onToolResult(evt);
40351
+ }
40352
+ }
40353
+ }
39505
40354
  });
39506
40355
  api.getCurrentSession().then((session) => {
39507
40356
  useChatStore.getState().loadInitial(session.sessionId);
@@ -39517,14 +40366,26 @@ function App() {
39517
40366
  });
39518
40367
  const unsubActivityClear = api.onActivityClear(() => {
39519
40368
  useActivityStore.getState().clear();
40369
+ useToolProgressStore.getState().clearAll();
40370
+ useToolEventsStore.getState().clearRun();
39520
40371
  useUsageStore.getState().resetRun();
39521
40372
  });
39522
40373
  const unsubActivity = api.onActivity((event) => {
39523
- useActivityStore.getState().push({
40374
+ const enrichedEvent = {
39524
40375
  id: `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
39525
40376
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
39526
40377
  ...event
39527
- });
40378
+ };
40379
+ useActivityStore.getState().push(enrichedEvent);
40380
+ if (event.type === "tool-call") {
40381
+ useToolEventsStore.getState().onToolCall(enrichedEvent);
40382
+ } else if (event.type === "tool-result") {
40383
+ useToolEventsStore.getState().onToolResult(enrichedEvent);
40384
+ }
40385
+ });
40386
+ const unsubToolProgress = api.onToolProgress((event) => {
40387
+ useToolProgressStore.getState().reportProgress(event);
40388
+ useToolEventsStore.getState().onToolProgress(event);
39528
40389
  });
39529
40390
  const unsubSkillLoaded = api.onSkillLoaded((skillName) => {
39530
40391
  useActivityStore.getState().addSkill(skillName);
@@ -39571,6 +40432,7 @@ function App() {
39571
40432
  unsub6();
39572
40433
  unsubActivity();
39573
40434
  unsubActivityClear();
40435
+ unsubToolProgress();
39574
40436
  unsubSkillLoaded();
39575
40437
  unsubUsage();
39576
40438
  };