@soederpop/luca 0.1.2 → 0.1.3

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 (366) hide show
  1. package/CLAUDE.md +2 -0
  2. package/assistants/codingAssistant/hooks.ts +1 -5
  3. package/assistants/inkbot/CORE.md +69 -0
  4. package/assistants/inkbot/hooks.ts +14 -0
  5. package/assistants/inkbot/tools.ts +47 -0
  6. package/commands/inkbot.ts +353 -0
  7. package/dist/agi/container.server.d.ts +63 -0
  8. package/dist/agi/container.server.d.ts.map +1 -0
  9. package/dist/agi/endpoints/ask.d.ts +20 -0
  10. package/dist/agi/endpoints/ask.d.ts.map +1 -0
  11. package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
  12. package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
  13. package/dist/agi/endpoints/conversations.d.ts +18 -0
  14. package/dist/agi/endpoints/conversations.d.ts.map +1 -0
  15. package/dist/agi/endpoints/experts.d.ts +8 -0
  16. package/dist/agi/endpoints/experts.d.ts.map +1 -0
  17. package/dist/agi/feature.d.ts +9 -0
  18. package/dist/agi/feature.d.ts.map +1 -0
  19. package/dist/agi/features/assistant.d.ts +509 -0
  20. package/dist/agi/features/assistant.d.ts.map +1 -0
  21. package/dist/agi/features/assistants-manager.d.ts +236 -0
  22. package/dist/agi/features/assistants-manager.d.ts.map +1 -0
  23. package/dist/agi/features/autonomous-assistant.d.ts +281 -0
  24. package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
  25. package/dist/agi/features/browser-use.d.ts +479 -0
  26. package/dist/agi/features/browser-use.d.ts.map +1 -0
  27. package/dist/agi/features/claude-code.d.ts +824 -0
  28. package/dist/agi/features/claude-code.d.ts.map +1 -0
  29. package/dist/agi/features/conversation-history.d.ts +245 -0
  30. package/dist/agi/features/conversation-history.d.ts.map +1 -0
  31. package/dist/agi/features/conversation.d.ts +464 -0
  32. package/dist/agi/features/conversation.d.ts.map +1 -0
  33. package/dist/agi/features/docs-reader.d.ts +72 -0
  34. package/dist/agi/features/docs-reader.d.ts.map +1 -0
  35. package/dist/agi/features/file-tools.d.ts +110 -0
  36. package/dist/agi/features/file-tools.d.ts.map +1 -0
  37. package/dist/agi/features/luca-coder.d.ts +323 -0
  38. package/dist/agi/features/luca-coder.d.ts.map +1 -0
  39. package/dist/agi/features/openai-codex.d.ts +381 -0
  40. package/dist/agi/features/openai-codex.d.ts.map +1 -0
  41. package/dist/agi/features/openapi.d.ts +200 -0
  42. package/dist/agi/features/openapi.d.ts.map +1 -0
  43. package/dist/agi/features/skills-library.d.ts +167 -0
  44. package/dist/agi/features/skills-library.d.ts.map +1 -0
  45. package/dist/agi/index.d.ts +5 -0
  46. package/dist/agi/index.d.ts.map +1 -0
  47. package/dist/agi/lib/interceptor-chain.d.ts +44 -0
  48. package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
  49. package/dist/agi/lib/token-counter.d.ts +13 -0
  50. package/dist/agi/lib/token-counter.d.ts.map +1 -0
  51. package/dist/bootstrap/generated.d.ts +5 -0
  52. package/dist/bootstrap/generated.d.ts.map +1 -0
  53. package/dist/browser.d.ts +12 -0
  54. package/dist/browser.d.ts.map +1 -0
  55. package/dist/bus.d.ts +29 -0
  56. package/dist/bus.d.ts.map +1 -0
  57. package/dist/cli/build-info.d.ts +4 -0
  58. package/dist/cli/build-info.d.ts.map +1 -0
  59. package/dist/cli/cli.d.ts +3 -0
  60. package/dist/cli/cli.d.ts.map +1 -0
  61. package/dist/client.d.ts +60 -0
  62. package/dist/client.d.ts.map +1 -0
  63. package/dist/clients/civitai/index.d.ts +472 -0
  64. package/dist/clients/civitai/index.d.ts.map +1 -0
  65. package/dist/clients/client-template.d.ts +30 -0
  66. package/dist/clients/client-template.d.ts.map +1 -0
  67. package/dist/clients/comfyui/index.d.ts +281 -0
  68. package/dist/clients/comfyui/index.d.ts.map +1 -0
  69. package/dist/clients/elevenlabs/index.d.ts +197 -0
  70. package/dist/clients/elevenlabs/index.d.ts.map +1 -0
  71. package/dist/clients/graph.d.ts +64 -0
  72. package/dist/clients/graph.d.ts.map +1 -0
  73. package/dist/clients/openai/index.d.ts +247 -0
  74. package/dist/clients/openai/index.d.ts.map +1 -0
  75. package/dist/clients/rest.d.ts +92 -0
  76. package/dist/clients/rest.d.ts.map +1 -0
  77. package/dist/clients/supabase/index.d.ts +176 -0
  78. package/dist/clients/supabase/index.d.ts.map +1 -0
  79. package/dist/clients/websocket.d.ts +127 -0
  80. package/dist/clients/websocket.d.ts.map +1 -0
  81. package/dist/command.d.ts +163 -0
  82. package/dist/command.d.ts.map +1 -0
  83. package/dist/commands/bootstrap.d.ts +20 -0
  84. package/dist/commands/bootstrap.d.ts.map +1 -0
  85. package/dist/commands/chat.d.ts +37 -0
  86. package/dist/commands/chat.d.ts.map +1 -0
  87. package/dist/commands/code.d.ts +28 -0
  88. package/dist/commands/code.d.ts.map +1 -0
  89. package/dist/commands/console.d.ts +22 -0
  90. package/dist/commands/console.d.ts.map +1 -0
  91. package/dist/commands/describe.d.ts +50 -0
  92. package/dist/commands/describe.d.ts.map +1 -0
  93. package/dist/commands/eval.d.ts +23 -0
  94. package/dist/commands/eval.d.ts.map +1 -0
  95. package/dist/commands/help.d.ts +25 -0
  96. package/dist/commands/help.d.ts.map +1 -0
  97. package/dist/commands/index.d.ts +18 -0
  98. package/dist/commands/index.d.ts.map +1 -0
  99. package/dist/commands/introspect.d.ts +24 -0
  100. package/dist/commands/introspect.d.ts.map +1 -0
  101. package/dist/commands/mcp.d.ts +35 -0
  102. package/dist/commands/mcp.d.ts.map +1 -0
  103. package/dist/commands/prompt.d.ts +38 -0
  104. package/dist/commands/prompt.d.ts.map +1 -0
  105. package/dist/commands/run.d.ts +24 -0
  106. package/dist/commands/run.d.ts.map +1 -0
  107. package/dist/commands/sandbox-mcp.d.ts +34 -0
  108. package/dist/commands/sandbox-mcp.d.ts.map +1 -0
  109. package/dist/commands/save-api-docs.d.ts +21 -0
  110. package/dist/commands/save-api-docs.d.ts.map +1 -0
  111. package/dist/commands/scaffold.d.ts +24 -0
  112. package/dist/commands/scaffold.d.ts.map +1 -0
  113. package/dist/commands/select.d.ts +22 -0
  114. package/dist/commands/select.d.ts.map +1 -0
  115. package/dist/commands/serve.d.ts +29 -0
  116. package/dist/commands/serve.d.ts.map +1 -0
  117. package/dist/container-describer.d.ts +144 -0
  118. package/dist/container-describer.d.ts.map +1 -0
  119. package/dist/container.d.ts +451 -0
  120. package/dist/container.d.ts.map +1 -0
  121. package/dist/endpoint.d.ts +113 -0
  122. package/dist/endpoint.d.ts.map +1 -0
  123. package/dist/feature.d.ts +47 -0
  124. package/dist/feature.d.ts.map +1 -0
  125. package/dist/graft.d.ts +29 -0
  126. package/dist/graft.d.ts.map +1 -0
  127. package/dist/hash-object.d.ts +8 -0
  128. package/dist/hash-object.d.ts.map +1 -0
  129. package/dist/helper.d.ts +209 -0
  130. package/dist/helper.d.ts.map +1 -0
  131. package/dist/introspection/generated.node.d.ts +44623 -0
  132. package/dist/introspection/generated.node.d.ts.map +1 -0
  133. package/dist/introspection/generated.web.d.ts +1412 -0
  134. package/dist/introspection/generated.web.d.ts.map +1 -0
  135. package/dist/introspection/index.d.ts +156 -0
  136. package/dist/introspection/index.d.ts.map +1 -0
  137. package/dist/introspection/scan.d.ts +147 -0
  138. package/dist/introspection/scan.d.ts.map +1 -0
  139. package/dist/node/container.d.ts +256 -0
  140. package/dist/node/container.d.ts.map +1 -0
  141. package/dist/node/feature.d.ts +9 -0
  142. package/dist/node/feature.d.ts.map +1 -0
  143. package/dist/node/features/container-link.d.ts +213 -0
  144. package/dist/node/features/container-link.d.ts.map +1 -0
  145. package/dist/node/features/content-db.d.ts +354 -0
  146. package/dist/node/features/content-db.d.ts.map +1 -0
  147. package/dist/node/features/disk-cache.d.ts +236 -0
  148. package/dist/node/features/disk-cache.d.ts.map +1 -0
  149. package/dist/node/features/dns.d.ts +511 -0
  150. package/dist/node/features/dns.d.ts.map +1 -0
  151. package/dist/node/features/docker.d.ts +485 -0
  152. package/dist/node/features/docker.d.ts.map +1 -0
  153. package/dist/node/features/downloader.d.ts +73 -0
  154. package/dist/node/features/downloader.d.ts.map +1 -0
  155. package/dist/node/features/figlet-fonts.d.ts +4 -0
  156. package/dist/node/features/figlet-fonts.d.ts.map +1 -0
  157. package/dist/node/features/file-manager.d.ts +177 -0
  158. package/dist/node/features/file-manager.d.ts.map +1 -0
  159. package/dist/node/features/fs.d.ts +635 -0
  160. package/dist/node/features/fs.d.ts.map +1 -0
  161. package/dist/node/features/git.d.ts +329 -0
  162. package/dist/node/features/git.d.ts.map +1 -0
  163. package/dist/node/features/google-auth.d.ts +200 -0
  164. package/dist/node/features/google-auth.d.ts.map +1 -0
  165. package/dist/node/features/google-calendar.d.ts +194 -0
  166. package/dist/node/features/google-calendar.d.ts.map +1 -0
  167. package/dist/node/features/google-docs.d.ts +138 -0
  168. package/dist/node/features/google-docs.d.ts.map +1 -0
  169. package/dist/node/features/google-drive.d.ts +202 -0
  170. package/dist/node/features/google-drive.d.ts.map +1 -0
  171. package/dist/node/features/google-mail.d.ts +221 -0
  172. package/dist/node/features/google-mail.d.ts.map +1 -0
  173. package/dist/node/features/google-sheets.d.ts +157 -0
  174. package/dist/node/features/google-sheets.d.ts.map +1 -0
  175. package/dist/node/features/grep.d.ts +207 -0
  176. package/dist/node/features/grep.d.ts.map +1 -0
  177. package/dist/node/features/helpers.d.ts +236 -0
  178. package/dist/node/features/helpers.d.ts.map +1 -0
  179. package/dist/node/features/ink.d.ts +332 -0
  180. package/dist/node/features/ink.d.ts.map +1 -0
  181. package/dist/node/features/ipc-socket.d.ts +298 -0
  182. package/dist/node/features/ipc-socket.d.ts.map +1 -0
  183. package/dist/node/features/json-tree.d.ts +140 -0
  184. package/dist/node/features/json-tree.d.ts.map +1 -0
  185. package/dist/node/features/networking.d.ts +373 -0
  186. package/dist/node/features/networking.d.ts.map +1 -0
  187. package/dist/node/features/nlp.d.ts +125 -0
  188. package/dist/node/features/nlp.d.ts.map +1 -0
  189. package/dist/node/features/opener.d.ts +93 -0
  190. package/dist/node/features/opener.d.ts.map +1 -0
  191. package/dist/node/features/os.d.ts +168 -0
  192. package/dist/node/features/os.d.ts.map +1 -0
  193. package/dist/node/features/package-finder.d.ts +419 -0
  194. package/dist/node/features/package-finder.d.ts.map +1 -0
  195. package/dist/node/features/postgres.d.ts +173 -0
  196. package/dist/node/features/postgres.d.ts.map +1 -0
  197. package/dist/node/features/proc.d.ts +285 -0
  198. package/dist/node/features/proc.d.ts.map +1 -0
  199. package/dist/node/features/process-manager.d.ts +427 -0
  200. package/dist/node/features/process-manager.d.ts.map +1 -0
  201. package/dist/node/features/python.d.ts +477 -0
  202. package/dist/node/features/python.d.ts.map +1 -0
  203. package/dist/node/features/redis.d.ts +247 -0
  204. package/dist/node/features/redis.d.ts.map +1 -0
  205. package/dist/node/features/repl.d.ts +84 -0
  206. package/dist/node/features/repl.d.ts.map +1 -0
  207. package/dist/node/features/runpod.d.ts +527 -0
  208. package/dist/node/features/runpod.d.ts.map +1 -0
  209. package/dist/node/features/secure-shell.d.ts +145 -0
  210. package/dist/node/features/secure-shell.d.ts.map +1 -0
  211. package/dist/node/features/semantic-search.d.ts +207 -0
  212. package/dist/node/features/semantic-search.d.ts.map +1 -0
  213. package/dist/node/features/sqlite.d.ts +180 -0
  214. package/dist/node/features/sqlite.d.ts.map +1 -0
  215. package/dist/node/features/telegram.d.ts +173 -0
  216. package/dist/node/features/telegram.d.ts.map +1 -0
  217. package/dist/node/features/transpiler.d.ts +51 -0
  218. package/dist/node/features/transpiler.d.ts.map +1 -0
  219. package/dist/node/features/tts.d.ts +108 -0
  220. package/dist/node/features/tts.d.ts.map +1 -0
  221. package/dist/node/features/ui.d.ts +562 -0
  222. package/dist/node/features/ui.d.ts.map +1 -0
  223. package/dist/node/features/vault.d.ts +90 -0
  224. package/dist/node/features/vault.d.ts.map +1 -0
  225. package/dist/node/features/vm.d.ts +285 -0
  226. package/dist/node/features/vm.d.ts.map +1 -0
  227. package/dist/node/features/yaml-tree.d.ts +118 -0
  228. package/dist/node/features/yaml-tree.d.ts.map +1 -0
  229. package/dist/node/features/yaml.d.ts +127 -0
  230. package/dist/node/features/yaml.d.ts.map +1 -0
  231. package/dist/node.d.ts +67 -0
  232. package/dist/node.d.ts.map +1 -0
  233. package/dist/python/generated.d.ts +2 -0
  234. package/dist/python/generated.d.ts.map +1 -0
  235. package/dist/react/index.d.ts +36 -0
  236. package/dist/react/index.d.ts.map +1 -0
  237. package/dist/registry.d.ts +97 -0
  238. package/dist/registry.d.ts.map +1 -0
  239. package/dist/scaffolds/generated.d.ts +13 -0
  240. package/dist/scaffolds/generated.d.ts.map +1 -0
  241. package/dist/scaffolds/template.d.ts +11 -0
  242. package/dist/scaffolds/template.d.ts.map +1 -0
  243. package/dist/schemas/base.d.ts +254 -0
  244. package/dist/schemas/base.d.ts.map +1 -0
  245. package/dist/selector.d.ts +130 -0
  246. package/dist/selector.d.ts.map +1 -0
  247. package/dist/server.d.ts +89 -0
  248. package/dist/server.d.ts.map +1 -0
  249. package/dist/servers/express.d.ts +104 -0
  250. package/dist/servers/express.d.ts.map +1 -0
  251. package/dist/servers/mcp.d.ts +201 -0
  252. package/dist/servers/mcp.d.ts.map +1 -0
  253. package/dist/servers/socket.d.ts +121 -0
  254. package/dist/servers/socket.d.ts.map +1 -0
  255. package/dist/state.d.ts +24 -0
  256. package/dist/state.d.ts.map +1 -0
  257. package/dist/web/clients/socket.d.ts +37 -0
  258. package/dist/web/clients/socket.d.ts.map +1 -0
  259. package/dist/web/container.d.ts +55 -0
  260. package/dist/web/container.d.ts.map +1 -0
  261. package/dist/web/extension.d.ts +4 -0
  262. package/dist/web/extension.d.ts.map +1 -0
  263. package/dist/web/feature.d.ts +8 -0
  264. package/dist/web/feature.d.ts.map +1 -0
  265. package/dist/web/features/asset-loader.d.ts +35 -0
  266. package/dist/web/features/asset-loader.d.ts.map +1 -0
  267. package/dist/web/features/container-link.d.ts +167 -0
  268. package/dist/web/features/container-link.d.ts.map +1 -0
  269. package/dist/web/features/esbuild.d.ts +51 -0
  270. package/dist/web/features/esbuild.d.ts.map +1 -0
  271. package/dist/web/features/helpers.d.ts +140 -0
  272. package/dist/web/features/helpers.d.ts.map +1 -0
  273. package/dist/web/features/network.d.ts +69 -0
  274. package/dist/web/features/network.d.ts.map +1 -0
  275. package/dist/web/features/speech.d.ts +71 -0
  276. package/dist/web/features/speech.d.ts.map +1 -0
  277. package/dist/web/features/vault.d.ts +62 -0
  278. package/dist/web/features/vault.d.ts.map +1 -0
  279. package/dist/web/features/vm.d.ts +48 -0
  280. package/dist/web/features/vm.d.ts.map +1 -0
  281. package/dist/web/features/voice-recognition.d.ts +96 -0
  282. package/dist/web/features/voice-recognition.d.ts.map +1 -0
  283. package/dist/web/shims/isomorphic-vm.d.ts +22 -0
  284. package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
  285. package/docs/apis/features/agi/assistant.md +1 -0
  286. package/docs/apis/features/agi/assistants-manager.md +62 -2
  287. package/docs/apis/features/agi/auto-assistant.md +11 -109
  288. package/docs/apis/features/agi/claude-code.md +138 -0
  289. package/docs/apis/features/agi/conversation.md +60 -31
  290. package/docs/apis/features/agi/luca-coder.md +407 -0
  291. package/docs/apis/features/agi/openapi.md +2 -2
  292. package/docs/apis/features/agi/skills-library.md +12 -0
  293. package/docs/apis/features/node/python.md +81 -11
  294. package/docs/apis/features/node/transpiler.md +74 -0
  295. package/docs/apis/features/web/esbuild.md +0 -6
  296. package/docs/apis/servers/mcp.md +2 -2
  297. package/docs/examples/entity.md +124 -0
  298. package/package.json +73 -21
  299. package/src/agi/feature.ts +13 -0
  300. package/src/agi/features/assistant.ts +36 -25
  301. package/src/agi/features/assistants-manager.ts +70 -5
  302. package/src/agi/features/autonomous-assistant.ts +1 -5
  303. package/src/agi/features/browser-use.ts +2 -2
  304. package/src/agi/features/claude-code.ts +165 -1
  305. package/src/agi/features/conversation-history.ts +2 -6
  306. package/src/agi/features/conversation.ts +95 -3
  307. package/src/agi/features/docs-reader.ts +2 -1
  308. package/src/agi/features/file-tools.ts +2 -2
  309. package/src/agi/features/luca-coder.ts +1 -5
  310. package/src/agi/features/openai-codex.ts +1 -1
  311. package/src/agi/features/openapi.ts +3 -3
  312. package/src/agi/features/skills-library.ts +87 -6
  313. package/src/agi/lib/interceptor-chain.ts +10 -0
  314. package/src/agi/lib/token-counter.ts +1 -1
  315. package/src/bootstrap/generated.ts +126 -1
  316. package/src/bus.ts +27 -5
  317. package/src/cli/build-info.ts +2 -2
  318. package/src/client.ts +2 -2
  319. package/src/clients/elevenlabs/index.ts +5 -0
  320. package/src/commands/bootstrap.ts +2 -1
  321. package/src/commands/chat.ts +1 -0
  322. package/src/commands/code.ts +4 -2
  323. package/src/commands/prompt.ts +34 -34
  324. package/src/commands/sandbox-mcp.ts +69 -163
  325. package/src/commands/save-api-docs.ts +10 -8
  326. package/src/commands/select.ts +8 -3
  327. package/src/container-describer.ts +70 -84
  328. package/src/container.ts +93 -3
  329. package/src/endpoint.ts +1 -1
  330. package/src/entity.ts +173 -0
  331. package/src/feature.ts +3 -3
  332. package/src/helper.ts +8 -4
  333. package/src/introspection/generated.agi.ts +1246 -798
  334. package/src/introspection/generated.node.ts +892 -798
  335. package/src/introspection/generated.web.ts +95 -3
  336. package/src/introspection/scan.ts +1 -1
  337. package/src/node/container.ts +1 -1
  338. package/src/node/features/content-db.ts +3 -3
  339. package/src/node/features/file-manager.ts +10 -9
  340. package/src/node/features/git.ts +5 -5
  341. package/src/node/features/helpers.ts +1 -1
  342. package/src/node/features/json-tree.ts +1 -1
  343. package/src/node/features/os.ts +3 -3
  344. package/src/node/features/package-finder.ts +1 -1
  345. package/src/node/features/process-manager.ts +1 -1
  346. package/src/node/features/python.ts +3 -3
  347. package/src/node/features/redis.ts +1 -1
  348. package/src/node/features/repl.ts +2 -2
  349. package/src/node/features/transpiler.ts +2 -2
  350. package/src/node/features/ui.ts +1 -1
  351. package/src/node/features/vm.ts +3 -3
  352. package/src/node/features/yaml-tree.ts +1 -1
  353. package/src/node.ts +1 -0
  354. package/src/python/generated.ts +1 -1
  355. package/src/scaffolds/generated.ts +1 -1
  356. package/src/selector.ts +74 -4
  357. package/src/server.ts +2 -2
  358. package/src/servers/mcp.ts +6 -6
  359. package/src/web/features/helpers.ts +1 -1
  360. package/src/web/features/network.ts +1 -0
  361. package/test/conversation.test.ts +220 -0
  362. package/tsconfig.build.json +12 -0
  363. package/tsconfig.json +1 -1
  364. package/scripts/examples/telegram-ink-ui.ts +0 -302
  365. package/scripts/examples/using-openai-codex.ts +0 -23
  366. package/scripts/examples/vm-loading-esm-modules.ts +0 -16
@@ -1,7 +1,7 @@
1
1
  import { setBuildTimeData, setContainerBuildTimeData } from './index.js';
2
2
 
3
3
  // Auto-generated introspection registry data
4
- // Generated at: 2026-03-30T06:52:54.962Z
4
+ // Generated at: 2026-04-03T01:24:52.187Z
5
5
 
6
6
  setBuildTimeData('features.containerLink', {
7
7
  "id": "features.containerLink",
@@ -767,7 +767,7 @@ setContainerBuildTimeData('Container', {
767
767
  "description": "The id of the feature to create."
768
768
  },
769
769
  "options": {
770
- "type": "ConstructorParameters<Features[T]>[0]",
770
+ "type": "FeatureInputOptions<Features>[T] | Record<string, unknown>",
771
771
  "description": "The options to pass to the feature constructor."
772
772
  }
773
773
  },
@@ -776,6 +776,52 @@ setContainerBuildTimeData('Container', {
776
776
  ],
777
777
  "returns": "InstanceType<Features[T]>"
778
778
  },
779
+ "entity": {
780
+ "description": "Creates a lightweight entity object with observable state, a typed event bus, and access to the container. Same id + options always returns the same cached base instance. An optional third argument auto-extends the entity with functions and getters. All extended methods and getters can access the entity (state, options, container, on/off/emit, etc.) via `this`.",
781
+ "parameters": {
782
+ "id": {
783
+ "type": "string",
784
+ "description": "Stable identifier for this entity (included in cache key)"
785
+ },
786
+ "options": {
787
+ "type": "TOptions",
788
+ "description": "Arbitrary options stored on `entity.options` (included in cache key)"
789
+ },
790
+ "extensions": {
791
+ "type": "Ext & ThisType<Entity<TState, TOptions, TEvents> & Ext>",
792
+ "description": "Optional object of functions/getters to graft onto the entity"
793
+ }
794
+ },
795
+ "required": [
796
+ "id"
797
+ ],
798
+ "returns": "Entity<TState, TOptions, TEvents> & Ext",
799
+ "examples": [
800
+ {
801
+ "language": "ts",
802
+ "code": "// Basic entity with typed state and events\nconst counter = container.entity<{ count: number }>('counter')\ncounter.setState({ count: 0 })\ncounter.on('tick', () => counter.setState(s => ({ count: s.count + 1 })))\n\n// With options and auto-extension\nconst user = container.entity('user:42', { name: 'Alice' }, {\n greet() { return `Hello ${this.options.name}` },\n get label() { return `User: ${this.options.name}` },\n})\nuser.greet() // \"Hello Alice\""
803
+ }
804
+ ]
805
+ },
806
+ "getHelperByUUID": {
807
+ "description": "Look up any helper instance (feature, client, server) by its UUID. Returns undefined if the UUID is unknown or the instance was never created.",
808
+ "parameters": {
809
+ "uuid": {
810
+ "type": "string",
811
+ "description": "The `instance.uuid` value assigned at construction time"
812
+ }
813
+ },
814
+ "required": [
815
+ "uuid"
816
+ ],
817
+ "returns": "Helper | undefined",
818
+ "examples": [
819
+ {
820
+ "language": "ts",
821
+ "code": "const assistant = container.feature('assistant')\nconst { uuid } = assistant\n// ... later ...\nconst same = container.getHelperByUUID(uuid) // === assistant"
822
+ }
823
+ ]
824
+ },
779
825
  "start": {
780
826
  "description": "Start the container. Emits the 'started' event and sets `state.started` to true. Plugins and features can listen for this event to perform initialization.",
781
827
  "parameters": {},
@@ -1841,7 +1887,7 @@ export const containerIntrospectionData = [
1841
1887
  "description": "The id of the feature to create."
1842
1888
  },
1843
1889
  "options": {
1844
- "type": "ConstructorParameters<Features[T]>[0]",
1890
+ "type": "FeatureInputOptions<Features>[T] | Record<string, unknown>",
1845
1891
  "description": "The options to pass to the feature constructor."
1846
1892
  }
1847
1893
  },
@@ -1850,6 +1896,52 @@ export const containerIntrospectionData = [
1850
1896
  ],
1851
1897
  "returns": "InstanceType<Features[T]>"
1852
1898
  },
1899
+ "entity": {
1900
+ "description": "Creates a lightweight entity object with observable state, a typed event bus, and access to the container. Same id + options always returns the same cached base instance. An optional third argument auto-extends the entity with functions and getters. All extended methods and getters can access the entity (state, options, container, on/off/emit, etc.) via `this`.",
1901
+ "parameters": {
1902
+ "id": {
1903
+ "type": "string",
1904
+ "description": "Stable identifier for this entity (included in cache key)"
1905
+ },
1906
+ "options": {
1907
+ "type": "TOptions",
1908
+ "description": "Arbitrary options stored on `entity.options` (included in cache key)"
1909
+ },
1910
+ "extensions": {
1911
+ "type": "Ext & ThisType<Entity<TState, TOptions, TEvents> & Ext>",
1912
+ "description": "Optional object of functions/getters to graft onto the entity"
1913
+ }
1914
+ },
1915
+ "required": [
1916
+ "id"
1917
+ ],
1918
+ "returns": "Entity<TState, TOptions, TEvents> & Ext",
1919
+ "examples": [
1920
+ {
1921
+ "language": "ts",
1922
+ "code": "// Basic entity with typed state and events\nconst counter = container.entity<{ count: number }>('counter')\ncounter.setState({ count: 0 })\ncounter.on('tick', () => counter.setState(s => ({ count: s.count + 1 })))\n\n// With options and auto-extension\nconst user = container.entity('user:42', { name: 'Alice' }, {\n greet() { return `Hello ${this.options.name}` },\n get label() { return `User: ${this.options.name}` },\n})\nuser.greet() // \"Hello Alice\""
1923
+ }
1924
+ ]
1925
+ },
1926
+ "getHelperByUUID": {
1927
+ "description": "Look up any helper instance (feature, client, server) by its UUID. Returns undefined if the UUID is unknown or the instance was never created.",
1928
+ "parameters": {
1929
+ "uuid": {
1930
+ "type": "string",
1931
+ "description": "The `instance.uuid` value assigned at construction time"
1932
+ }
1933
+ },
1934
+ "required": [
1935
+ "uuid"
1936
+ ],
1937
+ "returns": "Helper | undefined",
1938
+ "examples": [
1939
+ {
1940
+ "language": "ts",
1941
+ "code": "const assistant = container.feature('assistant')\nconst { uuid } = assistant\n// ... later ...\nconst same = container.getHelperByUUID(uuid) // === assistant"
1942
+ }
1943
+ ]
1944
+ },
1853
1945
  "start": {
1854
1946
  "description": "Start the container. Emits the 'started' event and sets `state.started` to true. Plugins and features can listen for this event to perform initialization.",
1855
1947
  "parameters": {},
@@ -587,7 +587,7 @@ export class IntrospectionScannerFeature extends Feature<IntrospectionScannerSta
587
587
  if (!commentText.startsWith('/**')) continue;
588
588
 
589
589
  const match = commentText.match(/@returns?\s*\{([^}]+)\}/);
590
- if (match) return match[1].trim();
590
+ if (match && match[1]) return match[1].trim();
591
591
  }
592
592
  }
593
593
 
@@ -366,7 +366,7 @@ export class NodeContainer<
366
366
  }
367
367
 
368
368
  /** Returns URL utility functions for parsing URIs. */
369
- get urlUtils(): { parse: (uri: string) => url.URL | null } {
369
+ get urlUtils(): { parse: (uri: string) => url.UrlWithStringQuery } {
370
370
  return {
371
371
  parse: (uri: string) => url.parse(uri)
372
372
  }
@@ -46,7 +46,7 @@ export class ContentDb extends Feature<ContentDbState, ContentDbOptions> {
46
46
  static { Feature.register(this, 'contentDb') }
47
47
 
48
48
  /** Tools that any assistant can use to progressively explore this collection. */
49
- static tools: Record<string, { schema: z.ZodType; handler?: Function }> = {
49
+ static override tools: Record<string, { schema: z.ZodType; handler?: Function }> = {
50
50
  getCollectionOverview: {
51
51
  schema: z.object({}).describe(
52
52
  'Get a high-level overview of the document collection: models, document counts, directory tree, and search index status. Call this first to understand what is available.'
@@ -460,7 +460,7 @@ export class ContentDb extends Feature<ContentDbState, ContentDbOptions> {
460
460
  // Dynamically import and attach SemanticSearch if not already registered
461
461
  const { SemanticSearch } = await import('./semantic-search.js')
462
462
  if (!this.container.features.available.includes('semanticSearch')) {
463
- SemanticSearch.attach(this.container as any)
463
+ ;(SemanticSearch as any).attach(this.container as any)
464
464
  }
465
465
 
466
466
  // Store search index in ~/.luca/contentbase/{hash}/ keyed by the real (symlink-resolved) collection path
@@ -660,7 +660,7 @@ export class ContentDb extends Feature<ContentDbState, ContentDbOptions> {
660
660
  get queries(): Record<string, ReturnType<typeof this.query>> {
661
661
  const queryChains: [string, ReturnType<typeof this.query>][] = []
662
662
  for (const modelName of this.modelNames) {
663
- const queryChain = this.query(this.models[modelName])
663
+ const queryChain = this.query(this.models[modelName]!)
664
664
  const pluralized = this.container.utils.stringUtils.pluralize(modelName).toLowerCase()
665
665
  queryChains.push([modelName.toLowerCase(), queryChain])
666
666
  queryChains.push([pluralized, queryChain])
@@ -147,7 +147,7 @@ export class FileManager<
147
147
 
148
148
  /** Returns the list of directories currently being watched. */
149
149
  get watchedPaths(): string[] {
150
- return this.state.get("watchedPaths") || [];
150
+ return (this.state.get("watchedPaths") as string[] | undefined) || [];
151
151
  }
152
152
 
153
153
  /**
@@ -199,7 +199,7 @@ export class FileManager<
199
199
  const { git } = this.container;
200
200
  if (!git.isRepo) return null;
201
201
 
202
- const gitDir = pathJoin(git.repoRoot, '.git');
202
+ const gitDir = pathJoin(git.repoRoot!, '.git');
203
203
  const head = readFileSync(pathJoin(gitDir, 'HEAD'), 'utf8').trim();
204
204
 
205
205
  // Detached HEAD — already a sha
@@ -217,7 +217,7 @@ export class FileManager<
217
217
  const ref = head.slice(5);
218
218
  const packed = readFileSync(packedRefsPath, 'utf8');
219
219
  const match = packed.match(new RegExp(`^([0-9a-f]{40}) ${ref}`, 'm'));
220
- if (match) return match[1];
220
+ if (match) return match[1] ?? null;
221
221
  }
222
222
 
223
223
  return null;
@@ -334,8 +334,8 @@ export class FileManager<
334
334
  if (cwdRelative) {
335
335
  const prefix = cwdRelative + '/';
336
336
  for (let i = 0; i < fileIds.length; i++) {
337
- if (fileIds[i].startsWith(prefix)) {
338
- fileIds[i] = fileIds[i].slice(prefix.length);
337
+ if (fileIds[i]!.startsWith(prefix)) {
338
+ fileIds[i] = fileIds[i]!.slice(prefix.length);
339
339
  }
340
340
  }
341
341
  }
@@ -422,12 +422,12 @@ export class FileManager<
422
422
 
423
423
  // If already watching, just add the new paths
424
424
  if (this.isWatching && this.watcher) {
425
- const currentPaths: string[] = this.state.get("watchedPaths") || [];
425
+ const currentPaths: string[] = (this.state.get("watchedPaths") as string[] | undefined) || [];
426
426
  const newPaths = pathsToWatch.filter(p => !currentPaths.includes(p));
427
427
 
428
428
  if (newPaths.length) {
429
429
  this.watcher.add(newPaths);
430
- this.state.set("watchedPaths", [...currentPaths, ...newPaths]);
430
+ this.state.set("watchedPaths", [...currentPaths, ...newPaths] as any);
431
431
  }
432
432
 
433
433
  return;
@@ -481,7 +481,7 @@ export class FileManager<
481
481
 
482
482
  watcher.on("ready", () => {
483
483
  this.state.set("watching", true);
484
- this.state.set("watchedPaths", pathsToWatch);
484
+ this.state.set("watchedPaths", pathsToWatch as any);
485
485
  });
486
486
 
487
487
  this.watcher = watcher;
@@ -495,7 +495,7 @@ export class FileManager<
495
495
  if (this.watcher) {
496
496
  this.watcher.close();
497
497
  this.state.set("watching", false);
498
- this.state.set("watchedPaths", []);
498
+ this.state.set("watchedPaths", [] as any);
499
499
  this.watcher = null;
500
500
  }
501
501
  }
@@ -508,6 +508,7 @@ export class FileManager<
508
508
  const stats = statSync(absolutePath);
509
509
  this.files.set(path, {
510
510
  dirname: dir,
511
+ relativeDirname: this.container.paths.relative(dir),
511
512
  absolutePath,
512
513
  relativePath: path,
513
514
  name,
@@ -155,7 +155,7 @@ export class Git extends Feature {
155
155
  */
156
156
  get branch(): string | null {
157
157
  if(!this.isRepo) { return null }
158
- return this.container.feature('proc').exec(`${this.gitPath} branch`).split("\n").filter(line => line.startsWith('*')).map(line => line.replace('*', '').trim()).pop()
158
+ return this.container.feature('proc').exec(`${this.gitPath} branch`).split("\n").filter(line => line.startsWith('*')).map(line => line.replace('*', '').trim()).pop() ?? null
159
159
  }
160
160
 
161
161
  /**
@@ -230,7 +230,7 @@ export class Git extends Feature {
230
230
  */
231
231
  get repoRoot(): string | null {
232
232
  if (this.state.has('repoRoot')) {
233
- return this.state.get('repoRoot')
233
+ return this.state.get('repoRoot') ?? null
234
234
  }
235
235
 
236
236
  const repoRoot = this.container.fs.findUp('.git')
@@ -507,12 +507,12 @@ export class Git extends Feature {
507
507
  if (str.startsWith('github.com/')) str = str.replace('github.com/', '')
508
508
  if (str.includes('#')) {
509
509
  const parts = str.split('#')
510
- str = parts[0]
511
- ref = parts[1]
510
+ str = parts[0] ?? str
511
+ ref = parts[1] ?? ref
512
512
  }
513
513
 
514
514
  const parts = str.split('/')
515
- return { user: parts[0], repo: parts[1], ref, subdir: parts.slice(2).join('/') }
515
+ return { user: parts[0] ?? '', repo: parts[1] ?? '', ref, subdir: parts.slice(2).join('/') }
516
516
  }
517
517
 
518
518
  /**
@@ -201,7 +201,7 @@ export class Helpers extends Feature<HelpersState, HelpersOptions> {
201
201
  }
202
202
 
203
203
  // Schemas
204
- const schemasModule = { CommandOptionsSchema: commands.baseClass?.optionsSchema || z.object({}) }
204
+ const schemasModule: Record<string, any> = { CommandOptionsSchema: commands.baseClass?.optionsSchema || z.object({}) }
205
205
  try {
206
206
  // Pull all base schemas from the already-loaded schemas/base module
207
207
  const baseSchemas = require('../../schemas/base.js')
@@ -121,7 +121,7 @@ export class JsonTree<T extends JsonTreeState = JsonTreeState> extends Feature<T
121
121
  for (const file of jsonFiles.filter(Boolean)) {
122
122
  if (file?.relativePath) {
123
123
  const fileContent = fileSystem.readFile(file.relativePath);
124
- const fileData = JSON.parse(fileContent);
124
+ const fileData = JSON.parse(String(fileContent));
125
125
  const path = file.relativePath
126
126
  .replace(/\.json$/, "")
127
127
  .replace(basePath + "/", "")
@@ -207,12 +207,12 @@ export class OS extends Feature {
207
207
  displays.push({
208
208
  name: d._name ?? 'Unknown',
209
209
  resolution: {
210
- width: resMatch ? parseInt(resMatch[1], 10) : 0,
211
- height: resMatch ? parseInt(resMatch[2], 10) : 0,
210
+ width: resMatch ? parseInt(resMatch[1] ?? '0', 10) : 0,
211
+ height: resMatch ? parseInt(resMatch[2] ?? '0', 10) : 0,
212
212
  },
213
213
  retina: /retina/i.test(d._spdisplays_resolution ?? '') || /retina/i.test(d.spdisplays_display_type ?? ''),
214
214
  main: d.spdisplays_main === 'spdisplays_yes' || /yes/i.test(d.spdisplays_main ?? ''),
215
- refreshRate: hzMatch ? parseFloat(hzMatch[1]) : undefined,
215
+ refreshRate: hzMatch ? parseFloat(hzMatch[1] ?? '0') : undefined,
216
216
  connectionType: d.spdisplays_connection_type ?? undefined,
217
217
  })
218
218
  }
@@ -296,7 +296,7 @@ export class PackageFinder<
296
296
  */
297
297
  get scopes(): string[] {
298
298
  return Array.from(
299
- new Set(this.packageNames.filter(p => p.startsWith('@')).map(p => p.split('/')[0]))
299
+ new Set(this.packageNames.filter(p => p.startsWith('@')).map(p => p.split('/')[0]).filter((s): s is string => s !== undefined))
300
300
  )
301
301
  }
302
302
 
@@ -436,7 +436,7 @@ export class ProcessManager extends Feature {
436
436
  static { Feature.register(this, 'processManager') }
437
437
 
438
438
  /** Tools that an assistant can use to spawn and manage processes. */
439
- static tools: Record<string, { schema: z.ZodType; handler?: Function }> = {
439
+ static override tools: Record<string, { schema: z.ZodType; handler?: Function }> = {
440
440
  spawnProcess: {
441
441
  schema: z.object({
442
442
  command: z.string().describe('The command to execute (e.g. "node", "bun", "python")'),
@@ -59,7 +59,7 @@ export const PythonEventsSchema = FeatureEventsSchema.extend({
59
59
  }).describe('Install result')]).describe('When dependency installation fails'),
60
60
  codeExecuted: z.tuple([z.object({
61
61
  code: z.string().describe('The Python code that was executed'),
62
- variables: z.record(z.any()).describe('Variables passed to the execution'),
62
+ variables: z.record(z.string(), z.any()).describe('Variables passed to the execution'),
63
63
  result: z.object({
64
64
  stdout: z.string().describe('Standard output'),
65
65
  stderr: z.string().describe('Standard error'),
@@ -68,7 +68,7 @@ export const PythonEventsSchema = FeatureEventsSchema.extend({
68
68
  }).describe('Code execution details')]).describe('When Python code finishes executing'),
69
69
  fileExecuted: z.tuple([z.object({
70
70
  filePath: z.string().describe('Path to the executed Python file'),
71
- variables: z.record(z.any()).describe('Variables passed as arguments'),
71
+ variables: z.record(z.string(), z.any()).describe('Variables passed as arguments'),
72
72
  result: z.object({
73
73
  stdout: z.string().describe('Standard output'),
74
74
  stderr: z.string().describe('Standard error'),
@@ -532,7 +532,7 @@ export class Python<
532
532
  */
533
533
  private _parsePythonCommand(extraArgs: string[]): { command: string, args: string[] } {
534
534
  const parts = this.pythonPath.split(/\s+/)
535
- return { command: parts[0], args: [...parts.slice(1), ...extraArgs] }
535
+ return { command: parts[0] ?? 'python', args: [...parts.slice(1), ...extraArgs] }
536
536
  }
537
537
 
538
538
  /**
@@ -400,7 +400,7 @@ export class RedisFeature extends Feature<RedisState, RedisOptions> {
400
400
  )
401
401
 
402
402
  if (existing) {
403
- if (existing.state !== 'running') {
403
+ if (existing.status !== 'running') {
404
404
  await docker.startContainer(name)
405
405
  }
406
406
  return existing.id
@@ -101,7 +101,7 @@ export class Repl<
101
101
 
102
102
  // Load existing history
103
103
  try {
104
- const content = fs.readFile(this._historyPath, 'utf-8')
104
+ const content = this.container.fs.readFile(this._historyPath, 'utf-8') as string
105
105
  this._history = content.split('\n').filter(Boolean).reverse()
106
106
  } catch {}
107
107
 
@@ -204,7 +204,7 @@ export class Repl<
204
204
  private _saveHistory(line: string) {
205
205
  if (!this._historyPath || !line.trim()) return
206
206
  try {
207
- fs.appendFileSync(this._historyPath, line + '\n')
207
+ this.container.fs.appendFile(this._historyPath, line + '\n')
208
208
  } catch {}
209
209
  }
210
210
  }
@@ -45,8 +45,8 @@ function esmToCjs(code: string): string {
45
45
  .replace(/^export\s+\{([^}]*)\}\s*;?$/gm, (_match, body: string) => {
46
46
  return body.split(',').map(s => {
47
47
  const parts = s.trim().split(/\s+as\s+/)
48
- const local = parts[0].trim()
49
- const exported = (parts[1] || parts[0]).trim()
48
+ const local = (parts[0] ?? '').trim()
49
+ const exported = (parts[1] ?? parts[0] ?? '').trim()
50
50
  return local ? `exports['${exported}'] = ${local};` : ''
51
51
  }).filter(Boolean).join(' ')
52
52
  })
@@ -2,7 +2,7 @@ import { z } from 'zod'
2
2
  import { FeatureStateSchema } from '../../schemas/base.js'
3
3
  import { Feature } from "../feature.js";
4
4
  import colors from "chalk";
5
- import type { Fonts } from "figlet";
5
+ import type { FontName as Fonts } from "figlet";
6
6
  import { figlet, fontNames } from "./figlet-fonts.js";
7
7
  import inquirer from "inquirer";
8
8
  import { marked } from 'marked';
@@ -219,9 +219,9 @@ export class VM<
219
219
 
220
220
  // Find the last non-empty line
221
221
  let lastIdx = lines.length - 1
222
- while (lastIdx > 0 && !lines[lastIdx].trim()) lastIdx--
222
+ while (lastIdx > 0 && !(lines[lastIdx] ?? '').trim()) lastIdx--
223
223
 
224
- let lastLine = lines[lastIdx]!
224
+ let lastLine = lines[lastIdx] ?? ''
225
225
 
226
226
  // For single-line code with semicolons (e.g. CLI eval), split the last line
227
227
  // into statements and only try to return the final statement.
@@ -390,7 +390,7 @@ export class VM<
390
390
  if (!fs.exists(filePath)) return {}
391
391
 
392
392
  const raw = fs.readFile(filePath)
393
- const { code } = this.container.feature('transpiler').transformSync(raw, { format: 'cjs' })
393
+ const { code } = this.container.feature('transpiler').transformSync(String(raw), { format: 'cjs' })
394
394
 
395
395
  const sharedExports = {}
396
396
  const { context } = this.performSync(code, {
@@ -113,7 +113,7 @@ export class YamlTree<T extends YamlTreeState = YamlTreeState> extends Feature<T
113
113
  for (const file of yamlFiles.filter(Boolean)) {
114
114
  if(file?.relativePath) {
115
115
  const fileContent = fileSystem.readFile(file.relativePath);
116
- const fileData = yamlFeature.parse(fileContent);
116
+ const fileData = yamlFeature.parse(String(fileContent));
117
117
  const path = file.relativePath.replace(/\.ya?ml$/, "").replace(basePath + "/", "").split("/").filter(v => v?.length).map(p => camelCase(p));
118
118
  set(tree, path, fileData)
119
119
  }
package/src/node.ts CHANGED
@@ -65,6 +65,7 @@ export type { AvailableFeatures, FeatureOptions, FeatureState } from './feature'
65
65
  export type { NodeContainer, NodeFeatures } from './node/container'
66
66
  export type { AvailableServers, StartOptions, ServersInterface } from './server'
67
67
  export type { HelperState, HelperOptions } from './helper'
68
+ export type { Entity } from './entity'
68
69
  export type { EventMap } from './bus'
69
70
  export type { SetStateValue, StateChangeType } from './state'
70
71
 
@@ -1,5 +1,5 @@
1
1
  // Auto-generated Python bridge script
2
- // Generated at: 2026-03-30T06:52:57.841Z
2
+ // Generated at: 2026-04-03T01:24:54.795Z
3
3
  // Source: src/python/bridge.py
4
4
  //
5
5
  // Do not edit manually. Run: luca build-python-bridge
@@ -1,5 +1,5 @@
1
1
  // Auto-generated scaffold and MCP readme content
2
- // Generated at: 2026-03-30T06:52:56.013Z
2
+ // Generated at: 2026-04-03T01:24:53.146Z
3
3
  // Source: docs/scaffolds/*.md, docs/examples/assistant/, and docs/mcp/readme.md
4
4
  //
5
5
  // Do not edit manually. Run: luca build-scaffolds
package/src/selector.ts CHANGED
@@ -135,17 +135,17 @@ export class Selector<
135
135
  }
136
136
 
137
137
  // Run the selector
138
- this.state.set('running' as any, true)
138
+ this.state.set('running' as any, true as any)
139
139
  this.emit('started' as any)
140
140
 
141
141
  let data: any
142
142
  try {
143
143
  data = await this.run(parsed, this.context)
144
- this.state.set('running' as any, false)
145
- this.state.set('lastRanAt' as any, Date.now())
144
+ this.state.set('running' as any, false as any)
145
+ this.state.set('lastRanAt' as any, Date.now() as any)
146
146
  this.emit('completed' as any, data)
147
147
  } catch (err: any) {
148
- this.state.set('running' as any, false)
148
+ this.state.set('running' as any, false as any)
149
149
  this.emit('failed' as any, err)
150
150
  throw err
151
151
  }
@@ -197,6 +197,76 @@ export class SelectorsRegistry extends Registry<Selector<any>> {
197
197
  override scope = 'selectors'
198
198
  override baseClass = Selector as any
199
199
 
200
+ /**
201
+ * Convert all registered selectors into a `{ schemas, handlers }` object
202
+ * compatible with `assistant.use()`.
203
+ *
204
+ * Each selector becomes a tool whose parameters come from the selector's
205
+ * `argsSchema` (with internal fields stripped) and whose handler dispatches
206
+ * the selector and returns the data directly (cache metadata is not exposed).
207
+ *
208
+ * @param container - The container used to instantiate and run selectors
209
+ * @param options - Optional filter/transform options
210
+ * @param options.include - Only include these selector names (default: all)
211
+ * @param options.exclude - Exclude these selector names (default: none)
212
+ * @param options.prefix - Prefix tool names (e.g. 'sel_' → 'sel_packageInfo')
213
+ */
214
+ toTools(
215
+ container: Container<any> & SelectorsInterface,
216
+ options?: { include?: string[], exclude?: string[], prefix?: string },
217
+ ): { schemas: Record<string, z.ZodType>, handlers: Record<string, Function> } {
218
+ const schemas: Record<string, z.ZodType> = {}
219
+ const handlers: Record<string, Function> = {}
220
+ const prefix = options?.prefix ?? ''
221
+ const includeSet = options?.include ? new Set(options.include) : null
222
+ const excludeSet = new Set(options?.exclude ?? [])
223
+
224
+ // Internal fields from HelperOptionsSchema and SelectorOptionsSchema
225
+ const internalFields = ['name', '_cacheKey', 'dispatchSource']
226
+
227
+ for (const name of this.available) {
228
+ if (excludeSet.has(name)) continue
229
+ if (includeSet && !includeSet.has(name)) continue
230
+
231
+ const Sel = this.lookup(name) as typeof Selector
232
+ const rawSchema = Sel.argsSchema
233
+ const description = Sel.selectorDescription || Sel.description || name
234
+
235
+ let toolSchema: z.ZodType
236
+ try {
237
+ const shape = typeof (rawSchema as any)?._def?.shape === 'function'
238
+ ? (rawSchema as any)._def.shape()
239
+ : (rawSchema as any)?._def?.shape
240
+
241
+ if (shape) {
242
+ const cleanShape: Record<string, z.ZodType> = {}
243
+ for (const [key, val] of Object.entries(shape)) {
244
+ if (internalFields.includes(key)) continue
245
+ cleanShape[key] = val as z.ZodType
246
+ }
247
+
248
+ toolSchema = Object.keys(cleanShape).length > 0
249
+ ? z.object(cleanShape).describe(description)
250
+ : z.object({}).describe(description)
251
+ } else {
252
+ toolSchema = z.object({}).describe(description)
253
+ }
254
+ } catch {
255
+ toolSchema = z.object({}).describe(description)
256
+ }
257
+
258
+ const toolName = `${prefix}${name}`
259
+ schemas[toolName] = toolSchema
260
+ handlers[toolName] = async (args: Record<string, any>) => {
261
+ const sel = (container.select as any)(name)
262
+ const result = await sel.select(args ?? {})
263
+ return result.data
264
+ }
265
+ }
266
+
267
+ return { schemas, handlers }
268
+ }
269
+
200
270
  /**
201
271
  * Discover and register selectors from a directory.
202
272
  * Detection order:
package/src/server.ts CHANGED
@@ -30,7 +30,7 @@ export class Server<T extends ServerState = ServerState, K extends ServerOptions
30
30
  static override eventsSchema = ServerEventsSchema
31
31
 
32
32
  /** Self-register a Server subclass from a static initialization block. */
33
- static register: (SubClass: typeof Server, id?: string) => typeof Server
33
+ static register: (SubClass: abstract new (options: any, context: any) => Server, id?: string) => abstract new (options: any, context: any) => Server
34
34
 
35
35
  override get initialState() : T {
36
36
  return ({
@@ -203,7 +203,7 @@ export const helperCache = new Map()
203
203
  * ```
204
204
  */
205
205
  Server.register = function registerServer(
206
- SubClass: typeof Server,
206
+ SubClass: abstract new (options: any, context: any) => Server,
207
207
  id?: string,
208
208
  ) {
209
209
  const registryId = id ?? SubClass.name[0]!.toLowerCase() + SubClass.name.slice(1)
@@ -33,9 +33,9 @@ export type MCPContext = {
33
33
  export interface RegisteredTool {
34
34
  name: string
35
35
  description?: string
36
- schema?: z.ZodObject<any>
36
+ schema?: z.ZodType
37
37
  jsonSchema?: Record<string, any>
38
- handler: (args: any, ctx: MCPContext) => any
38
+ handler: Function
39
39
  }
40
40
 
41
41
  /** A registered MCP resource with its URI, metadata, and handler. */
@@ -61,9 +61,9 @@ export type PromptMessage = {
61
61
  }
62
62
 
63
63
  type ToolRegistrationOptions = {
64
- schema?: z.ZodObject<any>
64
+ schema?: z.ZodType
65
65
  description?: string
66
- handler: (args: any, ctx: MCPContext) => any
66
+ handler?: Function | ((args: any, ctx: any) => any)
67
67
  }
68
68
 
69
69
  type ResourceRegistrationOptions = {
@@ -340,7 +340,7 @@ export class MCPServer extends Server<MCPServerState, MCPServerOptions> {
340
340
  * @param name - Unique tool name
341
341
  * @param options - Tool schema, description, and handler
342
342
  */
343
- tool(name: string, options: ToolRegistrationOptions): this {
343
+ override tool(name: string, options: ToolRegistrationOptions): this {
344
344
  let jsonSchema: Record<string, any> | undefined
345
345
 
346
346
  if (options.schema) {
@@ -357,7 +357,7 @@ export class MCPServer extends Server<MCPServerState, MCPServerOptions> {
357
357
  description: options.description,
358
358
  schema: options.schema,
359
359
  jsonSchema,
360
- handler: options.handler,
360
+ handler: options.handler ?? (() => {}),
361
361
  }
362
362
 
363
363
  this._tools.set(name, registered)