luca 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/.github/workflows/release.yaml +1 -0
  2. package/CLAUDE.md +10 -2
  3. package/README.md +130 -112
  4. package/assistants/codingAssistant/CORE.md +6 -1
  5. package/assistants/codingAssistant/hooks.ts +1 -1
  6. package/assistants/inkbot/hooks.ts +1 -1
  7. package/assistants/inkbot/tools.ts +1 -1
  8. package/bun.lock +264 -321
  9. package/commands/audit-docs.ts +2 -2
  10. package/commands/build-bootstrap.ts +2 -3
  11. package/commands/build-python-bridge.ts +2 -3
  12. package/commands/build-scaffolds.ts +2 -3
  13. package/commands/bundle-consumer-project.ts +521 -0
  14. package/commands/generate-api-docs.ts +2 -2
  15. package/commands/inkbot.ts +2 -2
  16. package/commands/release.ts +2 -2
  17. package/commands/social.ts +137 -0
  18. package/commands/try-all-challenges.ts +3 -3
  19. package/commands/try-challenge.ts +3 -3
  20. package/datasets/lora/agentic-loop-session-candidates.jsonl +91 -0
  21. package/datasets/lora/agentic-loop-session-curation-summary.json +123 -0
  22. package/datasets/lora/luca-session-candidates.jsonl +29 -0
  23. package/datasets/lora/luca-session-curation-summary.json +121 -0
  24. package/datasets/lora/review-batch-1.jsonl +30 -0
  25. package/datasets/lora/review-manifest.json +41 -0
  26. package/datasets/lora/review-queue.jsonl +120 -0
  27. package/datasets/lora/review-schema.json +134 -0
  28. package/datasets/lora/review-template.jsonl +2 -0
  29. package/datasets/lora/review-ui.html +725 -0
  30. package/dist/agi/container.server.d.ts +2 -2
  31. package/dist/agi/features/assistant.d.ts +2 -2
  32. package/dist/agi/features/assistants-manager.d.ts +1 -1
  33. package/dist/agi/features/autonomous-assistant.d.ts +1 -1
  34. package/dist/agi/features/browser-use.d.ts +1 -1
  35. package/dist/agi/features/claude-code.d.ts +1 -1
  36. package/dist/agi/features/conversation-history.d.ts +2 -2
  37. package/dist/agi/features/conversation.d.ts +1 -1
  38. package/dist/agi/features/docs-reader.d.ts +1 -1
  39. package/dist/agi/features/file-tools.d.ts +1 -1
  40. package/dist/agi/features/luca-coder.d.ts +1 -1
  41. package/dist/agi/features/openai-codex.d.ts +1 -1
  42. package/dist/agi/features/skills-library.d.ts +1 -1
  43. package/dist/clients/civitai/index.d.ts +4 -4
  44. package/dist/clients/client-template.d.ts +4 -4
  45. package/dist/clients/comfyui/index.d.ts +2 -2
  46. package/dist/clients/elevenlabs/index.d.ts +2 -2
  47. package/dist/clients/openai/index.d.ts +2 -2
  48. package/dist/clients/supabase/index.d.ts +3 -3
  49. package/dist/command.d.ts +1 -1
  50. package/dist/node/container.d.ts +1 -1
  51. package/dist/node/features/helpers.d.ts +3 -3
  52. package/dist/node/features/semantic-search.d.ts +1 -1
  53. package/dist/node/features/vm.d.ts +3 -3
  54. package/dist/node.d.ts +1 -1
  55. package/dist/scaffolds/generated.d.ts +1 -1
  56. package/dist/selector.d.ts +1 -1
  57. package/features/cipher-social.ts +493 -0
  58. package/index.html +217 -190
  59. package/luca.console.ts +1 -1
  60. package/package.json +7 -2
  61. package/public/index.html +217 -190
  62. package/public/slides-ai-native.html +1 -1
  63. package/public/slides-intro.html +2 -2
  64. package/scripts/curate-claude-sessions.ts +561 -0
  65. package/scripts/examples/ask-luca-expert.ts +1 -1
  66. package/scripts/examples/assistant-questions.ts +1 -1
  67. package/scripts/examples/excalidraw-expert.ts +1 -1
  68. package/scripts/examples/file-manager.ts +1 -1
  69. package/scripts/examples/ideas.ts +1 -1
  70. package/scripts/examples/interactive-chat.ts +1 -1
  71. package/scripts/examples/opening-a-web-browser.ts +1 -1
  72. package/scripts/examples/telegram-bot.ts +1 -1
  73. package/scripts/examples/using-assistant-with-mcp.ts +1 -1
  74. package/scripts/examples/using-claude-code.ts +1 -1
  75. package/scripts/examples/using-contentdb.ts +2 -2
  76. package/scripts/examples/using-conversations.ts +1 -1
  77. package/scripts/examples/using-disk-cache.ts +1 -1
  78. package/scripts/examples/using-docker-shell.ts +1 -1
  79. package/scripts/examples/using-elevenlabs.ts +1 -1
  80. package/scripts/examples/using-google-calendar.ts +1 -1
  81. package/scripts/examples/using-google-docs.ts +1 -1
  82. package/scripts/examples/using-google-drive.ts +1 -1
  83. package/scripts/examples/using-google-sheets.ts +1 -1
  84. package/scripts/examples/using-nlp.ts +1 -1
  85. package/scripts/examples/using-ollama.ts +1 -1
  86. package/scripts/examples/using-postgres.ts +1 -1
  87. package/scripts/examples/using-runpod.ts +1 -1
  88. package/scripts/examples/using-tts.ts +1 -1
  89. package/scripts/scaffold.ts +5 -5
  90. package/scripts/scratch.ts +1 -1
  91. package/scripts/test-assistant-hooks.ts +1 -1
  92. package/scripts/test-docs-reader.ts +1 -1
  93. package/src/agi/container.server.ts +6 -2
  94. package/src/agi/features/agent-memory.ts +25 -25
  95. package/src/agi/features/assistant.ts +34 -5
  96. package/src/agi/features/assistants-manager.ts +122 -6
  97. package/src/agi/features/autonomous-assistant.ts +1 -1
  98. package/src/agi/features/browser-use.ts +20 -1
  99. package/src/agi/features/claude-code.ts +51 -5
  100. package/src/agi/features/coding-tools.ts +1 -1
  101. package/src/agi/features/conversation-history.ts +181 -4
  102. package/src/agi/features/conversation.ts +186 -15
  103. package/src/agi/features/docs-reader.ts +2 -2
  104. package/src/agi/features/file-tools.ts +49 -2
  105. package/src/agi/features/luca-coder.ts +7 -5
  106. package/src/agi/features/mcp-bridge.ts +532 -0
  107. package/src/agi/features/openai-codex.ts +2 -2
  108. package/src/agi/features/skills-library.ts +131 -52
  109. package/src/agi/lib/token-counter.ts +80 -0
  110. package/src/bootstrap/generated.ts +56 -57
  111. package/src/browser.ts +1 -1
  112. package/src/cli/build-info.ts +2 -2
  113. package/src/cli/cli.ts +2 -2
  114. package/src/clients/civitai/index.ts +5 -5
  115. package/src/clients/client-template.ts +4 -4
  116. package/src/clients/comfyui/index.ts +4 -4
  117. package/src/clients/elevenlabs/index.ts +4 -4
  118. package/src/clients/openai/index.ts +7 -7
  119. package/src/clients/supabase/index.ts +4 -4
  120. package/src/clients/voicebox/index.ts +4 -4
  121. package/src/command.ts +2 -1
  122. package/src/commands/chat.ts +1 -0
  123. package/src/commands/eval.ts +2 -56
  124. package/src/commands/introspect.ts +1 -1
  125. package/src/commands/prompt.ts +41 -9
  126. package/src/container-describer.ts +8 -1
  127. package/src/container.ts +13 -0
  128. package/src/entity.ts +2 -2
  129. package/src/helper.ts +1 -1
  130. package/src/introspection/generated.agi.ts +29596 -27654
  131. package/src/introspection/generated.node.ts +20284 -19247
  132. package/src/introspection/generated.web.ts +605 -584
  133. package/src/introspection/scan.ts +11 -6
  134. package/src/node/container.ts +9 -1
  135. package/src/node/features/content-db.ts +39 -2
  136. package/src/node/features/display-result.ts +57 -0
  137. package/src/node/features/helpers.ts +46 -7
  138. package/src/node/features/python.ts +25 -19
  139. package/src/node/features/repl.ts +1 -1
  140. package/src/node/features/secure-shell.ts +11 -17
  141. package/src/node/features/semantic-search.ts +2 -2
  142. package/src/node/features/socket-repl.ts +336 -0
  143. package/src/node/features/telnyx-assistant-connector.ts +1206 -0
  144. package/src/node/features/transpiler.ts +2 -3
  145. package/src/node/features/ui.ts +5 -0
  146. package/src/node/features/vm.ts +20 -3
  147. package/src/node.ts +3 -3
  148. package/src/python/generated.ts +0 -1
  149. package/src/scaffolds/generated.ts +82 -83
  150. package/src/selector.ts +1 -1
  151. package/src/servers/express.ts +1 -1
  152. package/src/web/features/helpers.ts +22 -0
  153. package/tsconfig.json +12 -12
  154. package/docs/CLI.md +0 -335
  155. package/docs/CNAME +0 -1
  156. package/docs/README.md +0 -60
  157. package/docs/TABLE-OF-CONTENTS.md +0 -183
  158. package/docs/apis/clients/elevenlabs.md +0 -308
  159. package/docs/apis/clients/graph.md +0 -107
  160. package/docs/apis/clients/openai.md +0 -429
  161. package/docs/apis/clients/rest.md +0 -161
  162. package/docs/apis/clients/websocket.md +0 -174
  163. package/docs/apis/features/agi/assistant.md +0 -625
  164. package/docs/apis/features/agi/assistants-manager.md +0 -282
  165. package/docs/apis/features/agi/auto-assistant.md +0 -279
  166. package/docs/apis/features/agi/browser-use.md +0 -802
  167. package/docs/apis/features/agi/claude-code.md +0 -884
  168. package/docs/apis/features/agi/conversation-history.md +0 -364
  169. package/docs/apis/features/agi/conversation.md +0 -548
  170. package/docs/apis/features/agi/docs-reader.md +0 -99
  171. package/docs/apis/features/agi/file-tools.md +0 -163
  172. package/docs/apis/features/agi/luca-coder.md +0 -407
  173. package/docs/apis/features/agi/openai-codex.md +0 -396
  174. package/docs/apis/features/agi/openapi.md +0 -138
  175. package/docs/apis/features/agi/semantic-search.md +0 -387
  176. package/docs/apis/features/agi/skills-library.md +0 -239
  177. package/docs/apis/features/node/container-link.md +0 -192
  178. package/docs/apis/features/node/content-db.md +0 -450
  179. package/docs/apis/features/node/disk-cache.md +0 -379
  180. package/docs/apis/features/node/dns.md +0 -652
  181. package/docs/apis/features/node/docker.md +0 -706
  182. package/docs/apis/features/node/downloader.md +0 -81
  183. package/docs/apis/features/node/esbuild.md +0 -60
  184. package/docs/apis/features/node/file-manager.md +0 -191
  185. package/docs/apis/features/node/fs.md +0 -1217
  186. package/docs/apis/features/node/git.md +0 -371
  187. package/docs/apis/features/node/google-auth.md +0 -193
  188. package/docs/apis/features/node/google-calendar.md +0 -202
  189. package/docs/apis/features/node/google-docs.md +0 -173
  190. package/docs/apis/features/node/google-drive.md +0 -246
  191. package/docs/apis/features/node/google-mail.md +0 -214
  192. package/docs/apis/features/node/google-sheets.md +0 -194
  193. package/docs/apis/features/node/grep.md +0 -292
  194. package/docs/apis/features/node/helpers.md +0 -164
  195. package/docs/apis/features/node/ink.md +0 -334
  196. package/docs/apis/features/node/ipc-socket.md +0 -249
  197. package/docs/apis/features/node/json-tree.md +0 -86
  198. package/docs/apis/features/node/networking.md +0 -316
  199. package/docs/apis/features/node/nlp.md +0 -133
  200. package/docs/apis/features/node/opener.md +0 -97
  201. package/docs/apis/features/node/os.md +0 -146
  202. package/docs/apis/features/node/package-finder.md +0 -392
  203. package/docs/apis/features/node/postgres.md +0 -234
  204. package/docs/apis/features/node/proc.md +0 -399
  205. package/docs/apis/features/node/process-manager.md +0 -305
  206. package/docs/apis/features/node/python.md +0 -604
  207. package/docs/apis/features/node/redis.md +0 -380
  208. package/docs/apis/features/node/repl.md +0 -88
  209. package/docs/apis/features/node/runpod.md +0 -674
  210. package/docs/apis/features/node/secure-shell.md +0 -176
  211. package/docs/apis/features/node/semantic-search.md +0 -408
  212. package/docs/apis/features/node/sqlite.md +0 -233
  213. package/docs/apis/features/node/telegram.md +0 -279
  214. package/docs/apis/features/node/transpiler.md +0 -74
  215. package/docs/apis/features/node/tts.md +0 -133
  216. package/docs/apis/features/node/ui.md +0 -701
  217. package/docs/apis/features/node/vault.md +0 -59
  218. package/docs/apis/features/node/vm.md +0 -75
  219. package/docs/apis/features/node/yaml-tree.md +0 -85
  220. package/docs/apis/features/node/yaml.md +0 -176
  221. package/docs/apis/features/web/asset-loader.md +0 -59
  222. package/docs/apis/features/web/container-link.md +0 -192
  223. package/docs/apis/features/web/esbuild.md +0 -54
  224. package/docs/apis/features/web/helpers.md +0 -164
  225. package/docs/apis/features/web/network.md +0 -44
  226. package/docs/apis/features/web/speech.md +0 -69
  227. package/docs/apis/features/web/vault.md +0 -59
  228. package/docs/apis/features/web/vm.md +0 -75
  229. package/docs/apis/features/web/voice.md +0 -84
  230. package/docs/apis/servers/express.md +0 -171
  231. package/docs/apis/servers/mcp.md +0 -238
  232. package/docs/apis/servers/websocket.md +0 -170
  233. package/docs/bootstrap/CLAUDE.md +0 -101
  234. package/docs/bootstrap/SKILL.md +0 -341
  235. package/docs/bootstrap/templates/about-command.ts +0 -41
  236. package/docs/bootstrap/templates/docs-models.ts +0 -22
  237. package/docs/bootstrap/templates/docs-readme.md +0 -43
  238. package/docs/bootstrap/templates/example-feature.ts +0 -53
  239. package/docs/bootstrap/templates/health-endpoint.ts +0 -15
  240. package/docs/bootstrap/templates/luca-cli.ts +0 -30
  241. package/docs/bootstrap/templates/runme.md +0 -54
  242. package/docs/challenges/caching-proxy.md +0 -16
  243. package/docs/challenges/content-db-round-trip.md +0 -14
  244. package/docs/challenges/custom-command.md +0 -9
  245. package/docs/challenges/file-watcher-pipeline.md +0 -11
  246. package/docs/challenges/grep-audit-report.md +0 -15
  247. package/docs/challenges/multi-feature-dashboard.md +0 -14
  248. package/docs/challenges/process-orchestrator.md +0 -17
  249. package/docs/challenges/rest-api-server-with-client.md +0 -12
  250. package/docs/challenges/script-runner-with-vm.md +0 -11
  251. package/docs/challenges/simple-rest-api.md +0 -15
  252. package/docs/challenges/websocket-serve-and-client.md +0 -11
  253. package/docs/challenges/yaml-config-system.md +0 -14
  254. package/docs/command-system-overhaul.md +0 -94
  255. package/docs/documentation-audit.md +0 -134
  256. package/docs/examples/assistant/CORE.md +0 -18
  257. package/docs/examples/assistant/hooks.ts +0 -3
  258. package/docs/examples/assistant/tools.ts +0 -10
  259. package/docs/examples/assistant-hooks-reference.ts +0 -171
  260. package/docs/examples/assistant-with-process-manager.md +0 -84
  261. package/docs/examples/content-db.md +0 -77
  262. package/docs/examples/disk-cache.md +0 -83
  263. package/docs/examples/docker.md +0 -101
  264. package/docs/examples/downloader.md +0 -70
  265. package/docs/examples/entity.md +0 -124
  266. package/docs/examples/esbuild.md +0 -80
  267. package/docs/examples/feature-as-tool-provider.md +0 -143
  268. package/docs/examples/file-manager.md +0 -82
  269. package/docs/examples/fs.md +0 -83
  270. package/docs/examples/git.md +0 -85
  271. package/docs/examples/google-auth.md +0 -88
  272. package/docs/examples/google-calendar.md +0 -94
  273. package/docs/examples/google-docs.md +0 -82
  274. package/docs/examples/google-drive.md +0 -96
  275. package/docs/examples/google-sheets.md +0 -95
  276. package/docs/examples/grep.md +0 -85
  277. package/docs/examples/ink-blocks.md +0 -75
  278. package/docs/examples/ink-renderer.md +0 -41
  279. package/docs/examples/ink.md +0 -103
  280. package/docs/examples/ipc-socket.md +0 -103
  281. package/docs/examples/json-tree.md +0 -91
  282. package/docs/examples/networking.md +0 -58
  283. package/docs/examples/nlp.md +0 -91
  284. package/docs/examples/opener.md +0 -78
  285. package/docs/examples/os.md +0 -72
  286. package/docs/examples/package-finder.md +0 -89
  287. package/docs/examples/postgres.md +0 -91
  288. package/docs/examples/proc.md +0 -81
  289. package/docs/examples/process-manager.md +0 -79
  290. package/docs/examples/python.md +0 -132
  291. package/docs/examples/repl.md +0 -93
  292. package/docs/examples/runpod.md +0 -119
  293. package/docs/examples/secure-shell.md +0 -92
  294. package/docs/examples/sqlite.md +0 -86
  295. package/docs/examples/structured-output-with-assistants.md +0 -144
  296. package/docs/examples/telegram.md +0 -77
  297. package/docs/examples/tts.md +0 -86
  298. package/docs/examples/ui.md +0 -80
  299. package/docs/examples/vault.md +0 -70
  300. package/docs/examples/vm.md +0 -86
  301. package/docs/examples/websocket-ask-and-reply-example.md +0 -128
  302. package/docs/examples/yaml-tree.md +0 -93
  303. package/docs/examples/yaml.md +0 -104
  304. package/docs/ideas/assistant-factory-pattern.md +0 -142
  305. package/docs/in-memory-fs.md +0 -4
  306. package/docs/introspection-audit.md +0 -49
  307. package/docs/introspection.md +0 -164
  308. package/docs/mcp/readme.md +0 -162
  309. package/docs/models.ts +0 -41
  310. package/docs/philosophy.md +0 -86
  311. package/docs/principles.md +0 -7
  312. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +0 -34
  313. package/docs/prompts/check-for-undocumented-features.md +0 -27
  314. package/docs/prompts/mcp-test-easy-command.md +0 -27
  315. package/docs/scaffolds/client.md +0 -149
  316. package/docs/scaffolds/command.md +0 -120
  317. package/docs/scaffolds/endpoint.md +0 -171
  318. package/docs/scaffolds/feature.md +0 -158
  319. package/docs/scaffolds/selector.md +0 -91
  320. package/docs/scaffolds/server.md +0 -196
  321. package/docs/selectors.md +0 -115
  322. package/docs/sessions/custom-command/attempt-log-2.md +0 -195
  323. package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +0 -728
  324. package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +0 -555
  325. package/docs/sessions/grep-audit-report/attempt-log-1.md +0 -289
  326. package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +0 -679
  327. package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +0 -1
  328. package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +0 -920
  329. package/docs/sessions/simple-rest-api/attempt-log-1.md +0 -593
  330. package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +0 -995
  331. package/docs/tutorials/00-bootstrap.md +0 -166
  332. package/docs/tutorials/01-getting-started.md +0 -106
  333. package/docs/tutorials/02-container.md +0 -210
  334. package/docs/tutorials/03-scripts.md +0 -194
  335. package/docs/tutorials/04-features-overview.md +0 -196
  336. package/docs/tutorials/05-state-and-events.md +0 -171
  337. package/docs/tutorials/06-servers.md +0 -157
  338. package/docs/tutorials/07-endpoints.md +0 -198
  339. package/docs/tutorials/08-commands.md +0 -252
  340. package/docs/tutorials/09-clients.md +0 -162
  341. package/docs/tutorials/10-creating-features.md +0 -203
  342. package/docs/tutorials/11-contentbase.md +0 -191
  343. package/docs/tutorials/12-assistants.md +0 -215
  344. package/docs/tutorials/13-introspection.md +0 -157
  345. package/docs/tutorials/14-type-system.md +0 -174
  346. package/docs/tutorials/15-project-patterns.md +0 -222
  347. package/docs/tutorials/16-google-features.md +0 -534
  348. package/docs/tutorials/17-tui-blocks.md +0 -530
  349. package/docs/tutorials/18-semantic-search.md +0 -334
  350. package/docs/tutorials/19-python-sessions.md +0 -401
  351. package/docs/tutorials/20-browser-esm.md +0 -234
  352. package/index.ts +0 -1
  353. package/src/agi/endpoints/ask.ts +0 -60
  354. package/src/agi/endpoints/conversations/[id].ts +0 -45
  355. package/src/agi/endpoints/conversations.ts +0 -31
  356. package/src/agi/endpoints/experts.ts +0 -37
  357. package/test/assistant-hooks.test.ts +0 -306
  358. package/test/assistant.test.ts +0 -81
  359. package/test/bus.test.ts +0 -134
  360. package/test/clients-servers.test.ts +0 -217
  361. package/test/command.test.ts +0 -267
  362. package/test/container-link.test.ts +0 -274
  363. package/test/conversation.test.ts +0 -220
  364. package/test/features.test.ts +0 -160
  365. package/test/fork-and-research.test.ts +0 -450
  366. package/test/integration.test.ts +0 -787
  367. package/test/interceptor-chain.test.ts +0 -61
  368. package/test/node-container.test.ts +0 -121
  369. package/test/python-session.test.ts +0 -105
  370. package/test/rate-limit.test.ts +0 -272
  371. package/test/semantic-search.test.ts +0 -550
  372. package/test/state.test.ts +0 -121
  373. package/test/vm-context.test.ts +0 -146
  374. package/test/vm-loadmodule.test.ts +0 -213
  375. package/test/websocket-ask.test.ts +0 -101
  376. package/test-integration/assistant.test.ts +0 -138
  377. package/test-integration/assistants-manager.test.ts +0 -113
  378. package/test-integration/claude-code.test.ts +0 -98
  379. package/test-integration/conversation-history.test.ts +0 -205
  380. package/test-integration/conversation.test.ts +0 -137
  381. package/test-integration/elevenlabs.test.ts +0 -55
  382. package/test-integration/google-services.test.ts +0 -80
  383. package/test-integration/helpers.ts +0 -89
  384. package/test-integration/memory.test.ts +0 -204
  385. package/test-integration/openai-codex.test.ts +0 -93
  386. package/test-integration/runpod.test.ts +0 -58
  387. package/test-integration/server-endpoints.test.ts +0 -97
  388. package/test-integration/telegram.test.ts +0 -46
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/agi'
1
+ import container from 'luca/agi'
2
2
 
3
3
  async function main() {
4
4
  const chat = container.feature('conversation', {
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  async function main() {
4
4
  const cache = container.feature('diskCache')
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  async function main() {
4
4
  const docker = container.feature('docker', { enable: true, autoRefresh: true })
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
  import '../../src/clients/elevenlabs'
3
3
 
4
4
  async function main() {
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  async function main() {
4
4
  // GoogleAuth reads GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET from env.
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  // Pass a document ID as the first argument, or omit to list available docs.
4
4
  // You can find the ID in a Google Docs URL:
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  async function main() {
4
4
  // GoogleAuth reads GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET from env.
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  // Pass a spreadsheet ID as the first argument, or set DEFAULT_SPREADSHEET_ID env var.
4
4
  // You can find the ID in a Google Sheets URL:
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  const nlp = container.feature('nlp', { enable: true })
4
4
 
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/agi'
1
+ import container from 'luca/agi'
2
2
 
3
3
  const conversation = container.feature('conversation', {
4
4
  local: true,
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  const DEFAULT_DATABASE_URL = 'postgresql://postgres:postgres@127.0.0.1:54322/postgres'
4
4
 
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  async function main() {
4
4
  const runpod = container.feature('runpod')
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
 
3
3
  async function main() {
4
4
  const tts = container.feature('tts', { enable: true })
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/node'
1
+ import container from 'luca/node'
2
2
  import { join } from 'path'
3
3
 
4
4
  const { ui, fs, argv } = container
@@ -84,15 +84,15 @@ function generateClient(name: string, description: string): string {
84
84
 
85
85
  return ui.endent`
86
86
  import { z } from 'zod'
87
- import { ClientStateSchema, ClientOptionsSchema } from '@soederpop/luca/schemas/base.js'
87
+ import { ClientStateSchema, ClientOptionsSchema } from 'luca/schemas/base.js'
88
88
  import {
89
89
  type ClientsInterface,
90
90
  clients,
91
91
  RestClient,
92
- } from '@soederpop/luca/client'
93
- import { type ContainerContext } from '@soederpop/luca/container'
92
+ } from 'luca/client'
93
+ import { type ContainerContext } from 'luca/container'
94
94
 
95
- declare module '@soederpop/luca/client' {
95
+ declare module 'luca/client' {
96
96
  interface AvailableClients {
97
97
  ${registryKey}: typeof ${className}
98
98
  }
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/agi'
1
+ import container from 'luca/agi'
2
2
 
3
3
  const fs = container.feature('fs')
4
4
 
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/agi'
1
+ import container from 'luca/agi'
2
2
 
3
3
  const coder = container.feature('assistant', { folder: 'assistants/codingAssistant' })
4
4
 
@@ -1,4 +1,4 @@
1
- import container from '@soederpop/luca/agi'
1
+ import container from 'luca/agi'
2
2
 
3
3
  const reader = container.feature('docsReader', {
4
4
  contentDb: (await container.docs.load())
@@ -13,12 +13,13 @@ import { AssistantsManager } from './features/assistants-manager'
13
13
  import { DocsReader } from './features/docs-reader'
14
14
  import { SkillsLibrary } from './features/skills-library'
15
15
  import { BrowserUse } from './features/browser-use'
16
- import { SemanticSearch } from '@soederpop/luca/node/features/semantic-search'
17
- import { ContentDb } from '@soederpop/luca/node/features/content-db'
16
+ import { SemanticSearch } from 'luca/node/features/semantic-search'
17
+ import { ContentDb } from 'luca/node/features/content-db'
18
18
  import { FileTools } from './features/file-tools'
19
19
  import { LucaCoder } from './features/luca-coder'
20
20
  import { Memory } from './features/agent-memory'
21
21
  import { CodingTools } from './features/coding-tools'
22
+ import { McpBridge } from './features/mcp-bridge'
22
23
 
23
24
  import type { ConversationTool } from './features/conversation'
24
25
  import type { ZodType } from 'zod'
@@ -37,6 +38,7 @@ export {
37
38
  LucaCoder,
38
39
  Memory,
39
40
  CodingTools,
41
+ McpBridge,
40
42
  SemanticSearch,
41
43
  ContentDb,
42
44
  NodeContainer,
@@ -65,6 +67,7 @@ export interface AGIFeatures extends NodeFeatures {
65
67
  lucaCoder: typeof LucaCoder
66
68
  memory: typeof Memory
67
69
  codingTools: typeof CodingTools
70
+ mcpBridge: typeof McpBridge
68
71
  }
69
72
 
70
73
  export interface ConversationFactoryOptions {
@@ -143,6 +146,7 @@ const container = new AGIContainer()
143
146
  .use(LucaCoder)
144
147
  .use(Memory)
145
148
  .use(CodingTools)
149
+ .use(McpBridge)
146
150
  .use(SemanticSearch)
147
151
 
148
152
  container.docs = container.feature('contentDb', {
@@ -3,7 +3,7 @@ import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '.
3
3
  import { Feature } from '../feature.js'
4
4
  import type { Helper } from '../../helper.js'
5
5
 
6
- declare module '@soederpop/luca/feature' {
6
+ declare module 'luca/feature' {
7
7
  interface AvailableFeatures {
8
8
  memory: typeof Memory
9
9
  }
@@ -169,13 +169,13 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
169
169
  )
170
170
  `)
171
171
 
172
- const rows = await this.db.query<{ value: number }>(
172
+ const rows = await this.db.query(
173
173
  'SELECT value FROM epochs WHERE namespace = ?',
174
174
  [this.options.namespace]
175
- )
175
+ ) as { value: number }[]
176
176
 
177
177
  if (rows.length) {
178
- this.state.set('epoch', rows[0].value)
178
+ this.state.set('epoch', rows[0]!.value)
179
179
  } else {
180
180
  await this.db.execute('INSERT INTO epochs (namespace, value) VALUES (?, 1)', [this.options.namespace])
181
181
  }
@@ -299,7 +299,7 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
299
299
  await this.ensureDb()
300
300
 
301
301
  const results = await this.search(category, text, 1)
302
- if (results.length > 0 && (1 - results[0].distance) >= similarityThreshold) {
302
+ if (results.length > 0 && (1 - results[0]!.distance) >= similarityThreshold) {
303
303
  return null
304
304
  }
305
305
 
@@ -316,10 +316,10 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
316
316
  async get(category: string, id: number): Promise<MemoryRecord | null> {
317
317
  await this.ensureDb()
318
318
 
319
- const rows = await this.db.query<any>(
319
+ const rows = await this.db.query(
320
320
  'SELECT id, category, document, metadata, created_at, updated_at FROM memories WHERE namespace = ? AND category = ? AND id = ?',
321
321
  [this.options.namespace, category, id]
322
- )
322
+ ) as any[]
323
323
 
324
324
  if (!rows.length) return null
325
325
  return this.rowToMemory(rows[0])
@@ -340,10 +340,10 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
340
340
 
341
341
  const { limit = 20, sortOrder = 'desc', filterMetadata } = options
342
342
 
343
- let rows = await this.db.query<any>(
343
+ let rows = await this.db.query(
344
344
  `SELECT id, category, document, metadata, created_at, updated_at FROM memories WHERE namespace = ? AND category = ? ORDER BY created_at ${sortOrder === 'asc' ? 'ASC' : 'DESC'} LIMIT ?`,
345
345
  [this.options.namespace, category, limit]
346
- )
346
+ ) as any[]
347
347
 
348
348
  if (filterMetadata) {
349
349
  rows = rows.filter((row: any) => {
@@ -462,18 +462,18 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
462
462
  await this.ensureDb()
463
463
 
464
464
  if (category) {
465
- const rows = await this.db.query<{ cnt: number }>(
465
+ const rows = await this.db.query(
466
466
  'SELECT COUNT(*) as cnt FROM memories WHERE namespace = ? AND category = ?',
467
467
  [this.options.namespace, category]
468
- )
469
- return rows[0].cnt
468
+ ) as { cnt: number }[]
469
+ return rows[0]!.cnt
470
470
  }
471
471
 
472
- const rows = await this.db.query<{ cnt: number }>(
472
+ const rows = await this.db.query(
473
473
  'SELECT COUNT(*) as cnt FROM memories WHERE namespace = ?',
474
474
  [this.options.namespace]
475
- )
476
- return rows[0].cnt
475
+ ) as { cnt: number }[]
476
+ return rows[0]!.cnt
477
477
  }
478
478
 
479
479
  /**
@@ -484,10 +484,10 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
484
484
  async categories(): Promise<string[]> {
485
485
  await this.ensureDb()
486
486
 
487
- const rows = await this.db.query<{ category: string }>(
487
+ const rows = await this.db.query(
488
488
  'SELECT DISTINCT category FROM memories WHERE namespace = ?',
489
489
  [this.options.namespace]
490
- )
490
+ ) as { category: string }[]
491
491
 
492
492
  return rows.map((r: { category: string }) => r.category)
493
493
  }
@@ -510,10 +510,10 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
510
510
 
511
511
  const queryEmbedding = await this.embed(query)
512
512
 
513
- const rows = await this.db.query<any>(
513
+ const rows = await this.db.query(
514
514
  'SELECT id, category, document, metadata, embedding, created_at, updated_at FROM memories WHERE namespace = ? AND category = ? AND embedding IS NOT NULL',
515
515
  [this.options.namespace, category]
516
- )
516
+ ) as any[]
517
517
 
518
518
  let scored = rows.map((row: any) => {
519
519
  const stored = this.blobToFloat64(row.embedding)
@@ -600,10 +600,10 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
600
600
  async exportToJson(): Promise<{ namespace: string; epoch: number; memories: MemoryRecord[] }> {
601
601
  await this.ensureDb()
602
602
 
603
- const rows = await this.db.query<any>(
603
+ const rows = await this.db.query(
604
604
  'SELECT id, category, document, metadata, created_at, updated_at FROM memories WHERE namespace = ? ORDER BY category, id',
605
605
  [this.options.namespace]
606
- )
606
+ ) as any[]
607
607
 
608
608
  return {
609
609
  namespace: this.options.namespace,
@@ -651,7 +651,7 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
651
651
  private float64ToBlob(arr: number[]): Buffer {
652
652
  const buf = Buffer.alloc(arr.length * 8)
653
653
  for (let i = 0; i < arr.length; i++) {
654
- buf.writeDoubleLE(arr[i], i * 8)
654
+ buf.writeDoubleLE(arr[i]!, i * 8)
655
655
  }
656
656
  return buf
657
657
  }
@@ -670,9 +670,9 @@ export class Memory extends Feature<MemoryState, MemoryOptions> {
670
670
  private cosineDistance(a: number[], b: number[]): number {
671
671
  let dot = 0, magA = 0, magB = 0
672
672
  for (let i = 0; i < a.length; i++) {
673
- dot += a[i] * b[i]
674
- magA += a[i] * a[i]
675
- magB += b[i] * b[i]
673
+ dot += a[i]! * b[i]!
674
+ magA += a[i]! * a[i]!
675
+ magB += b[i]! * b[i]!
676
676
  }
677
677
  const similarity = dot / (Math.sqrt(magA) * Math.sqrt(magB))
678
678
  return 1 - similarity
@@ -1,16 +1,16 @@
1
1
  import { z } from 'zod'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
- import { type AvailableFeatures } from '@soederpop/luca/feature'
3
+ import { type AvailableFeatures } from 'luca/feature'
4
4
  import { Feature } from '../feature.js'
5
5
  import type { Conversation, ConversationTool, ContentPart, AskOptions, ForkOptions, Message } from './conversation'
6
- import type { ContentDb } from '@soederpop/luca/node'
6
+ import type { ContentDb } from 'luca/node'
7
7
  import type { ConversationHistory, ConversationMeta } from './conversation-history'
8
8
  import hashObject from '../../hash-object.js'
9
9
  import { InterceptorChain, type InterceptorFn, type InterceptorPoints, type InterceptorPoint } from '../lib/interceptor-chain.js'
10
10
  import type { Entity } from '../../entity.js'
11
11
  import { State } from '../../state.js'
12
12
 
13
- declare module '@soederpop/luca/feature' {
13
+ declare module 'luca/feature' {
14
14
  interface AvailableFeatures {
15
15
  assistant: typeof Assistant
16
16
  }
@@ -577,7 +577,25 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
577
577
  * }, z.object({ city: z.string() }).describe('Get weather for a city'))
578
578
  * ```
579
579
  */
580
- addTool(name: string, handler: (...args: any[]) => any, schema?: z.ZodType): this {
580
+ addTool(name: string, handler: (...args: any[]) => any, schema?: z.ZodType): this
581
+ addTool(handler: (...args: any[]) => any, schema?: z.ZodType): this
582
+ addTool(nameOrHandler: string | ((...args: any[]) => any), handlerOrSchema?: ((...args: any[]) => any) | z.ZodType, maybeSchema?: z.ZodType): this {
583
+ let name: string
584
+ let handler: (...args: any[]) => any
585
+ let schema: z.ZodType | undefined
586
+
587
+ if (typeof nameOrHandler === 'function') {
588
+ // addTool(handler, schema?) — extract name from function
589
+ handler = nameOrHandler
590
+ name = handler.name
591
+ schema = handlerOrSchema as z.ZodType | undefined
592
+ } else {
593
+ // addTool(name, handler, schema?)
594
+ name = nameOrHandler
595
+ handler = handlerOrSchema as (...args: any[]) => any
596
+ schema = maybeSchema
597
+ }
598
+
581
599
  if (!name) throw new Error('addTool handler must be a named function')
582
600
  if (!this._runtimeToolNames) this._runtimeToolNames = new Set()
583
601
  this._runtimeToolNames.add(name)
@@ -777,7 +795,7 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
777
795
  return this.mergeOptionTools(tools)
778
796
  }
779
797
 
780
- // Ensure virtual modules (zod, @soederpop/luca, etc.) are seeded so tools
798
+ // Ensure virtual modules (zod, luca, etc.) are seeded so tools
781
799
  // files outside the project tree can resolve them through the VM
782
800
  if (this.container.features.has('helpers')) {
783
801
  const helpers = this.container.feature('helpers') as any
@@ -1093,6 +1111,17 @@ export class Assistant extends Feature<AssistantState, AssistantOptions> {
1093
1111
  // Reload tools from disk (merges with option tools), then restore runtime tools
1094
1112
  const diskTools = this.loadTools()
1095
1113
  this.state.set('tools', { ...diskTools, ...runtimeTools })
1114
+
1115
+ // Re-process deferred `use` entries (export const use = [...] in tools.ts).
1116
+ // These replace tools from the same features, which is a no-op when unchanged.
1117
+ const deferredUse = this.state.get('deferredUse') as any[] | undefined
1118
+ if (deferredUse?.length) {
1119
+ for (const entry of deferredUse) {
1120
+ this.use(entry)
1121
+ }
1122
+ this.state.set('deferredUse', undefined)
1123
+ }
1124
+
1096
1125
  this.emit('toolsChanged')
1097
1126
 
1098
1127
  // Reload hooks from disk — triggerHook reads from state so new hooks are active immediately
@@ -1,11 +1,13 @@
1
1
  import { z } from 'zod'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
- import { type AvailableFeatures } from '@soederpop/luca/feature'
3
+ import { type AvailableFeatures } from 'luca/feature'
4
4
  import { Feature } from '../feature.js'
5
5
  import type { Assistant } from './assistant.js'
6
+ import type { ConversationHistory, ConversationMeta, ConversationRecord } from './conversation-history.js'
6
7
  import type { InterceptorFn, InterceptorPoint, InterceptorPoints } from '../lib/interceptor-chain.js'
8
+ import hashObject from '../../hash-object.js'
7
9
 
8
- declare module '@soederpop/luca/feature' {
10
+ declare module 'luca/feature' {
9
11
  interface AvailableFeatures {
10
12
  assistantsManager: typeof AssistantsManager
11
13
  }
@@ -200,15 +202,15 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
200
202
  let meta: Record<string, any> | undefined
201
203
 
202
204
  if (hasAbout) {
203
- about = fs.readFileSync(`${folder}/ABOUT.md`, 'utf8')
205
+ about = fs.readFileSync(`${folder}/ABOUT.md`, 'utf8') as string
204
206
  }
205
207
 
206
208
  try {
207
- const coreContent = fs.readFileSync(`${folder}/CORE.md`, 'utf8')
209
+ const coreContent = fs.readFileSync(`${folder}/CORE.md`, 'utf8') as string
208
210
  const fmMatch = coreContent.match(/^---\r?\n([\s\S]*?)\r?\n---/)
209
211
  if (fmMatch) {
210
212
  const yaml = this.container.feature('yaml')
211
- meta = yaml.parse(fmMatch[1])
213
+ meta = yaml.parse(fmMatch[1]!)
212
214
  }
213
215
  } catch {
214
216
  // CORE.md exists but couldn't be parsed — skip meta
@@ -275,7 +277,22 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
275
277
  * @returns {AssistantEntry[]} All discovered entries
276
278
  */
277
279
  list(): AssistantEntry[] {
278
- return Object.values(this.entries)
280
+ const discovered = Object.values(this.entries)
281
+ const discoveredNames = new Set(discovered.map((e) => e.name))
282
+
283
+ // Include registered factories that weren't discovered on disk
284
+ const registeredOnly = Object.keys(this.factories)
285
+ .filter((name) => !discoveredNames.has(name))
286
+ .map((name): AssistantEntry => ({
287
+ name,
288
+ folder: '',
289
+ hasCorePrompt: false,
290
+ hasTools: false,
291
+ hasHooks: false,
292
+ hasVoice: false,
293
+ }))
294
+
295
+ return [...discovered, ...registeredOnly]
279
296
  }
280
297
 
281
298
  /**
@@ -378,6 +395,105 @@ export class AssistantsManager extends Feature<AssistantsManagerState, Assistant
378
395
  }
379
396
  }
380
397
 
398
+ /**
399
+ * Reload tools, hooks, and system prompt from disk for active assistants.
400
+ * When called with a name, reloads only that assistant. When called without
401
+ * arguments, reloads all active instances.
402
+ *
403
+ * @param {string} [name] - Optional assistant name to reload. Omit to reload all.
404
+ * @returns {{ reloaded: string[] }} Names of assistants that were reloaded
405
+ * @throws {Error} If a specific name is given but no active instance exists for it
406
+ *
407
+ * @example
408
+ * ```typescript
409
+ * manager.reload('researcher') // reload one
410
+ * manager.reload() // reload all active
411
+ * ```
412
+ */
413
+ reload(name?: string): { reloaded: string[] } {
414
+ const reloaded: string[] = []
415
+
416
+ if (name) {
417
+ const instance = this.instances[name]
418
+ if (!instance) {
419
+ throw new Error(
420
+ `No active assistant "${name}" to reload. Active: ${Object.keys(this.instances).join(', ') || '(none)'}`
421
+ )
422
+ }
423
+ instance.reload()
424
+ reloaded.push(name)
425
+ } else {
426
+ for (const [key, instance] of Object.entries(this.instances)) {
427
+ instance.reload()
428
+ reloaded.push(key)
429
+ }
430
+ }
431
+
432
+ return { reloaded }
433
+ }
434
+
435
+ /**
436
+ * Build the thread prefix for a given assistant name, matching the
437
+ * convention used by the Assistant class: `name:cwdHash:`.
438
+ * This allows history lookups without an active instance.
439
+ *
440
+ * @param {string} assistantId - The assistant name
441
+ * @returns {string} The thread prefix
442
+ */
443
+ threadPrefixFor(assistantId: string): string {
444
+ const cwdHash = hashObject(this.container.cwd).slice(0, 8)
445
+ return `${assistantId}:${cwdHash}:`
446
+ }
447
+
448
+ /**
449
+ * Load conversation history for an assistant. Works whether or not the
450
+ * assistant is currently instantiated — uses the thread prefix convention
451
+ * to query the conversationHistory feature directly.
452
+ *
453
+ * @param {string} assistantId - The assistant name (e.g. 'researcher')
454
+ * @param {object} [options] - Query options
455
+ * @param {number} [options.limit] - Maximum number of records to return
456
+ * @param {boolean} [options.includeMessages] - Load full records with messages (default: false, returns metadata only)
457
+ * @param {string} [options.thread] - Load a specific thread ID instead of all threads for this assistant
458
+ * @returns {Promise<ConversationMeta[] | ConversationRecord[]>} Metadata or full records, newest first
459
+ *
460
+ * @example
461
+ * ```typescript
462
+ * // List recent sessions (metadata only)
463
+ * const sessions = await manager.loadAssistantHistory('researcher', { limit: 5 })
464
+ *
465
+ * // Load full records with messages
466
+ * const full = await manager.loadAssistantHistory('researcher', { includeMessages: true, limit: 3 })
467
+ *
468
+ * // Load a specific thread
469
+ * const thread = await manager.loadAssistantHistory('researcher', { thread: 'researcher:abc12345:2026-04-12' })
470
+ * ```
471
+ */
472
+ async loadAssistantHistory(
473
+ assistantId: string,
474
+ options?: { limit?: number; includeMessages?: boolean; thread?: string },
475
+ ): Promise<ConversationMeta[] | ConversationRecord[]> {
476
+ const history = this.container.feature('conversationHistory') as ConversationHistory
477
+
478
+ if (options?.thread) {
479
+ const record = await history.findByThread(options.thread)
480
+ return record ? [record] : []
481
+ }
482
+
483
+ const prefix = this.threadPrefixFor(assistantId)
484
+ const metas = await history.findByThreadPrefix(prefix)
485
+ const limited = options?.limit ? metas.slice(0, options.limit) : metas
486
+
487
+ if (!options?.includeMessages) return limited
488
+
489
+ const records: ConversationRecord[] = []
490
+ for (const meta of limited) {
491
+ const record = await history.load(meta.id)
492
+ if (record) records.push(record)
493
+ }
494
+ return records
495
+ }
496
+
381
497
  /**
382
498
  * Returns a previously created assistant instance by name.
383
499
  *
@@ -4,7 +4,7 @@ import { Feature } from '../feature.js'
4
4
  import type { Assistant } from './assistant.js'
5
5
  import type { ToolCallCtx } from '../lib/interceptor-chain.js'
6
6
 
7
- declare module '@soederpop/luca/feature' {
7
+ declare module 'luca/feature' {
8
8
  interface AvailableFeatures {
9
9
  autoAssistant: typeof AutonomousAssistant
10
10
  }
@@ -3,7 +3,7 @@ import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '.
3
3
  import { Feature } from '../feature.js'
4
4
  import type { Helper } from '../../helper.js'
5
5
 
6
- declare module '@soederpop/luca/feature' {
6
+ declare module 'luca/feature' {
7
7
  interface AvailableFeatures {
8
8
  browserUse: typeof BrowserUse
9
9
  }
@@ -220,6 +220,12 @@ export class BrowserUse extends Feature<BrowserUseState, BrowserUseOptions> {
220
220
  description: 'List all active browser sessions.',
221
221
  schema: z.object({}).describe('List all currently active browser sessions with their names and status.'),
222
222
  },
223
+ browserSetHeaded: {
224
+ description: 'Toggle browser visibility. Use headed mode to show the browser window, or headless mode to hide it.',
225
+ schema: z.object({
226
+ headed: z.boolean().describe('true to show the browser window (headed), false to hide it (headless)'),
227
+ }).describe('Toggle the browser between headed (visible window) and headless mode. When the user asks to see the browser or hide it, use this tool.'),
228
+ },
223
229
  }
224
230
 
225
231
  static { Feature.register(this, 'browserUse') }
@@ -490,6 +496,15 @@ export class BrowserUse extends Feature<BrowserUseState, BrowserUseOptions> {
490
496
  return this.exec('sessions')
491
497
  }
492
498
 
499
+ /**
500
+ * Toggle headed/headless mode
501
+ * @param headed - true for visible browser window, false for headless
502
+ */
503
+ setHeaded(headed: boolean): { success: boolean; headed: boolean } {
504
+ this.state.set('headed', headed)
505
+ return { success: true, headed }
506
+ }
507
+
493
508
  /**
494
509
  * Hover over an element
495
510
  * @param index - Element index
@@ -648,6 +663,10 @@ export class BrowserUse extends Feature<BrowserUseState, BrowserUseOptions> {
648
663
  async browserGetAttributes(options: { index: string }) {
649
664
  return this.getAttributes(options.index)
650
665
  }
666
+
667
+ async browserSetHeaded(options: { headed: boolean }) {
668
+ return this.setHeaded(options.headed)
669
+ }
651
670
  }
652
671
 
653
672
  export default BrowserUse