@chenlongapps/opencode-token-usage 0.4.8 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import { memo as _$memo } from "@opentui/solid";
2
2
  import { use as _$use } from "@opentui/solid";
3
+ import { effect as _$effect } from "@opentui/solid";
3
4
  import { insert as _$insert } from "@opentui/solid";
4
5
  import { createComponent as _$createComponent } from "@opentui/solid";
5
- import { effect as _$effect } from "@opentui/solid";
6
6
  import { createTextNode as _$createTextNode } from "@opentui/solid";
7
7
  import { insertNode as _$insertNode } from "@opentui/solid";
8
+ import { spread as _$spread } from "@opentui/solid";
9
+ import { mergeProps as _$mergeProps } from "@opentui/solid";
8
10
  import { setProp as _$setProp } from "@opentui/solid";
9
11
  import { createElement as _$createElement } from "@opentui/solid";
10
12
  import { Plugin } from "@opencode/plugin/tui";
@@ -12,10 +14,14 @@ import { useTerminalDimensions } from "@opentui/solid";
12
14
  import { createEffect, createMemo, createSignal, For, onCleanup, Show } from "solid-js";
13
15
  import { UsageController } from "./controller.js";
14
16
  import { PerformanceMonitor } from "./performance.js";
17
+ import { RuntimeMonitor } from "./runtime-monitor.js";
18
+ import { ContextSourceRpc } from "./context-rpc.js";
15
19
  import { breakdownRows } from "./context-sources.js";
20
+ import { createClickHandlers } from "./click.js";
16
21
  import { createSource } from "./source.js";
17
22
  import { bar, countLabel, fitUsageSummary, formatCompact, formatEstimatedCost, formatRateTier, formatRunTime, formatTokens, rateRows, requestRows, summaryRows, usageRows } from "./usage.js";
18
23
  function UsageView(props) {
24
+ const titleClick = createClickHandlers(() => props.openDetails?.(), () => !!props.context.renderer.getSelection()?.getSelectedText());
19
25
  const rows = createMemo(() => usageRows(props.state().summary, props.state().context, props.state().performance, props.state().runtime));
20
26
  const performanceStart = createMemo(() => rows().findIndex(([label]) => label === "Run Time" || label === "TPS" || label === "TTFT"));
21
27
  const status = () => ({
@@ -36,8 +42,12 @@ function UsageView(props) {
36
42
  var _el$2 = _$createElement("text"),
37
43
  _el$3 = _$createElement("b");
38
44
  _$insertNode(_el$2, _el$3);
45
+ _$spread(_el$2, _$mergeProps({
46
+ get fg() {
47
+ return props.context.theme.text.base;
48
+ }
49
+ }, titleClick), true);
39
50
  _$insertNode(_el$3, _$createTextNode(`Token Usage`));
40
- _$effect(_$p => _$setProp(_el$2, "fg", props.context.theme.text.base, _$p));
41
51
  return _el$2;
42
52
  }
43
53
  }), null);
@@ -92,9 +102,12 @@ function UsagePanel(props) {
92
102
  });
93
103
  const controller = new UsageController(createSource(props.context.client), listener => props.context.data.listen(({
94
104
  details
95
- }) => listener(details)), setState, 80, 3_000, 100, props.performance);
105
+ }) => listener(details)), setState, 80, 3_000, 100, props.performance, false, props.runtime);
96
106
  const unregister = props.register(controller);
97
- createEffect(() => controller.select(props.sessionID));
107
+ createEffect(() => {
108
+ controller.select(props.sessionID);
109
+ controller.setRunning(props.context.data.session.status(props.sessionID) === "running");
110
+ });
98
111
  onCleanup(() => {
99
112
  controller.dispose();
100
113
  unregister();
@@ -103,7 +116,8 @@ function UsagePanel(props) {
103
116
  get context() {
104
117
  return props.context;
105
118
  },
106
- state: state
119
+ state: state,
120
+ openDetails: () => props.open(props.sessionID)
107
121
  });
108
122
  }
109
123
  function ChildUsageDialog(props) {
@@ -200,14 +214,18 @@ function ChildUsageLauncher(props) {
200
214
  });
201
215
  const controller = new UsageController(createSource(props.context.client), listener => props.context.data.listen(({
202
216
  details
203
- }) => listener(details)), setState, 80, 3_000, 100, props.performance);
217
+ }) => listener(details)), setState, 80, 3_000, 100, props.performance, false, props.runtime);
204
218
  const unregister = props.register(controller);
205
- createEffect(() => controller.select(props.sessionID));
219
+ createEffect(() => {
220
+ controller.select(props.sessionID);
221
+ controller.setRunning(props.context.data.session.status(props.sessionID) === "running");
222
+ });
206
223
  onCleanup(() => {
207
224
  controller.dispose();
208
225
  unregister();
209
226
  });
210
227
  const dimensions = useTerminalDimensions();
228
+ const runtime = createMemo(() => formatRunTime(state().runtime, true));
211
229
  const summary = createMemo(() => {
212
230
  const current = state();
213
231
  if (!current.summary) return `Token Usage · ${{
@@ -219,7 +237,7 @@ function ChildUsageLauncher(props) {
219
237
  const context = current.context ? `${formatTokens(current.context.used)} / ${formatTokens(current.context.limit)} (${current.context.percent.toFixed(1)}%)` : "—";
220
238
  const cost = formatEstimatedCost(current.summary.cost, current.summary.costStatus) ?? "—";
221
239
  const tps = current.performance?.tps !== undefined && Number.isFinite(current.performance.tps) ? `${current.performance.tpsEstimated ? "~" : ""}${Math.max(0, current.performance.tps).toFixed(1)} tok/s` : "—";
222
- return fitUsageSummary([["Context", context], ["Total", formatTokens(current.summary.total)], ["Cost", cost], ["Time", formatRunTime(current.runtime, true)], ["TPS", tps]], Math.max(20, dimensions().width - 8), current.status === "stale");
240
+ return fitUsageSummary([["Context", context], ["Total", formatTokens(current.summary.total)], ["Cost", cost], ["Time", runtime()], ["TPS", tps]], Math.max(20, dimensions().width - 8), current.status === "stale");
223
241
  });
224
242
  return (() => {
225
243
  var _el$17 = _$createElement("box"),
@@ -231,7 +249,7 @@ function ChildUsageLauncher(props) {
231
249
  _$setProp(_el$17, "flexShrink", 0);
232
250
  _$setProp(_el$18, "wrapMode", "none");
233
251
  _$setProp(_el$18, "onMouseUp", event => {
234
- if (event.button === 0) props.open(props.sessionID, state);
252
+ if (event.button === 0) props.open(state);
235
253
  });
236
254
  _$insert(_el$18, summary);
237
255
  _$effect(_$p => _$setProp(_el$18, "fg", props.context.theme.text.muted, _$p));
@@ -246,9 +264,10 @@ function UsageDialog(props) {
246
264
  const dimensions = useTerminalDimensions();
247
265
  const controller = new UsageController(createSource(props.context.client), listener => props.context.data.listen(({
248
266
  details
249
- }) => listener(details)), setState, 80, 3_000, 100, props.performance, true);
267
+ }) => listener(details)), setState, 80, 3_000, 100, props.performance, true, props.runtime);
250
268
  const unregister = props.register(controller);
251
269
  controller.select(props.sessionID);
270
+ createEffect(() => controller.setRunning(props.context.data.session.status(props.sessionID) === "running"));
252
271
  onCleanup(() => {
253
272
  controller.dispose();
254
273
  unregister();
@@ -298,6 +317,7 @@ function UsageDialog(props) {
298
317
  }));
299
318
  const theme = () => props.context.theme.text;
300
319
  const context = createMemo(() => state().context);
320
+ const runtime = createMemo(() => formatRunTime(state().runtime));
301
321
  const request = createMemo(() => state().details?.request);
302
322
  const requestTime = createMemo(() => {
303
323
  const time = request()?.time;
@@ -405,12 +425,12 @@ function UsageDialog(props) {
405
425
  _el$30 = _$createElement("text"),
406
426
  _el$31 = _$createElement("b"),
407
427
  _el$33 = _$createElement("text"),
408
- _el$67 = _$createElement("box"),
409
- _el$68 = _$createElement("text"),
410
- _el$70 = _$createElement("text"),
411
- _el$72 = _$createElement("text");
428
+ _el$63 = _$createElement("box"),
429
+ _el$64 = _$createElement("text"),
430
+ _el$66 = _$createElement("text"),
431
+ _el$68 = _$createElement("text");
412
432
  _$insertNode(_el$28, _el$29);
413
- _$insertNode(_el$28, _el$67);
433
+ _$insertNode(_el$28, _el$63);
414
434
  _$setProp(_el$28, "paddingLeft", 2);
415
435
  _$setProp(_el$28, "paddingRight", 2);
416
436
  _$setProp(_el$28, "paddingBottom", 1);
@@ -435,7 +455,7 @@ function UsageDialog(props) {
435
455
  _$effect(_$p => _$setProp(_el$35, "fg", theme().muted, _$p));
436
456
  return _el$35;
437
457
  }
438
- }), _el$67);
458
+ }), _el$63);
439
459
  _$insert(_el$28, _$createComponent(Show, {
440
460
  get when() {
441
461
  return state().status !== "ready";
@@ -446,7 +466,7 @@ function UsageDialog(props) {
446
466
  _$effect(_$p => _$setProp(_el$36, "fg", theme().muted, _$p));
447
467
  return _el$36;
448
468
  }
449
- }), _el$67);
469
+ }), _el$63);
450
470
  _$insert(_el$28, _$createComponent(Show, {
451
471
  get when() {
452
472
  return state().summary;
@@ -470,10 +490,7 @@ function UsageDialog(props) {
470
490
  _el$55 = _$createElement("b"),
471
491
  _el$57 = _$createElement("box"),
472
492
  _el$58 = _$createElement("text"),
473
- _el$60 = _$createElement("text"),
474
- _el$61 = _$createElement("box"),
475
- _el$62 = _$createElement("text"),
476
- _el$63 = _$createElement("b");
493
+ _el$59 = _$createElement("b");
477
494
  _$insertNode(_el$37, _el$38);
478
495
  _$use(value => {
479
496
  scroll = value;
@@ -488,7 +505,7 @@ function UsageDialog(props) {
488
505
  _$insertNode(_el$38, _el$43);
489
506
  _$insertNode(_el$38, _el$48);
490
507
  _$insertNode(_el$38, _el$53);
491
- _$insertNode(_el$38, _el$61);
508
+ _$insertNode(_el$38, _el$57);
492
509
  _$setProp(_el$38, "gap", 1);
493
510
  _$insertNode(_el$39, _el$40);
494
511
  _$insertNode(_el$40, _el$41);
@@ -499,48 +516,48 @@ function UsageDialog(props) {
499
516
  },
500
517
  get fallback() {
501
518
  return (() => {
502
- var _el$74 = _$createElement("text");
503
- _$insertNode(_el$74, _$createTextNode(`Context usage unavailable`));
504
- _$effect(_$p => _$setProp(_el$74, "fg", theme().muted, _$p));
505
- return _el$74;
519
+ var _el$70 = _$createElement("text");
520
+ _$insertNode(_el$70, _$createTextNode(`Context usage unavailable`));
521
+ _$effect(_$p => _$setProp(_el$70, "fg", theme().muted, _$p));
522
+ return _el$70;
506
523
  })();
507
524
  },
508
525
  children: details => (() => {
509
- var _el$76 = _$createElement("box"),
510
- _el$77 = _$createElement("box"),
511
- _el$78 = _$createElement("text"),
512
- _el$80 = _$createElement("text"),
513
- _el$81 = _$createTextNode(` / `),
514
- _el$82 = _$createTextNode(` (`),
515
- _el$83 = _$createTextNode(`%)`);
526
+ var _el$72 = _$createElement("box"),
527
+ _el$73 = _$createElement("box"),
528
+ _el$74 = _$createElement("text"),
529
+ _el$76 = _$createElement("text"),
530
+ _el$77 = _$createTextNode(` / `),
531
+ _el$78 = _$createTextNode(` (`),
532
+ _el$79 = _$createTextNode(`%)`);
533
+ _$insertNode(_el$72, _el$73);
534
+ _$insertNode(_el$73, _el$74);
535
+ _$insertNode(_el$73, _el$76);
536
+ _$setProp(_el$73, "flexDirection", "row");
537
+ _$setProp(_el$73, "justifyContent", "space-between");
538
+ _$setProp(_el$73, "gap", 2);
539
+ _$insertNode(_el$74, _$createTextNode(`Used / Limit`));
540
+ _$setProp(_el$74, "flexShrink", 0);
516
541
  _$insertNode(_el$76, _el$77);
517
- _$insertNode(_el$77, _el$78);
518
- _$insertNode(_el$77, _el$80);
519
- _$setProp(_el$77, "flexDirection", "row");
520
- _$setProp(_el$77, "justifyContent", "space-between");
521
- _$setProp(_el$77, "gap", 2);
522
- _$insertNode(_el$78, _$createTextNode(`Used / Limit`));
523
- _$setProp(_el$78, "flexShrink", 0);
524
- _$insertNode(_el$80, _el$81);
525
- _$insertNode(_el$80, _el$82);
526
- _$insertNode(_el$80, _el$83);
527
- _$setProp(_el$80, "wrapMode", "word");
528
- _$setProp(_el$80, "minWidth", 0);
529
- _$insert(_el$80, () => number(details().used), _el$81);
530
- _$insert(_el$80, () => number(details().limit), _el$82);
531
- _$insert(_el$80, () => details().percent.toFixed(1), _el$83);
532
- _$insert(_el$76, () => barRow(details().percent, windowBar()), null);
542
+ _$insertNode(_el$76, _el$78);
543
+ _$insertNode(_el$76, _el$79);
544
+ _$setProp(_el$76, "wrapMode", "word");
545
+ _$setProp(_el$76, "minWidth", 0);
546
+ _$insert(_el$76, () => number(details().used), _el$77);
547
+ _$insert(_el$76, () => number(details().limit), _el$78);
548
+ _$insert(_el$76, () => details().percent.toFixed(1), _el$79);
549
+ _$insert(_el$72, () => barRow(details().percent, windowBar()), null);
533
550
  _$effect(_p$ => {
534
- var _v$23 = theme().muted,
535
- _v$24 = theme().base;
536
- _v$23 !== _p$.e && (_p$.e = _$setProp(_el$78, "fg", _v$23, _p$.e));
537
- _v$24 !== _p$.t && (_p$.t = _$setProp(_el$80, "fg", _v$24, _p$.t));
551
+ var _v$21 = theme().muted,
552
+ _v$22 = theme().base;
553
+ _v$21 !== _p$.e && (_p$.e = _$setProp(_el$74, "fg", _v$21, _p$.e));
554
+ _v$22 !== _p$.t && (_p$.t = _$setProp(_el$76, "fg", _v$22, _p$.t));
538
555
  return _p$;
539
556
  }, {
540
557
  e: undefined,
541
558
  t: undefined
542
559
  });
543
- return _el$76;
560
+ return _el$72;
544
561
  })()
545
562
  }), null);
546
563
  _$insertNode(_el$43, _el$44);
@@ -555,10 +572,10 @@ function UsageDialog(props) {
555
572
  return requestTime();
556
573
  },
557
574
  children: time => (() => {
558
- var _el$84 = _$createElement("text");
559
- _$insert(_el$84, time);
560
- _$effect(_$p => _$setProp(_el$84, "fg", theme().muted, _$p));
561
- return _el$84;
575
+ var _el$80 = _$createElement("text");
576
+ _$insert(_el$80, time);
577
+ _$effect(_$p => _$setProp(_el$80, "fg", theme().muted, _$p));
578
+ return _el$80;
562
579
  })()
563
580
  }), null);
564
581
  _$insert(_el$43, _$createComponent(Show, {
@@ -567,16 +584,16 @@ function UsageDialog(props) {
567
584
  },
568
585
  get fallback() {
569
586
  return (() => {
570
- var _el$85 = _$createElement("text");
571
- _$insertNode(_el$85, _$createTextNode(`Request usage unavailable`));
572
- _$effect(_$p => _$setProp(_el$85, "fg", theme().muted, _$p));
573
- return _el$85;
587
+ var _el$81 = _$createElement("text");
588
+ _$insertNode(_el$81, _$createTextNode(`Request usage unavailable`));
589
+ _$effect(_$p => _$setProp(_el$81, "fg", theme().muted, _$p));
590
+ return _el$81;
574
591
  })();
575
592
  },
576
593
  children: details => (() => {
577
- var _el$87 = _$createElement("box");
578
- _$insert(_el$87, () => requestRowsList(requestRows(details(), compact())));
579
- return _el$87;
594
+ var _el$83 = _$createElement("box");
595
+ _$insert(_el$83, () => requestRowsList(requestRows(details(), compact())));
596
+ return _el$83;
580
597
  })()
581
598
  }), null);
582
599
  _$insertNode(_el$48, _el$49);
@@ -591,10 +608,10 @@ function UsageDialog(props) {
591
608
  return sources();
592
609
  },
593
610
  children: captured => (() => {
594
- var _el$88 = _$createElement("text");
595
- _$insert(_el$88, () => new Date(captured().capturedAt).toLocaleTimeString());
596
- _$effect(_$p => _$setProp(_el$88, "fg", theme().muted, _$p));
597
- return _el$88;
611
+ var _el$84 = _$createElement("text");
612
+ _$insert(_el$84, () => new Date(captured().capturedAt).toLocaleTimeString());
613
+ _$effect(_$p => _$setProp(_el$84, "fg", theme().muted, _$p));
614
+ return _el$84;
598
615
  })()
599
616
  }), null);
600
617
  _$insert(_el$48, _$createComponent(Show, {
@@ -603,10 +620,10 @@ function UsageDialog(props) {
603
620
  },
604
621
  get fallback() {
605
622
  return (() => {
606
- var _el$89 = _$createElement("text");
607
- _$insertNode(_el$89, _$createTextNode(`Source estimates unavailable (no request snapshot or RPC)`));
608
- _$effect(_$p => _$setProp(_el$89, "fg", theme().muted, _$p));
609
- return _el$89;
623
+ var _el$85 = _$createElement("text");
624
+ _$insertNode(_el$85, _$createTextNode(`Source estimates unavailable (no request snapshot or RPC)`));
625
+ _$effect(_$p => _$setProp(_el$85, "fg", theme().muted, _$p));
626
+ return _el$85;
610
627
  })();
611
628
  },
612
629
  children: captured => _$createComponent(For, {
@@ -614,39 +631,39 @@ function UsageDialog(props) {
614
631
  return breakdownRows(captured(), detailed());
615
632
  },
616
633
  children: row => (() => {
617
- var _el$91 = _$createElement("box"),
618
- _el$92 = _$createElement("box"),
619
- _el$93 = _$createElement("text"),
620
- _el$94 = _$createElement("box"),
621
- _el$95 = _$createElement("text"),
622
- _el$96 = _$createElement("text"),
623
- _el$97 = _$createTextNode(`%`);
624
- _$insertNode(_el$91, _el$92);
625
- _$insertNode(_el$91, _el$94);
626
- _$insertNode(_el$91, _el$95);
627
- _$insertNode(_el$91, _el$96);
628
- _$setProp(_el$91, "flexDirection", "row");
629
- _$setProp(_el$91, "gap", 1);
634
+ var _el$87 = _$createElement("box"),
635
+ _el$88 = _$createElement("box"),
636
+ _el$89 = _$createElement("text"),
637
+ _el$90 = _$createElement("box"),
638
+ _el$91 = _$createElement("text"),
639
+ _el$92 = _$createElement("text"),
640
+ _el$93 = _$createTextNode(`%`);
641
+ _$insertNode(_el$87, _el$88);
642
+ _$insertNode(_el$87, _el$90);
643
+ _$insertNode(_el$87, _el$91);
644
+ _$insertNode(_el$87, _el$92);
645
+ _$setProp(_el$87, "flexDirection", "row");
646
+ _$setProp(_el$87, "gap", 1);
647
+ _$insertNode(_el$88, _el$89);
648
+ _$setProp(_el$88, "width", 14);
649
+ _$setProp(_el$88, "flexShrink", 0);
650
+ _$insert(_el$89, () => row.label);
651
+ _$setProp(_el$90, "flexShrink", 0);
652
+ _$insert(_el$90, () => barRow(row.percent, breakdownBar()));
653
+ _$setProp(_el$91, "flexShrink", 0);
654
+ _$insert(_el$91, () => number(row.tokens));
630
655
  _$insertNode(_el$92, _el$93);
631
- _$setProp(_el$92, "width", 14);
632
656
  _$setProp(_el$92, "flexShrink", 0);
633
- _$insert(_el$93, () => row.label);
634
- _$setProp(_el$94, "flexShrink", 0);
635
- _$insert(_el$94, () => barRow(row.percent, breakdownBar()));
636
- _$setProp(_el$95, "flexShrink", 0);
637
- _$insert(_el$95, () => number(row.tokens));
638
- _$insertNode(_el$96, _el$97);
639
- _$setProp(_el$96, "flexShrink", 0);
640
- _$insert(_el$96, () => row.percent.toFixed(1), _el$97);
657
+ _$insert(_el$92, () => row.percent.toFixed(1), _el$93);
641
658
  _$effect(_p$ => {
642
- var _v$25 = theme().muted,
643
- _v$26 = breakdownBar(),
644
- _v$27 = theme().base,
645
- _v$28 = theme().muted;
646
- _v$25 !== _p$.e && (_p$.e = _$setProp(_el$93, "fg", _v$25, _p$.e));
647
- _v$26 !== _p$.t && (_p$.t = _$setProp(_el$94, "width", _v$26, _p$.t));
648
- _v$27 !== _p$.a && (_p$.a = _$setProp(_el$95, "fg", _v$27, _p$.a));
649
- _v$28 !== _p$.o && (_p$.o = _$setProp(_el$96, "fg", _v$28, _p$.o));
659
+ var _v$23 = theme().muted,
660
+ _v$24 = breakdownBar(),
661
+ _v$25 = theme().base,
662
+ _v$26 = theme().muted;
663
+ _v$23 !== _p$.e && (_p$.e = _$setProp(_el$89, "fg", _v$23, _p$.e));
664
+ _v$24 !== _p$.t && (_p$.t = _$setProp(_el$90, "width", _v$24, _p$.t));
665
+ _v$25 !== _p$.a && (_p$.a = _$setProp(_el$91, "fg", _v$25, _p$.a));
666
+ _v$26 !== _p$.o && (_p$.o = _$setProp(_el$92, "fg", _v$26, _p$.o));
650
667
  return _p$;
651
668
  }, {
652
669
  e: undefined,
@@ -654,12 +671,11 @@ function UsageDialog(props) {
654
671
  a: undefined,
655
672
  o: undefined
656
673
  });
657
- return _el$91;
674
+ return _el$87;
658
675
  })()
659
676
  })
660
677
  }), null);
661
678
  _$insertNode(_el$53, _el$54);
662
- _$insertNode(_el$53, _el$57);
663
679
  _$insertNode(_el$54, _el$55);
664
680
  _$insertNode(_el$55, _$createTextNode(`Session`));
665
681
  _$insert(_el$53, _$createComponent(Show, {
@@ -668,10 +684,10 @@ function UsageDialog(props) {
668
684
  },
669
685
  get fallback() {
670
686
  return (() => {
671
- var _el$98 = _$createElement("text");
672
- _$insertNode(_el$98, _$createTextNode(`Session usage unavailable`));
673
- _$effect(_$p => _$setProp(_el$98, "fg", theme().muted, _$p));
674
- return _el$98;
687
+ var _el$94 = _$createElement("text");
688
+ _$insertNode(_el$94, _$createTextNode(`Session usage unavailable`));
689
+ _$effect(_$p => _$setProp(_el$94, "fg", theme().muted, _$p));
690
+ return _el$94;
675
691
  })();
676
692
  },
677
693
  children: summary => _$createComponent(Show, {
@@ -680,26 +696,26 @@ function UsageDialog(props) {
680
696
  },
681
697
  get fallback() {
682
698
  return (() => {
683
- var _el$100 = _$createElement("text"),
684
- _el$101 = _$createTextNode(` · `),
685
- _el$102 = _$createTextNode(` · `),
686
- _el$103 = _$createTextNode(` tokens · `),
687
- _el$104 = _$createTextNode(`% cached`);
688
- _$insertNode(_el$100, _el$101);
689
- _$insertNode(_el$100, _el$102);
690
- _$insertNode(_el$100, _el$103);
691
- _$insertNode(_el$100, _el$104);
692
- _$setProp(_el$100, "wrapMode", "word");
693
- _$insert(_el$100, () => countLabel(summary().steps, "step"), _el$101);
694
- _$insert(_el$100, () => countLabel(summary().calls, "call"), _el$102);
695
- _$insert(_el$100, () => formatCompact(summary().total), _el$103);
696
- _$insert(_el$100, () => (summary().cacheRate * 100).toFixed(1), _el$104);
697
- _$insert(_el$100, (() => {
699
+ var _el$96 = _$createElement("text"),
700
+ _el$97 = _$createTextNode(` · `),
701
+ _el$98 = _$createTextNode(` · `),
702
+ _el$99 = _$createTextNode(` tokens · `),
703
+ _el$100 = _$createTextNode(`% cached`);
704
+ _$insertNode(_el$96, _el$97);
705
+ _$insertNode(_el$96, _el$98);
706
+ _$insertNode(_el$96, _el$99);
707
+ _$insertNode(_el$96, _el$100);
708
+ _$setProp(_el$96, "wrapMode", "word");
709
+ _$insert(_el$96, () => countLabel(summary().steps, "step"), _el$97);
710
+ _$insert(_el$96, () => countLabel(summary().calls, "call"), _el$98);
711
+ _$insert(_el$96, () => formatCompact(summary().total), _el$99);
712
+ _$insert(_el$96, () => (summary().cacheRate * 100).toFixed(1), _el$100);
713
+ _$insert(_el$96, (() => {
698
714
  var _c$ = _$memo(() => !!formatEstimatedCost(summary().cost, summary().costStatus));
699
715
  return () => _c$() ? ` · ${formatEstimatedCost(summary().cost, summary().costStatus)}` : "";
700
716
  })(), null);
701
- _$effect(_$p => _$setProp(_el$100, "fg", theme().base, _$p));
702
- return _el$100;
717
+ _$effect(_$p => _$setProp(_el$96, "fg", theme().base, _$p));
718
+ return _el$96;
703
719
  })();
704
720
  },
705
721
  get children() {
@@ -708,60 +724,81 @@ function UsageDialog(props) {
708
724
  return summaryRows(summary());
709
725
  },
710
726
  children: ([label, value]) => (() => {
711
- var _el$105 = _$createElement("box"),
712
- _el$106 = _$createElement("text"),
713
- _el$107 = _$createElement("text");
714
- _$insertNode(_el$105, _el$106);
715
- _$insertNode(_el$105, _el$107);
716
- _$setProp(_el$105, "flexDirection", "row");
717
- _$setProp(_el$105, "justifyContent", "space-between");
718
- _$setProp(_el$105, "gap", 2);
719
- _$setProp(_el$106, "flexShrink", 0);
720
- _$insert(_el$106, label);
721
- _$insert(_el$107, value);
727
+ var _el$101 = _$createElement("box"),
728
+ _el$102 = _$createElement("text"),
729
+ _el$103 = _$createElement("text");
730
+ _$insertNode(_el$101, _el$102);
731
+ _$insertNode(_el$101, _el$103);
732
+ _$setProp(_el$101, "flexDirection", "row");
733
+ _$setProp(_el$101, "justifyContent", "space-between");
734
+ _$setProp(_el$101, "gap", 2);
735
+ _$setProp(_el$102, "flexShrink", 0);
736
+ _$insert(_el$102, label);
737
+ _$insert(_el$103, value);
722
738
  _$effect(_p$ => {
723
- var _v$29 = theme().muted,
724
- _v$30 = theme().base;
725
- _v$29 !== _p$.e && (_p$.e = _$setProp(_el$106, "fg", _v$29, _p$.e));
726
- _v$30 !== _p$.t && (_p$.t = _$setProp(_el$107, "fg", _v$30, _p$.t));
739
+ var _v$27 = theme().muted,
740
+ _v$28 = theme().base;
741
+ _v$27 !== _p$.e && (_p$.e = _$setProp(_el$102, "fg", _v$27, _p$.e));
742
+ _v$28 !== _p$.t && (_p$.t = _$setProp(_el$103, "fg", _v$28, _p$.t));
727
743
  return _p$;
728
744
  }, {
729
745
  e: undefined,
730
746
  t: undefined
731
747
  });
732
- return _el$105;
748
+ return _el$101;
733
749
  })()
734
750
  });
735
751
  }
736
752
  })
737
- }), _el$57);
753
+ }), null);
754
+ _$insert(_el$53, _$createComponent(Show, {
755
+ get when() {
756
+ return runtime();
757
+ },
758
+ children: time => (() => {
759
+ var _el$104 = _$createElement("box"),
760
+ _el$105 = _$createElement("text"),
761
+ _el$107 = _$createElement("text");
762
+ _$insertNode(_el$104, _el$105);
763
+ _$insertNode(_el$104, _el$107);
764
+ _$setProp(_el$104, "flexDirection", "row");
765
+ _$setProp(_el$104, "justifyContent", "space-between");
766
+ _$setProp(_el$104, "gap", 2);
767
+ _$insertNode(_el$105, _$createTextNode(`Run Time (this session)`));
768
+ _$setProp(_el$105, "wrapMode", "word");
769
+ _$setProp(_el$105, "minWidth", 0);
770
+ _$setProp(_el$107, "wrapMode", "word");
771
+ _$setProp(_el$107, "minWidth", 0);
772
+ _$insert(_el$107, time);
773
+ _$effect(_p$ => {
774
+ var _v$29 = theme().muted,
775
+ _v$30 = theme().base;
776
+ _v$29 !== _p$.e && (_p$.e = _$setProp(_el$105, "fg", _v$29, _p$.e));
777
+ _v$30 !== _p$.t && (_p$.t = _$setProp(_el$107, "fg", _v$30, _p$.t));
778
+ return _p$;
779
+ }, {
780
+ e: undefined,
781
+ t: undefined
782
+ });
783
+ return _el$104;
784
+ })()
785
+ }), null);
738
786
  _$insertNode(_el$57, _el$58);
739
- _$insertNode(_el$57, _el$60);
740
- _$setProp(_el$57, "flexDirection", "row");
741
- _$setProp(_el$57, "justifyContent", "space-between");
742
- _$setProp(_el$57, "gap", 2);
743
- _$insertNode(_el$58, _$createTextNode(`Run Time (this session)`));
744
- _$setProp(_el$58, "wrapMode", "word");
745
- _$setProp(_el$58, "minWidth", 0);
746
- _$setProp(_el$60, "wrapMode", "word");
747
- _$setProp(_el$60, "minWidth", 0);
748
- _$insert(_el$60, () => formatRunTime(state().runtime));
749
- _$insertNode(_el$61, _el$62);
750
- _$insertNode(_el$62, _el$63);
751
- _$insertNode(_el$63, _$createTextNode(`By Model`));
752
- _$insert(_el$61, _$createComponent(Show, {
787
+ _$insertNode(_el$58, _el$59);
788
+ _$insertNode(_el$59, _$createTextNode(`By Model`));
789
+ _$insert(_el$57, _$createComponent(Show, {
753
790
  get when() {
754
791
  return _$memo(() => !!detailed())() && models().length;
755
792
  },
756
793
  get children() {
757
- var _el$65 = _$createElement("text");
758
- _$insertNode(_el$65, _$createTextNode(`Rates used for Est. Cost · USD / 1M text tokens · incoming = Input + Cache Read + Cache Write`));
759
- _$setProp(_el$65, "wrapMode", "word");
760
- _$effect(_$p => _$setProp(_el$65, "fg", theme().muted, _$p));
761
- return _el$65;
794
+ var _el$61 = _$createElement("text");
795
+ _$insertNode(_el$61, _$createTextNode(`Rates used for Est. Cost · USD / 1M text tokens · incoming = Input + Cache Read + Cache Write`));
796
+ _$setProp(_el$61, "wrapMode", "word");
797
+ _$effect(_$p => _$setProp(_el$61, "fg", theme().muted, _$p));
798
+ return _el$61;
762
799
  }
763
800
  }), null);
764
- _$insert(_el$61, _$createComponent(Show, {
801
+ _$insert(_el$57, _$createComponent(Show, {
765
802
  get when() {
766
803
  return models().length;
767
804
  },
@@ -867,17 +904,13 @@ function UsageDialog(props) {
867
904
  _v$12 = theme().base,
868
905
  _v$13 = theme().base,
869
906
  _v$14 = theme().base,
870
- _v$15 = theme().muted,
871
- _v$16 = theme().base,
872
- _v$17 = theme().base;
907
+ _v$15 = theme().base;
873
908
  _v$10 !== _p$.e && (_p$.e = _$setProp(_el$37, "maxHeight", _v$10, _p$.e));
874
909
  _v$11 !== _p$.t && (_p$.t = _$setProp(_el$40, "fg", _v$11, _p$.t));
875
910
  _v$12 !== _p$.a && (_p$.a = _$setProp(_el$45, "fg", _v$12, _p$.a));
876
911
  _v$13 !== _p$.o && (_p$.o = _$setProp(_el$50, "fg", _v$13, _p$.o));
877
912
  _v$14 !== _p$.i && (_p$.i = _$setProp(_el$54, "fg", _v$14, _p$.i));
878
913
  _v$15 !== _p$.n && (_p$.n = _$setProp(_el$58, "fg", _v$15, _p$.n));
879
- _v$16 !== _p$.s && (_p$.s = _$setProp(_el$60, "fg", _v$16, _p$.s));
880
- _v$17 !== _p$.h && (_p$.h = _$setProp(_el$62, "fg", _v$17, _p$.h));
881
914
  return _p$;
882
915
  }, {
883
916
  e: undefined,
@@ -885,34 +918,32 @@ function UsageDialog(props) {
885
918
  a: undefined,
886
919
  o: undefined,
887
920
  i: undefined,
888
- n: undefined,
889
- s: undefined,
890
- h: undefined
921
+ n: undefined
891
922
  });
892
923
  return _el$37;
893
924
  }
894
- }), _el$67);
895
- _$insertNode(_el$67, _el$68);
896
- _$insertNode(_el$67, _el$70);
897
- _$insertNode(_el$67, _el$72);
898
- _$setProp(_el$67, "flexDirection", "row");
899
- _$insertNode(_el$68, _$createTextNode(`↑/↓ scroll · `));
900
- _$insertNode(_el$70, _$createTextNode(`d details`));
901
- _$setProp(_el$70, "onMouseUp", event => {
925
+ }), _el$63);
926
+ _$insertNode(_el$63, _el$64);
927
+ _$insertNode(_el$63, _el$66);
928
+ _$insertNode(_el$63, _el$68);
929
+ _$setProp(_el$63, "flexDirection", "row");
930
+ _$insertNode(_el$64, _$createTextNode(`↑/↓ scroll · `));
931
+ _$insertNode(_el$66, _$createTextNode(`d details`));
932
+ _$setProp(_el$66, "onMouseUp", event => {
902
933
  if (event.button === 0) toggleDetails();
903
934
  });
904
- _$insertNode(_el$72, _$createTextNode(` · esc close`));
935
+ _$insertNode(_el$68, _$createTextNode(` · esc close`));
905
936
  _$effect(_p$ => {
906
- var _v$18 = theme().base,
937
+ var _v$16 = theme().base,
938
+ _v$17 = theme().muted,
939
+ _v$18 = theme().muted,
907
940
  _v$19 = theme().muted,
908
- _v$20 = theme().muted,
909
- _v$21 = theme().muted,
910
- _v$22 = theme().muted;
911
- _v$18 !== _p$.e && (_p$.e = _$setProp(_el$30, "fg", _v$18, _p$.e));
912
- _v$19 !== _p$.t && (_p$.t = _$setProp(_el$33, "fg", _v$19, _p$.t));
913
- _v$20 !== _p$.a && (_p$.a = _$setProp(_el$68, "fg", _v$20, _p$.a));
914
- _v$21 !== _p$.o && (_p$.o = _$setProp(_el$70, "fg", _v$21, _p$.o));
915
- _v$22 !== _p$.i && (_p$.i = _$setProp(_el$72, "fg", _v$22, _p$.i));
941
+ _v$20 = theme().muted;
942
+ _v$16 !== _p$.e && (_p$.e = _$setProp(_el$30, "fg", _v$16, _p$.e));
943
+ _v$17 !== _p$.t && (_p$.t = _$setProp(_el$33, "fg", _v$17, _p$.t));
944
+ _v$18 !== _p$.a && (_p$.a = _$setProp(_el$64, "fg", _v$18, _p$.a));
945
+ _v$19 !== _p$.o && (_p$.o = _$setProp(_el$66, "fg", _v$19, _p$.o));
946
+ _v$20 !== _p$.i && (_p$.i = _$setProp(_el$68, "fg", _v$20, _p$.i));
916
947
  return _p$;
917
948
  }, {
918
949
  e: undefined,
@@ -930,6 +961,15 @@ export default Plugin.define({
930
961
  const performance = new PerformanceMonitor(listener => context.data.listen(({
931
962
  details
932
963
  }) => listener(details)));
964
+ const runtime = new RuntimeMonitor(listener => context.data.listen(({
965
+ details
966
+ }) => listener(details)));
967
+ const synchronizeRuntime = () => void runtime.synchronize(signal => context.client.rpc(ContextSourceRpc).clock({}, {
968
+ location: context.location ?? context.data.location.default(),
969
+ signal
970
+ }));
971
+ synchronizeRuntime();
972
+ const stopClockSync = context.data.on("server.connected", synchronizeRuntime);
933
973
  const controllers = new Set();
934
974
  const register = controller => {
935
975
  controllers.add(controller);
@@ -937,6 +977,19 @@ export default Plugin.define({
937
977
  controllers.delete(controller);
938
978
  };
939
979
  };
980
+ const openUsage = sessionID => {
981
+ context.ui.dialog.show(() => _$createComponent(UsageDialog, {
982
+ context: context,
983
+ sessionID: sessionID,
984
+ performance: performance,
985
+ runtime: runtime,
986
+ register: register
987
+ }));
988
+ context.ui.dialog.set({
989
+ size: "large",
990
+ centered: true
991
+ });
992
+ };
940
993
  const remove = context.ui.slot({
941
994
  append: "sidebar.content",
942
995
  render: props => _$createComponent(UsagePanel, {
@@ -945,10 +998,12 @@ export default Plugin.define({
945
998
  return props.sessionID;
946
999
  },
947
1000
  performance: performance,
948
- register: register
1001
+ runtime: runtime,
1002
+ register: register,
1003
+ open: openUsage
949
1004
  })
950
1005
  });
951
- const openChildUsage = (sessionID, state) => {
1006
+ const openChildUsage = state => {
952
1007
  context.ui.dialog.show(() => _$createComponent(ChildUsageDialog, {
953
1008
  context: context,
954
1009
  state: state
@@ -972,6 +1027,7 @@ export default Plugin.define({
972
1027
  return props.sessionID;
973
1028
  },
974
1029
  performance: performance,
1030
+ runtime: runtime,
975
1031
  register: register,
976
1032
  open: openChildUsage
977
1033
  });
@@ -995,18 +1051,7 @@ export default Plugin.define({
995
1051
  run: () => {
996
1052
  const route = context.ui.router.current();
997
1053
  if (route.type !== "session") return;
998
- context.ui.dialog.show(() => _$createComponent(UsageDialog, {
999
- context: context,
1000
- get sessionID() {
1001
- return route.sessionID;
1002
- },
1003
- performance: performance,
1004
- register: register
1005
- }));
1006
- context.ui.dialog.set({
1007
- size: "large",
1008
- centered: true
1009
- });
1054
+ openUsage(route.sessionID);
1010
1055
  }
1011
1056
  }]
1012
1057
  }));
@@ -1020,6 +1065,8 @@ export default Plugin.define({
1020
1065
  removeChild();
1021
1066
  removeCommand();
1022
1067
  performance.dispose();
1068
+ runtime.dispose();
1069
+ stopClockSync();
1023
1070
  };
1024
1071
  }
1025
1072
  });