research-copilot 0.2.0 → 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 +751 -259
  2. package/app/out/preload/index.js +5 -0
  3. package/app/out/renderer/assets/{MilkdownMarkdownEditor-Czh2N6UQ.js → MilkdownMarkdownEditor-D7GYpVZn.js} +50 -50
  4. package/app/out/renderer/assets/{arc-BWoErJNa.js → arc-Kp4J_Jd7.js} +1 -1
  5. package/app/out/renderer/assets/{blockDiagram-c4efeb88-Bod-vAlS.js → blockDiagram-c4efeb88-DkMSdn8j.js} +8 -8
  6. package/app/out/renderer/assets/{c4Diagram-c83219d4-CTVUA_li.js → c4Diagram-c83219d4-DqAGxrYw.js} +3 -3
  7. package/app/out/renderer/assets/{channel-CxGr5Q5E.js → channel-S4GQrISQ.js} +1 -1
  8. package/app/out/renderer/assets/{classDiagram-beda092f-DABwUrsU.js → classDiagram-beda092f-B7AsTCEg.js} +6 -6
  9. package/app/out/renderer/assets/{classDiagram-v2-2358418a-CFt8hqf5.js → classDiagram-v2-2358418a-B4oFy-In.js} +10 -10
  10. package/app/out/renderer/assets/{clone-BL91dKYn.js → clone-Dv1e6zYr.js} +1 -1
  11. package/app/out/renderer/assets/{createText-1719965b-DGkv4rEO.js → createText-1719965b-HBXHvWlI.js} +2 -2
  12. package/app/out/renderer/assets/{edges-96097737-Gf41lQOd.js → edges-96097737-B6X5lcC0.js} +3 -3
  13. package/app/out/renderer/assets/{erDiagram-0228fc6a-Dj75BiRy.js → erDiagram-0228fc6a-BmBmTBlH.js} +5 -5
  14. package/app/out/renderer/assets/{flowDb-c6c81e3f-C_xVBMxS.js → flowDb-c6c81e3f-CObz36ob.js} +1 -1
  15. package/app/out/renderer/assets/{flowDiagram-50d868cf-B-lLn2XC.js → flowDiagram-50d868cf-C2hFHxwF.js} +12 -12
  16. package/app/out/renderer/assets/{flowDiagram-v2-4f6560a1-BFnLU3PE.js → flowDiagram-v2-4f6560a1-DEe8EygW.js} +12 -12
  17. package/app/out/renderer/assets/{flowchart-elk-definition-6af322e1-DmjfyXbt.js → flowchart-elk-definition-6af322e1-CgTtfYKk.js} +6 -6
  18. package/app/out/renderer/assets/{ganttDiagram-a2739b55-BTPRekAy.js → ganttDiagram-a2739b55-C5Pq4zEy.js} +3 -3
  19. package/app/out/renderer/assets/{gitGraphDiagram-82fe8481-1riYxgGS.js → gitGraphDiagram-82fe8481-oLp0f8Ll.js} +2 -2
  20. package/app/out/renderer/assets/{graph-CvDtMlX-.js → graph-51iZ6wgR.js} +1 -1
  21. package/app/out/renderer/assets/{index-0kPJXDfu.js → index-32eUzqVW.js} +3 -3
  22. package/app/out/renderer/assets/{index-5325376f-BGaoNMNN.js → index-5325376f-yLvOW-Os.js} +6 -6
  23. package/app/out/renderer/assets/{index-O3gvL3-Z.js → index-AuZa-hTj.js} +3 -3
  24. package/app/out/renderer/assets/{index-BxOmAXUZ.js → index-B9a4DKM-.js} +3 -3
  25. package/app/out/renderer/assets/{index-NHbUPOmb.js → index-BMsuFGn6.js} +3 -3
  26. package/app/out/renderer/assets/{index-BnRwUKpv.js → index-BQA_Kvr6.js} +3 -3
  27. package/app/out/renderer/assets/{index-y5XZ-0EB.js → index-BSd80-j9.js} +4 -4
  28. package/app/out/renderer/assets/{index-zr8uxb8p.js → index-BfWWn8B_.js} +6 -6
  29. package/app/out/renderer/assets/{index-3LdRym1K.js → index-Bscx_5dF.js} +3 -3
  30. package/app/out/renderer/assets/{index-BgSz3yUy.js → index-CAOQIqEc.js} +6 -6
  31. package/app/out/renderer/assets/{index-BCOrnr8q.js → index-CTmGCKqa.js} +4 -4
  32. package/app/out/renderer/assets/{index-BK5rYWMs.js → index-CmpSV9Ld.js} +5 -5
  33. package/app/out/renderer/assets/{index-cAZJ88Np.js → index-Cn2e13ja.js} +6 -6
  34. package/app/out/renderer/assets/{index-CnL9yPzK.js → index-D_Y7v6pE.js} +3 -3
  35. package/app/out/renderer/assets/{index-BVNrdWzl.js → index-DjqJjt6u.js} +6 -6
  36. package/app/out/renderer/assets/{index-8tvmsRje.js → index-DppxBL77.js} +3 -3
  37. package/app/out/renderer/assets/{index-CUPy7R5v.js → index-Du-Z3sl4.js} +915 -72
  38. package/app/out/renderer/assets/{index-B4djqBxS.js → index-FGsCVYSr.js} +1 -1
  39. package/app/out/renderer/assets/{index-Ctwkk-AW.css → index-L4DJn7cw.css} +12 -8
  40. package/app/out/renderer/assets/{index-DrvR7Peq.js → index-UajPJYNV.js} +3 -3
  41. package/app/out/renderer/assets/{index-CXN1f9OT.js → index-_Z53hJps.js} +3 -3
  42. package/app/out/renderer/assets/{index-D2fFfHUR.js → index-_iFRQTkA.js} +6 -6
  43. package/app/out/renderer/assets/{index-B9lieynj.js → index-ohN9yRWw.js} +6 -6
  44. package/app/out/renderer/assets/{index-Bii7x9Rr.js → index-shoMWskw.js} +3 -3
  45. package/app/out/renderer/assets/{index-qS7qbXvX.js → index-y1Od1ed6.js} +3 -3
  46. package/app/out/renderer/assets/{infoDiagram-8eee0895-Cq8aXV8u.js → infoDiagram-8eee0895-Cm0Hm5ZX.js} +2 -2
  47. package/app/out/renderer/assets/{journeyDiagram-c64418c1-D4ewDrYD.js → journeyDiagram-c64418c1-A2Gw9bVu.js} +4 -4
  48. package/app/out/renderer/assets/{layout-CZmLZO9t.js → layout-C5N2nTfF.js} +2 -2
  49. package/app/out/renderer/assets/{line-D7kWOiRx.js → line-Dn6BEQAK.js} +1 -1
  50. package/app/out/renderer/assets/{linear-B055Dz0c.js → linear-8wk0rPUX.js} +1 -1
  51. package/app/out/renderer/assets/{mindmap-definition-8da855dc-D6EW4QCj.js → mindmap-definition-8da855dc-BVy6ISnb.js} +3 -3
  52. package/app/out/renderer/assets/{pieDiagram-a8764435-BX_Dz4T9.js → pieDiagram-a8764435-B9_axIHE.js} +3 -3
  53. package/app/out/renderer/assets/{quadrantDiagram-1e28029f-BsI6xGsm.js → quadrantDiagram-1e28029f-B1kmkDFg.js} +3 -3
  54. package/app/out/renderer/assets/{requirementDiagram-08caed73-c2d8T0BS.js → requirementDiagram-08caed73-C_bNWUtT.js} +5 -5
  55. package/app/out/renderer/assets/{sankeyDiagram-a04cb91d-CkDhRKRC.js → sankeyDiagram-a04cb91d-CD2h1LiI.js} +2 -2
  56. package/app/out/renderer/assets/{sequenceDiagram-c5b8d532-DS0RKYnD.js → sequenceDiagram-c5b8d532-B6d6cuqi.js} +3 -3
  57. package/app/out/renderer/assets/{stateDiagram-1ecb1508-BjTK27QX.js → stateDiagram-1ecb1508-CkuNj_3H.js} +6 -6
  58. package/app/out/renderer/assets/{stateDiagram-v2-c2b004d7-D1wWbeR3.js → stateDiagram-v2-c2b004d7-CevZ3tno.js} +10 -10
  59. package/app/out/renderer/assets/{styles-b4e223ce-DXUfbXTM.js → styles-b4e223ce-DAe5WQrg.js} +1 -1
  60. package/app/out/renderer/assets/{styles-ca3715f6-CE_JRTmB.js → styles-ca3715f6-BDSX88bY.js} +1 -1
  61. package/app/out/renderer/assets/{styles-d45a18b0-CdtAXXSE.js → styles-d45a18b0-SE9h7les.js} +4 -4
  62. package/app/out/renderer/assets/{svgDrawCommon-b86b1483-dCxPWgBl.js → svgDrawCommon-b86b1483-D1mpNbDQ.js} +1 -1
  63. package/app/out/renderer/assets/{timeline-definition-faaaa080-B7ZP3Dqw.js → timeline-definition-faaaa080-7Ha-nm4M.js} +3 -3
  64. package/app/out/renderer/assets/{xychartDiagram-f5964ef8-CXagmo1Q.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-Czh2N6UQ.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
  }
@@ -28993,7 +29763,8 @@ function parseFlagArgs(raw) {
28993
29763
  return { cleaned: cleaned.trim(), flags };
28994
29764
  }
28995
29765
  function ChatInput() {
28996
- const [text2, setText] = reactExports.useState("");
29766
+ const text2 = useChatStore((s15) => s15.draftText);
29767
+ const setText = useChatStore((s15) => s15.setDraftText);
28997
29768
  const [showMention, setShowMention] = reactExports.useState(false);
28998
29769
  const [mentionQuery, setMentionQuery] = reactExports.useState("");
28999
29770
  const [showCommand, setShowCommand] = reactExports.useState(false);
@@ -29010,7 +29781,6 @@ function ChatInput() {
29010
29781
  const hasProject = useSessionStore((s15) => s15.hasProject);
29011
29782
  const refreshEntities = useEntityStore((s15) => s15.refreshAll);
29012
29783
  reactExports.useEffect(() => {
29013
- setText("");
29014
29784
  setShowMention(false);
29015
29785
  setShowCommand(false);
29016
29786
  setPendingImages([]);
@@ -29988,7 +30758,7 @@ function CenterPanel() {
29988
30758
  }
29989
30759
  const remarkPlugins = [remarkGfm];
29990
30760
  const LazyMilkdownMarkdownEditor = reactExports.lazy(async () => {
29991
- const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-Czh2N6UQ.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);
29992
30762
  return { default: mod.MilkdownMarkdownEditor };
29993
30763
  });
29994
30764
  const typeIcons = {
@@ -30585,6 +31355,9 @@ function StatusBar() {
30585
31355
  const events = useActivityStore((s15) => s15.events);
30586
31356
  const activeSkills = useActivityStore((s15) => s15.activeSkills);
30587
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);
30588
31361
  const runCost = useUsageStore((s15) => s15.runCost);
30589
31362
  const runCacheHitRate = useUsageStore((s15) => s15.runCacheHitRate);
30590
31363
  const allTimeTokens = useUsageStore((s15) => s15.allTimeTokens);
@@ -30626,12 +31399,12 @@ function StatusBar() {
30626
31399
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
30627
31400
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 whitespace-nowrap", children: [
30628
31401
  hasRunUsage && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30629
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
31402
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { title: `In: ${formatTokens(runPromptTokens)} · Cache: ${formatTokens(runCachedTokens)} · Out: ${formatTokens(runCompletionTokens)}`, children: [
30630
31403
  formatTokens(runTokens),
30631
31404
  " tokens"
30632
31405
  ] }),
30633
31406
  runCost > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-success", children: formatCost(runCost) }),
30634
- 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: [
30635
31408
  Math.round(runCacheHitRate * 100),
30636
31409
  "% cache"
30637
31410
  ] })
@@ -39390,6 +40163,53 @@ class ErrorBoundary extends reactExports.Component {
39390
40163
  ] }) });
39391
40164
  }
39392
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
+ }));
39393
40213
  const api = window.api;
39394
40214
  function FolderGate({ onOpenSettings }) {
39395
40215
  const pickFolder = useSessionStore((s15) => s15.pickFolder);
@@ -39521,6 +40341,16 @@ function App() {
39521
40341
  });
39522
40342
  }
39523
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
+ }
39524
40354
  });
39525
40355
  api.getCurrentSession().then((session) => {
39526
40356
  useChatStore.getState().loadInitial(session.sessionId);
@@ -39536,14 +40366,26 @@ function App() {
39536
40366
  });
39537
40367
  const unsubActivityClear = api.onActivityClear(() => {
39538
40368
  useActivityStore.getState().clear();
40369
+ useToolProgressStore.getState().clearAll();
40370
+ useToolEventsStore.getState().clearRun();
39539
40371
  useUsageStore.getState().resetRun();
39540
40372
  });
39541
40373
  const unsubActivity = api.onActivity((event) => {
39542
- useActivityStore.getState().push({
40374
+ const enrichedEvent = {
39543
40375
  id: `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
39544
40376
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
39545
40377
  ...event
39546
- });
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);
39547
40389
  });
39548
40390
  const unsubSkillLoaded = api.onSkillLoaded((skillName) => {
39549
40391
  useActivityStore.getState().addSkill(skillName);
@@ -39590,6 +40432,7 @@ function App() {
39590
40432
  unsub6();
39591
40433
  unsubActivity();
39592
40434
  unsubActivityClear();
40435
+ unsubToolProgress();
39593
40436
  unsubSkillLoaded();
39594
40437
  unsubUsage();
39595
40438
  };