luca 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (763) hide show
  1. package/.github/workflows/release.yaml +169 -0
  2. package/AGENTS.md +99 -0
  3. package/CLAUDE.md +115 -0
  4. package/CNAME +1 -0
  5. package/README.md +257 -9
  6. package/RUNME.md +56 -0
  7. package/assistants/codingAssistant/ABOUT.md +5 -0
  8. package/assistants/codingAssistant/CORE.md +28 -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 +2769 -0
  20. package/bunfig.toml +3 -0
  21. package/commands/audit-docs.ts +740 -0
  22. package/commands/build-bootstrap.ts +118 -0
  23. package/commands/build-python-bridge.ts +43 -0
  24. package/commands/build-scaffolds.ts +176 -0
  25. package/commands/generate-api-docs.ts +114 -0
  26. package/commands/inkbot.ts +874 -0
  27. package/commands/release.ts +80 -0
  28. package/commands/try-all-challenges.ts +543 -0
  29. package/commands/try-challenge.ts +100 -0
  30. package/dist/agi/container.server.d.ts +63 -0
  31. package/dist/agi/container.server.d.ts.map +1 -0
  32. package/dist/agi/endpoints/ask.d.ts +20 -0
  33. package/dist/agi/endpoints/ask.d.ts.map +1 -0
  34. package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
  35. package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
  36. package/dist/agi/endpoints/conversations.d.ts +18 -0
  37. package/dist/agi/endpoints/conversations.d.ts.map +1 -0
  38. package/dist/agi/endpoints/experts.d.ts +8 -0
  39. package/dist/agi/endpoints/experts.d.ts.map +1 -0
  40. package/dist/agi/feature.d.ts +9 -0
  41. package/dist/agi/feature.d.ts.map +1 -0
  42. package/dist/agi/features/assistant.d.ts +509 -0
  43. package/dist/agi/features/assistant.d.ts.map +1 -0
  44. package/dist/agi/features/assistants-manager.d.ts +236 -0
  45. package/dist/agi/features/assistants-manager.d.ts.map +1 -0
  46. package/dist/agi/features/autonomous-assistant.d.ts +281 -0
  47. package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
  48. package/dist/agi/features/browser-use.d.ts +479 -0
  49. package/dist/agi/features/browser-use.d.ts.map +1 -0
  50. package/dist/agi/features/claude-code.d.ts +824 -0
  51. package/dist/agi/features/claude-code.d.ts.map +1 -0
  52. package/dist/agi/features/conversation-history.d.ts +245 -0
  53. package/dist/agi/features/conversation-history.d.ts.map +1 -0
  54. package/dist/agi/features/conversation.d.ts +464 -0
  55. package/dist/agi/features/conversation.d.ts.map +1 -0
  56. package/dist/agi/features/docs-reader.d.ts +72 -0
  57. package/dist/agi/features/docs-reader.d.ts.map +1 -0
  58. package/dist/agi/features/file-tools.d.ts +110 -0
  59. package/dist/agi/features/file-tools.d.ts.map +1 -0
  60. package/dist/agi/features/luca-coder.d.ts +323 -0
  61. package/dist/agi/features/luca-coder.d.ts.map +1 -0
  62. package/dist/agi/features/openai-codex.d.ts +381 -0
  63. package/dist/agi/features/openai-codex.d.ts.map +1 -0
  64. package/dist/agi/features/openapi.d.ts +200 -0
  65. package/dist/agi/features/openapi.d.ts.map +1 -0
  66. package/dist/agi/features/skills-library.d.ts +167 -0
  67. package/dist/agi/features/skills-library.d.ts.map +1 -0
  68. package/dist/agi/index.d.ts +5 -0
  69. package/dist/agi/index.d.ts.map +1 -0
  70. package/dist/agi/lib/interceptor-chain.d.ts +44 -0
  71. package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
  72. package/dist/agi/lib/token-counter.d.ts +13 -0
  73. package/dist/agi/lib/token-counter.d.ts.map +1 -0
  74. package/dist/bootstrap/generated.d.ts +5 -0
  75. package/dist/bootstrap/generated.d.ts.map +1 -0
  76. package/dist/browser.d.ts +12 -0
  77. package/dist/browser.d.ts.map +1 -0
  78. package/dist/bus.d.ts +29 -0
  79. package/dist/bus.d.ts.map +1 -0
  80. package/dist/cli/build-info.d.ts +4 -0
  81. package/dist/cli/build-info.d.ts.map +1 -0
  82. package/dist/cli/cli.d.ts +3 -12
  83. package/dist/cli/cli.d.ts.map +1 -0
  84. package/dist/client.d.ts +60 -0
  85. package/dist/client.d.ts.map +1 -0
  86. package/dist/clients/civitai/index.d.ts +472 -0
  87. package/dist/clients/civitai/index.d.ts.map +1 -0
  88. package/dist/clients/client-template.d.ts +30 -0
  89. package/dist/clients/client-template.d.ts.map +1 -0
  90. package/dist/clients/comfyui/index.d.ts +281 -0
  91. package/dist/clients/comfyui/index.d.ts.map +1 -0
  92. package/dist/clients/elevenlabs/index.d.ts +197 -0
  93. package/dist/clients/elevenlabs/index.d.ts.map +1 -0
  94. package/dist/clients/graph.d.ts +64 -0
  95. package/dist/clients/graph.d.ts.map +1 -0
  96. package/dist/clients/openai/index.d.ts +247 -0
  97. package/dist/clients/openai/index.d.ts.map +1 -0
  98. package/dist/clients/rest.d.ts +92 -0
  99. package/dist/clients/rest.d.ts.map +1 -0
  100. package/dist/clients/supabase/index.d.ts +176 -0
  101. package/dist/clients/supabase/index.d.ts.map +1 -0
  102. package/dist/clients/websocket.d.ts +127 -0
  103. package/dist/clients/websocket.d.ts.map +1 -0
  104. package/dist/command.d.ts +163 -0
  105. package/dist/command.d.ts.map +1 -0
  106. package/dist/commands/bootstrap.d.ts +20 -0
  107. package/dist/commands/bootstrap.d.ts.map +1 -0
  108. package/dist/commands/chat.d.ts +37 -0
  109. package/dist/commands/chat.d.ts.map +1 -0
  110. package/dist/commands/code.d.ts +28 -0
  111. package/dist/commands/code.d.ts.map +1 -0
  112. package/dist/commands/console.d.ts +22 -0
  113. package/dist/commands/console.d.ts.map +1 -0
  114. package/dist/commands/describe.d.ts +50 -0
  115. package/dist/commands/describe.d.ts.map +1 -0
  116. package/dist/commands/eval.d.ts +23 -0
  117. package/dist/commands/eval.d.ts.map +1 -0
  118. package/dist/commands/help.d.ts +25 -0
  119. package/dist/commands/help.d.ts.map +1 -0
  120. package/dist/commands/index.d.ts +18 -0
  121. package/dist/commands/index.d.ts.map +1 -0
  122. package/dist/commands/introspect.d.ts +24 -0
  123. package/dist/commands/introspect.d.ts.map +1 -0
  124. package/dist/commands/mcp.d.ts +35 -0
  125. package/dist/commands/mcp.d.ts.map +1 -0
  126. package/dist/commands/prompt.d.ts +38 -0
  127. package/dist/commands/prompt.d.ts.map +1 -0
  128. package/dist/commands/run.d.ts +24 -0
  129. package/dist/commands/run.d.ts.map +1 -0
  130. package/dist/commands/sandbox-mcp.d.ts +34 -0
  131. package/dist/commands/sandbox-mcp.d.ts.map +1 -0
  132. package/dist/commands/save-api-docs.d.ts +21 -0
  133. package/dist/commands/save-api-docs.d.ts.map +1 -0
  134. package/dist/commands/scaffold.d.ts +24 -0
  135. package/dist/commands/scaffold.d.ts.map +1 -0
  136. package/dist/commands/select.d.ts +22 -0
  137. package/dist/commands/select.d.ts.map +1 -0
  138. package/dist/commands/serve.d.ts +29 -0
  139. package/dist/commands/serve.d.ts.map +1 -0
  140. package/dist/container-describer.d.ts +144 -0
  141. package/dist/container-describer.d.ts.map +1 -0
  142. package/dist/container.d.ts +451 -0
  143. package/dist/container.d.ts.map +1 -0
  144. package/dist/endpoint.d.ts +113 -0
  145. package/dist/endpoint.d.ts.map +1 -0
  146. package/dist/feature.d.ts +47 -0
  147. package/dist/feature.d.ts.map +1 -0
  148. package/dist/graft.d.ts +29 -0
  149. package/dist/graft.d.ts.map +1 -0
  150. package/dist/hash-object.d.ts +8 -0
  151. package/dist/hash-object.d.ts.map +1 -0
  152. package/dist/helper.d.ts +209 -0
  153. package/dist/helper.d.ts.map +1 -0
  154. package/dist/introspection/generated.node.d.ts +44623 -0
  155. package/dist/introspection/generated.node.d.ts.map +1 -0
  156. package/dist/introspection/generated.web.d.ts +1412 -0
  157. package/dist/introspection/generated.web.d.ts.map +1 -0
  158. package/dist/introspection/index.d.ts +156 -0
  159. package/dist/introspection/index.d.ts.map +1 -0
  160. package/dist/introspection/scan.d.ts +147 -0
  161. package/dist/introspection/scan.d.ts.map +1 -0
  162. package/dist/node/container.d.ts +256 -0
  163. package/dist/node/container.d.ts.map +1 -0
  164. package/dist/node/feature.d.ts +9 -0
  165. package/dist/node/feature.d.ts.map +1 -0
  166. package/dist/node/features/container-link.d.ts +213 -0
  167. package/dist/node/features/container-link.d.ts.map +1 -0
  168. package/dist/node/features/content-db.d.ts +354 -0
  169. package/dist/node/features/content-db.d.ts.map +1 -0
  170. package/dist/node/features/disk-cache.d.ts +236 -0
  171. package/dist/node/features/disk-cache.d.ts.map +1 -0
  172. package/dist/node/features/dns.d.ts +511 -0
  173. package/dist/node/features/dns.d.ts.map +1 -0
  174. package/dist/node/features/docker.d.ts +485 -0
  175. package/dist/node/features/docker.d.ts.map +1 -0
  176. package/dist/node/features/downloader.d.ts +73 -0
  177. package/dist/node/features/downloader.d.ts.map +1 -0
  178. package/dist/node/features/figlet-fonts.d.ts +4 -0
  179. package/dist/node/features/figlet-fonts.d.ts.map +1 -0
  180. package/dist/node/features/file-manager.d.ts +177 -0
  181. package/dist/node/features/file-manager.d.ts.map +1 -0
  182. package/dist/node/features/fs.d.ts +635 -0
  183. package/dist/node/features/fs.d.ts.map +1 -0
  184. package/dist/node/features/git.d.ts +329 -0
  185. package/dist/node/features/git.d.ts.map +1 -0
  186. package/dist/node/features/google-auth.d.ts +200 -0
  187. package/dist/node/features/google-auth.d.ts.map +1 -0
  188. package/dist/node/features/google-calendar.d.ts +194 -0
  189. package/dist/node/features/google-calendar.d.ts.map +1 -0
  190. package/dist/node/features/google-docs.d.ts +138 -0
  191. package/dist/node/features/google-docs.d.ts.map +1 -0
  192. package/dist/node/features/google-drive.d.ts +202 -0
  193. package/dist/node/features/google-drive.d.ts.map +1 -0
  194. package/dist/node/features/google-mail.d.ts +221 -0
  195. package/dist/node/features/google-mail.d.ts.map +1 -0
  196. package/dist/node/features/google-sheets.d.ts +157 -0
  197. package/dist/node/features/google-sheets.d.ts.map +1 -0
  198. package/dist/node/features/grep.d.ts +207 -0
  199. package/dist/node/features/grep.d.ts.map +1 -0
  200. package/dist/node/features/helpers.d.ts +236 -0
  201. package/dist/node/features/helpers.d.ts.map +1 -0
  202. package/dist/node/features/ink.d.ts +332 -0
  203. package/dist/node/features/ink.d.ts.map +1 -0
  204. package/dist/node/features/ipc-socket.d.ts +298 -0
  205. package/dist/node/features/ipc-socket.d.ts.map +1 -0
  206. package/dist/node/features/json-tree.d.ts +140 -0
  207. package/dist/node/features/json-tree.d.ts.map +1 -0
  208. package/dist/node/features/networking.d.ts +373 -0
  209. package/dist/node/features/networking.d.ts.map +1 -0
  210. package/dist/node/features/nlp.d.ts +125 -0
  211. package/dist/node/features/nlp.d.ts.map +1 -0
  212. package/dist/node/features/opener.d.ts +93 -0
  213. package/dist/node/features/opener.d.ts.map +1 -0
  214. package/dist/node/features/os.d.ts +168 -0
  215. package/dist/node/features/os.d.ts.map +1 -0
  216. package/dist/node/features/package-finder.d.ts +419 -0
  217. package/dist/node/features/package-finder.d.ts.map +1 -0
  218. package/dist/node/features/postgres.d.ts +173 -0
  219. package/dist/node/features/postgres.d.ts.map +1 -0
  220. package/dist/node/features/proc.d.ts +285 -0
  221. package/dist/node/features/proc.d.ts.map +1 -0
  222. package/dist/node/features/process-manager.d.ts +427 -0
  223. package/dist/node/features/process-manager.d.ts.map +1 -0
  224. package/dist/node/features/python.d.ts +477 -0
  225. package/dist/node/features/python.d.ts.map +1 -0
  226. package/dist/node/features/redis.d.ts +247 -0
  227. package/dist/node/features/redis.d.ts.map +1 -0
  228. package/dist/node/features/repl.d.ts +84 -0
  229. package/dist/node/features/repl.d.ts.map +1 -0
  230. package/dist/node/features/runpod.d.ts +527 -0
  231. package/dist/node/features/runpod.d.ts.map +1 -0
  232. package/dist/node/features/secure-shell.d.ts +145 -0
  233. package/dist/node/features/secure-shell.d.ts.map +1 -0
  234. package/dist/node/features/semantic-search.d.ts +207 -0
  235. package/dist/node/features/semantic-search.d.ts.map +1 -0
  236. package/dist/node/features/sqlite.d.ts +180 -0
  237. package/dist/node/features/sqlite.d.ts.map +1 -0
  238. package/dist/node/features/telegram.d.ts +173 -0
  239. package/dist/node/features/telegram.d.ts.map +1 -0
  240. package/dist/node/features/transpiler.d.ts +51 -0
  241. package/dist/node/features/transpiler.d.ts.map +1 -0
  242. package/dist/node/features/tts.d.ts +108 -0
  243. package/dist/node/features/tts.d.ts.map +1 -0
  244. package/dist/node/features/ui.d.ts +562 -0
  245. package/dist/node/features/ui.d.ts.map +1 -0
  246. package/dist/node/features/vault.d.ts +90 -0
  247. package/dist/node/features/vault.d.ts.map +1 -0
  248. package/dist/node/features/vm.d.ts +285 -0
  249. package/dist/node/features/vm.d.ts.map +1 -0
  250. package/dist/node/features/yaml-tree.d.ts +118 -0
  251. package/dist/node/features/yaml-tree.d.ts.map +1 -0
  252. package/dist/node/features/yaml.d.ts +127 -0
  253. package/dist/node/features/yaml.d.ts.map +1 -0
  254. package/dist/node.d.ts +67 -0
  255. package/dist/node.d.ts.map +1 -0
  256. package/dist/python/generated.d.ts +2 -0
  257. package/dist/python/generated.d.ts.map +1 -0
  258. package/dist/react/index.d.ts +36 -0
  259. package/dist/react/index.d.ts.map +1 -0
  260. package/dist/registry.d.ts +97 -0
  261. package/dist/registry.d.ts.map +1 -0
  262. package/dist/scaffolds/generated.d.ts +13 -0
  263. package/dist/scaffolds/generated.d.ts.map +1 -0
  264. package/dist/scaffolds/template.d.ts +11 -0
  265. package/dist/scaffolds/template.d.ts.map +1 -0
  266. package/dist/schemas/base.d.ts +254 -0
  267. package/dist/schemas/base.d.ts.map +1 -0
  268. package/dist/selector.d.ts +130 -0
  269. package/dist/selector.d.ts.map +1 -0
  270. package/dist/server.d.ts +89 -0
  271. package/dist/server.d.ts.map +1 -0
  272. package/dist/servers/express.d.ts +104 -0
  273. package/dist/servers/express.d.ts.map +1 -0
  274. package/dist/servers/mcp.d.ts +201 -0
  275. package/dist/servers/mcp.d.ts.map +1 -0
  276. package/dist/servers/socket.d.ts +121 -0
  277. package/dist/servers/socket.d.ts.map +1 -0
  278. package/dist/state.d.ts +24 -0
  279. package/dist/state.d.ts.map +1 -0
  280. package/dist/web/clients/socket.d.ts +37 -0
  281. package/dist/web/clients/socket.d.ts.map +1 -0
  282. package/dist/web/container.d.ts +55 -0
  283. package/dist/web/container.d.ts.map +1 -0
  284. package/dist/web/extension.d.ts +4 -0
  285. package/dist/web/extension.d.ts.map +1 -0
  286. package/dist/web/feature.d.ts +8 -0
  287. package/dist/web/feature.d.ts.map +1 -0
  288. package/dist/web/features/asset-loader.d.ts +35 -0
  289. package/dist/web/features/asset-loader.d.ts.map +1 -0
  290. package/dist/web/features/container-link.d.ts +167 -0
  291. package/dist/web/features/container-link.d.ts.map +1 -0
  292. package/dist/web/features/esbuild.d.ts +51 -0
  293. package/dist/web/features/esbuild.d.ts.map +1 -0
  294. package/dist/web/features/helpers.d.ts +140 -0
  295. package/dist/web/features/helpers.d.ts.map +1 -0
  296. package/dist/web/features/network.d.ts +69 -0
  297. package/dist/web/features/network.d.ts.map +1 -0
  298. package/dist/web/features/speech.d.ts +71 -0
  299. package/dist/web/features/speech.d.ts.map +1 -0
  300. package/dist/web/features/vault.d.ts +62 -0
  301. package/dist/web/features/vault.d.ts.map +1 -0
  302. package/dist/web/features/vm.d.ts +48 -0
  303. package/dist/web/features/vm.d.ts.map +1 -0
  304. package/dist/web/features/voice-recognition.d.ts +96 -0
  305. package/dist/web/features/voice-recognition.d.ts.map +1 -0
  306. package/dist/web/shims/isomorphic-vm.d.ts +22 -0
  307. package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
  308. package/docs/CLI.md +335 -0
  309. package/docs/CNAME +1 -0
  310. package/docs/README.md +60 -0
  311. package/docs/TABLE-OF-CONTENTS.md +183 -0
  312. package/docs/apis/clients/elevenlabs.md +308 -0
  313. package/docs/apis/clients/graph.md +107 -0
  314. package/docs/apis/clients/openai.md +429 -0
  315. package/docs/apis/clients/rest.md +161 -0
  316. package/docs/apis/clients/websocket.md +174 -0
  317. package/docs/apis/features/agi/assistant.md +625 -0
  318. package/docs/apis/features/agi/assistants-manager.md +282 -0
  319. package/docs/apis/features/agi/auto-assistant.md +279 -0
  320. package/docs/apis/features/agi/browser-use.md +802 -0
  321. package/docs/apis/features/agi/claude-code.md +884 -0
  322. package/docs/apis/features/agi/conversation-history.md +364 -0
  323. package/docs/apis/features/agi/conversation.md +548 -0
  324. package/docs/apis/features/agi/docs-reader.md +99 -0
  325. package/docs/apis/features/agi/file-tools.md +163 -0
  326. package/docs/apis/features/agi/luca-coder.md +407 -0
  327. package/docs/apis/features/agi/openai-codex.md +396 -0
  328. package/docs/apis/features/agi/openapi.md +138 -0
  329. package/docs/apis/features/agi/semantic-search.md +387 -0
  330. package/docs/apis/features/agi/skills-library.md +239 -0
  331. package/docs/apis/features/node/container-link.md +192 -0
  332. package/docs/apis/features/node/content-db.md +450 -0
  333. package/docs/apis/features/node/disk-cache.md +379 -0
  334. package/docs/apis/features/node/dns.md +652 -0
  335. package/docs/apis/features/node/docker.md +706 -0
  336. package/docs/apis/features/node/downloader.md +81 -0
  337. package/docs/apis/features/node/esbuild.md +60 -0
  338. package/docs/apis/features/node/file-manager.md +191 -0
  339. package/docs/apis/features/node/fs.md +1217 -0
  340. package/docs/apis/features/node/git.md +371 -0
  341. package/docs/apis/features/node/google-auth.md +193 -0
  342. package/docs/apis/features/node/google-calendar.md +202 -0
  343. package/docs/apis/features/node/google-docs.md +173 -0
  344. package/docs/apis/features/node/google-drive.md +246 -0
  345. package/docs/apis/features/node/google-mail.md +214 -0
  346. package/docs/apis/features/node/google-sheets.md +194 -0
  347. package/docs/apis/features/node/grep.md +292 -0
  348. package/docs/apis/features/node/helpers.md +164 -0
  349. package/docs/apis/features/node/ink.md +334 -0
  350. package/docs/apis/features/node/ipc-socket.md +249 -0
  351. package/docs/apis/features/node/json-tree.md +86 -0
  352. package/docs/apis/features/node/networking.md +316 -0
  353. package/docs/apis/features/node/nlp.md +133 -0
  354. package/docs/apis/features/node/opener.md +97 -0
  355. package/docs/apis/features/node/os.md +146 -0
  356. package/docs/apis/features/node/package-finder.md +392 -0
  357. package/docs/apis/features/node/postgres.md +234 -0
  358. package/docs/apis/features/node/proc.md +399 -0
  359. package/docs/apis/features/node/process-manager.md +305 -0
  360. package/docs/apis/features/node/python.md +604 -0
  361. package/docs/apis/features/node/redis.md +380 -0
  362. package/docs/apis/features/node/repl.md +88 -0
  363. package/docs/apis/features/node/runpod.md +674 -0
  364. package/docs/apis/features/node/secure-shell.md +176 -0
  365. package/docs/apis/features/node/semantic-search.md +408 -0
  366. package/docs/apis/features/node/sqlite.md +233 -0
  367. package/docs/apis/features/node/telegram.md +279 -0
  368. package/docs/apis/features/node/transpiler.md +74 -0
  369. package/docs/apis/features/node/tts.md +133 -0
  370. package/docs/apis/features/node/ui.md +701 -0
  371. package/docs/apis/features/node/vault.md +59 -0
  372. package/docs/apis/features/node/vm.md +75 -0
  373. package/docs/apis/features/node/yaml-tree.md +85 -0
  374. package/docs/apis/features/node/yaml.md +176 -0
  375. package/docs/apis/features/web/asset-loader.md +59 -0
  376. package/docs/apis/features/web/container-link.md +192 -0
  377. package/docs/apis/features/web/esbuild.md +54 -0
  378. package/docs/apis/features/web/helpers.md +164 -0
  379. package/docs/apis/features/web/network.md +44 -0
  380. package/docs/apis/features/web/speech.md +69 -0
  381. package/docs/apis/features/web/vault.md +59 -0
  382. package/docs/apis/features/web/vm.md +75 -0
  383. package/docs/apis/features/web/voice.md +84 -0
  384. package/docs/apis/servers/express.md +171 -0
  385. package/docs/apis/servers/mcp.md +238 -0
  386. package/docs/apis/servers/websocket.md +170 -0
  387. package/docs/bootstrap/CLAUDE.md +101 -0
  388. package/docs/bootstrap/SKILL.md +341 -0
  389. package/docs/bootstrap/templates/about-command.ts +41 -0
  390. package/docs/bootstrap/templates/docs-models.ts +22 -0
  391. package/docs/bootstrap/templates/docs-readme.md +43 -0
  392. package/docs/bootstrap/templates/example-feature.ts +53 -0
  393. package/docs/bootstrap/templates/health-endpoint.ts +15 -0
  394. package/docs/bootstrap/templates/luca-cli.ts +30 -0
  395. package/docs/bootstrap/templates/runme.md +54 -0
  396. package/docs/challenges/caching-proxy.md +16 -0
  397. package/docs/challenges/content-db-round-trip.md +14 -0
  398. package/docs/challenges/custom-command.md +9 -0
  399. package/docs/challenges/file-watcher-pipeline.md +11 -0
  400. package/docs/challenges/grep-audit-report.md +15 -0
  401. package/docs/challenges/multi-feature-dashboard.md +14 -0
  402. package/docs/challenges/process-orchestrator.md +17 -0
  403. package/docs/challenges/rest-api-server-with-client.md +12 -0
  404. package/docs/challenges/script-runner-with-vm.md +11 -0
  405. package/docs/challenges/simple-rest-api.md +15 -0
  406. package/docs/challenges/websocket-serve-and-client.md +11 -0
  407. package/docs/challenges/yaml-config-system.md +14 -0
  408. package/docs/command-system-overhaul.md +94 -0
  409. package/docs/documentation-audit.md +134 -0
  410. package/docs/examples/assistant/CORE.md +18 -0
  411. package/docs/examples/assistant/hooks.ts +3 -0
  412. package/docs/examples/assistant/tools.ts +10 -0
  413. package/docs/examples/assistant-hooks-reference.ts +171 -0
  414. package/docs/examples/assistant-with-process-manager.md +84 -0
  415. package/docs/examples/content-db.md +77 -0
  416. package/docs/examples/disk-cache.md +83 -0
  417. package/docs/examples/docker.md +101 -0
  418. package/docs/examples/downloader.md +70 -0
  419. package/docs/examples/entity.md +124 -0
  420. package/docs/examples/esbuild.md +80 -0
  421. package/docs/examples/feature-as-tool-provider.md +143 -0
  422. package/docs/examples/file-manager.md +82 -0
  423. package/docs/examples/fs.md +83 -0
  424. package/docs/examples/git.md +85 -0
  425. package/docs/examples/google-auth.md +88 -0
  426. package/docs/examples/google-calendar.md +94 -0
  427. package/docs/examples/google-docs.md +82 -0
  428. package/docs/examples/google-drive.md +96 -0
  429. package/docs/examples/google-sheets.md +95 -0
  430. package/docs/examples/grep.md +85 -0
  431. package/docs/examples/ink-blocks.md +75 -0
  432. package/docs/examples/ink-renderer.md +41 -0
  433. package/docs/examples/ink.md +103 -0
  434. package/docs/examples/ipc-socket.md +103 -0
  435. package/docs/examples/json-tree.md +91 -0
  436. package/docs/examples/networking.md +58 -0
  437. package/docs/examples/nlp.md +91 -0
  438. package/docs/examples/opener.md +78 -0
  439. package/docs/examples/os.md +72 -0
  440. package/docs/examples/package-finder.md +89 -0
  441. package/docs/examples/postgres.md +91 -0
  442. package/docs/examples/proc.md +81 -0
  443. package/docs/examples/process-manager.md +79 -0
  444. package/docs/examples/python.md +132 -0
  445. package/docs/examples/repl.md +93 -0
  446. package/docs/examples/runpod.md +119 -0
  447. package/docs/examples/secure-shell.md +92 -0
  448. package/docs/examples/sqlite.md +86 -0
  449. package/docs/examples/structured-output-with-assistants.md +144 -0
  450. package/docs/examples/telegram.md +77 -0
  451. package/docs/examples/tts.md +86 -0
  452. package/docs/examples/ui.md +80 -0
  453. package/docs/examples/vault.md +70 -0
  454. package/docs/examples/vm.md +86 -0
  455. package/docs/examples/websocket-ask-and-reply-example.md +128 -0
  456. package/docs/examples/yaml-tree.md +93 -0
  457. package/docs/examples/yaml.md +104 -0
  458. package/docs/ideas/assistant-factory-pattern.md +142 -0
  459. package/docs/in-memory-fs.md +4 -0
  460. package/docs/introspection-audit.md +49 -0
  461. package/docs/introspection.md +164 -0
  462. package/docs/mcp/readme.md +162 -0
  463. package/docs/models.ts +41 -0
  464. package/docs/philosophy.md +86 -0
  465. package/docs/principles.md +7 -0
  466. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
  467. package/docs/prompts/check-for-undocumented-features.md +27 -0
  468. package/docs/prompts/mcp-test-easy-command.md +27 -0
  469. package/docs/scaffolds/client.md +149 -0
  470. package/docs/scaffolds/command.md +120 -0
  471. package/docs/scaffolds/endpoint.md +171 -0
  472. package/docs/scaffolds/feature.md +158 -0
  473. package/docs/scaffolds/selector.md +91 -0
  474. package/docs/scaffolds/server.md +196 -0
  475. package/docs/selectors.md +115 -0
  476. package/docs/sessions/custom-command/attempt-log-2.md +195 -0
  477. package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +728 -0
  478. package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +555 -0
  479. package/docs/sessions/grep-audit-report/attempt-log-1.md +289 -0
  480. package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +679 -0
  481. package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +1 -0
  482. package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +920 -0
  483. package/docs/sessions/simple-rest-api/attempt-log-1.md +593 -0
  484. package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +995 -0
  485. package/docs/tutorials/00-bootstrap.md +166 -0
  486. package/docs/tutorials/01-getting-started.md +106 -0
  487. package/docs/tutorials/02-container.md +210 -0
  488. package/docs/tutorials/03-scripts.md +194 -0
  489. package/docs/tutorials/04-features-overview.md +196 -0
  490. package/docs/tutorials/05-state-and-events.md +171 -0
  491. package/docs/tutorials/06-servers.md +157 -0
  492. package/docs/tutorials/07-endpoints.md +198 -0
  493. package/docs/tutorials/08-commands.md +252 -0
  494. package/docs/tutorials/09-clients.md +162 -0
  495. package/docs/tutorials/10-creating-features.md +203 -0
  496. package/docs/tutorials/11-contentbase.md +191 -0
  497. package/docs/tutorials/12-assistants.md +215 -0
  498. package/docs/tutorials/13-introspection.md +157 -0
  499. package/docs/tutorials/14-type-system.md +174 -0
  500. package/docs/tutorials/15-project-patterns.md +222 -0
  501. package/docs/tutorials/16-google-features.md +534 -0
  502. package/docs/tutorials/17-tui-blocks.md +530 -0
  503. package/docs/tutorials/18-semantic-search.md +334 -0
  504. package/docs/tutorials/19-python-sessions.md +401 -0
  505. package/docs/tutorials/20-browser-esm.md +234 -0
  506. package/index.html +1430 -0
  507. package/index.ts +1 -0
  508. package/install.sh +84 -0
  509. package/luca.cli.ts +16 -0
  510. package/luca.console.ts +9 -0
  511. package/main.py +6 -0
  512. package/package.json +219 -58
  513. package/public/index.html +1430 -0
  514. package/public/slides-ai-native.html +902 -0
  515. package/public/slides-intro.html +974 -0
  516. package/pyproject.toml +7 -0
  517. package/scripts/build-web.ts +28 -0
  518. package/scripts/examples/ask-luca-expert.ts +42 -0
  519. package/scripts/examples/assistant-questions.ts +12 -0
  520. package/scripts/examples/excalidraw-expert.ts +75 -0
  521. package/scripts/examples/expert-chat.ts +0 -0
  522. package/scripts/examples/file-manager.ts +14 -0
  523. package/scripts/examples/ideas.ts +12 -0
  524. package/scripts/examples/interactive-chat.ts +20 -0
  525. package/scripts/examples/openai-tool-calls.ts +113 -0
  526. package/scripts/examples/opening-a-web-browser.ts +5 -0
  527. package/scripts/examples/telegram-bot.ts +79 -0
  528. package/scripts/examples/using-assistant-with-mcp.ts +555 -0
  529. package/scripts/examples/using-claude-code.ts +10 -0
  530. package/scripts/examples/using-contentdb.ts +35 -0
  531. package/scripts/examples/using-conversations.ts +35 -0
  532. package/scripts/examples/using-disk-cache.ts +10 -0
  533. package/scripts/examples/using-docker-shell.ts +75 -0
  534. package/scripts/examples/using-elevenlabs.ts +25 -0
  535. package/scripts/examples/using-google-calendar.ts +57 -0
  536. package/scripts/examples/using-google-docs.ts +74 -0
  537. package/scripts/examples/using-google-drive.ts +74 -0
  538. package/scripts/examples/using-google-sheets.ts +89 -0
  539. package/scripts/examples/using-nlp.ts +55 -0
  540. package/scripts/examples/using-ollama.ts +11 -0
  541. package/scripts/examples/using-postgres.ts +55 -0
  542. package/scripts/examples/using-runpod.ts +32 -0
  543. package/scripts/examples/using-tts.ts +40 -0
  544. package/scripts/scaffold.ts +391 -0
  545. package/scripts/scratch.ts +15 -0
  546. package/scripts/stamp-build.sh +12 -0
  547. package/scripts/test-assistant-hooks.ts +13 -0
  548. package/scripts/test-docs-reader.ts +10 -0
  549. package/scripts/test-linux-binary.sh +80 -0
  550. package/scripts/update-introspection-data.ts +58 -0
  551. package/src/agi/README.md +14 -0
  552. package/src/agi/container.server.ts +152 -0
  553. package/src/agi/endpoints/ask.ts +60 -0
  554. package/src/agi/endpoints/conversations/[id].ts +45 -0
  555. package/src/agi/endpoints/conversations.ts +31 -0
  556. package/src/agi/endpoints/experts.ts +37 -0
  557. package/src/agi/feature.ts +13 -0
  558. package/src/agi/features/agent-memory.ts +694 -0
  559. package/src/agi/features/assistant.ts +1624 -0
  560. package/src/agi/features/assistants-manager.ts +418 -0
  561. package/src/agi/features/autonomous-assistant.ts +431 -0
  562. package/src/agi/features/browser-use.ts +653 -0
  563. package/src/agi/features/claude-code.ts +1538 -0
  564. package/src/agi/features/coding-tools.ts +175 -0
  565. package/src/agi/features/conversation-history.ts +495 -0
  566. package/src/agi/features/conversation.ts +1323 -0
  567. package/src/agi/features/docs-reader.ts +167 -0
  568. package/src/agi/features/file-tools.ts +293 -0
  569. package/src/agi/features/luca-coder.ts +639 -0
  570. package/src/agi/features/openai-codex.ts +651 -0
  571. package/src/agi/features/openapi.ts +445 -0
  572. package/src/agi/features/skills-library.ts +478 -0
  573. package/src/agi/index.ts +6 -0
  574. package/src/agi/lib/interceptor-chain.ts +89 -0
  575. package/src/agi/lib/token-counter.ts +122 -0
  576. package/src/bootstrap/generated.ts +9792 -0
  577. package/src/browser.ts +25 -0
  578. package/src/bus.ts +122 -0
  579. package/src/cli/build-info.ts +4 -0
  580. package/src/cli/cli.ts +355 -0
  581. package/src/client.ts +170 -0
  582. package/src/clients/civitai/index.ts +537 -0
  583. package/src/clients/client-template.ts +41 -0
  584. package/src/clients/comfyui/index.ts +604 -0
  585. package/src/clients/elevenlabs/index.ts +317 -0
  586. package/src/clients/graph.ts +87 -0
  587. package/src/clients/openai/index.ts +456 -0
  588. package/src/clients/rest.ts +207 -0
  589. package/src/clients/supabase/index.ts +357 -0
  590. package/src/clients/voicebox/index.ts +300 -0
  591. package/src/clients/websocket.ts +251 -0
  592. package/src/command.ts +505 -0
  593. package/src/commands/bootstrap.ts +244 -0
  594. package/src/commands/chat.ts +308 -0
  595. package/src/commands/code.ts +371 -0
  596. package/src/commands/console.ts +189 -0
  597. package/src/commands/describe.ts +243 -0
  598. package/src/commands/eval.ts +121 -0
  599. package/src/commands/help.ts +240 -0
  600. package/src/commands/index.ts +19 -0
  601. package/src/commands/introspect.ts +218 -0
  602. package/src/commands/mcp.ts +64 -0
  603. package/src/commands/prompt.ts +982 -0
  604. package/src/commands/run.ts +278 -0
  605. package/src/commands/sandbox-mcp.ts +343 -0
  606. package/src/commands/save-api-docs.ts +51 -0
  607. package/src/commands/scaffold.ts +225 -0
  608. package/src/commands/select.ts +99 -0
  609. package/src/commands/serve.ts +208 -0
  610. package/src/container-describer.ts +1084 -0
  611. package/src/container.ts +1186 -0
  612. package/src/endpoint.ts +365 -0
  613. package/src/entity.ts +173 -0
  614. package/src/feature.ts +118 -0
  615. package/src/graft.ts +181 -0
  616. package/src/hash-object.ts +97 -0
  617. package/src/helper.ts +849 -0
  618. package/src/introspection/generated.agi.ts +40208 -0
  619. package/src/introspection/generated.node.ts +28686 -0
  620. package/src/introspection/generated.web.ts +2251 -0
  621. package/src/introspection/index.ts +296 -0
  622. package/src/introspection/scan.ts +1131 -0
  623. package/src/node/container.ts +409 -0
  624. package/src/node/feature.ts +13 -0
  625. package/src/node/features/container-link.ts +559 -0
  626. package/src/node/features/content-db.ts +812 -0
  627. package/src/node/features/disk-cache.ts +388 -0
  628. package/src/node/features/dns.ts +669 -0
  629. package/src/node/features/docker.ts +921 -0
  630. package/src/node/features/downloader.ts +79 -0
  631. package/src/node/features/figlet-fonts.ts +600 -0
  632. package/src/node/features/file-manager.ts +535 -0
  633. package/src/node/features/fs.ts +1050 -0
  634. package/src/node/features/git.ts +592 -0
  635. package/src/node/features/google-auth.ts +504 -0
  636. package/src/node/features/google-calendar.ts +306 -0
  637. package/src/node/features/google-docs.ts +412 -0
  638. package/src/node/features/google-drive.ts +346 -0
  639. package/src/node/features/google-mail.ts +540 -0
  640. package/src/node/features/google-sheets.ts +286 -0
  641. package/src/node/features/grep.ts +427 -0
  642. package/src/node/features/helpers.ts +735 -0
  643. package/src/node/features/ink.ts +490 -0
  644. package/src/node/features/ipc-socket.ts +649 -0
  645. package/src/node/features/json-tree.ts +170 -0
  646. package/src/node/features/networking.ts +961 -0
  647. package/src/node/features/nlp.ts +212 -0
  648. package/src/node/features/opener.ts +180 -0
  649. package/src/node/features/os.ts +403 -0
  650. package/src/node/features/package-finder.ts +540 -0
  651. package/src/node/features/postgres.ts +289 -0
  652. package/src/node/features/proc.ts +503 -0
  653. package/src/node/features/process-manager.ts +844 -0
  654. package/src/node/features/python.ts +906 -0
  655. package/src/node/features/redis.ts +446 -0
  656. package/src/node/features/repl.ts +212 -0
  657. package/src/node/features/runpod.ts +811 -0
  658. package/src/node/features/secure-shell.ts +267 -0
  659. package/src/node/features/semantic-search.ts +935 -0
  660. package/src/node/features/sqlite.ts +289 -0
  661. package/src/node/features/telegram.ts +343 -0
  662. package/src/node/features/transpiler.ts +161 -0
  663. package/src/node/features/tts.ts +185 -0
  664. package/src/node/features/ui.ts +786 -0
  665. package/src/node/features/vault.ts +153 -0
  666. package/src/node/features/vm.ts +462 -0
  667. package/src/node/features/yaml-tree.ts +148 -0
  668. package/src/node/features/yaml.ts +133 -0
  669. package/src/node.ts +76 -0
  670. package/src/python/bridge.py +220 -0
  671. package/src/python/generated.ts +227 -0
  672. package/src/react/index.ts +175 -0
  673. package/src/registry.ts +210 -0
  674. package/src/scaffolds/generated.ts +1815 -0
  675. package/src/scaffolds/template.ts +46 -0
  676. package/src/schemas/base.ts +296 -0
  677. package/src/selector.ts +352 -0
  678. package/src/server.ts +229 -0
  679. package/src/servers/express.ts +283 -0
  680. package/src/servers/mcp.ts +802 -0
  681. package/src/servers/socket.ts +258 -0
  682. package/src/state.ts +101 -0
  683. package/src/web/clients/socket.ts +99 -0
  684. package/src/web/container.ts +75 -0
  685. package/src/web/extension.ts +30 -0
  686. package/src/web/feature.ts +12 -0
  687. package/src/web/features/asset-loader.ts +72 -0
  688. package/src/web/features/container-link.ts +382 -0
  689. package/src/web/features/esbuild.ts +93 -0
  690. package/src/web/features/helpers.ts +269 -0
  691. package/src/web/features/network.ts +85 -0
  692. package/src/web/features/speech.ts +104 -0
  693. package/src/web/features/vault.ts +207 -0
  694. package/src/web/features/vm.ts +85 -0
  695. package/src/web/features/voice-recognition.ts +161 -0
  696. package/src/web/shims/isomorphic-vm.ts +149 -0
  697. package/test/assistant-hooks.test.ts +306 -0
  698. package/test/assistant.test.ts +81 -0
  699. package/test/bus.test.ts +134 -0
  700. package/test/clients-servers.test.ts +217 -0
  701. package/test/command.test.ts +267 -0
  702. package/test/container-link.test.ts +274 -0
  703. package/test/conversation.test.ts +220 -0
  704. package/test/features.test.ts +160 -0
  705. package/test/fork-and-research.test.ts +450 -0
  706. package/test/integration.test.ts +787 -0
  707. package/test/interceptor-chain.test.ts +61 -0
  708. package/test/node-container.test.ts +121 -0
  709. package/test/python-session.test.ts +105 -0
  710. package/test/rate-limit.test.ts +272 -0
  711. package/test/semantic-search.test.ts +550 -0
  712. package/test/state.test.ts +121 -0
  713. package/test/vm-context.test.ts +146 -0
  714. package/test/vm-loadmodule.test.ts +213 -0
  715. package/test/websocket-ask.test.ts +101 -0
  716. package/test-integration/assistant.test.ts +138 -0
  717. package/test-integration/assistants-manager.test.ts +113 -0
  718. package/test-integration/claude-code.test.ts +98 -0
  719. package/test-integration/conversation-history.test.ts +205 -0
  720. package/test-integration/conversation.test.ts +137 -0
  721. package/test-integration/elevenlabs.test.ts +55 -0
  722. package/test-integration/google-services.test.ts +80 -0
  723. package/test-integration/helpers.ts +89 -0
  724. package/test-integration/memory.test.ts +204 -0
  725. package/test-integration/openai-codex.test.ts +93 -0
  726. package/test-integration/runpod.test.ts +58 -0
  727. package/test-integration/server-endpoints.test.ts +97 -0
  728. package/test-integration/telegram.test.ts +46 -0
  729. package/tsconfig.build.json +12 -0
  730. package/tsconfig.json +58 -0
  731. package/uv.lock +8 -0
  732. package/LICENSE +0 -21
  733. package/dist/cli/cli.js +0 -48
  734. package/dist/cli/common.d.ts +0 -2
  735. package/dist/cli/common.js +0 -6
  736. package/dist/cli/index.d.ts +0 -2
  737. package/dist/cli/index.js +0 -5
  738. package/dist/cli/run.d.ts +0 -1
  739. package/dist/cli/run.js +0 -38
  740. package/dist/core/index.d.ts +0 -4
  741. package/dist/core/index.js +0 -32
  742. package/dist/core/read.d.ts +0 -2
  743. package/dist/core/read.js +0 -29
  744. package/dist/core/request.d.ts +0 -1
  745. package/dist/core/request.js +0 -2
  746. package/dist/core/write.d.ts +0 -2
  747. package/dist/core/write.js +0 -21
  748. package/dist/index.d.ts +0 -1
  749. package/dist/index.js +0 -5
  750. package/dist/utils/common.d.ts +0 -9
  751. package/dist/utils/common.js +0 -57
  752. package/dist/utils/consts.d.ts +0 -3
  753. package/dist/utils/consts.js +0 -11
  754. package/dist/utils/dict.d.ts +0 -1
  755. package/dist/utils/dict.js +0 -7
  756. package/dist/utils/index.d.ts +0 -5
  757. package/dist/utils/index.js +0 -21
  758. package/dist/utils/log.d.ts +0 -1
  759. package/dist/utils/log.js +0 -5
  760. package/dist/utils/types.d.ts +0 -1
  761. package/dist/utils/types.js +0 -2
  762. package/dist/utils/utils.test.d.ts +0 -1
  763. package/dist/utils/utils.test.js +0 -7
package/src/helper.ts ADDED
@@ -0,0 +1,849 @@
1
+ import { Bus, type EventMap } from "./bus.js";
2
+ import { type SetStateValue, State } from "./state.js";
3
+ import type { ContainerContext } from './container.js'
4
+ import uuid from 'node-uuid'
5
+ import { get } from 'lodash-es'
6
+ import { introspect, type HelperIntrospection, type IntrospectionSection, type ExampleIntrospection } from "./introspection/index.js";
7
+ import { z } from 'zod'
8
+ import { HelperStateSchema, HelperOptionsSchema, HelperEventsSchema } from './schemas/base.js'
9
+
10
+ export type HelperState = z.infer<typeof HelperStateSchema>
11
+ export type HelperOptions = z.infer<typeof HelperOptionsSchema>
12
+
13
+ /**
14
+ * Helpers are used to represent types of modules.
15
+ *
16
+ * You don't create instances of helpers directly, the container creates instances through
17
+ * factory functions that use the subclasses of Helper as a template. The container
18
+ * provides dependency injection and injects a context object into the Helper constructor.
19
+ *
20
+ * A Helper is something that can be introspected at runtime to learn about the interface.
21
+ *
22
+ * A helper has state.
23
+ *
24
+ * A helper is an event bus.
25
+ *
26
+ * A helper is connected to the container and can access the container's state, events, shared context, or
27
+ * other helpers and features in the container's registry.
28
+ */
29
+ export abstract class Helper<T extends HelperState = HelperState, K extends HelperOptions = any, E extends EventMap = EventMap> {
30
+ static shortcut: string = "unspecified"
31
+
32
+ static description: string = "No description provided"
33
+ static envVars: string[] = []
34
+
35
+ static stateSchema: z.ZodType = HelperStateSchema
36
+ static optionsSchema: z.ZodType = HelperOptionsSchema
37
+ static eventsSchema: z.ZodType = HelperEventsSchema
38
+ static tools: Record<string, { schema: z.ZodType, handler?: Function }> = {}
39
+
40
+ protected readonly _context: ContainerContext
41
+ protected readonly _events = new Bus<E>()
42
+ protected readonly _options: K
43
+ protected readonly _instanceTools: Record<string, { schema: z.ZodType, handler?: Function }> = {}
44
+
45
+ readonly state: State<T>
46
+
47
+ readonly uuid = uuid.v4()
48
+
49
+ get initialState() : T {
50
+ return {} as T
51
+ }
52
+
53
+ static introspect(section?: IntrospectionSection) : HelperIntrospection | undefined {
54
+ const data = introspect((this as any).shortcut || '')
55
+ if (!data || !section) return data
56
+ return filterIntrospection(data, section)
57
+ }
58
+
59
+ static introspectAsText(sectionOrDepth?: IntrospectionSection | number, startHeadingDepth?: number) : string {
60
+ const { section, depth } = resolveIntrospectAsTextArgs(sectionOrDepth, startHeadingDepth)
61
+ const introspection = this.introspect()
62
+ if (!introspection) return ''
63
+ return presentIntrospectionJSONAsMarkdown(introspection, depth, section)
64
+ }
65
+
66
+ /**
67
+ * Returns the introspection data formatted as a TypeScript interface declaration.
68
+ * Useful for AI agents that reason better with structured type information,
69
+ * or for generating `.d.ts` files that accurately describe a helper's public API.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * console.log(container.feature('fs').introspectAsType())
74
+ * // interface FS {
75
+ * // readonly cwd: string;
76
+ * // readFile(path: string): Promise<string>;
77
+ * // ...
78
+ * // }
79
+ * ```
80
+ */
81
+ static introspectAsType(section?: IntrospectionSection) : string {
82
+ const introspection = this.introspect()
83
+ if (!introspection) return ''
84
+ return presentIntrospectionAsTypeScript(introspection, section)
85
+ }
86
+
87
+
88
+ /**
89
+ * All Helpers can be introspect()ed and, assuming the introspection data has been loaded into the registry,
90
+ * will report information about the Helper that can only get extracted by reading the code, e.g. the type interfaces
91
+ * for the helper's options, state, and the events it emits, as well as the documentation from the helpers code for
92
+ * each of the methods and properties.
93
+ *
94
+ * Pass a section name to get only that section: `'methods'`, `'getters'`, `'events'`, `'state'`, `'options'`, `'envVars'`
95
+ */
96
+ introspect(section?: IntrospectionSection) : HelperIntrospection | undefined {
97
+ const base = (this.constructor as any).introspect()
98
+ if (!base || !section) return base
99
+ return filterIntrospection(base, section)
100
+ }
101
+
102
+ /**
103
+ * Returns the introspection data formatted as a markdown string.
104
+ *
105
+ * The first argument can be a section name (`'methods'`, `'getters'`, etc.) to render only
106
+ * that section, or a number for the starting heading depth (backward compatible).
107
+ */
108
+ introspectAsText(sectionOrDepth?: IntrospectionSection | number, startHeadingDepth?: number) : string {
109
+ const { section, depth } = resolveIntrospectAsTextArgs(sectionOrDepth, startHeadingDepth)
110
+ const introspection = this.introspect()
111
+ if (!introspection) return ''
112
+ return presentIntrospectionJSONAsMarkdown(introspection, depth, section)
113
+ }
114
+
115
+ /**
116
+ * Returns the introspection data formatted as a TypeScript interface declaration.
117
+ * Useful for AI agents that reason better with structured type information,
118
+ * or for generating `.d.ts` files that accurately describe a helper's public API.
119
+ */
120
+ introspectAsType(section?: IntrospectionSection) : string {
121
+ const introspection = this.introspect()
122
+ if (!introspection) return ''
123
+ return presentIntrospectionAsTypeScript(introspection, section)
124
+ }
125
+
126
+ constructor(options: K, context: ContainerContext) {
127
+ const optionSchema = (this.constructor as any).optionsSchema
128
+ if (optionSchema && typeof optionSchema.safeParse === 'function') {
129
+ const parsed = optionSchema.safeParse(options || {})
130
+ if (parsed.success) {
131
+ this._options = parsed.data as K
132
+ } else {
133
+ const details = parsed.error.issues.map((issue: any) => `${issue.path?.join('.') || 'options'}: ${issue.message}`).join('; ')
134
+ throw new Error(`Invalid options for ${(this.constructor as any).shortcut || this.constructor.name}: ${details || parsed.error.message}`)
135
+ }
136
+ } else {
137
+ this._options = options
138
+ }
139
+ this._context = context;
140
+ this.state = new State<T>({ initialState: this.initialState });
141
+
142
+ this.hide('_context', '_state', '_options', '_events', '_instanceTools', 'uuid')
143
+
144
+ this.state.observe(() => {
145
+ (this as any).emit('stateChange', this.state.current)
146
+ })
147
+
148
+ this.afterInitialize()
149
+
150
+ this.container.emit('helperInitialized', this)
151
+ }
152
+
153
+ /**
154
+ * Returns the names of the methods for this helper.
155
+ */
156
+ get $methods() : string[] {
157
+ return Object.keys((this.introspect() || {}).methods || [])
158
+ }
159
+
160
+ /**
161
+ * Returns the names of the getters for this helper.
162
+ */
163
+ get $getters() : string[] {
164
+ return Object.keys((this.introspect() || {}).getters || [])
165
+ }
166
+
167
+ /**
168
+ * The static shortcut identifier for this helper type, e.g. "features.assistant".
169
+ */
170
+ get shortcut(): string {
171
+ return (this.constructor as any).shortcut || ''
172
+ }
173
+
174
+ /**
175
+ * Every helper has a cache key which is computed at the time it is created through the container.
176
+ *
177
+ * This ensures only a single instance of the helper exists for the requested options.
178
+ */
179
+ get cacheKey() {
180
+ return this._options._cacheKey
181
+ }
182
+
183
+ /**
184
+ * This method will get called in the constructor and can be used instead of overriding the constructor
185
+ * in your helper subclases.
186
+ */
187
+ afterInitialize() {
188
+ // override this method to do something after the helper is initialized
189
+ }
190
+
191
+ setState(newState: SetStateValue<T>) {
192
+ this.state.setState(newState)
193
+ return this
194
+ }
195
+
196
+ /**
197
+ * Convenience method for putting properties on the helper that aren't enumerable,
198
+ * which is a convenience for the REPL mainly.
199
+ */
200
+ hide(...propNames: string[]) {
201
+ propNames.map((propName) => {
202
+ Object.defineProperty(this, propName, { enumerable: false })
203
+ })
204
+
205
+ return this
206
+ }
207
+
208
+ /**
209
+ * python / lodash style get method, which will get a value from the container using dot notation
210
+ * and will return a default value if the value is not found.
211
+ */
212
+ tryGet<K extends (string | string[]), T extends object = any>(key: K, defaultValue?: T) {
213
+ return get(this, key, defaultValue)
214
+ }
215
+
216
+ /**
217
+ * Register a tool on this instance at runtime. Instance tools take precedence
218
+ * over class-level static tools in toTools().
219
+ */
220
+ tool(name: string, options: { schema: z.ZodType, handler?: Function }): this {
221
+ this._instanceTools[name] = options
222
+ return this
223
+ }
224
+
225
+ /**
226
+ * Called when another helper (e.g. an assistant) consumes this helper's
227
+ * tools via `use()`. Override this to detect the consumer type and react —
228
+ * for example, adding system prompt extensions to an assistant.
229
+ *
230
+ * Use `consumer.shortcut` to identify the consumer type:
231
+ * ```typescript
232
+ * override setupToolsConsumer(consumer: Helper) {
233
+ * if (consumer.shortcut === 'features.assistant') {
234
+ * (consumer as any).addSystemPromptExtension('myFeature', 'usage hints here')
235
+ * }
236
+ * }
237
+ * ```
238
+ *
239
+ * The default implementation is a no-op.
240
+ *
241
+ * @param consumer - The helper instance that is consuming this helper's tools
242
+ */
243
+ setupToolsConsumer(consumer: Helper): void {}
244
+
245
+ /**
246
+ * Collect all tools from the inheritance chain and instance, returning
247
+ * { schemas, handlers } with matching keys. Walks the prototype chain
248
+ * so subclass tools override parent tools. Instance tools win over all.
249
+ *
250
+ * If a tool has no explicit handler but this instance has a method with
251
+ * the same name, a handler is auto-generated that delegates to that method.
252
+ */
253
+ toTools(options?: { only?: string[], except?: string[] }): { schemas: Record<string, z.ZodType>, handlers: Record<string, Function>, setup?: (consumer: Helper) => void } {
254
+ // Walk the prototype chain collecting static tools (parent-first, child overwrites)
255
+ const merged: Record<string, { schema: z.ZodType, description?: string, handler?: Function }> = {}
256
+ const chain: Function[] = []
257
+
258
+ let current = this.constructor as any
259
+ while (current && current !== Object) {
260
+ if (Object.hasOwn(current, 'tools') && current.tools) {
261
+ chain.unshift(current)
262
+ }
263
+ current = Object.getPrototypeOf(current)
264
+ }
265
+
266
+ for (const ctor of chain) {
267
+ Object.assign(merged, (ctor as any).tools)
268
+ }
269
+
270
+ // Instance tools win over static
271
+ Object.assign(merged, this._instanceTools)
272
+
273
+ // Filter tools by only/except before building schemas and handlers
274
+ let names = Object.keys(merged)
275
+ if (options?.only) names = names.filter(n => options.only!.includes(n))
276
+ if (options?.except) names = names.filter(n => !options.except!.includes(n))
277
+
278
+ const schemas: Record<string, z.ZodType> = {}
279
+ const handlers: Record<string, Function> = {}
280
+
281
+ for (const name of names) {
282
+ const entry = merged[name]!
283
+ // If the tool entry has a description but the schema doesn't, attach it
284
+ // so addTool() picks it up from jsonSchema.description.
285
+ schemas[name] = entry.description && !entry.schema.description
286
+ ? entry.schema.describe(entry.description)
287
+ : entry.schema
288
+ if (entry.handler) {
289
+ handlers[name] = (args: any) => entry.handler!(args, this)
290
+ } else if (typeof (this as any)[name] === 'function') {
291
+ handlers[name] = (args: any) => (this as any)[name](args)
292
+ }
293
+ }
294
+
295
+ const result: { schemas: Record<string, z.ZodType>, handlers: Record<string, Function>, setup?: (consumer: Helper) => void } = { schemas, handlers }
296
+
297
+ // If this helper has a setupToolsConsumer override, package it as a setup
298
+ // function so consumers of toTools() can call it without needing the helper ref
299
+ const proto = Object.getPrototypeOf(this)
300
+ if (proto && proto.constructor !== Helper && typeof this.setupToolsConsumer === 'function' && this.setupToolsConsumer !== Helper.prototype.setupToolsConsumer) {
301
+ result.setup = (consumer: Helper) => this.setupToolsConsumer(consumer)
302
+ }
303
+
304
+ return result
305
+ }
306
+
307
+ /**
308
+ * The options passed to the helper when it was created.
309
+ */
310
+ get options() {
311
+ return this._options;
312
+ }
313
+
314
+ /**
315
+ * The context object that was passed to the helper when it was created, this is decided by the container
316
+ * and not something you would manipulate.
317
+ */
318
+ get context() {
319
+ return this._context;
320
+ }
321
+
322
+ /**
323
+ * The container that the helper is connected to.
324
+ */
325
+ get container() {
326
+ return this.context.container;
327
+ }
328
+
329
+ emit<Ev extends string & keyof E>(event: Ev, ...args: E[Ev]) {
330
+ this._events.emit(event, ...args)
331
+ return this
332
+ }
333
+
334
+ on(event: '*', listener: (event: string, ...args: any[]) => void): this
335
+ on<Ev extends string & keyof E>(event: Ev, listener: (...args: E[Ev]) => void): this
336
+ on<Ev extends string & keyof E>(event: Ev | '*', listener: any) {
337
+ this._events.on(event as any, listener)
338
+ return this
339
+ }
340
+
341
+ off(event: '*', listener?: (event: string, ...args: any[]) => void): this
342
+ off<Ev extends string & keyof E>(event: Ev, listener?: (...args: E[Ev]) => void): this
343
+ off<Ev extends string & keyof E>(event: Ev | '*', listener?: any) {
344
+ this._events.off(event as any, listener)
345
+ return this
346
+ }
347
+
348
+ once<Ev extends string & keyof E>(event: Ev, listener: (...args: E[Ev]) => void) {
349
+ this._events.once(event, listener)
350
+ return this
351
+ }
352
+
353
+ async waitFor<Ev extends string & keyof E>(event: Ev) {
354
+ const resp = await this._events.waitFor(event)
355
+ return resp
356
+ }
357
+ }
358
+
359
+ const INTROSPECTION_SECTIONS: IntrospectionSection[] = ['methods', 'getters', 'events', 'state', 'options', 'envVars', 'examples', 'usage']
360
+
361
+ function filterIntrospection(data: HelperIntrospection, section: IntrospectionSection): HelperIntrospection {
362
+ const filtered: HelperIntrospection = {
363
+ id: data.id,
364
+ description: data.description,
365
+ shortcut: data.shortcut,
366
+ methods: {},
367
+ getters: {},
368
+ events: {},
369
+ state: {},
370
+ options: {},
371
+ envVars: [],
372
+ }
373
+
374
+ if (section === 'examples') {
375
+ // For examples section, include class-level examples and full methods/getters (they carry inline examples)
376
+ filtered.examples = data.examples
377
+ filtered.methods = data.methods
378
+ filtered.getters = data.getters
379
+ } else if (section === 'usage') {
380
+ // Usage is derived from options + shortcut, so pass those through
381
+ filtered.options = data.options
382
+ } else {
383
+ filtered[section] = data[section] as any
384
+ }
385
+
386
+ return filtered
387
+ }
388
+
389
+ function resolveIntrospectAsTextArgs(sectionOrDepth?: IntrospectionSection | number, startHeadingDepth?: number) {
390
+ let section: IntrospectionSection | undefined
391
+ let depth = 1
392
+
393
+ if (typeof sectionOrDepth === 'string') {
394
+ section = sectionOrDepth
395
+ depth = startHeadingDepth ?? 1
396
+ } else if (typeof sectionOrDepth === 'number') {
397
+ depth = sectionOrDepth
398
+ }
399
+
400
+ return { section, depth }
401
+ }
402
+
403
+ function renderMethodsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
404
+ const sections: string[] = []
405
+ if (!introspection.methods || Object.keys(introspection.methods).length === 0) return sections
406
+
407
+ sections.push(`${heading(2)} Methods`)
408
+
409
+ for (const [methodName, methodInfo] of Object.entries(introspection.methods)) {
410
+ sections.push(`${heading(3)} ${methodName}`)
411
+
412
+ if (methodInfo.description) {
413
+ sections.push(methodInfo.description)
414
+ }
415
+
416
+ if (methodInfo.parameters && Object.keys(methodInfo.parameters).length > 0) {
417
+ const tableRows = [
418
+ `**Parameters:**`,
419
+ '',
420
+ `| Name | Type | Required | Description |`,
421
+ `|------|------|----------|-------------|`,
422
+ ]
423
+
424
+ for (const [paramName, paramInfo] of Object.entries(methodInfo.parameters)) {
425
+ const isRequired = methodInfo.required?.includes(paramName) ? '✓' : ''
426
+ const type = paramInfo.type || 'any'
427
+ const description = paramInfo.description || ''
428
+ tableRows.push(`| \`${paramName}\` | \`${type}\` | ${isRequired} | ${description} |`)
429
+
430
+ // Render expanded type properties if available
431
+ if (paramInfo.properties && Object.keys(paramInfo.properties).length > 0) {
432
+ tableRows.push('')
433
+ tableRows.push(`\`${type}\` properties:`)
434
+ tableRows.push('')
435
+ tableRows.push(`| Property | Type | Description |`)
436
+ tableRows.push(`|----------|------|-------------|`)
437
+
438
+ for (const [propName, propInfo] of Object.entries(paramInfo.properties)) {
439
+ tableRows.push(`| \`${propName}\` | \`${propInfo.type || 'any'}\` | ${propInfo.description || ''} |`)
440
+ }
441
+ }
442
+ }
443
+ sections.push(tableRows.join('\n'))
444
+ }
445
+
446
+ if (methodInfo.returns) {
447
+ sections.push(`**Returns:** \`${methodInfo.returns}\``)
448
+ }
449
+
450
+ if (methodInfo.examples && methodInfo.examples.length > 0) {
451
+ for (const example of methodInfo.examples) {
452
+ sections.push(`\`\`\`${normalizeLang(example.language)}\n${example.code}\n\`\`\``)
453
+ }
454
+ }
455
+
456
+ sections.push('')
457
+ }
458
+
459
+ return sections
460
+ }
461
+
462
+ function renderGettersSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
463
+ const sections: string[] = []
464
+ if (!introspection.getters || Object.keys(introspection.getters).length === 0) return sections
465
+
466
+ const tableRows = [
467
+ `${heading(2)} Getters`,
468
+ '',
469
+ `| Property | Type | Description |`,
470
+ `|----------|------|-------------|`,
471
+ ]
472
+
473
+ for (const [getterName, getterInfo] of Object.entries(introspection.getters)) {
474
+ const type = getterInfo.returns || 'any'
475
+ const description = getterInfo.description || ''
476
+ tableRows.push(`| \`${getterName}\` | \`${type}\` | ${description} |`)
477
+ }
478
+ sections.push(tableRows.join('\n'))
479
+
480
+ return sections
481
+ }
482
+
483
+ function renderEventsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
484
+ const sections: string[] = []
485
+ if (!introspection.events || Object.keys(introspection.events).length === 0) return sections
486
+
487
+ sections.push(`${heading(2)} Events (Zod v4 schema)`)
488
+
489
+ for (const [eventName, eventInfo] of Object.entries(introspection.events)) {
490
+ sections.push(`${heading(3)} ${eventName}`)
491
+
492
+ if (eventInfo.description) {
493
+ sections.push(eventInfo.description)
494
+ }
495
+
496
+ if (eventInfo.arguments && Object.keys(eventInfo.arguments).length > 0) {
497
+ const tableRows = [
498
+ `**Event Arguments:**`,
499
+ '',
500
+ `| Name | Type | Description |`,
501
+ `|------|------|-------------|`,
502
+ ]
503
+
504
+ for (const [argName, argInfo] of Object.entries(eventInfo.arguments)) {
505
+ tableRows.push(`| \`${argName}\` | \`${argInfo.type || 'any'}\` | ${argInfo.description || ''} |`)
506
+ }
507
+ sections.push(tableRows.join('\n'))
508
+ }
509
+
510
+ sections.push('')
511
+ }
512
+
513
+ return sections
514
+ }
515
+
516
+ function renderStateSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
517
+ const sections: string[] = []
518
+ if (!introspection.state || Object.keys(introspection.state).length === 0) return sections
519
+
520
+ const tableRows = [
521
+ `${heading(2)} State (Zod v4 schema)`,
522
+ '',
523
+ `| Property | Type | Description |`,
524
+ `|----------|------|-------------|`,
525
+ ]
526
+
527
+ for (const [stateName, stateInfo] of Object.entries(introspection.state)) {
528
+ tableRows.push(`| \`${stateName}\` | \`${stateInfo.type || 'any'}\` | ${stateInfo.description || ''} |`)
529
+ }
530
+ sections.push(tableRows.join('\n'))
531
+
532
+ return sections
533
+ }
534
+
535
+ function renderOptionsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
536
+ const sections: string[] = []
537
+ if (!introspection.options || Object.keys(introspection.options).length === 0) return sections
538
+
539
+ const tableRows = [
540
+ `${heading(2)} Options (Zod v4 schema)`,
541
+ '',
542
+ `| Property | Type | Description |`,
543
+ `|----------|------|-------------|`,
544
+ ]
545
+
546
+ for (const [optName, optInfo] of Object.entries(introspection.options)) {
547
+ tableRows.push(`| \`${optName}\` | \`${optInfo.type || 'any'}\` | ${optInfo.description || ''} |`)
548
+ }
549
+ sections.push(tableRows.join('\n'))
550
+
551
+ return sections
552
+ }
553
+
554
+ function renderUsageSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
555
+ const sections: string[] = []
556
+
557
+ // Derive the factory method from the shortcut, e.g. "features.diskCache" -> container.feature('diskCache', { ... })
558
+ const shortcut = introspection.shortcut || introspection.id || ''
559
+ const parts = shortcut.split('.')
560
+ if (parts.length < 2) return sections
561
+
562
+ const scope = parts[0]! // e.g. "features"
563
+ const name = parts.slice(1).join('.') // e.g. "diskCache"
564
+ // Singular form: features -> feature, clients -> client, servers -> server, commands -> command, endpoints -> endpoint
565
+ const factoryMethod = scope.endsWith('s') ? scope.slice(0, -1) : scope
566
+
567
+ const options = introspection.options || {}
568
+ const optionEntries = Object.entries(options)
569
+
570
+ sections.push(`${heading(2)} Usage`)
571
+
572
+ if (optionEntries.length === 0) {
573
+ sections.push(`\`\`\`ts\ncontainer.${factoryMethod}('${name}')\n\`\`\``)
574
+ } else {
575
+ const optionLines = optionEntries.map(([optName, optInfo]) => {
576
+ const desc = optInfo.description ? `// ${optInfo.description}` : ''
577
+ return ` ${desc}\n ${optName},`
578
+ }).join('\n')
579
+
580
+ sections.push(`\`\`\`ts\ncontainer.${factoryMethod}('${name}', {\n${optionLines}\n})\n\`\`\``)
581
+ }
582
+
583
+ return sections
584
+ }
585
+
586
+ function renderEnvVarsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
587
+ const sections: string[] = []
588
+ if (!introspection.envVars || introspection.envVars.length === 0) return sections
589
+
590
+ sections.push(`${heading(2)} Environment Variables`)
591
+ sections.push(introspection.envVars.map((envVar) => `- \`${envVar}\``).join('\n'))
592
+
593
+ return sections
594
+ }
595
+
596
+ function renderExamplesSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
597
+ const sections: string[] = []
598
+
599
+ // Collect all examples: class-level, method-level, getter-level
600
+ const allExamples: { source: string; examples: ExampleIntrospection[] }[] = []
601
+
602
+ if (introspection.examples && introspection.examples.length > 0) {
603
+ allExamples.push({ source: introspection.id, examples: introspection.examples })
604
+ }
605
+
606
+ for (const [name, method] of Object.entries(introspection.methods || {})) {
607
+ if (method.examples && method.examples.length > 0) {
608
+ allExamples.push({ source: name, examples: method.examples })
609
+ }
610
+ }
611
+
612
+ for (const [name, getter] of Object.entries(introspection.getters || {})) {
613
+ if (getter.examples && getter.examples.length > 0) {
614
+ allExamples.push({ source: name, examples: getter.examples })
615
+ }
616
+ }
617
+
618
+ if (allExamples.length === 0) return sections
619
+
620
+ sections.push(`${heading(2)} Examples`)
621
+
622
+ for (const { source, examples } of allExamples) {
623
+ sections.push(`**${source}**`)
624
+ for (const example of examples) {
625
+ sections.push(`\`\`\`${normalizeLang(example.language)}\n${example.code}\n\`\`\``)
626
+ }
627
+ sections.push('')
628
+ }
629
+
630
+ return sections
631
+ }
632
+
633
+ /** Normalize verbose language names to short tags for code fences */
634
+ function normalizeLang(lang: string): string {
635
+ if (lang === 'typescript') return 'ts'
636
+ if (lang === 'javascript') return 'js'
637
+ return lang
638
+ }
639
+
640
+ export { presentIntrospectionJSONAsMarkdown as presentIntrospectionAsMarkdown }
641
+ export { presentIntrospectionAsTypeScript, renderTypeScriptParams, normalizeTypeString, isGenericObjectType }
642
+
643
+ function presentIntrospectionJSONAsMarkdown(introspection: HelperIntrospection, startHeadingDepth: number = 1, section?: IntrospectionSection) {
644
+ const sections: string[] = []
645
+ const heading = (level: number) => '#'.repeat(Math.max(1, startHeadingDepth + level - 1))
646
+
647
+ if (!section) {
648
+ const title = introspection.className
649
+ ? `${heading(1)} ${introspection.className} (${introspection.id})`
650
+ : `${heading(1)} ${introspection.id}`
651
+ sections.push(`${title}\n\n${introspection.description}`)
652
+ }
653
+
654
+ const renderers: Record<IntrospectionSection, () => string[]> = {
655
+ usage: () => renderUsageSection(introspection, heading),
656
+ options: () => renderOptionsSection(introspection, heading),
657
+ methods: () => renderMethodsSection(introspection, heading),
658
+ getters: () => renderGettersSection(introspection, heading),
659
+ events: () => renderEventsSection(introspection, heading),
660
+ state: () => renderStateSection(introspection, heading),
661
+ envVars: () => renderEnvVarsSection(introspection, heading),
662
+ examples: () => renderExamplesSection(introspection, heading),
663
+ }
664
+
665
+ if (section) {
666
+ sections.push(...renderers[section]())
667
+ } else {
668
+ for (const renderer of Object.values(renderers)) {
669
+ sections.push(...renderer())
670
+ }
671
+ }
672
+
673
+ return sections.join('\n\n')
674
+ }
675
+
676
+ /**
677
+ * Renders introspection data as a TypeScript interface declaration.
678
+ * Produces a valid interface string that describes the helper's public API —
679
+ * getters, methods, state shape, options shape, and event listener signatures.
680
+ */
681
+ function presentIntrospectionAsTypeScript(introspection: HelperIntrospection, section?: IntrospectionSection): string {
682
+ const interfaceName = introspection.className || introspection.id.split('.').pop() || 'Unknown'
683
+ const members: string[] = []
684
+
685
+ const shouldRender = (s: IntrospectionSection) => !section || section === s
686
+
687
+ // Getters
688
+ if (shouldRender('getters') && introspection.getters && Object.keys(introspection.getters).length > 0) {
689
+ for (const [name, info] of Object.entries(introspection.getters)) {
690
+ const returnType = normalizeTypeString(info.returns || 'any')
691
+ if (info.description) {
692
+ members.push(` /** ${info.description} */`)
693
+ }
694
+ members.push(` readonly ${name}: ${returnType};`)
695
+ }
696
+ }
697
+
698
+ // Methods
699
+ if (shouldRender('methods') && introspection.methods && Object.keys(introspection.methods).length > 0) {
700
+ if (members.length > 0) members.push('')
701
+ for (const [name, info] of Object.entries(introspection.methods)) {
702
+ if (info.description) {
703
+ members.push(` /** ${info.description} */`)
704
+ }
705
+ const params = renderTypeScriptParams(info)
706
+ const returnType = normalizeTypeString(info.returns || 'void')
707
+ members.push(` ${name}(${params}): ${returnType};`)
708
+ }
709
+ }
710
+
711
+ // State — render as the observable State<T> object, not just currentState
712
+ if (shouldRender('state') && introspection.state && Object.keys(introspection.state).length > 0) {
713
+ if (members.length > 0) members.push('')
714
+ const stateMembers = Object.entries(introspection.state)
715
+ .map(([name, info]) => {
716
+ const comment = info.description ? ` /** ${info.description} */\n` : ''
717
+ return `${comment} ${name}: ${normalizeTypeString(info.type || 'any')};`
718
+ })
719
+ .join('\n')
720
+ const stateShape = `{\n${stateMembers}\n }`
721
+ members.push(` state: {`)
722
+ members.push(` /** The current version number, incremented on each change */`)
723
+ members.push(` readonly version: number;`)
724
+ members.push(` /** Get the value of a state key */`)
725
+ members.push(` get<K extends keyof T>(key: K): T[K] | undefined;`)
726
+ members.push(` /** Set a state key to a new value, notifying observers */`)
727
+ members.push(` set<K extends keyof T>(key: K, value: T[K]): this;`)
728
+ members.push(` /** Delete a state key, notifying observers */`)
729
+ members.push(` delete<K extends keyof T>(key: K): this;`)
730
+ members.push(` /** Check if a state key exists */`)
731
+ members.push(` has<K extends keyof T>(key: K): boolean;`)
732
+ members.push(` /** Get all state keys */`)
733
+ members.push(` keys(): string[];`)
734
+ members.push(` /** Get the current state snapshot */`)
735
+ members.push(` readonly current: ${stateShape};`)
736
+ members.push(` /** Get all entries as [key, value] pairs */`)
737
+ members.push(` entries(): [string, any][];`)
738
+ members.push(` /** Get all state values */`)
739
+ members.push(` values(): any[];`)
740
+ members.push(` /** Register an observer callback for state changes. Returns an unsubscribe function. */`)
741
+ members.push(` observe(callback: (changeType: 'add' | 'update' | 'delete', key: string, value?: any) => void): () => void;`)
742
+ members.push(` /** Merge partial state, notifying observers for each changed key */`)
743
+ members.push(` setState(value: Partial<${stateShape}> | ((current: ${stateShape}, state: this) => Partial<${stateShape}>)): void;`)
744
+ members.push(` /** Clear all state, notifying observers */`)
745
+ members.push(` clear(): void;`)
746
+ members.push(` };`)
747
+ }
748
+
749
+ // Options
750
+ if (shouldRender('options') && introspection.options && Object.keys(introspection.options).length > 0) {
751
+ if (members.length > 0) members.push('')
752
+ const optionMembers = Object.entries(introspection.options)
753
+ .map(([name, info]) => {
754
+ const comment = info.description ? ` /** ${info.description} */\n` : ''
755
+ return `${comment} ${name}?: ${normalizeTypeString(info.type || 'any')};`
756
+ })
757
+ .join('\n')
758
+ members.push(` options: {\n${optionMembers}\n };`)
759
+ }
760
+
761
+ // Events — rendered as on() overloads
762
+ if (shouldRender('events') && introspection.events && Object.keys(introspection.events).length > 0) {
763
+ if (members.length > 0) members.push('')
764
+ for (const [eventName, eventInfo] of Object.entries(introspection.events)) {
765
+ const args = Object.entries(eventInfo.arguments || {})
766
+ const listenerParams = args.length > 0
767
+ ? args.map(([argName, argInfo]) => `${argName}: ${normalizeTypeString(argInfo.type || 'any')}`).join(', ')
768
+ : ''
769
+ if (eventInfo.description) {
770
+ members.push(` /** ${eventInfo.description} */`)
771
+ }
772
+ members.push(` on(event: '${eventName}', listener: (${listenerParams}) => void): this;`)
773
+ }
774
+ }
775
+
776
+ const description = introspection.description
777
+ ? `/**\n * ${introspection.description.split('\n').join('\n * ')}\n */\n`
778
+ : ''
779
+
780
+ const mainInterface = `${description}interface ${interfaceName} {\n${members.join('\n')}\n}`
781
+
782
+ // Emit referenced type declarations above the main interface
783
+ const types = introspection.types
784
+ if (types && Object.keys(types).length > 0) {
785
+ const typeDeclarations = Object.entries(types).map(([typeName, typeInfo]) => {
786
+ const typeDesc = typeInfo.description
787
+ ? `/**\n * ${typeInfo.description.split('\n').join('\n * ')}\n */\n`
788
+ : ''
789
+ const props = Object.entries(typeInfo.properties)
790
+ .map(([propName, propInfo]) => {
791
+ const comment = propInfo.description ? ` /** ${propInfo.description} */\n` : ''
792
+ const opt = propInfo.optional ? '?' : ''
793
+ return `${comment} ${propName}${opt}: ${normalizeTypeString(propInfo.type || 'any')};`
794
+ })
795
+ .join('\n')
796
+ return `${typeDesc}interface ${typeName} {\n${props}\n}`
797
+ })
798
+
799
+ return typeDeclarations.join('\n\n') + '\n\n' + mainInterface
800
+ }
801
+
802
+ return mainInterface
803
+ }
804
+
805
+ /** Build a TypeScript parameter list string from method introspection */
806
+ function renderTypeScriptParams(method: { parameters: Record<string, { type: string, description?: string, properties?: Record<string, { type: string, description?: string }> }>, required: string[] }): string {
807
+ const entries = Object.entries(method.parameters || {})
808
+ if (entries.length === 0) return ''
809
+
810
+ return entries.map(([name, info]) => {
811
+ const isRequired = (method.required || []).includes(name)
812
+ let type = normalizeTypeString(info.type || 'any')
813
+
814
+ // If the parameter has expanded sub-properties but a generic type string,
815
+ // render an inline object type from those properties instead
816
+ if (info.properties && Object.keys(info.properties).length > 0 && isGenericObjectType(type)) {
817
+ const props = Object.entries(info.properties)
818
+ .map(([propName, propInfo]) => `${propName}?: ${normalizeTypeString(propInfo.type || 'any')}`)
819
+ .join('; ')
820
+ type = `{ ${props} }`
821
+ }
822
+
823
+ return `${name}${isRequired ? '' : '?'}: ${type}`
824
+ }).join(', ')
825
+ }
826
+
827
+ /** Returns true if the type string looks like a generic object type that sub-properties would refine */
828
+ function isGenericObjectType(type: string): boolean {
829
+ const lower = type.toLowerCase()
830
+ return lower === 'object' || lower === 'any' || lower === 'record<string, any>' || lower === '{}'
831
+ }
832
+
833
+ /** Clean up type strings from introspection data for use in interface declarations */
834
+ function normalizeTypeString(type: string): string {
835
+ if (!type) return 'any'
836
+ // The AST scanner sometimes wraps types in quotes
837
+ type = type.replace(/^["']|["']$/g, '')
838
+ // Convert internal ReturnType<typeof this.container.feature<'name'>> to a clean import reference
839
+ // e.g. ReturnType<typeof this.container.feature<'proc'>> → import('luca').Proc
840
+ type = type.replace(
841
+ /ReturnType<typeof this\.container\.(feature|client|server)<'([^']+)'>>/g,
842
+ (_match, _kind, name) => {
843
+ // Convert shortcut name to PascalCase class name
844
+ const className = name.replace(/(^|[-_])(\w)/g, (_: string, _sep: string, ch: string) => ch.toUpperCase())
845
+ return `import('@soederpop/luca').${className}`
846
+ }
847
+ )
848
+ return type
849
+ }