onbuzz 4.9.13 → 4.10.0

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 (451) hide show
  1. package/node_modules/glob/README.md +31 -5
  2. package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
  3. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
  4. package/node_modules/glob/dist/commonjs/glob.js +2 -1
  5. package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
  6. package/node_modules/glob/dist/commonjs/index.min.js +3 -3
  7. package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
  8. package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
  9. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
  10. package/node_modules/glob/dist/commonjs/pattern.js +4 -0
  11. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
  12. package/node_modules/glob/dist/esm/glob.d.ts +8 -0
  13. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
  14. package/node_modules/glob/dist/esm/glob.js +2 -1
  15. package/node_modules/glob/dist/esm/glob.js.map +1 -1
  16. package/node_modules/glob/dist/esm/index.min.js +3 -3
  17. package/node_modules/glob/dist/esm/index.min.js.map +4 -4
  18. package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
  19. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
  20. package/node_modules/glob/dist/esm/pattern.js +4 -0
  21. package/node_modules/glob/dist/esm/pattern.js.map +1 -1
  22. package/node_modules/{@isaacs → glob/node_modules}/balanced-match/README.md +7 -10
  23. package/node_modules/{@isaacs → glob/node_modules}/balanced-match/package.json +7 -18
  24. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/README.md +3 -6
  25. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.js +6 -4
  26. package/node_modules/glob/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -0
  27. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.js +6 -4
  28. package/node_modules/glob/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
  29. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/package.json +11 -7
  30. package/node_modules/glob/node_modules/minimatch/README.md +76 -1
  31. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +1 -1
  32. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -1
  33. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -1
  34. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +4 -2
  35. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -1
  36. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +309 -55
  37. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -1
  38. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -1
  39. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +2 -4
  40. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -1
  41. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +1 -1
  42. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -1
  43. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +4 -4
  44. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -1
  45. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +81 -1
  46. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
  47. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +232 -134
  48. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
  49. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +1 -1
  50. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -1
  51. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +8 -8
  52. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -1
  53. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +1 -1
  54. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -1
  55. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
  56. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +4 -2
  57. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -1
  58. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +309 -55
  59. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -1
  60. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -1
  61. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +2 -4
  62. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
  63. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +1 -1
  64. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -1
  65. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +4 -4
  66. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -1
  67. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +81 -1
  68. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
  69. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +232 -134
  70. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -1
  71. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +1 -1
  72. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -1
  73. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +8 -8
  74. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
  75. package/node_modules/glob/node_modules/minimatch/package.json +17 -11
  76. package/node_modules/glob/package.json +10 -13
  77. package/node_modules/minipass/LICENSE.md +55 -0
  78. package/node_modules/minipass/dist/commonjs/index.d.ts +12 -16
  79. package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -1
  80. package/node_modules/minipass/dist/commonjs/index.js +13 -3
  81. package/node_modules/minipass/dist/commonjs/index.js.map +1 -1
  82. package/node_modules/minipass/dist/esm/index.d.ts +12 -16
  83. package/node_modules/minipass/dist/esm/index.d.ts.map +1 -1
  84. package/node_modules/minipass/dist/esm/index.js +3 -1
  85. package/node_modules/minipass/dist/esm/index.js.map +1 -1
  86. package/node_modules/minipass/package.json +9 -14
  87. package/node_modules/path-scurry/node_modules/lru-cache/README.md +96 -10
  88. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.d.ts.map +1 -0
  89. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.js.map +1 -0
  90. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.d.ts +5 -0
  91. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
  92. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +1400 -0
  93. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -0
  94. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
  95. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -0
  96. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
  97. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +7 -0
  98. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts +12 -0
  99. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts.map +1 -0
  100. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
  101. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js.map +1 -0
  102. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.cjs.map +1 -0
  103. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
  104. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
  105. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
  106. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +109 -32
  107. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
  108. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +334 -197
  109. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
  110. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
  111. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +4 -4
  112. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.d.ts.map +1 -0
  113. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.js.map +1 -0
  114. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.d.ts +5 -0
  115. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
  116. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts +1400 -0
  117. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -0
  118. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
  119. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -0
  120. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
  121. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +7 -0
  122. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts +12 -0
  123. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts.map +1 -0
  124. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
  125. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js.map +1 -0
  126. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts +12 -0
  127. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts.map +1 -0
  128. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
  129. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js.map +1 -0
  130. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.d.ts.map +1 -0
  131. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.js.map +1 -0
  132. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
  133. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
  134. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts +1400 -0
  135. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -0
  136. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
  137. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -0
  138. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
  139. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js.map +7 -0
  140. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts +12 -0
  141. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts.map +1 -0
  142. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
  143. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js.map +1 -0
  144. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
  145. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.mjs.map +1 -0
  146. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
  147. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
  148. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +109 -32
  149. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
  150. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +333 -196
  151. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -1
  152. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +1 -1
  153. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +4 -4
  154. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.d.ts.map +1 -0
  155. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.js.map +1 -0
  156. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
  157. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
  158. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts +1400 -0
  159. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -0
  160. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
  161. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js.map +1 -0
  162. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
  163. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js.map +7 -0
  164. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts +12 -0
  165. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts.map +1 -0
  166. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
  167. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js.map +1 -0
  168. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts +12 -0
  169. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts.map +1 -0
  170. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
  171. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js.map +1 -0
  172. package/node_modules/path-scurry/node_modules/lru-cache/package.json +71 -18
  173. package/node_modules/path-scurry/package.json +8 -24
  174. package/package.json +1 -1
  175. package/scripts/debug-balance-probe.mjs +35 -35
  176. package/scripts/push-image.sh +43 -43
  177. package/scripts/setup-acr.sh +65 -65
  178. package/scripts/verify-optional-deps.js +96 -1
  179. package/src/__tests__/composioCliFlags.test.js +239 -239
  180. package/src/analyzers/CSSAnalyzer.js +298 -297
  181. package/src/analyzers/ConfigValidator.js +691 -690
  182. package/src/analyzers/ESLintAnalyzer.js +320 -320
  183. package/src/analyzers/JavaScriptAnalyzer.js +260 -261
  184. package/src/analyzers/PrettierFormatter.js +246 -247
  185. package/src/analyzers/PythonAnalyzer.js +283 -283
  186. package/src/analyzers/SecurityAnalyzer.js +729 -729
  187. package/src/analyzers/SparrowAnalyzer.js +341 -341
  188. package/src/analyzers/TypeScriptAnalyzer.js +247 -247
  189. package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -41
  190. package/src/analyzers/__tests__/ConfigValidator.test.js +362 -362
  191. package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -40
  192. package/src/analyzers/__tests__/PythonAnalyzer.test.js +205 -208
  193. package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -303
  194. package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -187
  195. package/src/analyzers/codeCloneDetector/analyzer.js +344 -344
  196. package/src/analyzers/codeCloneDetector/detector.js +250 -250
  197. package/src/analyzers/codeCloneDetector/index.js +194 -192
  198. package/src/analyzers/codeCloneDetector/parser.js +199 -199
  199. package/src/core/__tests__/agentPool.test.js +866 -866
  200. package/src/core/__tests__/agentPoolAutoResume.test.js +209 -209
  201. package/src/core/__tests__/agentPoolWakeOnMessage.test.js +315 -315
  202. package/src/core/__tests__/agentScheduler.emptyResponseChatStall.test.js +213 -213
  203. package/src/core/__tests__/agentScheduler.errorCategorisation.test.js +246 -246
  204. package/src/core/__tests__/agentScheduler.firstChunkTimeout.test.js +138 -138
  205. package/src/core/__tests__/agentScheduler.modeTransitions.test.js +233 -233
  206. package/src/core/__tests__/agentScheduler.nativePromptPick.test.js +319 -319
  207. package/src/core/__tests__/agentScheduler.taskLifecycleInstruction.test.js +78 -78
  208. package/src/core/__tests__/agentScheduler.visualizer.test.js +258 -258
  209. package/src/core/__tests__/flowCheckpointStore.test.js +140 -140
  210. package/src/core/__tests__/flowEndToEnd.test.js +565 -565
  211. package/src/core/__tests__/flowFieldMapping.test.js +188 -189
  212. package/src/core/__tests__/flowLintClientMirror.test.js +96 -98
  213. package/src/core/__tests__/flowSavePayload.test.js +170 -169
  214. package/src/core/__tests__/flowTemplates.test.js +311 -311
  215. package/src/core/__tests__/flowVersionStore.test.js +123 -123
  216. package/src/core/__tests__/messageProcessor.test.js +669 -669
  217. package/src/core/__tests__/stateManager.test.js +0 -1
  218. package/src/core/agentPool.js +2474 -2475
  219. package/src/core/agentScheduler.js +1 -4
  220. package/src/core/contextManager.js +708 -708
  221. package/src/core/flowExecutor.js +1510 -1510
  222. package/src/core/flowFieldMapping.js +136 -138
  223. package/src/core/messageProcessor.js +953 -954
  224. package/src/core/orchestrator.js +593 -595
  225. package/src/core/stateManager.js +1765 -1752
  226. package/src/index.js +1221 -1221
  227. package/src/interfaces/__tests__/archivedAgentDelete.test.js +207 -207
  228. package/src/interfaces/__tests__/bulkAgentRoute.test.js +361 -361
  229. package/src/interfaces/__tests__/imageServing.test.js +228 -228
  230. package/src/interfaces/__tests__/remoteSessionAuth.test.js +308 -308
  231. package/src/interfaces/__tests__/videoJobsRoutes.test.js +178 -179
  232. package/src/interfaces/__tests__/webServer.marketplace.test.js +629 -629
  233. package/src/interfaces/schedulerRoutes.js +50 -50
  234. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +341 -350
  235. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -156
  236. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +325 -330
  237. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +385 -388
  238. package/src/interfaces/terminal/api/session.js +265 -266
  239. package/src/interfaces/terminal/api/websocket.js +496 -497
  240. package/src/interfaces/terminal/components/AgentCreator.js +691 -705
  241. package/src/interfaces/terminal/components/AgentEditor.js +676 -678
  242. package/src/interfaces/terminal/components/AgentSwitcher.js +331 -330
  243. package/src/interfaces/terminal/components/ErrorPanel.js +263 -264
  244. package/src/interfaces/terminal/components/Header.js +28 -28
  245. package/src/interfaces/terminal/components/Layout.js +598 -603
  246. package/src/interfaces/terminal/components/MessageList.js +280 -281
  247. package/src/interfaces/terminal/components/SettingsPanel.js +410 -415
  248. package/src/interfaces/terminal/components/StatusBar.js +2 -0
  249. package/src/interfaces/terminal/index.js +168 -168
  250. package/src/interfaces/terminal/state/useAgentControl.js +496 -496
  251. package/src/interfaces/terminal/state/useAgents.js +537 -537
  252. package/src/interfaces/terminal/state/useMessages.js +629 -630
  253. package/src/interfaces/terminal/state/useTools.js +554 -554
  254. package/src/interfaces/terminal/utils/debugLogger.js +44 -44
  255. package/src/interfaces/terminal/utils/settingsStorage.js +232 -232
  256. package/src/interfaces/webServer.js +7578 -7579
  257. package/src/interfaces/webServer.js.bak +7046 -7046
  258. package/src/modules/fileExplorer/__tests__/zipDownload.test.js +237 -237
  259. package/src/modules/fileExplorer/controller.js +470 -469
  260. package/src/modules/fileExplorer/routes.js +285 -286
  261. package/src/modules/widget/__tests__/isDisabled.test.js +41 -41
  262. package/src/modules/widget/__tests__/routes.test.js +677 -678
  263. package/src/modules/widget/__tests__/runtime.test.js +401 -401
  264. package/src/modules/widget/__tests__/versioning.test.js +309 -309
  265. package/src/modules/widget/__tests__/webComponentRuntime.test.js +565 -565
  266. package/src/modules/widget/__tests__/widgetTool.test.js +316 -316
  267. package/src/modules/widget/routes.js +435 -435
  268. package/src/modules/widget/runtime/bundle.js +640 -640
  269. package/src/modules/widget/runtime/webComponentBundle.js +470 -470
  270. package/src/modules/widget/schema.js +182 -181
  271. package/src/modules/widget/widgetTool.js +1389 -1389
  272. package/src/services/__tests__/agentActivityService.test.js +401 -402
  273. package/src/services/__tests__/benchmarkService.test.js +184 -184
  274. package/src/services/__tests__/contextInjectionService.test.js +246 -246
  275. package/src/services/__tests__/conversationQuery.test.js +721 -723
  276. package/src/services/__tests__/credentialVault.test.js +469 -469
  277. package/src/services/__tests__/discordService.integration.test.js +638 -639
  278. package/src/services/__tests__/flowContextService.test.js +590 -590
  279. package/src/services/__tests__/memoryService.test.js +1 -1
  280. package/src/services/__tests__/messageSource.test.js +380 -380
  281. package/src/services/__tests__/modelRouterNaming.test.js +111 -111
  282. package/src/services/__tests__/projectDetector.test.js +34 -34
  283. package/src/services/__tests__/promptService.test.js +242 -242
  284. package/src/services/__tests__/telegramService.test.js +941 -941
  285. package/src/services/__tests__/tokenCountingService.test.js +48 -48
  286. package/src/services/agentActivityService.js +419 -420
  287. package/src/services/aiService.js +2997 -3001
  288. package/src/services/apiKeyManager.js +359 -359
  289. package/src/services/benchmarkService.js +196 -196
  290. package/src/services/codebaseKnowledgeService.js +2 -2
  291. package/src/services/composioService.js +738 -738
  292. package/src/services/conversationCompactionService.js +1258 -1257
  293. package/src/services/credentialVault.js +685 -685
  294. package/src/services/discordService.js +792 -793
  295. package/src/services/embeddings/__tests__/azureCustomProvider.test.js +232 -232
  296. package/src/services/embeddings/__tests__/embeddingService.test.js +417 -417
  297. package/src/services/embeddings/__tests__/localProvider.test.js +263 -263
  298. package/src/services/embeddings/autoRecall.js +218 -219
  299. package/src/services/embeddings/indexers/__tests__/agentIndexer.test.js +232 -232
  300. package/src/services/embeddings/indexers/__tests__/memoryIndexer.test.js +418 -418
  301. package/src/services/embeddings/indexers/__tests__/reminisceIndexer.test.js +356 -357
  302. package/src/services/embeddings/indexers/__tests__/skillsIndexer.test.js +145 -145
  303. package/src/services/embeddings/indexers/__tests__/taskIndexer.test.js +146 -146
  304. package/src/services/embeddings/indexers/composioIndexer.js +279 -279
  305. package/src/services/embeddings/providerInterface.js +206 -206
  306. package/src/services/embeddings/providers/localProvider.js +11 -7
  307. package/src/services/embeddings/providers/openaiProvider.js +101 -101
  308. package/src/services/embeddings/vectorStore/inMemoryJsonStore.js +356 -356
  309. package/src/services/errorHandler.js +809 -809
  310. package/src/services/flowContextService.js +586 -586
  311. package/src/services/grounding/MockAdapter.js +125 -125
  312. package/src/services/modelRouterService.js +26 -31
  313. package/src/services/modelsService.js +322 -322
  314. package/src/services/ollamaService.js +452 -452
  315. package/src/services/projectDetector.js +403 -404
  316. package/src/services/promptService.js +418 -418
  317. package/src/services/qualityInspector.js +795 -795
  318. package/src/services/scheduleService.js +726 -726
  319. package/src/services/serviceRegistry.js +386 -386
  320. package/src/services/telegrafBot.js +174 -174
  321. package/src/services/telegramService.js +1972 -1972
  322. package/src/services/visualEditorBridge.js +1033 -1033
  323. package/src/services/visualEditorServer.js +1769 -1774
  324. package/src/services/whatsappService.js +667 -668
  325. package/src/tools/__tests__/agentCommunicationTool.findAgent.test.js +226 -226
  326. package/src/tools/__tests__/agentCommunicationTool.test.js +3 -3
  327. package/src/tools/__tests__/agentDelayTool.test.js +342 -342
  328. package/src/tools/__tests__/baseTool.test.js +3 -3
  329. package/src/tools/__tests__/codeMapTool.test.js +915 -915
  330. package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -309
  331. package/src/tools/__tests__/fileTreeTool.test.js +274 -274
  332. package/src/tools/__tests__/filesystemTool.test.js +815 -815
  333. package/src/tools/__tests__/foundryWebSearchTool.test.js +252 -252
  334. package/src/tools/__tests__/imageTool.validator.test.js +194 -194
  335. package/src/tools/__tests__/jobDoneTool.test.js +580 -581
  336. package/src/tools/__tests__/memoryTool.forgetStale.test.js +272 -272
  337. package/src/tools/__tests__/memoryTool.reminisce.test.js +2 -2
  338. package/src/tools/__tests__/memoryTool.reminisceSemanticSearch.test.js +301 -301
  339. package/src/tools/__tests__/memoryTool.semanticSearch.test.js +405 -405
  340. package/src/tools/__tests__/memoryTool.teamPool.test.js +293 -293
  341. package/src/tools/__tests__/memoryTool.test.js +1 -1
  342. package/src/tools/__tests__/seekTool.test.js +282 -282
  343. package/src/tools/__tests__/skillsTool.search.test.js +164 -164
  344. package/src/tools/__tests__/skillsTool.test.js +226 -226
  345. package/src/tools/__tests__/staticAnalysisTool.test.js +509 -509
  346. package/src/tools/__tests__/taskManagerTool.discipline.test.js +137 -137
  347. package/src/tools/__tests__/taskManagerTool.search.test.js +143 -143
  348. package/src/tools/__tests__/taskManagerTool.test.js +866 -866
  349. package/src/tools/__tests__/terminalTool.test.js +448 -448
  350. package/src/tools/__tests__/toolShapeForgiveness.test.js +259 -260
  351. package/src/tools/__tests__/userPromptTool.test.js +297 -297
  352. package/src/tools/__tests__/videoTool.jobs.test.js +147 -147
  353. package/src/tools/__tests__/webTool.e2e.test.js +609 -603
  354. package/src/tools/__tests__/webTool.unit.test.js +195 -195
  355. package/src/tools/__tests__/webTool.visionModel.test.js +75 -75
  356. package/src/tools/agentCommunicationTool.js +8 -10
  357. package/src/tools/agentDelayTool.js +496 -497
  358. package/src/tools/asyncToolManager.js +602 -603
  359. package/src/tools/baseTool.js +12 -11
  360. package/src/tools/cloneDetectionTool.js +576 -581
  361. package/src/tools/codeMapTool.js +0 -6
  362. package/src/tools/composioTool.js +617 -617
  363. package/src/tools/dependencyResolverTool.js +1211 -1212
  364. package/src/tools/desktop/DesktopTool.js +629 -638
  365. package/src/tools/desktop/__tests__/DesktopTool.e2e.test.js +306 -306
  366. package/src/tools/desktop/__tests__/DesktopTool.test.js +507 -507
  367. package/src/tools/desktop/__tests__/osController.test.js +364 -364
  368. package/src/tools/desktop/osController.js +491 -491
  369. package/src/tools/docxTool.js +623 -623
  370. package/src/tools/excelTool.js +636 -636
  371. package/src/tools/fileContentReplaceTool.js +5 -7
  372. package/src/tools/fileSystemTool.js +12 -19
  373. package/src/tools/fileTreeTool.js +840 -840
  374. package/src/tools/foundryWebSearchTool.js +273 -273
  375. package/src/tools/helpTool.js +198 -198
  376. package/src/tools/imageTool.js +1397 -1397
  377. package/src/tools/importAnalyzerTool.js +1056 -1056
  378. package/src/tools/jobDoneTool.js +495 -495
  379. package/src/tools/memoryTool.js +1 -1
  380. package/src/tools/office/pres/__tests__/presSystem.test.js +365 -365
  381. package/src/tools/office/pres/archetypes/agenda.js +61 -61
  382. package/src/tools/office/pres/archetypes/bentoGrid.js +218 -219
  383. package/src/tools/office/pres/archetypes/bigStat.js +140 -142
  384. package/src/tools/office/pres/archetypes/closing.js +70 -70
  385. package/src/tools/office/pres/archetypes/hero.js +70 -70
  386. package/src/tools/office/pres/archetypes/productHero.js +93 -94
  387. package/src/tools/office/pres/archetypes/table.js +73 -74
  388. package/src/tools/office/pres/backgrounds/orb.js +66 -66
  389. package/src/tools/office/pres/components.js +422 -423
  390. package/src/tools/officeTool.js +441 -441
  391. package/src/tools/pdfTool.js +625 -627
  392. package/src/tools/platformControlTool.js +1081 -1081
  393. package/src/tools/seekTool.js +917 -918
  394. package/src/tools/skillsTool.js +1 -1
  395. package/src/tools/staticAnalysisTool.js +2143 -2146
  396. package/src/tools/taskManagerTool.js +3324 -3324
  397. package/src/tools/terminalTool.js +2615 -2618
  398. package/src/tools/videoTool.js +1303 -1303
  399. package/src/tools/visionTool.js +508 -508
  400. package/src/tools/visualEditorTool.js +1289 -1290
  401. package/src/tools/webTool.js +3368 -3368
  402. package/src/tools/whatsappTool.js +464 -464
  403. package/src/types/__tests__/agent.test.js +499 -499
  404. package/src/types/__tests__/contextReference.test.js +606 -606
  405. package/src/types/__tests__/conversation.test.js +555 -555
  406. package/src/types/__tests__/toolCommand.test.js +584 -584
  407. package/src/types/contextReference.js +974 -971
  408. package/src/types/conversation.js +729 -729
  409. package/src/types/toolCommand.js +746 -746
  410. package/src/utilities/__tests__/attachmentValidator.test.js +80 -80
  411. package/src/utilities/__tests__/auditReport.test.js +328 -328
  412. package/src/utilities/__tests__/directoryAccessManager.test.js +388 -388
  413. package/src/utilities/__tests__/jsonRepair.test.js +103 -104
  414. package/src/utilities/__tests__/modeTransitionReasons.test.js +105 -105
  415. package/src/utilities/__tests__/platformUtils.test.js +80 -87
  416. package/src/utilities/__tests__/structuredFileValidator.test.js +261 -263
  417. package/src/utilities/__tests__/toolConstants.test.js +92 -94
  418. package/src/utilities/__tests__/useIsTouchDevice.detect.test.js +114 -114
  419. package/src/utilities/__tests__/webUiUtilSync.test.js +117 -117
  420. package/src/utilities/attachmentValidator.js +284 -288
  421. package/src/utilities/authCache.js.backup-1779570472481 +121 -121
  422. package/src/utilities/browserStealth.js +631 -630
  423. package/src/utilities/configManager.js +616 -617
  424. package/src/utilities/directoryAccessManager.js +564 -565
  425. package/src/utilities/fileProcessor.js +308 -307
  426. package/src/utilities/humanBehavior.js +454 -453
  427. package/src/utilities/logger.js +479 -479
  428. package/src/utilities/structuredFileValidator.js +696 -699
  429. package/src/utilities/tagParser.js +5 -10
  430. package/src/utilities/userDataDir.js +308 -308
  431. package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +0 -1
  432. package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +0 -1
  433. package/node_modules/minipass/LICENSE +0 -15
  434. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/LICENSE.md +0 -0
  435. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts +0 -0
  436. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts.map +0 -0
  437. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js +0 -0
  438. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js.map +0 -0
  439. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/package.json +0 -0
  440. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts +0 -0
  441. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts.map +0 -0
  442. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js +0 -0
  443. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js.map +0 -0
  444. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/package.json +0 -0
  445. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/LICENSE +0 -0
  446. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts +0 -0
  447. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts.map +0 -0
  448. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/package.json +0 -0
  449. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts +0 -0
  450. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts.map +0 -0
  451. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/package.json +0 -0
@@ -1,603 +1,598 @@
1
- /**
2
- * Main Layout Component
3
- * Integrates all state management hooks and renders the complete UI
4
- */
5
-
6
- import React, { useState, useEffect } from 'react';
7
- import { Box, useInput, useStdout } from 'ink';
8
- import { debugLog } from '../utils/debugLogger.js';
9
-
10
- // Import state management hooks
11
- import { SessionManager } from '../api/session.js';
12
- import { WebSocketManager } from '../api/websocket.js';
13
- import { MessageRouter } from '../api/messageRouter.js';
14
- import { useConnection } from '../state/useConnection.js';
15
- import { useAgents } from '../state/useAgents.js';
16
- import { useMessages } from '../state/useMessages.js';
17
- import { useAgentControl } from '../state/useAgentControl.js';
18
- import { useTools } from '../state/useTools.js';
19
-
20
- // Import settings storage utility
21
- import { loadSettings, saveSettings, hasLoxiaApiKey } from '../utils/settingsStorage.js';
22
-
23
- // Import child components
24
- import Header from './Header.js';
25
- import StatusBar from './StatusBar.js';
26
- import MessageList from './MessageList.js';
27
- import InputBox from './InputBox.js';
28
-
29
- // Import Phase 10 advanced components
30
- import AgentSwitcher from './AgentSwitcher.js';
31
- import AgentCreator from './AgentCreator.js';
32
- import AgentEditor from './AgentEditor.js';
33
- import SettingsPanel from './SettingsPanel.js';
34
- import SearchPanel from './SearchPanel.js';
35
- import HelpPanel from './HelpPanel.js';
36
- import ErrorPanel from './ErrorPanel.js';
37
-
38
- /**
39
- * Main Layout Component
40
- */
41
- export function Layout({ host = 'localhost', port = 8080 }) {
42
- // Get terminal dimensions for responsive layout
43
- const { stdout } = useStdout();
44
- const terminalHeight = stdout?.rows || 24; // Default to 24 rows if not available
45
- const terminalWidth = stdout?.columns || 80; // Default to 80 columns if not available
46
-
47
- // Calculate compact mode: hide header/statusbar if terminal is too small
48
- // Minimum comfortable height: 15 rows (3 for input, 12+ for messages)
49
- const compactMode = terminalHeight < 15;
50
-
51
- // Phase 10: Settings state - Load from persistent storage (must load before creating managers)
52
- const [settings, setSettings] = useState(() => loadSettings());
53
-
54
- // Initialize managers (with settings)
55
- const [sessionManager] = useState(() => new SessionManager(host, port));
56
- const [wsManager] = useState(() => new WebSocketManager(host, port, {
57
- reconnectDelay: settings.reconnectDelay,
58
- heartbeatInterval: settings.heartbeatInterval,
59
- }));
60
- const [messageRouter] = useState(() => new MessageRouter(wsManager));
61
-
62
- // Current agent state
63
- const [currentAgent, setCurrentAgent] = useState(null);
64
-
65
- // Phase 10: Overlay state
66
- const [activeOverlay, setActiveOverlay] = useState(null); // 'switcher', 'creator', 'editor', 'settings', 'search', 'help', 'errors'
67
-
68
- // Agent being edited
69
- const [agentToEdit, setAgentToEdit] = useState(null);
70
-
71
- // Error tracking state
72
- const [errors, setErrors] = useState([]);
73
-
74
- // Add error to the error log
75
- const addError = (type, message, stack) => {
76
- const error = {
77
- timestamp: Date.now(),
78
- type: type || 'ERROR',
79
- message: message || 'Unknown error',
80
- stack: stack || '',
81
- };
82
-
83
- setErrors(prev => {
84
- // Keep max 50 errors
85
- const newErrors = [error, ...prev].slice(0, 50);
86
- return newErrors;
87
- });
88
- };
89
-
90
- // Clear all errors
91
- const clearErrors = () => {
92
- setErrors([]);
93
- };
94
-
95
- // Dismiss a single error
96
- const dismissError = (index) => {
97
- setErrors(prev => prev.filter((_, i) => i !== index));
98
- };
99
-
100
- // Set up global error listeners
101
- useEffect(() => {
102
- const handleError = (error) => {
103
- addError('UNCAUGHT EXCEPTION', error.message, error.stack);
104
- };
105
-
106
- const handleRejection = (reason) => {
107
- const message = reason?.message || String(reason);
108
- const stack = reason?.stack || '';
109
- addError('UNHANDLED REJECTION', message, stack);
110
- };
111
-
112
- // Capture console.error calls (suppress output to prevent UI corruption)
113
- const originalConsoleError = console.error;
114
- console.error = (...args) => {
115
- const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
116
- addError('CONSOLE ERROR', message);
117
- // DON'T call original console.error to prevent errors appearing above UI
118
- };
119
-
120
- process.on('uncaughtException', handleError);
121
- process.on('unhandledRejection', handleRejection);
122
-
123
- return () => {
124
- process.removeListener('uncaughtException', handleError);
125
- process.removeListener('unhandledRejection', handleRejection);
126
- console.error = originalConsoleError;
127
- };
128
- }, []);
129
-
130
- // Connection state
131
- const connection = useConnection(sessionManager, wsManager);
132
-
133
- // Agent management
134
- const agents = useAgents(sessionManager, messageRouter);
135
-
136
- // Messages management
137
- const messages = useMessages(sessionManager, messageRouter, currentAgent?.agentId);
138
-
139
- // Agent control (mode, model)
140
- const agentControl = useAgentControl(sessionManager, messageRouter, currentAgent);
141
-
142
- // Tools management
143
- const tools = useTools(sessionManager, messageRouter, currentAgent?.agentId);
144
-
145
- // Initialize connection on mount
146
- useEffect(() => {
147
- connection.connect();
148
-
149
- return () => {
150
- connection.disconnect();
151
- };
152
- }, []);
153
-
154
- // Load agents when connected
155
- useEffect(() => {
156
- if (connection.isConnected && agents.agents.length === 0) {
157
- agents.fetchAgents();
158
- }
159
- // eslint-disable-next-line react-hooks/exhaustive-deps
160
- }, [connection.isConnected, agents.agents.length]);
161
-
162
- // Set current agent when agents are loaded
163
- useEffect(() => {
164
- if (agents.agents.length > 0 && !currentAgent) {
165
- setCurrentAgent(agents.agents[0]);
166
- }
167
- // eslint-disable-next-line react-hooks/exhaustive-deps
168
- }, [agents.agents.length, currentAgent]);
169
-
170
- // Onboarding: Auto-show settings if no Loxia API key is configured
171
- useEffect(() => {
172
- if (!hasLoxiaApiKey()) {
173
- // Delay slightly to allow UI to initialize
174
- const timer = setTimeout(() => {
175
- setActiveOverlay('settings');
176
- }, 500);
177
- return () => clearTimeout(timer);
178
- }
179
- }, []);
180
-
181
- // Register API keys with SessionManager on connection
182
- useEffect(() => {
183
- const registerApiKeys = async () => {
184
- if (connection.isConnected && settings.apiKeys) {
185
- try {
186
- await sessionManager.setApiKeys(
187
- settings.apiKeys.loxia,
188
- {
189
- anthropic: settings.apiKeys.anthropic,
190
- openai: settings.apiKeys.openai,
191
- deepseek: settings.apiKeys.deepseek,
192
- }
193
- );
194
- } catch (error) {
195
- // Silently fail - user will see errors when making requests
196
- addError('API KEY ERROR', `Failed to register API keys on startup: ${error.message}`);
197
- }
198
- }
199
- };
200
-
201
- registerApiKeys();
202
- // eslint-disable-next-line react-hooks/exhaustive-deps
203
- }, [connection.isConnected]);
204
-
205
- // Keyboard shortcuts - only enable if raw mode is supported
206
- const isRawModeSupported = process.stdin.isTTY && typeof process.stdin.setRawMode === 'function';
207
-
208
- useInput((char, key) => {
209
- // Skip if raw mode is not supported
210
- if (!isRawModeSupported) {
211
- return;
212
- }
213
-
214
- // Don't handle shortcuts if an overlay is active (overlays handle their own input)
215
- if (activeOverlay) {
216
- return;
217
- }
218
-
219
- // Phase 10: Advanced feature shortcuts
220
- // Ctrl+S - Agent Switcher
221
- if (key.ctrl && char === 's') {
222
- setActiveOverlay('switcher');
223
- }
224
- // Ctrl+N - New Agent Creator
225
- else if (key.ctrl && char === 'n') {
226
- setActiveOverlay('creator');
227
- }
228
- // Alt+S - Settings Panel (changed from Ctrl+, to avoid Windows settings conflict)
229
- else if (key.meta && char === 's') {
230
- setActiveOverlay('settings');
231
- }
232
- // Ctrl+F - Search Panel
233
- else if (key.ctrl && char === 'f') {
234
- setActiveOverlay('search');
235
- }
236
- // Ctrl+E - Error Panel
237
- else if (key.ctrl && char === 'e') {
238
- setActiveOverlay('errors');
239
- }
240
- // Alt+H - Help Panel (Ctrl+H conflicts with backspace, F1 doesn't work in remote terminals)
241
- else if (key.meta && char === 'h') {
242
- setActiveOverlay('help');
243
- }
244
-
245
- // Phase 9: Existing shortcuts
246
- // Ctrl+R - Refresh/Reconnect
247
- else if (key.ctrl && char === 'r') {
248
- if (connection.isConnected) {
249
- connection.reconnect();
250
- } else {
251
- connection.connect();
252
- }
253
- }
254
- // Ctrl+L - Clear messages
255
- else if (key.ctrl && char === 'l') {
256
- messages.clearMessages();
257
- }
258
- // Ctrl+A - Reload agents
259
- else if (key.ctrl && char === 'a') {
260
- agents.fetchAgents();
261
- }
262
- // Ctrl+T - Reload tools
263
- else if (key.ctrl && char === 't') {
264
- if (currentAgent) {
265
- tools.fetchTools();
266
- }
267
- }
268
- }, { isActive: isRawModeSupported });
269
-
270
- // Send message handler
271
- const handleSendMessage = async (content) => {
272
- // DEBUG: Log received content
273
- debugLog('Layout handleSendMessage', ' Called with content:', JSON.stringify(content));
274
- debugLog('Layout handleSendMessage', ' content type:', typeof content);
275
- debugLog('Layout handleSendMessage', ' content value:', content);
276
-
277
- // Defensive validation: ensure content is a non-empty string
278
- if (typeof content !== 'string' || !content || content.trim().length === 0) {
279
- debugLog('Layout handleSendMessage', ' VALIDATION FAILED - content is invalid');
280
- debugLog('Layout handleSendMessage', ' typeof content:', typeof content);
281
- debugLog('Layout handleSendMessage', ' !content:', !content);
282
- debugLog('Layout handleSendMessage', ' trim length:', typeof content === 'string' ? content.trim().length : 'N/A');
283
- addError('MESSAGE ERROR', 'Cannot send message: content is empty or invalid');
284
- return;
285
- }
286
-
287
- debugLog('Layout handleSendMessage', ' Validation PASSED, currentAgent:', currentAgent?.name);
288
-
289
- if (!currentAgent) {
290
- debugLog('Layout handleSendMessage', ' BLOCKED: No current agent');
291
- return;
292
- }
293
-
294
- try {
295
- debugLog('Layout handleSendMessage', ' Calling messages.sendMessage with:', JSON.stringify(content));
296
- await messages.sendMessage(content);
297
- debugLog('Layout handleSendMessage', ' messages.sendMessage completed successfully');
298
- } catch (error) {
299
- // Add to error panel instead of console
300
- debugLog('Layout handleSendMessage', ' ERROR:', error.message);
301
- addError('MESSAGE ERROR', `Failed to send message: ${error.message}`, error.stack);
302
- }
303
- };
304
-
305
- // Handle errors from MessageList
306
- const handleMessageError = (errorMessage) => {
307
- addError('MESSAGE ERROR', errorMessage);
308
- };
309
-
310
- // Agent switching handler
311
- const handleSwitchAgent = async (agent) => {
312
- if (!agent) return;
313
-
314
- setActiveOverlay(null);
315
-
316
- // Check if agent is loaded - if not, use switchAgent to load it first
317
- if (!agent.isLoaded) {
318
- try {
319
- const result = await agents.switchAgent(agent.agentId);
320
- if (result.success) {
321
- // Get the updated agent after import
322
- const updatedAgent = agents.agents.find(a => a.agentId === agent.agentId) || agent;
323
- setCurrentAgent({ ...updatedAgent, isLoaded: true });
324
- } else {
325
- addError('AGENT ERROR', `Failed to load agent: ${result.error || 'Unknown error'}`);
326
- }
327
- } catch (err) {
328
- addError('AGENT ERROR', `Failed to load agent: ${err.message}`);
329
- }
330
- } else {
331
- setCurrentAgent(agent);
332
- }
333
- };
334
-
335
- // Agent editing handler
336
- const handleEditAgent = (agent) => {
337
- if (agent) {
338
- setAgentToEdit(agent);
339
- setActiveOverlay('editor');
340
- }
341
- };
342
-
343
- // Agent save handler (from editor)
344
- const handleSaveAgent = async (agentId, updates) => {
345
- try {
346
- // Call useAgents hook's updateAgentConfig method
347
- await agents.updateAgentConfig(agentId, updates);
348
-
349
- // Update currentAgent if it was the one being edited
350
- if (currentAgent?.agentId === agentId) {
351
- setCurrentAgent({ ...currentAgent, ...updates });
352
- }
353
-
354
- // Refresh agent list to ensure consistency
355
- await agents.fetchAgents();
356
-
357
- // Close editor overlay
358
- setActiveOverlay(null);
359
- setAgentToEdit(null);
360
- } catch (error) {
361
- // Re-throw to let AgentEditor handle the error display
362
- throw error;
363
- }
364
- };
365
-
366
- // Agent deletion handler
367
- const handleDeleteAgent = async (agent) => {
368
- try {
369
- // Call useAgents hook's deleteAgent method
370
- await agents.deleteAgent(agent.agentId);
371
-
372
- // If the deleted agent was current, update currentAgent to the new current one from agents hook
373
- if (currentAgent?.agentId === agent.agentId) {
374
- // useAgents already switched to another agent, just update local state
375
- const remainingAgents = agents.agents.filter(a => a.agentId !== agent.agentId);
376
- if (remainingAgents.length > 0) {
377
- setCurrentAgent(remainingAgents[0]);
378
- } else {
379
- setCurrentAgent(null);
380
- }
381
- }
382
-
383
- // Refresh agent list to ensure consistency
384
- await agents.fetchAgents();
385
- } catch (error) {
386
- addError('AGENT DELETION ERROR', `Failed to delete agent: ${error.message}`, error.stack);
387
- }
388
- };
389
-
390
- // Phase 10: Overlay handlers
391
- const handleCreateAgent = async (formData) => {
392
- console.log('[DEBUG handleCreateAgent] Called with formData:', formData);
393
- try {
394
- console.log('[DEBUG handleCreateAgent] Calling agents.createAgent...');
395
- // Create agent using useAgents hook
396
- const result = await agents.createAgent({
397
- name: formData.name,
398
- model: formData.model,
399
- mode: formData.mode || 'AGENT',
400
- systemPrompt: formData.systemPrompt || '',
401
- dynamicModelRouting: formData.dynamicModelRouting !== undefined ? formData.dynamicModelRouting : true, // User choice or default to enabled
402
- platformProvided: true, // Use platform routing (not direct API access)
403
- capabilities: formData.capabilities || [], // User-selected capabilities
404
- switchTo: true, // Automatically switch to newly created agent
405
- });
406
-
407
- console.log('[DEBUG handleCreateAgent] Result:', result);
408
- console.log('[DEBUG handleCreateAgent] result.success:', result.success, 'result.agent:', result.agent);
409
-
410
- if (result.success && result.agent) {
411
- // Agent was created and added to the list automatically by useAgents hook
412
- // The hook also set it as current agent (switchTo: true)
413
- console.log('[DEBUG handleCreateAgent] SUCCESS! Setting current agent and closing overlay');
414
- setCurrentAgent(result.agent);
415
- setActiveOverlay(null);
416
- console.log('[DEBUG handleCreateAgent] setActiveOverlay(null) called');
417
- } else {
418
- console.log('[DEBUG handleCreateAgent] FAILED! result.success or result.agent is falsy');
419
- addError('AGENT CREATION ERROR', 'Failed to create agent: Unknown error');
420
- // Close overlay anyway so user isn't stuck - they can see error in error panel (Ctrl+E)
421
- setActiveOverlay(null);
422
- }
423
- } catch (error) {
424
- console.log('[DEBUG handleCreateAgent] EXCEPTION:', error.message, error.stack);
425
- addError('AGENT CREATION ERROR', `Failed to create agent: ${error.message}`, error.stack);
426
- // Close overlay anyway so user isn't stuck - they can see error in error panel (Ctrl+E)
427
- setActiveOverlay(null);
428
- }
429
- };
430
-
431
- const handleSaveSettings = async (newSettings) => {
432
- try {
433
- // Persist settings to disk
434
- const success = saveSettings(newSettings);
435
- if (!success) {
436
- addError('SETTINGS ERROR', 'Failed to save settings to disk');
437
- return;
438
- }
439
-
440
- // Update local state
441
- setSettings(newSettings);
442
-
443
- // Register API keys with SessionManager if provided
444
- if (newSettings.apiKeys) {
445
- try {
446
- await sessionManager.setApiKeys(
447
- newSettings.apiKeys.loxia,
448
- {
449
- anthropic: newSettings.apiKeys.anthropic,
450
- openai: newSettings.apiKeys.openai,
451
- deepseek: newSettings.apiKeys.deepseek,
452
- }
453
- );
454
- } catch (error) {
455
- // API key registration failed, but settings were saved
456
- addError('API KEY ERROR', `Settings saved but failed to register API keys: ${error.message}`);
457
- }
458
- }
459
-
460
- // Close settings overlay
461
- setActiveOverlay(null);
462
- } catch (error) {
463
- addError('SETTINGS ERROR', `Failed to save settings: ${error.message}`, error.stack);
464
- }
465
- };
466
-
467
- const handleSelectMessage = (message) => {
468
- // Scroll to or highlight the selected message
469
- console.log('Selected message:', message.id);
470
- setActiveOverlay(null);
471
- };
472
-
473
- const handleCloseOverlay = () => {
474
- setActiveOverlay(null);
475
- setAgentToEdit(null); // Clear agent to edit when closing
476
- };
477
-
478
- // Conditional rendering: if overlay is active, render ONLY the overlay
479
- // This is the Ink-native way to handle modals (no absolute positioning support)
480
- if (activeOverlay === 'switcher') {
481
- return React.createElement(AgentSwitcher, {
482
- agents: agents.agents,
483
- currentAgentId: currentAgent?.agentId,
484
- onSelect: handleSwitchAgent,
485
- onClose: handleCloseOverlay,
486
- onDelete: handleDeleteAgent, // Pass delete handler
487
- onEdit: handleEditAgent, // Pass edit handler
488
- terminalHeight, // Pass terminal dimensions for fullscreen rendering
489
- terminalWidth,
490
- });
491
- }
492
-
493
- if (activeOverlay === 'editor') {
494
- return React.createElement(AgentEditor, {
495
- agent: agentToEdit,
496
- onSave: handleSaveAgent,
497
- onClose: handleCloseOverlay,
498
- availableModels: ['anthropic-sonnet', 'anthropic-haiku', 'gpt-4', 'gpt-4-mini', 'gpt-5.1-codex-mini', 'deepseek-r1', 'phi-4', 'phi-4-reasoning'],
499
- terminalHeight, // Pass terminal dimensions for fullscreen rendering
500
- terminalWidth,
501
- });
502
- }
503
-
504
- if (activeOverlay === 'creator') {
505
- return React.createElement(AgentCreator, {
506
- sessionManager,
507
- onCancel: handleCloseOverlay,
508
- onCreate: handleCreateAgent,
509
- terminalHeight, // Pass terminal dimensions for fullscreen rendering
510
- terminalWidth,
511
- });
512
- }
513
-
514
- if (activeOverlay === 'settings') {
515
- return React.createElement(SettingsPanel, {
516
- settings,
517
- onSave: handleSaveSettings,
518
- onCancel: handleCloseOverlay,
519
- terminalHeight, // Pass terminal dimensions for fullscreen rendering
520
- terminalWidth,
521
- });
522
- }
523
-
524
- if (activeOverlay === 'search') {
525
- return React.createElement(SearchPanel, {
526
- messages: messages.messages,
527
- onSelect: handleSelectMessage,
528
- onClose: handleCloseOverlay,
529
- terminalHeight, // Pass terminal dimensions for fullscreen rendering
530
- terminalWidth,
531
- });
532
- }
533
-
534
- if (activeOverlay === 'help') {
535
- return React.createElement(HelpPanel, {
536
- onClose: handleCloseOverlay,
537
- terminalHeight, // Pass terminal dimensions for fullscreen rendering
538
- terminalWidth,
539
- });
540
- }
541
-
542
- if (activeOverlay === 'errors') {
543
- return React.createElement(ErrorPanel, {
544
- errors,
545
- onClose: handleCloseOverlay,
546
- onClear: clearErrors,
547
- onDismiss: dismissError,
548
- terminalHeight, // Pass terminal dimensions for fullscreen rendering
549
- terminalWidth,
550
- });
551
- }
552
-
553
- // Default: render normal UI layout (responsive based on terminal height)
554
- return React.createElement(
555
- Box,
556
- { flexDirection: 'column', minHeight: terminalHeight, maxHeight: terminalHeight },
557
- // Header (hidden in compact mode)
558
- !compactMode && React.createElement(Header, {
559
- currentAgent,
560
- connectionStatus: connection.connectionStatus,
561
- isConnected: connection.isConnected,
562
- }),
563
-
564
- // Main content area (message list) - fills remaining space
565
- React.createElement(MessageList, {
566
- messages: messages.messages,
567
- loading: messages.loading,
568
- error: messages.error,
569
- onError: handleMessageError,
570
- compactMode, // Pass compact mode flag
571
- currentAgent, // Pass current agent for compact mode display
572
- isConnected: connection.isConnected, // Pass connection status for compact mode
573
- terminalHeight, // Pass terminal height for scroll calculation
574
- terminalWidth, // Pass terminal width for responsive rendering
575
- showTimestamps: settings.showTimestamps, // Pass showTimestamps setting
576
- colorScheme: settings.colorScheme, // Pass colorScheme setting
577
- }),
578
-
579
- // Input box
580
- React.createElement(InputBox, {
581
- onSubmit: handleSendMessage,
582
- disabled: !connection.isConnected || !currentAgent,
583
- placeholder: currentAgent
584
- ? `Message ${currentAgent.name}...`
585
- : 'No agent selected',
586
- }),
587
-
588
- // Status bar (hidden in compact mode)
589
- !compactMode && React.createElement(StatusBar, {
590
- connectionStatus: connection.connectionStatus,
591
- connectionUptime: connection.connectionUptime,
592
- currentAgent,
593
- currentMode: agentControl.currentMode,
594
- messageCount: messages.messages.length,
595
- activeAgentCount: agents.agents.filter(a => a.isLoaded).length,
596
- totalAgentCount: agents.agents.length,
597
- toolCount: tools.tools.length,
598
- errorCount: errors.length,
599
- })
600
- );
601
- }
602
-
603
- export default Layout;
1
+ /**
2
+ * Main Layout Component
3
+ * Integrates all state management hooks and renders the complete UI
4
+ */
5
+
6
+ import React, { useState, useEffect } from 'react';
7
+ import { Box, useInput, useStdout } from 'ink';
8
+ import { debugLog } from '../utils/debugLogger.js';
9
+
10
+ // Import state management hooks
11
+ import { SessionManager } from '../api/session.js';
12
+ import { WebSocketManager } from '../api/websocket.js';
13
+ import { MessageRouter } from '../api/messageRouter.js';
14
+ import { useConnection } from '../state/useConnection.js';
15
+ import { useAgents } from '../state/useAgents.js';
16
+ import { useMessages } from '../state/useMessages.js';
17
+ import { useAgentControl } from '../state/useAgentControl.js';
18
+ import { useTools } from '../state/useTools.js';
19
+
20
+ // Import settings storage utility
21
+ import { loadSettings, saveSettings, hasLoxiaApiKey } from '../utils/settingsStorage.js';
22
+
23
+ // Import child components
24
+ import Header from './Header.js';
25
+ import StatusBar from './StatusBar.js';
26
+ import MessageList from './MessageList.js';
27
+ import InputBox from './InputBox.js';
28
+
29
+ // Import Phase 10 advanced components
30
+ import AgentSwitcher from './AgentSwitcher.js';
31
+ import AgentCreator from './AgentCreator.js';
32
+ import AgentEditor from './AgentEditor.js';
33
+ import SettingsPanel from './SettingsPanel.js';
34
+ import SearchPanel from './SearchPanel.js';
35
+ import HelpPanel from './HelpPanel.js';
36
+ import ErrorPanel from './ErrorPanel.js';
37
+
38
+ /**
39
+ * Main Layout Component
40
+ */
41
+ export function Layout({ host = 'localhost', port = 8080 }) {
42
+ // Get terminal dimensions for responsive layout
43
+ const { stdout } = useStdout();
44
+ const terminalHeight = stdout?.rows || 24; // Default to 24 rows if not available
45
+ const terminalWidth = stdout?.columns || 80; // Default to 80 columns if not available
46
+
47
+ // Calculate compact mode: hide header/statusbar if terminal is too small
48
+ // Minimum comfortable height: 15 rows (3 for input, 12+ for messages)
49
+ const compactMode = terminalHeight < 15;
50
+
51
+ // Phase 10: Settings state - Load from persistent storage (must load before creating managers)
52
+ const [settings, setSettings] = useState(() => loadSettings());
53
+
54
+ // Initialize managers (with settings)
55
+ const [sessionManager] = useState(() => new SessionManager(host, port));
56
+ const [wsManager] = useState(() => new WebSocketManager(host, port, {
57
+ reconnectDelay: settings.reconnectDelay,
58
+ heartbeatInterval: settings.heartbeatInterval,
59
+ }));
60
+ const [messageRouter] = useState(() => new MessageRouter(wsManager));
61
+
62
+ // Current agent state
63
+ const [currentAgent, setCurrentAgent] = useState(null);
64
+
65
+ // Phase 10: Overlay state
66
+ const [activeOverlay, setActiveOverlay] = useState(null); // 'switcher', 'creator', 'editor', 'settings', 'search', 'help', 'errors'
67
+
68
+ // Agent being edited
69
+ const [agentToEdit, setAgentToEdit] = useState(null);
70
+
71
+ // Error tracking state
72
+ const [errors, setErrors] = useState([]);
73
+
74
+ // Add error to the error log
75
+ const addError = (type, message, stack) => {
76
+ const error = {
77
+ timestamp: Date.now(),
78
+ type: type || 'ERROR',
79
+ message: message || 'Unknown error',
80
+ stack: stack || '',
81
+ };
82
+
83
+ setErrors(prev => {
84
+ // Keep max 50 errors
85
+ const newErrors = [error, ...prev].slice(0, 50);
86
+ return newErrors;
87
+ });
88
+ };
89
+
90
+ // Clear all errors
91
+ const clearErrors = () => {
92
+ setErrors([]);
93
+ };
94
+
95
+ // Dismiss a single error
96
+ const dismissError = (index) => {
97
+ setErrors(prev => prev.filter((_, i) => i !== index));
98
+ };
99
+
100
+ // Set up global error listeners
101
+ useEffect(() => {
102
+ const handleError = (error) => {
103
+ addError('UNCAUGHT EXCEPTION', error.message, error.stack);
104
+ };
105
+
106
+ const handleRejection = (reason) => {
107
+ const message = reason?.message || String(reason);
108
+ const stack = reason?.stack || '';
109
+ addError('UNHANDLED REJECTION', message, stack);
110
+ };
111
+
112
+ // Capture console.error calls (suppress output to prevent UI corruption)
113
+ const originalConsoleError = console.error;
114
+ console.error = (...args) => {
115
+ const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
116
+ addError('CONSOLE ERROR', message);
117
+ // DON'T call original console.error to prevent errors appearing above UI
118
+ };
119
+
120
+ process.on('uncaughtException', handleError);
121
+ process.on('unhandledRejection', handleRejection);
122
+
123
+ return () => {
124
+ process.removeListener('uncaughtException', handleError);
125
+ process.removeListener('unhandledRejection', handleRejection);
126
+ console.error = originalConsoleError;
127
+ };
128
+ }, []);
129
+
130
+ // Connection state
131
+ const connection = useConnection(sessionManager, wsManager);
132
+
133
+ // Agent management
134
+ const agents = useAgents(sessionManager, messageRouter);
135
+
136
+ // Messages management
137
+ const messages = useMessages(sessionManager, messageRouter, currentAgent?.agentId);
138
+
139
+ // Agent control (mode, model)
140
+ const agentControl = useAgentControl(sessionManager, messageRouter, currentAgent);
141
+
142
+ // Tools management
143
+ const tools = useTools(sessionManager, messageRouter, currentAgent?.agentId);
144
+
145
+ // Initialize connection on mount
146
+ useEffect(() => {
147
+ connection.connect();
148
+
149
+ return () => {
150
+ connection.disconnect();
151
+ };
152
+ }, []);
153
+
154
+ // Load agents when connected
155
+ useEffect(() => {
156
+ if (connection.isConnected && agents.agents.length === 0) {
157
+ agents.fetchAgents();
158
+ }
159
+
160
+ }, [connection.isConnected, agents.agents.length]);
161
+
162
+ // Set current agent when agents are loaded
163
+ useEffect(() => {
164
+ if (agents.agents.length > 0 && !currentAgent) {
165
+ setCurrentAgent(agents.agents[0]);
166
+ }
167
+
168
+ }, [agents.agents.length, currentAgent]);
169
+
170
+ // Onboarding: Auto-show settings if no Loxia API key is configured
171
+ useEffect(() => {
172
+ if (!hasLoxiaApiKey()) {
173
+ // Delay slightly to allow UI to initialize
174
+ const timer = setTimeout(() => {
175
+ setActiveOverlay('settings');
176
+ }, 500);
177
+ return () => clearTimeout(timer);
178
+ }
179
+ }, []);
180
+
181
+ // Register API keys with SessionManager on connection
182
+ useEffect(() => {
183
+ const registerApiKeys = async () => {
184
+ if (connection.isConnected && settings.apiKeys) {
185
+ try {
186
+ await sessionManager.setApiKeys(
187
+ settings.apiKeys.loxia,
188
+ {
189
+ anthropic: settings.apiKeys.anthropic,
190
+ openai: settings.apiKeys.openai,
191
+ deepseek: settings.apiKeys.deepseek,
192
+ }
193
+ );
194
+ } catch (error) {
195
+ // Silently fail - user will see errors when making requests
196
+ addError('API KEY ERROR', `Failed to register API keys on startup: ${error.message}`);
197
+ }
198
+ }
199
+ };
200
+
201
+ registerApiKeys();
202
+
203
+ }, [connection.isConnected]);
204
+
205
+ // Keyboard shortcuts - only enable if raw mode is supported
206
+ const isRawModeSupported = process.stdin.isTTY && typeof process.stdin.setRawMode === 'function';
207
+
208
+ useInput((char, key) => {
209
+ // Skip if raw mode is not supported
210
+ if (!isRawModeSupported) {
211
+ return;
212
+ }
213
+
214
+ // Don't handle shortcuts if an overlay is active (overlays handle their own input)
215
+ if (activeOverlay) {
216
+ return;
217
+ }
218
+
219
+ // Phase 10: Advanced feature shortcuts
220
+ // Ctrl+S - Agent Switcher
221
+ if (key.ctrl && char === 's') {
222
+ setActiveOverlay('switcher');
223
+ }
224
+ // Ctrl+N - New Agent Creator
225
+ else if (key.ctrl && char === 'n') {
226
+ setActiveOverlay('creator');
227
+ }
228
+ // Alt+S - Settings Panel (changed from Ctrl+, to avoid Windows settings conflict)
229
+ else if (key.meta && char === 's') {
230
+ setActiveOverlay('settings');
231
+ }
232
+ // Ctrl+F - Search Panel
233
+ else if (key.ctrl && char === 'f') {
234
+ setActiveOverlay('search');
235
+ }
236
+ // Ctrl+E - Error Panel
237
+ else if (key.ctrl && char === 'e') {
238
+ setActiveOverlay('errors');
239
+ }
240
+ // Alt+H - Help Panel (Ctrl+H conflicts with backspace, F1 doesn't work in remote terminals)
241
+ else if (key.meta && char === 'h') {
242
+ setActiveOverlay('help');
243
+ }
244
+
245
+ // Phase 9: Existing shortcuts
246
+ // Ctrl+R - Refresh/Reconnect
247
+ else if (key.ctrl && char === 'r') {
248
+ if (connection.isConnected) {
249
+ connection.reconnect();
250
+ } else {
251
+ connection.connect();
252
+ }
253
+ }
254
+ // Ctrl+L - Clear messages
255
+ else if (key.ctrl && char === 'l') {
256
+ messages.clearMessages();
257
+ }
258
+ // Ctrl+A - Reload agents
259
+ else if (key.ctrl && char === 'a') {
260
+ agents.fetchAgents();
261
+ }
262
+ // Ctrl+T - Reload tools
263
+ else if (key.ctrl && char === 't') {
264
+ if (currentAgent) {
265
+ tools.fetchTools();
266
+ }
267
+ }
268
+ }, { isActive: isRawModeSupported });
269
+
270
+ // Send message handler
271
+ const handleSendMessage = async (content) => {
272
+ // DEBUG: Log received content
273
+ debugLog('Layout handleSendMessage', ' Called with content:', JSON.stringify(content));
274
+ debugLog('Layout handleSendMessage', ' content type:', typeof content);
275
+ debugLog('Layout handleSendMessage', ' content value:', content);
276
+
277
+ // Defensive validation: ensure content is a non-empty string
278
+ if (typeof content !== 'string' || !content || content.trim().length === 0) {
279
+ debugLog('Layout handleSendMessage', ' VALIDATION FAILED - content is invalid');
280
+ debugLog('Layout handleSendMessage', ' typeof content:', typeof content);
281
+ debugLog('Layout handleSendMessage', ' !content:', !content);
282
+ debugLog('Layout handleSendMessage', ' trim length:', typeof content === 'string' ? content.trim().length : 'N/A');
283
+ addError('MESSAGE ERROR', 'Cannot send message: content is empty or invalid');
284
+ return;
285
+ }
286
+
287
+ debugLog('Layout handleSendMessage', ' Validation PASSED, currentAgent:', currentAgent?.name);
288
+
289
+ if (!currentAgent) {
290
+ debugLog('Layout handleSendMessage', ' BLOCKED: No current agent');
291
+ return;
292
+ }
293
+
294
+ try {
295
+ debugLog('Layout handleSendMessage', ' Calling messages.sendMessage with:', JSON.stringify(content));
296
+ await messages.sendMessage(content);
297
+ debugLog('Layout handleSendMessage', ' messages.sendMessage completed successfully');
298
+ } catch (error) {
299
+ // Add to error panel instead of console
300
+ debugLog('Layout handleSendMessage', ' ERROR:', error.message);
301
+ addError('MESSAGE ERROR', `Failed to send message: ${error.message}`, error.stack);
302
+ }
303
+ };
304
+
305
+ // Handle errors from MessageList
306
+ const handleMessageError = (errorMessage) => {
307
+ addError('MESSAGE ERROR', errorMessage);
308
+ };
309
+
310
+ // Agent switching handler
311
+ const handleSwitchAgent = async (agent) => {
312
+ if (!agent) return;
313
+
314
+ setActiveOverlay(null);
315
+
316
+ // Check if agent is loaded - if not, use switchAgent to load it first
317
+ if (!agent.isLoaded) {
318
+ try {
319
+ const result = await agents.switchAgent(agent.agentId);
320
+ if (result.success) {
321
+ // Get the updated agent after import
322
+ const updatedAgent = agents.agents.find(a => a.agentId === agent.agentId) || agent;
323
+ setCurrentAgent({ ...updatedAgent, isLoaded: true });
324
+ } else {
325
+ addError('AGENT ERROR', `Failed to load agent: ${result.error || 'Unknown error'}`);
326
+ }
327
+ } catch (err) {
328
+ addError('AGENT ERROR', `Failed to load agent: ${err.message}`);
329
+ }
330
+ } else {
331
+ setCurrentAgent(agent);
332
+ }
333
+ };
334
+
335
+ // Agent editing handler
336
+ const handleEditAgent = (agent) => {
337
+ if (agent) {
338
+ setAgentToEdit(agent);
339
+ setActiveOverlay('editor');
340
+ }
341
+ };
342
+
343
+ // Agent save handler (from editor)
344
+ const handleSaveAgent = async (agentId, updates) => {
345
+ // Call useAgents hook's updateAgentConfig method
346
+ await agents.updateAgentConfig(agentId, updates);
347
+
348
+ // Update currentAgent if it was the one being edited
349
+ if (currentAgent?.agentId === agentId) {
350
+ setCurrentAgent({ ...currentAgent, ...updates });
351
+ }
352
+
353
+ // Refresh agent list to ensure consistency
354
+ await agents.fetchAgents();
355
+
356
+ // Close editor overlay
357
+ setActiveOverlay(null);
358
+ setAgentToEdit(null);
359
+ };
360
+
361
+ // Agent deletion handler
362
+ const handleDeleteAgent = async (agent) => {
363
+ try {
364
+ // Call useAgents hook's deleteAgent method
365
+ await agents.deleteAgent(agent.agentId);
366
+
367
+ // If the deleted agent was current, update currentAgent to the new current one from agents hook
368
+ if (currentAgent?.agentId === agent.agentId) {
369
+ // useAgents already switched to another agent, just update local state
370
+ const remainingAgents = agents.agents.filter(a => a.agentId !== agent.agentId);
371
+ if (remainingAgents.length > 0) {
372
+ setCurrentAgent(remainingAgents[0]);
373
+ } else {
374
+ setCurrentAgent(null);
375
+ }
376
+ }
377
+
378
+ // Refresh agent list to ensure consistency
379
+ await agents.fetchAgents();
380
+ } catch (error) {
381
+ addError('AGENT DELETION ERROR', `Failed to delete agent: ${error.message}`, error.stack);
382
+ }
383
+ };
384
+
385
+ // Phase 10: Overlay handlers
386
+ const handleCreateAgent = async (formData) => {
387
+ console.log('[DEBUG handleCreateAgent] Called with formData:', formData);
388
+ try {
389
+ console.log('[DEBUG handleCreateAgent] Calling agents.createAgent...');
390
+ // Create agent using useAgents hook
391
+ const result = await agents.createAgent({
392
+ name: formData.name,
393
+ model: formData.model,
394
+ mode: formData.mode || 'AGENT',
395
+ systemPrompt: formData.systemPrompt || '',
396
+ dynamicModelRouting: formData.dynamicModelRouting !== undefined ? formData.dynamicModelRouting : true, // User choice or default to enabled
397
+ platformProvided: true, // Use platform routing (not direct API access)
398
+ capabilities: formData.capabilities || [], // User-selected capabilities
399
+ switchTo: true, // Automatically switch to newly created agent
400
+ });
401
+
402
+ console.log('[DEBUG handleCreateAgent] Result:', result);
403
+ console.log('[DEBUG handleCreateAgent] result.success:', result.success, 'result.agent:', result.agent);
404
+
405
+ if (result.success && result.agent) {
406
+ // Agent was created and added to the list automatically by useAgents hook
407
+ // The hook also set it as current agent (switchTo: true)
408
+ console.log('[DEBUG handleCreateAgent] SUCCESS! Setting current agent and closing overlay');
409
+ setCurrentAgent(result.agent);
410
+ setActiveOverlay(null);
411
+ console.log('[DEBUG handleCreateAgent] setActiveOverlay(null) called');
412
+ } else {
413
+ console.log('[DEBUG handleCreateAgent] FAILED! result.success or result.agent is falsy');
414
+ addError('AGENT CREATION ERROR', 'Failed to create agent: Unknown error');
415
+ // Close overlay anyway so user isn't stuck - they can see error in error panel (Ctrl+E)
416
+ setActiveOverlay(null);
417
+ }
418
+ } catch (error) {
419
+ console.log('[DEBUG handleCreateAgent] EXCEPTION:', error.message, error.stack);
420
+ addError('AGENT CREATION ERROR', `Failed to create agent: ${error.message}`, error.stack);
421
+ // Close overlay anyway so user isn't stuck - they can see error in error panel (Ctrl+E)
422
+ setActiveOverlay(null);
423
+ }
424
+ };
425
+
426
+ const handleSaveSettings = async (newSettings) => {
427
+ try {
428
+ // Persist settings to disk
429
+ const success = saveSettings(newSettings);
430
+ if (!success) {
431
+ addError('SETTINGS ERROR', 'Failed to save settings to disk');
432
+ return;
433
+ }
434
+
435
+ // Update local state
436
+ setSettings(newSettings);
437
+
438
+ // Register API keys with SessionManager if provided
439
+ if (newSettings.apiKeys) {
440
+ try {
441
+ await sessionManager.setApiKeys(
442
+ newSettings.apiKeys.loxia,
443
+ {
444
+ anthropic: newSettings.apiKeys.anthropic,
445
+ openai: newSettings.apiKeys.openai,
446
+ deepseek: newSettings.apiKeys.deepseek,
447
+ }
448
+ );
449
+ } catch (error) {
450
+ // API key registration failed, but settings were saved
451
+ addError('API KEY ERROR', `Settings saved but failed to register API keys: ${error.message}`);
452
+ }
453
+ }
454
+
455
+ // Close settings overlay
456
+ setActiveOverlay(null);
457
+ } catch (error) {
458
+ addError('SETTINGS ERROR', `Failed to save settings: ${error.message}`, error.stack);
459
+ }
460
+ };
461
+
462
+ const handleSelectMessage = (message) => {
463
+ // Scroll to or highlight the selected message
464
+ console.log('Selected message:', message.id);
465
+ setActiveOverlay(null);
466
+ };
467
+
468
+ const handleCloseOverlay = () => {
469
+ setActiveOverlay(null);
470
+ setAgentToEdit(null); // Clear agent to edit when closing
471
+ };
472
+
473
+ // Conditional rendering: if overlay is active, render ONLY the overlay
474
+ // This is the Ink-native way to handle modals (no absolute positioning support)
475
+ if (activeOverlay === 'switcher') {
476
+ return React.createElement(AgentSwitcher, {
477
+ agents: agents.agents,
478
+ currentAgentId: currentAgent?.agentId,
479
+ onSelect: handleSwitchAgent,
480
+ onClose: handleCloseOverlay,
481
+ onDelete: handleDeleteAgent, // Pass delete handler
482
+ onEdit: handleEditAgent, // Pass edit handler
483
+ terminalHeight, // Pass terminal dimensions for fullscreen rendering
484
+ terminalWidth,
485
+ });
486
+ }
487
+
488
+ if (activeOverlay === 'editor') {
489
+ return React.createElement(AgentEditor, {
490
+ agent: agentToEdit,
491
+ onSave: handleSaveAgent,
492
+ onClose: handleCloseOverlay,
493
+ availableModels: ['anthropic-sonnet', 'anthropic-haiku', 'gpt-4', 'gpt-4-mini', 'gpt-5.1-codex-mini', 'deepseek-r1', 'phi-4', 'phi-4-reasoning'],
494
+ terminalHeight, // Pass terminal dimensions for fullscreen rendering
495
+ terminalWidth,
496
+ });
497
+ }
498
+
499
+ if (activeOverlay === 'creator') {
500
+ return React.createElement(AgentCreator, {
501
+ sessionManager,
502
+ onCancel: handleCloseOverlay,
503
+ onCreate: handleCreateAgent,
504
+ terminalHeight, // Pass terminal dimensions for fullscreen rendering
505
+ terminalWidth,
506
+ });
507
+ }
508
+
509
+ if (activeOverlay === 'settings') {
510
+ return React.createElement(SettingsPanel, {
511
+ settings,
512
+ onSave: handleSaveSettings,
513
+ onCancel: handleCloseOverlay,
514
+ terminalHeight, // Pass terminal dimensions for fullscreen rendering
515
+ terminalWidth,
516
+ });
517
+ }
518
+
519
+ if (activeOverlay === 'search') {
520
+ return React.createElement(SearchPanel, {
521
+ messages: messages.messages,
522
+ onSelect: handleSelectMessage,
523
+ onClose: handleCloseOverlay,
524
+ terminalHeight, // Pass terminal dimensions for fullscreen rendering
525
+ terminalWidth,
526
+ });
527
+ }
528
+
529
+ if (activeOverlay === 'help') {
530
+ return React.createElement(HelpPanel, {
531
+ onClose: handleCloseOverlay,
532
+ terminalHeight, // Pass terminal dimensions for fullscreen rendering
533
+ terminalWidth,
534
+ });
535
+ }
536
+
537
+ if (activeOverlay === 'errors') {
538
+ return React.createElement(ErrorPanel, {
539
+ errors,
540
+ onClose: handleCloseOverlay,
541
+ onClear: clearErrors,
542
+ onDismiss: dismissError,
543
+ terminalHeight, // Pass terminal dimensions for fullscreen rendering
544
+ terminalWidth,
545
+ });
546
+ }
547
+
548
+ // Default: render normal UI layout (responsive based on terminal height)
549
+ return React.createElement(
550
+ Box,
551
+ { flexDirection: 'column', minHeight: terminalHeight, maxHeight: terminalHeight },
552
+ // Header (hidden in compact mode)
553
+ !compactMode && React.createElement(Header, {
554
+ currentAgent,
555
+ connectionStatus: connection.connectionStatus,
556
+ isConnected: connection.isConnected,
557
+ }),
558
+
559
+ // Main content area (message list) - fills remaining space
560
+ React.createElement(MessageList, {
561
+ messages: messages.messages,
562
+ loading: messages.loading,
563
+ error: messages.error,
564
+ onError: handleMessageError,
565
+ compactMode, // Pass compact mode flag
566
+ currentAgent, // Pass current agent for compact mode display
567
+ isConnected: connection.isConnected, // Pass connection status for compact mode
568
+ terminalHeight, // Pass terminal height for scroll calculation
569
+ terminalWidth, // Pass terminal width for responsive rendering
570
+ showTimestamps: settings.showTimestamps, // Pass showTimestamps setting
571
+ colorScheme: settings.colorScheme, // Pass colorScheme setting
572
+ }),
573
+
574
+ // Input box
575
+ React.createElement(InputBox, {
576
+ onSubmit: handleSendMessage,
577
+ disabled: !connection.isConnected || !currentAgent,
578
+ placeholder: currentAgent
579
+ ? `Message ${currentAgent.name}...`
580
+ : 'No agent selected',
581
+ }),
582
+
583
+ // Status bar (hidden in compact mode)
584
+ !compactMode && React.createElement(StatusBar, {
585
+ connectionStatus: connection.connectionStatus,
586
+ connectionUptime: connection.connectionUptime,
587
+ currentAgent,
588
+ currentMode: agentControl.currentMode,
589
+ messageCount: messages.messages.length,
590
+ activeAgentCount: agents.agents.filter(a => a.isLoaded).length,
591
+ totalAgentCount: agents.agents.length,
592
+ toolCount: tools.tools.length,
593
+ errorCount: errors.length,
594
+ })
595
+ );
596
+ }
597
+
598
+ export default Layout;