@aragon-agent/cli 0.6.11 → 0.6.13
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/CHANGELOG.md +10 -1
- package/README.md +97 -20
- package/dist/agent/controller.d.ts +38 -3
- package/dist/agent/controller.js +151 -60
- package/dist/agent/model-profile-settings.d.ts +31 -0
- package/dist/agent/model-profile-settings.js +199 -0
- package/dist/agent/queued-messages.d.ts +20 -0
- package/dist/agent/queued-messages.js +46 -0
- package/dist/agent/reducer.d.ts +21 -2
- package/dist/agent/reducer.js +65 -37
- package/dist/cli.js +15 -1
- package/dist/commands/builtins.js +83 -42
- package/dist/commands/queue-command.d.ts +3 -0
- package/dist/commands/queue-command.js +5 -0
- package/dist/commands/registry.d.ts +3 -0
- package/dist/compaction/child.d.ts +4 -2
- package/dist/compaction/child.js +4 -1
- package/dist/compaction/compactor.d.ts +7 -2
- package/dist/compaction/compactor.js +13 -11
- package/dist/compaction/context-command.js +5 -0
- package/dist/compaction/wiring.d.ts +4 -3
- package/dist/compaction/wiring.js +6 -1
- package/dist/config/cli-commands.d.ts +2 -0
- package/dist/config/cli-commands.js +16 -4
- package/dist/config/load.d.ts +2 -1
- package/dist/config/load.js +15 -8
- package/dist/config/model-profile-resolution.d.ts +20 -0
- package/dist/config/model-profile-resolution.js +81 -0
- package/dist/config/model-profile-store.d.ts +67 -0
- package/dist/config/model-profile-store.js +153 -0
- package/dist/config/model-profiles.d.ts +44 -0
- package/dist/config/model-profiles.js +121 -0
- package/dist/config/schema.d.ts +9 -0
- package/dist/config/store.d.ts +11 -1
- package/dist/config/store.js +43 -27
- package/dist/fast/resolve.d.ts +2 -1
- package/dist/fast/resolve.js +6 -4
- package/dist/fast/wiring.d.ts +5 -3
- package/dist/fast/wiring.js +8 -4
- package/dist/input/enter-sequences.d.ts +11 -10
- package/dist/input/enter-sequences.js +29 -27
- package/dist/input/stdin-filter.js +93 -28
- package/dist/logging/install.d.ts +3 -0
- package/dist/logging/install.js +4 -2
- package/dist/logging/secret-registry.d.ts +2 -0
- package/dist/logging/secret-registry.js +18 -0
- package/dist/session/persist.d.ts +6 -7
- package/dist/session/persist.js +6 -9
- package/dist/session/store.d.ts +4 -1
- package/dist/session/validate-session.d.ts +3 -0
- package/dist/session/validate-session.js +207 -0
- package/dist/team/runtime.d.ts +2 -1
- package/dist/team/subagent.d.ts +3 -1
- package/dist/team/subagent.js +3 -1
- package/dist/ui/ActivityLine.d.ts +6 -70
- package/dist/ui/ActivityLine.js +12 -34
- package/dist/ui/App.d.ts +1 -0
- package/dist/ui/App.js +161 -226
- package/dist/ui/BottomStatusRow.d.ts +6 -86
- package/dist/ui/BottomStatusRow.js +11 -26
- package/dist/ui/Composer.d.ts +18 -84
- package/dist/ui/Composer.js +9 -100
- package/dist/ui/PromptInput.d.ts +6 -2
- package/dist/ui/PromptInput.js +91 -105
- package/dist/ui/QueuePanel.d.ts +8 -0
- package/dist/ui/QueuePanel.js +9 -0
- package/dist/ui/QueueStatusRow.d.ts +24 -0
- package/dist/ui/QueueStatusRow.js +51 -0
- package/dist/ui/StatusBar.d.ts +15 -149
- package/dist/ui/StatusBar.js +27 -112
- package/dist/ui/clipboard-task.d.ts +29 -0
- package/dist/ui/clipboard-task.js +66 -0
- package/dist/ui/clipboard.d.ts +29 -50
- package/dist/ui/clipboard.js +141 -75
- package/dist/ui/composer-input.d.ts +28 -0
- package/dist/ui/composer-input.js +46 -0
- package/dist/ui/composer-limits.d.ts +3 -4
- package/dist/ui/composer-limits.js +4 -9
- package/dist/ui/composer-rows.d.ts +1 -1
- package/dist/ui/composer-rows.js +24 -137
- package/dist/ui/editor-navigation.d.ts +45 -0
- package/dist/ui/editor-navigation.js +85 -0
- package/dist/ui/editor-reducer.d.ts +9 -0
- package/dist/ui/editor-reducer.js +31 -15
- package/dist/ui/enter-frames.d.ts +15 -31
- package/dist/ui/enter-frames.js +14 -33
- package/dist/ui/interaction-copy.d.ts +77 -0
- package/dist/ui/interaction-copy.js +40 -0
- package/dist/ui/interaction-hints.d.ts +18 -0
- package/dist/ui/interaction-hints.js +92 -0
- package/dist/ui/layout/budget.js +1 -1
- package/dist/ui/layout/queue-layout.d.ts +19 -0
- package/dist/ui/layout/queue-layout.js +26 -0
- package/dist/ui/layout/status-layout.d.ts +55 -0
- package/dist/ui/layout/status-layout.js +109 -0
- package/dist/ui/layout/todo-layout.d.ts +1 -0
- package/dist/ui/layout/todo-layout.js +1 -1
- package/dist/ui/overlays/HelpOverlay.js +11 -3
- package/dist/ui/overlays/ModelProfileEditor.d.ts +12 -0
- package/dist/ui/overlays/ModelProfileEditor.js +103 -0
- package/dist/ui/overlays/ModelProfilePicker.d.ts +35 -0
- package/dist/ui/overlays/ModelProfilePicker.js +167 -0
- package/dist/ui/overlays/QueueOverlay.d.ts +22 -0
- package/dist/ui/overlays/QueueOverlay.js +79 -0
- package/dist/ui/overlays/SettingsScreen.d.ts +9 -2
- package/dist/ui/overlays/SettingsScreen.js +347 -3
- package/dist/ui/overlays/model-profile-state.d.ts +74 -0
- package/dist/ui/overlays/model-profile-state.js +119 -0
- package/dist/ui/run-status-row.d.ts +7 -19
- package/dist/ui/run-status-row.js +2 -18
- package/dist/ui/selection/selection-controller.d.ts +2 -2
- package/dist/ui/selection/selection-controller.js +58 -20
- package/dist/ui/transcript-text.js +20 -12
- package/dist/ui/use-wheel-routing.js +2 -1
- package/package.json +2 -2
package/dist/ui/PromptInput.js
CHANGED
|
@@ -28,11 +28,14 @@ import { recognize } from '../input/keymap.js';
|
|
|
28
28
|
import { AutocompletePopup } from './AutocompletePopup.js';
|
|
29
29
|
import { buildAutocompleteLayout } from './layout/autocomplete.js';
|
|
30
30
|
import { editorReducer, INITIAL_EDITOR_STATE, } from './editor-reducer.js';
|
|
31
|
-
import { hasPasteFrame
|
|
32
|
-
import { hasEnterFrame,
|
|
31
|
+
import { hasPasteFrame } from './paste-frames.js';
|
|
32
|
+
import { hasEnterFrame, splitEnterFrames, } from './enter-frames.js';
|
|
33
|
+
import { planComposerInput } from './composer-input.js';
|
|
33
34
|
import { allocatePasteId, expandPastes, expandRangeOverTokens } from './paste-tokens.js';
|
|
34
35
|
import { draftMaxRows } from './composer-limits.js';
|
|
35
36
|
import { layoutComposer, splitRowAtColumn } from './composer-rows.js';
|
|
37
|
+
import { moveVisualCursor, snapGrapheme, stepGrapheme } from './editor-navigation.js';
|
|
38
|
+
import { interactionCopy } from './interaction-copy.js';
|
|
36
39
|
import { PASTE_DRAFT_MAX_BYTES, PASTE_MAX_BLOCKS, formatPasteSize, } from '../input/limits.js';
|
|
37
40
|
// ---------------------------------------------------------------------------
|
|
38
41
|
// The scroll chip (§4.2)
|
|
@@ -132,6 +135,8 @@ export function draftLimitRefusal(segments, editor) {
|
|
|
132
135
|
// ---------------------------------------------------------------------------
|
|
133
136
|
const isSpace = (ch) => !!ch && /\s/.test(ch);
|
|
134
137
|
function lineStart(buffer, cursor) {
|
|
138
|
+
if (cursor <= 0)
|
|
139
|
+
return 0;
|
|
135
140
|
const nl = buffer.lastIndexOf('\n', cursor - 1);
|
|
136
141
|
return nl === -1 ? 0 : nl + 1;
|
|
137
142
|
}
|
|
@@ -165,23 +170,23 @@ function nextWord(buffer, cursor) {
|
|
|
165
170
|
* label the user then sends INSTEAD of the text it stands for.
|
|
166
171
|
*/
|
|
167
172
|
function killRange(buffer, from, to) {
|
|
168
|
-
const range = expandRangeOverTokens(buffer, from, to);
|
|
173
|
+
const range = expandRangeOverTokens(buffer, snapGrapheme(buffer, from), snapGrapheme(buffer, to, true));
|
|
169
174
|
return { buffer: buffer.slice(0, range.from) + buffer.slice(range.to), cursor: range.from };
|
|
170
175
|
}
|
|
171
176
|
/** Apply an edit intent as a pure buffer/cursor transform. */
|
|
172
177
|
export function applyEdit(buffer, cursor, intent) {
|
|
178
|
+
cursor = snapGrapheme(buffer, cursor);
|
|
173
179
|
switch (intent) {
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
// a synthetic unit buys a correctness the user cannot notice.
|
|
180
|
+
// Navigation may enter a token label; insertion and range deletion retain
|
|
181
|
+
// the existing token snapping and expansion contracts.
|
|
177
182
|
case 'home':
|
|
178
183
|
return { buffer, cursor: lineStart(buffer, cursor) };
|
|
179
184
|
case 'end':
|
|
180
185
|
return { buffer, cursor: lineEnd(buffer, cursor) };
|
|
181
186
|
case 'wordLeft':
|
|
182
|
-
return { buffer, cursor: prevWord(buffer, cursor) };
|
|
187
|
+
return { buffer, cursor: snapGrapheme(buffer, prevWord(buffer, cursor)) };
|
|
183
188
|
case 'wordRight':
|
|
184
|
-
return { buffer, cursor: nextWord(buffer, cursor) };
|
|
189
|
+
return { buffer, cursor: snapGrapheme(buffer, nextWord(buffer, cursor), true) };
|
|
185
190
|
case 'deleteWordBack':
|
|
186
191
|
return killRange(buffer, prevWord(buffer, cursor), cursor);
|
|
187
192
|
case 'killToStart':
|
|
@@ -196,19 +201,8 @@ export function applyEdit(buffer, cursor, intent) {
|
|
|
196
201
|
* prompt-history recall.
|
|
197
202
|
*/
|
|
198
203
|
export function moveVertical(buffer, cursor, dir) {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
return null;
|
|
202
|
-
const before = buffer.slice(0, cursor);
|
|
203
|
-
const idx = before.split('\n').length - 1;
|
|
204
|
-
const col = before.length - (before.lastIndexOf('\n') + 1);
|
|
205
|
-
const target = dir === 'up' ? idx - 1 : idx + 1;
|
|
206
|
-
if (target < 0 || target >= lines.length)
|
|
207
|
-
return null;
|
|
208
|
-
let start = 0;
|
|
209
|
-
for (let i = 0; i < target; i += 1)
|
|
210
|
-
start += lines[i].length + 1;
|
|
211
|
-
return { cursor: start + Math.min(col, lines[target].length) };
|
|
204
|
+
const moved = moveVisualCursor({ buffer, cursor, direction: dir, cols: Number.MAX_SAFE_INTEGER });
|
|
205
|
+
return moved ? { cursor: moved.cursor } : null;
|
|
212
206
|
}
|
|
213
207
|
/**
|
|
214
208
|
* Slash-command suggestions when the buffer is a bare `/word` (no space yet).
|
|
@@ -249,7 +243,7 @@ function isControlSeq(input) {
|
|
|
249
243
|
// ---------------------------------------------------------------------------
|
|
250
244
|
// Component
|
|
251
245
|
// ---------------------------------------------------------------------------
|
|
252
|
-
export function PromptInput({ cols: colsProp, cursorVisible = true, onInteraction, isActive, running, history, commands, cwd, theme, caps, popupMaxRows, popupMaxHeight, onPopupRowsChange, agentMode, onSubmit, onHelp, onEscape, onEscapeDismiss, reducedMotion = false, borderColor, onDraftChange, onNotice, scrolledLines = 0, }) {
|
|
246
|
+
export function PromptInput({ cols: colsProp, cursorVisible = true, onInteraction, isActive, running, history, commands, cwd, theme, caps, popupMaxRows, popupMaxHeight, onPopupRowsChange, onCompletionContextChange, deleteDisambiguated = false, agentMode, onSubmit, onHelp, onEscape, onEscapeDismiss, reducedMotion = false, borderColor, onDraftChange, onNotice, scrolledLines = 0, }) {
|
|
253
247
|
const { stdout } = useStdout();
|
|
254
248
|
const [editor, dispatch] = useReducer(editorReducer, INITIAL_EDITOR_STATE);
|
|
255
249
|
const { buffer, cursor, historyIndex, dismissed, sel } = editor;
|
|
@@ -279,6 +273,17 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
279
273
|
onPopupRowsChange?.(popupLayout.rowCount);
|
|
280
274
|
}, [onPopupRowsChange, popupLayout.rowCount]);
|
|
281
275
|
useLayoutEffect(() => () => onPopupRowsChange?.(0), [onPopupRowsChange]);
|
|
276
|
+
const completion = popupVisible ? popupKind ?? 'none' : 'none';
|
|
277
|
+
const completionCallback = useRef(onCompletionContextChange);
|
|
278
|
+
completionCallback.current = onCompletionContextChange;
|
|
279
|
+
const lastCompletion = useRef();
|
|
280
|
+
useLayoutEffect(() => {
|
|
281
|
+
if (!onCompletionContextChange || lastCompletion.current === completion)
|
|
282
|
+
return;
|
|
283
|
+
lastCompletion.current = completion;
|
|
284
|
+
onCompletionContextChange?.(completion);
|
|
285
|
+
}, [onCompletionContextChange, completion]);
|
|
286
|
+
useLayoutEffect(() => () => completionCallback.current?.('none'), []);
|
|
282
287
|
// --- Debounced `@file` scan. ---------------------------------------------
|
|
283
288
|
useEffect(() => {
|
|
284
289
|
if (fileQuery === null || fileQuery.length < 1) {
|
|
@@ -346,6 +351,8 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
346
351
|
const overflows = wide.hiddenAbove > 0 || wide.hiddenBelow > 0;
|
|
347
352
|
const usableCols = overflows ? Math.max(8, baseCols - OVERFLOW_CELLS - 1) : baseCols;
|
|
348
353
|
const layout = overflows ? measure(usableCols) : wide;
|
|
354
|
+
const preferredColumnWidth = useRef();
|
|
355
|
+
useLayoutEffect(() => { preferredColumnWidth.current = undefined; }, [usableCols]);
|
|
349
356
|
const draftRowCount = Math.max(1, layout.rows.length);
|
|
350
357
|
const caretResetKey = useMemo(() => ({}), [buffer, cursor, isActive, usableCols]);
|
|
351
358
|
// --- Draft presence and height, reported only on a transition. -----------
|
|
@@ -371,18 +378,42 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
371
378
|
onInteraction?.();
|
|
372
379
|
dispatch({ type: 'insert', text });
|
|
373
380
|
};
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
const resolveSubmit = (state) => {
|
|
382
|
+
const suggestions = state.dismissed ? null : slashSuggestions(state.buffer, commands);
|
|
383
|
+
const selectedIndex = Math.min(state.sel, (suggestions?.length ?? 0) - 1);
|
|
384
|
+
const suggestionLayout = buildAutocompleteLayout({
|
|
385
|
+
itemCount: isActive ? suggestions?.length ?? 0 : 0,
|
|
386
|
+
selected: selectedIndex, maxRows: popupMaxRows, maxHeight: popupMaxHeight,
|
|
387
|
+
});
|
|
388
|
+
const selected = suggestionLayout.rowCount > 0 ? suggestions?.[selectedIndex] : undefined;
|
|
389
|
+
const text = selected?.label ?? expandPastes(state.buffer, state.pastes);
|
|
390
|
+
return text.trim().length > 0 ? text : null;
|
|
391
|
+
};
|
|
392
|
+
const transact = (intents) => {
|
|
393
|
+
const plan = planComposerInput({
|
|
394
|
+
editor, intents, resolveSubmit, checkPasteLimit: draftLimitRefusal,
|
|
395
|
+
});
|
|
396
|
+
if (plan.refusal) {
|
|
397
|
+
onNotice?.('warn', plan.refusal);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
383
400
|
onInteraction?.();
|
|
384
|
-
|
|
385
|
-
|
|
401
|
+
let result = { accepted: true };
|
|
402
|
+
if (plan.submission !== undefined) {
|
|
403
|
+
try {
|
|
404
|
+
result = onSubmit(plan.submission);
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
result = { accepted: false, reason: error instanceof Error ? error.message : String(error) };
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
dispatch({ type: 'adopt', state: result.accepted ? plan.nextEditor : plan.rejectedEditor });
|
|
411
|
+
if (!result.accepted) {
|
|
412
|
+
onNotice?.('error', result.reason ?? 'Message was not accepted; input is kept in the draft.');
|
|
413
|
+
}
|
|
414
|
+
else if (plan.notice) {
|
|
415
|
+
onNotice?.('warn', plan.notice);
|
|
416
|
+
}
|
|
386
417
|
};
|
|
387
418
|
const recallUp = () => {
|
|
388
419
|
if (history.length === 0)
|
|
@@ -421,9 +452,12 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
421
452
|
};
|
|
422
453
|
const verticalOrHistory = (dir) => {
|
|
423
454
|
onInteraction?.();
|
|
424
|
-
const moved =
|
|
455
|
+
const moved = moveVisualCursor({ buffer, cursor, cols: usableCols, direction: dir,
|
|
456
|
+
preferredVisualColumn: preferredColumnWidth.current === usableCols
|
|
457
|
+
? editor.preferredVisualColumn : undefined });
|
|
425
458
|
if (moved) {
|
|
426
|
-
|
|
459
|
+
preferredColumnWidth.current = usableCols;
|
|
460
|
+
dispatch({ type: 'moveCursor', ...moved });
|
|
427
461
|
return;
|
|
428
462
|
}
|
|
429
463
|
// At an edge: recall history only from an empty buffer or while already
|
|
@@ -447,6 +481,16 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
447
481
|
return;
|
|
448
482
|
if (key.pageUp || key.pageDown || (key.shift && (key.upArrow || key.downArrow)))
|
|
449
483
|
return;
|
|
484
|
+
if ((key.return || input === '\r') && (key.meta || key.shift)) {
|
|
485
|
+
insert('\n');
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (hasPasteFrame(input) || hasEnterFrame(input) || /[\r\n]/.test(input)) {
|
|
489
|
+
const intents = splitEnterFrames(input).map((frame) => frame.kind === 'paste' ? { ...frame, id: allocatePasteId() } : frame);
|
|
490
|
+
if (intents.length > 0)
|
|
491
|
+
transact(intents);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
450
494
|
// Popup navigation owns Up/Down/Tab/→/Enter/Esc while it is open.
|
|
451
495
|
if (popupVisible) {
|
|
452
496
|
if (key.upArrow) {
|
|
@@ -464,9 +508,7 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
464
508
|
return;
|
|
465
509
|
}
|
|
466
510
|
if (key.return && popupKind === 'slash') {
|
|
467
|
-
|
|
468
|
-
if (label)
|
|
469
|
-
submit(label);
|
|
511
|
+
transact([{ kind: 'submit' }]);
|
|
470
512
|
return;
|
|
471
513
|
}
|
|
472
514
|
if (key.escape) {
|
|
@@ -481,11 +523,15 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
481
523
|
return;
|
|
482
524
|
}
|
|
483
525
|
// Line-editing intents (Home/End/word/kill) recognized from raw keys.
|
|
484
|
-
const intent =
|
|
526
|
+
const intent = key.meta && (key.backspace || key.delete)
|
|
527
|
+
? 'deleteWordBack' : recognize(input, key);
|
|
485
528
|
if (intent) {
|
|
486
529
|
onInteraction?.();
|
|
487
530
|
const next = applyEdit(buffer, cursor, intent);
|
|
488
|
-
|
|
531
|
+
const moving = intent === 'home' || intent === 'end'
|
|
532
|
+
|| intent === 'wordLeft' || intent === 'wordRight';
|
|
533
|
+
dispatch(moving ? { type: 'moveCursor', cursor: next.cursor }
|
|
534
|
+
: { type: 'replace', buffer: next.buffer, cursor: next.cursor });
|
|
489
535
|
return;
|
|
490
536
|
}
|
|
491
537
|
if (key.ctrl)
|
|
@@ -497,7 +543,7 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
497
543
|
}
|
|
498
544
|
if (buffer.trim().length === 0)
|
|
499
545
|
return;
|
|
500
|
-
submit
|
|
546
|
+
transact([{ kind: 'submit' }]);
|
|
501
547
|
return;
|
|
502
548
|
}
|
|
503
549
|
if (key.backspace || key.delete) {
|
|
@@ -506,19 +552,17 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
506
552
|
// unconditional dispatch and a no-op at the left edge returns the same
|
|
507
553
|
// state object — which React bails out on, exactly as the old
|
|
508
554
|
// `if (cursor > 0)` skipped the `setState`s.
|
|
509
|
-
dispatch({ type: 'backspace' });
|
|
555
|
+
dispatch({ type: key.delete && deleteDisambiguated ? 'delete' : 'backspace' });
|
|
510
556
|
return;
|
|
511
557
|
}
|
|
512
558
|
if (key.leftArrow) {
|
|
513
559
|
onInteraction?.();
|
|
514
|
-
|
|
515
|
-
dispatch({ type: 'moveCursor', cursor: Math.max(0, cursor - step) });
|
|
560
|
+
dispatch({ type: 'moveCursor', cursor: stepGrapheme(buffer, cursor, 'left') });
|
|
516
561
|
return;
|
|
517
562
|
}
|
|
518
563
|
if (key.rightArrow) {
|
|
519
564
|
onInteraction?.();
|
|
520
|
-
|
|
521
|
-
dispatch({ type: 'moveCursor', cursor: Math.min(buffer.length, cursor + step) });
|
|
565
|
+
dispatch({ type: 'moveCursor', cursor: stepGrapheme(buffer, cursor, 'right') });
|
|
522
566
|
return;
|
|
523
567
|
}
|
|
524
568
|
// `!key.shift` is load-bearing: Shift+↑/↓ is the viewport's line-scroll
|
|
@@ -537,71 +581,13 @@ export function PromptInput({ cols: colsProp, cursorVisible = true, onInteractio
|
|
|
537
581
|
onHelp();
|
|
538
582
|
return;
|
|
539
583
|
}
|
|
540
|
-
// A PASTE (section 5.4). It sits AFTER every key branch so a paste can
|
|
541
|
-
// never be shadowed by a key test, and BEFORE `isControlSeq` because a
|
|
542
|
-
// framed string starts with NUL and would otherwise be dropped.
|
|
543
|
-
//
|
|
544
|
-
// The text runs inside `segments` are already sanitised (I-14): Ink drains
|
|
545
|
-
// its whole buffer in one `read()`, so this same string can carry the `\r`
|
|
546
|
-
// of a user who pasted and pressed Enter inside the burst window.
|
|
547
|
-
//
|
|
548
|
-
// NO NEWLINE INTENT IN THE CHUNK (tui-shift-enter-copy-queue 3.5):
|
|
549
|
-
// that same one-`read()` coalescing means a paste frame can share an
|
|
550
|
-
// `input` with an enter frame or a bare Ctrl+J, and those chunks
|
|
551
|
-
// belong to the newline branch below, whose `mergeWithPasteRuns`
|
|
552
|
-
// interleaves both families in byte order. This branch's
|
|
553
|
-
// `splitPasteFrames` would strip the enter frame's NUL and leak its
|
|
554
|
-
// letter as text. A multi-line payload (a `\n` of its own) routes
|
|
555
|
-
// there too and comes back byte-identical inside its paste segment.
|
|
556
|
-
if (hasPasteFrame(input) && !hasEnterFrame(input) && !input.includes('\n')) {
|
|
557
|
-
const runs = splitPasteFrames(input);
|
|
558
|
-
const segments = runs.map((run) => run.kind === 'paste' ? { kind: 'paste', text: run.text, id: allocatePasteId() } : run);
|
|
559
|
-
if (segments.length === 0)
|
|
560
|
-
return;
|
|
561
|
-
const refusal = draftLimitRefusal(segments, editor);
|
|
562
|
-
if (refusal) {
|
|
563
|
-
// A refusal dispatches NOTHING, so the draft is byte-for-byte
|
|
564
|
-
// unchanged (AC-9) — and it is never silent (D-11).
|
|
565
|
-
onNotice?.('warn', refusal);
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
onInteraction?.();
|
|
569
|
-
dispatch({ type: 'input', segments });
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
// A NEWLINE INTENT, from either source (tui-shift-enter-copy-queue
|
|
573
|
-
// 3.5): the NUL frame the filter wrote for Shift+Enter / Alt+Enter /
|
|
574
|
-
// CSI-u Enter, or a bare `\n` (Ctrl+J), which Ink delivers WITHOUT
|
|
575
|
-
// `key.return`. Sits beside the paste branch -- after every key test so
|
|
576
|
-
// it can never shadow one, before `isControlSeq` because both sources
|
|
577
|
-
// begin with a control byte and would otherwise be dropped. ONE
|
|
578
|
-
// dispatch carries the whole ordered chunk, paste runs included when
|
|
579
|
-
// Ink coalesced the filter's two writes into one input string.
|
|
580
|
-
if (hasEnterFrame(input) || input.includes('\n')) {
|
|
581
|
-
const runs = mergeWithPasteRuns(input, splitEnterFrames(input));
|
|
582
|
-
const segments = runs.map((run) => run.kind === 'paste' ? { kind: 'paste', text: run.text, id: allocatePasteId() } : run);
|
|
583
|
-
if (segments.length === 0)
|
|
584
|
-
return;
|
|
585
|
-
const refusal = draftLimitRefusal(segments, editor);
|
|
586
|
-
if (refusal) {
|
|
587
|
-
onNotice?.('warn', refusal);
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
onInteraction?.();
|
|
591
|
-
dispatch({ type: 'input', segments });
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
594
584
|
// Printable input — drop any unrecognized control/escape byte.
|
|
595
585
|
if (input && !key.tab && !isControlSeq(input))
|
|
596
586
|
insert(input);
|
|
597
587
|
}, { isActive });
|
|
598
588
|
const marker = running ? glyphs.steer : glyphs.caret;
|
|
599
589
|
const markerColor = running ? theme.toolRunning : theme.primary;
|
|
600
|
-
const placeholder = running
|
|
601
|
-
? `Type to queue a message, Esc twice to interrupt${glyphs.ellipsis}`
|
|
602
|
-
: agentMode === 'plan'
|
|
603
|
-
? `Describe what you want to build; I'll research and plan it first${glyphs.ellipsis}`
|
|
604
|
-
: `Send a message (/ for commands, @ for files)${glyphs.ellipsis}`;
|
|
590
|
+
const placeholder = running ? interactionCopy.runningPlaceholder : interactionCopy.idlePlaceholder;
|
|
605
591
|
const overflow = overflowChip(layout.hiddenAbove, layout.hiddenBelow, glyphs);
|
|
606
592
|
const tokenColor = theme.hintFg ?? theme.muted;
|
|
607
593
|
const renderSegments = (segments, keyPrefix) => segments.map((segment, i) => (_jsx(Text, { color: segment.kind === 'token' ? tokenColor : undefined, children: segment.text }, `${keyPrefix}${i}`)));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { QueueLayout } from './layout/queue-layout.js';
|
|
3
|
+
import type { Theme } from './theme.js';
|
|
4
|
+
/** Persistent receipt-backed footer, with no timer or separate queue state. */
|
|
5
|
+
export declare const QueuePanel: React.NamedExoticComponent<{
|
|
6
|
+
layout: QueueLayout;
|
|
7
|
+
theme: Theme;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
/** Persistent receipt-backed footer, with no timer or separate queue state. */
|
|
5
|
+
export const QueuePanel = React.memo(function QueuePanel({ layout, theme }) {
|
|
6
|
+
if (!layout.rows)
|
|
7
|
+
return null;
|
|
8
|
+
return _jsxs(Box, { flexDirection: "column", flexShrink: 0, height: layout.rows, children: [_jsx(Text, { color: theme.accent, wrap: "truncate", children: layout.title }), layout.rows > 1 && layout.items.map((item) => _jsx(Text, { color: theme.muted, wrap: "truncate", children: item.label }, item.queueId))] });
|
|
9
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PendingSteering } from '../agent/queued-messages.js';
|
|
3
|
+
import type { TermCapabilities } from './capabilities.js';
|
|
4
|
+
import type { Theme } from './theme.js';
|
|
5
|
+
export interface QueueStatusRowProps {
|
|
6
|
+
pending: readonly PendingSteering[];
|
|
7
|
+
paused: boolean;
|
|
8
|
+
columns: number;
|
|
9
|
+
compact: boolean;
|
|
10
|
+
theme: Theme;
|
|
11
|
+
caps: TermCapabilities;
|
|
12
|
+
}
|
|
13
|
+
/** Return the first nonempty logical line without terminal control characters. */
|
|
14
|
+
export declare function queueSummary(text: string): string;
|
|
15
|
+
/** Truncate at a whole grapheme, reserving the ellipsis in the same cell budget. */
|
|
16
|
+
export declare function truncateSummary(text: string, columns: number, ellipsis: string): string;
|
|
17
|
+
/** Format a queue using only the columns assigned by the status bar. */
|
|
18
|
+
export declare function formatQueueStatus(props: Omit<QueueStatusRowProps, 'theme'>): {
|
|
19
|
+
prefix: string;
|
|
20
|
+
body: string;
|
|
21
|
+
suffix: string;
|
|
22
|
+
};
|
|
23
|
+
/** Fixed single-line pending receipt feedback; no timeout or spinner. */
|
|
24
|
+
export declare function QueueStatusRow(props: QueueStatusRowProps): React.ReactElement;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
import stringWidth from 'string-width';
|
|
4
|
+
import stripAnsi from 'strip-ansi';
|
|
5
|
+
import { pickGlyphs } from './glyphs.js';
|
|
6
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
|
|
7
|
+
/** Return the first nonempty logical line without terminal control characters. */
|
|
8
|
+
export function queueSummary(text) {
|
|
9
|
+
return stripAnsi(text).split(/\r\n|[\r\n]/)
|
|
10
|
+
.map((line) => line.replace(/\t/g, ' ').replace(/[\x00-\x1f\x7f-\x9f]/g, '').trim())
|
|
11
|
+
.find(Boolean) ?? '(empty)';
|
|
12
|
+
}
|
|
13
|
+
/** Truncate at a whole grapheme, reserving the ellipsis in the same cell budget. */
|
|
14
|
+
export function truncateSummary(text, columns, ellipsis) {
|
|
15
|
+
if (stringWidth(text) <= columns)
|
|
16
|
+
return text;
|
|
17
|
+
if (columns < stringWidth(ellipsis))
|
|
18
|
+
return '';
|
|
19
|
+
let out = '';
|
|
20
|
+
let used = stringWidth(ellipsis);
|
|
21
|
+
for (const { segment } of segmenter.segment(text)) {
|
|
22
|
+
const width = stringWidth(segment);
|
|
23
|
+
if (used + width > columns)
|
|
24
|
+
break;
|
|
25
|
+
used += width;
|
|
26
|
+
out += segment;
|
|
27
|
+
}
|
|
28
|
+
return out + ellipsis;
|
|
29
|
+
}
|
|
30
|
+
/** Format a queue using only the columns assigned by the status bar. */
|
|
31
|
+
export function formatQueueStatus(props) {
|
|
32
|
+
if (!props.pending.length)
|
|
33
|
+
return { prefix: '', body: '', suffix: '' };
|
|
34
|
+
const prefix = props.paused
|
|
35
|
+
? (props.compact ? 'Queue(p): ' : 'Queue (paused): ') : 'Queue: ';
|
|
36
|
+
const remaining = props.pending.length - 1;
|
|
37
|
+
const suffix = remaining === 0 ? '' : props.compact
|
|
38
|
+
? `(+${remaining > 99 ? '99+' : remaining})` : `(+${remaining} more)`;
|
|
39
|
+
const tail = suffix ? ` ${suffix}` : '';
|
|
40
|
+
const budget = Math.max(0, props.columns - stringWidth(prefix + tail));
|
|
41
|
+
return {
|
|
42
|
+
prefix,
|
|
43
|
+
body: truncateSummary(queueSummary(props.pending[0].text), budget, pickGlyphs(props.caps).ellipsis),
|
|
44
|
+
suffix: tail,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Fixed single-line pending receipt feedback; no timeout or spinner. */
|
|
48
|
+
export function QueueStatusRow(props) {
|
|
49
|
+
const parts = formatQueueStatus(props);
|
|
50
|
+
return _jsxs(Text, { children: [_jsx(Text, { color: props.theme.accent, children: parts.prefix }), _jsxs(Text, { color: props.theme.muted, children: [parts.body, parts.suffix] })] });
|
|
51
|
+
}
|
package/dist/ui/StatusBar.d.ts
CHANGED
|
@@ -1,40 +1,27 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Status bar (spec §4.8). Width-aware, borderless, EXACTLY one row: a left
|
|
3
|
-
* cluster (run status, model, thinking level) and a right cluster (context
|
|
4
|
-
* gauge, occupancy pair, session total, cost, tokens/sec + elapsed while
|
|
5
|
-
* running, off-bottom `↑N`). Clusters drop out gracefully on narrow terminals.
|
|
6
|
-
*
|
|
7
|
-
* THE RIGHT CLUSTER'S WIDTH LADDER (context-usage-gauge-accuracy §3.6):
|
|
8
|
-
*
|
|
9
|
-
* >= 96 [####....] 43% 86.0k/200.0k total 1.2M^ 48.0k v $3.21 12 tok/s 1m02s
|
|
10
|
-
* 72-95 [####....] 43% 86.0k/200.0k $3.21
|
|
11
|
-
* 60-71 [####....] 43% $3.21
|
|
12
|
-
* < 60 43% $3.21
|
|
13
|
-
*
|
|
14
|
-
* Dropping the round border here buys back 3 rows of a 24-row terminal — an
|
|
15
|
-
* eighth of the screen was being spent framing a single line of text.
|
|
16
|
-
*/
|
|
1
|
+
/** A single row of complete, measured status fields. */
|
|
17
2
|
import React from 'react';
|
|
18
3
|
import type { Theme } from './theme.js';
|
|
19
4
|
import type { TermCapabilities } from './capabilities.js';
|
|
20
5
|
import type { UsageTotal } from '../agent/reducer.js';
|
|
21
6
|
import type { ContextUsageSnapshot } from '../compaction/types.js';
|
|
22
|
-
import {
|
|
23
|
-
|
|
7
|
+
import type { AgentMode } from '../agent/agent-mode.js';
|
|
8
|
+
import type { PendingSteering } from '../agent/queued-messages.js';
|
|
9
|
+
import { type RunPhase } from './layout/status-layout.js';
|
|
10
|
+
export interface StatusBarProps {
|
|
11
|
+
runPhase?: RunPhase;
|
|
12
|
+
activeTool?: {
|
|
13
|
+
name: string;
|
|
14
|
+
toolCallId: string;
|
|
15
|
+
} | null;
|
|
16
|
+
runOutcome?: "none" | "ended" | "interrupted" | "failed";
|
|
17
|
+
reducedMotion?: boolean;
|
|
18
|
+
waitingForConfirmation?: boolean;
|
|
19
|
+
stopping?: boolean;
|
|
20
|
+
pendingSteering?: readonly PendingSteering[];
|
|
24
21
|
interruptHint?: string;
|
|
25
22
|
model: string;
|
|
26
23
|
provider: string;
|
|
27
24
|
usageTotal: UsageTotal;
|
|
28
|
-
/**
|
|
29
|
-
* Context occupancy, as one object (context-usage-gauge-accuracy §4.3).
|
|
30
|
-
*
|
|
31
|
-
* IT REPLACED FOUR PARALLEL PROPS - `contextTokens`, `contextWindow`,
|
|
32
|
-
* `contextWindowKnown`, `contextEstimated`. Four props describing one reading
|
|
33
|
-
* are four chances for a caller to update three of them, which is the props-
|
|
34
|
-
* layer form of the "many writers" defect this feature removed from the
|
|
35
|
-
* reducer. `usageTotal` stays separate because it genuinely IS another
|
|
36
|
-
* quantity: session spend, not occupancy.
|
|
37
|
-
*/
|
|
38
25
|
context: ContextUsageSnapshot;
|
|
39
26
|
status: 'idle' | 'running';
|
|
40
27
|
elapsedMs: number;
|
|
@@ -42,157 +29,36 @@ interface StatusBarProps {
|
|
|
42
29
|
tokPerSec: number;
|
|
43
30
|
theme: Theme;
|
|
44
31
|
caps: TermCapabilities;
|
|
45
|
-
/**
|
|
46
|
-
* Lines scrolled off the bottom; > 0 renders `↑N`. Inline mode has no
|
|
47
|
-
* self-drawn viewport, so it simply never sends anything but 0 — the bar
|
|
48
|
-
* needs no render-mode branch of its own.
|
|
49
|
-
*/
|
|
50
32
|
scrolledLines?: number;
|
|
51
|
-
/**
|
|
52
|
-
* Ctrl+L redraw carrier — invariant I-5 (spec §4.13). See `redrawChar`.
|
|
53
|
-
*/
|
|
54
33
|
redrawNonce?: number;
|
|
55
34
|
agentMode?: AgentMode;
|
|
56
|
-
/** Non-null while a deferred `plan -> build` waits for `agent_end`. */
|
|
57
35
|
pendingAgentMode?: AgentMode | null;
|
|
58
|
-
/**
|
|
59
|
-
* Live subagent counts (team-subagents §6.2), or absent when no dispatch is
|
|
60
|
-
* running — an ordinary session's bar is then unchanged.
|
|
61
|
-
*
|
|
62
|
-
* LEFT CLUSTER, and it degrades (D-20 / P2-1). The left cluster is
|
|
63
|
-
* `flexShrink={0}`, so every column it takes comes out of the context gauge
|
|
64
|
-
* and the cost readout opposite it; on an 80-column terminal the full
|
|
65
|
-
* `agents 3/5` visibly squeezes them, and the gauge is how a user notices they
|
|
66
|
-
* are about to run out of context. Below `TEAM_LIMITS.statusCompactCols` this
|
|
67
|
-
* therefore renders as `[3]` — the running count alone.
|
|
68
|
-
*
|
|
69
|
-
* This does NOT contradict the "no `cols >= N` breakpoint" rule above: that
|
|
70
|
-
* rule is written about `agentMode`, whose reason is that the mode must never
|
|
71
|
-
* be unreportable. The team counter has a second, fuller home in `TeamPanel`
|
|
72
|
-
* and a third in `TeamCard`; it is the one readout on this bar that can afford
|
|
73
|
-
* to degrade.
|
|
74
|
-
*/
|
|
75
36
|
teamActive?: {
|
|
76
37
|
running: number;
|
|
77
38
|
total: number;
|
|
78
39
|
};
|
|
79
|
-
/**
|
|
80
|
-
* Live todo counts (todo-plan-execution §6.3), or absent.
|
|
81
|
-
*
|
|
82
|
-
* `App` sends this ONLY when a list exists AND the rail does not: with the
|
|
83
|
-
* rail on screen the numbers are already there in a larger typeface, and
|
|
84
|
-
* duplicating them costs the context gauge columns it cannot spare. This is
|
|
85
|
-
* therefore the INLINE-MODE and NARROW-TERMINAL fallback for R-d, which is
|
|
86
|
-
* exactly why it is here rather than being folded into the rail's own gate.
|
|
87
|
-
*
|
|
88
|
-
* Degrades below `TODO_LIMITS.statusCompactCols` from `todo 2/7` to `[2/7]`,
|
|
89
|
-
* the same treatment and the same justification as the team counter's
|
|
90
|
-
* `agents 3/5` -> `[3]`. See the note on `agentMode` for why that rule does
|
|
91
|
-
* NOT apply to the mode word.
|
|
92
|
-
*/
|
|
93
40
|
todoActive?: {
|
|
94
41
|
done: number;
|
|
95
42
|
total: number;
|
|
96
43
|
};
|
|
97
|
-
/**
|
|
98
|
-
* Live background services (background-service-supervision §3.8), or absent
|
|
99
|
-
* when none are running — an ordinary session's bar is then unchanged.
|
|
100
|
-
*
|
|
101
|
-
* LEFT CLUSTER, after the todo chip, and it DEGRADES rather than hiding below
|
|
102
|
-
* `PROC_LIMITS.statusCompactCols`. That is the `todoActive` / `teamActive`
|
|
103
|
-
* ladder rather than `compactionActive`'s hide-below-threshold one, and the
|
|
104
|
-
* choice is deliberate: `compact` and `fast` describe something the CLI is
|
|
105
|
-
* doing to itself, whereas this is a PROCESS ON THE USER'S MACHINE HOLDING A
|
|
106
|
-
* PORT. A narrow terminal is a reason to shorten it, never a reason to stop
|
|
107
|
-
* saying it.
|
|
108
|
-
*
|
|
109
|
-
* `live` counts `starting | ready | running`. The transcript records events
|
|
110
|
-
* about a service (D-11); this is where "what is running right now" lives,
|
|
111
|
-
* alongside `/bg` and `bash_output`.
|
|
112
|
-
*/
|
|
113
44
|
servicesActive?: {
|
|
114
45
|
live: number;
|
|
115
46
|
};
|
|
116
|
-
/**
|
|
117
|
-
* Live retry state (llm-api-retry-backoff §6.6), or absent when nothing is
|
|
118
|
-
* retrying — an ordinary session's bar is then unchanged.
|
|
119
|
-
*
|
|
120
|
-
* LEFT CLUSTER, after `teamActive`, and it DEGRADES. It is a run-state fact like
|
|
121
|
-
* `agents 3/5`, and the left cluster is `flexShrink={0}` so every column it takes
|
|
122
|
-
* comes out of the context gauge; below `RETRY_UI.statusCompactCols` it renders
|
|
123
|
-
* as `[r3]`.
|
|
124
|
-
*
|
|
125
|
-
* This does NOT contradict the "no `cols >= N` breakpoint" rule on `agentMode`
|
|
126
|
-
* above: that rule exists because the MODE must never be unreportable. The retry
|
|
127
|
-
* has a second, fuller home in the transcript card, which is exactly why it is
|
|
128
|
-
* the kind of readout that can afford to shrink.
|
|
129
|
-
*/
|
|
130
47
|
retryActive?: {
|
|
131
48
|
attempt: number;
|
|
132
49
|
max: number;
|
|
133
50
|
secondsLeft: number;
|
|
134
51
|
};
|
|
135
|
-
/**
|
|
136
|
-
* Render-governor rung (tui-render-performance L4). `> 0` renders a muted
|
|
137
|
-
* `eco` chip.
|
|
138
|
-
*
|
|
139
|
-
* I-L4-2 — THE GOVERNOR IS USER-VISIBLE, and this is where. A user who cannot
|
|
140
|
-
* see why the stream got chunkier will conclude the model got slower, and
|
|
141
|
-
* degrading silently is the one thing a claim of robustness cannot afford.
|
|
142
|
-
* It sits in the RIGHT cluster next to the other derived numbers and is
|
|
143
|
-
* suppressed on a narrow terminal, which is the `teamActive` treatment rather
|
|
144
|
-
* than the `agentMode` one: the mode must never be unreportable, whereas an
|
|
145
|
-
* eco chip on a 50-column terminal costs the context gauge more than it says.
|
|
146
|
-
*/
|
|
147
52
|
ecoRung?: number;
|
|
148
|
-
/**
|
|
149
|
-
* The live fast tier (fast-model-tier §6), or absent when it is off for this
|
|
150
|
-
* session — in which case an ordinary session's bar is byte-identical.
|
|
151
|
-
*
|
|
152
|
-
* RIGHT CLUSTER, next to `eco`, and it DEGRADES below
|
|
153
|
-
* `FAST_LIMITS.statusCompactCols`. This is the `teamActive` / `ecoRung`
|
|
154
|
-
* treatment rather than the `agentMode` one, and the distinction is the note
|
|
155
|
-
* on `agentMode` above: the mode must never be unreportable, whereas the fast
|
|
156
|
-
* tier has a fuller home in `/fast status` — which is the GUARANTEED reporting
|
|
157
|
-
* surface — and a chip on a 60-column terminal costs the context gauge more
|
|
158
|
-
* than it says.
|
|
159
|
-
*
|
|
160
|
-
* `inFlight` renders `fast*`, so a review that is taking a while is visible
|
|
161
|
-
* without a spinner competing with the run's own.
|
|
162
|
-
*/
|
|
163
53
|
fastActive?: {
|
|
164
54
|
inFlight: boolean;
|
|
165
55
|
};
|
|
166
|
-
/**
|
|
167
|
-
* Live context compaction (context-auto-compaction §6.2), or absent when it is
|
|
168
|
-
* off for this session — in which case an ordinary session's bar is unchanged.
|
|
169
|
-
*
|
|
170
|
-
* RIGHT CLUSTER, next to `fast` and `eco`, and it DEGRADES below
|
|
171
|
-
* `COMPACTION_LIMITS.statusCompactCols`. The `teamActive` / `ecoRung` /
|
|
172
|
-
* `fastActive` treatment rather than the `agentMode` one, for the reason the
|
|
173
|
-
* note on `agentMode` gives: the mode must never be unreportable, whereas
|
|
174
|
-
* compaction has a fuller home in `/compact status` — the GUARANTEED reporting
|
|
175
|
-
* surface (§6.5) — and a chip on a 60-column terminal costs the context gauge
|
|
176
|
-
* more than it says.
|
|
177
|
-
*
|
|
178
|
-
* `inFlight` renders `compacting`, so a summarization that is taking a while is
|
|
179
|
-
* visible on this row without a spinner competing with the activity line's.
|
|
180
|
-
*/
|
|
181
56
|
compactionActive?: {
|
|
182
57
|
inFlight: boolean;
|
|
183
58
|
};
|
|
184
|
-
/**
|
|
185
|
-
* Where the gauge turns amber and red (§6.2).
|
|
186
|
-
*
|
|
187
|
-
* ABSENT means today's hardcoded `{ warn: 60, high: 85 }`, so a session with
|
|
188
|
-
* compaction off renders a byte-identical bar. When present these are
|
|
189
|
-
* `warnThreshold * 100` and `threshold * 100`, which is what makes the colour
|
|
190
|
-
* the user sees agree with the number the trigger fires on.
|
|
191
|
-
*/
|
|
192
59
|
gaugeMarks?: {
|
|
193
60
|
warn: number;
|
|
194
61
|
high: number;
|
|
195
62
|
};
|
|
196
63
|
}
|
|
197
64
|
export declare function StatusBar(props: StatusBarProps): React.ReactElement;
|
|
198
|
-
export {};
|