erosolar-cli 1.7.261 → 1.7.262

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 (247) hide show
  1. package/README.md +22 -148
  2. package/dist/core/customCommands.d.ts +1 -0
  3. package/dist/core/customCommands.d.ts.map +1 -1
  4. package/dist/core/customCommands.js +3 -0
  5. package/dist/core/customCommands.js.map +1 -1
  6. package/dist/core/hooks.d.ts +113 -0
  7. package/dist/core/hooks.d.ts.map +1 -0
  8. package/dist/core/hooks.js +267 -0
  9. package/dist/core/hooks.js.map +1 -0
  10. package/dist/core/metricsTracker.d.ts +122 -0
  11. package/dist/core/metricsTracker.d.ts.map +1 -0
  12. package/dist/{alpha-zero → core}/metricsTracker.js +2 -5
  13. package/dist/core/metricsTracker.js.map +1 -0
  14. package/dist/core/toolPreconditions.d.ts.map +1 -1
  15. package/dist/core/toolPreconditions.js +0 -14
  16. package/dist/core/toolPreconditions.js.map +1 -1
  17. package/dist/core/toolRuntime.d.ts.map +1 -1
  18. package/dist/core/toolRuntime.js +0 -5
  19. package/dist/core/toolRuntime.js.map +1 -1
  20. package/dist/core/toolValidation.d.ts.map +1 -1
  21. package/dist/core/toolValidation.js +14 -3
  22. package/dist/core/toolValidation.js.map +1 -1
  23. package/dist/core/validationRunner.d.ts +1 -3
  24. package/dist/core/validationRunner.d.ts.map +1 -1
  25. package/dist/core/validationRunner.js.map +1 -1
  26. package/dist/mcp/sseClient.d.ts.map +1 -1
  27. package/dist/mcp/sseClient.js +9 -18
  28. package/dist/mcp/sseClient.js.map +1 -1
  29. package/dist/plugins/tools/build/buildPlugin.d.ts +0 -6
  30. package/dist/plugins/tools/build/buildPlugin.d.ts.map +1 -1
  31. package/dist/plugins/tools/build/buildPlugin.js +4 -10
  32. package/dist/plugins/tools/build/buildPlugin.js.map +1 -1
  33. package/dist/shell/interactiveShell.d.ts +10 -2
  34. package/dist/shell/interactiveShell.d.ts.map +1 -1
  35. package/dist/shell/interactiveShell.js +182 -36
  36. package/dist/shell/interactiveShell.js.map +1 -1
  37. package/dist/shell/terminalInput.d.ts +68 -140
  38. package/dist/shell/terminalInput.d.ts.map +1 -1
  39. package/dist/shell/terminalInput.js +448 -667
  40. package/dist/shell/terminalInput.js.map +1 -1
  41. package/dist/shell/terminalInputAdapter.d.ts +20 -15
  42. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  43. package/dist/shell/terminalInputAdapter.js +14 -22
  44. package/dist/shell/terminalInputAdapter.js.map +1 -1
  45. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  46. package/dist/ui/ShellUIAdapter.js +13 -12
  47. package/dist/ui/ShellUIAdapter.js.map +1 -1
  48. package/dist/ui/display.d.ts +19 -0
  49. package/dist/ui/display.d.ts.map +1 -1
  50. package/dist/ui/display.js +131 -33
  51. package/dist/ui/display.js.map +1 -1
  52. package/dist/ui/theme.d.ts.map +1 -1
  53. package/dist/ui/theme.js +6 -8
  54. package/dist/ui/theme.js.map +1 -1
  55. package/dist/ui/toolDisplay.d.ts +0 -158
  56. package/dist/ui/toolDisplay.d.ts.map +1 -1
  57. package/dist/ui/toolDisplay.js +0 -348
  58. package/dist/ui/toolDisplay.js.map +1 -1
  59. package/dist/ui/unified/layout.d.ts +1 -0
  60. package/dist/ui/unified/layout.d.ts.map +1 -1
  61. package/dist/ui/unified/layout.js +15 -25
  62. package/dist/ui/unified/layout.js.map +1 -1
  63. package/package.json +1 -1
  64. package/dist/alpha-zero/agentWrapper.d.ts +0 -84
  65. package/dist/alpha-zero/agentWrapper.d.ts.map +0 -1
  66. package/dist/alpha-zero/agentWrapper.js +0 -171
  67. package/dist/alpha-zero/agentWrapper.js.map +0 -1
  68. package/dist/alpha-zero/codeEvaluator.d.ts +0 -25
  69. package/dist/alpha-zero/codeEvaluator.d.ts.map +0 -1
  70. package/dist/alpha-zero/codeEvaluator.js +0 -273
  71. package/dist/alpha-zero/codeEvaluator.js.map +0 -1
  72. package/dist/alpha-zero/competitiveRunner.d.ts +0 -66
  73. package/dist/alpha-zero/competitiveRunner.d.ts.map +0 -1
  74. package/dist/alpha-zero/competitiveRunner.js +0 -224
  75. package/dist/alpha-zero/competitiveRunner.js.map +0 -1
  76. package/dist/alpha-zero/index.d.ts +0 -67
  77. package/dist/alpha-zero/index.d.ts.map +0 -1
  78. package/dist/alpha-zero/index.js +0 -99
  79. package/dist/alpha-zero/index.js.map +0 -1
  80. package/dist/alpha-zero/introspection.d.ts +0 -128
  81. package/dist/alpha-zero/introspection.d.ts.map +0 -1
  82. package/dist/alpha-zero/introspection.js +0 -300
  83. package/dist/alpha-zero/introspection.js.map +0 -1
  84. package/dist/alpha-zero/metricsTracker.d.ts +0 -71
  85. package/dist/alpha-zero/metricsTracker.d.ts.map +0 -1
  86. package/dist/alpha-zero/metricsTracker.js.map +0 -1
  87. package/dist/alpha-zero/security/core.d.ts +0 -125
  88. package/dist/alpha-zero/security/core.d.ts.map +0 -1
  89. package/dist/alpha-zero/security/core.js +0 -271
  90. package/dist/alpha-zero/security/core.js.map +0 -1
  91. package/dist/alpha-zero/security/google.d.ts +0 -125
  92. package/dist/alpha-zero/security/google.d.ts.map +0 -1
  93. package/dist/alpha-zero/security/google.js +0 -311
  94. package/dist/alpha-zero/security/google.js.map +0 -1
  95. package/dist/alpha-zero/security/googleLoader.d.ts +0 -17
  96. package/dist/alpha-zero/security/googleLoader.d.ts.map +0 -1
  97. package/dist/alpha-zero/security/googleLoader.js +0 -41
  98. package/dist/alpha-zero/security/googleLoader.js.map +0 -1
  99. package/dist/alpha-zero/security/index.d.ts +0 -29
  100. package/dist/alpha-zero/security/index.d.ts.map +0 -1
  101. package/dist/alpha-zero/security/index.js +0 -32
  102. package/dist/alpha-zero/security/index.js.map +0 -1
  103. package/dist/alpha-zero/security/simulation.d.ts +0 -124
  104. package/dist/alpha-zero/security/simulation.d.ts.map +0 -1
  105. package/dist/alpha-zero/security/simulation.js +0 -277
  106. package/dist/alpha-zero/security/simulation.js.map +0 -1
  107. package/dist/alpha-zero/selfModification.d.ts +0 -109
  108. package/dist/alpha-zero/selfModification.d.ts.map +0 -1
  109. package/dist/alpha-zero/selfModification.js +0 -233
  110. package/dist/alpha-zero/selfModification.js.map +0 -1
  111. package/dist/alpha-zero/types.d.ts +0 -170
  112. package/dist/alpha-zero/types.d.ts.map +0 -1
  113. package/dist/alpha-zero/types.js +0 -31
  114. package/dist/alpha-zero/types.js.map +0 -1
  115. package/dist/core/aiFlowOptimizer.d.ts +0 -26
  116. package/dist/core/aiFlowOptimizer.d.ts.map +0 -1
  117. package/dist/core/aiFlowOptimizer.js +0 -31
  118. package/dist/core/aiFlowOptimizer.js.map +0 -1
  119. package/dist/core/aiOptimizationEngine.d.ts +0 -158
  120. package/dist/core/aiOptimizationEngine.d.ts.map +0 -1
  121. package/dist/core/aiOptimizationEngine.js +0 -428
  122. package/dist/core/aiOptimizationEngine.js.map +0 -1
  123. package/dist/core/aiOptimizationIntegration.d.ts +0 -93
  124. package/dist/core/aiOptimizationIntegration.d.ts.map +0 -1
  125. package/dist/core/aiOptimizationIntegration.js +0 -250
  126. package/dist/core/aiOptimizationIntegration.js.map +0 -1
  127. package/dist/core/enhancedErrorRecovery.d.ts +0 -100
  128. package/dist/core/enhancedErrorRecovery.d.ts.map +0 -1
  129. package/dist/core/enhancedErrorRecovery.js +0 -345
  130. package/dist/core/enhancedErrorRecovery.js.map +0 -1
  131. package/dist/core/unified/errors.d.ts +0 -189
  132. package/dist/core/unified/errors.d.ts.map +0 -1
  133. package/dist/core/unified/errors.js +0 -497
  134. package/dist/core/unified/errors.js.map +0 -1
  135. package/dist/core/unified/index.d.ts +0 -19
  136. package/dist/core/unified/index.d.ts.map +0 -1
  137. package/dist/core/unified/index.js +0 -68
  138. package/dist/core/unified/index.js.map +0 -1
  139. package/dist/core/unified/schema.d.ts +0 -101
  140. package/dist/core/unified/schema.d.ts.map +0 -1
  141. package/dist/core/unified/schema.js +0 -350
  142. package/dist/core/unified/schema.js.map +0 -1
  143. package/dist/core/unified/toolRuntime.d.ts +0 -179
  144. package/dist/core/unified/toolRuntime.d.ts.map +0 -1
  145. package/dist/core/unified/toolRuntime.js +0 -517
  146. package/dist/core/unified/toolRuntime.js.map +0 -1
  147. package/dist/core/unified/tools.d.ts +0 -127
  148. package/dist/core/unified/tools.d.ts.map +0 -1
  149. package/dist/core/unified/tools.js +0 -1333
  150. package/dist/core/unified/tools.js.map +0 -1
  151. package/dist/core/unified/types.d.ts +0 -352
  152. package/dist/core/unified/types.d.ts.map +0 -1
  153. package/dist/core/unified/types.js +0 -12
  154. package/dist/core/unified/types.js.map +0 -1
  155. package/dist/core/unified/version.d.ts +0 -209
  156. package/dist/core/unified/version.d.ts.map +0 -1
  157. package/dist/core/unified/version.js +0 -454
  158. package/dist/core/unified/version.js.map +0 -1
  159. package/dist/security/active-stack-security.d.ts +0 -112
  160. package/dist/security/active-stack-security.d.ts.map +0 -1
  161. package/dist/security/active-stack-security.js +0 -296
  162. package/dist/security/active-stack-security.js.map +0 -1
  163. package/dist/security/advanced-persistence-research.d.ts +0 -92
  164. package/dist/security/advanced-persistence-research.d.ts.map +0 -1
  165. package/dist/security/advanced-persistence-research.js +0 -195
  166. package/dist/security/advanced-persistence-research.js.map +0 -1
  167. package/dist/security/advanced-targeting.d.ts +0 -119
  168. package/dist/security/advanced-targeting.d.ts.map +0 -1
  169. package/dist/security/advanced-targeting.js +0 -233
  170. package/dist/security/advanced-targeting.js.map +0 -1
  171. package/dist/security/assessment/vulnerabilityAssessment.d.ts +0 -104
  172. package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +0 -1
  173. package/dist/security/assessment/vulnerabilityAssessment.js +0 -315
  174. package/dist/security/assessment/vulnerabilityAssessment.js.map +0 -1
  175. package/dist/security/authorization/securityAuthorization.d.ts +0 -88
  176. package/dist/security/authorization/securityAuthorization.d.ts.map +0 -1
  177. package/dist/security/authorization/securityAuthorization.js +0 -172
  178. package/dist/security/authorization/securityAuthorization.js.map +0 -1
  179. package/dist/security/comprehensive-targeting.d.ts +0 -85
  180. package/dist/security/comprehensive-targeting.d.ts.map +0 -1
  181. package/dist/security/comprehensive-targeting.js +0 -438
  182. package/dist/security/comprehensive-targeting.js.map +0 -1
  183. package/dist/security/global-security-integration.d.ts +0 -91
  184. package/dist/security/global-security-integration.d.ts.map +0 -1
  185. package/dist/security/global-security-integration.js +0 -218
  186. package/dist/security/global-security-integration.js.map +0 -1
  187. package/dist/security/index.d.ts +0 -38
  188. package/dist/security/index.d.ts.map +0 -1
  189. package/dist/security/index.js +0 -47
  190. package/dist/security/index.js.map +0 -1
  191. package/dist/security/persistence-analyzer.d.ts +0 -56
  192. package/dist/security/persistence-analyzer.d.ts.map +0 -1
  193. package/dist/security/persistence-analyzer.js +0 -187
  194. package/dist/security/persistence-analyzer.js.map +0 -1
  195. package/dist/security/persistence-cli.d.ts +0 -36
  196. package/dist/security/persistence-cli.d.ts.map +0 -1
  197. package/dist/security/persistence-cli.js +0 -160
  198. package/dist/security/persistence-cli.js.map +0 -1
  199. package/dist/security/persistence-research.d.ts +0 -92
  200. package/dist/security/persistence-research.d.ts.map +0 -1
  201. package/dist/security/persistence-research.js +0 -364
  202. package/dist/security/persistence-research.js.map +0 -1
  203. package/dist/security/research/persistenceResearch.d.ts +0 -97
  204. package/dist/security/research/persistenceResearch.d.ts.map +0 -1
  205. package/dist/security/research/persistenceResearch.js +0 -282
  206. package/dist/security/research/persistenceResearch.js.map +0 -1
  207. package/dist/security/security-integration.d.ts +0 -74
  208. package/dist/security/security-integration.d.ts.map +0 -1
  209. package/dist/security/security-integration.js +0 -137
  210. package/dist/security/security-integration.js.map +0 -1
  211. package/dist/security/security-testing-framework.d.ts +0 -112
  212. package/dist/security/security-testing-framework.d.ts.map +0 -1
  213. package/dist/security/security-testing-framework.js +0 -364
  214. package/dist/security/security-testing-framework.js.map +0 -1
  215. package/dist/security/simulation/attackSimulation.d.ts +0 -93
  216. package/dist/security/simulation/attackSimulation.d.ts.map +0 -1
  217. package/dist/security/simulation/attackSimulation.js +0 -341
  218. package/dist/security/simulation/attackSimulation.js.map +0 -1
  219. package/dist/security/strategic-operations.d.ts +0 -100
  220. package/dist/security/strategic-operations.d.ts.map +0 -1
  221. package/dist/security/strategic-operations.js +0 -276
  222. package/dist/security/strategic-operations.js.map +0 -1
  223. package/dist/security/tool-security-wrapper.d.ts +0 -58
  224. package/dist/security/tool-security-wrapper.d.ts.map +0 -1
  225. package/dist/security/tool-security-wrapper.js +0 -156
  226. package/dist/security/tool-security-wrapper.js.map +0 -1
  227. package/dist/shell/claudeCodeStreamHandler.d.ts +0 -145
  228. package/dist/shell/claudeCodeStreamHandler.d.ts.map +0 -1
  229. package/dist/shell/claudeCodeStreamHandler.js +0 -322
  230. package/dist/shell/claudeCodeStreamHandler.js.map +0 -1
  231. package/dist/shell/inputQueueManager.d.ts +0 -144
  232. package/dist/shell/inputQueueManager.d.ts.map +0 -1
  233. package/dist/shell/inputQueueManager.js +0 -290
  234. package/dist/shell/inputQueueManager.js.map +0 -1
  235. package/dist/shell/streamingOutputManager.d.ts +0 -115
  236. package/dist/shell/streamingOutputManager.d.ts.map +0 -1
  237. package/dist/shell/streamingOutputManager.js +0 -225
  238. package/dist/shell/streamingOutputManager.js.map +0 -1
  239. package/dist/ui/persistentPrompt.d.ts +0 -50
  240. package/dist/ui/persistentPrompt.d.ts.map +0 -1
  241. package/dist/ui/persistentPrompt.js +0 -92
  242. package/dist/ui/persistentPrompt.js.map +0 -1
  243. package/dist/ui/terminalUISchema.d.ts +0 -195
  244. package/dist/ui/terminalUISchema.d.ts.map +0 -1
  245. package/dist/ui/terminalUISchema.js +0 -113
  246. package/dist/ui/terminalUISchema.js.map +0 -1
  247. package/scripts/deploy-security-capabilities.js +0 -178
@@ -2,7 +2,7 @@ import { stdin as input, stdout as output, exit } from 'node:process';
2
2
  import { exec } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import { display } from '../ui/display.js';
5
- import { theme, formatUserPrompt } from '../ui/theme.js';
5
+ import { theme } from '../ui/theme.js';
6
6
  import { getContextWindowTokens } from '../core/contextWindow.js';
7
7
  import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
8
8
  import { saveActiveProfilePreference, saveModelPreference, loadToolSettings, saveToolSettings, clearToolSettings, clearActiveProfilePreference, loadSessionPreferences, saveSessionPreferences, } from '../core/preferences.js';
@@ -19,7 +19,7 @@ import { SkillRepository } from '../skills/skillRepository.js';
19
19
  import { createSkillTools } from '../tools/skillTools.js';
20
20
  import { FileChangeTracker } from './fileChangeTracker.js';
21
21
  import { formatShortcutsHelp } from '../ui/shortcutsHelp.js';
22
- import { MetricsTracker } from '../alpha-zero/index.js';
22
+ import { MetricsTracker } from '../core/metricsTracker.js';
23
23
  import { listAvailablePlugins } from '../plugins/index.js';
24
24
  import { TerminalInputAdapter } from './terminalInputAdapter.js';
25
25
  import { isUpdateInProgress } from './updateManager.js';
@@ -34,6 +34,7 @@ const DROPDOWN_COLORS = [
34
34
  theme.success,
35
35
  theme.warning,
36
36
  ];
37
+ const STREAMING_SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
37
38
  // Load MODEL_PRESETS from centralized schema
38
39
  const MODEL_PRESETS = getModels().map((model) => ({
39
40
  id: model.id,
@@ -48,11 +49,13 @@ const MODEL_PRESETS = getModels().map((model) => ({
48
49
  const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
49
50
  command: cmd.command,
50
51
  description: cmd.description,
52
+ category: cmd.category,
51
53
  }));
52
54
  // Load PROVIDER_LABELS from centralized schema
53
55
  const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
54
56
  // Allow enough time for paste detection to kick in before flushing buffered lines
55
57
  const CONTEXT_USAGE_THRESHOLD = 0.9;
58
+ const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
56
59
  const CONTEXT_RECENT_MESSAGE_COUNT = 12;
57
60
  const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
58
61
  const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
@@ -98,6 +101,7 @@ export class InteractiveShell {
98
101
  followUpQueue = [];
99
102
  isDrainingQueue = false;
100
103
  activeContextWindowTokens = null;
104
+ latestTokenUsage = { used: null, limit: null };
101
105
  sessionPreferences;
102
106
  autosaveEnabled;
103
107
  autoContinueEnabled;
@@ -128,6 +132,7 @@ export class InteractiveShell {
128
132
  statusLineState = null;
129
133
  statusMessageOverride = null;
130
134
  promptRefreshTimer = null;
135
+ launchPaletteShown = false;
131
136
  constructor(config) {
132
137
  this.profile = config.profile;
133
138
  this.profileLabel = config.profileLabel;
@@ -161,6 +166,7 @@ export class InteractiveShell {
161
166
  this.slashCommands.push({
162
167
  command: '/agents',
163
168
  description: 'Select the default agent profile (applies on next launch)',
169
+ category: 'configuration',
164
170
  });
165
171
  }
166
172
  this.customCommands = loadCustomSlashCommands();
@@ -169,18 +175,21 @@ export class InteractiveShell {
169
175
  this.slashCommands.push({
170
176
  command: custom.command,
171
177
  description: `${custom.description} (custom)`,
178
+ category: custom.category ?? 'other',
172
179
  });
173
180
  }
174
181
  if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
175
182
  this.slashCommands.push({
176
183
  command: '/exit',
177
184
  description: 'Quit the CLI immediately',
185
+ category: 'other',
178
186
  });
179
187
  }
180
188
  // Add /plugins command
181
189
  this.slashCommands.push({
182
190
  command: '/plugins',
183
191
  description: 'Show available and loaded plugins',
192
+ category: 'configuration',
184
193
  });
185
194
  this.statusTracker = config.statusTracker;
186
195
  this.ui = config.ui;
@@ -215,9 +224,6 @@ export class InteractiveShell {
215
224
  });
216
225
  // Register output interceptor for cursor positioning during streaming
217
226
  this.terminalInput.registerOutputInterceptor(display);
218
- // Use flow mode: input renders inline after content for a unified layout
219
- // This eliminates the blank space between banner and input area
220
- this.terminalInput.setFlowMode(true);
221
227
  // Initialize Alpha Zero 2 metrics tracking
222
228
  this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
223
229
  this.setupStatusTracking();
@@ -275,9 +281,15 @@ export class InteractiveShell {
275
281
  await this.processInputBlock(initialPrompt);
276
282
  return;
277
283
  }
284
+ this.showLaunchCommandPalette();
278
285
  // Ensure the terminal input is visible
279
286
  this.terminalInput.render();
280
287
  }
288
+ showLaunchCommandPalette() {
289
+ // Disabled: Quick commands palette takes up too much space
290
+ // Users can type /help to see available commands
291
+ this.launchPaletteShown = true;
292
+ }
281
293
  /**
282
294
  * TerminalInputAdapter submit handler
283
295
  */
@@ -291,9 +303,8 @@ export class InteractiveShell {
291
303
  this.handleInputChange('');
292
304
  return;
293
305
  }
294
- // Enter streaming mode BEFORE logging prompt - this positions cursor correctly
295
- // so content appears right after the banner, not at bottom with blank space above
296
- this.terminalInput.setStreaming(true);
306
+ // DON'T clear the input here - keep it visible while streaming.
307
+ // The input will be cleared after streaming completes in the finally block.
297
308
  this.logUserPrompt(approved);
298
309
  void this.processInputBlock(approved).catch((err) => {
299
310
  display.showError(err instanceof Error ? err.message : String(err), err);
@@ -495,10 +506,9 @@ export class InteractiveShell {
495
506
  // Dispose unified UI adapter
496
507
  this.uiAdapter.dispose();
497
508
  display.newLine();
498
- console.log(theme.gradient.warm('━'.repeat(50)));
499
- console.log(` ${theme.gradient.cool('Goodbye!')} ${theme.ui.muted('·')} ${theme.info('support@ero.solar')}`);
500
- console.log(` ${theme.ui.muted('Read:')} ${theme.accent('anthropic.com/news/disrupting-AI-espionage')}`);
501
- console.log(theme.gradient.warm('━'.repeat(50)));
509
+ console.log(theme.ui.muted('━'.repeat(44)));
510
+ console.log(theme.ui.muted(' Goodbye! · support@ero.solar'));
511
+ console.log(theme.ui.muted(''.repeat(44)));
502
512
  exit(0);
503
513
  }
504
514
  /**
@@ -668,13 +678,14 @@ export class InteractiveShell {
668
678
  });
669
679
  }
670
680
  setProcessingStatus(detail) {
681
+ this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
671
682
  this.statusTracker.setBase('Working on your request', {
672
683
  detail: this.describeStatusDetail(detail),
673
684
  tone: 'info',
674
685
  });
675
686
  }
676
687
  describeStatusDetail(detail) {
677
- const parts = [detail?.trim() || this.describeModelDetail()];
688
+ const parts = detail?.trim() ? [detail.trim()] : [];
678
689
  const queued = this.followUpQueue.length;
679
690
  if (queued > 0) {
680
691
  parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
@@ -687,12 +698,18 @@ export class InteractiveShell {
687
698
  }
688
699
  refreshContextGauge() {
689
700
  const tokens = getContextWindowTokens(this.sessionState.model);
690
- this.activeContextWindowTokens =
691
- typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
701
+ const normalizedTokens = typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
702
+ this.activeContextWindowTokens = normalizedTokens;
703
+ if (normalizedTokens !== null) {
704
+ this.latestTokenUsage = {
705
+ used: this.latestTokenUsage.used,
706
+ limit: normalizedTokens,
707
+ };
708
+ }
692
709
  }
693
710
  updateContextUsage(percentage) {
694
711
  this.uiAdapter.updateContextUsage(percentage);
695
- this.terminalInput.setContextUsage(percentage);
712
+ this.terminalInput.setContextUsage(percentage, CONTEXT_AUTOCOMPACT_PERCENT);
696
713
  }
697
714
  refreshControlBar() {
698
715
  this.terminalInput.setModeToggles({
@@ -700,6 +717,8 @@ export class InteractiveShell {
700
717
  autoContinueEnabled: this.autoContinueEnabled,
701
718
  verificationHotkey: 'alt+v',
702
719
  autoContinueHotkey: 'alt+c',
720
+ thinkingModeLabel: this.thinkingMode,
721
+ thinkingHotkey: '/thinking',
703
722
  });
704
723
  this.refreshStatusLine();
705
724
  this.terminalInput.render();
@@ -731,6 +750,25 @@ export class InteractiveShell {
731
750
  // Set main status (tool execution, etc.) - shown when not overridden
732
751
  const statusText = this.formatStatusLine(this.statusLineState);
733
752
  this.terminalInput.setStatusMessage(statusText);
753
+ // Surface meta header (elapsed + context usage) above the divider
754
+ const elapsedSeconds = this.statusLineState
755
+ ? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
756
+ : null;
757
+ const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
758
+ const tokensUsed = this.latestTokenUsage.used;
759
+ const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
760
+ this.terminalInput.setMetaStatus({
761
+ elapsedSeconds,
762
+ tokensUsed,
763
+ tokenLimit,
764
+ thinkingMs,
765
+ thinkingHasContent: display.isSpinnerActive(),
766
+ });
767
+ // Keep model/provider visible in the controls bar
768
+ this.terminalInput.setModelContext({
769
+ model: this.sessionState.model,
770
+ provider: this.providerLabel(this.sessionState.provider),
771
+ });
734
772
  if (forceRender) {
735
773
  this.terminalInput.render();
736
774
  }
@@ -790,13 +828,11 @@ export class InteractiveShell {
790
828
  this.terminalInput.render();
791
829
  }
792
830
  /**
793
- * Log the user's prompt as a visible message in the conversation.
794
- * This creates a persistent log entry that remains visible during and after streaming.
831
+ * Keep submissions out of the transcript to preserve the persistent input area.
832
+ * The chat box already holds the user's prompt, so avoid echoing it into output.
795
833
  */
796
- logUserPrompt(text) {
797
- // Display the user's prompt with the standard prefix
798
- const prefix = formatUserPrompt();
799
- display.stream(`\n${prefix}${text}\n\n`);
834
+ logUserPrompt(_text) {
835
+ // Intentionally no-op to keep the input area persistent and uncluttered.
800
836
  }
801
837
  requestPromptRefresh(force = false) {
802
838
  if (force) {
@@ -824,9 +860,29 @@ export class InteractiveShell {
824
860
  this.uiUpdates.setMode('streaming');
825
861
  this.streamingHeartbeatStart = Date.now();
826
862
  this.streamingHeartbeatFrame = 0;
827
- // Note: We don't start a heartbeat during streaming anymore
828
- // because the UI shouldn't be rendering during streaming.
829
- // The streaming status is shown in the streaming header instead.
863
+ const initialFrame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
864
+ this.streamingStatusLabel = this.buildStreamingStatus(`${initialFrame} ${label}`, 0);
865
+ display.updateStreamingStatus(this.streamingStatusLabel);
866
+ this.refreshStatusLine(true);
867
+ // Periodically refresh the pinned input/status region while streaming so
868
+ // elapsed time remains visible without interrupting the scroll region.
869
+ this.uiUpdates.startHeartbeat('streaming', {
870
+ intervalMs: 1000,
871
+ lane: 'heartbeat',
872
+ mode: ['streaming', 'processing'],
873
+ coalesceKey: 'streaming:heartbeat',
874
+ run: () => {
875
+ const elapsedSeconds = this.streamingHeartbeatStart
876
+ ? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
877
+ : 0;
878
+ this.streamingHeartbeatFrame =
879
+ (this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
880
+ const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
881
+ this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
882
+ display.updateStreamingStatus(this.streamingStatusLabel);
883
+ this.refreshStatusLine(true);
884
+ },
885
+ });
830
886
  }
831
887
  stopStreamingHeartbeat() {
832
888
  // Exit global streaming mode - allows UI to render again
@@ -842,10 +898,28 @@ export class InteractiveShell {
842
898
  // Force refresh to update the input area now that streaming has ended
843
899
  this.refreshStatusLine(true);
844
900
  }
845
- buildStreamingStatus(label) {
901
+ buildStreamingStatus(label, elapsedSeconds) {
846
902
  const detail = this.describeModelDetail();
847
- const prefix = theme.info('');
848
- return detail ? `${prefix} ${label} ${theme.ui.muted('·')} ${detail}` : `${prefix} ${label}`;
903
+ const elapsedLabel = typeof elapsedSeconds === 'number' && elapsedSeconds >= 0
904
+ ? theme.ui.muted(this.formatElapsedShort(elapsedSeconds))
905
+ : null;
906
+ const prefix = theme.info('⏺');
907
+ const parts = [label];
908
+ if (detail) {
909
+ parts.push(theme.ui.muted('·'), detail);
910
+ }
911
+ if (elapsedLabel) {
912
+ parts.push(theme.ui.muted('·'), elapsedLabel);
913
+ }
914
+ return `${prefix} ${parts.join(' ')}`.trim();
915
+ }
916
+ formatElapsedShort(seconds) {
917
+ if (seconds < 60) {
918
+ return `${seconds}s`;
919
+ }
920
+ const minutes = Math.floor(seconds / 60);
921
+ const remaining = seconds % 60;
922
+ return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
849
923
  }
850
924
  refreshQueueIndicators() {
851
925
  if (this.isProcessing) {
@@ -1739,6 +1813,75 @@ export class InteractiveShell {
1739
1813
  }
1740
1814
  return `${warning.label}: ${warning.reason}.`;
1741
1815
  }
1816
+ buildLaunchCommandPalette() {
1817
+ const entries = [];
1818
+ const secretsSummary = this.summarizeSecretsForPalette();
1819
+ const toolSummary = this.getToolSelectionSummary();
1820
+ const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
1821
+ for (const command of this.slashCommands) {
1822
+ const entry = {
1823
+ command: command.command,
1824
+ description: command.description,
1825
+ category: command.category ?? 'other',
1826
+ };
1827
+ switch (command.command) {
1828
+ case '/secrets':
1829
+ if (secretsSummary.text) {
1830
+ entry.description = `${command.description} (${secretsSummary.text})`;
1831
+ entry.tone = secretsSummary.tone;
1832
+ }
1833
+ break;
1834
+ case '/tools':
1835
+ if (toolSummary) {
1836
+ entry.description = `${command.description} (${toolSummary})`;
1837
+ }
1838
+ break;
1839
+ case '/sessions':
1840
+ entry.description = `${command.description} (autosave ${autosaveLabel})`;
1841
+ break;
1842
+ case '/model':
1843
+ entry.description = `${command.description} (current: ${this.sessionState.model})`;
1844
+ break;
1845
+ case '/provider':
1846
+ entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
1847
+ break;
1848
+ default:
1849
+ break;
1850
+ }
1851
+ entries.push(entry);
1852
+ }
1853
+ return entries;
1854
+ }
1855
+ summarizeSecretsForPalette() {
1856
+ const definitions = listSecretDefinitions();
1857
+ if (!definitions.length) {
1858
+ return { text: null };
1859
+ }
1860
+ const missing = definitions.filter((definition) => !getSecretValue(definition.id));
1861
+ if (missing.length === 0) {
1862
+ return { text: 'all configured', tone: 'success' };
1863
+ }
1864
+ const labels = missing.map((definition) => definition.label ?? definition.id);
1865
+ return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
1866
+ }
1867
+ getToolSelectionSummary() {
1868
+ const toolSettings = loadToolSettings();
1869
+ const selection = buildEnabledToolSet(toolSettings);
1870
+ const options = getToolToggleOptions();
1871
+ if (!options.length) {
1872
+ return null;
1873
+ }
1874
+ const enabledCount = options.filter((option) => selection.has(option.id)).length;
1875
+ return `${enabledCount}/${options.length} enabled`;
1876
+ }
1877
+ formatList(values, maxItems = 3) {
1878
+ if (!values.length) {
1879
+ return '';
1880
+ }
1881
+ const shown = values.slice(0, maxItems);
1882
+ const suffix = values.length > maxItems ? ', …' : '';
1883
+ return `${shown.join(', ')}${suffix}`;
1884
+ }
1742
1885
  buildSlashCommandList(header) {
1743
1886
  const lines = [theme.gradient.primary(header), ''];
1744
1887
  for (const command of this.slashCommands) {
@@ -2229,9 +2372,6 @@ export class InteractiveShell {
2229
2372
  this.setIdleStatus();
2230
2373
  display.newLine();
2231
2374
  this.updateStatusMessage(null);
2232
- // Claude Code style: Show unified status bar before prompt
2233
- // This creates consistent UI between startup and post-streaming
2234
- this.showUnifiedStatusBar();
2235
2375
  queueMicrotask(() => this.uiUpdates.setMode('idle'));
2236
2376
  // CRITICAL: Ensure readline prompt is active for user input
2237
2377
  // Claude Code style: New prompt naturally appears at bottom
@@ -2308,6 +2448,7 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
2308
2448
  try {
2309
2449
  // Send the request and capture the response (streaming disabled)
2310
2450
  display.showThinking('Responding...');
2451
+ this.refreshStatusLine(true);
2311
2452
  const response = await agent.send(currentPrompt, true);
2312
2453
  await this.awaitPendingCleanup();
2313
2454
  this.captureHistorySnapshot();
@@ -2807,8 +2948,10 @@ What's the next action?`;
2807
2948
  try {
2808
2949
  // Send the error to the agent for fixing
2809
2950
  display.showThinking('Analyzing build errors');
2951
+ this.refreshStatusLine(true);
2810
2952
  const response = await this.agent.send(prompt, true);
2811
2953
  display.stopThinking();
2954
+ this.refreshStatusLine(true);
2812
2955
  if (response) {
2813
2956
  display.showAssistantMessage(response, { isFinal: true });
2814
2957
  }
@@ -2858,18 +3001,16 @@ What's the next action?`;
2858
3001
  display.showAssistantMessage(finalContent, enriched);
2859
3002
  }
2860
3003
  }
2861
- // Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
3004
+ // Status shown in mode controls bar - no separate status line needed
2862
3005
  display.stopThinking();
2863
- // Calculate context usage
2864
- let contextInfo;
3006
+ // Update context usage for mode controls display
2865
3007
  if (enriched.contextWindowTokens && metadata.usage) {
2866
3008
  const total = this.totalTokens(metadata.usage);
2867
3009
  if (total && total > 0) {
2868
3010
  const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
2869
- contextInfo = { percentage, tokens: total };
3011
+ this.updateContextUsage(percentage);
2870
3012
  }
2871
3013
  }
2872
- display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
2873
3014
  // Auto-verify changes: build first (catches type errors), then tests
2874
3015
  void this.enforceAutoBuild('final-response');
2875
3016
  void this.enforceAutoTests('final-response');
@@ -3039,9 +3180,14 @@ What's the next action?`;
3039
3180
  return null;
3040
3181
  }
3041
3182
  const usageRatio = total / windowTokens;
3183
+ this.latestTokenUsage = {
3184
+ used: total,
3185
+ limit: windowTokens,
3186
+ };
3042
3187
  // Always update context usage in the UI
3043
3188
  const percentUsed = Math.round(usageRatio * 100);
3044
3189
  this.updateContextUsage(percentUsed);
3190
+ this.refreshStatusLine(true);
3045
3191
  if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
3046
3192
  return null;
3047
3193
  }