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,640 +1,640 @@
1
- /**
2
- * Widget runtime bundle — STRING, served to every jsx-mode iframe.
3
- *
4
- * This file is a Node module that exports a plain string. The string is
5
- * JavaScript that runs INSIDE the sandboxed iframe. Keep it self-contained:
6
- * the iframe has null origin, no network (CSP connect-src 'none'), and
7
- * no same-origin access — there is no way to lazy-load anything.
8
- *
9
- * Why inline everything as a single string (not a bundled file served
10
- * via <script src>): the iframe's CSP is script-src 'self' which, for a
11
- * srcdoc document, resolves 'self' to a unique/null origin that can't
12
- * match any URL. Inline scripts (via 'unsafe-inline' in CSP) are the
13
- * only reliable path.
14
- *
15
- * Contains:
16
- * - A minimal Preact-flavoured h()/render() (hand-rolled, ~500 LOC)
17
- * - htm-style tagged-template compiler (~200 LOC)
18
- * - The loxia.* SDK (postMessage bridge)
19
- * - A small primitive catalogue: Card, Button, Input, Text, Metric, Row, Col
20
- *
21
- * MVP note: the primitive catalog is intentionally minimal. Agents can
22
- * use plain HTML elements in their render functions too — `h('div', ...)`
23
- * and `html\`<div>...\`` both work. Primitives are ergonomics.
24
- */
25
-
26
- export const WIDGET_RUNTIME = `
27
- /* ==== Loxia widget runtime v1 ==== */
28
- (function () {
29
- 'use strict';
30
-
31
- /* ---------- tiny VDOM (Preact-flavoured) ---------- */
32
- // VNode: { type, props, children }
33
- function h(type, props, ...children) {
34
- return { type, props: props || {}, children: children.flat(Infinity).filter(c => c != null && c !== false) };
35
- }
36
-
37
- // Render a VNode/text into a real DOM node. Very small — re-renders
38
- // replace the whole subtree rather than diffing (fine for MVP widget
39
- // sizes; can upgrade later).
40
- function createDom(v) {
41
- if (v == null || v === false) return document.createTextNode('');
42
- if (typeof v === 'string' || typeof v === 'number') return document.createTextNode(String(v));
43
- if (typeof v.type === 'function') {
44
- // Component — call with props + children and recurse.
45
- const childrenArg = v.children.length === 1 ? v.children[0] : v.children;
46
- const out = v.type({ ...v.props, children: childrenArg });
47
- return createDom(out);
48
- }
49
- // Native element
50
- const el = document.createElement(v.type);
51
- for (const [k, val] of Object.entries(v.props || {})) {
52
- if (val == null || val === false) continue;
53
- if (k === 'children') continue;
54
- if (k === 'style' && typeof val === 'object') {
55
- Object.assign(el.style, val);
56
- } else if (k === 'className') {
57
- el.setAttribute('class', String(val));
58
- } else if (k === 'dangerouslySetInnerHTML') {
59
- // Deliberately not supported — users who want HTML can use kind:'html'.
60
- console.warn('[loxia] dangerouslySetInnerHTML is not supported in jsx widgets');
61
- } else if (k.startsWith('on') && typeof val === 'function') {
62
- el.addEventListener(k.slice(2).toLowerCase(), val);
63
- } else {
64
- el.setAttribute(k, String(val));
65
- }
66
- }
67
- for (const child of v.children) {
68
- el.appendChild(createDom(child));
69
- }
70
- return el;
71
- }
72
-
73
- let _rootEl = null;
74
- let _rootVNode = null;
75
- function renderToRoot(vnode, container) {
76
- _rootEl = container;
77
- _rootVNode = vnode;
78
- container.innerHTML = '';
79
- container.appendChild(createDom(vnode));
80
- scheduleHeight();
81
- }
82
-
83
- /* ---------- htm-ish tagged-template compiler ---------- */
84
- // Parses: html\`<Card title=\${t}><Button onClick=\${f}>hi<//></>\`
85
- // into a VNode tree using the h() above. Small but sufficient for
86
- // widget-shape templates (elements, attributes, children, closing tags
87
- // in "//" form, component references via \${Component}).
88
- //
89
- // Adapted from the public-domain htm algorithm; rewritten terse for inlining.
90
- const CACHE = new WeakMap();
91
- function html(strings) {
92
- const values = Array.prototype.slice.call(arguments, 1);
93
- let tree = CACHE.get(strings);
94
- if (!tree) {
95
- tree = parseTemplate(strings);
96
- CACHE.set(strings, tree);
97
- }
98
- return evalTree(tree, values);
99
- }
100
-
101
- // Parse the template array into an instruction list we can replay with values.
102
- // Instructions: [kind, ...]
103
- // [1, type] OPEN (type is string|index)
104
- // [2] CLOSE
105
- // [3, name, valueOrIdx, isIndex] ATTR
106
- // [4, textOrIdx, isIndex] CHILD
107
- function parseTemplate(strings) {
108
- const insts = [];
109
- let buf = '';
110
- let mode = 'text'; // text | tag | attr
111
- for (let i = 0; i < strings.length; i++) {
112
- const s = strings[i];
113
- for (let j = 0; j < s.length; j++) {
114
- const c = s[j];
115
- if (mode === 'text') {
116
- if (c === '<') {
117
- if (buf.trim()) insts.push([4, buf, false]);
118
- buf = '';
119
- mode = 'tag';
120
- } else {
121
- buf += c;
122
- }
123
- } else if (mode === 'tag') {
124
- if (c === '>') {
125
- commitTag(insts, buf);
126
- buf = '';
127
- mode = 'text';
128
- } else if (/\\s/.test(c) && buf) {
129
- commitTag(insts, buf);
130
- buf = '';
131
- mode = 'attr';
132
- } else if (c === '/' && j + 1 < s.length && s[j + 1] === '>') {
133
- // self-close: <Foo/> — commit then close
134
- commitTag(insts, buf);
135
- insts.push([2]);
136
- buf = '';
137
- j++;
138
- mode = 'text';
139
- } else {
140
- buf += c;
141
- }
142
- } else if (mode === 'attr') {
143
- if (c === '>') {
144
- if (buf.trim()) parseAttr(insts, buf);
145
- buf = '';
146
- mode = 'text';
147
- } else if (c === '/' && j + 1 < s.length && s[j + 1] === '>') {
148
- if (buf.trim()) parseAttr(insts, buf);
149
- insts.push([2]);
150
- buf = '';
151
- j++;
152
- mode = 'text';
153
- } else {
154
- buf += c;
155
- }
156
- }
157
- }
158
- // End of string segment — the value at index i goes next.
159
- // (Tagged template invariant: strings.length === values.length + 1,
160
- // so "there is a value after strings[i]" iff i < strings.length - 1.
161
- // We can't reference values here — parseTemplate runs with only the
162
- // strings array; values are substituted later in evalTree.)
163
- if (i < strings.length - 1) {
164
- if (mode === 'text') {
165
- if (buf) insts.push([4, buf, false]);
166
- buf = '';
167
- insts.push([4, i, true]);
168
- } else if (mode === 'attr') {
169
- const trimmed = buf.trim();
170
- if (trimmed.endsWith('=')) {
171
- // buf may contain earlier COMPLETED attrs followed by a new
172
- // name ending in "=". Example: 'id="b" onClick=' → the
173
- // earlier part 'id="b"' is a complete attr we must run
174
- // through parseAttr; the final word (after last whitespace)
175
- // is the name of the interpolated attribute.
176
- const withoutEq = trimmed.slice(0, -1);
177
- const m = withoutEq.match(/^([\\s\\S]*?)(\\S+)\\s*\$/);
178
- if (m && m[1].trim()) {
179
- parseAttr(insts, m[1].trim());
180
- insts.push([3, m[2].trim(), i, true]);
181
- } else {
182
- insts.push([3, withoutEq.trim(), i, true]);
183
- }
184
- } else if (trimmed === '') {
185
- // spread — not supported in MVP; ignore
186
- } else {
187
- // Something like 'id="b" onClick' (boolean-ish / \${Comp}-as-type).
188
- // parseAttr splits multi-attrs; last token becomes boolean or
189
- // value-holder depending on our interpretation. Keep prior
190
- // behaviour — pass the whole thing.
191
- parseAttr(insts, trimmed + '=' + JSON.stringify('__val__' + i));
192
- }
193
- buf = '';
194
- } else if (mode === 'tag') {
195
- // opener is the value — \${Comp}
196
- insts.push([1, i, true]);
197
- buf = '';
198
- mode = 'attr';
199
- }
200
- }
201
- }
202
- if (buf.trim()) insts.push([4, buf, false]);
203
- return insts;
204
- }
205
-
206
- function commitTag(insts, raw) {
207
- const t = raw.trim();
208
- if (!t) return;
209
- if (t.startsWith('/')) {
210
- insts.push([2]);
211
- } else {
212
- insts.push([1, t, false]);
213
- }
214
- }
215
-
216
- function parseAttr(insts, raw) {
217
- // Attrs separated by whitespace, each as "name" or "name=value" or 'name="value"'
218
- const parts = raw.match(/[^\\s"']+=\"[^\"]*\"|[^\\s"']+='[^']*'|[^\\s"']+/g) || [];
219
- for (const part of parts) {
220
- const eq = part.indexOf('=');
221
- if (eq === -1) {
222
- insts.push([3, part, true, false]); // boolean attr
223
- } else {
224
- const name = part.slice(0, eq);
225
- let val = part.slice(eq + 1);
226
- if ((val.startsWith('"') && val.endsWith('"')) ||
227
- (val.startsWith("'") && val.endsWith("'"))) {
228
- val = val.slice(1, -1);
229
- }
230
- insts.push([3, name, val, false]);
231
- }
232
- }
233
- }
234
-
235
- // Walk instructions, substituting values, building a tree of {type, props, children}.
236
- function evalTree(insts, values) {
237
- const stack = [{ type: '__root__', props: {}, children: [] }];
238
- for (const inst of insts) {
239
- const top = stack[stack.length - 1];
240
- if (inst[0] === 1) {
241
- const type = inst[2] ? values[inst[1]] : inst[1];
242
- const node = { type, props: {}, children: [] };
243
- top.children.push(node);
244
- stack.push(node);
245
- } else if (inst[0] === 2) {
246
- if (stack.length > 1) stack.pop();
247
- } else if (inst[0] === 3) {
248
- const [, name, valOrIdx, isIdx] = inst;
249
- top.props[name] = isIdx ? values[valOrIdx] : valOrIdx;
250
- } else if (inst[0] === 4) {
251
- const [, valOrIdx, isIdx] = inst;
252
- const v = isIdx ? values[valOrIdx] : valOrIdx;
253
- if (Array.isArray(v)) for (const x of v) top.children.push(x);
254
- else if (v != null) top.children.push(v);
255
- }
256
- }
257
- const root = stack[0];
258
- return root.children.length === 1 ? root.children[0] : root.children;
259
- }
260
-
261
- /* ---------- primitives (ergonomic wrappers) ---------- */
262
- function LoxiaCard({ title, children, padding = 'md' }) {
263
- const pad = padding === 'sm' ? '8px' : padding === 'lg' ? '24px' : '16px';
264
- return h('div', {
265
- className: 'loxia-card',
266
- style: {
267
- background: 'var(--loxia-card-bg, rgb(var(--gray-50)))',
268
- border: '1px solid var(--loxia-card-border, rgb(var(--gray-200)))',
269
- borderRadius: '8px',
270
- padding: pad,
271
- color: 'rgb(var(--gray-900))',
272
- fontFamily: '-apple-system, BlinkMacSystemFont, Segoe UI, sans-serif',
273
- },
274
- },
275
- title ? h('div', { style: { fontWeight: '600', marginBottom: '8px', fontSize: '14px' } }, title) : null,
276
- children
277
- );
278
- }
279
-
280
- function LoxiaButton({ label, onClick, children, variant = 'primary', disabled }) {
281
- const bg = variant === 'primary' ? 'rgb(var(--loxia-600))' :
282
- variant === 'danger' ? '#dc2626' : 'rgb(var(--gray-200))';
283
- const color = variant === 'primary' || variant === 'danger' ? 'white' : 'rgb(var(--gray-900))';
284
- return h('button', {
285
- onClick: disabled ? undefined : onClick,
286
- disabled,
287
- style: {
288
- background: bg, color, border: 'none',
289
- padding: '6px 14px', borderRadius: '6px', fontSize: '13px',
290
- cursor: disabled ? 'not-allowed' : 'pointer',
291
- opacity: disabled ? 0.5 : 1,
292
- },
293
- }, label || children);
294
- }
295
-
296
- function LoxiaInput({ value, onChange, placeholder, type = 'text' }) {
297
- return h('input', {
298
- type, value: value ?? '', placeholder: placeholder ?? '',
299
- onInput: (e) => onChange && onChange(e.target.value),
300
- style: {
301
- padding: '6px 10px', border: '1px solid rgb(var(--gray-300))',
302
- borderRadius: '6px', fontSize: '13px', width: '100%',
303
- background: 'rgb(var(--gray-50))', color: 'rgb(var(--gray-900))',
304
- },
305
- });
306
- }
307
-
308
- function LoxiaText({ children, tone = 'default', size = 'md' }) {
309
- const color = tone === 'muted' ? 'rgb(var(--gray-500))' : 'rgb(var(--gray-900))';
310
- const fs = size === 'sm' ? '12px' : size === 'lg' ? '16px' : '14px';
311
- return h('span', { style: { color, fontSize: fs } }, children);
312
- }
313
-
314
- function LoxiaMetric({ label, value, unit }) {
315
- return h('div', { style: { display: 'flex', flexDirection: 'column', gap: '2px' } },
316
- h('div', { style: { fontSize: '11px', color: 'rgb(var(--gray-500))', textTransform: 'uppercase', letterSpacing: '0.05em' } }, label),
317
- h('div', { style: { fontSize: '20px', fontWeight: '600', color: 'rgb(var(--gray-900))' } },
318
- value, unit ? h('span', { style: { fontSize: '13px', fontWeight: '400', color: 'rgb(var(--gray-500))', marginLeft: '4px' } }, unit) : null
319
- )
320
- );
321
- }
322
-
323
- function LoxiaRow({ children, gap = 'md', justify = 'start', align = 'start' }) {
324
- const g = gap === 'sm' ? '6px' : gap === 'lg' ? '20px' : '12px';
325
- return h('div', { style: { display: 'flex', flexDirection: 'row', gap: g, justifyContent: justify, alignItems: align, flexWrap: 'wrap' } }, children);
326
- }
327
- function LoxiaCol({ children, gap = 'md' }) {
328
- const g = gap === 'sm' ? '6px' : gap === 'lg' ? '20px' : '12px';
329
- return h('div', { style: { display: 'flex', flexDirection: 'column', gap: g } }, children);
330
- }
331
-
332
- /* ---------- postMessage SDK ---------- */
333
- const _updateListeners = [];
334
- function sendEvent(evt) {
335
- try {
336
- window.parent.postMessage({ __loxia: true, type: 'event', widgetId: window.__loxiaWidgetId, payload: evt }, '*');
337
- } catch (err) {
338
- console.warn('[loxia] sendEvent failed', err);
339
- }
340
- }
341
- function onUpdate(cb) { if (typeof cb === 'function') _updateListeners.push(cb); }
342
- function requestHeight(px) {
343
- try {
344
- window.parent.postMessage({ __loxia: true, type: 'resize', widgetId: window.__loxiaWidgetId, height: px }, '*');
345
- } catch {}
346
- }
347
-
348
- window.addEventListener('message', (e) => {
349
- if (!e.data || e.data.__loxia !== true) return;
350
- if (e.source !== window.parent) return;
351
- if (e.data.type === 'update' && e.data.props) {
352
- _updateListeners.forEach(cb => { try { cb(e.data.props); } catch (err) { console.warn('[loxia] update handler threw', err); } });
353
- _reRender();
354
- } else if (e.data.type === 'theme' && e.data.tokens) {
355
- applyThemeTokens(e.data.tokens);
356
- }
357
- });
358
-
359
- function applyThemeTokens(tokens) {
360
- const root = document.documentElement;
361
- for (const [k, v] of Object.entries(tokens)) {
362
- root.style.setProperty('--' + k, v);
363
- }
364
- }
365
-
366
- /* ---------- auto-resize ---------- */
367
- let _heightDebounce = null;
368
- function scheduleHeight() {
369
- if (_heightDebounce) clearTimeout(_heightDebounce);
370
- _heightDebounce = setTimeout(() => {
371
- const h = Math.ceil(document.body.scrollHeight);
372
- requestHeight(h);
373
- }, 50);
374
- }
375
-
376
- if (typeof ResizeObserver !== 'undefined') {
377
- const ro = new ResizeObserver(() => scheduleHeight());
378
- document.addEventListener('DOMContentLoaded', () => ro.observe(document.body));
379
- } else {
380
- // Fallback: just post once after load.
381
- document.addEventListener('DOMContentLoaded', () => setTimeout(scheduleHeight, 50));
382
- }
383
-
384
- /* ---------- hooks (for the ROOT component only) ---------- */
385
- // Agents are heavily trained on React hooks and reach for useState
386
- // reflexively. Supporting a minimal hooks set for the root component
387
- // eliminates a whole class of "widget didn't render" failures.
388
- //
389
- // Scope limitation: hooks are tracked by CALL ORDER in the root render.
390
- // Nested components calling hooks would break the call-order contract
391
- // (different trees, different orders) — so we only guarantee correctness
392
- // for the root App function. The tool description tells the agent to
393
- // keep state in the root component, which is almost always fine.
394
- const _hookCells = [];
395
- let _hookIdx = 0;
396
- function _sameDeps(a, b) {
397
- if (a === b) return true;
398
- if (!a || !b) return false;
399
- if (a.length !== b.length) return false;
400
- for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
401
- return true;
402
- }
403
- function useState(initial) {
404
- const i = _hookIdx++;
405
- if (!_hookCells[i]) _hookCells[i] = { value: typeof initial === 'function' ? initial() : initial };
406
- const cell = _hookCells[i];
407
- const setValue = (v) => {
408
- const next = typeof v === 'function' ? v(cell.value) : v;
409
- if (next === cell.value) return;
410
- cell.value = next;
411
- _reRender();
412
- };
413
- return [cell.value, setValue];
414
- }
415
- function useRef(initial) {
416
- const i = _hookIdx++;
417
- if (!_hookCells[i]) _hookCells[i] = { current: initial };
418
- return _hookCells[i];
419
- }
420
- function useMemo(compute, deps) {
421
- const i = _hookIdx++;
422
- const cell = _hookCells[i] || (_hookCells[i] = { deps: null, value: undefined });
423
- if (cell.deps === null || !_sameDeps(cell.deps, deps)) {
424
- cell.value = compute();
425
- cell.deps = deps ? deps.slice() : null;
426
- }
427
- return cell.value;
428
- }
429
- function useCallback(fn, deps) { return useMemo(() => fn, deps); }
430
- // useReducer — implemented as a thin wrapper over useState so agents
431
- // that know the pattern can reach for it. \`dispatch(action)\` calls
432
- // reducer(state, action) and schedules a re-render.
433
- function useReducer(reducer, initial, init) {
434
- const [state, setState] = useState(init ? init(initial) : initial);
435
- const dispatch = useCallback(function(action) {
436
- setState(function(prev) { return reducer(prev, action); });
437
- }, [reducer]);
438
- return [state, dispatch];
439
- }
440
- function useEffect(fn, deps) {
441
- const i = _hookIdx++;
442
- const cell = _hookCells[i] || (_hookCells[i] = { deps: null, cleanup: null });
443
- const changed = cell.deps === null || !_sameDeps(cell.deps, deps);
444
- if (changed) {
445
- if (typeof cell.cleanup === 'function') { try { cell.cleanup(); } catch (err) { console.warn('[loxia] effect cleanup threw', err); } }
446
- cell.deps = deps ? deps.slice() : null;
447
- // Defer until after DOM paint, matching React semantics.
448
- setTimeout(() => {
449
- try { cell.cleanup = fn() || null; }
450
- catch (err) {
451
- if (window.__loxiaReportError) window.__loxiaReportError(err, 'effect');
452
- else console.warn('[loxia] effect threw', err);
453
- }
454
- }, 0);
455
- }
456
- }
457
-
458
- /* ---------- mount API ---------- */
459
- let _agentComponent = null;
460
- let _currentProps = null;
461
- function _reRender() {
462
- if (!_agentComponent || !_rootEl) return;
463
- _hookIdx = 0; // reset hook counter for this render pass
464
- let vnode = _agentComponent({ ...(_currentProps || {}) });
465
- // Factory-style agent code (return function App(){...};): the
466
- // outer wrapper returned a function rather than a vnode. Promote
467
- // it to the real component and re-run so hooks run in the RIGHT
468
- // component's scope.
469
- if (typeof vnode === 'function') {
470
- _agentComponent = vnode;
471
- _hookIdx = 0;
472
- vnode = _agentComponent({ ...(_currentProps || {}) });
473
- }
474
- renderToRoot(vnode, _rootEl);
475
- }
476
-
477
- window.loxia = {
478
- h, html, render: (component, initialProps) => {
479
- _agentComponent = component;
480
- _currentProps = initialProps || {};
481
- const root = document.getElementById('root') || document.body;
482
- _rootEl = root;
483
- _reRender();
484
- },
485
- sendEvent, onUpdate, requestHeight,
486
- useState, useEffect, useMemo, useCallback, useRef, useReducer,
487
- primitives: { LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol },
488
- };
489
- // Expose as bare globals AND as properties on h, so all of these work:
490
- // h.useState, loxia.useState, and bare useState
491
- // const { useState } = h; (← what agents keep writing — now works)
492
- // Bare globals — every one of these also exists under the namespace
493
- // aliases (React.X, preact.X, etc.) so agents can write bare OR
494
- // namespaced without thinking about it.
495
- const _Fragment = function Fragment(props){ return props && props.children; };
496
- Object.assign(window, {
497
- h, html, createElement: h, Fragment: _Fragment,
498
- LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol,
499
- useState, useEffect, useMemo, useCallback, useRef, useReducer,
500
- });
501
- Object.assign(h, { useState, useEffect, useMemo, useCallback, useRef, useReducer });
502
-
503
- // Namespace aliases. Agents are trained on online tutorials that use a
504
- // variety of names — htmPreact, preact, preactHooks, React, htm, etc.
505
- // Rather than fight the training data name-by-name (whack-a-mole),
506
- // we do two things:
507
- //
508
- // 1. Enumerate every plausible global name.
509
- // 2. Wrap the namespace object in a Proxy so accessing an unknown
510
- // property (e.g. 'preact.useLayoutEffect' or 'React.Children')
511
- // doesn't throw — it returns a clearly-named no-op we can point
512
- // the agent at. Better to fail loudly with "useLayoutEffect is
513
- // not implemented in this runtime" than with a cryptic undefined.
514
- //
515
- // If an identifier we didn't list comes up, add it to NS_NAMES and the
516
- // agent's next attempt will succeed. New additions are always O(1).
517
- const _nsBase = {
518
- h, html, render: window.loxia.render,
519
- useState, useEffect, useMemo, useCallback, useRef, useReducer,
520
- createElement: h,
521
- Fragment: function Fragment(props){ return props && props.children; },
522
- LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol,
523
- };
524
- // Self-reference so "import X from 'preact'" (X.default pattern) works.
525
- _nsBase.default = _nsBase;
526
-
527
- // Known-missing APIs. Return a stub (function OR class constructor)
528
- // that throws with a specific, actionable message instead of
529
- // undefined. The agent's next-turn feedback sees the API name
530
- // explicitly, so retry paths are direct — no guessing why
531
- // \`class X extends React.Component\` failed with "undefined is not a
532
- // constructor." This list is the SINGLE SOURCE OF TRUTH; the tool
533
- // description references it by name and tests assert alignment.
534
- //
535
- // Split into two groups:
536
- // - _notImplementedClasses: used with \`new\` / \`extends\`; we return
537
- // a class whose constructor throws with the specific name.
538
- // - _notImplementedFns: everything else — a function that throws.
539
- const _notImplementedClasses = new Set([
540
- 'Component', 'PureComponent',
541
- ]);
542
- const _notImplementedFns = new Set([
543
- // Hooks we do not implement
544
- 'useLayoutEffect', 'useImperativeHandle', 'useContext',
545
- 'useDeferredValue', 'useTransition', 'useId', 'useSyncExternalStore',
546
- 'useErrorBoundary',
547
- // Non-hook APIs
548
- 'createContext', 'createRef', 'forwardRef', 'memo',
549
- 'lazy', 'Suspense', 'StrictMode', 'Children', 'cloneElement',
550
- 'isValidElement',
551
- ]);
552
- function _makeNotImplementedFn(key) {
553
- return function notImplemented() {
554
- throw new Error(
555
- "'" + key + "' is not implemented in this widget runtime. " +
556
- 'Supported hooks: useState, useEffect, useMemo, useCallback, useRef. ' +
557
- 'Supported primitives: h, html, LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol. ' +
558
- 'This runtime is function-components-only (no class components, no context, no suspense).'
559
- );
560
- };
561
- }
562
- function _makeNotImplementedClass(key) {
563
- // Returning a class (rather than a plain function) makes the message
564
- // land correctly whether the agent does \`new X()\` or \`class Y extends X\`.
565
- const C = function(){};
566
- C.prototype = {};
567
- // Subclass attempts: \`class Y extends Component { ... }\` will run our
568
- // constructor when \`super()\` is called from Y's constructor.
569
- C.prototype.constructor = function() {
570
- throw new Error(
571
- "'" + key + "' is not implemented in this widget runtime. " +
572
- 'Class components are not supported — use a function component ' +
573
- 'with useState/useEffect hooks instead.'
574
- );
575
- };
576
- // Also throw if used without new (e.g. \`Component()\` direct call).
577
- const asFn = function() {
578
- throw new Error("'" + key + "' is not implemented in this widget runtime (class components not supported — use function components with useState).");
579
- };
580
- asFn.prototype = C.prototype;
581
- return asFn;
582
- }
583
- const _ns = new Proxy(_nsBase, {
584
- get(target, key) {
585
- if (key in target) return target[key];
586
- if (typeof key !== 'string') return undefined;
587
- if (_notImplementedClasses.has(key)) return _makeNotImplementedClass(key);
588
- if (_notImplementedFns.has(key)) return _makeNotImplementedFn(key);
589
- return undefined;
590
- },
591
- });
592
-
593
- // Expose as bare globals too — agents that write \`class X extends Component\`
594
- // without any namespace still hit the named error.
595
- for (const _className of _notImplementedClasses) {
596
- window[_className] = _makeNotImplementedClass(_className);
597
- }
598
- for (const _fnName of _notImplementedFns) {
599
- // Only set if not already defined (don't override anything legitimate).
600
- if (!(_fnName in window)) window[_fnName] = _makeNotImplementedFn(_fnName);
601
- }
602
-
603
- // Every known alias points at the SAME proxy, so agents can reach for
604
- // whichever name their training data surfaced and the destructure
605
- // pattern works uniformly: const { useState } = <any-of-these>.
606
- const NS_NAMES = [
607
- // htm + preact ecosystem
608
- 'htmPreact', 'htm_preact', 'preactHtm', 'htm', 'Htm',
609
- 'preact', 'Preact', 'preactjs',
610
- // hooks-specific package names
611
- 'preactHooks', 'PreactHooks', 'preact_hooks',
612
- 'hooks', 'Hooks',
613
- // React ecosystem (we aren't React but the surface matches closely)
614
- 'React', 'react',
615
- 'reactHooks', 'ReactHooks', 'react_hooks',
616
- // Signals / standalone bundles that sometimes appear
617
- 'preactStandalone', 'preact_standalone',
618
- ];
619
- for (const _name of NS_NAMES) {
620
- window[_name] = _ns;
621
- }
622
- // ReactDOM gets a minimal render shim — React code often uses
623
- // ReactDOM.render(vnode, target) as a mount call. We map it into loxia.render.
624
- window.ReactDOM = {
625
- render: function(vnode, target) {
626
- window.loxia.render(function() { return vnode; }, {});
627
- },
628
- createRoot: function() {
629
- return {
630
- render: function(vnode) {
631
- window.loxia.render(function() { return vnode; }, {});
632
- },
633
- unmount: function() {},
634
- };
635
- },
636
- };
637
- })();
638
- `;
639
-
640
- export default WIDGET_RUNTIME;
1
+ /**
2
+ * Widget runtime bundle — STRING, served to every jsx-mode iframe.
3
+ *
4
+ * This file is a Node module that exports a plain string. The string is
5
+ * JavaScript that runs INSIDE the sandboxed iframe. Keep it self-contained:
6
+ * the iframe has null origin, no network (CSP connect-src 'none'), and
7
+ * no same-origin access — there is no way to lazy-load anything.
8
+ *
9
+ * Why inline everything as a single string (not a bundled file served
10
+ * via <script src>): the iframe's CSP is script-src 'self' which, for a
11
+ * srcdoc document, resolves 'self' to a unique/null origin that can't
12
+ * match any URL. Inline scripts (via 'unsafe-inline' in CSP) are the
13
+ * only reliable path.
14
+ *
15
+ * Contains:
16
+ * - A minimal Preact-flavoured h()/render() (hand-rolled, ~500 LOC)
17
+ * - htm-style tagged-template compiler (~200 LOC)
18
+ * - The loxia.* SDK (postMessage bridge)
19
+ * - A small primitive catalogue: Card, Button, Input, Text, Metric, Row, Col
20
+ *
21
+ * MVP note: the primitive catalog is intentionally minimal. Agents can
22
+ * use plain HTML elements in their render functions too — `h('div', ...)`
23
+ * and `html\`<div>...\`` both work. Primitives are ergonomics.
24
+ */
25
+
26
+ export const WIDGET_RUNTIME = `
27
+ /* ==== Loxia widget runtime v1 ==== */
28
+ (function () {
29
+ 'use strict';
30
+
31
+ /* ---------- tiny VDOM (Preact-flavoured) ---------- */
32
+ // VNode: { type, props, children }
33
+ function h(type, props, ...children) {
34
+ return { type, props: props || {}, children: children.flat(Infinity).filter(c => c != null && c !== false) };
35
+ }
36
+
37
+ // Render a VNode/text into a real DOM node. Very small — re-renders
38
+ // replace the whole subtree rather than diffing (fine for MVP widget
39
+ // sizes; can upgrade later).
40
+ function createDom(v) {
41
+ if (v == null || v === false) return document.createTextNode('');
42
+ if (typeof v === 'string' || typeof v === 'number') return document.createTextNode(String(v));
43
+ if (typeof v.type === 'function') {
44
+ // Component — call with props + children and recurse.
45
+ const childrenArg = v.children.length === 1 ? v.children[0] : v.children;
46
+ const out = v.type({ ...v.props, children: childrenArg });
47
+ return createDom(out);
48
+ }
49
+ // Native element
50
+ const el = document.createElement(v.type);
51
+ for (const [k, val] of Object.entries(v.props || {})) {
52
+ if (val == null || val === false) continue;
53
+ if (k === 'children') continue;
54
+ if (k === 'style' && typeof val === 'object') {
55
+ Object.assign(el.style, val);
56
+ } else if (k === 'className') {
57
+ el.setAttribute('class', String(val));
58
+ } else if (k === 'dangerouslySetInnerHTML') {
59
+ // Deliberately not supported — users who want HTML can use kind:'html'.
60
+ console.warn('[loxia] dangerouslySetInnerHTML is not supported in jsx widgets');
61
+ } else if (k.startsWith('on') && typeof val === 'function') {
62
+ el.addEventListener(k.slice(2).toLowerCase(), val);
63
+ } else {
64
+ el.setAttribute(k, String(val));
65
+ }
66
+ }
67
+ for (const child of v.children) {
68
+ el.appendChild(createDom(child));
69
+ }
70
+ return el;
71
+ }
72
+
73
+ let _rootEl = null;
74
+ let _rootVNode = null;
75
+ function renderToRoot(vnode, container) {
76
+ _rootEl = container;
77
+ _rootVNode = vnode;
78
+ container.innerHTML = '';
79
+ container.appendChild(createDom(vnode));
80
+ scheduleHeight();
81
+ }
82
+
83
+ /* ---------- htm-ish tagged-template compiler ---------- */
84
+ // Parses: html\`<Card title=\${t}><Button onClick=\${f}>hi<//></>\`
85
+ // into a VNode tree using the h() above. Small but sufficient for
86
+ // widget-shape templates (elements, attributes, children, closing tags
87
+ // in "//" form, component references via \${Component}).
88
+ //
89
+ // Adapted from the public-domain htm algorithm; rewritten terse for inlining.
90
+ const CACHE = new WeakMap();
91
+ function html(strings) {
92
+ const values = Array.prototype.slice.call(arguments, 1);
93
+ let tree = CACHE.get(strings);
94
+ if (!tree) {
95
+ tree = parseTemplate(strings);
96
+ CACHE.set(strings, tree);
97
+ }
98
+ return evalTree(tree, values);
99
+ }
100
+
101
+ // Parse the template array into an instruction list we can replay with values.
102
+ // Instructions: [kind, ...]
103
+ // [1, type] OPEN (type is string|index)
104
+ // [2] CLOSE
105
+ // [3, name, valueOrIdx, isIndex] ATTR
106
+ // [4, textOrIdx, isIndex] CHILD
107
+ function parseTemplate(strings) {
108
+ const insts = [];
109
+ let buf = '';
110
+ let mode = 'text'; // text | tag | attr
111
+ for (let i = 0; i < strings.length; i++) {
112
+ const s = strings[i];
113
+ for (let j = 0; j < s.length; j++) {
114
+ const c = s[j];
115
+ if (mode === 'text') {
116
+ if (c === '<') {
117
+ if (buf.trim()) insts.push([4, buf, false]);
118
+ buf = '';
119
+ mode = 'tag';
120
+ } else {
121
+ buf += c;
122
+ }
123
+ } else if (mode === 'tag') {
124
+ if (c === '>') {
125
+ commitTag(insts, buf);
126
+ buf = '';
127
+ mode = 'text';
128
+ } else if (/\\s/.test(c) && buf) {
129
+ commitTag(insts, buf);
130
+ buf = '';
131
+ mode = 'attr';
132
+ } else if (c === '/' && j + 1 < s.length && s[j + 1] === '>') {
133
+ // self-close: <Foo/> — commit then close
134
+ commitTag(insts, buf);
135
+ insts.push([2]);
136
+ buf = '';
137
+ j++;
138
+ mode = 'text';
139
+ } else {
140
+ buf += c;
141
+ }
142
+ } else if (mode === 'attr') {
143
+ if (c === '>') {
144
+ if (buf.trim()) parseAttr(insts, buf);
145
+ buf = '';
146
+ mode = 'text';
147
+ } else if (c === '/' && j + 1 < s.length && s[j + 1] === '>') {
148
+ if (buf.trim()) parseAttr(insts, buf);
149
+ insts.push([2]);
150
+ buf = '';
151
+ j++;
152
+ mode = 'text';
153
+ } else {
154
+ buf += c;
155
+ }
156
+ }
157
+ }
158
+ // End of string segment — the value at index i goes next.
159
+ // (Tagged template invariant: strings.length === values.length + 1,
160
+ // so "there is a value after strings[i]" iff i < strings.length - 1.
161
+ // We can't reference values here — parseTemplate runs with only the
162
+ // strings array; values are substituted later in evalTree.)
163
+ if (i < strings.length - 1) {
164
+ if (mode === 'text') {
165
+ if (buf) insts.push([4, buf, false]);
166
+ buf = '';
167
+ insts.push([4, i, true]);
168
+ } else if (mode === 'attr') {
169
+ const trimmed = buf.trim();
170
+ if (trimmed.endsWith('=')) {
171
+ // buf may contain earlier COMPLETED attrs followed by a new
172
+ // name ending in "=". Example: 'id="b" onClick=' → the
173
+ // earlier part 'id="b"' is a complete attr we must run
174
+ // through parseAttr; the final word (after last whitespace)
175
+ // is the name of the interpolated attribute.
176
+ const withoutEq = trimmed.slice(0, -1);
177
+ const m = withoutEq.match(/^([\\s\\S]*?)(\\S+)\\s*$/);
178
+ if (m && m[1].trim()) {
179
+ parseAttr(insts, m[1].trim());
180
+ insts.push([3, m[2].trim(), i, true]);
181
+ } else {
182
+ insts.push([3, withoutEq.trim(), i, true]);
183
+ }
184
+ } else if (trimmed === '') {
185
+ // spread — not supported in MVP; ignore
186
+ } else {
187
+ // Something like 'id="b" onClick' (boolean-ish / \${Comp}-as-type).
188
+ // parseAttr splits multi-attrs; last token becomes boolean or
189
+ // value-holder depending on our interpretation. Keep prior
190
+ // behaviour — pass the whole thing.
191
+ parseAttr(insts, trimmed + '=' + JSON.stringify('__val__' + i));
192
+ }
193
+ buf = '';
194
+ } else if (mode === 'tag') {
195
+ // opener is the value — \${Comp}
196
+ insts.push([1, i, true]);
197
+ buf = '';
198
+ mode = 'attr';
199
+ }
200
+ }
201
+ }
202
+ if (buf.trim()) insts.push([4, buf, false]);
203
+ return insts;
204
+ }
205
+
206
+ function commitTag(insts, raw) {
207
+ const t = raw.trim();
208
+ if (!t) return;
209
+ if (t.startsWith('/')) {
210
+ insts.push([2]);
211
+ } else {
212
+ insts.push([1, t, false]);
213
+ }
214
+ }
215
+
216
+ function parseAttr(insts, raw) {
217
+ // Attrs separated by whitespace, each as "name" or "name=value" or 'name="value"'
218
+ const parts = raw.match(/[^\\s"']+="[^"]*"|[^\\s"']+='[^']*'|[^\\s"']+/g) || [];
219
+ for (const part of parts) {
220
+ const eq = part.indexOf('=');
221
+ if (eq === -1) {
222
+ insts.push([3, part, true, false]); // boolean attr
223
+ } else {
224
+ const name = part.slice(0, eq);
225
+ let val = part.slice(eq + 1);
226
+ if ((val.startsWith('"') && val.endsWith('"')) ||
227
+ (val.startsWith("'") && val.endsWith("'"))) {
228
+ val = val.slice(1, -1);
229
+ }
230
+ insts.push([3, name, val, false]);
231
+ }
232
+ }
233
+ }
234
+
235
+ // Walk instructions, substituting values, building a tree of {type, props, children}.
236
+ function evalTree(insts, values) {
237
+ const stack = [{ type: '__root__', props: {}, children: [] }];
238
+ for (const inst of insts) {
239
+ const top = stack[stack.length - 1];
240
+ if (inst[0] === 1) {
241
+ const type = inst[2] ? values[inst[1]] : inst[1];
242
+ const node = { type, props: {}, children: [] };
243
+ top.children.push(node);
244
+ stack.push(node);
245
+ } else if (inst[0] === 2) {
246
+ if (stack.length > 1) stack.pop();
247
+ } else if (inst[0] === 3) {
248
+ const [, name, valOrIdx, isIdx] = inst;
249
+ top.props[name] = isIdx ? values[valOrIdx] : valOrIdx;
250
+ } else if (inst[0] === 4) {
251
+ const [, valOrIdx, isIdx] = inst;
252
+ const v = isIdx ? values[valOrIdx] : valOrIdx;
253
+ if (Array.isArray(v)) for (const x of v) top.children.push(x);
254
+ else if (v != null) top.children.push(v);
255
+ }
256
+ }
257
+ const root = stack[0];
258
+ return root.children.length === 1 ? root.children[0] : root.children;
259
+ }
260
+
261
+ /* ---------- primitives (ergonomic wrappers) ---------- */
262
+ function LoxiaCard({ title, children, padding = 'md' }) {
263
+ const pad = padding === 'sm' ? '8px' : padding === 'lg' ? '24px' : '16px';
264
+ return h('div', {
265
+ className: 'loxia-card',
266
+ style: {
267
+ background: 'var(--loxia-card-bg, rgb(var(--gray-50)))',
268
+ border: '1px solid var(--loxia-card-border, rgb(var(--gray-200)))',
269
+ borderRadius: '8px',
270
+ padding: pad,
271
+ color: 'rgb(var(--gray-900))',
272
+ fontFamily: '-apple-system, BlinkMacSystemFont, Segoe UI, sans-serif',
273
+ },
274
+ },
275
+ title ? h('div', { style: { fontWeight: '600', marginBottom: '8px', fontSize: '14px' } }, title) : null,
276
+ children
277
+ );
278
+ }
279
+
280
+ function LoxiaButton({ label, onClick, children, variant = 'primary', disabled }) {
281
+ const bg = variant === 'primary' ? 'rgb(var(--loxia-600))' :
282
+ variant === 'danger' ? '#dc2626' : 'rgb(var(--gray-200))';
283
+ const color = variant === 'primary' || variant === 'danger' ? 'white' : 'rgb(var(--gray-900))';
284
+ return h('button', {
285
+ onClick: disabled ? undefined : onClick,
286
+ disabled,
287
+ style: {
288
+ background: bg, color, border: 'none',
289
+ padding: '6px 14px', borderRadius: '6px', fontSize: '13px',
290
+ cursor: disabled ? 'not-allowed' : 'pointer',
291
+ opacity: disabled ? 0.5 : 1,
292
+ },
293
+ }, label || children);
294
+ }
295
+
296
+ function LoxiaInput({ value, onChange, placeholder, type = 'text' }) {
297
+ return h('input', {
298
+ type, value: value ?? '', placeholder: placeholder ?? '',
299
+ onInput: (e) => onChange && onChange(e.target.value),
300
+ style: {
301
+ padding: '6px 10px', border: '1px solid rgb(var(--gray-300))',
302
+ borderRadius: '6px', fontSize: '13px', width: '100%',
303
+ background: 'rgb(var(--gray-50))', color: 'rgb(var(--gray-900))',
304
+ },
305
+ });
306
+ }
307
+
308
+ function LoxiaText({ children, tone = 'default', size = 'md' }) {
309
+ const color = tone === 'muted' ? 'rgb(var(--gray-500))' : 'rgb(var(--gray-900))';
310
+ const fs = size === 'sm' ? '12px' : size === 'lg' ? '16px' : '14px';
311
+ return h('span', { style: { color, fontSize: fs } }, children);
312
+ }
313
+
314
+ function LoxiaMetric({ label, value, unit }) {
315
+ return h('div', { style: { display: 'flex', flexDirection: 'column', gap: '2px' } },
316
+ h('div', { style: { fontSize: '11px', color: 'rgb(var(--gray-500))', textTransform: 'uppercase', letterSpacing: '0.05em' } }, label),
317
+ h('div', { style: { fontSize: '20px', fontWeight: '600', color: 'rgb(var(--gray-900))' } },
318
+ value, unit ? h('span', { style: { fontSize: '13px', fontWeight: '400', color: 'rgb(var(--gray-500))', marginLeft: '4px' } }, unit) : null
319
+ )
320
+ );
321
+ }
322
+
323
+ function LoxiaRow({ children, gap = 'md', justify = 'start', align = 'start' }) {
324
+ const g = gap === 'sm' ? '6px' : gap === 'lg' ? '20px' : '12px';
325
+ return h('div', { style: { display: 'flex', flexDirection: 'row', gap: g, justifyContent: justify, alignItems: align, flexWrap: 'wrap' } }, children);
326
+ }
327
+ function LoxiaCol({ children, gap = 'md' }) {
328
+ const g = gap === 'sm' ? '6px' : gap === 'lg' ? '20px' : '12px';
329
+ return h('div', { style: { display: 'flex', flexDirection: 'column', gap: g } }, children);
330
+ }
331
+
332
+ /* ---------- postMessage SDK ---------- */
333
+ const _updateListeners = [];
334
+ function sendEvent(evt) {
335
+ try {
336
+ window.parent.postMessage({ __loxia: true, type: 'event', widgetId: window.__loxiaWidgetId, payload: evt }, '*');
337
+ } catch (err) {
338
+ console.warn('[loxia] sendEvent failed', err);
339
+ }
340
+ }
341
+ function onUpdate(cb) { if (typeof cb === 'function') _updateListeners.push(cb); }
342
+ function requestHeight(px) {
343
+ try {
344
+ window.parent.postMessage({ __loxia: true, type: 'resize', widgetId: window.__loxiaWidgetId, height: px }, '*');
345
+ } catch {}
346
+ }
347
+
348
+ window.addEventListener('message', (e) => {
349
+ if (!e.data || e.data.__loxia !== true) return;
350
+ if (e.source !== window.parent) return;
351
+ if (e.data.type === 'update' && e.data.props) {
352
+ _updateListeners.forEach(cb => { try { cb(e.data.props); } catch (err) { console.warn('[loxia] update handler threw', err); } });
353
+ _reRender();
354
+ } else if (e.data.type === 'theme' && e.data.tokens) {
355
+ applyThemeTokens(e.data.tokens);
356
+ }
357
+ });
358
+
359
+ function applyThemeTokens(tokens) {
360
+ const root = document.documentElement;
361
+ for (const [k, v] of Object.entries(tokens)) {
362
+ root.style.setProperty('--' + k, v);
363
+ }
364
+ }
365
+
366
+ /* ---------- auto-resize ---------- */
367
+ let _heightDebounce = null;
368
+ function scheduleHeight() {
369
+ if (_heightDebounce) clearTimeout(_heightDebounce);
370
+ _heightDebounce = setTimeout(() => {
371
+ const h = Math.ceil(document.body.scrollHeight);
372
+ requestHeight(h);
373
+ }, 50);
374
+ }
375
+
376
+ if (typeof ResizeObserver !== 'undefined') {
377
+ const ro = new ResizeObserver(() => scheduleHeight());
378
+ document.addEventListener('DOMContentLoaded', () => ro.observe(document.body));
379
+ } else {
380
+ // Fallback: just post once after load.
381
+ document.addEventListener('DOMContentLoaded', () => setTimeout(scheduleHeight, 50));
382
+ }
383
+
384
+ /* ---------- hooks (for the ROOT component only) ---------- */
385
+ // Agents are heavily trained on React hooks and reach for useState
386
+ // reflexively. Supporting a minimal hooks set for the root component
387
+ // eliminates a whole class of "widget didn't render" failures.
388
+ //
389
+ // Scope limitation: hooks are tracked by CALL ORDER in the root render.
390
+ // Nested components calling hooks would break the call-order contract
391
+ // (different trees, different orders) — so we only guarantee correctness
392
+ // for the root App function. The tool description tells the agent to
393
+ // keep state in the root component, which is almost always fine.
394
+ const _hookCells = [];
395
+ let _hookIdx = 0;
396
+ function _sameDeps(a, b) {
397
+ if (a === b) return true;
398
+ if (!a || !b) return false;
399
+ if (a.length !== b.length) return false;
400
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
401
+ return true;
402
+ }
403
+ function useState(initial) {
404
+ const i = _hookIdx++;
405
+ if (!_hookCells[i]) _hookCells[i] = { value: typeof initial === 'function' ? initial() : initial };
406
+ const cell = _hookCells[i];
407
+ const setValue = (v) => {
408
+ const next = typeof v === 'function' ? v(cell.value) : v;
409
+ if (next === cell.value) return;
410
+ cell.value = next;
411
+ _reRender();
412
+ };
413
+ return [cell.value, setValue];
414
+ }
415
+ function useRef(initial) {
416
+ const i = _hookIdx++;
417
+ if (!_hookCells[i]) _hookCells[i] = { current: initial };
418
+ return _hookCells[i];
419
+ }
420
+ function useMemo(compute, deps) {
421
+ const i = _hookIdx++;
422
+ const cell = _hookCells[i] || (_hookCells[i] = { deps: null, value: undefined });
423
+ if (cell.deps === null || !_sameDeps(cell.deps, deps)) {
424
+ cell.value = compute();
425
+ cell.deps = deps ? deps.slice() : null;
426
+ }
427
+ return cell.value;
428
+ }
429
+ function useCallback(fn, deps) { return useMemo(() => fn, deps); }
430
+ // useReducer — implemented as a thin wrapper over useState so agents
431
+ // that know the pattern can reach for it. \`dispatch(action)\` calls
432
+ // reducer(state, action) and schedules a re-render.
433
+ function useReducer(reducer, initial, init) {
434
+ const [state, setState] = useState(init ? init(initial) : initial);
435
+ const dispatch = useCallback(function(action) {
436
+ setState(function(prev) { return reducer(prev, action); });
437
+ }, [reducer]);
438
+ return [state, dispatch];
439
+ }
440
+ function useEffect(fn, deps) {
441
+ const i = _hookIdx++;
442
+ const cell = _hookCells[i] || (_hookCells[i] = { deps: null, cleanup: null });
443
+ const changed = cell.deps === null || !_sameDeps(cell.deps, deps);
444
+ if (changed) {
445
+ if (typeof cell.cleanup === 'function') { try { cell.cleanup(); } catch (err) { console.warn('[loxia] effect cleanup threw', err); } }
446
+ cell.deps = deps ? deps.slice() : null;
447
+ // Defer until after DOM paint, matching React semantics.
448
+ setTimeout(() => {
449
+ try { cell.cleanup = fn() || null; }
450
+ catch (err) {
451
+ if (window.__loxiaReportError) window.__loxiaReportError(err, 'effect');
452
+ else console.warn('[loxia] effect threw', err);
453
+ }
454
+ }, 0);
455
+ }
456
+ }
457
+
458
+ /* ---------- mount API ---------- */
459
+ let _agentComponent = null;
460
+ let _currentProps = null;
461
+ function _reRender() {
462
+ if (!_agentComponent || !_rootEl) return;
463
+ _hookIdx = 0; // reset hook counter for this render pass
464
+ let vnode = _agentComponent({ ...(_currentProps || {}) });
465
+ // Factory-style agent code (return function App(){...};): the
466
+ // outer wrapper returned a function rather than a vnode. Promote
467
+ // it to the real component and re-run so hooks run in the RIGHT
468
+ // component's scope.
469
+ if (typeof vnode === 'function') {
470
+ _agentComponent = vnode;
471
+ _hookIdx = 0;
472
+ vnode = _agentComponent({ ...(_currentProps || {}) });
473
+ }
474
+ renderToRoot(vnode, _rootEl);
475
+ }
476
+
477
+ window.loxia = {
478
+ h, html, render: (component, initialProps) => {
479
+ _agentComponent = component;
480
+ _currentProps = initialProps || {};
481
+ const root = document.getElementById('root') || document.body;
482
+ _rootEl = root;
483
+ _reRender();
484
+ },
485
+ sendEvent, onUpdate, requestHeight,
486
+ useState, useEffect, useMemo, useCallback, useRef, useReducer,
487
+ primitives: { LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol },
488
+ };
489
+ // Expose as bare globals AND as properties on h, so all of these work:
490
+ // h.useState, loxia.useState, and bare useState
491
+ // const { useState } = h; (← what agents keep writing — now works)
492
+ // Bare globals — every one of these also exists under the namespace
493
+ // aliases (React.X, preact.X, etc.) so agents can write bare OR
494
+ // namespaced without thinking about it.
495
+ const _Fragment = function Fragment(props){ return props && props.children; };
496
+ Object.assign(window, {
497
+ h, html, createElement: h, Fragment: _Fragment,
498
+ LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol,
499
+ useState, useEffect, useMemo, useCallback, useRef, useReducer,
500
+ });
501
+ Object.assign(h, { useState, useEffect, useMemo, useCallback, useRef, useReducer });
502
+
503
+ // Namespace aliases. Agents are trained on online tutorials that use a
504
+ // variety of names — htmPreact, preact, preactHooks, React, htm, etc.
505
+ // Rather than fight the training data name-by-name (whack-a-mole),
506
+ // we do two things:
507
+ //
508
+ // 1. Enumerate every plausible global name.
509
+ // 2. Wrap the namespace object in a Proxy so accessing an unknown
510
+ // property (e.g. 'preact.useLayoutEffect' or 'React.Children')
511
+ // doesn't throw — it returns a clearly-named no-op we can point
512
+ // the agent at. Better to fail loudly with "useLayoutEffect is
513
+ // not implemented in this runtime" than with a cryptic undefined.
514
+ //
515
+ // If an identifier we didn't list comes up, add it to NS_NAMES and the
516
+ // agent's next attempt will succeed. New additions are always O(1).
517
+ const _nsBase = {
518
+ h, html, render: window.loxia.render,
519
+ useState, useEffect, useMemo, useCallback, useRef, useReducer,
520
+ createElement: h,
521
+ Fragment: function Fragment(props){ return props && props.children; },
522
+ LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol,
523
+ };
524
+ // Self-reference so "import X from 'preact'" (X.default pattern) works.
525
+ _nsBase.default = _nsBase;
526
+
527
+ // Known-missing APIs. Return a stub (function OR class constructor)
528
+ // that throws with a specific, actionable message instead of
529
+ // undefined. The agent's next-turn feedback sees the API name
530
+ // explicitly, so retry paths are direct — no guessing why
531
+ // \`class X extends React.Component\` failed with "undefined is not a
532
+ // constructor." This list is the SINGLE SOURCE OF TRUTH; the tool
533
+ // description references it by name and tests assert alignment.
534
+ //
535
+ // Split into two groups:
536
+ // - _notImplementedClasses: used with \`new\` / \`extends\`; we return
537
+ // a class whose constructor throws with the specific name.
538
+ // - _notImplementedFns: everything else — a function that throws.
539
+ const _notImplementedClasses = new Set([
540
+ 'Component', 'PureComponent',
541
+ ]);
542
+ const _notImplementedFns = new Set([
543
+ // Hooks we do not implement
544
+ 'useLayoutEffect', 'useImperativeHandle', 'useContext',
545
+ 'useDeferredValue', 'useTransition', 'useId', 'useSyncExternalStore',
546
+ 'useErrorBoundary',
547
+ // Non-hook APIs
548
+ 'createContext', 'createRef', 'forwardRef', 'memo',
549
+ 'lazy', 'Suspense', 'StrictMode', 'Children', 'cloneElement',
550
+ 'isValidElement',
551
+ ]);
552
+ function _makeNotImplementedFn(key) {
553
+ return function notImplemented() {
554
+ throw new Error(
555
+ "'" + key + "' is not implemented in this widget runtime. " +
556
+ 'Supported hooks: useState, useEffect, useMemo, useCallback, useRef. ' +
557
+ 'Supported primitives: h, html, LoxiaCard, LoxiaButton, LoxiaInput, LoxiaText, LoxiaMetric, LoxiaRow, LoxiaCol. ' +
558
+ 'This runtime is function-components-only (no class components, no context, no suspense).'
559
+ );
560
+ };
561
+ }
562
+ function _makeNotImplementedClass(key) {
563
+ // Returning a class (rather than a plain function) makes the message
564
+ // land correctly whether the agent does \`new X()\` or \`class Y extends X\`.
565
+ const C = function(){};
566
+ C.prototype = {};
567
+ // Subclass attempts: \`class Y extends Component { ... }\` will run our
568
+ // constructor when \`super()\` is called from Y's constructor.
569
+ C.prototype.constructor = function() {
570
+ throw new Error(
571
+ "'" + key + "' is not implemented in this widget runtime. " +
572
+ 'Class components are not supported — use a function component ' +
573
+ 'with useState/useEffect hooks instead.'
574
+ );
575
+ };
576
+ // Also throw if used without new (e.g. \`Component()\` direct call).
577
+ const asFn = function() {
578
+ throw new Error("'" + key + "' is not implemented in this widget runtime (class components not supported — use function components with useState).");
579
+ };
580
+ asFn.prototype = C.prototype;
581
+ return asFn;
582
+ }
583
+ const _ns = new Proxy(_nsBase, {
584
+ get(target, key) {
585
+ if (key in target) return target[key];
586
+ if (typeof key !== 'string') return undefined;
587
+ if (_notImplementedClasses.has(key)) return _makeNotImplementedClass(key);
588
+ if (_notImplementedFns.has(key)) return _makeNotImplementedFn(key);
589
+ return undefined;
590
+ },
591
+ });
592
+
593
+ // Expose as bare globals too — agents that write \`class X extends Component\`
594
+ // without any namespace still hit the named error.
595
+ for (const _className of _notImplementedClasses) {
596
+ window[_className] = _makeNotImplementedClass(_className);
597
+ }
598
+ for (const _fnName of _notImplementedFns) {
599
+ // Only set if not already defined (don't override anything legitimate).
600
+ if (!(_fnName in window)) window[_fnName] = _makeNotImplementedFn(_fnName);
601
+ }
602
+
603
+ // Every known alias points at the SAME proxy, so agents can reach for
604
+ // whichever name their training data surfaced and the destructure
605
+ // pattern works uniformly: const { useState } = <any-of-these>.
606
+ const NS_NAMES = [
607
+ // htm + preact ecosystem
608
+ 'htmPreact', 'htm_preact', 'preactHtm', 'htm', 'Htm',
609
+ 'preact', 'Preact', 'preactjs',
610
+ // hooks-specific package names
611
+ 'preactHooks', 'PreactHooks', 'preact_hooks',
612
+ 'hooks', 'Hooks',
613
+ // React ecosystem (we aren't React but the surface matches closely)
614
+ 'React', 'react',
615
+ 'reactHooks', 'ReactHooks', 'react_hooks',
616
+ // Signals / standalone bundles that sometimes appear
617
+ 'preactStandalone', 'preact_standalone',
618
+ ];
619
+ for (const _name of NS_NAMES) {
620
+ window[_name] = _ns;
621
+ }
622
+ // ReactDOM gets a minimal render shim — React code often uses
623
+ // ReactDOM.render(vnode, target) as a mount call. We map it into loxia.render.
624
+ window.ReactDOM = {
625
+ render: function(vnode, target) {
626
+ window.loxia.render(function() { return vnode; }, {});
627
+ },
628
+ createRoot: function() {
629
+ return {
630
+ render: function(vnode) {
631
+ window.loxia.render(function() { return vnode; }, {});
632
+ },
633
+ unmount: function() {},
634
+ };
635
+ },
636
+ };
637
+ })();
638
+ `;
639
+
640
+ export default WIDGET_RUNTIME;