gaunt-sloth 2.0.0-alpha.2 → 2.0.0-alpha.21

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 (127) hide show
  1. package/README.md +55 -5
  2. package/cli.js +43 -10
  3. package/dist/cli.js +33 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/adkEvalRunner.d.ts +66 -0
  6. package/dist/commands/adkEvalRunner.js +69 -0
  7. package/dist/commands/adkEvalRunner.js.map +1 -0
  8. package/dist/commands/agUiEvalRunner.d.ts +73 -0
  9. package/dist/commands/agUiEvalRunner.js +216 -0
  10. package/dist/commands/agUiEvalRunner.js.map +1 -0
  11. package/dist/commands/askCommand.d.ts +3 -2
  12. package/dist/commands/askCommand.js +26 -7
  13. package/dist/commands/askCommand.js.map +1 -1
  14. package/dist/commands/batchCommand.d.ts +78 -0
  15. package/dist/commands/batchCommand.js +245 -0
  16. package/dist/commands/batchCommand.js.map +1 -0
  17. package/dist/commands/cliOptionParsers.d.ts +12 -0
  18. package/dist/commands/cliOptionParsers.js +18 -0
  19. package/dist/commands/cliOptionParsers.js.map +1 -0
  20. package/dist/commands/commandIntrospection.d.ts +6 -6
  21. package/dist/commands/commandIntrospection.js +12 -12
  22. package/dist/commands/commandIntrospection.js.map +1 -1
  23. package/dist/commands/commandUtils.d.ts +16 -16
  24. package/dist/commands/commandUtils.js +20 -20
  25. package/dist/commands/commandUtils.js.map +1 -1
  26. package/dist/commands/configCommand.d.ts +24 -0
  27. package/dist/commands/configCommand.js +117 -0
  28. package/dist/commands/configCommand.js.map +1 -0
  29. package/dist/commands/configSetup.d.ts +1 -1
  30. package/dist/commands/configSetup.js +17 -2
  31. package/dist/commands/configSetup.js.map +1 -1
  32. package/dist/commands/evalCommand.d.ts +41 -0
  33. package/dist/commands/evalCommand.js +483 -0
  34. package/dist/commands/evalCommand.js.map +1 -0
  35. package/dist/commands/execCommand.js +4 -1
  36. package/dist/commands/execCommand.js.map +1 -1
  37. package/dist/commands/firstRunDialog.d.ts +39 -5
  38. package/dist/commands/firstRunDialog.js +72 -10
  39. package/dist/commands/firstRunDialog.js.map +1 -1
  40. package/dist/commands/getCommand.js +7 -7
  41. package/dist/commands/getCommand.js.map +1 -1
  42. package/dist/commands/historyCommand.d.ts +17 -0
  43. package/dist/commands/historyCommand.js +102 -0
  44. package/dist/commands/historyCommand.js.map +1 -0
  45. package/dist/commands/initCommand.d.ts +3 -0
  46. package/dist/commands/initCommand.js +9 -4
  47. package/dist/commands/initCommand.js.map +1 -1
  48. package/dist/commands/insightsCommand.d.ts +8 -0
  49. package/dist/commands/insightsCommand.js +32 -0
  50. package/dist/commands/insightsCommand.js.map +1 -0
  51. package/dist/commands/modelsCommand.d.ts +25 -0
  52. package/dist/commands/modelsCommand.js +96 -0
  53. package/dist/commands/modelsCommand.js.map +1 -0
  54. package/dist/commands/prCommand.js +14 -15
  55. package/dist/commands/prCommand.js.map +1 -1
  56. package/dist/commands/prDiscovery.d.ts +2 -2
  57. package/dist/commands/prDiscovery.js +27 -29
  58. package/dist/commands/prDiscovery.js.map +1 -1
  59. package/dist/commands/reviewCommand.js +15 -10
  60. package/dist/commands/reviewCommand.js.map +1 -1
  61. package/dist/commands/workflowCommand.d.ts +19 -0
  62. package/dist/commands/workflowCommand.js +77 -0
  63. package/dist/commands/workflowCommand.js.map +1 -0
  64. package/dist/helpers/jira/jiraLogWork.js.map +1 -1
  65. package/dist/modules/startSession.js +9 -7
  66. package/dist/modules/startSession.js.map +1 -1
  67. package/dist/tools/gthJiraLogWorkTool.js +3 -3
  68. package/dist/tools/gthJiraLogWorkTool.js.map +1 -1
  69. package/dist/tui/components/App.js +321 -21
  70. package/dist/tui/components/App.js.map +1 -1
  71. package/dist/tui/components/ApprovalPrompt.d.ts +18 -0
  72. package/dist/tui/components/ApprovalPrompt.js +26 -0
  73. package/dist/tui/components/ApprovalPrompt.js.map +1 -0
  74. package/dist/tui/components/DebugPanel.d.ts +29 -9
  75. package/dist/tui/components/DebugPanel.js +46 -23
  76. package/dist/tui/components/DebugPanel.js.map +1 -1
  77. package/dist/tui/components/FetchProgress.d.ts +36 -0
  78. package/dist/tui/components/FetchProgress.js +39 -0
  79. package/dist/tui/components/FetchProgress.js.map +1 -0
  80. package/dist/tui/components/LiveTurn.d.ts +26 -4
  81. package/dist/tui/components/LiveTurn.js +104 -18
  82. package/dist/tui/components/LiveTurn.js.map +1 -1
  83. package/dist/tui/components/NoticeBar.d.ts +32 -0
  84. package/dist/tui/components/NoticeBar.js +39 -0
  85. package/dist/tui/components/NoticeBar.js.map +1 -0
  86. package/dist/tui/components/PromptInput.d.ts +26 -1
  87. package/dist/tui/components/PromptInput.js +93 -7
  88. package/dist/tui/components/PromptInput.js.map +1 -1
  89. package/dist/tui/components/Rule.js.map +1 -1
  90. package/dist/tui/components/SelectList.d.ts +98 -9
  91. package/dist/tui/components/SelectList.js +209 -26
  92. package/dist/tui/components/SelectList.js.map +1 -1
  93. package/dist/tui/components/SlashCommandMenu.d.ts +20 -0
  94. package/dist/tui/components/SlashCommandMenu.js +28 -0
  95. package/dist/tui/components/SlashCommandMenu.js.map +1 -0
  96. package/dist/tui/components/StatusBar.d.ts +7 -1
  97. package/dist/tui/components/StatusBar.js +7 -3
  98. package/dist/tui/components/StatusBar.js.map +1 -1
  99. package/dist/tui/components/Transcript.js +6 -1
  100. package/dist/tui/components/Transcript.js.map +1 -1
  101. package/dist/tui/debugRender.d.ts +41 -6
  102. package/dist/tui/debugRender.js +126 -12
  103. package/dist/tui/debugRender.js.map +1 -1
  104. package/dist/tui/debugSearch.d.ts +40 -0
  105. package/dist/tui/debugSearch.js +73 -0
  106. package/dist/tui/debugSearch.js.map +1 -0
  107. package/dist/tui/markdown.js +0 -0
  108. package/dist/tui/markdown.js.map +1 -1
  109. package/dist/tui/pasteParser.d.ts +21 -0
  110. package/dist/tui/pasteParser.js +24 -0
  111. package/dist/tui/pasteParser.js.map +1 -0
  112. package/dist/tui/selectCancelled.d.ts +13 -0
  113. package/dist/tui/selectCancelled.js +17 -0
  114. package/dist/tui/selectCancelled.js.map +1 -0
  115. package/dist/tui/slashCommands.d.ts +220 -1
  116. package/dist/tui/slashCommands.js +408 -1
  117. package/dist/tui/slashCommands.js.map +1 -1
  118. package/dist/tui/tuiSessionModule.js +249 -24
  119. package/dist/tui/tuiSessionModule.js.map +1 -1
  120. package/dist/tui/types.d.ts +96 -7
  121. package/dist/tui/viewModel.d.ts +34 -0
  122. package/dist/tui/viewModel.js +67 -0
  123. package/dist/tui/viewModel.js.map +1 -1
  124. package/dist/utils/stdinPolicy.d.ts +31 -0
  125. package/dist/utils/stdinPolicy.js +37 -0
  126. package/dist/utils/stdinPolicy.js.map +1 -0
  127. package/package.json +21 -17
@@ -2,18 +2,85 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { render } from 'ink';
3
3
  import { initConfig } from '@gaunt-sloth/core/config.js';
4
4
  import { GthAgentRunner } from '@gaunt-sloth/core/core/GthAgentRunner.js';
5
+ import { mergeToolOutputIntoEvents } from '@gaunt-sloth/core/core/toolOutputChannel.js';
5
6
  import { StatusLevel } from '@gaunt-sloth/core/core/types.js';
6
- import { flushSessionLog, initSessionLogging, stopSessionLogging, } from '@gaunt-sloth/core/utils/consoleUtils.js';
7
+ import { beginWarningCapture, endWarningCapture, flushSessionLog, initSessionLogging, stopSessionLogging, } from '@gaunt-sloth/core/utils/consoleUtils.js';
7
8
  import { appendToFile, getCommandOutputFilePath } from '@gaunt-sloth/core/utils/fileUtils.js';
8
- import { env, stdout } from '@gaunt-sloth/core/utils/systemUtils.js';
9
+ import { env, getProjectDir, stdout } from '@gaunt-sloth/core/utils/systemUtils.js';
10
+ import { openConversationSafe, recordSessionSafe, } from '@gaunt-sloth/core/history/recordSession.js';
11
+ import { openHistoryStore, resolveHistoryDbPath } from '@gaunt-sloth/core/history/historyStore.js';
12
+ import { formatConversationList, formatInsightsSummary, formatSearchResults, } from '@gaunt-sloth/core/history/historyFormat.js';
9
13
  import { HumanMessage } from '@langchain/core/messages';
10
14
  import { MemorySaver } from '@langchain/langgraph';
11
15
  import { createResolvers } from '@gaunt-sloth/agent/resolvers.js';
12
- import { gthDeepAgentFactory } from '@gaunt-sloth/agent/core/gthDeepAgentFactory.js';
13
- import { GthDeepAgent } from '@gaunt-sloth/agent/core/GthDeepAgent.js';
16
+ import { resolveAgentFactory } from '@gaunt-sloth/agent/core/resolveAgentFactory.js';
17
+ import { GthAbstractAgent } from '@gaunt-sloth/core/core/GthAbstractAgent.js';
18
+ import { writeDebugDump } from '@gaunt-sloth/core/utils/debugDump.js';
14
19
  import { App } from '#src/tui/components/App.js';
15
- import { renderHistory, renderRequestDetails, renderResponse } from '#src/tui/debugRender.js';
20
+ import { formatConfigSummary } from '#src/tui/slashCommands.js';
21
+ import { collectMcpOverview, renderHistory, renderMcpDetails, renderSystemDetails, renderToolDetails, renderResponse, } from '#src/tui/debugRender.js';
16
22
  import { viewportBumpSequence } from '#src/tui/terminal.js';
23
+ /**
24
+ * GS2-7 (B20) — build the read-only history slash-command props from the local store, fail-soft.
25
+ * If no DB is available (history never enabled / file missing / unopenable) it returns `{}`, so
26
+ * `/history` `/insights` `/search` render their "history unavailable" notices. Never throws — a
27
+ * store problem must not affect starting a session.
28
+ */
29
+ function buildHistorySlashProps(config) {
30
+ try {
31
+ const dbPath = resolveHistoryDbPath(config.history?.dbPath);
32
+ const store = openHistoryStore(dbPath, { create: false });
33
+ if (!store)
34
+ return {};
35
+ try {
36
+ const historySummary = formatConversationList(store.listConversations(20));
37
+ const insightsSummary = formatInsightsSummary(store.insights());
38
+ // Search runs later (at dispatch), so it re-opens read-only per call rather than holding a
39
+ // connection open for the session; still fully fail-soft.
40
+ const historySearch = (query) => {
41
+ try {
42
+ const s = openHistoryStore(dbPath, { create: false });
43
+ if (!s)
44
+ return formatSearchResults([]);
45
+ try {
46
+ return formatSearchResults(s.search(query, 20));
47
+ }
48
+ finally {
49
+ s.close();
50
+ }
51
+ }
52
+ catch {
53
+ return formatSearchResults([]);
54
+ }
55
+ };
56
+ return { historySummary, insightsSummary, historySearch };
57
+ }
58
+ finally {
59
+ store.close();
60
+ }
61
+ }
62
+ catch {
63
+ return {};
64
+ }
65
+ }
66
+ /**
67
+ * GS2-46 — the real `/debug-dump` writer, injected into `<App>` the same way `historySearch` is:
68
+ * forwards the App-assembled input straight to the core writer, which does the actual fs I/O
69
+ * (mkdir + writeFileSync per file under the GLOBAL `~/.gsloth/debug-dumps/<timestamp>/`) plus
70
+ * gathers env/version info, the in-memory debugLog ring buffer, and best-effort git repo state
71
+ * itself. GS2-47 — the writer applies the shared secret-redaction pass (ON by default) unless the
72
+ * caller-resolved `redact` flag opts out; the flag is forwarded verbatim.
73
+ */
74
+ function dumpDebugSession(input) {
75
+ return writeDebugDump({
76
+ transcript: input.transcript,
77
+ config: input.config,
78
+ modelDisplayName: input.modelDisplayName,
79
+ // GS2-47 — the slash command resolved redact-on-by-default (config + `--unsafe-no-redact`);
80
+ // forward it so the writer applies (or skips) the shared secret-redaction pass.
81
+ redact: input.redact,
82
+ });
83
+ }
17
84
  /** Fan-out so the runner's status callback can reach the mounted React app. */
18
85
  function createStatusBridge() {
19
86
  const listeners = new Set();
@@ -31,8 +98,16 @@ function createStatusBridge() {
31
98
  },
32
99
  };
33
100
  }
34
- /** Fan-out so the deep agent's wrapModelCall debug sink can reach the mounted React app. */
35
- function createDebugBridge() {
101
+ /**
102
+ * Fan-out so the deep agent's wrapModelCall debug sink can reach the mounted React app.
103
+ *
104
+ * TUI-C20: `config` + `resolvers` are threaded in so each request capture can also carry the MCP
105
+ * tab's overview. The per-server discovery instructions come from EXT-32's
106
+ * {@link AgentResolvers.getMcpServerInstructions} accessor (captured once, reused here — never
107
+ * re-queried), collected via `collectMcpOverview`; the per-server tools are regrouped from the same
108
+ * `extras.tools` catalogue the Tools tab renders.
109
+ */
110
+ function createDebugBridge(config, resolvers) {
36
111
  const listeners = new Set();
37
112
  const emit = (capture) => {
38
113
  for (const l of listeners)
@@ -46,15 +121,67 @@ function createDebugBridge() {
46
121
  };
47
122
  },
48
123
  capture: {
49
- onRequest: (messages, extras) => emit({
50
- kind: 'request',
51
- text: renderHistory(messages),
52
- details: renderRequestDetails(extras),
53
- }),
124
+ onRequest: (messages, extras) => {
125
+ const { servers, instructions, failures } = collectMcpOverview(config, resolvers);
126
+ emit({
127
+ kind: 'request',
128
+ text: renderHistory(messages),
129
+ system: renderSystemDetails(extras),
130
+ tools: renderToolDetails(extras),
131
+ mcp: renderMcpDetails(extras, servers, instructions, failures),
132
+ });
133
+ },
54
134
  onResponse: (response) => emit({ kind: 'response', text: renderResponse(response) }),
55
135
  },
56
136
  };
57
137
  }
138
+ /**
139
+ * Fan-out so the runner's tool-approval callback can reach the mounted React app. Modeled on
140
+ * {@link createStatusBridge}, but promise-based: when the runner suspends on a
141
+ * `run_shell_command` interrupt and calls the approval callback, the bridge creates a pending
142
+ * record (the {@link PendingToolInterrupt} plus a `resolve`), emits it to the subscribed
143
+ * `<App>`, and hands the callback a Promise it awaits until the app resolves a decision.
144
+ *
145
+ * Fail-closed: if the session ends / the app unmounts while an approval is still pending, every
146
+ * outstanding record is resolved as a reject (`abortPending`), so a suspended run can never hang
147
+ * — matching the readline path's "anything not o/s/a → reject" default.
148
+ */
149
+ function createApprovalBridge() {
150
+ const listeners = new Set();
151
+ // Records that have been emitted but not yet resolved (used by abortPending on teardown).
152
+ const outstanding = new Set();
153
+ return {
154
+ /** Wired to `runner.setToolApprovalCallback`: returns a Promise the runner awaits. */
155
+ request: (pending) => new Promise((resolve) => {
156
+ let settled = false;
157
+ const record = {
158
+ pending,
159
+ resolve: (decision) => {
160
+ if (settled)
161
+ return;
162
+ settled = true;
163
+ outstanding.delete(record);
164
+ resolve(decision);
165
+ },
166
+ };
167
+ outstanding.add(record);
168
+ for (const l of listeners)
169
+ l(record);
170
+ }),
171
+ subscribe: (cb) => {
172
+ listeners.add(cb);
173
+ return () => {
174
+ listeners.delete(cb);
175
+ };
176
+ },
177
+ /** Resolve every still-pending approval as a reject (fail-closed) on teardown. */
178
+ abortPending: () => {
179
+ for (const record of [...outstanding]) {
180
+ record.resolve({ type: 'reject', message: 'Session ended before approval.' });
181
+ }
182
+ },
183
+ };
184
+ }
58
185
  /**
59
186
  * Ink TUI counterpart to `createInteractiveSession` (the readline path). Same lifecycle —
60
187
  * init config, session logging, a `GthAgentRunner` driving the deep agent — but it renders
@@ -76,31 +203,112 @@ export async function createTuiSession(sessionConfig, commandLineConfigOverrides
76
203
  // Holder so `onResetFrame` can reach the not-yet-created render instance (App writes the
77
204
  // /clear scroll/clear escapes itself, then asks Ink to forget its last frame — TUI-C12).
78
205
  let resetFrame;
79
- const instance = render(_jsx(App, { agent: createFixtureTuiAgent(fixturePath), mode: sessionConfig.mode, readyMessage: sessionConfig.readyMessage, exitMessage: sessionConfig.exitMessage, initialMessage: message, onResetFrame: () => resetFrame?.() }));
206
+ const instance = render(_jsx(App, { agent: createFixtureTuiAgent(fixturePath), mode: sessionConfig.mode, readyMessage: sessionConfig.readyMessage, exitMessage: sessionConfig.exitMessage, initialMessage: message,
207
+ // QA-6: wire the real /debug-dump writer into the fixture branch too (same function
208
+ // reference the non-fixture render uses below) so the e2e PTY suite can exercise the
209
+ // actual archive-write path instead of only ever hitting the "unavailable" fallback.
210
+ // resolvedConfig is deliberately left unset here — DebugDumpInput.config is
211
+ // optional/opaque and the command already handles it being undefined.
212
+ dumpDebugSession: dumpDebugSession, onResetFrame: () => resetFrame?.() }));
80
213
  resetFrame = () => instance.clear();
81
214
  await instance.waitUntilExit();
82
215
  return;
83
216
  }
84
- const config = { ...(await initConfig(commandLineConfigOverrides)) };
217
+ // TUI-C19: capture the transient load-time advisories (config validation warnings — unknown
218
+ // keys, deprecated names — emitted via `displayWarning` inside `initConfig`) so they can be
219
+ // threaded into the TUI's persistent notice surface instead of scrolling out of sight the moment
220
+ // Ink takes over the screen. try/finally so a config throw can't leak the capture window.
221
+ let startupAdvisories = [];
222
+ let config;
223
+ beginWarningCapture();
224
+ try {
225
+ config = { ...(await initConfig(commandLineConfigOverrides)) };
226
+ }
227
+ finally {
228
+ startupAdvisories = endWarningCapture();
229
+ }
85
230
  const checkpointSaver = new MemorySaver();
231
+ // GS2-19: one conversation per TUI session; each completed turn (logTurn) is stamped with its id
232
+ // so the whole chat groups under one conversation. Opt-in / fail-soft (undefined unless history
233
+ // is enabled and the store opened); turns fall back to per-turn conversations otherwise.
234
+ const conversationId = openConversationSafe(config, {
235
+ command: sessionConfig.mode,
236
+ project: getProjectDir(),
237
+ model: config.modelDisplayName,
238
+ }) ?? undefined;
86
239
  const logFileName = getCommandOutputFilePath(config, sessionConfig.mode);
87
240
  if (logFileName) {
88
241
  initSessionLogging(logFileName, config.streamSessionInferenceLog);
89
242
  }
90
243
  const bridge = createStatusBridge();
91
- const debugBridge = createDebugBridge();
92
- const runner = new GthAgentRunner(bridge.emit, createResolvers(), gthDeepAgentFactory);
244
+ // TUI-C20: the resolvers are hoisted so the debug bridge can read the SAME MCP instructions the
245
+ // agent captured (via getMcpServerInstructions) for the /debug MCP tab — not a second capture.
246
+ const resolvers = createResolvers();
247
+ const debugBridge = createDebugBridge(config, resolvers);
248
+ const approvalBridge = createApprovalBridge();
249
+ // B5: TUI code/chat default to the LEAN backend; an explicit config.agent.backend overrides it
250
+ // (deep is now opt-in / experimental). Mirrors the readline path in createInteractiveSession,
251
+ // askCommand, and execCommand — the TUI is the default interactive surface, so it must match.
252
+ // createResolvers() is unchanged, so a lean session keeps the full toolset.
253
+ const runner = new GthAgentRunner(bridge.emit, resolvers, resolveAgentFactory(config, 'lean'));
254
+ // GS2-63: the interactive TUI ALWAYS shows the technical run-header preamble (Workdir/Model/
255
+ // Tools/Middleware). The `output.header: false` opt-out applies to non-TUI text modes only, so
256
+ // the config handed to the agent forces it on regardless of the user's setting — the header
257
+ // lines route through the status bridge into the notice surface here, not raw stdout. A fresh
258
+ // object (not an in-place mutation) so nothing else that already captured `config` is affected.
259
+ const agentConfig = { ...config, output: { ...config.output, header: true } };
93
260
  try {
94
- await runner.init(sessionConfig.mode, config, checkpointSaver);
95
- // Attach the debug sink to the live deep agent (opt-in; the wrapModelCall middleware reads
96
- // it lazily, so this only enables capture for the TUI's /debug panel — the lean/AG-UI
97
- // contracts are untouched). Guarded by an instanceof so a non-deep agent simply has no
98
- // debug capture rather than failing.
261
+ await runner.init(sessionConfig.mode, agentConfig, checkpointSaver);
262
+ // Any MCP server that failed to connect during init (resolveTools ran inside runner.init).
263
+ // Captured here so the persistent NoticeBar can name it — otherwise the only signal is a
264
+ // displayWarning that Ink has already painted over, which is the bug this surfaces.
265
+ const mcpFailures = resolvers?.getMcpConnectionFailures?.() ?? [];
266
+ // Tool-approval (human-in-the-loop) prompt for gated tools — the readline counterpart in
267
+ // interactiveSessionModule. The runner consults the allow-list BEFORE calling this, so
268
+ // trusted commands never reach the TUI prompt; otherwise the bridge surfaces the pending
269
+ // command in the mounted <App> and awaits the human's scoped decision (o/s/a → approve,
270
+ // anything else → reject, fail-closed).
271
+ runner.setToolApprovalCallback((pending) => approvalBridge.request(pending));
272
+ // Attach the debug sink to the live agent (opt-in; each backend's wrapModelCall middleware
273
+ // reads it lazily, so this only enables capture for the TUI's /debug panel — the AG-UI
274
+ // contract is untouched). Both the lean (default) and deep backends extend GthAbstractAgent
275
+ // and install the capture middleware, so the panel populates on either.
99
276
  const agent = runner.getAgent();
100
- if (agent instanceof GthDeepAgent) {
277
+ if (agent instanceof GthAbstractAgent) {
101
278
  agent.debugCapture = debugBridge.capture;
102
279
  }
280
+ // GS2-16: wall-clock start of the in-flight turn, stamped when runTurn begins and read by
281
+ // logTurn on completion (turns are sequential in the TUI). 0 until the first turn runs.
282
+ let turnStartedAt = 0;
103
283
  const logTurn = (userInput, assistantText) => {
284
+ // GS2-16: live token usage + invoked tool names + duration for this turn, fail-soft. The
285
+ // runner may lack stats support (e.g. under test) → guard; empty tally when unavailable.
286
+ let runStats = { tools: [] };
287
+ try {
288
+ const s = runner.getRunStats?.();
289
+ if (s)
290
+ runStats = s;
291
+ }
292
+ catch {
293
+ /* fail-soft: analytics must never affect the session */
294
+ }
295
+ const durationMs = turnStartedAt > 0 ? Date.now() - turnStartedAt : undefined;
296
+ // GS2-7 (B20): opt-in, fail-soft history — records each completed turn as a session when
297
+ // `history.enabled`. Independent of the per-run md log (so it works even with
298
+ // writeOutputToFile off) and fully guarded, so it never affects the session.
299
+ // GS2-16 threads token/tool/duration analytics; costUsd is left unset (no reliable price).
300
+ recordSessionSafe(config, {
301
+ conversationId, // GS2-19: group every turn under this session's conversation
302
+ command: sessionConfig.mode,
303
+ project: getProjectDir(),
304
+ model: config.modelDisplayName,
305
+ prompt: userInput,
306
+ response: assistantText,
307
+ tokensInput: runStats.tokensInput,
308
+ tokensOutput: runStats.tokensOutput,
309
+ tools: runStats.tools.length > 0 ? runStats.tools : undefined,
310
+ durationMs,
311
+ });
104
312
  if (!logFileName)
105
313
  return;
106
314
  appendToFile(logFileName, `## User\n\n${userInput}\n\n## Assistant\n\n${assistantText}\n\n`);
@@ -108,13 +316,26 @@ export async function createTuiSession(sessionConfig, commandLineConfigOverrides
108
316
  };
109
317
  const tuiAgent = {
110
318
  async *runTurn(userInput, signal) {
111
- yield* runner.processMessagesWithEvents([new HumanMessage(userInput)], signal);
319
+ turnStartedAt = Date.now(); // GS2-16: mark turn start for durationMs in logTurn
320
+ // TUI-C17: subscribe to the tool-output channel for the turn and merge each live
321
+ // custom/dev-tool stdout/stderr chunk (and its "Executing" notice) into the event
322
+ // stream as `tool_output` events — so tool output lands in `foldEvents`/the managed
323
+ // frame instead of leaking to raw stdout above Ink's render tree. Unsubscribes when
324
+ // the turn ends, restoring the default (headless) stdout sink between turns.
325
+ yield* mergeToolOutputIntoEvents(runner.processMessagesWithEvents([new HumanMessage(userInput)], signal));
112
326
  },
113
327
  // `/clear` rotates the runner's thread_id so the model context truly matches the
114
328
  // cleared transcript (the checkpointer otherwise replays the whole prior conversation).
115
329
  resetThread() {
116
330
  runner.resetThread();
117
331
  },
332
+ // `/auto-approve` applies the runner's session-scoped shell auto-approval flag (EXT-12):
333
+ // 'on'/'off' set it explicitly, 'toggle' flips it. Returns the landed state for the notice.
334
+ setAutoApprove(action) {
335
+ if (action === 'toggle')
336
+ return runner.toggleSessionYolo();
337
+ return runner.setSessionYolo(action === 'on');
338
+ },
118
339
  };
119
340
  // "Bump up" the screen on launch the clear/Ctrl+L way (TUI-C13): scroll whatever was on
120
341
  // screen before `gth`/`gsloth` ran up and out of the visible viewport (it stays in
@@ -128,7 +349,10 @@ export async function createTuiSession(sessionConfig, commandLineConfigOverrides
128
349
  // writes the scroll/viewport-clear escapes, then calls this to make Ink forget its last
129
350
  // frame so the re-render lands cleanly at the top (TUI-C12).
130
351
  let resetFrame;
131
- const instance = render(_jsx(App, { agent: tuiAgent, mode: sessionConfig.mode, modelDisplayName: config.modelDisplayName, readyMessage: sessionConfig.readyMessage, exitMessage: sessionConfig.exitMessage, initialMessage: message, subscribeStatus: bridge.subscribe, subscribeDebug: debugBridge.subscribe, onTurnComplete: logTurn, onResetFrame: () => resetFrame?.(), onExit: async () => {
352
+ const instance = render(_jsx(App, { agent: tuiAgent, mode: sessionConfig.mode, modelDisplayName: config.modelDisplayName, initialAutoApprove: runner.isSessionYolo(), configSummary: formatConfigSummary(config), resolvedConfig: config, dumpDebugSession: dumpDebugSession, advisories: startupAdvisories, mcpFailures: mcpFailures, ...buildHistorySlashProps(config), readyMessage: sessionConfig.readyMessage, exitMessage: sessionConfig.exitMessage, initialMessage: message, subscribeStatus: bridge.subscribe, subscribeDebug: debugBridge.subscribe, subscribeApproval: approvalBridge.subscribe, onTurnComplete: logTurn, onResetFrame: () => resetFrame?.(), onExit: async () => {
353
+ // Fail-closed: resolve any approval still awaiting a decision before tearing down,
354
+ // so a suspended run can never hang on an unanswered prompt.
355
+ approvalBridge.abortPending();
132
356
  await runner.cleanup();
133
357
  stopSessionLogging();
134
358
  } }));
@@ -136,6 +360,7 @@ export async function createTuiSession(sessionConfig, commandLineConfigOverrides
136
360
  await instance.waitUntilExit();
137
361
  }
138
362
  catch (err) {
363
+ approvalBridge.abortPending();
139
364
  await runner.cleanup();
140
365
  stopSessionLogging();
141
366
  throw err;
@@ -1 +1 @@
1
- {"version":3,"file":"tuiSessionModule.js","sourceRoot":"","sources":["../../src/tui/tuiSessionModule.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tuiSessionModule.js","sourceRoot":"","sources":["../../src/tui/tuiSessionModule.tsx"],"names":[],"mappings":"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"}
@@ -1,6 +1,17 @@
1
- import type { AgentStreamEvent } from '@gaunt-sloth/core/core/types.js';
1
+ import type { AgentStreamEvent, PendingToolInterrupt, ToolApprovalDecision, McpConnectionFailure } from '@gaunt-sloth/core/core/types.js';
2
2
  import type { TurnViewModel } from '#src/tui/viewModel.js';
3
3
  import type { CommandNoticeTone } from '#src/tui/components/CommandNotice.js';
4
+ import type { DebugDumpInput } from '#src/tui/slashCommands.js';
5
+ /**
6
+ * One in-flight tool-approval request bridged from the runner into the mounted `<App>`
7
+ * (EXT-9 Phase B2): the {@link PendingToolInterrupt} the runner suspended on, plus a `resolve`
8
+ * that hands the human's {@link ToolApprovalDecision} back to the awaiting runner callback.
9
+ * Idempotent — calling `resolve` more than once is a no-op (the first decision wins).
10
+ */
11
+ export interface PendingApproval {
12
+ pending: PendingToolInterrupt;
13
+ resolve: (decision: ToolApprovalDecision) => void;
14
+ }
4
15
  /**
5
16
  * The minimal agent surface the Ink `<App>` drives. Decoupling the component from
6
17
  * `GthAgentRunner` keeps the UI unit-testable with a scripted fake (a generator that
@@ -15,18 +26,28 @@ export interface TuiAgent {
15
26
  * Optional so the fixture agent (no real checkpointer thread) may omit it.
16
27
  */
17
28
  resetThread?(): void;
29
+ /**
30
+ * EXT-12 — apply a change to the runner's session-scoped auto-approve flag (shell auto-approval)
31
+ * and return the NEW state, so the App can render a state-aware notice and status indicator.
32
+ * `'on'`/`'off'` set it explicitly, `'toggle'` flips it. Wired to the `/auto-approve` slash
33
+ * command. Optional so the fixture agent (no runner) may omit it.
34
+ */
35
+ setAutoApprove?(action: 'on' | 'off' | 'toggle'): boolean;
18
36
  }
19
37
  /**
20
- * One debug capture from the deep agent's `wrapModelCall` middleware. `kind: 'request'`
21
- * carries the full message history sent to the model plus, in `details`, the non-message
22
- * request parts (system prompt, tool definitions, model params) rendered for the dedicated
23
- * "Sent to model (system + tools)" tab; `kind: 'response'` carries the resolved raw model response.
24
- * All arrive pre-rendered as strings so the panel just slices lines.
38
+ * One debug capture from the agent's `wrapModelCall` middleware. `kind: 'request'`
39
+ * carries the full message history (`text`) sent to the model plus the non-message request parts
40
+ * pre-rendered for two dedicated tabs (TUI-C16): `system` (model params, tool-choice, system
41
+ * prompt) and `tools` (the tool catalogue), plus `mcp` (TUI-C20: the per-server MCP overview —
42
+ * instructions + server-prefixed tools). `kind: 'response'` carries the resolved raw model
43
+ * response. All arrive pre-rendered as strings so the panel just slices lines.
25
44
  */
26
45
  export type TuiDebugCapture = {
27
46
  kind: 'request';
28
47
  text: string;
29
- details: string;
48
+ system: string;
49
+ tools: string;
50
+ mcp: string;
30
51
  } | {
31
52
  kind: 'response';
32
53
  text: string;
@@ -51,6 +72,11 @@ export type TranscriptItem = {
51
72
  title: string;
52
73
  lines: string[];
53
74
  tone: CommandNoticeTone;
75
+ } | {
76
+ kind: 'reasoning';
77
+ id: number;
78
+ reasoning: string;
79
+ turnNumber: number;
54
80
  };
55
81
  /** Props for the root `<App>`; the real session wires these to a `GthAgentRunner`. */
56
82
  export interface TuiAppProps {
@@ -58,6 +84,62 @@ export interface TuiAppProps {
58
84
  mode: string;
59
85
  /** Model/provider display name for the status bar and `/model` (from `config.modelDisplayName`). */
60
86
  modelDisplayName?: string;
87
+ /**
88
+ * EXT-12 — initial state of the session auto-approve flag, so the status bar shows the
89
+ * indicator from the first frame when `run_shell_command.yolo` pre-enabled it in config. The App
90
+ * keeps its own state after this; the session module seeds it from `runner.isSessionYolo()`.
91
+ * Defaults to off (undefined) — the fixture / non-shell sessions omit it.
92
+ */
93
+ initialAutoApprove?: boolean;
94
+ /**
95
+ * Pre-rendered, secret-free summary lines of the resolved config for the read-only `/config`
96
+ * slash command (GS2-1). Built once by the session module via `formatConfigSummary`; omitted by
97
+ * the fixture agent (no config loaded), where `/config` shows an "unavailable" notice.
98
+ */
99
+ configSummary?: string[];
100
+ /**
101
+ * GS2-7 (B20) — pre-rendered recent-session lines for `/history` and analytics lines for
102
+ * `/insights`, plus a fail-soft search provider for `/search`. All built by the session module
103
+ * from the local, opt-in history store; omitted when no store is available (history off / DB
104
+ * missing), where the commands show an "unavailable" notice.
105
+ */
106
+ historySummary?: string[];
107
+ insightsSummary?: string[];
108
+ historySearch?: (query: string) => string[];
109
+ /**
110
+ * GS2-46 — the resolved config (the live `GthConfig`), for `/debug-dump`. Kept `unknown` here
111
+ * (this component never inspects it — it just forwards it into `dumpDebugSession`) so the TUI
112
+ * layer stays decoupled from the core config type. Omitted by the fixture agent, where
113
+ * `/debug-dump` reports itself unavailable.
114
+ */
115
+ resolvedConfig?: unknown;
116
+ /**
117
+ * GS2-46 — fs-writing implementation for `/debug-dump` (an UNSANITIZED diagnostic archive:
118
+ * transcript, resolved config, env/version info, the in-memory debugLog ring buffer, and
119
+ * best-effort git repo state), wired to `packages/core/src/utils/debugDump.ts#writeDebugDump`
120
+ * the same way `historySearch` wires to the local history store. Omitted by the fixture agent.
121
+ */
122
+ dumpDebugSession?: (input: DebugDumpInput) => {
123
+ archiveDir: string;
124
+ };
125
+ /**
126
+ * TUI-C19 — non-fatal startup advisories to surface persistently (currently the load-time
127
+ * config-validation warnings — unknown keys, deprecated names — captured around `initConfig`).
128
+ * When non-empty, the chrome shows a standing "config has problems" line OUTSIDE `<Static>` (so
129
+ * it never scrolls away) and `/config` renders the actual warning text. Kept a generic string
130
+ * list so other non-fatal startup advisories can post here later without a schema change; the
131
+ * fixture/AG-UI paths omit it. Absent/empty ⇒ no standing line and `/config` shows no warnings.
132
+ */
133
+ advisories?: string[];
134
+ /**
135
+ * Per-server MCP connection failures captured during agent init (resolveTools). When non-empty,
136
+ * the chrome shows a standing line naming the unavailable server(s) OUTSIDE `<Static>` — a
137
+ * connection failure is otherwise only a transient `displayWarning` that Ink paints over. Kept
138
+ * separate from `advisories` because those are config-validation warnings pointing at `/config`;
139
+ * an MCP failure is not a config problem and points at the `/debug` MCP tab instead. The
140
+ * fixture/AG-UI paths omit it. Absent/empty ⇒ no standing line.
141
+ */
142
+ mcpFailures?: McpConnectionFailure[];
61
143
  /** Greeting shown before the first prompt (mirrors the readline `readyMessage`). */
62
144
  readyMessage: string;
63
145
  /** Hint shown in the status bar / on start (mirrors the readline `exitMessage`). */
@@ -72,6 +154,13 @@ export interface TuiAppProps {
72
154
  * so the readline/AG-UI paths and the fixture agent (which have no such sink) simply omit it.
73
155
  */
74
156
  subscribeDebug?: (cb: (capture: TuiDebugCapture) => void) => () => void;
157
+ /**
158
+ * Subscribe to tool-approval requests bridged from the runner (EXT-9 Phase B2): each
159
+ * {@link PendingApproval} carries the pending `run_shell_command` interrupt and a `resolve`
160
+ * the app calls with the human's scoped decision. Optional so the fixture/AG-UI paths (which
161
+ * never surface approvals) simply omit it.
162
+ */
163
+ subscribeApproval?: (cb: (record: PendingApproval) => void) => () => void;
75
164
  /** Called once a turn finishes, with the user input and the final assistant text. */
76
165
  onTurnComplete?: (userInput: string, assistantText: string) => void;
77
166
  /**
@@ -17,8 +17,28 @@ export interface ToolCallViewModel {
17
17
  /** Accumulated `tool_args` deltas (raw JSON text as streamed). */
18
18
  argsText: string;
19
19
  status: 'running' | 'done';
20
+ /**
21
+ * TUI-C17 — accumulated LIVE output streamed while the tool executed (`tool_output` events:
22
+ * verbatim child stdout/stderr chunks, in arrival order). Distinct from `result` (the final
23
+ * model-facing tool result): this is what the child printed as it ran. Living here (React
24
+ * state, not ephemeral stdout) is what makes it survive re-renders; TUI-C30 consumes it for
25
+ * the per-tool output preview.
26
+ */
27
+ output?: string;
28
+ /**
29
+ * TUI-C30 — the "🔧 Executing …" announcement (`tool_output` events with `isNotice`), kept
30
+ * SEPARATE from `output` so the raw-output preview never counts the notice as an output line
31
+ * and the expanded panel can style it as chrome rather than child output.
32
+ */
33
+ notice?: string;
20
34
  /** Present once a `tool_result` arrives. */
21
35
  result?: string;
36
+ /**
37
+ * True when the `tool_result` event reported `isError` (the real LangChain
38
+ * `ToolMessage.status === 'error'` signal). Undefined means success; the renderer drives
39
+ * the ✗/error glyph from this, never from sniffing the result text.
40
+ */
41
+ isError?: boolean;
22
42
  }
23
43
  /** The renderable state of a single in-progress assistant turn. */
24
44
  export interface TurnViewModel {
@@ -74,3 +94,17 @@ argsBuffers?: Map<string, string>): SubagentTreeViewModel;
74
94
  * map per call so the reducer stays referentially honest for tests and replay.
75
95
  */
76
96
  export declare function foldSubagentTree(events: AgentStreamEvent[], state?: SubagentTreeViewModel): SubagentTreeViewModel;
97
+ /** The tool name the lean agent uses to record its checklist. Matches `gthChecklistTool.ts`. */
98
+ export declare const CHECKLIST_TOOL_NAME = "gth_checklist";
99
+ export type ChecklistItemStatus = 'pending' | 'in_progress' | 'completed';
100
+ /** One checklist row parsed from a `gth_checklist` tool call's args. */
101
+ export interface ChecklistItemViewModel {
102
+ content: string;
103
+ status: ChecklistItemStatus;
104
+ }
105
+ /**
106
+ * Best-effort parse of a (possibly partial) streamed `gth_checklist` args JSON into rows. Mirrors
107
+ * {@link parseTaskArgs}: a half-streamed or malformed buffer never throws — it returns `null` so
108
+ * the renderer keeps showing the last good state (or falls back to the generic tool panel).
109
+ */
110
+ export declare function parseChecklistArgs(argsText: string): ChecklistItemViewModel[] | null;