erosolar-cli 1.7.341 → 1.7.342

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 (327) hide show
  1. package/README.md +24 -148
  2. package/dist/bin/erosolar.js +5 -21
  3. package/dist/bin/erosolar.js.map +1 -1
  4. package/dist/capabilities/agentSpawningCapability.d.ts.map +1 -1
  5. package/dist/capabilities/agentSpawningCapability.js +56 -31
  6. package/dist/capabilities/agentSpawningCapability.js.map +1 -1
  7. package/dist/contracts/agent-schemas.json +0 -15
  8. package/dist/contracts/tools.schema.json +0 -9
  9. package/dist/core/agent.d.ts +2 -2
  10. package/dist/core/agent.d.ts.map +1 -1
  11. package/dist/core/agent.js.map +1 -1
  12. package/dist/core/customCommands.d.ts +1 -0
  13. package/dist/core/customCommands.d.ts.map +1 -1
  14. package/dist/core/customCommands.js +3 -0
  15. package/dist/core/customCommands.js.map +1 -1
  16. package/dist/core/hooks.d.ts +113 -0
  17. package/dist/core/hooks.d.ts.map +1 -0
  18. package/dist/core/hooks.js +267 -0
  19. package/dist/core/hooks.js.map +1 -0
  20. package/dist/core/metricsTracker.d.ts +122 -0
  21. package/dist/core/metricsTracker.d.ts.map +1 -0
  22. package/dist/{alpha-zero → core}/metricsTracker.js +2 -5
  23. package/dist/core/metricsTracker.js.map +1 -0
  24. package/dist/core/securityAssessment.d.ts +91 -0
  25. package/dist/core/securityAssessment.d.ts.map +1 -0
  26. package/dist/core/securityAssessment.js +580 -0
  27. package/dist/core/securityAssessment.js.map +1 -0
  28. package/dist/core/sessionStore.d.ts +2 -0
  29. package/dist/core/sessionStore.d.ts.map +1 -1
  30. package/dist/core/sessionStore.js +1 -0
  31. package/dist/core/sessionStore.js.map +1 -1
  32. package/dist/core/toolPreconditions.d.ts.map +1 -1
  33. package/dist/core/toolPreconditions.js +0 -14
  34. package/dist/core/toolPreconditions.js.map +1 -1
  35. package/dist/core/toolRuntime.d.ts +22 -1
  36. package/dist/core/toolRuntime.d.ts.map +1 -1
  37. package/dist/core/toolRuntime.js +0 -5
  38. package/dist/core/toolRuntime.js.map +1 -1
  39. package/dist/core/toolValidation.d.ts.map +1 -1
  40. package/dist/core/toolValidation.js +14 -3
  41. package/dist/core/toolValidation.js.map +1 -1
  42. package/dist/core/validationRunner.d.ts +1 -3
  43. package/dist/core/validationRunner.d.ts.map +1 -1
  44. package/dist/core/validationRunner.js.map +1 -1
  45. package/dist/core/verification.d.ts +137 -0
  46. package/dist/core/verification.d.ts.map +1 -0
  47. package/dist/core/verification.js +323 -0
  48. package/dist/core/verification.js.map +1 -0
  49. package/dist/headless/headlessApp.d.ts.map +1 -1
  50. package/dist/headless/headlessApp.js +21 -0
  51. package/dist/headless/headlessApp.js.map +1 -1
  52. package/dist/mcp/sseClient.d.ts.map +1 -1
  53. package/dist/mcp/sseClient.js +9 -18
  54. package/dist/mcp/sseClient.js.map +1 -1
  55. package/dist/plugins/tools/build/buildPlugin.d.ts +0 -6
  56. package/dist/plugins/tools/build/buildPlugin.d.ts.map +1 -1
  57. package/dist/plugins/tools/build/buildPlugin.js +4 -10
  58. package/dist/plugins/tools/build/buildPlugin.js.map +1 -1
  59. package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
  60. package/dist/plugins/tools/nodeDefaults.js +0 -2
  61. package/dist/plugins/tools/nodeDefaults.js.map +1 -1
  62. package/dist/runtime/agentSession.d.ts +2 -2
  63. package/dist/runtime/agentSession.d.ts.map +1 -1
  64. package/dist/runtime/agentSession.js +2 -2
  65. package/dist/runtime/agentSession.js.map +1 -1
  66. package/dist/shell/interactiveShell.d.ts +19 -7
  67. package/dist/shell/interactiveShell.d.ts.map +1 -1
  68. package/dist/shell/interactiveShell.js +271 -166
  69. package/dist/shell/interactiveShell.js.map +1 -1
  70. package/dist/shell/shellApp.d.ts +2 -0
  71. package/dist/shell/shellApp.d.ts.map +1 -1
  72. package/dist/shell/shellApp.js +82 -9
  73. package/dist/shell/shellApp.js.map +1 -1
  74. package/dist/shell/systemPrompt.d.ts.map +1 -1
  75. package/dist/shell/systemPrompt.js +1 -4
  76. package/dist/shell/systemPrompt.js.map +1 -1
  77. package/dist/shell/terminalInput.d.ts +215 -120
  78. package/dist/shell/terminalInput.d.ts.map +1 -1
  79. package/dist/shell/terminalInput.js +926 -537
  80. package/dist/shell/terminalInput.js.map +1 -1
  81. package/dist/shell/terminalInputAdapter.d.ts +99 -21
  82. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  83. package/dist/shell/terminalInputAdapter.js +131 -30
  84. package/dist/shell/terminalInputAdapter.js.map +1 -1
  85. package/dist/subagents/agentConfig.d.ts +27 -0
  86. package/dist/subagents/agentConfig.d.ts.map +1 -0
  87. package/dist/subagents/agentConfig.js +89 -0
  88. package/dist/subagents/agentConfig.js.map +1 -0
  89. package/dist/subagents/agentRegistry.d.ts +33 -0
  90. package/dist/subagents/agentRegistry.d.ts.map +1 -0
  91. package/dist/subagents/agentRegistry.js +162 -0
  92. package/dist/subagents/agentRegistry.js.map +1 -0
  93. package/dist/subagents/taskRunner.d.ts +7 -1
  94. package/dist/subagents/taskRunner.d.ts.map +1 -1
  95. package/dist/subagents/taskRunner.js +180 -47
  96. package/dist/subagents/taskRunner.js.map +1 -1
  97. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  98. package/dist/ui/ShellUIAdapter.js +13 -12
  99. package/dist/ui/ShellUIAdapter.js.map +1 -1
  100. package/dist/ui/display.d.ts +24 -45
  101. package/dist/ui/display.d.ts.map +1 -1
  102. package/dist/ui/display.js +140 -259
  103. package/dist/ui/display.js.map +1 -1
  104. package/dist/ui/theme.d.ts.map +1 -1
  105. package/dist/ui/theme.js +6 -8
  106. package/dist/ui/theme.js.map +1 -1
  107. package/dist/ui/toolDisplay.d.ts +0 -158
  108. package/dist/ui/toolDisplay.d.ts.map +1 -1
  109. package/dist/ui/toolDisplay.js +0 -348
  110. package/dist/ui/toolDisplay.js.map +1 -1
  111. package/dist/ui/unified/layout.d.ts +1 -0
  112. package/dist/ui/unified/layout.d.ts.map +1 -1
  113. package/dist/ui/unified/layout.js +25 -179
  114. package/dist/ui/unified/layout.js.map +1 -1
  115. package/dist/utils/frontmatter.d.ts +10 -0
  116. package/dist/utils/frontmatter.d.ts.map +1 -0
  117. package/dist/utils/frontmatter.js +78 -0
  118. package/dist/utils/frontmatter.js.map +1 -0
  119. package/package.json +4 -4
  120. package/dist/alpha-zero/agentWrapper.d.ts +0 -84
  121. package/dist/alpha-zero/agentWrapper.d.ts.map +0 -1
  122. package/dist/alpha-zero/agentWrapper.js +0 -171
  123. package/dist/alpha-zero/agentWrapper.js.map +0 -1
  124. package/dist/alpha-zero/codeEvaluator.d.ts +0 -25
  125. package/dist/alpha-zero/codeEvaluator.d.ts.map +0 -1
  126. package/dist/alpha-zero/codeEvaluator.js +0 -273
  127. package/dist/alpha-zero/codeEvaluator.js.map +0 -1
  128. package/dist/alpha-zero/competitiveRunner.d.ts +0 -66
  129. package/dist/alpha-zero/competitiveRunner.d.ts.map +0 -1
  130. package/dist/alpha-zero/competitiveRunner.js +0 -224
  131. package/dist/alpha-zero/competitiveRunner.js.map +0 -1
  132. package/dist/alpha-zero/index.d.ts +0 -67
  133. package/dist/alpha-zero/index.d.ts.map +0 -1
  134. package/dist/alpha-zero/index.js +0 -99
  135. package/dist/alpha-zero/index.js.map +0 -1
  136. package/dist/alpha-zero/introspection.d.ts +0 -128
  137. package/dist/alpha-zero/introspection.d.ts.map +0 -1
  138. package/dist/alpha-zero/introspection.js +0 -300
  139. package/dist/alpha-zero/introspection.js.map +0 -1
  140. package/dist/alpha-zero/metricsTracker.d.ts +0 -71
  141. package/dist/alpha-zero/metricsTracker.d.ts.map +0 -1
  142. package/dist/alpha-zero/metricsTracker.js.map +0 -1
  143. package/dist/alpha-zero/security/core.d.ts +0 -125
  144. package/dist/alpha-zero/security/core.d.ts.map +0 -1
  145. package/dist/alpha-zero/security/core.js +0 -271
  146. package/dist/alpha-zero/security/core.js.map +0 -1
  147. package/dist/alpha-zero/security/google.d.ts +0 -125
  148. package/dist/alpha-zero/security/google.d.ts.map +0 -1
  149. package/dist/alpha-zero/security/google.js +0 -311
  150. package/dist/alpha-zero/security/google.js.map +0 -1
  151. package/dist/alpha-zero/security/googleLoader.d.ts +0 -17
  152. package/dist/alpha-zero/security/googleLoader.d.ts.map +0 -1
  153. package/dist/alpha-zero/security/googleLoader.js +0 -41
  154. package/dist/alpha-zero/security/googleLoader.js.map +0 -1
  155. package/dist/alpha-zero/security/index.d.ts +0 -29
  156. package/dist/alpha-zero/security/index.d.ts.map +0 -1
  157. package/dist/alpha-zero/security/index.js +0 -32
  158. package/dist/alpha-zero/security/index.js.map +0 -1
  159. package/dist/alpha-zero/security/simulation.d.ts +0 -124
  160. package/dist/alpha-zero/security/simulation.d.ts.map +0 -1
  161. package/dist/alpha-zero/security/simulation.js +0 -277
  162. package/dist/alpha-zero/security/simulation.js.map +0 -1
  163. package/dist/alpha-zero/selfModification.d.ts +0 -109
  164. package/dist/alpha-zero/selfModification.d.ts.map +0 -1
  165. package/dist/alpha-zero/selfModification.js +0 -233
  166. package/dist/alpha-zero/selfModification.js.map +0 -1
  167. package/dist/alpha-zero/types.d.ts +0 -170
  168. package/dist/alpha-zero/types.d.ts.map +0 -1
  169. package/dist/alpha-zero/types.js +0 -31
  170. package/dist/alpha-zero/types.js.map +0 -1
  171. package/dist/capabilities/securityTestingCapability.d.ts +0 -13
  172. package/dist/capabilities/securityTestingCapability.d.ts.map +0 -1
  173. package/dist/capabilities/securityTestingCapability.js +0 -25
  174. package/dist/capabilities/securityTestingCapability.js.map +0 -1
  175. package/dist/core/aiFlowOptimizer.d.ts +0 -26
  176. package/dist/core/aiFlowOptimizer.d.ts.map +0 -1
  177. package/dist/core/aiFlowOptimizer.js +0 -31
  178. package/dist/core/aiFlowOptimizer.js.map +0 -1
  179. package/dist/core/aiOptimizationEngine.d.ts +0 -158
  180. package/dist/core/aiOptimizationEngine.d.ts.map +0 -1
  181. package/dist/core/aiOptimizationEngine.js +0 -428
  182. package/dist/core/aiOptimizationEngine.js.map +0 -1
  183. package/dist/core/aiOptimizationIntegration.d.ts +0 -93
  184. package/dist/core/aiOptimizationIntegration.d.ts.map +0 -1
  185. package/dist/core/aiOptimizationIntegration.js +0 -250
  186. package/dist/core/aiOptimizationIntegration.js.map +0 -1
  187. package/dist/core/enhancedErrorRecovery.d.ts +0 -100
  188. package/dist/core/enhancedErrorRecovery.d.ts.map +0 -1
  189. package/dist/core/enhancedErrorRecovery.js +0 -345
  190. package/dist/core/enhancedErrorRecovery.js.map +0 -1
  191. package/dist/core/hooksSystem.d.ts +0 -65
  192. package/dist/core/hooksSystem.d.ts.map +0 -1
  193. package/dist/core/hooksSystem.js +0 -273
  194. package/dist/core/hooksSystem.js.map +0 -1
  195. package/dist/core/memorySystem.d.ts +0 -48
  196. package/dist/core/memorySystem.d.ts.map +0 -1
  197. package/dist/core/memorySystem.js +0 -271
  198. package/dist/core/memorySystem.js.map +0 -1
  199. package/dist/core/unified/errors.d.ts +0 -189
  200. package/dist/core/unified/errors.d.ts.map +0 -1
  201. package/dist/core/unified/errors.js +0 -497
  202. package/dist/core/unified/errors.js.map +0 -1
  203. package/dist/core/unified/index.d.ts +0 -19
  204. package/dist/core/unified/index.d.ts.map +0 -1
  205. package/dist/core/unified/index.js +0 -68
  206. package/dist/core/unified/index.js.map +0 -1
  207. package/dist/core/unified/schema.d.ts +0 -101
  208. package/dist/core/unified/schema.d.ts.map +0 -1
  209. package/dist/core/unified/schema.js +0 -350
  210. package/dist/core/unified/schema.js.map +0 -1
  211. package/dist/core/unified/toolRuntime.d.ts +0 -179
  212. package/dist/core/unified/toolRuntime.d.ts.map +0 -1
  213. package/dist/core/unified/toolRuntime.js +0 -517
  214. package/dist/core/unified/toolRuntime.js.map +0 -1
  215. package/dist/core/unified/tools.d.ts +0 -127
  216. package/dist/core/unified/tools.d.ts.map +0 -1
  217. package/dist/core/unified/tools.js +0 -1333
  218. package/dist/core/unified/tools.js.map +0 -1
  219. package/dist/core/unified/types.d.ts +0 -352
  220. package/dist/core/unified/types.d.ts.map +0 -1
  221. package/dist/core/unified/types.js +0 -12
  222. package/dist/core/unified/types.js.map +0 -1
  223. package/dist/core/unified/version.d.ts +0 -209
  224. package/dist/core/unified/version.d.ts.map +0 -1
  225. package/dist/core/unified/version.js +0 -454
  226. package/dist/core/unified/version.js.map +0 -1
  227. package/dist/plugins/tools/security/securityPlugin.d.ts +0 -3
  228. package/dist/plugins/tools/security/securityPlugin.d.ts.map +0 -1
  229. package/dist/plugins/tools/security/securityPlugin.js +0 -12
  230. package/dist/plugins/tools/security/securityPlugin.js.map +0 -1
  231. package/dist/security/active-stack-security.d.ts +0 -112
  232. package/dist/security/active-stack-security.d.ts.map +0 -1
  233. package/dist/security/active-stack-security.js +0 -296
  234. package/dist/security/active-stack-security.js.map +0 -1
  235. package/dist/security/advanced-persistence-research.d.ts +0 -92
  236. package/dist/security/advanced-persistence-research.d.ts.map +0 -1
  237. package/dist/security/advanced-persistence-research.js +0 -195
  238. package/dist/security/advanced-persistence-research.js.map +0 -1
  239. package/dist/security/advanced-targeting.d.ts +0 -119
  240. package/dist/security/advanced-targeting.d.ts.map +0 -1
  241. package/dist/security/advanced-targeting.js +0 -233
  242. package/dist/security/advanced-targeting.js.map +0 -1
  243. package/dist/security/assessment/vulnerabilityAssessment.d.ts +0 -104
  244. package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +0 -1
  245. package/dist/security/assessment/vulnerabilityAssessment.js +0 -315
  246. package/dist/security/assessment/vulnerabilityAssessment.js.map +0 -1
  247. package/dist/security/authorization/securityAuthorization.d.ts +0 -88
  248. package/dist/security/authorization/securityAuthorization.d.ts.map +0 -1
  249. package/dist/security/authorization/securityAuthorization.js +0 -172
  250. package/dist/security/authorization/securityAuthorization.js.map +0 -1
  251. package/dist/security/comprehensive-targeting.d.ts +0 -85
  252. package/dist/security/comprehensive-targeting.d.ts.map +0 -1
  253. package/dist/security/comprehensive-targeting.js +0 -438
  254. package/dist/security/comprehensive-targeting.js.map +0 -1
  255. package/dist/security/global-security-integration.d.ts +0 -91
  256. package/dist/security/global-security-integration.d.ts.map +0 -1
  257. package/dist/security/global-security-integration.js +0 -218
  258. package/dist/security/global-security-integration.js.map +0 -1
  259. package/dist/security/index.d.ts +0 -38
  260. package/dist/security/index.d.ts.map +0 -1
  261. package/dist/security/index.js +0 -47
  262. package/dist/security/index.js.map +0 -1
  263. package/dist/security/persistence-analyzer.d.ts +0 -56
  264. package/dist/security/persistence-analyzer.d.ts.map +0 -1
  265. package/dist/security/persistence-analyzer.js +0 -187
  266. package/dist/security/persistence-analyzer.js.map +0 -1
  267. package/dist/security/persistence-cli.d.ts +0 -36
  268. package/dist/security/persistence-cli.d.ts.map +0 -1
  269. package/dist/security/persistence-cli.js +0 -160
  270. package/dist/security/persistence-cli.js.map +0 -1
  271. package/dist/security/persistence-research.d.ts +0 -92
  272. package/dist/security/persistence-research.d.ts.map +0 -1
  273. package/dist/security/persistence-research.js +0 -364
  274. package/dist/security/persistence-research.js.map +0 -1
  275. package/dist/security/research/persistenceResearch.d.ts +0 -97
  276. package/dist/security/research/persistenceResearch.d.ts.map +0 -1
  277. package/dist/security/research/persistenceResearch.js +0 -282
  278. package/dist/security/research/persistenceResearch.js.map +0 -1
  279. package/dist/security/security-integration.d.ts +0 -74
  280. package/dist/security/security-integration.d.ts.map +0 -1
  281. package/dist/security/security-integration.js +0 -137
  282. package/dist/security/security-integration.js.map +0 -1
  283. package/dist/security/security-testing-framework.d.ts +0 -112
  284. package/dist/security/security-testing-framework.d.ts.map +0 -1
  285. package/dist/security/security-testing-framework.js +0 -364
  286. package/dist/security/security-testing-framework.js.map +0 -1
  287. package/dist/security/simulation/attackSimulation.d.ts +0 -93
  288. package/dist/security/simulation/attackSimulation.d.ts.map +0 -1
  289. package/dist/security/simulation/attackSimulation.js +0 -341
  290. package/dist/security/simulation/attackSimulation.js.map +0 -1
  291. package/dist/security/strategic-operations.d.ts +0 -100
  292. package/dist/security/strategic-operations.d.ts.map +0 -1
  293. package/dist/security/strategic-operations.js +0 -276
  294. package/dist/security/strategic-operations.js.map +0 -1
  295. package/dist/security/tool-security-wrapper.d.ts +0 -58
  296. package/dist/security/tool-security-wrapper.d.ts.map +0 -1
  297. package/dist/security/tool-security-wrapper.js +0 -156
  298. package/dist/security/tool-security-wrapper.js.map +0 -1
  299. package/dist/shell/claudeCodeStreamHandler.d.ts +0 -145
  300. package/dist/shell/claudeCodeStreamHandler.d.ts.map +0 -1
  301. package/dist/shell/claudeCodeStreamHandler.js +0 -322
  302. package/dist/shell/claudeCodeStreamHandler.js.map +0 -1
  303. package/dist/shell/inputQueueManager.d.ts +0 -144
  304. package/dist/shell/inputQueueManager.d.ts.map +0 -1
  305. package/dist/shell/inputQueueManager.js +0 -290
  306. package/dist/shell/inputQueueManager.js.map +0 -1
  307. package/dist/shell/metricsTracker.d.ts +0 -60
  308. package/dist/shell/metricsTracker.d.ts.map +0 -1
  309. package/dist/shell/metricsTracker.js +0 -119
  310. package/dist/shell/metricsTracker.js.map +0 -1
  311. package/dist/shell/streamingOutputManager.d.ts +0 -115
  312. package/dist/shell/streamingOutputManager.d.ts.map +0 -1
  313. package/dist/shell/streamingOutputManager.js +0 -225
  314. package/dist/shell/streamingOutputManager.js.map +0 -1
  315. package/dist/tools/securityTools.d.ts +0 -22
  316. package/dist/tools/securityTools.d.ts.map +0 -1
  317. package/dist/tools/securityTools.js +0 -448
  318. package/dist/tools/securityTools.js.map +0 -1
  319. package/dist/ui/persistentPrompt.d.ts +0 -50
  320. package/dist/ui/persistentPrompt.d.ts.map +0 -1
  321. package/dist/ui/persistentPrompt.js +0 -92
  322. package/dist/ui/persistentPrompt.js.map +0 -1
  323. package/dist/ui/terminalUISchema.d.ts +0 -195
  324. package/dist/ui/terminalUISchema.d.ts.map +0 -1
  325. package/dist/ui/terminalUISchema.js +0 -113
  326. package/dist/ui/terminalUISchema.js.map +0 -1
  327. package/scripts/deploy-security-capabilities.js +0 -178
@@ -2,7 +2,7 @@ import { stdin as input, stdout as output, exit } from 'node:process';
2
2
  import { exec } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import { display } from '../ui/display.js';
5
- import { theme, formatUserPrompt } from '../ui/theme.js';
5
+ import { theme } from '../ui/theme.js';
6
6
  import { getContextWindowTokens } from '../core/contextWindow.js';
7
7
  import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
8
8
  import { saveActiveProfilePreference, saveModelPreference, loadToolSettings, saveToolSettings, clearToolSettings, clearActiveProfilePreference, loadSessionPreferences, saveSessionPreferences, } from '../core/preferences.js';
@@ -19,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 './metricsTracker.js';
22
+ import { MetricsTracker } from '../core/metricsTracker.js';
23
23
  import { listAvailablePlugins } from '../plugins/index.js';
24
- import { loadMemory, listMemoryPaths, getDefaultProjectMemoryPath, getUserMemoryEditPath, } from '../core/memorySystem.js';
25
24
  import { TerminalInputAdapter } from './terminalInputAdapter.js';
26
- import { isUpdateInProgress } from './updateManager.js';
25
+ import { renderSessionFrame } from '../ui/unified/layout.js';
26
+ import { isUpdateInProgress, maybeOfferCliUpdate } 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,6 +35,7 @@ const DROPDOWN_COLORS = [
35
35
  theme.success,
36
36
  theme.warning,
37
37
  ];
38
+ const STREAMING_SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
38
39
  // Load MODEL_PRESETS from centralized schema
39
40
  const MODEL_PRESETS = getModels().map((model) => ({
40
41
  id: model.id,
@@ -49,11 +50,13 @@ const MODEL_PRESETS = getModels().map((model) => ({
49
50
  const BASE_SLASH_COMMANDS = getSlashCommands().map((cmd) => ({
50
51
  command: cmd.command,
51
52
  description: cmd.description,
53
+ category: cmd.category,
52
54
  }));
53
55
  // Load PROVIDER_LABELS from centralized schema
54
56
  const PROVIDER_LABELS = Object.fromEntries(getProviders().map((provider) => [provider.id, provider.label]));
55
57
  // Allow enough time for paste detection to kick in before flushing buffered lines
56
58
  const CONTEXT_USAGE_THRESHOLD = 0.9;
59
+ const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
57
60
  const CONTEXT_RECENT_MESSAGE_COUNT = 12;
58
61
  const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
59
62
  const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
@@ -94,11 +97,12 @@ export class InteractiveShell {
94
97
  uiAdapter;
95
98
  uiUpdates;
96
99
  _fileChangeTracker = new FileChangeTracker(); // Reserved for future file tracking features
97
- sessionMetrics; // Session performance tracking
100
+ alphaZeroMetrics; // Alpha Zero 2 performance tracking
98
101
  statusSubscription = null;
99
102
  followUpQueue = [];
100
103
  isDrainingQueue = false;
101
104
  activeContextWindowTokens = null;
105
+ latestTokenUsage = { used: null, limit: null };
102
106
  sessionPreferences;
103
107
  autosaveEnabled;
104
108
  autoContinueEnabled;
@@ -129,6 +133,9 @@ export class InteractiveShell {
129
133
  statusLineState = null;
130
134
  statusMessageOverride = null;
131
135
  promptRefreshTimer = null;
136
+ launchPaletteShown = false;
137
+ version;
138
+ alternateScreenEnabled;
132
139
  constructor(config) {
133
140
  this.profile = config.profile;
134
141
  this.profileLabel = config.profileLabel;
@@ -142,6 +149,8 @@ export class InteractiveShell {
142
149
  this.autoContinueEnabled = this.sessionPreferences.autoContinue;
143
150
  this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
144
151
  this._enabledPlugins = config.enabledPlugins ?? [];
152
+ this.version = config.version ?? '0.0.0';
153
+ this.alternateScreenEnabled = config.alternateScreen ?? true;
145
154
  this.initializeSessionHistory();
146
155
  this.sessionState = {
147
156
  provider: config.initialModel.provider,
@@ -162,6 +171,7 @@ export class InteractiveShell {
162
171
  this.slashCommands.push({
163
172
  command: '/agents',
164
173
  description: 'Select the default agent profile (applies on next launch)',
174
+ category: 'configuration',
165
175
  });
166
176
  }
167
177
  this.customCommands = loadCustomSlashCommands();
@@ -170,18 +180,21 @@ export class InteractiveShell {
170
180
  this.slashCommands.push({
171
181
  command: custom.command,
172
182
  description: `${custom.description} (custom)`,
183
+ category: custom.category ?? 'other',
173
184
  });
174
185
  }
175
186
  if (!this.slashCommands.some((cmd) => cmd.command === '/exit')) {
176
187
  this.slashCommands.push({
177
188
  command: '/exit',
178
189
  description: 'Quit the CLI immediately',
190
+ category: 'other',
179
191
  });
180
192
  }
181
193
  // Add /plugins command
182
194
  this.slashCommands.push({
183
195
  command: '/plugins',
184
196
  description: 'Show available and loaded plugins',
197
+ category: 'configuration',
185
198
  });
186
199
  this.statusTracker = config.statusTracker;
187
200
  this.ui = config.ui;
@@ -214,19 +227,25 @@ export class InteractiveShell {
214
227
  onToggleVerify: () => this.toggleVerificationMode(),
215
228
  onToggleAutoContinue: () => this.toggleAutoContinueMode(),
216
229
  });
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();
224
230
  // Initialize Alpha Zero 2 metrics tracking
225
- this.sessionMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
231
+ this.alphaZeroMetrics = new MetricsTracker(`${this.profile}-${Date.now()}`);
226
232
  this.setupStatusTracking();
227
233
  this.refreshContextGauge();
234
+ // Start terminal input (sets up handlers)
228
235
  this.terminalInput.start();
236
+ // Enter alternate screen buffer when enabled, otherwise clear the main screen for layout
237
+ if (this.alternateScreenEnabled) {
238
+ this.terminalInput.enterAlternateScreen();
239
+ }
240
+ else if (output.isTTY) {
241
+ this.terminalInput.clearScreen();
242
+ }
243
+ // Stream banner first - this sets up scroll region dynamically
244
+ const banner = this.buildBanner();
245
+ this.terminalInput.streamContent(banner + '\n\n');
246
+ // Render chat box after banner is streamed
229
247
  this.refreshControlBar();
248
+ this.terminalInput.forceRender();
230
249
  this.rebuildAgent();
231
250
  this.setupHandlers();
232
251
  this.refreshBannerSessionInfo();
@@ -246,6 +265,10 @@ export class InteractiveShell {
246
265
  this.activeSessionId = stored.id;
247
266
  this.activeSessionTitle = stored.title;
248
267
  this.sessionResumeNotice = `Resumed session "${stored.title}".`;
268
+ // Restore scrollback buffer if available
269
+ if (stored.scrollbackBuffer && Array.isArray(stored.scrollbackBuffer)) {
270
+ this.terminalInput.loadScrollbackBuffer(stored.scrollbackBuffer);
271
+ }
249
272
  return;
250
273
  }
251
274
  display.showWarning(`Session "${this.sessionRestoreConfig.sessionId}" not found. Starting fresh session.`);
@@ -259,6 +282,10 @@ export class InteractiveShell {
259
282
  this.activeSessionId = null;
260
283
  this.activeSessionTitle = autosave.title;
261
284
  this.sessionResumeNotice = 'Restored last autosaved session.';
285
+ // Restore scrollback buffer if available
286
+ if (autosave.scrollbackBuffer && Array.isArray(autosave.scrollbackBuffer)) {
287
+ this.terminalInput.loadScrollbackBuffer(autosave.scrollbackBuffer);
288
+ }
262
289
  return;
263
290
  }
264
291
  display.showWarning('No autosaved session found. Starting fresh session.');
@@ -273,14 +300,24 @@ export class InteractiveShell {
273
300
  this.sessionResumeNotice = null;
274
301
  }
275
302
  async start(initialPrompt) {
303
+ // Check for updates in background (non-blocking)
304
+ if (this.version) {
305
+ void maybeOfferCliUpdate(this.version);
306
+ }
276
307
  if (initialPrompt) {
277
308
  this.logUserPrompt(initialPrompt);
278
309
  await this.processInputBlock(initialPrompt);
279
310
  return;
280
311
  }
312
+ this.showLaunchCommandPalette();
281
313
  // Ensure the terminal input is visible
282
314
  this.terminalInput.render();
283
315
  }
316
+ showLaunchCommandPalette() {
317
+ // Disabled: Quick commands palette takes up too much space
318
+ // Users can type /help to see available commands
319
+ this.launchPaletteShown = true;
320
+ }
284
321
  /**
285
322
  * TerminalInputAdapter submit handler
286
323
  */
@@ -294,9 +331,8 @@ export class InteractiveShell {
294
331
  this.handleInputChange('');
295
332
  return;
296
333
  }
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);
334
+ // DON'T clear the input here - keep it visible while streaming.
335
+ // The input will be cleared after streaming completes in the finally block.
300
336
  this.logUserPrompt(approved);
301
337
  void this.processInputBlock(approved).catch((err) => {
302
338
  display.showError(err instanceof Error ? err.message : String(err), err);
@@ -485,6 +521,10 @@ export class InteractiveShell {
485
521
  return;
486
522
  }
487
523
  this.shuttingDown = true;
524
+ const shouldRestoreScrollback = this.alternateScreenEnabled && this.terminalInput.isAlternateScreenActive();
525
+ const scrollbackSnapshot = shouldRestoreScrollback
526
+ ? this.terminalInput.getScrollbackSnapshot()
527
+ : null;
488
528
  // Stop any active spinner to prevent process hang
489
529
  display.stopThinking(false);
490
530
  this.stopStreamingHeartbeat();
@@ -493,18 +533,34 @@ export class InteractiveShell {
493
533
  this.teardownStatusTracking();
494
534
  // Clear any pending cleanup to prevent hanging
495
535
  this.pendingCleanup = null;
536
+ // Reset terminal state before disposing adapters
537
+ this.terminalInput.exitStreamingScrollRegion();
538
+ if (this.alternateScreenEnabled) {
539
+ this.terminalInput.exitAlternateScreen();
540
+ }
496
541
  // Dispose terminal input handler
497
542
  this.terminalInput.dispose();
498
543
  // Dispose unified UI adapter
499
544
  this.uiAdapter.dispose();
545
+ if (scrollbackSnapshot && scrollbackSnapshot.length > 0) {
546
+ this.restoreScrollbackSnapshot(scrollbackSnapshot);
547
+ }
500
548
  display.newLine();
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)));
549
+ console.log(theme.ui.muted(''.repeat(44)));
550
+ console.log(theme.ui.muted(' Goodbye! · support@ero.solar'));
551
+ console.log(theme.ui.muted(''.repeat(44)));
506
552
  exit(0);
507
553
  }
554
+ restoreScrollbackSnapshot(lines) {
555
+ if (!lines.length) {
556
+ return;
557
+ }
558
+ const transcript = lines.join('\n');
559
+ const separator = theme.ui.muted('─'.repeat(44));
560
+ const header = theme.ui.muted('Restored scrollback from this session:');
561
+ // Write directly to stdout after exiting alternate screen to preserve the transcript
562
+ process.stdout.write(`\n${separator}\n${header}\n${transcript}\n${separator}\n`);
563
+ }
508
564
  /**
509
565
  * Update status bar message
510
566
  */
@@ -672,13 +728,14 @@ export class InteractiveShell {
672
728
  });
673
729
  }
674
730
  setProcessingStatus(detail) {
731
+ this.latestTokenUsage = { used: null, limit: this.latestTokenUsage.limit };
675
732
  this.statusTracker.setBase('Working on your request', {
676
733
  detail: this.describeStatusDetail(detail),
677
734
  tone: 'info',
678
735
  });
679
736
  }
680
737
  describeStatusDetail(detail) {
681
- const parts = [detail?.trim() || this.describeModelDetail()];
738
+ const parts = detail?.trim() ? [detail.trim()] : [];
682
739
  const queued = this.followUpQueue.length;
683
740
  if (queued > 0) {
684
741
  parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
@@ -691,12 +748,18 @@ export class InteractiveShell {
691
748
  }
692
749
  refreshContextGauge() {
693
750
  const tokens = getContextWindowTokens(this.sessionState.model);
694
- this.activeContextWindowTokens =
695
- typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
751
+ const normalizedTokens = typeof tokens === 'number' && Number.isFinite(tokens) ? tokens : null;
752
+ this.activeContextWindowTokens = normalizedTokens;
753
+ if (normalizedTokens !== null) {
754
+ this.latestTokenUsage = {
755
+ used: this.latestTokenUsage.used,
756
+ limit: normalizedTokens,
757
+ };
758
+ }
696
759
  }
697
760
  updateContextUsage(percentage) {
698
761
  this.uiAdapter.updateContextUsage(percentage);
699
- this.terminalInput.setContextUsage(percentage);
762
+ this.terminalInput.setContextUsage(percentage, CONTEXT_AUTOCOMPACT_PERCENT);
700
763
  }
701
764
  refreshControlBar() {
702
765
  this.terminalInput.setModeToggles({
@@ -704,9 +767,9 @@ export class InteractiveShell {
704
767
  autoContinueEnabled: this.autoContinueEnabled,
705
768
  verificationHotkey: 'alt+v',
706
769
  autoContinueHotkey: 'alt+c',
770
+ thinkingModeLabel: this.thinkingMode,
771
+ thinkingHotkey: '/thinking',
707
772
  });
708
- // Update persistent model info display
709
- this.terminalInput.setModelInfo(this.describeModelDetail());
710
773
  this.refreshStatusLine();
711
774
  this.terminalInput.render();
712
775
  }
@@ -737,6 +800,25 @@ export class InteractiveShell {
737
800
  // Set main status (tool execution, etc.) - shown when not overridden
738
801
  const statusText = this.formatStatusLine(this.statusLineState);
739
802
  this.terminalInput.setStatusMessage(statusText);
803
+ // Surface meta header (elapsed + context usage) above the divider
804
+ const elapsedSeconds = this.statusLineState
805
+ ? Math.max(0, Math.floor((Date.now() - this.statusLineState.startedAt) / 1000))
806
+ : null;
807
+ const thinkingMs = display.isSpinnerActive() ? display.getThinkingElapsedMs() : null;
808
+ const tokensUsed = this.latestTokenUsage.used;
809
+ const tokenLimit = this.latestTokenUsage.limit ?? this.activeContextWindowTokens;
810
+ this.terminalInput.setMetaStatus({
811
+ elapsedSeconds,
812
+ tokensUsed,
813
+ tokenLimit,
814
+ thinkingMs,
815
+ thinkingHasContent: display.isSpinnerActive(),
816
+ });
817
+ // Keep model/provider visible in the controls bar
818
+ this.terminalInput.setModelContext({
819
+ model: this.sessionState.model,
820
+ provider: this.providerLabel(this.sessionState.provider),
821
+ });
740
822
  if (forceRender) {
741
823
  this.terminalInput.render();
742
824
  }
@@ -796,15 +878,14 @@ export class InteractiveShell {
796
878
  this.terminalInput.render();
797
879
  }
798
880
  /**
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.
881
+ * Log user prompt to the scroll region so it's part of the conversation flow.
801
882
  */
802
883
  logUserPrompt(text) {
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());
884
+ if (!text.trim())
885
+ return;
886
+ // Format with user prompt prefix and write to scroll region
887
+ const formatted = `${theme.user('>')} ${text}\n`;
888
+ this.terminalInput.writeToScrollRegion(formatted);
808
889
  }
809
890
  requestPromptRefresh(force = false) {
810
891
  if (force) {
@@ -829,16 +910,40 @@ export class InteractiveShell {
829
910
  this.stopStreamingHeartbeat();
830
911
  // Enter global streaming mode - blocks all non-streaming UI output
831
912
  enterStreamingMode();
913
+ // Set up scroll region for streaming content
914
+ this.terminalInput.enterStreamingScrollRegion();
832
915
  this.uiUpdates.setMode('streaming');
833
916
  this.streamingHeartbeatStart = Date.now();
834
917
  this.streamingHeartbeatFrame = 0;
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.
918
+ const initialFrame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
919
+ this.streamingStatusLabel = this.buildStreamingStatus(`${initialFrame} ${label}`, 0);
920
+ display.updateStreamingStatus(this.streamingStatusLabel);
921
+ this.refreshStatusLine(true);
922
+ // Periodically refresh the pinned input/status region while streaming so
923
+ // elapsed time remains visible without interrupting the scroll region.
924
+ this.uiUpdates.startHeartbeat('streaming', {
925
+ intervalMs: 1000,
926
+ lane: 'heartbeat',
927
+ mode: ['streaming', 'processing'],
928
+ coalesceKey: 'streaming:heartbeat',
929
+ run: () => {
930
+ const elapsedSeconds = this.streamingHeartbeatStart
931
+ ? Math.max(0, Math.floor((Date.now() - this.streamingHeartbeatStart) / 1000))
932
+ : 0;
933
+ this.streamingHeartbeatFrame =
934
+ (this.streamingHeartbeatFrame + 1) % STREAMING_SPINNER_FRAMES.length;
935
+ const frame = STREAMING_SPINNER_FRAMES[this.streamingHeartbeatFrame];
936
+ this.streamingStatusLabel = this.buildStreamingStatus(`${frame} ${label}`, elapsedSeconds);
937
+ display.updateStreamingStatus(this.streamingStatusLabel);
938
+ this.refreshStatusLine(true);
939
+ },
940
+ });
838
941
  }
839
942
  stopStreamingHeartbeat() {
840
943
  // Exit global streaming mode - allows UI to render again
841
944
  exitStreamingMode();
945
+ // Exit scroll region mode
946
+ this.terminalInput.exitStreamingScrollRegion();
842
947
  this.uiUpdates.stopHeartbeat('streaming');
843
948
  this.streamingHeartbeatStart = null;
844
949
  this.streamingHeartbeatFrame = 0;
@@ -850,10 +955,28 @@ export class InteractiveShell {
850
955
  // Force refresh to update the input area now that streaming has ended
851
956
  this.refreshStatusLine(true);
852
957
  }
853
- buildStreamingStatus(label) {
958
+ buildStreamingStatus(label, elapsedSeconds) {
854
959
  const detail = this.describeModelDetail();
855
- const prefix = theme.info('');
856
- return detail ? `${prefix} ${label} ${theme.ui.muted('·')} ${detail}` : `${prefix} ${label}`;
960
+ const elapsedLabel = typeof elapsedSeconds === 'number' && elapsedSeconds >= 0
961
+ ? theme.ui.muted(this.formatElapsedShort(elapsedSeconds))
962
+ : null;
963
+ const prefix = theme.info('⏺');
964
+ const parts = [label];
965
+ if (detail) {
966
+ parts.push(theme.ui.muted('·'), detail);
967
+ }
968
+ if (elapsedLabel) {
969
+ parts.push(theme.ui.muted('·'), elapsedLabel);
970
+ }
971
+ return `${prefix} ${parts.join(' ')}`.trim();
972
+ }
973
+ formatElapsedShort(seconds) {
974
+ if (seconds < 60) {
975
+ return `${seconds}s`;
976
+ }
977
+ const minutes = Math.floor(seconds / 60);
978
+ const remaining = seconds % 60;
979
+ return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
857
980
  }
858
981
  refreshQueueIndicators() {
859
982
  if (this.isProcessing) {
@@ -1101,17 +1224,6 @@ export class InteractiveShell {
1101
1224
  case '/discover':
1102
1225
  await this.discoverModelsCommand();
1103
1226
  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;
1115
1227
  default:
1116
1228
  if (!(await this.tryCustomSlashCommand(command, input))) {
1117
1229
  display.showWarning(`Unknown command "${command}".`);
@@ -1420,99 +1532,6 @@ export class InteractiveShell {
1420
1532
  // Display keyboard shortcuts help (Claude Code style)
1421
1533
  display.showSystemMessage(formatShortcutsHelp());
1422
1534
  }
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
- }
1516
1535
  showFileChangeSummary() {
1517
1536
  const summary = this._fileChangeTracker.getSummary();
1518
1537
  const changes = this._fileChangeTracker.getAllChanges();
@@ -1555,11 +1574,11 @@ When working in this codebase:
1555
1574
  display.showSystemMessage(lines.join('\n'));
1556
1575
  }
1557
1576
  showAlphaZeroMetrics() {
1558
- const summary = this.sessionMetrics.getPerformanceSummary();
1577
+ const summary = this.alphaZeroMetrics.getPerformanceSummary();
1559
1578
  display.showSystemMessage(summary);
1560
1579
  }
1561
1580
  showImprovementSuggestions() {
1562
- const suggestions = this.sessionMetrics.getImprovementSuggestions();
1581
+ const suggestions = this.alphaZeroMetrics.getImprovementSuggestions();
1563
1582
  if (suggestions.length === 0) {
1564
1583
  display.showInfo('No improvement suggestions at this time. Keep using the shell to generate metrics!');
1565
1584
  return;
@@ -1605,7 +1624,9 @@ When working in this codebase:
1605
1624
  }
1606
1625
  }
1607
1626
  lines.push(theme.secondary('CLI Flags:'));
1627
+ lines.push(' --alpha-zero Enable Alpha Zero 2 RL framework');
1608
1628
  lines.push(' --coding Enable enhanced coding tools');
1629
+ lines.push(' --security Enable security research tools');
1609
1630
  lines.push(' --all-plugins Enable all optional plugins');
1610
1631
  display.showSystemMessage(lines.join('\n'));
1611
1632
  }
@@ -1654,6 +1675,7 @@ When working in this codebase:
1654
1675
  model: this.sessionState.model,
1655
1676
  workspaceRoot: this.workingDir,
1656
1677
  messages: history,
1678
+ scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
1657
1679
  });
1658
1680
  this.cachedHistory = history;
1659
1681
  this.updateActiveSession(summary, true);
@@ -1832,6 +1854,7 @@ When working in this codebase:
1832
1854
  workspaceRoot: this.workingDir,
1833
1855
  title: this.activeSessionTitle,
1834
1856
  messages: this.cachedHistory,
1857
+ scrollbackBuffer: this.terminalInput.getScrollbackBuffer(),
1835
1858
  });
1836
1859
  }
1837
1860
  describeWorkspaceOptions() {
@@ -1849,6 +1872,75 @@ When working in this codebase:
1849
1872
  }
1850
1873
  return `${warning.label}: ${warning.reason}.`;
1851
1874
  }
1875
+ buildLaunchCommandPalette() {
1876
+ const entries = [];
1877
+ const secretsSummary = this.summarizeSecretsForPalette();
1878
+ const toolSummary = this.getToolSelectionSummary();
1879
+ const autosaveLabel = this.autosaveEnabled ? 'on' : 'off';
1880
+ for (const command of this.slashCommands) {
1881
+ const entry = {
1882
+ command: command.command,
1883
+ description: command.description,
1884
+ category: command.category ?? 'other',
1885
+ };
1886
+ switch (command.command) {
1887
+ case '/secrets':
1888
+ if (secretsSummary.text) {
1889
+ entry.description = `${command.description} (${secretsSummary.text})`;
1890
+ entry.tone = secretsSummary.tone;
1891
+ }
1892
+ break;
1893
+ case '/tools':
1894
+ if (toolSummary) {
1895
+ entry.description = `${command.description} (${toolSummary})`;
1896
+ }
1897
+ break;
1898
+ case '/sessions':
1899
+ entry.description = `${command.description} (autosave ${autosaveLabel})`;
1900
+ break;
1901
+ case '/model':
1902
+ entry.description = `${command.description} (current: ${this.sessionState.model})`;
1903
+ break;
1904
+ case '/provider':
1905
+ entry.description = `${command.description} (current: ${this.providerLabel(this.sessionState.provider)})`;
1906
+ break;
1907
+ default:
1908
+ break;
1909
+ }
1910
+ entries.push(entry);
1911
+ }
1912
+ return entries;
1913
+ }
1914
+ summarizeSecretsForPalette() {
1915
+ const definitions = listSecretDefinitions();
1916
+ if (!definitions.length) {
1917
+ return { text: null };
1918
+ }
1919
+ const missing = definitions.filter((definition) => !getSecretValue(definition.id));
1920
+ if (missing.length === 0) {
1921
+ return { text: 'all configured', tone: 'success' };
1922
+ }
1923
+ const labels = missing.map((definition) => definition.label ?? definition.id);
1924
+ return { text: `missing ${this.formatList(labels)}`, tone: 'warn' };
1925
+ }
1926
+ getToolSelectionSummary() {
1927
+ const toolSettings = loadToolSettings();
1928
+ const selection = buildEnabledToolSet(toolSettings);
1929
+ const options = getToolToggleOptions();
1930
+ if (!options.length) {
1931
+ return null;
1932
+ }
1933
+ const enabledCount = options.filter((option) => selection.has(option.id)).length;
1934
+ return `${enabledCount}/${options.length} enabled`;
1935
+ }
1936
+ formatList(values, maxItems = 3) {
1937
+ if (!values.length) {
1938
+ return '';
1939
+ }
1940
+ const shown = values.slice(0, maxItems);
1941
+ const suffix = values.length > maxItems ? ', …' : '';
1942
+ return `${shown.join(', ')}${suffix}`;
1943
+ }
1852
1944
  buildSlashCommandList(header) {
1853
1945
  const lines = [theme.gradient.primary(header), ''];
1854
1946
  for (const command of this.slashCommands) {
@@ -2317,7 +2409,7 @@ When working in this codebase:
2317
2409
  this.autosaveIfEnabled();
2318
2410
  // Track metrics with Alpha Zero 2
2319
2411
  const elapsedMs = Date.now() - requestStartTime;
2320
- this.sessionMetrics.recordMessage(elapsedMs);
2412
+ this.alphaZeroMetrics.recordMessage(elapsedMs);
2321
2413
  if (!responseText?.trim()) {
2322
2414
  display.showWarning('The provider returned an empty response. Check your API key/provider selection or retry the prompt.');
2323
2415
  }
@@ -2335,14 +2427,10 @@ When working in this codebase:
2335
2427
  this.stopStreamingHeartbeat();
2336
2428
  this.isProcessing = false;
2337
2429
  this.terminalInput.setStreaming(false);
2338
- this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
2339
2430
  this.uiAdapter.endProcessing('Ready for prompts');
2340
2431
  this.setIdleStatus();
2341
2432
  display.newLine();
2342
2433
  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();
2346
2434
  queueMicrotask(() => this.uiUpdates.setMode('idle'));
2347
2435
  // CRITICAL: Ensure readline prompt is active for user input
2348
2436
  // Claude Code style: New prompt naturally appears at bottom
@@ -2419,13 +2507,14 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
2419
2507
  try {
2420
2508
  // Send the request and capture the response (streaming disabled)
2421
2509
  display.showThinking('Responding...');
2510
+ this.refreshStatusLine(true);
2422
2511
  const response = await agent.send(currentPrompt, true);
2423
2512
  await this.awaitPendingCleanup();
2424
2513
  this.captureHistorySnapshot();
2425
2514
  this.autosaveIfEnabled();
2426
2515
  // Track metrics
2427
2516
  const elapsedMs = Date.now() - overallStartTime;
2428
- this.sessionMetrics.recordMessage(elapsedMs);
2517
+ this.alphaZeroMetrics.recordMessage(elapsedMs);
2429
2518
  if (!response?.trim()) {
2430
2519
  display.showWarning('Model returned an empty response. Retrying this iteration...');
2431
2520
  consecutiveNoProgress++;
@@ -2562,7 +2651,6 @@ What's the next action?`;
2562
2651
  this.stopStreamingHeartbeat();
2563
2652
  this.isProcessing = false;
2564
2653
  this.terminalInput.setStreaming(false);
2565
- this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
2566
2654
  this.uiAdapter.endProcessing('Ready for prompts');
2567
2655
  this.setIdleStatus();
2568
2656
  this.updateStatusMessage(null);
@@ -2919,8 +3007,10 @@ What's the next action?`;
2919
3007
  try {
2920
3008
  // Send the error to the agent for fixing
2921
3009
  display.showThinking('Analyzing build errors');
3010
+ this.refreshStatusLine(true);
2922
3011
  const response = await this.agent.send(prompt, true);
2923
3012
  display.stopThinking();
3013
+ this.refreshStatusLine(true);
2924
3014
  if (response) {
2925
3015
  display.showAssistantMessage(response, { isFinal: true });
2926
3016
  }
@@ -2947,8 +3037,8 @@ What's the next action?`;
2947
3037
  };
2948
3038
  this.agent = this.runtimeSession.createAgent(selection, {
2949
3039
  onStreamChunk: (chunk) => {
2950
- // Stream output directly - no spinner during streaming to avoid race conditions
2951
- display.stream(chunk);
3040
+ // Stream output using clean streamContent() - chat box floats below
3041
+ this.terminalInput.streamContent(chunk);
2952
3042
  },
2953
3043
  onStreamFallback: (info) => this.handleStreamingFallback(info),
2954
3044
  onAssistantMessage: (content, metadata) => {
@@ -2970,18 +3060,16 @@ What's the next action?`;
2970
3060
  display.showAssistantMessage(finalContent, enriched);
2971
3061
  }
2972
3062
  }
2973
- // Show status line at end (Claude Code style: "• Context X% used • Ready for prompts (2s)")
3063
+ // Status shown in mode controls bar - no separate status line needed
2974
3064
  display.stopThinking();
2975
- // Calculate context usage
2976
- let contextInfo;
3065
+ // Update context usage for mode controls display
2977
3066
  if (enriched.contextWindowTokens && metadata.usage) {
2978
3067
  const total = this.totalTokens(metadata.usage);
2979
3068
  if (total && total > 0) {
2980
3069
  const percentage = Math.round((total / enriched.contextWindowTokens) * 100);
2981
- contextInfo = { percentage, tokens: total };
3070
+ this.updateContextUsage(percentage);
2982
3071
  }
2983
3072
  }
2984
- display.showStatusLine('Ready for prompts', enriched.elapsedMs, contextInfo);
2985
3073
  // Auto-verify changes: build first (catches type errors), then tests
2986
3074
  void this.enforceAutoBuild('final-response');
2987
3075
  void this.enforceAutoTests('final-response');
@@ -3051,7 +3139,6 @@ What's the next action?`;
3051
3139
  this.stopStreamingHeartbeat();
3052
3140
  this.updateStatusMessage(null);
3053
3141
  this.terminalInput.setStreaming(false);
3054
- this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
3055
3142
  this.terminalInput.render();
3056
3143
  },
3057
3144
  onVerificationNeeded: () => {
@@ -3088,7 +3175,6 @@ What's the next action?`;
3088
3175
  resetChatBoxAfterModelSwap() {
3089
3176
  this.updateStatusMessage(null);
3090
3177
  this.terminalInput.setStreaming(false);
3091
- this.terminalInput.setContentEndRow(display.getTotalWrittenLines());
3092
3178
  this.terminalInput.render();
3093
3179
  this.ensureReadlineReady();
3094
3180
  }
@@ -3153,9 +3239,14 @@ What's the next action?`;
3153
3239
  return null;
3154
3240
  }
3155
3241
  const usageRatio = total / windowTokens;
3242
+ this.latestTokenUsage = {
3243
+ used: total,
3244
+ limit: windowTokens,
3245
+ };
3156
3246
  // Always update context usage in the UI
3157
3247
  const percentUsed = Math.round(usageRatio * 100);
3158
3248
  this.updateContextUsage(percentUsed);
3249
+ this.refreshStatusLine(true);
3159
3250
  if (usageRatio < CONTEXT_USAGE_THRESHOLD) {
3160
3251
  return null;
3161
3252
  }
@@ -3422,6 +3513,22 @@ What's the next action?`;
3422
3513
  this.sessionState.reasoningEffort = preset.reasoningEffort;
3423
3514
  }
3424
3515
  }
3516
+ /**
3517
+ * Build the session banner.
3518
+ */
3519
+ buildBanner() {
3520
+ const terminalWidth = output.columns ?? 100;
3521
+ const width = Math.min(terminalWidth - 4, 110);
3522
+ return renderSessionFrame({
3523
+ profileLabel: this.profileLabel,
3524
+ profileName: this.profile,
3525
+ model: this.sessionState.model,
3526
+ provider: this.sessionState.provider,
3527
+ workspace: this.workingDir,
3528
+ version: this.version,
3529
+ width,
3530
+ });
3531
+ }
3425
3532
  refreshBannerSessionInfo() {
3426
3533
  const nextState = {
3427
3534
  model: this.sessionState.model,
@@ -3432,13 +3539,11 @@ What's the next action?`;
3432
3539
  return;
3433
3540
  }
3434
3541
  this.refreshContextGauge();
3435
- display.updateSessionInfo(nextState.model, nextState.provider);
3436
- // Update the persistent model info display in terminal input
3437
- this.terminalInput.setModelInfo(this.describeModelDetail());
3542
+ // Banner is no longer stored in display - it was streamed as content
3543
+ // Model/provider changes are visible in the control bar
3438
3544
  if (!this.isProcessing) {
3439
3545
  this.setIdleStatus();
3440
3546
  }
3441
- // Pinned header rows are disabled; scroll region handles all output.
3442
3547
  this.bannerSessionState = nextState;
3443
3548
  }
3444
3549
  providerLabel(id) {