luca 2.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/.github/workflows/release.yaml +170 -0
  2. package/AGENTS.md +99 -0
  3. package/CLAUDE.md +123 -0
  4. package/CNAME +1 -0
  5. package/README.md +275 -9
  6. package/RUNME.md +56 -0
  7. package/assistants/codingAssistant/ABOUT.md +5 -0
  8. package/assistants/codingAssistant/CORE.md +33 -0
  9. package/assistants/codingAssistant/hooks.ts +21 -0
  10. package/assistants/codingAssistant/tools.ts +12 -0
  11. package/assistants/inkbot/ABOUT.md +16 -0
  12. package/assistants/inkbot/CORE.md +330 -0
  13. package/assistants/inkbot/hooks.ts +6 -0
  14. package/assistants/inkbot/tools.ts +53 -0
  15. package/assistants/researcher/ABOUT.md +5 -0
  16. package/assistants/researcher/CORE.md +46 -0
  17. package/assistants/researcher/hooks.ts +16 -0
  18. package/assistants/researcher/tools.ts +237 -0
  19. package/bun.lock +2667 -0
  20. package/bunfig.toml +3 -0
  21. package/commands/audit-docs.ts +740 -0
  22. package/commands/build-bootstrap.ts +117 -0
  23. package/commands/build-python-bridge.ts +42 -0
  24. package/commands/build-scaffolds.ts +175 -0
  25. package/commands/bundle-consumer-project.ts +521 -0
  26. package/commands/generate-api-docs.ts +114 -0
  27. package/commands/inkbot.ts +874 -0
  28. package/commands/release.ts +80 -0
  29. package/commands/try-all-challenges.ts +543 -0
  30. package/commands/try-challenge.ts +100 -0
  31. package/dist/agi/container.server.d.ts +63 -0
  32. package/dist/agi/container.server.d.ts.map +1 -0
  33. package/dist/agi/endpoints/ask.d.ts +20 -0
  34. package/dist/agi/endpoints/ask.d.ts.map +1 -0
  35. package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
  36. package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
  37. package/dist/agi/endpoints/conversations.d.ts +18 -0
  38. package/dist/agi/endpoints/conversations.d.ts.map +1 -0
  39. package/dist/agi/endpoints/experts.d.ts +8 -0
  40. package/dist/agi/endpoints/experts.d.ts.map +1 -0
  41. package/dist/agi/feature.d.ts +9 -0
  42. package/dist/agi/feature.d.ts.map +1 -0
  43. package/dist/agi/features/assistant.d.ts +509 -0
  44. package/dist/agi/features/assistant.d.ts.map +1 -0
  45. package/dist/agi/features/assistants-manager.d.ts +236 -0
  46. package/dist/agi/features/assistants-manager.d.ts.map +1 -0
  47. package/dist/agi/features/autonomous-assistant.d.ts +281 -0
  48. package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
  49. package/dist/agi/features/browser-use.d.ts +479 -0
  50. package/dist/agi/features/browser-use.d.ts.map +1 -0
  51. package/dist/agi/features/claude-code.d.ts +824 -0
  52. package/dist/agi/features/claude-code.d.ts.map +1 -0
  53. package/dist/agi/features/conversation-history.d.ts +245 -0
  54. package/dist/agi/features/conversation-history.d.ts.map +1 -0
  55. package/dist/agi/features/conversation.d.ts +464 -0
  56. package/dist/agi/features/conversation.d.ts.map +1 -0
  57. package/dist/agi/features/docs-reader.d.ts +72 -0
  58. package/dist/agi/features/docs-reader.d.ts.map +1 -0
  59. package/dist/agi/features/file-tools.d.ts +110 -0
  60. package/dist/agi/features/file-tools.d.ts.map +1 -0
  61. package/dist/agi/features/luca-coder.d.ts +323 -0
  62. package/dist/agi/features/luca-coder.d.ts.map +1 -0
  63. package/dist/agi/features/openai-codex.d.ts +381 -0
  64. package/dist/agi/features/openai-codex.d.ts.map +1 -0
  65. package/dist/agi/features/openapi.d.ts +200 -0
  66. package/dist/agi/features/openapi.d.ts.map +1 -0
  67. package/dist/agi/features/skills-library.d.ts +167 -0
  68. package/dist/agi/features/skills-library.d.ts.map +1 -0
  69. package/dist/agi/index.d.ts +5 -0
  70. package/dist/agi/index.d.ts.map +1 -0
  71. package/dist/agi/lib/interceptor-chain.d.ts +44 -0
  72. package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
  73. package/dist/agi/lib/token-counter.d.ts +13 -0
  74. package/dist/agi/lib/token-counter.d.ts.map +1 -0
  75. package/dist/bootstrap/generated.d.ts +5 -0
  76. package/dist/bootstrap/generated.d.ts.map +1 -0
  77. package/dist/browser.d.ts +12 -0
  78. package/dist/browser.d.ts.map +1 -0
  79. package/dist/bus.d.ts +29 -0
  80. package/dist/bus.d.ts.map +1 -0
  81. package/dist/cli/build-info.d.ts +4 -0
  82. package/dist/cli/build-info.d.ts.map +1 -0
  83. package/dist/cli/cli.d.ts +3 -12
  84. package/dist/cli/cli.d.ts.map +1 -0
  85. package/dist/client.d.ts +60 -0
  86. package/dist/client.d.ts.map +1 -0
  87. package/dist/clients/civitai/index.d.ts +472 -0
  88. package/dist/clients/civitai/index.d.ts.map +1 -0
  89. package/dist/clients/client-template.d.ts +30 -0
  90. package/dist/clients/client-template.d.ts.map +1 -0
  91. package/dist/clients/comfyui/index.d.ts +281 -0
  92. package/dist/clients/comfyui/index.d.ts.map +1 -0
  93. package/dist/clients/elevenlabs/index.d.ts +197 -0
  94. package/dist/clients/elevenlabs/index.d.ts.map +1 -0
  95. package/dist/clients/graph.d.ts +64 -0
  96. package/dist/clients/graph.d.ts.map +1 -0
  97. package/dist/clients/openai/index.d.ts +247 -0
  98. package/dist/clients/openai/index.d.ts.map +1 -0
  99. package/dist/clients/rest.d.ts +92 -0
  100. package/dist/clients/rest.d.ts.map +1 -0
  101. package/dist/clients/supabase/index.d.ts +176 -0
  102. package/dist/clients/supabase/index.d.ts.map +1 -0
  103. package/dist/clients/websocket.d.ts +127 -0
  104. package/dist/clients/websocket.d.ts.map +1 -0
  105. package/dist/command.d.ts +163 -0
  106. package/dist/command.d.ts.map +1 -0
  107. package/dist/commands/bootstrap.d.ts +20 -0
  108. package/dist/commands/bootstrap.d.ts.map +1 -0
  109. package/dist/commands/chat.d.ts +37 -0
  110. package/dist/commands/chat.d.ts.map +1 -0
  111. package/dist/commands/code.d.ts +28 -0
  112. package/dist/commands/code.d.ts.map +1 -0
  113. package/dist/commands/console.d.ts +22 -0
  114. package/dist/commands/console.d.ts.map +1 -0
  115. package/dist/commands/describe.d.ts +50 -0
  116. package/dist/commands/describe.d.ts.map +1 -0
  117. package/dist/commands/eval.d.ts +23 -0
  118. package/dist/commands/eval.d.ts.map +1 -0
  119. package/dist/commands/help.d.ts +25 -0
  120. package/dist/commands/help.d.ts.map +1 -0
  121. package/dist/commands/index.d.ts +18 -0
  122. package/dist/commands/index.d.ts.map +1 -0
  123. package/dist/commands/introspect.d.ts +24 -0
  124. package/dist/commands/introspect.d.ts.map +1 -0
  125. package/dist/commands/mcp.d.ts +35 -0
  126. package/dist/commands/mcp.d.ts.map +1 -0
  127. package/dist/commands/prompt.d.ts +38 -0
  128. package/dist/commands/prompt.d.ts.map +1 -0
  129. package/dist/commands/run.d.ts +24 -0
  130. package/dist/commands/run.d.ts.map +1 -0
  131. package/dist/commands/sandbox-mcp.d.ts +34 -0
  132. package/dist/commands/sandbox-mcp.d.ts.map +1 -0
  133. package/dist/commands/save-api-docs.d.ts +21 -0
  134. package/dist/commands/save-api-docs.d.ts.map +1 -0
  135. package/dist/commands/scaffold.d.ts +24 -0
  136. package/dist/commands/scaffold.d.ts.map +1 -0
  137. package/dist/commands/select.d.ts +22 -0
  138. package/dist/commands/select.d.ts.map +1 -0
  139. package/dist/commands/serve.d.ts +29 -0
  140. package/dist/commands/serve.d.ts.map +1 -0
  141. package/dist/container-describer.d.ts +144 -0
  142. package/dist/container-describer.d.ts.map +1 -0
  143. package/dist/container.d.ts +451 -0
  144. package/dist/container.d.ts.map +1 -0
  145. package/dist/endpoint.d.ts +113 -0
  146. package/dist/endpoint.d.ts.map +1 -0
  147. package/dist/feature.d.ts +47 -0
  148. package/dist/feature.d.ts.map +1 -0
  149. package/dist/graft.d.ts +29 -0
  150. package/dist/graft.d.ts.map +1 -0
  151. package/dist/hash-object.d.ts +8 -0
  152. package/dist/hash-object.d.ts.map +1 -0
  153. package/dist/helper.d.ts +209 -0
  154. package/dist/helper.d.ts.map +1 -0
  155. package/dist/introspection/generated.node.d.ts +44623 -0
  156. package/dist/introspection/generated.node.d.ts.map +1 -0
  157. package/dist/introspection/generated.web.d.ts +1412 -0
  158. package/dist/introspection/generated.web.d.ts.map +1 -0
  159. package/dist/introspection/index.d.ts +156 -0
  160. package/dist/introspection/index.d.ts.map +1 -0
  161. package/dist/introspection/scan.d.ts +147 -0
  162. package/dist/introspection/scan.d.ts.map +1 -0
  163. package/dist/node/container.d.ts +256 -0
  164. package/dist/node/container.d.ts.map +1 -0
  165. package/dist/node/feature.d.ts +9 -0
  166. package/dist/node/feature.d.ts.map +1 -0
  167. package/dist/node/features/container-link.d.ts +213 -0
  168. package/dist/node/features/container-link.d.ts.map +1 -0
  169. package/dist/node/features/content-db.d.ts +354 -0
  170. package/dist/node/features/content-db.d.ts.map +1 -0
  171. package/dist/node/features/disk-cache.d.ts +236 -0
  172. package/dist/node/features/disk-cache.d.ts.map +1 -0
  173. package/dist/node/features/dns.d.ts +511 -0
  174. package/dist/node/features/dns.d.ts.map +1 -0
  175. package/dist/node/features/docker.d.ts +485 -0
  176. package/dist/node/features/docker.d.ts.map +1 -0
  177. package/dist/node/features/downloader.d.ts +73 -0
  178. package/dist/node/features/downloader.d.ts.map +1 -0
  179. package/dist/node/features/figlet-fonts.d.ts +4 -0
  180. package/dist/node/features/figlet-fonts.d.ts.map +1 -0
  181. package/dist/node/features/file-manager.d.ts +177 -0
  182. package/dist/node/features/file-manager.d.ts.map +1 -0
  183. package/dist/node/features/fs.d.ts +635 -0
  184. package/dist/node/features/fs.d.ts.map +1 -0
  185. package/dist/node/features/git.d.ts +329 -0
  186. package/dist/node/features/git.d.ts.map +1 -0
  187. package/dist/node/features/google-auth.d.ts +200 -0
  188. package/dist/node/features/google-auth.d.ts.map +1 -0
  189. package/dist/node/features/google-calendar.d.ts +194 -0
  190. package/dist/node/features/google-calendar.d.ts.map +1 -0
  191. package/dist/node/features/google-docs.d.ts +138 -0
  192. package/dist/node/features/google-docs.d.ts.map +1 -0
  193. package/dist/node/features/google-drive.d.ts +202 -0
  194. package/dist/node/features/google-drive.d.ts.map +1 -0
  195. package/dist/node/features/google-mail.d.ts +221 -0
  196. package/dist/node/features/google-mail.d.ts.map +1 -0
  197. package/dist/node/features/google-sheets.d.ts +157 -0
  198. package/dist/node/features/google-sheets.d.ts.map +1 -0
  199. package/dist/node/features/grep.d.ts +207 -0
  200. package/dist/node/features/grep.d.ts.map +1 -0
  201. package/dist/node/features/helpers.d.ts +236 -0
  202. package/dist/node/features/helpers.d.ts.map +1 -0
  203. package/dist/node/features/ink.d.ts +332 -0
  204. package/dist/node/features/ink.d.ts.map +1 -0
  205. package/dist/node/features/ipc-socket.d.ts +298 -0
  206. package/dist/node/features/ipc-socket.d.ts.map +1 -0
  207. package/dist/node/features/json-tree.d.ts +140 -0
  208. package/dist/node/features/json-tree.d.ts.map +1 -0
  209. package/dist/node/features/networking.d.ts +373 -0
  210. package/dist/node/features/networking.d.ts.map +1 -0
  211. package/dist/node/features/nlp.d.ts +125 -0
  212. package/dist/node/features/nlp.d.ts.map +1 -0
  213. package/dist/node/features/opener.d.ts +93 -0
  214. package/dist/node/features/opener.d.ts.map +1 -0
  215. package/dist/node/features/os.d.ts +168 -0
  216. package/dist/node/features/os.d.ts.map +1 -0
  217. package/dist/node/features/package-finder.d.ts +419 -0
  218. package/dist/node/features/package-finder.d.ts.map +1 -0
  219. package/dist/node/features/postgres.d.ts +173 -0
  220. package/dist/node/features/postgres.d.ts.map +1 -0
  221. package/dist/node/features/proc.d.ts +285 -0
  222. package/dist/node/features/proc.d.ts.map +1 -0
  223. package/dist/node/features/process-manager.d.ts +427 -0
  224. package/dist/node/features/process-manager.d.ts.map +1 -0
  225. package/dist/node/features/python.d.ts +477 -0
  226. package/dist/node/features/python.d.ts.map +1 -0
  227. package/dist/node/features/redis.d.ts +247 -0
  228. package/dist/node/features/redis.d.ts.map +1 -0
  229. package/dist/node/features/repl.d.ts +84 -0
  230. package/dist/node/features/repl.d.ts.map +1 -0
  231. package/dist/node/features/runpod.d.ts +527 -0
  232. package/dist/node/features/runpod.d.ts.map +1 -0
  233. package/dist/node/features/secure-shell.d.ts +145 -0
  234. package/dist/node/features/secure-shell.d.ts.map +1 -0
  235. package/dist/node/features/semantic-search.d.ts +207 -0
  236. package/dist/node/features/semantic-search.d.ts.map +1 -0
  237. package/dist/node/features/sqlite.d.ts +180 -0
  238. package/dist/node/features/sqlite.d.ts.map +1 -0
  239. package/dist/node/features/telegram.d.ts +173 -0
  240. package/dist/node/features/telegram.d.ts.map +1 -0
  241. package/dist/node/features/transpiler.d.ts +51 -0
  242. package/dist/node/features/transpiler.d.ts.map +1 -0
  243. package/dist/node/features/tts.d.ts +108 -0
  244. package/dist/node/features/tts.d.ts.map +1 -0
  245. package/dist/node/features/ui.d.ts +562 -0
  246. package/dist/node/features/ui.d.ts.map +1 -0
  247. package/dist/node/features/vault.d.ts +90 -0
  248. package/dist/node/features/vault.d.ts.map +1 -0
  249. package/dist/node/features/vm.d.ts +285 -0
  250. package/dist/node/features/vm.d.ts.map +1 -0
  251. package/dist/node/features/yaml-tree.d.ts +118 -0
  252. package/dist/node/features/yaml-tree.d.ts.map +1 -0
  253. package/dist/node/features/yaml.d.ts +127 -0
  254. package/dist/node/features/yaml.d.ts.map +1 -0
  255. package/dist/node.d.ts +67 -0
  256. package/dist/node.d.ts.map +1 -0
  257. package/dist/python/generated.d.ts +2 -0
  258. package/dist/python/generated.d.ts.map +1 -0
  259. package/dist/react/index.d.ts +36 -0
  260. package/dist/react/index.d.ts.map +1 -0
  261. package/dist/registry.d.ts +97 -0
  262. package/dist/registry.d.ts.map +1 -0
  263. package/dist/scaffolds/generated.d.ts +13 -0
  264. package/dist/scaffolds/generated.d.ts.map +1 -0
  265. package/dist/scaffolds/template.d.ts +11 -0
  266. package/dist/scaffolds/template.d.ts.map +1 -0
  267. package/dist/schemas/base.d.ts +254 -0
  268. package/dist/schemas/base.d.ts.map +1 -0
  269. package/dist/selector.d.ts +130 -0
  270. package/dist/selector.d.ts.map +1 -0
  271. package/dist/server.d.ts +89 -0
  272. package/dist/server.d.ts.map +1 -0
  273. package/dist/servers/express.d.ts +104 -0
  274. package/dist/servers/express.d.ts.map +1 -0
  275. package/dist/servers/mcp.d.ts +201 -0
  276. package/dist/servers/mcp.d.ts.map +1 -0
  277. package/dist/servers/socket.d.ts +121 -0
  278. package/dist/servers/socket.d.ts.map +1 -0
  279. package/dist/state.d.ts +24 -0
  280. package/dist/state.d.ts.map +1 -0
  281. package/dist/web/clients/socket.d.ts +37 -0
  282. package/dist/web/clients/socket.d.ts.map +1 -0
  283. package/dist/web/container.d.ts +55 -0
  284. package/dist/web/container.d.ts.map +1 -0
  285. package/dist/web/extension.d.ts +4 -0
  286. package/dist/web/extension.d.ts.map +1 -0
  287. package/dist/web/feature.d.ts +8 -0
  288. package/dist/web/feature.d.ts.map +1 -0
  289. package/dist/web/features/asset-loader.d.ts +35 -0
  290. package/dist/web/features/asset-loader.d.ts.map +1 -0
  291. package/dist/web/features/container-link.d.ts +167 -0
  292. package/dist/web/features/container-link.d.ts.map +1 -0
  293. package/dist/web/features/esbuild.d.ts +51 -0
  294. package/dist/web/features/esbuild.d.ts.map +1 -0
  295. package/dist/web/features/helpers.d.ts +140 -0
  296. package/dist/web/features/helpers.d.ts.map +1 -0
  297. package/dist/web/features/network.d.ts +69 -0
  298. package/dist/web/features/network.d.ts.map +1 -0
  299. package/dist/web/features/speech.d.ts +71 -0
  300. package/dist/web/features/speech.d.ts.map +1 -0
  301. package/dist/web/features/vault.d.ts +62 -0
  302. package/dist/web/features/vault.d.ts.map +1 -0
  303. package/dist/web/features/vm.d.ts +48 -0
  304. package/dist/web/features/vm.d.ts.map +1 -0
  305. package/dist/web/features/voice-recognition.d.ts +96 -0
  306. package/dist/web/features/voice-recognition.d.ts.map +1 -0
  307. package/dist/web/shims/isomorphic-vm.d.ts +22 -0
  308. package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
  309. package/index.html +1457 -0
  310. package/index.ts +1 -0
  311. package/install.sh +84 -0
  312. package/luca.cli.ts +16 -0
  313. package/luca.console.ts +9 -0
  314. package/main.py +6 -0
  315. package/package.json +219 -58
  316. package/public/index.html +1457 -0
  317. package/public/slides-ai-native.html +902 -0
  318. package/public/slides-intro.html +974 -0
  319. package/pyproject.toml +7 -0
  320. package/scripts/build-web.ts +28 -0
  321. package/scripts/examples/ask-luca-expert.ts +42 -0
  322. package/scripts/examples/assistant-questions.ts +12 -0
  323. package/scripts/examples/excalidraw-expert.ts +75 -0
  324. package/scripts/examples/expert-chat.ts +0 -0
  325. package/scripts/examples/file-manager.ts +14 -0
  326. package/scripts/examples/ideas.ts +12 -0
  327. package/scripts/examples/interactive-chat.ts +20 -0
  328. package/scripts/examples/openai-tool-calls.ts +113 -0
  329. package/scripts/examples/opening-a-web-browser.ts +5 -0
  330. package/scripts/examples/telegram-bot.ts +79 -0
  331. package/scripts/examples/using-assistant-with-mcp.ts +555 -0
  332. package/scripts/examples/using-claude-code.ts +10 -0
  333. package/scripts/examples/using-contentdb.ts +35 -0
  334. package/scripts/examples/using-conversations.ts +35 -0
  335. package/scripts/examples/using-disk-cache.ts +10 -0
  336. package/scripts/examples/using-docker-shell.ts +75 -0
  337. package/scripts/examples/using-elevenlabs.ts +25 -0
  338. package/scripts/examples/using-google-calendar.ts +57 -0
  339. package/scripts/examples/using-google-docs.ts +74 -0
  340. package/scripts/examples/using-google-drive.ts +74 -0
  341. package/scripts/examples/using-google-sheets.ts +89 -0
  342. package/scripts/examples/using-nlp.ts +55 -0
  343. package/scripts/examples/using-ollama.ts +11 -0
  344. package/scripts/examples/using-postgres.ts +55 -0
  345. package/scripts/examples/using-runpod.ts +32 -0
  346. package/scripts/examples/using-tts.ts +40 -0
  347. package/scripts/scaffold.ts +391 -0
  348. package/scripts/scratch.ts +15 -0
  349. package/scripts/stamp-build.sh +12 -0
  350. package/scripts/test-assistant-hooks.ts +13 -0
  351. package/scripts/test-docs-reader.ts +10 -0
  352. package/scripts/test-linux-binary.sh +80 -0
  353. package/scripts/update-introspection-data.ts +58 -0
  354. package/src/agi/README.md +14 -0
  355. package/src/agi/container.server.ts +156 -0
  356. package/src/agi/feature.ts +13 -0
  357. package/src/agi/features/agent-memory.ts +694 -0
  358. package/src/agi/features/assistant.ts +1653 -0
  359. package/src/agi/features/assistants-manager.ts +534 -0
  360. package/src/agi/features/autonomous-assistant.ts +431 -0
  361. package/src/agi/features/browser-use.ts +672 -0
  362. package/src/agi/features/claude-code.ts +1584 -0
  363. package/src/agi/features/coding-tools.ts +175 -0
  364. package/src/agi/features/conversation-history.ts +672 -0
  365. package/src/agi/features/conversation.ts +1494 -0
  366. package/src/agi/features/docs-reader.ts +167 -0
  367. package/src/agi/features/file-tools.ts +340 -0
  368. package/src/agi/features/luca-coder.ts +641 -0
  369. package/src/agi/features/mcp-bridge.ts +532 -0
  370. package/src/agi/features/openai-codex.ts +651 -0
  371. package/src/agi/features/openapi.ts +445 -0
  372. package/src/agi/features/skills-library.ts +557 -0
  373. package/src/agi/index.ts +6 -0
  374. package/src/agi/lib/interceptor-chain.ts +89 -0
  375. package/src/agi/lib/token-counter.ts +202 -0
  376. package/src/bootstrap/generated.ts +9791 -0
  377. package/src/browser.ts +25 -0
  378. package/src/bus.ts +122 -0
  379. package/src/cli/build-info.ts +4 -0
  380. package/src/cli/cli.ts +355 -0
  381. package/src/client.ts +170 -0
  382. package/src/clients/civitai/index.ts +537 -0
  383. package/src/clients/client-template.ts +41 -0
  384. package/src/clients/comfyui/index.ts +604 -0
  385. package/src/clients/elevenlabs/index.ts +317 -0
  386. package/src/clients/graph.ts +87 -0
  387. package/src/clients/openai/index.ts +456 -0
  388. package/src/clients/rest.ts +207 -0
  389. package/src/clients/supabase/index.ts +357 -0
  390. package/src/clients/voicebox/index.ts +300 -0
  391. package/src/clients/websocket.ts +251 -0
  392. package/src/command.ts +506 -0
  393. package/src/commands/bootstrap.ts +244 -0
  394. package/src/commands/chat.ts +309 -0
  395. package/src/commands/code.ts +371 -0
  396. package/src/commands/console.ts +189 -0
  397. package/src/commands/describe.ts +243 -0
  398. package/src/commands/eval.ts +67 -0
  399. package/src/commands/help.ts +240 -0
  400. package/src/commands/index.ts +19 -0
  401. package/src/commands/introspect.ts +218 -0
  402. package/src/commands/mcp.ts +64 -0
  403. package/src/commands/prompt.ts +1014 -0
  404. package/src/commands/run.ts +278 -0
  405. package/src/commands/sandbox-mcp.ts +343 -0
  406. package/src/commands/save-api-docs.ts +51 -0
  407. package/src/commands/scaffold.ts +225 -0
  408. package/src/commands/select.ts +99 -0
  409. package/src/commands/serve.ts +208 -0
  410. package/src/container-describer.ts +1091 -0
  411. package/src/container.ts +1199 -0
  412. package/src/endpoint.ts +365 -0
  413. package/src/entity.ts +173 -0
  414. package/src/feature.ts +118 -0
  415. package/src/graft.ts +181 -0
  416. package/src/hash-object.ts +97 -0
  417. package/src/helper.ts +849 -0
  418. package/src/introspection/generated.agi.ts +41200 -0
  419. package/src/introspection/generated.node.ts +28773 -0
  420. package/src/introspection/generated.web.ts +2272 -0
  421. package/src/introspection/index.ts +296 -0
  422. package/src/introspection/scan.ts +1136 -0
  423. package/src/node/container.ts +409 -0
  424. package/src/node/feature.ts +13 -0
  425. package/src/node/features/container-link.ts +559 -0
  426. package/src/node/features/content-db.ts +849 -0
  427. package/src/node/features/disk-cache.ts +388 -0
  428. package/src/node/features/display-result.ts +57 -0
  429. package/src/node/features/dns.ts +669 -0
  430. package/src/node/features/docker.ts +921 -0
  431. package/src/node/features/downloader.ts +79 -0
  432. package/src/node/features/figlet-fonts.ts +600 -0
  433. package/src/node/features/file-manager.ts +535 -0
  434. package/src/node/features/fs.ts +1050 -0
  435. package/src/node/features/git.ts +592 -0
  436. package/src/node/features/google-auth.ts +504 -0
  437. package/src/node/features/google-calendar.ts +306 -0
  438. package/src/node/features/google-docs.ts +412 -0
  439. package/src/node/features/google-drive.ts +346 -0
  440. package/src/node/features/google-mail.ts +540 -0
  441. package/src/node/features/google-sheets.ts +286 -0
  442. package/src/node/features/grep.ts +427 -0
  443. package/src/node/features/helpers.ts +762 -0
  444. package/src/node/features/ink.ts +490 -0
  445. package/src/node/features/ipc-socket.ts +649 -0
  446. package/src/node/features/json-tree.ts +170 -0
  447. package/src/node/features/networking.ts +961 -0
  448. package/src/node/features/nlp.ts +212 -0
  449. package/src/node/features/opener.ts +180 -0
  450. package/src/node/features/os.ts +403 -0
  451. package/src/node/features/package-finder.ts +540 -0
  452. package/src/node/features/postgres.ts +289 -0
  453. package/src/node/features/proc.ts +503 -0
  454. package/src/node/features/process-manager.ts +844 -0
  455. package/src/node/features/python.ts +912 -0
  456. package/src/node/features/redis.ts +446 -0
  457. package/src/node/features/repl.ts +212 -0
  458. package/src/node/features/runpod.ts +811 -0
  459. package/src/node/features/secure-shell.ts +261 -0
  460. package/src/node/features/semantic-search.ts +935 -0
  461. package/src/node/features/sqlite.ts +289 -0
  462. package/src/node/features/telegram.ts +343 -0
  463. package/src/node/features/transpiler.ts +160 -0
  464. package/src/node/features/tts.ts +185 -0
  465. package/src/node/features/ui.ts +791 -0
  466. package/src/node/features/vault.ts +153 -0
  467. package/src/node/features/vm.ts +462 -0
  468. package/src/node/features/yaml-tree.ts +148 -0
  469. package/src/node/features/yaml.ts +133 -0
  470. package/src/node.ts +76 -0
  471. package/src/python/bridge.py +220 -0
  472. package/src/python/generated.ts +226 -0
  473. package/src/react/index.ts +175 -0
  474. package/src/registry.ts +210 -0
  475. package/src/scaffolds/generated.ts +1814 -0
  476. package/src/scaffolds/template.ts +46 -0
  477. package/src/schemas/base.ts +296 -0
  478. package/src/selector.ts +352 -0
  479. package/src/server.ts +229 -0
  480. package/src/servers/express.ts +283 -0
  481. package/src/servers/mcp.ts +802 -0
  482. package/src/servers/socket.ts +258 -0
  483. package/src/state.ts +101 -0
  484. package/src/web/clients/socket.ts +99 -0
  485. package/src/web/container.ts +75 -0
  486. package/src/web/extension.ts +30 -0
  487. package/src/web/feature.ts +12 -0
  488. package/src/web/features/asset-loader.ts +72 -0
  489. package/src/web/features/container-link.ts +382 -0
  490. package/src/web/features/esbuild.ts +93 -0
  491. package/src/web/features/helpers.ts +291 -0
  492. package/src/web/features/network.ts +85 -0
  493. package/src/web/features/speech.ts +104 -0
  494. package/src/web/features/vault.ts +207 -0
  495. package/src/web/features/vm.ts +85 -0
  496. package/src/web/features/voice-recognition.ts +161 -0
  497. package/src/web/shims/isomorphic-vm.ts +149 -0
  498. package/tsconfig.build.json +12 -0
  499. package/tsconfig.json +58 -0
  500. package/uv.lock +8 -0
  501. package/LICENSE +0 -21
  502. package/dist/cli/cli.js +0 -48
  503. package/dist/cli/common.d.ts +0 -2
  504. package/dist/cli/common.js +0 -6
  505. package/dist/cli/index.d.ts +0 -2
  506. package/dist/cli/index.js +0 -5
  507. package/dist/cli/run.d.ts +0 -1
  508. package/dist/cli/run.js +0 -38
  509. package/dist/core/index.d.ts +0 -4
  510. package/dist/core/index.js +0 -32
  511. package/dist/core/read.d.ts +0 -2
  512. package/dist/core/read.js +0 -29
  513. package/dist/core/request.d.ts +0 -1
  514. package/dist/core/request.js +0 -2
  515. package/dist/core/write.d.ts +0 -2
  516. package/dist/core/write.js +0 -21
  517. package/dist/index.d.ts +0 -1
  518. package/dist/index.js +0 -5
  519. package/dist/utils/common.d.ts +0 -9
  520. package/dist/utils/common.js +0 -57
  521. package/dist/utils/consts.d.ts +0 -3
  522. package/dist/utils/consts.js +0 -11
  523. package/dist/utils/dict.d.ts +0 -1
  524. package/dist/utils/dict.js +0 -7
  525. package/dist/utils/index.d.ts +0 -5
  526. package/dist/utils/index.js +0 -21
  527. package/dist/utils/log.d.ts +0 -1
  528. package/dist/utils/log.js +0 -5
  529. package/dist/utils/types.d.ts +0 -1
  530. package/dist/utils/types.js +0 -2
  531. package/dist/utils/utils.test.d.ts +0 -1
  532. package/dist/utils/utils.test.js +0 -7
@@ -0,0 +1,365 @@
1
+ import { Helper } from './helper.js'
2
+ import type { Container, ContainerContext } from './container.js'
3
+ import { Registry } from './registry.js'
4
+ import { z } from 'zod'
5
+ import { EndpointStateSchema, EndpointOptionsSchema, EndpointEventsSchema } from './schemas/base.js'
6
+
7
+ export interface AvailableEndpoints {}
8
+
9
+ export type EndpointState = z.infer<typeof EndpointStateSchema>
10
+ export type EndpointOptions = z.infer<typeof EndpointOptionsSchema>
11
+
12
+ export type EndpointHandler = (
13
+ parameters: Record<string, any>,
14
+ context: EndpointContext
15
+ ) => Promise<any> | any
16
+
17
+ export type EndpointContext = {
18
+ container: Container<any>
19
+ request: any
20
+ response: any
21
+ query: Record<string, any>
22
+ body: Record<string, any>
23
+ params: Record<string, any>
24
+ }
25
+
26
+ export interface EndpointRateLimit {
27
+ /** Maximum requests allowed per window */
28
+ maxRequests: number
29
+ /** Window size in seconds (default: 1) */
30
+ windowSeconds?: number
31
+ }
32
+
33
+ export interface EndpointModule {
34
+ path: string
35
+ get?: EndpointHandler
36
+ post?: EndpointHandler
37
+ put?: EndpointHandler
38
+ patch?: EndpointHandler
39
+ delete?: EndpointHandler
40
+ getSchema?: z.ZodType
41
+ postSchema?: z.ZodType
42
+ putSchema?: z.ZodType
43
+ patchSchema?: z.ZodType
44
+ deleteSchema?: z.ZodType
45
+ /** Rate limit applied to all methods on this endpoint */
46
+ rateLimit?: EndpointRateLimit
47
+ /** Per-method rate limits (overrides the endpoint-level rateLimit) */
48
+ getRateLimit?: EndpointRateLimit
49
+ postRateLimit?: EndpointRateLimit
50
+ putRateLimit?: EndpointRateLimit
51
+ patchRateLimit?: EndpointRateLimit
52
+ deleteRateLimit?: EndpointRateLimit
53
+ description?: string
54
+ tags?: string[]
55
+ }
56
+
57
+ const HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete'] as const
58
+
59
+ /** All recognized exports on an endpoint module */
60
+ const KNOWN_EXPORTS = new Set([
61
+ 'path', 'description', 'tags', 'default', 'rateLimit',
62
+ ...HTTP_METHODS,
63
+ ...HTTP_METHODS.map(m => `${m}Schema`),
64
+ ...HTTP_METHODS.map(m => `${m}RateLimit`),
65
+ ])
66
+
67
+ /**
68
+ * Sliding-window rate limiter keyed by IP address.
69
+ * Tracks timestamps of requests and prunes entries older than the window.
70
+ */
71
+ class RateLimiter {
72
+ private _windows = new Map<string, number[]>()
73
+
74
+ /** Returns true if the request is allowed, false if rate-limited. */
75
+ allow(key: string, maxRequests: number, windowMs: number): boolean {
76
+ const now = Date.now()
77
+ let timestamps = this._windows.get(key)
78
+
79
+ if (!timestamps) {
80
+ timestamps = []
81
+ this._windows.set(key, timestamps)
82
+ }
83
+
84
+ // Prune timestamps outside the window
85
+ while (timestamps.length > 0 && (timestamps[0] ?? 0) <= now - windowMs) {
86
+ timestamps.shift()
87
+ }
88
+
89
+ if (timestamps.length >= maxRequests) {
90
+ return false
91
+ }
92
+
93
+ timestamps.push(now)
94
+ return true
95
+ }
96
+
97
+ /** Clear all tracking state */
98
+ reset(): void {
99
+ this._windows.clear()
100
+ }
101
+ }
102
+
103
+ export type EndpointFactory = <T extends keyof AvailableEndpoints>(
104
+ key: T,
105
+ options?: ConstructorParameters<AvailableEndpoints[T]>[0]
106
+ ) => NonNullable<InstanceType<AvailableEndpoints[T]>>
107
+
108
+ export interface EndpointsInterface {
109
+ endpoints: EndpointsRegistry
110
+ endpoint: EndpointFactory
111
+ }
112
+
113
+ export class Endpoint<
114
+ T extends EndpointState = EndpointState,
115
+ K extends EndpointOptions = EndpointOptions
116
+ > extends Helper<T, K> {
117
+ static override shortcut = 'endpoints.base'
118
+ static override description = 'File-based HTTP endpoint with Remix-like DX'
119
+ static override stateSchema = EndpointStateSchema
120
+ static override optionsSchema = EndpointOptionsSchema
121
+ static override eventsSchema = EndpointEventsSchema
122
+
123
+ private _module: EndpointModule | null = null
124
+ private _rateLimiter = new RateLimiter()
125
+
126
+ static attach(container: Container & EndpointsInterface): any {
127
+ Object.assign(container, {
128
+ get endpoints() {
129
+ return endpoints
130
+ },
131
+
132
+ endpoint<T extends keyof AvailableEndpoints>(
133
+ id: T,
134
+ options?: ConstructorParameters<AvailableEndpoints[T]>[0]
135
+ ): InstanceType<AvailableEndpoints[T]> {
136
+ const BaseClass = endpoints.lookup(id as string) as any
137
+
138
+ return container.createHelperInstance({
139
+ cache: helperCache,
140
+ type: 'endpoint',
141
+ id: String(id),
142
+ BaseClass,
143
+ options,
144
+ fallbackName: String(id),
145
+ }) as InstanceType<AvailableEndpoints[T]>
146
+ },
147
+ })
148
+
149
+ container.registerHelperType('endpoints', 'endpoint')
150
+
151
+ return container
152
+ }
153
+
154
+ override get initialState(): T {
155
+ return ({
156
+ mounted: false,
157
+ path: this.options.path || '',
158
+ methods: [],
159
+ requestCount: 0,
160
+ } as unknown) as T
161
+ }
162
+
163
+ get path() {
164
+ return this.options.path
165
+ }
166
+
167
+ get module() {
168
+ return this._module
169
+ }
170
+
171
+ get methods(): string[] {
172
+ if (!this._module) return []
173
+ return HTTP_METHODS.filter((m) => typeof (this._module as any)[m] === 'function')
174
+ }
175
+
176
+ get isMounted() {
177
+ return !!this.state.get('mounted')
178
+ }
179
+
180
+ async load(mod?: EndpointModule): Promise<this> {
181
+ if (mod) {
182
+ this._module = mod
183
+ } else if (this.options.filePath) {
184
+ const imported = await import(`${this.options.filePath}?t=${Date.now()}`)
185
+ this._module = imported.default || imported
186
+ }
187
+
188
+ // Note: DELETE handlers should be exported as `export { del as delete }`.
189
+ // We no longer remap `destroy` → `delete` because ESM namespace objects
190
+ // are frozen and the mutation throws on Bun.
191
+
192
+ this.state.set('methods', this.methods)
193
+ this.state.set('path', this.path)
194
+ this.emit('loaded', this._module)
195
+ return this
196
+ }
197
+
198
+ async reload(): Promise<this> {
199
+ this._module = null
200
+ if (this.options.filePath) {
201
+ const helpers = this.container.feature('helpers') as any
202
+ const mod = await helpers.loadModuleExports(this.options.filePath, { cacheBust: true })
203
+ const endpointModule: EndpointModule = mod.default || mod
204
+ return this.load(endpointModule)
205
+ }
206
+ return this.load()
207
+ }
208
+
209
+ handler(method: string): EndpointHandler | undefined {
210
+ return this._module?.[method as keyof EndpointModule] as EndpointHandler | undefined
211
+ }
212
+
213
+ schema(method: string): z.ZodType | undefined {
214
+ return this._module?.[`${method}Schema` as keyof EndpointModule] as z.ZodType | undefined
215
+ }
216
+
217
+ /** Returns the rate limit config for a given method, or undefined if none. */
218
+ rateLimitFor(method: string): EndpointRateLimit | undefined {
219
+ const perMethod = this._module?.[`${method}RateLimit` as keyof EndpointModule] as EndpointRateLimit | undefined
220
+ return perMethod || this._module?.rateLimit
221
+ }
222
+
223
+ /** Access the rate limiter instance (useful for testing or manual resets) */
224
+ get rateLimiter(): RateLimiter {
225
+ return this._rateLimiter
226
+ }
227
+
228
+ mount(app: any): this {
229
+ for (const method of this.methods) {
230
+ const endpoint = this
231
+
232
+ app[method](this.path, async (req: any, res: any) => {
233
+ try {
234
+ // Rate limit check
235
+ const limit = endpoint.rateLimitFor(method)
236
+ if (limit) {
237
+ const ip = req.ip || req.socket?.remoteAddress || 'unknown'
238
+ const key = `${method}:${ip}`
239
+ const windowMs = (limit.windowSeconds ?? 1) * 1000
240
+ if (!endpoint._rateLimiter.allow(key, limit.maxRequests, windowMs)) {
241
+ endpoint.emit('error', new Error(`Rate limit exceeded for ${method.toUpperCase()} ${endpoint.path}`))
242
+ res.status(429).json({ error: 'Too Many Requests' })
243
+ return
244
+ }
245
+ }
246
+
247
+ const currentHandler = endpoint.handler(method)
248
+ if (!currentHandler) {
249
+ res.status(404).json({ error: 'Not found' })
250
+ return
251
+ }
252
+
253
+ const parameters = { ...req.query, ...req.body, ...req.params }
254
+ const currentSchema = endpoint.schema(method)
255
+ const validated = currentSchema ? currentSchema.parse(parameters) : parameters
256
+
257
+ const ctx: EndpointContext = {
258
+ container: endpoint.container,
259
+ request: req,
260
+ response: res,
261
+ query: req.query || {},
262
+ body: req.body || {},
263
+ params: req.params || {},
264
+ }
265
+
266
+ const result = await currentHandler(validated, ctx)
267
+ endpoint.state.set('requestCount', (endpoint.state.get('requestCount') || 0) + 1)
268
+ endpoint.emit('request', method, endpoint.path, parameters)
269
+
270
+ if (!res.headersSent) {
271
+ res.json(result)
272
+ }
273
+ } catch (err: any) {
274
+ endpoint.emit('error', err)
275
+ if (!res.headersSent) {
276
+ if (err.name === 'ZodError') {
277
+ const issues = err.issues || err.errors || []
278
+ const details = issues.map((e: any) => `${(e.path || []).join('.')}: ${e.message}`).join(', ')
279
+ console.error(`[${method.toUpperCase()} ${endpoint.path}] Validation failed: ${details}`)
280
+ res.status(400).json({ error: `Validation failed: ${details}`, details: issues })
281
+ } else {
282
+ console.error(`[${method.toUpperCase()} ${endpoint.path}] ${err.message}`)
283
+ res.status(500).json({ error: err.message })
284
+ }
285
+ }
286
+ }
287
+ })
288
+ }
289
+
290
+ this.state.set('mounted', true)
291
+ this.emit('mounted', this.path)
292
+ return this
293
+ }
294
+
295
+ toOpenAPIPathItem(): Record<string, any> {
296
+ const pathItem: Record<string, any> = {}
297
+
298
+ for (const method of this.methods) {
299
+ const methodSchema = this.schema(method)
300
+ const operationId = `${method}_${this.path.replace(/\//g, '_').replace(/^_/, '')}`
301
+
302
+ const operation: Record<string, any> = {
303
+ operationId,
304
+ summary: this._module?.description || `${method.toUpperCase()} ${this.path}`,
305
+ tags: this._module?.tags || [],
306
+ responses: {
307
+ '200': {
308
+ description: 'Successful response',
309
+ content: { 'application/json': { schema: { type: 'object' } } },
310
+ },
311
+ ...(this.rateLimitFor(method) ? { '429': { description: 'Rate limit exceeded' } } : {}),
312
+ '400': { description: 'Validation error' },
313
+ '500': { description: 'Server error' },
314
+ },
315
+ }
316
+
317
+ if (methodSchema) {
318
+ try {
319
+ const jsonSchema = (methodSchema as any).toJSONSchema()
320
+
321
+ if (method === 'get' || method === 'delete') {
322
+ operation.parameters = Object.entries((jsonSchema as any).properties || {}).map(
323
+ ([name, prop]: [string, any]) => ({
324
+ name,
325
+ in: 'query',
326
+ required: (jsonSchema as any).required?.includes(name) || false,
327
+ schema: prop,
328
+ description: prop.description || '',
329
+ })
330
+ )
331
+ } else {
332
+ operation.requestBody = {
333
+ required: true,
334
+ content: { 'application/json': { schema: jsonSchema } },
335
+ }
336
+ }
337
+ } catch {
338
+ // Schema conversion failed, serve without parameter docs
339
+ }
340
+ }
341
+
342
+ pathItem[method] = operation
343
+ }
344
+
345
+ return pathItem
346
+ }
347
+ }
348
+
349
+ export function warnUnknownExports(mod: Record<string, any>, filePath: string): void {
350
+ const unknown = Object.keys(mod).filter(k => !k.startsWith('__') && !KNOWN_EXPORTS.has(k))
351
+ if (unknown.length > 0) {
352
+ console.warn(`[endpoint] ${filePath}: unknown exports: ${unknown.join(', ')}`)
353
+ }
354
+ }
355
+
356
+ export class EndpointsRegistry extends Registry<Endpoint<any>> {
357
+ override scope = 'endpoints'
358
+ override baseClass = Endpoint
359
+ }
360
+
361
+ export const endpoints = new EndpointsRegistry()
362
+
363
+ export const helperCache = new Map()
364
+
365
+ export default Endpoint
package/src/entity.ts ADDED
@@ -0,0 +1,173 @@
1
+ import { Bus, type EventMap } from './bus.js'
2
+ import { State, type SetStateValue } from './state.js'
3
+ import type { Container } from './container.js'
4
+ import uuid from 'node-uuid'
5
+ import { z } from 'zod'
6
+
7
+ /**
8
+ * An Entity is a lightweight, composable object with observable state, a typed event bus,
9
+ * and a reference to the container. Unlike Helpers, Entities are not class-based — they
10
+ * are plain objects created directly via `container.entity()` and extended via `.extend()`.
11
+ *
12
+ * Same id + options always returns the same underlying state/bus instance (cached).
13
+ *
14
+ * @template TState - Shape of the entity's observable state
15
+ * @template TOptions - Shape of the options passed at construction
16
+ * @template TEvents - Event map for the typed event bus
17
+ */
18
+ export type Entity<
19
+ TState extends Record<string, any> = Record<string, any>,
20
+ TOptions extends Record<string, any> = Record<string, any>,
21
+ TEvents extends EventMap = EventMap,
22
+ > = {
23
+ /** The id passed to container.entity() */
24
+ readonly id: string
25
+ /** Per-instance UUID */
26
+ readonly uuid: string
27
+ /** The options the entity was created with */
28
+ readonly options: TOptions
29
+ /** Observable state */
30
+ readonly state: State<TState>
31
+ /** The container this entity belongs to */
32
+ readonly container: Container<any>
33
+
34
+ on<E extends keyof TEvents>(event: E, listener: (...args: TEvents[E]) => void): void
35
+ off<E extends keyof TEvents>(event: E, listener?: (...args: TEvents[E]) => void): void
36
+ once<E extends keyof TEvents>(event: E, listener: (...args: TEvents[E]) => void): void
37
+ emit<E extends keyof TEvents>(event: E, ...args: TEvents[E]): void
38
+ waitFor<E extends keyof TEvents>(event: E): Promise<TEvents[E]>
39
+ setState(value: SetStateValue<TState>): void
40
+
41
+ /**
42
+ * Graft an object of functions and getters onto this entity, returning a new type-safe
43
+ * object. The base entity (state, events, container, options) is accessible via `this`
44
+ * in all grafted methods and getters. Chaining `.extend()` on the result works correctly —
45
+ * each layer has access to everything in the layers below it.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const session = container.entity('session:abc', { userId: '42' })
50
+ * const rich = session.extend({
51
+ * greet() { return `Hello user ${this.options.userId}` },
52
+ * get label() { return `Session ${this.id}` },
53
+ * })
54
+ * rich.greet() // "Hello user 42"
55
+ * ```
56
+ */
57
+ extend<Ext extends Record<string, any>>(
58
+ extensions: Ext & ThisType<Entity<TState, TOptions, TEvents> & Ext>
59
+ ): Entity<TState, TOptions, TEvents> & Ext
60
+
61
+ /**
62
+ * Register a method on this entity as an AI tool with the given Zod schema.
63
+ * Chainable — returns `this` so you can stack multiple `.expose()` calls.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const agent = container.entity('agent', {})
68
+ * .extend({ search({ query }: { query: string }) { ... } })
69
+ * .expose('search', z.object({ query: z.string() }))
70
+ *
71
+ * assistant.addTools(agent)
72
+ * ```
73
+ */
74
+ expose(this: Entity<TState, TOptions, TEvents>, functionName: string, schema: z.ZodType): Entity<TState, TOptions, TEvents>
75
+
76
+ /**
77
+ * Returns `{ schemas, handlers }` for all tools registered via `.expose()`.
78
+ * Compatible with `assistant.addTools()` and the standard `toTools` contract.
79
+ */
80
+ toTools(): { schemas: Record<string, z.ZodType>; handlers: Record<string, Function> }
81
+ }
82
+
83
+ /** @internal */
84
+ export function createEntityObject<
85
+ TState extends Record<string, any> = Record<string, any>,
86
+ TOptions extends Record<string, any> = Record<string, any>,
87
+ TEvents extends EventMap = EventMap,
88
+ >(
89
+ id: string,
90
+ container: Container<any>,
91
+ options: TOptions,
92
+ ): Entity<TState, TOptions, TEvents> {
93
+ const _events = new Bus<TEvents>()
94
+ const _state = new State<TState>()
95
+
96
+ const _exposed = new Map<string, z.ZodType>()
97
+
98
+ const entity: Entity<TState, TOptions, TEvents> = {
99
+ id,
100
+ uuid: (uuid as any).v4(),
101
+ options,
102
+ state: _state,
103
+ container,
104
+ on(event: any, listener: any) { _events.on(event, listener) },
105
+ off(event: any, listener?: any) { _events.off(event, listener) },
106
+ once(event: any, listener: any) { _events.once(event, listener) },
107
+ emit(event: any, ...args: any[]) { _events.emit(event, ...args as any) },
108
+ waitFor(event: any) { return _events.waitFor(event) },
109
+ setState(value: any) { _state.setState(value) },
110
+ extend(extensions: any) { return applyExtensions(this as any, extensions) },
111
+ expose(functionName: string, schema: z.ZodType) {
112
+ // Each prototype layer gets its own _exposed map (lazy-created on write)
113
+ if (!Object.prototype.hasOwnProperty.call(this, '_exposed')) {
114
+ ;(this as any)._exposed = new Map<string, z.ZodType>()
115
+ }
116
+ ;(this as any)._exposed.set(functionName, schema)
117
+ return this
118
+ },
119
+ toTools() {
120
+ const schemas: Record<string, z.ZodType> = {}
121
+ const handlers: Record<string, Function> = {}
122
+
123
+ // Walk the prototype chain collecting _exposed maps; shallower layers win
124
+ let obj: any = this
125
+ while (obj !== null) {
126
+ if (Object.prototype.hasOwnProperty.call(obj, '_exposed')) {
127
+ for (const [name, schema] of (obj._exposed as Map<string, z.ZodType>)) {
128
+ if (!(name in schemas)) {
129
+ schemas[name] = schema
130
+ handlers[name] = (args: any) => (this as any)[name](args)
131
+ }
132
+ }
133
+ }
134
+ obj = Object.getPrototypeOf(obj)
135
+ }
136
+
137
+ return { schemas, handlers }
138
+ },
139
+ }
140
+
141
+ ;(entity as any)._exposed = _exposed
142
+
143
+ return entity
144
+ }
145
+
146
+ /**
147
+ * Graft extensions onto an entity via prototype delegation.
148
+ *
149
+ * The extended object's prototype is `base`, so all base properties (state, container,
150
+ * on/off/emit, etc.) are reachable through `this` in any grafted method or getter.
151
+ * Calling `.extend()` on the result correctly uses the extended object as the new base.
152
+ */
153
+ function applyExtensions<
154
+ TState extends Record<string, any>,
155
+ TOptions extends Record<string, any>,
156
+ TEvents extends EventMap,
157
+ Ext extends Record<string, any>,
158
+ >(
159
+ base: Entity<TState, TOptions, TEvents>,
160
+ extensions: Ext,
161
+ ): Entity<TState, TOptions, TEvents> & Ext {
162
+ const extended = Object.create(base) as Entity<TState, TOptions, TEvents> & Ext
163
+
164
+ for (const key of Object.getOwnPropertyNames(extensions)) {
165
+ const descriptor = Object.getOwnPropertyDescriptor(extensions, key)!
166
+ Object.defineProperty(extended, key, {
167
+ ...descriptor,
168
+ configurable: true,
169
+ })
170
+ }
171
+
172
+ return extended
173
+ }
package/src/feature.ts ADDED
@@ -0,0 +1,118 @@
1
+ import { Helper } from './helper.js';
2
+ import { Registry } from './registry.js'
3
+ import type { ContainerContext } from './container.js'
4
+ import { kebabCase, camelCase } from 'lodash-es'
5
+ import type { YAML } from './node/features/yaml.js';
6
+ import { z } from 'zod'
7
+ import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from './schemas/base.js'
8
+
9
+ /**
10
+ * Use module augmentation to register features, the same way you would register
11
+ * them at runtime. This will help developers get autocomplete etc.
12
+ */
13
+ export interface AvailableFeatures {
14
+ yaml: typeof YAML
15
+ }
16
+
17
+ export type FeatureOptions = z.infer<typeof FeatureOptionsSchema>
18
+ export type FeatureState = z.infer<typeof FeatureStateSchema>
19
+
20
+ export abstract class Feature<T extends FeatureState = FeatureState, K extends FeatureOptions = FeatureOptions> extends Helper<T, K> {
21
+ static override stateSchema = FeatureStateSchema
22
+ static override optionsSchema = FeatureOptionsSchema
23
+ static override eventsSchema = FeatureEventsSchema
24
+
25
+ /** Self-register a Feature subclass from a static initialization block. */
26
+ static register: (SubClass: abstract new (options: any, context: any) => Feature, id?: string) => abstract new (options: any, context: any) => Feature
27
+
28
+ override get shortcut() {
29
+ return (this.constructor as any).shortcut as string
30
+ }
31
+
32
+ get isEnabled() {
33
+ return this.state.get('enabled')
34
+ }
35
+
36
+ constructor(options: K, context: ContainerContext) {
37
+ super(options, context)
38
+
39
+ if(typeof context.container !== 'object') {
40
+ console.error(this, options, context)
41
+ throw new Error('You should not instantiate a feature directly. Use container.feature() instead.')
42
+ }
43
+
44
+
45
+ if(options?.enable) {
46
+ this.enable()
47
+ }
48
+ }
49
+
50
+ /**
51
+ * For features where there only needs to be a single instance, you
52
+ * can use this method to attach the feature to the container.
53
+ */
54
+ protected attachToContainer() {
55
+ Object.defineProperty(this.container, this.shortcut.split('.').pop()!, {
56
+ get: () => this,
57
+ configurable: true,
58
+ enumerable: true,
59
+ })
60
+ }
61
+
62
+ async enable(options: any = {}) : Promise<this> {
63
+ this.attachToContainer()
64
+ this.emit('enabled')
65
+ this.state.set('enabled', true)
66
+
67
+ this.container.emit('featureEnabled', this.shortcut, this)
68
+
69
+ return this
70
+ }
71
+ }
72
+
73
+ export class FeaturesRegistry extends Registry<Feature<any, any>> {
74
+ override scope = "features"
75
+ override baseClass = Feature as any
76
+ }
77
+
78
+ export const features = new FeaturesRegistry()
79
+
80
+ /**
81
+ * Self-register a Feature subclass from a static initialization block.
82
+ * IMPORTANT: Place the static block AFTER all static override declarations
83
+ * so schemas, envVars, and other metadata are set before interceptRegistration fires.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * export default class DNS extends Feature<DnsState, DnsOptions> {
88
+ * static override stateSchema = DnsStateSchema
89
+ * static override optionsSchema = DnsOptionsSchema
90
+ * static { Feature.register(this, 'dns') } // must come last
91
+ * }
92
+ * ```
93
+ */
94
+ Feature.register = function registerFeature(
95
+ SubClass: abstract new (options: any, context: any) => Feature,
96
+ id?: string,
97
+ ) {
98
+ const registryId = id ?? SubClass.name[0]!.toLowerCase() + SubClass.name.slice(1)
99
+
100
+ // Auto-set shortcut if not explicitly overridden on this class
101
+ if (!Object.getOwnPropertyDescriptor(SubClass, 'shortcut')?.value ||
102
+ (SubClass as any).shortcut === 'unspecified') {
103
+ ;(SubClass as any).shortcut = `features.${registryId}` as const
104
+ }
105
+
106
+ // Register in the features registry (interceptRegistration sees all statics above)
107
+ features.register(registryId, SubClass as any)
108
+
109
+ // Generate default attach() if not explicitly overridden on this class
110
+ if (!Object.getOwnPropertyDescriptor(SubClass, 'attach')) {
111
+ ;(SubClass as any).attach = (container: any) => {
112
+ features.register(registryId, SubClass as any)
113
+ return container
114
+ }
115
+ }
116
+
117
+ return SubClass
118
+ }