@fraziym/axoniz 0.1.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 (512) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/agents/definition.d.ts +15 -0
  4. package/dist/agents/definition.d.ts.map +1 -0
  5. package/dist/agents/definition.js +41 -0
  6. package/dist/agents/definition.js.map +1 -0
  7. package/dist/agents/index.d.ts +12 -0
  8. package/dist/agents/index.d.ts.map +1 -0
  9. package/dist/agents/index.js +11 -0
  10. package/dist/agents/index.js.map +1 -0
  11. package/dist/agents/registry.d.ts +17 -0
  12. package/dist/agents/registry.d.ts.map +1 -0
  13. package/dist/agents/registry.js +23 -0
  14. package/dist/agents/registry.js.map +1 -0
  15. package/dist/agents/specialized.d.ts +31 -0
  16. package/dist/agents/specialized.d.ts.map +1 -0
  17. package/dist/agents/specialized.js +75 -0
  18. package/dist/agents/specialized.js.map +1 -0
  19. package/dist/awareness/index.d.ts +14 -0
  20. package/dist/awareness/index.d.ts.map +1 -0
  21. package/dist/awareness/index.js +22 -0
  22. package/dist/awareness/index.js.map +1 -0
  23. package/dist/awareness/service.d.ts +180 -0
  24. package/dist/awareness/service.d.ts.map +1 -0
  25. package/dist/awareness/service.js +789 -0
  26. package/dist/awareness/service.js.map +1 -0
  27. package/dist/cli/entry.d.ts +13 -0
  28. package/dist/cli/entry.d.ts.map +1 -0
  29. package/dist/cli/entry.js +35 -0
  30. package/dist/cli/entry.js.map +1 -0
  31. package/dist/comms/telegram.d.ts +41 -0
  32. package/dist/comms/telegram.d.ts.map +1 -0
  33. package/dist/comms/telegram.js +332 -0
  34. package/dist/comms/telegram.js.map +1 -0
  35. package/dist/core/agent.d.ts +252 -0
  36. package/dist/core/agent.d.ts.map +1 -0
  37. package/dist/core/agent.js +1399 -0
  38. package/dist/core/agent.js.map +1 -0
  39. package/dist/core/auth.d.ts +23 -0
  40. package/dist/core/auth.d.ts.map +1 -0
  41. package/dist/core/auth.js +113 -0
  42. package/dist/core/auth.js.map +1 -0
  43. package/dist/core/authority.d.ts +118 -0
  44. package/dist/core/authority.d.ts.map +1 -0
  45. package/dist/core/authority.js +402 -0
  46. package/dist/core/authority.js.map +1 -0
  47. package/dist/core/backend/async_queue.d.ts +17 -0
  48. package/dist/core/backend/async_queue.d.ts.map +1 -0
  49. package/dist/core/backend/async_queue.js +66 -0
  50. package/dist/core/backend/async_queue.js.map +1 -0
  51. package/dist/core/backend/index.d.ts +24 -0
  52. package/dist/core/backend/index.d.ts.map +1 -0
  53. package/dist/core/backend/index.js +128 -0
  54. package/dist/core/backend/index.js.map +1 -0
  55. package/dist/core/backend/llama_server.d.ts +39 -0
  56. package/dist/core/backend/llama_server.d.ts.map +1 -0
  57. package/dist/core/backend/llama_server.js +182 -0
  58. package/dist/core/backend/llama_server.js.map +1 -0
  59. package/dist/core/backend/llamacpp.d.ts +40 -0
  60. package/dist/core/backend/llamacpp.d.ts.map +1 -0
  61. package/dist/core/backend/llamacpp.js +200 -0
  62. package/dist/core/backend/llamacpp.js.map +1 -0
  63. package/dist/core/backend/lmstudio.d.ts +53 -0
  64. package/dist/core/backend/lmstudio.d.ts.map +1 -0
  65. package/dist/core/backend/lmstudio.js +274 -0
  66. package/dist/core/backend/lmstudio.js.map +1 -0
  67. package/dist/core/backend/ollama.d.ts +25 -0
  68. package/dist/core/backend/ollama.d.ts.map +1 -0
  69. package/dist/core/backend/ollama.js +86 -0
  70. package/dist/core/backend/ollama.js.map +1 -0
  71. package/dist/core/backend/openai.d.ts +27 -0
  72. package/dist/core/backend/openai.d.ts.map +1 -0
  73. package/dist/core/backend/openai.js +84 -0
  74. package/dist/core/backend/openai.js.map +1 -0
  75. package/dist/core/backend/types.d.ts +73 -0
  76. package/dist/core/backend/types.d.ts.map +1 -0
  77. package/dist/core/backend/types.js +137 -0
  78. package/dist/core/backend/types.js.map +1 -0
  79. package/dist/core/chat_store.d.ts +77 -0
  80. package/dist/core/chat_store.d.ts.map +1 -0
  81. package/dist/core/chat_store.js +332 -0
  82. package/dist/core/chat_store.js.map +1 -0
  83. package/dist/core/cli.d.ts +82 -0
  84. package/dist/core/cli.d.ts.map +1 -0
  85. package/dist/core/cli.js +602 -0
  86. package/dist/core/cli.js.map +1 -0
  87. package/dist/core/config.d.ts +127 -0
  88. package/dist/core/config.d.ts.map +1 -0
  89. package/dist/core/config.js +295 -0
  90. package/dist/core/config.js.map +1 -0
  91. package/dist/core/debug.d.ts +8 -0
  92. package/dist/core/debug.d.ts.map +1 -0
  93. package/dist/core/debug.js +8 -0
  94. package/dist/core/debug.js.map +1 -0
  95. package/dist/core/downloader.d.ts +31 -0
  96. package/dist/core/downloader.d.ts.map +1 -0
  97. package/dist/core/downloader.js +180 -0
  98. package/dist/core/downloader.js.map +1 -0
  99. package/dist/core/errors.d.ts +80 -0
  100. package/dist/core/errors.d.ts.map +1 -0
  101. package/dist/core/errors.js +134 -0
  102. package/dist/core/errors.js.map +1 -0
  103. package/dist/core/extras.d.ts +160 -0
  104. package/dist/core/extras.d.ts.map +1 -0
  105. package/dist/core/extras.js +553 -0
  106. package/dist/core/extras.js.map +1 -0
  107. package/dist/core/health.d.ts +27 -0
  108. package/dist/core/health.d.ts.map +1 -0
  109. package/dist/core/health.js +96 -0
  110. package/dist/core/health.js.map +1 -0
  111. package/dist/core/history.d.ts +50 -0
  112. package/dist/core/history.d.ts.map +1 -0
  113. package/dist/core/history.js +276 -0
  114. package/dist/core/history.js.map +1 -0
  115. package/dist/core/index.d.ts +6 -0
  116. package/dist/core/index.d.ts.map +1 -0
  117. package/dist/core/index.js +6 -0
  118. package/dist/core/index.js.map +1 -0
  119. package/dist/core/intelligence/ast_index.d.ts +255 -0
  120. package/dist/core/intelligence/ast_index.d.ts.map +1 -0
  121. package/dist/core/intelligence/ast_index.js +1369 -0
  122. package/dist/core/intelligence/ast_index.js.map +1 -0
  123. package/dist/core/intelligence/confidence.d.ts +113 -0
  124. package/dist/core/intelligence/confidence.d.ts.map +1 -0
  125. package/dist/core/intelligence/confidence.js +298 -0
  126. package/dist/core/intelligence/confidence.js.map +1 -0
  127. package/dist/core/intelligence/context_compressor.d.ts +80 -0
  128. package/dist/core/intelligence/context_compressor.d.ts.map +1 -0
  129. package/dist/core/intelligence/context_compressor.js +245 -0
  130. package/dist/core/intelligence/context_compressor.js.map +1 -0
  131. package/dist/core/intelligence/daemon.d.ts +247 -0
  132. package/dist/core/intelligence/daemon.d.ts.map +1 -0
  133. package/dist/core/intelligence/daemon.js +842 -0
  134. package/dist/core/intelligence/daemon.js.map +1 -0
  135. package/dist/core/intelligence/index.d.ts +60 -0
  136. package/dist/core/intelligence/index.d.ts.map +1 -0
  137. package/dist/core/intelligence/index.js +101 -0
  138. package/dist/core/intelligence/index.js.map +1 -0
  139. package/dist/core/intelligence/predictor.d.ts +246 -0
  140. package/dist/core/intelligence/predictor.d.ts.map +1 -0
  141. package/dist/core/intelligence/predictor.js +590 -0
  142. package/dist/core/intelligence/predictor.js.map +1 -0
  143. package/dist/core/intelligence/reflex.d.ts +84 -0
  144. package/dist/core/intelligence/reflex.d.ts.map +1 -0
  145. package/dist/core/intelligence/reflex.js +344 -0
  146. package/dist/core/intelligence/reflex.js.map +1 -0
  147. package/dist/core/intelligence/self_correction.d.ts +121 -0
  148. package/dist/core/intelligence/self_correction.d.ts.map +1 -0
  149. package/dist/core/intelligence/self_correction.js +327 -0
  150. package/dist/core/intelligence/self_correction.js.map +1 -0
  151. package/dist/core/intelligence/skill_distiller.d.ts +100 -0
  152. package/dist/core/intelligence/skill_distiller.d.ts.map +1 -0
  153. package/dist/core/intelligence/skill_distiller.js +246 -0
  154. package/dist/core/intelligence/skill_distiller.js.map +1 -0
  155. package/dist/core/intelligence/swarm.d.ts +330 -0
  156. package/dist/core/intelligence/swarm.d.ts.map +1 -0
  157. package/dist/core/intelligence/swarm.js +1064 -0
  158. package/dist/core/intelligence/swarm.js.map +1 -0
  159. package/dist/core/intelligence/trajectory.d.ts +107 -0
  160. package/dist/core/intelligence/trajectory.d.ts.map +1 -0
  161. package/dist/core/intelligence/trajectory.js +330 -0
  162. package/dist/core/intelligence/trajectory.js.map +1 -0
  163. package/dist/core/logger.d.ts +111 -0
  164. package/dist/core/logger.d.ts.map +1 -0
  165. package/dist/core/logger.js +640 -0
  166. package/dist/core/logger.js.map +1 -0
  167. package/dist/core/loop.d.ts +123 -0
  168. package/dist/core/loop.d.ts.map +1 -0
  169. package/dist/core/loop.js +423 -0
  170. package/dist/core/loop.js.map +1 -0
  171. package/dist/core/memory.d.ts +81 -0
  172. package/dist/core/memory.d.ts.map +1 -0
  173. package/dist/core/memory.js +328 -0
  174. package/dist/core/memory.js.map +1 -0
  175. package/dist/core/metrics.d.ts +29 -0
  176. package/dist/core/metrics.d.ts.map +1 -0
  177. package/dist/core/metrics.js +109 -0
  178. package/dist/core/metrics.js.map +1 -0
  179. package/dist/core/models.d.ts +51 -0
  180. package/dist/core/models.d.ts.map +1 -0
  181. package/dist/core/models.js +146 -0
  182. package/dist/core/models.js.map +1 -0
  183. package/dist/core/optimizer.d.ts +34 -0
  184. package/dist/core/optimizer.d.ts.map +1 -0
  185. package/dist/core/optimizer.js +131 -0
  186. package/dist/core/optimizer.js.map +1 -0
  187. package/dist/core/persona.d.ts +35 -0
  188. package/dist/core/persona.d.ts.map +1 -0
  189. package/dist/core/persona.js +126 -0
  190. package/dist/core/persona.js.map +1 -0
  191. package/dist/core/rate_limit.d.ts +23 -0
  192. package/dist/core/rate_limit.d.ts.map +1 -0
  193. package/dist/core/rate_limit.js +62 -0
  194. package/dist/core/rate_limit.js.map +1 -0
  195. package/dist/core/runner.d.ts +63 -0
  196. package/dist/core/runner.d.ts.map +1 -0
  197. package/dist/core/runner.js +671 -0
  198. package/dist/core/runner.js.map +1 -0
  199. package/dist/core/stream_parser.d.ts +43 -0
  200. package/dist/core/stream_parser.d.ts.map +1 -0
  201. package/dist/core/stream_parser.js +140 -0
  202. package/dist/core/stream_parser.js.map +1 -0
  203. package/dist/core/tool_schemas.d.ts +26 -0
  204. package/dist/core/tool_schemas.d.ts.map +1 -0
  205. package/dist/core/tool_schemas.js +124 -0
  206. package/dist/core/tool_schemas.js.map +1 -0
  207. package/dist/core/which.d.ts +2 -0
  208. package/dist/core/which.d.ts.map +1 -0
  209. package/dist/core/which.js +35 -0
  210. package/dist/core/which.js.map +1 -0
  211. package/dist/goals/index.d.ts +9 -0
  212. package/dist/goals/index.d.ts.map +1 -0
  213. package/dist/goals/index.js +17 -0
  214. package/dist/goals/index.js.map +1 -0
  215. package/dist/goals/service.d.ts +115 -0
  216. package/dist/goals/service.d.ts.map +1 -0
  217. package/dist/goals/service.js +415 -0
  218. package/dist/goals/service.js.map +1 -0
  219. package/dist/goals/types.d.ts +47 -0
  220. package/dist/goals/types.d.ts.map +1 -0
  221. package/dist/goals/types.js +66 -0
  222. package/dist/goals/types.js.map +1 -0
  223. package/dist/index.d.ts +22 -0
  224. package/dist/index.d.ts.map +1 -0
  225. package/dist/index.js +22 -0
  226. package/dist/index.js.map +1 -0
  227. package/dist/integrations/autonomous_startup.d.ts +51 -0
  228. package/dist/integrations/autonomous_startup.d.ts.map +1 -0
  229. package/dist/integrations/autonomous_startup.js +419 -0
  230. package/dist/integrations/autonomous_startup.js.map +1 -0
  231. package/dist/integrations/goose.d.ts +105 -0
  232. package/dist/integrations/goose.d.ts.map +1 -0
  233. package/dist/integrations/goose.js +408 -0
  234. package/dist/integrations/goose.js.map +1 -0
  235. package/dist/integrations/index.d.ts +21 -0
  236. package/dist/integrations/index.d.ts.map +1 -0
  237. package/dist/integrations/index.js +17 -0
  238. package/dist/integrations/index.js.map +1 -0
  239. package/dist/integrations/mcp.d.ts +73 -0
  240. package/dist/integrations/mcp.d.ts.map +1 -0
  241. package/dist/integrations/mcp.js +307 -0
  242. package/dist/integrations/mcp.js.map +1 -0
  243. package/dist/integrations/mempalace.d.ts +18 -0
  244. package/dist/integrations/mempalace.d.ts.map +1 -0
  245. package/dist/integrations/mempalace.js +25 -0
  246. package/dist/integrations/mempalace.js.map +1 -0
  247. package/dist/integrations/multi_agent.d.ts +82 -0
  248. package/dist/integrations/multi_agent.d.ts.map +1 -0
  249. package/dist/integrations/multi_agent.js +280 -0
  250. package/dist/integrations/multi_agent.js.map +1 -0
  251. package/dist/integrations/unified_memory.d.ts +415 -0
  252. package/dist/integrations/unified_memory.d.ts.map +1 -0
  253. package/dist/integrations/unified_memory.js +1489 -0
  254. package/dist/integrations/unified_memory.js.map +1 -0
  255. package/dist/roles/beru.yaml +48 -0
  256. package/dist/sidecar/client.d.ts +63 -0
  257. package/dist/sidecar/client.d.ts.map +1 -0
  258. package/dist/sidecar/client.js +222 -0
  259. package/dist/sidecar/client.js.map +1 -0
  260. package/dist/sidecar/index.d.ts +7 -0
  261. package/dist/sidecar/index.d.ts.map +1 -0
  262. package/dist/sidecar/index.js +6 -0
  263. package/dist/sidecar/index.js.map +1 -0
  264. package/dist/startup.d.ts +22 -0
  265. package/dist/startup.d.ts.map +1 -0
  266. package/dist/startup.js +194 -0
  267. package/dist/startup.js.map +1 -0
  268. package/dist/tools/_internal.d.ts +90 -0
  269. package/dist/tools/_internal.d.ts.map +1 -0
  270. package/dist/tools/_internal.js +375 -0
  271. package/dist/tools/_internal.js.map +1 -0
  272. package/dist/tools/_smoke.d.ts +2 -0
  273. package/dist/tools/_smoke.d.ts.map +1 -0
  274. package/dist/tools/_smoke.js +203 -0
  275. package/dist/tools/_smoke.js.map +1 -0
  276. package/dist/tools/axodex_tools.d.ts +51 -0
  277. package/dist/tools/axodex_tools.d.ts.map +1 -0
  278. package/dist/tools/axodex_tools.js +181 -0
  279. package/dist/tools/axodex_tools.js.map +1 -0
  280. package/dist/tools/code_tools.d.ts +33 -0
  281. package/dist/tools/code_tools.d.ts.map +1 -0
  282. package/dist/tools/code_tools.js +191 -0
  283. package/dist/tools/code_tools.js.map +1 -0
  284. package/dist/tools/computer_tools.d.ts +59 -0
  285. package/dist/tools/computer_tools.d.ts.map +1 -0
  286. package/dist/tools/computer_tools.js +348 -0
  287. package/dist/tools/computer_tools.js.map +1 -0
  288. package/dist/tools/file_tools.d.ts +51 -0
  289. package/dist/tools/file_tools.d.ts.map +1 -0
  290. package/dist/tools/file_tools.js +424 -0
  291. package/dist/tools/file_tools.js.map +1 -0
  292. package/dist/tools/index.d.ts +13 -0
  293. package/dist/tools/index.d.ts.map +1 -0
  294. package/dist/tools/index.js +13 -0
  295. package/dist/tools/index.js.map +1 -0
  296. package/dist/tools/shell_tools.d.ts +39 -0
  297. package/dist/tools/shell_tools.d.ts.map +1 -0
  298. package/dist/tools/shell_tools.js +163 -0
  299. package/dist/tools/shell_tools.js.map +1 -0
  300. package/dist/tools/web_tools.d.ts +31 -0
  301. package/dist/tools/web_tools.d.ts.map +1 -0
  302. package/dist/tools/web_tools.js +117 -0
  303. package/dist/tools/web_tools.js.map +1 -0
  304. package/dist/voice/index.d.ts +41 -0
  305. package/dist/voice/index.d.ts.map +1 -0
  306. package/dist/voice/index.js +58 -0
  307. package/dist/voice/index.js.map +1 -0
  308. package/dist/voice/light_daemon.d.ts +197 -0
  309. package/dist/voice/light_daemon.d.ts.map +1 -0
  310. package/dist/voice/light_daemon.js +746 -0
  311. package/dist/voice/light_daemon.js.map +1 -0
  312. package/dist/voice/setup.d.ts +63 -0
  313. package/dist/voice/setup.d.ts.map +1 -0
  314. package/dist/voice/setup.js +443 -0
  315. package/dist/voice/setup.js.map +1 -0
  316. package/dist/voice/stt.d.ts +148 -0
  317. package/dist/voice/stt.d.ts.map +1 -0
  318. package/dist/voice/stt.js +361 -0
  319. package/dist/voice/stt.js.map +1 -0
  320. package/dist/voice/tts.d.ts +168 -0
  321. package/dist/voice/tts.d.ts.map +1 -0
  322. package/dist/voice/tts.js +698 -0
  323. package/dist/voice/tts.js.map +1 -0
  324. package/dist/voice/voice_loop.d.ts +101 -0
  325. package/dist/voice/voice_loop.d.ts.map +1 -0
  326. package/dist/voice/voice_loop.js +463 -0
  327. package/dist/voice/voice_loop.js.map +1 -0
  328. package/dist/voice/wake_word.d.ts +153 -0
  329. package/dist/voice/wake_word.d.ts.map +1 -0
  330. package/dist/voice/wake_word.js +458 -0
  331. package/dist/voice/wake_word.js.map +1 -0
  332. package/dist/voice/wav.d.ts +99 -0
  333. package/dist/voice/wav.d.ts.map +1 -0
  334. package/dist/voice/wav.js +306 -0
  335. package/dist/voice/wav.js.map +1 -0
  336. package/dist/web/broker.d.ts +33 -0
  337. package/dist/web/broker.d.ts.map +1 -0
  338. package/dist/web/broker.js +58 -0
  339. package/dist/web/broker.js.map +1 -0
  340. package/dist/web/open_browser.d.ts +2 -0
  341. package/dist/web/open_browser.d.ts.map +1 -0
  342. package/dist/web/open_browser.js +42 -0
  343. package/dist/web/open_browser.js.map +1 -0
  344. package/dist/web/server.d.ts +54 -0
  345. package/dist/web/server.d.ts.map +1 -0
  346. package/dist/web/server.js +831 -0
  347. package/dist/web/server.js.map +1 -0
  348. package/dist/web/static/app.js +4121 -0
  349. package/dist/web/static/index.html +2281 -0
  350. package/dist/web/static/js/MODULE_SUMMARY.md +124 -0
  351. package/dist/web/static/js/a11y.js +165 -0
  352. package/dist/web/static/js/admin.js +2145 -0
  353. package/dist/web/static/js/assistant.js +475 -0
  354. package/dist/web/static/js/calendar/reminders.js +114 -0
  355. package/dist/web/static/js/calendar/utils.js +166 -0
  356. package/dist/web/static/js/calendar.js +3348 -0
  357. package/dist/web/static/js/censor.js +356 -0
  358. package/dist/web/static/js/chat.js +4546 -0
  359. package/dist/web/static/js/chatRenderer.js +2294 -0
  360. package/dist/web/static/js/chatStream.js +276 -0
  361. package/dist/web/static/js/codeRunner.js +398 -0
  362. package/dist/web/static/js/color/hex.js +14 -0
  363. package/dist/web/static/js/colorPicker.js +453 -0
  364. package/dist/web/static/js/compare/icons.js +77 -0
  365. package/dist/web/static/js/compare/index.js +1482 -0
  366. package/dist/web/static/js/compare/models.js +104 -0
  367. package/dist/web/static/js/compare/panes.js +817 -0
  368. package/dist/web/static/js/compare/probe.js +78 -0
  369. package/dist/web/static/js/compare/scoreboard.js +223 -0
  370. package/dist/web/static/js/compare/selector.js +1335 -0
  371. package/dist/web/static/js/compare/state.js +58 -0
  372. package/dist/web/static/js/compare/stream.js +695 -0
  373. package/dist/web/static/js/compare/vote.js +254 -0
  374. package/dist/web/static/js/cookbook-diagnosis.js +694 -0
  375. package/dist/web/static/js/cookbook-hwfit.js +1888 -0
  376. package/dist/web/static/js/cookbook.js +2093 -0
  377. package/dist/web/static/js/cookbookDownload.js +633 -0
  378. package/dist/web/static/js/cookbookProgressSignal.js +29 -0
  379. package/dist/web/static/js/cookbookRunning.js +3506 -0
  380. package/dist/web/static/js/cookbookServe.js +2128 -0
  381. package/dist/web/static/js/document.js +9731 -0
  382. package/dist/web/static/js/documentLibrary.js +3376 -0
  383. package/dist/web/static/js/dragSort.js +265 -0
  384. package/dist/web/static/js/editor/ai-inpaint.js +374 -0
  385. package/dist/web/static/js/editor/ai-models.js +273 -0
  386. package/dist/web/static/js/editor/ai-rembg.js +230 -0
  387. package/dist/web/static/js/editor/ai-tool-runner.js +147 -0
  388. package/dist/web/static/js/editor/ai-tools-misc.js +216 -0
  389. package/dist/web/static/js/editor/build/controls.js +366 -0
  390. package/dist/web/static/js/editor/build/popups.js +112 -0
  391. package/dist/web/static/js/editor/build/right-panel.js +200 -0
  392. package/dist/web/static/js/editor/build/toolbar.js +73 -0
  393. package/dist/web/static/js/editor/build/topbar.js +131 -0
  394. package/dist/web/static/js/editor/build/transform-popup.js +109 -0
  395. package/dist/web/static/js/editor/canvas-coords.js +21 -0
  396. package/dist/web/static/js/editor/canvas-events.js +197 -0
  397. package/dist/web/static/js/editor/canvas-transforms.js +132 -0
  398. package/dist/web/static/js/editor/checkerboard.js +24 -0
  399. package/dist/web/static/js/editor/clipboard-and-drop.js +133 -0
  400. package/dist/web/static/js/editor/composite-helpers.js +83 -0
  401. package/dist/web/static/js/editor/filters/blur.js +118 -0
  402. package/dist/web/static/js/editor/filters/edge-feather.js +70 -0
  403. package/dist/web/static/js/editor/fx/adj-popup.js +677 -0
  404. package/dist/web/static/js/editor/fx/filter-string.js +38 -0
  405. package/dist/web/static/js/editor/fx/histogram.js +67 -0
  406. package/dist/web/static/js/editor/fx/pixel-pass.js +249 -0
  407. package/dist/web/static/js/editor/harmonize-masks.js +116 -0
  408. package/dist/web/static/js/editor/history-panel.js +176 -0
  409. package/dist/web/static/js/editor/keyboard-shortcuts.js +271 -0
  410. package/dist/web/static/js/editor/layer-helpers.js +131 -0
  411. package/dist/web/static/js/editor/layer-panel.js +600 -0
  412. package/dist/web/static/js/editor/mask-utils.js +91 -0
  413. package/dist/web/static/js/editor/shortcuts-popover.js +149 -0
  414. package/dist/web/static/js/editor/slider-ux.js +191 -0
  415. package/dist/web/static/js/editor/snap.js +107 -0
  416. package/dist/web/static/js/editor/state.js +257 -0
  417. package/dist/web/static/js/editor/stroke-pipeline.js +162 -0
  418. package/dist/web/static/js/editor/stroke-tool-sliders.js +64 -0
  419. package/dist/web/static/js/editor/tools/clone.js +81 -0
  420. package/dist/web/static/js/editor/tools/crop.js +137 -0
  421. package/dist/web/static/js/editor/tools/flood-fill.js +72 -0
  422. package/dist/web/static/js/editor/tools/lasso-mask.js +171 -0
  423. package/dist/web/static/js/editor/tools/lasso.js +65 -0
  424. package/dist/web/static/js/editor/tools/move.js +79 -0
  425. package/dist/web/static/js/editor/tools/stroke.js +123 -0
  426. package/dist/web/static/js/editor/tools/transform-drag.js +174 -0
  427. package/dist/web/static/js/editor/tools/transform-handles.js +271 -0
  428. package/dist/web/static/js/editor/tools/transform-session.js +381 -0
  429. package/dist/web/static/js/editor/tools/wand.js +46 -0
  430. package/dist/web/static/js/editor/wire-import.js +148 -0
  431. package/dist/web/static/js/editor/wire-inpaint-controls.js +164 -0
  432. package/dist/web/static/js/editor/wire-merge-buttons.js +103 -0
  433. package/dist/web/static/js/editor/wire-selection-controls.js +170 -0
  434. package/dist/web/static/js/editor/wire-topbar-menus.js +174 -0
  435. package/dist/web/static/js/editor/wire-topbar-overflow.js +49 -0
  436. package/dist/web/static/js/editor/wire-topbar.js +188 -0
  437. package/dist/web/static/js/emailInbox.js +1245 -0
  438. package/dist/web/static/js/emailLibrary/replyRecipients.js +27 -0
  439. package/dist/web/static/js/emailLibrary/signatureFold.js +339 -0
  440. package/dist/web/static/js/emailLibrary/state.js +34 -0
  441. package/dist/web/static/js/emailLibrary/utils.js +202 -0
  442. package/dist/web/static/js/emailLibrary.js +5217 -0
  443. package/dist/web/static/js/emojiPicker.js +311 -0
  444. package/dist/web/static/js/escMenuStack.js +102 -0
  445. package/dist/web/static/js/fileHandler.js +295 -0
  446. package/dist/web/static/js/gallery.js +2835 -0
  447. package/dist/web/static/js/galleryEditor.js +3798 -0
  448. package/dist/web/static/js/group.js +955 -0
  449. package/dist/web/static/js/init.js +405 -0
  450. package/dist/web/static/js/keyboard-shortcuts.js +292 -0
  451. package/dist/web/static/js/langIcons.js +187 -0
  452. package/dist/web/static/js/markdown/tableRow.js +19 -0
  453. package/dist/web/static/js/markdown.js +806 -0
  454. package/dist/web/static/js/memory.js +1418 -0
  455. package/dist/web/static/js/modalManager.js +1552 -0
  456. package/dist/web/static/js/modalSnap.js +782 -0
  457. package/dist/web/static/js/model/matchKey.js +19 -0
  458. package/dist/web/static/js/modelPicker.js +695 -0
  459. package/dist/web/static/js/modelSort.js +33 -0
  460. package/dist/web/static/js/models.js +642 -0
  461. package/dist/web/static/js/notes.js +5054 -0
  462. package/dist/web/static/js/package.json +1 -0
  463. package/dist/web/static/js/platform.js +47 -0
  464. package/dist/web/static/js/presets.js +1110 -0
  465. package/dist/web/static/js/providers.js +93 -0
  466. package/dist/web/static/js/rag.js +177 -0
  467. package/dist/web/static/js/research/jobs.js +335 -0
  468. package/dist/web/static/js/research/panel.js +1233 -0
  469. package/dist/web/static/js/researchSynapse.js +225 -0
  470. package/dist/web/static/js/search-chat.js +201 -0
  471. package/dist/web/static/js/search.js +52 -0
  472. package/dist/web/static/js/section-management.js +260 -0
  473. package/dist/web/static/js/sessions.js +3108 -0
  474. package/dist/web/static/js/settings.js +4991 -0
  475. package/dist/web/static/js/sidebar-layout.js +573 -0
  476. package/dist/web/static/js/signature.js +504 -0
  477. package/dist/web/static/js/skills.js +1908 -0
  478. package/dist/web/static/js/slashAutocomplete.js +267 -0
  479. package/dist/web/static/js/slashCommands.js +6099 -0
  480. package/dist/web/static/js/spinner.js +406 -0
  481. package/dist/web/static/js/storage.js +123 -0
  482. package/dist/web/static/js/tasks.js +2699 -0
  483. package/dist/web/static/js/theme.js +2086 -0
  484. package/dist/web/static/js/tileManager.js +386 -0
  485. package/dist/web/static/js/tourAutoplay.js +133 -0
  486. package/dist/web/static/js/tourHints.js +179 -0
  487. package/dist/web/static/js/tts-ai.js +521 -0
  488. package/dist/web/static/js/ui.js +1288 -0
  489. package/dist/web/static/js/util/ordinal.js +13 -0
  490. package/dist/web/static/js/voiceRecorder.js +283 -0
  491. package/dist/web/static/js/windowDrag.js +326 -0
  492. package/dist/web/static/js/windowResize.js +233 -0
  493. package/dist/web/static/landing.html +824 -0
  494. package/dist/web/static/lib/docx.umd.min.js +20116 -0
  495. package/dist/web/static/lib/highlight.min.js +1213 -0
  496. package/dist/web/static/lib/html2pdf.bundle.min.js +3 -0
  497. package/dist/web/static/lib/mammoth.browser.min.js +21 -0
  498. package/dist/web/static/lib/qrcode.min.js +8 -0
  499. package/dist/web/static/lib/xlsx.full.min.js +24 -0
  500. package/dist/web/static/login.html +582 -0
  501. package/dist/web/static/manifest.json +15 -0
  502. package/dist/web/static/style.css +35733 -0
  503. package/dist/web/static/sw.js +144 -0
  504. package/dist/workflows/engine.d.ts +162 -0
  505. package/dist/workflows/engine.d.ts.map +1 -0
  506. package/dist/workflows/engine.js +625 -0
  507. package/dist/workflows/engine.js.map +1 -0
  508. package/dist/workflows/index.d.ts +8 -0
  509. package/dist/workflows/index.d.ts.map +1 -0
  510. package/dist/workflows/index.js +14 -0
  511. package/dist/workflows/index.js.map +1 -0
  512. package/package.json +112 -0
@@ -0,0 +1,746 @@
1
+ /**
2
+ * src/voice/light_daemon.ts
3
+ * ============================
4
+ * BERU Light Voice Daemon — two-tier, minimal RAM.
5
+ *
6
+ * Architecture
7
+ * ------------
8
+ * ALWAYS ON (idle RAM ~80-160 MB total):
9
+ * openwakeword ONNX — ~1 MB — wake word detection
10
+ * faster-whisper tiny — ~75 MB — speech-to-text (int8 CPU)
11
+ * edge-tts — 0 MB — text-to-speech (MS cloud stream)
12
+ *
13
+ * ON DEMAND (no weights ever loaded locally):
14
+ * Tier 1 — regex classifier answers simple queries instantly (time, date, …)
15
+ * Tier 2 — one stateless HTTP call to Anthropic / Groq / OpenAI
16
+ * only fires when the query is complex
17
+ * zero model weights in RAM
18
+ *
19
+ * NEVER LOADED:
20
+ * The full axoniz Agent, LM Studio, Ollama, or any local LLM.
21
+ *
22
+ * Usage
23
+ * -----
24
+ * const d = start_light_daemon();
25
+ * // runs forever — say "Beru" to wake
26
+ * // d.say("BERU is online.")
27
+ *
28
+ * ── Node reality ─────────────────────────────────────────────────────────────
29
+ * Scheduling, watching, intent classification, LLM calls, trimming and event
30
+ * emission are ported faithfully. Only the OS-level audio primitives degrade:
31
+ * - wake word → `WakeWordDetector` from src/voice/wake_word.ts (register a
32
+ * detector; `openwakeword`/`pvporcupine` are Python-only)
33
+ * - mic → registered audio input driver (was `pyaudio`)
34
+ * - STT → `_WhisperSTT` wraps the pluggable `STTEngine` (was
35
+ * `faster-whisper`; no Node engine is installed)
36
+ * - TTS → `msedge-tts` (installed) via `src/voice/tts.ts`
37
+ * Every degraded path returns/emits a clear `[ERROR] …` string and never throws.
38
+ */
39
+ import { getLogger } from "../core/logger.js";
40
+ import { get_tts, speakWithFallback } from "./tts.js";
41
+ import { get_stt } from "./stt.js";
42
+ import { AUDIO_INPUT_MISSING_ERROR, getAudioInputDriver, pcm16MeanAbs, writeWav, } from "./wav.js";
43
+ import { get_wake_detector, registerClipRecognizer, sleep } from "./wake_word.js";
44
+ import fs from "node:fs";
45
+ import os from "node:os";
46
+ import path from "node:path";
47
+ const logger = getLogger();
48
+ /* ─────────────────────────────────────────────────────────────────────────────
49
+ * Constants
50
+ * ───────────────────────────────────────────────────────────────────────────── */
51
+ export const WHISPER_MODEL = process.env.BERU_WHISPER_MODEL ?? "tiny";
52
+ export const WHISPER_DEVICE = "cpu"; // keep it on CPU — no VRAM consumed
53
+ export const SAMPLE_RATE = 16_000;
54
+ export const LISTEN_SECS = 7; // max recording window after wake word
55
+ export const SILENCE_THRESH = 500; // PCM energy threshold — ignores BERU's own TTS echo
56
+ export const SILENCE_FRAMES = 20; // consecutive silent frames before stop (~0.5s)
57
+ /** Master debug flag — set to false to quiet down. */
58
+ export let DBG = true;
59
+ export function setDbg(on) {
60
+ DBG = on;
61
+ }
62
+ function _dbg(msg) {
63
+ if (!DBG)
64
+ return;
65
+ const d = new Date();
66
+ const ts = `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}.${String(d.getMilliseconds()).padStart(3, "0")}`;
67
+ process.stdout.write(` [BERU:${ts}] ${msg}\n`);
68
+ }
69
+ /* ─────────────────────────────────────────────────────────────────────────────
70
+ * Tier 1 — Intent classifier (pure regex, zero latency, zero RAM)
71
+ * ───────────────────────────────────────────────────────────────────────────── */
72
+ export const _STOP_WORDS = new Set([
73
+ "stop listening",
74
+ "go to sleep",
75
+ "shut up",
76
+ "quiet",
77
+ "nevermind",
78
+ "stop",
79
+ "sleep",
80
+ "goodbye",
81
+ ]);
82
+ const _LOCAL_PATTERNS = [
83
+ String.raw `\btime\b`,
84
+ String.raw `\bdate\b`,
85
+ String.raw `\bday\b`,
86
+ String.raw `\byear\b`,
87
+ String.raw `\bhello\b`,
88
+ String.raw `\bhi\b`,
89
+ String.raw `\bhey\b`,
90
+ String.raw `\bthank(s| you)\b`,
91
+ String.raw `\bbye\b`,
92
+ String.raw `\bwho are you\b`,
93
+ String.raw `\bstatus\b`,
94
+ ];
95
+ const _LLM_PATTERNS = [
96
+ String.raw `\b(load|use|switch to|activate)\b.*(big|full|smart|model|claude|gpt|groq)\b`,
97
+ String.raw `\bthink harder\b`,
98
+ String.raw `\bmore detail\b`,
99
+ String.raw `\bexplain.+detail\b`,
100
+ String.raw `\b(write|create|build|generate|implement|debug|refactor|analyse|analyze)\b`,
101
+ String.raw `\bhow (do|does|can|would|should)\b`,
102
+ String.raw `\bwhy (is|does|did|are|were)\b`,
103
+ String.raw `\bwhat (is|are|was|were|does|did)\b`,
104
+ String.raw `\bcan you\b`,
105
+ String.raw `\bcould you\b`,
106
+ ];
107
+ /** Returns 'stop', 'local', or 'llm'. */
108
+ export function _classify(text) {
109
+ const low = text.toLowerCase().trim();
110
+ if ([..._STOP_WORDS].some((s) => low.includes(s)))
111
+ return "stop";
112
+ for (const pat of _LLM_PATTERNS)
113
+ if (new RegExp(pat).test(low))
114
+ return "llm";
115
+ for (const pat of _LOCAL_PATTERNS)
116
+ if (new RegExp(pat).test(low))
117
+ return "local";
118
+ // short = probably local, long = probably llm
119
+ return low.split(/\s+/).length <= 4 ? "local" : "llm";
120
+ }
121
+ /** `%I:%M %p` with the Python `.lstrip("0")` behaviour. */
122
+ function twelveHourClock(d = new Date()) {
123
+ return d
124
+ .toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: true })
125
+ .replace(/^0/, "");
126
+ }
127
+ function localDateStr(d = new Date()) {
128
+ return d
129
+ .toLocaleDateString("en-US", { weekday: "long", month: "long", day: "2-digit" })
130
+ .replace(" 0", " ");
131
+ }
132
+ function pick(arr) {
133
+ return arr[Math.floor(Math.random() * arr.length)];
134
+ }
135
+ /** Answer without any network call. */
136
+ export function _local_response(text) {
137
+ const low = text.toLowerCase();
138
+ const now = new Date();
139
+ if (/\btime\b/.test(low))
140
+ return `It's ${twelveHourClock(now)}.`;
141
+ if (/\b(date|today|day)\b/.test(low))
142
+ return `Today is ${localDateStr(now)}.`;
143
+ if (/\byear\b/.test(low))
144
+ return `It's ${now.getFullYear()}.`;
145
+ if (/\b(hello|hi|hey)\b/.test(low)) {
146
+ return pick(["Hello, my liege.", "Here and ready.", "What do you need?"]);
147
+ }
148
+ if (/\bthank(s| you)\b/.test(low)) {
149
+ return pick(["Of course.", "Always.", "Your will is my mission."]);
150
+ }
151
+ if (/\bwho are you\b/.test(low))
152
+ return "I'm BERU. Your shadow army of one.";
153
+ if (/\bstatus\b/.test(low)) {
154
+ return "Light daemon online. Whisper STT active. Waiting for commands.";
155
+ }
156
+ return pick(["I'm here. What do you need?", "Standing by.", "Go ahead."]);
157
+ }
158
+ /* ─────────────────────────────────────────────────────────────────────────────
159
+ * Tier 2 — Stateless LLM API client (no local weights ever)
160
+ * ───────────────────────────────────────────────────────────────────────────── */
161
+ /**
162
+ * TODO(port): Python imported the `anthropic`, `groq` and `openai` SDKs. None is
163
+ * installed here, so each provider is called over plain `fetch` against the same
164
+ * REST endpoints — same models, same prompts, same shapes, zero new dependencies.
165
+ * Recommended replacement: keep the HTTP path; add `undici` ProxyAgent only if a
166
+ * corporate proxy is required.
167
+ */
168
+ export class _LLMClient {
169
+ static SYSTEM = "You are BERU, a sharp military-precision AI assistant. " +
170
+ "Speak in short direct sentences. " +
171
+ "Current time: {time}. Date: {date}.";
172
+ provider;
173
+ apiKey;
174
+ model;
175
+ baseUrl;
176
+ _backend;
177
+ constructor(provider = "auto", apiKey = null, model = null, baseUrl = null) {
178
+ this.provider = provider;
179
+ this.apiKey = apiKey;
180
+ this.model = model;
181
+ this.baseUrl = baseUrl;
182
+ this._backend = this._detect();
183
+ _dbg(`LLM backend detected: ${this._backend}`);
184
+ }
185
+ _detect() {
186
+ if (this.provider && this.provider !== "auto") {
187
+ _dbg(`LLM provider forced to: ${this.provider}`);
188
+ return this.provider;
189
+ }
190
+ for (const [prov, env] of [
191
+ ["groq", "GROQ_API_KEY"],
192
+ ["anthropic", "ANTHROPIC_API_KEY"],
193
+ ["openai", "OPENAI_API_KEY"],
194
+ ]) {
195
+ if (process.env[env]) {
196
+ _dbg(`Found API key for ${prov} — using it`);
197
+ return prov;
198
+ }
199
+ }
200
+ _dbg("No LLM API key found. Tier 2 disabled.");
201
+ return "none";
202
+ }
203
+ get backend() {
204
+ return this._backend;
205
+ }
206
+ get available() {
207
+ return this._backend !== "none";
208
+ }
209
+ async ask(prompt, maxTokens = 200) {
210
+ const now = new Date();
211
+ const system = _LLMClient.SYSTEM.replace("{time}", twelveHourClock(now)).replace("{date}", now.toLocaleDateString("en-US", {
212
+ weekday: "long",
213
+ month: "long",
214
+ day: "2-digit",
215
+ year: "numeric",
216
+ }));
217
+ _dbg(`LLM ask [${this._backend}]: '${prompt.slice(0, 80)}'`);
218
+ const t0 = Date.now();
219
+ try {
220
+ let result;
221
+ if (this._backend === "anthropic") {
222
+ result = await this._ask_anthropic(system, prompt, maxTokens);
223
+ }
224
+ else if (this._backend === "groq") {
225
+ result = await this._ask_groq(system, prompt, maxTokens);
226
+ }
227
+ else if (this._backend === "openai") {
228
+ result = await this._ask_openai(system, prompt, maxTokens);
229
+ }
230
+ else {
231
+ return ("No LLM backend configured. " +
232
+ "Set ANTHROPIC_API_KEY, GROQ_API_KEY, or OPENAI_API_KEY.");
233
+ }
234
+ _dbg(`LLM responded in ${((Date.now() - t0) / 1000).toFixed(2)}s: '${result.slice(0, 80)}'`);
235
+ return result;
236
+ }
237
+ catch (e) {
238
+ logger.error(`[LightDaemon] LLM error: ${errText(e)}`);
239
+ _dbg(`LLM ERROR: ${errText(e)}`);
240
+ return `LLM call failed: ${errText(e)}`;
241
+ }
242
+ }
243
+ async _ask_anthropic(system, prompt, maxTokens) {
244
+ const key = this.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
245
+ const base = (this.baseUrl ?? "https://api.anthropic.com").replace(/\/+$/, "");
246
+ const json = await httpJson(`${base}/v1/messages`, {
247
+ model: this.model ?? "claude-haiku-4-5-20251001",
248
+ max_tokens: maxTokens,
249
+ system,
250
+ messages: [{ role: "user", content: prompt }],
251
+ }, {
252
+ "x-api-key": key,
253
+ "anthropic-version": "2023-06-01",
254
+ });
255
+ const content = json["content"];
256
+ return (content?.[0]?.text ?? "").trim();
257
+ }
258
+ async _ask_groq(system, prompt, maxTokens) {
259
+ const key = this.apiKey ?? process.env.GROQ_API_KEY ?? "";
260
+ const base = (this.baseUrl ?? "https://api.groq.com/openai/v1").replace(/\/+$/, "");
261
+ const json = await httpJson(`${base}/chat/completions`, {
262
+ model: this.model ?? "llama3-8b-8192",
263
+ max_tokens: maxTokens,
264
+ messages: [
265
+ { role: "system", content: system },
266
+ { role: "user", content: prompt },
267
+ ],
268
+ }, { Authorization: `Bearer ${key}` });
269
+ return firstChoiceText(json);
270
+ }
271
+ async _ask_openai(system, prompt, maxTokens) {
272
+ const key = this.apiKey ?? process.env.OPENAI_API_KEY ?? "";
273
+ const base = (this.baseUrl ?? "https://api.openai.com/v1").replace(/\/+$/, "");
274
+ const json = await httpJson(`${base}/chat/completions`, {
275
+ model: this.model ?? "gpt-4o-mini",
276
+ max_tokens: maxTokens,
277
+ messages: [
278
+ { role: "system", content: system },
279
+ { role: "user", content: prompt },
280
+ ],
281
+ }, { Authorization: `Bearer ${key}` });
282
+ return firstChoiceText(json);
283
+ }
284
+ }
285
+ function firstChoiceText(json) {
286
+ const choices = json["choices"];
287
+ return (choices?.[0]?.message?.content ?? "").trim();
288
+ }
289
+ async function httpJson(url, payload, headers = {}) {
290
+ const res = await fetch(url, {
291
+ method: "POST",
292
+ headers: { "Content-Type": "application/json", ...headers },
293
+ body: JSON.stringify(payload),
294
+ signal: AbortSignal.timeout(60_000),
295
+ });
296
+ const body = await res.text();
297
+ if (!res.ok)
298
+ throw new Error(`HTTP ${res.status}: ${body.slice(0, 300)}`);
299
+ return JSON.parse(body);
300
+ }
301
+ /* ─────────────────────────────────────────────────────────────────────────────
302
+ * STT — whisper-tiny slot, always loaded, stays in RAM
303
+ * ───────────────────────────────────────────────────────────────────────────── */
304
+ /**
305
+ * TODO(port): Python held a `faster_whisper.WhisperModel` here. No Node STT
306
+ * engine is installed. `_WhisperSTT` now wraps the pluggable `STTEngine` from
307
+ * src/voice/stt.ts (register one with `registerSTTBackend`, or put a whisper.cpp
308
+ * `whisper-cli` on PATH). Until then `available` is false and `transcribe_pcm`
309
+ * returns "" while emitting a descriptive `[ERROR] …` via `lastError`.
310
+ */
311
+ export class _WhisperSTT {
312
+ /** Exposed because the Python daemon printed it in `start()`/`info()`. */
313
+ _model_size;
314
+ _engine;
315
+ _lastError = "";
316
+ constructor(modelSize = WHISPER_MODEL, engine = null) {
317
+ this._model_size = modelSize;
318
+ this._engine = engine ?? get_stt("auto", { modelSize });
319
+ }
320
+ get lastError() {
321
+ return this._lastError || this._engine.lastError;
322
+ }
323
+ get available() {
324
+ return this._engine.is_available;
325
+ }
326
+ /** Transcribe raw 16-bit 16 kHz mono PCM. Returns text or empty string. */
327
+ async transcribe_pcm(pcmBytes) {
328
+ if (!pcmBytes || pcmBytes.length === 0) {
329
+ _dbg("transcribe_pcm: empty audio");
330
+ return "";
331
+ }
332
+ if (!this.available) {
333
+ this._lastError =
334
+ "[ERROR] STT unavailable — no Whisper engine for Node.js " +
335
+ "(faster-whisper is Python-only). registerSTTBackend() or install whisper.cpp.";
336
+ _dbg(this._lastError);
337
+ return "";
338
+ }
339
+ const tmp = path.join(os.tmpdir(), `beru-light-stt-${Date.now()}-${Math.floor(Math.random() * 1e6)}.wav`);
340
+ try {
341
+ // Hand-rolled RIFF header — replaces Python's `wave` module.
342
+ writeWav(tmp, pcmBytes, SAMPLE_RATE, 1);
343
+ _dbg(`Transcribing ${(pcmBytes.length / 2 / SAMPLE_RATE).toFixed(1)}s audio…`);
344
+ const t0 = Date.now();
345
+ const text = (await this._engine.transcribe(tmp)) ?? "";
346
+ if (this._engine.lastError)
347
+ this._lastError = this._engine.lastError;
348
+ _dbg(`Whisper done in ${((Date.now() - t0) / 1000).toFixed(2)}s → '${text}'`);
349
+ return text.trim();
350
+ }
351
+ catch (e) {
352
+ _dbg(`Whisper transcribe ERROR: ${errText(e)}`);
353
+ this._lastError = `[ERROR] STT transcribe failed: ${errText(e)}`;
354
+ return "";
355
+ }
356
+ finally {
357
+ try {
358
+ fs.unlinkSync(tmp);
359
+ }
360
+ catch {
361
+ /* best effort */
362
+ }
363
+ }
364
+ }
365
+ async transcribePcm(pcmBytes) {
366
+ return this.transcribe_pcm(pcmBytes);
367
+ }
368
+ }
369
+ /**
370
+ * Record from mic until silence or timeout. Returns raw 16-bit PCM bytes.
371
+ *
372
+ * TODO(port): Python used `pyaudio` (PortAudio) with a 1024-frame read loop.
373
+ * There is no Node audio I/O dependency installed — a driver registered through
374
+ * `setAudioInputDriver()` supplies the frames; without one this logs a clear
375
+ * `[ERROR] …` and returns an empty buffer.
376
+ */
377
+ export async function _record_mic(arg = LISTEN_SECS, signal) {
378
+ const opts = typeof arg === "number" ? { max_secs: arg, signal } : arg;
379
+ const maxSecs = opts.max_secs ?? LISTEN_SECS;
380
+ const driver = getAudioInputDriver();
381
+ if (!driver) {
382
+ _dbg(AUDIO_INPUT_MISSING_ERROR);
383
+ return Buffer.alloc(0);
384
+ }
385
+ _dbg(`Opening mic (max ${maxSecs}s, silence_thresh=${SILENCE_THRESH})…`);
386
+ try {
387
+ const pcm = await driver.record({
388
+ maxSeconds: maxSecs,
389
+ sampleRate: SAMPLE_RATE,
390
+ // ~0.5s of silence before stopping, matching SILENCE_FRAMES * 1024 frames.
391
+ silenceSeconds: (SILENCE_FRAMES * 1024) / SAMPLE_RATE,
392
+ energyThreshold: SILENCE_THRESH,
393
+ signal: opts.signal,
394
+ });
395
+ const secs = pcm.length / 2 / SAMPLE_RATE;
396
+ const energy = pcm16MeanAbs(pcm);
397
+ _dbg(`Recorded ${secs.toFixed(1)}s, mean_energy=${energy.toFixed(1)}, ` +
398
+ `speech_started=${energy > SILENCE_THRESH}`);
399
+ if (energy <= SILENCE_THRESH) {
400
+ _dbg("No speech energy detected — discarding audio");
401
+ return Buffer.alloc(0);
402
+ }
403
+ return pcm;
404
+ }
405
+ catch (e) {
406
+ _dbg(`ERROR recording mic: ${errText(e)}`);
407
+ return Buffer.alloc(0);
408
+ }
409
+ }
410
+ /* ─────────────────────────────────────────────────────────────────────────────
411
+ * TTS — edge-tts (streams, 0 local RAM) with offline fallback
412
+ * ───────────────────────────────────────────────────────────────────────────── */
413
+ let _speakEngine = null;
414
+ function speakEngine() {
415
+ if (_speakEngine === null)
416
+ _speakEngine = get_tts();
417
+ return _speakEngine;
418
+ }
419
+ /** Test/DI hook. */
420
+ export function setSpeakEngine(engine) {
421
+ _speakEngine = engine;
422
+ }
423
+ /**
424
+ * Speak text aloud. Priority (ported from the Python module-level `_speak()`):
425
+ * 1. msedge-tts → audio output driver (best quality, free)
426
+ * 2. msedge-tts → OS player fallback (PowerShell MediaPlayer on Windows)
427
+ * 3. offline OS TTS slot (was pyttsx3 — NOT implemented)
428
+ * 4. print (last resort)
429
+ *
430
+ * TODO(port): step 1/2 require a registered audio output driver; step 3 needs a
431
+ * Node offline TTS backend (see `OFFLINE_TTS_ERROR` in src/voice/tts.ts). All
432
+ * failures are logged as `[ERROR] …` and never throw.
433
+ */
434
+ export async function _speak(text) {
435
+ if (!text)
436
+ return;
437
+ _dbg(`Speaking: '${text.slice(0, 80)}'`);
438
+ const t0 = Date.now();
439
+ try {
440
+ const ok = await speakWithFallback(text);
441
+ if (ok)
442
+ _dbg(`TTS done in ${((Date.now() - t0) / 1000).toFixed(2)}s`);
443
+ const err = speakEngine().lastError;
444
+ if (err)
445
+ _dbg(err);
446
+ }
447
+ catch (e) {
448
+ _dbg(`TTS failed: ${errText(e)}`);
449
+ process.stdout.write(` [BERU says] ${text}\n`);
450
+ }
451
+ }
452
+ export function _speak_sync_fallback(text) {
453
+ process.stdout.write(` [BERU says] ${text}\n`);
454
+ }
455
+ /* ─────────────────────────────────────────────────────────────────────────────
456
+ * Response trimmer
457
+ * ───────────────────────────────────────────────────────────────────────────── */
458
+ export function _trim(text, maxChars = 300) {
459
+ const hadCode = /```/.test(text);
460
+ let out = text.replace(/```[\s\S]*?```/g, "");
461
+ out = out.replace(/`([^`\n]+)`/g, "$1");
462
+ out = out.replace(/\*{1,2}(.*?)\*{1,2}/g, "$1");
463
+ out = out.replace(/#{1,6}\s+/g, "");
464
+ out = out.replace(/\n{2,}/g, ". ");
465
+ out = out.replace(/\s{2,}/g, " ").trim();
466
+ const suffix = hadCode ? " I've put the code in the chat." : "";
467
+ if (out.length <= maxChars)
468
+ return (out + suffix).trim();
469
+ const sents = out.split(/(?<=[.!?])\s+/);
470
+ let acc = "";
471
+ for (const s of sents) {
472
+ if (acc.length + s.length > maxChars)
473
+ break;
474
+ acc += s + " ";
475
+ }
476
+ return ((acc.trim() || out.slice(0, maxChars) + "…") + suffix).trim();
477
+ }
478
+ /* ─────────────────────────────────────────────────────────────────────────────
479
+ * Main daemon class
480
+ * ───────────────────────────────────────────────────────────────────────────── */
481
+ /** Small promise/flag signal replacing `threading.Event`. */
482
+ class Signal {
483
+ _set = false;
484
+ _waiters = [];
485
+ set() {
486
+ this._set = true;
487
+ const waiters = this._waiters;
488
+ this._waiters = [];
489
+ for (const w of waiters)
490
+ w();
491
+ }
492
+ clear() {
493
+ this._set = false;
494
+ }
495
+ is_set() {
496
+ return this._set;
497
+ }
498
+ async wait(timeoutSeconds) {
499
+ if (this._set)
500
+ return true;
501
+ return await new Promise((resolve) => {
502
+ let settled = false;
503
+ const done = (v) => {
504
+ if (settled)
505
+ return;
506
+ settled = true;
507
+ resolve(v);
508
+ };
509
+ const timer = setTimeout(() => done(false), Math.max(0, timeoutSeconds * 1000));
510
+ this._waiters.push(() => {
511
+ clearTimeout(timer);
512
+ done(true);
513
+ });
514
+ });
515
+ }
516
+ }
517
+ export class LightVoiceDaemon {
518
+ /**
519
+ * BERU light voice daemon.
520
+ *
521
+ * Idle RAM: ~80 MB (whisper-tiny int8 CPU + openwakeword ONNX)
522
+ * NO local LLM is ever loaded. Complex queries go to the API only.
523
+ */
524
+ _llm;
525
+ _stt;
526
+ _wwd = null;
527
+ _on_state;
528
+ _state = "IDLE";
529
+ _stop_ev = new Signal();
530
+ _wake_ev = new Signal();
531
+ _abort = null;
532
+ _thread = null;
533
+ constructor(options = {}) {
534
+ _dbg("LightVoiceDaemon.__init__ — initialising (no LLM loaded)");
535
+ this._llm = new _LLMClient(options.provider ?? "auto", options.api_key ?? null, options.model ?? null, options.base_url ?? null);
536
+ this._stt = new _WhisperSTT(options.whisper_model ?? WHISPER_MODEL);
537
+ this._on_state = options.on_state_change ?? null;
538
+ }
539
+ /* ── Public API ─────────────────────────────────────────────────────────── */
540
+ start() {
541
+ _dbg("start() called — spinning up wake word + main loop");
542
+ this._stop_ev.clear();
543
+ this._abort = new AbortController();
544
+ const signal = this._abort.signal;
545
+ this._wwd = this._init_wake_word();
546
+ this._wwd.start();
547
+ this._thread = this._loop(signal)
548
+ .catch((e) => {
549
+ logger.error(`[LightDaemon] loop crashed: ${errText(e)}`);
550
+ })
551
+ .finally(() => {
552
+ this._thread = null;
553
+ });
554
+ console.log("\n [BERU] Light daemon online");
555
+ console.log(` [BERU] STT : whisper-${this._stt._model_size} (${this._stt.available ? "ready" : "UNAVAILABLE"})`);
556
+ console.log(` [BERU] LLM : ${this._llm.backend} (${this._llm.available ? "ready" : "no key — Tier 2 disabled"})`);
557
+ console.log(` [BERU] Wake: ${this._wwd.backend}`);
558
+ console.log(" [BERU] Say 'Beru' to activate\n");
559
+ if (!this._stt.available && this._stt.lastError) {
560
+ console.log(` ${this._stt.lastError}\n`);
561
+ }
562
+ }
563
+ stop() {
564
+ _dbg("stop() called");
565
+ this._stop_ev.set();
566
+ this._abort?.abort();
567
+ this._abort = null;
568
+ this._wwd?.stop();
569
+ }
570
+ is_running() {
571
+ return this._thread !== null;
572
+ }
573
+ isRunning() {
574
+ return this.is_running();
575
+ }
576
+ get state() {
577
+ return this._state;
578
+ }
579
+ /** Speak text immediately (compat with the old LightDaemon API). */
580
+ say(text, async_ = false) {
581
+ if (async_) {
582
+ void _speak(text).catch((e) => logger.debug(`[LightDaemon] say error: ${errText(e)}`));
583
+ }
584
+ else {
585
+ void _speak(text);
586
+ }
587
+ }
588
+ /** Capture one utterance and return its transcription. */
589
+ async listen_once() {
590
+ const pcm = await _record_mic(LISTEN_SECS);
591
+ if (pcm.length === 0)
592
+ return null;
593
+ const text = await this._stt.transcribe_pcm(pcm);
594
+ return text || null;
595
+ }
596
+ async listenOnce() {
597
+ return this.listen_once();
598
+ }
599
+ info() {
600
+ return {
601
+ state: this._state,
602
+ stt: this._stt.available ? `whisper-${this._stt._model_size}` : "unavailable",
603
+ tts: "msedge-tts → os-tts (unimplemented) → print",
604
+ stt_ready: this._stt.available,
605
+ llm: this._llm.backend,
606
+ llm_available: this._llm.available,
607
+ wake_word: this._wwd ? this._wwd.backend : "not started",
608
+ };
609
+ }
610
+ /* ── Internals ──────────────────────────────────────────────────────────── */
611
+ _set_state(s) {
612
+ if (s !== this._state)
613
+ _dbg(`State: ${this._state} → ${s}`);
614
+ this._state = s;
615
+ if (this._on_state) {
616
+ try {
617
+ this._on_state(s);
618
+ }
619
+ catch {
620
+ /* state callbacks must never break the loop */
621
+ }
622
+ }
623
+ }
624
+ /**
625
+ * Wire the whisper-polling fallback so the wake detector can reuse this
626
+ * daemon's STT engine — this is the Node equivalent of the Python "faster-whisper
627
+ * is already a dep of light_daemon" coupling.
628
+ */
629
+ _init_wake_word() {
630
+ _dbg("Initialising wake word detector…");
631
+ registerClipRecognizer({
632
+ name: "light-daemon-stt",
633
+ recognizePcm: (pcm) => this._stt.transcribe_pcm(pcm),
634
+ });
635
+ return get_wake_detector((word) => this._on_wake(word));
636
+ }
637
+ _on_wake(word) {
638
+ _dbg(`*** WAKE WORD FIRED *** '${word}' | current state: ${this._state}`);
639
+ if (this._state === "LISTENING" || this._state === "THINKING" || this._state === "TRANSCRIBING") {
640
+ _dbg("Ignoring wake — already processing");
641
+ return;
642
+ }
643
+ this._wake_ev.set();
644
+ }
645
+ async _loop(signal) {
646
+ _dbg("Main event loop started");
647
+ while (!this._stop_ev.is_set() && !signal.aborted) {
648
+ this._set_state("IDLE");
649
+ const fired = await this._wake_ev.wait(1.0);
650
+ if (!fired)
651
+ continue;
652
+ this._wake_ev.clear();
653
+ if (this._stop_ev.is_set())
654
+ break;
655
+ // ── Acknowledge ─────────────────────────────────────────────────────
656
+ this._set_state("ACKNOWLEDGING");
657
+ await _speak(pick(["Yes?", "Listening.", "Go ahead.", "Ready.", "Here."]));
658
+ await sleep(0.4, signal); // brief gap so the mic doesn't capture BERU's own voice
659
+ // ── Record ──────────────────────────────────────────────────────────
660
+ this._set_state("LISTENING");
661
+ const pcm = await _record_mic({ max_secs: LISTEN_SECS, signal });
662
+ if (pcm.length === 0) {
663
+ _dbg("Empty recording — no speech energy");
664
+ await _speak(pick(["Didn't catch that.", "Say that once more."]));
665
+ continue;
666
+ }
667
+ // ── Transcribe (whisper-tiny, local, fast) ───────────────────────────
668
+ this._set_state("TRANSCRIBING");
669
+ const text = await this._stt.transcribe_pcm(pcm);
670
+ if (!text) {
671
+ _dbg("Whisper returned empty string");
672
+ await _speak("Couldn't make that out.");
673
+ continue;
674
+ }
675
+ console.log(` [BERU] Heard: '${text}'`);
676
+ // ── Classify intent ─────────────────────────────────────────────────
677
+ const tier = _classify(text);
678
+ console.log(` [BERU] Tier: ${tier}`);
679
+ if (tier === "stop") {
680
+ this._set_state("IDLE");
681
+ await _speak("Got it. Going quiet.");
682
+ continue;
683
+ }
684
+ // ── Tier 1: local instant answer ────────────────────────────────────
685
+ if (tier === "local") {
686
+ this._set_state("RESPONDING_LOCAL");
687
+ const response = _local_response(text);
688
+ _dbg(`Local response: '${response}'`);
689
+ await _speak(response);
690
+ continue;
691
+ }
692
+ // ── Tier 2: LLM API call ────────────────────────────────────────────
693
+ this._set_state("THINKING");
694
+ if (!this._llm.available) {
695
+ await _speak("I need an API key for that. Set ANTHROPIC_API_KEY, GROQ_API_KEY, or OPENAI_API_KEY.");
696
+ continue;
697
+ }
698
+ await _speak(pick(["On it.", "One moment.", "Let me check."]));
699
+ const response = await this._llm.ask(text);
700
+ const spoken = _trim(response);
701
+ this._set_state("SPEAKING");
702
+ await _speak(spoken);
703
+ }
704
+ this._set_state("IDLE");
705
+ _dbg("Loop exited cleanly.");
706
+ }
707
+ /** Expose the wake detector for tests/embedding. */
708
+ get wakeDetector() {
709
+ return this._wwd;
710
+ }
711
+ }
712
+ /* ─────────────────────────────────────────────────────────────────────────────
713
+ * Singleton & public entry point
714
+ * ───────────────────────────────────────────────────────────────────────────── */
715
+ /** Keep LightDaemon as an alias so older code doesn't break. */
716
+ export const LightDaemon = LightVoiceDaemon;
717
+ let _daemon = null;
718
+ /**
719
+ * Start BERU's light voice daemon in the background.
720
+ * No local LLM is ever loaded. Returns immediately.
721
+ */
722
+ export function start_light_daemon(options = {}) {
723
+ if (_daemon !== null && _daemon.is_running()) {
724
+ _dbg("Daemon already running — returning existing instance");
725
+ return _daemon;
726
+ }
727
+ _dbg("Creating new LightVoiceDaemon…");
728
+ _daemon = new LightVoiceDaemon(options);
729
+ _daemon.start();
730
+ return _daemon;
731
+ }
732
+ /** camelCase alias of `start_light_daemon`. */
733
+ export const startLightDaemon = start_light_daemon;
734
+ export function get_daemon() {
735
+ return _daemon;
736
+ }
737
+ /** camelCase alias of `get_daemon`. */
738
+ export const getDaemon = get_daemon;
739
+ /** Test/DI hook — replace the singleton. */
740
+ export function setDaemon(d) {
741
+ _daemon = d;
742
+ }
743
+ function errText(e) {
744
+ return e instanceof Error ? e.message : String(e);
745
+ }
746
+ //# sourceMappingURL=light_daemon.js.map