erosolar-cli 1.7.274 → 1.7.275

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 +0 -1
  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 -10
  235. package/dist/shell/interactiveShell.d.ts.map +1 -1
  236. package/dist/shell/interactiveShell.js +160 -198
  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 +1 -36
  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 +176 -74
  254. package/dist/shell/terminalInput.d.ts.map +1 -1
  255. package/dist/shell/terminalInput.js +879 -490
  256. package/dist/shell/terminalInput.js.map +1 -1
  257. package/dist/shell/terminalInputAdapter.d.ts +33 -28
  258. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  259. package/dist/shell/terminalInputAdapter.js +46 -26
  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 +8 -23
  273. package/dist/ui/display.d.ts.map +1 -1
  274. package/dist/ui/display.js +55 -141
  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 +1 -1
  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,8 +19,9 @@ 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
26
  import { isUpdateInProgress } from './updateManager.js';
26
27
  import { writeLock } from '../ui/writeLock.js';
@@ -34,7 +35,6 @@ const DROPDOWN_COLORS = [
34
35
  theme.success,
35
36
  theme.warning,
36
37
  ];
37
- const STREAMING_SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
38
38
  // Load MODEL_PRESETS from centralized schema
39
39
  const MODEL_PRESETS = getModels().map((model) => ({
40
40
  id: model.id,
@@ -49,13 +49,11 @@ const MODEL_PRESETS = getModels().map((model) => ({
49
49
  const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
50
50
  command: cmd.command,
51
51
  description: cmd.description,
52
- category: cmd.category,
53
52
  }));
54
53
  // Load PROVIDER_LABELS from centralized schema
55
54
  const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
56
55
  // Allow enough time for paste detection to kick in before flushing buffered lines
57
56
  const CONTEXT_USAGE_THRESHOLD = 0.9;
58
- const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
59
57
  const CONTEXT_RECENT_MESSAGE_COUNT = 12;
60
58
  const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
61
59
  const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
@@ -96,12 +94,11 @@ export class InteractiveShell {
96
94
  uiAdapter;
97
95
  uiUpdates;
98
96
  _fileChangeTracker = new FileChangeTracker(); // Reserved for future file tracking features
99
- alphaZeroMetrics; // Alpha Zero 2 performance tracking
97
+ sessionMetrics; // Session performance tracking
100
98
  statusSubscription = null;
101
99
  followUpQueue = [];
102
100
  isDrainingQueue = false;
103
101
  activeContextWindowTokens = null;
104
- latestTokenUsage = { used: null, limit: null };
105
102
  sessionPreferences;
106
103
  autosaveEnabled;
107
104
  autoContinueEnabled;
@@ -132,7 +129,6 @@ export class InteractiveShell {
132
129
  statusLineState = null;
133
130
  statusMessageOverride = null;
134
131
  promptRefreshTimer = null;
135
- launchPaletteShown = false;
136
132
  constructor(config) {
137
133
  this.profile = config.profile;
138
134
  this.profileLabel = config.profileLabel;
@@ -166,7 +162,6 @@ export class InteractiveShell {
166
162
  this.slashCommands.push({
167
163
  command: '/agents',
168
164
  description: 'Select the default agent profile (applies on next launch)',
169
- category: 'configuration',
170
165
  });
171
166
  }
172
167
  this.customCommands = loadCustomSlashCommands();
@@ -175,21 +170,18 @@ export class InteractiveShell {
175
170
  this.slashCommands.push({
176
171
  command: custom.command,
177
172
  description: `${custom.description} (custom)`,
178
- category: custom.category ?? 'other',
179
173
  });
180
174
  }
181
175
  if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
182
176
  this.slashCommands.push({
183
177
  command: '/exit',
184
178
  description: 'Quit the CLI immediately',
185
- category: 'other',
186
179
  });
187
180
  }
188
181
  // Add /plugins command
189
182
  this.slashCommands.push({
190
183
  command: '/plugins',
191
184
  description: 'Show available and loaded plugins',
192
- category: 'configuration',
193
185
  });
194
186
  this.statusTracker = config.statusTracker;
195
187
  this.ui = config.ui;
@@ -224,18 +216,21 @@ export class InteractiveShell {
224
216
  });
225
217
  // Register output interceptor for cursor positioning during streaming
226
218
  this.terminalInput.registerOutputInterceptor(display);
219
+ // Set banner renderer for unified UI initialization
220
+ // When streaming mode is entered, the screen is cleared and banner re-rendered
221
+ // inside the scroll region for a consistent layout
222
+ this.terminalInput.setBannerRenderer(() => display.renderBannerToContent());
223
+ // Use flow mode: input renders inline after content for a unified layout
224
+ // This eliminates the blank space between banner and input area
225
+ this.terminalInput.setFlowMode(true);
226
+ // Set content end row so input renders right after startup content
227
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
227
228
  // Initialize Alpha Zero 2 metrics tracking
228
- this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
229
+ this.sessionMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
229
230
  this.setupStatusTracking();
230
231
  this.refreshContextGauge();
231
232
  this.terminalInput.start();
232
233
  this.refreshControlBar();
233
- // Clear and re-render banner in the scroll region so it's part of the unified UI
234
- this.terminalInput.clearScrollRegion();
235
- const bannerContent = display.getRenderedBanner();
236
- if (bannerContent) {
237
- this.terminalInput.writeToScrollRegion(bannerContent + '\n');
238
- }
239
234
  this.rebuildAgent();
240
235
  this.setupHandlers();
241
236
  this.refreshBannerSessionInfo();
@@ -287,15 +282,9 @@ export class InteractiveShell {
287
282
  await this.processInputBlock(initialPrompt);
288
283
  return;
289
284
  }
290
- this.showLaunchCommandPalette();
291
285
  // Ensure the terminal input is visible
292
286
  this.terminalInput.render();
293
287
  }
294
- showLaunchCommandPalette() {
295
- // Disabled: Quick commands palette takes up too much space
296
- // Users can type /help to see available commands
297
- this.launchPaletteShown = true;
298
- }
299
288
  /**
300
289
  * TerminalInputAdapter submit handler
301
290
  */
@@ -309,8 +298,9 @@ export class InteractiveShell {
309
298
  this.handleInputChange('');
310
299
  return;
311
300
  }
312
- // DON'T clear the input here - keep it visible while streaming.
313
- // The input will be cleared after streaming completes in the finally block.
301
+ // Enter streaming mode BEFORE logging prompt - this positions cursor correctly
302
+ // so content appears right after the banner, not at bottom with blank space above
303
+ this.terminalInput.setStreaming(true);
314
304
  this.logUserPrompt(approved);
315
305
  void this.processInputBlock(approved).catch((err) => {
316
306
  display.showError(err instanceof Error ? err.message : String(err), err);
@@ -512,9 +502,10 @@ export class InteractiveShell {
512
502
  // Dispose unified UI adapter
513
503
  this.uiAdapter.dispose();
514
504
  display.newLine();
515
- console.log(theme.ui.muted('━'.repeat(44)));
516
- console.log(theme.ui.muted(' Goodbye! · support@ero.solar'));
517
- console.log(theme.ui.muted(''.repeat(44)));
505
+ console.log(theme.gradient.warm('━'.repeat(50)));
506
+ console.log(` ${theme.gradient.cool('Goodbye!')} ${theme.ui.muted('·')} ${theme.info('support@ero.solar')}`);
507
+ console.log(` ${theme.ui.muted('Read:')} ${theme.accent('anthropic.com/news/disrupting-AI-espionage')}`);
508
+ console.log(theme.gradient.warm('━'.repeat(50)));
518
509
  exit(0);
519
510
  }
520
511
  /**
@@ -684,14 +675,13 @@ export class InteractiveShell {
684
675
  });
685
676
  }
686
677
  setProcessingStatus(detail) {
687
- this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
688
678
  this.statusTracker.setBase('Working on your request', {
689
679
  detail: this.describeStatusDetail(detail),
690
680
  tone: 'info',
691
681
  });
692
682
  }
693
683
  describeStatusDetail(detail) {
694
- const parts = detail?.trim() ? [detail.trim()] : [];
684
+ const parts = [detail?.trim() || this.describeModelDetail()];
695
685
  const queued = this.followUpQueue.length;
696
686
  if (queued > 0) {
697
687
  parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
@@ -704,18 +694,12 @@ export class InteractiveShell {
704
694
  }
705
695
  refreshContextGauge() {
706
696
  const tokens = getContextWindowTokens(this.sessionState.model);
707
- const normalizedTokens = typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
708
- this.activeContextWindowTokens = normalizedTokens;
709
- if (normalizedTokens !== null) {
710
- this.latestTokenUsage = {
711
- used: this.latestTokenUsage.used,
712
- limit: normalizedTokens,
713
- };
714
- }
697
+ this.activeContextWindowTokens =
698
+ typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
715
699
  }
716
700
  updateContextUsage(percentage) {
717
701
  this.uiAdapter.updateContextUsage(percentage);
718
- this.terminalInput.setContextUsage(percentage, CONTEXT_AUTOCOMPACT_PERCENT);
702
+ this.terminalInput.setContextUsage(percentage);
719
703
  }
720
704
  refreshControlBar() {
721
705
  this.terminalInput.setModeToggles({
@@ -723,9 +707,9 @@ export class InteractiveShell {
723
707
  autoContinueEnabled: this.autoContinueEnabled,
724
708
  verificationHotkey: 'alt+v',
725
709
  autoContinueHotkey: 'alt+c',
726
- thinkingModeLabel: this.thinkingMode,
727
- thinkingHotkey: '/thinking',
728
710
  });
711
+ // Update persistent model info display
712
+ this.terminalInput.setModelInfo(this.describeModelDetail());
729
713
  this.refreshStatusLine();
730
714
  this.terminalInput.render();
731
715
  }
@@ -756,25 +740,6 @@ export class InteractiveShell {
756
740
  // Set main status (tool execution, etc.) - shown when not overridden
757
741
  const statusText = this.formatStatusLine(this.statusLineState);
758
742
  this.terminalInput.setStatusMessage(statusText);
759
- // Surface meta header (elapsed + context usage) above the divider
760
- const elapsedSeconds = this.statusLineState
761
- ? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
762
- : null;
763
- const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
764
- const tokensUsed = this.latestTokenUsage.used;
765
- const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
766
- this.terminalInput.setMetaStatus({
767
- elapsedSeconds,
768
- tokensUsed,
769
- tokenLimit,
770
- thinkingMs,
771
- thinkingHasContent: display.isSpinnerActive(),
772
- });
773
- // Keep model/provider visible in the controls bar
774
- this.terminalInput.setModelContext({
775
- model: this.sessionState.model,
776
- provider: this.providerLabel(this.sessionState.provider),
777
- });
778
743
  if (forceRender) {
779
744
  this.terminalInput.render();
780
745
  }
@@ -834,14 +799,13 @@ export class InteractiveShell {
834
799
  this.terminalInput.render();
835
800
  }
836
801
  /**
837
- * Log user prompt to the scroll region so it's part of the conversation flow.
802
+ * Log the user's prompt as a visible message in the conversation.
803
+ * This creates a persistent log entry that remains visible during and after streaming.
838
804
  */
839
805
  logUserPrompt(text) {
840
- if (!text.trim())
841
- return;
842
- // Format with user prompt prefix and write to scroll region
843
- const formatted = `${theme.user('>')} ${text}\n`;
844
- this.terminalInput.writeToScrollRegion(formatted);
806
+ // Display the user's prompt with the standard prefix
807
+ const prefix = formatUserPrompt();
808
+ display.stream(`\n${prefix}${text}\n\n`);
845
809
  }
846
810
  requestPromptRefresh(force = false) {
847
811
  if (force) {
@@ -869,29 +833,9 @@ export class InteractiveShell {
869
833
  this.uiUpdates.setMode('streaming');
870
834
  this.streamingHeartbeatStart = Date.now();
871
835
  this.streamingHeartbeatFrame = 0;
872
- const initialFrame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
873
- this.streamingStatusLabel = this.buildStreamingStatus(`${initialFrame} ${label}`, 0);
874
- display.updateStreamingStatus(this.streamingStatusLabel);
875
- this.refreshStatusLine(true);
876
- // Periodically refresh the pinned input/status region while streaming so
877
- // elapsed time remains visible without interrupting the scroll region.
878
- this.uiUpdates.startHeartbeat('streaming', {
879
- intervalMs: 1000,
880
- lane: 'heartbeat',
881
- mode: ['streaming', 'processing'],
882
- coalesceKey: 'streaming:heartbeat',
883
- run: () => {
884
- const elapsedSeconds = this.streamingHeartbeatStart
885
- ? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
886
- : 0;
887
- this.streamingHeartbeatFrame =
888
- (this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
889
- const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
890
- this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
891
- display.updateStreamingStatus(this.streamingStatusLabel);
892
- this.refreshStatusLine(true);
893
- },
894
- });
836
+ // Note: We don't start a heartbeat during streaming anymore
837
+ // because the UI shouldn't be rendering during streaming.
838
+ // The streaming status is shown in the streaming header instead.
895
839
  }
896
840
  stopStreamingHeartbeat() {
897
841
  // Exit global streaming mode - allows UI to render again
@@ -907,28 +851,10 @@ export class InteractiveShell {
907
851
  // Force refresh to update the input area now that streaming has ended
908
852
  this.refreshStatusLine(true);
909
853
  }
910
- buildStreamingStatus(label, elapsedSeconds) {
854
+ buildStreamingStatus(label) {
911
855
  const detail = this.describeModelDetail();
912
- const elapsedLabel = typeof elapsedSeconds === 'number' && elapsedSeconds >= 0
913
- ? theme.ui.muted(this.formatElapsedShort(elapsedSeconds))
914
- : null;
915
- const prefix = theme.info('⏺');
916
- const parts = [label];
917
- if (detail) {
918
- parts.push(theme.ui.muted('·'), detail);
919
- }
920
- if (elapsedLabel) {
921
- parts.push(theme.ui.muted('·'), elapsedLabel);
922
- }
923
- return `${prefix} ${parts.join(' ')}`.trim();
924
- }
925
- formatElapsedShort(seconds) {
926
- if (seconds < 60) {
927
- return `${seconds}s`;
928
- }
929
- const minutes = Math.floor(seconds / 60);
930
- const remaining = seconds % 60;
931
- return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
856
+ const prefix = theme.info('');
857
+ return detail ? `${prefix} ${label} ${theme.ui.muted('·')} ${detail}` : `${prefix} ${label}`;
932
858
  }
933
859
  refreshQueueIndicators() {
934
860
  if (this.isProcessing) {
@@ -1176,6 +1102,17 @@ export class InteractiveShell {
1176
1102
  case '/discover':
1177
1103
  await this.discoverModelsCommand();
1178
1104
  break;
1105
+ case '/memory':
1106
+ this.handleMemoryCommand(input);
1107
+ break;
1108
+ case '/clear':
1109
+ display.clear();
1110
+ this.cachedHistory = [];
1111
+ display.showInfo('Conversation cleared.');
1112
+ break;
1113
+ case '/help':
1114
+ this.showHelp();
1115
+ break;
1179
1116
  default:
1180
1117
  if (!(await this.tryCustomSlashCommand(command, input))) {
1181
1118
  display.showWarning(`Unknown command "${command}".`);
@@ -1484,6 +1421,99 @@ export class InteractiveShell {
1484
1421
  // Display keyboard shortcuts help (Claude Code style)
1485
1422
  display.showSystemMessage(formatShortcutsHelp());
1486
1423
  }
1424
+ handleMemoryCommand(input) {
1425
+ const tokens = input.trim().split(/\s+/).slice(1);
1426
+ const action = (tokens.shift() ?? 'show').toLowerCase();
1427
+ switch (action) {
1428
+ case '':
1429
+ case 'show':
1430
+ case 'list': {
1431
+ this.showMemoryStatus();
1432
+ break;
1433
+ }
1434
+ case 'paths': {
1435
+ this.showMemoryPaths();
1436
+ break;
1437
+ }
1438
+ case 'edit': {
1439
+ const level = (tokens[0] ?? 'project').toLowerCase();
1440
+ this.openMemoryForEdit(level);
1441
+ break;
1442
+ }
1443
+ default:
1444
+ display.showWarning('Usage: /memory [show|paths|edit <user|project>]');
1445
+ break;
1446
+ }
1447
+ }
1448
+ showMemoryStatus() {
1449
+ const memory = loadMemory(this.workingDir);
1450
+ const lines = [];
1451
+ lines.push(theme.bold('Persistent Memory'));
1452
+ lines.push('');
1453
+ if (memory.sources.length === 0) {
1454
+ lines.push(theme.secondary('No memory files found.'));
1455
+ lines.push('');
1456
+ lines.push(`Create ${theme.info('EROSOLAR.md')} in your project to add persistent context.`);
1457
+ lines.push(`Use ${theme.info('/memory edit project')} to create one.`);
1458
+ }
1459
+ else {
1460
+ for (const source of memory.sources) {
1461
+ const levelLabel = source.level === 'enterprise' ? 'Enterprise' :
1462
+ source.level === 'user' ? 'User' : 'Project';
1463
+ const preview = source.content.slice(0, 200).replace(/\n/g, ' ').trim();
1464
+ const truncated = source.content.length > 200 ? '...' : '';
1465
+ lines.push(`${theme.success('●')} ${theme.bold(levelLabel)}: ${source.path}`);
1466
+ lines.push(` ${theme.dim(preview + truncated)}`);
1467
+ lines.push('');
1468
+ }
1469
+ if (memory.importedPaths.length > memory.sources.length) {
1470
+ lines.push(theme.secondary(`Imported ${memory.importedPaths.length - memory.sources.length} additional files via @imports.`));
1471
+ }
1472
+ }
1473
+ display.showSystemMessage(lines.join('\n'));
1474
+ }
1475
+ showMemoryPaths() {
1476
+ const paths = listMemoryPaths(this.workingDir);
1477
+ const lines = [];
1478
+ lines.push(theme.bold('Memory File Locations'));
1479
+ lines.push('');
1480
+ for (const { level, path, exists } of paths) {
1481
+ const icon = exists ? theme.success('✓') : theme.dim('○');
1482
+ const levelLabel = level.charAt(0).toUpperCase() + level.slice(1);
1483
+ lines.push(`${icon} ${levelLabel}: ${path}`);
1484
+ }
1485
+ lines.push('');
1486
+ lines.push(theme.secondary('Create any of these files to add persistent memory.'));
1487
+ lines.push(theme.secondary('Use @path/to/file.md syntax to import other files.'));
1488
+ display.showSystemMessage(lines.join('\n'));
1489
+ }
1490
+ openMemoryForEdit(level) {
1491
+ let targetPath;
1492
+ if (level === 'user') {
1493
+ targetPath = getUserMemoryEditPath();
1494
+ }
1495
+ else if (level === 'project') {
1496
+ targetPath = getDefaultProjectMemoryPath(this.workingDir);
1497
+ }
1498
+ else {
1499
+ display.showWarning('Specify "user" or "project" to edit. Enterprise memory is read-only.');
1500
+ return;
1501
+ }
1502
+ display.showInfo(`Memory file: ${targetPath}`);
1503
+ display.showInfo('Create or edit this file to add persistent context for the AI.');
1504
+ display.showInfo('');
1505
+ display.showInfo('Example EROSOLAR.md content:');
1506
+ display.showInfo('');
1507
+ display.showInfo(theme.dim(`# Project Guidelines
1508
+
1509
+ When working in this codebase:
1510
+ - Follow TypeScript strict mode conventions
1511
+ - Use functional patterns where appropriate
1512
+ - Run tests before committing
1513
+
1514
+ @./docs/coding-standards.md
1515
+ `));
1516
+ }
1487
1517
  showFileChangeSummary() {
1488
1518
  const summary = this._fileChangeTracker.getSummary();
1489
1519
  const changes = this._fileChangeTracker.getAllChanges();
@@ -1526,11 +1556,11 @@ export class InteractiveShell {
1526
1556
  display.showSystemMessage(lines.join('\n'));
1527
1557
  }
1528
1558
  showAlphaZeroMetrics() {
1529
- const summary = this.alphaZeroMetrics.getPerformanceSummary();
1559
+ const summary = this.sessionMetrics.getPerformanceSummary();
1530
1560
  display.showSystemMessage(summary);
1531
1561
  }
1532
1562
  showImprovementSuggestions() {
1533
- const suggestions = this.alphaZeroMetrics.getImprovementSuggestions();
1563
+ const suggestions = this.sessionMetrics.getImprovementSuggestions();
1534
1564
  if (suggestions.length === 0) {
1535
1565
  display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
1536
1566
  return;
@@ -1576,9 +1606,7 @@ export class InteractiveShell {
1576
1606
  }
1577
1607
  }
1578
1608
  lines.push(theme.secondary('CLI Flags:'));
1579
- lines.push(' --alpha-zero Enable Alpha Zero 2 RL framework');
1580
1609
  lines.push(' --coding Enable enhanced coding tools');
1581
- lines.push(' --security Enable security research tools');
1582
1610
  lines.push(' --all-plugins Enable all optional plugins');
1583
1611
  display.showSystemMessage(lines.join('\n'));
1584
1612
  }
@@ -1822,75 +1850,6 @@ export class InteractiveShell {
1822
1850
  }
1823
1851
  return `${warning.label}: ${warning.reason}.`;
1824
1852
  }
1825
- buildLaunchCommandPalette() {
1826
- const entries = [];
1827
- const secretsSummary = this.summarizeSecretsForPalette();
1828
- const toolSummary = this.getToolSelectionSummary();
1829
- const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
1830
- for (const command of this.slashCommands) {
1831
- const entry = {
1832
- command: command.command,
1833
- description: command.description,
1834
- category: command.category ?? 'other',
1835
- };
1836
- switch (command.command) {
1837
- case '/secrets':
1838
- if (secretsSummary.text) {
1839
- entry.description = `${command.description} (${secretsSummary.text})`;
1840
- entry.tone = secretsSummary.tone;
1841
- }
1842
- break;
1843
- case '/tools':
1844
- if (toolSummary) {
1845
- entry.description = `${command.description} (${toolSummary})`;
1846
- }
1847
- break;
1848
- case '/sessions':
1849
- entry.description = `${command.description} (autosave ${autosaveLabel})`;
1850
- break;
1851
- case '/model':
1852
- entry.description = `${command.description} (current: ${this.sessionState.model})`;
1853
- break;
1854
- case '/provider':
1855
- entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
1856
- break;
1857
- default:
1858
- break;
1859
- }
1860
- entries.push(entry);
1861
- }
1862
- return entries;
1863
- }
1864
- summarizeSecretsForPalette() {
1865
- const definitions = listSecretDefinitions();
1866
- if (!definitions.length) {
1867
- return { text: null };
1868
- }
1869
- const missing = definitions.filter((definition) => !getSecretValue(definition.id));
1870
- if (missing.length === 0) {
1871
- return { text: 'all configured', tone: 'success' };
1872
- }
1873
- const labels = missing.map((definition) => definition.label ?? definition.id);
1874
- return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
1875
- }
1876
- getToolSelectionSummary() {
1877
- const toolSettings = loadToolSettings();
1878
- const selection = buildEnabledToolSet(toolSettings);
1879
- const options = getToolToggleOptions();
1880
- if (!options.length) {
1881
- return null;
1882
- }
1883
- const enabledCount = options.filter((option) => selection.has(option.id)).length;
1884
- return `${enabledCount}/${options.length} enabled`;
1885
- }
1886
- formatList(values, maxItems = 3) {
1887
- if (!values.length) {
1888
- return '';
1889
- }
1890
- const shown = values.slice(0, maxItems);
1891
- const suffix = values.length > maxItems ? ', …' : '';
1892
- return `${shown.join(', ')}${suffix}`;
1893
- }
1894
1853
  buildSlashCommandList(header) {
1895
1854
  const lines = [theme.gradient.primary(header), ''];
1896
1855
  for (const command of this.slashCommands) {
@@ -2359,7 +2318,7 @@ export class InteractiveShell {
2359
2318
  this.autosaveIfEnabled();
2360
2319
  // Track metrics with Alpha Zero 2
2361
2320
  const elapsedMs = Date.now() - requestStartTime;
2362
- this.alphaZeroMetrics.recordMessage(elapsedMs);
2321
+ this.sessionMetrics.recordMessage(elapsedMs);
2363
2322
  if (!responseText?.trim()) {
2364
2323
  display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
2365
2324
  }
@@ -2377,10 +2336,14 @@ export class InteractiveShell {
2377
2336
  this.stopStreamingHeartbeat();
2378
2337
  this.isProcessing = false;
2379
2338
  this.terminalInput.setStreaming(false);
2339
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
2380
2340
  this.uiAdapter.endProcessing('Ready for prompts');
2381
2341
  this.setIdleStatus();
2382
2342
  display.newLine();
2383
2343
  this.updateStatusMessage(null);
2344
+ // Claude Code style: Show unified status bar before prompt
2345
+ // This creates consistent UI between startup and post-streaming
2346
+ this.showUnifiedStatusBar();
2384
2347
  queueMicrotask(() => this.uiUpdates.setMode('idle'));
2385
2348
  // CRITICAL: Ensure readline prompt is active for user input
2386
2349
  // Claude Code style: New prompt naturally appears at bottom
@@ -2457,14 +2420,13 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
2457
2420
  try {
2458
2421
  // Send the request and capture the response (streaming disabled)
2459
2422
  display.showThinking('Responding...');
2460
- this.refreshStatusLine(true);
2461
2423
  const response = await agent.send(currentPrompt, true);
2462
2424
  await this.awaitPendingCleanup();
2463
2425
  this.captureHistorySnapshot();
2464
2426
  this.autosaveIfEnabled();
2465
2427
  // Track metrics
2466
2428
  const elapsedMs = Date.now() - overallStartTime;
2467
- this.alphaZeroMetrics.recordMessage(elapsedMs);
2429
+ this.sessionMetrics.recordMessage(elapsedMs);
2468
2430
  if (!response?.trim()) {
2469
2431
  display.showWarning('Model returned an empty response. Retrying this iteration...');
2470
2432
  consecutiveNoProgress++;
@@ -2601,6 +2563,7 @@ What's the next action?`;
2601
2563
  this.stopStreamingHeartbeat();
2602
2564
  this.isProcessing = false;
2603
2565
  this.terminalInput.setStreaming(false);
2566
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
2604
2567
  this.uiAdapter.endProcessing('Ready for prompts');
2605
2568
  this.setIdleStatus();
2606
2569
  this.updateStatusMessage(null);
@@ -2957,10 +2920,8 @@ What's the next action?`;
2957
2920
  try {
2958
2921
  // Send the error to the agent for fixing
2959
2922
  display.showThinking('Analyzing build errors');
2960
- this.refreshStatusLine(true);
2961
2923
  const response = await this.agent.send(prompt, true);
2962
2924
  display.stopThinking();
2963
- this.refreshStatusLine(true);
2964
2925
  if (response) {
2965
2926
  display.showAssistantMessage(response, { isFinal: true });
2966
2927
  }
@@ -3010,16 +2971,18 @@ What's the next action?`;
3010
2971
  display.showAssistantMessage(finalContent, enriched);
3011
2972
  }
3012
2973
  }
3013
- // Status shown in mode controls bar - no separate status line needed
2974
+ // Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
3014
2975
  display.stopThinking();
3015
- // Update context usage for mode controls display
2976
+ // Calculate context usage
2977
+ let contextInfo;
3016
2978
  if (enriched.contextWindowTokens && metadata.usage) {
3017
2979
  const total = this.totalTokens(metadata.usage);
3018
2980
  if (total && total > 0) {
3019
2981
  const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
3020
- this.updateContextUsage(percentage);
2982
+ contextInfo = { percentage, tokens: total };
3021
2983
  }
3022
2984
  }
2985
+ display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
3023
2986
  // Auto-verify changes: build first (catches type errors), then tests
3024
2987
  void this.enforceAutoBuild('final-response');
3025
2988
  void this.enforceAutoTests('final-response');
@@ -3089,6 +3052,7 @@ What's the next action?`;
3089
3052
  this.stopStreamingHeartbeat();
3090
3053
  this.updateStatusMessage(null);
3091
3054
  this.terminalInput.setStreaming(false);
3055
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
3092
3056
  this.terminalInput.render();
3093
3057
  },
3094
3058
  onVerificationNeeded: () => {
@@ -3125,6 +3089,7 @@ What's the next action?`;
3125
3089
  resetChatBoxAfterModelSwap() {
3126
3090
  this.updateStatusMessage(null);
3127
3091
  this.terminalInput.setStreaming(false);
3092
+ this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
3128
3093
  this.terminalInput.render();
3129
3094
  this.ensureReadlineReady();
3130
3095
  }
@@ -3189,14 +3154,9 @@ What's the next action?`;
3189
3154
  return null;
3190
3155
  }
3191
3156
  const usageRatio = total / windowTokens;
3192
- this.latestTokenUsage = {
3193
- used: total,
3194
- limit: windowTokens,
3195
- };
3196
3157
  // Always update context usage in the UI
3197
3158
  const percentUsed = Math.round(usageRatio * 100);
3198
3159
  this.updateContextUsage(percentUsed);
3199
- this.refreshStatusLine(true);
3200
3160
  if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
3201
3161
  return null;
3202
3162
  }
@@ -3474,6 +3434,8 @@ What's the next action?`;
3474
3434
  }
3475
3435
  this.refreshContextGauge();
3476
3436
  display.updateSessionInfo(nextState.model, nextState.provider);
3437
+ // Update the persistent model info display in terminal input
3438
+ this.terminalInput.setModelInfo(this.describeModelDetail());
3477
3439
  if (!this.isProcessing) {
3478
3440
  this.setIdleStatus();
3479
3441
  }