@soederpop/luca 0.1.2 → 0.2.1

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 (381) hide show
  1. package/.github/workflows/release.yaml +167 -0
  2. package/CLAUDE.md +2 -0
  3. package/README.md +3 -0
  4. package/assistants/codingAssistant/ABOUT.md +3 -0
  5. package/assistants/codingAssistant/CORE.md +22 -17
  6. package/assistants/codingAssistant/hooks.ts +17 -4
  7. package/assistants/codingAssistant/tools.ts +1 -106
  8. package/assistants/inkbot/ABOUT.md +5 -0
  9. package/assistants/inkbot/CORE.md +71 -0
  10. package/assistants/inkbot/hooks.ts +14 -0
  11. package/assistants/inkbot/tools.ts +47 -0
  12. package/bun.lock +20 -4
  13. package/commands/inkbot.ts +353 -0
  14. package/commands/release.ts +75 -181
  15. package/dist/agi/container.server.d.ts +63 -0
  16. package/dist/agi/container.server.d.ts.map +1 -0
  17. package/dist/agi/endpoints/ask.d.ts +20 -0
  18. package/dist/agi/endpoints/ask.d.ts.map +1 -0
  19. package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
  20. package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
  21. package/dist/agi/endpoints/conversations.d.ts +18 -0
  22. package/dist/agi/endpoints/conversations.d.ts.map +1 -0
  23. package/dist/agi/endpoints/experts.d.ts +8 -0
  24. package/dist/agi/endpoints/experts.d.ts.map +1 -0
  25. package/dist/agi/feature.d.ts +9 -0
  26. package/dist/agi/feature.d.ts.map +1 -0
  27. package/dist/agi/features/assistant.d.ts +509 -0
  28. package/dist/agi/features/assistant.d.ts.map +1 -0
  29. package/dist/agi/features/assistants-manager.d.ts +236 -0
  30. package/dist/agi/features/assistants-manager.d.ts.map +1 -0
  31. package/dist/agi/features/autonomous-assistant.d.ts +281 -0
  32. package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
  33. package/dist/agi/features/browser-use.d.ts +479 -0
  34. package/dist/agi/features/browser-use.d.ts.map +1 -0
  35. package/dist/agi/features/claude-code.d.ts +824 -0
  36. package/dist/agi/features/claude-code.d.ts.map +1 -0
  37. package/dist/agi/features/conversation-history.d.ts +245 -0
  38. package/dist/agi/features/conversation-history.d.ts.map +1 -0
  39. package/dist/agi/features/conversation.d.ts +464 -0
  40. package/dist/agi/features/conversation.d.ts.map +1 -0
  41. package/dist/agi/features/docs-reader.d.ts +72 -0
  42. package/dist/agi/features/docs-reader.d.ts.map +1 -0
  43. package/dist/agi/features/file-tools.d.ts +110 -0
  44. package/dist/agi/features/file-tools.d.ts.map +1 -0
  45. package/dist/agi/features/luca-coder.d.ts +323 -0
  46. package/dist/agi/features/luca-coder.d.ts.map +1 -0
  47. package/dist/agi/features/openai-codex.d.ts +381 -0
  48. package/dist/agi/features/openai-codex.d.ts.map +1 -0
  49. package/dist/agi/features/openapi.d.ts +200 -0
  50. package/dist/agi/features/openapi.d.ts.map +1 -0
  51. package/dist/agi/features/skills-library.d.ts +167 -0
  52. package/dist/agi/features/skills-library.d.ts.map +1 -0
  53. package/dist/agi/index.d.ts +5 -0
  54. package/dist/agi/index.d.ts.map +1 -0
  55. package/dist/agi/lib/interceptor-chain.d.ts +44 -0
  56. package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
  57. package/dist/agi/lib/token-counter.d.ts +13 -0
  58. package/dist/agi/lib/token-counter.d.ts.map +1 -0
  59. package/dist/bootstrap/generated.d.ts +5 -0
  60. package/dist/bootstrap/generated.d.ts.map +1 -0
  61. package/dist/browser.d.ts +12 -0
  62. package/dist/browser.d.ts.map +1 -0
  63. package/dist/bus.d.ts +29 -0
  64. package/dist/bus.d.ts.map +1 -0
  65. package/dist/cli/build-info.d.ts +4 -0
  66. package/dist/cli/build-info.d.ts.map +1 -0
  67. package/dist/cli/cli.d.ts +3 -0
  68. package/dist/cli/cli.d.ts.map +1 -0
  69. package/dist/client.d.ts +60 -0
  70. package/dist/client.d.ts.map +1 -0
  71. package/dist/clients/civitai/index.d.ts +472 -0
  72. package/dist/clients/civitai/index.d.ts.map +1 -0
  73. package/dist/clients/client-template.d.ts +30 -0
  74. package/dist/clients/client-template.d.ts.map +1 -0
  75. package/dist/clients/comfyui/index.d.ts +281 -0
  76. package/dist/clients/comfyui/index.d.ts.map +1 -0
  77. package/dist/clients/elevenlabs/index.d.ts +197 -0
  78. package/dist/clients/elevenlabs/index.d.ts.map +1 -0
  79. package/dist/clients/graph.d.ts +64 -0
  80. package/dist/clients/graph.d.ts.map +1 -0
  81. package/dist/clients/openai/index.d.ts +247 -0
  82. package/dist/clients/openai/index.d.ts.map +1 -0
  83. package/dist/clients/rest.d.ts +92 -0
  84. package/dist/clients/rest.d.ts.map +1 -0
  85. package/dist/clients/supabase/index.d.ts +176 -0
  86. package/dist/clients/supabase/index.d.ts.map +1 -0
  87. package/dist/clients/websocket.d.ts +127 -0
  88. package/dist/clients/websocket.d.ts.map +1 -0
  89. package/dist/command.d.ts +163 -0
  90. package/dist/command.d.ts.map +1 -0
  91. package/dist/commands/bootstrap.d.ts +20 -0
  92. package/dist/commands/bootstrap.d.ts.map +1 -0
  93. package/dist/commands/chat.d.ts +37 -0
  94. package/dist/commands/chat.d.ts.map +1 -0
  95. package/dist/commands/code.d.ts +28 -0
  96. package/dist/commands/code.d.ts.map +1 -0
  97. package/dist/commands/console.d.ts +22 -0
  98. package/dist/commands/console.d.ts.map +1 -0
  99. package/dist/commands/describe.d.ts +50 -0
  100. package/dist/commands/describe.d.ts.map +1 -0
  101. package/dist/commands/eval.d.ts +23 -0
  102. package/dist/commands/eval.d.ts.map +1 -0
  103. package/dist/commands/help.d.ts +25 -0
  104. package/dist/commands/help.d.ts.map +1 -0
  105. package/dist/commands/index.d.ts +18 -0
  106. package/dist/commands/index.d.ts.map +1 -0
  107. package/dist/commands/introspect.d.ts +24 -0
  108. package/dist/commands/introspect.d.ts.map +1 -0
  109. package/dist/commands/mcp.d.ts +35 -0
  110. package/dist/commands/mcp.d.ts.map +1 -0
  111. package/dist/commands/prompt.d.ts +38 -0
  112. package/dist/commands/prompt.d.ts.map +1 -0
  113. package/dist/commands/run.d.ts +24 -0
  114. package/dist/commands/run.d.ts.map +1 -0
  115. package/dist/commands/sandbox-mcp.d.ts +34 -0
  116. package/dist/commands/sandbox-mcp.d.ts.map +1 -0
  117. package/dist/commands/save-api-docs.d.ts +21 -0
  118. package/dist/commands/save-api-docs.d.ts.map +1 -0
  119. package/dist/commands/scaffold.d.ts +24 -0
  120. package/dist/commands/scaffold.d.ts.map +1 -0
  121. package/dist/commands/select.d.ts +22 -0
  122. package/dist/commands/select.d.ts.map +1 -0
  123. package/dist/commands/serve.d.ts +29 -0
  124. package/dist/commands/serve.d.ts.map +1 -0
  125. package/dist/container-describer.d.ts +144 -0
  126. package/dist/container-describer.d.ts.map +1 -0
  127. package/dist/container.d.ts +451 -0
  128. package/dist/container.d.ts.map +1 -0
  129. package/dist/endpoint.d.ts +113 -0
  130. package/dist/endpoint.d.ts.map +1 -0
  131. package/dist/feature.d.ts +47 -0
  132. package/dist/feature.d.ts.map +1 -0
  133. package/dist/graft.d.ts +29 -0
  134. package/dist/graft.d.ts.map +1 -0
  135. package/dist/hash-object.d.ts +8 -0
  136. package/dist/hash-object.d.ts.map +1 -0
  137. package/dist/helper.d.ts +209 -0
  138. package/dist/helper.d.ts.map +1 -0
  139. package/dist/introspection/generated.node.d.ts +44623 -0
  140. package/dist/introspection/generated.node.d.ts.map +1 -0
  141. package/dist/introspection/generated.web.d.ts +1412 -0
  142. package/dist/introspection/generated.web.d.ts.map +1 -0
  143. package/dist/introspection/index.d.ts +156 -0
  144. package/dist/introspection/index.d.ts.map +1 -0
  145. package/dist/introspection/scan.d.ts +147 -0
  146. package/dist/introspection/scan.d.ts.map +1 -0
  147. package/dist/node/container.d.ts +256 -0
  148. package/dist/node/container.d.ts.map +1 -0
  149. package/dist/node/feature.d.ts +9 -0
  150. package/dist/node/feature.d.ts.map +1 -0
  151. package/dist/node/features/container-link.d.ts +213 -0
  152. package/dist/node/features/container-link.d.ts.map +1 -0
  153. package/dist/node/features/content-db.d.ts +354 -0
  154. package/dist/node/features/content-db.d.ts.map +1 -0
  155. package/dist/node/features/disk-cache.d.ts +236 -0
  156. package/dist/node/features/disk-cache.d.ts.map +1 -0
  157. package/dist/node/features/dns.d.ts +511 -0
  158. package/dist/node/features/dns.d.ts.map +1 -0
  159. package/dist/node/features/docker.d.ts +485 -0
  160. package/dist/node/features/docker.d.ts.map +1 -0
  161. package/dist/node/features/downloader.d.ts +73 -0
  162. package/dist/node/features/downloader.d.ts.map +1 -0
  163. package/dist/node/features/figlet-fonts.d.ts +4 -0
  164. package/dist/node/features/figlet-fonts.d.ts.map +1 -0
  165. package/dist/node/features/file-manager.d.ts +177 -0
  166. package/dist/node/features/file-manager.d.ts.map +1 -0
  167. package/dist/node/features/fs.d.ts +635 -0
  168. package/dist/node/features/fs.d.ts.map +1 -0
  169. package/dist/node/features/git.d.ts +329 -0
  170. package/dist/node/features/git.d.ts.map +1 -0
  171. package/dist/node/features/google-auth.d.ts +200 -0
  172. package/dist/node/features/google-auth.d.ts.map +1 -0
  173. package/dist/node/features/google-calendar.d.ts +194 -0
  174. package/dist/node/features/google-calendar.d.ts.map +1 -0
  175. package/dist/node/features/google-docs.d.ts +138 -0
  176. package/dist/node/features/google-docs.d.ts.map +1 -0
  177. package/dist/node/features/google-drive.d.ts +202 -0
  178. package/dist/node/features/google-drive.d.ts.map +1 -0
  179. package/dist/node/features/google-mail.d.ts +221 -0
  180. package/dist/node/features/google-mail.d.ts.map +1 -0
  181. package/dist/node/features/google-sheets.d.ts +157 -0
  182. package/dist/node/features/google-sheets.d.ts.map +1 -0
  183. package/dist/node/features/grep.d.ts +207 -0
  184. package/dist/node/features/grep.d.ts.map +1 -0
  185. package/dist/node/features/helpers.d.ts +236 -0
  186. package/dist/node/features/helpers.d.ts.map +1 -0
  187. package/dist/node/features/ink.d.ts +332 -0
  188. package/dist/node/features/ink.d.ts.map +1 -0
  189. package/dist/node/features/ipc-socket.d.ts +298 -0
  190. package/dist/node/features/ipc-socket.d.ts.map +1 -0
  191. package/dist/node/features/json-tree.d.ts +140 -0
  192. package/dist/node/features/json-tree.d.ts.map +1 -0
  193. package/dist/node/features/networking.d.ts +373 -0
  194. package/dist/node/features/networking.d.ts.map +1 -0
  195. package/dist/node/features/nlp.d.ts +125 -0
  196. package/dist/node/features/nlp.d.ts.map +1 -0
  197. package/dist/node/features/opener.d.ts +93 -0
  198. package/dist/node/features/opener.d.ts.map +1 -0
  199. package/dist/node/features/os.d.ts +168 -0
  200. package/dist/node/features/os.d.ts.map +1 -0
  201. package/dist/node/features/package-finder.d.ts +419 -0
  202. package/dist/node/features/package-finder.d.ts.map +1 -0
  203. package/dist/node/features/postgres.d.ts +173 -0
  204. package/dist/node/features/postgres.d.ts.map +1 -0
  205. package/dist/node/features/proc.d.ts +285 -0
  206. package/dist/node/features/proc.d.ts.map +1 -0
  207. package/dist/node/features/process-manager.d.ts +427 -0
  208. package/dist/node/features/process-manager.d.ts.map +1 -0
  209. package/dist/node/features/python.d.ts +477 -0
  210. package/dist/node/features/python.d.ts.map +1 -0
  211. package/dist/node/features/redis.d.ts +247 -0
  212. package/dist/node/features/redis.d.ts.map +1 -0
  213. package/dist/node/features/repl.d.ts +84 -0
  214. package/dist/node/features/repl.d.ts.map +1 -0
  215. package/dist/node/features/runpod.d.ts +527 -0
  216. package/dist/node/features/runpod.d.ts.map +1 -0
  217. package/dist/node/features/secure-shell.d.ts +145 -0
  218. package/dist/node/features/secure-shell.d.ts.map +1 -0
  219. package/dist/node/features/semantic-search.d.ts +207 -0
  220. package/dist/node/features/semantic-search.d.ts.map +1 -0
  221. package/dist/node/features/sqlite.d.ts +180 -0
  222. package/dist/node/features/sqlite.d.ts.map +1 -0
  223. package/dist/node/features/telegram.d.ts +173 -0
  224. package/dist/node/features/telegram.d.ts.map +1 -0
  225. package/dist/node/features/transpiler.d.ts +51 -0
  226. package/dist/node/features/transpiler.d.ts.map +1 -0
  227. package/dist/node/features/tts.d.ts +108 -0
  228. package/dist/node/features/tts.d.ts.map +1 -0
  229. package/dist/node/features/ui.d.ts +562 -0
  230. package/dist/node/features/ui.d.ts.map +1 -0
  231. package/dist/node/features/vault.d.ts +90 -0
  232. package/dist/node/features/vault.d.ts.map +1 -0
  233. package/dist/node/features/vm.d.ts +285 -0
  234. package/dist/node/features/vm.d.ts.map +1 -0
  235. package/dist/node/features/yaml-tree.d.ts +118 -0
  236. package/dist/node/features/yaml-tree.d.ts.map +1 -0
  237. package/dist/node/features/yaml.d.ts +127 -0
  238. package/dist/node/features/yaml.d.ts.map +1 -0
  239. package/dist/node.d.ts +67 -0
  240. package/dist/node.d.ts.map +1 -0
  241. package/dist/python/generated.d.ts +2 -0
  242. package/dist/python/generated.d.ts.map +1 -0
  243. package/dist/react/index.d.ts +36 -0
  244. package/dist/react/index.d.ts.map +1 -0
  245. package/dist/registry.d.ts +97 -0
  246. package/dist/registry.d.ts.map +1 -0
  247. package/dist/scaffolds/generated.d.ts +13 -0
  248. package/dist/scaffolds/generated.d.ts.map +1 -0
  249. package/dist/scaffolds/template.d.ts +11 -0
  250. package/dist/scaffolds/template.d.ts.map +1 -0
  251. package/dist/schemas/base.d.ts +254 -0
  252. package/dist/schemas/base.d.ts.map +1 -0
  253. package/dist/selector.d.ts +130 -0
  254. package/dist/selector.d.ts.map +1 -0
  255. package/dist/server.d.ts +89 -0
  256. package/dist/server.d.ts.map +1 -0
  257. package/dist/servers/express.d.ts +104 -0
  258. package/dist/servers/express.d.ts.map +1 -0
  259. package/dist/servers/mcp.d.ts +201 -0
  260. package/dist/servers/mcp.d.ts.map +1 -0
  261. package/dist/servers/socket.d.ts +121 -0
  262. package/dist/servers/socket.d.ts.map +1 -0
  263. package/dist/state.d.ts +24 -0
  264. package/dist/state.d.ts.map +1 -0
  265. package/dist/web/clients/socket.d.ts +37 -0
  266. package/dist/web/clients/socket.d.ts.map +1 -0
  267. package/dist/web/container.d.ts +55 -0
  268. package/dist/web/container.d.ts.map +1 -0
  269. package/dist/web/extension.d.ts +4 -0
  270. package/dist/web/extension.d.ts.map +1 -0
  271. package/dist/web/feature.d.ts +8 -0
  272. package/dist/web/feature.d.ts.map +1 -0
  273. package/dist/web/features/asset-loader.d.ts +35 -0
  274. package/dist/web/features/asset-loader.d.ts.map +1 -0
  275. package/dist/web/features/container-link.d.ts +167 -0
  276. package/dist/web/features/container-link.d.ts.map +1 -0
  277. package/dist/web/features/esbuild.d.ts +51 -0
  278. package/dist/web/features/esbuild.d.ts.map +1 -0
  279. package/dist/web/features/helpers.d.ts +140 -0
  280. package/dist/web/features/helpers.d.ts.map +1 -0
  281. package/dist/web/features/network.d.ts +69 -0
  282. package/dist/web/features/network.d.ts.map +1 -0
  283. package/dist/web/features/speech.d.ts +71 -0
  284. package/dist/web/features/speech.d.ts.map +1 -0
  285. package/dist/web/features/vault.d.ts +62 -0
  286. package/dist/web/features/vault.d.ts.map +1 -0
  287. package/dist/web/features/vm.d.ts +48 -0
  288. package/dist/web/features/vm.d.ts.map +1 -0
  289. package/dist/web/features/voice-recognition.d.ts +96 -0
  290. package/dist/web/features/voice-recognition.d.ts.map +1 -0
  291. package/dist/web/shims/isomorphic-vm.d.ts +22 -0
  292. package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
  293. package/docs/apis/features/agi/assistant.md +1 -0
  294. package/docs/apis/features/agi/assistants-manager.md +62 -2
  295. package/docs/apis/features/agi/auto-assistant.md +11 -109
  296. package/docs/apis/features/agi/claude-code.md +138 -0
  297. package/docs/apis/features/agi/conversation.md +60 -31
  298. package/docs/apis/features/agi/luca-coder.md +407 -0
  299. package/docs/apis/features/agi/openapi.md +2 -2
  300. package/docs/apis/features/agi/skills-library.md +12 -0
  301. package/docs/apis/features/node/python.md +81 -11
  302. package/docs/apis/features/node/transpiler.md +74 -0
  303. package/docs/apis/features/web/esbuild.md +0 -6
  304. package/docs/apis/servers/mcp.md +2 -2
  305. package/docs/examples/entity.md +124 -0
  306. package/docs/ideas/assistant-factory-pattern.md +142 -0
  307. package/package.json +74 -21
  308. package/src/agi/container.server.ts +10 -0
  309. package/src/agi/feature.ts +13 -0
  310. package/src/agi/features/agent-memory.ts +694 -0
  311. package/src/agi/features/assistant.ts +37 -26
  312. package/src/agi/features/assistants-manager.ts +95 -5
  313. package/src/agi/features/autonomous-assistant.ts +1 -5
  314. package/src/agi/features/browser-use.ts +32 -2
  315. package/src/agi/features/claude-code.ts +165 -1
  316. package/src/agi/features/coding-tools.ts +175 -0
  317. package/src/agi/features/conversation-history.ts +2 -6
  318. package/src/agi/features/conversation.ts +95 -3
  319. package/src/agi/features/docs-reader.ts +2 -1
  320. package/src/agi/features/file-tools.ts +35 -28
  321. package/src/agi/features/luca-coder.ts +1 -5
  322. package/src/agi/features/openai-codex.ts +1 -1
  323. package/src/agi/features/openapi.ts +3 -3
  324. package/src/agi/features/skills-library.ts +111 -13
  325. package/src/agi/lib/interceptor-chain.ts +10 -0
  326. package/src/agi/lib/token-counter.ts +1 -1
  327. package/src/bootstrap/generated.ts +126 -1
  328. package/src/bus.ts +27 -5
  329. package/src/cli/build-info.ts +2 -2
  330. package/src/client.ts +2 -2
  331. package/src/clients/elevenlabs/index.ts +5 -0
  332. package/src/clients/voicebox/index.ts +300 -0
  333. package/src/commands/bootstrap.ts +2 -1
  334. package/src/commands/chat.ts +1 -0
  335. package/src/commands/code.ts +4 -2
  336. package/src/commands/prompt.ts +34 -34
  337. package/src/commands/sandbox-mcp.ts +69 -163
  338. package/src/commands/save-api-docs.ts +10 -8
  339. package/src/commands/select.ts +8 -3
  340. package/src/container-describer.ts +70 -84
  341. package/src/container.ts +93 -3
  342. package/src/endpoint.ts +1 -1
  343. package/src/entity.ts +173 -0
  344. package/src/feature.ts +3 -3
  345. package/src/helper.ts +8 -4
  346. package/src/introspection/generated.agi.ts +3012 -1356
  347. package/src/introspection/generated.node.ts +179 -33
  348. package/src/introspection/generated.web.ts +95 -3
  349. package/src/introspection/scan.ts +1 -1
  350. package/src/node/container.ts +1 -1
  351. package/src/node/features/content-db.ts +57 -30
  352. package/src/node/features/file-manager.ts +10 -9
  353. package/src/node/features/git.ts +5 -5
  354. package/src/node/features/helpers.ts +1 -1
  355. package/src/node/features/json-tree.ts +1 -1
  356. package/src/node/features/os.ts +3 -3
  357. package/src/node/features/package-finder.ts +1 -1
  358. package/src/node/features/process-manager.ts +51 -18
  359. package/src/node/features/python.ts +3 -3
  360. package/src/node/features/redis.ts +1 -1
  361. package/src/node/features/repl.ts +2 -2
  362. package/src/node/features/transpiler.ts +2 -2
  363. package/src/node/features/ui.ts +1 -1
  364. package/src/node/features/vm.ts +3 -3
  365. package/src/node/features/yaml-tree.ts +1 -1
  366. package/src/node.ts +1 -0
  367. package/src/python/generated.ts +1 -1
  368. package/src/scaffolds/generated.ts +1 -1
  369. package/src/selector.ts +74 -4
  370. package/src/server.ts +2 -2
  371. package/src/servers/mcp.ts +6 -6
  372. package/src/web/features/helpers.ts +1 -1
  373. package/src/web/features/network.ts +1 -0
  374. package/test/assistant.test.ts +14 -5
  375. package/test/conversation.test.ts +220 -0
  376. package/test-integration/memory.test.ts +204 -0
  377. package/tsconfig.build.json +12 -0
  378. package/tsconfig.json +1 -1
  379. package/scripts/examples/telegram-ink-ui.ts +0 -302
  380. package/scripts/examples/using-openai-codex.ts +0 -23
  381. package/scripts/examples/vm-loading-esm-modules.ts +0 -16
@@ -0,0 +1,300 @@
1
+ import { z } from 'zod'
2
+ import { ClientStateSchema, ClientOptionsSchema, ClientEventsSchema } from '@soederpop/luca/schemas/base.js'
3
+ import { Client } from "@soederpop/luca/client";
4
+ import { RestClient } from "../rest";
5
+ import type { ContainerContext } from "@soederpop/luca/container";
6
+ import type { NodeContainer } from "../../node/container.js";
7
+
8
+ declare module "@soederpop/luca/client" {
9
+ interface AvailableClients {
10
+ voicebox: typeof VoiceBoxClient;
11
+ }
12
+ }
13
+
14
+ export const VoiceBoxClientOptionsSchema = ClientOptionsSchema.extend({
15
+ baseURL: z.string().optional().describe('VoiceBox server URL (falls back to VOICEBOX_URL env var, default http://127.0.0.1:17493)'),
16
+ defaultProfileId: z.string().optional().describe('Default voice profile ID for synthesis'),
17
+ defaultEngine: z.string().optional().default('qwen').describe('Default TTS engine (qwen, luxtts, chatterbox, chatterbox_turbo)'),
18
+ defaultModelSize: z.string().optional().default('1.7B').describe('Default model size (1.7B or 0.6B)'),
19
+ defaultLanguage: z.string().optional().default('en').describe('Default language code'),
20
+ })
21
+ export type VoiceBoxClientOptions = z.infer<typeof VoiceBoxClientOptionsSchema>
22
+
23
+ export const VoiceBoxClientStateSchema = ClientStateSchema.extend({
24
+ requestCount: z.number().default(0).describe('Total number of API requests made'),
25
+ characterCount: z.number().default(0).describe('Total characters sent for synthesis'),
26
+ lastRequestTime: z.number().nullable().default(null).describe('Timestamp of the last API request'),
27
+ })
28
+ export type VoiceBoxClientState = z.infer<typeof VoiceBoxClientStateSchema>
29
+
30
+ export const VoiceBoxClientEventsSchema = ClientEventsSchema.extend({
31
+ speech: z.tuple([z.object({
32
+ profileId: z.string(),
33
+ text: z.string(),
34
+ audioSize: z.number(),
35
+ })]).describe('Emitted after speech synthesis completes'),
36
+ profiles: z.tuple([z.array(z.any())]).describe('Emitted after listing profiles'),
37
+ })
38
+
39
+ export type EffectConfig = {
40
+ type: string
41
+ enabled?: boolean
42
+ params?: Record<string, any>
43
+ }
44
+
45
+ export type SynthesizeOptions = {
46
+ profileId?: string
47
+ engine?: string
48
+ modelSize?: string
49
+ language?: string
50
+ instruct?: string
51
+ seed?: number
52
+ maxChunkChars?: number
53
+ crossfadeMs?: number
54
+ normalize?: boolean
55
+ effectsChain?: EffectConfig[]
56
+ disableCache?: boolean
57
+ }
58
+
59
+ /**
60
+ * VoiceBox client — local TTS synthesis via VoiceBox.sh REST API (Qwen3-TTS).
61
+ *
62
+ * Provides methods for managing voice profiles and generating speech audio locally.
63
+ * Uses the streaming endpoint for synchronous synthesis (returns WAV buffer).
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const vb = container.client('voicebox')
68
+ * await vb.connect()
69
+ * const profiles = await vb.listProfiles()
70
+ * const audio = await vb.synthesize('Hello world', { profileId: profiles[0].id })
71
+ * // audio is a Buffer of WAV data
72
+ * ```
73
+ */
74
+ export class VoiceBoxClient extends RestClient<VoiceBoxClientState, VoiceBoxClientOptions> {
75
+ static override shortcut = "clients.voicebox" as const
76
+ static override envVars = ['VOICEBOX_URL']
77
+ static override stateSchema = VoiceBoxClientStateSchema
78
+ static override optionsSchema = VoiceBoxClientOptionsSchema
79
+ static override eventsSchema = VoiceBoxClientEventsSchema
80
+
81
+ static { Client.register(this, 'voicebox') }
82
+
83
+ override get initialState(): VoiceBoxClientState {
84
+ return {
85
+ ...super.initialState,
86
+ requestCount: 0,
87
+ characterCount: 0,
88
+ lastRequestTime: null,
89
+ }
90
+ }
91
+
92
+ constructor(options: VoiceBoxClientOptions, context: ContainerContext) {
93
+ options = {
94
+ ...options,
95
+ baseURL: options.baseURL || process.env.VOICEBOX_URL || 'http://127.0.0.1:17493',
96
+ }
97
+ super(options, context)
98
+ }
99
+
100
+ override get container(): NodeContainer {
101
+ return super.container as unknown as NodeContainer
102
+ }
103
+
104
+ private trackRequest(characters = 0) {
105
+ const requestCount = this.state.get('requestCount') || 0
106
+ const characterCount = this.state.get('characterCount') || 0
107
+ this.setState({
108
+ requestCount: requestCount + 1,
109
+ characterCount: characterCount + characters,
110
+ lastRequestTime: Date.now(),
111
+ })
112
+ }
113
+
114
+ /**
115
+ * Validate the VoiceBox server is reachable by hitting the health endpoint.
116
+ */
117
+ override async connect(): Promise<this> {
118
+ try {
119
+ const health = await this.get('/health')
120
+ if (health?.status !== 'ok' && health?.status !== 'healthy') {
121
+ // Accept any 200 response as healthy
122
+ }
123
+ await super.connect()
124
+ this.emit('connected' as any)
125
+ return this
126
+ } catch (error) {
127
+ this.emit('failure', error)
128
+ throw error
129
+ }
130
+ }
131
+
132
+ /**
133
+ * List all voice profiles.
134
+ *
135
+ * @returns Array of voice profile objects
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const profiles = await vb.listProfiles()
140
+ * console.log(profiles.map(p => `${p.name} (${p.sample_count} samples)`))
141
+ * ```
142
+ */
143
+ async listProfiles(): Promise<any[]> {
144
+ this.trackRequest()
145
+ const result = await this.get('/profiles')
146
+ const profiles = Array.isArray(result) ? result : []
147
+ this.emit('profiles', profiles)
148
+ return profiles
149
+ }
150
+
151
+ /**
152
+ * Get a single voice profile by ID.
153
+ */
154
+ async getProfile(profileId: string): Promise<any> {
155
+ this.trackRequest()
156
+ return this.get(`/profiles/${profileId}`)
157
+ }
158
+
159
+ /**
160
+ * Create a new voice profile.
161
+ */
162
+ async createProfile(name: string, options: { description?: string; language?: string } = {}): Promise<any> {
163
+ this.trackRequest()
164
+ return this.post('/profiles', { name, ...options })
165
+ }
166
+
167
+ /**
168
+ * List available audio effects and their parameter definitions.
169
+ */
170
+ async listEffects(): Promise<any> {
171
+ this.trackRequest()
172
+ return this.get('/effects/available')
173
+ }
174
+
175
+ /**
176
+ * Synthesize speech from text using the streaming endpoint.
177
+ * Returns audio as a WAV Buffer (synchronous — blocks until audio is ready).
178
+ *
179
+ * @param text - The text to convert to speech
180
+ * @param options - Profile, engine, model, and other synthesis options
181
+ * @returns Audio data as a WAV Buffer
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const audio = await vb.synthesize('Hello world', { profileId: 'abc-123' })
186
+ * // audio is a Buffer of WAV data
187
+ * ```
188
+ */
189
+ async synthesize(text: string, options: SynthesizeOptions = {}): Promise<Buffer> {
190
+ const profileId = options.profileId || this.options.defaultProfileId
191
+ if (!profileId) throw new Error('profileId is required for VoiceBox synthesis')
192
+
193
+ const engine = options.engine || this.options.defaultEngine || 'qwen'
194
+ const modelSize = options.modelSize || this.options.defaultModelSize || '1.7B'
195
+ const language = options.language || this.options.defaultLanguage || 'en'
196
+
197
+ const body: Record<string, any> = {
198
+ profile_id: profileId,
199
+ text,
200
+ language,
201
+ engine,
202
+ model_size: modelSize,
203
+ }
204
+
205
+ if (options.instruct) body.instruct = options.instruct
206
+ if (options.seed != null) body.seed = options.seed
207
+ if (options.maxChunkChars != null) body.max_chunk_chars = options.maxChunkChars
208
+ if (options.crossfadeMs != null) body.crossfade_ms = options.crossfadeMs
209
+ if (options.normalize != null) body.normalize = options.normalize
210
+ if (options.effectsChain) body.effects_chain = options.effectsChain
211
+
212
+ // Check disk cache
213
+ if (!options.disableCache) {
214
+ const { hashObject } = this.container.utils
215
+ const cacheKey = `voicebox:${hashObject({ text, profileId, engine, modelSize, language, instruct: options.instruct })}`
216
+ const diskCache = this.container.feature('diskCache')
217
+
218
+ if (await diskCache.has(cacheKey)) {
219
+ const cached = await diskCache.get(cacheKey)
220
+ const audioBuffer = Buffer.from(cached, 'base64')
221
+ this.emit('speech', { profileId, text, audioSize: audioBuffer.length })
222
+ return audioBuffer
223
+ }
224
+
225
+ const audioBuffer = await this.fetchStreamAudio(body, text.length)
226
+ await diskCache.set(cacheKey, audioBuffer.toString('base64'))
227
+ this.emit('speech', { profileId, text, audioSize: audioBuffer.length })
228
+ return audioBuffer
229
+ }
230
+
231
+ const audioBuffer = await this.fetchStreamAudio(body, text.length)
232
+ this.emit('speech', { profileId, text, audioSize: audioBuffer.length })
233
+ return audioBuffer
234
+ }
235
+
236
+ /**
237
+ * Generate speech asynchronously (returns metadata, not audio).
238
+ * Use getAudio() to fetch the audio after generation completes.
239
+ */
240
+ async generate(text: string, options: SynthesizeOptions = {}): Promise<any> {
241
+ const profileId = options.profileId || this.options.defaultProfileId
242
+ if (!profileId) throw new Error('profileId is required for VoiceBox generation')
243
+
244
+ const body: Record<string, any> = {
245
+ profile_id: profileId,
246
+ text,
247
+ language: options.language || this.options.defaultLanguage || 'en',
248
+ engine: options.engine || this.options.defaultEngine || 'qwen',
249
+ model_size: options.modelSize || this.options.defaultModelSize || '1.7B',
250
+ }
251
+
252
+ if (options.instruct) body.instruct = options.instruct
253
+ if (options.seed != null) body.seed = options.seed
254
+ if (options.effectsChain) body.effects_chain = options.effectsChain
255
+
256
+ this.trackRequest(text.length)
257
+ return this.post('/generate', body)
258
+ }
259
+
260
+ /**
261
+ * Fetch generated audio by generation ID. Returns WAV Buffer.
262
+ */
263
+ async getAudio(generationId: string): Promise<Buffer> {
264
+ this.trackRequest()
265
+ const response = await this.axios({
266
+ method: 'GET',
267
+ url: `/audio/${generationId}`,
268
+ responseType: 'arraybuffer',
269
+ headers: { Accept: 'audio/wav' },
270
+ })
271
+ return Buffer.from(response.data)
272
+ }
273
+
274
+ /**
275
+ * Synthesize and write audio to a file.
276
+ */
277
+ async say(text: string, outputPath: string, options: SynthesizeOptions = {}): Promise<string> {
278
+ const audio = await this.synthesize(text, options)
279
+ const resolvedPath = this.container.paths.resolve(outputPath)
280
+ await this.container.fs.writeFileAsync(resolvedPath, audio)
281
+ return resolvedPath
282
+ }
283
+
284
+ private async fetchStreamAudio(body: Record<string, any>, charCount: number): Promise<Buffer> {
285
+ this.trackRequest(charCount)
286
+ const response = await this.axios({
287
+ method: 'POST',
288
+ url: '/generate/stream',
289
+ data: body,
290
+ responseType: 'arraybuffer',
291
+ headers: {
292
+ 'Content-Type': 'application/json',
293
+ Accept: 'audio/wav',
294
+ },
295
+ })
296
+ return Buffer.from(response.data)
297
+ }
298
+ }
299
+
300
+ export default VoiceBoxClient
@@ -2,6 +2,7 @@ import { z } from 'zod'
2
2
  import { commands } from '../command.js'
3
3
  import { CommandOptionsSchema } from '../schemas/base.js'
4
4
  import type { ContainerContext } from '../container.js'
5
+ import type { NodeContainer } from '../node/container.js'
5
6
  import { bootstrapFiles, bootstrapTemplates, bootstrapExamples, bootstrapTutorials } from '../bootstrap/generated.js'
6
7
  import { generateScaffold } from '../scaffolds/template.js'
7
8
 
@@ -17,7 +18,7 @@ export const argsSchema = CommandOptionsSchema.extend({
17
18
  })
18
19
 
19
20
  async function bootstrap(options: z.infer<typeof argsSchema>, context: ContainerContext) {
20
- const { container } = context
21
+ const container = context.container as unknown as NodeContainer
21
22
  const args = container.argv._ as string[]
22
23
  const fs = container.feature('fs')
23
24
  const ui = container.feature('ui')
@@ -186,6 +186,7 @@ export default async function chat(options: z.infer<typeof argsSchema>, context:
186
186
  const items = Array.isArray(options.use) ? options.use : [options.use]
187
187
  for (const item of items) {
188
188
  const [namepart, optStr] = item.split(':')
189
+ if (!namepart) continue
189
190
  const featureOpts: Record<string, any> = { enable: true }
190
191
  if (optStr) {
191
192
  for (const pair of optStr.split(';')) {
@@ -36,7 +36,7 @@ export default async function code(options: z.infer<typeof argsSchema>, context:
36
36
  if (options.prompt) {
37
37
  const resolved = container.paths.resolve(options.prompt)
38
38
  if (fs.exists(resolved)) {
39
- systemPrompt = fs.readFile(resolved)
39
+ systemPrompt = String(fs.readFile(resolved))
40
40
  } else if (!options.prompt.endsWith('.md')) {
41
41
  systemPrompt = options.prompt
42
42
  } else {
@@ -81,6 +81,8 @@ export default async function code(options: z.infer<typeof argsSchema>, context:
81
81
  model: options.model,
82
82
  local: options.local,
83
83
  skills: extraSkills,
84
+ maxTokens: 2048,
85
+ autoLoadLucaSkill: true,
84
86
  })
85
87
 
86
88
  // ── UI setup ───────────────────────────────────────────────────────────
@@ -319,7 +321,7 @@ export default async function code(options: z.infer<typeof argsSchema>, context:
319
321
 
320
322
  const featureContext: Record<string, any> = {}
321
323
  for (const fname of container.features.available) {
322
- try { featureContext[fname] = container.feature(fname) } catch {}
324
+ try { featureContext[fname] = (container as any).feature(fname) } catch {}
323
325
  }
324
326
 
325
327
  const replPrompt = ui.colors.magenta('console') + ui.colors.dim(' > ')
@@ -257,16 +257,16 @@ async function runParallel(
257
257
 
258
258
  function pushLines(idx: number, text: string) {
259
259
  const newLines = text.split('\n')
260
- promptStates[idx].lines.push(...newLines)
261
- if (promptStates[idx].lines.length > MAX_LINES) {
262
- promptStates[idx].lines = promptStates[idx].lines.slice(-MAX_LINES)
260
+ promptStates[idx]!.lines.push(...newLines)
261
+ if (promptStates[idx]!.lines.length > MAX_LINES) {
262
+ promptStates[idx]!.lines = promptStates[idx]!.lines.slice(-MAX_LINES)
263
263
  }
264
264
  }
265
265
 
266
266
  function pushToolLine(idx: number, text: string) {
267
- promptStates[idx].lines.push(text)
268
- if (promptStates[idx].lines.length > MAX_LINES) {
269
- promptStates[idx].lines.splice(0, 1)
267
+ promptStates[idx]!.lines.push(text)
268
+ if (promptStates[idx]!.lines.length > MAX_LINES) {
269
+ promptStates[idx]!.lines.splice(0, 1)
270
270
  }
271
271
  }
272
272
 
@@ -304,7 +304,7 @@ async function runParallel(
304
304
  if (!Array.isArray(content)) return
305
305
 
306
306
  const usage = message?.message?.usage ?? message?.usage
307
- if (usage?.output_tokens) promptStates[idx].outputTokens += usage.output_tokens
307
+ if (usage?.output_tokens) promptStates[idx]!.outputTokens += usage.output_tokens
308
308
 
309
309
  for (const block of content) {
310
310
  if (block.type === 'text' && block.text) {
@@ -321,33 +321,33 @@ async function runParallel(
321
321
  const idx = sessionMap.get(sessionId)
322
322
  if (idx === undefined) return
323
323
  if (event.type === 'assistant' || event.type === 'tool_result' || event.type === 'message' || event.type === 'function_call_output') {
324
- promptStates[idx].collectedEvents.push(event)
324
+ promptStates[idx]!.collectedEvents.push(event)
325
325
  }
326
326
  })
327
327
  }
328
328
 
329
329
  // Start all sessions — merge per-prompt agentOptions with shared runOptions
330
330
  for (let i = 0; i < prepared.length; i++) {
331
- const perPromptOptions = { ...prepared[i].agentOptions, ...runOptions }
331
+ const perPromptOptions = { ...prepared[i]!.agentOptions, ...runOptions }
332
332
  if (options.model) perPromptOptions.model = options.model
333
- const id = await feature.start(prepared[i].promptContent, perPromptOptions)
333
+ const id = await feature.start(prepared[i]!.promptContent, perPromptOptions)
334
334
  sessionMap.set(id, i)
335
335
  }
336
336
 
337
337
  const ids = [...sessionMap.keys()]
338
338
  sessionPromise = Promise.allSettled(ids.map((id) => feature.waitForSession(id))).then((results) => {
339
339
  results.forEach((r, ri) => {
340
- const id = ids[ri]
340
+ const id = ids[ri]!
341
341
  const idx = sessionMap.get(id)!
342
- promptStates[idx].durationMs = Date.now() - promptStates[idx].startTime
342
+ promptStates[idx]!.durationMs = Date.now() - promptStates[idx]!.startTime
343
343
  if (r.status === 'fulfilled' && r.value?.status === 'error') {
344
- promptStates[idx].status = 'error'
345
- promptStates[idx].error = r.value?.error || 'Session failed'
344
+ promptStates[idx]!.status = 'error'
345
+ promptStates[idx]!.error = r.value?.error || 'Session failed'
346
346
  } else if (r.status === 'rejected') {
347
- promptStates[idx].status = 'error'
348
- promptStates[idx].error = String(r.reason)
347
+ promptStates[idx]!.status = 'error'
348
+ promptStates[idx]!.error = String(r.reason)
349
349
  } else {
350
- promptStates[idx].status = 'done'
350
+ promptStates[idx]!.status = 'done'
351
351
  }
352
352
  })
353
353
  allDone = true
@@ -375,16 +375,16 @@ async function runParallel(
375
375
 
376
376
  assistant.on('chunk', (text: string) => {
377
377
  lineBuffers[i] += text
378
- const parts = lineBuffers[i].split('\n')
378
+ const parts = lineBuffers[i]!.split('\n')
379
379
  lineBuffers[i] = parts.pop() || ''
380
380
  if (parts.length) {
381
- promptStates[i].lines.push(...parts)
382
- if (promptStates[i].lines.length > MAX_LINES) {
383
- promptStates[i].lines = promptStates[i].lines.slice(-MAX_LINES)
381
+ promptStates[i]!.lines.push(...parts)
382
+ if (promptStates[i]!.lines.length > MAX_LINES) {
383
+ promptStates[i]!.lines = promptStates[i]!.lines.slice(-MAX_LINES)
384
384
  }
385
385
  }
386
386
  if (options['out-file']) {
387
- promptStates[i].collectedEvents.push({ type: 'assistant', message: { content: [{ type: 'text', text }] } })
387
+ promptStates[i]!.collectedEvents.push({ type: 'assistant', message: { content: [{ type: 'text', text }] } })
388
388
  }
389
389
  })
390
390
 
@@ -392,7 +392,7 @@ async function runParallel(
392
392
  const argsStr = JSON.stringify(args).slice(0, 80)
393
393
  pushToolLine(i, ` > ${toolName}(${argsStr})`)
394
394
  if (options['out-file']) {
395
- promptStates[i].collectedEvents.push({
395
+ promptStates[i]!.collectedEvents.push({
396
396
  type: 'assistant',
397
397
  message: { content: [{ type: 'tool_use', name: toolName, input: args }] },
398
398
  })
@@ -403,7 +403,7 @@ async function runParallel(
403
403
  const preview = typeof result === 'string' ? result.slice(0, 60) : JSON.stringify(result).slice(0, 60)
404
404
  pushToolLine(i, ` ✓ ${toolName} → ${preview}`)
405
405
  if (options['out-file']) {
406
- promptStates[i].collectedEvents.push({
406
+ promptStates[i]!.collectedEvents.push({
407
407
  type: 'tool_result',
408
408
  content: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
409
409
  })
@@ -418,20 +418,20 @@ async function runParallel(
418
418
  return assistant
419
419
  })
420
420
 
421
- sessionPromise = Promise.allSettled(assistants.map((a, i) => a.ask(prepared[i].promptContent))).then(
421
+ sessionPromise = Promise.allSettled(assistants.map((a, i) => a.ask(prepared[i]!.promptContent))).then(
422
422
  (results) => {
423
423
  results.forEach((r, i) => {
424
- promptStates[i].durationMs = Date.now() - promptStates[i].startTime
424
+ promptStates[i]!.durationMs = Date.now() - promptStates[i]!.startTime
425
425
  // Flush remaining line buffer
426
426
  if (lineBuffers[i]) {
427
- promptStates[i].lines.push(lineBuffers[i])
427
+ promptStates[i]!.lines.push(lineBuffers[i]!)
428
428
  lineBuffers[i] = ''
429
429
  }
430
430
  if (r.status === 'rejected') {
431
- promptStates[i].status = 'error'
432
- promptStates[i].error = String(r.reason)
431
+ promptStates[i]!.status = 'error'
432
+ promptStates[i]!.error = String(r.reason)
433
433
  } else {
434
- promptStates[i].status = 'done'
434
+ promptStates[i]!.status = 'done'
435
435
  }
436
436
  })
437
437
  allDone = true
@@ -551,9 +551,9 @@ async function runParallel(
551
551
  const stem = dotIdx > 0 ? base.slice(0, dotIdx) : base
552
552
 
553
553
  for (let i = 0; i < promptStates.length; i++) {
554
- const ps = promptStates[i]
554
+ const ps = promptStates[i]!
555
555
  if (!ps.collectedEvents.length) continue
556
- const promptBasename = paths.basename(prepared[i].resolvedPath)
556
+ const promptBasename = paths.basename(prepared[i]!.resolvedPath)
557
557
  const promptStem = promptBasename.lastIndexOf('.') > 0 ? promptBasename.slice(0, promptBasename.lastIndexOf('.')) : promptBasename
558
558
  const outPath = paths.resolve(`${stem}-${promptStem}${ext}`)
559
559
  const markdown = formatSessionMarkdown(ps.collectedEvents, options['include-output'])
@@ -655,7 +655,7 @@ async function resolveInputs(
655
655
 
656
656
  // Build wizard questions for missing inputs
657
657
  const questions = missing.map((key) => {
658
- const def = inputDefs[key]
658
+ const def = inputDefs[key]!
659
659
  const q: Record<string, any> = {
660
660
  name: key,
661
661
  message: def.description || key,
@@ -920,7 +920,7 @@ export default async function prompt(options: z.infer<typeof argsSchema>, contex
920
920
  }
921
921
 
922
922
  // --- Single prompt mode ---
923
- const promptPath = allPaths[0]
923
+ const promptPath = allPaths[0]!
924
924
  const p = await preparePrompt(promptPath, options, container)
925
925
 
926
926
  if (!p) {