erosolar-cli 2.1.215 → 2.1.217

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 (195) hide show
  1. package/dist/browser/BrowserSessionManager.d.ts.map +1 -1
  2. package/dist/browser/BrowserSessionManager.js.map +1 -1
  3. package/dist/config.js +3 -3
  4. package/dist/config.js.map +1 -1
  5. package/dist/contracts/schemas/agent.schema.json +2 -1
  6. package/dist/contracts/v1/agent.d.ts +9 -2
  7. package/dist/contracts/v1/agent.d.ts.map +1 -1
  8. package/dist/core/agent.d.ts +18 -2
  9. package/dist/core/agent.d.ts.map +1 -1
  10. package/dist/core/agent.js +112 -29
  11. package/dist/core/agent.js.map +1 -1
  12. package/dist/core/agentRulebook.js +1 -1
  13. package/dist/core/agentRulebook.js.map +1 -1
  14. package/dist/core/agentSchemaLoader.d.ts.map +1 -1
  15. package/dist/core/agentSchemaLoader.js +1 -0
  16. package/dist/core/agentSchemaLoader.js.map +1 -1
  17. package/dist/core/alphaZeroEngine.d.ts +1 -1
  18. package/dist/core/alphaZeroEngine.d.ts.map +1 -1
  19. package/dist/core/alphaZeroEngine.js +1 -1
  20. package/dist/core/alphaZeroEngine.js.map +1 -1
  21. package/dist/core/contextManager.d.ts +1 -1
  22. package/dist/core/contextManager.d.ts.map +1 -1
  23. package/dist/core/contextManager.js +1 -1
  24. package/dist/core/contextManager.js.map +1 -1
  25. package/dist/core/deepBugAnalyzer.d.ts +1 -1
  26. package/dist/core/deepBugAnalyzer.d.ts.map +1 -1
  27. package/dist/core/deepBugAnalyzer.js +8 -8
  28. package/dist/core/deepBugAnalyzer.js.map +1 -1
  29. package/dist/core/failureRecovery.d.ts +1 -1
  30. package/dist/core/failureRecovery.d.ts.map +1 -1
  31. package/dist/core/failureRecovery.js +2 -1
  32. package/dist/core/failureRecovery.js.map +1 -1
  33. package/dist/core/hooks.js +2 -2
  34. package/dist/core/hooks.js.map +1 -1
  35. package/dist/core/intelligentTestFlows.d.ts.map +1 -1
  36. package/dist/core/intelligentTestFlows.js +0 -9
  37. package/dist/core/intelligentTestFlows.js.map +1 -1
  38. package/dist/core/learningPersistence.js.map +1 -1
  39. package/dist/core/memorySystem.js.map +1 -1
  40. package/dist/core/metricsTracker.d.ts +1 -1
  41. package/dist/core/metricsTracker.d.ts.map +1 -1
  42. package/dist/core/metricsTracker.js +1 -1
  43. package/dist/core/metricsTracker.js.map +1 -1
  44. package/dist/core/multilinePasteHandler.js +3 -3
  45. package/dist/core/multilinePasteHandler.js.map +1 -1
  46. package/dist/core/outputStyles.js +1 -1
  47. package/dist/core/outputStyles.js.map +1 -1
  48. package/dist/core/performanceMonitor.d.ts.map +1 -1
  49. package/dist/core/performanceMonitor.js +5 -1
  50. package/dist/core/performanceMonitor.js.map +1 -1
  51. package/dist/core/preferences.d.ts.map +1 -1
  52. package/dist/core/preferences.js +1 -0
  53. package/dist/core/preferences.js.map +1 -1
  54. package/dist/core/productTestHarness.d.ts.map +1 -1
  55. package/dist/core/productTestHarness.js +7 -1
  56. package/dist/core/productTestHarness.js.map +1 -1
  57. package/dist/core/schemaValidator.d.ts.map +1 -1
  58. package/dist/core/schemaValidator.js.map +1 -1
  59. package/dist/core/selfEvolution.d.ts.map +1 -1
  60. package/dist/core/selfEvolution.js +1 -20
  61. package/dist/core/selfEvolution.js.map +1 -1
  62. package/dist/core/selfImprovement.d.ts +1 -1
  63. package/dist/core/selfImprovement.d.ts.map +1 -1
  64. package/dist/core/selfImprovement.js +2 -2
  65. package/dist/core/selfImprovement.js.map +1 -1
  66. package/dist/core/toolPreconditions.js +2 -0
  67. package/dist/core/toolPreconditions.js.map +1 -1
  68. package/dist/core/toolRuntime.d.ts.map +1 -1
  69. package/dist/core/toolRuntime.js +1 -0
  70. package/dist/core/toolRuntime.js.map +1 -1
  71. package/dist/core/validationRunner.d.ts.map +1 -1
  72. package/dist/core/validationRunner.js +9 -5
  73. package/dist/core/validationRunner.js.map +1 -1
  74. package/dist/headless/evalMode.d.ts.map +1 -1
  75. package/dist/headless/evalMode.js +4 -0
  76. package/dist/headless/evalMode.js.map +1 -1
  77. package/dist/intelligence/docGenerator.js +1 -1
  78. package/dist/intelligence/docGenerator.js.map +1 -1
  79. package/dist/mcp/stdioClient.d.ts.map +1 -1
  80. package/dist/mcp/stdioClient.js +1 -0
  81. package/dist/mcp/stdioClient.js.map +1 -1
  82. package/dist/providers/anthropicProvider.d.ts.map +1 -1
  83. package/dist/providers/anthropicProvider.js +2 -10
  84. package/dist/providers/anthropicProvider.js.map +1 -1
  85. package/dist/providers/googleProvider.js +1 -0
  86. package/dist/providers/googleProvider.js.map +1 -1
  87. package/dist/providers/openaiResponsesProvider.js.map +1 -1
  88. package/dist/runtime/agentController.d.ts +1 -0
  89. package/dist/runtime/agentController.d.ts.map +1 -1
  90. package/dist/runtime/agentController.js +23 -1
  91. package/dist/runtime/agentController.js.map +1 -1
  92. package/dist/runtime/agentHost.d.ts.map +1 -1
  93. package/dist/runtime/agentHost.js +1 -0
  94. package/dist/runtime/agentHost.js.map +1 -1
  95. package/dist/shell/autoExecutor.d.ts.map +1 -1
  96. package/dist/shell/autoExecutor.js +8 -5
  97. package/dist/shell/autoExecutor.js.map +1 -1
  98. package/dist/shell/interactiveShell.d.ts +16 -0
  99. package/dist/shell/interactiveShell.d.ts.map +1 -1
  100. package/dist/shell/interactiveShell.js +354 -165
  101. package/dist/shell/interactiveShell.js.map +1 -1
  102. package/dist/shell/vimMode.d.ts.map +1 -1
  103. package/dist/shell/vimMode.js +3 -2
  104. package/dist/shell/vimMode.js.map +1 -1
  105. package/dist/skills/skillRepository.d.ts.map +1 -1
  106. package/dist/skills/skillRepository.js +1 -0
  107. package/dist/skills/skillRepository.js.map +1 -1
  108. package/dist/subagents/taskRunner.d.ts.map +1 -1
  109. package/dist/subagents/taskRunner.js +2 -1
  110. package/dist/subagents/taskRunner.js.map +1 -1
  111. package/dist/tools/advancedTestGenerationTools.js +4 -1
  112. package/dist/tools/advancedTestGenerationTools.js.map +1 -1
  113. package/dist/tools/backgroundBashTools.js.map +1 -1
  114. package/dist/tools/bashTools.d.ts.map +1 -1
  115. package/dist/tools/bashTools.js +5 -6
  116. package/dist/tools/bashTools.js.map +1 -1
  117. package/dist/tools/buildTools.d.ts.map +1 -1
  118. package/dist/tools/buildTools.js +6 -4
  119. package/dist/tools/buildTools.js.map +1 -1
  120. package/dist/tools/codeQualityTools.d.ts.map +1 -1
  121. package/dist/tools/codeQualityTools.js +1 -0
  122. package/dist/tools/codeQualityTools.js.map +1 -1
  123. package/dist/tools/dependencyTools.d.ts.map +1 -1
  124. package/dist/tools/dependencyTools.js +1 -0
  125. package/dist/tools/dependencyTools.js.map +1 -1
  126. package/dist/tools/devTools.d.ts.map +1 -1
  127. package/dist/tools/devTools.js +1 -0
  128. package/dist/tools/devTools.js.map +1 -1
  129. package/dist/tools/diffUtils.d.ts.map +1 -1
  130. package/dist/tools/diffUtils.js +0 -2
  131. package/dist/tools/diffUtils.js.map +1 -1
  132. package/dist/tools/editTools.js.map +1 -1
  133. package/dist/tools/enhancedAnalysisTools.d.ts.map +1 -1
  134. package/dist/tools/enhancedAnalysisTools.js +1 -13
  135. package/dist/tools/enhancedAnalysisTools.js.map +1 -1
  136. package/dist/tools/enhancedCodeIntelligenceTools.js.map +1 -1
  137. package/dist/tools/enhancedDevWorkflowTools.d.ts.map +1 -1
  138. package/dist/tools/enhancedDevWorkflowTools.js +1 -0
  139. package/dist/tools/enhancedDevWorkflowTools.js.map +1 -1
  140. package/dist/tools/fileTools.d.ts.map +1 -1
  141. package/dist/tools/fileTools.js +3 -0
  142. package/dist/tools/fileTools.js.map +1 -1
  143. package/dist/tools/frontendTestingTools.js +1 -1
  144. package/dist/tools/frontendTestingTools.js.map +1 -1
  145. package/dist/tools/globTools.js.map +1 -1
  146. package/dist/tools/grepTools.js.map +1 -1
  147. package/dist/tools/learnTools.js +0 -6
  148. package/dist/tools/learnTools.js.map +1 -1
  149. package/dist/tools/localExplore.d.ts.map +1 -1
  150. package/dist/tools/localExplore.js +0 -1
  151. package/dist/tools/localExplore.js.map +1 -1
  152. package/dist/tools/notebookEditTools.js.map +1 -1
  153. package/dist/tools/searchTools.js +2 -0
  154. package/dist/tools/searchTools.js.map +1 -1
  155. package/dist/tools/testingTools.d.ts.map +1 -1
  156. package/dist/tools/testingTools.js +8 -4
  157. package/dist/tools/testingTools.js.map +1 -1
  158. package/dist/tools/webTools.d.ts.map +1 -1
  159. package/dist/tools/webTools.js.map +1 -1
  160. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  161. package/dist/ui/ShellUIAdapter.js +4 -17
  162. package/dist/ui/ShellUIAdapter.js.map +1 -1
  163. package/dist/ui/UnifiedUIRenderer.d.ts +1 -1
  164. package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -1
  165. package/dist/ui/UnifiedUIRenderer.js +41 -27
  166. package/dist/ui/UnifiedUIRenderer.js.map +1 -1
  167. package/dist/ui/codeHighlighter.js +1 -1
  168. package/dist/ui/codeHighlighter.js.map +1 -1
  169. package/dist/ui/display.d.ts.map +1 -1
  170. package/dist/ui/display.js +4 -3
  171. package/dist/ui/display.js.map +1 -1
  172. package/dist/ui/errorFormatter.d.ts.map +1 -1
  173. package/dist/ui/errorFormatter.js +1 -0
  174. package/dist/ui/errorFormatter.js.map +1 -1
  175. package/dist/ui/inPlaceUpdater.d.ts +1 -1
  176. package/dist/ui/inPlaceUpdater.d.ts.map +1 -1
  177. package/dist/ui/inPlaceUpdater.js +1 -3
  178. package/dist/ui/inPlaceUpdater.js.map +1 -1
  179. package/dist/ui/layout.d.ts.map +1 -1
  180. package/dist/ui/layout.js +1 -0
  181. package/dist/ui/layout.js.map +1 -1
  182. package/dist/ui/richText.d.ts.map +1 -1
  183. package/dist/ui/richText.js +7 -1
  184. package/dist/ui/richText.js.map +1 -1
  185. package/dist/ui/toolDisplay.d.ts +1 -1
  186. package/dist/ui/toolDisplay.d.ts.map +1 -1
  187. package/dist/ui/toolDisplay.js +11 -5
  188. package/dist/ui/toolDisplay.js.map +1 -1
  189. package/dist/utils/askUserPrompt.d.ts.map +1 -1
  190. package/dist/utils/askUserPrompt.js +1 -0
  191. package/dist/utils/askUserPrompt.js.map +1 -1
  192. package/dist/utils/planFormatter.d.ts.map +1 -1
  193. package/dist/utils/planFormatter.js +1 -0
  194. package/dist/utils/planFormatter.js.map +1 -1
  195. package/package.json +1 -1
@@ -161,6 +161,10 @@ export class InteractiveShell {
161
161
  lastAssistantResponse = null;
162
162
  responseRendered = false;
163
163
  remainingIssueFixQueued = false;
164
+ lastBuildStatus = null;
165
+ lastTestStatus = null;
166
+ lastRunToolCount = null;
167
+ lastRunDurationSeconds = null;
164
168
  lastFailure = null;
165
169
  lastAutoTestRun = null;
166
170
  // Auto-build tracking
@@ -183,6 +187,9 @@ export class InteractiveShell {
183
187
  statusMessageOverride = null;
184
188
  inlineCommandActive = false;
185
189
  inlinePanelScopeActive = false;
190
+ inlinePanelBase = [];
191
+ inlinePanelNotices = [];
192
+ inlinePanelClearTimer = null;
186
193
  promptRefreshTimer = null;
187
194
  launchPaletteShown = false;
188
195
  version;
@@ -410,6 +417,7 @@ export class InteractiveShell {
410
417
  const workspace = this.abbreviatePath(this.workingDir);
411
418
  const version = this.version || this.getPackageInfo().version || 'dev';
412
419
  const frame = (content) => theme.gradient.primary(content);
420
+ // eslint-disable-next-line no-control-regex
413
421
  const stripAnsi = (value) => value.replace(/\u001B\[[0-?]*[ -/]*[@-~]/g, '');
414
422
  const padCenter = (text, width) => {
415
423
  const len = stripAnsi(text).length;
@@ -1205,15 +1213,14 @@ export class InteractiveShell {
1205
1213
  }
1206
1214
  const trimmed = input.trim();
1207
1215
  if (!trimmed) {
1208
- display.showWarning('Enter a number, "save", "defaults", or "cancel".');
1216
+ this.appendInlineNotice('Enter a number, "save", "defaults", or "cancel".', 'warning');
1209
1217
  this.syncRendererInput();
1210
1218
  return;
1211
1219
  }
1212
1220
  const normalized = trimmed.toLowerCase();
1213
1221
  if (normalized === 'cancel') {
1214
1222
  this.pendingInteraction = null;
1215
- display.showInfo('Tool selection cancelled.');
1216
- this.clearInlinePanel();
1223
+ this.showInlineStatus('Tool selection cancelled.', 'info', { autoClearMs: 1600 });
1217
1224
  this.syncRendererInput();
1218
1225
  return;
1219
1226
  }
@@ -1224,9 +1231,14 @@ export class InteractiveShell {
1224
1231
  return;
1225
1232
  }
1226
1233
  if (normalized === 'save') {
1227
- await this.persistToolSelection(pending);
1234
+ const result = await this.persistToolSelection(pending);
1228
1235
  this.pendingInteraction = null;
1229
- this.clearInlinePanel();
1236
+ if (result) {
1237
+ this.showInlineStatus(result.message, result.tone ?? 'info', { autoClearMs: 1800 });
1238
+ }
1239
+ else {
1240
+ this.clearInlinePanel();
1241
+ }
1230
1242
  this.syncRendererInput();
1231
1243
  return;
1232
1244
  }
@@ -1234,11 +1246,11 @@ export class InteractiveShell {
1234
1246
  if (Number.isFinite(choice)) {
1235
1247
  const option = pending.options[choice - 1];
1236
1248
  if (!option) {
1237
- display.showWarning('That option is not available.');
1249
+ this.appendInlineNotice('That option is not available.', 'warning');
1238
1250
  }
1239
1251
  else {
1240
1252
  if (option.locked) {
1241
- display.showInfo('The default tool package is always enabled and cannot be toggled.');
1253
+ this.appendInlineNotice('The default tool package is always enabled and cannot be toggled.', 'info');
1242
1254
  }
1243
1255
  else {
1244
1256
  if (pending.selection.has(option.id)) {
@@ -1253,26 +1265,24 @@ export class InteractiveShell {
1253
1265
  this.syncRendererInput();
1254
1266
  return;
1255
1267
  }
1256
- display.showWarning('Enter a number, "save", "defaults", or "cancel".');
1268
+ this.appendInlineNotice('Enter a number, "save", "defaults", or "cancel".', 'warning');
1257
1269
  this.syncRendererInput();
1258
1270
  }
1259
1271
  async persistToolSelection(interaction) {
1260
1272
  if (setsEqual(interaction.selection, interaction.initialSelection)) {
1261
- display.showInfo('No changes to save.');
1262
- return;
1273
+ return { message: 'No changes to save.', tone: 'info' };
1263
1274
  }
1264
1275
  const defaults = buildEnabledToolSet(null, this.profile);
1265
1276
  if (setsEqual(interaction.selection, defaults)) {
1266
1277
  clearToolSettings();
1267
- display.showInfo('Tool settings cleared. Defaults will be used on the next launch.');
1268
- return;
1278
+ return { message: 'Tool settings cleared. Defaults will be used on the next launch.', tone: 'info' };
1269
1279
  }
1270
1280
  const ordered = interaction.options
1271
1281
  .filter((option) => !option.locked)
1272
1282
  .map((option) => option.id)
1273
1283
  .filter((id) => interaction.selection.has(id));
1274
1284
  saveToolSettings({ enabledTools: ordered });
1275
- display.showInfo('Tool settings saved. Restart the CLI to apply them.');
1285
+ return { message: 'Tool settings saved. Restart the CLI to apply them.', tone: 'success' };
1276
1286
  }
1277
1287
  async handleAgentSelectionInput(input) {
1278
1288
  const pending = this.pendingInteraction;
@@ -1281,58 +1291,69 @@ export class InteractiveShell {
1281
1291
  }
1282
1292
  if (!this.agentMenu) {
1283
1293
  this.pendingInteraction = null;
1284
- display.showWarning('Agent selection is unavailable in this CLI.');
1294
+ this.showInlineStatus('Agent selection is unavailable in this CLI.', 'warning', { autoClearMs: 1600 });
1285
1295
  this.syncRendererInput();
1286
1296
  return;
1287
1297
  }
1288
1298
  const trimmed = input.trim();
1289
1299
  if (!trimmed) {
1290
- display.showWarning('Enter a number or type "cancel".');
1300
+ this.appendInlineNotice('Enter a number or type "cancel".', 'warning');
1291
1301
  this.syncRendererInput();
1292
1302
  return;
1293
1303
  }
1294
1304
  if (trimmed.toLowerCase() === 'cancel') {
1295
1305
  this.pendingInteraction = null;
1296
- display.showInfo('Agent selection cancelled.');
1297
- this.clearInlinePanel();
1306
+ this.showInlineStatus('Agent selection cancelled.', 'info', { autoClearMs: 1600 });
1298
1307
  this.syncRendererInput();
1299
1308
  return;
1300
1309
  }
1301
1310
  const choice = Number.parseInt(trimmed, 10);
1302
1311
  if (!Number.isFinite(choice)) {
1303
- display.showWarning('Please enter a valid number.');
1312
+ this.appendInlineNotice('Please enter a valid number.', 'warning');
1304
1313
  this.syncRendererInput();
1305
1314
  return;
1306
1315
  }
1307
1316
  const option = pending.options[choice - 1];
1308
1317
  if (!option) {
1309
- display.showWarning('That option is not available.');
1318
+ this.appendInlineNotice('That option is not available.', 'warning');
1310
1319
  this.syncRendererInput();
1311
1320
  return;
1312
1321
  }
1313
- await this.persistAgentSelection(option.name);
1314
1322
  this.pendingInteraction = null;
1315
- this.clearInlinePanel();
1323
+ const result = await this.persistAgentSelection(option.name);
1324
+ if (result) {
1325
+ this.showInlineStatus(result.message, result.tone ?? 'info', { autoClearMs: 2000 });
1326
+ }
1327
+ else {
1328
+ this.clearInlinePanel();
1329
+ }
1316
1330
  this.syncRendererInput();
1317
1331
  }
1318
1332
  async persistAgentSelection(profileName) {
1319
1333
  if (!this.agentMenu) {
1320
- return;
1334
+ return null;
1321
1335
  }
1322
1336
  const currentDefault = this.agentMenu.persistedProfile ?? this.agentMenu.defaultProfile;
1323
1337
  if (profileName === currentDefault) {
1324
- display.showInfo(`${this.agentMenuLabel(profileName)} is already configured for the next launch.`);
1325
- return;
1338
+ return {
1339
+ message: `${this.agentMenuLabel(profileName)} is already configured for the next launch.`,
1340
+ tone: 'info',
1341
+ };
1326
1342
  }
1327
1343
  if (profileName === this.agentMenu.defaultProfile) {
1328
1344
  clearActiveProfilePreference();
1329
1345
  this.agentMenu.persistedProfile = null;
1330
- display.showInfo(`${this.agentMenuLabel(profileName)} restored as the default agent. Restart the CLI to switch.`);
1331
- return;
1346
+ return {
1347
+ message: `${this.agentMenuLabel(profileName)} restored as the default agent. Restart the CLI to switch.`,
1348
+ tone: 'success',
1349
+ };
1332
1350
  }
1333
1351
  saveActiveProfilePreference(profileName);
1334
1352
  this.agentMenu.persistedProfile = profileName;
1335
- display.showInfo(`${this.agentMenuLabel(profileName)} will load the next time you start the CLI. Restart to switch now.`);
1353
+ return {
1354
+ message: `${this.agentMenuLabel(profileName)} will load the next time you start the CLI. Restart to switch now.`,
1355
+ tone: 'success',
1356
+ };
1336
1357
  }
1337
1358
  /**
1338
1359
  * Show plan approval UI with interactive step selection
@@ -1385,7 +1406,7 @@ export class InteractiveShell {
1385
1406
  lines.push(` ${theme.primary('cancel')} Cancel planning`);
1386
1407
  lines.push(` ${theme.primary('[text]')} Submit your own solution instead`);
1387
1408
  lines.push('');
1388
- display.showSystemMessage(lines.join('\n'));
1409
+ this.showInlinePanel(lines);
1389
1410
  this.syncRendererInput();
1390
1411
  }
1391
1412
  async handlePlanApprovalInput(input) {
@@ -1394,7 +1415,7 @@ export class InteractiveShell {
1394
1415
  return;
1395
1416
  const trimmed = input.trim();
1396
1417
  if (!trimmed) {
1397
- display.showWarning('Enter a command or your own solution.');
1418
+ this.appendInlineNotice('Enter a command or your own solution.', 'warning');
1398
1419
  this.syncRendererInput();
1399
1420
  return;
1400
1421
  }
@@ -1402,7 +1423,7 @@ export class InteractiveShell {
1402
1423
  // Cancel
1403
1424
  if (lower === 'cancel' || lower === 'c') {
1404
1425
  this.pendingInteraction = null;
1405
- display.showInfo('Plan cancelled. You can continue with a different approach.');
1426
+ this.showInlineStatus('Plan cancelled. You can continue with a different approach.', 'info', { autoClearMs: 1800 });
1406
1427
  this.syncRendererInput();
1407
1428
  return;
1408
1429
  }
@@ -1422,7 +1443,7 @@ export class InteractiveShell {
1422
1443
  if (lower === 'go' || lower === 'g' || lower === 'yes' || lower === 'y') {
1423
1444
  const selectedSteps = pending.steps.filter(s => pending.selectedSteps.has(s.id));
1424
1445
  if (selectedSteps.length === 0) {
1425
- display.showWarning('No steps selected. Select steps or enter your own solution.');
1446
+ this.appendInlineNotice('No steps selected. Select steps or enter your own solution.', 'warning');
1426
1447
  this.syncRendererInput();
1427
1448
  return;
1428
1449
  }
@@ -1449,13 +1470,13 @@ export class InteractiveShell {
1449
1470
  // User submitted their own solution - treat as custom input
1450
1471
  if (trimmed.length > 10) {
1451
1472
  this.pendingInteraction = null;
1452
- display.showInfo('Using your custom solution...');
1473
+ this.showInlineStatus('Using your custom solution...', 'info', { autoClearMs: 1400 });
1453
1474
  // Send the custom solution as the implementation request
1454
1475
  const customPrompt = `The user has provided their own solution instead of the plan. Please implement this:\n\n${trimmed}`;
1455
1476
  await this.enqueuePromptForProcessing(customPrompt, 'programmatic');
1456
1477
  return;
1457
1478
  }
1458
- display.showWarning('Invalid input. Enter a step number, command (go/cancel/all/none), or your own solution.');
1479
+ this.appendInlineNotice('Invalid input. Enter a step number, command (go/cancel/all/none), or your own solution.', 'warning');
1459
1480
  this.syncRendererInput();
1460
1481
  }
1461
1482
  async runWithCriticalApproval(label, detail, action) {
@@ -1501,7 +1522,7 @@ export class InteractiveShell {
1501
1522
  }
1502
1523
  lines.push('');
1503
1524
  lines.push('Type "yes" to proceed or "no" to cancel.');
1504
- display.showSystemMessage(lines.join('\n'));
1525
+ this.showInlinePanel(lines);
1505
1526
  this.syncRendererInput();
1506
1527
  }
1507
1528
  async handleCriticalApprovalInput(input) {
@@ -1511,23 +1532,25 @@ export class InteractiveShell {
1511
1532
  }
1512
1533
  const normalized = input.trim().toLowerCase();
1513
1534
  if (!normalized) {
1514
- display.showWarning('Enter "yes" to proceed or "no" to cancel.');
1535
+ this.appendInlineNotice('Enter "yes" to proceed or "no" to cancel.', 'warning');
1515
1536
  this.syncRendererInput();
1516
1537
  return;
1517
1538
  }
1518
1539
  if (normalized === 'yes' || normalized === 'y') {
1519
1540
  this.pendingInteraction = null;
1520
1541
  await pending.onApprove();
1542
+ this.showInlineStatus('Approved.', 'success', { autoClearMs: 1400 });
1521
1543
  this.syncRendererInput();
1522
1544
  return;
1523
1545
  }
1524
1546
  if (normalized === 'no' || normalized === 'n' || normalized === 'cancel' || normalized === 'c') {
1525
1547
  this.pendingInteraction = null;
1526
1548
  pending.onCancel?.();
1549
+ this.showInlineStatus('Action cancelled.', 'info', { autoClearMs: 1400 });
1527
1550
  this.syncRendererInput();
1528
1551
  return;
1529
1552
  }
1530
- display.showWarning('Please respond with "yes" to proceed or "no" to cancel.');
1553
+ this.appendInlineNotice('Please respond with "yes" to proceed or "no" to cancel.', 'warning');
1531
1554
  this.syncRendererInput();
1532
1555
  }
1533
1556
  setupHandlers() {
@@ -1635,6 +1658,28 @@ export class InteractiveShell {
1635
1658
  }
1636
1659
  describeStatusDetail(detail) {
1637
1660
  const parts = detail?.trim() ? [detail.trim()] : [];
1661
+ // Build/test health
1662
+ if (this.lastBuildStatus) {
1663
+ parts.push(this.lastBuildStatus === 'ok' ? 'build ok' : 'build failing');
1664
+ }
1665
+ if (this.lastTestStatus) {
1666
+ parts.push(this.lastTestStatus === 'ok' ? 'tests ok' : 'tests failing');
1667
+ }
1668
+ // Recent run metrics
1669
+ if (this.lastRunDurationSeconds !== null) {
1670
+ const durationLabel = this.formatElapsedTime(this.lastRunDurationSeconds);
1671
+ const toolsLabel = this.lastRunToolCount != null ? `${this.lastRunToolCount} tool${this.lastRunToolCount === 1 ? '' : 's'}` : '';
1672
+ parts.push(`last ${durationLabel}${toolsLabel ? ` · ${toolsLabel}` : ''}`);
1673
+ }
1674
+ // Dirty workspace indicator
1675
+ if (this.hasRecordedWrites()) {
1676
+ parts.push('writes dirty');
1677
+ }
1678
+ // Context headroom warning
1679
+ const ctxPercent = this.computeContextPercent();
1680
+ if (ctxPercent !== null && ctxPercent >= 85) {
1681
+ parts.push(`ctx ${ctxPercent}%`);
1682
+ }
1638
1683
  // Show queued prompts in the prompt inbox (Ctrl+Enter during streaming)
1639
1684
  const inboxDepth = this.promptInbox.length + (this.promptInFlight ? 1 : 0);
1640
1685
  if (inboxDepth > 0) {
@@ -1700,6 +1745,15 @@ export class InteractiveShell {
1700
1745
  const provider = this.providerLabel(this.sessionState.provider);
1701
1746
  return `${provider} · ${this.sessionState.model}`;
1702
1747
  }
1748
+ hasRecordedWrites() {
1749
+ return this._fileChangeTracker.getAllChanges().length > 0;
1750
+ }
1751
+ computeContextPercent() {
1752
+ if (!this.latestTokenUsage.used || !this.latestTokenUsage.limit || this.latestTokenUsage.limit <= 0) {
1753
+ return null;
1754
+ }
1755
+ return Math.min(100, Math.max(0, Math.round((this.latestTokenUsage.used / this.latestTokenUsage.limit) * 100)));
1756
+ }
1703
1757
  refreshContextGauge() {
1704
1758
  // First try to get context window from provider API (real value)
1705
1759
  // Fall back to static model mapping only if provider API is not available
@@ -1736,7 +1790,7 @@ export class InteractiveShell {
1736
1790
  // Ignore errors - keep using static mapping
1737
1791
  }
1738
1792
  }
1739
- updateContextUsage(percentage, autoCompactThreshold = CONTEXT_AUTOCOMPACT_PERCENT) {
1793
+ updateContextUsage(percentage, _autoCompactThreshold = CONTEXT_AUTOCOMPACT_PERCENT) {
1740
1794
  this.uiAdapter.updateContextUsage(percentage);
1741
1795
  this.terminalInput.setContextUsage(percentage);
1742
1796
  }
@@ -1756,7 +1810,7 @@ export class InteractiveShell {
1756
1810
  profile: this.profileLabel,
1757
1811
  workspace: workspaceDisplay,
1758
1812
  directory: workspaceDisplay,
1759
- writes: this.describeEditGuardMode(),
1813
+ writes: `${this.describeEditGuardMode()} · ${this.hasRecordedWrites() ? 'dirty' : 'clean'}`,
1760
1814
  sessionLabel: this.describeSessionLabel(),
1761
1815
  thinkingLabel: (this.thinkingMode || 'off').toString(),
1762
1816
  autosave: this.autosaveEnabled,
@@ -2510,7 +2564,7 @@ export class InteractiveShell {
2510
2564
  }
2511
2565
  switch (this.pendingInteraction.type) {
2512
2566
  case 'model-loading':
2513
- display.showInfo('Still fetching model options. Please wait a moment.');
2567
+ this.appendInlineNotice('Still fetching model options. Please wait a moment.', 'info');
2514
2568
  this.syncRendererInput();
2515
2569
  return true;
2516
2570
  case 'model-provider':
@@ -2544,7 +2598,7 @@ export class InteractiveShell {
2544
2598
  async processSlashCommand(input) {
2545
2599
  const [command] = input.split(/\s+/);
2546
2600
  if (!command) {
2547
- display.showWarning('Enter a slash command.');
2601
+ this.showSlashWarning('Enter a slash command.');
2548
2602
  this.syncRendererInput();
2549
2603
  return;
2550
2604
  }
@@ -2720,7 +2774,7 @@ export class InteractiveShell {
2720
2774
  break;
2721
2775
  default:
2722
2776
  if (!(await this.tryCustomSlashCommand(command, input))) {
2723
- display.showWarning(`Unknown command "${command}".`);
2777
+ this.showInlineStatus(`Unknown command "${command}".`, 'warning', { autoClearMs: 1800 });
2724
2778
  }
2725
2779
  break;
2726
2780
  }
@@ -2740,7 +2794,7 @@ export class InteractiveShell {
2740
2794
  }
2741
2795
  const args = fullInput.slice(command.length).trim();
2742
2796
  if (custom.requireInput && !args) {
2743
- display.showWarning(`${command} requires additional input.`);
2797
+ this.showSlashWarning(`${command} requires additional input.`);
2744
2798
  return true;
2745
2799
  }
2746
2800
  const prompt = buildCustomCommandPrompt(custom, args, {
@@ -2750,10 +2804,10 @@ export class InteractiveShell {
2750
2804
  model: this.sessionState.model,
2751
2805
  }).trim();
2752
2806
  if (!prompt) {
2753
- display.showWarning(`Custom command ${command} did not produce any text. Check ${custom.source} for errors.`);
2807
+ this.showSlashWarning(`Custom command ${command} did not produce any text. Check ${custom.source} for errors.`);
2754
2808
  return true;
2755
2809
  }
2756
- display.showInfo(`Running ${command} from ${custom.source}...`);
2810
+ this.showSlashInfo(`Running ${command} from ${custom.source}...`);
2757
2811
  await this.processRequest(prompt);
2758
2812
  return true;
2759
2813
  }
@@ -2832,7 +2886,7 @@ export class InteractiveShell {
2832
2886
  }
2833
2887
  async runRepoChecksCommand() {
2834
2888
  if (this.isProcessing) {
2835
- display.showWarning('Wait for the active response to finish before running checks.');
2889
+ this.showSlashWarning('Wait for the active response to finish before running checks.');
2836
2890
  return;
2837
2891
  }
2838
2892
  const call = {
@@ -2840,34 +2894,34 @@ export class InteractiveShell {
2840
2894
  name: 'run_repo_checks',
2841
2895
  arguments: {},
2842
2896
  };
2843
- display.showInfo('Running repo checks (npm test/build/lint when available)...');
2897
+ this.showSlashInfo('Running repo checks (npm test/build/lint when available)...');
2844
2898
  const output = await this.runtimeSession.toolRuntime.execute(call);
2845
2899
  display.showSystemMessage(output);
2846
2900
  }
2847
2901
  async refreshWorkspaceContextCommand(input) {
2848
2902
  if (this.isProcessing) {
2849
- display.showWarning('Wait for the active response to finish before refreshing the snapshot.');
2903
+ this.showSlashWarning('Wait for the active response to finish before refreshing the snapshot.');
2850
2904
  return;
2851
2905
  }
2852
2906
  const { overrides, error } = this.parseContextOverrideTokens(input);
2853
2907
  if (error) {
2854
- display.showWarning(`${error} ${this.describeContextOverrideUsage()}`);
2908
+ this.showSlashWarning(`${error} ${this.describeContextOverrideUsage()}`);
2855
2909
  return;
2856
2910
  }
2857
2911
  if (overrides) {
2858
2912
  this.workspaceOptions = { ...this.workspaceOptions, ...overrides };
2859
2913
  }
2860
- display.showInfo('Refreshing workspace snapshot...');
2914
+ this.showSlashInfo('Refreshing workspace snapshot...');
2861
2915
  const context = buildWorkspaceContext(this.workingDir, this.workspaceOptions);
2862
2916
  const profileConfig = this.runtimeSession.refreshWorkspaceContext(context);
2863
2917
  const tools = this.runtimeSession.toolRuntime.listProviderTools();
2864
2918
  this.baseSystemPrompt = buildInteractiveSystemPrompt(profileConfig.systemPrompt, profileConfig.label, tools);
2865
2919
  if (this.rebuildAgent()) {
2866
- display.showInfo(`Workspace snapshot refreshed (${this.describeWorkspaceOptions()}).`);
2920
+ this.showSlashInfo(`Workspace snapshot refreshed (${this.describeWorkspaceOptions()}).`);
2867
2921
  this.resetChatBoxAfterModelSwap();
2868
2922
  }
2869
2923
  else {
2870
- display.showWarning('Workspace snapshot refreshed, but the agent failed to rebuild. Run /doctor for details.');
2924
+ this.showSlashWarning('Workspace snapshot refreshed, but the agent failed to rebuild. Run /doctor for details.');
2871
2925
  }
2872
2926
  }
2873
2927
  parseContextOverrideTokens(input) {
@@ -2942,7 +2996,7 @@ export class InteractiveShell {
2942
2996
  this.clearAutosaveCommand();
2943
2997
  return;
2944
2998
  default:
2945
- display.showWarning('Usage: /sessions [list|save <title>|load <id>|delete <id>|new <title>|autosave on|off|clear]');
2999
+ this.showSlashWarning('Usage: /sessions [list|save <title>|load <id>|delete <id>|new <title>|autosave on|off|clear]');
2946
3000
  return;
2947
3001
  }
2948
3002
  }
@@ -2979,7 +3033,7 @@ export class InteractiveShell {
2979
3033
  case 'view': {
2980
3034
  const identifier = filtered.shift();
2981
3035
  if (!identifier) {
2982
- display.showWarning('Usage: /skills show <skill-id> [sections=metadata,body]');
3036
+ this.showSlashWarning('Usage: /skills show <skill-id> [sections=metadata,body]');
2983
3037
  return;
2984
3038
  }
2985
3039
  let sectionsArg;
@@ -3009,13 +3063,13 @@ export class InteractiveShell {
3009
3063
  break;
3010
3064
  }
3011
3065
  default:
3012
- display.showWarning('Usage: /skills [list|refresh|show <id> [sections=a,b]]');
3066
+ this.showSlashWarning('Usage: /skills [list|refresh|show <id> [sections=a,b]]');
3013
3067
  break;
3014
3068
  }
3015
3069
  }
3016
3070
  catch (error) {
3017
3071
  const message = error instanceof Error ? error.message : String(error);
3018
- display.showError(`Skill command failed: ${message}`);
3072
+ this.showInlineStatus(`Skill command failed: ${message}`, 'error');
3019
3073
  }
3020
3074
  }
3021
3075
  async invokeSkillTool(name, args) {
@@ -3029,16 +3083,15 @@ export class InteractiveShell {
3029
3083
  handleThinkingCommand(input) {
3030
3084
  const value = input.slice('/thinking'.length).trim().toLowerCase();
3031
3085
  if (!value) {
3032
- display.showInfo(`Thinking mode is currently ${theme.info(this.thinkingMode)}. Usage: /thinking [balanced|extended].` +
3033
- ' Press Tab any time to toggle.');
3086
+ this.showSlashInfo(`Thinking mode is currently ${theme.info(this.thinkingMode)}. Usage: /thinking [balanced|extended]. Press Tab any time to toggle.`);
3034
3087
  return;
3035
3088
  }
3036
3089
  if (value !== 'balanced' && value !== 'extended') {
3037
- display.showWarning('Usage: /thinking [balanced|extended]');
3090
+ this.showSlashWarning('Usage: /thinking [balanced|extended]');
3038
3091
  return;
3039
3092
  }
3040
3093
  if (this.isProcessing) {
3041
- display.showWarning('Wait until the current request finishes before changing thinking mode.');
3094
+ this.showSlashWarning('Wait until the current request finishes before changing thinking mode.');
3042
3095
  return;
3043
3096
  }
3044
3097
  this.thinkingMode = value;
@@ -3063,20 +3116,20 @@ export class InteractiveShell {
3063
3116
  .slice(1)
3064
3117
  .filter(Boolean);
3065
3118
  if (!paths.length) {
3066
- display.showInfo(`Usage: /attach <file> [...]. Text-only, max ${Math.round(MAX_ATTACHMENT_BYTES / 1024)}KB per file; large files are truncated.`);
3119
+ this.showSlashInfo(`Usage: /attach <file> [...]. Text-only, max ${Math.round(MAX_ATTACHMENT_BYTES / 1024)}KB per file; large files are truncated.`);
3067
3120
  return;
3068
3121
  }
3069
3122
  if (this.isProcessing) {
3070
- display.showWarning('Wait for the current request to finish before attaching files.');
3123
+ this.showSlashWarning('Wait for the current request to finish before attaching files.');
3071
3124
  return;
3072
3125
  }
3073
3126
  if (!this.agent && !this.rebuildAgent()) {
3074
- display.showWarning('Configure a provider via /secrets before attaching files.');
3127
+ this.showSlashWarning('Configure a provider via /secrets before attaching files.');
3075
3128
  return;
3076
3129
  }
3077
3130
  const agent = this.agent;
3078
3131
  if (!agent) {
3079
- display.showWarning('No active agent is available. Try again in a moment.');
3132
+ this.showSlashWarning('No active agent is available. Try again in a moment.');
3080
3133
  return;
3081
3134
  }
3082
3135
  const history = agent.getHistory();
@@ -3084,7 +3137,7 @@ export class InteractiveShell {
3084
3137
  for (const rawPath of paths) {
3085
3138
  const filePath = resolve(this.workingDir, rawPath);
3086
3139
  if (!existsSync(filePath)) {
3087
- display.showWarning(`File not found: ${rawPath}`);
3140
+ this.showSlashWarning(`File not found: ${rawPath}`);
3088
3141
  continue;
3089
3142
  }
3090
3143
  let stats;
@@ -3092,15 +3145,15 @@ export class InteractiveShell {
3092
3145
  stats = statSync(filePath);
3093
3146
  }
3094
3147
  catch (error) {
3095
- display.showWarning(`Unable to read file: ${rawPath} (${error instanceof Error ? error.message : 'unknown error'})`);
3148
+ this.showSlashWarning(`Unable to read file: ${rawPath} (${error instanceof Error ? error.message : 'unknown error'})`);
3096
3149
  continue;
3097
3150
  }
3098
3151
  if (!stats.isFile()) {
3099
- display.showWarning(`Not a file: ${rawPath}`);
3152
+ this.showSlashWarning(`Not a file: ${rawPath}`);
3100
3153
  continue;
3101
3154
  }
3102
3155
  if (stats.size > MAX_ATTACHMENT_BYTES) {
3103
- display.showWarning(`Skipped ${rawPath} (${Math.round(stats.size / 1024)}KB) — limit is ${Math.round(MAX_ATTACHMENT_BYTES / 1024)}KB.`);
3156
+ this.showSlashWarning(`Skipped ${rawPath} (${Math.round(stats.size / 1024)}KB) — limit is ${Math.round(MAX_ATTACHMENT_BYTES / 1024)}KB.`);
3104
3157
  continue;
3105
3158
  }
3106
3159
  let buffer;
@@ -3108,11 +3161,11 @@ export class InteractiveShell {
3108
3161
  buffer = readFileSync(filePath);
3109
3162
  }
3110
3163
  catch (error) {
3111
- display.showWarning(`Failed to read ${rawPath}: ${error instanceof Error ? error.message : String(error)}`);
3164
+ this.showSlashWarning(`Failed to read ${rawPath}: ${error instanceof Error ? error.message : String(error)}`);
3112
3165
  continue;
3113
3166
  }
3114
3167
  if (this.isBinaryBuffer(buffer)) {
3115
- display.showWarning(`Skipped ${rawPath} — binary files are not attached.`);
3168
+ this.showSlashWarning(`Skipped ${rawPath} — binary files are not attached.`);
3116
3169
  continue;
3117
3170
  }
3118
3171
  let content = buffer.toString('utf-8');
@@ -3135,7 +3188,7 @@ export class InteractiveShell {
3135
3188
  attachedSummaries.push(`${displayPath} (${kb}KB${truncated ? ', truncated' : ''})`);
3136
3189
  }
3137
3190
  if (!attachedSummaries.length) {
3138
- display.showWarning('No attachments were added. Ensure files exist, are under the size limit, and are text.');
3191
+ this.showSlashWarning('No attachments were added. Ensure files exist, are under the size limit, and are text.');
3139
3192
  return;
3140
3193
  }
3141
3194
  agent.loadHistory(history);
@@ -3162,7 +3215,7 @@ export class InteractiveShell {
3162
3215
  const summary = this._fileChangeTracker.getSummary();
3163
3216
  const changes = this._fileChangeTracker.getAllChanges();
3164
3217
  if (changes.length === 0) {
3165
- display.showInfo('No files modified in this session.');
3218
+ this.showSlashInfo('No files modified in this session.');
3166
3219
  return;
3167
3220
  }
3168
3221
  const lines = [];
@@ -3206,7 +3259,7 @@ export class InteractiveShell {
3206
3259
  showImprovementSuggestions() {
3207
3260
  const suggestions = this.alphaZeroMetrics.getImprovementSuggestions();
3208
3261
  if (suggestions.length === 0) {
3209
- display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
3262
+ this.showSlashInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
3210
3263
  return;
3211
3264
  }
3212
3265
  const lines = [
@@ -3240,8 +3293,8 @@ export class InteractiveShell {
3240
3293
  const newValue = args[1] === 'on' ? true : args[1] === 'off' ? false : undefined;
3241
3294
  const updated = toggleFeatureFlag(matchedKey, newValue);
3242
3295
  const status = updated[matchedKey] ? theme.success('enabled') : theme.ui.muted('disabled');
3243
- display.showInfo(`Feature "${FEATURE_FLAG_INFO[matchedKey].label}" is now ${status}.`);
3244
- display.showInfo('Changes will take effect on next launch or after /features refresh.');
3296
+ this.showSlashInfo(`Feature "${FEATURE_FLAG_INFO[matchedKey].label}" is now ${status}.`);
3297
+ this.showSlashInfo('Changes will take effect on next launch or after /features refresh.');
3245
3298
  return;
3246
3299
  }
3247
3300
  else if (featureName === 'all') {
@@ -3252,11 +3305,11 @@ export class InteractiveShell {
3252
3305
  updated[key] = newValue;
3253
3306
  }
3254
3307
  saveFeatureFlags(updated);
3255
- display.showInfo(`All features ${newValue ? theme.success('enabled') : theme.ui.muted('disabled')}.`);
3308
+ this.showSlashInfo(`All features ${newValue ? theme.success('enabled') : theme.ui.muted('disabled')}.`);
3256
3309
  return;
3257
3310
  }
3258
3311
  else {
3259
- display.showWarning(`Unknown feature: ${featureName}`);
3312
+ this.showSlashWarning(`Unknown feature: ${featureName}`);
3260
3313
  }
3261
3314
  }
3262
3315
  // Show features menu
@@ -3294,10 +3347,10 @@ export class InteractiveShell {
3294
3347
  if (subcommand === 'commit') {
3295
3348
  const result = commitLearning(args.slice(1).join(' ') || 'Manual learning checkpoint', this.workingDir);
3296
3349
  if (result.success) {
3297
- display.showInfo(`Learning committed: ${result.commitHash}`);
3350
+ this.showSlashInfo(`Learning committed: ${result.commitHash}`);
3298
3351
  }
3299
3352
  else {
3300
- display.showWarning(`Could not commit: ${result.error}`);
3353
+ this.showSlashWarning(`Could not commit: ${result.error}`);
3301
3354
  }
3302
3355
  return;
3303
3356
  }
@@ -3892,7 +3945,7 @@ export class InteractiveShell {
3892
3945
  if (subcommand === 'generate') {
3893
3946
  const targetPath = args[1];
3894
3947
  if (!targetPath) {
3895
- display.showWarning('Usage: /test generate <file-path>');
3948
+ this.showSlashWarning('Usage: /test generate <file-path>');
3896
3949
  return;
3897
3950
  }
3898
3951
  display.showSystemMessage(theme.gradient.primary(`🧪 Generating Test Flows for ${targetPath}...`));
@@ -4076,12 +4129,12 @@ export class InteractiveShell {
4076
4129
  async saveSessionCommand(title) {
4077
4130
  const agent = this.agent;
4078
4131
  if (!agent) {
4079
- display.showWarning('Start a conversation before saving a session.');
4132
+ this.showSlashWarning('Start a conversation before saving a session.');
4080
4133
  return;
4081
4134
  }
4082
4135
  const history = agent.getHistory();
4083
4136
  if (!history || history.length <= 1) {
4084
- display.showWarning('You need at least one user message before saving a session.');
4137
+ this.showSlashWarning('You need at least one user message before saving a session.');
4085
4138
  return;
4086
4139
  }
4087
4140
  const summary = saveSessionSnapshot({
@@ -4098,17 +4151,17 @@ export class InteractiveShell {
4098
4151
  this.updateActiveSession(summary, true);
4099
4152
  this.sessionResumeNotice = null;
4100
4153
  this.autosaveIfEnabled();
4101
- display.showInfo(`Session saved as "${summary.title}" (id ${this.formatSessionId(summary.id)}).`);
4154
+ this.showSlashInfo(`Session saved as "${summary.title}" (id ${this.formatSessionId(summary.id)}).`);
4102
4155
  }
4103
4156
  async loadSessionCommand(selector) {
4104
4157
  const summary = this.resolveSessionBySelector(selector);
4105
4158
  if (!summary) {
4106
- display.showWarning('No session matches that selection.');
4159
+ this.showSlashWarning('No session matches that selection.');
4107
4160
  return;
4108
4161
  }
4109
4162
  const stored = loadSessionById(summary.id);
4110
4163
  if (!stored) {
4111
- display.showWarning('Failed to load that session. It may have been corrupted or deleted.');
4164
+ this.showSlashWarning('Failed to load that session. It may have been corrupted or deleted.');
4112
4165
  return;
4113
4166
  }
4114
4167
  this.cachedHistory = stored.messages;
@@ -4117,28 +4170,28 @@ export class InteractiveShell {
4117
4170
  if (this.agent) {
4118
4171
  this.agent.loadHistory(stored.messages);
4119
4172
  this.sessionResumeNotice = null;
4120
- display.showInfo(`Loaded session "${summary.title}".`);
4173
+ this.showSlashInfo(`Loaded session "${summary.title}".`);
4121
4174
  this.refreshContextGauge();
4122
4175
  this.captureHistorySnapshot();
4123
4176
  this.pendingHistoryLoad = null;
4124
4177
  }
4125
4178
  else {
4126
4179
  this.pendingHistoryLoad = stored.messages;
4127
- display.showInfo(`Session "${summary.title}" queued to load once the agent is ready.`);
4180
+ this.showSlashInfo(`Session "${summary.title}" queued to load once the agent is ready.`);
4128
4181
  }
4129
4182
  this.autosaveIfEnabled();
4130
4183
  }
4131
4184
  deleteSessionCommand(selector) {
4132
4185
  const summary = this.resolveSessionBySelector(selector);
4133
4186
  if (!summary) {
4134
- display.showWarning('No session matches that selection.');
4187
+ this.showSlashWarning('No session matches that selection.');
4135
4188
  return;
4136
4189
  }
4137
4190
  if (!deleteSession(summary.id)) {
4138
- display.showWarning('Unable to delete that session.');
4191
+ this.showSlashWarning('Unable to delete that session.');
4139
4192
  return;
4140
4193
  }
4141
- display.showInfo(`Deleted session "${summary.title}".`);
4194
+ this.showSlashInfo(`Deleted session "${summary.title}".`);
4142
4195
  if (this.activeSessionId === summary.id) {
4143
4196
  this.activeSessionId = null;
4144
4197
  this.activeSessionTitle = null;
@@ -4160,22 +4213,22 @@ export class InteractiveShell {
4160
4213
  this.sessionResumeNotice = null;
4161
4214
  saveSessionPreferences({ lastSessionId: null });
4162
4215
  clearAutosaveSnapshot(this.profile);
4163
- display.showInfo('Started a new empty session.');
4216
+ this.showSlashInfo('Started a new empty session.');
4164
4217
  this.refreshContextGauge();
4165
4218
  }
4166
4219
  toggleAutosaveCommand(value) {
4167
4220
  if (!value) {
4168
- display.showWarning('Usage: /sessions autosave on|off');
4221
+ this.showSlashWarning('Usage: /sessions autosave on|off');
4169
4222
  return;
4170
4223
  }
4171
4224
  const normalized = value.toLowerCase();
4172
4225
  if (normalized !== 'on' && normalized !== 'off') {
4173
- display.showWarning('Usage: /sessions autosave on|off');
4226
+ this.showSlashWarning('Usage: /sessions autosave on|off');
4174
4227
  return;
4175
4228
  }
4176
4229
  this.autosaveEnabled = normalized === 'on';
4177
4230
  saveSessionPreferences({ autosave: this.autosaveEnabled });
4178
- display.showInfo(`Autosave ${this.autosaveEnabled ? 'enabled' : 'disabled'}.`);
4231
+ this.showSlashInfo(`Autosave ${this.autosaveEnabled ? 'enabled' : 'disabled'}.`);
4179
4232
  if (!this.autosaveEnabled) {
4180
4233
  clearAutosaveSnapshot(this.profile);
4181
4234
  }
@@ -4186,7 +4239,7 @@ export class InteractiveShell {
4186
4239
  }
4187
4240
  clearAutosaveCommand() {
4188
4241
  clearAutosaveSnapshot(this.profile);
4189
- display.showInfo('Cleared autosave history.');
4242
+ this.showSlashInfo('Cleared autosave history.');
4190
4243
  }
4191
4244
  // ==================== Erosolar-CLI Style Commands ====================
4192
4245
  async handleRewindCommand(_input) {
@@ -4314,7 +4367,7 @@ export class InteractiveShell {
4314
4367
  }
4315
4368
  showCompactionHistory() {
4316
4369
  if (!this.contextCompactionLog.length) {
4317
- display.showInfo('No context compactions recorded yet.');
4370
+ this.showSlashInfo('No context compactions recorded yet.');
4318
4371
  return;
4319
4372
  }
4320
4373
  const entries = [...this.contextCompactionLog].slice(-10).reverse();
@@ -4346,7 +4399,7 @@ export class InteractiveShell {
4346
4399
  }
4347
4400
  display.clear();
4348
4401
  clearAutosaveSnapshot(this.profile);
4349
- display.showInfo('Conversation cleared. Starting fresh.');
4402
+ this.showSlashInfo('Conversation cleared. Starting fresh.');
4350
4403
  this.syncRendererInput();
4351
4404
  }
4352
4405
  async handleDiffCommand() {
@@ -4354,7 +4407,7 @@ export class InteractiveShell {
4354
4407
  await execAsync('git rev-parse --is-inside-work-tree', { cwd: this.workingDir });
4355
4408
  }
4356
4409
  catch {
4357
- display.showWarning('Not a git repository. No diff to show.');
4410
+ this.showSlashWarning('Not a git repository. No diff to show.');
4358
4411
  return;
4359
4412
  }
4360
4413
  const cachedResults = [];
@@ -4394,7 +4447,7 @@ export class InteractiveShell {
4394
4447
  // ignore diff errors
4395
4448
  }
4396
4449
  if (results.length === 0 && cachedResults.length === 0) {
4397
- display.showInfo('No changes detected. Working tree is clean.');
4450
+ this.showSlashInfo('No changes detected. Working tree is clean.');
4398
4451
  return;
4399
4452
  }
4400
4453
  display.showSystemMessage([...cachedResults, ...results].join('\n'));
@@ -4452,11 +4505,11 @@ export class InteractiveShell {
4452
4505
  // Show session list and auto-select the most recent
4453
4506
  const sessions = listSessions(this.profile);
4454
4507
  if (sessions.length > 0) {
4455
- display.showInfo('Resuming most recent session...');
4508
+ this.showSlashInfo('Resuming most recent session...');
4456
4509
  await this.loadSessionCommand('1');
4457
4510
  }
4458
4511
  else {
4459
- display.showWarning('No previous sessions found. Use /sessions to manage sessions.');
4512
+ this.showSlashWarning('No previous sessions found. Use /sessions to manage sessions.');
4460
4513
  }
4461
4514
  }
4462
4515
  }
@@ -4475,18 +4528,18 @@ export class InteractiveShell {
4475
4528
  }
4476
4529
  async handleReviewCommand() {
4477
4530
  if (this.isProcessing) {
4478
- display.showWarning('Wait for the current operation to finish.');
4531
+ this.showSlashWarning('Wait for the current operation to finish.');
4479
4532
  return;
4480
4533
  }
4481
- display.showInfo('Triggering code review of pending changes...');
4534
+ this.showSlashInfo('Triggering code review of pending changes...');
4482
4535
  await this.processRequest('Please review all the code changes we made in this session. Look for bugs, security issues, and improvements.');
4483
4536
  }
4484
4537
  async handleSecurityReviewCommand() {
4485
4538
  if (this.isProcessing) {
4486
- display.showWarning('Wait for the current operation to finish.');
4539
+ this.showSlashWarning('Wait for the current operation to finish.');
4487
4540
  return;
4488
4541
  }
4489
- display.showInfo('Running comprehensive security review...');
4542
+ this.showSlashInfo('Running comprehensive security review...');
4490
4543
  await this.processRequest('Please perform a comprehensive security review of the codebase. Check for OWASP top 10 vulnerabilities, insecure patterns, and potential attack vectors.');
4491
4544
  }
4492
4545
  handleBugCommand() {
@@ -4552,7 +4605,7 @@ export class InteractiveShell {
4552
4605
  this.setCriticalApprovalMode('approval', 'command');
4553
4606
  return;
4554
4607
  }
4555
- display.showWarning('Usage: /approvals [auto|ask|status]');
4608
+ this.showSlashWarning('Usage: /approvals [auto|ask|status]');
4556
4609
  }
4557
4610
  handlePermissionsCommand() {
4558
4611
  const lines = [];
@@ -4602,38 +4655,39 @@ export class InteractiveShell {
4602
4655
  const currentVersion = this.version || this.getPackageInfo().version || '1.7.458';
4603
4656
  const updateInfo = await checkForUpdates(currentVersion);
4604
4657
  if (!updateInfo) {
4605
- display.showWarning('Unable to check for updates (network issue or timeout).');
4658
+ this.showSlashWarning('Unable to check for updates (network issue or timeout).');
4606
4659
  return;
4607
4660
  }
4608
4661
  if (!updateInfo.updateAvailable) {
4609
- display.showSuccess(`You're on the latest version (v${updateInfo.current}).`);
4662
+ this.showSlashSuccess(`You're on the latest version (v${updateInfo.current}).`);
4610
4663
  return;
4611
4664
  }
4612
4665
  // Show update info and perform update immediately (no interactive prompt)
4613
- display.showInfo(`Update available: v${updateInfo.current} → v${updateInfo.latest}`);
4666
+ this.showSlashInfo(`Update available: v${updateInfo.current} → v${updateInfo.latest}`);
4614
4667
  await performUpdate(updateInfo, (msg) => this.streamEventBlock(msg));
4615
4668
  }
4616
4669
  catch (error) {
4617
- display.showError(`Update check failed: ${error instanceof Error ? error.message : String(error)}`);
4670
+ const detail = error instanceof Error ? error.message : String(error);
4671
+ this.showInlineStatus(`Update check failed: ${detail}`, 'error');
4618
4672
  }
4619
4673
  return;
4620
4674
  }
4621
4675
  if (subcommand === 'auto' || subcommand === 'always') {
4622
4676
  saveSessionPreferences({ autoUpdate: true });
4623
- display.showSuccess('Auto-update enabled. Updates will install automatically.');
4677
+ this.showSlashSuccess('Auto-update enabled. Updates will install automatically.');
4624
4678
  return;
4625
4679
  }
4626
4680
  if (subcommand === 'skip' || subcommand === 'never' || subcommand === 'off') {
4627
4681
  saveSessionPreferences({ autoUpdate: false });
4628
- display.showInfo('Auto-update disabled. Updates will be skipped silently.');
4682
+ this.showSlashInfo('Auto-update disabled. Updates will be skipped silently.');
4629
4683
  return;
4630
4684
  }
4631
4685
  if (subcommand === 'ask' || subcommand === 'prompt' || subcommand === 'reset' || subcommand === 'notify') {
4632
4686
  saveSessionPreferences({ autoUpdate: null });
4633
- display.showInfo('Update preference reset. You will see a notification when updates are available.');
4687
+ this.showSlashInfo('Update preference reset. You will see a notification when updates are available.');
4634
4688
  return;
4635
4689
  }
4636
- display.showWarning('Usage: /update [check|auto|skip|notify|status]');
4690
+ this.showSlashWarning('Usage: /update [check|auto|skip|notify|status]');
4637
4691
  }
4638
4692
  handleInitCommand(input) {
4639
4693
  const tokens = input.split(/\s+/).slice(1);
@@ -4641,7 +4695,7 @@ export class InteractiveShell {
4641
4695
  const target = join(this.workingDir, 'AGENTS.md');
4642
4696
  if (confirm) {
4643
4697
  if (existsSync(target)) {
4644
- display.showWarning(`AGENTS.md already exists at ${target}.`);
4698
+ this.showSlashWarning(`AGENTS.md already exists at ${target}.`);
4645
4699
  return;
4646
4700
  }
4647
4701
  const template = [
@@ -4668,11 +4722,11 @@ export class InteractiveShell {
4668
4722
  ].join('\n');
4669
4723
  try {
4670
4724
  writeFileSync(target, `${template}\n`, { flag: 'wx' });
4671
- display.showInfo(`Created ${target}. Update it with project-specific guidance for Codex.`);
4725
+ this.showSlashSuccess(`Created ${target}. Update it with project-specific guidance for Codex.`);
4672
4726
  }
4673
4727
  catch (error) {
4674
4728
  const message = error instanceof Error ? error.message : String(error);
4675
- display.showError(`Failed to create AGENTS.md: ${message}`);
4729
+ this.showInlineStatus(`Failed to create AGENTS.md: ${message}`, 'error');
4676
4730
  }
4677
4731
  return;
4678
4732
  }
@@ -4695,10 +4749,10 @@ export class InteractiveShell {
4695
4749
  }
4696
4750
  async handleCompactCommand() {
4697
4751
  if (this.isProcessing) {
4698
- display.showWarning('Wait for the current operation to finish.');
4752
+ this.showSlashWarning('Wait for the current operation to finish.');
4699
4753
  return;
4700
4754
  }
4701
- display.showInfo('Compacting conversation context...');
4755
+ this.showSlashInfo('Compacting conversation context...');
4702
4756
  await this.performContextCompaction('Manual /compact request');
4703
4757
  }
4704
4758
  // ==================== End Erosolar-CLI Style Commands ====================
@@ -4859,9 +4913,136 @@ export class InteractiveShell {
4859
4913
  return `${shown.join(', ')}${suffix}`;
4860
4914
  }
4861
4915
  showInlinePanel(lines) {
4916
+ const normalized = (lines ?? [])
4917
+ .map(line => line.replace(/\s+$/g, ''))
4918
+ .filter(line => line.trim().length > 0);
4919
+ // Reset any pending auto-clear timer whenever we render a fresh panel
4920
+ if (this.inlinePanelClearTimer) {
4921
+ clearTimeout(this.inlinePanelClearTimer);
4922
+ this.inlinePanelClearTimer = null;
4923
+ }
4924
+ this.inlinePanelBase = normalized;
4925
+ this.inlinePanelNotices = [];
4926
+ this.flushInlinePanel();
4927
+ }
4928
+ appendInlineNotice(message, tone = 'info') {
4929
+ const normalized = message.trim();
4930
+ if (!normalized)
4931
+ return;
4932
+ this.inlinePanelNotices.push({ text: normalized, tone });
4933
+ // Keep the most recent notices to prevent runaway growth
4934
+ const MAX_NOTICES = 3;
4935
+ if (this.inlinePanelNotices.length > MAX_NOTICES) {
4936
+ this.inlinePanelNotices = this.inlinePanelNotices.slice(-MAX_NOTICES);
4937
+ }
4938
+ this.flushInlinePanel();
4939
+ }
4940
+ showInlineStatus(message, tone = 'info', options) {
4941
+ const normalized = message.trim();
4942
+ if (!normalized) {
4943
+ this.clearInlinePanel();
4944
+ return;
4945
+ }
4946
+ if (this.inlinePanelClearTimer) {
4947
+ clearTimeout(this.inlinePanelClearTimer);
4948
+ this.inlinePanelClearTimer = null;
4949
+ }
4950
+ this.inlinePanelBase = [];
4951
+ this.inlinePanelNotices = [{ text: normalized, tone }];
4952
+ this.flushInlinePanel();
4953
+ if (options?.autoClearMs && options.autoClearMs > 0) {
4954
+ this.inlinePanelClearTimer = setTimeout(() => {
4955
+ this.clearInlinePanel();
4956
+ }, options.autoClearMs);
4957
+ }
4958
+ }
4959
+ flushInlinePanel() {
4960
+ if (!this.inlinePanelBase.length && !this.inlinePanelNotices.length) {
4961
+ display.clearInlinePanel();
4962
+ return;
4963
+ }
4964
+ const lines = [...this.inlinePanelBase];
4965
+ if (this.inlinePanelNotices.length) {
4966
+ if (lines.length) {
4967
+ lines.push('');
4968
+ }
4969
+ for (const notice of this.inlinePanelNotices) {
4970
+ lines.push(this.formatInlineNotice(notice));
4971
+ }
4972
+ }
4862
4973
  display.showInlinePanel(lines);
4863
4974
  }
4975
+ formatInlineNotice(notice) {
4976
+ const prefix = (() => {
4977
+ switch (notice.tone) {
4978
+ case 'success':
4979
+ return theme.success('✓');
4980
+ case 'warning':
4981
+ return theme.warning('!');
4982
+ case 'error':
4983
+ return theme.error('✖');
4984
+ case 'info':
4985
+ default:
4986
+ return theme.info('ℹ');
4987
+ }
4988
+ })();
4989
+ return `${prefix} ${notice.text}`;
4990
+ }
4991
+ showSlashWarning(message) {
4992
+ const normalized = message.trim();
4993
+ if (!normalized)
4994
+ return;
4995
+ if (this.inlineCommandActive || this.pendingInteraction) {
4996
+ if (this.inlinePanelBase.length) {
4997
+ this.appendInlineNotice(normalized, 'warning');
4998
+ }
4999
+ else {
5000
+ this.showInlineStatus(normalized, 'warning', { autoClearMs: 1800 });
5001
+ }
5002
+ this.syncRendererInput();
5003
+ return;
5004
+ }
5005
+ display.showWarning(normalized);
5006
+ }
5007
+ showSlashInfo(message) {
5008
+ const normalized = message.trim();
5009
+ if (!normalized)
5010
+ return;
5011
+ if (this.inlineCommandActive || this.pendingInteraction) {
5012
+ if (this.inlinePanelBase.length) {
5013
+ this.appendInlineNotice(normalized, 'info');
5014
+ }
5015
+ else {
5016
+ this.showInlineStatus(normalized, 'info', { autoClearMs: 1600 });
5017
+ }
5018
+ this.syncRendererInput();
5019
+ return;
5020
+ }
5021
+ display.showInfo(normalized);
5022
+ }
5023
+ showSlashSuccess(message) {
5024
+ const normalized = message.trim();
5025
+ if (!normalized)
5026
+ return;
5027
+ if (this.inlineCommandActive || this.pendingInteraction) {
5028
+ if (this.inlinePanelBase.length) {
5029
+ this.appendInlineNotice(normalized, 'success');
5030
+ }
5031
+ else {
5032
+ this.showInlineStatus(normalized, 'success', { autoClearMs: 1600 });
5033
+ }
5034
+ this.syncRendererInput();
5035
+ return;
5036
+ }
5037
+ display.showSuccess(normalized);
5038
+ }
4864
5039
  clearInlinePanel() {
5040
+ if (this.inlinePanelClearTimer) {
5041
+ clearTimeout(this.inlinePanelClearTimer);
5042
+ this.inlinePanelClearTimer = null;
5043
+ }
5044
+ this.inlinePanelBase = [];
5045
+ this.inlinePanelNotices = [];
4865
5046
  display.clearInlinePanel();
4866
5047
  }
4867
5048
  shouldCaptureInlinePanel() {
@@ -4884,9 +5065,8 @@ export class InteractiveShell {
4884
5065
  const providerStatuses = await quickCheckProviders();
4885
5066
  const providerOptions = this.buildProviderOptionsWithDiscovery(providerStatuses);
4886
5067
  if (!providerOptions.length) {
4887
- display.showWarning('No providers are available.');
4888
5068
  this.pendingInteraction = null;
4889
- this.clearInlinePanel();
5069
+ this.showInlineStatus('No providers are available.', 'warning');
4890
5070
  this.syncRendererInput();
4891
5071
  return;
4892
5072
  }
@@ -4906,9 +5086,8 @@ export class InteractiveShell {
4906
5086
  this.pendingInteraction = { type: 'model-provider', options: providerOptions };
4907
5087
  }
4908
5088
  catch (error) {
4909
- display.showError('Failed to load model list. Try again in a moment.', error);
4910
5089
  this.pendingInteraction = null;
4911
- this.clearInlinePanel();
5090
+ this.showInlineStatus('Failed to load model list. Try again in a moment.', 'error');
4912
5091
  this.syncRendererInput();
4913
5092
  }
4914
5093
  }
@@ -5039,9 +5218,8 @@ export class InteractiveShell {
5039
5218
  }
5040
5219
  }
5041
5220
  if (!allModels.length) {
5042
- display.showWarning(`No models available for ${option.label}.`);
5043
5221
  this.pendingInteraction = null;
5044
- this.clearInlinePanel();
5222
+ this.showInlineStatus(`No models available for ${option.label}.`, 'warning');
5045
5223
  return;
5046
5224
  }
5047
5225
  const lines = [
@@ -5079,7 +5257,7 @@ export class InteractiveShell {
5079
5257
  showToolsMenu() {
5080
5258
  const options = getToolToggleOptions();
5081
5259
  if (!options.length) {
5082
- display.showWarning('No configurable tools are available.');
5260
+ this.showInlineStatus('No configurable tools are available.', 'warning', { autoClearMs: 1600 });
5083
5261
  return;
5084
5262
  }
5085
5263
  const selection = buildEnabledToolSet(loadToolSettings(), this.profile);
@@ -5422,7 +5600,7 @@ export class InteractiveShell {
5422
5600
  }
5423
5601
  showAgentsMenu() {
5424
5602
  if (!this.agentMenu) {
5425
- display.showWarning('Agent selection is not available in this CLI.');
5603
+ this.showSlashWarning('Agent selection is not available in this CLI.');
5426
5604
  return;
5427
5605
  }
5428
5606
  const lines = [
@@ -5464,27 +5642,26 @@ export class InteractiveShell {
5464
5642
  }
5465
5643
  const trimmed = input.trim();
5466
5644
  if (!trimmed) {
5467
- display.showWarning('Enter a number or type cancel.');
5645
+ this.appendInlineNotice('Enter a number or type cancel.', 'warning');
5468
5646
  this.syncRendererInput();
5469
5647
  return;
5470
5648
  }
5471
5649
  if (trimmed.toLowerCase() === 'cancel') {
5472
5650
  this.pendingInteraction = null;
5473
- display.showInfo('Model selection cancelled.');
5474
- this.clearInlinePanel();
5651
+ this.showInlineStatus('Model selection cancelled.', 'info', { autoClearMs: 1400 });
5475
5652
  this.syncRendererInput();
5476
5653
  return;
5477
5654
  }
5478
5655
  const choice = Number.parseInt(trimmed, 10);
5479
5656
  const optionCount = pending.options.length;
5480
5657
  if (!Number.isFinite(choice) || choice < 1 || choice > optionCount) {
5481
- display.showWarning(`Enter a number between 1 and ${optionCount}.`);
5658
+ this.appendInlineNotice(`Enter a number between 1 and ${optionCount}.`, 'warning');
5482
5659
  this.syncRendererInput();
5483
5660
  return;
5484
5661
  }
5485
5662
  const option = pending.options[choice - 1];
5486
5663
  if (!option) {
5487
- display.showWarning(`Enter a number between 1 and ${optionCount}.`);
5664
+ this.appendInlineNotice(`Enter a number between 1 and ${optionCount}.`, 'warning');
5488
5665
  this.syncRendererInput();
5489
5666
  return;
5490
5667
  }
@@ -5499,7 +5676,7 @@ export class InteractiveShell {
5499
5676
  const trimmed = input.trim();
5500
5677
  const optionCount = pending.options.length;
5501
5678
  if (!trimmed) {
5502
- display.showWarning(`Enter 1-${optionCount}, "back", or "cancel".`);
5679
+ this.appendInlineNotice(`Enter 1-${optionCount}, "back", or "cancel".`, 'warning');
5503
5680
  this.syncRendererInput();
5504
5681
  return;
5505
5682
  }
@@ -5510,20 +5687,19 @@ export class InteractiveShell {
5510
5687
  }
5511
5688
  if (trimmed.toLowerCase() === 'cancel') {
5512
5689
  this.pendingInteraction = null;
5513
- display.showInfo('Model selection cancelled.');
5514
- this.clearInlinePanel();
5690
+ this.showInlineStatus('Model selection cancelled.', 'info', { autoClearMs: 1400 });
5515
5691
  this.syncRendererInput();
5516
5692
  return;
5517
5693
  }
5518
5694
  const choice = Number.parseInt(trimmed, 10);
5519
5695
  if (!Number.isFinite(choice) || choice < 1 || choice > optionCount) {
5520
- display.showWarning(`Enter 1-${optionCount}, "back", or "cancel".`);
5696
+ this.appendInlineNotice(`Enter 1-${optionCount}, "back", or "cancel".`, 'warning');
5521
5697
  this.syncRendererInput();
5522
5698
  return;
5523
5699
  }
5524
5700
  const preset = pending.options[choice - 1];
5525
5701
  if (!preset) {
5526
- display.showWarning(`Enter 1-${optionCount}, "back", or "cancel".`);
5702
+ this.appendInlineNotice(`Enter 1-${optionCount}, "back", or "cancel".`, 'warning');
5527
5703
  this.syncRendererInput();
5528
5704
  return;
5529
5705
  }
@@ -5547,13 +5723,16 @@ export class InteractiveShell {
5547
5723
  reasoningEffort: preset.reasoningEffort,
5548
5724
  };
5549
5725
  this.applyPresetReasoningDefaults();
5550
- if (this.rebuildAgent()) {
5551
- display.showInfo(`Switched to ${preset.label}.`);
5726
+ const rebuilt = this.rebuildAgent();
5727
+ if (rebuilt) {
5552
5728
  this.refreshSessionContext();
5553
5729
  this.persistSessionPreference();
5554
5730
  this.resetChatBoxAfterModelSwap();
5731
+ this.showInlineStatus(`Switched to ${preset.label}.`, 'success', { autoClearMs: 1600 });
5732
+ }
5733
+ else {
5734
+ this.showInlineStatus(`Failed to switch to ${preset.label}. Run /doctor for details.`, 'warning');
5555
5735
  }
5556
- this.clearInlinePanel();
5557
5736
  }
5558
5737
  async handleSecretSelection(input) {
5559
5738
  const pending = this.pendingInteraction;
@@ -5563,26 +5742,25 @@ export class InteractiveShell {
5563
5742
  const trimmed = input.trim();
5564
5743
  const optionCount = pending.options.length;
5565
5744
  if (!trimmed) {
5566
- display.showWarning(`Enter 1-${optionCount} or "cancel".`);
5745
+ this.appendInlineNotice(`Enter 1-${optionCount} or "cancel".`, 'warning');
5567
5746
  this.syncRendererInput();
5568
5747
  return;
5569
5748
  }
5570
5749
  if (trimmed.toLowerCase() === 'cancel') {
5571
5750
  this.pendingInteraction = null;
5572
- display.showInfo('Secret management cancelled.');
5573
- this.clearInlinePanel();
5751
+ this.showInlineStatus('Secret management cancelled.', 'info', { autoClearMs: 1600 });
5574
5752
  this.syncRendererInput();
5575
5753
  return;
5576
5754
  }
5577
5755
  const choice = Number.parseInt(trimmed, 10);
5578
5756
  if (!Number.isFinite(choice) || choice < 1 || choice > optionCount) {
5579
- display.showWarning(`Enter 1-${optionCount} or "cancel".`);
5757
+ this.appendInlineNotice(`Enter 1-${optionCount} or "cancel".`, 'warning');
5580
5758
  this.syncRendererInput();
5581
5759
  return;
5582
5760
  }
5583
5761
  const secret = pending.options[choice - 1];
5584
5762
  if (!secret) {
5585
- display.showWarning(`Enter 1-${optionCount} or "cancel".`);
5763
+ this.appendInlineNotice(`Enter 1-${optionCount} or "cancel".`, 'warning');
5586
5764
  this.syncRendererInput();
5587
5765
  return;
5588
5766
  }
@@ -5601,7 +5779,7 @@ export class InteractiveShell {
5601
5779
  }
5602
5780
  const trimmed = input.trim();
5603
5781
  if (!trimmed) {
5604
- display.showWarning('Enter a value or type cancel.');
5782
+ this.appendInlineNotice('Enter a value or type cancel.', 'warning');
5605
5783
  this.syncRendererInput();
5606
5784
  return;
5607
5785
  }
@@ -5609,14 +5787,12 @@ export class InteractiveShell {
5609
5787
  this.pendingInteraction = null;
5610
5788
  this.pendingSecretRetry = null;
5611
5789
  this.terminalInput.setSecretMode(false);
5612
- display.showInfo('Secret unchanged.');
5613
- this.clearInlinePanel();
5790
+ this.showInlineStatus('Secret unchanged.', 'info', { autoClearMs: 1600 });
5614
5791
  this.syncRendererInput();
5615
5792
  return;
5616
5793
  }
5617
5794
  try {
5618
5795
  setSecretValue(pending.secret.id, trimmed);
5619
- display.showInfo(`${pending.secret.label} updated.`);
5620
5796
  this.pendingInteraction = null;
5621
5797
  const deferred = this.pendingSecretRetry;
5622
5798
  this.pendingSecretRetry = null;
@@ -5628,15 +5804,15 @@ export class InteractiveShell {
5628
5804
  if (deferred) {
5629
5805
  await deferred();
5630
5806
  }
5807
+ this.showInlineStatus(`${pending.secret.label} updated.`, 'success', { autoClearMs: 1600 });
5631
5808
  }
5632
5809
  catch (error) {
5633
5810
  const message = error instanceof Error ? error.message : String(error);
5634
- display.showError(message);
5811
+ this.showInlineStatus(message, 'error');
5635
5812
  this.pendingInteraction = null;
5636
5813
  this.pendingSecretRetry = null;
5637
5814
  }
5638
5815
  this.terminalInput.setSecretMode(false);
5639
- this.clearInlinePanel();
5640
5816
  this.syncRendererInput();
5641
5817
  }
5642
5818
  async processRequest(request, options) {
@@ -5677,6 +5853,7 @@ export class InteractiveShell {
5677
5853
  this.syncRendererInput();
5678
5854
  this.renderer?.render();
5679
5855
  const requestStartTime = Date.now(); // Alpha Zero 2 timing
5856
+ let elapsedMs = null;
5680
5857
  // Clear previous parallel agents and start fresh for new request
5681
5858
  const parallelManager = getParallelAgentManager();
5682
5859
  parallelManager.clear();
@@ -5718,7 +5895,7 @@ export class InteractiveShell {
5718
5895
  this.captureHistorySnapshot();
5719
5896
  this.autosaveIfEnabled();
5720
5897
  // Track metrics with Alpha Zero 2
5721
- const elapsedMs = Date.now() - requestStartTime;
5898
+ elapsedMs = Date.now() - requestStartTime;
5722
5899
  this.alphaZeroMetrics.recordMessage(elapsedMs);
5723
5900
  if (!responseText?.trim()) {
5724
5901
  display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
@@ -5835,6 +6012,8 @@ export class InteractiveShell {
5835
6012
  });
5836
6013
  this.responseRendered = true;
5837
6014
  }
6015
+ this.lastRunDurationSeconds = elapsedMs !== null ? Math.max(0, Math.round(elapsedMs / 1000)) : null;
6016
+ this.lastRunToolCount = this.currentToolCalls.length;
5838
6017
  this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
5839
6018
  display.stopThinking(false);
5840
6019
  this.uiUpdates.setMode('processing');
@@ -6211,6 +6390,7 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`
6211
6390
  const summary = this.buildTestSummary(command, combinedOutput, true);
6212
6391
  display.showTestEvent(summary);
6213
6392
  this.statusTracker.clearOverride('tests');
6393
+ this.lastTestStatus = 'ok';
6214
6394
  return true;
6215
6395
  }
6216
6396
  catch (error) {
@@ -6222,6 +6402,7 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`
6222
6402
  detail: 'Auto-run npm test failed',
6223
6403
  tone: 'danger',
6224
6404
  });
6405
+ this.lastTestStatus = 'fail';
6225
6406
  return false;
6226
6407
  }
6227
6408
  finally {
@@ -6269,6 +6450,7 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`
6269
6450
  const finishedAt = Date.now();
6270
6451
  this.lastAutoBuildRun = finishedAt;
6271
6452
  this.lastBuildSucceededAt = finishedAt;
6453
+ this.lastBuildStatus = 'ok';
6272
6454
  const outputText = [stdout, stderr].filter(Boolean).join('\n').trim();
6273
6455
  display.showSystemMessage('✅ Build succeeded.');
6274
6456
  if (outputText && outputText.length < 500) {
@@ -6282,6 +6464,7 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`
6282
6464
  const finishedAt = Date.now();
6283
6465
  this.lastAutoBuildRun = finishedAt;
6284
6466
  this.lastBuildSucceededAt = null;
6467
+ this.lastBuildStatus = 'fail';
6285
6468
  const errorOutput = this.formatCommandError(error);
6286
6469
  display.showWarning('⚠️ Build failed. Feeding errors back to agent...');
6287
6470
  if (errorOutput) {
@@ -6799,6 +6982,12 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
6799
6982
  this.renderer?.setActivity('Thinking');
6800
6983
  }
6801
6984
  },
6985
+ onEditExplanation: (payload) => {
6986
+ const label = payload.files.length ? payload.files.join(', ') : payload.toolName ?? 'edit';
6987
+ const header = label ? `Edit explanation (${label})` : 'Edit explanation';
6988
+ display.showSystemMessage(`${header}:\n${payload.explanation}`);
6989
+ this.ui.controller.recordAssistantThought(payload.explanation);
6990
+ },
6802
6991
  onVerificationNeeded: (response, context) => {
6803
6992
  this.lastAssistantResponse = response;
6804
6993
  void this.runAutoQualityChecks('verification', response, context);
@@ -6817,7 +7006,7 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
6817
7006
  display.showSystemMessage(`⚡ Retry ${attempt}/${maxAttempts}: ${shortError}${error.message.length > 100 ? '...' : ''}`);
6818
7007
  this.renderer?.setActivity(`Retrying (${attempt}/${maxAttempts})...`);
6819
7008
  },
6820
- });
7009
+ }, undefined, { explainEdits: true });
6821
7010
  // Register global AI enhancer for explore tool - uses active model by default
6822
7011
  this.registerExploreAIEnhancer();
6823
7012
  // Fetch real context window from provider API (async, updates in background)
@@ -7600,19 +7789,19 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
7600
7789
  const providerOptions = this.buildProviderOptions();
7601
7790
  const match = providerOptions.find((opt) => opt.provider.toLowerCase() === targetProvider || opt.label.toLowerCase() === targetProvider);
7602
7791
  if (!match) {
7603
- display.showWarning(`Unknown provider "${targetProvider}".`);
7792
+ this.showSlashWarning(`Unknown provider "${targetProvider}".`);
7604
7793
  const available = providerOptions.map((opt) => opt.provider).join(', ');
7605
- display.showInfo(`Available providers: ${available}`);
7794
+ this.showSlashInfo(`Available providers: ${available}`);
7606
7795
  return;
7607
7796
  }
7608
7797
  if (match.provider === this.sessionState.provider) {
7609
- display.showInfo(`Already using ${match.label}.`);
7798
+ this.showSlashInfo(`Already using ${match.label}.`);
7610
7799
  return;
7611
7800
  }
7612
7801
  // Get default model for the provider
7613
7802
  const models = MODEL_PRESETS.filter((preset) => preset.provider === match.provider);
7614
7803
  if (!models.length) {
7615
- display.showWarning(`No models available for ${match.label}.`);
7804
+ this.showSlashWarning(`No models available for ${match.label}.`);
7616
7805
  return;
7617
7806
  }
7618
7807
  const defaultModel = models[0];
@@ -7630,21 +7819,21 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
7630
7819
  if (this.rebuildAgent()) {
7631
7820
  this.persistSessionPreference();
7632
7821
  this.refreshSessionContext();
7633
- display.showInfo(`Switched from ${this.providerLabel(oldProvider)}/${oldModel} to ${match.label}/${defaultModel.id}`);
7822
+ this.showSlashSuccess(`Switched from ${this.providerLabel(oldProvider)}/${oldModel} to ${match.label}/${defaultModel.id}`);
7634
7823
  this.resetChatBoxAfterModelSwap();
7635
7824
  }
7636
7825
  else {
7637
7826
  // Revert on failure
7638
7827
  this.sessionState.provider = oldProvider;
7639
7828
  this.sessionState.model = oldModel;
7640
- display.showError(`Failed to switch to ${match.label}. Reverted to ${this.providerLabel(oldProvider)}.`);
7829
+ this.showInlineStatus(`Failed to switch to ${match.label}. Reverted to ${this.providerLabel(oldProvider)}.`, 'error');
7641
7830
  }
7642
7831
  }
7643
7832
  /**
7644
7833
  * Discover models from provider APIs.
7645
7834
  */
7646
7835
  async discoverModelsCommand() {
7647
- display.showInfo('Discovering models from provider APIs...');
7836
+ this.showSlashInfo('Discovering models from provider APIs...');
7648
7837
  try {
7649
7838
  const result = await discoverAllModels();
7650
7839
  const lines = [
@@ -7676,7 +7865,7 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
7676
7865
  }
7677
7866
  catch (error) {
7678
7867
  const message = error instanceof Error ? error.message : String(error);
7679
- display.showError(`Discovery failed: ${message}`);
7868
+ this.showInlineStatus(`Discovery failed: ${message}`, 'error');
7680
7869
  }
7681
7870
  }
7682
7871
  /**
@@ -7685,8 +7874,8 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
7685
7874
  showConfiguredProviders() {
7686
7875
  const providerOptions = this.buildProviderOptions();
7687
7876
  if (!providerOptions.length) {
7688
- display.showWarning('No providers are configured.');
7689
- display.showInfo('Set an API key: OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, etc.');
7877
+ this.showSlashWarning('No providers are configured.');
7878
+ this.showSlashInfo('Set an API key: OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, etc.');
7690
7879
  return;
7691
7880
  }
7692
7881
  const lines = [
@@ -7720,8 +7909,8 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
7720
7909
  {
7721
7910
  const provider = tokens[1]?.toLowerCase();
7722
7911
  if (!provider) {
7723
- display.showWarning('Usage: /local use <provider>');
7724
- display.showInfo('Example: /local use ollama');
7912
+ this.showSlashWarning('Usage: /local use <provider>');
7913
+ this.showSlashInfo('Example: /local use ollama');
7725
7914
  return;
7726
7915
  }
7727
7916
  await this.handleProviderCommand(`/provider ${provider}`);
@@ -7742,7 +7931,7 @@ Please fix these now. Re-run build/tests as needed. End with TASK_FULLY_COMPLETE
7742
7931
  { id: 'vllm', label: 'vLLM', url: 'http://localhost:8000', envVar: 'VLLM_BASE_URL' },
7743
7932
  { id: 'llamacpp', label: 'llama.cpp', url: 'http://localhost:8080', envVar: 'LLAMACPP_BASE_URL' },
7744
7933
  ];
7745
- display.showInfo('Scanning for local LLM servers...');
7934
+ this.showSlashInfo('Scanning for local LLM servers...');
7746
7935
  const results = [];
7747
7936
  for (const provider of localProviders) {
7748
7937
  const baseUrl = process.env[provider.envVar] || provider.url;