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,705 +1,691 @@
1
- /**
2
- * AgentCreator Component
3
- * Multi-step wizard for creating new agents
4
- */
5
-
6
- import React, { useState, useEffect } from 'react';
7
- import { Box, Text, useInput } from 'ink';
8
-
9
- const STEPS = {
10
- NAME: 0,
11
- MODEL: 1,
12
- MODE: 2,
13
- DYNAMIC_ROUTING: 3,
14
- ROUTING_STRATEGY: 4,
15
- CAPABILITIES: 5,
16
- SYSTEM_PROMPT: 6,
17
- CONFIRM: 7,
18
- };
19
-
20
- const STEP_TITLES = [
21
- 'Agent Name',
22
- 'Select Model',
23
- 'Select Mode',
24
- 'Dynamic Model Routing',
25
- 'Routing Strategy (Optional)',
26
- 'Select Capabilities',
27
- 'System Prompt (Optional)',
28
- 'Confirm & Create'
29
- ];
30
-
31
- const MODES = [
32
- { value: 'chat', label: 'Chat Mode', description: 'Interactive conversation' },
33
- { value: 'auto', label: 'Auto Mode', description: 'Autonomous execution' },
34
- ];
35
-
36
- // Tools will be fetched dynamically from API
37
-
38
- const DYNAMIC_ROUTING_OPTIONS = [
39
- { value: true, label: 'Yes - Use dynamic routing', description: 'Recommended' },
40
- { value: false, label: 'No - Use model directly', description: 'Advanced users' },
41
- ];
42
-
43
- export function AgentCreator({ sessionManager, onCancel, onCreate, terminalHeight = 24, terminalWidth = 80 }) {
44
- // terminalHeight and terminalWidth are now passed as props from Layout.js
45
-
46
- const [step, setStep] = useState(STEPS.NAME);
47
- const [models, setModels] = useState([]);
48
- const [modelsLoading, setModelsLoading] = useState(true);
49
- const [modelsError, setModelsError] = useState(null);
50
- const [tools, setTools] = useState([]);
51
- const [toolsLoading, setToolsLoading] = useState(false);
52
- const [toolsError, setToolsError] = useState(null);
53
- const [formData, setFormData] = useState({
54
- name: '',
55
- model: '',
56
- mode: MODES[0].value,
57
- dynamicModelRouting: true, // Default to enabled
58
- routingStrategy: '',
59
- capabilities: [], // Array of tool names
60
- systemPrompt: '',
61
- });
62
- const [selectedIndex, setSelectedIndex] = useState(0);
63
- const [scrollOffset, setScrollOffset] = useState(0);
64
- const [inputBuffer, setInputBuffer] = useState('');
65
-
66
- // Calculate max visible items based on terminal height
67
- // Reserve space for: dialog header (1), dialog borders (3), step title (1),
68
- // inner borders (2), compact status line (1), shortcuts (3), margins (2) = 13 lines
69
- // Reduced from 16 to 13 by removing scroll indicators, bordered footer, and redundant instructions
70
- const RESERVED_LINES = 13;
71
- const MAX_VISIBLE_ITEMS = Math.max(3, Math.min(15, terminalHeight - RESERVED_LINES));
72
- const MAX_VISIBLE_MODELS = Math.max(5, Math.min(8, terminalHeight - 14)); // For model selection
73
-
74
- // Fetch available models from API
75
- useEffect(() => {
76
- async function fetchModels() {
77
- try {
78
- setModelsLoading(true);
79
- const data = await sessionManager.makeRequest('GET', '/api/llm/models');
80
-
81
- // Map API response to UI format
82
- const mappedModels = data.models.map(model => ({
83
- value: model.name,
84
- label: formatModelLabel(model),
85
- description: formatModelDescription(model),
86
- }));
87
-
88
- setModels(mappedModels);
89
-
90
- // Set default model
91
- if (mappedModels.length > 0) {
92
- setFormData(prev => ({ ...prev, model: mappedModels[0].value }));
93
- }
94
-
95
- setModelsLoading(false);
96
- } catch (error) {
97
- console.error('Error fetching models:', error);
98
- setModelsError(error.message);
99
- setModelsLoading(false);
100
- }
101
- }
102
-
103
- if (sessionManager) {
104
- fetchModels();
105
- }
106
- }, [sessionManager]);
107
-
108
- // Fetch available tools from API when CAPABILITIES step is reached
109
- useEffect(() => {
110
- async function fetchTools() {
111
- if (step !== STEPS.CAPABILITIES) return;
112
-
113
- try {
114
- setToolsLoading(true);
115
- setToolsError(null);
116
- const data = await sessionManager.makeRequest('GET', '/api/tools');
117
-
118
- if (data.success && data.tools) {
119
- // Map API response to UI format
120
- const mappedTools = data.tools.map(tool => ({
121
- value: tool.name,
122
- label: tool.name,
123
- description: tool.description || 'No description available',
124
- }));
125
-
126
- setTools(mappedTools);
127
- } else {
128
- throw new Error(data.error || 'Failed to fetch tools');
129
- }
130
-
131
- setToolsLoading(false);
132
- } catch (error) {
133
- console.error('Error fetching tools:', error);
134
- setToolsError(error.message);
135
- setToolsLoading(false);
136
- // Set empty tools array as fallback
137
- setTools([]);
138
- }
139
- }
140
-
141
- if (sessionManager && step === STEPS.CAPABILITIES) {
142
- fetchTools();
143
- }
144
- }, [sessionManager, step]);
145
-
146
- // Helper function to format model names for display
147
- function formatModelLabel(model) {
148
- // Use displayName from API if available
149
- if (model.displayName) {
150
- return model.displayName;
151
- }
152
-
153
- // Otherwise, format the name field programmatically
154
- // Convert "anthropic-sonnet" to "Anthropic Sonnet"
155
- const name = model.name || '';
156
- return name
157
- .split('-')
158
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
159
- .join(' ');
160
- }
161
-
162
- // Helper function to truncate text with ellipsis
163
- function truncate(text, maxLength) {
164
- if (text.length <= maxLength) return text;
165
- return text.substring(0, maxLength - 3) + '...';
166
- }
167
-
168
- // Helper function to format model descriptions from API data
169
- function formatModelDescription(model) {
170
- // Use API data for description
171
- const parts = [];
172
-
173
- if (model.category) {
174
- parts.push(model.category);
175
- }
176
-
177
- if (model.maxTokens) {
178
- parts.push(`${(model.maxTokens / 1000).toFixed(0)}K tokens`);
179
- }
180
-
181
- if (model.pricing?.input) {
182
- parts.push(`$${model.pricing.input}/1K`);
183
- }
184
-
185
- if (model.supportsVision) {
186
- parts.push('vision');
187
- }
188
-
189
- const description = parts.length > 0 ? parts.join(', ') : model.type || 'LLM';
190
-
191
- // Truncate to max 50 characters to prevent wrapping
192
- return truncate(description, 50);
193
- }
194
-
195
- useInput((char, key) => {
196
- // Cancel on Escape
197
- if (key.escape) {
198
- // Defer callback to avoid setState during render
199
- setTimeout(() => onCancel(), 0);
200
- return;
201
- }
202
-
203
- // Back on Ctrl+B
204
- if (key.ctrl && char === 'b' && step > STEPS.NAME) {
205
- // Skip routing strategy step if dynamic routing is disabled
206
- const prevStep = (step === STEPS.CAPABILITIES && !formData.dynamicModelRouting)
207
- ? STEPS.DYNAMIC_ROUTING
208
- : step - 1;
209
- setStep(prevStep);
210
- return;
211
- }
212
-
213
- // Handle based on current step
214
- if (step === STEPS.NAME || step === STEPS.SYSTEM_PROMPT || step === STEPS.ROUTING_STRATEGY) {
215
- // Text input steps
216
- if (key.return) {
217
- if (step === STEPS.NAME && inputBuffer.trim()) {
218
- setFormData({ ...formData, name: inputBuffer.trim() });
219
- setInputBuffer('');
220
- setStep(STEPS.MODEL);
221
- } else if (step === STEPS.ROUTING_STRATEGY) {
222
- setFormData({ ...formData, routingStrategy: inputBuffer.trim() });
223
- setInputBuffer('');
224
- setStep(STEPS.CAPABILITIES);
225
- } else if (step === STEPS.SYSTEM_PROMPT) {
226
- setFormData({ ...formData, systemPrompt: inputBuffer.trim() });
227
- setInputBuffer('');
228
- setStep(STEPS.CONFIRM);
229
- }
230
- } else if (key.backspace || key.delete) {
231
- setInputBuffer(prev => prev.slice(0, -1));
232
- } else if (char && !key.ctrl && !key.meta) {
233
- setInputBuffer(prev => prev + char);
234
- }
235
- } else if (step === STEPS.MODEL || step === STEPS.MODE || step === STEPS.DYNAMIC_ROUTING) {
236
- // Selection steps (single-select)
237
- const options = step === STEPS.MODEL ? models : (step === STEPS.MODE ? MODES : DYNAMIC_ROUTING_OPTIONS);
238
-
239
- if (key.upArrow) {
240
- setSelectedIndex(prev => {
241
- const newIndex = Math.max(0, prev - 1);
242
- // Scroll up if needed (for MODEL step only)
243
- if (step === STEPS.MODEL && newIndex < scrollOffset) {
244
- setScrollOffset(newIndex);
245
- }
246
- return newIndex;
247
- });
248
- } else if (key.downArrow) {
249
- setSelectedIndex(prev => {
250
- const newIndex = Math.min(options.length - 1, prev + 1);
251
- // Scroll down if needed (for MODEL step only)
252
- if (step === STEPS.MODEL && newIndex >= scrollOffset + MAX_VISIBLE_MODELS) {
253
- setScrollOffset(newIndex - MAX_VISIBLE_MODELS + 1);
254
- }
255
- return newIndex;
256
- });
257
- } else if (key.return) {
258
- if (step === STEPS.MODEL) {
259
- setFormData({ ...formData, model: models[selectedIndex].value });
260
- setSelectedIndex(0);
261
- setScrollOffset(0);
262
- setStep(STEPS.MODE);
263
- } else if (step === STEPS.MODE) {
264
- setFormData({ ...formData, mode: MODES[selectedIndex].value });
265
- setSelectedIndex(0);
266
- setStep(STEPS.DYNAMIC_ROUTING);
267
- } else if (step === STEPS.DYNAMIC_ROUTING) {
268
- const routingEnabled = DYNAMIC_ROUTING_OPTIONS[selectedIndex].value;
269
- setFormData({ ...formData, dynamicModelRouting: routingEnabled });
270
- setSelectedIndex(0);
271
- setInputBuffer('');
272
- // Skip strategy step if routing is disabled
273
- setStep(routingEnabled ? STEPS.ROUTING_STRATEGY : STEPS.CAPABILITIES);
274
- }
275
- }
276
- } else if (step === STEPS.CAPABILITIES) {
277
- // Multi-select step for capabilities (tools) with scrolling
278
- if (key.upArrow) {
279
- setSelectedIndex(prev => {
280
- const newIndex = Math.max(0, prev - 1);
281
- // Adjust scroll offset to keep selected item visible
282
- setScrollOffset(currentOffset => {
283
- if (newIndex < currentOffset) {
284
- return newIndex; // Scroll up to show item
285
- }
286
- return currentOffset;
287
- });
288
- return newIndex;
289
- });
290
- } else if (key.downArrow) {
291
- setSelectedIndex(prev => {
292
- const newIndex = Math.min(tools.length - 1, prev + 1);
293
- // Adjust scroll offset to keep selected item visible
294
- setScrollOffset(currentOffset => {
295
- if (newIndex >= currentOffset + MAX_VISIBLE_ITEMS) {
296
- return newIndex - MAX_VISIBLE_ITEMS + 1; // Scroll down to show item
297
- }
298
- return currentOffset;
299
- });
300
- return newIndex;
301
- });
302
- } else if (char === ' ' || key.space) {
303
- // Toggle selection
304
- if (tools.length > 0 && tools[selectedIndex]) {
305
- const toolName = tools[selectedIndex].value;
306
- setFormData(prev => {
307
- const capabilities = prev.capabilities || [];
308
- const isSelected = capabilities.includes(toolName);
309
- return {
310
- ...prev,
311
- capabilities: isSelected
312
- ? capabilities.filter(c => c !== toolName)
313
- : [...capabilities, toolName]
314
- };
315
- });
316
- }
317
- } else if (key.return) {
318
- // Continue to next step
319
- setSelectedIndex(0);
320
- setScrollOffset(0); // Reset scroll
321
- setStep(STEPS.SYSTEM_PROMPT);
322
- }
323
- } else if (step === STEPS.CONFIRM) {
324
- // Confirmation step
325
- if (key.return) {
326
- // Defer callback to avoid setState during render
327
- setTimeout(() => {
328
- onCreate(formData);
329
- }, 0);
330
- return;
331
- }
332
- }
333
- });
334
-
335
- const renderStep = () => {
336
- if (step === STEPS.NAME) {
337
- return React.createElement(
338
- Box,
339
- { flexDirection: 'column' },
340
- React.createElement(Text, {}, 'Enter agent name:'),
341
- React.createElement(
342
- Box,
343
- { marginTop: 1 },
344
- React.createElement(Text, {}, '> ', inputBuffer, String.fromCharCode(0x2588))
345
- )
346
- );
347
- }
348
-
349
- if (step === STEPS.MODEL) {
350
- return React.createElement(
351
- Box,
352
- { flexDirection: 'column', alignItems: 'center' },
353
- React.createElement(Text, {}, 'Select model:'),
354
- React.createElement(
355
- Box,
356
- { flexDirection: 'column', marginTop: 1, alignItems: 'center', width: '100%' },
357
- modelsLoading
358
- ? React.createElement(Text, { dimColor: true }, 'Loading models from server...')
359
- : modelsError
360
- ? React.createElement(
361
- Box,
362
- { flexDirection: 'column', alignItems: 'center' },
363
- React.createElement(Text, { color: 'red' }, 'Failed to load models:'),
364
- React.createElement(Text, { dimColor: true }, modelsError),
365
- React.createElement(Text, { dimColor: true, marginTop: 1 }, 'Press Esc to cancel')
366
- )
367
- : models.length === 0
368
- ? React.createElement(Text, { dimColor: true }, 'No models available')
369
- : React.createElement(
370
- Box,
371
- { flexDirection: 'column', alignItems: 'center' },
372
- // Visible models (with scroll window)
373
- models.slice(scrollOffset, scrollOffset + MAX_VISIBLE_MODELS).map((model, visibleIndex) => {
374
- const actualIndex = scrollOffset + visibleIndex;
375
- const isSelected = actualIndex === selectedIndex;
376
-
377
- return React.createElement(
378
- Box,
379
- { key: model.value },
380
- React.createElement(
381
- Text,
382
- { backgroundColor: isSelected ? 'blue' : undefined, color: isSelected ? 'white' : undefined },
383
- isSelected ? '> ' : ' ',
384
- model.label,
385
- React.createElement(Text, { dimColor: true }, ` - ${model.description}`)
386
- )
387
- );
388
- }),
389
- // Scroll indicator
390
- models.length > MAX_VISIBLE_MODELS &&
391
- React.createElement(
392
- Box,
393
- { marginTop: 1 },
394
- React.createElement(
395
- Text,
396
- { dimColor: true },
397
- `Showing ${scrollOffset + 1}-${Math.min(scrollOffset + MAX_VISIBLE_MODELS, models.length)} of ${models.length}`
398
- )
399
- )
400
- )
401
- )
402
- );
403
- }
404
-
405
- if (step === STEPS.MODE) {
406
- return React.createElement(
407
- Box,
408
- { flexDirection: 'column', alignItems: 'center' },
409
- React.createElement(Text, {}, 'Select mode:'),
410
- React.createElement(
411
- Box,
412
- { flexDirection: 'column', marginTop: 1, alignItems: 'center' },
413
- MODES.map((mode, index) =>
414
- React.createElement(
415
- Box,
416
- { key: mode.value },
417
- React.createElement(
418
- Text,
419
- { backgroundColor: index === selectedIndex ? 'blue' : undefined, color: index === selectedIndex ? 'white' : undefined },
420
- index === selectedIndex ? '> ' : ' ',
421
- mode.label,
422
- React.createElement(Text, { dimColor: true }, ` - ${mode.description}`)
423
- )
424
- )
425
- )
426
- )
427
- );
428
- }
429
-
430
- if (step === STEPS.DYNAMIC_ROUTING) {
431
- return React.createElement(
432
- Box,
433
- { flexDirection: 'column', alignItems: 'center', width: '80%' },
434
- React.createElement(Text, { bold: true }, 'Dynamic Model Routing'),
435
- React.createElement(
436
- Box,
437
- { flexDirection: 'column', marginTop: 1, alignItems: 'center', borderStyle: 'single', borderColor: 'cyan', paddingX: 2, paddingY: 1, width: '100%' },
438
- React.createElement(Text, { dimColor: true, textAlign: 'center' }, 'Enable automatic API provider selection based on session context'),
439
- React.createElement(
440
- Box,
441
- { flexDirection: 'column', marginTop: 1, width: '100%' },
442
- DYNAMIC_ROUTING_OPTIONS.map((option, index) =>
443
- React.createElement(
444
- Box,
445
- { key: String(option.value), marginTop: index > 0 ? 1 : 0 },
446
- React.createElement(
447
- Text,
448
- { backgroundColor: index === selectedIndex ? 'blue' : undefined, color: index === selectedIndex ? 'white' : undefined },
449
- index === selectedIndex ? '● ' : '○ ',
450
- option.label,
451
- React.createElement(Text, { dimColor: true }, ` (${option.description})`)
452
- )
453
- )
454
- )
455
- )
456
- )
457
- );
458
- }
459
-
460
- if (step === STEPS.ROUTING_STRATEGY) {
461
- return React.createElement(
462
- Box,
463
- { flexDirection: 'column', alignItems: 'center', width: '80%' },
464
- React.createElement(Text, { bold: true }, 'Routing Strategy (Optional)'),
465
- React.createElement(
466
- Box,
467
- { flexDirection: 'column', marginTop: 1, borderStyle: 'single', borderColor: 'cyan', paddingX: 2, paddingY: 1, width: '100%' },
468
- React.createElement(Text, { dimColor: true }, 'Custom instructions for model selection. Press Enter to skip.'),
469
- React.createElement(Text, { dimColor: true, italic: true }, 'e.g. Prefer fast models for short questions. Use Claude for code.'),
470
- React.createElement(
471
- Box,
472
- { marginTop: 1 },
473
- React.createElement(Text, { color: 'cyan' }, '> '),
474
- React.createElement(Text, null, inputBuffer || '')
475
- )
476
- )
477
- );
478
- }
479
-
480
- if (step === STEPS.CAPABILITIES) {
481
- const selectedCapabilities = formData.capabilities || [];
482
- const selectedCount = selectedCapabilities.length;
483
-
484
- return React.createElement(
485
- Box,
486
- { flexDirection: 'column', alignItems: 'center', width: '100%', maxHeight: contentMaxHeight },
487
- React.createElement(Text, { bold: true }, 'Select Capabilities (Tools)'),
488
- React.createElement(
489
- Box,
490
- { flexDirection: 'column', marginTop: 1, borderStyle: 'single', borderColor: 'cyan', paddingX: 2, paddingY: 1, width: '100%', maxHeight: contentMaxHeight - 6 },
491
- // Show loading state
492
- toolsLoading && React.createElement(
493
- Box,
494
- { justifyContent: 'center', paddingY: 2 },
495
- React.createElement(Text, { color: 'yellow' }, '⏳ Loading available tools from API...')
496
- ),
497
- // Show error state
498
- toolsError && React.createElement(
499
- Box,
500
- { flexDirection: 'column', paddingY: 1 },
501
- React.createElement(Text, { color: 'red' }, '✗ Error loading tools: ', toolsError),
502
- React.createElement(Text, { dimColor: true, marginTop: 1 }, 'Press Enter to continue without tools')
503
- ),
504
- // Show tools list (if loaded successfully) - with scrolling viewport
505
- !toolsLoading && !toolsError && tools.length > 0 && (() => {
506
- // Calculate visible slice of tools
507
- const visibleTools = tools.slice(scrollOffset, scrollOffset + MAX_VISIBLE_ITEMS);
508
- const hasMore = tools.length > MAX_VISIBLE_ITEMS;
509
- const showingFrom = scrollOffset + 1;
510
- const showingTo = Math.min(scrollOffset + MAX_VISIBLE_ITEMS, tools.length);
511
-
512
- return [
513
- // Visible tools
514
- ...visibleTools.map((tool, visibleIndex) => {
515
- const actualIndex = scrollOffset + visibleIndex;
516
- const isSelected = selectedCapabilities.includes(tool.value);
517
- const isCurrent = actualIndex === selectedIndex;
518
-
519
- // Create compact display: checkbox + label only, truncated to fit terminal
520
- // Available width = 95% of terminal - borders(2) - padding(4) - checkbox(6) ≈ 0.95*width - 12
521
- const maxLabelLength = Math.max(40, Math.floor(terminalWidth * 0.95) - 12);
522
- const displayText = `${isCurrent ? '▶' : ' '} ${isSelected ? '[✓]' : '[ ]'} ${truncate(tool.label, maxLabelLength)}`;
523
-
524
- return React.createElement(
525
- Box,
526
- { key: tool.value },
527
- React.createElement(
528
- Text,
529
- {
530
- backgroundColor: isCurrent ? 'blue' : undefined,
531
- color: isCurrent ? 'white' : undefined
532
- },
533
- displayText
534
- )
535
- );
536
- }),
537
- ];
538
- })(),
539
- // Show empty state (if no tools available)
540
- !toolsLoading && !toolsError && tools.length === 0 && React.createElement(
541
- Box,
542
- { justifyContent: 'center', paddingY: 2 },
543
- React.createElement(Text, { dimColor: true }, 'No tools available. Press Enter to continue.')
544
- ),
545
- // Compact status line (selection count + scroll info) - only show if tools are loaded
546
- !toolsLoading && !toolsError && tools.length > 0 && (() => {
547
- const showingFrom = scrollOffset + 1;
548
- const showingTo = Math.min(scrollOffset + MAX_VISIBLE_ITEMS, tools.length);
549
- const hasScrollUp = scrollOffset > 0;
550
- const hasScrollDown = scrollOffset + MAX_VISIBLE_ITEMS < tools.length;
551
-
552
- // Build compact status line
553
- const parts = [];
554
-
555
- // Scroll up indicator
556
- if (hasScrollUp) {
557
- parts.push(`↑${scrollOffset} more`);
558
- }
559
-
560
- // Selection count (always show)
561
- parts.push(`${selectedCount} selected`);
562
-
563
- // Current view range (only if there are more tools than visible)
564
- if (tools.length > MAX_VISIBLE_ITEMS) {
565
- parts.push(`${showingFrom}-${showingTo}/${tools.length}`);
566
- }
567
-
568
- // Scroll down indicator
569
- if (hasScrollDown) {
570
- parts.push(`${tools.length - showingTo} more↓`);
571
- }
572
-
573
- return React.createElement(
574
- Box,
575
- { marginTop: 1, justifyContent: 'center' },
576
- React.createElement(
577
- Text,
578
- { dimColor: true },
579
- parts.join(' • ')
580
- )
581
- );
582
- })()
583
- )
584
- );
585
- }
586
-
587
- if (step === STEPS.SYSTEM_PROMPT) {
588
- return React.createElement(
589
- Box,
590
- { flexDirection: 'column' },
591
- React.createElement(Text, {}, 'System prompt (optional, press Enter to skip):'),
592
- React.createElement(
593
- Box,
594
- { marginTop: 1 },
595
- React.createElement(Text, {}, '> ', inputBuffer, String.fromCharCode(0x2588))
596
- )
597
- );
598
- }
599
-
600
- if (step === STEPS.CONFIRM) {
601
- const selectedCapabilities = formData.capabilities || [];
602
- // Map selected tool names to their labels (or fallback to the name if not found)
603
- const capabilityLabels = selectedCapabilities.map(cap =>
604
- tools.find(t => t.value === cap)?.label || cap
605
- );
606
-
607
- return React.createElement(
608
- Box,
609
- { flexDirection: 'column' },
610
- React.createElement(Text, { bold: true }, 'Confirm agent creation:'),
611
- React.createElement(Box, { marginTop: 1 }, React.createElement(Text, {}, 'Name: ', React.createElement(Text, { color: 'cyan' }, formData.name))),
612
- React.createElement(Box, {}, React.createElement(Text, {}, 'Model: ', React.createElement(Text, { color: 'cyan' }, models.find(m => m.value === formData.model)?.label || formData.model))),
613
- React.createElement(Box, {}, React.createElement(Text, {}, 'Mode: ', React.createElement(Text, { color: 'cyan' }, MODES.find(m => m.value === formData.mode)?.label))),
614
- React.createElement(
615
- Box,
616
- {},
617
- React.createElement(Text, {}, 'Dynamic Routing: ', React.createElement(Text, { color: formData.dynamicModelRouting ? 'green' : 'yellow' }, formData.dynamicModelRouting ? 'Enabled' : 'Disabled'))
618
- ),
619
- formData.dynamicModelRouting && formData.routingStrategy && React.createElement(
620
- Box,
621
- {},
622
- React.createElement(Text, {}, 'Routing Strategy: ', React.createElement(Text, { color: 'cyan', dimColor: true }, formData.routingStrategy.length > 60 ? formData.routingStrategy.slice(0, 57) + '...' : formData.routingStrategy))
623
- ),
624
- React.createElement(
625
- Box,
626
- {},
627
- React.createElement(Text, {}, 'Capabilities: ', React.createElement(
628
- Text,
629
- { color: 'cyan' },
630
- selectedCapabilities.length > 0 ? `${selectedCapabilities.length} selected` : 'None'
631
- ))
632
- ),
633
- selectedCapabilities.length > 0 && React.createElement(
634
- Box,
635
- { flexDirection: 'column', marginLeft: 2, marginTop: 1 },
636
- capabilityLabels.map((label, index) =>
637
- React.createElement(Text, { key: index, dimColor: true }, `• ${label}`)
638
- )
639
- ),
640
- formData.systemPrompt &&
641
- React.createElement(Box, { marginTop: 1 }, React.createElement(Text, {}, 'Prompt: ', React.createElement(Text, { color: 'cyan', dimColor: true }, formData.systemPrompt.substring(0, 40) + '...'))),
642
- React.createElement(
643
- Box,
644
- { marginTop: 1 },
645
- React.createElement(Text, { color: 'green' }, 'Press Enter to create, Esc to cancel')
646
- )
647
- );
648
- }
649
- };
650
-
651
- // Calculate constrained heights to prevent overflow
652
- const dialogMaxHeight = Math.floor(terminalHeight * 0.85) - 2; // Dialog takes max 85% of screen minus 2 rows for breathing room
653
- const contentMaxHeight = dialogMaxHeight - 7; // Leave room for header (3) + footer (4)
654
-
655
- return React.createElement(
656
- Box,
657
- {
658
- flexDirection: 'column',
659
- minHeight: terminalHeight,
660
- maxHeight: terminalHeight,
661
- justifyContent: 'center',
662
- alignItems: 'center',
663
- backgroundColor: 'black',
664
- },
665
- React.createElement(
666
- Box,
667
- {
668
- flexDirection: 'column',
669
- width: '95%',
670
- maxHeight: dialogMaxHeight,
671
- borderStyle: 'round',
672
- borderColor: 'cyan',
673
- backgroundColor: 'black',
674
- paddingX: 2,
675
- paddingY: 1
676
- },
677
- React.createElement(
678
- Box,
679
- { marginBottom: 1 },
680
- React.createElement(Text, { bold: true, color: 'cyan' }, `Create New Agent (Step ${step + 1}/${Object.keys(STEPS).length})`)
681
- ),
682
- renderStep(),
683
- React.createElement(
684
- Box,
685
- { marginTop: 1, borderTop: true, borderStyle: 'single', paddingTop: 1 },
686
- React.createElement(
687
- Text,
688
- { dimColor: true },
689
- // Show appropriate shortcuts for current step
690
- step === STEPS.CONFIRM
691
- ? 'Enter: Create Ctrl+B: Back Esc: Cancel'
692
- : step === STEPS.NAME || step === STEPS.SYSTEM_PROMPT || step === STEPS.ROUTING_STRATEGY
693
- ? 'Enter: Next Esc: Cancel'
694
- : step === STEPS.CAPABILITIES
695
- ? '↑↓: Navigate Space: Toggle Enter: Continue Ctrl+B: Back Esc: Cancel'
696
- : step === STEPS.MODEL || step === STEPS.MODE || step === STEPS.DYNAMIC_ROUTING
697
- ? '↑↓: Navigate Enter: Select Ctrl+B: Back Esc: Cancel'
698
- : 'Esc: Cancel'
699
- )
700
- )
701
- )
702
- );
703
- }
704
-
705
- export default AgentCreator;
1
+ /**
2
+ * AgentCreator Component
3
+ * Multi-step wizard for creating new agents
4
+ */
5
+
6
+ import React, { useState, useEffect } from 'react';
7
+ import { Box, Text, useInput } from 'ink';
8
+
9
+ const STEPS = {
10
+ NAME: 0,
11
+ MODEL: 1,
12
+ MODE: 2,
13
+ DYNAMIC_ROUTING: 3,
14
+ ROUTING_STRATEGY: 4,
15
+ CAPABILITIES: 5,
16
+ SYSTEM_PROMPT: 6,
17
+ CONFIRM: 7,
18
+ };
19
+
20
+ const MODES = [
21
+ { value: 'chat', label: 'Chat Mode', description: 'Interactive conversation' },
22
+ { value: 'auto', label: 'Auto Mode', description: 'Autonomous execution' },
23
+ ];
24
+
25
+ // Tools will be fetched dynamically from API
26
+
27
+ const DYNAMIC_ROUTING_OPTIONS = [
28
+ { value: true, label: 'Yes - Use dynamic routing', description: 'Recommended' },
29
+ { value: false, label: 'No - Use model directly', description: 'Advanced users' },
30
+ ];
31
+
32
+ export function AgentCreator({ sessionManager, onCancel, onCreate, terminalHeight = 24, terminalWidth = 80 }) {
33
+ // terminalHeight and terminalWidth are now passed as props from Layout.js
34
+
35
+ const [step, setStep] = useState(STEPS.NAME);
36
+ const [models, setModels] = useState([]);
37
+ const [modelsLoading, setModelsLoading] = useState(true);
38
+ const [modelsError, setModelsError] = useState(null);
39
+ const [tools, setTools] = useState([]);
40
+ const [toolsLoading, setToolsLoading] = useState(false);
41
+ const [toolsError, setToolsError] = useState(null);
42
+ const [formData, setFormData] = useState({
43
+ name: '',
44
+ model: '',
45
+ mode: MODES[0].value,
46
+ dynamicModelRouting: true, // Default to enabled
47
+ routingStrategy: '',
48
+ capabilities: [], // Array of tool names
49
+ systemPrompt: '',
50
+ });
51
+ const [selectedIndex, setSelectedIndex] = useState(0);
52
+ const [scrollOffset, setScrollOffset] = useState(0);
53
+ const [inputBuffer, setInputBuffer] = useState('');
54
+
55
+ // Calculate max visible items based on terminal height
56
+ // Reserve space for: dialog header (1), dialog borders (3), step title (1),
57
+ // inner borders (2), compact status line (1), shortcuts (3), margins (2) = 13 lines
58
+ // Reduced from 16 to 13 by removing scroll indicators, bordered footer, and redundant instructions
59
+ const RESERVED_LINES = 13;
60
+ const MAX_VISIBLE_ITEMS = Math.max(3, Math.min(15, terminalHeight - RESERVED_LINES));
61
+ const MAX_VISIBLE_MODELS = Math.max(5, Math.min(8, terminalHeight - 14)); // For model selection
62
+
63
+ // Fetch available models from API
64
+ useEffect(() => {
65
+ async function fetchModels() {
66
+ try {
67
+ setModelsLoading(true);
68
+ const data = await sessionManager.makeRequest('GET', '/api/llm/models');
69
+
70
+ // Map API response to UI format
71
+ const mappedModels = data.models.map(model => ({
72
+ value: model.name,
73
+ label: formatModelLabel(model),
74
+ description: formatModelDescription(model),
75
+ }));
76
+
77
+ setModels(mappedModels);
78
+
79
+ // Set default model
80
+ if (mappedModels.length > 0) {
81
+ setFormData(prev => ({ ...prev, model: mappedModels[0].value }));
82
+ }
83
+
84
+ setModelsLoading(false);
85
+ } catch (error) {
86
+ console.error('Error fetching models:', error);
87
+ setModelsError(error.message);
88
+ setModelsLoading(false);
89
+ }
90
+ }
91
+
92
+ if (sessionManager) {
93
+ fetchModels();
94
+ }
95
+ }, [sessionManager]);
96
+
97
+ // Fetch available tools from API when CAPABILITIES step is reached
98
+ useEffect(() => {
99
+ async function fetchTools() {
100
+ if (step !== STEPS.CAPABILITIES) return;
101
+
102
+ try {
103
+ setToolsLoading(true);
104
+ setToolsError(null);
105
+ const data = await sessionManager.makeRequest('GET', '/api/tools');
106
+
107
+ if (data.success && data.tools) {
108
+ // Map API response to UI format
109
+ const mappedTools = data.tools.map(tool => ({
110
+ value: tool.name,
111
+ label: tool.name,
112
+ description: tool.description || 'No description available',
113
+ }));
114
+
115
+ setTools(mappedTools);
116
+ } else {
117
+ throw new Error(data.error || 'Failed to fetch tools');
118
+ }
119
+
120
+ setToolsLoading(false);
121
+ } catch (error) {
122
+ console.error('Error fetching tools:', error);
123
+ setToolsError(error.message);
124
+ setToolsLoading(false);
125
+ // Set empty tools array as fallback
126
+ setTools([]);
127
+ }
128
+ }
129
+
130
+ if (sessionManager && step === STEPS.CAPABILITIES) {
131
+ fetchTools();
132
+ }
133
+ }, [sessionManager, step]);
134
+
135
+ // Helper function to format model names for display
136
+ function formatModelLabel(model) {
137
+ // Use displayName from API if available
138
+ if (model.displayName) {
139
+ return model.displayName;
140
+ }
141
+
142
+ // Otherwise, format the name field programmatically
143
+ // Convert "anthropic-sonnet" to "Anthropic Sonnet"
144
+ const name = model.name || '';
145
+ return name
146
+ .split('-')
147
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
148
+ .join(' ');
149
+ }
150
+
151
+ // Helper function to truncate text with ellipsis
152
+ function truncate(text, maxLength) {
153
+ if (text.length <= maxLength) return text;
154
+ return text.substring(0, maxLength - 3) + '...';
155
+ }
156
+
157
+ // Helper function to format model descriptions from API data
158
+ function formatModelDescription(model) {
159
+ // Use API data for description
160
+ const parts = [];
161
+
162
+ if (model.category) {
163
+ parts.push(model.category);
164
+ }
165
+
166
+ if (model.maxTokens) {
167
+ parts.push(`${(model.maxTokens / 1000).toFixed(0)}K tokens`);
168
+ }
169
+
170
+ if (model.pricing?.input) {
171
+ parts.push(`$${model.pricing.input}/1K`);
172
+ }
173
+
174
+ if (model.supportsVision) {
175
+ parts.push('vision');
176
+ }
177
+
178
+ const description = parts.length > 0 ? parts.join(', ') : model.type || 'LLM';
179
+
180
+ // Truncate to max 50 characters to prevent wrapping
181
+ return truncate(description, 50);
182
+ }
183
+
184
+ useInput((char, key) => {
185
+ // Cancel on Escape
186
+ if (key.escape) {
187
+ // Defer callback to avoid setState during render
188
+ setTimeout(() => onCancel(), 0);
189
+ return;
190
+ }
191
+
192
+ // Back on Ctrl+B
193
+ if (key.ctrl && char === 'b' && step > STEPS.NAME) {
194
+ // Skip routing strategy step if dynamic routing is disabled
195
+ const prevStep = (step === STEPS.CAPABILITIES && !formData.dynamicModelRouting)
196
+ ? STEPS.DYNAMIC_ROUTING
197
+ : step - 1;
198
+ setStep(prevStep);
199
+ return;
200
+ }
201
+
202
+ // Handle based on current step
203
+ if (step === STEPS.NAME || step === STEPS.SYSTEM_PROMPT || step === STEPS.ROUTING_STRATEGY) {
204
+ // Text input steps
205
+ if (key.return) {
206
+ if (step === STEPS.NAME && inputBuffer.trim()) {
207
+ setFormData({ ...formData, name: inputBuffer.trim() });
208
+ setInputBuffer('');
209
+ setStep(STEPS.MODEL);
210
+ } else if (step === STEPS.ROUTING_STRATEGY) {
211
+ setFormData({ ...formData, routingStrategy: inputBuffer.trim() });
212
+ setInputBuffer('');
213
+ setStep(STEPS.CAPABILITIES);
214
+ } else if (step === STEPS.SYSTEM_PROMPT) {
215
+ setFormData({ ...formData, systemPrompt: inputBuffer.trim() });
216
+ setInputBuffer('');
217
+ setStep(STEPS.CONFIRM);
218
+ }
219
+ } else if (key.backspace || key.delete) {
220
+ setInputBuffer(prev => prev.slice(0, -1));
221
+ } else if (char && !key.ctrl && !key.meta) {
222
+ setInputBuffer(prev => prev + char);
223
+ }
224
+ } else if (step === STEPS.MODEL || step === STEPS.MODE || step === STEPS.DYNAMIC_ROUTING) {
225
+ // Selection steps (single-select)
226
+ const options = step === STEPS.MODEL ? models : (step === STEPS.MODE ? MODES : DYNAMIC_ROUTING_OPTIONS);
227
+
228
+ if (key.upArrow) {
229
+ setSelectedIndex(prev => {
230
+ const newIndex = Math.max(0, prev - 1);
231
+ // Scroll up if needed (for MODEL step only)
232
+ if (step === STEPS.MODEL && newIndex < scrollOffset) {
233
+ setScrollOffset(newIndex);
234
+ }
235
+ return newIndex;
236
+ });
237
+ } else if (key.downArrow) {
238
+ setSelectedIndex(prev => {
239
+ const newIndex = Math.min(options.length - 1, prev + 1);
240
+ // Scroll down if needed (for MODEL step only)
241
+ if (step === STEPS.MODEL && newIndex >= scrollOffset + MAX_VISIBLE_MODELS) {
242
+ setScrollOffset(newIndex - MAX_VISIBLE_MODELS + 1);
243
+ }
244
+ return newIndex;
245
+ });
246
+ } else if (key.return) {
247
+ if (step === STEPS.MODEL) {
248
+ setFormData({ ...formData, model: models[selectedIndex].value });
249
+ setSelectedIndex(0);
250
+ setScrollOffset(0);
251
+ setStep(STEPS.MODE);
252
+ } else if (step === STEPS.MODE) {
253
+ setFormData({ ...formData, mode: MODES[selectedIndex].value });
254
+ setSelectedIndex(0);
255
+ setStep(STEPS.DYNAMIC_ROUTING);
256
+ } else if (step === STEPS.DYNAMIC_ROUTING) {
257
+ const routingEnabled = DYNAMIC_ROUTING_OPTIONS[selectedIndex].value;
258
+ setFormData({ ...formData, dynamicModelRouting: routingEnabled });
259
+ setSelectedIndex(0);
260
+ setInputBuffer('');
261
+ // Skip strategy step if routing is disabled
262
+ setStep(routingEnabled ? STEPS.ROUTING_STRATEGY : STEPS.CAPABILITIES);
263
+ }
264
+ }
265
+ } else if (step === STEPS.CAPABILITIES) {
266
+ // Multi-select step for capabilities (tools) with scrolling
267
+ if (key.upArrow) {
268
+ setSelectedIndex(prev => {
269
+ const newIndex = Math.max(0, prev - 1);
270
+ // Adjust scroll offset to keep selected item visible
271
+ setScrollOffset(currentOffset => {
272
+ if (newIndex < currentOffset) {
273
+ return newIndex; // Scroll up to show item
274
+ }
275
+ return currentOffset;
276
+ });
277
+ return newIndex;
278
+ });
279
+ } else if (key.downArrow) {
280
+ setSelectedIndex(prev => {
281
+ const newIndex = Math.min(tools.length - 1, prev + 1);
282
+ // Adjust scroll offset to keep selected item visible
283
+ setScrollOffset(currentOffset => {
284
+ if (newIndex >= currentOffset + MAX_VISIBLE_ITEMS) {
285
+ return newIndex - MAX_VISIBLE_ITEMS + 1; // Scroll down to show item
286
+ }
287
+ return currentOffset;
288
+ });
289
+ return newIndex;
290
+ });
291
+ } else if (char === ' ' || key.space) {
292
+ // Toggle selection
293
+ if (tools.length > 0 && tools[selectedIndex]) {
294
+ const toolName = tools[selectedIndex].value;
295
+ setFormData(prev => {
296
+ const capabilities = prev.capabilities || [];
297
+ const isSelected = capabilities.includes(toolName);
298
+ return {
299
+ ...prev,
300
+ capabilities: isSelected
301
+ ? capabilities.filter(c => c !== toolName)
302
+ : [...capabilities, toolName]
303
+ };
304
+ });
305
+ }
306
+ } else if (key.return) {
307
+ // Continue to next step
308
+ setSelectedIndex(0);
309
+ setScrollOffset(0); // Reset scroll
310
+ setStep(STEPS.SYSTEM_PROMPT);
311
+ }
312
+ } else if (step === STEPS.CONFIRM) {
313
+ // Confirmation step
314
+ if (key.return) {
315
+ // Defer callback to avoid setState during render
316
+ setTimeout(() => {
317
+ onCreate(formData);
318
+ }, 0);
319
+ return;
320
+ }
321
+ }
322
+ });
323
+
324
+ const renderStep = () => {
325
+ if (step === STEPS.NAME) {
326
+ return React.createElement(
327
+ Box,
328
+ { flexDirection: 'column' },
329
+ React.createElement(Text, {}, 'Enter agent name:'),
330
+ React.createElement(
331
+ Box,
332
+ { marginTop: 1 },
333
+ React.createElement(Text, {}, '> ', inputBuffer, String.fromCharCode(0x2588))
334
+ )
335
+ );
336
+ }
337
+
338
+ if (step === STEPS.MODEL) {
339
+ return React.createElement(
340
+ Box,
341
+ { flexDirection: 'column', alignItems: 'center' },
342
+ React.createElement(Text, {}, 'Select model:'),
343
+ React.createElement(
344
+ Box,
345
+ { flexDirection: 'column', marginTop: 1, alignItems: 'center', width: '100%' },
346
+ modelsLoading
347
+ ? React.createElement(Text, { dimColor: true }, 'Loading models from server...')
348
+ : modelsError
349
+ ? React.createElement(
350
+ Box,
351
+ { flexDirection: 'column', alignItems: 'center' },
352
+ React.createElement(Text, { color: 'red' }, 'Failed to load models:'),
353
+ React.createElement(Text, { dimColor: true }, modelsError),
354
+ React.createElement(Text, { dimColor: true, marginTop: 1 }, 'Press Esc to cancel')
355
+ )
356
+ : models.length === 0
357
+ ? React.createElement(Text, { dimColor: true }, 'No models available')
358
+ : React.createElement(
359
+ Box,
360
+ { flexDirection: 'column', alignItems: 'center' },
361
+ // Visible models (with scroll window)
362
+ models.slice(scrollOffset, scrollOffset + MAX_VISIBLE_MODELS).map((model, visibleIndex) => {
363
+ const actualIndex = scrollOffset + visibleIndex;
364
+ const isSelected = actualIndex === selectedIndex;
365
+
366
+ return React.createElement(
367
+ Box,
368
+ { key: model.value },
369
+ React.createElement(
370
+ Text,
371
+ { backgroundColor: isSelected ? 'blue' : undefined, color: isSelected ? 'white' : undefined },
372
+ isSelected ? '> ' : ' ',
373
+ model.label,
374
+ React.createElement(Text, { dimColor: true }, ` - ${model.description}`)
375
+ )
376
+ );
377
+ }),
378
+ // Scroll indicator
379
+ models.length > MAX_VISIBLE_MODELS &&
380
+ React.createElement(
381
+ Box,
382
+ { marginTop: 1 },
383
+ React.createElement(
384
+ Text,
385
+ { dimColor: true },
386
+ `Showing ${scrollOffset + 1}-${Math.min(scrollOffset + MAX_VISIBLE_MODELS, models.length)} of ${models.length}`
387
+ )
388
+ )
389
+ )
390
+ )
391
+ );
392
+ }
393
+
394
+ if (step === STEPS.MODE) {
395
+ return React.createElement(
396
+ Box,
397
+ { flexDirection: 'column', alignItems: 'center' },
398
+ React.createElement(Text, {}, 'Select mode:'),
399
+ React.createElement(
400
+ Box,
401
+ { flexDirection: 'column', marginTop: 1, alignItems: 'center' },
402
+ MODES.map((mode, index) =>
403
+ React.createElement(
404
+ Box,
405
+ { key: mode.value },
406
+ React.createElement(
407
+ Text,
408
+ { backgroundColor: index === selectedIndex ? 'blue' : undefined, color: index === selectedIndex ? 'white' : undefined },
409
+ index === selectedIndex ? '> ' : ' ',
410
+ mode.label,
411
+ React.createElement(Text, { dimColor: true }, ` - ${mode.description}`)
412
+ )
413
+ )
414
+ )
415
+ )
416
+ );
417
+ }
418
+
419
+ if (step === STEPS.DYNAMIC_ROUTING) {
420
+ return React.createElement(
421
+ Box,
422
+ { flexDirection: 'column', alignItems: 'center', width: '80%' },
423
+ React.createElement(Text, { bold: true }, 'Dynamic Model Routing'),
424
+ React.createElement(
425
+ Box,
426
+ { flexDirection: 'column', marginTop: 1, alignItems: 'center', borderStyle: 'single', borderColor: 'cyan', paddingX: 2, paddingY: 1, width: '100%' },
427
+ React.createElement(Text, { dimColor: true, textAlign: 'center' }, 'Enable automatic API provider selection based on session context'),
428
+ React.createElement(
429
+ Box,
430
+ { flexDirection: 'column', marginTop: 1, width: '100%' },
431
+ DYNAMIC_ROUTING_OPTIONS.map((option, index) =>
432
+ React.createElement(
433
+ Box,
434
+ { key: String(option.value), marginTop: index > 0 ? 1 : 0 },
435
+ React.createElement(
436
+ Text,
437
+ { backgroundColor: index === selectedIndex ? 'blue' : undefined, color: index === selectedIndex ? 'white' : undefined },
438
+ index === selectedIndex ? '● ' : ' ',
439
+ option.label,
440
+ React.createElement(Text, { dimColor: true }, ` (${option.description})`)
441
+ )
442
+ )
443
+ )
444
+ )
445
+ )
446
+ );
447
+ }
448
+
449
+ if (step === STEPS.ROUTING_STRATEGY) {
450
+ return React.createElement(
451
+ Box,
452
+ { flexDirection: 'column', alignItems: 'center', width: '80%' },
453
+ React.createElement(Text, { bold: true }, 'Routing Strategy (Optional)'),
454
+ React.createElement(
455
+ Box,
456
+ { flexDirection: 'column', marginTop: 1, borderStyle: 'single', borderColor: 'cyan', paddingX: 2, paddingY: 1, width: '100%' },
457
+ React.createElement(Text, { dimColor: true }, 'Custom instructions for model selection. Press Enter to skip.'),
458
+ React.createElement(Text, { dimColor: true, italic: true }, 'e.g. Prefer fast models for short questions. Use Claude for code.'),
459
+ React.createElement(
460
+ Box,
461
+ { marginTop: 1 },
462
+ React.createElement(Text, { color: 'cyan' }, '> '),
463
+ React.createElement(Text, null, inputBuffer || '')
464
+ )
465
+ )
466
+ );
467
+ }
468
+
469
+ if (step === STEPS.CAPABILITIES) {
470
+ const selectedCapabilities = formData.capabilities || [];
471
+ const selectedCount = selectedCapabilities.length;
472
+
473
+ return React.createElement(
474
+ Box,
475
+ { flexDirection: 'column', alignItems: 'center', width: '100%', maxHeight: contentMaxHeight },
476
+ React.createElement(Text, { bold: true }, 'Select Capabilities (Tools)'),
477
+ React.createElement(
478
+ Box,
479
+ { flexDirection: 'column', marginTop: 1, borderStyle: 'single', borderColor: 'cyan', paddingX: 2, paddingY: 1, width: '100%', maxHeight: contentMaxHeight - 6 },
480
+ // Show loading state
481
+ toolsLoading && React.createElement(
482
+ Box,
483
+ { justifyContent: 'center', paddingY: 2 },
484
+ React.createElement(Text, { color: 'yellow' }, '⏳ Loading available tools from API...')
485
+ ),
486
+ // Show error state
487
+ toolsError && React.createElement(
488
+ Box,
489
+ { flexDirection: 'column', paddingY: 1 },
490
+ React.createElement(Text, { color: 'red' }, ' Error loading tools: ', toolsError),
491
+ React.createElement(Text, { dimColor: true, marginTop: 1 }, 'Press Enter to continue without tools')
492
+ ),
493
+ // Show tools list (if loaded successfully) - with scrolling viewport
494
+ !toolsLoading && !toolsError && tools.length > 0 && (() => {
495
+ // Calculate visible slice of tools
496
+ const visibleTools = tools.slice(scrollOffset, scrollOffset + MAX_VISIBLE_ITEMS);
497
+
498
+ return [
499
+ // Visible tools
500
+ ...visibleTools.map((tool, visibleIndex) => {
501
+ const actualIndex = scrollOffset + visibleIndex;
502
+ const isSelected = selectedCapabilities.includes(tool.value);
503
+ const isCurrent = actualIndex === selectedIndex;
504
+
505
+ // Create compact display: checkbox + label only, truncated to fit terminal
506
+ // Available width = 95% of terminal - borders(2) - padding(4) - checkbox(6) ≈ 0.95*width - 12
507
+ const maxLabelLength = Math.max(40, Math.floor(terminalWidth * 0.95) - 12);
508
+ const displayText = `${isCurrent ? '▶' : ' '} ${isSelected ? '[✓]' : '[ ]'} ${truncate(tool.label, maxLabelLength)}`;
509
+
510
+ return React.createElement(
511
+ Box,
512
+ { key: tool.value },
513
+ React.createElement(
514
+ Text,
515
+ {
516
+ backgroundColor: isCurrent ? 'blue' : undefined,
517
+ color: isCurrent ? 'white' : undefined
518
+ },
519
+ displayText
520
+ )
521
+ );
522
+ }),
523
+ ];
524
+ })(),
525
+ // Show empty state (if no tools available)
526
+ !toolsLoading && !toolsError && tools.length === 0 && React.createElement(
527
+ Box,
528
+ { justifyContent: 'center', paddingY: 2 },
529
+ React.createElement(Text, { dimColor: true }, 'No tools available. Press Enter to continue.')
530
+ ),
531
+ // Compact status line (selection count + scroll info) - only show if tools are loaded
532
+ !toolsLoading && !toolsError && tools.length > 0 && (() => {
533
+ const showingFrom = scrollOffset + 1;
534
+ const showingTo = Math.min(scrollOffset + MAX_VISIBLE_ITEMS, tools.length);
535
+ const hasScrollUp = scrollOffset > 0;
536
+ const hasScrollDown = scrollOffset + MAX_VISIBLE_ITEMS < tools.length;
537
+
538
+ // Build compact status line
539
+ const parts = [];
540
+
541
+ // Scroll up indicator
542
+ if (hasScrollUp) {
543
+ parts.push(`↑${scrollOffset} more`);
544
+ }
545
+
546
+ // Selection count (always show)
547
+ parts.push(`${selectedCount} selected`);
548
+
549
+ // Current view range (only if there are more tools than visible)
550
+ if (tools.length > MAX_VISIBLE_ITEMS) {
551
+ parts.push(`${showingFrom}-${showingTo}/${tools.length}`);
552
+ }
553
+
554
+ // Scroll down indicator
555
+ if (hasScrollDown) {
556
+ parts.push(`${tools.length - showingTo} more↓`);
557
+ }
558
+
559
+ return React.createElement(
560
+ Box,
561
+ { marginTop: 1, justifyContent: 'center' },
562
+ React.createElement(
563
+ Text,
564
+ { dimColor: true },
565
+ parts.join(' • ')
566
+ )
567
+ );
568
+ })()
569
+ )
570
+ );
571
+ }
572
+
573
+ if (step === STEPS.SYSTEM_PROMPT) {
574
+ return React.createElement(
575
+ Box,
576
+ { flexDirection: 'column' },
577
+ React.createElement(Text, {}, 'System prompt (optional, press Enter to skip):'),
578
+ React.createElement(
579
+ Box,
580
+ { marginTop: 1 },
581
+ React.createElement(Text, {}, '> ', inputBuffer, String.fromCharCode(0x2588))
582
+ )
583
+ );
584
+ }
585
+
586
+ if (step === STEPS.CONFIRM) {
587
+ const selectedCapabilities = formData.capabilities || [];
588
+ // Map selected tool names to their labels (or fallback to the name if not found)
589
+ const capabilityLabels = selectedCapabilities.map(cap =>
590
+ tools.find(t => t.value === cap)?.label || cap
591
+ );
592
+
593
+ return React.createElement(
594
+ Box,
595
+ { flexDirection: 'column' },
596
+ React.createElement(Text, { bold: true }, 'Confirm agent creation:'),
597
+ React.createElement(Box, { marginTop: 1 }, React.createElement(Text, {}, 'Name: ', React.createElement(Text, { color: 'cyan' }, formData.name))),
598
+ React.createElement(Box, {}, React.createElement(Text, {}, 'Model: ', React.createElement(Text, { color: 'cyan' }, models.find(m => m.value === formData.model)?.label || formData.model))),
599
+ React.createElement(Box, {}, React.createElement(Text, {}, 'Mode: ', React.createElement(Text, { color: 'cyan' }, MODES.find(m => m.value === formData.mode)?.label))),
600
+ React.createElement(
601
+ Box,
602
+ {},
603
+ React.createElement(Text, {}, 'Dynamic Routing: ', React.createElement(Text, { color: formData.dynamicModelRouting ? 'green' : 'yellow' }, formData.dynamicModelRouting ? 'Enabled' : 'Disabled'))
604
+ ),
605
+ formData.dynamicModelRouting && formData.routingStrategy && React.createElement(
606
+ Box,
607
+ {},
608
+ React.createElement(Text, {}, 'Routing Strategy: ', React.createElement(Text, { color: 'cyan', dimColor: true }, formData.routingStrategy.length > 60 ? formData.routingStrategy.slice(0, 57) + '...' : formData.routingStrategy))
609
+ ),
610
+ React.createElement(
611
+ Box,
612
+ {},
613
+ React.createElement(Text, {}, 'Capabilities: ', React.createElement(
614
+ Text,
615
+ { color: 'cyan' },
616
+ selectedCapabilities.length > 0 ? `${selectedCapabilities.length} selected` : 'None'
617
+ ))
618
+ ),
619
+ selectedCapabilities.length > 0 && React.createElement(
620
+ Box,
621
+ { flexDirection: 'column', marginLeft: 2, marginTop: 1 },
622
+ capabilityLabels.map((label, index) =>
623
+ React.createElement(Text, { key: index, dimColor: true }, `• ${label}`)
624
+ )
625
+ ),
626
+ formData.systemPrompt &&
627
+ React.createElement(Box, { marginTop: 1 }, React.createElement(Text, {}, 'Prompt: ', React.createElement(Text, { color: 'cyan', dimColor: true }, formData.systemPrompt.substring(0, 40) + '...'))),
628
+ React.createElement(
629
+ Box,
630
+ { marginTop: 1 },
631
+ React.createElement(Text, { color: 'green' }, 'Press Enter to create, Esc to cancel')
632
+ )
633
+ );
634
+ }
635
+ };
636
+
637
+ // Calculate constrained heights to prevent overflow
638
+ const dialogMaxHeight = Math.floor(terminalHeight * 0.85) - 2; // Dialog takes max 85% of screen minus 2 rows for breathing room
639
+ const contentMaxHeight = dialogMaxHeight - 7; // Leave room for header (3) + footer (4)
640
+
641
+ return React.createElement(
642
+ Box,
643
+ {
644
+ flexDirection: 'column',
645
+ minHeight: terminalHeight,
646
+ maxHeight: terminalHeight,
647
+ justifyContent: 'center',
648
+ alignItems: 'center',
649
+ backgroundColor: 'black',
650
+ },
651
+ React.createElement(
652
+ Box,
653
+ {
654
+ flexDirection: 'column',
655
+ width: '95%',
656
+ maxHeight: dialogMaxHeight,
657
+ borderStyle: 'round',
658
+ borderColor: 'cyan',
659
+ backgroundColor: 'black',
660
+ paddingX: 2,
661
+ paddingY: 1
662
+ },
663
+ React.createElement(
664
+ Box,
665
+ { marginBottom: 1 },
666
+ React.createElement(Text, { bold: true, color: 'cyan' }, `Create New Agent (Step ${step + 1}/${Object.keys(STEPS).length})`)
667
+ ),
668
+ renderStep(),
669
+ React.createElement(
670
+ Box,
671
+ { marginTop: 1, borderTop: true, borderStyle: 'single', paddingTop: 1 },
672
+ React.createElement(
673
+ Text,
674
+ { dimColor: true },
675
+ // Show appropriate shortcuts for current step
676
+ step === STEPS.CONFIRM
677
+ ? 'Enter: Create Ctrl+B: Back Esc: Cancel'
678
+ : step === STEPS.NAME || step === STEPS.SYSTEM_PROMPT || step === STEPS.ROUTING_STRATEGY
679
+ ? 'Enter: Next Esc: Cancel'
680
+ : step === STEPS.CAPABILITIES
681
+ ? '↑↓: Navigate Space: Toggle Enter: Continue Ctrl+B: Back Esc: Cancel'
682
+ : step === STEPS.MODEL || step === STEPS.MODE || step === STEPS.DYNAMIC_ROUTING
683
+ ? '↑↓: Navigate Enter: Select Ctrl+B: Back Esc: Cancel'
684
+ : 'Esc: Cancel'
685
+ )
686
+ )
687
+ )
688
+ );
689
+ }
690
+
691
+ export default AgentCreator;