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,762 @@
1
+ import { z } from 'zod'
2
+ import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
+ import { Feature } from '../feature.js'
4
+ import { Feature as UniversalFeature } from '../../feature.js'
5
+ import { Client, clients } from '../../client.js'
6
+ import { allHelperInstances } from '../../container.js'
7
+ import type { Helper } from '../../helper.js'
8
+ import { RestClient } from '../../clients/rest.js'
9
+ import { GraphClient } from '../../clients/graph.js'
10
+ import { WebSocketClient } from '../../clients/websocket.js'
11
+ import { Server, servers } from '../../server.js'
12
+ import { ExpressServer } from '../../servers/express.js'
13
+ import { WebsocketServer } from '../../servers/socket.js'
14
+ import { Command, commands } from '../../command.js'
15
+ import { graftModule, isNativeHelperClass } from '../../graft.js'
16
+ import { endpoints } from '../../endpoint.js'
17
+ import { Selector, selectors } from '../../selector.js'
18
+ import type { Registry } from '../../registry.js'
19
+ import type { FileManager } from './file-manager.js'
20
+ import type { VM } from './vm.js'
21
+ import { resolve, parse } from 'path'
22
+ import { existsSync } from 'fs'
23
+
24
+ export const HelpersStateSchema = FeatureStateSchema.extend({
25
+ discovered: z.record(z.string(), z.boolean()).default({}).describe('Which registry types have been discovered'),
26
+ registered: z.array(z.string()).default([]).describe('Names of project-level helpers that were discovered (type.name)'),
27
+ })
28
+
29
+ export type HelpersState = z.infer<typeof HelpersStateSchema>
30
+
31
+ export const HelpersOptionsSchema = FeatureOptionsSchema.extend({
32
+ rootDir: z.string().optional().describe('Root directory to scan for helper folders. Defaults to container.cwd'),
33
+ })
34
+
35
+ export type HelpersOptions = z.infer<typeof HelpersOptionsSchema>
36
+
37
+ export const HelpersEventsSchema = FeatureEventsSchema.extend({
38
+ discovered: z.tuple([
39
+ z.string().describe('Registry type that was discovered'),
40
+ z.array(z.string()).describe('Names of newly registered helpers'),
41
+ ]).describe('Emitted after a registry type has been discovered'),
42
+ registered: z.tuple([
43
+ z.string().describe('Registry type'),
44
+ z.string().describe('Helper name'),
45
+ z.any().describe('The helper class or module'),
46
+ ]).describe('Emitted when a single helper is registered'),
47
+ })
48
+
49
+ type RegistryType = 'features' | 'clients' | 'servers' | 'commands' | 'endpoints' | 'selectors'
50
+
51
+ const CLASS_BASED: RegistryType[] = ['features', 'clients', 'servers']
52
+
53
+ /**
54
+ * The Helpers feature is a unified gateway for discovering and registering
55
+ * project-level helpers from conventional folder locations.
56
+ *
57
+ * It scans known folder names (features/, clients/, servers/, commands/, endpoints/, selectors/)
58
+ * and handles registration differently based on the helper type:
59
+ *
60
+ * - Class-based (features, clients, servers): Dynamic import, validate subclass, register
61
+ * - Config-based (commands, endpoints, selectors): Delegate to existing discovery mechanisms
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const helpers = container.feature('helpers', { enable: true })
66
+ *
67
+ * // Discover all helper types
68
+ * await helpers.discoverAll()
69
+ *
70
+ * // Discover a specific type
71
+ * await helpers.discover('features')
72
+ *
73
+ * // Unified view of all available helpers
74
+ * console.log(helpers.available)
75
+ * ```
76
+ */
77
+ export class Helpers extends Feature<HelpersState, HelpersOptions> {
78
+ static override shortcut = 'features.helpers' as const
79
+ static override description = 'Unified gateway for discovering and registering project-level helpers'
80
+ static override stateSchema = HelpersStateSchema
81
+ static override optionsSchema = HelpersOptionsSchema
82
+ static override eventsSchema = HelpersEventsSchema
83
+ static { Feature.register(this, 'helpers') }
84
+
85
+ /** In-flight or completed discovery promises, keyed by registry type */
86
+ private _discoveryPromises: Map<string, Promise<string[]>> = new Map()
87
+ /** Cached results from completed discoveries */
88
+ private _discoveryResults: Map<string, string[]> = new Map()
89
+ /** In-flight or completed discoverAll promise */
90
+ private _discoverAllPromise: Promise<Record<string, string[]>> | null = null
91
+
92
+ /**
93
+ * Returns a mapping from registry type name to its registry singleton, base class, and conventional folder candidates.
94
+ */
95
+ private get registryMap(): Record<RegistryType, { registry: Registry<any>, baseClass: any, folders: string[] }> {
96
+ return {
97
+ features: { registry: this.container.features as any, baseClass: UniversalFeature, folders: ['features'] },
98
+ clients: { registry: clients, baseClass: Client, folders: ['clients'] },
99
+ servers: { registry: servers, baseClass: Server, folders: ['servers'] },
100
+ commands: { registry: commands, baseClass: null, folders: ['commands'] },
101
+ endpoints: { registry: endpoints, baseClass: null, folders: ['endpoints'] },
102
+ selectors: { registry: selectors, baseClass: null, folders: ['selectors'] },
103
+ }
104
+ }
105
+
106
+ /** The root directory to scan for helper folders. */
107
+ get rootDir(): string {
108
+ return this.options.rootDir || this.container.cwd
109
+ }
110
+
111
+ /**
112
+ * Whether to use native `import()` for loading project helpers.
113
+ * True only if `luca` is actually resolvable in `node_modules`.
114
+ * Warns when `node_modules` exists but the package is missing.
115
+ */
116
+ get useNativeImport(): boolean {
117
+ const hasNodeModules = existsSync(resolve(this.rootDir, 'node_modules'))
118
+ const hasLuca = hasNodeModules && existsSync(resolve(this.rootDir, 'node_modules', '@soederpop', 'luca'))
119
+
120
+ // VM bundling handles missing luca gracefully — no warning needed
121
+
122
+ return hasLuca
123
+ }
124
+
125
+
126
+ /** Track whether we've seeded the VM with virtual modules */
127
+ private _vmSeeded = false
128
+
129
+ /**
130
+ * Seeds the VM feature with virtual modules so that project-level files
131
+ * can `import` / `require('luca')`, `zod`, etc. without
132
+ * needing them in `node_modules`.
133
+ *
134
+ * Called automatically when `useNativeImport` is false.
135
+ * Can also be called externally (e.g. from the CLI) to pre-seed before discovery.
136
+ */
137
+ seedVirtualModules(): void {
138
+ if (this._vmSeeded) return
139
+ this._vmSeeded = true
140
+
141
+ const vm = this.container.feature('vm') as unknown as VM
142
+
143
+ // Provide the full luca barrel — everything node.ts exports
144
+ // We build the exports object from the already-loaded modules in memory
145
+ const lucaExports: Record<string, any> = {
146
+ // Core classes
147
+ Feature: UniversalFeature,
148
+ Container: this.container.constructor,
149
+ Helper: Object.getPrototypeOf(UniversalFeature.prototype).constructor,
150
+ Client,
151
+ Server,
152
+ Command,
153
+ Registry: Object.getPrototypeOf(this.container.features).constructor,
154
+
155
+ // Utilities
156
+ graftModule,
157
+ isNativeHelperClass,
158
+
159
+ // Registries
160
+ features: this.container.features,
161
+ clients,
162
+ servers,
163
+ commands,
164
+ endpoints,
165
+ selectors,
166
+
167
+ // Registry classes
168
+ ClientsRegistry: clients.constructor,
169
+ CommandsRegistry: commands.constructor,
170
+ EndpointsRegistry: endpoints.constructor,
171
+ ServersRegistry: servers.constructor,
172
+ SelectorsRegistry: selectors.constructor,
173
+ FeaturesRegistry: this.container.features.constructor,
174
+
175
+ // Helper subclasses
176
+ Selector,
177
+ RestClient,
178
+ GraphClient,
179
+ WebSocketClient,
180
+ ExpressServer,
181
+ WebsocketServer,
182
+
183
+ // The singleton container
184
+ default: this.container,
185
+
186
+ // Convenient feature instances
187
+ fs: this.container.feature('fs'),
188
+ ui: this.container.feature('ui'),
189
+ vm,
190
+ proc: this.container.feature('proc'),
191
+
192
+ // Zod re-export
193
+ z,
194
+ }
195
+
196
+ // Schemas
197
+ const schemasModule: Record<string, any> = { CommandOptionsSchema: commands.baseClass?.optionsSchema || z.object({}) }
198
+ try {
199
+ // Pull all base schemas from the already-loaded schemas/base module
200
+ const baseSchemas = require('../../schemas/base.js')
201
+ Object.assign(lucaExports, baseSchemas)
202
+ Object.assign(schemasModule, baseSchemas)
203
+ } catch {
204
+ // Fallback: provide the essentials
205
+ lucaExports.FeatureStateSchema = FeatureStateSchema
206
+ lucaExports.FeatureOptionsSchema = FeatureOptionsSchema
207
+ lucaExports.FeatureEventsSchema = FeatureEventsSchema
208
+ schemasModule.FeatureStateSchema = FeatureStateSchema
209
+ schemasModule.FeatureOptionsSchema = FeatureOptionsSchema
210
+ schemasModule.FeatureEventsSchema = FeatureEventsSchema
211
+ }
212
+
213
+ vm.defineModule('luca', lucaExports)
214
+ vm.defineModule('luca/schemas', schemasModule)
215
+ vm.defineModule('luca/node', lucaExports)
216
+
217
+ // Deep import paths AIs and developers might reach for
218
+ vm.defineModule('luca/client', { Client, ClientsRegistry: clients.constructor, default: Client })
219
+ vm.defineModule('luca/server', { Server, ServersRegistry: servers.constructor, default: Server })
220
+ vm.defineModule('luca/clients/rest', { RestClient, default: RestClient })
221
+ vm.defineModule('luca/clients/graph', { GraphClient, default: GraphClient })
222
+ vm.defineModule('luca/clients/websocket', { WebSocketClient, default: WebSocketClient })
223
+ vm.defineModule('luca/servers/express', { ExpressServer, default: ExpressServer })
224
+ vm.defineModule('luca/servers/socket', { WebsocketServer, default: WebsocketServer })
225
+
226
+ vm.defineModule('zod', { z, default: { z } })
227
+ }
228
+
229
+ /**
230
+ * Returns all instantiated helper instances across all types, optionally filtered by class.
231
+ *
232
+ * @param FilterClass - When provided, only instances of this class are returned.
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * // All instances of any type
237
+ * container.helpers.getInstances()
238
+ *
239
+ * // All Assistant instances
240
+ * const assistants = container.helpers.getInstances(Assistant)
241
+ * ```
242
+ */
243
+ getInstances(): Helper[]
244
+ getInstances<T extends Helper>(FilterClass: new (...args: any[]) => T): T[]
245
+ getInstances<T extends Helper>(FilterClass?: new (...args: any[]) => T): Helper[] | T[] {
246
+ return FilterClass ? allHelperInstances(FilterClass) : allHelperInstances()
247
+ }
248
+
249
+ /**
250
+ * Returns a unified view of all available helpers across all registries.
251
+ * Each key is a registry type, each value is the list of helper names in that registry.
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * container.helpers.available
256
+ * // { features: ['fs', 'git', ...], clients: ['rest', 'websocket'], ... }
257
+ * ```
258
+ */
259
+ get available(): Record<string, string[]> {
260
+ const result: Record<string, string[]> = {}
261
+ for (const [type, { registry }] of Object.entries(this.registryMap)) {
262
+ result[type] = registry.available
263
+ }
264
+ return result
265
+ }
266
+
267
+ /**
268
+ * Ensures the fileManager feature is started before using it for discovery.
269
+ *
270
+ * @returns The started fileManager instance
271
+ */
272
+ private async ensureFileManager(): Promise<FileManager> {
273
+ const fm = this.container.feature('fileManager', { enable: true }) as unknown as FileManager
274
+ if (!fm.isStarted) {
275
+ await fm.start()
276
+ }
277
+ return fm
278
+ }
279
+
280
+ /**
281
+ * Resolves which conventional folder path exists for a given registry type.
282
+ * Tries each candidate folder in order and returns the first one that exists.
283
+ *
284
+ * @param type - The registry type to resolve the folder for
285
+ * @returns Absolute path to the folder, or null if none exist
286
+ */
287
+ private resolveFolderPath(type: RegistryType): string | null {
288
+ const { folders } = this.registryMap[type]
289
+ const { fs } = this.container
290
+
291
+ for (const candidate of folders) {
292
+ const dir = resolve(this.rootDir, candidate)
293
+ if (fs.exists(dir)) {
294
+ return dir
295
+ }
296
+ }
297
+
298
+ return null
299
+ }
300
+
301
+ /**
302
+ * Discover and register project-level helpers of the given type.
303
+ *
304
+ * Idempotent: the first caller triggers the actual scan. Subsequent callers
305
+ * receive the cached results. If discovery is in-flight, callers await the
306
+ * same promise — no duplicate work.
307
+ *
308
+ * @param type - Which type of helpers to discover
309
+ * @param options - Optional overrides
310
+ * @param options.directory - Override the directory to scan
311
+ * @returns Names of helpers that were discovered and registered
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * const names = await container.helpers.discover('features')
316
+ * console.log(names) // ['myCustomFeature']
317
+ * ```
318
+ */
319
+ async discover(type: RegistryType, options: { directory?: string } = {}): Promise<string[]> {
320
+ // Key by type + resolved directory so that different directories
321
+ // (e.g. project commands/ vs ~/.luca/commands/) are discovered independently
322
+ // while concurrent calls to the same directory coalesce on one promise.
323
+ const dir = options.directory || this.resolveFolderPath(type)
324
+ const cacheKey = dir ? `${type}:${dir}` : type
325
+
326
+ // Return cached results if already completed
327
+ if (this._discoveryResults.has(cacheKey)) {
328
+ return this._discoveryResults.get(cacheKey)!
329
+ }
330
+
331
+ // If in-flight, await the same promise
332
+ if (this._discoveryPromises.has(cacheKey)) {
333
+ return this._discoveryPromises.get(cacheKey)!
334
+ }
335
+
336
+ // First caller — start the work and store the promise
337
+ const promise = this._doDiscover(type, { directory: dir || undefined })
338
+ this._discoveryPromises.set(cacheKey, promise)
339
+
340
+ const names = await promise
341
+
342
+ // Cache the final results
343
+ this._discoveryResults.set(cacheKey, names)
344
+
345
+ return names
346
+ }
347
+
348
+ /** Internal: performs the actual discovery work for a single type. */
349
+ private async _doDiscover(type: RegistryType, options: { directory?: string } = {}): Promise<string[]> {
350
+ const dir = options.directory || this.resolveFolderPath(type)
351
+
352
+ if (!dir) {
353
+ return []
354
+ }
355
+
356
+ let names: string[]
357
+
358
+ if (CLASS_BASED.includes(type)) {
359
+ names = await this.discoverClassBased(type, dir)
360
+ } else {
361
+ names = await this.discoverConfigBased(type, dir)
362
+ }
363
+
364
+ // Update state for observability
365
+ const discovered = this.state.get('discovered') || {}
366
+ this.state.set('discovered', { ...discovered, [type]: true })
367
+
368
+ const existing = this.state.get('registered') || []
369
+ this.state.set('registered', [...existing, ...names.map(n => `${type}.${n}`)])
370
+
371
+ this.emit('discovered' as any, type, names)
372
+
373
+ return names
374
+ }
375
+
376
+ /**
377
+ * Discover all helper types from their conventional folder locations.
378
+ *
379
+ * Idempotent: safe to call from multiple places (luca.cli.ts, commands, etc.).
380
+ * The first caller triggers discovery; all others receive the same results.
381
+ *
382
+ * @returns Map of registry type to discovered helper names
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * const results = await container.helpers.discoverAll()
387
+ * // { features: ['myFeature'], clients: [], servers: [], commands: ['deploy'], endpoints: [] }
388
+ * ```
389
+ */
390
+ async discoverAll(): Promise<Record<string, string[]>> {
391
+ if (this._discoverAllPromise) {
392
+ return this._discoverAllPromise
393
+ }
394
+
395
+ this._discoverAllPromise = this._doDiscoverAll()
396
+ return this._discoverAllPromise
397
+ }
398
+
399
+ /** Internal: performs the actual discoverAll work. */
400
+ private async _doDiscoverAll(): Promise<Record<string, string[]>> {
401
+ const results: Record<string, string[]> = {}
402
+
403
+ for (const type of ['features', 'clients', 'servers', 'commands', 'endpoints', 'selectors'] as RegistryType[]) {
404
+ results[type] = await this.discover(type)
405
+ }
406
+
407
+ return results
408
+ }
409
+
410
+ /**
411
+ * Look up a helper class by type and name.
412
+ *
413
+ * @param type - The registry type (features, clients, servers, commands, endpoints)
414
+ * @param name - The helper name within that registry
415
+ * @returns The helper constructor
416
+ *
417
+ * @example
418
+ * ```typescript
419
+ * const FsClass = container.helpers.lookup('features', 'fs')
420
+ * ```
421
+ */
422
+ lookup(type: RegistryType, name: string): any {
423
+ const { registry } = this.registryMap[type]
424
+ return registry.lookup(name)
425
+ }
426
+
427
+ /**
428
+ * Get the introspection description for a specific helper.
429
+ *
430
+ * @param type - The registry type
431
+ * @param name - The helper name
432
+ * @returns Markdown description of the helper's interface
433
+ */
434
+ describe(type: RegistryType, name: string): string {
435
+ const { registry } = this.registryMap[type]
436
+ return registry.describe(name)
437
+ }
438
+
439
+ /**
440
+ * Load a module either via native `import()` or the VM's virtual module system.
441
+ * Uses the same `useNativeImport` check as discovery to decide the loading strategy.
442
+ *
443
+ * @param absPath - Absolute path to the module file
444
+ * @param options - Optional settings
445
+ * @param options.cacheBust - When true, appends a timestamp query to bypass the native import cache (useful for hot reload)
446
+ * @returns The module's exports
447
+ */
448
+ async loadModuleExports(absPath: string, options?: { cacheBust?: boolean }): Promise<Record<string, any>> {
449
+ if (this.useNativeImport) {
450
+ const importPath = options?.cacheBust ? `${absPath}?t=${Date.now()}` : absPath
451
+ const mod = await import(importPath)
452
+ return mod
453
+ }
454
+
455
+ this.seedVirtualModules()
456
+ const vm = this.container.feature('vm') as unknown as VM
457
+ return vm.loadModule(absPath)
458
+ }
459
+
460
+ /**
461
+ * Discovers class-based helpers (features, clients, servers) from a directory.
462
+ * Uses fileManager when available (fast in git repos), falls back to Glob.
463
+ */
464
+ private async discoverClassBased(type: RegistryType, dir: string): Promise<string[]> {
465
+ const { registry, baseClass } = this.registryMap[type]
466
+ const discovered: string[] = []
467
+
468
+ // Load build-time introspection data before importing helpers so that
469
+ // interceptRegistration() can merge JSDoc descriptions from the generated file.
470
+ const introspectionFile = resolve(dir, 'introspection.generated.ts')
471
+ try {
472
+ if (existsSync(introspectionFile)) {
473
+ await import(introspectionFile)
474
+ }
475
+ } catch {}
476
+
477
+ // Try fileManager first (faster in git repos, and now symlink-aware),
478
+ // fall back to fs.walk which also follows symlinks natively.
479
+ let files: string[] = []
480
+ try {
481
+ const fm = await this.ensureFileManager()
482
+ const absPatterns = [`${dir}/*.ts`, `${dir}/**/*.ts`]
483
+ // Only use relative patterns when rootDir matches the container cwd,
484
+ // otherwise the fileManager (rooted in cwd) returns files from the
485
+ // wrong project which then get resolved against this.rootDir.
486
+ const useRelative = this.rootDir === this.container.cwd
487
+ const relPatterns = useRelative ? [`${type}/*.ts`, `${type}/**/*.ts`] : []
488
+ const matched = fm.match([...absPatterns, ...relPatterns])
489
+ files = matched.map((f: string) => f.startsWith('/') ? f : resolve(this.rootDir, f))
490
+ } catch {}
491
+
492
+ // Fall back to fs.walk if fileManager found nothing
493
+ if (files.length === 0) {
494
+ const { fs } = this.container
495
+ const walked = fs.walk(dir, { include: ['**/*.ts'] })
496
+ files = walked.files
497
+ }
498
+
499
+ for (const absPath of files) {
500
+ const { name: fileName } = parse(absPath)
501
+
502
+ if (fileName.includes('.test.') || fileName.includes('.spec.') || fileName.includes('.generated')) {
503
+ continue
504
+ }
505
+ try {
506
+ const mod = await this.loadModuleExports(absPath)
507
+ const ExportedClass = mod.default || mod
508
+
509
+ // Class-based: default export is a subclass of the base
510
+ if (typeof ExportedClass === 'function' && isNativeHelperClass(ExportedClass, baseClass)) {
511
+ const shortcut = ExportedClass.shortcut as string | undefined
512
+ const registryName = shortcut
513
+ ? shortcut.replace(`${type}.`, '')
514
+ : this.fileNameToRegistryName(fileName)
515
+
516
+ discovered.push(registryName)
517
+
518
+ if (!registry.has(registryName)) {
519
+ registry.register(registryName, ExportedClass)
520
+ this.emit('registered' as any, type, registryName, ExportedClass)
521
+ }
522
+ } else {
523
+ // Module-based: graft exports onto a generated subclass
524
+ const moduleExports = mod.default && typeof mod.default === 'object' ? mod.default : mod
525
+ const isGraftable = (
526
+ moduleExports.description !== undefined ||
527
+ moduleExports.stateSchema !== undefined ||
528
+ moduleExports.optionsSchema !== undefined ||
529
+ typeof moduleExports.run === 'function' ||
530
+ typeof moduleExports.handler === 'function'
531
+ )
532
+
533
+ if (isGraftable) {
534
+ const registryName = this.fileNameToRegistryName(fileName)
535
+ const GraftedClass = graftModule(baseClass, moduleExports, registryName, type as any)
536
+
537
+ discovered.push(registryName)
538
+
539
+ if (!registry.has(registryName)) {
540
+ registry.register(registryName, GraftedClass as any)
541
+ this.emit('registered' as any, type, registryName, GraftedClass)
542
+ }
543
+ }
544
+ }
545
+
546
+ } catch (err: any) {
547
+ if (err.message?.includes('name collision')) {
548
+ throw err
549
+ }
550
+ console.warn(`Helpers gateway: failed to load ${type} from ${absPath}: ${err.message}`)
551
+ }
552
+ }
553
+
554
+ return discovered
555
+ }
556
+
557
+ /**
558
+ * Discovers config-based helpers (commands, endpoints) by delegating
559
+ * to existing discovery mechanisms.
560
+ */
561
+ private async discoverConfigBased(type: RegistryType, dir: string): Promise<string[]> {
562
+ const { registry } = this.registryMap[type]
563
+ const beforeNames = new Set(registry.available)
564
+
565
+ if (type === 'commands') {
566
+ if (this.useNativeImport) {
567
+ await commands.discover({ directory: dir })
568
+ } else {
569
+ await this.discoverCommandsViaVM(dir)
570
+ }
571
+ } else if (type === 'endpoints') {
572
+ await this.discoverEndpoints(dir)
573
+ } else if (type === 'selectors') {
574
+ if (this.useNativeImport) {
575
+ await selectors.discover({ directory: dir })
576
+ } else {
577
+ await this.discoverSelectorsViaVM(dir)
578
+ }
579
+ }
580
+
581
+ const afterNames = new Set(registry.available)
582
+ return [...afterNames].filter(n => !beforeNames.has(n))
583
+ }
584
+
585
+ /**
586
+ * Discovers commands using the VM's virtual module system.
587
+ * Mirrors CommandsRegistry.discover() but uses vm.loadModule() instead of import().
588
+ */
589
+ private async discoverCommandsViaVM(dir: string): Promise<void> {
590
+ this.seedVirtualModules()
591
+ const { fs } = this.container
592
+ // Commands are top-level only (not recursive) — walk and filter to *.ts in the immediate dir
593
+ const walked = fs.walk(dir, { include: ['*.ts'] })
594
+ const tsFiles = walked.files
595
+ .map(f => parse(f))
596
+ .filter(p => p.dir === dir) // top-level only
597
+ .map(p => p.base)
598
+
599
+ for (const file of tsFiles) {
600
+ if (file === 'index.ts') continue
601
+
602
+ const absPath = resolve(dir, file)
603
+ const name = file.replace(/\.ts$/, '')
604
+
605
+ if (commands.has(name)) continue
606
+
607
+ try {
608
+ const mod = await this.loadModuleExports(absPath)
609
+
610
+ // 1. Class-based: default export extends Command
611
+ if (isNativeHelperClass(mod.default, Command)) {
612
+ const ExportedClass = mod.default
613
+ if (!ExportedClass.shortcut || ExportedClass.shortcut === 'commands.base') {
614
+ ExportedClass.shortcut = `commands.${name}`
615
+ }
616
+ if (!ExportedClass.commandDescription && ExportedClass.description) {
617
+ ExportedClass.commandDescription = ExportedClass.description
618
+ }
619
+ commands.register(name, ExportedClass)
620
+ continue
621
+ }
622
+
623
+ const commandModule = mod.default || mod
624
+
625
+ // 2. Module-based with `run` export (new SimpleCommand pattern)
626
+ if (typeof commandModule.run === 'function') {
627
+ const Grafted = graftModule(Command as any, commandModule, name, 'commands')
628
+ commands.register(name, Grafted as any)
629
+ continue
630
+ }
631
+
632
+ // 3. Legacy: `handler` export
633
+ if (typeof commandModule.handler === 'function') {
634
+ const Grafted = graftModule(Command as any, {
635
+ description: commandModule.description,
636
+ argsSchema: commandModule.argsSchema,
637
+ positionals: commandModule.positionals ?? mod.positionals,
638
+ handler: commandModule.handler,
639
+ }, name, 'commands')
640
+ commands.register(name, Grafted as any)
641
+ continue
642
+ }
643
+
644
+ // 4. Plain default-exported function: export default async function name(options, context)
645
+ if (typeof mod.default === 'function' && !isNativeHelperClass(mod.default, Command)) {
646
+ const Grafted = graftModule(Command as any, {
647
+ description: mod.description || '',
648
+ argsSchema: mod.argsSchema,
649
+ positionals: mod.positionals,
650
+ handler: mod.default,
651
+ }, name, 'commands')
652
+ commands.register(name, Grafted as any)
653
+ }
654
+ } catch (err: any) {
655
+ console.warn(`Helpers gateway: failed to load command from ${absPath}: ${err.message}`)
656
+ }
657
+ }
658
+ }
659
+
660
+ /**
661
+ * Discovers selectors using the VM's virtual module system.
662
+ * Mirrors discoverCommandsViaVM but uses selectors registry and Selector base class.
663
+ */
664
+ private async discoverSelectorsViaVM(dir: string): Promise<void> {
665
+ this.seedVirtualModules()
666
+ const { fs } = this.container
667
+ const walked = fs.walk(dir, { include: ['*.ts'] })
668
+ const tsFiles = walked.files
669
+ .map(f => parse(f))
670
+ .filter(p => p.dir === dir)
671
+ .map(p => p.base)
672
+
673
+ for (const file of tsFiles) {
674
+ if (file === 'index.ts') continue
675
+
676
+ const absPath = resolve(dir, file)
677
+ const name = file.replace(/\.ts$/, '')
678
+
679
+ if (selectors.has(name)) continue
680
+
681
+ try {
682
+ const mod = await this.loadModuleExports(absPath)
683
+
684
+ // 1. Class-based: default export extends Selector
685
+ if (isNativeHelperClass(mod.default, Selector)) {
686
+ const ExportedClass = mod.default
687
+ if (!ExportedClass.shortcut || ExportedClass.shortcut === 'selectors.base') {
688
+ ExportedClass.shortcut = `selectors.${name}`
689
+ }
690
+ selectors.register(name, ExportedClass)
691
+ continue
692
+ }
693
+
694
+ const selectorModule = mod.default || mod
695
+
696
+ // 2. Module-based with `run` export
697
+ if (typeof selectorModule.run === 'function') {
698
+ const Grafted = graftModule(Selector as any, selectorModule, name, 'selectors')
699
+ selectors.register(name, Grafted as any)
700
+ }
701
+ } catch (err: any) {
702
+ console.warn(`Helpers gateway: failed to load selector from ${absPath}: ${err.message}`)
703
+ }
704
+ }
705
+ }
706
+
707
+ /**
708
+ * Discovers endpoints from a directory, registering them for discoverability.
709
+ * Actual mounting to an express server is handled separately by ExpressServer.useEndpoints().
710
+ */
711
+ private async discoverEndpoints(dir: string): Promise<void> {
712
+ const { fs } = this.container
713
+ const walked = fs.walk(dir, { include: ['**/*.ts'] })
714
+
715
+ for (const file of walked.files) {
716
+ try {
717
+ const mod = await this.loadModuleExports(file)
718
+ const endpointModule = mod.default || mod
719
+
720
+ if (endpointModule.path && typeof endpointModule.path === 'string') {
721
+ const name = endpointModule.path.replace(/^\//, '').replace(/\//g, '_') || parse(file).name
722
+
723
+ if (!endpoints.has(name)) {
724
+ // Import the module so it's available, but don't mount it to a server
725
+ // The express server's useEndpoints() handles the actual mounting
726
+ }
727
+ }
728
+ } catch (err: any) {
729
+ console.warn(`Helpers gateway: failed to load endpoint from ${file}: ${err.message}`)
730
+ }
731
+ }
732
+ }
733
+
734
+ /**
735
+ * Check if a class is a subclass of a given base class by walking the prototype chain.
736
+ * Uses identity comparison first, then falls back to name comparison to handle
737
+ * cross-module boundaries (e.g. compiled binary vs dynamically imported modules
738
+ * that resolve to separate module instances of the same class).
739
+ */
740
+ private isSubclassOf(candidate: any, base: any): boolean {
741
+ if (!candidate || !base) return false
742
+ if (candidate === base) return true
743
+
744
+ let proto = Object.getPrototypeOf(candidate)
745
+ while (proto) {
746
+ if (proto === base || (base.name && proto.name === base.name)) return true
747
+ proto = Object.getPrototypeOf(proto)
748
+ }
749
+ return false
750
+ }
751
+
752
+ /**
753
+ * Convert a kebab-case or snake_case filename to a camelCase registry name.
754
+ */
755
+ private fileNameToRegistryName(fileName: string): string {
756
+ return fileName
757
+ .replace(/[-_](.)/g, (_, c: string) => c.toUpperCase())
758
+ .replace(/^(.)/, (_, c: string) => c.toLowerCase())
759
+ }
760
+ }
761
+
762
+ export default Helpers