erosolar-cli 1.7.333 → 1.7.334

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 (323) hide show
  1. package/README.md +148 -24
  2. package/dist/alpha-zero/agentWrapper.d.ts +84 -0
  3. package/dist/alpha-zero/agentWrapper.d.ts.map +1 -0
  4. package/dist/alpha-zero/agentWrapper.js +171 -0
  5. package/dist/alpha-zero/agentWrapper.js.map +1 -0
  6. package/dist/alpha-zero/codeEvaluator.d.ts +25 -0
  7. package/dist/alpha-zero/codeEvaluator.d.ts.map +1 -0
  8. package/dist/alpha-zero/codeEvaluator.js +273 -0
  9. package/dist/alpha-zero/codeEvaluator.js.map +1 -0
  10. package/dist/alpha-zero/competitiveRunner.d.ts +66 -0
  11. package/dist/alpha-zero/competitiveRunner.d.ts.map +1 -0
  12. package/dist/alpha-zero/competitiveRunner.js +224 -0
  13. package/dist/alpha-zero/competitiveRunner.js.map +1 -0
  14. package/dist/alpha-zero/index.d.ts +67 -0
  15. package/dist/alpha-zero/index.d.ts.map +1 -0
  16. package/dist/alpha-zero/index.js +99 -0
  17. package/dist/alpha-zero/index.js.map +1 -0
  18. package/dist/alpha-zero/introspection.d.ts +128 -0
  19. package/dist/alpha-zero/introspection.d.ts.map +1 -0
  20. package/dist/alpha-zero/introspection.js +300 -0
  21. package/dist/alpha-zero/introspection.js.map +1 -0
  22. package/dist/alpha-zero/metricsTracker.d.ts +71 -0
  23. package/dist/alpha-zero/metricsTracker.d.ts.map +1 -0
  24. package/dist/{core → alpha-zero}/metricsTracker.js +5 -2
  25. package/dist/alpha-zero/metricsTracker.js.map +1 -0
  26. package/dist/alpha-zero/security/core.d.ts +125 -0
  27. package/dist/alpha-zero/security/core.d.ts.map +1 -0
  28. package/dist/alpha-zero/security/core.js +271 -0
  29. package/dist/alpha-zero/security/core.js.map +1 -0
  30. package/dist/alpha-zero/security/google.d.ts +125 -0
  31. package/dist/alpha-zero/security/google.d.ts.map +1 -0
  32. package/dist/alpha-zero/security/google.js +311 -0
  33. package/dist/alpha-zero/security/google.js.map +1 -0
  34. package/dist/alpha-zero/security/googleLoader.d.ts +17 -0
  35. package/dist/alpha-zero/security/googleLoader.d.ts.map +1 -0
  36. package/dist/alpha-zero/security/googleLoader.js +41 -0
  37. package/dist/alpha-zero/security/googleLoader.js.map +1 -0
  38. package/dist/alpha-zero/security/index.d.ts +29 -0
  39. package/dist/alpha-zero/security/index.d.ts.map +1 -0
  40. package/dist/alpha-zero/security/index.js +32 -0
  41. package/dist/alpha-zero/security/index.js.map +1 -0
  42. package/dist/alpha-zero/security/simulation.d.ts +124 -0
  43. package/dist/alpha-zero/security/simulation.d.ts.map +1 -0
  44. package/dist/alpha-zero/security/simulation.js +277 -0
  45. package/dist/alpha-zero/security/simulation.js.map +1 -0
  46. package/dist/alpha-zero/selfModification.d.ts +109 -0
  47. package/dist/alpha-zero/selfModification.d.ts.map +1 -0
  48. package/dist/alpha-zero/selfModification.js +233 -0
  49. package/dist/alpha-zero/selfModification.js.map +1 -0
  50. package/dist/alpha-zero/types.d.ts +170 -0
  51. package/dist/alpha-zero/types.d.ts.map +1 -0
  52. package/dist/alpha-zero/types.js +31 -0
  53. package/dist/alpha-zero/types.js.map +1 -0
  54. package/dist/bin/erosolar.js +21 -5
  55. package/dist/bin/erosolar.js.map +1 -1
  56. package/dist/capabilities/agentSpawningCapability.d.ts.map +1 -1
  57. package/dist/capabilities/agentSpawningCapability.js +31 -56
  58. package/dist/capabilities/agentSpawningCapability.js.map +1 -1
  59. package/dist/capabilities/securityTestingCapability.d.ts +13 -0
  60. package/dist/capabilities/securityTestingCapability.d.ts.map +1 -0
  61. package/dist/capabilities/securityTestingCapability.js +25 -0
  62. package/dist/capabilities/securityTestingCapability.js.map +1 -0
  63. package/dist/contracts/agent-schemas.json +15 -0
  64. package/dist/contracts/tools.schema.json +9 -0
  65. package/dist/core/agent.d.ts +2 -2
  66. package/dist/core/agent.d.ts.map +1 -1
  67. package/dist/core/agent.js.map +1 -1
  68. package/dist/core/aiFlowOptimizer.d.ts +26 -0
  69. package/dist/core/aiFlowOptimizer.d.ts.map +1 -0
  70. package/dist/core/aiFlowOptimizer.js +31 -0
  71. package/dist/core/aiFlowOptimizer.js.map +1 -0
  72. package/dist/core/aiOptimizationEngine.d.ts +158 -0
  73. package/dist/core/aiOptimizationEngine.d.ts.map +1 -0
  74. package/dist/core/aiOptimizationEngine.js +428 -0
  75. package/dist/core/aiOptimizationEngine.js.map +1 -0
  76. package/dist/core/aiOptimizationIntegration.d.ts +93 -0
  77. package/dist/core/aiOptimizationIntegration.d.ts.map +1 -0
  78. package/dist/core/aiOptimizationIntegration.js +250 -0
  79. package/dist/core/aiOptimizationIntegration.js.map +1 -0
  80. package/dist/core/customCommands.d.ts +0 -1
  81. package/dist/core/customCommands.d.ts.map +1 -1
  82. package/dist/core/customCommands.js +0 -3
  83. package/dist/core/customCommands.js.map +1 -1
  84. package/dist/core/enhancedErrorRecovery.d.ts +100 -0
  85. package/dist/core/enhancedErrorRecovery.d.ts.map +1 -0
  86. package/dist/core/enhancedErrorRecovery.js +345 -0
  87. package/dist/core/enhancedErrorRecovery.js.map +1 -0
  88. package/dist/core/hooksSystem.d.ts +65 -0
  89. package/dist/core/hooksSystem.d.ts.map +1 -0
  90. package/dist/core/hooksSystem.js +273 -0
  91. package/dist/core/hooksSystem.js.map +1 -0
  92. package/dist/core/memorySystem.d.ts +48 -0
  93. package/dist/core/memorySystem.d.ts.map +1 -0
  94. package/dist/core/memorySystem.js +271 -0
  95. package/dist/core/memorySystem.js.map +1 -0
  96. package/dist/core/toolPreconditions.d.ts.map +1 -1
  97. package/dist/core/toolPreconditions.js +14 -0
  98. package/dist/core/toolPreconditions.js.map +1 -1
  99. package/dist/core/toolRuntime.d.ts +1 -22
  100. package/dist/core/toolRuntime.d.ts.map +1 -1
  101. package/dist/core/toolRuntime.js +5 -0
  102. package/dist/core/toolRuntime.js.map +1 -1
  103. package/dist/core/toolValidation.d.ts.map +1 -1
  104. package/dist/core/toolValidation.js +3 -14
  105. package/dist/core/toolValidation.js.map +1 -1
  106. package/dist/core/unified/errors.d.ts +189 -0
  107. package/dist/core/unified/errors.d.ts.map +1 -0
  108. package/dist/core/unified/errors.js +497 -0
  109. package/dist/core/unified/errors.js.map +1 -0
  110. package/dist/core/unified/index.d.ts +19 -0
  111. package/dist/core/unified/index.d.ts.map +1 -0
  112. package/dist/core/unified/index.js +68 -0
  113. package/dist/core/unified/index.js.map +1 -0
  114. package/dist/core/unified/schema.d.ts +101 -0
  115. package/dist/core/unified/schema.d.ts.map +1 -0
  116. package/dist/core/unified/schema.js +350 -0
  117. package/dist/core/unified/schema.js.map +1 -0
  118. package/dist/core/unified/toolRuntime.d.ts +179 -0
  119. package/dist/core/unified/toolRuntime.d.ts.map +1 -0
  120. package/dist/core/unified/toolRuntime.js +517 -0
  121. package/dist/core/unified/toolRuntime.js.map +1 -0
  122. package/dist/core/unified/tools.d.ts +127 -0
  123. package/dist/core/unified/tools.d.ts.map +1 -0
  124. package/dist/core/unified/tools.js +1333 -0
  125. package/dist/core/unified/tools.js.map +1 -0
  126. package/dist/core/unified/types.d.ts +352 -0
  127. package/dist/core/unified/types.d.ts.map +1 -0
  128. package/dist/core/unified/types.js +12 -0
  129. package/dist/core/unified/types.js.map +1 -0
  130. package/dist/core/unified/version.d.ts +209 -0
  131. package/dist/core/unified/version.d.ts.map +1 -0
  132. package/dist/core/unified/version.js +454 -0
  133. package/dist/core/unified/version.js.map +1 -0
  134. package/dist/core/validationRunner.d.ts +3 -1
  135. package/dist/core/validationRunner.d.ts.map +1 -1
  136. package/dist/core/validationRunner.js.map +1 -1
  137. package/dist/headless/headlessApp.d.ts.map +1 -1
  138. package/dist/headless/headlessApp.js +0 -21
  139. package/dist/headless/headlessApp.js.map +1 -1
  140. package/dist/mcp/sseClient.d.ts.map +1 -1
  141. package/dist/mcp/sseClient.js +18 -9
  142. package/dist/mcp/sseClient.js.map +1 -1
  143. package/dist/plugins/tools/build/buildPlugin.d.ts +6 -0
  144. package/dist/plugins/tools/build/buildPlugin.d.ts.map +1 -1
  145. package/dist/plugins/tools/build/buildPlugin.js +10 -4
  146. package/dist/plugins/tools/build/buildPlugin.js.map +1 -1
  147. package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
  148. package/dist/plugins/tools/nodeDefaults.js +2 -0
  149. package/dist/plugins/tools/nodeDefaults.js.map +1 -1
  150. package/dist/plugins/tools/security/securityPlugin.d.ts +3 -0
  151. package/dist/plugins/tools/security/securityPlugin.d.ts.map +1 -0
  152. package/dist/plugins/tools/security/securityPlugin.js +12 -0
  153. package/dist/plugins/tools/security/securityPlugin.js.map +1 -0
  154. package/dist/runtime/agentSession.d.ts +2 -2
  155. package/dist/runtime/agentSession.d.ts.map +1 -1
  156. package/dist/runtime/agentSession.js +2 -2
  157. package/dist/runtime/agentSession.js.map +1 -1
  158. package/dist/security/active-stack-security.d.ts +112 -0
  159. package/dist/security/active-stack-security.d.ts.map +1 -0
  160. package/dist/security/active-stack-security.js +296 -0
  161. package/dist/security/active-stack-security.js.map +1 -0
  162. package/dist/security/advanced-persistence-research.d.ts +92 -0
  163. package/dist/security/advanced-persistence-research.d.ts.map +1 -0
  164. package/dist/security/advanced-persistence-research.js +195 -0
  165. package/dist/security/advanced-persistence-research.js.map +1 -0
  166. package/dist/security/advanced-targeting.d.ts +119 -0
  167. package/dist/security/advanced-targeting.d.ts.map +1 -0
  168. package/dist/security/advanced-targeting.js +233 -0
  169. package/dist/security/advanced-targeting.js.map +1 -0
  170. package/dist/security/assessment/vulnerabilityAssessment.d.ts +104 -0
  171. package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +1 -0
  172. package/dist/security/assessment/vulnerabilityAssessment.js +315 -0
  173. package/dist/security/assessment/vulnerabilityAssessment.js.map +1 -0
  174. package/dist/security/authorization/securityAuthorization.d.ts +88 -0
  175. package/dist/security/authorization/securityAuthorization.d.ts.map +1 -0
  176. package/dist/security/authorization/securityAuthorization.js +172 -0
  177. package/dist/security/authorization/securityAuthorization.js.map +1 -0
  178. package/dist/security/comprehensive-targeting.d.ts +85 -0
  179. package/dist/security/comprehensive-targeting.d.ts.map +1 -0
  180. package/dist/security/comprehensive-targeting.js +438 -0
  181. package/dist/security/comprehensive-targeting.js.map +1 -0
  182. package/dist/security/global-security-integration.d.ts +91 -0
  183. package/dist/security/global-security-integration.d.ts.map +1 -0
  184. package/dist/security/global-security-integration.js +218 -0
  185. package/dist/security/global-security-integration.js.map +1 -0
  186. package/dist/security/index.d.ts +38 -0
  187. package/dist/security/index.d.ts.map +1 -0
  188. package/dist/security/index.js +47 -0
  189. package/dist/security/index.js.map +1 -0
  190. package/dist/security/persistence-analyzer.d.ts +56 -0
  191. package/dist/security/persistence-analyzer.d.ts.map +1 -0
  192. package/dist/security/persistence-analyzer.js +187 -0
  193. package/dist/security/persistence-analyzer.js.map +1 -0
  194. package/dist/security/persistence-cli.d.ts +36 -0
  195. package/dist/security/persistence-cli.d.ts.map +1 -0
  196. package/dist/security/persistence-cli.js +160 -0
  197. package/dist/security/persistence-cli.js.map +1 -0
  198. package/dist/security/persistence-research.d.ts +92 -0
  199. package/dist/security/persistence-research.d.ts.map +1 -0
  200. package/dist/security/persistence-research.js +364 -0
  201. package/dist/security/persistence-research.js.map +1 -0
  202. package/dist/security/research/persistenceResearch.d.ts +97 -0
  203. package/dist/security/research/persistenceResearch.d.ts.map +1 -0
  204. package/dist/security/research/persistenceResearch.js +282 -0
  205. package/dist/security/research/persistenceResearch.js.map +1 -0
  206. package/dist/security/security-integration.d.ts +74 -0
  207. package/dist/security/security-integration.d.ts.map +1 -0
  208. package/dist/security/security-integration.js +137 -0
  209. package/dist/security/security-integration.js.map +1 -0
  210. package/dist/security/security-testing-framework.d.ts +112 -0
  211. package/dist/security/security-testing-framework.d.ts.map +1 -0
  212. package/dist/security/security-testing-framework.js +364 -0
  213. package/dist/security/security-testing-framework.js.map +1 -0
  214. package/dist/security/simulation/attackSimulation.d.ts +93 -0
  215. package/dist/security/simulation/attackSimulation.d.ts.map +1 -0
  216. package/dist/security/simulation/attackSimulation.js +341 -0
  217. package/dist/security/simulation/attackSimulation.js.map +1 -0
  218. package/dist/security/strategic-operations.d.ts +100 -0
  219. package/dist/security/strategic-operations.d.ts.map +1 -0
  220. package/dist/security/strategic-operations.js +276 -0
  221. package/dist/security/strategic-operations.js.map +1 -0
  222. package/dist/security/tool-security-wrapper.d.ts +58 -0
  223. package/dist/security/tool-security-wrapper.d.ts.map +1 -0
  224. package/dist/security/tool-security-wrapper.js +156 -0
  225. package/dist/security/tool-security-wrapper.js.map +1 -0
  226. package/dist/shell/claudeCodeStreamHandler.d.ts +145 -0
  227. package/dist/shell/claudeCodeStreamHandler.d.ts.map +1 -0
  228. package/dist/shell/claudeCodeStreamHandler.js +322 -0
  229. package/dist/shell/claudeCodeStreamHandler.js.map +1 -0
  230. package/dist/shell/inputQueueManager.d.ts +144 -0
  231. package/dist/shell/inputQueueManager.d.ts.map +1 -0
  232. package/dist/shell/inputQueueManager.js +290 -0
  233. package/dist/shell/inputQueueManager.js.map +1 -0
  234. package/dist/shell/interactiveShell.d.ts +7 -16
  235. package/dist/shell/interactiveShell.d.ts.map +1 -1
  236. package/dist/shell/interactiveShell.js +166 -235
  237. package/dist/shell/interactiveShell.js.map +1 -1
  238. package/dist/shell/metricsTracker.d.ts +60 -0
  239. package/dist/shell/metricsTracker.d.ts.map +1 -0
  240. package/dist/shell/metricsTracker.js +119 -0
  241. package/dist/shell/metricsTracker.js.map +1 -0
  242. package/dist/shell/shellApp.d.ts +0 -2
  243. package/dist/shell/shellApp.d.ts.map +1 -1
  244. package/dist/shell/shellApp.js +9 -40
  245. package/dist/shell/shellApp.js.map +1 -1
  246. package/dist/shell/streamingOutputManager.d.ts +115 -0
  247. package/dist/shell/streamingOutputManager.d.ts.map +1 -0
  248. package/dist/shell/streamingOutputManager.js +225 -0
  249. package/dist/shell/streamingOutputManager.js.map +1 -0
  250. package/dist/shell/systemPrompt.d.ts.map +1 -1
  251. package/dist/shell/systemPrompt.js +4 -1
  252. package/dist/shell/systemPrompt.js.map +1 -1
  253. package/dist/shell/terminalInput.d.ts +118 -149
  254. package/dist/shell/terminalInput.d.ts.map +1 -1
  255. package/dist/shell/terminalInput.js +532 -689
  256. package/dist/shell/terminalInput.js.map +1 -1
  257. package/dist/shell/terminalInputAdapter.d.ts +21 -79
  258. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  259. package/dist/shell/terminalInputAdapter.js +30 -99
  260. package/dist/shell/terminalInputAdapter.js.map +1 -1
  261. package/dist/subagents/taskRunner.d.ts +1 -7
  262. package/dist/subagents/taskRunner.d.ts.map +1 -1
  263. package/dist/subagents/taskRunner.js +47 -180
  264. package/dist/subagents/taskRunner.js.map +1 -1
  265. package/dist/tools/securityTools.d.ts +22 -0
  266. package/dist/tools/securityTools.d.ts.map +1 -0
  267. package/dist/tools/securityTools.js +448 -0
  268. package/dist/tools/securityTools.js.map +1 -0
  269. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  270. package/dist/ui/ShellUIAdapter.js +12 -13
  271. package/dist/ui/ShellUIAdapter.js.map +1 -1
  272. package/dist/ui/display.d.ts +45 -24
  273. package/dist/ui/display.d.ts.map +1 -1
  274. package/dist/ui/display.js +259 -140
  275. package/dist/ui/display.js.map +1 -1
  276. package/dist/ui/persistentPrompt.d.ts +50 -0
  277. package/dist/ui/persistentPrompt.d.ts.map +1 -0
  278. package/dist/ui/persistentPrompt.js +92 -0
  279. package/dist/ui/persistentPrompt.js.map +1 -0
  280. package/dist/ui/terminalUISchema.d.ts +195 -0
  281. package/dist/ui/terminalUISchema.d.ts.map +1 -0
  282. package/dist/ui/terminalUISchema.js +113 -0
  283. package/dist/ui/terminalUISchema.js.map +1 -0
  284. package/dist/ui/theme.d.ts.map +1 -1
  285. package/dist/ui/theme.js +8 -6
  286. package/dist/ui/theme.js.map +1 -1
  287. package/dist/ui/toolDisplay.d.ts +158 -0
  288. package/dist/ui/toolDisplay.d.ts.map +1 -1
  289. package/dist/ui/toolDisplay.js +348 -0
  290. package/dist/ui/toolDisplay.js.map +1 -1
  291. package/dist/ui/unified/layout.d.ts +0 -1
  292. package/dist/ui/unified/layout.d.ts.map +1 -1
  293. package/dist/ui/unified/layout.js +25 -15
  294. package/dist/ui/unified/layout.js.map +1 -1
  295. package/package.json +4 -4
  296. package/scripts/deploy-security-capabilities.js +178 -0
  297. package/dist/core/hooks.d.ts +0 -113
  298. package/dist/core/hooks.d.ts.map +0 -1
  299. package/dist/core/hooks.js +0 -267
  300. package/dist/core/hooks.js.map +0 -1
  301. package/dist/core/metricsTracker.d.ts +0 -122
  302. package/dist/core/metricsTracker.d.ts.map +0 -1
  303. package/dist/core/metricsTracker.js.map +0 -1
  304. package/dist/core/securityAssessment.d.ts +0 -91
  305. package/dist/core/securityAssessment.d.ts.map +0 -1
  306. package/dist/core/securityAssessment.js +0 -580
  307. package/dist/core/securityAssessment.js.map +0 -1
  308. package/dist/core/verification.d.ts +0 -137
  309. package/dist/core/verification.d.ts.map +0 -1
  310. package/dist/core/verification.js +0 -323
  311. package/dist/core/verification.js.map +0 -1
  312. package/dist/subagents/agentConfig.d.ts +0 -27
  313. package/dist/subagents/agentConfig.d.ts.map +0 -1
  314. package/dist/subagents/agentConfig.js +0 -89
  315. package/dist/subagents/agentConfig.js.map +0 -1
  316. package/dist/subagents/agentRegistry.d.ts +0 -33
  317. package/dist/subagents/agentRegistry.d.ts.map +0 -1
  318. package/dist/subagents/agentRegistry.js +0 -162
  319. package/dist/subagents/agentRegistry.js.map +0 -1
  320. package/dist/utils/frontmatter.d.ts +0 -10
  321. package/dist/utils/frontmatter.d.ts.map +0 -1
  322. package/dist/utils/frontmatter.js +0 -78
  323. package/dist/utils/frontmatter.js.map +0 -1
@@ -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 } from '../ui/theme.js';
5
+ import { theme, formatUserPrompt } 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,11 +19,11 @@ 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 '../core/metricsTracker.js';
22
+ import { MetricsTracker } from './metricsTracker.js';
23
23
  import { listAvailablePlugins } from '../plugins/index.js';
24
+ import { loadMemory, listMemoryPaths, getDefaultProjectMemoryPath, getUserMemoryEditPath, } from '../core/memorySystem.js';
24
25
  import { TerminalInputAdapter } from './terminalInputAdapter.js';
25
- import { renderSessionFrame } from '../ui/unified/layout.js';
26
- import { isUpdateInProgress, maybeOfferCliUpdate } from './updateManager.js';
26
+ import { isUpdateInProgress } from './updateManager.js';
27
27
  import { writeLock } from '../ui/writeLock.js';
28
28
  import { enterStreamingMode, exitStreamingMode } from '../ui/globalWriteLock.js';
29
29
  const execAsync = promisify(exec);
@@ -35,7 +35,6 @@ const DROPDOWN_COLORS = [
35
35
  theme.success,
36
36
  theme.warning,
37
37
  ];
38
- const STREAMING_SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
39
38
  // Load MODEL_PRESETS from centralized schema
40
39
  const MODEL_PRESETS = getModels().map((model) => ({
41
40
  id: model.id,
@@ -50,13 +49,11 @@ const MODEL_PRESETS = getModels().map((model) => ({
50
49
  const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
51
50
  command: cmd.command,
52
51
  description: cmd.description,
53
- category: cmd.category,
54
52
  }));
55
53
  // Load PROVIDER_LABELS from centralized schema
56
54
  const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
57
55
  // Allow enough time for paste detection to kick in before flushing buffered lines
58
56
  const CONTEXT_USAGE_THRESHOLD = 0.9;
59
- const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
60
57
  const CONTEXT_RECENT_MESSAGE_COUNT = 12;
61
58
  const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
62
59
  const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
@@ -97,12 +94,11 @@ export class InteractiveShell {
97
94
  uiAdapter;
98
95
  uiUpdates;
99
96
  _fileChangeTracker = new FileChangeTracker(); // Reserved for future file tracking features
100
- alphaZeroMetrics; // Alpha Zero 2 performance tracking
97
+ sessionMetrics; // Session performance tracking
101
98
  statusSubscription = null;
102
99
  followUpQueue = [];
103
100
  isDrainingQueue = false;
104
101
  activeContextWindowTokens = null;
105
- latestTokenUsage = { used: null, limit: null };
106
102
  sessionPreferences;
107
103
  autosaveEnabled;
108
104
  autoContinueEnabled;
@@ -133,8 +129,6 @@ export class InteractiveShell {
133
129
  statusLineState = null;
134
130
  statusMessageOverride = null;
135
131
  promptRefreshTimer = null;
136
- launchPaletteShown = false;
137
- version;
138
132
  constructor(config) {
139
133
  this.profile = config.profile;
140
134
  this.profileLabel = config.profileLabel;
@@ -148,7 +142,6 @@ export class InteractiveShell {
148
142
  this.autoContinueEnabled = this.sessionPreferences.autoContinue;
149
143
  this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
150
144
  this._enabledPlugins = config.enabledPlugins ?? [];
151
- this.version = config.version ?? '0.0.0';
152
145
  this.initializeSessionHistory();
153
146
  this.sessionState = {
154
147
  provider: config.initialModel.provider,
@@ -169,7 +162,6 @@ export class InteractiveShell {
169
162
  this.slashCommands.push({
170
163
  command: '/agents',
171
164
  description: 'Select the default agent profile (applies on next launch)',
172
- category: 'configuration',
173
165
  });
174
166
  }
175
167
  this.customCommands = loadCustomSlashCommands();
@@ -178,21 +170,18 @@ export class InteractiveShell {
178
170
  this.slashCommands.push({
179
171
  command: custom.command,
180
172
  description: `${custom.description} (custom)`,
181
- category: custom.category ?? 'other',
182
173
  });
183
174
  }
184
175
  if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
185
176
  this.slashCommands.push({
186
177
  command: '/exit',
187
178
  description: 'Quit the CLI immediately',
188
- category: 'other',
189
179
  });
190
180
  }
191
181
  // Add /plugins command
192
182
  this.slashCommands.push({
193
183
  command: '/plugins',
194
184
  description: 'Show available and loaded plugins',
195
- category: 'configuration',
196
185
  });
197
186
  this.statusTracker = config.statusTracker;
198
187
  this.ui = config.ui;
@@ -225,21 +214,19 @@ export class InteractiveShell {
225
214
  onToggleVerify: () => this.toggleVerificationMode(),
226
215
  onToggleAutoContinue: () => this.toggleAutoContinueMode(),
227
216
  });
217
+ // Register output interceptor for cursor positioning during streaming
218
+ this.terminalInput.registerOutputInterceptor(display);
219
+ // Set banner content to be written during unified UI initialization
220
+ this.terminalInput.setBannerContent(display.getBannerContent());
221
+ // Initialize unified UI - clears screen, sets up scroll region, writes banner,
222
+ // and renders input area at bottom
223
+ this.terminalInput.initializeUnifiedUI();
228
224
  // Initialize Alpha Zero 2 metrics tracking
229
- this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
225
+ this.sessionMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
230
226
  this.setupStatusTracking();
231
227
  this.refreshContextGauge();
232
- // Start terminal input (sets up handlers)
233
228
  this.terminalInput.start();
234
- // Enter alternate screen buffer for clean UI control
235
- // This preserves user's terminal history when they exit
236
- this.terminalInput.enterAlternateScreen();
237
- // Stream banner first - this sets up scroll region dynamically
238
- const banner = this.buildBanner();
239
- this.terminalInput.streamContent(banner + '\n\n');
240
- // Render chat box after banner is streamed
241
229
  this.refreshControlBar();
242
- this.terminalInput.forceRender();
243
230
  this.rebuildAgent();
244
231
  this.setupHandlers();
245
232
  this.refreshBannerSessionInfo();
@@ -286,24 +273,14 @@ export class InteractiveShell {
286
273
  this.sessionResumeNotice = null;
287
274
  }
288
275
  async start(initialPrompt) {
289
- // Check for updates in background (non-blocking)
290
- if (this.version) {
291
- void maybeOfferCliUpdate(this.version);
292
- }
293
276
  if (initialPrompt) {
294
277
  this.logUserPrompt(initialPrompt);
295
278
  await this.processInputBlock(initialPrompt);
296
279
  return;
297
280
  }
298
- this.showLaunchCommandPalette();
299
281
  // Ensure the terminal input is visible
300
282
  this.terminalInput.render();
301
283
  }
302
- showLaunchCommandPalette() {
303
- // Disabled: Quick commands palette takes up too much space
304
- // Users can type /help to see available commands
305
- this.launchPaletteShown = true;
306
- }
307
284
  /**
308
285
  * TerminalInputAdapter submit handler
309
286
  */
@@ -317,8 +294,9 @@ export class InteractiveShell {
317
294
  this.handleInputChange('');
318
295
  return;
319
296
  }
320
- // DON'T clear the input here - keep it visible while streaming.
321
- // The input will be cleared after streaming completes in the finally block.
297
+ // Enter streaming mode BEFORE logging prompt - this positions cursor correctly
298
+ // so content appears right after the banner, not at bottom with blank space above
299
+ this.terminalInput.setStreaming(true);
322
300
  this.logUserPrompt(approved);
323
301
  void this.processInputBlock(approved).catch((err) => {
324
302
  display.showError(err instanceof Error ? err.message : String(err), err);
@@ -519,12 +497,12 @@ export class InteractiveShell {
519
497
  this.terminalInput.dispose();
520
498
  // Dispose unified UI adapter
521
499
  this.uiAdapter.dispose();
522
- // Exit alternate screen buffer before printing goodbye
523
- this.terminalInput.exitAlternateScreen();
524
500
  display.newLine();
525
- console.log(theme.ui.muted(''.repeat(44)));
526
- console.log(theme.ui.muted(' Goodbye! · support@ero.solar'));
527
- console.log(theme.ui.muted(''.repeat(44)));
501
+ const version = display.getVersion() || 'unknown';
502
+ console.log(theme.gradient.warm('━'.repeat(50)));
503
+ console.log(` ${theme.gradient.cool('✨ Goodbye!')} ${theme.ui.muted('·')} ${theme.info(`erosolar-cli v${version}`)}`);
504
+ console.log(` ${theme.ui.muted('Support:')} ${theme.info('support@ero.solar')}`);
505
+ console.log(theme.gradient.warm('━'.repeat(50)));
528
506
  exit(0);
529
507
  }
530
508
  /**
@@ -694,14 +672,13 @@ export class InteractiveShell {
694
672
  });
695
673
  }
696
674
  setProcessingStatus(detail) {
697
- this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
698
675
  this.statusTracker.setBase('Working on your request', {
699
676
  detail: this.describeStatusDetail(detail),
700
677
  tone: 'info',
701
678
  });
702
679
  }
703
680
  describeStatusDetail(detail) {
704
- const parts = detail?.trim() ? [detail.trim()] : [];
681
+ const parts = [detail?.trim() || this.describeModelDetail()];
705
682
  const queued = this.followUpQueue.length;
706
683
  if (queued > 0) {
707
684
  parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
@@ -714,18 +691,12 @@ export class InteractiveShell {
714
691
  }
715
692
  refreshContextGauge() {
716
693
  const tokens = getContextWindowTokens(this.sessionState.model);
717
- const normalizedTokens = typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
718
- this.activeContextWindowTokens = normalizedTokens;
719
- if (normalizedTokens !== null) {
720
- this.latestTokenUsage = {
721
- used: this.latestTokenUsage.used,
722
- limit: normalizedTokens,
723
- };
724
- }
694
+ this.activeContextWindowTokens =
695
+ typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
725
696
  }
726
697
  updateContextUsage(percentage) {
727
698
  this.uiAdapter.updateContextUsage(percentage);
728
- this.terminalInput.setContextUsage(percentage, CONTEXT_AUTOCOMPACT_PERCENT);
699
+ this.terminalInput.setContextUsage(percentage);
729
700
  }
730
701
  refreshControlBar() {
731
702
  this.terminalInput.setModeToggles({
@@ -733,9 +704,9 @@ export class InteractiveShell {
733
704
  autoContinueEnabled: this.autoContinueEnabled,
734
705
  verificationHotkey: 'alt+v',
735
706
  autoContinueHotkey: 'alt+c',
736
- thinkingModeLabel: this.thinkingMode,
737
- thinkingHotkey: '/thinking',
738
707
  });
708
+ // Update persistent model info display
709
+ this.terminalInput.setModelInfo(this.describeModelDetail());
739
710
  this.refreshStatusLine();
740
711
  this.terminalInput.render();
741
712
  }
@@ -766,25 +737,6 @@ export class InteractiveShell {
766
737
  // Set main status (tool execution, etc.) - shown when not overridden
767
738
  const statusText = this.formatStatusLine(this.statusLineState);
768
739
  this.terminalInput.setStatusMessage(statusText);
769
- // Surface meta header (elapsed + context usage) above the divider
770
- const elapsedSeconds = this.statusLineState
771
- ? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
772
- : null;
773
- const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
774
- const tokensUsed = this.latestTokenUsage.used;
775
- const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
776
- this.terminalInput.setMetaStatus({
777
- elapsedSeconds,
778
- tokensUsed,
779
- tokenLimit,
780
- thinkingMs,
781
- thinkingHasContent: display.isSpinnerActive(),
782
- });
783
- // Keep model/provider visible in the controls bar
784
- this.terminalInput.setModelContext({
785
- model: this.sessionState.model,
786
- provider: this.providerLabel(this.sessionState.provider),
787
- });
788
740
  if (forceRender) {
789
741
  this.terminalInput.render();
790
742
  }
@@ -844,14 +796,15 @@ export class InteractiveShell {
844
796
  this.terminalInput.render();
845
797
  }
846
798
  /**
847
- * Log user prompt to the scroll region so it's part of the conversation flow.
799
+ * Log the user's prompt as a visible message in the conversation.
800
+ * This creates a persistent log entry that remains visible during and after streaming.
848
801
  */
849
802
  logUserPrompt(text) {
850
- if (!text.trim())
851
- return;
852
- // Format with user prompt prefix and write to scroll region
853
- const formatted = `${theme.user('>')} ${text}\n`;
854
- this.terminalInput.writeToScrollRegion(formatted);
803
+ // Display the user's prompt with the standard prefix
804
+ const prefix = formatUserPrompt();
805
+ display.stream(`\n${prefix}${text}\n\n`);
806
+ // Update content end row so chat box renders below the user prompt
807
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
855
808
  }
856
809
  requestPromptRefresh(force = false) {
857
810
  if (force) {
@@ -876,40 +829,16 @@ export class InteractiveShell {
876
829
  this.stopStreamingHeartbeat();
877
830
  // Enter global streaming mode - blocks all non-streaming UI output
878
831
  enterStreamingMode();
879
- // Set up scroll region for streaming content
880
- this.terminalInput.enterStreamingScrollRegion();
881
832
  this.uiUpdates.setMode('streaming');
882
833
  this.streamingHeartbeatStart = Date.now();
883
834
  this.streamingHeartbeatFrame = 0;
884
- const initialFrame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
885
- this.streamingStatusLabel = this.buildStreamingStatus(`${initialFrame} ${label}`, 0);
886
- display.updateStreamingStatus(this.streamingStatusLabel);
887
- this.refreshStatusLine(true);
888
- // Periodically refresh the pinned input/status region while streaming so
889
- // elapsed time remains visible without interrupting the scroll region.
890
- this.uiUpdates.startHeartbeat('streaming', {
891
- intervalMs: 1000,
892
- lane: 'heartbeat',
893
- mode: ['streaming', 'processing'],
894
- coalesceKey: 'streaming:heartbeat',
895
- run: () => {
896
- const elapsedSeconds = this.streamingHeartbeatStart
897
- ? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
898
- : 0;
899
- this.streamingHeartbeatFrame =
900
- (this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
901
- const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
902
- this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
903
- display.updateStreamingStatus(this.streamingStatusLabel);
904
- this.refreshStatusLine(true);
905
- },
906
- });
835
+ // Note: We don't start a heartbeat during streaming anymore
836
+ // because the UI shouldn't be rendering during streaming.
837
+ // The streaming status is shown in the streaming header instead.
907
838
  }
908
839
  stopStreamingHeartbeat() {
909
840
  // Exit global streaming mode - allows UI to render again
910
841
  exitStreamingMode();
911
- // Exit scroll region mode
912
- this.terminalInput.exitStreamingScrollRegion();
913
842
  this.uiUpdates.stopHeartbeat('streaming');
914
843
  this.streamingHeartbeatStart = null;
915
844
  this.streamingHeartbeatFrame = 0;
@@ -921,28 +850,10 @@ export class InteractiveShell {
921
850
  // Force refresh to update the input area now that streaming has ended
922
851
  this.refreshStatusLine(true);
923
852
  }
924
- buildStreamingStatus(label, elapsedSeconds) {
853
+ buildStreamingStatus(label) {
925
854
  const detail = this.describeModelDetail();
926
- const elapsedLabel = typeof elapsedSeconds === 'number' && elapsedSeconds >= 0
927
- ? theme.ui.muted(this.formatElapsedShort(elapsedSeconds))
928
- : null;
929
- const prefix = theme.info('⏺');
930
- const parts = [label];
931
- if (detail) {
932
- parts.push(theme.ui.muted('·'), detail);
933
- }
934
- if (elapsedLabel) {
935
- parts.push(theme.ui.muted('·'), elapsedLabel);
936
- }
937
- return `${prefix} ${parts.join(' ')}`.trim();
938
- }
939
- formatElapsedShort(seconds) {
940
- if (seconds < 60) {
941
- return `${seconds}s`;
942
- }
943
- const minutes = Math.floor(seconds / 60);
944
- const remaining = seconds % 60;
945
- return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
855
+ const prefix = theme.info('');
856
+ return detail ? `${prefix} ${label} ${theme.ui.muted('·')} ${detail}` : `${prefix} ${label}`;
946
857
  }
947
858
  refreshQueueIndicators() {
948
859
  if (this.isProcessing) {
@@ -1190,6 +1101,17 @@ export class InteractiveShell {
1190
1101
  case '/discover':
1191
1102
  await this.discoverModelsCommand();
1192
1103
  break;
1104
+ case '/memory':
1105
+ this.handleMemoryCommand(input);
1106
+ break;
1107
+ case '/clear':
1108
+ display.clear();
1109
+ this.cachedHistory = [];
1110
+ display.showInfo('Conversation cleared.');
1111
+ break;
1112
+ case '/help':
1113
+ this.showHelp();
1114
+ break;
1193
1115
  default:
1194
1116
  if (!(await this.tryCustomSlashCommand(command, input))) {
1195
1117
  display.showWarning(`Unknown command "${command}".`);
@@ -1498,6 +1420,99 @@ export class InteractiveShell {
1498
1420
  // Display keyboard shortcuts help (Claude Code style)
1499
1421
  display.showSystemMessage(formatShortcutsHelp());
1500
1422
  }
1423
+ handleMemoryCommand(input) {
1424
+ const tokens = input.trim().split(/\s+/).slice(1);
1425
+ const action = (tokens.shift() ?? 'show').toLowerCase();
1426
+ switch (action) {
1427
+ case '':
1428
+ case 'show':
1429
+ case 'list': {
1430
+ this.showMemoryStatus();
1431
+ break;
1432
+ }
1433
+ case 'paths': {
1434
+ this.showMemoryPaths();
1435
+ break;
1436
+ }
1437
+ case 'edit': {
1438
+ const level = (tokens[0] ?? 'project').toLowerCase();
1439
+ this.openMemoryForEdit(level);
1440
+ break;
1441
+ }
1442
+ default:
1443
+ display.showWarning('Usage: /memory [show|paths|edit <user|project>]');
1444
+ break;
1445
+ }
1446
+ }
1447
+ showMemoryStatus() {
1448
+ const memory = loadMemory(this.workingDir);
1449
+ const lines = [];
1450
+ lines.push(theme.bold('Persistent Memory'));
1451
+ lines.push('');
1452
+ if (memory.sources.length === 0) {
1453
+ lines.push(theme.secondary('No memory files found.'));
1454
+ lines.push('');
1455
+ lines.push(`Create ${theme.info('EROSOLAR.md')} in your project to add persistent context.`);
1456
+ lines.push(`Use ${theme.info('/memory edit project')} to create one.`);
1457
+ }
1458
+ else {
1459
+ for (const source of memory.sources) {
1460
+ const levelLabel = source.level === 'enterprise' ? 'Enterprise' :
1461
+ source.level === 'user' ? 'User' : 'Project';
1462
+ const preview = source.content.slice(0, 200).replace(/\n/g, ' ').trim();
1463
+ const truncated = source.content.length > 200 ? '...' : '';
1464
+ lines.push(`${theme.success('●')} ${theme.bold(levelLabel)}: ${source.path}`);
1465
+ lines.push(` ${theme.dim(preview + truncated)}`);
1466
+ lines.push('');
1467
+ }
1468
+ if (memory.importedPaths.length > memory.sources.length) {
1469
+ lines.push(theme.secondary(`Imported ${memory.importedPaths.length - memory.sources.length} additional files via @imports.`));
1470
+ }
1471
+ }
1472
+ display.showSystemMessage(lines.join('\n'));
1473
+ }
1474
+ showMemoryPaths() {
1475
+ const paths = listMemoryPaths(this.workingDir);
1476
+ const lines = [];
1477
+ lines.push(theme.bold('Memory File Locations'));
1478
+ lines.push('');
1479
+ for (const { level, path, exists } of paths) {
1480
+ const icon = exists ? theme.success('✓') : theme.dim('○');
1481
+ const levelLabel = level.charAt(0).toUpperCase() + level.slice(1);
1482
+ lines.push(`${icon} ${levelLabel}: ${path}`);
1483
+ }
1484
+ lines.push('');
1485
+ lines.push(theme.secondary('Create any of these files to add persistent memory.'));
1486
+ lines.push(theme.secondary('Use @path/to/file.md syntax to import other files.'));
1487
+ display.showSystemMessage(lines.join('\n'));
1488
+ }
1489
+ openMemoryForEdit(level) {
1490
+ let targetPath;
1491
+ if (level === 'user') {
1492
+ targetPath = getUserMemoryEditPath();
1493
+ }
1494
+ else if (level === 'project') {
1495
+ targetPath = getDefaultProjectMemoryPath(this.workingDir);
1496
+ }
1497
+ else {
1498
+ display.showWarning('Specify "user" or "project" to edit. Enterprise memory is read-only.');
1499
+ return;
1500
+ }
1501
+ display.showInfo(`Memory file: ${targetPath}`);
1502
+ display.showInfo('Create or edit this file to add persistent context for the AI.');
1503
+ display.showInfo('');
1504
+ display.showInfo('Example EROSOLAR.md content:');
1505
+ display.showInfo('');
1506
+ display.showInfo(theme.dim(`# Project Guidelines
1507
+
1508
+ When working in this codebase:
1509
+ - Follow TypeScript strict mode conventions
1510
+ - Use functional patterns where appropriate
1511
+ - Run tests before committing
1512
+
1513
+ @./docs/coding-standards.md
1514
+ `));
1515
+ }
1501
1516
  showFileChangeSummary() {
1502
1517
  const summary = this._fileChangeTracker.getSummary();
1503
1518
  const changes = this._fileChangeTracker.getAllChanges();
@@ -1540,11 +1555,11 @@ export class InteractiveShell {
1540
1555
  display.showSystemMessage(lines.join('\n'));
1541
1556
  }
1542
1557
  showAlphaZeroMetrics() {
1543
- const summary = this.alphaZeroMetrics.getPerformanceSummary();
1558
+ const summary = this.sessionMetrics.getPerformanceSummary();
1544
1559
  display.showSystemMessage(summary);
1545
1560
  }
1546
1561
  showImprovementSuggestions() {
1547
- const suggestions = this.alphaZeroMetrics.getImprovementSuggestions();
1562
+ const suggestions = this.sessionMetrics.getImprovementSuggestions();
1548
1563
  if (suggestions.length === 0) {
1549
1564
  display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
1550
1565
  return;
@@ -1590,9 +1605,7 @@ export class InteractiveShell {
1590
1605
  }
1591
1606
  }
1592
1607
  lines.push(theme.secondary('CLI Flags:'));
1593
- lines.push(' --alpha-zero Enable Alpha Zero 2 RL framework');
1594
1608
  lines.push(' --coding Enable enhanced coding tools');
1595
- lines.push(' --security Enable security research tools');
1596
1609
  lines.push(' --all-plugins Enable all optional plugins');
1597
1610
  display.showSystemMessage(lines.join('\n'));
1598
1611
  }
@@ -1836,75 +1849,6 @@ export class InteractiveShell {
1836
1849
  }
1837
1850
  return `${warning.label}: ${warning.reason}.`;
1838
1851
  }
1839
- buildLaunchCommandPalette() {
1840
- const entries = [];
1841
- const secretsSummary = this.summarizeSecretsForPalette();
1842
- const toolSummary = this.getToolSelectionSummary();
1843
- const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
1844
- for (const command of this.slashCommands) {
1845
- const entry = {
1846
- command: command.command,
1847
- description: command.description,
1848
- category: command.category ?? 'other',
1849
- };
1850
- switch (command.command) {
1851
- case '/secrets':
1852
- if (secretsSummary.text) {
1853
- entry.description = `${command.description} (${secretsSummary.text})`;
1854
- entry.tone = secretsSummary.tone;
1855
- }
1856
- break;
1857
- case '/tools':
1858
- if (toolSummary) {
1859
- entry.description = `${command.description} (${toolSummary})`;
1860
- }
1861
- break;
1862
- case '/sessions':
1863
- entry.description = `${command.description} (autosave ${autosaveLabel})`;
1864
- break;
1865
- case '/model':
1866
- entry.description = `${command.description} (current: ${this.sessionState.model})`;
1867
- break;
1868
- case '/provider':
1869
- entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
1870
- break;
1871
- default:
1872
- break;
1873
- }
1874
- entries.push(entry);
1875
- }
1876
- return entries;
1877
- }
1878
- summarizeSecretsForPalette() {
1879
- const definitions = listSecretDefinitions();
1880
- if (!definitions.length) {
1881
- return { text: null };
1882
- }
1883
- const missing = definitions.filter((definition) => !getSecretValue(definition.id));
1884
- if (missing.length === 0) {
1885
- return { text: 'all configured', tone: 'success' };
1886
- }
1887
- const labels = missing.map((definition) => definition.label ?? definition.id);
1888
- return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
1889
- }
1890
- getToolSelectionSummary() {
1891
- const toolSettings = loadToolSettings();
1892
- const selection = buildEnabledToolSet(toolSettings);
1893
- const options = getToolToggleOptions();
1894
- if (!options.length) {
1895
- return null;
1896
- }
1897
- const enabledCount = options.filter((option) => selection.has(option.id)).length;
1898
- return `${enabledCount}/${options.length} enabled`;
1899
- }
1900
- formatList(values, maxItems = 3) {
1901
- if (!values.length) {
1902
- return '';
1903
- }
1904
- const shown = values.slice(0, maxItems);
1905
- const suffix = values.length > maxItems ? ', …' : '';
1906
- return `${shown.join(', ')}${suffix}`;
1907
- }
1908
1852
  buildSlashCommandList(header) {
1909
1853
  const lines = [theme.gradient.primary(header), ''];
1910
1854
  for (const command of this.slashCommands) {
@@ -2373,7 +2317,7 @@ export class InteractiveShell {
2373
2317
  this.autosaveIfEnabled();
2374
2318
  // Track metrics with Alpha Zero 2
2375
2319
  const elapsedMs = Date.now() - requestStartTime;
2376
- this.alphaZeroMetrics.recordMessage(elapsedMs);
2320
+ this.sessionMetrics.recordMessage(elapsedMs);
2377
2321
  if (!responseText?.trim()) {
2378
2322
  display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
2379
2323
  }
@@ -2391,10 +2335,14 @@ export class InteractiveShell {
2391
2335
  this.stopStreamingHeartbeat();
2392
2336
  this.isProcessing = false;
2393
2337
  this.terminalInput.setStreaming(false);
2338
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
2394
2339
  this.uiAdapter.endProcessing('Ready for prompts');
2395
2340
  this.setIdleStatus();
2396
2341
  display.newLine();
2397
2342
  this.updateStatusMessage(null);
2343
+ // Claude Code style: Show unified status bar before prompt
2344
+ // This creates consistent UI between startup and post-streaming
2345
+ this.showUnifiedStatusBar();
2398
2346
  queueMicrotask(() => this.uiUpdates.setMode('idle'));
2399
2347
  // CRITICAL: Ensure readline prompt is active for user input
2400
2348
  // Claude Code style: New prompt naturally appears at bottom
@@ -2471,14 +2419,13 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
2471
2419
  try {
2472
2420
  // Send the request and capture the response (streaming disabled)
2473
2421
  display.showThinking('Responding...');
2474
- this.refreshStatusLine(true);
2475
2422
  const response = await agent.send(currentPrompt, true);
2476
2423
  await this.awaitPendingCleanup();
2477
2424
  this.captureHistorySnapshot();
2478
2425
  this.autosaveIfEnabled();
2479
2426
  // Track metrics
2480
2427
  const elapsedMs = Date.now() - overallStartTime;
2481
- this.alphaZeroMetrics.recordMessage(elapsedMs);
2428
+ this.sessionMetrics.recordMessage(elapsedMs);
2482
2429
  if (!response?.trim()) {
2483
2430
  display.showWarning('Model returned an empty response. Retrying this iteration...');
2484
2431
  consecutiveNoProgress++;
@@ -2615,6 +2562,7 @@ What's the next action?`;
2615
2562
  this.stopStreamingHeartbeat();
2616
2563
  this.isProcessing = false;
2617
2564
  this.terminalInput.setStreaming(false);
2565
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
2618
2566
  this.uiAdapter.endProcessing('Ready for prompts');
2619
2567
  this.setIdleStatus();
2620
2568
  this.updateStatusMessage(null);
@@ -2971,10 +2919,8 @@ What's the next action?`;
2971
2919
  try {
2972
2920
  // Send the error to the agent for fixing
2973
2921
  display.showThinking('Analyzing build errors');
2974
- this.refreshStatusLine(true);
2975
2922
  const response = await this.agent.send(prompt, true);
2976
2923
  display.stopThinking();
2977
- this.refreshStatusLine(true);
2978
2924
  if (response) {
2979
2925
  display.showAssistantMessage(response, { isFinal: true });
2980
2926
  }
@@ -3001,8 +2947,8 @@ What's the next action?`;
3001
2947
  };
3002
2948
  this.agent = this.runtimeSession.createAgent(selection, {
3003
2949
  onStreamChunk: (chunk) => {
3004
- // Stream output using clean streamContent() - chat box floats below
3005
- this.terminalInput.streamContent(chunk);
2950
+ // Stream output directly - no spinner during streaming to avoid race conditions
2951
+ display.stream(chunk);
3006
2952
  },
3007
2953
  onStreamFallback: (info) => this.handleStreamingFallback(info),
3008
2954
  onAssistantMessage: (content, metadata) => {
@@ -3024,16 +2970,18 @@ What's the next action?`;
3024
2970
  display.showAssistantMessage(finalContent, enriched);
3025
2971
  }
3026
2972
  }
3027
- // Status shown in mode controls bar - no separate status line needed
2973
+ // Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
3028
2974
  display.stopThinking();
3029
- // Update context usage for mode controls display
2975
+ // Calculate context usage
2976
+ let contextInfo;
3030
2977
  if (enriched.contextWindowTokens && metadata.usage) {
3031
2978
  const total = this.totalTokens(metadata.usage);
3032
2979
  if (total && total > 0) {
3033
2980
  const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
3034
- this.updateContextUsage(percentage);
2981
+ contextInfo = { percentage, tokens: total };
3035
2982
  }
3036
2983
  }
2984
+ display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
3037
2985
  // Auto-verify changes: build first (catches type errors), then tests
3038
2986
  void this.enforceAutoBuild('final-response');
3039
2987
  void this.enforceAutoTests('final-response');
@@ -3103,6 +3051,7 @@ What's the next action?`;
3103
3051
  this.stopStreamingHeartbeat();
3104
3052
  this.updateStatusMessage(null);
3105
3053
  this.terminalInput.setStreaming(false);
3054
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
3106
3055
  this.terminalInput.render();
3107
3056
  },
3108
3057
  onVerificationNeeded: () => {
@@ -3139,6 +3088,7 @@ What's the next action?`;
3139
3088
  resetChatBoxAfterModelSwap() {
3140
3089
  this.updateStatusMessage(null);
3141
3090
  this.terminalInput.setStreaming(false);
3091
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
3142
3092
  this.terminalInput.render();
3143
3093
  this.ensureReadlineReady();
3144
3094
  }
@@ -3203,14 +3153,9 @@ What's the next action?`;
3203
3153
  return null;
3204
3154
  }
3205
3155
  const usageRatio = total / windowTokens;
3206
- this.latestTokenUsage = {
3207
- used: total,
3208
- limit: windowTokens,
3209
- };
3210
3156
  // Always update context usage in the UI
3211
3157
  const percentUsed = Math.round(usageRatio * 100);
3212
3158
  this.updateContextUsage(percentUsed);
3213
- this.refreshStatusLine(true);
3214
3159
  if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
3215
3160
  return null;
3216
3161
  }
@@ -3477,22 +3422,6 @@ What's the next action?`;
3477
3422
  this.sessionState.reasoningEffort = preset.reasoningEffort;
3478
3423
  }
3479
3424
  }
3480
- /**
3481
- * Build the session banner.
3482
- */
3483
- buildBanner() {
3484
- const terminalWidth = output.columns ?? 100;
3485
- const width = Math.min(terminalWidth - 4, 110);
3486
- return renderSessionFrame({
3487
- profileLabel: this.profileLabel,
3488
- profileName: this.profile,
3489
- model: this.sessionState.model,
3490
- provider: this.sessionState.provider,
3491
- workspace: this.workingDir,
3492
- version: this.version,
3493
- width,
3494
- });
3495
- }
3496
3425
  refreshBannerSessionInfo() {
3497
3426
  const nextState = {
3498
3427
  model: this.sessionState.model,
@@ -3503,11 +3432,13 @@ What's the next action?`;
3503
3432
  return;
3504
3433
  }
3505
3434
  this.refreshContextGauge();
3506
- // Banner is no longer stored in display - it was streamed as content
3507
- // Model/provider changes are visible in the control bar
3435
+ display.updateSessionInfo(nextState.model, nextState.provider);
3436
+ // Update the persistent model info display in terminal input
3437
+ this.terminalInput.setModelInfo(this.describeModelDetail());
3508
3438
  if (!this.isProcessing) {
3509
3439
  this.setIdleStatus();
3510
3440
  }
3441
+ // Pinned header rows are disabled; scroll region handles all output.
3511
3442
  this.bannerSessionState = nextState;
3512
3443
  }
3513
3444
  providerLabel(id) {