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
@@ -0,0 +1,1084 @@
1
+ import type { IntrospectionSection, MethodIntrospection, GetterIntrospection, HelperIntrospection } from './introspection/index.js'
2
+ import { presentIntrospectionAsMarkdown } from './helper.js'
3
+ import { z } from 'zod'
4
+
5
+ type Platform = 'browser' | 'server' | 'node' | 'all'
6
+
7
+ type ResolvedTarget =
8
+ | { kind: 'container' }
9
+ | { kind: 'registry'; name: string }
10
+ | { kind: 'helper'; registry: string; id: string }
11
+ | { kind: 'member'; registry: string; id: string; member: string; memberType: 'method' | 'getter' }
12
+ | { kind: 'browser-helper'; id: string }
13
+ | { kind: 'browser-member'; id: string; member: string; memberType: 'method' | 'getter' }
14
+
15
+ type DescribeOptions = {
16
+ sections?: (IntrospectionSection | 'description')[]
17
+ noTitle?: boolean
18
+ headingDepth?: number
19
+ platform?: Platform
20
+ }
21
+
22
+ type DescribeResult = { json: any; text: string }
23
+
24
+ type BrowserFeatureData = {
25
+ introspection: Map<string, HelperIntrospection>
26
+ constructors: Map<string, any>
27
+ available: string[]
28
+ collidingIds: Set<string>
29
+ }
30
+
31
+ class DescribeError extends Error {
32
+ constructor(message: string) {
33
+ super(message)
34
+ this.name = 'DescribeError'
35
+ }
36
+ }
37
+
38
+ /** Known top-level helper base class names — anything above these is "shared" */
39
+ const BASE_CLASS_NAMES = new Set(['Helper', 'Feature', 'Client', 'Server'])
40
+
41
+ /** Maps flag names to the section they represent. */
42
+ const SECTION_FLAGS: Record<string, IntrospectionSection | 'description'> = {
43
+ 'description': 'description',
44
+ 'usage': 'usage',
45
+ 'methods': 'methods',
46
+ 'getters': 'getters',
47
+ 'events': 'events',
48
+ 'state': 'state',
49
+ 'options': 'options',
50
+ 'env-vars': 'envVars',
51
+ 'envvars': 'envVars',
52
+ 'examples': 'examples',
53
+ 'only-methods': 'methods',
54
+ 'only-getters': 'getters',
55
+ 'only-events': 'events',
56
+ 'only-state': 'state',
57
+ 'only-options': 'options',
58
+ 'only-env-vars': 'envVars',
59
+ 'only-envvars': 'envVars',
60
+ 'only-examples': 'examples',
61
+ }
62
+
63
+ /**
64
+ * Encapsulates container introspection and description logic.
65
+ * Discovers registries dynamically from the container's own state —
66
+ * it knows nothing about which helpers exist until it asks the container.
67
+ * Browser feature data can be injected externally via setBrowserData().
68
+ */
69
+ export class ContainerDescriber {
70
+ container: any
71
+ private _browserData: BrowserFeatureData | null = null
72
+ private _initialized = false
73
+
74
+ constructor(container: any) {
75
+ this.container = container
76
+ }
77
+
78
+ /** The registry names this container actually has, discovered at runtime. */
79
+ private get registryNames(): string[] {
80
+ return this.container.registryNames || ['features']
81
+ }
82
+
83
+ /**
84
+ * Discover all helpers. Must be called before resolve/getData.
85
+ */
86
+ async initialize(): Promise<void> {
87
+ if (this._initialized) return
88
+ await this.container.helpers.discoverAll()
89
+ this._initialized = true
90
+ }
91
+
92
+ /**
93
+ * Inject browser feature data from an external source.
94
+ * The describer doesn't own browser loading — that's the caller's job.
95
+ */
96
+ setBrowserData(data: BrowserFeatureData): void {
97
+ this._browserData = data
98
+ }
99
+
100
+ /**
101
+ * High-level: describe one or more targets, returning combined json and text.
102
+ */
103
+ async describe(targets: string[], options: DescribeOptions = {}): Promise<DescribeResult> {
104
+ const platform = this.normalizePlatform(options.platform || 'all')
105
+ await this.initialize()
106
+
107
+ const sections = options.sections || []
108
+ const noTitle = options.noTitle || false
109
+
110
+ const resolved: ResolvedTarget[] = []
111
+ for (const target of targets) {
112
+ resolved.push(...this.resolve(target, platform))
113
+ }
114
+
115
+ const isMulti = resolved.length > 1 || resolved.some((r) => r.kind === 'registry')
116
+ const headingDepth = options.headingDepth ?? (isMulti ? 2 : 1)
117
+
118
+ const results = resolved.map((item) => this.getData(item, { sections, noTitle, headingDepth, platform }))
119
+
120
+ if (resolved.length === 1) {
121
+ return results[0]!
122
+ }
123
+
124
+ return {
125
+ json: results.map((r) => r.json),
126
+ text: `# Luca Helper Descriptions\n\nBelow you'll find documentation.\n\n${results.map((r) => r.text).join('\n\n---\n\n')}`,
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Describe the container itself.
132
+ */
133
+ async describeContainer(options: DescribeOptions = {}): Promise<DescribeResult> {
134
+ await this.initialize()
135
+ return this.getContainerData(options.sections || [], options.noTitle || false, options.headingDepth || 1)
136
+ }
137
+
138
+ /**
139
+ * Describe a registry by name.
140
+ */
141
+ async describeRegistry(registryName: string, options: DescribeOptions = {}): Promise<DescribeResult> {
142
+ const platform = this.normalizePlatform(options.platform || 'all')
143
+ await this.initialize()
144
+ const name = this.matchRegistryName(registryName)
145
+ if (!name) throw new DescribeError(`Unknown registry: ${registryName}. Available: ${this.registryNames.join(', ')}`)
146
+ return this.getRegistryData(name, options.sections || [], options.noTitle || false, options.headingDepth || 1, platform)
147
+ }
148
+
149
+ /**
150
+ * Describe a specific helper by name (qualified or unqualified).
151
+ */
152
+ async describeHelper(target: string, options: DescribeOptions = {}): Promise<DescribeResult> {
153
+ const platform = this.normalizePlatform(options.platform || 'all')
154
+ await this.initialize()
155
+
156
+ const resolved = this.resolve(target, platform)
157
+ if (resolved.length === 0) throw new DescribeError(`Could not resolve: ${target}`)
158
+
159
+ const headingDepth = options.headingDepth ?? (resolved.length > 1 ? 2 : 1)
160
+ const results = resolved.map((item) => this.getData(item, { ...options, headingDepth, platform }))
161
+
162
+ if (results.length === 1) return results[0]!
163
+ return {
164
+ json: results.map((r) => r.json),
165
+ text: results.map((r) => r.text).join('\n\n---\n\n'),
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Describe a specific member (method or getter) on a helper.
171
+ */
172
+ async describeMember(helperAndMember: string, options: DescribeOptions = {}): Promise<DescribeResult> {
173
+ return this.describeHelper(helperAndMember, options)
174
+ }
175
+
176
+ /**
177
+ * Collect sections from a flags object (as produced by the CLI args schema).
178
+ */
179
+ static getSectionsFromFlags(flags: Record<string, any>): (IntrospectionSection | 'description')[] {
180
+ const sections: (IntrospectionSection | 'description')[] = []
181
+ for (const [flag, section] of Object.entries(SECTION_FLAGS)) {
182
+ if (flags[flag] && !sections.includes(section)) {
183
+ sections.push(section)
184
+ }
185
+ }
186
+ return sections
187
+ }
188
+
189
+ /**
190
+ * Generate tool definitions suitable for use with AI assistant tool-calling interfaces.
191
+ * Registry names in the enum are populated dynamically from the container.
192
+ */
193
+ toTools(): { schemas: Record<string, z.ZodType>; handlers: Record<string, Function> } {
194
+ const registryEnum = this.registryNames as [string, ...string[]]
195
+ const sectionEnum = ['description', 'usage', 'methods', 'getters', 'events', 'state', 'options', 'envVars', 'examples'] as const
196
+ const platformEnum = ['browser', 'server', 'all'] as const
197
+
198
+ const schemas: Record<string, z.ZodType> = {
199
+ describe_container: z.object({
200
+ sections: z.array(z.enum(sectionEnum)).optional().describe('Which sections to include. Omit for all.'),
201
+ }).describe('Describe the container itself — its class, registries, and configuration.'),
202
+
203
+ describe_registry: z.object({
204
+ registry: z.enum(registryEnum).describe(`Which registry to describe. Available: ${registryEnum.join(', ')}`),
205
+ platform: z.enum(platformEnum).optional().describe('Filter by platform. Defaults to all.'),
206
+ sections: z.array(z.enum(sectionEnum)).optional().describe('Which sections to include per helper. Omit for concise index.'),
207
+ }).describe(`List all helpers in a registry with concise summaries. Available registries: ${registryEnum.join(', ')}`),
208
+
209
+ describe_helper: z.object({
210
+ target: z.string().describe('The helper to describe. Examples: "fs", "features.fs", "fs.readFile", "ui.banner"'),
211
+ platform: z.enum(platformEnum).optional().describe('Filter by platform. Defaults to all.'),
212
+ sections: z.array(z.enum(sectionEnum)).optional().describe('Which sections to include. Omit for all.'),
213
+ }).describe('Describe a specific helper by name. Supports qualified names like "features.fs" or unqualified like "fs". Also supports member access like "fs.readFile" or "ui.banner".'),
214
+ }
215
+
216
+ const handlers: Record<string, Function> = {
217
+ describe_container: async (args: any) => {
218
+ const result = await this.describeContainer({ sections: args.sections })
219
+ return result.text
220
+ },
221
+ describe_registry: async (args: any) => {
222
+ const result = await this.describeRegistry(args.registry, {
223
+ sections: args.sections,
224
+ platform: args.platform,
225
+ })
226
+ return result.text
227
+ },
228
+ describe_helper: async (args: any) => {
229
+ const result = await this.describeHelper(args.target, {
230
+ sections: args.sections,
231
+ platform: args.platform,
232
+ })
233
+ return result.text
234
+ },
235
+ }
236
+
237
+ return { schemas, handlers }
238
+ }
239
+
240
+ /**
241
+ * Register the describer tools on an assistant and append a system prompt
242
+ * extension explaining how and when to use them.
243
+ *
244
+ * @param assistant - Any assistant instance that exposes `use()` and `addSystemPromptExtension()`
245
+ */
246
+ setupToolsConsumer(assistant: {
247
+ use: (tools: { schemas: Record<string, z.ZodType>; handlers: Record<string, Function> }) => void
248
+ addSystemPromptExtension: (key: string, value: string) => void
249
+ }): void {
250
+ assistant.use(this.toTools())
251
+
252
+ const registries = this.registryNames.join(', ')
253
+
254
+ assistant.addSystemPromptExtension('container_describer', `
255
+ ## Container Introspection Tools
256
+
257
+ You have access to three tools for exploring the runtime container and its helpers:
258
+
259
+ - **describe_container** — Overview of the container itself: its registries, configuration, and what it provides.
260
+ - **describe_registry** — List all helpers in a registry with concise summaries. Available registries: ${registries}.
261
+ - **describe_helper** — Full docs for a specific helper. Accepts unqualified names ("fs"), registry-qualified names ("features.fs"), or member access ("fs.readFile", "ui.banner").
262
+
263
+ Use these tools whenever you are unsure what helpers are available, what a helper does, or how to call one of its methods. Always prefer introspecting the container over guessing at method signatures.
264
+ `.trim())
265
+ }
266
+
267
+ // --- Resolution ---
268
+
269
+ /**
270
+ * Parse a target string into one or more resolved targets.
271
+ */
272
+ resolve(target: string, platform: Platform = 'all'): ResolvedTarget[] {
273
+ const lower = target.toLowerCase()
274
+ const includeNode = this.shouldIncludeNode(platform)
275
+ const includeBrowser = this.shouldIncludeBrowser(platform)
276
+
277
+ if (lower === 'container' || lower === 'self') {
278
+ return [{ kind: 'container' }]
279
+ }
280
+
281
+ // Check if it matches a registry name
282
+ const registryMatch = this.matchRegistryName(target)
283
+ if (registryMatch && !target.includes('.')) {
284
+ return [{ kind: 'registry', name: registryMatch }]
285
+ }
286
+
287
+ if (target.includes('.')) {
288
+ const [prefix, ...rest] = target.split('.')
289
+ const id = rest.join('.')
290
+ const registry = this.matchRegistryName(prefix!)
291
+
292
+ if (registry) {
293
+ const results: ResolvedTarget[] = []
294
+
295
+ if (includeNode) {
296
+ const reg = this.container[registry]
297
+ const resolved = this.fuzzyFind(reg, id)
298
+ if (resolved) results.push({ kind: 'helper', registry, id: resolved })
299
+ }
300
+
301
+ if (includeBrowser && registry === 'features') {
302
+ const browserFound = this.fuzzyFindBrowser(id)
303
+ if (browserFound) results.push({ kind: 'browser-helper', id: browserFound })
304
+ }
305
+
306
+ if (results.length === 0) {
307
+ const reg = this.container[registry]
308
+ const availableMsg = includeNode ? reg.available.join(', ') : ''
309
+ const browserMsg = includeBrowser && this._browserData ? this._browserData.available.join(', ') : ''
310
+ const combined = [availableMsg, browserMsg].filter(Boolean).join(', ')
311
+ throw new DescribeError(`"${id}" is not registered in ${registry}. Available: ${combined}`)
312
+ }
313
+
314
+ return results
315
+ }
316
+
317
+ // Not a registry prefix — try "helper.member"
318
+ const helperName = prefix!
319
+ const memberName = rest.join('.')
320
+ const results: ResolvedTarget[] = []
321
+
322
+ if (includeNode) {
323
+ const memberResult = this.resolveHelperMember(helperName, memberName)
324
+ if (memberResult) results.push(memberResult)
325
+ }
326
+
327
+ if (includeBrowser) {
328
+ try {
329
+ const browserResult = this.resolveBrowserHelperMember(helperName, memberName)
330
+ if (browserResult) results.push(browserResult)
331
+ } catch (e) {
332
+ if (results.length === 0) throw e
333
+ }
334
+ }
335
+
336
+ if (results.length > 0) return results
337
+ }
338
+
339
+ // Unqualified name: search all registries
340
+ const matches: ResolvedTarget[] = []
341
+
342
+ if (includeNode) {
343
+ for (const registryName of this.registryNames) {
344
+ const reg = this.container[registryName]
345
+ if (!reg) continue
346
+ const found = this.fuzzyFind(reg, target)
347
+ if (found) {
348
+ matches.push({ kind: 'helper', registry: registryName, id: found })
349
+ }
350
+ }
351
+ }
352
+
353
+ if (includeBrowser) {
354
+ const browserFound = this.fuzzyFindBrowser(target)
355
+ if (browserFound) {
356
+ matches.push({ kind: 'browser-helper', id: browserFound })
357
+ }
358
+ }
359
+
360
+ if (matches.length === 0) {
361
+ const lines = [`"${target}" was not found in any registry.`, '', 'Available:']
362
+ if (includeNode) {
363
+ for (const registryName of this.registryNames) {
364
+ const reg = this.container[registryName]
365
+ if (reg && reg.available.length > 0) {
366
+ lines.push(` ${registryName}: ${reg.available.join(', ')}`)
367
+ }
368
+ }
369
+ }
370
+ if (includeBrowser && this._browserData && this._browserData.available.length > 0) {
371
+ lines.push(` browser features: ${this._browserData.available.join(', ')}`)
372
+ }
373
+ throw new DescribeError(lines.join('\n'))
374
+ }
375
+
376
+ const nodeMatches = matches.filter(m => m.kind === 'helper')
377
+ if (nodeMatches.length > 1) {
378
+ const lines = [`"${target}" is ambiguous — found in multiple registries:`]
379
+ for (const m of nodeMatches) {
380
+ if (m.kind === 'helper') lines.push(` ${m.registry}.${m.id}`)
381
+ }
382
+ lines.push('', `Please qualify it, e.g.: ${(nodeMatches[0] as any).registry}.${target}`)
383
+ throw new DescribeError(lines.join('\n'))
384
+ }
385
+
386
+ return matches
387
+ }
388
+
389
+ /**
390
+ * Get data for a resolved target.
391
+ */
392
+ getData(item: ResolvedTarget, options: DescribeOptions = {}): DescribeResult {
393
+ const sections = options.sections || []
394
+ const noTitle = options.noTitle || false
395
+ const headingDepth = options.headingDepth || 1
396
+ const platform = options.platform || 'all'
397
+
398
+ switch (item.kind) {
399
+ case 'container':
400
+ return this.getContainerData(sections, noTitle, headingDepth)
401
+ case 'registry':
402
+ return this.getRegistryData(item.name, sections, noTitle, headingDepth, platform)
403
+ case 'helper':
404
+ return this.getHelperData(item.registry, item.id, sections, noTitle, headingDepth)
405
+ case 'member':
406
+ return this.getMemberData(item.registry, item.id, item.member, item.memberType, headingDepth)
407
+ case 'browser-helper':
408
+ return this.getBrowserHelperData(item.id, sections, noTitle, headingDepth)
409
+ case 'browser-member':
410
+ return this.getBrowserMemberData(item.id, item.member, item.memberType, headingDepth)
411
+ }
412
+ }
413
+
414
+ // --- Private: Platform helpers ---
415
+
416
+ private normalizePlatform(p: string): Platform {
417
+ if (p === 'node') return 'server'
418
+ if (p === 'web') return 'browser'
419
+ return p as Platform
420
+ }
421
+
422
+ private shouldIncludeNode(platform: Platform): boolean {
423
+ return platform === 'server' || platform === 'node' || platform === 'all'
424
+ }
425
+
426
+ private shouldIncludeBrowser(platform: Platform): boolean {
427
+ return platform === 'browser' || platform === 'all'
428
+ }
429
+
430
+ // --- Private: Fuzzy matching ---
431
+
432
+ private normalize(name: string): string {
433
+ return name.replace(/\.[tj]sx?$/, '').replace(/[-_]/g, '').toLowerCase()
434
+ }
435
+
436
+ private fuzzyFind(registry: any, input: string): string | undefined {
437
+ if (registry.has(input)) return input
438
+ const norm = this.normalize(input)
439
+ return (registry.available as string[]).find((id: string) => this.normalize(id) === norm)
440
+ }
441
+
442
+ private fuzzyFindBrowser(input: string): string | undefined {
443
+ if (!this._browserData) return undefined
444
+ const norm = this.normalize(input)
445
+ return this._browserData.available.find(id => this.normalize(id) === norm)
446
+ }
447
+
448
+ /**
449
+ * Match a user-provided name to an actual registry name on the container.
450
+ * Handles pluralization and case variations dynamically.
451
+ */
452
+ private matchRegistryName(name: string): string | undefined {
453
+ const lower = name.toLowerCase()
454
+ return this.registryNames.find(
455
+ (r) => r === lower || r === lower + 's' || r.replace(/s$/, '') === lower
456
+ )
457
+ }
458
+
459
+ // --- Private: Member resolution ---
460
+
461
+ private resolveHelperMember(helperName: string, memberName: string): ResolvedTarget | null {
462
+ for (const registryName of this.registryNames) {
463
+ const reg = this.container[registryName]
464
+ if (!reg) continue
465
+ const found = this.fuzzyFind(reg, helperName)
466
+ if (!found) continue
467
+
468
+ const Ctor = reg.lookup(found)
469
+ const introspection = Ctor.introspect?.()
470
+ if (!introspection) continue
471
+
472
+ if (introspection.methods?.[memberName]) {
473
+ return { kind: 'member', registry: registryName, id: found, member: memberName, memberType: 'method' }
474
+ }
475
+ if (introspection.getters?.[memberName]) {
476
+ return { kind: 'member', registry: registryName, id: found, member: memberName, memberType: 'getter' }
477
+ }
478
+
479
+ const allMembers = [
480
+ ...Object.keys(introspection.methods || {}).map((m: string) => m + '()'),
481
+ ...Object.keys(introspection.getters || {}),
482
+ ].sort()
483
+ throw new DescribeError(
484
+ `"${memberName}" is not a known method or getter on ${found}.\n\nAvailable members:\n ${allMembers.join(', ')}`
485
+ )
486
+ }
487
+ return null
488
+ }
489
+
490
+ private resolveBrowserHelperMember(helperName: string, memberName: string): ResolvedTarget | null {
491
+ if (!this._browserData) return null
492
+ const found = this.fuzzyFindBrowser(helperName)
493
+ if (!found) return null
494
+
495
+ const data = this._browserData.introspection.get(`features.${found}`)
496
+ if (!data) return null
497
+
498
+ if (data.methods?.[memberName]) {
499
+ return { kind: 'browser-member', id: found, member: memberName, memberType: 'method' }
500
+ }
501
+ if (data.getters?.[memberName]) {
502
+ return { kind: 'browser-member', id: found, member: memberName, memberType: 'getter' }
503
+ }
504
+
505
+ const allMembers = [
506
+ ...Object.keys(data.methods || {}).map((m: string) => m + '()'),
507
+ ...Object.keys(data.getters || {}),
508
+ ].sort()
509
+ throw new DescribeError(
510
+ `"${memberName}" is not a known method or getter on ${found} (browser).\n\nAvailable members:\n ${allMembers.join(', ')}`
511
+ )
512
+ }
513
+
514
+ // --- Private: Data getters ---
515
+
516
+ private getContainerData(sections: (IntrospectionSection | 'description')[], noTitle: boolean, headingDepth: number): DescribeResult {
517
+ const container = this.container
518
+
519
+ if (sections.length === 0) {
520
+ const data = container.introspect()
521
+ return { json: data, text: container.introspectAsText(undefined, headingDepth) }
522
+ }
523
+
524
+ const data = container.introspect()
525
+ const introspectionSections = sections.filter((s): s is IntrospectionSection => s !== 'description')
526
+ const textParts: string[] = []
527
+ const jsonResult: Record<string, any> = {}
528
+ const h = '#'.repeat(headingDepth)
529
+
530
+ if (!noTitle) {
531
+ const className = data.className || 'Container'
532
+ textParts.push(`${h} ${className} (Container)`)
533
+ jsonResult.className = className
534
+ if (data.description) {
535
+ textParts.push(data.description)
536
+ jsonResult.description = data.description
537
+ }
538
+ }
539
+
540
+ for (const section of introspectionSections) {
541
+ textParts.push(container.introspectAsText(section, headingDepth))
542
+ jsonResult[section] = data[section]
543
+ }
544
+
545
+ return { json: jsonResult, text: textParts.join('\n\n') }
546
+ }
547
+
548
+ private getHelperData(registryName: string, id: string, sections: (IntrospectionSection | 'description')[], noTitle: boolean, headingDepth: number): DescribeResult {
549
+ const registry = this.container[registryName]
550
+ const Ctor = registry.lookup(id)
551
+ const text = this.renderHelperText(Ctor, sections, noTitle, headingDepth)
552
+
553
+ let finalText = text
554
+ if (sections.length === 0 && !noTitle) {
555
+ const summary = this.buildHelperSummary(Ctor)
556
+ if (summary) {
557
+ const sectionHeading = '#'.repeat(headingDepth + 1) + ' '
558
+ const idx = text.indexOf('\n' + sectionHeading)
559
+ if (idx >= 0) {
560
+ finalText = text.slice(0, idx) + '\n\n' + summary + '\n' + text.slice(idx)
561
+ }
562
+ }
563
+ }
564
+
565
+ return {
566
+ json: this.renderHelperJson(Ctor, sections, noTitle),
567
+ text: finalText,
568
+ }
569
+ }
570
+
571
+ private getMemberData(registryName: string, id: string, member: string, memberType: 'method' | 'getter', headingDepth: number): DescribeResult {
572
+ const registry = this.container[registryName]
573
+ const Ctor = registry.lookup(id)
574
+ const introspection = Ctor.introspect?.()
575
+ const h = '#'.repeat(headingDepth)
576
+ const hSub = '#'.repeat(headingDepth + 1)
577
+
578
+ if (memberType === 'method') {
579
+ const method = introspection?.methods?.[member] as MethodIntrospection | undefined
580
+ if (!method) return { json: {}, text: `No introspection data for ${id}.${member}()` }
581
+
582
+ const parts: string[] = []
583
+ parts.push(`${h} ${id}.${member}()`)
584
+ parts.push(`> method on **${introspection.className || id}**`)
585
+ if (method.description) parts.push(method.description)
586
+
587
+ const paramEntries = Object.entries(method.parameters || {})
588
+ if (paramEntries.length > 0) {
589
+ const paramLines = [`${hSub} Parameters`, '']
590
+ for (const [name, info] of paramEntries) {
591
+ const req = (method.required || []).includes(name) ? ' *(required)*' : ''
592
+ paramLines.push(`- **${name}** \`${info.type}\`${req}${info.description ? ' — ' + info.description : ''}`)
593
+ if (info.properties) {
594
+ for (const [propName, propInfo] of Object.entries(info.properties)) {
595
+ paramLines.push(` - **${propName}** \`${propInfo.type}\`${propInfo.description ? ' — ' + propInfo.description : ''}`)
596
+ }
597
+ }
598
+ }
599
+ parts.push(paramLines.join('\n'))
600
+ }
601
+
602
+ if (method.returns && method.returns !== 'void') {
603
+ parts.push(`${hSub} Returns\n\n\`${method.returns}\``)
604
+ }
605
+
606
+ if (method.examples?.length) {
607
+ parts.push(`${hSub} Examples`)
608
+ for (const ex of method.examples) {
609
+ parts.push(`\`\`\`${ex.language || 'typescript'}\n${ex.code}\n\`\`\``)
610
+ }
611
+ }
612
+
613
+ return { json: { [member]: method, _helper: id, _type: 'method' }, text: parts.join('\n\n') }
614
+ }
615
+
616
+ const getter = introspection?.getters?.[member] as GetterIntrospection | undefined
617
+ if (!getter) return { json: {}, text: `No introspection data for ${id}.${member}` }
618
+
619
+ const parts: string[] = []
620
+ parts.push(`${h} ${id}.${member}`)
621
+ parts.push(`> getter on **${introspection.className || id}** — returns \`${getter.returns || 'unknown'}\``)
622
+ if (getter.description) parts.push(getter.description)
623
+
624
+ if (getter.examples?.length) {
625
+ parts.push(`${hSub} Examples`)
626
+ for (const ex of getter.examples) {
627
+ parts.push(`\`\`\`${ex.language || 'typescript'}\n${ex.code}\n\`\`\``)
628
+ }
629
+ }
630
+
631
+ return { json: { [member]: getter, _helper: id, _type: 'getter' }, text: parts.join('\n\n') }
632
+ }
633
+
634
+ private getBrowserHelperData(id: string, sections: (IntrospectionSection | 'description')[], noTitle: boolean, headingDepth: number): DescribeResult {
635
+ const data = this._browserData!.introspection.get(`features.${id}`)
636
+ if (!data) return { json: {}, text: `No browser introspection data for ${id}` }
637
+
638
+ const text = this.renderBrowserHelperText(data, sections, noTitle, headingDepth)
639
+
640
+ let finalText = text
641
+ if (sections.length === 0 && !noTitle) {
642
+ const summary = this.buildBrowserHelperSummary(data)
643
+ if (summary) {
644
+ const sectionHeading = '#'.repeat(headingDepth + 1) + ' '
645
+ const idx = text.indexOf('\n' + sectionHeading)
646
+ if (idx >= 0) {
647
+ finalText = text.slice(0, idx) + '\n\n' + summary + '\n' + text.slice(idx)
648
+ }
649
+ }
650
+ }
651
+
652
+ return {
653
+ json: this.renderBrowserHelperJson(data, sections, noTitle),
654
+ text: finalText,
655
+ }
656
+ }
657
+
658
+ private getBrowserMemberData(id: string, member: string, memberType: 'method' | 'getter', headingDepth: number): DescribeResult {
659
+ const data = this._browserData!.introspection.get(`features.${id}`)
660
+ if (!data) return { json: {}, text: `No browser introspection data for ${id}` }
661
+
662
+ const h = '#'.repeat(headingDepth)
663
+ const hSub = '#'.repeat(headingDepth + 1)
664
+
665
+ if (memberType === 'method') {
666
+ const method = data.methods?.[member] as MethodIntrospection | undefined
667
+ if (!method) return { json: {}, text: `No introspection data for ${id}.${member}()` }
668
+
669
+ const parts: string[] = [`${h} ${id}.${member}() (browser)`]
670
+ parts.push(`> method on **${data.className || id}**`)
671
+ if (method.description) parts.push(method.description)
672
+
673
+ const paramEntries = Object.entries(method.parameters || {})
674
+ if (paramEntries.length > 0) {
675
+ const paramLines = [`${hSub} Parameters`, '']
676
+ for (const [name, info] of paramEntries) {
677
+ const req = (method.required || []).includes(name) ? ' *(required)*' : ''
678
+ paramLines.push(`- **${name}** \`${info.type}\`${req}${info.description ? ' — ' + info.description : ''}`)
679
+ }
680
+ parts.push(paramLines.join('\n'))
681
+ }
682
+
683
+ if (method.returns && method.returns !== 'void') {
684
+ parts.push(`${hSub} Returns\n\n\`${method.returns}\``)
685
+ }
686
+
687
+ return { json: { [member]: method, _helper: id, _type: 'method', _platform: 'browser' }, text: parts.join('\n\n') }
688
+ }
689
+
690
+ const getter = data.getters?.[member] as GetterIntrospection | undefined
691
+ if (!getter) return { json: {}, text: `No introspection data for ${id}.${member}` }
692
+
693
+ const parts: string[] = [`${h} ${id}.${member} (browser)`]
694
+ parts.push(`> getter on **${data.className || id}** — returns \`${getter.returns || 'unknown'}\``)
695
+ if (getter.description) parts.push(getter.description)
696
+
697
+ return { json: { [member]: getter, _helper: id, _type: 'getter', _platform: 'browser' }, text: parts.join('\n\n') }
698
+ }
699
+
700
+ private getRegistryData(registryName: string, sections: (IntrospectionSection | 'description')[], noTitle: boolean, headingDepth: number, platform: Platform): DescribeResult {
701
+ const includeNode = this.shouldIncludeNode(platform)
702
+ const includeBrowser = this.shouldIncludeBrowser(platform) && registryName === 'features' && this._browserData
703
+
704
+ const registry = this.container[registryName]
705
+ const nodeAvailable: string[] = includeNode ? registry.available : []
706
+ const browserAvailable: string[] = includeBrowser ? this._browserData!.available : []
707
+
708
+ const collidingIds = includeBrowser ? this._browserData!.collidingIds : new Set<string>()
709
+ const totalCount = nodeAvailable.length + browserAvailable.filter(id => !includeNode || !collidingIds.has(id)).length
710
+
711
+ if (totalCount === 0) {
712
+ return { json: {}, text: `No ${registryName} are registered.` }
713
+ }
714
+
715
+ if (sections.length === 0) {
716
+ const h = '#'.repeat(headingDepth)
717
+ const hSub = '#'.repeat(headingDepth + 1)
718
+ const jsonResult: Record<string, any> = {}
719
+ const textParts: string[] = [`${h} Available ${registryName} (${totalCount})\n`]
720
+
721
+ if (includeNode) {
722
+ const baseClass = registry.baseClass
723
+ if (baseClass) {
724
+ const shared = this.collectSharedMembers(baseClass)
725
+ const label = registryName[0]!.toUpperCase() + registryName.slice(1).replace(/s$/, '')
726
+
727
+ if (shared.getters.length) textParts.push(`**Shared ${label} Getters:** ${shared.getters.join(', ')}\n`)
728
+ if (shared.methods.length) textParts.push(`**Shared ${label} Methods:** ${shared.methods.map(m => m + '()').join(', ')}\n`)
729
+ jsonResult._shared = { methods: shared.methods, getters: shared.getters }
730
+ }
731
+
732
+ const baseClassRef = registry.baseClass
733
+ const sorted = [...nodeAvailable].sort((a, b) => {
734
+ const aCtor = registry.lookup(a)
735
+ const bCtor = registry.lookup(b)
736
+ const aIsDirect = !this.findIntermediateParent(aCtor, baseClassRef)
737
+ const bIsDirect = !this.findIntermediateParent(bCtor, baseClassRef)
738
+ if (aIsDirect && !bIsDirect) return -1
739
+ if (!aIsDirect && bIsDirect) return 1
740
+ return 0
741
+ })
742
+
743
+ for (const id of sorted) {
744
+ const Ctor = registry.lookup(id)
745
+ const introspection = Ctor.introspect?.()
746
+ const description = introspection?.description || Ctor.description || 'No description provided'
747
+ const summary = this.extractSummary(description)
748
+ const featureGetters = Object.keys(introspection?.getters || {}).sort()
749
+ const featureMethods = Object.keys(introspection?.methods || {}).sort()
750
+ const intermediate = this.findIntermediateParent(Ctor, baseClassRef)
751
+
752
+ const platformTag = includeBrowser && collidingIds.has(id) ? ' (node)' : ''
753
+
754
+ const entryJson: Record<string, any> = { description: summary, methods: featureMethods, getters: featureGetters }
755
+ if (intermediate) {
756
+ entryJson.extends = intermediate.name
757
+ entryJson.inheritedMethods = intermediate.methods
758
+ entryJson.inheritedGetters = intermediate.getters
759
+ }
760
+ if (platformTag) entryJson.platform = 'node'
761
+ jsonResult[id + (platformTag ? ':node' : '')] = entryJson
762
+
763
+ const extendsLine = intermediate ? `\n> extends ${intermediate.name}\n` : ''
764
+ const memberLines: string[] = []
765
+ if (featureGetters.length) memberLines.push(` getters: ${featureGetters.join(', ')}`)
766
+ if (featureMethods.length) memberLines.push(` methods: ${featureMethods.map(m => m + '()').join(', ')}`)
767
+ if (intermediate) {
768
+ if (intermediate.getters.length) memberLines.push(` inherited getters: ${intermediate.getters.join(', ')}`)
769
+ if (intermediate.methods.length) memberLines.push(` inherited methods: ${intermediate.methods.map(m => m + '()').join(', ')}`)
770
+ }
771
+ const memberBlock = memberLines.length ? '\n' + memberLines.join('\n') + '\n' : ''
772
+ textParts.push(`${hSub} ${id}${platformTag}${extendsLine}\n${summary}\n${memberBlock}`)
773
+ }
774
+ }
775
+
776
+ if (includeBrowser) {
777
+ for (const id of browserAvailable.sort()) {
778
+ if (includeNode && collidingIds.has(id)) {
779
+ const data = this._browserData!.introspection.get(`features.${id}`)
780
+ if (!data) continue
781
+ const summary = this.extractSummary(data.description || 'No description provided')
782
+ const featureGetters = Object.keys(data.getters || {}).sort()
783
+ const featureMethods = Object.keys(data.methods || {}).sort()
784
+
785
+ jsonResult[id + ':browser'] = { description: summary, methods: featureMethods, getters: featureGetters, platform: 'browser' }
786
+
787
+ const memberLines: string[] = []
788
+ if (featureGetters.length) memberLines.push(` getters: ${featureGetters.join(', ')}`)
789
+ if (featureMethods.length) memberLines.push(` methods: ${featureMethods.map(m => m + '()').join(', ')}`)
790
+ const memberBlock = memberLines.length ? '\n' + memberLines.join('\n') + '\n' : ''
791
+ textParts.push(`${hSub} ${id} (browser)\n${summary}\n${memberBlock}`)
792
+ continue
793
+ }
794
+
795
+ const data = this._browserData!.introspection.get(`features.${id}`)
796
+ if (!data) continue
797
+ const summary = this.extractSummary(data.description || 'No description provided')
798
+ const featureGetters = Object.keys(data.getters || {}).sort()
799
+ const featureMethods = Object.keys(data.methods || {}).sort()
800
+
801
+ const platformTag = !includeNode ? '' : ' (browser)'
802
+ jsonResult[id] = { description: summary, methods: featureMethods, getters: featureGetters, platform: 'browser' }
803
+
804
+ const memberLines: string[] = []
805
+ if (featureGetters.length) memberLines.push(` getters: ${featureGetters.join(', ')}`)
806
+ if (featureMethods.length) memberLines.push(` methods: ${featureMethods.map(m => m + '()').join(', ')}`)
807
+ const memberBlock = memberLines.length ? '\n' + memberLines.join('\n') + '\n' : ''
808
+ textParts.push(`${hSub} ${id}${platformTag}\n${summary}\n${memberBlock}`)
809
+ }
810
+ }
811
+
812
+ return { json: jsonResult, text: textParts.join('\n') }
813
+ }
814
+
815
+ // Sections specified: render each helper in detail
816
+ const jsonResult: Record<string, any> = {}
817
+ const textParts: string[] = []
818
+
819
+ if (includeNode) {
820
+ for (const id of nodeAvailable) {
821
+ const Ctor = registry.lookup(id)
822
+ jsonResult[id] = this.renderHelperJson(Ctor, sections, noTitle)
823
+ textParts.push(this.renderHelperText(Ctor, sections, noTitle, headingDepth))
824
+ }
825
+ }
826
+
827
+ if (includeBrowser) {
828
+ for (const id of browserAvailable) {
829
+ if (includeNode && collidingIds.has(id)) continue
830
+ const data = this._browserData!.introspection.get(`features.${id}`)
831
+ if (!data) continue
832
+ jsonResult[id] = this.renderBrowserHelperJson(data, sections, noTitle)
833
+ textParts.push(this.renderBrowserHelperText(data, sections, noTitle, headingDepth))
834
+ }
835
+ }
836
+
837
+ return { json: jsonResult, text: textParts.join('\n\n---\n\n') }
838
+ }
839
+
840
+ // --- Private: Rendering helpers ---
841
+
842
+ private renderTitle(Ctor: any, headingDepth = 1): string {
843
+ const data = Ctor.introspect?.()
844
+ const id = data?.id || Ctor.shortcut || Ctor.name
845
+ const className = data?.className || Ctor.name
846
+ const h = '#'.repeat(headingDepth)
847
+ return className ? `${h} ${className} (${id})` : `${h} ${id}`
848
+ }
849
+
850
+ private renderHelperText(Ctor: any, sections: (IntrospectionSection | 'description')[], noTitle: boolean, headingDepth: number): string {
851
+ if (sections.length === 0) {
852
+ if (noTitle) {
853
+ const data = Ctor.introspect?.()
854
+ if (!data) return 'No introspection data available.'
855
+ const parts: string[] = [data.description]
856
+ const text = Ctor.introspectAsText?.(headingDepth)
857
+ if (text) {
858
+ const lines = text.split('\n')
859
+ const headingPrefix = '#'.repeat(headingDepth + 1) + ' '
860
+ let startIdx = 0
861
+ for (let i = 0; i < lines.length; i++) {
862
+ if (i > 0 && lines[i]!.startsWith(headingPrefix)) {
863
+ startIdx = i
864
+ break
865
+ }
866
+ }
867
+ if (startIdx > 0) {
868
+ parts.length = 0
869
+ parts.push(data.description)
870
+ parts.push(lines.slice(startIdx).join('\n'))
871
+ }
872
+ }
873
+ return parts.join('\n\n')
874
+ }
875
+ return Ctor.introspectAsText?.(headingDepth) ?? `${this.renderTitle(Ctor, headingDepth)}\n\nNo introspection data available.`
876
+ }
877
+
878
+ const introspectionSections = sections.filter((s): s is IntrospectionSection => s !== 'description')
879
+ const parts: string[] = []
880
+
881
+ if (!noTitle) {
882
+ const data = Ctor.introspect?.()
883
+ parts.push(this.renderTitle(Ctor, headingDepth))
884
+ if (data?.description) parts.push(data.description)
885
+ }
886
+
887
+ for (const section of introspectionSections) {
888
+ const text = Ctor.introspectAsText?.(section, headingDepth)
889
+ if (text) parts.push(text)
890
+ }
891
+
892
+ return parts.join('\n\n') || `${noTitle ? '' : this.renderTitle(Ctor, headingDepth) + '\n\n'}No introspection data available.`
893
+ }
894
+
895
+ private renderHelperJson(Ctor: any, sections: (IntrospectionSection | 'description')[], noTitle: boolean): any {
896
+ if (sections.length === 0) return Ctor.introspect?.() ?? {}
897
+
898
+ const data = Ctor.introspect?.() ?? {}
899
+ const result: Record<string, any> = {}
900
+
901
+ if (!noTitle) {
902
+ result.id = data.id
903
+ if (data.className) result.className = data.className
904
+ }
905
+
906
+ for (const section of sections) {
907
+ if (section === 'description') {
908
+ result.id = data.id
909
+ if (data.className) result.className = data.className
910
+ result.description = data.description
911
+ } else if (section === 'usage') {
912
+ result.usage = { shortcut: data.shortcut, options: data.options }
913
+ } else {
914
+ const sectionData = Ctor.introspect?.(section)
915
+ if (sectionData) result[section] = sectionData[section]
916
+ }
917
+ }
918
+
919
+ return result
920
+ }
921
+
922
+ private renderBrowserHelperText(data: HelperIntrospection, sections: (IntrospectionSection | 'description')[], noTitle: boolean, headingDepth: number): string {
923
+ const h = '#'.repeat(headingDepth)
924
+ const className = data.className || data.id
925
+
926
+ if (sections.length === 0) {
927
+ const body = presentIntrospectionAsMarkdown(data, headingDepth)
928
+ if (noTitle) {
929
+ const lines = body.split('\n')
930
+ const sectionHeading = '#'.repeat(headingDepth + 1) + ' '
931
+ const firstSectionIdx = lines.findIndex((l, i) => i > 0 && l.startsWith(sectionHeading))
932
+ const desc = data.description ? data.description + '\n\n' : ''
933
+ if (firstSectionIdx > 0) return desc + lines.slice(firstSectionIdx).join('\n')
934
+ return desc.trim() || 'No introspection data available.'
935
+ }
936
+ return body
937
+ }
938
+
939
+ const parts: string[] = []
940
+ if (!noTitle) {
941
+ parts.push(`${h} ${className} (${data.id})`)
942
+ if (data.description) parts.push(data.description)
943
+ }
944
+
945
+ const introspectionSections = sections.filter((s): s is IntrospectionSection => s !== 'description')
946
+ for (const section of introspectionSections) {
947
+ const text = presentIntrospectionAsMarkdown(data, headingDepth, section)
948
+ if (text) parts.push(text)
949
+ }
950
+
951
+ return parts.join('\n\n') || `${noTitle ? '' : `${h} ${className}\n\n`}No introspection data available.`
952
+ }
953
+
954
+ private renderBrowserHelperJson(data: HelperIntrospection, sections: (IntrospectionSection | 'description')[], noTitle: boolean): any {
955
+ if (sections.length === 0) return data
956
+
957
+ const result: Record<string, any> = {}
958
+ if (!noTitle) {
959
+ result.id = data.id
960
+ if (data.className) result.className = data.className
961
+ }
962
+ for (const section of sections) {
963
+ if (section === 'description') {
964
+ result.id = data.id
965
+ if (data.className) result.className = data.className
966
+ result.description = data.description
967
+ } else if (section === 'usage') {
968
+ result.usage = { shortcut: data.shortcut, options: data.options }
969
+ } else {
970
+ result[section] = (data as any)[section]
971
+ }
972
+ }
973
+ return result
974
+ }
975
+
976
+ // --- Private: Summary builders ---
977
+
978
+ private extractSummary(description: string): string {
979
+ const cut = description.search(/\s\*\*[A-Z][\w\s]+:\*\*|```|^\s*[-*]\s/m)
980
+ const text = cut > 0 ? description.slice(0, cut).trim() : description
981
+ if (text.length <= 300) return text
982
+ const sentenceEnd = text.lastIndexOf('. ', 300)
983
+ if (sentenceEnd > 100) return text.slice(0, sentenceEnd + 1)
984
+ return text.slice(0, 300).trim() + '...'
985
+ }
986
+
987
+ private buildHelperSummary(Ctor: any): string {
988
+ const introspection = Ctor.introspect?.()
989
+ const ownMethods = Object.keys(introspection?.methods || {}).sort()
990
+ const ownGetters = Object.keys(introspection?.getters || {}).sort()
991
+
992
+ const chain: any[] = []
993
+ let current = Object.getPrototypeOf(Ctor)
994
+ while (current && current.name && !BASE_CLASS_NAMES.has(current.name) && current !== Function.prototype) {
995
+ chain.push(current)
996
+ current = Object.getPrototypeOf(current)
997
+ }
998
+
999
+ const lines: string[] = []
1000
+ if (chain.length > 0) lines.push(`> extends ${chain[0].name}`)
1001
+ if (ownGetters.length) lines.push(`getters: ${ownGetters.join(', ')}`)
1002
+ if (ownMethods.length) lines.push(`methods: ${ownMethods.map(m => m + '()').join(', ')}`)
1003
+
1004
+ for (const parent of chain) {
1005
+ const parentIntrospection = parent.introspect?.()
1006
+ const inheritedMethods = Object.keys(parentIntrospection?.methods || {}).sort()
1007
+ const inheritedGetters = Object.keys(parentIntrospection?.getters || {}).sort()
1008
+ if (inheritedGetters.length) lines.push(`inherited getters (${parent.name}): ${inheritedGetters.join(', ')}`)
1009
+ if (inheritedMethods.length) lines.push(`inherited methods (${parent.name}): ${inheritedMethods.map(m => m + '()').join(', ')}`)
1010
+ }
1011
+
1012
+ return lines.join('\n')
1013
+ }
1014
+
1015
+ private buildBrowserHelperSummary(data: HelperIntrospection): string {
1016
+ const ownMethods = Object.keys(data.methods || {}).sort()
1017
+ const ownGetters = Object.keys(data.getters || {}).sort()
1018
+ const lines: string[] = []
1019
+ if (ownGetters.length) lines.push(`getters: ${ownGetters.join(', ')}`)
1020
+ if (ownMethods.length) lines.push(`methods: ${ownMethods.map(m => m + '()').join(', ')}`)
1021
+ return lines.join('\n')
1022
+ }
1023
+
1024
+ // --- Private: Prototype chain helpers ---
1025
+
1026
+ private collectSharedMembers(baseClass: any): { methods: string[]; getters: string[] } {
1027
+ const methods: string[] = []
1028
+ const getters: string[] = []
1029
+
1030
+ let proto = baseClass?.prototype
1031
+ while (proto && proto.constructor.name !== 'Object') {
1032
+ for (const k of Object.getOwnPropertyNames(proto)) {
1033
+ if (k === 'constructor' || k.startsWith('_')) continue
1034
+ const desc = Object.getOwnPropertyDescriptor(proto, k)
1035
+ if (!desc) continue
1036
+ if (desc.get && !getters.includes(k)) getters.push(k)
1037
+ else if (typeof desc.value === 'function' && !methods.includes(k)) methods.push(k)
1038
+ }
1039
+ proto = Object.getPrototypeOf(proto)
1040
+ }
1041
+
1042
+ return { methods: methods.sort(), getters: getters.sort() }
1043
+ }
1044
+
1045
+ private findIntermediateParent(Ctor: any, baseClass: any): { name: string; methods: string[]; getters: string[] } | null {
1046
+ if (!baseClass) return null
1047
+
1048
+ let parent = Object.getPrototypeOf(Ctor)
1049
+ if (!parent || parent === baseClass) return null
1050
+
1051
+ const chain: any[] = []
1052
+ let current = parent
1053
+ while (current && current !== baseClass && current !== Function.prototype) {
1054
+ chain.push(current)
1055
+ current = Object.getPrototypeOf(current)
1056
+ }
1057
+
1058
+ if (chain.length === 0 || current !== baseClass) return null
1059
+
1060
+ const intermediate = chain[0]
1061
+ const methods: string[] = []
1062
+ const getters: string[] = []
1063
+
1064
+ const proto = intermediate?.prototype
1065
+ if (proto) {
1066
+ for (const k of Object.getOwnPropertyNames(proto)) {
1067
+ if (k === 'constructor' || k.startsWith('_')) continue
1068
+ const desc = Object.getOwnPropertyDescriptor(proto, k)
1069
+ if (!desc) continue
1070
+ if (desc.get && !getters.includes(k)) getters.push(k)
1071
+ else if (typeof desc.value === 'function' && !methods.includes(k)) methods.push(k)
1072
+ }
1073
+ }
1074
+
1075
+ return {
1076
+ name: intermediate.name,
1077
+ methods: methods.sort(),
1078
+ getters: getters.sort(),
1079
+ }
1080
+ }
1081
+ }
1082
+
1083
+ export { DescribeError, SECTION_FLAGS }
1084
+ export type { ResolvedTarget, Platform, DescribeOptions, DescribeResult, BrowserFeatureData }