luca 2.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/.github/workflows/release.yaml +170 -0
  2. package/AGENTS.md +99 -0
  3. package/CLAUDE.md +123 -0
  4. package/CNAME +1 -0
  5. package/README.md +275 -9
  6. package/RUNME.md +56 -0
  7. package/assistants/codingAssistant/ABOUT.md +5 -0
  8. package/assistants/codingAssistant/CORE.md +33 -0
  9. package/assistants/codingAssistant/hooks.ts +21 -0
  10. package/assistants/codingAssistant/tools.ts +12 -0
  11. package/assistants/inkbot/ABOUT.md +16 -0
  12. package/assistants/inkbot/CORE.md +330 -0
  13. package/assistants/inkbot/hooks.ts +6 -0
  14. package/assistants/inkbot/tools.ts +53 -0
  15. package/assistants/researcher/ABOUT.md +5 -0
  16. package/assistants/researcher/CORE.md +46 -0
  17. package/assistants/researcher/hooks.ts +16 -0
  18. package/assistants/researcher/tools.ts +237 -0
  19. package/bun.lock +2667 -0
  20. package/bunfig.toml +3 -0
  21. package/commands/audit-docs.ts +740 -0
  22. package/commands/build-bootstrap.ts +117 -0
  23. package/commands/build-python-bridge.ts +42 -0
  24. package/commands/build-scaffolds.ts +175 -0
  25. package/commands/bundle-consumer-project.ts +521 -0
  26. package/commands/generate-api-docs.ts +114 -0
  27. package/commands/inkbot.ts +874 -0
  28. package/commands/release.ts +80 -0
  29. package/commands/try-all-challenges.ts +543 -0
  30. package/commands/try-challenge.ts +100 -0
  31. package/dist/agi/container.server.d.ts +63 -0
  32. package/dist/agi/container.server.d.ts.map +1 -0
  33. package/dist/agi/endpoints/ask.d.ts +20 -0
  34. package/dist/agi/endpoints/ask.d.ts.map +1 -0
  35. package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
  36. package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
  37. package/dist/agi/endpoints/conversations.d.ts +18 -0
  38. package/dist/agi/endpoints/conversations.d.ts.map +1 -0
  39. package/dist/agi/endpoints/experts.d.ts +8 -0
  40. package/dist/agi/endpoints/experts.d.ts.map +1 -0
  41. package/dist/agi/feature.d.ts +9 -0
  42. package/dist/agi/feature.d.ts.map +1 -0
  43. package/dist/agi/features/assistant.d.ts +509 -0
  44. package/dist/agi/features/assistant.d.ts.map +1 -0
  45. package/dist/agi/features/assistants-manager.d.ts +236 -0
  46. package/dist/agi/features/assistants-manager.d.ts.map +1 -0
  47. package/dist/agi/features/autonomous-assistant.d.ts +281 -0
  48. package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
  49. package/dist/agi/features/browser-use.d.ts +479 -0
  50. package/dist/agi/features/browser-use.d.ts.map +1 -0
  51. package/dist/agi/features/claude-code.d.ts +824 -0
  52. package/dist/agi/features/claude-code.d.ts.map +1 -0
  53. package/dist/agi/features/conversation-history.d.ts +245 -0
  54. package/dist/agi/features/conversation-history.d.ts.map +1 -0
  55. package/dist/agi/features/conversation.d.ts +464 -0
  56. package/dist/agi/features/conversation.d.ts.map +1 -0
  57. package/dist/agi/features/docs-reader.d.ts +72 -0
  58. package/dist/agi/features/docs-reader.d.ts.map +1 -0
  59. package/dist/agi/features/file-tools.d.ts +110 -0
  60. package/dist/agi/features/file-tools.d.ts.map +1 -0
  61. package/dist/agi/features/luca-coder.d.ts +323 -0
  62. package/dist/agi/features/luca-coder.d.ts.map +1 -0
  63. package/dist/agi/features/openai-codex.d.ts +381 -0
  64. package/dist/agi/features/openai-codex.d.ts.map +1 -0
  65. package/dist/agi/features/openapi.d.ts +200 -0
  66. package/dist/agi/features/openapi.d.ts.map +1 -0
  67. package/dist/agi/features/skills-library.d.ts +167 -0
  68. package/dist/agi/features/skills-library.d.ts.map +1 -0
  69. package/dist/agi/index.d.ts +5 -0
  70. package/dist/agi/index.d.ts.map +1 -0
  71. package/dist/agi/lib/interceptor-chain.d.ts +44 -0
  72. package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
  73. package/dist/agi/lib/token-counter.d.ts +13 -0
  74. package/dist/agi/lib/token-counter.d.ts.map +1 -0
  75. package/dist/bootstrap/generated.d.ts +5 -0
  76. package/dist/bootstrap/generated.d.ts.map +1 -0
  77. package/dist/browser.d.ts +12 -0
  78. package/dist/browser.d.ts.map +1 -0
  79. package/dist/bus.d.ts +29 -0
  80. package/dist/bus.d.ts.map +1 -0
  81. package/dist/cli/build-info.d.ts +4 -0
  82. package/dist/cli/build-info.d.ts.map +1 -0
  83. package/dist/cli/cli.d.ts +3 -12
  84. package/dist/cli/cli.d.ts.map +1 -0
  85. package/dist/client.d.ts +60 -0
  86. package/dist/client.d.ts.map +1 -0
  87. package/dist/clients/civitai/index.d.ts +472 -0
  88. package/dist/clients/civitai/index.d.ts.map +1 -0
  89. package/dist/clients/client-template.d.ts +30 -0
  90. package/dist/clients/client-template.d.ts.map +1 -0
  91. package/dist/clients/comfyui/index.d.ts +281 -0
  92. package/dist/clients/comfyui/index.d.ts.map +1 -0
  93. package/dist/clients/elevenlabs/index.d.ts +197 -0
  94. package/dist/clients/elevenlabs/index.d.ts.map +1 -0
  95. package/dist/clients/graph.d.ts +64 -0
  96. package/dist/clients/graph.d.ts.map +1 -0
  97. package/dist/clients/openai/index.d.ts +247 -0
  98. package/dist/clients/openai/index.d.ts.map +1 -0
  99. package/dist/clients/rest.d.ts +92 -0
  100. package/dist/clients/rest.d.ts.map +1 -0
  101. package/dist/clients/supabase/index.d.ts +176 -0
  102. package/dist/clients/supabase/index.d.ts.map +1 -0
  103. package/dist/clients/websocket.d.ts +127 -0
  104. package/dist/clients/websocket.d.ts.map +1 -0
  105. package/dist/command.d.ts +163 -0
  106. package/dist/command.d.ts.map +1 -0
  107. package/dist/commands/bootstrap.d.ts +20 -0
  108. package/dist/commands/bootstrap.d.ts.map +1 -0
  109. package/dist/commands/chat.d.ts +37 -0
  110. package/dist/commands/chat.d.ts.map +1 -0
  111. package/dist/commands/code.d.ts +28 -0
  112. package/dist/commands/code.d.ts.map +1 -0
  113. package/dist/commands/console.d.ts +22 -0
  114. package/dist/commands/console.d.ts.map +1 -0
  115. package/dist/commands/describe.d.ts +50 -0
  116. package/dist/commands/describe.d.ts.map +1 -0
  117. package/dist/commands/eval.d.ts +23 -0
  118. package/dist/commands/eval.d.ts.map +1 -0
  119. package/dist/commands/help.d.ts +25 -0
  120. package/dist/commands/help.d.ts.map +1 -0
  121. package/dist/commands/index.d.ts +18 -0
  122. package/dist/commands/index.d.ts.map +1 -0
  123. package/dist/commands/introspect.d.ts +24 -0
  124. package/dist/commands/introspect.d.ts.map +1 -0
  125. package/dist/commands/mcp.d.ts +35 -0
  126. package/dist/commands/mcp.d.ts.map +1 -0
  127. package/dist/commands/prompt.d.ts +38 -0
  128. package/dist/commands/prompt.d.ts.map +1 -0
  129. package/dist/commands/run.d.ts +24 -0
  130. package/dist/commands/run.d.ts.map +1 -0
  131. package/dist/commands/sandbox-mcp.d.ts +34 -0
  132. package/dist/commands/sandbox-mcp.d.ts.map +1 -0
  133. package/dist/commands/save-api-docs.d.ts +21 -0
  134. package/dist/commands/save-api-docs.d.ts.map +1 -0
  135. package/dist/commands/scaffold.d.ts +24 -0
  136. package/dist/commands/scaffold.d.ts.map +1 -0
  137. package/dist/commands/select.d.ts +22 -0
  138. package/dist/commands/select.d.ts.map +1 -0
  139. package/dist/commands/serve.d.ts +29 -0
  140. package/dist/commands/serve.d.ts.map +1 -0
  141. package/dist/container-describer.d.ts +144 -0
  142. package/dist/container-describer.d.ts.map +1 -0
  143. package/dist/container.d.ts +451 -0
  144. package/dist/container.d.ts.map +1 -0
  145. package/dist/endpoint.d.ts +113 -0
  146. package/dist/endpoint.d.ts.map +1 -0
  147. package/dist/feature.d.ts +47 -0
  148. package/dist/feature.d.ts.map +1 -0
  149. package/dist/graft.d.ts +29 -0
  150. package/dist/graft.d.ts.map +1 -0
  151. package/dist/hash-object.d.ts +8 -0
  152. package/dist/hash-object.d.ts.map +1 -0
  153. package/dist/helper.d.ts +209 -0
  154. package/dist/helper.d.ts.map +1 -0
  155. package/dist/introspection/generated.node.d.ts +44623 -0
  156. package/dist/introspection/generated.node.d.ts.map +1 -0
  157. package/dist/introspection/generated.web.d.ts +1412 -0
  158. package/dist/introspection/generated.web.d.ts.map +1 -0
  159. package/dist/introspection/index.d.ts +156 -0
  160. package/dist/introspection/index.d.ts.map +1 -0
  161. package/dist/introspection/scan.d.ts +147 -0
  162. package/dist/introspection/scan.d.ts.map +1 -0
  163. package/dist/node/container.d.ts +256 -0
  164. package/dist/node/container.d.ts.map +1 -0
  165. package/dist/node/feature.d.ts +9 -0
  166. package/dist/node/feature.d.ts.map +1 -0
  167. package/dist/node/features/container-link.d.ts +213 -0
  168. package/dist/node/features/container-link.d.ts.map +1 -0
  169. package/dist/node/features/content-db.d.ts +354 -0
  170. package/dist/node/features/content-db.d.ts.map +1 -0
  171. package/dist/node/features/disk-cache.d.ts +236 -0
  172. package/dist/node/features/disk-cache.d.ts.map +1 -0
  173. package/dist/node/features/dns.d.ts +511 -0
  174. package/dist/node/features/dns.d.ts.map +1 -0
  175. package/dist/node/features/docker.d.ts +485 -0
  176. package/dist/node/features/docker.d.ts.map +1 -0
  177. package/dist/node/features/downloader.d.ts +73 -0
  178. package/dist/node/features/downloader.d.ts.map +1 -0
  179. package/dist/node/features/figlet-fonts.d.ts +4 -0
  180. package/dist/node/features/figlet-fonts.d.ts.map +1 -0
  181. package/dist/node/features/file-manager.d.ts +177 -0
  182. package/dist/node/features/file-manager.d.ts.map +1 -0
  183. package/dist/node/features/fs.d.ts +635 -0
  184. package/dist/node/features/fs.d.ts.map +1 -0
  185. package/dist/node/features/git.d.ts +329 -0
  186. package/dist/node/features/git.d.ts.map +1 -0
  187. package/dist/node/features/google-auth.d.ts +200 -0
  188. package/dist/node/features/google-auth.d.ts.map +1 -0
  189. package/dist/node/features/google-calendar.d.ts +194 -0
  190. package/dist/node/features/google-calendar.d.ts.map +1 -0
  191. package/dist/node/features/google-docs.d.ts +138 -0
  192. package/dist/node/features/google-docs.d.ts.map +1 -0
  193. package/dist/node/features/google-drive.d.ts +202 -0
  194. package/dist/node/features/google-drive.d.ts.map +1 -0
  195. package/dist/node/features/google-mail.d.ts +221 -0
  196. package/dist/node/features/google-mail.d.ts.map +1 -0
  197. package/dist/node/features/google-sheets.d.ts +157 -0
  198. package/dist/node/features/google-sheets.d.ts.map +1 -0
  199. package/dist/node/features/grep.d.ts +207 -0
  200. package/dist/node/features/grep.d.ts.map +1 -0
  201. package/dist/node/features/helpers.d.ts +236 -0
  202. package/dist/node/features/helpers.d.ts.map +1 -0
  203. package/dist/node/features/ink.d.ts +332 -0
  204. package/dist/node/features/ink.d.ts.map +1 -0
  205. package/dist/node/features/ipc-socket.d.ts +298 -0
  206. package/dist/node/features/ipc-socket.d.ts.map +1 -0
  207. package/dist/node/features/json-tree.d.ts +140 -0
  208. package/dist/node/features/json-tree.d.ts.map +1 -0
  209. package/dist/node/features/networking.d.ts +373 -0
  210. package/dist/node/features/networking.d.ts.map +1 -0
  211. package/dist/node/features/nlp.d.ts +125 -0
  212. package/dist/node/features/nlp.d.ts.map +1 -0
  213. package/dist/node/features/opener.d.ts +93 -0
  214. package/dist/node/features/opener.d.ts.map +1 -0
  215. package/dist/node/features/os.d.ts +168 -0
  216. package/dist/node/features/os.d.ts.map +1 -0
  217. package/dist/node/features/package-finder.d.ts +419 -0
  218. package/dist/node/features/package-finder.d.ts.map +1 -0
  219. package/dist/node/features/postgres.d.ts +173 -0
  220. package/dist/node/features/postgres.d.ts.map +1 -0
  221. package/dist/node/features/proc.d.ts +285 -0
  222. package/dist/node/features/proc.d.ts.map +1 -0
  223. package/dist/node/features/process-manager.d.ts +427 -0
  224. package/dist/node/features/process-manager.d.ts.map +1 -0
  225. package/dist/node/features/python.d.ts +477 -0
  226. package/dist/node/features/python.d.ts.map +1 -0
  227. package/dist/node/features/redis.d.ts +247 -0
  228. package/dist/node/features/redis.d.ts.map +1 -0
  229. package/dist/node/features/repl.d.ts +84 -0
  230. package/dist/node/features/repl.d.ts.map +1 -0
  231. package/dist/node/features/runpod.d.ts +527 -0
  232. package/dist/node/features/runpod.d.ts.map +1 -0
  233. package/dist/node/features/secure-shell.d.ts +145 -0
  234. package/dist/node/features/secure-shell.d.ts.map +1 -0
  235. package/dist/node/features/semantic-search.d.ts +207 -0
  236. package/dist/node/features/semantic-search.d.ts.map +1 -0
  237. package/dist/node/features/sqlite.d.ts +180 -0
  238. package/dist/node/features/sqlite.d.ts.map +1 -0
  239. package/dist/node/features/telegram.d.ts +173 -0
  240. package/dist/node/features/telegram.d.ts.map +1 -0
  241. package/dist/node/features/transpiler.d.ts +51 -0
  242. package/dist/node/features/transpiler.d.ts.map +1 -0
  243. package/dist/node/features/tts.d.ts +108 -0
  244. package/dist/node/features/tts.d.ts.map +1 -0
  245. package/dist/node/features/ui.d.ts +562 -0
  246. package/dist/node/features/ui.d.ts.map +1 -0
  247. package/dist/node/features/vault.d.ts +90 -0
  248. package/dist/node/features/vault.d.ts.map +1 -0
  249. package/dist/node/features/vm.d.ts +285 -0
  250. package/dist/node/features/vm.d.ts.map +1 -0
  251. package/dist/node/features/yaml-tree.d.ts +118 -0
  252. package/dist/node/features/yaml-tree.d.ts.map +1 -0
  253. package/dist/node/features/yaml.d.ts +127 -0
  254. package/dist/node/features/yaml.d.ts.map +1 -0
  255. package/dist/node.d.ts +67 -0
  256. package/dist/node.d.ts.map +1 -0
  257. package/dist/python/generated.d.ts +2 -0
  258. package/dist/python/generated.d.ts.map +1 -0
  259. package/dist/react/index.d.ts +36 -0
  260. package/dist/react/index.d.ts.map +1 -0
  261. package/dist/registry.d.ts +97 -0
  262. package/dist/registry.d.ts.map +1 -0
  263. package/dist/scaffolds/generated.d.ts +13 -0
  264. package/dist/scaffolds/generated.d.ts.map +1 -0
  265. package/dist/scaffolds/template.d.ts +11 -0
  266. package/dist/scaffolds/template.d.ts.map +1 -0
  267. package/dist/schemas/base.d.ts +254 -0
  268. package/dist/schemas/base.d.ts.map +1 -0
  269. package/dist/selector.d.ts +130 -0
  270. package/dist/selector.d.ts.map +1 -0
  271. package/dist/server.d.ts +89 -0
  272. package/dist/server.d.ts.map +1 -0
  273. package/dist/servers/express.d.ts +104 -0
  274. package/dist/servers/express.d.ts.map +1 -0
  275. package/dist/servers/mcp.d.ts +201 -0
  276. package/dist/servers/mcp.d.ts.map +1 -0
  277. package/dist/servers/socket.d.ts +121 -0
  278. package/dist/servers/socket.d.ts.map +1 -0
  279. package/dist/state.d.ts +24 -0
  280. package/dist/state.d.ts.map +1 -0
  281. package/dist/web/clients/socket.d.ts +37 -0
  282. package/dist/web/clients/socket.d.ts.map +1 -0
  283. package/dist/web/container.d.ts +55 -0
  284. package/dist/web/container.d.ts.map +1 -0
  285. package/dist/web/extension.d.ts +4 -0
  286. package/dist/web/extension.d.ts.map +1 -0
  287. package/dist/web/feature.d.ts +8 -0
  288. package/dist/web/feature.d.ts.map +1 -0
  289. package/dist/web/features/asset-loader.d.ts +35 -0
  290. package/dist/web/features/asset-loader.d.ts.map +1 -0
  291. package/dist/web/features/container-link.d.ts +167 -0
  292. package/dist/web/features/container-link.d.ts.map +1 -0
  293. package/dist/web/features/esbuild.d.ts +51 -0
  294. package/dist/web/features/esbuild.d.ts.map +1 -0
  295. package/dist/web/features/helpers.d.ts +140 -0
  296. package/dist/web/features/helpers.d.ts.map +1 -0
  297. package/dist/web/features/network.d.ts +69 -0
  298. package/dist/web/features/network.d.ts.map +1 -0
  299. package/dist/web/features/speech.d.ts +71 -0
  300. package/dist/web/features/speech.d.ts.map +1 -0
  301. package/dist/web/features/vault.d.ts +62 -0
  302. package/dist/web/features/vault.d.ts.map +1 -0
  303. package/dist/web/features/vm.d.ts +48 -0
  304. package/dist/web/features/vm.d.ts.map +1 -0
  305. package/dist/web/features/voice-recognition.d.ts +96 -0
  306. package/dist/web/features/voice-recognition.d.ts.map +1 -0
  307. package/dist/web/shims/isomorphic-vm.d.ts +22 -0
  308. package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
  309. package/index.html +1457 -0
  310. package/index.ts +1 -0
  311. package/install.sh +84 -0
  312. package/luca.cli.ts +16 -0
  313. package/luca.console.ts +9 -0
  314. package/main.py +6 -0
  315. package/package.json +219 -58
  316. package/public/index.html +1457 -0
  317. package/public/slides-ai-native.html +902 -0
  318. package/public/slides-intro.html +974 -0
  319. package/pyproject.toml +7 -0
  320. package/scripts/build-web.ts +28 -0
  321. package/scripts/examples/ask-luca-expert.ts +42 -0
  322. package/scripts/examples/assistant-questions.ts +12 -0
  323. package/scripts/examples/excalidraw-expert.ts +75 -0
  324. package/scripts/examples/expert-chat.ts +0 -0
  325. package/scripts/examples/file-manager.ts +14 -0
  326. package/scripts/examples/ideas.ts +12 -0
  327. package/scripts/examples/interactive-chat.ts +20 -0
  328. package/scripts/examples/openai-tool-calls.ts +113 -0
  329. package/scripts/examples/opening-a-web-browser.ts +5 -0
  330. package/scripts/examples/telegram-bot.ts +79 -0
  331. package/scripts/examples/using-assistant-with-mcp.ts +555 -0
  332. package/scripts/examples/using-claude-code.ts +10 -0
  333. package/scripts/examples/using-contentdb.ts +35 -0
  334. package/scripts/examples/using-conversations.ts +35 -0
  335. package/scripts/examples/using-disk-cache.ts +10 -0
  336. package/scripts/examples/using-docker-shell.ts +75 -0
  337. package/scripts/examples/using-elevenlabs.ts +25 -0
  338. package/scripts/examples/using-google-calendar.ts +57 -0
  339. package/scripts/examples/using-google-docs.ts +74 -0
  340. package/scripts/examples/using-google-drive.ts +74 -0
  341. package/scripts/examples/using-google-sheets.ts +89 -0
  342. package/scripts/examples/using-nlp.ts +55 -0
  343. package/scripts/examples/using-ollama.ts +11 -0
  344. package/scripts/examples/using-postgres.ts +55 -0
  345. package/scripts/examples/using-runpod.ts +32 -0
  346. package/scripts/examples/using-tts.ts +40 -0
  347. package/scripts/scaffold.ts +391 -0
  348. package/scripts/scratch.ts +15 -0
  349. package/scripts/stamp-build.sh +12 -0
  350. package/scripts/test-assistant-hooks.ts +13 -0
  351. package/scripts/test-docs-reader.ts +10 -0
  352. package/scripts/test-linux-binary.sh +80 -0
  353. package/scripts/update-introspection-data.ts +58 -0
  354. package/src/agi/README.md +14 -0
  355. package/src/agi/container.server.ts +156 -0
  356. package/src/agi/feature.ts +13 -0
  357. package/src/agi/features/agent-memory.ts +694 -0
  358. package/src/agi/features/assistant.ts +1653 -0
  359. package/src/agi/features/assistants-manager.ts +534 -0
  360. package/src/agi/features/autonomous-assistant.ts +431 -0
  361. package/src/agi/features/browser-use.ts +672 -0
  362. package/src/agi/features/claude-code.ts +1584 -0
  363. package/src/agi/features/coding-tools.ts +175 -0
  364. package/src/agi/features/conversation-history.ts +672 -0
  365. package/src/agi/features/conversation.ts +1494 -0
  366. package/src/agi/features/docs-reader.ts +167 -0
  367. package/src/agi/features/file-tools.ts +340 -0
  368. package/src/agi/features/luca-coder.ts +641 -0
  369. package/src/agi/features/mcp-bridge.ts +532 -0
  370. package/src/agi/features/openai-codex.ts +651 -0
  371. package/src/agi/features/openapi.ts +445 -0
  372. package/src/agi/features/skills-library.ts +557 -0
  373. package/src/agi/index.ts +6 -0
  374. package/src/agi/lib/interceptor-chain.ts +89 -0
  375. package/src/agi/lib/token-counter.ts +202 -0
  376. package/src/bootstrap/generated.ts +9791 -0
  377. package/src/browser.ts +25 -0
  378. package/src/bus.ts +122 -0
  379. package/src/cli/build-info.ts +4 -0
  380. package/src/cli/cli.ts +355 -0
  381. package/src/client.ts +170 -0
  382. package/src/clients/civitai/index.ts +537 -0
  383. package/src/clients/client-template.ts +41 -0
  384. package/src/clients/comfyui/index.ts +604 -0
  385. package/src/clients/elevenlabs/index.ts +317 -0
  386. package/src/clients/graph.ts +87 -0
  387. package/src/clients/openai/index.ts +456 -0
  388. package/src/clients/rest.ts +207 -0
  389. package/src/clients/supabase/index.ts +357 -0
  390. package/src/clients/voicebox/index.ts +300 -0
  391. package/src/clients/websocket.ts +251 -0
  392. package/src/command.ts +506 -0
  393. package/src/commands/bootstrap.ts +244 -0
  394. package/src/commands/chat.ts +309 -0
  395. package/src/commands/code.ts +371 -0
  396. package/src/commands/console.ts +189 -0
  397. package/src/commands/describe.ts +243 -0
  398. package/src/commands/eval.ts +67 -0
  399. package/src/commands/help.ts +240 -0
  400. package/src/commands/index.ts +19 -0
  401. package/src/commands/introspect.ts +218 -0
  402. package/src/commands/mcp.ts +64 -0
  403. package/src/commands/prompt.ts +1014 -0
  404. package/src/commands/run.ts +278 -0
  405. package/src/commands/sandbox-mcp.ts +343 -0
  406. package/src/commands/save-api-docs.ts +51 -0
  407. package/src/commands/scaffold.ts +225 -0
  408. package/src/commands/select.ts +99 -0
  409. package/src/commands/serve.ts +208 -0
  410. package/src/container-describer.ts +1091 -0
  411. package/src/container.ts +1199 -0
  412. package/src/endpoint.ts +365 -0
  413. package/src/entity.ts +173 -0
  414. package/src/feature.ts +118 -0
  415. package/src/graft.ts +181 -0
  416. package/src/hash-object.ts +97 -0
  417. package/src/helper.ts +849 -0
  418. package/src/introspection/generated.agi.ts +41200 -0
  419. package/src/introspection/generated.node.ts +28773 -0
  420. package/src/introspection/generated.web.ts +2272 -0
  421. package/src/introspection/index.ts +296 -0
  422. package/src/introspection/scan.ts +1136 -0
  423. package/src/node/container.ts +409 -0
  424. package/src/node/feature.ts +13 -0
  425. package/src/node/features/container-link.ts +559 -0
  426. package/src/node/features/content-db.ts +849 -0
  427. package/src/node/features/disk-cache.ts +388 -0
  428. package/src/node/features/display-result.ts +57 -0
  429. package/src/node/features/dns.ts +669 -0
  430. package/src/node/features/docker.ts +921 -0
  431. package/src/node/features/downloader.ts +79 -0
  432. package/src/node/features/figlet-fonts.ts +600 -0
  433. package/src/node/features/file-manager.ts +535 -0
  434. package/src/node/features/fs.ts +1050 -0
  435. package/src/node/features/git.ts +592 -0
  436. package/src/node/features/google-auth.ts +504 -0
  437. package/src/node/features/google-calendar.ts +306 -0
  438. package/src/node/features/google-docs.ts +412 -0
  439. package/src/node/features/google-drive.ts +346 -0
  440. package/src/node/features/google-mail.ts +540 -0
  441. package/src/node/features/google-sheets.ts +286 -0
  442. package/src/node/features/grep.ts +427 -0
  443. package/src/node/features/helpers.ts +762 -0
  444. package/src/node/features/ink.ts +490 -0
  445. package/src/node/features/ipc-socket.ts +649 -0
  446. package/src/node/features/json-tree.ts +170 -0
  447. package/src/node/features/networking.ts +961 -0
  448. package/src/node/features/nlp.ts +212 -0
  449. package/src/node/features/opener.ts +180 -0
  450. package/src/node/features/os.ts +403 -0
  451. package/src/node/features/package-finder.ts +540 -0
  452. package/src/node/features/postgres.ts +289 -0
  453. package/src/node/features/proc.ts +503 -0
  454. package/src/node/features/process-manager.ts +844 -0
  455. package/src/node/features/python.ts +912 -0
  456. package/src/node/features/redis.ts +446 -0
  457. package/src/node/features/repl.ts +212 -0
  458. package/src/node/features/runpod.ts +811 -0
  459. package/src/node/features/secure-shell.ts +261 -0
  460. package/src/node/features/semantic-search.ts +935 -0
  461. package/src/node/features/sqlite.ts +289 -0
  462. package/src/node/features/telegram.ts +343 -0
  463. package/src/node/features/transpiler.ts +160 -0
  464. package/src/node/features/tts.ts +185 -0
  465. package/src/node/features/ui.ts +791 -0
  466. package/src/node/features/vault.ts +153 -0
  467. package/src/node/features/vm.ts +462 -0
  468. package/src/node/features/yaml-tree.ts +148 -0
  469. package/src/node/features/yaml.ts +133 -0
  470. package/src/node.ts +76 -0
  471. package/src/python/bridge.py +220 -0
  472. package/src/python/generated.ts +226 -0
  473. package/src/react/index.ts +175 -0
  474. package/src/registry.ts +210 -0
  475. package/src/scaffolds/generated.ts +1814 -0
  476. package/src/scaffolds/template.ts +46 -0
  477. package/src/schemas/base.ts +296 -0
  478. package/src/selector.ts +352 -0
  479. package/src/server.ts +229 -0
  480. package/src/servers/express.ts +283 -0
  481. package/src/servers/mcp.ts +802 -0
  482. package/src/servers/socket.ts +258 -0
  483. package/src/state.ts +101 -0
  484. package/src/web/clients/socket.ts +99 -0
  485. package/src/web/container.ts +75 -0
  486. package/src/web/extension.ts +30 -0
  487. package/src/web/feature.ts +12 -0
  488. package/src/web/features/asset-loader.ts +72 -0
  489. package/src/web/features/container-link.ts +382 -0
  490. package/src/web/features/esbuild.ts +93 -0
  491. package/src/web/features/helpers.ts +291 -0
  492. package/src/web/features/network.ts +85 -0
  493. package/src/web/features/speech.ts +104 -0
  494. package/src/web/features/vault.ts +207 -0
  495. package/src/web/features/vm.ts +85 -0
  496. package/src/web/features/voice-recognition.ts +161 -0
  497. package/src/web/shims/isomorphic-vm.ts +149 -0
  498. package/tsconfig.build.json +12 -0
  499. package/tsconfig.json +58 -0
  500. package/uv.lock +8 -0
  501. package/LICENSE +0 -21
  502. package/dist/cli/cli.js +0 -48
  503. package/dist/cli/common.d.ts +0 -2
  504. package/dist/cli/common.js +0 -6
  505. package/dist/cli/index.d.ts +0 -2
  506. package/dist/cli/index.js +0 -5
  507. package/dist/cli/run.d.ts +0 -1
  508. package/dist/cli/run.js +0 -38
  509. package/dist/core/index.d.ts +0 -4
  510. package/dist/core/index.js +0 -32
  511. package/dist/core/read.d.ts +0 -2
  512. package/dist/core/read.js +0 -29
  513. package/dist/core/request.d.ts +0 -1
  514. package/dist/core/request.js +0 -2
  515. package/dist/core/write.d.ts +0 -2
  516. package/dist/core/write.js +0 -21
  517. package/dist/index.d.ts +0 -1
  518. package/dist/index.js +0 -5
  519. package/dist/utils/common.d.ts +0 -9
  520. package/dist/utils/common.js +0 -57
  521. package/dist/utils/consts.d.ts +0 -3
  522. package/dist/utils/consts.js +0 -11
  523. package/dist/utils/dict.d.ts +0 -1
  524. package/dist/utils/dict.js +0 -7
  525. package/dist/utils/index.d.ts +0 -5
  526. package/dist/utils/index.js +0 -21
  527. package/dist/utils/log.d.ts +0 -1
  528. package/dist/utils/log.js +0 -5
  529. package/dist/utils/types.d.ts +0 -1
  530. package/dist/utils/types.js +0 -2
  531. package/dist/utils/utils.test.d.ts +0 -1
  532. package/dist/utils/utils.test.js +0 -7
@@ -0,0 +1,244 @@
1
+ import { z } from 'zod'
2
+ import { commands } from '../command.js'
3
+ import { CommandOptionsSchema } from '../schemas/base.js'
4
+ import type { ContainerContext } from '../container.js'
5
+ import type { NodeContainer } from '../node/container.js'
6
+ import { bootstrapFiles, bootstrapTemplates, bootstrapExamples, bootstrapTutorials } from '../bootstrap/generated.js'
7
+ import { generateScaffold } from '../scaffolds/template.js'
8
+
9
+ declare module '../command.js' {
10
+ interface AvailableCommands {
11
+ bootstrap: ReturnType<typeof commands.registerHandler>
12
+ }
13
+ }
14
+
15
+ export const argsSchema = CommandOptionsSchema.extend({
16
+ output: z.string().default('.').describe('Output folder path (defaults to cwd)'),
17
+ 'update-skill': z.boolean().default(false).describe('Only update .claude/skills/luca-framework in the current project'),
18
+ })
19
+
20
+ async function bootstrap(options: z.infer<typeof argsSchema>, context: ContainerContext) {
21
+ const container = context.container as unknown as NodeContainer
22
+ const args = container.argv._ as string[]
23
+ const fs = container.feature('fs')
24
+ const ui = container.feature('ui')
25
+ const proc = container.feature('proc')
26
+
27
+ // ── --update-skill: refresh skill files in the current project ──
28
+ if (options['update-skill']) {
29
+ return await updateSkill(container, fs, ui)
30
+ }
31
+
32
+ // Require an explicit target — don't silently bootstrap into cwd
33
+ let target = args[1] || (options.output !== '.' ? options.output : '')
34
+
35
+ if (!target) {
36
+ const answer = await ui.askQuestion('Project name (folder to create):')
37
+ target = answer?.question?.trim()
38
+ if (!target) {
39
+ ui.print.red('\n No project name given, aborting.\n')
40
+ return
41
+ }
42
+ }
43
+
44
+ const outputDir = container.paths.resolve(target)
45
+ await fs.ensureFolder(outputDir)
46
+ const mkPath = (...segments: string[]) => container.paths.resolve(outputDir, ...segments)
47
+
48
+ ui.print.cyan('\n luca bootstrap\n')
49
+
50
+ // ── Check for AI coding tools ──────────────────────────────────
51
+ await checkToolAvailability(ui, proc)
52
+
53
+ // ── 1. .env (only if missing) ──────────────────────────────────
54
+ const envPath = mkPath('.env')
55
+ if (!fs.exists(envPath)) {
56
+ await writeFile(fs, ui, envPath, '', '.env')
57
+ } else {
58
+ ui.print.dim(' .env already exists, skipping')
59
+ }
60
+
61
+ // ── 2. CLAUDE.md ───────────────────────────────────────────────
62
+ await writeFile(fs, ui, mkPath('CLAUDE.md'), bootstrapFiles['CLAUDE'] || '', 'CLAUDE.md')
63
+
64
+ // ── 3. .claude/skills/luca-framework/ ──────────────────────────
65
+ const skillDir = mkPath('.claude', 'skills', 'luca-framework')
66
+ await fs.ensureFolder(skillDir)
67
+ await writeFile(fs, ui, container.paths.resolve(skillDir, 'SKILL.md'), bootstrapFiles['SKILL'] || '', '.claude/skills/luca-framework/SKILL.md')
68
+
69
+ // ── 3b. examples and tutorials ─────────────────────────────────
70
+ const examplesDir = container.paths.resolve(skillDir, 'references', 'examples')
71
+ await fs.ensureFolder(examplesDir)
72
+ for (const [filename, content] of Object.entries(bootstrapExamples)) {
73
+ await fs.writeFileAsync(container.paths.resolve(examplesDir, filename), content)
74
+ }
75
+ ui.print.cyan(` Writing ${Object.keys(bootstrapExamples).length} example docs...`)
76
+
77
+ const tutorialsDir = container.paths.resolve(skillDir, 'references', 'tutorials')
78
+ await fs.ensureFolder(tutorialsDir)
79
+ for (const [filename, content] of Object.entries(bootstrapTutorials)) {
80
+ await fs.writeFileAsync(container.paths.resolve(tutorialsDir, filename), content)
81
+ }
82
+ ui.print.cyan(` Writing ${Object.keys(bootstrapTutorials).length} tutorial docs...`)
83
+
84
+ // ── 4. docs/ folder ────────────────────────────────────────────
85
+ await fs.ensureFolder(mkPath('docs'))
86
+ await writeFile(fs, ui, mkPath('docs', 'models.ts'), bootstrapTemplates['docs-models'] || '', 'docs/models.ts')
87
+ await writeFile(fs, ui, mkPath('docs', 'README.md'), bootstrapTemplates['docs-readme'] || '', 'docs/README.md')
88
+
89
+ // ── 5. commands/about.ts ────────────────────────────────────────
90
+ await fs.ensureFolder(mkPath('commands'))
91
+ await writeFile(fs, ui, mkPath('commands', 'about.ts'), bootstrapTemplates['about-command'] || '', 'commands/about.ts')
92
+
93
+ // ── 6. features/example.ts (scaffold-based) ────────────────────
94
+ await fs.ensureFolder(mkPath('features'))
95
+ const featureCode = generateScaffold('feature', 'example', 'An example feature demonstrating the luca feature pattern')
96
+ || bootstrapTemplates['example-feature'] || ''
97
+ await writeFile(fs, ui, mkPath('features', 'example.ts'), featureCode, 'features/example.ts')
98
+
99
+ // ── 7. endpoints/health.ts ─────────────────────────────────────
100
+ await fs.ensureFolder(mkPath('endpoints'))
101
+ await writeFile(fs, ui, mkPath('endpoints', 'health.ts'), bootstrapTemplates['health-endpoint'] || '', 'endpoints/health.ts')
102
+
103
+ // ── 8. luca.cli.ts ─────────────────────────────────────────────
104
+ await writeFile(fs, ui, mkPath('luca.cli.ts'), bootstrapTemplates['luca-cli'] || '', 'luca.cli.ts')
105
+
106
+ // ── 9. RUNME.md ────────────────────────────────────────────────
107
+ await writeFile(fs, ui, mkPath('RUNME.md'), bootstrapTemplates['runme'] || '', 'RUNME.md')
108
+
109
+ // ── 10. .claude/settings.json (permissions for AI coding tools) ──
110
+ const settingsPath = mkPath('.claude', 'settings.json')
111
+ const claudeSettings = {
112
+ permissions: {
113
+ allow: [
114
+ 'Bash(luca *)',
115
+ 'Bash(bun run *)',
116
+ 'Bash(bun test *)',
117
+ ],
118
+ },
119
+ }
120
+
121
+ if (!fs.exists(settingsPath)) {
122
+ await fs.ensureFolder(mkPath('.claude'))
123
+ await writeFile(fs, ui, settingsPath, JSON.stringify(claudeSettings, null, 2) + '\n', '.claude/settings.json')
124
+ } else {
125
+ // Merge luca permissions into existing settings
126
+ try {
127
+ const existing = JSON.parse(fs.readFile(settingsPath) as string)
128
+ const perms = existing.permissions || {}
129
+ const allow = new Set(perms.allow || [])
130
+ for (const rule of claudeSettings.permissions.allow) {
131
+ allow.add(rule)
132
+ }
133
+ existing.permissions = { ...perms, allow: [...allow] }
134
+ await writeFile(fs, ui, settingsPath, JSON.stringify(existing, null, 2) + '\n', '.claude/settings.json (merged)')
135
+ } catch {
136
+ ui.print.yellow(' ⚠ Could not parse existing .claude/settings.json, skipping merge')
137
+ }
138
+ }
139
+
140
+ // ── Summary ────────────────────────────────────────────────────
141
+ ui.print('')
142
+ ui.print.green(' ✓ Bootstrap complete!\n')
143
+ ui.print(' Your project is ready. Here\'s what to try:\n')
144
+ ui.print(' luca — see available commands')
145
+ ui.print(' luca about — project info + discovered helpers')
146
+ ui.print(' luca serve — start the API server (try /api/health)')
147
+ ui.print(' luca describe fs — learn about any built-in feature')
148
+ ui.print(' luca RUNME — run the interactive markdown demo')
149
+ ui.print('')
150
+ ui.print(' Need to build something? Use scaffold:\n')
151
+ ui.print(' luca scaffold command deploy — add a CLI command')
152
+ ui.print(' luca scaffold feature cache — add a container feature')
153
+ ui.print(' luca scaffold endpoint users — add a REST route')
154
+ ui.print(' luca scaffold client github — add an API client')
155
+ ui.print(' luca scaffold server mqtt — add a server')
156
+ ui.print('')
157
+ ui.print.dim(' Run luca scaffold <type> --tutorial for a full guide on any type')
158
+ ui.print('')
159
+ }
160
+
161
+ // ── Helpers ──────────────────────────────────────────────────────────
162
+
163
+ async function updateSkill(container: any, fs: any, ui: any) {
164
+ const skillDir = container.paths.resolve('.claude', 'skills', 'luca-framework')
165
+
166
+ // Wipe existing skill directory so stale files don't linger
167
+ if (fs.exists(skillDir)) {
168
+ await fs.rmdir(skillDir)
169
+ }
170
+
171
+ await fs.ensureFolder(skillDir)
172
+ await writeFile(fs, ui, container.paths.resolve(skillDir, 'SKILL.md'), bootstrapFiles['SKILL'] || '', '.claude/skills/luca-framework/SKILL.md')
173
+
174
+ const examplesDir = container.paths.resolve(skillDir, 'references', 'examples')
175
+ await fs.ensureFolder(examplesDir)
176
+ for (const [filename, content] of Object.entries(bootstrapExamples)) {
177
+ await fs.writeFileAsync(container.paths.resolve(examplesDir, filename), content)
178
+ }
179
+ ui.print.cyan(` Writing ${Object.keys(bootstrapExamples).length} example docs...`)
180
+
181
+ const tutorialsDir = container.paths.resolve(skillDir, 'references', 'tutorials')
182
+ await fs.ensureFolder(tutorialsDir)
183
+ for (const [filename, content] of Object.entries(bootstrapTutorials)) {
184
+ await fs.writeFileAsync(container.paths.resolve(tutorialsDir, filename), content)
185
+ }
186
+ ui.print.cyan(` Writing ${Object.keys(bootstrapTutorials).length} tutorial docs...`)
187
+
188
+ ui.print('')
189
+ ui.print.green(' ✓ Skill updated!')
190
+ ui.print('')
191
+ }
192
+
193
+ async function writeFile(fs: any, ui: any, path: string, content: string, label: string) {
194
+ ui.print.cyan(` Writing ${label}...`)
195
+ await fs.writeFileAsync(path, content)
196
+ }
197
+
198
+ async function checkToolAvailability(ui: any, proc: any) {
199
+ const tools: { name: string; found: boolean; envKey?: string; envFound?: boolean }[] = []
200
+
201
+ for (const name of ['claude', 'codex']) {
202
+ let found = false
203
+ try {
204
+ const result = await proc.exec(`which ${name}`, { silent: true })
205
+ found = result.exitCode === 0 && result.stdout.trim().length > 0
206
+ } catch {
207
+ found = false
208
+ }
209
+ tools.push({ name, found })
210
+ }
211
+
212
+ const openaiKey = !!process.env.OPENAI_API_KEY
213
+ const hasAnyCodingTool = tools.some(t => t.found)
214
+
215
+ if (!hasAnyCodingTool) {
216
+ ui.print.yellow(' ┌─────────────────────────────────────────────────────────────┐')
217
+ ui.print.yellow(' │ No AI coding assistant detected (claude, codex) │')
218
+ ui.print.yellow(' │ │')
219
+ ui.print.yellow(' │ Luca works best with an AI coding assistant. │')
220
+ ui.print.yellow(' │ │')
221
+ ui.print.yellow(' │ Claude Code: https://docs.anthropic.com/en/docs/claude-code│')
222
+ ui.print.yellow(' │ Codex CLI: https://github.com/openai/codex │')
223
+ ui.print.yellow(' └─────────────────────────────────────────────────────────────┘')
224
+ ui.print('')
225
+ } else {
226
+ for (const t of tools) {
227
+ if (t.found) ui.print.green(` ✓ ${t.name} detected`)
228
+ }
229
+ }
230
+
231
+ if (!openaiKey) {
232
+ ui.print.dim(' ℹ OPENAI_API_KEY not set (only needed for codex/OpenAI features)')
233
+ } else {
234
+ ui.print.green(' ✓ OPENAI_API_KEY set')
235
+ }
236
+
237
+ ui.print('')
238
+ }
239
+
240
+ commands.registerHandler('bootstrap', {
241
+ description: 'Scaffold a new luca project with commands, features, endpoints, docs, and AI assistant configuration',
242
+ argsSchema,
243
+ handler: bootstrap,
244
+ })
@@ -0,0 +1,309 @@
1
+ import { z } from 'zod'
2
+ import * as readline from 'readline'
3
+ import { commands } from '../command'
4
+ import { CommandOptionsSchema } from '../schemas/base'
5
+ import type { ContainerContext } from '../container'
6
+
7
+ declare module '../command.js' {
8
+ interface AvailableCommands {
9
+ chat: ReturnType<typeof commands.registerHandler>
10
+ }
11
+ }
12
+
13
+ export const argsSchema = CommandOptionsSchema.extend({
14
+ model: z.string().optional().describe('Override the LLM model for the assistant'),
15
+ local: z.boolean().default(false).describe('Whether to use a local API server'),
16
+ resume: z.string().optional().describe('Thread ID or conversation ID to resume'),
17
+ list: z.boolean().optional().describe('List recent conversations and exit'),
18
+ historyMode: z.enum(['lifecycle', 'daily', 'persistent', 'session']).optional().describe('Override history persistence mode'),
19
+ offRecord: z.boolean().optional().describe('Alias for --history-mode lifecycle (ephemeral, no persistence)'),
20
+ clear: z.boolean().optional().describe('Clear the conversation history for the resolved history mode and exit'),
21
+ prependPrompt: z.string().optional().describe('Text or path to a markdown file to prepend to the system prompt'),
22
+ appendPrompt: z.string().optional().describe('Text or path to a markdown file to append to the system prompt'),
23
+ use: z.union([z.string(), z.array(z.string())]).optional().describe('Feature(s) to inject into the assistant via .use(). Supports options: --use "contentDb:rootPath=/tmp;lazy=true"'),
24
+ forbidTool: z.union([z.string(), z.array(z.string())]).optional().describe('Tool name patterns to exclude (supports * glob). Can be specified multiple times.'),
25
+ allowTool: z.union([z.string(), z.array(z.string())]).optional().describe('Tool name patterns to allow (strict allowlist, supports * glob). Can be specified multiple times.'),
26
+ })
27
+
28
+ export default async function chat(options: z.infer<typeof argsSchema>, context: ContainerContext) {
29
+ const container = context.container as any
30
+ const ui = container.feature('ui')
31
+
32
+ const manager = container.feature('assistantsManager')
33
+ await manager.discover()
34
+
35
+ const entries = manager.list()
36
+
37
+ if (entries.length === 0) {
38
+ console.error(ui.colors.red('No assistants found.'))
39
+ console.error(ui.colors.dim(` Create a directory with a CORE.md file anywhere in the project.`))
40
+ process.exit(1)
41
+ }
42
+
43
+ const requestedName = container.argv._[1] as string | undefined
44
+ let name: string
45
+
46
+ if (requestedName) {
47
+ const entry = manager.get(requestedName)
48
+ if (!entry) {
49
+ const available = entries.map((e: any) => e.name).join(', ')
50
+ console.error(ui.colors.red(`Assistant "${requestedName}" not found.`))
51
+ console.error(ui.colors.dim(` Available: ${available}`))
52
+ process.exit(1)
53
+ }
54
+ name = requestedName
55
+ } else if (entries.length === 1) {
56
+ name = entries[0].name
57
+ } else {
58
+ const answers = await ui.wizard([
59
+ {
60
+ type: 'list',
61
+ name: 'assistant',
62
+ message: 'Choose an assistant',
63
+ choices: entries.map((e: any) => ({ name: e.name, value: e.name })),
64
+ },
65
+ ])
66
+ name = answers.assistant
67
+ }
68
+
69
+ // Resolve history mode: --off-record overrides everything to lifecycle
70
+ // CLI defaults to 'daily' for interactive persistence
71
+ const historyMode = options.offRecord
72
+ ? 'lifecycle'
73
+ : (options.historyMode || 'daily')
74
+
75
+ const createOptions: Record<string, any> = { historyMode, injectTimestamps: true }
76
+ if (options.model) createOptions.model = options.model
77
+ if (options.local) createOptions.local = options.local
78
+ if (options.forbidTool) createOptions.forbidTools = Array.isArray(options.forbidTool) ? options.forbidTool : [options.forbidTool]
79
+ if (options.allowTool) createOptions.allowTools = Array.isArray(options.allowTool) ? options.allowTool : [options.allowTool]
80
+
81
+ // Resolve --prepend-prompt / --append-prompt: if it's an existing file, read it; if it ends in .md but doesn't exist, error
82
+ const fs = container.feature('fs')
83
+ for (const flag of ['prependPrompt', 'appendPrompt'] as const) {
84
+ const raw = options[flag]
85
+ if (!raw) continue
86
+ const resolved = container.paths.resolve(raw)
87
+ if (fs.exists(resolved)) {
88
+ createOptions[flag] = fs.readFile(resolved)
89
+ } else if (raw.endsWith('.md')) {
90
+ console.error(ui.colors.red(`File not found: ${resolved}`))
91
+ process.exit(1)
92
+ } else {
93
+ createOptions[flag] = raw
94
+ }
95
+ }
96
+
97
+ const assistant = manager.create(name, createOptions)
98
+
99
+ // --clear: wipe history for the current mode and exit
100
+ if (options.clear) {
101
+ const deleted = await assistant.clearHistory()
102
+ if (deleted > 0) {
103
+ console.log(ui.colors.green(` Cleared ${deleted} conversation(s) for ${ui.colors.cyan(name)} (${historyMode} mode).`))
104
+ } else {
105
+ console.log(ui.colors.dim(` No history to clear for ${ui.colors.cyan(name)} (${historyMode} mode).`))
106
+ }
107
+ return
108
+ }
109
+
110
+ // --list: show recent conversations and exit
111
+ if (options.list) {
112
+ const history = await assistant.listHistory({ limit: 20 })
113
+ if (history.length === 0) {
114
+ console.log(ui.colors.dim(' No saved conversations.'))
115
+ } else {
116
+ console.log()
117
+ console.log(ui.colors.dim(' Recent conversations:'))
118
+ console.log()
119
+ for (const meta of history) {
120
+ const date = new Date(meta.updatedAt).toLocaleString()
121
+ const msgs = ui.colors.dim(`(${meta.messageCount} messages)`)
122
+ console.log(` ${ui.colors.cyan(meta.thread)} ${msgs}`)
123
+ console.log(` ${ui.colors.dim(date)} - ${meta.title}`)
124
+ }
125
+ console.log()
126
+ console.log(ui.colors.dim(` Resume with: luca chat ${name} --resume <thread-id>`))
127
+ }
128
+ return
129
+ }
130
+
131
+ // --resume: set thread override before start
132
+ if (options.resume) {
133
+ assistant.resumeThread(options.resume)
134
+ }
135
+
136
+ const ink = container.feature('ink', { enable: true })
137
+ await ink.loadModules()
138
+ const React = ink.React
139
+ const { Text } = ink.components
140
+
141
+ // Use the raw ink render (sync) since modules are already loaded
142
+ const inkModule = await import('ink')
143
+
144
+ let responseBuffer = ''
145
+ let inkInstance: any = null
146
+
147
+ function mdElement(content: string) {
148
+ const rendered = content ? String(ui.markdown(content)).trimEnd() : ''
149
+ return React.createElement(Text, null, rendered)
150
+ }
151
+
152
+ assistant.on('chunk', (text: string) => {
153
+ responseBuffer += text
154
+ if (!inkInstance) {
155
+ process.stdout.write('\n')
156
+ inkInstance = inkModule.render(mdElement(responseBuffer), { patchConsole: false })
157
+ } else {
158
+ inkInstance.rerender(mdElement(responseBuffer))
159
+ }
160
+ })
161
+
162
+ assistant.on('toolCall', (toolName: string, args: any) => {
163
+ if (inkInstance) { inkInstance.unmount(); inkInstance = null }
164
+ responseBuffer = ''
165
+ const argsStr = JSON.stringify(args).slice(0, 120)
166
+ process.stdout.write(ui.colors.dim(`\n ⟳ ${toolName}`) + ui.colors.dim(`(${argsStr})\n`))
167
+ })
168
+
169
+ assistant.on('toolResult', (toolName: string, result: any) => {
170
+ const preview = typeof result === 'string' ? result.slice(0, 100) : JSON.stringify(result).slice(0, 100)
171
+ process.stdout.write(ui.colors.green(` ✓ ${toolName}`) + ui.colors.dim(` → ${preview}${preview.length >= 100 ? '…' : ''}\n`))
172
+ })
173
+
174
+ assistant.on('toolError', (toolName: string, error: any) => {
175
+ const msg = error?.message || String(error)
176
+ process.stdout.write(ui.colors.red(` ✗ ${toolName}: ${msg}\n`))
177
+ })
178
+
179
+ assistant.on('response', () => {
180
+ if (inkInstance) { inkInstance.unmount(); inkInstance = null }
181
+ responseBuffer = ''
182
+ process.stdout.write('\n')
183
+ })
184
+
185
+ // --use: inject features into the assistant
186
+ if (options.use) {
187
+ const items = Array.isArray(options.use) ? options.use : [options.use]
188
+ for (const item of items) {
189
+ const [namepart, optStr] = item.split(':')
190
+ if (!namepart) continue
191
+ const featureOpts: Record<string, any> = { enable: true }
192
+ if (optStr) {
193
+ for (const pair of optStr.split(';')) {
194
+ const [k, v] = pair.split('=')
195
+ if (k) featureOpts[k.trim()] = v?.trim() === 'true' ? true : v?.trim() === 'false' ? false : v?.trim()
196
+ }
197
+ }
198
+ const feature = container.feature(namepart.trim(), featureOpts)
199
+ assistant.use(feature)
200
+ }
201
+ }
202
+
203
+ // Start the assistant (loads history if applicable)
204
+ await assistant.start()
205
+
206
+ const messageCount = assistant.messages?.length || 0
207
+ const isResuming = historyMode !== 'lifecycle' && messageCount > 1
208
+
209
+ let rl = readline.createInterface({
210
+ input: process.stdin,
211
+ output: process.stdout,
212
+ })
213
+
214
+ let rlClosed = false
215
+ rl.on('close', () => { rlClosed = true })
216
+
217
+ function ensureRl() {
218
+ if (rlClosed) {
219
+ rl = readline.createInterface({ input: process.stdin, output: process.stdout })
220
+ rlClosed = false
221
+ rl.on('close', () => { rlClosed = true })
222
+ }
223
+ }
224
+
225
+ function prompt(): Promise<string> {
226
+ return new Promise((resolve) => {
227
+ ensureRl()
228
+ rl.question(ui.colors.dim(`\n${name} > `), (answer: string) => resolve(answer.trim()))
229
+ })
230
+ }
231
+
232
+ console.log()
233
+ if (isResuming) {
234
+ console.log(ui.colors.dim(` Resuming conversation with ${ui.colors.cyan(name)} (${messageCount} messages). Type .exit to quit.`))
235
+ } else {
236
+ console.log(ui.colors.dim(` Chatting with ${ui.colors.cyan(name)}. Type .exit to quit.`))
237
+ }
238
+ if (historyMode !== 'lifecycle') {
239
+ console.log(ui.colors.dim(` Mode: ${historyMode}`))
240
+ }
241
+ console.log()
242
+
243
+ while (true) {
244
+ const question = await prompt()
245
+
246
+ if (!question) continue
247
+ if (question === '.exit') break
248
+
249
+ if (question === '/console') {
250
+ // Pause chat readline so the REPL can own stdin
251
+ rl.close()
252
+
253
+ // Build feature context like `luca console` does
254
+ const featureContext: Record<string, any> = {}
255
+ for (const fname of container.features.available) {
256
+ try { featureContext[fname] = container.feature(fname) } catch {}
257
+ }
258
+
259
+ const replPrompt = ui.colors.magenta('console') + ui.colors.dim(' > ')
260
+ const repl = container.feature('repl', { prompt: replPrompt })
261
+
262
+ console.log()
263
+ console.log(ui.colors.dim(' Dropping into console. The assistant is available as `assistant`.'))
264
+ console.log(ui.colors.dim(' Type .exit to return to chat.'))
265
+ console.log()
266
+
267
+ await repl.start({
268
+ context: {
269
+ ...featureContext,
270
+ assistant,
271
+ console,
272
+ setTimeout, setInterval, clearTimeout, clearInterval,
273
+ fetch,
274
+ },
275
+ })
276
+
277
+ // Wait for the REPL to close
278
+ await new Promise<void>((resolve) => {
279
+ repl._rl!.on('close', resolve)
280
+ })
281
+
282
+ // Resume chat readline
283
+ console.log()
284
+ console.log(ui.colors.dim(` Back in chat with ${ui.colors.cyan(name)}.`))
285
+ rl = readline.createInterface({ input: process.stdin, output: process.stdout })
286
+ rlClosed = false
287
+ rl.on('close', () => { rlClosed = true })
288
+ continue
289
+ }
290
+
291
+ await assistant.ask(question)
292
+ }
293
+
294
+ rl.close()
295
+
296
+ // Show resume instruction for non-lifecycle modes
297
+ if (historyMode !== 'lifecycle' && assistant.currentThreadId) {
298
+ console.log()
299
+ console.log(ui.colors.dim(` Session saved. To resume this conversation:`))
300
+ console.log(ui.colors.dim(` luca chat ${name} --resume ${assistant.currentThreadId}`))
301
+ console.log()
302
+ }
303
+ }
304
+
305
+ commands.registerHandler('chat', {
306
+ description: 'Start an interactive chat session with a local assistant',
307
+ argsSchema,
308
+ handler: chat,
309
+ })