luca 1.1.2 → 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 (754) 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 -8
  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 -0
  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 -66
  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/index.d.ts +0 -2
  734. package/dist/cli/index.js +0 -5
  735. package/dist/cli/run.d.ts +0 -12
  736. package/dist/cli/run.js +0 -42
  737. package/dist/config/consts.d.ts +0 -2
  738. package/dist/config/consts.js +0 -29
  739. package/dist/config/default.d.ts +0 -8
  740. package/dist/config/default.js +0 -15
  741. package/dist/config/initConfig.d.ts +0 -1
  742. package/dist/config/initConfig.js +0 -52
  743. package/dist/config/openConfig.d.ts +0 -2
  744. package/dist/config/openConfig.js +0 -24
  745. package/dist/config/runConfig.d.ts +0 -3
  746. package/dist/config/runConfig.js +0 -117
  747. package/dist/config/types.d.ts +0 -13
  748. package/dist/config/types.js +0 -2
  749. package/dist/index.d.ts +0 -1
  750. package/dist/index.js +0 -5
  751. package/dist/utils/common.d.ts +0 -2
  752. package/dist/utils/common.js +0 -52
  753. package/dist/utils/index.d.ts +0 -1
  754. package/dist/utils/index.js +0 -17
@@ -0,0 +1,1131 @@
1
+ import { Feature } from '../feature.js';
2
+ import type { HelperIntrospection, MethodIntrospection, GetterIntrospection, EventIntrospection, ContainerIntrospection, ExampleIntrospection } from './index.js';
3
+ import * as ts from 'typescript';
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ import { glob } from 'glob';
7
+ import { z } from 'zod'
8
+ import { FeatureStateSchema, FeatureOptionsSchema } from '../schemas/base.js'
9
+
10
+ export const IntrospectionScannerStateSchema = FeatureStateSchema.extend({
11
+ scanResults: z.array(z.any()).default([]),
12
+ containerResults: z.array(z.any()).default([]),
13
+ lastScanTime: z.date().nullable().default(null),
14
+ scannedFiles: z.array(z.string()).default([]),
15
+ })
16
+
17
+ export const IntrospectionScannerOptionsSchema = FeatureOptionsSchema.extend({
18
+ src: z.array(z.string()).optional(),
19
+ outputPath: z.string().optional(),
20
+ includePrivate: z.boolean().optional(),
21
+ importSource: z.string().optional(),
22
+ })
23
+
24
+ export type IntrospectionScannerState = z.infer<typeof IntrospectionScannerStateSchema>
25
+ export type IntrospectionScannerOptions = z.infer<typeof IntrospectionScannerOptionsSchema>
26
+
27
+ export class IntrospectionScannerFeature extends Feature<IntrospectionScannerState, IntrospectionScannerOptions> {
28
+ static override shortcut = 'introspectionScanner';
29
+ static override description = 'Scans TypeScript files for Helper classes and generates introspection data using AST analysis';
30
+ static override stateSchema = IntrospectionScannerStateSchema;
31
+ static override optionsSchema = IntrospectionScannerOptionsSchema;
32
+
33
+ override get initialState(): IntrospectionScannerState {
34
+ return {
35
+ ...super.initialState,
36
+ scanResults: [],
37
+ containerResults: [],
38
+ lastScanTime: null,
39
+ scannedFiles: []
40
+ };
41
+ }
42
+
43
+ override async enable(options: Partial<IntrospectionScannerOptions> = {}): Promise<this> {
44
+ const fullOptions: IntrospectionScannerOptions = {
45
+ src: [],
46
+ outputPath: 'src/introspection/generated.ts',
47
+ includePrivate: false,
48
+ ...options
49
+ };
50
+
51
+ await super.enable(fullOptions);
52
+
53
+ if (!this.options.src || this.options.src.length === 0) {
54
+ throw new Error('IntrospectionScanner requires src directories to be specified');
55
+ }
56
+
57
+ return this;
58
+ }
59
+
60
+ /**
61
+ * Scan the specified source directories for Helper classes and extract introspection data
62
+ */
63
+ async scan(): Promise<HelperIntrospection[]> {
64
+ const startTime = Date.now();
65
+ this.emit('scanStarted', { directories: this.options.src });
66
+
67
+ try {
68
+ const results: HelperIntrospection[] = [];
69
+ const containerResults: Partial<ContainerIntrospection>[] = [];
70
+ const scannedFiles: string[] = [];
71
+
72
+ for (const srcDir of this.options.src || []) {
73
+ const files = await this.findTypeScriptFiles(srcDir);
74
+ scannedFiles.push(...files);
75
+
76
+ for (const file of files) {
77
+ const { helpers, containers } = await this.analyzeFile(file);
78
+ results.push(...helpers);
79
+ containerResults.push(...containers);
80
+ }
81
+ }
82
+
83
+ this.setState({
84
+ scanResults: results,
85
+ containerResults,
86
+ lastScanTime: new Date(),
87
+ scannedFiles
88
+ });
89
+
90
+ const duration = Date.now() - startTime;
91
+ this.emit('scanCompleted', {
92
+ results: results.length,
93
+ containers: containerResults.length,
94
+ files: scannedFiles.length,
95
+ duration
96
+ });
97
+
98
+ return results;
99
+ } catch (error) {
100
+ this.emit('scanFailed', error);
101
+ throw error;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Generate a TypeScript file that populates the introspection registry
107
+ */
108
+ async generateRegistryScript(): Promise<string> {
109
+ let results = this.state.get('scanResults');
110
+ if (!results || results.length === 0) {
111
+ await this.scan();
112
+ results = this.state.get('scanResults');
113
+ }
114
+
115
+ const containerResults = this.state.get('containerResults') || [];
116
+ const script = this.createRegistryScript(results!, containerResults);
117
+
118
+ if (this.options.outputPath) {
119
+ await fs.promises.writeFile(this.options.outputPath, script);
120
+ this.emit('scriptGenerated', { path: this.options.outputPath });
121
+ }
122
+
123
+ return script;
124
+ }
125
+
126
+ private async findTypeScriptFiles(srcPath: string): Promise<string[]> {
127
+ // If it's a direct .ts file path, return it directly (if it exists)
128
+ if (srcPath.endsWith('.ts')) {
129
+ try {
130
+ await fs.promises.access(srcPath);
131
+ return [srcPath];
132
+ } catch {
133
+ return [];
134
+ }
135
+ }
136
+
137
+ const pattern = path.join(srcPath, '**/*.ts');
138
+ return await glob(pattern, {
139
+ ignore: ['**/*.d.ts', '**/node_modules/**']
140
+ });
141
+ }
142
+
143
+ private async analyzeFile(filePath: string): Promise<{ helpers: HelperIntrospection[], containers: Partial<ContainerIntrospection>[] }> {
144
+ const sourceCode = await fs.promises.readFile(filePath, 'utf-8');
145
+ const sourceFile = ts.createSourceFile(
146
+ filePath,
147
+ sourceCode,
148
+ ts.ScriptTarget.Latest,
149
+ true
150
+ );
151
+
152
+ const helpers: HelperIntrospection[] = [];
153
+ const containers: Partial<ContainerIntrospection>[] = [];
154
+
155
+ const visit = (node: ts.Node) => {
156
+ if (ts.isClassDeclaration(node)) {
157
+ if (this.extendsContainer(node)) {
158
+ const containerData = this.analyzeContainerClass(node, sourceFile);
159
+ if (containerData) {
160
+ containers.push(containerData);
161
+ }
162
+ } else {
163
+ const introspection = this.analyzeClass(node, sourceFile);
164
+ if (introspection) {
165
+ helpers.push(introspection);
166
+ }
167
+ }
168
+ }
169
+ ts.forEachChild(node, visit);
170
+ };
171
+
172
+ visit(sourceFile);
173
+ return { helpers, containers };
174
+ }
175
+
176
+ private analyzeClass(classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): HelperIntrospection | null {
177
+ const className = classNode.name?.text;
178
+ if (!className) return null;
179
+
180
+ // Check if this extends Helper, Feature, Client, or Server
181
+ const isHelperClass = this.extendsHelper(classNode);
182
+ if (!isHelperClass) return null;
183
+
184
+ const shortcut = this.extractShortcut(classNode);
185
+ if (!shortcut) return null;
186
+
187
+ const description = this.extractJSDocDescription(classNode);
188
+ const methods = this.extractMethods(classNode, sourceFile);
189
+ const getters = this.extractGetters(classNode, sourceFile);
190
+ const events = this.extractEvents(classNode, sourceFile);
191
+ const examples = this.extractJSDocExamples(classNode);
192
+ const types = this.collectReferencedTypes(methods, getters, sourceFile);
193
+
194
+ // state and options are derived at runtime from Zod schemas
195
+ // via interceptRegistration — no need to extract them at build time
196
+ return {
197
+ id: shortcut,
198
+ description: description || `${className} helper`,
199
+ shortcut,
200
+ className,
201
+ methods,
202
+ getters,
203
+ events,
204
+ state: {},
205
+ options: {},
206
+ envVars: [],
207
+ ...(examples.length > 0 ? { examples } : {}),
208
+ ...(Object.keys(types).length > 0 ? { types } : {}),
209
+ };
210
+ }
211
+
212
+ private extendsHelper(classNode: ts.ClassDeclaration): boolean {
213
+ if (!classNode.heritageClauses) return false;
214
+
215
+ for (const clause of classNode.heritageClauses) {
216
+ if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
217
+ for (const type of clause.types) {
218
+ if (type.expression) {
219
+ const typeName = type.expression.getText();
220
+ if (['Helper', 'Feature', 'Client', 'Server'].some(base => typeName.includes(base))) {
221
+ return true;
222
+ }
223
+ }
224
+ }
225
+ }
226
+ }
227
+ return false;
228
+ }
229
+
230
+ /**
231
+ * Container-specific getters to exclude from introspection.
232
+ * These are framework internals (class references, utility objects) not useful in inspection.
233
+ */
234
+ private static CONTAINER_SKIP_GETTERS = new Set([
235
+ 'Feature', 'Helper', 'State', 'z',
236
+ ]);
237
+
238
+ private extendsContainer(classNode: ts.ClassDeclaration): boolean {
239
+ const className = classNode.name?.text;
240
+ const containerNames = ['Container', 'NodeContainer', 'WebContainer', 'AGIContainer'];
241
+
242
+ // The root Container class itself is a container
243
+ if (className && containerNames.includes(className)) return true;
244
+
245
+ if (!classNode.heritageClauses) return false;
246
+
247
+ for (const clause of classNode.heritageClauses) {
248
+ if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
249
+ for (const type of clause.types) {
250
+ if (type.expression) {
251
+ const typeName = type.expression.getText();
252
+ if (containerNames.some(base => typeName.includes(base))) {
253
+ return true;
254
+ }
255
+ }
256
+ }
257
+ }
258
+ }
259
+ return false;
260
+ }
261
+
262
+ /**
263
+ * Analyze a Container class and extract introspection data.
264
+ * Container classes don't have a shortcut; they use className as the key.
265
+ */
266
+ private analyzeContainerClass(classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): Partial<ContainerIntrospection> | null {
267
+ const className = classNode.name?.text;
268
+ if (!className) return null;
269
+
270
+ const description = this.extractJSDocDescription(classNode);
271
+ const methods = this.extractContainerMethods(classNode, sourceFile);
272
+ const getters = this.extractContainerGetters(classNode, sourceFile);
273
+ const events = this.extractEvents(classNode, sourceFile);
274
+
275
+ return {
276
+ className,
277
+ description: description || `${className} container`,
278
+ methods,
279
+ getters,
280
+ events,
281
+ };
282
+ }
283
+
284
+
285
+ private extractContainerMethods(classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): Record<string, MethodIntrospection> {
286
+ const methods: Record<string, MethodIntrospection> = {};
287
+
288
+ for (const member of classNode.members) {
289
+ if (ts.isMethodDeclaration(member) && member.name) {
290
+ const methodName = member.name.getText();
291
+
292
+ // Skip private methods unless includePrivate is true
293
+ const isPrivate = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.PrivateKeyword);
294
+ if (isPrivate && !this.options.includePrivate) continue;
295
+
296
+ // Skip static methods
297
+ const isStatic = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
298
+ if (isStatic) continue;
299
+
300
+ // Skip methods starting with _ (internal methods like _hide)
301
+ if (methodName.startsWith('_')) continue;
302
+
303
+ // Skip methods tagged with @internal
304
+ if (this.hasJSDocTag(member, 'internal')) continue;
305
+
306
+ const description = this.extractJSDocDescription(member) || '';
307
+ const parameters = this.extractParameters(member);
308
+ const required = this.extractRequiredParameters(member);
309
+ const returns = this.extractReturnType(member);
310
+ const examples = this.extractJSDocExamples(member);
311
+
312
+ methods[methodName] = {
313
+ description,
314
+ parameters,
315
+ required,
316
+ returns,
317
+ ...(examples.length > 0 ? { examples } : {}),
318
+ };
319
+ }
320
+ }
321
+
322
+ return methods;
323
+ }
324
+
325
+ private extractContainerGetters(classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): Record<string, GetterIntrospection> {
326
+ const getters: Record<string, GetterIntrospection> = {};
327
+
328
+ for (const member of classNode.members) {
329
+ if (ts.isGetAccessorDeclaration(member) && member.name) {
330
+ const getterName = member.name.getText();
331
+
332
+ // Skip container framework getters
333
+ if (IntrospectionScannerFeature.CONTAINER_SKIP_GETTERS.has(getterName)) continue;
334
+
335
+ // Skip getters tagged with @internal
336
+ if (this.hasJSDocTag(member, 'internal')) continue;
337
+
338
+ // Skip private getters unless includePrivate is true
339
+ const isPrivate = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.PrivateKeyword);
340
+ if (isPrivate && !this.options.includePrivate) continue;
341
+
342
+ // Skip static getters
343
+ const isStatic = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
344
+ if (isStatic) continue;
345
+
346
+ const description = this.extractJSDocDescriptionFromAccessor(member) || '';
347
+ const returns = this.resolveReturnType(member, member.type, 'any');
348
+ const examples = this.extractJSDocExamples(member);
349
+
350
+ getters[getterName] = {
351
+ description,
352
+ returns,
353
+ ...(examples.length > 0 ? { examples } : {}),
354
+ };
355
+ }
356
+ }
357
+
358
+ return getters;
359
+ }
360
+
361
+ private extractShortcut(classNode: ts.ClassDeclaration): string | null {
362
+ // Look for static shortcut property
363
+ for (const member of classNode.members) {
364
+ if (ts.isPropertyDeclaration(member) &&
365
+ member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword) &&
366
+ member.name?.getText() === 'shortcut') {
367
+
368
+ if (member.initializer) {
369
+ if (ts.isStringLiteral(member.initializer)) {
370
+ return member.initializer.text;
371
+ } else if (ts.isAsExpression(member.initializer) && ts.isStringLiteral(member.initializer.expression)) {
372
+ return member.initializer.expression.text;
373
+ } else {
374
+ // For cases like "features.fs" as const, extract the string part
375
+ const text = member.initializer.getText();
376
+ const match = text.match(/^"([^"]+)"/);
377
+ if (match && match[1]) {
378
+ return match[1];
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ return null;
385
+ }
386
+
387
+ private extractJSDocDescription(node: ts.ClassDeclaration | ts.MethodDeclaration): string | null {
388
+ // Use TypeScript's built-in function to get leading comments
389
+ const sourceFile = node.getSourceFile();
390
+ const fullText = sourceFile.getFullText();
391
+
392
+ // Get the text range for the node including leading trivia (comments)
393
+ const ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());
394
+
395
+ if (ranges && ranges.length > 0) {
396
+ // Find the last JSDoc comment (the one immediately before the node)
397
+ for (let i = ranges.length - 1; i >= 0; i--) {
398
+ const range = ranges[i];
399
+ if (!range) continue;
400
+ const commentText = fullText.substring(range.pos, range.end);
401
+
402
+ // Check if it's a JSDoc comment (starts with /**)
403
+ if (commentText.startsWith('/**')) {
404
+ // Extract the content between /** and */
405
+ const content = commentText.slice(3, -2);
406
+
407
+ // Clean up by removing * prefixes and extracting main description
408
+ const lines = content.split('\n');
409
+ const cleanLines: string[] = [];
410
+
411
+ for (const line of lines) {
412
+ const cleaned = line.replace(/^\s*\*\s?/, '').trim();
413
+ if (cleaned && !cleaned.startsWith('@')) {
414
+ cleanLines.push(cleaned);
415
+ } else if (cleaned.startsWith('@')) {
416
+ // Stop at first @tag
417
+ break;
418
+ }
419
+ }
420
+
421
+ const description = cleanLines.join(' ').trim();
422
+ return description || null;
423
+ }
424
+ }
425
+ }
426
+
427
+ return null;
428
+ }
429
+
430
+ private extractJSDocParamDescriptions(method: ts.MethodDeclaration): {
431
+ params: Record<string, string>,
432
+ subProps: Record<string, Record<string, string>>
433
+ } {
434
+ const params: Record<string, string> = {};
435
+ const subProps: Record<string, Record<string, string>> = {};
436
+
437
+ const sourceFile = method.getSourceFile();
438
+ const fullText = sourceFile.getFullText();
439
+
440
+ const ranges = ts.getLeadingCommentRanges(fullText, method.getFullStart());
441
+
442
+ if (ranges && ranges.length > 0) {
443
+ for (let i = ranges.length - 1; i >= 0; i--) {
444
+ const range = ranges[i];
445
+ if (range) {
446
+ const commentText = fullText.substring(range.pos, range.end);
447
+
448
+ if (commentText.startsWith('/**')) {
449
+ const content = commentText.slice(3, -2);
450
+
451
+ const lines = content.split('\n');
452
+ for (const line of lines) {
453
+ const cleaned = line.replace(/^\s*\*\s?/, '').trim();
454
+
455
+ // Match @param {type} name.subProp or @param {type} [name.subProp=default] - description
456
+ const paramMatch = cleaned.match(/^@param\s+(?:\{[^}]*\}\s+)?\[?([\w.]+)(?:=[^\]]*)?\]?\s*-?\s*(.+)$/);
457
+ if (paramMatch && paramMatch[1] && paramMatch[2]) {
458
+ const fullName = paramMatch[1];
459
+ const description = paramMatch[2].trim();
460
+
461
+ if (fullName.includes('.')) {
462
+ // Sub-property: e.g. options.cached -> { options: { cached: "..." } }
463
+ const parts = fullName.split('.');
464
+ const parentName = parts[0]!;
465
+ const propName = parts.slice(1).join('.');
466
+ if (!subProps[parentName]) subProps[parentName] = {};
467
+ subProps[parentName]![propName] = description;
468
+ } else {
469
+ params[fullName] = description;
470
+ }
471
+ }
472
+ }
473
+ break;
474
+ }
475
+ }
476
+ }
477
+ }
478
+
479
+ return { params, subProps };
480
+ }
481
+
482
+ private extractMethods(classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): Record<string, MethodIntrospection> {
483
+ const methods: Record<string, MethodIntrospection> = {};
484
+
485
+ for (const member of classNode.members) {
486
+ if (ts.isMethodDeclaration(member) && member.name) {
487
+ const methodName = member.name.getText();
488
+
489
+ // Skip private methods unless includePrivate is true
490
+ const isPrivate = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.PrivateKeyword);
491
+ if (isPrivate && !this.options.includePrivate) continue;
492
+
493
+ // Skip static methods (like attach)
494
+ const isStatic = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
495
+ if (isStatic) continue;
496
+
497
+ // Skip methods tagged with @internal
498
+ if (this.hasJSDocTag(member, 'internal')) continue;
499
+
500
+ const description = this.extractJSDocDescription(member) || '';
501
+ const parameters = this.extractParameters(member);
502
+ const required = this.extractRequiredParameters(member);
503
+ const returns = this.extractReturnType(member);
504
+ const examples = this.extractJSDocExamples(member);
505
+
506
+ methods[methodName] = {
507
+ description,
508
+ parameters,
509
+ required,
510
+ returns,
511
+ ...(examples.length > 0 ? { examples } : {}),
512
+ };
513
+ }
514
+ }
515
+
516
+ return methods;
517
+ }
518
+
519
+ /**
520
+ * Base class getters that should be excluded from introspection output.
521
+ * These are inherited from Helper/Feature and not specific to individual features.
522
+ */
523
+ private static BASE_GETTERS = new Set([
524
+ 'initialState', 'container', 'options', 'context', 'cacheKey', 'isEnabled', 'shortcut'
525
+ ]);
526
+
527
+ /**
528
+ * Base class events that should be excluded from introspection output.
529
+ * These are inherited from Helper lifecycle and not specific to individual helpers.
530
+ */
531
+ private static BASE_EVENTS = new Set([
532
+ 'stateChange', 'enabled'
533
+ ]);
534
+
535
+ private extractGetters(classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): Record<string, GetterIntrospection> {
536
+ const getters: Record<string, GetterIntrospection> = {};
537
+
538
+ for (const member of classNode.members) {
539
+ if (ts.isGetAccessorDeclaration(member) && member.name) {
540
+ const getterName = member.name.getText();
541
+
542
+ // Skip base class getters
543
+ if (IntrospectionScannerFeature.BASE_GETTERS.has(getterName)) continue;
544
+
545
+ // Skip private getters unless includePrivate is true
546
+ const isPrivate = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.PrivateKeyword);
547
+ if (isPrivate && !this.options.includePrivate) continue;
548
+
549
+ // Skip static getters
550
+ const isStatic = member.modifiers?.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
551
+ if (isStatic) continue;
552
+
553
+ // Skip getters tagged with @internal
554
+ if (this.hasJSDocTag(member, 'internal')) continue;
555
+
556
+ const description = this.extractJSDocDescriptionFromAccessor(member) || '';
557
+ const returns = this.resolveReturnType(member, member.type, 'any');
558
+ const examples = this.extractJSDocExamples(member);
559
+
560
+ getters[getterName] = {
561
+ description,
562
+ returns,
563
+ ...(examples.length > 0 ? { examples } : {}),
564
+ };
565
+ }
566
+ }
567
+
568
+ return getters;
569
+ }
570
+
571
+ /**
572
+ * Extract a return type from a node, preferring explicit TS annotation,
573
+ * falling back to JSDoc @returns {Type}, then to the given default.
574
+ */
575
+ private resolveReturnType(node: ts.Node, typeNode: ts.TypeNode | undefined, fallback: string): string {
576
+ if (typeNode) return typeNode.getText();
577
+
578
+ const sourceFile = node.getSourceFile();
579
+ const fullText = sourceFile.getFullText();
580
+ const ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());
581
+
582
+ if (ranges && ranges.length > 0) {
583
+ for (let i = ranges.length - 1; i >= 0; i--) {
584
+ const range = ranges[i];
585
+ if (!range) continue;
586
+ const commentText = fullText.substring(range.pos, range.end);
587
+ if (!commentText.startsWith('/**')) continue;
588
+
589
+ const match = commentText.match(/@returns?\s*\{([^}]+)\}/);
590
+ if (match && match[1]) return match[1].trim();
591
+ }
592
+ }
593
+
594
+ return fallback;
595
+ }
596
+
597
+ /**
598
+ * Check if a node's JSDoc comment contains a specific @tag (e.g. @internal).
599
+ */
600
+ private hasJSDocTag(node: ts.Node, tagName: string): boolean {
601
+ const sourceFile = node.getSourceFile();
602
+ const fullText = sourceFile.getFullText();
603
+ const ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());
604
+
605
+ if (!ranges || ranges.length === 0) return false;
606
+
607
+ for (let i = ranges.length - 1; i >= 0; i--) {
608
+ const range = ranges[i];
609
+ if (!range) continue;
610
+ const commentText = fullText.substring(range.pos, range.end);
611
+ if (!commentText.startsWith('/**')) continue;
612
+
613
+ // Check for @tagName anywhere in the JSDoc
614
+ if (new RegExp(`@${tagName}\\b`).test(commentText)) {
615
+ return true;
616
+ }
617
+ }
618
+
619
+ return false;
620
+ }
621
+
622
+ private extractJSDocDescriptionFromAccessor(node: ts.GetAccessorDeclaration): string | null {
623
+ const sourceFile = node.getSourceFile();
624
+ const fullText = sourceFile.getFullText();
625
+
626
+ const ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());
627
+
628
+ if (ranges && ranges.length > 0) {
629
+ for (let i = ranges.length - 1; i >= 0; i--) {
630
+ const range = ranges[i];
631
+ if (!range) continue;
632
+ const commentText = fullText.substring(range.pos, range.end);
633
+
634
+ if (commentText.startsWith('/**')) {
635
+ const content = commentText.slice(3, -2);
636
+ const lines = content.split('\n');
637
+ const cleanLines: string[] = [];
638
+
639
+ for (const line of lines) {
640
+ const cleaned = line.replace(/^\s*\*\s?/, '').trim();
641
+ if (cleaned && !cleaned.startsWith('@')) {
642
+ cleanLines.push(cleaned);
643
+ } else if (cleaned.startsWith('@')) {
644
+ break;
645
+ }
646
+ }
647
+
648
+ const description = cleanLines.join(' ').trim();
649
+ return description || null;
650
+ }
651
+ }
652
+ }
653
+
654
+ return null;
655
+ }
656
+
657
+ /**
658
+ * Extract @example blocks from JSDoc comments on any node type.
659
+ * Supports fenced code blocks (```lang ... ```) within @example tags.
660
+ * Returns an empty array if no examples are found.
661
+ */
662
+ private extractJSDocExamples(node: ts.Node): ExampleIntrospection[] {
663
+ const sourceFile = node.getSourceFile();
664
+ const fullText = sourceFile.getFullText();
665
+ const ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());
666
+
667
+ if (!ranges || ranges.length === 0) return [];
668
+
669
+ for (let i = ranges.length - 1; i >= 0; i--) {
670
+ const range = ranges[i];
671
+ if (!range) continue;
672
+ const commentText = fullText.substring(range.pos, range.end);
673
+ if (!commentText.startsWith('/**')) continue;
674
+
675
+ const content = commentText.slice(3, -2);
676
+ const lines = content.split('\n');
677
+ const examples: ExampleIntrospection[] = [];
678
+
679
+ let inExample = false;
680
+ let inFence = false;
681
+ let language = 'ts';
682
+ let codeLines: string[] = [];
683
+
684
+ for (const line of lines) {
685
+ const cleaned = line.replace(/^\s*\*\s?/, '');
686
+
687
+ if (cleaned.trim().startsWith('@example')) {
688
+ // If we were already collecting an example, save it
689
+ if (inExample && codeLines.length > 0) {
690
+ examples.push({ language, code: codeLines.join('\n').trim() });
691
+ }
692
+ inExample = true;
693
+ inFence = false;
694
+ language = 'ts';
695
+ codeLines = [];
696
+ continue;
697
+ }
698
+
699
+ if (!inExample) continue;
700
+
701
+ // Another @tag ends the current example
702
+ if (cleaned.trim().startsWith('@') && !cleaned.trim().startsWith('@example')) {
703
+ if (codeLines.length > 0) {
704
+ examples.push({ language, code: codeLines.join('\n').trim() });
705
+ }
706
+ inExample = false;
707
+ inFence = false;
708
+ codeLines = [];
709
+ continue;
710
+ }
711
+
712
+ const trimmed = cleaned.trim();
713
+
714
+ if (!inFence && trimmed.startsWith('```')) {
715
+ inFence = true;
716
+ const lang = trimmed.slice(3).trim();
717
+ if (lang) language = lang === 'typescript' ? 'ts' : lang === 'javascript' ? 'js' : lang;
718
+ continue;
719
+ }
720
+
721
+ if (inFence && trimmed === '```') {
722
+ inFence = false;
723
+ // Don't end the example yet — there could be more fences or text
724
+ continue;
725
+ }
726
+
727
+ if (inFence) {
728
+ codeLines.push(cleaned.replace(/^\s?/, ''));
729
+ } else if (inExample && trimmed) {
730
+ // Unfenced example code line
731
+ codeLines.push(cleaned.replace(/^\s?/, ''));
732
+ }
733
+ }
734
+
735
+ // Flush final example
736
+ if (inExample && codeLines.length > 0) {
737
+ examples.push({ language, code: codeLines.join('\n').trim() });
738
+ }
739
+
740
+ return examples;
741
+ }
742
+
743
+ return [];
744
+ }
745
+
746
+ private static PRIMITIVE_TYPES = new Set([
747
+ 'string', 'number', 'boolean', 'any', 'void', 'undefined', 'null',
748
+ 'never', 'unknown', 'object', 'bigint', 'symbol',
749
+ ]);
750
+
751
+ private extractParameters(method: ts.MethodDeclaration): Record<string, { type: string, description: string, properties?: Record<string, { type: string, description: string }> }> {
752
+ const parameters: Record<string, { type: string, description: string, properties?: Record<string, { type: string, description: string }> }> = {};
753
+
754
+ // Extract JSDoc parameter descriptions (including sub-property descriptions)
755
+ const { params: paramDescriptions, subProps } = this.extractJSDocParamDescriptions(method);
756
+ const sourceFile = method.getSourceFile();
757
+
758
+ for (const param of method.parameters) {
759
+ const paramName = param.name.getText();
760
+ const type = param.type ? param.type.getText() : 'any';
761
+
762
+ // Use JSDoc description if available, otherwise fallback to generic description
763
+ const description = paramDescriptions[paramName] || `Parameter ${paramName}`;
764
+
765
+ const entry: { type: string, description: string, properties?: Record<string, { type: string, description: string }> } = { type, description };
766
+
767
+ // Resolve non-primitive types to their member properties
768
+ const baseType = type.replace(/\[\]$/, '').replace(/\s*\|.*$/, '').trim();
769
+ if (!IntrospectionScannerFeature.PRIMITIVE_TYPES.has(baseType)) {
770
+ const properties = this.resolveTypeProperties(baseType, sourceFile);
771
+ if (properties) {
772
+ entry.properties = properties;
773
+ }
774
+ }
775
+
776
+ // Merge JSDoc sub-property descriptions (e.g. @param {boolean} [options.cached] - ...)
777
+ // into the resolved type properties
778
+ const jsdocSubProps = subProps[paramName];
779
+ if (jsdocSubProps) {
780
+ if (!entry.properties) entry.properties = {};
781
+ for (const [propName, propDesc] of Object.entries(jsdocSubProps)) {
782
+ if (entry.properties[propName]) {
783
+ // Enrich existing property with JSDoc description if it was empty
784
+ if (!entry.properties[propName].description) {
785
+ entry.properties[propName].description = propDesc;
786
+ }
787
+ } else {
788
+ entry.properties[propName] = { type: 'any', description: propDesc };
789
+ }
790
+ }
791
+ }
792
+
793
+ parameters[paramName] = entry;
794
+ }
795
+
796
+ return parameters;
797
+ }
798
+
799
+ /**
800
+ * Resolves a type name to its member properties by searching the source file
801
+ * for type alias or interface declarations.
802
+ */
803
+ private resolveTypeProperties(typeName: string, sourceFile: ts.SourceFile): Record<string, { type: string, description: string }> | null {
804
+ for (const statement of sourceFile.statements) {
805
+ // Handle: type Foo = { ... }
806
+ if (ts.isTypeAliasDeclaration(statement) && statement.name.text === typeName) {
807
+ if (ts.isTypeLiteralNode(statement.type)) {
808
+ return this.extractTypeLiteralMembers(statement.type, sourceFile);
809
+ }
810
+ }
811
+ // Handle: interface Foo { ... }
812
+ if (ts.isInterfaceDeclaration(statement) && statement.name.text === typeName) {
813
+ return this.extractInterfaceMembers(statement, sourceFile);
814
+ }
815
+ }
816
+ return null;
817
+ }
818
+
819
+ private extractTypeLiteralMembers(node: ts.TypeLiteralNode, sourceFile: ts.SourceFile): Record<string, { type: string, description: string }> {
820
+ const members: Record<string, { type: string, description: string }> = {};
821
+
822
+ for (const member of node.members) {
823
+ if (ts.isPropertySignature(member) && member.name) {
824
+ const name = member.name.getText();
825
+ const type = member.type ? member.type.getText() : 'any';
826
+ const description = this.extractJSDocFromNode(member, sourceFile) || '';
827
+ members[name] = { type, description };
828
+ }
829
+ }
830
+
831
+ return Object.keys(members).length > 0 ? members : null as any;
832
+ }
833
+
834
+ private extractInterfaceMembers(node: ts.InterfaceDeclaration, sourceFile: ts.SourceFile): Record<string, { type: string, description: string }> {
835
+ const members: Record<string, { type: string, description: string }> = {};
836
+
837
+ for (const member of node.members) {
838
+ if (ts.isPropertySignature(member) && member.name) {
839
+ const name = member.name.getText();
840
+ const type = member.type ? member.type.getText() : 'any';
841
+ const description = this.extractJSDocFromNode(member, sourceFile) || '';
842
+ members[name] = { type, description };
843
+ }
844
+ }
845
+
846
+ return Object.keys(members).length > 0 ? members : null as any;
847
+ }
848
+
849
+ /**
850
+ * Collect all non-primitive type names referenced in method parameters and return types,
851
+ * then resolve each to its properties from the source file. Returns a map of type name
852
+ * to its property definitions, suitable for emitting as standalone interface declarations.
853
+ */
854
+ private collectReferencedTypes(
855
+ methods: Record<string, MethodIntrospection>,
856
+ getters: Record<string, { returns: string; description: string }>,
857
+ sourceFile: ts.SourceFile
858
+ ): Record<string, { description: string; properties: Record<string, { type: string; description: string; optional?: boolean }> }> {
859
+ const types: Record<string, { description: string; properties: Record<string, { type: string; description: string; optional?: boolean }> }> = {};
860
+ const seen = new Set<string>();
861
+
862
+ const tryResolve = (rawType: string) => {
863
+ // Extract type names from complex type strings
864
+ // e.g. "Promise<GrepMatch[]>" -> "GrepMatch"
865
+ // e.g. "GrepOptions" -> "GrepOptions"
866
+ // e.g. "string | Foo" -> "Foo"
867
+ // e.g. "Omit<GrepOptions, 'pattern'>" -> "GrepOptions"
868
+ const typeNames = this.extractTypeNames(rawType);
869
+
870
+ for (const typeName of typeNames) {
871
+ if (seen.has(typeName)) continue;
872
+ seen.add(typeName);
873
+
874
+ if (IntrospectionScannerFeature.PRIMITIVE_TYPES.has(typeName)) continue;
875
+
876
+ const properties = this.resolveTypePropertiesWithOptional(typeName, sourceFile);
877
+ if (properties && Object.keys(properties).length > 0) {
878
+ // Extract JSDoc description from the type declaration itself
879
+ const description = this.extractTypeDescription(typeName, sourceFile) || '';
880
+ types[typeName] = { description, properties };
881
+
882
+ // Recursively resolve types referenced in properties
883
+ for (const prop of Object.values(properties)) {
884
+ tryResolve(prop.type);
885
+ }
886
+ }
887
+ }
888
+ };
889
+
890
+ // Collect from method parameters and return types
891
+ for (const method of Object.values(methods)) {
892
+ for (const param of Object.values(method.parameters || {})) {
893
+ tryResolve(param.type);
894
+ }
895
+ if (method.returns) {
896
+ tryResolve(method.returns);
897
+ }
898
+ }
899
+
900
+ // Collect from getter return types
901
+ for (const getter of Object.values(getters)) {
902
+ if (getter.returns) {
903
+ tryResolve(getter.returns);
904
+ }
905
+ }
906
+
907
+ return types;
908
+ }
909
+
910
+ /**
911
+ * Extract concrete type names from a potentially complex type string.
912
+ * Handles generics, unions, intersections, arrays, and utility types.
913
+ */
914
+ private extractTypeNames(typeStr: string): string[] {
915
+ if (!typeStr) return [];
916
+
917
+ // Remove Promise<...> wrapper but keep the inner type
918
+ // Remove array suffix [], Partial<>, Omit<>, Pick<>, etc.
919
+ // Split on | and & for unions/intersections
920
+ const names: string[] = [];
921
+
922
+ // Match identifiers that look like type names (PascalCase or known patterns)
923
+ // This regex finds all capitalized identifiers that aren't JS built-ins
924
+ const matches = typeStr.match(/\b([A-Z][A-Za-z0-9_]*)\b/g) || [];
925
+ const BUILTIN_TYPES = new Set([
926
+ 'Promise', 'Array', 'Record', 'Map', 'Set', 'WeakMap', 'WeakSet',
927
+ 'Partial', 'Required', 'Readonly', 'Pick', 'Omit', 'Exclude', 'Extract',
928
+ 'Buffer', 'Date', 'RegExp', 'Error', 'Function', 'Symbol',
929
+ 'AsyncIterable', 'Iterable', 'Iterator', 'AsyncIterator',
930
+ 'InstanceType', 'ReturnType', 'Parameters',
931
+ 'HTMLElement', 'Event', 'EventTarget',
932
+ 'Stats', // Node.js fs.Stats — commonly used but not resolvable in-file
933
+ ]);
934
+
935
+ for (const match of matches) {
936
+ if (!BUILTIN_TYPES.has(match) && !IntrospectionScannerFeature.PRIMITIVE_TYPES.has(match.toLowerCase())) {
937
+ names.push(match);
938
+ }
939
+ }
940
+
941
+ return [...new Set(names)];
942
+ }
943
+
944
+ /**
945
+ * Like resolveTypeProperties but also captures whether each property is optional (has ?).
946
+ */
947
+ private resolveTypePropertiesWithOptional(typeName: string, sourceFile: ts.SourceFile): Record<string, { type: string; description: string; optional?: boolean }> | null {
948
+ for (const statement of sourceFile.statements) {
949
+ if (ts.isTypeAliasDeclaration(statement) && statement.name.text === typeName) {
950
+ if (ts.isTypeLiteralNode(statement.type)) {
951
+ return this.extractTypeLiteralMembersWithOptional(statement.type, sourceFile);
952
+ }
953
+ }
954
+ if (ts.isInterfaceDeclaration(statement) && statement.name.text === typeName) {
955
+ return this.extractInterfaceMembersWithOptional(statement, sourceFile);
956
+ }
957
+ }
958
+ return null;
959
+ }
960
+
961
+ private extractTypeLiteralMembersWithOptional(node: ts.TypeLiteralNode, sourceFile: ts.SourceFile): Record<string, { type: string; description: string; optional?: boolean }> | null {
962
+ const members: Record<string, { type: string; description: string; optional?: boolean }> = {};
963
+ for (const member of node.members) {
964
+ if (ts.isPropertySignature(member) && member.name) {
965
+ const name = member.name.getText();
966
+ const type = member.type ? member.type.getText() : 'any';
967
+ const description = this.extractJSDocFromNode(member, sourceFile) || '';
968
+ const optional = !!member.questionToken;
969
+ members[name] = { type, description, ...(optional ? { optional } : {}) };
970
+ }
971
+ }
972
+ return Object.keys(members).length > 0 ? members : null;
973
+ }
974
+
975
+ private extractInterfaceMembersWithOptional(node: ts.InterfaceDeclaration, sourceFile: ts.SourceFile): Record<string, { type: string; description: string; optional?: boolean }> | null {
976
+ const members: Record<string, { type: string; description: string; optional?: boolean }> = {};
977
+ for (const member of node.members) {
978
+ if (ts.isPropertySignature(member) && member.name) {
979
+ const name = member.name.getText();
980
+ const type = member.type ? member.type.getText() : 'any';
981
+ const description = this.extractJSDocFromNode(member, sourceFile) || '';
982
+ const optional = !!member.questionToken;
983
+ members[name] = { type, description, ...(optional ? { optional } : {}) };
984
+ }
985
+ }
986
+ return Object.keys(members).length > 0 ? members : null;
987
+ }
988
+
989
+ /**
990
+ * Extract the JSDoc description from a type alias or interface declaration.
991
+ */
992
+ private extractTypeDescription(typeName: string, sourceFile: ts.SourceFile): string | null {
993
+ for (const statement of sourceFile.statements) {
994
+ if (
995
+ (ts.isTypeAliasDeclaration(statement) || ts.isInterfaceDeclaration(statement)) &&
996
+ statement.name.text === typeName
997
+ ) {
998
+ return this.extractJSDocFromNode(statement, sourceFile);
999
+ }
1000
+ }
1001
+ return null;
1002
+ }
1003
+
1004
+ /**
1005
+ * Extracts a JSDoc description from any node that may have leading comments.
1006
+ */
1007
+ private extractJSDocFromNode(node: ts.Node, sourceFile: ts.SourceFile): string | null {
1008
+ const fullText = sourceFile.getFullText();
1009
+ const ranges = ts.getLeadingCommentRanges(fullText, node.getFullStart());
1010
+
1011
+ if (ranges && ranges.length > 0) {
1012
+ for (let i = ranges.length - 1; i >= 0; i--) {
1013
+ const range = ranges[i];
1014
+ if (!range) continue;
1015
+ const commentText = fullText.substring(range.pos, range.end);
1016
+
1017
+ if (commentText.startsWith('/**')) {
1018
+ const content = commentText.slice(3, -2);
1019
+ const lines = content.split('\n');
1020
+ const cleanLines: string[] = [];
1021
+
1022
+ for (const line of lines) {
1023
+ const cleaned = line.replace(/^\s*\*\s?/, '').trim();
1024
+ if (cleaned && !cleaned.startsWith('@')) {
1025
+ cleanLines.push(cleaned);
1026
+ } else if (cleaned.startsWith('@')) {
1027
+ break;
1028
+ }
1029
+ }
1030
+
1031
+ return cleanLines.join(' ').trim() || null;
1032
+ }
1033
+
1034
+ // Handle single-line // comments
1035
+ if (commentText.startsWith('//')) {
1036
+ return commentText.replace(/^\/\/\s*/, '').trim() || null;
1037
+ }
1038
+ }
1039
+ }
1040
+
1041
+ return null;
1042
+ }
1043
+
1044
+ private extractRequiredParameters(method: ts.MethodDeclaration): string[] {
1045
+ return method.parameters
1046
+ .filter(param => !param.questionToken && !param.initializer)
1047
+ .map(param => param.name.getText());
1048
+ }
1049
+
1050
+ private extractReturnType(method: ts.MethodDeclaration): string {
1051
+ return this.resolveReturnType(method, method.type, 'void');
1052
+ }
1053
+
1054
+ private extractEvents(classNode: ts.ClassDeclaration, sourceFile: ts.SourceFile): Record<string, EventIntrospection> {
1055
+ const events: Record<string, EventIntrospection> = {};
1056
+
1057
+ // Look for this.emit() calls in methods
1058
+ const visit = (node: ts.Node) => {
1059
+ if (ts.isCallExpression(node) &&
1060
+ ts.isPropertyAccessExpression(node.expression) &&
1061
+ node.expression.expression &&
1062
+ node.expression.expression.kind === ts.SyntaxKind.ThisKeyword &&
1063
+ node.expression.name.text === 'emit') {
1064
+
1065
+ if (node.arguments.length > 0 && ts.isStringLiteral(node.arguments[0]!)) {
1066
+ const eventName = node.arguments[0]!.text;
1067
+
1068
+ // Skip base class lifecycle events
1069
+ if (IntrospectionScannerFeature.BASE_EVENTS.has(eventName)) return;
1070
+
1071
+ if (!events[eventName]) {
1072
+ events[eventName] = {
1073
+ name: eventName,
1074
+ description: `Event emitted by ${classNode.name?.text || 'class'}`,
1075
+ arguments: {}
1076
+ };
1077
+ }
1078
+ }
1079
+ }
1080
+ ts.forEachChild(node, visit);
1081
+ };
1082
+
1083
+ for (const member of classNode.members) {
1084
+ if (ts.isMethodDeclaration(member)) {
1085
+ visit(member);
1086
+ }
1087
+ }
1088
+
1089
+ return events;
1090
+ }
1091
+
1092
+ private createRegistryScript(results: HelperIntrospection[], containerResults: Partial<ContainerIntrospection>[] = []): string {
1093
+ const hasContainers = containerResults.length > 0;
1094
+
1095
+ const importSource = this.options.importSource || './index.js';
1096
+ let imports = `import { setBuildTimeData`;
1097
+ if (hasContainers) {
1098
+ imports += `, setContainerBuildTimeData`;
1099
+ }
1100
+ imports += ` } from '${importSource}';\n\n`;
1101
+
1102
+ const registrations = results.map(result => {
1103
+ const data = JSON.stringify(result, null, 2);
1104
+ return `setBuildTimeData('${result.id}', ${data});`;
1105
+ }).join('\n\n');
1106
+
1107
+ let containerRegistrations = '';
1108
+ if (hasContainers) {
1109
+ containerRegistrations = '\n\n// Container introspection data\n' + containerResults.map(result => {
1110
+ const data = JSON.stringify(result, null, 2);
1111
+ return `setContainerBuildTimeData('${result.className}', ${data});`;
1112
+ }).join('\n\n');
1113
+ }
1114
+
1115
+ const exportStatement = `\nexport const introspectionData = ${JSON.stringify(results, null, 2)};\n`;
1116
+ const containerExport = hasContainers ? `\nexport const containerIntrospectionData = ${JSON.stringify(containerResults, null, 2)};\n` : '';
1117
+
1118
+ return `${imports}// Auto-generated introspection registry data\n// Generated at: ${new Date().toISOString()}\n\n${registrations}${containerRegistrations}${exportStatement}${containerExport}`;
1119
+ }
1120
+ }
1121
+
1122
+ // Register the feature
1123
+ import { features } from '../feature.js';
1124
+
1125
+ declare module '../feature.js' {
1126
+ interface AvailableFeatures {
1127
+ introspectionScanner: typeof IntrospectionScannerFeature;
1128
+ }
1129
+ }
1130
+
1131
+ export default features.register('introspectionScanner', IntrospectionScannerFeature);