erosolar-cli 1.7.356 → 1.7.358

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 (328) 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 +41 -7
  67. package/dist/shell/interactiveShell.d.ts.map +1 -1
  68. package/dist/shell/interactiveShell.js +399 -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 +250 -125
  78. package/dist/shell/terminalInput.d.ts.map +1 -1
  79. package/dist/shell/terminalInput.js +1061 -612
  80. package/dist/shell/terminalInput.js.map +1 -1
  81. package/dist/shell/terminalInputAdapter.d.ts +106 -24
  82. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  83. package/dist/shell/terminalInputAdapter.js +137 -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 +200 -49
  96. package/dist/subagents/taskRunner.js.map +1 -1
  97. package/dist/ui/ShellUIAdapter.d.ts +7 -1
  98. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  99. package/dist/ui/ShellUIAdapter.js +42 -18
  100. package/dist/ui/ShellUIAdapter.js.map +1 -1
  101. package/dist/ui/display.d.ts +24 -45
  102. package/dist/ui/display.d.ts.map +1 -1
  103. package/dist/ui/display.js +148 -274
  104. package/dist/ui/display.js.map +1 -1
  105. package/dist/ui/theme.d.ts.map +1 -1
  106. package/dist/ui/theme.js +6 -8
  107. package/dist/ui/theme.js.map +1 -1
  108. package/dist/ui/toolDisplay.d.ts +0 -158
  109. package/dist/ui/toolDisplay.d.ts.map +1 -1
  110. package/dist/ui/toolDisplay.js +0 -348
  111. package/dist/ui/toolDisplay.js.map +1 -1
  112. package/dist/ui/unified/layout.d.ts +20 -0
  113. package/dist/ui/unified/layout.d.ts.map +1 -1
  114. package/dist/ui/unified/layout.js +105 -216
  115. package/dist/ui/unified/layout.js.map +1 -1
  116. package/dist/utils/frontmatter.d.ts +10 -0
  117. package/dist/utils/frontmatter.d.ts.map +1 -0
  118. package/dist/utils/frontmatter.js +78 -0
  119. package/dist/utils/frontmatter.js.map +1 -0
  120. package/package.json +4 -4
  121. package/dist/alpha-zero/agentWrapper.d.ts +0 -84
  122. package/dist/alpha-zero/agentWrapper.d.ts.map +0 -1
  123. package/dist/alpha-zero/agentWrapper.js +0 -171
  124. package/dist/alpha-zero/agentWrapper.js.map +0 -1
  125. package/dist/alpha-zero/codeEvaluator.d.ts +0 -25
  126. package/dist/alpha-zero/codeEvaluator.d.ts.map +0 -1
  127. package/dist/alpha-zero/codeEvaluator.js +0 -273
  128. package/dist/alpha-zero/codeEvaluator.js.map +0 -1
  129. package/dist/alpha-zero/competitiveRunner.d.ts +0 -66
  130. package/dist/alpha-zero/competitiveRunner.d.ts.map +0 -1
  131. package/dist/alpha-zero/competitiveRunner.js +0 -224
  132. package/dist/alpha-zero/competitiveRunner.js.map +0 -1
  133. package/dist/alpha-zero/index.d.ts +0 -67
  134. package/dist/alpha-zero/index.d.ts.map +0 -1
  135. package/dist/alpha-zero/index.js +0 -99
  136. package/dist/alpha-zero/index.js.map +0 -1
  137. package/dist/alpha-zero/introspection.d.ts +0 -128
  138. package/dist/alpha-zero/introspection.d.ts.map +0 -1
  139. package/dist/alpha-zero/introspection.js +0 -300
  140. package/dist/alpha-zero/introspection.js.map +0 -1
  141. package/dist/alpha-zero/metricsTracker.d.ts +0 -71
  142. package/dist/alpha-zero/metricsTracker.d.ts.map +0 -1
  143. package/dist/alpha-zero/metricsTracker.js.map +0 -1
  144. package/dist/alpha-zero/security/core.d.ts +0 -125
  145. package/dist/alpha-zero/security/core.d.ts.map +0 -1
  146. package/dist/alpha-zero/security/core.js +0 -271
  147. package/dist/alpha-zero/security/core.js.map +0 -1
  148. package/dist/alpha-zero/security/google.d.ts +0 -125
  149. package/dist/alpha-zero/security/google.d.ts.map +0 -1
  150. package/dist/alpha-zero/security/google.js +0 -311
  151. package/dist/alpha-zero/security/google.js.map +0 -1
  152. package/dist/alpha-zero/security/googleLoader.d.ts +0 -17
  153. package/dist/alpha-zero/security/googleLoader.d.ts.map +0 -1
  154. package/dist/alpha-zero/security/googleLoader.js +0 -41
  155. package/dist/alpha-zero/security/googleLoader.js.map +0 -1
  156. package/dist/alpha-zero/security/index.d.ts +0 -29
  157. package/dist/alpha-zero/security/index.d.ts.map +0 -1
  158. package/dist/alpha-zero/security/index.js +0 -32
  159. package/dist/alpha-zero/security/index.js.map +0 -1
  160. package/dist/alpha-zero/security/simulation.d.ts +0 -124
  161. package/dist/alpha-zero/security/simulation.d.ts.map +0 -1
  162. package/dist/alpha-zero/security/simulation.js +0 -277
  163. package/dist/alpha-zero/security/simulation.js.map +0 -1
  164. package/dist/alpha-zero/selfModification.d.ts +0 -109
  165. package/dist/alpha-zero/selfModification.d.ts.map +0 -1
  166. package/dist/alpha-zero/selfModification.js +0 -233
  167. package/dist/alpha-zero/selfModification.js.map +0 -1
  168. package/dist/alpha-zero/types.d.ts +0 -170
  169. package/dist/alpha-zero/types.d.ts.map +0 -1
  170. package/dist/alpha-zero/types.js +0 -31
  171. package/dist/alpha-zero/types.js.map +0 -1
  172. package/dist/capabilities/securityTestingCapability.d.ts +0 -13
  173. package/dist/capabilities/securityTestingCapability.d.ts.map +0 -1
  174. package/dist/capabilities/securityTestingCapability.js +0 -25
  175. package/dist/capabilities/securityTestingCapability.js.map +0 -1
  176. package/dist/core/aiFlowOptimizer.d.ts +0 -26
  177. package/dist/core/aiFlowOptimizer.d.ts.map +0 -1
  178. package/dist/core/aiFlowOptimizer.js +0 -31
  179. package/dist/core/aiFlowOptimizer.js.map +0 -1
  180. package/dist/core/aiOptimizationEngine.d.ts +0 -158
  181. package/dist/core/aiOptimizationEngine.d.ts.map +0 -1
  182. package/dist/core/aiOptimizationEngine.js +0 -428
  183. package/dist/core/aiOptimizationEngine.js.map +0 -1
  184. package/dist/core/aiOptimizationIntegration.d.ts +0 -93
  185. package/dist/core/aiOptimizationIntegration.d.ts.map +0 -1
  186. package/dist/core/aiOptimizationIntegration.js +0 -250
  187. package/dist/core/aiOptimizationIntegration.js.map +0 -1
  188. package/dist/core/enhancedErrorRecovery.d.ts +0 -100
  189. package/dist/core/enhancedErrorRecovery.d.ts.map +0 -1
  190. package/dist/core/enhancedErrorRecovery.js +0 -345
  191. package/dist/core/enhancedErrorRecovery.js.map +0 -1
  192. package/dist/core/hooksSystem.d.ts +0 -65
  193. package/dist/core/hooksSystem.d.ts.map +0 -1
  194. package/dist/core/hooksSystem.js +0 -273
  195. package/dist/core/hooksSystem.js.map +0 -1
  196. package/dist/core/memorySystem.d.ts +0 -48
  197. package/dist/core/memorySystem.d.ts.map +0 -1
  198. package/dist/core/memorySystem.js +0 -271
  199. package/dist/core/memorySystem.js.map +0 -1
  200. package/dist/core/unified/errors.d.ts +0 -189
  201. package/dist/core/unified/errors.d.ts.map +0 -1
  202. package/dist/core/unified/errors.js +0 -497
  203. package/dist/core/unified/errors.js.map +0 -1
  204. package/dist/core/unified/index.d.ts +0 -19
  205. package/dist/core/unified/index.d.ts.map +0 -1
  206. package/dist/core/unified/index.js +0 -68
  207. package/dist/core/unified/index.js.map +0 -1
  208. package/dist/core/unified/schema.d.ts +0 -101
  209. package/dist/core/unified/schema.d.ts.map +0 -1
  210. package/dist/core/unified/schema.js +0 -350
  211. package/dist/core/unified/schema.js.map +0 -1
  212. package/dist/core/unified/toolRuntime.d.ts +0 -179
  213. package/dist/core/unified/toolRuntime.d.ts.map +0 -1
  214. package/dist/core/unified/toolRuntime.js +0 -517
  215. package/dist/core/unified/toolRuntime.js.map +0 -1
  216. package/dist/core/unified/tools.d.ts +0 -127
  217. package/dist/core/unified/tools.d.ts.map +0 -1
  218. package/dist/core/unified/tools.js +0 -1333
  219. package/dist/core/unified/tools.js.map +0 -1
  220. package/dist/core/unified/types.d.ts +0 -352
  221. package/dist/core/unified/types.d.ts.map +0 -1
  222. package/dist/core/unified/types.js +0 -12
  223. package/dist/core/unified/types.js.map +0 -1
  224. package/dist/core/unified/version.d.ts +0 -209
  225. package/dist/core/unified/version.d.ts.map +0 -1
  226. package/dist/core/unified/version.js +0 -454
  227. package/dist/core/unified/version.js.map +0 -1
  228. package/dist/plugins/tools/security/securityPlugin.d.ts +0 -3
  229. package/dist/plugins/tools/security/securityPlugin.d.ts.map +0 -1
  230. package/dist/plugins/tools/security/securityPlugin.js +0 -12
  231. package/dist/plugins/tools/security/securityPlugin.js.map +0 -1
  232. package/dist/security/active-stack-security.d.ts +0 -112
  233. package/dist/security/active-stack-security.d.ts.map +0 -1
  234. package/dist/security/active-stack-security.js +0 -296
  235. package/dist/security/active-stack-security.js.map +0 -1
  236. package/dist/security/advanced-persistence-research.d.ts +0 -92
  237. package/dist/security/advanced-persistence-research.d.ts.map +0 -1
  238. package/dist/security/advanced-persistence-research.js +0 -195
  239. package/dist/security/advanced-persistence-research.js.map +0 -1
  240. package/dist/security/advanced-targeting.d.ts +0 -119
  241. package/dist/security/advanced-targeting.d.ts.map +0 -1
  242. package/dist/security/advanced-targeting.js +0 -233
  243. package/dist/security/advanced-targeting.js.map +0 -1
  244. package/dist/security/assessment/vulnerabilityAssessment.d.ts +0 -104
  245. package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +0 -1
  246. package/dist/security/assessment/vulnerabilityAssessment.js +0 -315
  247. package/dist/security/assessment/vulnerabilityAssessment.js.map +0 -1
  248. package/dist/security/authorization/securityAuthorization.d.ts +0 -88
  249. package/dist/security/authorization/securityAuthorization.d.ts.map +0 -1
  250. package/dist/security/authorization/securityAuthorization.js +0 -172
  251. package/dist/security/authorization/securityAuthorization.js.map +0 -1
  252. package/dist/security/comprehensive-targeting.d.ts +0 -85
  253. package/dist/security/comprehensive-targeting.d.ts.map +0 -1
  254. package/dist/security/comprehensive-targeting.js +0 -438
  255. package/dist/security/comprehensive-targeting.js.map +0 -1
  256. package/dist/security/global-security-integration.d.ts +0 -91
  257. package/dist/security/global-security-integration.d.ts.map +0 -1
  258. package/dist/security/global-security-integration.js +0 -218
  259. package/dist/security/global-security-integration.js.map +0 -1
  260. package/dist/security/index.d.ts +0 -38
  261. package/dist/security/index.d.ts.map +0 -1
  262. package/dist/security/index.js +0 -47
  263. package/dist/security/index.js.map +0 -1
  264. package/dist/security/persistence-analyzer.d.ts +0 -56
  265. package/dist/security/persistence-analyzer.d.ts.map +0 -1
  266. package/dist/security/persistence-analyzer.js +0 -187
  267. package/dist/security/persistence-analyzer.js.map +0 -1
  268. package/dist/security/persistence-cli.d.ts +0 -36
  269. package/dist/security/persistence-cli.d.ts.map +0 -1
  270. package/dist/security/persistence-cli.js +0 -160
  271. package/dist/security/persistence-cli.js.map +0 -1
  272. package/dist/security/persistence-research.d.ts +0 -92
  273. package/dist/security/persistence-research.d.ts.map +0 -1
  274. package/dist/security/persistence-research.js +0 -364
  275. package/dist/security/persistence-research.js.map +0 -1
  276. package/dist/security/research/persistenceResearch.d.ts +0 -97
  277. package/dist/security/research/persistenceResearch.d.ts.map +0 -1
  278. package/dist/security/research/persistenceResearch.js +0 -282
  279. package/dist/security/research/persistenceResearch.js.map +0 -1
  280. package/dist/security/security-integration.d.ts +0 -74
  281. package/dist/security/security-integration.d.ts.map +0 -1
  282. package/dist/security/security-integration.js +0 -137
  283. package/dist/security/security-integration.js.map +0 -1
  284. package/dist/security/security-testing-framework.d.ts +0 -112
  285. package/dist/security/security-testing-framework.d.ts.map +0 -1
  286. package/dist/security/security-testing-framework.js +0 -364
  287. package/dist/security/security-testing-framework.js.map +0 -1
  288. package/dist/security/simulation/attackSimulation.d.ts +0 -93
  289. package/dist/security/simulation/attackSimulation.d.ts.map +0 -1
  290. package/dist/security/simulation/attackSimulation.js +0 -341
  291. package/dist/security/simulation/attackSimulation.js.map +0 -1
  292. package/dist/security/strategic-operations.d.ts +0 -100
  293. package/dist/security/strategic-operations.d.ts.map +0 -1
  294. package/dist/security/strategic-operations.js +0 -276
  295. package/dist/security/strategic-operations.js.map +0 -1
  296. package/dist/security/tool-security-wrapper.d.ts +0 -58
  297. package/dist/security/tool-security-wrapper.d.ts.map +0 -1
  298. package/dist/security/tool-security-wrapper.js +0 -156
  299. package/dist/security/tool-security-wrapper.js.map +0 -1
  300. package/dist/shell/claudeCodeStreamHandler.d.ts +0 -145
  301. package/dist/shell/claudeCodeStreamHandler.d.ts.map +0 -1
  302. package/dist/shell/claudeCodeStreamHandler.js +0 -322
  303. package/dist/shell/claudeCodeStreamHandler.js.map +0 -1
  304. package/dist/shell/inputQueueManager.d.ts +0 -144
  305. package/dist/shell/inputQueueManager.d.ts.map +0 -1
  306. package/dist/shell/inputQueueManager.js +0 -290
  307. package/dist/shell/inputQueueManager.js.map +0 -1
  308. package/dist/shell/metricsTracker.d.ts +0 -60
  309. package/dist/shell/metricsTracker.d.ts.map +0 -1
  310. package/dist/shell/metricsTracker.js +0 -119
  311. package/dist/shell/metricsTracker.js.map +0 -1
  312. package/dist/shell/streamingOutputManager.d.ts +0 -115
  313. package/dist/shell/streamingOutputManager.d.ts.map +0 -1
  314. package/dist/shell/streamingOutputManager.js +0 -225
  315. package/dist/shell/streamingOutputManager.js.map +0 -1
  316. package/dist/tools/securityTools.d.ts +0 -22
  317. package/dist/tools/securityTools.d.ts.map +0 -1
  318. package/dist/tools/securityTools.js +0 -448
  319. package/dist/tools/securityTools.js.map +0 -1
  320. package/dist/ui/persistentPrompt.d.ts +0 -50
  321. package/dist/ui/persistentPrompt.d.ts.map +0 -1
  322. package/dist/ui/persistentPrompt.js +0 -92
  323. package/dist/ui/persistentPrompt.js.map +0 -1
  324. package/dist/ui/terminalUISchema.d.ts +0 -195
  325. package/dist/ui/terminalUISchema.d.ts.map +0 -1
  326. package/dist/ui/terminalUISchema.js +0 -113
  327. package/dist/ui/terminalUISchema.js.map +0 -1
  328. package/scripts/deploy-security-capabilities.js +0 -178
@@ -1,5 +1,5 @@
1
1
  import { createSpinner } from 'nanospinner';
2
- import { clearScreenDown, cursorTo, moveCursor } from 'node:readline';
2
+ import { clearScreenDown, cursorTo } from 'node:readline';
3
3
  import { theme, icons } from './theme.js';
4
4
  import { formatRichContent, renderMessagePanel, renderMessageBody } from './richText.js';
5
5
  import { getTerminalColumns } from './layout.js';
@@ -7,7 +7,7 @@ import { highlightError } from './textHighlighter.js';
7
7
  import { renderSectionHeading } from './designSystem.js';
8
8
  import { isPlainOutputMode } from './outputMode.js';
9
9
  import { writeLock } from './writeLock.js';
10
- import { renderSessionFrame, renderStatusLine } from './unified/layout.js';
10
+ import { renderStatusLine } from './unified/layout.js';
11
11
  import { isStreamingMode } from './globalWriteLock.js';
12
12
  /**
13
13
  * Output lock to prevent race conditions during spinner/stream output.
@@ -159,11 +159,6 @@ const DISPLAY_CONSTANTS = {
159
159
  };
160
160
  // Enhanced spinner frames with smooth animation
161
161
  const SPINNER_FRAMES = ['◐', '◓', '◑', '◒', '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
162
- const clampWidthToAvailable = (available, min, max) => {
163
- const bounded = Math.max(1, Math.floor(available));
164
- const preferred = Math.max(min, Math.min(bounded, max));
165
- return Math.min(preferred, bounded);
166
- };
167
162
  /**
168
163
  * Display class manages all terminal UI output for the application.
169
164
  *
@@ -259,10 +254,10 @@ export class Display {
259
254
  interceptor.beforeWrite?.();
260
255
  }
261
256
  }
262
- notifyAfterOutput() {
257
+ notifyAfterOutput(content) {
263
258
  const interceptors = Array.from(this.outputInterceptors);
264
259
  for (let index = interceptors.length - 1; index >= 0; index -= 1) {
265
- interceptors[index]?.afterWrite?.();
260
+ interceptors[index]?.afterWrite?.(content);
266
261
  }
267
262
  }
268
263
  write(value, target = this.outputStream) {
@@ -291,29 +286,36 @@ export class Display {
291
286
  if (typeof content !== 'string' || !content) {
292
287
  return;
293
288
  }
294
- // During streaming mode, write directly without locks for smooth output
295
- // StdoutLineTracker patches outputStream.write, so lines are tracked automatically
289
+ // Normalize carriage returns to avoid overwriting streamed content on the same line.
290
+ // Some providers emit '\r' when streaming; convert to '\n' so we append instead of rewriting.
291
+ const normalized = content.includes('\r')
292
+ ? content.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
293
+ : content;
294
+ // During streaming, use withLock to prevent interleaving with escape codes.
295
+ // This ensures the before/write/after sequence is atomic.
296
296
  if (isStreamingMode()) {
297
- this.notifyBeforeOutput();
298
- try {
299
- this.outputStream.write(content);
300
- }
301
- catch {
302
- // Ignore write failures to keep UI resilient
303
- }
304
- finally {
305
- this.notifyAfterOutput();
306
- }
297
+ writeLock.withLock(() => {
298
+ this.notifyBeforeOutput();
299
+ try {
300
+ this.outputStream.write(normalized);
301
+ }
302
+ catch {
303
+ // Ignore write failures to keep UI resilient
304
+ }
305
+ finally {
306
+ this.notifyAfterOutput(normalized);
307
+ }
308
+ }, 'display.writeRaw.streaming');
307
309
  return;
308
310
  }
309
311
  // Outside streaming mode, use locks to coordinate with other UI
310
312
  writeLock.withLock(() => {
311
313
  this.notifyBeforeOutput();
312
314
  try {
313
- this.write(content);
315
+ this.write(normalized);
314
316
  }
315
317
  finally {
316
- this.notifyAfterOutput();
318
+ this.notifyAfterOutput(normalized);
317
319
  }
318
320
  }, 'display.writeRaw');
319
321
  }
@@ -358,125 +360,7 @@ export class Display {
358
360
  }
359
361
  return getTerminalColumns();
360
362
  }
361
- bannerState = null;
362
- bannerContext = null;
363
- /**
364
- * Stores banner information. When silent=true, only stores state without writing.
365
- * The banner can then be rendered later via renderBannerToContent().
366
- *
367
- * @param silent If true, only store state without writing to stdout (default: true)
368
- */
369
- showWelcome(profileLabel, profileName, model, provider, workingDir, version, silent = true) {
370
- // Validate required inputs
371
- if (!model?.trim() || !provider?.trim() || !workingDir?.trim()) {
372
- return;
373
- }
374
- const width = this.getBannerWidth();
375
- const banner = this.buildClaudeStyleBanner(profileLabel ?? '', profileName ?? '', model, provider, workingDir, width, version);
376
- if (!banner) {
377
- return;
378
- }
379
- const height = this.measureBannerHeight(banner);
380
- this.bannerState = {
381
- startLine: 0, // Will be set when actually rendered
382
- height,
383
- width,
384
- workingDir,
385
- version: version?.trim() || undefined,
386
- model,
387
- provider,
388
- profileLabel: profileLabel ?? '',
389
- profileName: profileName ?? '',
390
- };
391
- this.bannerContext = {
392
- workingDir,
393
- model,
394
- provider,
395
- profileLabel: profileLabel ?? '',
396
- profileName: profileName ?? '',
397
- version: version?.trim() || undefined,
398
- };
399
- // Only write to stdout if not silent
400
- if (!silent) {
401
- const startLine = this.stdoutTracker.totalLines;
402
- this.withOutput(() => {
403
- this.writeLine(banner);
404
- });
405
- this.bannerState.startLine = startLine;
406
- }
407
- }
408
- /**
409
- * Get the current version string (if set during showWelcome).
410
- */
411
- getVersion() {
412
- return this.bannerContext?.version;
413
- }
414
- /**
415
- * Get the current banner content as a string.
416
- * Used by TerminalInput to re-render the banner inside the scroll region.
417
- * Returns null if no banner has been displayed yet.
418
- */
419
- getBannerContent() {
420
- const state = this.bannerState;
421
- if (!state) {
422
- return null;
423
- }
424
- const width = this.getBannerWidth();
425
- return this.buildClaudeStyleBanner(state.profileLabel, state.profileName, state.model, state.provider, state.workingDir, width, state.version);
426
- }
427
- /**
428
- * Render banner directly to stdout (for unified UI re-rendering).
429
- * This writes the banner without updating tracking state.
430
- * Returns the number of lines written.
431
- */
432
- renderBannerToContent() {
433
- const banner = this.getBannerContent();
434
- if (!banner) {
435
- return 0;
436
- }
437
- this.withOutput(() => {
438
- this.writeLine(banner);
439
- });
440
- return this.measureBannerHeight(banner);
441
- }
442
- /**
443
- * Updates the session information banner with new model/provider by appending
444
- * a new banner entry in the scroll region (no pinned header rewriting).
445
- */
446
- updateSessionInfo(model, provider) {
447
- const state = this.bannerState;
448
- if (!state) {
449
- return;
450
- }
451
- const width = this.getBannerWidth();
452
- const banner = this.buildClaudeStyleBanner(state.profileLabel, state.profileName, model, provider, state.workingDir, width, state.version);
453
- const height = this.measureBannerHeight(banner);
454
- // If height changed or rewrite failed, do full re-render
455
- if (height !== state.height || !this.tryRewriteBanner(state, banner)) {
456
- this.renderAndStoreBanner(state, model, provider);
457
- this.bannerContext = {
458
- workingDir: state.workingDir,
459
- model: state.model,
460
- provider: state.provider,
461
- profileLabel: state.profileLabel,
462
- profileName: state.profileName,
463
- version: state.version,
464
- };
465
- return;
466
- }
467
- state.model = model;
468
- state.provider = provider;
469
- state.width = width;
470
- state.height = height;
471
- this.bannerContext = {
472
- workingDir: state.workingDir,
473
- model,
474
- provider,
475
- profileLabel: state.profileLabel,
476
- profileName: state.profileName,
477
- version: state.version,
478
- };
479
- }
363
+ // Banner is now streamed by the shell - no storage needed
480
364
  showThinking(message = 'Thinking...') {
481
365
  // If we already have a spinner, just update its text instead of creating a new one
482
366
  if (this.activeSpinner) {
@@ -756,7 +640,7 @@ export class Display {
756
640
  if (!normalized) {
757
641
  return [];
758
642
  }
759
- const width = clampWidthToAvailable(this.getColumnWidth(), DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, DISPLAY_CONSTANTS.MAX_ACTION_WIDTH);
643
+ const width = Math.max(DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, Math.min(this.getColumnWidth(), DISPLAY_CONSTANTS.MAX_ACTION_WIDTH));
760
644
  const samplePrefix = this.buildSubActionPrefixes(status, true).prefix;
761
645
  const contentWidth = Math.max(DISPLAY_CONSTANTS.MIN_CONTENT_WIDTH, width - this.visibleLength(samplePrefix));
762
646
  const blocks = formatRichContent(normalized, contentWidth);
@@ -846,8 +730,7 @@ export class Display {
846
730
  { text: `${theme.success('✓')} ${normalized}`, tone: 'success' },
847
731
  elapsed ? { text: `(${elapsed})`, tone: 'muted' } : null,
848
732
  ].filter(Boolean);
849
- const width = clampWidthToAvailable(this.getColumnWidth() - 2, 8, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH);
850
- const line = renderStatusLine(parts, width);
733
+ const line = renderStatusLine(parts, this.getColumnWidth() - 2);
851
734
  this.withOutput(() => {
852
735
  this.writeLine(line);
853
736
  });
@@ -857,6 +740,23 @@ export class Display {
857
740
  // Tools are available but not listed verbosely on startup
858
741
  // Parameter prefixed with underscore to indicate intentionally unused
859
742
  }
743
+ /**
744
+ * Show a compact launch panel of slash commands with wrapped descriptions.
745
+ */
746
+ showCommandPalette(commands, options) {
747
+ if (!commands || commands.length === 0) {
748
+ return;
749
+ }
750
+ const panel = this.buildCommandPalette(commands, options);
751
+ if (!panel.trim()) {
752
+ return;
753
+ }
754
+ this.withOutput(() => {
755
+ this.writeLine();
756
+ this.writeLine(panel);
757
+ this.writeLine();
758
+ });
759
+ }
860
760
  /**
861
761
  * Show ready message with keyboard shortcuts hint (compact)
862
762
  * Note: Commands are now shown in the banner, so this is a no-op
@@ -875,58 +775,17 @@ export class Display {
875
775
  // Claude Code style: don't show providers on startup, keep it minimal
876
776
  }
877
777
  /**
878
- * Show unified status bar - Now a no-op.
879
- * Status is shown in the inline input area's mode controls line.
778
+ * Show unified status bar - Claude Code style (minimal)
779
+ * Note: No-op - status is shown in mode controls line
880
780
  */
881
781
  showUnifiedStatusBar(_providers) {
882
- // No-op: Status is shown in the inline input area's mode controls line
782
+ // No-op - banner is streamed as content, status shown in control bar
883
783
  }
884
784
  /**
885
- * Show streaming header in a unified frame with model/provider/workspace context.
886
- * Keeps the streaming section visually connected to the launch banner.
785
+ * Show streaming header - no-op, banner is streamed as content
887
786
  */
888
- showStreamingHeader(options) {
889
- const banner = this.bannerState;
890
- const model = banner ? this.formatModelLabel(banner.model) : null;
891
- const provider = banner?.provider ?? '';
892
- const workspace = banner?.workingDir ?? '';
893
- if (!model && !provider && !workspace) {
894
- return;
895
- }
896
- const width = clampWidthToAvailable(this.getColumnWidth() - 4, DISPLAY_CONSTANTS.MIN_MESSAGE_WIDTH, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH);
897
- const spaceAbove = options?.spaceAbove ?? true;
898
- const spaceBelow = options?.spaceBelow ?? true;
899
- // Plain output keeps the header lightweight
900
- if (isPlainOutputMode()) {
901
- const label = model ? `Streaming ${model}` : 'Streaming response';
902
- this.withOutput(() => {
903
- if (spaceAbove) {
904
- this.writeLine();
905
- }
906
- this.writeLine(`--- ${label} ---`);
907
- if (spaceBelow) {
908
- this.writeLine();
909
- }
910
- });
911
- return;
912
- }
913
- const sessionFrame = renderSessionFrame({
914
- profileLabel: banner?.profileLabel ?? '',
915
- profileName: banner?.profileName ?? '',
916
- model: model ?? '',
917
- provider,
918
- workspace,
919
- width,
920
- });
921
- this.withOutput(() => {
922
- if (spaceAbove) {
923
- this.writeLine();
924
- }
925
- this.writeLine(sessionFrame);
926
- if (spaceBelow) {
927
- this.writeLine();
928
- }
929
- });
787
+ showStreamingHeader(_options) {
788
+ // No-op - banner is streamed as content by the shell
930
789
  }
931
790
  /**
932
791
  * Show model commands help
@@ -969,7 +828,7 @@ export class Display {
969
828
  if (index < 1 || total < 1 || index > total) {
970
829
  return;
971
830
  }
972
- const width = clampWidthToAvailable(this.getColumnWidth(), DISPLAY_CONSTANTS.MIN_THOUGHT_WIDTH, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH);
831
+ const width = Math.max(DISPLAY_CONSTANTS.MIN_THOUGHT_WIDTH, Math.min(this.getColumnWidth(), DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
973
832
  const heading = renderSectionHeading(`Plan ${index}/${total}`, {
974
833
  subtitle: step,
975
834
  icon: icons.arrow,
@@ -991,78 +850,14 @@ export class Display {
991
850
  }
992
851
  });
993
852
  this.stdoutTracker.reset();
994
- if (this.bannerState) {
995
- this.renderAndStoreBanner(this.bannerState, this.bannerState.model, this.bannerState.provider);
996
- }
853
+ // Banner is streamed content - no re-render on clear
997
854
  }
998
855
  newLine() {
999
856
  this.withOutput(() => {
1000
857
  this.writeLine();
1001
858
  });
1002
859
  }
1003
- getBannerWidth() {
1004
- const availableColumns = this.getColumnWidth();
1005
- const available = availableColumns - DISPLAY_CONSTANTS.BANNER_PADDING;
1006
- return clampWidthToAvailable(available, DISPLAY_CONSTANTS.MIN_BANNER_WIDTH, DISPLAY_CONSTANTS.MAX_BANNER_WIDTH);
1007
- }
1008
- measureBannerHeight(banner) {
1009
- if (!banner) {
1010
- return 0;
1011
- }
1012
- return banner.split('\n').length;
1013
- }
1014
- /**
1015
- * Attempts to rewrite the banner in place using terminal cursor manipulation.
1016
- * Returns true if successful, false if rewrite is not possible.
1017
- */
1018
- tryRewriteBanner(state, banner) {
1019
- if (!this.outputStream.isTTY) {
1020
- return false;
1021
- }
1022
- if (!banner || state.height <= 0) {
1023
- return false;
1024
- }
1025
- const linesWritten = this.stdoutTracker.totalLines;
1026
- const linesAfterBanner = linesWritten - (state.startLine + state.height);
1027
- if (linesAfterBanner < 0) {
1028
- return false;
1029
- }
1030
- const totalOffset = linesAfterBanner + state.height;
1031
- const maxRows = this.outputStream.rows;
1032
- if (typeof maxRows === 'number' && maxRows > 0 && totalOffset > maxRows) {
1033
- return false;
1034
- }
1035
- try {
1036
- this.withOutput(() => {
1037
- moveCursor(this.outputStream, 0, -totalOffset);
1038
- cursorTo(this.outputStream, 0);
1039
- this.stdoutTracker.withSuspended(() => {
1040
- this.outputStream.write(`${banner}\n`);
1041
- });
1042
- if (linesAfterBanner > 0) {
1043
- moveCursor(this.outputStream, 0, linesAfterBanner);
1044
- }
1045
- cursorTo(this.outputStream, 0);
1046
- });
1047
- return true;
1048
- }
1049
- catch {
1050
- return false;
1051
- }
1052
- }
1053
- renderAndStoreBanner(state, model, provider) {
1054
- const width = this.getBannerWidth();
1055
- const banner = this.buildClaudeStyleBanner(state.profileLabel, state.profileName, model, provider, state.workingDir, width, state.version);
1056
- const startLine = this.stdoutTracker.totalLines;
1057
- this.withOutput(() => {
1058
- this.writeLine(banner);
1059
- });
1060
- state.startLine = startLine;
1061
- state.height = this.measureBannerHeight(banner);
1062
- state.width = width;
1063
- state.model = model;
1064
- state.provider = provider;
1065
- }
860
+ // Legacy banner methods removed - banner is streamed as content by the shell
1066
861
  formatModelLabel(model) {
1067
862
  if (/gpt-5\.1-?codex/i.test(model)) {
1068
863
  return model;
@@ -1129,8 +924,7 @@ export class Display {
1129
924
  }
1130
925
  resolveMessageWidth() {
1131
926
  const columns = this.getColumnWidth();
1132
- const available = columns - DISPLAY_CONSTANTS.MESSAGE_PADDING;
1133
- return clampWidthToAvailable(available, DISPLAY_CONSTANTS.MIN_MESSAGE_WIDTH, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH);
927
+ return Math.max(DISPLAY_CONSTANTS.MIN_MESSAGE_WIDTH, Math.min(columns - DISPLAY_CONSTANTS.MESSAGE_PADDING, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
1134
928
  }
1135
929
  formatTelemetryLine(metadata) {
1136
930
  if (!metadata) {
@@ -1161,16 +955,96 @@ export class Display {
1161
955
  }
1162
956
  return `${seconds}s`;
1163
957
  }
1164
- buildClaudeStyleBanner(_profileLabel, _profileName, model, provider, workingDir, _width, version) {
1165
- return renderSessionFrame({
1166
- profileLabel: _profileLabel,
1167
- profileName: _profileName,
1168
- model: this.formatModelLabel(model),
1169
- provider,
1170
- workspace: workingDir,
1171
- version,
1172
- width: _width,
958
+ buildCommandPalette(commands, options) {
959
+ if (!commands.length) {
960
+ return '';
961
+ }
962
+ const width = Math.max(DISPLAY_CONSTANTS.MIN_MESSAGE_WIDTH, Math.min(this.getColumnWidth() - 2, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
963
+ const indent = ' ';
964
+ const grouped = this.groupPaletteCommands(commands);
965
+ const commandWidth = this.computeCommandColumnWidth(commands, width, indent.length);
966
+ const descWidth = Math.max(DISPLAY_CONSTANTS.MIN_WRAP_WIDTH, width - indent.length - commandWidth - 1);
967
+ const title = options?.title ?? 'Slash commands';
968
+ const intro = options?.intro ?? 'Describe a task or pick a command below:';
969
+ const lines = [];
970
+ lines.push(theme.gradient.primary(title));
971
+ const introLines = this.wrapLine(intro, width);
972
+ for (const line of introLines) {
973
+ lines.push(theme.ui.muted(line));
974
+ }
975
+ lines.push('');
976
+ grouped.forEach(({ category, items }, index) => {
977
+ const label = this.formatPaletteCategory(category);
978
+ if (label) {
979
+ lines.push(theme.bold(label));
980
+ }
981
+ for (const item of items) {
982
+ const wrappedDesc = this.wrapLine(item.description, descWidth);
983
+ const paddedCommand = item.command.padEnd(commandWidth);
984
+ const commandLabel = theme.primary(paddedCommand);
985
+ const firstLine = wrappedDesc[0] ?? '';
986
+ lines.push(`${indent}${commandLabel} ${this.colorizePaletteText(firstLine, item.tone)}`);
987
+ for (const extra of wrappedDesc.slice(1)) {
988
+ lines.push(`${indent}${' '.repeat(commandWidth)} ${this.colorizePaletteText(extra, item.tone)}`);
989
+ }
990
+ }
991
+ if (index < grouped.length - 1) {
992
+ lines.push('');
993
+ }
1173
994
  });
995
+ return lines.join('\n').trimEnd();
996
+ }
997
+ groupPaletteCommands(commands) {
998
+ const FALLBACK = 'other';
999
+ const groups = new Map();
1000
+ for (const item of commands) {
1001
+ const key = (item.category ?? FALLBACK).toLowerCase();
1002
+ const bucket = groups.get(key) ?? [];
1003
+ bucket.push(item);
1004
+ groups.set(key, bucket);
1005
+ }
1006
+ const order = ['configuration', 'workspace', 'diagnostics', 'other'];
1007
+ const orderedKeys = [
1008
+ ...order.filter((key) => groups.has(key)),
1009
+ ...Array.from(groups.keys()).filter((key) => !order.includes(key)),
1010
+ ];
1011
+ return orderedKeys.map((category) => ({ category, items: groups.get(category) ?? [] }));
1012
+ }
1013
+ computeCommandColumnWidth(commands, totalWidth, indentWidth) {
1014
+ const longest = commands.reduce((max, item) => Math.max(max, this.visibleLength(item.command)), 0);
1015
+ const maxAllowed = Math.max(12, Math.min(longest + 2, Math.floor(totalWidth * 0.35)));
1016
+ const budget = Math.max(10, totalWidth - indentWidth - DISPLAY_CONSTANTS.MIN_WRAP_WIDTH);
1017
+ return Math.min(maxAllowed, budget);
1018
+ }
1019
+ formatPaletteCategory(category) {
1020
+ if (!category) {
1021
+ return 'Other';
1022
+ }
1023
+ switch (category.toLowerCase()) {
1024
+ case 'configuration':
1025
+ return 'Configuration';
1026
+ case 'workspace':
1027
+ return 'Workspace';
1028
+ case 'diagnostics':
1029
+ return 'Diagnostics';
1030
+ case 'other':
1031
+ return 'Other';
1032
+ default:
1033
+ return category[0]?.toUpperCase() + category.slice(1);
1034
+ }
1035
+ }
1036
+ colorizePaletteText(text, tone) {
1037
+ switch (tone) {
1038
+ case 'warn':
1039
+ return theme.warning(text);
1040
+ case 'success':
1041
+ return theme.success(text);
1042
+ case 'info':
1043
+ return theme.info(text);
1044
+ case 'muted':
1045
+ default:
1046
+ return theme.ui.muted(text);
1047
+ }
1174
1048
  }
1175
1049
  /**
1176
1050
  * Wraps text with a prefix on the first line and optional continuation prefix.
@@ -1180,9 +1054,9 @@ export class Display {
1180
1054
  if (!text) {
1181
1055
  return prefix.trimEnd();
1182
1056
  }
1183
- const width = clampWidthToAvailable(this.getColumnWidth(), DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, DISPLAY_CONSTANTS.MAX_ACTION_WIDTH);
1057
+ const width = Math.max(DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, Math.min(this.getColumnWidth(), DISPLAY_CONSTANTS.MAX_ACTION_WIDTH));
1184
1058
  const prefixWidth = this.visibleLength(prefix);
1185
- const available = Math.max(1, Math.min(width - prefixWidth, Math.max(DISPLAY_CONSTANTS.MIN_CONTENT_WIDTH, width - prefixWidth)));
1059
+ const available = Math.max(DISPLAY_CONSTANTS.MIN_CONTENT_WIDTH, width - prefixWidth);
1186
1060
  const indent = typeof options?.continuationPrefix === 'string'
1187
1061
  ? options.continuationPrefix
1188
1062
  : ' '.repeat(Math.max(0, prefixWidth));
@@ -1234,14 +1108,14 @@ export class Display {
1234
1108
  border: theme.ui.border,
1235
1109
  label: theme.info,
1236
1110
  };
1237
- const width = clampWidthToAvailable(this.getColumnWidth() - 4, DISPLAY_CONSTANTS.MIN_THOUGHT_WIDTH, DISPLAY_CONSTANTS.MAX_THOUGHT_WIDTH);
1111
+ const width = Math.min(this.getColumnWidth() - 4, 70);
1238
1112
  const lines = [];
1239
1113
  // Simple header
1240
1114
  lines.push(`${theme.ui.muted('⏺')} ${thinkingStyle.label('Thinking')}`);
1241
1115
  // Parse and format the thinking content with simple indentation
1242
1116
  const contentLines = content.split('\n').filter(line => line.trim());
1243
1117
  for (const line of contentLines) {
1244
- const wrapped = this.wrapLine(line.trim(), Math.max(1, width - 4));
1118
+ const wrapped = this.wrapLine(line.trim(), width - 4);
1245
1119
  for (const wrappedLine of wrapped) {
1246
1120
  lines.push(` ${thinkingStyle.text(wrappedLine)}`);
1247
1121
  }