onbuzz 3.4.0 → 3.6.2

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 (562) hide show
  1. package/package.json +1 -1
  2. package/scripts/bump-version.js +116 -0
  3. package/src/__test-utils__/fixtures/malformedJson.js +31 -0
  4. package/src/__test-utils__/globalSetup.js +9 -0
  5. package/src/__test-utils__/globalTeardown.js +12 -0
  6. package/src/__test-utils__/mockFactories.js +101 -0
  7. package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -0
  8. package/src/analyzers/__tests__/ConfigValidator.test.js +362 -0
  9. package/src/analyzers/__tests__/ESLintAnalyzer.test.js +271 -0
  10. package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -0
  11. package/src/analyzers/__tests__/PrettierFormatter.test.js +197 -0
  12. package/src/analyzers/__tests__/PythonAnalyzer.test.js +208 -0
  13. package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -0
  14. package/src/analyzers/__tests__/SparrowAnalyzer.test.js +270 -0
  15. package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -0
  16. package/src/core/__tests__/agentPool.test.js +601 -0
  17. package/src/core/__tests__/agentScheduler.test.js +576 -0
  18. package/src/core/__tests__/contextManager.test.js +252 -0
  19. package/src/core/__tests__/flowExecutor.test.js +262 -0
  20. package/src/core/__tests__/messageProcessor.test.js +627 -0
  21. package/src/core/__tests__/orchestrator.test.js +257 -0
  22. package/src/core/__tests__/stateManager.test.js +375 -0
  23. package/src/core/agentPool.js +26 -4
  24. package/src/core/agentScheduler.js +79 -21
  25. package/src/core/messageProcessor.js +110 -2
  26. package/src/index.js +27 -11
  27. package/src/interfaces/__tests__/imageServing.test.js +228 -0
  28. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +3 -5
  29. package/src/interfaces/webServer.js +97 -13
  30. package/src/services/__tests__/agentActivityService.test.js +319 -0
  31. package/src/services/__tests__/apiKeyManager.test.js +206 -0
  32. package/src/services/__tests__/benchmarkService.test.js +184 -0
  33. package/src/services/__tests__/budgetService.test.js +211 -0
  34. package/src/services/__tests__/contextInjectionService.test.js +205 -0
  35. package/src/services/__tests__/conversationCompactionService.test.js +280 -0
  36. package/src/services/__tests__/credentialVault.test.js +469 -0
  37. package/src/services/__tests__/errorHandler.test.js +314 -0
  38. package/src/services/__tests__/fileAttachmentService.test.js +278 -0
  39. package/src/services/__tests__/flowContextService.test.js +199 -0
  40. package/src/services/__tests__/memoryService.test.js +450 -0
  41. package/src/services/__tests__/modelRouterService.test.js +388 -0
  42. package/src/services/__tests__/modelsService.test.js +261 -0
  43. package/src/services/__tests__/portRegistry.test.js +123 -0
  44. package/src/services/__tests__/projectDetector.test.js +34 -0
  45. package/src/services/__tests__/promptService.test.js +242 -0
  46. package/src/services/__tests__/qualityInspector.test.js +97 -0
  47. package/src/services/__tests__/scheduleService.test.js +308 -0
  48. package/src/services/__tests__/serviceRegistry.test.js +74 -0
  49. package/src/services/__tests__/skillsService.test.js +402 -0
  50. package/src/services/__tests__/tokenCountingService.test.js +48 -0
  51. package/src/services/conversationCompactionService.js +2 -2
  52. package/src/services/visualEditorServer.js +26 -7
  53. package/src/tools/__tests__/agentCommunicationTool.test.js +500 -0
  54. package/src/tools/__tests__/agentDelayTool.test.js +342 -0
  55. package/src/tools/__tests__/asyncToolManager.test.js +344 -0
  56. package/src/tools/__tests__/baseTool.test.js +420 -0
  57. package/src/tools/__tests__/codeMapTool.test.js +348 -0
  58. package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -0
  59. package/src/tools/__tests__/fileTreeTool.test.js +274 -0
  60. package/src/tools/__tests__/filesystemTool.test.js +717 -0
  61. package/src/tools/__tests__/helpTool.test.js +204 -0
  62. package/src/tools/__tests__/jobDoneTool.test.js +296 -0
  63. package/src/tools/__tests__/memoryTool.test.js +297 -0
  64. package/src/tools/__tests__/seekTool.test.js +282 -0
  65. package/src/tools/__tests__/skillsTool.test.js +226 -0
  66. package/src/tools/__tests__/staticAnalysisTool.test.js +509 -0
  67. package/src/tools/__tests__/taskManagerTool.test.js +725 -0
  68. package/src/tools/__tests__/terminalTool.test.js +384 -0
  69. package/src/tools/__tests__/userPromptTool.test.js +297 -0
  70. package/src/tools/__tests__/webTool.e2e.test.js +25 -11
  71. package/src/tools/imageTool.js +41 -5
  72. package/src/tools/webTool.js +161 -48
  73. package/src/types/__tests__/agent.test.js +499 -0
  74. package/src/types/__tests__/contextReference.test.js +606 -0
  75. package/src/types/__tests__/conversation.test.js +555 -0
  76. package/src/types/__tests__/toolCommand.test.js +584 -0
  77. package/src/types/contextReference.js +1 -1
  78. package/src/utilities/__tests__/attachmentValidator.test.js +80 -0
  79. package/src/utilities/__tests__/configManager.test.js +397 -0
  80. package/src/utilities/__tests__/constants.test.js +49 -0
  81. package/src/utilities/__tests__/directoryAccessManager.test.js +388 -0
  82. package/src/utilities/__tests__/fileProcessor.test.js +104 -0
  83. package/src/utilities/__tests__/jsonRepair.test.js +104 -0
  84. package/src/utilities/__tests__/logger.test.js +129 -0
  85. package/src/utilities/__tests__/platformUtils.test.js +87 -0
  86. package/src/utilities/__tests__/structuredFileValidator.test.js +263 -0
  87. package/src/utilities/__tests__/tagParser.test.js +887 -0
  88. package/src/utilities/__tests__/toolConstants.test.js +94 -0
  89. package/src/utilities/tagParser.js +2 -2
  90. package/web-ui/build/index.html +2 -2
  91. package/web-ui/build/static/1c-8PZzOTzp.js +1 -0
  92. package/web-ui/build/static/abap-Bcx_Au1F.js +1 -0
  93. package/web-ui/build/static/abnf-BKTLqpWA.js +1 -0
  94. package/web-ui/build/static/abnf-J05BAvJt.js +1 -0
  95. package/web-ui/build/static/accesslog-Cp8_lqVY.js +1 -0
  96. package/web-ui/build/static/actionscript-BK0UaMrm.js +1 -0
  97. package/web-ui/build/static/actionscript-CyqZUddh.js +1 -0
  98. package/web-ui/build/static/ada-BNirS6Nr.js +1 -0
  99. package/web-ui/build/static/ada-BSFWcT1O.js +1 -0
  100. package/web-ui/build/static/agda-D0NJDJg7.js +1 -0
  101. package/web-ui/build/static/al-rWARKtwb.js +1 -0
  102. package/web-ui/build/static/angelscript-fCehtOYk.js +1 -0
  103. package/web-ui/build/static/antlr4-Dn9jrnZN.js +1 -0
  104. package/web-ui/build/static/apache-DaQCsvNW.js +1 -0
  105. package/web-ui/build/static/apacheconf-dY4i0Xvz.js +1 -0
  106. package/web-ui/build/static/apex-vhS4SI46.js +1 -0
  107. package/web-ui/build/static/apl-CKRkxH90.js +1 -0
  108. package/web-ui/build/static/applescript-CWmpQIEB.js +1 -0
  109. package/web-ui/build/static/applescript-DBaX7Uqo.js +1 -0
  110. package/web-ui/build/static/aql-8s41lrIa.js +1 -0
  111. package/web-ui/build/static/arcade-w2_RhAcq.js +1 -0
  112. package/web-ui/build/static/arduino-I7BtZTu6.js +1 -0
  113. package/web-ui/build/static/arduino-h2LZErKQ.js +1 -0
  114. package/web-ui/build/static/arff-C543-5a1.js +1 -0
  115. package/web-ui/build/static/armasm-DyZdFOzz.js +1 -0
  116. package/web-ui/build/static/asciidoc-ZzENlACu.js +1 -0
  117. package/web-ui/build/static/asciidoc-_j9x9bUz.js +1 -0
  118. package/web-ui/build/static/asm6502-CsNsmBfq.js +1 -0
  119. package/web-ui/build/static/asmatmel-CkIVf_tD.js +1 -0
  120. package/web-ui/build/static/aspectj-C6AQLme_.js +1 -0
  121. package/web-ui/build/static/aspnet-5AkdiVyL.js +1 -0
  122. package/web-ui/build/static/autohotkey-BRZVABiS.js +1 -0
  123. package/web-ui/build/static/autohotkey-DVTmfk_f.js +1 -0
  124. package/web-ui/build/static/autoit-3UEcWu5a.js +1 -0
  125. package/web-ui/build/static/autoit-BDByIKSH.js +1 -0
  126. package/web-ui/build/static/avisynth-BHc4uUkP.js +1 -0
  127. package/web-ui/build/static/avrasm-BAPq8_aI.js +1 -0
  128. package/web-ui/build/static/avro-idl-BKEBYUtv.js +1 -0
  129. package/web-ui/build/static/awk-CBCkArRT.js +1 -0
  130. package/web-ui/build/static/axapta-DlOgnXSZ.js +1 -0
  131. package/web-ui/build/static/bash-C6Brp5OE.js +1 -0
  132. package/web-ui/build/static/bash-DkEO7JRq.js +1 -0
  133. package/web-ui/build/static/basic-DG6TYB0R.js +1 -0
  134. package/web-ui/build/static/basic-DRPcNfAn.js +1 -0
  135. package/web-ui/build/static/batch-DdjZ5KC1.js +1 -0
  136. package/web-ui/build/static/bbcode-DCXEEs2w.js +1 -0
  137. package/web-ui/build/static/bicep-CpLhfOwt.js +1 -0
  138. package/web-ui/build/static/birb-DNWkqgQm.js +1 -0
  139. package/web-ui/build/static/bison-DwxbQHJ9.js +1 -0
  140. package/web-ui/build/static/bnf-Cgnt7npj.js +1 -0
  141. package/web-ui/build/static/bnf-DSTq_eu9.js +1 -0
  142. package/web-ui/build/static/brainfuck-Bi8mGutW.js +1 -0
  143. package/web-ui/build/static/brainfuck-DOWfqVtR.js +1 -0
  144. package/web-ui/build/static/brightscript-D95pbP-v.js +1 -0
  145. package/web-ui/build/static/bro-BrDVwXeg.js +1 -0
  146. package/web-ui/build/static/bsl-BMoXI84g.js +1 -0
  147. package/web-ui/build/static/c-CKH4C7-Z.js +1 -0
  148. package/web-ui/build/static/c-Z0txyaeJ.js +1 -0
  149. package/web-ui/build/static/c-like-Dzm9dMmR.js +1 -0
  150. package/web-ui/build/static/cal-DoyAwiUt.js +1 -0
  151. package/web-ui/build/static/capnproto-DeIi9LOH.js +1 -0
  152. package/web-ui/build/static/ceylon-Coim6DIe.js +1 -0
  153. package/web-ui/build/static/cfscript-CwsndC-j.js +1 -0
  154. package/web-ui/build/static/chaiscript-D6Aq-PSv.js +1 -0
  155. package/web-ui/build/static/cil-vi56VRk_.js +1 -0
  156. package/web-ui/build/static/clean-BfpKrTdp.js +1 -0
  157. package/web-ui/build/static/clojure-DUtl6BaB.js +1 -0
  158. package/web-ui/build/static/clojure-DXJHtDlY.js +1 -0
  159. package/web-ui/build/static/clojure-repl-BxwP5C3g.js +1 -0
  160. package/web-ui/build/static/cmake-C9_VZ1vH.js +1 -0
  161. package/web-ui/build/static/cmake-dplO-PGD.js +1 -0
  162. package/web-ui/build/static/cobol-DsZhu02V.js +1 -0
  163. package/web-ui/build/static/coffeescript-Cw9jtGNP.js +1 -0
  164. package/web-ui/build/static/coffeescript-DvDt4T2l.js +1 -0
  165. package/web-ui/build/static/concurnas-Bzc_Dcdd.js +1 -0
  166. package/web-ui/build/static/coq-Cv-5BqGo.js +1 -0
  167. package/web-ui/build/static/coq-DWFe2ssK.js +1 -0
  168. package/web-ui/build/static/cos-D6Lc6Cah.js +1 -0
  169. package/web-ui/build/static/cpp-BFmLjd76.js +1 -0
  170. package/web-ui/build/static/cpp-DVQgbHji.js +1 -0
  171. package/web-ui/build/static/crmsh-Cqveth9p.js +1 -0
  172. package/web-ui/build/static/crystal-0syYaH4Y.js +1 -0
  173. package/web-ui/build/static/crystal-Noptp-kr.js +1 -0
  174. package/web-ui/build/static/csharp-B799cFMH.js +1 -0
  175. package/web-ui/build/static/csharp-_HlvMZzJ.js +1 -0
  176. package/web-ui/build/static/cshtml-CnwOXlhP.js +1 -0
  177. package/web-ui/build/static/csp-1ffxIG_-.js +1 -0
  178. package/web-ui/build/static/csp-Bws60bPu.js +1 -0
  179. package/web-ui/build/static/css-BGdwXzpm.js +1 -0
  180. package/web-ui/build/static/css-extras-DZCECiOa.js +1 -0
  181. package/web-ui/build/static/csv-FMFGT0T4.js +1 -0
  182. package/web-ui/build/static/cypher-DnXoEwRp.js +1 -0
  183. package/web-ui/build/static/d-CBrts1xB.js +1 -0
  184. package/web-ui/build/static/d-qrJLxk2L.js +1 -0
  185. package/web-ui/build/static/dart-3vBSXJVV.js +1 -0
  186. package/web-ui/build/static/dart-Cj5b7BV9.js +1 -0
  187. package/web-ui/build/static/dataweave-BuFf63rk.js +1 -0
  188. package/web-ui/build/static/dax-Cl-se1JI.js +1 -0
  189. package/web-ui/build/static/delphi-CLkRb26y.js +1 -0
  190. package/web-ui/build/static/dhall--TIL2Z--.js +1 -0
  191. package/web-ui/build/static/diff-Bn-XL2om.js +1 -0
  192. package/web-ui/build/static/diff-BsTwly4w.js +1 -0
  193. package/web-ui/build/static/django-BfRtHnTS.js +1 -0
  194. package/web-ui/build/static/django-Dm9O4e3A.js +1 -0
  195. package/web-ui/build/static/dns-BIVEp3uD.js +1 -0
  196. package/web-ui/build/static/dns-zone-file-CO7LnOdh.js +1 -0
  197. package/web-ui/build/static/docker-BhwMip1R.js +1 -0
  198. package/web-ui/build/static/dockerfile-8Tjw9_jF.js +1 -0
  199. package/web-ui/build/static/dos-CRMiAo46.js +1 -0
  200. package/web-ui/build/static/dot-DPpW7LrJ.js +1 -0
  201. package/web-ui/build/static/dsconfig-D0zbYilI.js +1 -0
  202. package/web-ui/build/static/dts-C_-yqWEL.js +1 -0
  203. package/web-ui/build/static/dust-CucJgqnE.js +1 -0
  204. package/web-ui/build/static/ebnf-CCHK0H6j.js +1 -0
  205. package/web-ui/build/static/ebnf-CDdAcveH.js +1 -0
  206. package/web-ui/build/static/editorconfig-f-5b95UM.js +1 -0
  207. package/web-ui/build/static/eiffel-MmghFce7.js +1 -0
  208. package/web-ui/build/static/ejs-CPMN4-jk.js +1 -0
  209. package/web-ui/build/static/elixir-57Ldyw8h.js +1 -0
  210. package/web-ui/build/static/elixir-DTxnmhIt.js +1 -0
  211. package/web-ui/build/static/elm-ClV9zQoT.js +1 -0
  212. package/web-ui/build/static/elm-pX-i6o7U.js +1 -0
  213. package/web-ui/build/static/erb-BPeO9smT.js +1 -0
  214. package/web-ui/build/static/erb-BnZQ4STz.js +1 -0
  215. package/web-ui/build/static/erlang-DPtI7VK_.js +1 -0
  216. package/web-ui/build/static/erlang-KG5mg5wN.js +1 -0
  217. package/web-ui/build/static/erlang-repl-BqPVXZ3Y.js +1 -0
  218. package/web-ui/build/static/etlua-BRc0Qbbs.js +1 -0
  219. package/web-ui/build/static/excel-BAlZ9Hkj.js +1 -0
  220. package/web-ui/build/static/excel-formula-BOW-bnHh.js +1 -0
  221. package/web-ui/build/static/factor-DCCsCpGM.js +1 -0
  222. package/web-ui/build/static/false-CnqnCzBU.js +1 -0
  223. package/web-ui/build/static/firestore-security-rules-DtkQ3uEq.js +1 -0
  224. package/web-ui/build/static/fix-CfPjl4Xr.js +1 -0
  225. package/web-ui/build/static/flix-BCA3BceS.js +1 -0
  226. package/web-ui/build/static/flow-C-5ewqYW.js +1 -0
  227. package/web-ui/build/static/fortran-CfDtl8An.js +1 -0
  228. package/web-ui/build/static/fortran-DQ_knNPt.js +1 -0
  229. package/web-ui/build/static/fsharp-CcVQ3IqX.js +1 -0
  230. package/web-ui/build/static/fsharp-olQ6ojCa.js +1 -0
  231. package/web-ui/build/static/ftl-DIWHDyWt.js +1 -0
  232. package/web-ui/build/static/gams-_NVFTSj5.js +1 -0
  233. package/web-ui/build/static/gap-DIG5TV2b.js +1 -0
  234. package/web-ui/build/static/gauss-C8rjPjTG.js +1 -0
  235. package/web-ui/build/static/gcode-8wJu4gcL.js +1 -0
  236. package/web-ui/build/static/gcode-DjHf417I.js +1 -0
  237. package/web-ui/build/static/gdscript-BZdmRCYu.js +1 -0
  238. package/web-ui/build/static/gedcom-BVFJ8C_Q.js +1 -0
  239. package/web-ui/build/static/gherkin-7NQkoaub.js +1 -0
  240. package/web-ui/build/static/gherkin-bSpNbJ48.js +1 -0
  241. package/web-ui/build/static/git-BRY_UXsc.js +1 -0
  242. package/web-ui/build/static/glsl-Ck6ShGRC.js +1 -0
  243. package/web-ui/build/static/glsl-jwCJ0Pmg.js +1 -0
  244. package/web-ui/build/static/gml-BAjG4Kr2.js +1 -0
  245. package/web-ui/build/static/gml-BnhKb5Da.js +1 -0
  246. package/web-ui/build/static/gn-Dux09iX8.js +1 -0
  247. package/web-ui/build/static/go-BOG-9Cqk.js +1 -0
  248. package/web-ui/build/static/go-BWZB_3b5.js +1 -0
  249. package/web-ui/build/static/go-module-BVLW7KBE.js +1 -0
  250. package/web-ui/build/static/golo-BD_SOfwL.js +1 -0
  251. package/web-ui/build/static/gradle-zSadWOD2.js +1 -0
  252. package/web-ui/build/static/graphql-BQlyj78B.js +1 -0
  253. package/web-ui/build/static/groovy-BurRMqQS.js +1 -0
  254. package/web-ui/build/static/groovy-SP58zwlE.js +1 -0
  255. package/web-ui/build/static/haml-eZ5ah5KY.js +1 -0
  256. package/web-ui/build/static/haml-lFC47IZb.js +1 -0
  257. package/web-ui/build/static/handlebars-B4UXrB-Q.js +1 -0
  258. package/web-ui/build/static/handlebars-CQ-Q5HnC.js +1 -0
  259. package/web-ui/build/static/haskell-AQrRyTSy.js +1 -0
  260. package/web-ui/build/static/haskell-BZTSbaB_.js +1 -0
  261. package/web-ui/build/static/haxe-5l1X6ESp.js +1 -0
  262. package/web-ui/build/static/haxe-DBn90muG.js +1 -0
  263. package/web-ui/build/static/hcl-CnMewPLM.js +1 -0
  264. package/web-ui/build/static/hlsl-RAtuBzr5.js +1 -0
  265. package/web-ui/build/static/hoon-CSqRU_4M.js +1 -0
  266. package/web-ui/build/static/hpkp-_gNbXcHt.js +1 -0
  267. package/web-ui/build/static/hsp-DY1V4au3.js +1 -0
  268. package/web-ui/build/static/hsts-j5z2jJo8.js +1 -0
  269. package/web-ui/build/static/htmlbars-C5EHvatr.js +1 -0
  270. package/web-ui/build/static/http-DgWgQrZh.js +1 -0
  271. package/web-ui/build/static/http-DphJL0q2.js +1 -0
  272. package/web-ui/build/static/hy-DnBqjPsB.js +1 -0
  273. package/web-ui/build/static/ichigojam-DeiCOKyF.js +1 -0
  274. package/web-ui/build/static/icon-CWANFWY5.js +1 -0
  275. package/web-ui/build/static/icu-message-format-C7w3vpgC.js +1 -0
  276. package/web-ui/build/static/idris-BeD8eULz.js +1 -0
  277. package/web-ui/build/static/iecst-BIznHXqY.js +1 -0
  278. package/web-ui/build/static/ignore-BcFgcNaS.js +1 -0
  279. package/web-ui/build/static/index-D8uVofpo.js +13 -0
  280. package/web-ui/build/static/index-DPFadqM6.css +1 -0
  281. package/web-ui/build/static/index-SkOgWEAU.js +1 -0
  282. package/web-ui/build/static/index-Vd3WlhtC.js +747 -0
  283. package/web-ui/build/static/inform7-CkQD_jz-.js +1 -0
  284. package/web-ui/build/static/inform7-phQiuDty.js +1 -0
  285. package/web-ui/build/static/ini-Bw_QAbzV.js +1 -0
  286. package/web-ui/build/static/ini-CB8ZxX7y.js +1 -0
  287. package/web-ui/build/static/io-D6IgpCmL.js +1 -0
  288. package/web-ui/build/static/irpf90-Ctj0koST.js +1 -0
  289. package/web-ui/build/static/isbl-D2mGcH87.js +1 -0
  290. package/web-ui/build/static/j-KvHmDBWH.js +1 -0
  291. package/web-ui/build/static/java-BeBIdo5i.js +1 -0
  292. package/web-ui/build/static/java-llFZkHLe.js +1 -0
  293. package/web-ui/build/static/javadoc-DXvQGu0s.js +1 -0
  294. package/web-ui/build/static/javadoclike-B5qdA9KZ.js +1 -0
  295. package/web-ui/build/static/javascript-De6HzHvc.js +1 -0
  296. package/web-ui/build/static/javastacktrace-C5MolKiP.js +1 -0
  297. package/web-ui/build/static/jboss-cli-2TXd54zo.js +1 -0
  298. package/web-ui/build/static/jexl-W4AVA9fi.js +1 -0
  299. package/web-ui/build/static/jolie-DTJKRMZN.js +1 -0
  300. package/web-ui/build/static/jq-BYg-QQKh.js +1 -0
  301. package/web-ui/build/static/js-extras-BrYWd2VE.js +1 -0
  302. package/web-ui/build/static/js-templates-DorYpbHq.js +1 -0
  303. package/web-ui/build/static/jsdoc-CRF8n9pZ.js +1 -0
  304. package/web-ui/build/static/json-Dlcd7rla.js +1 -0
  305. package/web-ui/build/static/json-rhOJZzzZ.js +1 -0
  306. package/web-ui/build/static/json5-hTq1nNIW.js +1 -0
  307. package/web-ui/build/static/jsonp-CMg9Xvol.js +1 -0
  308. package/web-ui/build/static/jsstacktrace-hEeYxHtB.js +1 -0
  309. package/web-ui/build/static/jsx-B7PtA8WD.js +1 -0
  310. package/web-ui/build/static/julia-CNiEEY-n.js +1 -0
  311. package/web-ui/build/static/julia-eE0_SJlc.js +1 -0
  312. package/web-ui/build/static/julia-repl-CUJTTT4C.js +1 -0
  313. package/web-ui/build/static/keepalived-GUWJBqyD.js +1 -0
  314. package/web-ui/build/static/keyman-Bdf9MJyu.js +1 -0
  315. package/web-ui/build/static/kotlin-Ch6Bej5W.js +1 -0
  316. package/web-ui/build/static/kotlin-DFJ7D7Lw.js +1 -0
  317. package/web-ui/build/static/kumir-DJLIjcCs.js +1 -0
  318. package/web-ui/build/static/kusto-BM0YTwU4.js +1 -0
  319. package/web-ui/build/static/lasso-Z1DVS84K.js +1 -0
  320. package/web-ui/build/static/latex-BWbw71RK.js +1 -0
  321. package/web-ui/build/static/latex-CMzqmbhw.js +1 -0
  322. package/web-ui/build/static/latte-C1g8_grc.js +1 -0
  323. package/web-ui/build/static/ldif-C6QH3OIL.js +1 -0
  324. package/web-ui/build/static/leaf-CbR--ZsH.js +1 -0
  325. package/web-ui/build/static/less-ClVrKh2Z.js +1 -0
  326. package/web-ui/build/static/less-DNSxm8UA.js +1 -0
  327. package/web-ui/build/static/lilypond-lTzf_sWt.js +1 -0
  328. package/web-ui/build/static/liquid-Bn91mVfC.js +1 -0
  329. package/web-ui/build/static/lisp-CU3bHohQ.js +1 -0
  330. package/web-ui/build/static/lisp-DbgzE9W8.js +1 -0
  331. package/web-ui/build/static/livecodeserver-Cse1Uz3H.js +1 -0
  332. package/web-ui/build/static/livescript-BaxbgzWP.js +1 -0
  333. package/web-ui/build/static/livescript-nJt61DBy.js +1 -0
  334. package/web-ui/build/static/llvm-DBboo6UI.js +1 -0
  335. package/web-ui/build/static/llvm-vIy7XYVy.js +1 -0
  336. package/web-ui/build/static/log-CT7nfoDW.js +1 -0
  337. package/web-ui/build/static/lolcode-CUKVytZh.js +1 -0
  338. package/web-ui/build/static/lsl-CsAOlGF2.js +1 -0
  339. package/web-ui/build/static/lua-BuU2FFxP.js +1 -0
  340. package/web-ui/build/static/lua-CiDuKQaa.js +1 -0
  341. package/web-ui/build/static/magma-7vR0zcmS.js +1 -0
  342. package/web-ui/build/static/makefile-Buiz-Msh.js +1 -0
  343. package/web-ui/build/static/makefile-DXW_-6OY.js +1 -0
  344. package/web-ui/build/static/markdown-Bk5DUoGY.js +1 -0
  345. package/web-ui/build/static/markdown-CRS5W_Ai.js +1 -0
  346. package/web-ui/build/static/markup-templating-24odpmF3.js +1 -0
  347. package/web-ui/build/static/mathematica-BxcwhJUp.js +1 -0
  348. package/web-ui/build/static/matlab-3pJYx_Fb.js +1 -0
  349. package/web-ui/build/static/matlab-BqlRrzMf.js +1 -0
  350. package/web-ui/build/static/maxima-DlCfUpcj.js +1 -0
  351. package/web-ui/build/static/maxscript-Cu_gCaFU.js +1 -0
  352. package/web-ui/build/static/mel-D7iQ-5Up.js +1 -0
  353. package/web-ui/build/static/mel-DzBKNpoN.js +1 -0
  354. package/web-ui/build/static/mercury-Dfrb-i8A.js +1 -0
  355. package/web-ui/build/static/mermaid-WN7V2_Eq.js +1 -0
  356. package/web-ui/build/static/mipsasm-CcijzL0q.js +1 -0
  357. package/web-ui/build/static/mizar-Bk68zACP.js +1 -0
  358. package/web-ui/build/static/mizar-Twc2-iZ4.js +1 -0
  359. package/web-ui/build/static/mojolicious-DBbo2S7X.js +1 -0
  360. package/web-ui/build/static/mongodb-2RsFIjgg.js +1 -0
  361. package/web-ui/build/static/monkey-CPXtQ0Bf.js +1 -0
  362. package/web-ui/build/static/monkey-DjV7Wcek.js +1 -0
  363. package/web-ui/build/static/moonscript-B5M5as70.js +1 -0
  364. package/web-ui/build/static/moonscript-D1BHW4Il.js +1 -0
  365. package/web-ui/build/static/n1ql-D0heNDBD.js +1 -0
  366. package/web-ui/build/static/n1ql-DfHqXQD7.js +1 -0
  367. package/web-ui/build/static/n4js-CaPf44Dz.js +1 -0
  368. package/web-ui/build/static/nand2tetris-hdl-D1nf9mn4.js +1 -0
  369. package/web-ui/build/static/naniscript-DnCnu5ZX.js +1 -0
  370. package/web-ui/build/static/nasm-BZrSaMsK.js +1 -0
  371. package/web-ui/build/static/neon-D29Grm2v.js +1 -0
  372. package/web-ui/build/static/nevod-DgSNbQkE.js +1 -0
  373. package/web-ui/build/static/nginx-BAaDGDfT.js +1 -0
  374. package/web-ui/build/static/nginx-BvJ1lrHX.js +1 -0
  375. package/web-ui/build/static/nim--9zzVe5F.js +1 -0
  376. package/web-ui/build/static/nim-Br1relpU.js +1 -0
  377. package/web-ui/build/static/nix--0ftErCy.js +1 -0
  378. package/web-ui/build/static/nix-104ztQqr.js +1 -0
  379. package/web-ui/build/static/node-repl-BUMAf7_p.js +1 -0
  380. package/web-ui/build/static/nsis-BaeKybNA.js +1 -0
  381. package/web-ui/build/static/nsis-CdZEv2iA.js +1 -0
  382. package/web-ui/build/static/objectivec-DBB4ymdg.js +1 -0
  383. package/web-ui/build/static/objectivec-kFYXC6g4.js +1 -0
  384. package/web-ui/build/static/ocaml-D1GXvN7c.js +1 -0
  385. package/web-ui/build/static/ocaml-D80jRMPE.js +1 -0
  386. package/web-ui/build/static/opencl-fb7BfRdO.js +1 -0
  387. package/web-ui/build/static/openqasm-CWUBrR2w.js +1 -0
  388. package/web-ui/build/static/openscad-Dim7ILSL.js +1 -0
  389. package/web-ui/build/static/oxygene-BSwApkwz.js +1 -0
  390. package/web-ui/build/static/oz-CMtRoi5F.js +1 -0
  391. package/web-ui/build/static/parigp-AH8cZ38D.js +1 -0
  392. package/web-ui/build/static/parser-bBNjuhG3.js +1 -0
  393. package/web-ui/build/static/parser3-DUtoWEAd.js +1 -0
  394. package/web-ui/build/static/pascal-Cr3DPIYT.js +1 -0
  395. package/web-ui/build/static/pascaligo-pWW12jfs.js +1 -0
  396. package/web-ui/build/static/pcaxis-DBw9rxmr.js +1 -0
  397. package/web-ui/build/static/peoplecode-aCpMPm_s.js +1 -0
  398. package/web-ui/build/static/perl-BpZ7GmJ3.js +1 -0
  399. package/web-ui/build/static/perl-fnHTrqJL.js +1 -0
  400. package/web-ui/build/static/pf-Dz352ty7.js +1 -0
  401. package/web-ui/build/static/pgsql-CHPUdlI_.js +1 -0
  402. package/web-ui/build/static/php-BRwItjmS.js +1 -0
  403. package/web-ui/build/static/php-CrX_kswO.js +1 -0
  404. package/web-ui/build/static/php-extras-BmeRXDSO.js +1 -0
  405. package/web-ui/build/static/php-template-B0MFJ9RR.js +1 -0
  406. package/web-ui/build/static/phpdoc-wAPkJj9X.js +1 -0
  407. package/web-ui/build/static/plaintext-CmPk1gvP.js +1 -0
  408. package/web-ui/build/static/plsql-pWVw0sCJ.js +1 -0
  409. package/web-ui/build/static/pony-B4SXhyDS.js +1 -0
  410. package/web-ui/build/static/powerquery-ZJ28bdRR.js +1 -0
  411. package/web-ui/build/static/powershell-CWg1ca6z.js +1 -0
  412. package/web-ui/build/static/powershell-Dnl0aBXc.js +1 -0
  413. package/web-ui/build/static/processing-CbYVU7hZ.js +1 -0
  414. package/web-ui/build/static/processing-DnroirEw.js +1 -0
  415. package/web-ui/build/static/profile-DLNc-MTA.js +1 -0
  416. package/web-ui/build/static/prolog-4KlPFQus.js +1 -0
  417. package/web-ui/build/static/prolog-CtUicY87.js +1 -0
  418. package/web-ui/build/static/promql-C_i6OJVg.js +1 -0
  419. package/web-ui/build/static/properties-Cj0lBOSP.js +1 -0
  420. package/web-ui/build/static/properties-vGFibcz9.js +1 -0
  421. package/web-ui/build/static/protobuf-BOIGxbSP.js +1 -0
  422. package/web-ui/build/static/protobuf-CQ3su-J7.js +1 -0
  423. package/web-ui/build/static/psl-DeG5_YUF.js +1 -0
  424. package/web-ui/build/static/pug-BieVVXYz.js +1 -0
  425. package/web-ui/build/static/puppet-Ba40SVKU.js +1 -0
  426. package/web-ui/build/static/puppet-D7BzrcGt.js +1 -0
  427. package/web-ui/build/static/pure-DZnkz1iT.js +1 -0
  428. package/web-ui/build/static/purebasic-CLLZW_6G.js +1 -0
  429. package/web-ui/build/static/purebasic-CYPZo_H6.js +1 -0
  430. package/web-ui/build/static/purescript-Dyjfu5Id.js +1 -0
  431. package/web-ui/build/static/python-BdIWKxdN.js +1 -0
  432. package/web-ui/build/static/python-ofKsqxv7.js +1 -0
  433. package/web-ui/build/static/python-repl-DiTYb1xK.js +1 -0
  434. package/web-ui/build/static/q-B4P0If_I.js +1 -0
  435. package/web-ui/build/static/q-t_17xfY8.js +1 -0
  436. package/web-ui/build/static/qml-B5WhiN48.js +1 -0
  437. package/web-ui/build/static/qml-Dq0cESXJ.js +1 -0
  438. package/web-ui/build/static/qore-DCx30XRf.js +1 -0
  439. package/web-ui/build/static/qsharp-UrBScekp.js +1 -0
  440. package/web-ui/build/static/r-B0Ty1RKQ.js +1 -0
  441. package/web-ui/build/static/r-B0za8QKS.js +1 -0
  442. package/web-ui/build/static/racket-Dj6WEyhS.js +1 -0
  443. package/web-ui/build/static/reason-dj9hJSfr.js +1 -0
  444. package/web-ui/build/static/reasonml-B-q5_wag.js +1 -0
  445. package/web-ui/build/static/regex-4HEc5C1m.js +1 -0
  446. package/web-ui/build/static/rego-BdQe18RK.js +1 -0
  447. package/web-ui/build/static/renpy-CVMA2llL.js +1 -0
  448. package/web-ui/build/static/rest-9B4JWVGr.js +1 -0
  449. package/web-ui/build/static/rib-DR-U8OaT.js +1 -0
  450. package/web-ui/build/static/rip-Bu2t_rFZ.js +1 -0
  451. package/web-ui/build/static/roboconf-CJeXD5-I.js +1 -0
  452. package/web-ui/build/static/roboconf-DzDTVrdM.js +1 -0
  453. package/web-ui/build/static/robotframework-CR7KyPpN.js +1 -0
  454. package/web-ui/build/static/routeros-B2741z2k.js +1 -0
  455. package/web-ui/build/static/rsl-B9F_ZCgv.js +1 -0
  456. package/web-ui/build/static/ruby-I2JTNgyY.js +1 -0
  457. package/web-ui/build/static/ruby-QGDPOmJX.js +1 -0
  458. package/web-ui/build/static/ruleslanguage-CGzXEUCO.js +1 -0
  459. package/web-ui/build/static/rust-BxW5-WOm.js +1 -0
  460. package/web-ui/build/static/rust-CSOA43di.js +1 -0
  461. package/web-ui/build/static/sas-Bclfx4g3.js +1 -0
  462. package/web-ui/build/static/sas-xbQaiYjT.js +1 -0
  463. package/web-ui/build/static/sass-DJPbdNwd.js +1 -0
  464. package/web-ui/build/static/scala-Bo18NtHQ.js +1 -0
  465. package/web-ui/build/static/scala-Cy0JH-SG.js +1 -0
  466. package/web-ui/build/static/scheme-BjcWWjIx.js +1 -0
  467. package/web-ui/build/static/scheme-DQdj8PzN.js +1 -0
  468. package/web-ui/build/static/scilab-Bn1KHdK-.js +1 -0
  469. package/web-ui/build/static/scss-B1twkZBz.js +1 -0
  470. package/web-ui/build/static/scss-DmOuMI4v.js +1 -0
  471. package/web-ui/build/static/shell-BUlkJG0S.js +1 -0
  472. package/web-ui/build/static/shell-session-Bke-svxA.js +1 -0
  473. package/web-ui/build/static/smali-Ch9S16HV.js +1 -0
  474. package/web-ui/build/static/smali-D_yDr_Aj.js +1 -0
  475. package/web-ui/build/static/smalltalk-B9TfQ5Md.js +1 -0
  476. package/web-ui/build/static/smalltalk-EwbZxZsR.js +1 -0
  477. package/web-ui/build/static/smarty-9kDPpeSm.js +1 -0
  478. package/web-ui/build/static/sml-2fEfT7rd.js +1 -0
  479. package/web-ui/build/static/sml-BiwoLNk7.js +1 -0
  480. package/web-ui/build/static/solidity-n_x8Oe0h.js +1 -0
  481. package/web-ui/build/static/solution-file-B2mvjI3e.js +1 -0
  482. package/web-ui/build/static/soy-DPkgKBIS.js +1 -0
  483. package/web-ui/build/static/sparql-Cy95tds0.js +1 -0
  484. package/web-ui/build/static/splunk-spl-Ym3z9ouN.js +1 -0
  485. package/web-ui/build/static/sqf-CXZTG8WE.js +1 -0
  486. package/web-ui/build/static/sqf-Cwi3yg7f.js +1 -0
  487. package/web-ui/build/static/sql-DPxSQY4S.js +1 -0
  488. package/web-ui/build/static/sql-peh7ijGj.js +1 -0
  489. package/web-ui/build/static/sql_more-0YAbAuPw.js +1 -0
  490. package/web-ui/build/static/squirrel-CphzjV0e.js +1 -0
  491. package/web-ui/build/static/stan-0-xZ95-O.js +1 -0
  492. package/web-ui/build/static/stan-CaI4__2g.js +1 -0
  493. package/web-ui/build/static/stata-BrbzrGSs.js +1 -0
  494. package/web-ui/build/static/step21-C_qeyVLw.js +1 -0
  495. package/web-ui/build/static/stylus-Btycb2sZ.js +1 -0
  496. package/web-ui/build/static/stylus-FoBJ7jki.js +1 -0
  497. package/web-ui/build/static/subunit-Dpg-m04-.js +1 -0
  498. package/web-ui/build/static/swift-Cr9uZmgb.js +1 -0
  499. package/web-ui/build/static/swift-hGLFtD7e.js +1 -0
  500. package/web-ui/build/static/systemd-Bls2D9Vj.js +1 -0
  501. package/web-ui/build/static/t4-cs-C4qDO-jJ.js +1 -0
  502. package/web-ui/build/static/t4-templating-BbCFPMPO.js +1 -0
  503. package/web-ui/build/static/t4-vb-D1zoEccT.js +1 -0
  504. package/web-ui/build/static/taggerscript-CWHk9Gih.js +1 -0
  505. package/web-ui/build/static/tap-Bjt0UnzV.js +1 -0
  506. package/web-ui/build/static/tap-BnHKwLQs.js +1 -0
  507. package/web-ui/build/static/tcl-Zo9kx4y-.js +1 -0
  508. package/web-ui/build/static/tcl-fzLmefkt.js +1 -0
  509. package/web-ui/build/static/textile-9lIlUPH5.js +1 -0
  510. package/web-ui/build/static/thrift-M3K6r5Cy.js +1 -0
  511. package/web-ui/build/static/toml-HpaKqckc.js +1 -0
  512. package/web-ui/build/static/tp-DFKuxrKj.js +1 -0
  513. package/web-ui/build/static/tremor-D4_bUtMB.js +1 -0
  514. package/web-ui/build/static/tsx-o1RT-T90.js +1 -0
  515. package/web-ui/build/static/tt2-1xDqcN_2.js +1 -0
  516. package/web-ui/build/static/turtle-Dlt-aGky.js +1 -0
  517. package/web-ui/build/static/twig-CJ_BnGSR.js +1 -0
  518. package/web-ui/build/static/twig-CjsiSQb6.js +1 -0
  519. package/web-ui/build/static/typescript-B8B9zUn-.js +1 -0
  520. package/web-ui/build/static/typescript-D0Jgo8O7.js +1 -0
  521. package/web-ui/build/static/typoscript-C8Qke4ZB.js +1 -0
  522. package/web-ui/build/static/unrealscript-YxJdDNZ3.js +1 -0
  523. package/web-ui/build/static/uorazor-CtEVnqBv.js +1 -0
  524. package/web-ui/build/static/uri-YdaiQl4c.js +1 -0
  525. package/web-ui/build/static/v-CIyttMDD.js +1 -0
  526. package/web-ui/build/static/vala-DGslcym_.js +1 -0
  527. package/web-ui/build/static/vala-GFPx3uEJ.js +1 -0
  528. package/web-ui/build/static/vbnet-B20itab-.js +1 -0
  529. package/web-ui/build/static/vbnet-BdoN6egk.js +1 -0
  530. package/web-ui/build/static/vbscript-PHVh6Fp_.js +1 -0
  531. package/web-ui/build/static/vbscript-html-woH1VZ7U.js +1 -0
  532. package/web-ui/build/static/velocity-DtVfCZeg.js +1 -0
  533. package/web-ui/build/static/verilog-Bt6edXvM.js +1 -0
  534. package/web-ui/build/static/verilog-k_7lr9Zq.js +1 -0
  535. package/web-ui/build/static/vhdl-BMzOgOeK.js +1 -0
  536. package/web-ui/build/static/vhdl-BcAbtPG6.js +1 -0
  537. package/web-ui/build/static/vim-DrinG9a4.js +1 -0
  538. package/web-ui/build/static/vim-WihLATJL.js +1 -0
  539. package/web-ui/build/static/visual-basic-CJnvgPjM.js +1 -0
  540. package/web-ui/build/static/warpscript-zMlbUoZs.js +1 -0
  541. package/web-ui/build/static/wasm-GUnfTBUL.js +1 -0
  542. package/web-ui/build/static/web-idl-CfaLTG_r.js +1 -0
  543. package/web-ui/build/static/wiki-13AlLoOc.js +1 -0
  544. package/web-ui/build/static/wolfram-zHocYNXW.js +1 -0
  545. package/web-ui/build/static/wren-Byq862Iu.js +1 -0
  546. package/web-ui/build/static/x86asm-CLcOnePY.js +1 -0
  547. package/web-ui/build/static/xeora-BVHqWOFS.js +1 -0
  548. package/web-ui/build/static/xl-lXi8OYfr.js +1 -0
  549. package/web-ui/build/static/xml-KZjGBKxi.js +1 -0
  550. package/web-ui/build/static/xml-doc-DrQSDcEW.js +1 -0
  551. package/web-ui/build/static/xojo-DosHeFXU.js +1 -0
  552. package/web-ui/build/static/xquery-BZN1F14Q.js +1 -0
  553. package/web-ui/build/static/xquery-Cnz7ZLFr.js +1 -0
  554. package/web-ui/build/static/yaml-BzXOcy9u.js +1 -0
  555. package/web-ui/build/static/yaml-C207y5bt.js +1 -0
  556. package/web-ui/build/static/yang-ByrBdDIg.js +1 -0
  557. package/web-ui/build/static/zephir-bahTa7of.js +1 -0
  558. package/web-ui/build/static/zig-BlFYhdtC.js +1 -0
  559. package/src/tools/browserTool.js +0 -897
  560. package/src/utilities/platformUtils.test.js +0 -98
  561. package/web-ui/build/static/index-SmQFfvBs.js +0 -746
  562. package/web-ui/build/static/index-V2ySwjHp.css +0 -1
@@ -0,0 +1,199 @@
1
+ import { jest, describe, test, expect, beforeEach } from '@jest/globals';
2
+ import { createMockLogger } from '../../__test-utils__/mockFactories.js';
3
+
4
+ const { default: FlowContextService } = await import('../flowContextService.js');
5
+
6
+ describe('FlowContextService', () => {
7
+ let service;
8
+ let logger;
9
+
10
+ const baseFlowMetadata = {
11
+ flowId: 'flow-1',
12
+ flowName: 'Test Flow',
13
+ nodeName: 'Step A',
14
+ nodePosition: 1,
15
+ totalNodes: 3
16
+ };
17
+
18
+ beforeEach(() => {
19
+ logger = createMockLogger();
20
+ service = new FlowContextService({}, logger);
21
+ });
22
+
23
+ describe('buildFlowAgentContext', () => {
24
+ test('builds context with flow header for first agent (no previous data)', () => {
25
+ const result = service.buildFlowAgentContext(baseFlowMetadata, null);
26
+ expect(result).toContain('FLOW_EXECUTION_CONTEXT');
27
+ expect(result).toContain('Step A');
28
+ expect(result).toContain('1/3');
29
+ expect(result).toContain('Test Flow');
30
+ expect(result).toContain('FIRST agent in the flow');
31
+ expect(result).toContain('CRITICAL HANDOFF REQUIREMENT');
32
+ expect(result).toContain('job-done');
33
+ });
34
+
35
+ test('builds context with previous agent data', () => {
36
+ const prevData = {
37
+ agentId: 'prev-agent',
38
+ agentName: 'Previous Agent',
39
+ summary: 'Did some work',
40
+ filesCreated: ['/src/file.js', '/src/file2.js'],
41
+ output: 'Some output text'
42
+ };
43
+ const result = service.buildFlowAgentContext(baseFlowMetadata, prevData);
44
+ expect(result).toContain('CONTEXT FROM PREVIOUS AGENT');
45
+ expect(result).toContain('Previous Agent');
46
+ expect(result).toContain('Did some work');
47
+ expect(result).toContain('/src/file.js');
48
+ expect(result).toContain('/src/file2.js');
49
+ expect(result).toContain('Some output text');
50
+ expect(result).not.toContain('FIRST agent');
51
+ });
52
+
53
+ test('handles previous agent data without agent name', () => {
54
+ const prevData = { agentId: 'prev-1', summary: 'done' };
55
+ const result = service.buildFlowAgentContext(baseFlowMetadata, prevData);
56
+ expect(result).toContain('Previous agent ID: prev-1');
57
+ });
58
+
59
+ test('handles previous agent with no files created', () => {
60
+ const prevData = { agentId: 'prev-1', filesCreated: [] };
61
+ const result = service.buildFlowAgentContext(baseFlowMetadata, prevData);
62
+ expect(result).toContain('No files created');
63
+ });
64
+
65
+ test('handles missing nodeName gracefully', () => {
66
+ const meta = { ...baseFlowMetadata, nodeName: null };
67
+ const result = service.buildFlowAgentContext(meta, null);
68
+ expect(result).toContain('Agent');
69
+ });
70
+ });
71
+
72
+ describe('_formatPreviousOutput', () => {
73
+ test('returns empty string for null', () => {
74
+ expect(service._formatPreviousOutput(null)).toBe('');
75
+ });
76
+
77
+ test('converts object to JSON string', () => {
78
+ const result = service._formatPreviousOutput({ key: 'value' });
79
+ expect(result).toContain('"key"');
80
+ expect(result).toContain('"value"');
81
+ });
82
+
83
+ test('truncates long output', () => {
84
+ const longStr = 'x'.repeat(3000);
85
+ const result = service._formatPreviousOutput(longStr);
86
+ expect(result.length).toBeLessThan(3000);
87
+ expect(result).toContain('truncated');
88
+ });
89
+
90
+ test('returns short string as-is', () => {
91
+ expect(service._formatPreviousOutput('short')).toBe('short');
92
+ });
93
+ });
94
+
95
+ describe('buildContextSummary', () => {
96
+ test('returns summary object without previous agent', () => {
97
+ const summary = service.buildContextSummary(baseFlowMetadata, null);
98
+ expect(summary.flowId).toBe('flow-1');
99
+ expect(summary.flowName).toBe('Test Flow');
100
+ expect(summary.currentNode).toBe('Step A');
101
+ expect(summary.position).toBe('1/3');
102
+ expect(summary.hasPreviousAgent).toBe(false);
103
+ expect(summary.previousAgentId).toBeNull();
104
+ expect(summary.previousFilesCount).toBe(0);
105
+ });
106
+
107
+ test('returns summary with previous agent data', () => {
108
+ const prevData = { agentId: 'prev-1', filesCreated: ['a.txt', 'b.txt'] };
109
+ const summary = service.buildContextSummary(baseFlowMetadata, prevData);
110
+ expect(summary.hasPreviousAgent).toBe(true);
111
+ expect(summary.previousAgentId).toBe('prev-1');
112
+ expect(summary.previousFilesCount).toBe(2);
113
+ });
114
+ });
115
+
116
+ describe('validateJobDoneForFlow', () => {
117
+ test('returns valid for complete job-done result', () => {
118
+ const result = service.validateJobDoneForFlow({
119
+ summary: 'Completed the full analysis of the project with detailed findings',
120
+ details: 'All files created at /src/output.js',
121
+ filesCreated: ['/src/output.js']
122
+ });
123
+ expect(result.valid).toBe(true);
124
+ expect(result.warnings).toHaveLength(0);
125
+ expect(result.suggestions).toBeNull();
126
+ });
127
+
128
+ test('warns on too brief summary', () => {
129
+ const result = service.validateJobDoneForFlow({
130
+ summary: 'done',
131
+ details: 'some details'
132
+ });
133
+ expect(result.valid).toBe(false);
134
+ expect(result.warnings.some(w => w.includes('brief'))).toBe(true);
135
+ });
136
+
137
+ test('warns when no summary or details', () => {
138
+ const result = service.validateJobDoneForFlow({});
139
+ expect(result.valid).toBe(false);
140
+ expect(result.warnings.some(w => w.includes('No details'))).toBe(true);
141
+ });
142
+
143
+ test('warns when files mentioned but no paths listed', () => {
144
+ const result = service.validateJobDoneForFlow({
145
+ summary: 'I created several output files for the project analysis',
146
+ filesCreated: []
147
+ });
148
+ expect(result.warnings.some(w => w.includes('paths'))).toBe(true);
149
+ });
150
+
151
+ test('no warning when file mentioned with explicit path', () => {
152
+ const result = service.validateJobDoneForFlow({
153
+ summary: 'Created the output file at /src/output.js for the project',
154
+ filesCreated: ['/src/output.js']
155
+ });
156
+ expect(result.valid).toBe(true);
157
+ });
158
+ });
159
+
160
+ describe('extractFilePaths', () => {
161
+ test('extracts file paths from messages', () => {
162
+ const messages = [
163
+ { content: 'created file "/src/output.js"' },
164
+ { content: 'File written: /build/result.txt' }
165
+ ];
166
+ const paths = service.extractFilePaths(messages);
167
+ expect(paths).toContain('/src/output.js');
168
+ });
169
+
170
+ test('ignores HTTP URLs', () => {
171
+ const messages = [{ content: 'saved to https://example.com/file.txt' }];
172
+ const paths = service.extractFilePaths(messages);
173
+ expect(paths).toHaveLength(0);
174
+ });
175
+
176
+ test('handles non-string content', () => {
177
+ const messages = [{ content: { text: 'wrote to /src/file.js' } }];
178
+ const paths = service.extractFilePaths(messages);
179
+ expect(paths.length).toBeGreaterThanOrEqual(0);
180
+ });
181
+
182
+ test('returns empty for no matches', () => {
183
+ const messages = [{ content: 'no files here' }];
184
+ const paths = service.extractFilePaths(messages);
185
+ expect(paths).toHaveLength(0);
186
+ });
187
+
188
+ test('deduplicates paths', () => {
189
+ const messages = [
190
+ { content: 'created /src/file.js' },
191
+ { content: 'saved to /src/file.js' }
192
+ ];
193
+ const paths = service.extractFilePaths(messages);
194
+ // Set-based deduplication
195
+ const unique = [...new Set(paths)];
196
+ expect(unique.length).toBe(paths.length);
197
+ });
198
+ });
199
+ });
@@ -0,0 +1,450 @@
1
+ import { jest, describe, test, expect, beforeEach } from '@jest/globals';
2
+ import { createMockLogger } from '../../__test-utils__/mockFactories.js';
3
+
4
+ // Mock fs
5
+ const mockReadFile = jest.fn();
6
+ const mockWriteFile = jest.fn().mockResolvedValue(undefined);
7
+ const mockUnlink = jest.fn().mockResolvedValue(undefined);
8
+ jest.unstable_mockModule('fs', () => ({
9
+ promises: {
10
+ readFile: mockReadFile,
11
+ writeFile: mockWriteFile,
12
+ unlink: mockUnlink
13
+ }
14
+ }));
15
+
16
+ // Mock userDataDir
17
+ const mockGetUserDataPaths = jest.fn().mockReturnValue({
18
+ agents: '/tmp/test-agents',
19
+ settings: '/tmp/test-settings'
20
+ });
21
+ const mockEnsureUserDataDirs = jest.fn().mockResolvedValue(undefined);
22
+ jest.unstable_mockModule('../../utilities/userDataDir.js', () => ({
23
+ getUserDataPaths: mockGetUserDataPaths,
24
+ ensureUserDataDirs: mockEnsureUserDataDirs
25
+ }));
26
+
27
+ const { MemoryService, getMemoryService } = await import('../../services/memoryService.js');
28
+
29
+ describe('MemoryService', () => {
30
+ let service;
31
+ let logger;
32
+
33
+ beforeEach(() => {
34
+ logger = createMockLogger();
35
+ service = new MemoryService(logger);
36
+ jest.clearAllMocks();
37
+ });
38
+
39
+ // ── Constructor ──
40
+ test('constructor initializes with defaults', () => {
41
+ expect(service.logger).toBe(logger);
42
+ expect(service.memoriesCache).toBeInstanceOf(Map);
43
+ expect(service.agentsDir).toBeNull();
44
+ expect(service.initialized).toBe(false);
45
+ });
46
+
47
+ // ── initialize ──
48
+ test('initialize sets up paths and marks initialized', async () => {
49
+ await service.initialize();
50
+ expect(service.initialized).toBe(true);
51
+ expect(service.agentsDir).toBe('/tmp/test-agents');
52
+ expect(mockEnsureUserDataDirs).toHaveBeenCalled();
53
+ });
54
+
55
+ test('initialize skips if already initialized', async () => {
56
+ await service.initialize();
57
+ await service.initialize();
58
+ expect(mockEnsureUserDataDirs).toHaveBeenCalledTimes(1);
59
+ });
60
+
61
+ test('initialize throws on error', async () => {
62
+ mockEnsureUserDataDirs.mockRejectedValueOnce(new Error('permission denied'));
63
+ await expect(service.initialize()).rejects.toThrow('permission denied');
64
+ });
65
+
66
+ // ── _getMemoryFilePath ──
67
+ test('_getMemoryFilePath returns correct path', async () => {
68
+ await service.initialize();
69
+ const filePath = service._getMemoryFilePath('agent-1');
70
+ expect(filePath).toContain('agent-1-memory.json');
71
+ });
72
+
73
+ // ── _generateMemoryId ──
74
+ test('_generateMemoryId returns unique IDs', () => {
75
+ const id1 = service._generateMemoryId();
76
+ const id2 = service._generateMemoryId();
77
+ expect(id1).toMatch(/^mem-\d+-[a-z0-9]+$/);
78
+ expect(id1).not.toBe(id2);
79
+ });
80
+
81
+ // ── loadMemories ──
82
+ test('loadMemories loads from file and caches', async () => {
83
+ const memories = [
84
+ { id: 'mem-1', title: 'Test', description: '', content: 'data', createdAt: new Date().toISOString() }
85
+ ];
86
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
87
+
88
+ const result = await service.loadMemories('agent-1');
89
+ expect(result.length).toBe(1);
90
+ expect(result[0].title).toBe('Test');
91
+
92
+ // Second call should use cache
93
+ const result2 = await service.loadMemories('agent-1');
94
+ expect(result2).toBe(result);
95
+ expect(mockReadFile).toHaveBeenCalledTimes(1);
96
+ });
97
+
98
+ test('loadMemories returns empty array for ENOENT', async () => {
99
+ const error = new Error('not found');
100
+ error.code = 'ENOENT';
101
+ mockReadFile.mockRejectedValue(error);
102
+
103
+ const result = await service.loadMemories('new-agent');
104
+ expect(result).toEqual([]);
105
+ });
106
+
107
+ test('loadMemories returns empty on parse error', async () => {
108
+ mockReadFile.mockResolvedValue('not json');
109
+
110
+ const result = await service.loadMemories('bad-agent');
111
+ expect(result).toEqual([]);
112
+ });
113
+
114
+ test('loadMemories filters expired memories', async () => {
115
+ const pastDate = new Date(Date.now() - 86400000).toISOString();
116
+ const futureDate = new Date(Date.now() + 86400000).toISOString();
117
+ const memories = [
118
+ { id: 'mem-1', title: 'Expired', expiration: { type: 'date', value: pastDate } },
119
+ { id: 'mem-2', title: 'Active', expiration: { type: 'date', value: futureDate } },
120
+ { id: 'mem-3', title: 'No expiry' }
121
+ ];
122
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
123
+
124
+ const result = await service.loadMemories('agent-1');
125
+ expect(result.length).toBe(2);
126
+ expect(result.find(m => m.title === 'Expired')).toBeUndefined();
127
+ });
128
+
129
+ // ── saveMemories ──
130
+ test('saveMemories writes to file and updates cache', async () => {
131
+ const memories = [{ id: 'mem-1', title: 'Test' }];
132
+ await service.saveMemories('agent-1', memories);
133
+
134
+ expect(mockWriteFile).toHaveBeenCalled();
135
+ expect(service.memoriesCache.get('agent-1')).toBe(memories);
136
+ });
137
+
138
+ test('saveMemories throws on write error', async () => {
139
+ mockWriteFile.mockRejectedValueOnce(new Error('disk full'));
140
+ await expect(service.saveMemories('agent-1', [])).rejects.toThrow('disk full');
141
+ });
142
+
143
+ // ── addMemory ──
144
+ test('addMemory creates a new memory and saves', async () => {
145
+ mockReadFile.mockRejectedValue(Object.assign(new Error('ENOENT'), { code: 'ENOENT' }));
146
+
147
+ const memory = await service.addMemory('agent-1', {
148
+ title: 'New Memory',
149
+ description: 'Description',
150
+ content: 'Some content'
151
+ });
152
+
153
+ expect(memory.id).toMatch(/^mem-/);
154
+ expect(memory.title).toBe('New Memory');
155
+ expect(memory.description).toBe('Description');
156
+ expect(memory.content).toBe('Some content');
157
+ expect(memory.accessCount).toBe(0);
158
+ expect(mockWriteFile).toHaveBeenCalled();
159
+ });
160
+
161
+ test('addMemory with expiration date', async () => {
162
+ mockReadFile.mockRejectedValue(Object.assign(new Error('ENOENT'), { code: 'ENOENT' }));
163
+
164
+ const memory = await service.addMemory('agent-1', {
165
+ title: 'Expiring',
166
+ content: 'data',
167
+ expiration: '2030-01-01'
168
+ });
169
+
170
+ expect(memory.expiration.type).toBe('date');
171
+ });
172
+
173
+ // ── _parseExpiration ──
174
+ test('_parseExpiration returns never for null/undefined', () => {
175
+ expect(service._parseExpiration(null)).toEqual({ type: 'never', value: null });
176
+ expect(service._parseExpiration(undefined)).toEqual({ type: 'never', value: null });
177
+ });
178
+
179
+ test('_parseExpiration parses date string', () => {
180
+ const result = service._parseExpiration('2030-01-01');
181
+ expect(result.type).toBe('date');
182
+ expect(result.value).toBeDefined();
183
+ });
184
+
185
+ test('_parseExpiration treats non-date string as condition', () => {
186
+ const result = service._parseExpiration('when project is done');
187
+ expect(result.type).toBe('condition');
188
+ expect(result.value).toBe('when project is done');
189
+ });
190
+
191
+ test('_parseExpiration handles object input', () => {
192
+ const result = service._parseExpiration({ type: 'date', value: '2030-01-01' });
193
+ expect(result.type).toBe('date');
194
+ expect(result.value).toBe('2030-01-01');
195
+ });
196
+
197
+ test('_parseExpiration handles object with date property', () => {
198
+ const result = service._parseExpiration({ date: '2030-01-01' });
199
+ expect(result.value).toBe('2030-01-01');
200
+ });
201
+
202
+ test('_parseExpiration returns never for number input', () => {
203
+ const result = service._parseExpiration(12345);
204
+ expect(result.type).toBe('never');
205
+ });
206
+
207
+ // ── updateMemory ──
208
+ test('updateMemory updates existing memory', async () => {
209
+ const memories = [
210
+ { id: 'mem-1', title: 'Old Title', description: 'old', content: 'old content', updatedAt: '' }
211
+ ];
212
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
213
+
214
+ const result = await service.updateMemory('agent-1', 'mem-1', {
215
+ title: 'New Title',
216
+ content: 'new content'
217
+ });
218
+
219
+ expect(result.title).toBe('New Title');
220
+ expect(result.content).toBe('new content');
221
+ expect(result.description).toBe('old'); // unchanged
222
+ expect(mockWriteFile).toHaveBeenCalled();
223
+ });
224
+
225
+ test('updateMemory returns null for non-existent memory', async () => {
226
+ mockReadFile.mockRejectedValue(Object.assign(new Error('ENOENT'), { code: 'ENOENT' }));
227
+
228
+ const result = await service.updateMemory('agent-1', 'nonexistent', { title: 'New' });
229
+ expect(result).toBeNull();
230
+ });
231
+
232
+ test('updateMemory updates expiration', async () => {
233
+ const memories = [
234
+ { id: 'mem-1', title: 'Test', description: '', content: '', updatedAt: '' }
235
+ ];
236
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
237
+
238
+ const result = await service.updateMemory('agent-1', 'mem-1', {
239
+ expiration: '2030-06-01'
240
+ });
241
+
242
+ expect(result.expiration.type).toBe('date');
243
+ });
244
+
245
+ // ── deleteMemory ──
246
+ test('deleteMemory removes memory and saves', async () => {
247
+ const memories = [
248
+ { id: 'mem-1', title: 'Delete Me' },
249
+ { id: 'mem-2', title: 'Keep Me' }
250
+ ];
251
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
252
+
253
+ const result = await service.deleteMemory('agent-1', 'mem-1');
254
+ expect(result).toBe(true);
255
+ expect(mockWriteFile).toHaveBeenCalled();
256
+ });
257
+
258
+ test('deleteMemory returns false for non-existent memory', async () => {
259
+ mockReadFile.mockRejectedValue(Object.assign(new Error('ENOENT'), { code: 'ENOENT' }));
260
+
261
+ const result = await service.deleteMemory('agent-1', 'nonexistent');
262
+ expect(result).toBe(false);
263
+ });
264
+
265
+ // ── listMemories ──
266
+ test('listMemories returns grouped by date with titles level', async () => {
267
+ const memories = [
268
+ { id: 'mem-1', title: 'Memory 1', description: 'desc', createdAt: '2024-01-15T10:00:00Z' },
269
+ { id: 'mem-2', title: 'Memory 2', description: 'desc2', createdAt: '2024-01-15T11:00:00Z' }
270
+ ];
271
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
272
+
273
+ const result = await service.listMemories('agent-1', 'titles');
274
+ expect(result.count).toBe(2);
275
+ expect(result.grouped['2024-01-15'].length).toBe(2);
276
+ // titles level should only have id and title
277
+ expect(result.grouped['2024-01-15'][0]).toHaveProperty('id');
278
+ expect(result.grouped['2024-01-15'][0]).toHaveProperty('title');
279
+ expect(result.grouped['2024-01-15'][0]).not.toHaveProperty('description');
280
+ });
281
+
282
+ test('listMemories with descriptions level', async () => {
283
+ const memories = [
284
+ { id: 'mem-1', title: 'Memory 1', description: 'desc', createdAt: '2024-01-15T10:00:00Z' }
285
+ ];
286
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
287
+
288
+ const result = await service.listMemories('agent-1', 'descriptions');
289
+ const item = result.grouped['2024-01-15'][0];
290
+ expect(item).toHaveProperty('description');
291
+ expect(item).not.toHaveProperty('expiration');
292
+ });
293
+
294
+ test('listMemories with full level', async () => {
295
+ const memories = [
296
+ { id: 'mem-1', title: 'M1', description: 'd', expiration: null, createdAt: '2024-01-15T10:00:00Z', updatedAt: '2024-01-15T10:00:00Z' }
297
+ ];
298
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
299
+
300
+ const result = await service.listMemories('agent-1', 'full');
301
+ const item = result.grouped['2024-01-15'][0];
302
+ expect(item).toHaveProperty('expiration');
303
+ expect(item).toHaveProperty('createdAt');
304
+ });
305
+
306
+ test('listMemories with unknown level defaults to titles', async () => {
307
+ const memories = [
308
+ { id: 'mem-1', title: 'M1', description: 'd', createdAt: '2024-01-15T10:00:00Z' }
309
+ ];
310
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
311
+
312
+ const result = await service.listMemories('agent-1', 'unknown');
313
+ const item = result.grouped['2024-01-15'][0];
314
+ expect(item).toHaveProperty('id');
315
+ expect(item).toHaveProperty('title');
316
+ expect(item).not.toHaveProperty('description');
317
+ });
318
+
319
+ // ── readMemory ──
320
+ test('readMemory returns memory and updates access count', async () => {
321
+ const memories = [
322
+ { id: 'mem-1', title: 'Test', content: 'data', accessCount: 0 }
323
+ ];
324
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
325
+
326
+ const result = await service.readMemory('agent-1', 'mem-1');
327
+ expect(result.title).toBe('Test');
328
+ expect(result.accessCount).toBe(1);
329
+ expect(result.lastAccessed).toBeDefined();
330
+ expect(mockWriteFile).toHaveBeenCalled();
331
+ });
332
+
333
+ test('readMemory returns null for non-existent memory', async () => {
334
+ mockReadFile.mockRejectedValue(Object.assign(new Error('ENOENT'), { code: 'ENOENT' }));
335
+
336
+ const result = await service.readMemory('agent-1', 'nonexistent');
337
+ expect(result).toBeNull();
338
+ });
339
+
340
+ // ── searchMemories ──
341
+ test('searchMemories finds matching memories by title', async () => {
342
+ const memories = [
343
+ { id: 'mem-1', title: 'React Setup', description: 'How to setup React' },
344
+ { id: 'mem-2', title: 'Vue Guide', description: 'Vue framework guide' }
345
+ ];
346
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
347
+
348
+ const result = await service.searchMemories('agent-1', 'react');
349
+ expect(result.length).toBe(1);
350
+ expect(result[0].title).toBe('React Setup');
351
+ });
352
+
353
+ test('searchMemories finds matching memories by description', async () => {
354
+ const memories = [
355
+ { id: 'mem-1', title: 'Setup', description: 'How to configure database' }
356
+ ];
357
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
358
+
359
+ const result = await service.searchMemories('agent-1', 'database');
360
+ expect(result.length).toBe(1);
361
+ });
362
+
363
+ test('searchMemories returns empty for no matches', async () => {
364
+ const memories = [
365
+ { id: 'mem-1', title: 'Test', description: 'desc' }
366
+ ];
367
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
368
+
369
+ const result = await service.searchMemories('agent-1', 'xyz');
370
+ expect(result).toEqual([]);
371
+ });
372
+
373
+ // ── clearMemories ──
374
+ test('clearMemories removes all memories', async () => {
375
+ const memories = [
376
+ { id: 'mem-1', title: 'Test1' },
377
+ { id: 'mem-2', title: 'Test2' }
378
+ ];
379
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
380
+
381
+ const count = await service.clearMemories('agent-1');
382
+ expect(count).toBe(2);
383
+ expect(mockWriteFile).toHaveBeenCalled();
384
+ });
385
+
386
+ // ── deleteMemoryFile ──
387
+ test('deleteMemoryFile deletes file and clears cache', async () => {
388
+ service.memoriesCache.set('agent-1', [{ id: 'mem-1' }]);
389
+ await service.initialize();
390
+
391
+ const result = await service.deleteMemoryFile('agent-1');
392
+ expect(result).toBe(true);
393
+ expect(service.memoriesCache.has('agent-1')).toBe(false);
394
+ });
395
+
396
+ test('deleteMemoryFile returns true for already deleted', async () => {
397
+ await service.initialize();
398
+ const error = new Error('not found');
399
+ error.code = 'ENOENT';
400
+ mockUnlink.mockRejectedValueOnce(error);
401
+
402
+ const result = await service.deleteMemoryFile('agent-1');
403
+ expect(result).toBe(true);
404
+ });
405
+
406
+ test('deleteMemoryFile returns false on other errors', async () => {
407
+ await service.initialize();
408
+ mockUnlink.mockRejectedValueOnce(new Error('permission denied'));
409
+
410
+ const result = await service.deleteMemoryFile('agent-1');
411
+ expect(result).toBe(false);
412
+ });
413
+
414
+ // ── getMemoryStats ──
415
+ test('getMemoryStats returns correct statistics', async () => {
416
+ const soon = new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString(); // 3 days
417
+ const later = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(); // 30 days
418
+ const memories = [
419
+ { id: 'mem-1', accessCount: 5, expiration: { type: 'date', value: soon } },
420
+ { id: 'mem-2', accessCount: 3, expiration: { type: 'date', value: later } },
421
+ { id: 'mem-3', accessCount: 0 }
422
+ ];
423
+ mockReadFile.mockResolvedValue(JSON.stringify({ memories }));
424
+
425
+ const stats = await service.getMemoryStats('agent-1');
426
+ expect(stats.totalMemories).toBe(3);
427
+ expect(stats.totalAccessCount).toBe(8);
428
+ expect(stats.expiringWithin7Days).toBe(1);
429
+ expect(stats.averageAccessCount).toBe('2.67');
430
+ });
431
+
432
+ test('getMemoryStats returns zero averages for empty', async () => {
433
+ mockReadFile.mockRejectedValue(Object.assign(new Error('ENOENT'), { code: 'ENOENT' }));
434
+
435
+ const stats = await service.getMemoryStats('agent-1');
436
+ expect(stats.totalMemories).toBe(0);
437
+ expect(stats.averageAccessCount).toBe(0);
438
+ });
439
+
440
+ // ── _filterExpiredMemories ──
441
+ test('_filterExpiredMemories keeps condition-based and never expiration', () => {
442
+ const memories = [
443
+ { id: 'mem-1', expiration: { type: 'condition', value: 'some condition' } },
444
+ { id: 'mem-2', expiration: { type: 'never', value: null } },
445
+ { id: 'mem-3' }
446
+ ];
447
+ const result = service._filterExpiredMemories(memories);
448
+ expect(result.length).toBe(3);
449
+ });
450
+ });