erosolar-cli 1.7.285 → 1.7.286

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/README.md +24 -148
  2. package/dist/bin/erosolar.js +1 -0
  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/toolPreconditions.d.ts.map +1 -1
  29. package/dist/core/toolPreconditions.js +0 -14
  30. package/dist/core/toolPreconditions.js.map +1 -1
  31. package/dist/core/toolRuntime.d.ts +22 -1
  32. package/dist/core/toolRuntime.d.ts.map +1 -1
  33. package/dist/core/toolRuntime.js +0 -5
  34. package/dist/core/toolRuntime.js.map +1 -1
  35. package/dist/core/toolValidation.d.ts.map +1 -1
  36. package/dist/core/toolValidation.js +14 -3
  37. package/dist/core/toolValidation.js.map +1 -1
  38. package/dist/core/validationRunner.d.ts +1 -3
  39. package/dist/core/validationRunner.d.ts.map +1 -1
  40. package/dist/core/validationRunner.js.map +1 -1
  41. package/dist/core/verification.d.ts +137 -0
  42. package/dist/core/verification.d.ts.map +1 -0
  43. package/dist/core/verification.js +323 -0
  44. package/dist/core/verification.js.map +1 -0
  45. package/dist/headless/headlessApp.d.ts.map +1 -1
  46. package/dist/headless/headlessApp.js +21 -0
  47. package/dist/headless/headlessApp.js.map +1 -1
  48. package/dist/mcp/sseClient.d.ts.map +1 -1
  49. package/dist/mcp/sseClient.js +9 -18
  50. package/dist/mcp/sseClient.js.map +1 -1
  51. package/dist/plugins/tools/build/buildPlugin.d.ts +0 -6
  52. package/dist/plugins/tools/build/buildPlugin.d.ts.map +1 -1
  53. package/dist/plugins/tools/build/buildPlugin.js +4 -10
  54. package/dist/plugins/tools/build/buildPlugin.js.map +1 -1
  55. package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
  56. package/dist/plugins/tools/nodeDefaults.js +0 -2
  57. package/dist/plugins/tools/nodeDefaults.js.map +1 -1
  58. package/dist/runtime/agentSession.d.ts +2 -2
  59. package/dist/runtime/agentSession.d.ts.map +1 -1
  60. package/dist/runtime/agentSession.js +2 -2
  61. package/dist/runtime/agentSession.js.map +1 -1
  62. package/dist/shell/interactiveShell.d.ts +22 -7
  63. package/dist/shell/interactiveShell.d.ts.map +1 -1
  64. package/dist/shell/interactiveShell.js +229 -159
  65. package/dist/shell/interactiveShell.js.map +1 -1
  66. package/dist/shell/shellApp.d.ts +2 -0
  67. package/dist/shell/shellApp.d.ts.map +1 -1
  68. package/dist/shell/shellApp.js +40 -9
  69. package/dist/shell/shellApp.js.map +1 -1
  70. package/dist/shell/systemPrompt.d.ts.map +1 -1
  71. package/dist/shell/systemPrompt.js +1 -4
  72. package/dist/shell/systemPrompt.js.map +1 -1
  73. package/dist/shell/terminalInput.d.ts +78 -186
  74. package/dist/shell/terminalInput.d.ts.map +1 -1
  75. package/dist/shell/terminalInput.js +496 -927
  76. package/dist/shell/terminalInput.js.map +1 -1
  77. package/dist/shell/terminalInputAdapter.d.ts +28 -35
  78. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  79. package/dist/shell/terminalInputAdapter.js +26 -50
  80. package/dist/shell/terminalInputAdapter.js.map +1 -1
  81. package/dist/subagents/agentConfig.d.ts +27 -0
  82. package/dist/subagents/agentConfig.d.ts.map +1 -0
  83. package/dist/subagents/agentConfig.js +89 -0
  84. package/dist/subagents/agentConfig.js.map +1 -0
  85. package/dist/subagents/agentRegistry.d.ts +33 -0
  86. package/dist/subagents/agentRegistry.d.ts.map +1 -0
  87. package/dist/subagents/agentRegistry.js +162 -0
  88. package/dist/subagents/agentRegistry.js.map +1 -0
  89. package/dist/subagents/taskRunner.d.ts +7 -1
  90. package/dist/subagents/taskRunner.d.ts.map +1 -1
  91. package/dist/subagents/taskRunner.js +180 -47
  92. package/dist/subagents/taskRunner.js.map +1 -1
  93. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  94. package/dist/ui/ShellUIAdapter.js +13 -12
  95. package/dist/ui/ShellUIAdapter.js.map +1 -1
  96. package/dist/ui/display.d.ts +23 -44
  97. package/dist/ui/display.d.ts.map +1 -1
  98. package/dist/ui/display.js +139 -286
  99. package/dist/ui/display.js.map +1 -1
  100. package/dist/ui/theme.d.ts.map +1 -1
  101. package/dist/ui/theme.js +6 -8
  102. package/dist/ui/theme.js.map +1 -1
  103. package/dist/ui/toolDisplay.d.ts +0 -158
  104. package/dist/ui/toolDisplay.d.ts.map +1 -1
  105. package/dist/ui/toolDisplay.js +0 -348
  106. package/dist/ui/toolDisplay.js.map +1 -1
  107. package/dist/ui/unified/layout.d.ts +1 -0
  108. package/dist/ui/unified/layout.d.ts.map +1 -1
  109. package/dist/ui/unified/layout.js +15 -25
  110. package/dist/ui/unified/layout.js.map +1 -1
  111. package/dist/utils/frontmatter.d.ts +10 -0
  112. package/dist/utils/frontmatter.d.ts.map +1 -0
  113. package/dist/utils/frontmatter.js +78 -0
  114. package/dist/utils/frontmatter.js.map +1 -0
  115. package/package.json +1 -1
  116. package/dist/alpha-zero/agentWrapper.d.ts +0 -84
  117. package/dist/alpha-zero/agentWrapper.d.ts.map +0 -1
  118. package/dist/alpha-zero/agentWrapper.js +0 -171
  119. package/dist/alpha-zero/agentWrapper.js.map +0 -1
  120. package/dist/alpha-zero/codeEvaluator.d.ts +0 -25
  121. package/dist/alpha-zero/codeEvaluator.d.ts.map +0 -1
  122. package/dist/alpha-zero/codeEvaluator.js +0 -273
  123. package/dist/alpha-zero/codeEvaluator.js.map +0 -1
  124. package/dist/alpha-zero/competitiveRunner.d.ts +0 -66
  125. package/dist/alpha-zero/competitiveRunner.d.ts.map +0 -1
  126. package/dist/alpha-zero/competitiveRunner.js +0 -224
  127. package/dist/alpha-zero/competitiveRunner.js.map +0 -1
  128. package/dist/alpha-zero/index.d.ts +0 -67
  129. package/dist/alpha-zero/index.d.ts.map +0 -1
  130. package/dist/alpha-zero/index.js +0 -99
  131. package/dist/alpha-zero/index.js.map +0 -1
  132. package/dist/alpha-zero/introspection.d.ts +0 -128
  133. package/dist/alpha-zero/introspection.d.ts.map +0 -1
  134. package/dist/alpha-zero/introspection.js +0 -300
  135. package/dist/alpha-zero/introspection.js.map +0 -1
  136. package/dist/alpha-zero/metricsTracker.d.ts +0 -71
  137. package/dist/alpha-zero/metricsTracker.d.ts.map +0 -1
  138. package/dist/alpha-zero/metricsTracker.js.map +0 -1
  139. package/dist/alpha-zero/security/core.d.ts +0 -125
  140. package/dist/alpha-zero/security/core.d.ts.map +0 -1
  141. package/dist/alpha-zero/security/core.js +0 -271
  142. package/dist/alpha-zero/security/core.js.map +0 -1
  143. package/dist/alpha-zero/security/google.d.ts +0 -125
  144. package/dist/alpha-zero/security/google.d.ts.map +0 -1
  145. package/dist/alpha-zero/security/google.js +0 -311
  146. package/dist/alpha-zero/security/google.js.map +0 -1
  147. package/dist/alpha-zero/security/googleLoader.d.ts +0 -17
  148. package/dist/alpha-zero/security/googleLoader.d.ts.map +0 -1
  149. package/dist/alpha-zero/security/googleLoader.js +0 -41
  150. package/dist/alpha-zero/security/googleLoader.js.map +0 -1
  151. package/dist/alpha-zero/security/index.d.ts +0 -29
  152. package/dist/alpha-zero/security/index.d.ts.map +0 -1
  153. package/dist/alpha-zero/security/index.js +0 -32
  154. package/dist/alpha-zero/security/index.js.map +0 -1
  155. package/dist/alpha-zero/security/simulation.d.ts +0 -124
  156. package/dist/alpha-zero/security/simulation.d.ts.map +0 -1
  157. package/dist/alpha-zero/security/simulation.js +0 -277
  158. package/dist/alpha-zero/security/simulation.js.map +0 -1
  159. package/dist/alpha-zero/selfModification.d.ts +0 -109
  160. package/dist/alpha-zero/selfModification.d.ts.map +0 -1
  161. package/dist/alpha-zero/selfModification.js +0 -233
  162. package/dist/alpha-zero/selfModification.js.map +0 -1
  163. package/dist/alpha-zero/types.d.ts +0 -170
  164. package/dist/alpha-zero/types.d.ts.map +0 -1
  165. package/dist/alpha-zero/types.js +0 -31
  166. package/dist/alpha-zero/types.js.map +0 -1
  167. package/dist/capabilities/securityTestingCapability.d.ts +0 -13
  168. package/dist/capabilities/securityTestingCapability.d.ts.map +0 -1
  169. package/dist/capabilities/securityTestingCapability.js +0 -25
  170. package/dist/capabilities/securityTestingCapability.js.map +0 -1
  171. package/dist/core/aiFlowOptimizer.d.ts +0 -26
  172. package/dist/core/aiFlowOptimizer.d.ts.map +0 -1
  173. package/dist/core/aiFlowOptimizer.js +0 -31
  174. package/dist/core/aiFlowOptimizer.js.map +0 -1
  175. package/dist/core/aiOptimizationEngine.d.ts +0 -158
  176. package/dist/core/aiOptimizationEngine.d.ts.map +0 -1
  177. package/dist/core/aiOptimizationEngine.js +0 -428
  178. package/dist/core/aiOptimizationEngine.js.map +0 -1
  179. package/dist/core/aiOptimizationIntegration.d.ts +0 -93
  180. package/dist/core/aiOptimizationIntegration.d.ts.map +0 -1
  181. package/dist/core/aiOptimizationIntegration.js +0 -250
  182. package/dist/core/aiOptimizationIntegration.js.map +0 -1
  183. package/dist/core/enhancedErrorRecovery.d.ts +0 -100
  184. package/dist/core/enhancedErrorRecovery.d.ts.map +0 -1
  185. package/dist/core/enhancedErrorRecovery.js +0 -345
  186. package/dist/core/enhancedErrorRecovery.js.map +0 -1
  187. package/dist/core/hooksSystem.d.ts +0 -65
  188. package/dist/core/hooksSystem.d.ts.map +0 -1
  189. package/dist/core/hooksSystem.js +0 -273
  190. package/dist/core/hooksSystem.js.map +0 -1
  191. package/dist/core/memorySystem.d.ts +0 -48
  192. package/dist/core/memorySystem.d.ts.map +0 -1
  193. package/dist/core/memorySystem.js +0 -271
  194. package/dist/core/memorySystem.js.map +0 -1
  195. package/dist/core/unified/errors.d.ts +0 -189
  196. package/dist/core/unified/errors.d.ts.map +0 -1
  197. package/dist/core/unified/errors.js +0 -497
  198. package/dist/core/unified/errors.js.map +0 -1
  199. package/dist/core/unified/index.d.ts +0 -19
  200. package/dist/core/unified/index.d.ts.map +0 -1
  201. package/dist/core/unified/index.js +0 -68
  202. package/dist/core/unified/index.js.map +0 -1
  203. package/dist/core/unified/schema.d.ts +0 -101
  204. package/dist/core/unified/schema.d.ts.map +0 -1
  205. package/dist/core/unified/schema.js +0 -350
  206. package/dist/core/unified/schema.js.map +0 -1
  207. package/dist/core/unified/toolRuntime.d.ts +0 -179
  208. package/dist/core/unified/toolRuntime.d.ts.map +0 -1
  209. package/dist/core/unified/toolRuntime.js +0 -517
  210. package/dist/core/unified/toolRuntime.js.map +0 -1
  211. package/dist/core/unified/tools.d.ts +0 -127
  212. package/dist/core/unified/tools.d.ts.map +0 -1
  213. package/dist/core/unified/tools.js +0 -1333
  214. package/dist/core/unified/tools.js.map +0 -1
  215. package/dist/core/unified/types.d.ts +0 -352
  216. package/dist/core/unified/types.d.ts.map +0 -1
  217. package/dist/core/unified/types.js +0 -12
  218. package/dist/core/unified/types.js.map +0 -1
  219. package/dist/core/unified/version.d.ts +0 -209
  220. package/dist/core/unified/version.d.ts.map +0 -1
  221. package/dist/core/unified/version.js +0 -454
  222. package/dist/core/unified/version.js.map +0 -1
  223. package/dist/plugins/tools/security/securityPlugin.d.ts +0 -3
  224. package/dist/plugins/tools/security/securityPlugin.d.ts.map +0 -1
  225. package/dist/plugins/tools/security/securityPlugin.js +0 -12
  226. package/dist/plugins/tools/security/securityPlugin.js.map +0 -1
  227. package/dist/security/active-stack-security.d.ts +0 -112
  228. package/dist/security/active-stack-security.d.ts.map +0 -1
  229. package/dist/security/active-stack-security.js +0 -296
  230. package/dist/security/active-stack-security.js.map +0 -1
  231. package/dist/security/advanced-persistence-research.d.ts +0 -92
  232. package/dist/security/advanced-persistence-research.d.ts.map +0 -1
  233. package/dist/security/advanced-persistence-research.js +0 -195
  234. package/dist/security/advanced-persistence-research.js.map +0 -1
  235. package/dist/security/advanced-targeting.d.ts +0 -119
  236. package/dist/security/advanced-targeting.d.ts.map +0 -1
  237. package/dist/security/advanced-targeting.js +0 -233
  238. package/dist/security/advanced-targeting.js.map +0 -1
  239. package/dist/security/assessment/vulnerabilityAssessment.d.ts +0 -104
  240. package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +0 -1
  241. package/dist/security/assessment/vulnerabilityAssessment.js +0 -315
  242. package/dist/security/assessment/vulnerabilityAssessment.js.map +0 -1
  243. package/dist/security/authorization/securityAuthorization.d.ts +0 -88
  244. package/dist/security/authorization/securityAuthorization.d.ts.map +0 -1
  245. package/dist/security/authorization/securityAuthorization.js +0 -172
  246. package/dist/security/authorization/securityAuthorization.js.map +0 -1
  247. package/dist/security/comprehensive-targeting.d.ts +0 -85
  248. package/dist/security/comprehensive-targeting.d.ts.map +0 -1
  249. package/dist/security/comprehensive-targeting.js +0 -438
  250. package/dist/security/comprehensive-targeting.js.map +0 -1
  251. package/dist/security/global-security-integration.d.ts +0 -91
  252. package/dist/security/global-security-integration.d.ts.map +0 -1
  253. package/dist/security/global-security-integration.js +0 -218
  254. package/dist/security/global-security-integration.js.map +0 -1
  255. package/dist/security/index.d.ts +0 -38
  256. package/dist/security/index.d.ts.map +0 -1
  257. package/dist/security/index.js +0 -47
  258. package/dist/security/index.js.map +0 -1
  259. package/dist/security/persistence-analyzer.d.ts +0 -56
  260. package/dist/security/persistence-analyzer.d.ts.map +0 -1
  261. package/dist/security/persistence-analyzer.js +0 -187
  262. package/dist/security/persistence-analyzer.js.map +0 -1
  263. package/dist/security/persistence-cli.d.ts +0 -36
  264. package/dist/security/persistence-cli.d.ts.map +0 -1
  265. package/dist/security/persistence-cli.js +0 -160
  266. package/dist/security/persistence-cli.js.map +0 -1
  267. package/dist/security/persistence-research.d.ts +0 -92
  268. package/dist/security/persistence-research.d.ts.map +0 -1
  269. package/dist/security/persistence-research.js +0 -364
  270. package/dist/security/persistence-research.js.map +0 -1
  271. package/dist/security/research/persistenceResearch.d.ts +0 -97
  272. package/dist/security/research/persistenceResearch.d.ts.map +0 -1
  273. package/dist/security/research/persistenceResearch.js +0 -282
  274. package/dist/security/research/persistenceResearch.js.map +0 -1
  275. package/dist/security/security-integration.d.ts +0 -74
  276. package/dist/security/security-integration.d.ts.map +0 -1
  277. package/dist/security/security-integration.js +0 -137
  278. package/dist/security/security-integration.js.map +0 -1
  279. package/dist/security/security-testing-framework.d.ts +0 -112
  280. package/dist/security/security-testing-framework.d.ts.map +0 -1
  281. package/dist/security/security-testing-framework.js +0 -364
  282. package/dist/security/security-testing-framework.js.map +0 -1
  283. package/dist/security/simulation/attackSimulation.d.ts +0 -93
  284. package/dist/security/simulation/attackSimulation.d.ts.map +0 -1
  285. package/dist/security/simulation/attackSimulation.js +0 -341
  286. package/dist/security/simulation/attackSimulation.js.map +0 -1
  287. package/dist/security/strategic-operations.d.ts +0 -100
  288. package/dist/security/strategic-operations.d.ts.map +0 -1
  289. package/dist/security/strategic-operations.js +0 -276
  290. package/dist/security/strategic-operations.js.map +0 -1
  291. package/dist/security/tool-security-wrapper.d.ts +0 -58
  292. package/dist/security/tool-security-wrapper.d.ts.map +0 -1
  293. package/dist/security/tool-security-wrapper.js +0 -156
  294. package/dist/security/tool-security-wrapper.js.map +0 -1
  295. package/dist/shell/claudeCodeStreamHandler.d.ts +0 -145
  296. package/dist/shell/claudeCodeStreamHandler.d.ts.map +0 -1
  297. package/dist/shell/claudeCodeStreamHandler.js +0 -322
  298. package/dist/shell/claudeCodeStreamHandler.js.map +0 -1
  299. package/dist/shell/inputQueueManager.d.ts +0 -144
  300. package/dist/shell/inputQueueManager.d.ts.map +0 -1
  301. package/dist/shell/inputQueueManager.js +0 -290
  302. package/dist/shell/inputQueueManager.js.map +0 -1
  303. package/dist/shell/metricsTracker.d.ts +0 -60
  304. package/dist/shell/metricsTracker.d.ts.map +0 -1
  305. package/dist/shell/metricsTracker.js +0 -119
  306. package/dist/shell/metricsTracker.js.map +0 -1
  307. package/dist/shell/streamingOutputManager.d.ts +0 -115
  308. package/dist/shell/streamingOutputManager.d.ts.map +0 -1
  309. package/dist/shell/streamingOutputManager.js +0 -225
  310. package/dist/shell/streamingOutputManager.js.map +0 -1
  311. package/dist/tools/securityTools.d.ts +0 -22
  312. package/dist/tools/securityTools.d.ts.map +0 -1
  313. package/dist/tools/securityTools.js +0 -448
  314. package/dist/tools/securityTools.js.map +0 -1
  315. package/dist/ui/persistentPrompt.d.ts +0 -50
  316. package/dist/ui/persistentPrompt.d.ts.map +0 -1
  317. package/dist/ui/persistentPrompt.js +0 -92
  318. package/dist/ui/persistentPrompt.js.map +0 -1
  319. package/dist/ui/terminalUISchema.d.ts +0 -195
  320. package/dist/ui/terminalUISchema.d.ts.map +0 -1
  321. package/dist/ui/terminalUISchema.js +0 -113
  322. package/dist/ui/terminalUISchema.js.map +0 -1
  323. 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 { renderDivider, 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.
@@ -254,10 +254,10 @@ export class Display {
254
254
  interceptor.beforeWrite?.();
255
255
  }
256
256
  }
257
- notifyAfterOutput() {
257
+ notifyAfterOutput(content) {
258
258
  const interceptors = Array.from(this.outputInterceptors);
259
259
  for (let index = interceptors.length - 1; index >= 0; index -= 1) {
260
- interceptors[index]?.afterWrite?.();
260
+ interceptors[index]?.afterWrite?.(content);
261
261
  }
262
262
  }
263
263
  write(value, target = this.outputStream) {
@@ -286,29 +286,36 @@ export class Display {
286
286
  if (typeof content !== 'string' || !content) {
287
287
  return;
288
288
  }
289
- // During streaming mode, write directly without locks for smooth output
290
- // 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.
291
296
  if (isStreamingMode()) {
292
- this.notifyBeforeOutput();
293
- try {
294
- this.outputStream.write(content);
295
- }
296
- catch {
297
- // Ignore write failures to keep UI resilient
298
- }
299
- finally {
300
- this.notifyAfterOutput();
301
- }
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');
302
309
  return;
303
310
  }
304
311
  // Outside streaming mode, use locks to coordinate with other UI
305
312
  writeLock.withLock(() => {
306
313
  this.notifyBeforeOutput();
307
314
  try {
308
- this.write(content);
315
+ this.write(normalized);
309
316
  }
310
317
  finally {
311
- this.notifyAfterOutput();
318
+ this.notifyAfterOutput(normalized);
312
319
  }
313
320
  }, 'display.writeRaw');
314
321
  }
@@ -353,125 +360,7 @@ export class Display {
353
360
  }
354
361
  return getTerminalColumns();
355
362
  }
356
- bannerState = null;
357
- bannerContext = null;
358
- /**
359
- * Stores banner information. When silent=true, only stores state without writing.
360
- * The banner can then be rendered later via renderBannerToContent().
361
- *
362
- * @param silent If true, only store state without writing to stdout (default: true)
363
- */
364
- showWelcome(profileLabel, profileName, model, provider, workingDir, version, silent = true) {
365
- // Validate required inputs
366
- if (!model?.trim() || !provider?.trim() || !workingDir?.trim()) {
367
- return;
368
- }
369
- const width = this.getBannerWidth();
370
- const banner = this.buildClaudeStyleBanner(profileLabel ?? '', profileName ?? '', model, provider, workingDir, width, version);
371
- if (!banner) {
372
- return;
373
- }
374
- const height = this.measureBannerHeight(banner);
375
- this.bannerState = {
376
- startLine: 0, // Will be set when actually rendered
377
- height,
378
- width,
379
- workingDir,
380
- version: version?.trim() || undefined,
381
- model,
382
- provider,
383
- profileLabel: profileLabel ?? '',
384
- profileName: profileName ?? '',
385
- };
386
- this.bannerContext = {
387
- workingDir,
388
- model,
389
- provider,
390
- profileLabel: profileLabel ?? '',
391
- profileName: profileName ?? '',
392
- version: version?.trim() || undefined,
393
- };
394
- // Only write to stdout if not silent
395
- if (!silent) {
396
- const startLine = this.stdoutTracker.totalLines;
397
- this.withOutput(() => {
398
- this.writeLine(banner);
399
- });
400
- this.bannerState.startLine = startLine;
401
- }
402
- }
403
- /**
404
- * Get the current version string (if set during showWelcome).
405
- */
406
- getVersion() {
407
- return this.bannerContext?.version;
408
- }
409
- /**
410
- * Get the current banner content as a string.
411
- * Used by TerminalInput to re-render the banner inside the scroll region.
412
- * Returns null if no banner has been displayed yet.
413
- */
414
- getBannerContent() {
415
- const state = this.bannerState;
416
- if (!state) {
417
- return null;
418
- }
419
- const width = this.getBannerWidth();
420
- return this.buildClaudeStyleBanner(state.profileLabel, state.profileName, state.model, state.provider, state.workingDir, width, state.version);
421
- }
422
- /**
423
- * Render banner directly to stdout (for unified UI re-rendering).
424
- * This writes the banner without updating tracking state.
425
- * Returns the number of lines written.
426
- */
427
- renderBannerToContent() {
428
- const banner = this.getBannerContent();
429
- if (!banner) {
430
- return 0;
431
- }
432
- this.withOutput(() => {
433
- this.writeLine(banner);
434
- });
435
- return this.measureBannerHeight(banner);
436
- }
437
- /**
438
- * Updates the session information banner with new model/provider by appending
439
- * a new banner entry in the scroll region (no pinned header rewriting).
440
- */
441
- updateSessionInfo(model, provider) {
442
- const state = this.bannerState;
443
- if (!state) {
444
- return;
445
- }
446
- const width = this.getBannerWidth();
447
- const banner = this.buildClaudeStyleBanner(state.profileLabel, state.profileName, model, provider, state.workingDir, width, state.version);
448
- const height = this.measureBannerHeight(banner);
449
- // If height changed or rewrite failed, do full re-render
450
- if (height !== state.height || !this.tryRewriteBanner(state, banner)) {
451
- this.renderAndStoreBanner(state, model, provider);
452
- this.bannerContext = {
453
- workingDir: state.workingDir,
454
- model: state.model,
455
- provider: state.provider,
456
- profileLabel: state.profileLabel,
457
- profileName: state.profileName,
458
- version: state.version,
459
- };
460
- return;
461
- }
462
- state.model = model;
463
- state.provider = provider;
464
- state.width = width;
465
- state.height = height;
466
- this.bannerContext = {
467
- workingDir: state.workingDir,
468
- model,
469
- provider,
470
- profileLabel: state.profileLabel,
471
- profileName: state.profileName,
472
- version: state.version,
473
- };
474
- }
363
+ // Banner is now streamed by the shell - no storage needed
475
364
  showThinking(message = 'Thinking...') {
476
365
  // If we already have a spinner, just update its text instead of creating a new one
477
366
  if (this.activeSpinner) {
@@ -851,6 +740,23 @@ export class Display {
851
740
  // Tools are available but not listed verbosely on startup
852
741
  // Parameter prefixed with underscore to indicate intentionally unused
853
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
+ }
854
760
  /**
855
761
  * Show ready message with keyboard shortcuts hint (compact)
856
762
  * Note: Commands are now shown in the banner, so this is a no-op
@@ -870,85 +776,16 @@ export class Display {
870
776
  }
871
777
  /**
872
778
  * Show unified status bar - Claude Code style (minimal)
873
- * Note: Now a no-op - status is shown in mode controls line
779
+ * Note: No-op - status is shown in mode controls line
874
780
  */
875
781
  showUnifiedStatusBar(_providers) {
876
- const providers = _providers ?? [];
877
- const ctx = this.bannerContext;
878
- const width = Math.max(DISPLAY_CONSTANTS.MIN_ACTION_WIDTH, Math.min(this.getColumnWidth() - 2, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH));
879
- const parts = [];
880
- if (ctx?.model) {
881
- parts.push({ text: this.formatModelLabel(ctx.model), tone: 'info' });
882
- }
883
- if (ctx?.provider) {
884
- const providerStatus = providers.find((p) => p.provider === ctx.provider);
885
- let tone = 'muted';
886
- let suffix = '';
887
- if (providerStatus) {
888
- tone = providerStatus.available ? 'success' : 'warn';
889
- if (!providerStatus.available && providerStatus.latestModel) {
890
- suffix = ` (${providerStatus.latestModel})`;
891
- }
892
- }
893
- parts.push({ text: `@ ${ctx.provider}${suffix}`, tone });
894
- }
895
- if (ctx?.workingDir) {
896
- parts.push({ text: this.compactPath(ctx.workingDir, Math.max(16, width - 32)), tone: 'muted' });
897
- }
898
- parts.push({ text: 'ready', tone: 'success' });
899
- const line = renderStatusLine(parts, width);
900
- this.withOutput(() => {
901
- this.writeLine(renderDivider(width, 'status'));
902
- this.writeLine(line);
903
- this.writeLine();
904
- });
782
+ // No-op - banner is streamed as content, status shown in control bar
905
783
  }
906
784
  /**
907
- * Show streaming header in a unified frame with model/provider/workspace context.
908
- * Keeps the streaming section visually connected to the launch banner.
785
+ * Show streaming header - no-op, banner is streamed as content
909
786
  */
910
- showStreamingHeader(options) {
911
- const banner = this.bannerState;
912
- const model = banner ? this.formatModelLabel(banner.model) : null;
913
- const provider = banner?.provider ?? '';
914
- const workspace = banner?.workingDir ?? '';
915
- if (!model && !provider && !workspace) {
916
- return;
917
- }
918
- const width = Math.min(this.getColumnWidth() - 4, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH);
919
- const spaceAbove = options?.spaceAbove ?? true;
920
- const spaceBelow = options?.spaceBelow ?? true;
921
- // Plain output keeps the header lightweight
922
- if (isPlainOutputMode()) {
923
- const label = model ? `Streaming ${model}` : 'Streaming response';
924
- this.withOutput(() => {
925
- if (spaceAbove) {
926
- this.writeLine();
927
- }
928
- this.writeLine(`--- ${label} ---`);
929
- if (spaceBelow) {
930
- this.writeLine();
931
- }
932
- });
933
- return;
934
- }
935
- const sessionFrame = renderSessionFrame({
936
- profileLabel: banner?.profileLabel ?? '',
937
- profileName: banner?.profileName ?? '',
938
- model: model ?? '',
939
- provider,
940
- workspace,
941
- width,
942
- });
943
- this.withOutput(() => {
944
- if (spaceAbove) {
945
- this.writeLine();
946
- }
947
- this.writeLine(sessionFrame);
948
- if (spaceBelow) {
949
- this.writeLine();
950
- }
951
- });
787
+ showStreamingHeader(_options) {
788
+ // No-op - banner is streamed as content by the shell
952
789
  }
953
790
  /**
954
791
  * Show model commands help
@@ -1013,78 +850,14 @@ export class Display {
1013
850
  }
1014
851
  });
1015
852
  this.stdoutTracker.reset();
1016
- if (this.bannerState) {
1017
- this.renderAndStoreBanner(this.bannerState, this.bannerState.model, this.bannerState.provider);
1018
- }
853
+ // Banner is streamed content - no re-render on clear
1019
854
  }
1020
855
  newLine() {
1021
856
  this.withOutput(() => {
1022
857
  this.writeLine();
1023
858
  });
1024
859
  }
1025
- getBannerWidth() {
1026
- const availableColumns = this.getColumnWidth();
1027
- const effectiveWidth = Math.max(DISPLAY_CONSTANTS.MIN_BANNER_WIDTH, availableColumns - DISPLAY_CONSTANTS.BANNER_PADDING);
1028
- return Math.min(Math.max(effectiveWidth, DISPLAY_CONSTANTS.MIN_BANNER_WIDTH), DISPLAY_CONSTANTS.MAX_BANNER_WIDTH);
1029
- }
1030
- measureBannerHeight(banner) {
1031
- if (!banner) {
1032
- return 0;
1033
- }
1034
- return banner.split('\n').length;
1035
- }
1036
- /**
1037
- * Attempts to rewrite the banner in place using terminal cursor manipulation.
1038
- * Returns true if successful, false if rewrite is not possible.
1039
- */
1040
- tryRewriteBanner(state, banner) {
1041
- if (!this.outputStream.isTTY) {
1042
- return false;
1043
- }
1044
- if (!banner || state.height <= 0) {
1045
- return false;
1046
- }
1047
- const linesWritten = this.stdoutTracker.totalLines;
1048
- const linesAfterBanner = linesWritten - (state.startLine + state.height);
1049
- if (linesAfterBanner < 0) {
1050
- return false;
1051
- }
1052
- const totalOffset = linesAfterBanner + state.height;
1053
- const maxRows = this.outputStream.rows;
1054
- if (typeof maxRows === 'number' && maxRows > 0 && totalOffset > maxRows) {
1055
- return false;
1056
- }
1057
- try {
1058
- this.withOutput(() => {
1059
- moveCursor(this.outputStream, 0, -totalOffset);
1060
- cursorTo(this.outputStream, 0);
1061
- this.stdoutTracker.withSuspended(() => {
1062
- this.outputStream.write(`${banner}\n`);
1063
- });
1064
- if (linesAfterBanner > 0) {
1065
- moveCursor(this.outputStream, 0, linesAfterBanner);
1066
- }
1067
- cursorTo(this.outputStream, 0);
1068
- });
1069
- return true;
1070
- }
1071
- catch {
1072
- return false;
1073
- }
1074
- }
1075
- renderAndStoreBanner(state, model, provider) {
1076
- const width = this.getBannerWidth();
1077
- const banner = this.buildClaudeStyleBanner(state.profileLabel, state.profileName, model, provider, state.workingDir, width, state.version);
1078
- const startLine = this.stdoutTracker.totalLines;
1079
- this.withOutput(() => {
1080
- this.writeLine(banner);
1081
- });
1082
- state.startLine = startLine;
1083
- state.height = this.measureBannerHeight(banner);
1084
- state.width = width;
1085
- state.model = model;
1086
- state.provider = provider;
1087
- }
860
+ // Legacy banner methods removed - banner is streamed as content by the shell
1088
861
  formatModelLabel(model) {
1089
862
  if (/gpt-5\.1-?codex/i.test(model)) {
1090
863
  return model;
@@ -1182,16 +955,96 @@ export class Display {
1182
955
  }
1183
956
  return `${seconds}s`;
1184
957
  }
1185
- buildClaudeStyleBanner(_profileLabel, _profileName, model, provider, workingDir, _width, version) {
1186
- return renderSessionFrame({
1187
- profileLabel: _profileLabel,
1188
- profileName: _profileName,
1189
- model: this.formatModelLabel(model),
1190
- provider,
1191
- workspace: workingDir,
1192
- version,
1193
- 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
+ }
1194
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
+ }
1195
1048
  }
1196
1049
  /**
1197
1050
  * Wraps text with a prefix on the first line and optional continuation prefix.