@workerdeck/ui 0.22.0 → 1.0.0

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 (145) hide show
  1. package/build/{SessionPanel-DgwjH4Ve.mjs → SessionPanel-DDgBkHsi.mjs} +2196 -3364
  2. package/build/SessionPanel-DDgBkHsi.mjs.map +1 -0
  3. package/build/SessionPanel-E_L_ldQ5.d.mts +207 -0
  4. package/build/format-B8ZM9LPy.d.mts +16 -0
  5. package/build/format.d.mts +8 -75
  6. package/build/format.mjs +2 -2
  7. package/build/index.d.mts +63 -1138
  8. package/build/index.mjs +4 -300
  9. package/build/index.mjs.map +1 -1
  10. package/build/scoped.css +80 -24
  11. package/build/{status-BE-zg88x.mjs → status-C0HSLZas.mjs} +14 -85
  12. package/build/status-C0HSLZas.mjs.map +1 -0
  13. package/build/workspace.d.mts +9 -124
  14. package/build/workspace.mjs +13 -143
  15. package/build/workspace.mjs.map +1 -1
  16. package/package.json +4 -4
  17. package/src/components/agent/CodeEditor.tsx +31 -103
  18. package/src/components/agent/Composer.tsx +114 -333
  19. package/src/components/agent/ContextDialog.tsx +20 -41
  20. package/src/components/agent/ContextRing.tsx +6 -28
  21. package/src/components/agent/Conversation.tsx +21 -33
  22. package/src/components/agent/EditorTabs.tsx +39 -67
  23. package/src/components/agent/EngineIcon.tsx +29 -72
  24. package/src/components/agent/EntryIcon.tsx +16 -0
  25. package/src/components/agent/FileCard.tsx +10 -16
  26. package/src/components/agent/FileTree.tsx +52 -125
  27. package/src/components/agent/FileViewer.tsx +30 -60
  28. package/src/components/agent/HostFilesDialog.tsx +40 -69
  29. package/src/components/agent/Loader.tsx +3 -24
  30. package/src/components/agent/McpDialog.tsx +64 -137
  31. package/src/components/agent/Message.tsx +2 -21
  32. package/src/components/agent/ModelSelect.tsx +33 -62
  33. package/src/components/agent/PermissionModeSelect.tsx +21 -79
  34. package/src/components/agent/PermissionPrompt.tsx +59 -63
  35. package/src/components/agent/ProjectIcon.tsx +228 -93
  36. package/src/components/agent/PromptTokenText.tsx +10 -16
  37. package/src/components/agent/QuestionPrompt.tsx +43 -64
  38. package/src/components/agent/Reasoning.tsx +13 -16
  39. package/src/components/agent/Response.tsx +4 -6
  40. package/src/components/agent/Scrubber.tsx +31 -80
  41. package/src/components/agent/SessionBrowser.tsx +64 -243
  42. package/src/components/agent/SessionEmptyState.tsx +10 -40
  43. package/src/components/agent/SessionInfoDialog.tsx +46 -78
  44. package/src/components/agent/SessionItem.tsx +53 -320
  45. package/src/components/agent/SessionList.tsx +23 -39
  46. package/src/components/agent/SessionPanel.tsx +345 -923
  47. package/src/components/agent/SessionStatusIcon.tsx +14 -28
  48. package/src/components/agent/SessionSteps.tsx +34 -187
  49. package/src/components/agent/SessionWorkspace.tsx +108 -215
  50. package/src/components/agent/SkillsDialog.tsx +35 -80
  51. package/src/components/agent/StatusBar.tsx +51 -136
  52. package/src/components/agent/SubagentStrip.tsx +12 -77
  53. package/src/components/agent/ToolCallCard.tsx +94 -135
  54. package/src/components/agent/Transcript.tsx +103 -1288
  55. package/src/components/agent/TranscriptItemView.tsx +155 -0
  56. package/src/components/agent/TranscriptRows.tsx +418 -0
  57. package/src/components/agent/UsageDialog.tsx +7 -29
  58. package/src/components/agent/UsageMeters.tsx +18 -73
  59. package/src/components/agent/pulse.tsx +9 -32
  60. package/src/components/agent/scrubber-marks.ts +33 -103
  61. package/src/components/agent/status.ts +1 -5
  62. package/src/components/agent/tool-result-fetch.tsx +3 -25
  63. package/src/components/agent/tool-result-image.tsx +32 -111
  64. package/src/components/agent/transcript-rows.ts +41 -118
  65. package/src/components/agent/transcript-variant.tsx +3 -80
  66. package/src/components/agent/use-height-epoch.ts +10 -24
  67. package/src/components/agent/use-path-links.ts +45 -63
  68. package/src/components/agent/use-subagent-frame.ts +106 -0
  69. package/src/components/agent/use-transcript-jumps.ts +49 -107
  70. package/src/components/prompt-area/animated-placeholder.tsx +6 -5
  71. package/src/components/prompt-area/clipboard-helpers.ts +26 -21
  72. package/src/components/prompt-area/cursor-helpers.ts +79 -37
  73. package/src/components/prompt-area/dom-helpers.ts +97 -69
  74. package/src/components/prompt-area/file-strip.tsx +90 -80
  75. package/src/components/prompt-area/html-to-markdown.ts +67 -46
  76. package/src/components/prompt-area/image-strip.tsx +8 -18
  77. package/src/components/prompt-area/index.ts +2 -15
  78. package/src/components/prompt-area/prompt-area-engine.ts +100 -115
  79. package/src/components/prompt-area/prompt-area-list-ops.ts +66 -59
  80. package/src/components/prompt-area/prompt-area.tsx +31 -38
  81. package/src/components/prompt-area/remove-button.tsx +3 -9
  82. package/src/components/prompt-area/segment-helpers.ts +4 -12
  83. package/src/components/prompt-area/trigger-popover.tsx +15 -27
  84. package/src/components/prompt-area/trigger-presets.ts +0 -10
  85. package/src/components/prompt-area/types.ts +3 -8
  86. package/src/components/prompt-area/use-chip-editing.ts +305 -0
  87. package/src/components/prompt-area/use-markdown-mode.ts +7 -17
  88. package/src/components/prompt-area/use-prompt-area-events.ts +80 -86
  89. package/src/components/prompt-area/use-prompt-area-keydown.ts +598 -0
  90. package/src/components/prompt-area/use-prompt-area-state.ts +5 -23
  91. package/src/components/prompt-area/use-prompt-area.ts +170 -896
  92. package/src/components/prompt-area/use-trigger-search.ts +21 -19
  93. package/src/components/terminal/PermissionPrompt.tsx +56 -59
  94. package/src/components/terminal/QuestionPrompt.tsx +28 -79
  95. package/src/components/terminal/StatusLine.tsx +13 -63
  96. package/src/components/terminal/TerminalTranscript.tsx +44 -160
  97. package/src/components/terminal/affordances.tsx +68 -98
  98. package/src/components/terminal/blocks.ts +20 -156
  99. package/src/components/terminal/diff.tsx +19 -67
  100. package/src/components/terminal/height.ts +163 -313
  101. package/src/components/terminal/image-box.ts +0 -44
  102. package/src/components/terminal/items.tsx +150 -305
  103. package/src/components/terminal/markdown.tsx +36 -95
  104. package/src/components/terminal/press.tsx +26 -53
  105. package/src/components/terminal/prompt.tsx +40 -170
  106. package/src/components/terminal/result-preview.ts +8 -56
  107. package/src/components/terminal/row.tsx +11 -98
  108. package/src/components/terminal/scrubber.tsx +108 -401
  109. package/src/components/terminal/surface.tsx +6 -54
  110. package/src/components/terminal/todos.ts +66 -0
  111. package/src/components/terminal/tool-run.ts +21 -192
  112. package/src/components/ui/AlertDialog.tsx +8 -23
  113. package/src/components/ui/Badge.tsx +18 -29
  114. package/src/components/ui/Button.tsx +7 -15
  115. package/src/components/ui/Card.tsx +2 -13
  116. package/src/components/ui/CodeBlock.tsx +10 -37
  117. package/src/components/ui/CopyButton.tsx +10 -23
  118. package/src/components/ui/Dialog.tsx +23 -36
  119. package/src/components/ui/Empty.tsx +6 -29
  120. package/src/components/ui/Input.tsx +14 -16
  121. package/src/components/ui/Menu.tsx +6 -18
  122. package/src/components/ui/PortalScope.tsx +1 -21
  123. package/src/components/ui/ProgressRing.tsx +8 -19
  124. package/src/components/ui/Select.tsx +18 -31
  125. package/src/components/ui/Sonner.tsx +1 -2
  126. package/src/components/ui/Spinner.tsx +1 -1
  127. package/src/components/ui/Splitter.tsx +30 -64
  128. package/src/components/ui/Textarea.tsx +2 -5
  129. package/src/components/ui/Tooltip.tsx +3 -13
  130. package/src/format.ts +0 -9
  131. package/src/index.ts +16 -113
  132. package/src/lib/clipboard.ts +8 -28
  133. package/src/lib/css.ts +8 -0
  134. package/src/lib/format.ts +101 -86
  135. package/src/lib/plan-request.ts +16 -0
  136. package/src/lib/status.ts +45 -95
  137. package/src/lib/tool-icon.ts +39 -47
  138. package/src/lib/utils.ts +1 -3
  139. package/src/styles/terminal.css +81 -49
  140. package/src/styles/theme.css +136 -19
  141. package/src/workspace.ts +1 -24
  142. package/build/SessionPanel-13l25ubU.d.mts +0 -609
  143. package/build/SessionPanel-DgwjH4Ve.mjs.map +0 -1
  144. package/build/format-ljc3lKpA.d.mts +0 -59
  145. package/build/status-BE-zg88x.mjs.map +0 -1
package/build/scoped.css CHANGED
@@ -590,6 +590,9 @@
590
590
  .wd-root .max-h-64 {
591
591
  max-height: calc(var(--spacing) * 64);
592
592
  }
593
+ .wd-root .max-h-72 {
594
+ max-height: calc(var(--spacing) * 72);
595
+ }
593
596
  .wd-root .max-h-96 {
594
597
  max-height: calc(var(--spacing) * 96);
595
598
  }
@@ -1667,10 +1670,6 @@
1667
1670
  --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
1668
1671
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1669
1672
  }
1670
- .wd-root .ring {
1671
- --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
1672
- box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1673
- }
1674
1673
  .wd-root .ring-2 {
1675
1674
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
1676
1675
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -1689,9 +1688,6 @@
1689
1688
  --tw-blur: blur(8px);
1690
1689
  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
1691
1690
  }
1692
- .wd-root .filter {
1693
- filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
1694
- }
1695
1691
  .wd-root .backdrop-blur-\[1px\] {
1696
1692
  --tw-backdrop-blur: blur(1px);
1697
1693
  -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
@@ -1760,10 +1756,6 @@
1760
1756
  --tw-outline-style: none;
1761
1757
  outline-style: none;
1762
1758
  }
1763
- .wd-root .select-all {
1764
- -webkit-user-select: all;
1765
- user-select: all;
1766
- }
1767
1759
  .wd-root .select-none {
1768
1760
  -webkit-user-select: none;
1769
1761
  user-select: none;
@@ -2230,6 +2222,7 @@
2230
2222
  .wd-root .term-gutter {
2231
2223
  white-space: pre;
2232
2224
  user-select: none;
2225
+ pointer-events: none;
2233
2226
  color: var(--term-dim);
2234
2227
  }
2235
2228
  .wd-root .term-body {
@@ -2385,7 +2378,7 @@
2385
2378
  background: linear-gradient(var(--term-dim), var(--term-dim)) left center / 100% 1px no-repeat;
2386
2379
  }
2387
2380
  .wd-root [data-terminal] .term-rule-dashed {
2388
- background: repeating-linear-gradient( to right, var(--term-faint) 0 4px, transparent 4px 8px ) left center / 100% 1px no-repeat;
2381
+ background: repeating-linear-gradient(to right, var(--term-faint) 0 4px, transparent 4px 8px) left center / 100% 1px no-repeat;
2389
2382
  }
2390
2383
  .wd-root [data-terminal] .term-row[data-focused] {
2391
2384
  background: var(--term-row-hover);
@@ -2675,27 +2668,27 @@
2675
2668
  width: 12px;
2676
2669
  }
2677
2670
  .wd-root .term-scrubber .term-scrub-mark[data-kind='user'] {
2678
- background: linear-gradient( to bottom, var(--term-blue) 0 2px, var(--term-blue) 2px );
2671
+ background: linear-gradient(to bottom, var(--term-blue) 0 2px, var(--term-blue) 2px);
2679
2672
  @supports (color: color-mix(in lab, red, red)) {
2680
- background: linear-gradient( to bottom, var(--term-blue) 0 2px, color-mix(in srgb, var(--term-blue) 25%, transparent) 2px );
2673
+ background: linear-gradient(to bottom, var(--term-blue) 0 2px, color-mix(in srgb, var(--term-blue) 25%, transparent) 2px);
2681
2674
  }
2682
2675
  }
2683
2676
  .wd-root .term-scrubber .term-scrub-mark[data-kind='subagent'] {
2684
- background: linear-gradient( to bottom, var(--term-green) 0 2px, var(--term-green) 2px );
2677
+ background: linear-gradient(to bottom, var(--term-green) 0 2px, var(--term-green) 2px);
2685
2678
  @supports (color: color-mix(in lab, red, red)) {
2686
- background: linear-gradient( to bottom, var(--term-green) 0 2px, color-mix(in srgb, var(--term-green) 25%, transparent) 2px );
2679
+ background: linear-gradient(to bottom, var(--term-green) 0 2px, color-mix(in srgb, var(--term-green) 25%, transparent) 2px);
2687
2680
  }
2688
2681
  }
2689
2682
  .wd-root .term-scrubber .term-scrub-mark[data-kind='turn'] {
2690
- background: linear-gradient( to bottom, var(--term-fg) 0 2px, var(--term-fg) 2px );
2683
+ background: linear-gradient(to bottom, var(--term-fg) 0 2px, var(--term-fg) 2px);
2691
2684
  @supports (color: color-mix(in lab, red, red)) {
2692
- background: linear-gradient( to bottom, var(--term-fg) 0 2px, color-mix(in srgb, var(--term-fg) 25%, transparent) 2px );
2685
+ background: linear-gradient(to bottom, var(--term-fg) 0 2px, color-mix(in srgb, var(--term-fg) 25%, transparent) 2px);
2693
2686
  }
2694
2687
  }
2695
2688
  .wd-root .term-scrubber .term-scrub-mark[data-kind='turnFailed'] {
2696
- background: linear-gradient( to bottom, var(--term-red) 0 2px, var(--term-red) 2px );
2689
+ background: linear-gradient(to bottom, var(--term-red) 0 2px, var(--term-red) 2px);
2697
2690
  @supports (color: color-mix(in lab, red, red)) {
2698
- background: linear-gradient( to bottom, var(--term-red) 0 2px, color-mix(in srgb, var(--term-red) 25%, transparent) 2px );
2691
+ background: linear-gradient(to bottom, var(--term-red) 0 2px, color-mix(in srgb, var(--term-red) 25%, transparent) 2px);
2699
2692
  }
2700
2693
  }
2701
2694
  .wd-root .term-scrubber .term-scrub-mark[data-kind='error'] {
@@ -2826,7 +2819,7 @@
2826
2819
  --bg-code: #141414;
2827
2820
  --bg-elevated: #0a0a0acc;
2828
2821
  --row-hover: #2a2d2e;
2829
- --row-active: rgb(255 255 255 / 0.10);
2822
+ --row-active: rgb(255 255 255 / 0.1);
2830
2823
  --row-selected: #04395e;
2831
2824
  --row-selected-weak: #37373d;
2832
2825
  --badge: #616161;
@@ -2860,8 +2853,7 @@
2860
2853
  --shadow-md: 0 8px 20px rgba(0, 0, 0, 0.6);
2861
2854
  --shadow-lg: 0 24px 48px rgba(0, 0, 0, 0.7);
2862
2855
  --shine: #303030;
2863
- --frame-shadow: 0 4px 24px rgba(0, 0, 0, 0.55),
2864
- 0 2px 6px rgba(0, 0, 0, 0.45);
2856
+ --frame-shadow: 0 4px 24px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.45);
2865
2857
  --wd-scrub-bookmark: #c586c0;
2866
2858
  --surface: var(--bg-surface);
2867
2859
  --sidebar: #131313;
@@ -2939,6 +2931,70 @@
2939
2931
  height: 1rem;
2940
2932
  }
2941
2933
  }
2934
+ .wd-root [data-slot='message-content'] {
2935
+ font-size: var(--wd-font-size, var(--text-body-sm));
2936
+ line-height: 1.6;
2937
+ }
2938
+ .wd-root [data-slot='message-content'] h1 {
2939
+ font-size: 1.5em;
2940
+ line-height: 1.35;
2941
+ margin-top: 1.5em;
2942
+ }
2943
+ .wd-root [data-slot='message-content'] h2 {
2944
+ font-size: 1.3em;
2945
+ line-height: 1.35;
2946
+ margin-top: 1.5em;
2947
+ }
2948
+ .wd-root [data-slot='message-content'] h3 {
2949
+ font-size: 1.15em;
2950
+ line-height: 1.4;
2951
+ margin-top: 1.25em;
2952
+ }
2953
+ .wd-root [data-slot='message-content'] h4 {
2954
+ font-size: 1.05em;
2955
+ line-height: 1.4;
2956
+ margin-top: 1.25em;
2957
+ }
2958
+ .wd-root [data-slot='message-content'] h5 {
2959
+ font-size: 1em;
2960
+ line-height: 1.4;
2961
+ margin-top: 1em;
2962
+ }
2963
+ .wd-root [data-slot='message-content'] h6 {
2964
+ font-size: 1em;
2965
+ line-height: 1.4;
2966
+ margin-top: 1em;
2967
+ }
2968
+ .wd-root [data-slot='message-content'] pre {
2969
+ font-size: 0.9em;
2970
+ }
2971
+ .wd-root [data-slot='message-content'] code {
2972
+ font-size: 0.9em;
2973
+ }
2974
+ .wd-root [data-slot='message-content'] pre code {
2975
+ font-size: inherit;
2976
+ }
2977
+ .wd-root [data-slot='message-content'] table {
2978
+ font-size: 0.95em;
2979
+ }
2980
+ .wd-root [data-slot='message-content'] td {
2981
+ font-size: inherit;
2982
+ }
2983
+ .wd-root [data-slot='message-content'] th {
2984
+ font-size: inherit;
2985
+ }
2986
+ .wd-root [data-slot='message-content'] [data-streamdown='code-block-body'] {
2987
+ font-size: 0.9em;
2988
+ }
2989
+ .wd-root [data-slot='message-content'] :not(pre)>code {
2990
+ font-size: 0.9em;
2991
+ }
2992
+ .wd-root [data-slot='session-panel'] .prompt-area-container {
2993
+ font-size: var(--wd-font-size, var(--text-body-sm));
2994
+ }
2995
+ .wd-root [data-slot='session-panel'] .prompt-area-chip {
2996
+ font-size: var(--wd-font-size, 0.8125rem);
2997
+ }
2942
2998
  .wd-root .frame-shine {
2943
2999
  border: 1px solid transparent;
2944
3000
  background: linear-gradient(var(--bg), var(--bg)) padding-box, linear-gradient( 135deg, var(--shine) 0%, var(--shine) 55%, var(--shine) 100% ) border-box;
@@ -3068,7 +3124,7 @@
3068
3124
  overflow: hidden;
3069
3125
  white-space: nowrap;
3070
3126
  text-overflow: ellipsis;
3071
- font-size: var(--text-body-sm);
3127
+ font-size: var(--wd-font-size, var(--text-body-sm));
3072
3128
  color: var(--fg-2);
3073
3129
  background: var(--bg);
3074
3130
  @supports (color: color-mix(in lab, red, red)) {
@@ -11,7 +11,6 @@ function formatDuration(ms) {
11
11
  if (s < 60) return `${s.toFixed(1)}s`;
12
12
  return `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
13
13
  }
14
- /** Compact token count, Claude Code-style: 850 → "850", 359_000 → "359.0k", 1_200_000 → "1.2M". */
15
14
  function formatTokens(tokens) {
16
15
  if (tokens >= 1e6) return `${(tokens / 1e6).toFixed(1)}M`;
17
16
  if (tokens >= 1e3) return `${(tokens / 1e3).toFixed(1)}k`;
@@ -22,7 +21,6 @@ function formatBytes(bytes) {
22
21
  if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
23
22
  return `${bytes} B`;
24
23
  }
25
- /** Countdown to an epoch-ms deadline: "2h 18m", "12m", "<1m"; "now" once passed. */
26
24
  function formatCountdown(untilEpochMs, now = Date.now()) {
27
25
  const remaining = untilEpochMs - now;
28
26
  if (remaining <= 0) return "now";
@@ -44,19 +42,12 @@ function formatRelativeTime(epochMs, now = Date.now()) {
44
42
  if (h < 24) return `${h}h ago`;
45
43
  return `${Math.floor(h / 24)}d ago`;
46
44
  }
47
- /**
48
- * Human label for a rate-limit window key, compact: 'five_hour' → "5h",
49
- * 'seven_day_opus' → "7d opus". The per-model suffix is an open set — the CLI
50
- * adds buckets as plans gain them — so it is rewritten rather than enumerated.
51
- */
52
45
  function formatRateLimitWindow(key) {
53
46
  if (key === "five_hour") return "5h";
54
47
  if (key === "seven_day") return "7d";
55
48
  const spaced = key.replaceAll("_", " ");
56
49
  return key.startsWith("seven_day_") ? `7d ${spaced.slice(10)}` : spaced;
57
50
  }
58
- /** The same key spelled out, where there is room: 'five_hour' → "5-hour
59
- * session", 'seven_day_fable' → "Weekly · Fable". */
60
51
  function formatRateLimitWindowLong(key) {
61
52
  if (key === "five_hour") return "5-hour session";
62
53
  if (key === "seven_day") return "Weekly";
@@ -65,18 +56,10 @@ function formatRateLimitWindowLong(key) {
65
56
  if (!key.startsWith("seven_day_")) return capitalize(key.replaceAll("_", " "));
66
57
  return `Weekly · ${capitalize(key.slice(10).replaceAll("_", " "))}`;
67
58
  }
68
- /**
69
- * How long a rate-limit window is, in seconds — the denominator behind the pace
70
- * marker. Derived from the key rather than reported: the CLI sends a reset time
71
- * and a percentage, never a duration. `undefined` for a window whose key doesn't
72
- * say, and the marker is then simply not drawn rather than guessed.
73
- */
74
59
  function rateLimitWindowSeconds(key) {
75
60
  if (key === "five_hour") return 5 * 3600;
76
61
  if (key.startsWith("seven_day")) return 7 * 86400;
77
62
  }
78
- /** "8 secs ago" / "3 mins ago" — a freshness line finer-grained than
79
- * {@link formatRelativeTime}, because a poll that just landed should say so. */
80
63
  function formatAgoPrecise(epochMs, now = Date.now()) {
81
64
  const seconds = Math.max(0, Math.floor((now - epochMs) / 1e3));
82
65
  if (seconds < 60) return `${seconds} sec${seconds === 1 ? "" : "s"} ago`;
@@ -87,7 +70,6 @@ function formatAgoPrecise(epochMs, now = Date.now()) {
87
70
  const hours = Math.floor(seconds / 3600);
88
71
  return `${hours} hour${hours === 1 ? "" : "s"} ago`;
89
72
  }
90
- /** Compact one-line preview of a tool input for card headers. */
91
73
  function toolInputPreview(input, max = 80) {
92
74
  if (input === null || input === void 0) return "";
93
75
  if (typeof input === "object") {
@@ -98,9 +80,6 @@ function toolInputPreview(input, max = 80) {
98
80
  const text = JSON.stringify(input) ?? "";
99
81
  return text.length > max ? text.slice(0, max - 1) + "…" : text;
100
82
  }
101
- /** Families whose name isn't just a capitalised first letter, and how the
102
- * vendor writes the version after it. GPT is `GPT-5.6`; everyone else spaces
103
- * it. Anything unlisted is title-cased and spaced. */
104
83
  const MODEL_FAMILIES = {
105
84
  gpt: {
106
85
  name: "GPT",
@@ -114,33 +93,8 @@ const MODEL_FAMILIES = {
114
93
  mistral: { name: "Mistral" },
115
94
  grok: { name: "Grok" }
116
95
  };
117
- /**
118
- * The name a person says, from a wire model id:
119
- *
120
- * - `claude-opus-5[1m]` → "Opus 5"
121
- * - `claude-haiku-4-5-20251001` → "Haiku 4.5"
122
- * - `gpt-5.6-luna` → "GPT-5.6 Luna"
123
- * - `gemini-2.5-pro` → "Gemini 2.5 Pro"
124
- * - `o3-mini` → "o3 Mini"
125
- *
126
- * Three kinds of token after the family, because vendors mix them freely: a
127
- * **version** (`5`, `4-5`, `5.6` — joined with dots, since Anthropic splits what
128
- * OpenAI writes as one token), a **code name or tier** (`luna`, `codex`, `pro`,
129
- * `mini` — kept and capitalised, since it is often the only thing telling two
130
- * models apart), and a **snapshot date** (`20251001` — dropped; it is a build,
131
- * not a version).
132
- *
133
- * Anything genuinely unreadable falls back to the id: a wrong name is worse than
134
- * a raw one, which is at least true.
135
- *
136
- * The server has a narrower version of this (`friendlyModelName` in core's
137
- * `normalize.ts`) that derives Claude catalog names at authoring time. This one
138
- * is the *render-time* fallback for an id with no catalog row behind it — the
139
- * sidebar has only `SessionInfo.model` — so it has to cope with every vendor the
140
- * provider engine can reach, not just the CLI's own.
141
- */
142
96
  function friendlyModel(id) {
143
- if (!id) return void 0;
97
+ if (!id) return;
144
98
  const parts = (id.split("[")[0] ?? id).toLowerCase().split("-").filter(Boolean);
145
99
  if (parts[0] === "claude") parts.shift();
146
100
  const familyToken = parts.shift();
@@ -195,11 +149,6 @@ const STATUS_META = {
195
149
  severity: "none"
196
150
  }
197
151
  };
198
- /**
199
- * The status slot, connection first. A session status held over a dead socket is
200
- * the last thing we heard, not the current state — so a lost link takes the slot
201
- * rather than letting "Running" imply a turn is still streaming.
202
- */
203
152
  function statusPresentation(vitals) {
204
153
  if (!vitals) return {
205
154
  icon: "hubot",
@@ -222,16 +171,14 @@ function statusPresentation(vitals) {
222
171
  severity: "none"
223
172
  };
224
173
  }
225
- /** 0–100 → the colour a meter wears. One pair of thresholds for every surface. */
226
174
  function meterSeverity(pct) {
227
175
  if (pct === void 0) return "none";
228
176
  if (pct >= 95) return "error";
229
177
  if (pct >= 80) return "warning";
230
178
  return "none";
231
179
  }
232
- /** The window a lane points at, or `undefined` when this account has none. */
233
180
  function usageWindow(rateLimits, lane) {
234
- if (!rateLimits) return void 0;
181
+ if (!rateLimits) return;
235
182
  if (lane === "session") {
236
183
  const info = rateLimits.five_hour;
237
184
  return info ? {
@@ -248,13 +195,9 @@ function usageWindow(rateLimits, lane) {
248
195
  }
249
196
  return tightestWindow(Object.fromEntries(Object.entries(rateLimits).filter(([key]) => key.startsWith("seven_day_") && key !== "seven_day_oauth_apps")));
250
197
  }
251
- /** The rate-limit window that gets the one visible slot: whichever is fullest,
252
- * since the binding constraint is the one worth glancing at. Still the right
253
- * rule for a surface with exactly one slot; {@link usageWindow} is for one with
254
- * three. */
255
198
  function tightestWindow(rateLimits) {
256
199
  const entries = Object.entries(rateLimits ?? {});
257
- if (entries.length === 0) return void 0;
200
+ if (entries.length === 0) return;
258
201
  let best;
259
202
  for (const [key, info] of entries) if ((info.status === "rejected" ? Number.POSITIVE_INFINITY : info.utilization ?? -1) > (best === void 0 ? Number.NEGATIVE_INFINITY : best.info.status === "rejected" ? Number.POSITIVE_INFINITY : best.info.utilization ?? -1)) best = {
260
203
  key,
@@ -262,53 +205,39 @@ function tightestWindow(rateLimits) {
262
205
  };
263
206
  return best;
264
207
  }
265
- /** A rate-limit window's key, named for a human. A model-scoped bucket is named
266
- * for its model alone (`seven_day_fable` → "Fable"): the lane it sits in
267
- * already says weekly, and "Seven day fable" in a status bar is three words to
268
- * say one. */
269
208
  function windowLabel(key) {
270
209
  if (key === "five_hour") return "Session";
271
210
  if (key === "seven_day") return "Weekly";
272
211
  const words = (key.startsWith("seven_day_") ? key.slice(10) : key).replaceAll("_", " ");
273
212
  return words.charAt(0).toUpperCase() + words.slice(1);
274
213
  }
275
- /**
276
- * The catalog row a session is actually running, or `undefined` for a model the
277
- * list doesn't name. Matched leniently: a session reports the *resolved* id
278
- * (`claude-sonnet-5`) where the row may be keyed on the alias (`sonnet`), and
279
- * either can carry a `[1m]` context-window suffix.
280
- */
281
214
  function currentModel(vitals) {
282
215
  const id = vitals?.model;
283
- if (!id) return void 0;
216
+ if (!id) return;
284
217
  const bare = (value) => value.replace(/\[.*\]$/, "");
285
218
  const wanted = bare(id);
286
219
  return vitals.models.find((m) => bare(m.value) === wanted || m.resolvedModel && bare(m.resolvedModel) === wanted);
287
220
  }
288
- /** A session's model, named the way the picker names it. Falls back to the raw
289
- * id, and to "Default" while the session is on the CLI's own pick. */
290
221
  function modelLabel(vitals) {
291
222
  if (!vitals?.model) return "Default";
292
223
  return currentModel(vitals)?.displayName ?? vitals.model;
293
224
  }
294
- /** Context percentage as its meter severity — the reading and the colour come
295
- * from one place so a panel and a status bar never disagree.
296
- *
297
- * Takes only the number it reads, so the compact `ContextReading` that rides
298
- * the sessions list and the full `ContextUsage` on the event stream are coloured
299
- * by one rule rather than two. */
300
225
  function contextSeverity(usage) {
301
226
  return meterSeverity(usage?.percentage);
302
227
  }
303
- /** {@link meterSeverity} as a text colour class. Here rather than beside each
304
- * meter because the status bar, the context dialog and a sessions-list row all
305
- * paint the same reading, and a fourth copy of the thresholds is a fourth
306
- * chance for one surface to call 81% orange and another call it grey. */
307
228
  function meterColorClass(pct) {
308
229
  const severity = meterSeverity(pct);
309
230
  return severity === "error" ? "text-danger" : severity === "warning" ? "text-warning" : "text-fg-3";
310
231
  }
232
+ /**
233
+ * The fill colour for a meter bar. Deliberately a different ramp from
234
+ * {@link meterColorClass}: a bar reads as alarming later than a number does, so the tint
235
+ * turns at 70/90 where the text severity turns at 80/95.
236
+ */
237
+ function meterTintClass(pct) {
238
+ return pct >= 90 ? "bg-danger" : pct >= 70 ? "bg-warning" : "bg-accent";
239
+ }
311
240
  //#endregion
312
- export { formatRelativeTime as _, modelLabel as a, rateLimitWindowSeconds as b, usageWindow as c, formatBytes as d, formatCost as f, formatRateLimitWindowLong as g, formatRateLimitWindow as h, meterSeverity as i, windowLabel as l, formatDuration as m, currentModel as n, statusPresentation as o, formatCountdown as p, meterColorClass as r, tightestWindow as s, contextSeverity as t, formatAgoPrecise as u, formatTokens as v, toolInputPreview as x, friendlyModel as y };
241
+ export { toolInputPreview as S, formatRateLimitWindowLong as _, meterTintClass as a, friendlyModel as b, tightestWindow as c, formatAgoPrecise as d, formatBytes as f, formatRateLimitWindow as g, formatDuration as h, meterSeverity as i, usageWindow as l, formatCountdown as m, currentModel as n, modelLabel as o, formatCost as p, meterColorClass as r, statusPresentation as s, contextSeverity as t, windowLabel as u, formatRelativeTime as v, rateLimitWindowSeconds as x, formatTokens as y };
313
242
 
314
- //# sourceMappingURL=status-BE-zg88x.mjs.map
243
+ //# sourceMappingURL=status-C0HSLZas.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-C0HSLZas.mjs","names":[],"sources":["../src/lib/format.ts","../src/lib/status.ts"],"sourcesContent":["export function formatCost(usd: number | undefined): string {\n if (usd === undefined || Number.isNaN(usd)) {\n return '—'\n }\n if (usd === 0) {\n return '$0.00'\n }\n if (usd < 0.01) {\n return '<$0.01'\n }\n return `$${usd.toFixed(2)}`\n}\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`\n }\n const s = ms / 1000\n if (s < 60) {\n return `${s.toFixed(1)}s`\n }\n const m = Math.floor(s / 60)\n return `${m}m ${Math.round(s % 60)}s`\n}\n\nexport function formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) {\n return `${(tokens / 1_000_000).toFixed(1)}M`\n }\n if (tokens >= 1000) {\n return `${(tokens / 1000).toFixed(1)}k`\n }\n return String(Math.round(tokens))\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n }\n if (bytes >= 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${bytes} B`\n}\n\nexport function formatCountdown(untilEpochMs: number, now = Date.now()): string {\n const remaining = untilEpochMs - now\n if (remaining <= 0) {\n return 'now'\n }\n const minutes = Math.ceil(remaining / 60_000)\n if (minutes < 1) {\n return '<1m'\n }\n if (minutes < 60) {\n return `${minutes}m`\n }\n const days = Math.floor(minutes / (60 * 24))\n if (days >= 1) {\n return `${days}d ${Math.floor((minutes % (60 * 24)) / 60)}h`\n }\n return `${Math.floor(minutes / 60)}h ${minutes % 60}m`\n}\n\nexport function formatRelativeTime(epochMs: number | undefined, now = Date.now()): string {\n if (!epochMs) {\n return '—'\n }\n const diff = Math.max(0, now - epochMs)\n const s = Math.floor(diff / 1000)\n if (s < 60) {\n return 'just now'\n }\n const m = Math.floor(s / 60)\n if (m < 60) {\n return `${m}m ago`\n }\n const h = Math.floor(m / 60)\n if (h < 24) {\n return `${h}h ago`\n }\n const d = Math.floor(h / 24)\n return `${d}d ago`\n}\n\nexport function formatRateLimitWindow(key: string): string {\n if (key === 'five_hour') {\n return '5h'\n }\n if (key === 'seven_day') {\n return '7d'\n }\n const spaced = key.replaceAll('_', ' ')\n return key.startsWith('seven_day_') ? `7d ${spaced.slice('seven day '.length)}` : spaced\n}\n\nexport function formatRateLimitWindowLong(key: string): string {\n if (key === 'five_hour') {\n return '5-hour session'\n }\n if (key === 'seven_day') {\n return 'Weekly'\n }\n if (key === 'seven_day_oauth_apps') {\n return 'Weekly · apps'\n }\n const capitalize = (s: string) => s.replace(/\\b\\w/g, (c) => c.toUpperCase())\n if (!key.startsWith('seven_day_')) {\n return capitalize(key.replaceAll('_', ' '))\n }\n return `Weekly · ${capitalize(key.slice('seven_day_'.length).replaceAll('_', ' '))}`\n}\n\nexport function rateLimitWindowSeconds(key: string): number | undefined {\n if (key === 'five_hour') {\n return 5 * 3600\n }\n if (key.startsWith('seven_day')) {\n return 7 * 86_400\n }\n return undefined\n}\n\nexport function formatAgoPrecise(epochMs: number, now = Date.now()): string {\n const seconds = Math.max(0, Math.floor((now - epochMs) / 1000))\n if (seconds < 60) {\n return `${seconds} sec${seconds === 1 ? '' : 's'} ago`\n }\n if (seconds < 3600) {\n const minutes = Math.floor(seconds / 60)\n return `${minutes} min${minutes === 1 ? '' : 's'} ago`\n }\n const hours = Math.floor(seconds / 3600)\n return `${hours} hour${hours === 1 ? '' : 's'} ago`\n}\n\nexport function toolInputPreview(input: unknown, max = 80): string {\n if (input === null || input === undefined) {\n return ''\n }\n if (typeof input === 'object') {\n const o = input as Record<string, unknown>\n const primary = o.command ?? o.file_path ?? o.path ?? o.url ?? o.pattern ?? o.query ?? o.description\n if (typeof primary === 'string') {\n return primary.length > max ? primary.slice(0, max - 1) + '…' : primary\n }\n }\n const text = JSON.stringify(input) ?? ''\n return text.length > max ? text.slice(0, max - 1) + '…' : text\n}\n\nconst MODEL_FAMILIES: Record<string, { name: string; joiner?: string }> = {\n gpt: { name: 'GPT', joiner: '-' },\n deepseek: { name: 'DeepSeek' },\n glm: { name: 'GLM' },\n qwen: { name: 'Qwen' },\n kimi: { name: 'Kimi' },\n llama: { name: 'Llama' },\n mistral: { name: 'Mistral' },\n grok: { name: 'Grok' },\n}\n\nexport function friendlyModel(id: string | undefined): string | undefined {\n if (!id) {\n return undefined\n }\n const withoutVariant = id.split('[')[0] ?? id\n const parts = withoutVariant.toLowerCase().split('-').filter(Boolean)\n if (parts[0] === 'claude') {\n parts.shift()\n }\n const familyToken = parts.shift()\n if (!familyToken) {\n return id\n }\n const family = MODEL_FAMILIES[familyToken]\n const name =\n family?.name ??\n // OpenAI's reasoning series is lower-case by its own convention ('o3-mini'); \"O3\" reads as a different product.\n (/^o\\d+$/.test(familyToken) ? familyToken : `${familyToken.charAt(0).toUpperCase()}${familyToken.slice(1)}`)\n\n const version: string[] = []\n const words: string[] = []\n for (const part of parts) {\n if (/^\\d{8}$/.test(part)) {\n continue\n }\n if (/^\\d+(\\.\\d+)?$/.test(part)) {\n version.push(part)\n } else {\n words.push(`${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n }\n }\n const versioned = version.length > 0 ? `${name}${family?.joiner ?? ' '}${version.join('.')}` : name\n return [versioned, ...words].join(' ')\n}\n","import type { ModelOption, RateLimitInfo, SessionStatus } from '@workerdeck/protocol'\n\nexport type StatusSeverity = 'none' | 'warning' | 'error'\n\nexport type StatusPresentation = {\n icon: string\n label: string\n severity: StatusSeverity\n}\n\nexport type StatusReadings = {\n status: SessionStatus\n connection?: 'live' | 'reconnecting' | 'offline'\n}\n\nconst STATUS_META: Record<SessionStatus, StatusPresentation> = {\n starting: { icon: 'loading~spin', label: 'Starting', severity: 'none' },\n running: { icon: 'loading~spin', label: 'Running', severity: 'none' },\n awaiting_approval: { icon: 'warning', label: 'Needs approval', severity: 'warning' },\n idle: { icon: 'check', label: 'Idle', severity: 'none' },\n parked: { icon: 'debug-pause', label: 'Parked', severity: 'none' },\n failed: { icon: 'error', label: 'Failed', severity: 'error' },\n closed: { icon: 'circle-slash', label: 'Closed', severity: 'none' },\n}\n\nexport function statusPresentation(vitals: StatusReadings | undefined): StatusPresentation {\n if (!vitals) {\n return { icon: 'hubot', label: 'Connecting…', severity: 'none' }\n }\n if (vitals.connection === 'offline') {\n return { icon: 'debug-disconnect', label: 'Offline', severity: 'error' }\n }\n if (vitals.connection === 'reconnecting') {\n return { icon: 'sync~spin', label: 'Reconnecting…', severity: 'warning' }\n }\n return STATUS_META[vitals.status] ?? { icon: 'hubot', label: vitals.status, severity: 'none' }\n}\n\nexport function meterSeverity(pct: number | undefined): StatusSeverity {\n if (pct === undefined) {\n return 'none'\n }\n if (pct >= 95) {\n return 'error'\n }\n if (pct >= 80) {\n return 'warning'\n }\n return 'none'\n}\n\nexport type UsageLane = 'session' | 'weekly' | 'model'\n\nexport function usageWindow(\n rateLimits: Record<string, RateLimitInfo> | undefined,\n lane: UsageLane,\n): { key: string; info: RateLimitInfo } | undefined {\n if (!rateLimits) {\n return undefined\n }\n if (lane === 'session') {\n const info = rateLimits.five_hour\n return info ? { key: 'five_hour', info } : undefined\n }\n if (lane === 'weekly') {\n const info = rateLimits.seven_day\n return info ? { key: 'seven_day', info } : undefined\n }\n const scoped = Object.fromEntries(\n Object.entries(rateLimits).filter(([key]) => key.startsWith('seven_day_') && key !== 'seven_day_oauth_apps'),\n )\n return tightestWindow(scoped)\n}\n\nexport function tightestWindow(rateLimits: Record<string, RateLimitInfo> | undefined): { key: string; info: RateLimitInfo } | undefined {\n const entries = Object.entries(rateLimits ?? {})\n if (entries.length === 0) {\n return undefined\n }\n let best: { key: string; info: RateLimitInfo } | undefined\n for (const [key, info] of entries) {\n const rank = info.status === 'rejected' ? Number.POSITIVE_INFINITY : (info.utilization ?? -1)\n const bestRank =\n best === undefined\n ? Number.NEGATIVE_INFINITY\n : best.info.status === 'rejected'\n ? Number.POSITIVE_INFINITY\n : (best.info.utilization ?? -1)\n if (rank > bestRank) {\n best = { key, info }\n }\n }\n return best\n}\n\nexport function windowLabel(key: string): string {\n if (key === 'five_hour') {\n return 'Session'\n }\n if (key === 'seven_day') {\n return 'Weekly'\n }\n const scoped = key.startsWith('seven_day_') ? key.slice('seven_day_'.length) : key\n const words = scoped.replaceAll('_', ' ')\n return words.charAt(0).toUpperCase() + words.slice(1)\n}\n\nexport type ModelReadings = { model?: string; models: readonly ModelOption[] }\n\nexport function currentModel(vitals: ModelReadings | undefined): ModelOption | undefined {\n const id = vitals?.model\n if (!id) {\n return undefined\n }\n const bare = (value: string) => value.replace(/\\[.*\\]$/, '')\n const wanted = bare(id)\n return vitals.models.find((m) => bare(m.value) === wanted || (m.resolvedModel && bare(m.resolvedModel) === wanted))\n}\n\nexport function modelLabel(vitals: ModelReadings | undefined): string {\n if (!vitals?.model) {\n return 'Default'\n }\n return currentModel(vitals)?.displayName ?? vitals.model\n}\n\nexport function contextSeverity(usage: { percentage: number } | undefined): StatusSeverity {\n return meterSeverity(usage?.percentage)\n}\n\nexport function meterColorClass(pct: number | undefined): string {\n const severity = meterSeverity(pct)\n return severity === 'error' ? 'text-danger' : severity === 'warning' ? 'text-warning' : 'text-fg-3'\n}\n\n/**\n * The fill colour for a meter bar. Deliberately a different ramp from\n * {@link meterColorClass}: a bar reads as alarming later than a number does, so the tint\n * turns at 70/90 where the text severity turns at 80/95.\n */\nexport function meterTintClass(pct: number): string {\n return pct >= 90 ? 'bg-danger' : pct >= 70 ? 'bg-warning' : 'bg-accent'\n}\n"],"mappings":"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"}