dsh-ssh-tui 0.8.0 → 0.8.2-rc.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 (126) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/README.en.md +74 -8
  3. package/README.md +451 -577
  4. package/docs/display-mode.md +122 -0
  5. package/docs/release-notes-0.7.4.md +91 -0
  6. package/docs/release-notes-0.8.0.md +56 -0
  7. package/docs/release-notes-0.8.1.md +79 -0
  8. package/docs/release-notes-0.8.2-rc.1.md +159 -0
  9. package/docs/remote-ops.md +51 -0
  10. package/docs/terminals.md +53 -0
  11. package/docs/windows.md +13 -0
  12. package/lib/approval-state.js +148 -0
  13. package/lib/approval-state.js.map +1 -0
  14. package/lib/attach.js +4 -4
  15. package/lib/attach.js.map +1 -1
  16. package/lib/auth-failure.js +74 -0
  17. package/lib/auth-failure.js.map +1 -1
  18. package/lib/color-depth.js +26 -0
  19. package/lib/color-depth.js.map +1 -1
  20. package/lib/commands.js +2 -0
  21. package/lib/commands.js.map +1 -1
  22. package/lib/copy-text.js +30 -8
  23. package/lib/copy-text.js.map +1 -1
  24. package/lib/dialogs.js +124 -0
  25. package/lib/dialogs.js.map +1 -1
  26. package/lib/display-mode.js +147 -0
  27. package/lib/display-mode.js.map +1 -0
  28. package/lib/display-sock.js +490 -35
  29. package/lib/display-sock.js.map +1 -1
  30. package/lib/footer-accents.js +28 -0
  31. package/lib/footer-accents.js.map +1 -0
  32. package/lib/footer-budget.js +328 -0
  33. package/lib/footer-budget.js.map +1 -0
  34. package/lib/footer-format.js +433 -0
  35. package/lib/footer-format.js.map +1 -0
  36. package/lib/footer-layout.js +407 -0
  37. package/lib/footer-layout.js.map +1 -0
  38. package/lib/footer-meters.js +185 -0
  39. package/lib/footer-meters.js.map +1 -0
  40. package/lib/footer.js +19 -561
  41. package/lib/footer.js.map +1 -1
  42. package/lib/glyph-measure.js +92 -0
  43. package/lib/glyph-measure.js.map +1 -0
  44. package/lib/i18n/en.js +83 -7
  45. package/lib/i18n/en.js.map +1 -1
  46. package/lib/i18n/zh.js +85 -7
  47. package/lib/i18n/zh.js.map +1 -1
  48. package/lib/index.js +73 -5
  49. package/lib/index.js.map +1 -1
  50. package/lib/paint.js +75 -17
  51. package/lib/paint.js.map +1 -1
  52. package/lib/picker.js +14 -13
  53. package/lib/picker.js.map +1 -1
  54. package/lib/plan-projection.js +291 -0
  55. package/lib/plan-projection.js.map +1 -0
  56. package/lib/plan.js +61 -11
  57. package/lib/plan.js.map +1 -1
  58. package/lib/platform.js +96 -0
  59. package/lib/platform.js.map +1 -1
  60. package/lib/question-state.js +83 -0
  61. package/lib/question-state.js.map +1 -0
  62. package/lib/representation.js +283 -0
  63. package/lib/representation.js.map +1 -0
  64. package/lib/screen.js +105 -0
  65. package/lib/screen.js.map +1 -0
  66. package/lib/selection.js +5 -3
  67. package/lib/selection.js.map +1 -1
  68. package/lib/session-blank.js +81 -0
  69. package/lib/session-blank.js.map +1 -0
  70. package/lib/session-list.js +102 -81
  71. package/lib/session-list.js.map +1 -1
  72. package/lib/startup.js +56 -0
  73. package/lib/startup.js.map +1 -1
  74. package/lib/stats.js +101 -3
  75. package/lib/stats.js.map +1 -1
  76. package/lib/subagent-model.js +8 -7
  77. package/lib/subagent-model.js.map +1 -1
  78. package/lib/term-text.js +436 -69
  79. package/lib/term-text.js.map +1 -1
  80. package/lib/terminal-input.js +132 -10
  81. package/lib/terminal-input.js.map +1 -1
  82. package/lib/theme.js +335 -0
  83. package/lib/theme.js.map +1 -0
  84. package/lib/throughput.js +305 -0
  85. package/lib/throughput.js.map +1 -0
  86. package/lib/tool-present.js +67 -15
  87. package/lib/tool-present.js.map +1 -1
  88. package/lib/tui.js +4186 -1133
  89. package/lib/tui.js.map +1 -1
  90. package/lib/types/approval-state.d.ts +75 -0
  91. package/lib/types/attach.d.ts +6 -2
  92. package/lib/types/auth-failure.d.ts +55 -0
  93. package/lib/types/color-depth.d.ts +21 -0
  94. package/lib/types/commands.d.ts +6 -0
  95. package/lib/types/copy-text.d.ts +18 -1
  96. package/lib/types/dialogs.d.ts +147 -1
  97. package/lib/types/display-mode.d.ts +99 -0
  98. package/lib/types/display-sock.d.ts +90 -0
  99. package/lib/types/footer-accents.d.ts +22 -0
  100. package/lib/types/footer-budget.d.ts +204 -0
  101. package/lib/types/footer-format.d.ts +221 -0
  102. package/lib/types/footer-layout.d.ts +292 -0
  103. package/lib/types/footer-meters.d.ts +151 -0
  104. package/lib/types/footer.d.ts +19 -269
  105. package/lib/types/glyph-measure.d.ts +41 -0
  106. package/lib/types/index.d.ts +13 -0
  107. package/lib/types/paint.d.ts +48 -0
  108. package/lib/types/plan-projection.d.ts +162 -0
  109. package/lib/types/plan.d.ts +18 -2
  110. package/lib/types/platform.d.ts +83 -0
  111. package/lib/types/question-state.d.ts +96 -0
  112. package/lib/types/representation.d.ts +498 -0
  113. package/lib/types/screen.d.ts +126 -0
  114. package/lib/types/session-blank.d.ts +51 -0
  115. package/lib/types/session-list.d.ts +34 -0
  116. package/lib/types/startup.d.ts +30 -0
  117. package/lib/types/stats.d.ts +64 -1
  118. package/lib/types/subagent-model.d.ts +7 -6
  119. package/lib/types/term-text.d.ts +100 -24
  120. package/lib/types/terminal-input.d.ts +37 -0
  121. package/lib/types/theme.d.ts +109 -0
  122. package/lib/types/throughput.d.ts +163 -0
  123. package/lib/types/tool-present.d.ts +43 -2
  124. package/lib/types/transcript-types.d.ts +63 -2
  125. package/lib/types/tui.d.ts +960 -12
  126. package/package.json +73 -67
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Footer layout: the two chrome rows, and the `/status` report that spells the
3
+ * first one out.
4
+ *
5
+ * Layout assembles chips and rows; it does not decide how a chip degrades (that
6
+ * is `footer-budget.ts`) and does not spell a reading (that is
7
+ * `footer-format.ts`). The contract it does own is *where a signal lives*: the
8
+ * status row carries health, activity, speed, quota and context, the workspace
9
+ * row carries metadata, and the counters the status row gave up are answered by
10
+ * {@link formatStatusReport}.
11
+ *
12
+ * @module dsh-ssh-tui/footer-layout
13
+ */
14
+ import { t } from './i18n/index.js';
15
+ import { pinEmojiCells, truncateAnsiToWidth, visibleWidth } from './term-text.js';
16
+ import { describeSubagentFit, subagentProviderDiffers } from './subagent-model.js';
17
+ import { activeTheme, themeExtraToken, themeToken } from './theme.js';
18
+ import { downgradeSgr } from './color-depth.js';
19
+ import { formatQuotaStatusLine, } from './quota.js';
20
+ import { formatRate } from './throughput.js';
21
+ import { sessionTokenTotal } from './stats.js';
22
+ import { describeProviderRoute, formatContextPressureStatusLine, formatDuration, formatTokens, formatTokensPerSecond, shortModelName, subagentRouteLabel, } from './footer-format.js';
23
+ export const WAIT_INDICATOR_MS = 8000;
24
+ /** Stats groups in drop order (last is dropped first when the row is too wide). */
25
+ /**
26
+ * @deprecated Legacy surface, removed in 0.9.
27
+ *
28
+ * The status row shows one session total and `/status` prints the counters; this
29
+ * group list was the previous footer's first row, and the only thing still
30
+ * composing it is `statsText()` (itself test-only). Kept exported for 0.8.x.
31
+ */
32
+ export function footerStatsGroups(stats) {
33
+ const groups = [];
34
+ if (stats.steps > 0)
35
+ groups.push(t('footer.turnsSteps', { turns: stats.turns, steps: stats.steps }));
36
+ const billedInput = stats.inputTokens + stats.cacheReadTokens + stats.cacheWriteTokens;
37
+ if (billedInput > 0 || stats.outputTokens > 0) {
38
+ groups.push(t('footer.tokens', { input: formatTokens(billedInput), output: formatTokens(stats.outputTokens) }));
39
+ }
40
+ const speeds = [];
41
+ if (stats.decodeMs > 0 && stats.decodeTokens > 0) {
42
+ speeds.push(formatTokensPerSecond(stats.decodeTokens / (stats.decodeMs / 1_000)));
43
+ }
44
+ else if (stats.ttftSteps > 0) {
45
+ speeds.push(t('footer.ttft', { duration: formatDuration(stats.ttftMs / stats.ttftSteps) }));
46
+ }
47
+ if (speeds.length > 0)
48
+ groups.push(speeds.join(' '));
49
+ const durations = [];
50
+ if (stats.llmMs > 0)
51
+ durations.push(t('footer.llmMs', { duration: formatDuration(stats.llmMs) }));
52
+ if (stats.toolMs > 0)
53
+ durations.push(t('footer.toolMs', { duration: formatDuration(stats.toolMs) }));
54
+ if (durations.length > 0)
55
+ groups.push(durations.join(' '));
56
+ if (billedInput > 0)
57
+ groups.push(t('footer.cacheHit', { percent: Math.round(stats.cacheReadTokens / billedInput * 100) }));
58
+ return groups;
59
+ }
60
+ /**
61
+ * Fit an ordered strip into `width` cells, losing text before graphics.
62
+ *
63
+ * The old fitter dropped whole groups from the end, so a narrow terminal lost
64
+ * the ⚠ and the context ring — the two signals that say something is wrong —
65
+ * while keeping long numeric groups. Two passes now: every chip trades its text
66
+ * for its glyph in reverse priority order, and only then do whole groups go,
67
+ * again lowest priority first. The result never exceeds the width.
68
+ *
69
+ * Chips may carry SGR accents (the link pips, the ⚠) and the caller may pass a
70
+ * styled separator, so both the measurement and the final cut are ANSI-aware:
71
+ * feeding styled text to a plain-text truncator strips the accent's `ESC` and
72
+ * leaves its `[32m` body on the grid.
73
+ */
74
+ /**
75
+ * @deprecated Legacy surface, removed in 0.9.
76
+ *
77
+ * The default row stopped using this when the footer became the status row
78
+ * (`docs/plans/footer-debt.md`, D-7): what is left of it is the previous
79
+ * generation's fitting and formatting, kept exported so 0.8.x does not break an
80
+ * importer. New callers want the budget module's `runtimeStrip`, the meters, or
81
+ * `formatStatusReport` for the spelled-out numbers.
82
+ */
83
+ export function fitFooterChips(chips, width, separator = ' │ ') {
84
+ const limit = Math.max(1, width);
85
+ const state = chips
86
+ .filter(chip => chip.long !== '' || chip.short !== '')
87
+ .map(chip => ({ chip, full: true, present: true }));
88
+ const render = () => state
89
+ .filter(entry => entry.present)
90
+ .map(entry => (entry.full ? entry.chip.long : entry.chip.short))
91
+ .filter(text => text !== '')
92
+ .join(separator);
93
+ // Budget the way it will be painted: the frame pins a symbol like ⚠ with a
94
+ // variation selector and a reserving space, so the raw string measures one or
95
+ // two cells narrower than the row it becomes. Fitting the unpinned text left
96
+ // a row that overflowed the terminal by exactly that much.
97
+ const used = () => visibleWidth(pinEmojiCells(render()));
98
+ const byLeastImportant = [...state].sort((a, b) => b.chip.priority - a.chip.priority);
99
+ for (const entry of byLeastImportant) {
100
+ if (used() <= limit)
101
+ break;
102
+ entry.full = false;
103
+ }
104
+ for (const entry of byLeastImportant) {
105
+ if (used() <= limit)
106
+ break;
107
+ entry.present = false;
108
+ }
109
+ if (state.length > 0 && state.every(entry => !entry.present)) {
110
+ // Nothing fits, not even the glyphs. Keeping the most important group and
111
+ // letting the clip shorten it beats handing the user a blank row: a ⚠ cut
112
+ // to one cell still says the install is broken.
113
+ const best = [...state].sort((a, b) => a.chip.priority - b.chip.priority)[0];
114
+ if (best !== undefined) {
115
+ best.present = true;
116
+ best.full = false;
117
+ }
118
+ }
119
+ return truncateAnsiToWidth(render(), limit);
120
+ }
121
+ /**
122
+ * The roster's health as a chip: absent means `/mode` cannot switch presets and
123
+ * the preset-owned tools are missing. It leads the status row and keeps its glyph
124
+ * longest, because it is the one group that reports a broken install.
125
+ */
126
+ export function footerHealthChip(missing, color = false,
127
+ /** Which rows are missing: the 0.1.5 roster, or the 0.1.7 agent plane. */
128
+ kind = 'roster') {
129
+ if (!missing)
130
+ return undefined;
131
+ const glyph = color ? `\x1b[${themeExtraToken(activeTheme(), 'warn')}m⚠\x1b[0m` : '⚠';
132
+ return {
133
+ id: 'health',
134
+ long: `${glyph} ${t(kind === 'agent-plane' ? 'footer.agentPlaneMissing' : 'footer.rosterMissing')}`,
135
+ short: glyph,
136
+ priority: 0,
137
+ };
138
+ }
139
+ /**
140
+ * @deprecated Legacy surface, removed in 0.9.
141
+ *
142
+ * The default row stopped using this when the footer became the status row
143
+ * (`docs/plans/footer-debt.md`, D-7): what is left of it is the previous
144
+ * generation's fitting and formatting, kept exported so 0.8.x does not break an
145
+ * importer. New callers want the budget module's `runtimeStrip`, the meters, or
146
+ * `formatStatusReport` for the spelled-out numbers.
147
+ */
148
+ export function fitFooterStatsLine(chip, groups, width) {
149
+ const kept = [...groups];
150
+ const render = () => kept.length === 0 ? chip : `${chip} │ ${kept.join(' │ ')}`;
151
+ while (kept.length > 0 && visibleWidth(render()) > width)
152
+ kept.pop();
153
+ return truncateAnsiToWidth(render(), Math.max(1, width));
154
+ }
155
+ export function footerActivity(input) {
156
+ if (input.planReview)
157
+ return { kind: 'plan-review', text: t('footer.planReview') };
158
+ if (input.waitingQuestion)
159
+ return { kind: 'waiting', text: t('footer.waiting') };
160
+ // An approval is the one wait that used to read as idle: it is a `confirm`
161
+ // dialog, and the status row only recognised `questions` ones.
162
+ if (input.waitingApproval)
163
+ return { kind: 'approval', text: t('footer.approval') };
164
+ if (input.compacting)
165
+ return { kind: 'compacting', text: t('footer.compacting') };
166
+ // Only a running turn can be retrying: a chip left over from a finished turn
167
+ // (a missed event, or a retry of a background request such as the session
168
+ // title) must not hide the state the user is actually in.
169
+ if (input.running && input.retry !== undefined) {
170
+ return { kind: 'retry', text: t('footer.retry', { retry: input.retry.retry, max: input.retry.maxRetries }) };
171
+ }
172
+ if (input.subagents > 0) {
173
+ // `agent · 3m12s`: the verb and the clock. Which child it is (model, effort,
174
+ // role) is the identity row's job — putting `sub:grok-4.7(xhigh)` here broke
175
+ // the row's width on exactly the sessions that spawn the most children.
176
+ return { kind: 'agent', text: t('footer.agent') };
177
+ }
178
+ if (input.running && input.tools > 0) {
179
+ // The tool names itself rather than reporting a count: `⠹ edit · 28s` says
180
+ // what the session is doing, while `工具 1 · 28s` says how many of something
181
+ // unnamed are open. A count only appears when several run at once, where the
182
+ // question "which one" has no single answer.
183
+ const label = input.toolLabel?.trim() ?? '';
184
+ if (label !== '')
185
+ return { kind: 'tools', text: label };
186
+ return { kind: 'tools', text: t('footer.tools', { count: input.tools }) };
187
+ }
188
+ if (input.planLeftOpen)
189
+ return { kind: 'plan-open', text: t('footer.planOpen') };
190
+ if (input.planPending)
191
+ return { kind: 'plan-pending', text: t('footer.planSwitching') };
192
+ if (input.planActive)
193
+ return { kind: 'plan-pending', text: t('footer.planMode') };
194
+ if (input.goalPhase === 'active')
195
+ return { kind: 'goal', text: t('footer.goalActive') };
196
+ if (input.goalPhase === 'paused')
197
+ return { kind: 'goal', text: t('footer.goalPaused') };
198
+ if (input.goalPhase === 'blocked')
199
+ return { kind: 'goal', text: t('footer.goalBlocked') };
200
+ if (input.running && input.idleMs > WAIT_INDICATOR_MS) {
201
+ return { kind: 'waiting-llm', text: t('footer.waitSeconds', { seconds: Math.floor(input.idleMs / 1000) }) };
202
+ }
203
+ // What the running turn is actually doing. The window before the first token
204
+ // stays `运行中`: calling it 思考中 would claim the model is reasoning when the
205
+ // request may not even have been accepted yet, and would put a decode clock on
206
+ // a step that has decoded nothing.
207
+ if (input.running) {
208
+ if (input.streamingText === true)
209
+ return { kind: 'reply', text: t('footer.reply') };
210
+ if (input.streamingReasoning === true)
211
+ return { kind: 'thinking', text: t('footer.thinking') };
212
+ return { kind: 'idle', text: t('footer.running') };
213
+ }
214
+ return { kind: 'idle', text: t('footer.idle') };
215
+ }
216
+ /**
217
+ * Paint the `sub:` chip on an otherwise muted status line.
218
+ *
219
+ * Only a *foreign* route is accented: cyan when `/submodel` pinned a supplier
220
+ * the parent is not on. A child that follows the parent (or that was pinned
221
+ * back onto the parent's own provider) keeps the identity row's mute — the
222
+ * accent means "this route is not your parent's", and spending it on every
223
+ * child made the following case look pinned.
224
+ *
225
+ * The mute (`90`) is reopened after the chip so the rest of the identity row
226
+ * stays dim.
227
+ */
228
+ export function paintFooterSubagentChip(line, chip, foreign, muteSgr = themeToken(activeTheme(), 'system'), depth = 'truecolor', identitySgr = themeExtraToken(activeTheme(), 'subagent-foreign')) {
229
+ if (!foreign || chip === '' || !line.includes(chip))
230
+ return line;
231
+ const code = downgradeSgr(identitySgr, depth);
232
+ if (code === '')
233
+ return line;
234
+ const mute = muteSgr === '' ? '0' : muteSgr;
235
+ return line.replace(chip, `\x1b[${code}m${chip}\x1b[0m\x1b[${mute}m`);
236
+ }
237
+ export function footerSubagentForeign(input) {
238
+ return subagentProviderDiffers(input.provider, input.subProvider);
239
+ }
240
+ /**
241
+ * The workspace row: what this session is, not what it is doing.
242
+ *
243
+ * Quota and context used to live here and now own capacity meters on the row
244
+ * above, so they are deliberately absent: a number painted twice is a number the
245
+ * reader has to check twice. What is left is the configuration the header does
246
+ * not carry — the preset, the working directory, the child route, and the
247
+ * input's own transient state.
248
+ */
249
+ export function footerIdentityParts(input, options = {}) {
250
+ const parts = [];
251
+ if (input.compactView === true)
252
+ parts.push(`[${t('view.footerCompact')}]`);
253
+ // The preset is *not* here: the header prints it permanently, so a second copy
254
+ // in a footer fighting for cells bought nothing. The row carries what the header
255
+ // does not - where this session is working, and what is waiting for it.
256
+ if (input.cwdLabel !== undefined && input.cwdLabel !== '')
257
+ parts.push(input.cwdLabel);
258
+ // A balance-only route (DeepSeek) has no quota window to gauge, so its remaining
259
+ // credit stays as reference metadata rather than pretending to be a capacity
260
+ // meter it cannot fill - and it outlives the configuration below, because on
261
+ // that route it is the row's only reading.
262
+ if (input.balanceText !== undefined && input.balanceText !== '')
263
+ parts.push(input.balanceText);
264
+ if (options.omitModel !== true) {
265
+ const modelName = shortModelName(input.model);
266
+ const effort = input.effort === undefined || input.effort.trim() === '' ? '' : input.effort.trim();
267
+ const model = [modelName, effort].filter(part => part !== '').join(' ');
268
+ // Only an embedded surface with no header asks for this; `/status` is where
269
+ // the exact route lives, so it sits with the rest of the configuration.
270
+ if (model !== '')
271
+ parts.push(model);
272
+ }
273
+ if (input.search !== undefined)
274
+ parts.push(t('footer.search', { index: input.search.index + 1, total: input.search.total }));
275
+ if (input.foldedInput)
276
+ parts.push(t('footer.inputFolded'));
277
+ else if (input.multiLineInput)
278
+ parts.push(t('footer.multiLine'));
279
+ if (input.queued > 0)
280
+ parts.push(t('footer.queued', { count: input.queued }));
281
+ // The child route closes the row: configuration, inherited by every child and
282
+ // changed only by `/submodel`, so it is the first thing a narrow row gives up.
283
+ const sub = subagentRouteLabel(input.subModel, input.subProvider, input.subEffort);
284
+ if (sub !== '')
285
+ parts.push(sub);
286
+ // The subscription closes the row, behind even the child route: it is the
287
+ // context everything else is billed against, not something the reader acts on,
288
+ // so it is the first part a narrow row discards.
289
+ if (input.planBadge !== undefined && input.planBadge !== '')
290
+ parts.push(input.planBadge);
291
+ return parts;
292
+ }
293
+ /**
294
+ * Fit the workspace row under `width`.
295
+ *
296
+ * The metadata is secondary by construction: it follows the activity label at a
297
+ * dimmer intensity and is dropped from the right, one part at a time, rather
298
+ * than being allowed to wrap into the status row above it.
299
+ */
300
+ export function fitFooterStatusLine(activity, identity, width) {
301
+ const kept = [...identity];
302
+ // An empty label means this row carries metadata only (the status row's
303
+ // activity lives one line up), and then the joining spaces go with it: a row
304
+ // that opened with two blank cells read as a layout bug.
305
+ const render = () => {
306
+ const parts = kept.filter(part => part !== '');
307
+ if (activity === '')
308
+ return parts.join(' · ');
309
+ return parts.length === 0 ? activity : `${activity} ${parts.join(' · ')}`;
310
+ };
311
+ // From the right, which is the priority order the parts are already in: the
312
+ // child route goes first, then the row's state, and the working directory last.
313
+ while (kept.length > 0 && visibleWidth(render()) > width)
314
+ kept.pop();
315
+ return truncateAnsiToWidth(render(), Math.max(1, width));
316
+ }
317
+ /**
318
+ * Lines printed by `/status` — SSH first-boot diagnostics, no extra command.
319
+ *
320
+ * This is where the status row's removed telemetry lives. Turns, steps, model
321
+ * time, tool time, cache hit and the input/output breakdown are session
322
+ * analytics: they answer no question a live operator is asking, which is why
323
+ * they left the default row, and their disappearance would be information loss —
324
+ * so `/status` prints all of them, plus the throughput accounting, in the shapes
325
+ * the row used to use.
326
+ */
327
+ export function formatStatusReport(input) {
328
+ const route = describeProviderRoute(input.provider);
329
+ const effort = input.effort === undefined ? '' : ` (${input.effort})`;
330
+ const fit = describeSubagentFit({
331
+ parentProvider: input.provider,
332
+ parentModel: input.parentModel,
333
+ subProvider: input.subProvider,
334
+ subModel: input.subModel,
335
+ });
336
+ return [
337
+ `session: ${input.sessionId}`,
338
+ `plugin: dsh-ssh-tui ${input.pluginVersion}`,
339
+ `cwd: ${input.cwd ?? ''}`,
340
+ `route: ${input.provider}/${input.model}${effort}`,
341
+ `provider: ${route.kind}`,
342
+ `status: ${input.agentStatus}`,
343
+ `preset: ${input.preset}`,
344
+ `subagents: ${input.activeSubagents}`,
345
+ fit.line,
346
+ `plan: ${input.plan}`,
347
+ formatQuotaStatusLine(input.quota),
348
+ formatContextPressureStatusLine(input.context),
349
+ ...(input.stats === undefined ? [] : formatStatusStats(input.stats)),
350
+ ...(input.throughput === undefined ? [] : [formatStatusThroughput(input.throughput)]),
351
+ `paint: ${input.paint}`,
352
+ `disconnect: ${input.disconnect ?? 'pause'}`,
353
+ input.waitingQuestions > 0 ? `questions: waiting ${input.waitingQuestions}` : 'questions: none',
354
+ ];
355
+ }
356
+ /**
357
+ * The stats block `/status` prints: everything the default row gave up.
358
+ *
359
+ * `tokens/sec` here is the exact per-step rate (`decodeTokens / decodeMs`), not
360
+ * the running estimate, and the line says which span it covers: the last step
361
+ * and the session so far are different questions and only one of them is a
362
+ * benchmark.
363
+ */
364
+ export function formatStatusStats(stats) {
365
+ const billedInput = stats.inputTokens + stats.cacheReadTokens + stats.cacheWriteTokens;
366
+ const total = sessionTokenTotal({
367
+ inputTokens: stats.inputTokens,
368
+ outputTokens: stats.outputTokens,
369
+ reportedTokens: stats.totalTokens,
370
+ reportedSteps: stats.totalTokens > 0 ? 1 : 0,
371
+ unreportedSteps: stats.totalTokens > 0 ? 0 : 1,
372
+ cacheReadTokens: stats.cacheReadTokens,
373
+ cacheWriteTokens: stats.cacheWriteTokens,
374
+ });
375
+ const lines = [
376
+ `turns: ${stats.turns}`,
377
+ `steps: ${stats.steps}`,
378
+ `tokens: in ${formatTokens(billedInput)} · out ${formatTokens(stats.outputTokens)}`
379
+ + (total === undefined
380
+ ? ''
381
+ : ` · total ${formatTokens(total.tokens)} (${total.basis === 'harness' ? 'harness totalTokens' : 'billed parts summed'})`),
382
+ `tokens: cached read ${formatTokens(stats.cacheReadTokens)} · cached write ${formatTokens(stats.cacheWriteTokens)}`,
383
+ ];
384
+ if (billedInput > 0)
385
+ lines.push(`cache: hit ${Math.round(stats.cacheReadTokens / billedInput * 100)}%`);
386
+ if (stats.llmMs > 0)
387
+ lines.push(`model time: ${formatDuration(stats.llmMs)}`);
388
+ if (stats.toolMs > 0)
389
+ lines.push(`tool time: ${formatDuration(stats.toolMs)}`);
390
+ if (stats.ttftSteps > 0) {
391
+ const steps = stats.ttftSteps === 1 ? 'step' : 'steps';
392
+ lines.push(`ttft: ${formatDuration(stats.ttftMs / stats.ttftSteps)} avg over ${stats.ttftSteps} ${steps}`);
393
+ }
394
+ return lines;
395
+ }
396
+ /** One line: what the throughput number means, and which span it covers. */
397
+ export function formatStatusThroughput(throughput) {
398
+ const parts = [];
399
+ parts.push(throughput.settledRate === undefined
400
+ ? 'tokens/sec: no settled step yet'
401
+ : `tokens/sec: ${formatRate(throughput.settledRate)} (last settled step, output tokens / decode ms)`);
402
+ if (throughput.liveRate !== undefined && throughput.fresh) {
403
+ parts.push(`~${formatRate(throughput.liveRate)} live (estimated from ${throughput.liveChars} streamed chars)`);
404
+ }
405
+ return parts.join(' · ');
406
+ }
407
+ //# sourceMappingURL=footer-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer-layout.js","sourceRoot":"","sources":["../src/footer-layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * The three meter primitives the status row is built from.
3
+ *
4
+ * One component per kind of question, because a health question and a capacity
5
+ * question do not look alike:
6
+ *
7
+ * - {@link healthMeter} — "is this healthy?" Discrete levels, no bar. This is the
8
+ * SSH chip's four pips, generalised.
9
+ * - {@link capacityMeter} — "how much is left / how much is used?" A bar and a
10
+ * percent. The *direction* is a parameter, which is what lets quota (remaining)
11
+ * and context (used) share one implementation.
12
+ * - {@link performanceValue} — "how fast is it going?" A bare number, neutral,
13
+ * with a mark for the estimate and a dimmer form for a finished step.
14
+ *
15
+ * Nothing here knows what a row is, how wide it is, or in what order chips go:
16
+ * that is `footer-budget.ts`, and keeping the two apart is what stops a meter
17
+ * from growing a layout opinion.
18
+ *
19
+ * @module dsh-ssh-tui/footer-meters
20
+ */
21
+ import { asciiChromeEnabled } from './term-text.js';
22
+ import { activeTheme, themeThresholdToken } from './theme.js';
23
+ import { formatRate } from './throughput.js';
24
+ import { accent } from './color-depth.js';
25
+ import { CONTEXT_PRESSURE_DANGER_RATIO, CONTEXT_PRESSURE_WARN_RATIO, } from './footer-format.js';
26
+ /**
27
+ * The row's visual vocabulary, as reusable primitives.
28
+ *
29
+ * Three components, because the row answers three different kinds of question:
30
+ *
31
+ * - {@link healthMeter} — "is this healthy?" Discrete levels, no bar. This is
32
+ * the SSH chip's four pips, generalised; nothing else on the row copies it,
33
+ * because a health question and a capacity question do not look alike.
34
+ * - {@link capacityMeter} — "how much is left / how much is used?" A bar with a
35
+ * percent. The *direction* is a parameter, which is what lets quota (remaining)
36
+ * and context (used) share one implementation.
37
+ * - {@link performanceValue} — "how fast is it going?" A bare number, neutral,
38
+ * with a mark for the estimate and a dimmer form for a finished step.
39
+ *
40
+ * All three take `ascii` and answer with the project's own fallback glyphs, and
41
+ * none of them reach for a threshold colour on their own: the caller decides
42
+ * whether the number it is drawing has bands at all.
43
+ */
44
+ /** How many level marks a health meter has: the four pips the SSH chip always had. */
45
+ export const HEALTH_METER_LEVELS = 4;
46
+ /** Full and empty level marks. The empty one is the same cell, hollow. */
47
+ export const HEALTH_MARK_FILLED = '●';
48
+ export const HEALTH_MARK_EMPTY = '○';
49
+ /** ASCII fallback for the same four levels, from the project's own glyph table. */
50
+ export const HEALTH_ASCII_FILLED = '*';
51
+ export const HEALTH_ASCII_EMPTY = 'o';
52
+ /** Filled and empty cells of a capacity meter, matching the existing quota bar. */
53
+ export const CAPACITY_CELL_FILLED = '█';
54
+ export const CAPACITY_CELL_EMPTY = '░';
55
+ /** ASCII fallback for the capacity meter, from the project's own glyph table. */
56
+ export const CAPACITY_ASCII_FILLED = '#';
57
+ export const CAPACITY_ASCII_EMPTY = '.';
58
+ /** Segment counts by row budget. Three is the smallest bar that still reads. */
59
+ export const CAPACITY_SEGMENTS_WIDE = 8;
60
+ export const CAPACITY_SEGMENTS_MEDIUM = 5;
61
+ export const CAPACITY_SEGMENTS_NARROW = 3;
62
+ /**
63
+ * Colours for a capacity meter's filled portion.
64
+ *
65
+ * Context and quota answer different questions and have different runways, so
66
+ * they get different bands — but each one reuses a threshold the session already
67
+ * enforces, so the meter can never disagree with the alert beside it:
68
+ * context reuses the pressure levels `contextPressureView` uses (warn at 80%,
69
+ * danger at 95%, the same numbers that drive the compaction prompt), and quota
70
+ * reuses the first two of `QUOTA_ALERT_THRESHOLDS` (50 / 25 remaining), which is
71
+ * where the session starts telling the user about it.
72
+ */
73
+ export const CONTEXT_METER_WARN_PERCENT = CONTEXT_PRESSURE_WARN_RATIO * 100;
74
+ export const CONTEXT_METER_DANGER_PERCENT = CONTEXT_PRESSURE_DANGER_RATIO * 100;
75
+ /** First two entries of `quota.ts`'s `QUOTA_ALERT_THRESHOLDS`, in remaining percent. */
76
+ export const QUOTA_METER_WARN_PERCENT = 50;
77
+ export const QUOTA_METER_DANGER_PERCENT = 25;
78
+ /** Which band a capacity reading falls in, given what the number means. */
79
+ export function capacityLevel(percent, basis = 'used', quota = false) {
80
+ if (!Number.isFinite(percent))
81
+ return 'ok';
82
+ if (basis === 'remaining') {
83
+ // Remaining runs out downwards, so the bands are read on the way down; a
84
+ // quota is only "over" when almost nothing is left.
85
+ const warn = quota ? QUOTA_METER_WARN_PERCENT : 100 - CONTEXT_METER_WARN_PERCENT;
86
+ const danger = quota ? QUOTA_METER_DANGER_PERCENT : 100 - CONTEXT_METER_DANGER_PERCENT;
87
+ if (percent <= danger)
88
+ return 'over';
89
+ if (percent <= warn)
90
+ return 'warn';
91
+ return 'ok';
92
+ }
93
+ const warn = quota ? 100 - QUOTA_METER_WARN_PERCENT : CONTEXT_METER_WARN_PERCENT;
94
+ const danger = quota ? 100 - QUOTA_METER_DANGER_PERCENT : CONTEXT_METER_DANGER_PERCENT;
95
+ if (percent >= danger)
96
+ return 'over';
97
+ if (percent >= warn)
98
+ return 'warn';
99
+ return 'ok';
100
+ }
101
+ /**
102
+ * One capacity meter: `CTX ███████░░░ 61%`.
103
+ *
104
+ * An unusable percent paints a hollow bar with a question mark rather than `0%`:
105
+ * a reading nobody took is not a reading of zero, and `?%` is the same claim the
106
+ * quota chip has always made before its first reading lands.
107
+ *
108
+ * Colour, when asked for, lands only on the cells that carry the meaning — the
109
+ * filled run and the percent. Tinting the label and the empty cells would make
110
+ * the whole chip one colour and lose the hierarchy it exists to create.
111
+ */
112
+ export function capacityMeter(percent, options = {}) {
113
+ const segments = Math.max(0, options.segments ?? CAPACITY_SEGMENTS_WIDE);
114
+ const ascii = options.ascii ?? asciiChromeEnabled();
115
+ const filledGlyph = ascii ? CAPACITY_ASCII_FILLED : CAPACITY_CELL_FILLED;
116
+ const emptyGlyph = ascii ? CAPACITY_ASCII_EMPTY : CAPACITY_CELL_EMPTY;
117
+ const label = options.label === undefined || options.label === '' ? '' : `${options.label} `;
118
+ const detail = options.detail === undefined || options.detail === '' ? '' : ` · ${options.detail}`;
119
+ if (percent === undefined || !Number.isFinite(percent)) {
120
+ return { text: `${label}${emptyGlyph.repeat(segments)} ?%${detail}`, level: 'ok' };
121
+ }
122
+ const clamped = Math.max(0, Math.min(100, percent));
123
+ const level = capacityLevel(clamped, options.basis ?? 'used', options.quota === true);
124
+ const filled = Math.round(clamped / 100 * segments);
125
+ const percentText = `${Math.round(clamped)}%`;
126
+ const color = options.color === true && options.depth !== 'none';
127
+ const paint = (text) => color
128
+ ? accent(text, themeThresholdToken(activeTheme(), level), options.depth ?? 'truecolor')
129
+ : text;
130
+ if (options.percentOnly === true) {
131
+ return { text: `${label}${paint(percentText)}${detail}`, level };
132
+ }
133
+ const bar = `${paint(filledGlyph.repeat(filled))}${emptyGlyph.repeat(segments - filled)}`;
134
+ return { text: `${label}${bar} ${paint(percentText)}${detail}`, level };
135
+ }
136
+ /**
137
+ * One health meter: `●●●●`.
138
+ *
139
+ * Discrete levels, never a bar: a link is one of five states, and four pips say
140
+ * which at a glance. This is the component the SSH chip has always been — it
141
+ * simply became reusable when the quota and context meters arrived, so that the
142
+ * two things that *are* capacities stopped being drawn as pips.
143
+ */
144
+ export function healthMeter(level, options = {}) {
145
+ const levels = Math.max(1, options.levels ?? HEALTH_METER_LEVELS);
146
+ const filled = Math.max(0, Math.min(levels, Math.round(level)));
147
+ const ascii = options.ascii ?? asciiChromeEnabled();
148
+ const on = ascii ? HEALTH_ASCII_FILLED : HEALTH_MARK_FILLED;
149
+ const off = ascii ? HEALTH_ASCII_EMPTY : HEALTH_MARK_EMPTY;
150
+ return `${on.repeat(filled)}${off.repeat(levels - filled)}`;
151
+ }
152
+ /** Which form of the throughput number can be painted at all. */
153
+ export function performanceValueState(throughput, running) {
154
+ if (throughput === undefined)
155
+ return 'unavailable';
156
+ if (running && throughput.fresh && throughput.liveRate !== undefined)
157
+ return 'live';
158
+ if (!running && throughput.settledRate !== undefined && throughput.settledRate > 0)
159
+ return 'settled';
160
+ return 'unavailable';
161
+ }
162
+ /**
163
+ * The performance value: `160 tok/s`, `~160 tok/s`, `— tok/s`.
164
+ *
165
+ * Tokens per second is neutral telemetry, so this component never reaches for a
166
+ * threshold colour: the harness publishes no performance classification, and the
167
+ * same number means different things on a reasoning model, a small fast one, and
168
+ * a long-context request. `~` marks the live estimate — characters per second
169
+ * scaled by this session's own tokens-per-character — and the settled value has
170
+ * no mark because it is exact. A live value is lifted out of the row's muted
171
+ * style because it is the one number on the row that is *moving*; every theme
172
+ * understands "default intensity", and the mono theme keeps the distinction.
173
+ */
174
+ export function performanceValue(throughput, running, options = {}) {
175
+ const unit = options.short === true ? 't/s' : 'tok/s';
176
+ const state = options.state ?? performanceValueState(throughput, running);
177
+ if (state === 'unavailable')
178
+ return `— ${unit}`;
179
+ if (state === 'live') {
180
+ const text = `~${formatRate(throughput?.liveRate ?? 0)} ${unit}`;
181
+ return options.color === true ? `\x1b[0m${text}\x1b[0m` : text;
182
+ }
183
+ return `${formatRate(throughput?.settledRate ?? 0)} ${unit}`;
184
+ }
185
+ //# sourceMappingURL=footer-meters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer-meters.js","sourceRoot":"","sources":["../src/footer-meters.ts"],"names":[],"mappings":"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"}