gaunt-sloth 2.0.0-beta.11 → 2.0.0-beta.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.
Files changed (76) hide show
  1. package/cli.js +49 -0
  2. package/dist/commands/adkEvalRunner.d.ts +7 -6
  3. package/dist/commands/adkEvalRunner.js +3 -3
  4. package/dist/commands/adkEvalRunner.js.map +1 -1
  5. package/dist/commands/agUiEvalRunner.d.ts +4 -4
  6. package/dist/commands/agUiEvalRunner.js +8 -7
  7. package/dist/commands/agUiEvalRunner.js.map +1 -1
  8. package/dist/commands/askCommand.js +9 -1
  9. package/dist/commands/askCommand.js.map +1 -1
  10. package/dist/commands/batchCommand.d.ts +2 -2
  11. package/dist/commands/batchCommand.js +2 -2
  12. package/dist/commands/configCommand.d.ts +1 -1
  13. package/dist/commands/configCommand.js +1 -1
  14. package/dist/commands/configSetup.d.ts +1 -1
  15. package/dist/commands/evalCommand.d.ts +1 -1
  16. package/dist/commands/evalCommand.js +8 -3
  17. package/dist/commands/evalCommand.js.map +1 -1
  18. package/dist/commands/execCommand.d.ts +1 -1
  19. package/dist/commands/execCommand.js +9 -2
  20. package/dist/commands/execCommand.js.map +1 -1
  21. package/dist/commands/firstRunDialog.d.ts +3 -3
  22. package/dist/commands/firstRunDialog.js +2 -2
  23. package/dist/commands/historyCommand.d.ts +1 -1
  24. package/dist/commands/historyCommand.js +16 -4
  25. package/dist/commands/historyCommand.js.map +1 -1
  26. package/dist/commands/prDiscovery.d.ts +1 -1
  27. package/dist/tui/components/App.js +249 -24
  28. package/dist/tui/components/App.js.map +1 -1
  29. package/dist/tui/components/DebugPanel.d.ts +6 -3
  30. package/dist/tui/components/DebugPanel.js +15 -3
  31. package/dist/tui/components/DebugPanel.js.map +1 -1
  32. package/dist/tui/components/FetchProgress.d.ts +1 -1
  33. package/dist/tui/components/LaunchBanner.d.ts +1 -1
  34. package/dist/tui/components/LaunchBanner.js +1 -1
  35. package/dist/tui/components/LiveTurn.d.ts +6 -5
  36. package/dist/tui/components/LiveTurn.js +15 -14
  37. package/dist/tui/components/LiveTurn.js.map +1 -1
  38. package/dist/tui/components/PromptInput.d.ts +2 -2
  39. package/dist/tui/components/PromptInput.js +11 -6
  40. package/dist/tui/components/PromptInput.js.map +1 -1
  41. package/dist/tui/components/ResumePicker.d.ts +69 -0
  42. package/dist/tui/components/ResumePicker.js +93 -0
  43. package/dist/tui/components/ResumePicker.js.map +1 -0
  44. package/dist/tui/components/SelectList.d.ts +1 -1
  45. package/dist/tui/components/SelectList.js +1 -1
  46. package/dist/tui/components/SlashCommandMenu.d.ts +1 -1
  47. package/dist/tui/components/SlashCommandMenu.js +1 -1
  48. package/dist/tui/components/StatusBar.d.ts +27 -1
  49. package/dist/tui/components/StatusBar.js +13 -2
  50. package/dist/tui/components/StatusBar.js.map +1 -1
  51. package/dist/tui/debugRender.d.ts +26 -3
  52. package/dist/tui/debugRender.js +220 -2
  53. package/dist/tui/debugRender.js.map +1 -1
  54. package/dist/tui/fixtureAgent.d.ts +2 -2
  55. package/dist/tui/fixtureAgent.js +2 -2
  56. package/dist/tui/keyGuards.d.ts +1 -1
  57. package/dist/tui/keyGuards.js +1 -1
  58. package/dist/tui/ruleWidth.d.ts +1 -1
  59. package/dist/tui/ruleWidth.js +1 -1
  60. package/dist/tui/selectCancelled.d.ts +1 -1
  61. package/dist/tui/selectCancelled.js +1 -1
  62. package/dist/tui/transcriptWindow.js +7 -1
  63. package/dist/tui/transcriptWindow.js.map +1 -1
  64. package/dist/tui/tuiSessionModule.js +17 -1
  65. package/dist/tui/tuiSessionModule.js.map +1 -1
  66. package/dist/tui/types.d.ts +45 -7
  67. package/dist/tui/useMouse.d.ts +1 -1
  68. package/dist/tui/useMouse.js +1 -1
  69. package/dist/tui/useSlothAnimation.d.ts +1 -1
  70. package/dist/tui/viewModel.d.ts +64 -12
  71. package/dist/tui/viewModel.js +38 -11
  72. package/dist/tui/viewModel.js.map +1 -1
  73. package/dist/utils/configErrorGuard.d.ts +11 -3
  74. package/dist/utils/configErrorGuard.js +11 -3
  75. package/dist/utils/configErrorGuard.js.map +1 -1
  76. package/package.json +6 -6
@@ -37,7 +37,7 @@ export function defaultModelIndex(models) {
37
37
  }
38
38
  /**
39
39
  * Builds the `.gsloth.config.json` body for a chosen provider + model. Delegates to the shared
40
- * {@link buildInitConfigContent} so the interactive first-run path stamps the same `$schema`
40
+ * {@link @gaunt-sloth/core!providers/modelDiscovery.buildInitConfigContent | buildInitConfigContent} so the interactive first-run path stamps the same `$schema`
41
41
  * pointer (GS2-1) as the per-provider template writers. Previously this local builder omitted
42
42
  * `$schema`, so a config created through the first-run dialog got no editor autocomplete/validation.
43
43
  * First-run always has an explicit model chosen, so it is written into the config (unlike a bare
@@ -160,7 +160,7 @@ function makeDefaultSelect(ask) {
160
160
  /**
161
161
  * CFG-21 — the default {@link FirstRunDialogDeps.withProgress}: an Ink spinner while `run` is in
162
162
  * flight when the environment can drive interactive Ink (the same activation policy as
163
- * {@link makeDefaultSelect}), otherwise a plain printed line via {@link displayInfo} on the
163
+ * `makeDefaultSelect`), otherwise a plain printed line via {@link @gaunt-sloth/core!utils/consoleUtils.displayInfo | displayInfo} on the
164
164
  * readline / non-TTY path. Either way the wait is visible, never silent. The Ink module is
165
165
  * imported lazily so a readline-only run never loads React/Ink.
166
166
  */
@@ -20,7 +20,7 @@ export declare const NO_HISTORY_MESSAGE: string;
20
20
  * The first three are READ-ONLY and fail-soft: they open the store with `create: false`, so a
21
21
  * missing DB (nothing recorded yet, or history turned off) simply reports "no history yet" instead
22
22
  * of materialising an empty file.
23
- * (Opening still migrates a pre-GS2-19 DB in place — see {@link HistoryStore} migrate.) The DB
23
+ * (Opening still migrates a pre-GS2-19 DB in place — see {@link @gaunt-sloth/core!history/historyStore.HistoryStore | HistoryStore} migrate.) The DB
24
24
  * defaults to the global `~/.gsloth/history.db`; `--db <path>` overrides it. Local only — nothing
25
25
  * here touches the network.
26
26
  *
@@ -30,7 +30,7 @@ import { sessionConfigFor } from '#src/modules/sessionConfigs.js';
30
30
  * The first three are READ-ONLY and fail-soft: they open the store with `create: false`, so a
31
31
  * missing DB (nothing recorded yet, or history turned off) simply reports "no history yet" instead
32
32
  * of materialising an empty file.
33
- * (Opening still migrates a pre-GS2-19 DB in place — see {@link HistoryStore} migrate.) The DB
33
+ * (Opening still migrates a pre-GS2-19 DB in place — see {@link @gaunt-sloth/core!history/historyStore.HistoryStore | HistoryStore} migrate.) The DB
34
34
  * defaults to the global `~/.gsloth/history.db`; `--db <path>` overrides it. Local only — nothing
35
35
  * here touches the network.
36
36
  *
@@ -102,8 +102,13 @@ export function historyCommand(program, commandLineConfigOverrides = {}) {
102
102
  return;
103
103
  try {
104
104
  const stats = maintenance.stats(dbPath);
105
- if (stats.checkpointCount > 0)
105
+ // GS2-111 — checkpoints are not the whole store. A dropped `put` leaves a thread holding
106
+ // pending writes and no checkpoint: real bytes on disk that only `gth history prune` takes
107
+ // back. A guard on the checkpoint count alone made the one screen that reports the store's
108
+ // size silent about them (DL-1), so this is the pair GS2-108 settled on for `gth insights`.
109
+ if (stats.checkpointCount > 0 || stats.writeOnlyThreadCount > 0) {
106
110
  display(formatStoreSizeLine(stats));
111
+ }
107
112
  }
108
113
  finally {
109
114
  maintenance.close();
@@ -190,11 +195,17 @@ export function historyCommand(program, commandLineConfigOverrides = {}) {
190
195
  // is how a person finds out how much of the store was never reachable in the first place.
191
196
  const unaddressable = maintenance.unaddressable();
192
197
  const unaddressableBytes = maintenance.bytesOf(unaddressable);
198
+ // GS2-108 — and so does the write-only set: threads whose pending writes outlived the
199
+ // checkpoint they belonged to. This is the ONLY command that reaches them, because they
200
+ // carry no checkpoint to read an age from and the automatic pass reclaims nothing it
201
+ // cannot date. The reasoning is at `findWriteOnlyThreads`.
202
+ const writeOnly = maintenance.writeOnly();
203
+ const writeOnlyBytes = maintenance.bytesOf(writeOnly);
193
204
  displayInfo('History prune:');
194
- for (const line of formatPrunePlan(candidates, unaddressable.length, unaddressableBytes)) {
205
+ for (const line of formatPrunePlan(candidates, unaddressable.length, unaddressableBytes, writeOnly.length, writeOnlyBytes)) {
195
206
  display(line);
196
207
  }
197
- if (candidates.length === 0 && unaddressable.length === 0)
208
+ if (candidates.length === 0 && unaddressable.length === 0 && writeOnly.length === 0)
198
209
  return;
199
210
  if (!options.yes) {
200
211
  displayWarning('Nothing was removed. Re-run with `--yes` to remove it.');
@@ -204,6 +215,7 @@ export function historyCommand(program, commandLineConfigOverrides = {}) {
204
215
  const removed = maintenance.remove([
205
216
  ...candidates.map((c) => c.threadId),
206
217
  ...unaddressable,
218
+ ...writeOnly,
207
219
  ]);
208
220
  const vacuumed = maintenance.vacuum();
209
221
  const after = fileBytes(dbPath);
@@ -1 +1 @@
1
- {"version":3,"file":"historyCommand.js","sourceRoot":"","sources":["../../src/commands/historyCommand.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"historyCommand.js","sourceRoot":"","sources":["../../src/commands/historyCommand.ts"],"names":[],"mappings":"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"}
@@ -32,7 +32,7 @@ export interface PrDiscoveryConfig {
32
32
  * `set_requirements` is always retained regardless, since it is how the discovery agent
33
33
  * records the requirements it found. When omitted, all resolved tools remain available; an
34
34
  * empty array keeps only `set_requirements`. The discovery agent never inherits the
35
- * top-level {@link GthConfig.allowedTools}; this property is its only allow-list.
35
+ * top-level `GthConfig.allowedTools`; this property is its only allow-list.
36
36
  */
37
37
  allowedTools?: string[];
38
38
  }
@@ -5,6 +5,9 @@ import { foldEvents, foldSubagentEvents, initialSubagentTree, initialTurnViewMod
5
5
  import { buildRejectionMessage } from '@gaunt-sloth/core/core/shell/rejection.js';
6
6
  import { ApprovalStopError } from '@gaunt-sloth/core/core/shell/approvalStop.js';
7
7
  import { shouldAnnounceTermination } from '@gaunt-sloth/core/core/terminationNotice.js';
8
+ import { runEndReport } from '@gaunt-sloth/core/core/runRecap.js';
9
+ import { providerErrorNotice } from '@gaunt-sloth/core/core/providerErrorNotice.js';
10
+ import { readWaitNarration } from '@gaunt-sloth/core/core/waitNarration.js';
8
11
  import { attackBannerCopy, grantsRunAnyway, } from '@gaunt-sloth/core/core/shell/escalationSeverity.js';
9
12
  import { TranscriptViewport } from '#src/tui/components/TranscriptViewport.js';
10
13
  import { ApprovalPrompt } from '#src/tui/components/ApprovalPrompt.js';
@@ -22,15 +25,23 @@ import { ClearBanner } from '#src/tui/components/ClearBanner.js';
22
25
  import { LaunchBanner } from '#src/tui/components/LaunchBanner.js';
23
26
  import { MouseProvider } from '#src/tui/useMouse.js';
24
27
  import { DebugPanel, debugPanelLines, debugPanelRows, DEBUG_TABS, } from '#src/tui/components/DebugPanel.js';
28
+ import { renderApprovalDetails } from '#src/tui/debugRender.js';
25
29
  import { approvalPostureChoices, approvalsRungNotice, approvalsRefusalsNotice, approvalsStatusNotice, approvalsTrustNotice, approvalsUndenyNotice, COMPACTING_LINE, compactionFailedNotice, autocompactNotice, autocompactUnavailableNotice, compactionNotice, compactionUnavailableNotice, createCommandRegistry, dispatchSlashCommand, parseSlashCommand, toolsToggleNotice, } from '@gaunt-sloth/agent/modules/slashCommands.js';
26
- import { resumedConversationNotice, resumeFailedNotice, resumePickerNotice, resumeRefusalNotice, resumeSameConversationNotice, resumeUnavailableNotice, } from '@gaunt-sloth/agent/modules/sessionResume.js';
30
+ import { resumableConversationsNotice, resumedConversationNotice, resumeFailedNotice, resumeRefusalNotice, resumeSameConversationNotice, resumeUnavailableNotice, } from '@gaunt-sloth/agent/modules/sessionResume.js';
27
31
  import { ApprovalsPicker } from '#src/tui/components/ApprovalsPicker.js';
32
+ import { ResumePicker, resumeCancelledNotice } from '#src/tui/components/ResumePicker.js';
28
33
  import { TerminalSizeProvider, useTerminalSize } from '#src/tui/useTerminalSize.js';
29
34
  import { findMatches, scrollOffsetForLine, stepMatch } from '#src/tui/debugSearch.js';
30
35
  import { useTranscriptScroll } from '#src/tui/useTranscriptScroll.js';
31
36
  import { isComposingKeystroke, WHEEL_ROWS_PER_NOTCH } from '#src/tui/transcriptScroll.js';
32
37
  import { TUI_HINT_SUFFIX, TUI_KEY_BINDINGS } from '#src/tui/keyBindings.js';
33
38
  import { isTypedText, typedText } from '#src/tui/keyGuards.js';
39
+ /**
40
+ * The empty line list a debug tab that is not on screen hands the panel. A module-level constant so
41
+ * its identity is stable across renders: a fresh `[]` each time would make the memo that clamps the
42
+ * scroll offset recompute on every render of every other tab.
43
+ */
44
+ const NO_DEBUG_LINES = [];
34
45
  /** Rows of clipping viewport in the docked debug panel (default / restored size). */
35
46
  const DEBUG_VIEWPORT_HEIGHT = 8;
36
47
  /** Rows of chrome around the debug viewport we leave for when it is maximised (panel
@@ -128,6 +139,15 @@ export function App(props) {
128
139
  const [transcript, setTranscript] = useState(seeded);
129
140
  const [live, setLive] = useState(null);
130
141
  const [running, setRunning] = useState(false);
142
+ /**
143
+ * [[EXT-92]] scope (a) — what the run is waiting on, when that is not the model answering.
144
+ *
145
+ * Held as the whole rendered sentence rather than an activity code, because the words are
146
+ * `core/waitNarration.ts`'s to choose: it is the module that reaches every surface, and a second
147
+ * spelling of the same wait on this one is the drift the exported prefix exists to prevent. The
148
+ * status bar renders it in place of its own default label, so this costs no row.
149
+ */
150
+ const [waitActivity, setWaitActivity] = useState(undefined);
131
151
  const [turnCount, setTurnCount] = useState(props.resumed?.turns.length ?? 0);
132
152
  // Subagent tree, folded from `task` tool calls on the live event stream. No backend dispatches
133
153
  // subagents in this release, so nothing fills it today; kept for GS2-25's lean primitive.
@@ -169,6 +189,11 @@ export function App(props) {
169
189
  // chrome: unlike the status notice it is never committed to the transcript, and it owns the
170
190
  // keyboard while mounted (the prompt is suspended below, as it is for a pending approval).
171
191
  const [approvalsPicker, setApprovalsPicker] = useState(null);
192
+ // GS2-112 — the open bare-`/resume` picker's candidates, or null when none is showing. Transient
193
+ // chrome on the same terms as the approvals picker above: never committed to the transcript, and
194
+ // it owns the keyboard while mounted. The list is the snapshot taken when the picker opened; a
195
+ // landed resume replaces the screen, so the picker is closed before the choice is applied.
196
+ const [resumePicker, setResumePicker] = useState(null);
172
197
  // Whether to show the post-`/clear` "history cleared" banner. Hidden again the moment the next
173
198
  // user turn starts so it doesn't linger above a fresh conversation.
174
199
  const [clearedBanner, setClearedBanner] = useState(false);
@@ -221,6 +246,14 @@ export function App(props) {
221
246
  // GS2-20 — starts past the seeded items so a later push never reuses a seeded key.
222
247
  const idRef = useRef(seeded.length);
223
248
  const runningRef = useRef(false);
249
+ /**
250
+ * [[EXT-92]] scope (e) — whether the turn now ending was ended by a throw.
251
+ *
252
+ * A ref rather than state because the only reader is the `finally` of the same async function
253
+ * the catch runs in: a `setState` would not be visible there, and the fact has to be true at the
254
+ * instant the turn is committed, not on the next render.
255
+ */
256
+ const turnErroredRef = useRef(false);
224
257
  /**
225
258
  * GS2-23 — whether a `/compact` is awaiting its summary. Read where `runningRef` is read at
226
259
  * submit, so a plain message cannot start a turn on a thread that is about to be rewritten, and
@@ -249,6 +282,22 @@ export function App(props) {
249
282
  */
250
283
  const conversationIdRef = useRef(props.conversationId);
251
284
  const turnCountRef = useRef(props.resumed?.turns.length ?? 0);
285
+ /**
286
+ * [[EXT-178]] — which conversation the outstanding recap request still belongs to.
287
+ *
288
+ * The recap is a model call launched detached at the end of a turn, so up to
289
+ * `RUN_RECAP_TIMEOUT_MS` can pass between asking and answering, and the session does not stand
290
+ * still for it: `/clear` empties the transcript the recap is describing, and a new turn can
291
+ * start and finish inside the window. Appending then puts a summary of a wiped conversation onto
292
+ * a blank screen, or files the previous turn's recap under this one.
293
+ *
294
+ * So the request carries the epoch it was made in and drops itself if the epoch has moved. It is
295
+ * bumped by exactly the three events that make a pending recap wrong: a new turn starting,
296
+ * `/clear`, and this component unmounting. It is deliberately NOT `turnCountRef`, which counts
297
+ * turns for the status bar, is incremented after the recap is launched, and is reset to 0 by
298
+ * `/clear` — a counter that goes backwards cannot be compared for staleness.
299
+ */
300
+ const recapEpochRef = useRef(0);
252
301
  // Per-turn args buffers for the subagent fold (mirrors foldSubagentTree's internal map).
253
302
  const subagentBuffersRef = useRef(new Map());
254
303
  const debugFocusedRef = useRef(false);
@@ -260,10 +309,11 @@ export function App(props) {
260
309
  // inside <PromptInput>, where it lives.
261
310
  const promptHandleRef = useRef(null);
262
311
  // TUI-C51 — the one thing about the prompt that has to outlive it: the message a command was
263
- // dispatched beside. The prompt is unmounted in four states below, and one of them (`/approvals`
264
- // opening its picker) is entered by a command dispatched FROM the prompt — so the draft is put
265
- // here, where nothing unmounts, and the prompt takes it back when it returns. It stays a slot
266
- // rather than state: nothing here renders it, and the prompt empties it as soon as it has it.
312
+ // dispatched beside. The prompt is unmounted in five states below, and two of them (`/approvals`
313
+ // and a bare `/resume` opening their pickers) are entered by a command dispatched FROM the
314
+ // prompt — so the draft is put here, where nothing unmounts, and the prompt takes it back when
315
+ // it returns. It stays a slot rather than state: nothing here renders it, and the prompt empties
316
+ // it as soon as it has it.
267
317
  const promptDraftCarryRef = useRef(null);
268
318
  // TUI-C79 — set the moment a teardown starts, so a second `quit()` can tell "leaving" from
269
319
  // "already leaving" and skip straight to the unmount. See `quit()`.
@@ -283,6 +333,18 @@ export function App(props) {
283
333
  const debugViewport = debugViewportHeight(debugMaximized, terminalRows);
284
334
  // PageUp/PageDown step tracks the live viewport so maximise pages by (almost) a full screen.
285
335
  const debugPageStep = Math.max(1, debugViewport - 1);
336
+ // [[TUI-C27]] — the Auto-mode tab's lines: the approvals gate's own record of every gated tool
337
+ // call, plus the rater config in force (already held here, since `/approvals` moves it).
338
+ //
339
+ // **Read fresh on every render while that tab is on screen, deliberately, and memoised on
340
+ // nothing.** The decision this tab exists for emits no event: a call the rater approves on its
341
+ // first rating relays nothing to any surface — the tool simply runs — so anything keyed on the
342
+ // approval, negotiation or turn signals the App already has would look live and miss exactly it.
343
+ // A pull costs one render of a capped (50-record) buffer, and only while a user is looking at
344
+ // the tab; every other tab keeps the stable empty array and pays nothing.
345
+ const debugAuto = debugVisible && debugTab === 'auto'
346
+ ? renderApprovalDetails(props.readApprovalCaptures?.() ?? [], approvals).split('\n')
347
+ : NO_DEBUG_LINES;
286
348
  // The active section's line count drives the real maximum scroll offset, so neither the page
287
349
  // step nor the arrow step can push the offset past the end (the over-scroll bug that left
288
350
  // PgUp/↑ burning through phantom offset before anything moved — TUI-C11). Single-sourced with
@@ -294,8 +356,9 @@ export function App(props) {
294
356
  toolsLines: debugTools,
295
357
  mcpLines: debugMcp,
296
358
  responseLines: debugResponse,
359
+ autoLines: debugAuto,
297
360
  activeTab: debugTab,
298
- }), [subagents, debugHistory, debugSystem, debugTools, debugMcp, debugResponse, debugTab]);
361
+ }), [subagents, debugHistory, debugSystem, debugTools, debugMcp, debugResponse, debugAuto, debugTab]);
299
362
  const debugLineCount = debugLines.length;
300
363
  const debugMaxOffset = Math.max(0, debugLineCount - debugViewport);
301
364
  // Match line-indices for the current query over the active tab's lines — one search, every tab
@@ -394,6 +457,8 @@ export function App(props) {
394
457
  // A new exchange supersedes the post-/clear banner; drop it so it doesn't sit above
395
458
  // the fresh conversation.
396
459
  setClearedBanner(false);
460
+ // [[EXT-178]] — and it supersedes the previous turn's recap, which may still be in flight.
461
+ recapEpochRef.current += 1;
397
462
  push({ kind: 'user', text: userInput });
398
463
  // [[TUI-C69]] §5.4 — a new user turn is a person being reached, which ENDS any negotiation
399
464
  // still standing (the runner clears its own transcript on the same event). Rounds from the
@@ -403,11 +468,21 @@ export function App(props) {
403
468
  abortRef.current = ac;
404
469
  runningRef.current = true;
405
470
  setRunning(true);
471
+ // [[EXT-92]] — both per-turn facts start clean. `turnErroredRef` (scope e) is set by the
472
+ // catch and read by the `finally`; `waitActivity` (scope a) is a label the status bar may
473
+ // still be holding from the previous turn's last wait.
474
+ turnErroredRef.current = false;
475
+ setWaitActivity(undefined);
406
476
  setLiveTurn(initialTurnViewModel());
407
477
  // Fresh args-buffer map per turn so partial `task` JSON from a prior turn never bleeds in.
408
478
  subagentBuffersRef.current = new Map();
409
479
  try {
410
480
  for await (const event of agent.runTurn(userInput, ac.signal)) {
481
+ // [[EXT-92]] scope (a) — an event arriving IS the wait ending. Clearing here rather than
482
+ // waiting for a paired "done" narration is what keeps the core signal one-way and the
483
+ // plain surface to exactly one line per wait: there is no end message to emit, so there
484
+ // is none to print. The status bar falls back to its own default label.
485
+ setWaitActivity(undefined);
411
486
  // [[TUI-C99]] — folded from the REF, not from a local: an approval answered mid-turn
412
487
  // writes the outcome onto its tool call from a keystroke, and a local carried across the
413
488
  // loop would overwrite it on the very next event the resumed run produces.
@@ -427,16 +502,43 @@ export function App(props) {
427
502
  push({ kind: 'stop', parts: err.parts });
428
503
  }
429
504
  else {
505
+ // [[EXT-92]] scope (b) — a provider error is rendered as prose here, and the raw payload
506
+ // rides along in a field this item's renderer never prints.
507
+ //
508
+ // The whole defect was on this line. `err.message` for an OpenRouter refusal is
509
+ // `Provider returned error | metadata: {…}` — upstream flattens its own structured
510
+ // metadata into the message — so the user read a JSON blob while the provider's own
511
+ // sentence, its remedy hint, and the fact that it was a SHARED pool rather than their
512
+ // quota all sat unread inside it. Nothing had been lost: the same fields are still
513
+ // objects on `err`, which is why this needed a renderer rather than a parser.
514
+ // `providerErrorNotice` returns null for the ordinary runtime errors it has nothing to
515
+ // add to, and those keep exactly the rendering they had.
516
+ const notice = providerErrorNotice(err);
430
517
  push({
431
518
  kind: 'system',
432
519
  level: 'error',
433
- text: err instanceof Error ? err.message : String(err),
520
+ text: notice?.text ?? (err instanceof Error ? err.message : String(err)),
521
+ ...(notice ? { raw: notice.raw } : {}),
434
522
  });
435
523
  }
524
+ // [[EXT-92]] scope (e) — remember that this turn was ended by the failure above, so the
525
+ // `finally` can commit it as a turn that STOPPED rather than one that finished. An
526
+ // approvals stop is deliberately excluded: it already commits its own `stop` item saying
527
+ // so in full, and marking the turn as well would state the same ending twice.
528
+ if (!(err instanceof ApprovalStopError))
529
+ turnErroredRef.current = true;
436
530
  }
437
531
  finally {
532
+ // [[EXT-92]] scope (a) — the turn is over, so nothing is being waited on. In the `finally`
533
+ // because the endings that most need it are the ones that reach neither the loop's normal
534
+ // exit nor the catch: a turn cancelled mid-rating would otherwise leave the bar naming a
535
+ // wait that no longer exists.
536
+ setWaitActivity(undefined);
438
537
  const vm = liveVmRef.current ?? initialTurnViewModel();
439
- push({ kind: 'assistant', turn: vm });
538
+ push({
539
+ kind: 'assistant',
540
+ turn: turnErroredRef.current ? { ...vm, endedInError: true } : vm,
541
+ });
440
542
  // [[EXT-159]] — and, immediately under the answer, why the turn ended when that is not
441
543
  // simply "the model finished".
442
544
  //
@@ -454,6 +556,50 @@ export function App(props) {
454
556
  const reason = agent.getTerminationReason?.() ?? null;
455
557
  if (reason && shouldAnnounceTermination(reason))
456
558
  push({ kind: 'termination', reason });
559
+ // [[EXT-158]] — and the other silence: a turn that ended cleanly with its own checklist
560
+ // still carrying work. `shouldAnnounceTermination` declines `completed`, correctly — an
561
+ // ordinary answer needs no epitaph — which is exactly why this case had nothing at all.
562
+ //
563
+ // Committed as an ordinary `notice` item rather than a transcript kind of its own. The
564
+ // termination item earns its kind by carrying the REASON value so the transcript holds
565
+ // the classification rather than a rendered line; this fact has no such closed taxonomy
566
+ // to preserve, and a new kind would buy a second row-count case and a second renderer for
567
+ // a title and three lines the generic notice already draws.
568
+ //
569
+ // [[EXT-178]] — and its successor when the user has switched the recap on. The two speak
570
+ // for the same population, so exactly one of them is drawn: `runEndReport` decides, with
571
+ // the recap already resolved, and a recap that never arrived leaves the notice standing.
572
+ //
573
+ // **Detached from the turn's teardown, and that is the whole reason it is down here.**
574
+ // A recap is a model call made after the answer is already on screen; awaiting it in this
575
+ // `finally` would keep the spinner running and the prompt away for as long as a provider
576
+ // takes to reply, which is a worse thing to do to a finished turn than a late paragraph.
577
+ // The transcript is append-only and this lands at the bottom, where the reader is. With
578
+ // the default `off` rung nothing is contacted and the notice lands as it always did.
579
+ const work = agent.getOutstandingWork?.() ?? null;
580
+ const ending = reason;
581
+ // Detached means the session can move on underneath it, so the request carries the epoch
582
+ // it was made in and says nothing if `recapEpochRef` has moved on — see that ref.
583
+ const epoch = recapEpochRef.current;
584
+ void (async () => {
585
+ try {
586
+ const recap = (await agent.requestRunRecap?.(ending)) ?? null;
587
+ if (recapEpochRef.current !== epoch)
588
+ return;
589
+ const report = runEndReport(recap, work, ending);
590
+ if (report.kind !== 'silent') {
591
+ push({
592
+ kind: 'notice',
593
+ title: report.notice.title,
594
+ lines: report.notice.lines,
595
+ tone: report.kind === 'recap' ? 'info' : 'warn',
596
+ });
597
+ }
598
+ }
599
+ catch {
600
+ /* fail-soft: explaining a turn must never be what breaks the session */
601
+ }
602
+ })();
457
603
  }
458
604
  catch {
459
605
  /* fail-soft: explaining a turn must never be what breaks the session */
@@ -715,7 +861,31 @@ export function App(props) {
715
861
  // replaces the screen: the transcript on it belonged to the conversation being left, and the
716
862
  // model is now continuing another one, so the banner and the restored turns take its place —
717
863
  // the same wipe `/clear` does, without the cleared banner, because nothing was discarded (the
718
- // conversation left keeps everything recorded under it). Bare, it lists what could be resumed.
864
+ // conversation left keeps everything recorded under it). Bare, this surface offers the picker
865
+ // below; the readline session prints the list.
866
+ //
867
+ // GS2-112 — **why the interactive picker is one branch here and not a new protocol field.**
868
+ //
869
+ // `/resume` returns `resume?: { id?: number }`, and the missing id is not an omission to be
870
+ // filled in later: the command is pure and cannot reach the store or the runner, so the no-id
871
+ // case has always meant *the surface fulfils this*, which is what every other surface already
872
+ // does with it. The Ink TUI can show a list and read arrow keys; the readline session can print
873
+ // one; a server surface has no user at a keyboard at all. Choosing is therefore the surface's
874
+ // answer to the same request, and nothing in the request needs to change for this surface to
875
+ // give a better one.
876
+ //
877
+ // The alternative was weighed and rejected rather than overlooked. A cross-package chooser — a
878
+ // new result field carrying candidates, or a `chooseConversation` callback threaded from the
879
+ // agent down into the component — would put a widget's contract in the module both surfaces
880
+ // read from, to serve one surface, and would still leave this branch deciding when to open it.
881
+ // It buys nothing: the candidates are already here (`props.listResumeCandidates`, wired in
882
+ // `tuiSessionModule`), and the id the user picks re-enters the with-id path below, which is the
883
+ // same code `--resume <id>` runs at boot. One branch, one new component, no new protocol.
884
+ //
885
+ // **The readline surface keeps the printed list deliberately.** It is not a fallback that has
886
+ // been left behind: with no Ink tree there is nothing to arrow through, and the printed ids
887
+ // remain the only way in on that surface — so `resumableConversationsNotice` stays its list
888
+ // builder, and no picker wording is allowed to leak into it (pinned by a spec).
719
889
  const applyResume = useCallback(async (id) => {
720
890
  const commit = (notice) => push({
721
891
  kind: 'notice',
@@ -724,11 +894,23 @@ export function App(props) {
724
894
  tone: notice.tone ?? 'info',
725
895
  });
726
896
  if (id === undefined) {
897
+ // A session with no store behind it cannot list anything, let alone offer it: this prop is
898
+ // wired only where history is on and a store opened, so its absence is the same "resume is
899
+ // unavailable here" the with-id path reports below.
727
900
  if (!props.listResumeCandidates) {
728
901
  commit(resumeUnavailableNotice());
729
902
  return;
730
903
  }
731
- commit(resumePickerNotice(props.listResumeCandidates()));
904
+ const candidates = props.listResumeCandidates();
905
+ // With nothing to offer, say so and open nothing. An empty <SelectList> renders a "no
906
+ // matches" line and its Enter is inert, so a picker here would be a modal the user can
907
+ // only escape from — strictly worse than the sentence, which also explains what makes a
908
+ // conversation resumable.
909
+ if (candidates.length === 0) {
910
+ commit(resumableConversationsNotice(candidates));
911
+ return;
912
+ }
913
+ setResumePicker(candidates);
732
914
  return;
733
915
  }
734
916
  if (!agent.resumeConversation) {
@@ -1049,6 +1231,10 @@ export function App(props) {
1049
1231
  conversationId: conversationIdRef.current,
1050
1232
  toolsExpanded: toolsExpandedRef.current,
1051
1233
  debugVisible: debugVisibleRef.current,
1234
+ // TUI-C96 — this surface has the slash-command menu (<PromptInput> renders it
1235
+ // unconditionally), so the unknown-command notice may explain a shortened name by
1236
+ // pointing at it. The readline surface says false and gets the other sentence.
1237
+ hasSlashMenu: true,
1052
1238
  // TUI-C37 — undefined (not false) when this surface has no mouse layer, so `/mouse`
1053
1239
  // says it is unavailable rather than silently reporting "off".
1054
1240
  mouseEnabled: props.mouseEnabled === undefined ? undefined : mouseEnabledRef.current,
@@ -1102,6 +1288,9 @@ export function App(props) {
1102
1288
  // reset it too — a cleared session starts back at "turns: 0".
1103
1289
  turnCountRef.current = 0;
1104
1290
  setTurnCount(0);
1291
+ // [[EXT-178]] — a recap still in flight describes the conversation just wiped, so drop
1292
+ // it rather than append a summary of nothing onto a cleared screen.
1293
+ recapEpochRef.current += 1;
1105
1294
  }
1106
1295
  if (result.toggleTools) {
1107
1296
  // Flip the fold mode and commit the notice via the shared helper (single-sourced with
@@ -1227,13 +1416,19 @@ export function App(props) {
1227
1416
  // bare `exit` keyword all take it too).
1228
1417
  //
1229
1418
  // **The modal states are answered first, and they exit.** While an attack banner, an approval
1230
- // prompt or the approvals picker owns the keyboard, a turn IS in flight, so rung 2 would read
1231
- // "stop the turn" where the banner's own controls line says `Ctrl+C exits gth` and the user is
1232
- // looking for the way out of an irreversible action. So it exits, as the screen promises — and
1233
- // it goes through `quit()`, which resolves both bridges fail-closed on the way out rather than
1234
- // leaving the halt unanswered.
1419
+ // prompt or one of the pickers (`/approvals`, bare `/resume`) owns the keyboard, the prompt is
1420
+ // unmounted, so rung 1 has no buffer to scrap; and where that modal state was reached during a
1421
+ // turn, rung 2 would read "stop the turn" while the banner's own controls line says `Ctrl+C
1422
+ // exits gth` and the user is looking for the way out of an irreversible action. So it exits, as
1423
+ // the screen promises — and it goes through `quit()`, which resolves both bridges fail-closed
1424
+ // on the way out rather than leaving the halt unanswered.
1425
+ //
1426
+ // GS2-112 — the resume picker is in this set for coherence rather than for a case it changes
1427
+ // today: `/resume` is idle-only and the prompt is unmounted while its picker is up, so no turn
1428
+ // can be started under it and the ladder would fall to rung 3 and exit anyway. Naming it here
1429
+ // is what keeps that answer from depending on which rung happens to catch it.
1235
1430
  if (key.ctrl && input === 'c') {
1236
- if (pendingAttack || pendingApproval || approvalsPicker) {
1431
+ if (pendingAttack || pendingApproval || approvalsPicker || resumePicker) {
1237
1432
  quit();
1238
1433
  return;
1239
1434
  }
@@ -1369,11 +1564,11 @@ export function App(props) {
1369
1564
  resolveApproval('reject');
1370
1565
  return;
1371
1566
  }
1372
- // CFG-39 — while the `/approvals` picker is open it OWNS the keyboard, exactly as a pending
1373
- // approval does. <SelectList> is a useInput subscriber too and Ink runs every subscriber, so
1374
- // without this the arrow keys would also scroll the transcript and Esc would both cancel the
1375
- // picker and jump to the newest output. Returning here leaves the picker the only claimant.
1376
- if (approvalsPicker)
1567
+ // CFG-39, GS2-112 — while a picker is open it OWNS the keyboard, exactly as a pending approval
1568
+ // does. <SelectList> is a useInput subscriber too and Ink runs every subscriber, so without
1569
+ // this the arrow keys would also scroll the transcript and Esc would both cancel the picker and
1570
+ // jump to the newest output. Returning here leaves the picker the only claimant.
1571
+ if (approvalsPicker || resumePicker)
1377
1572
  return;
1378
1573
  if (key.escape && runningRef.current) {
1379
1574
  abortRef.current?.abort();
@@ -1588,6 +1783,12 @@ export function App(props) {
1588
1783
  };
1589
1784
  // eslint-disable-next-line react-hooks/exhaustive-deps
1590
1785
  }, []);
1786
+ // [[EXT-178]] — the third thing that invalidates a recap still in flight: this component going
1787
+ // away. A quit unmounts while a provider may still be holding the request open, and the reply
1788
+ // would then land on a session the user has left.
1789
+ useEffect(() => () => {
1790
+ recapEpochRef.current += 1;
1791
+ }, []);
1591
1792
  // Route agent status updates (warnings/errors) into the transcript instead of stdout,
1592
1793
  // which would otherwise corrupt Ink's frame. INFO/DEBUG system lines are suppressed in the
1593
1794
  // TUI: the agent's per-turn chatter (`Requested tools`, `Loaded tools`, `Workdir`, `Model`,
@@ -1598,6 +1799,17 @@ export function App(props) {
1598
1799
  if (!props.subscribeStatus)
1599
1800
  return;
1600
1801
  return props.subscribeStatus((level, message) => {
1802
+ // [[EXT-92]] scope (a) — a wait narration is INFO, and INFO is exactly what this handler
1803
+ // drops, so it is picked out BEFORE the filter and routed to the status bar instead of the
1804
+ // transcript. That is the right destination on both counts: it is a transient fact about the
1805
+ // present moment, which the transcript is the wrong shape for, and the bar is already the
1806
+ // TUI's wait renderer. Recognised by the prefix `core/waitNarration.ts` exports for this,
1807
+ // rather than by a copy of the wording here.
1808
+ const narration = readWaitNarration(message);
1809
+ if (narration !== null) {
1810
+ setWaitActivity(narration);
1811
+ return;
1812
+ }
1601
1813
  if (level === 'INFO' || level === 'DEBUG')
1602
1814
  return;
1603
1815
  if (message.trim())
@@ -1679,10 +1891,19 @@ export function App(props) {
1679
1891
  : 0) -
1680
1892
  (activeChecklist ? checklistPanelRows(activeChecklist) : 0) -
1681
1893
  negotiationPanelRows(negotiationRounds, terminalColumns);
1682
- return (_jsx(TerminalSizeProvider, { size: terminalSize, children: _jsx(MouseProvider, { subscribe: props.subscribeMouse, enabled: mouseEnabled, children: _jsxs(Box, { flexDirection: "column", height: terminalRows, children: [_jsxs(TranscriptViewport, { items: transcript, budgetRows: terminalRows, columns: terminalColumns, toolsExpanded: toolsExpanded, scroll: transcriptScroll, regionRows: transcriptRegionRows, geometry: transcriptGeometry, children: [clearedBanner ? _jsx(ClearBanner, {}) : null, showIntro && props.showLaunchBanner ? (_jsx(LaunchBanner, { model: modelDisplayName, provider: props.modelProviderType })) : null, showIntro ? _jsx(Text, { dimColor: true, children: readyMessage.trim() }) : null, live && transcript.length > 0 ? _jsx(BlankRow, {}) : null, live ? (_jsx(LiveTurn, { turn: live, toolsExpanded: toolsExpanded, streaming: true, columns: terminalColumns })) : null, pendingApproval ? (_jsxs(_Fragment, { children: [live || transcript.length > 0 ? _jsx(BlankRow, {}) : null, _jsx(ApprovalRequestPanel, { pending: pendingApproval.pending, columns: terminalColumns })] })) : null] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [debugVisible ? (_jsx(DebugPanel, { subagents: subagents, historyLines: debugHistory, systemLines: debugSystem, toolsLines: debugTools, mcpLines: debugMcp, responseLines: debugResponse, activeTab: debugTab, scrollOffset: debugScroll, focused: debugFocused, viewportHeight: debugViewport, maximized: debugMaximized, searchQuery: debugSearchQuery, searchActive: debugSearchInput, matchCount: debugMatches.length, currentMatchIndex: debugSearchCurrent, currentMatchLine: currentMatchLine })) : null, activeChecklist ? _jsx(ChecklistPanel, { items: activeChecklist }) : null, _jsx(NegotiationPanel, { rounds: negotiationRounds }), pendingAttack ? _jsx(AttackBanner, { halt: pendingAttack.halt, typed: attackTyped }) : null, pendingApproval && !pendingAttack ? (_jsx(ApprovalPrompt, { pending: pendingApproval.pending })) : null, approvalsPicker && !pendingApproval && !pendingAttack ? (_jsx(ApprovalsPicker, { choices: approvalsPicker, onSelect: (rung) => {
1894
+ return (_jsx(TerminalSizeProvider, { size: terminalSize, children: _jsx(MouseProvider, { subscribe: props.subscribeMouse, enabled: mouseEnabled, children: _jsxs(Box, { flexDirection: "column", height: terminalRows, children: [_jsxs(TranscriptViewport, { items: transcript, budgetRows: terminalRows, columns: terminalColumns, toolsExpanded: toolsExpanded, scroll: transcriptScroll, regionRows: transcriptRegionRows, geometry: transcriptGeometry, children: [clearedBanner ? _jsx(ClearBanner, {}) : null, showIntro && props.showLaunchBanner ? (_jsx(LaunchBanner, { model: modelDisplayName, provider: props.modelProviderType })) : null, showIntro ? _jsx(Text, { dimColor: true, children: readyMessage.trim() }) : null, live && transcript.length > 0 ? _jsx(BlankRow, {}) : null, live ? (_jsx(LiveTurn, { turn: live, toolsExpanded: toolsExpanded, streaming: true, columns: terminalColumns })) : null, pendingApproval ? (_jsxs(_Fragment, { children: [live || transcript.length > 0 ? _jsx(BlankRow, {}) : null, _jsx(ApprovalRequestPanel, { pending: pendingApproval.pending, columns: terminalColumns })] })) : null] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [debugVisible ? (_jsx(DebugPanel, { subagents: subagents, historyLines: debugHistory, systemLines: debugSystem, toolsLines: debugTools, mcpLines: debugMcp, responseLines: debugResponse, autoLines: debugAuto, activeTab: debugTab, scrollOffset: debugScroll, focused: debugFocused, viewportHeight: debugViewport, maximized: debugMaximized, searchQuery: debugSearchQuery, searchActive: debugSearchInput, matchCount: debugMatches.length, currentMatchIndex: debugSearchCurrent, currentMatchLine: currentMatchLine })) : null, activeChecklist ? _jsx(ChecklistPanel, { items: activeChecklist }) : null, _jsx(NegotiationPanel, { rounds: negotiationRounds }), pendingAttack ? _jsx(AttackBanner, { halt: pendingAttack.halt, typed: attackTyped }) : null, pendingApproval && !pendingAttack ? (_jsx(ApprovalPrompt, { pending: pendingApproval.pending })) : null, approvalsPicker && !pendingApproval && !pendingAttack ? (_jsx(ApprovalsPicker, { choices: approvalsPicker, onSelect: (rung) => {
1683
1895
  setApprovalsPicker(null);
1684
1896
  applyApprovalRung(rung);
1685
- }, onCancel: () => setApprovalsPicker(null) })) : null, _jsx(BlankRow, {}), _jsx(Rule, {}), _jsx(NoticeBar, { advisories: props.advisories }), _jsx(McpFailureBar, { failures: props.mcpFailures }), _jsx(StatusBar, { running: running, mode: mode, modelDisplayName: modelDisplayName,
1897
+ }, onCancel: () => setApprovalsPicker(null) })) : null, resumePicker && !approvalsPicker && !pendingApproval && !pendingAttack ? (_jsx(ResumePicker, { candidates: resumePicker, onSelect: (id) => {
1898
+ // Close BEFORE applying: a landed resume replaces the transcript and re-keys its
1899
+ // ids, and this list is a snapshot of the conversations as they were before it.
1900
+ setResumePicker(null);
1901
+ void applyResume(id);
1902
+ }, onCancel: () => {
1903
+ setResumePicker(null);
1904
+ const notice = resumeCancelledNotice();
1905
+ push({ kind: 'notice', title: notice.title, lines: notice.lines, tone: 'info' });
1906
+ } })) : null, _jsx(BlankRow, {}), _jsx(Rule, {}), _jsx(NoticeBar, { advisories: props.advisories }), _jsx(McpFailureBar, { failures: props.mcpFailures }), _jsx(StatusBar, { running: running, activity: waitActivity, mode: mode, modelDisplayName: modelDisplayName,
1686
1907
  // CFG-38 — the provider beside the model, and the live width it has to fit in: the
1687
1908
  // bar drops the provider rather than overflowing a narrow terminal.
1688
1909
  modelProviderType: props.modelProviderType, columns: terminalColumns, turnCount: turnCount, debugHint: debugVisible && !debugFocused, approvals: approvals
@@ -1690,7 +1911,11 @@ export function App(props) {
1690
1911
  rung: approvals.rung,
1691
1912
  raterProfile: approvals.rater,
1692
1913
  }
1693
- : undefined }), !debugFocused && !pendingApproval && !pendingAttack && !approvalsPicker ? (_jsxs(_Fragment, { children: [_jsx(BlankRow, {}), _jsx(PromptInput, { onSubmit: handleSubmit, commands: registry, onMenuStateChange: (active) => {
1914
+ : undefined }), !debugFocused &&
1915
+ !pendingApproval &&
1916
+ !pendingAttack &&
1917
+ !approvalsPicker &&
1918
+ !resumePicker ? (_jsxs(_Fragment, { children: [_jsx(BlankRow, {}), _jsx(PromptInput, { onSubmit: handleSubmit, commands: registry, onMenuStateChange: (active) => {
1694
1919
  slashMenuActiveRef.current = active;
1695
1920
  }, handleRef: promptHandleRef, draftCarryRef: promptDraftCarryRef, promptBlockRows: promptBlockRows }), _jsx(BlankRow, {})] })) : null, _jsx(Text, { dimColor: true, wrap: "truncate-end", children: `${exitMessage.trim()}${TUI_HINT_SUFFIX}` }), _jsx(Rule, {})] })] }) }) }));
1696
1921
  }