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,217 +0,0 @@
1
- import { describe, it, expect, spyOn } from 'bun:test'
2
- import { NodeContainer } from '../src/node/container'
3
- import { WebSocketClient } from '../src/clients/websocket'
4
- import { GraphClient } from '../src/clients/graph'
5
-
6
- describe('Clients', () => {
7
- it('container has clients registry after construction', () => {
8
- const c = new NodeContainer()
9
- expect(c.clients).toBeDefined()
10
- expect(typeof c.clients.has).toBe('function')
11
- expect(typeof c.clients.lookup).toBe('function')
12
- })
13
-
14
- it('has rest and graph clients registered', () => {
15
- const c = new NodeContainer()
16
- expect(c.clients.available).toContain('rest')
17
- expect(c.clients.available).toContain('graph')
18
- })
19
-
20
- it('container.client() factory creates a client', () => {
21
- const c = new NodeContainer()
22
- const rest = c.client('rest', { baseURL: 'https://example.com' })
23
- expect(rest).toBeDefined()
24
- expect(rest.uuid).toBeDefined()
25
- expect(rest.baseURL).toBe('https://example.com')
26
- })
27
-
28
- it('client has state with connected=false initially', () => {
29
- const c = new NodeContainer()
30
- const rest = c.client('rest')
31
- expect(rest.isConnected).toBe(false)
32
- })
33
-
34
- it('client.connect() sets connected state', async () => {
35
- const c = new NodeContainer()
36
- const rest = c.client('rest')
37
- await rest.connect()
38
- expect(rest.isConnected).toBe(true)
39
- })
40
-
41
- it('client has access to container via context', () => {
42
- const c = new NodeContainer()
43
- const rest = c.client('rest')
44
- expect(rest.container.uuid).toBe(c.uuid)
45
- })
46
- })
47
-
48
- describe('WebSocketClient', () => {
49
- it('is registered as websocket client', () => {
50
- const c = new NodeContainer()
51
- expect(c.clients.available).toContain('websocket')
52
- })
53
-
54
- it('factory creates a WebSocketClient instance', () => {
55
- const c = new NodeContainer()
56
- const ws = c.client('websocket', { baseURL: 'ws://localhost:8080' })
57
- expect(ws).toBeDefined()
58
- expect(ws).toBeInstanceOf(WebSocketClient)
59
- expect(ws.baseURL).toBe('ws://localhost:8080')
60
- })
61
-
62
- it('starts disconnected with correct initial state', () => {
63
- const c = new NodeContainer()
64
- const ws = c.client('websocket', { baseURL: 'ws://localhost:8080' })
65
- expect(ws.isConnected).toBe(false)
66
- expect(ws.hasError).toBe(false)
67
- expect(ws.state.get('reconnectAttempts')).toBe(0)
68
- })
69
-
70
- it('has send and disconnect methods', () => {
71
- const c = new NodeContainer()
72
- const ws = c.client('websocket', { baseURL: 'ws://localhost:8080' })
73
- expect(typeof ws.send).toBe('function')
74
- expect(typeof ws.disconnect).toBe('function')
75
- })
76
-
77
- it('accepts reconnect options', () => {
78
- const c = new NodeContainer()
79
- const ws = c.client('websocket', {
80
- baseURL: 'ws://localhost:8080',
81
- reconnect: true,
82
- reconnectInterval: 2000,
83
- maxReconnectAttempts: 5,
84
- })
85
- expect(ws.options.reconnect).toBe(true)
86
- expect(ws.options.reconnectInterval).toBe(2000)
87
- expect(ws.options.maxReconnectAttempts).toBe(5)
88
- })
89
-
90
- it('has proper event and state schemas', () => {
91
- expect(WebSocketClient.eventsSchema).toBeDefined()
92
- expect(WebSocketClient.stateSchema).toBeDefined()
93
- expect(WebSocketClient.optionsSchema).toBeDefined()
94
- })
95
- })
96
-
97
- describe('GraphClient', () => {
98
- it('is registered as graph client', () => {
99
- const c = new NodeContainer()
100
- expect(c.clients.available).toContain('graph')
101
- })
102
-
103
- it('factory creates a GraphClient instance', () => {
104
- const c = new NodeContainer()
105
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
106
- expect(gql).toBeDefined()
107
- expect(gql).toBeInstanceOf(GraphClient)
108
- })
109
-
110
- it('extends RestClient with HTTP methods', () => {
111
- const c = new NodeContainer()
112
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
113
- expect(typeof gql.get).toBe('function')
114
- expect(typeof gql.post).toBe('function')
115
- expect(typeof gql.put).toBe('function')
116
- expect(typeof gql.delete).toBe('function')
117
- expect(typeof gql.patch).toBe('function')
118
- })
119
-
120
- it('has query and mutate methods', () => {
121
- const c = new NodeContainer()
122
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
123
- expect(typeof gql.query).toBe('function')
124
- expect(typeof gql.mutate).toBe('function')
125
- })
126
-
127
- it('defaults endpoint to /graphql', () => {
128
- const c = new NodeContainer()
129
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
130
- expect(gql.endpoint).toBe('/graphql')
131
- })
132
-
133
- it('accepts custom endpoint option', () => {
134
- const c = new NodeContainer()
135
- const gql = c.client('graph', { baseURL: 'https://api.example.com', endpoint: '/api/graphql' })
136
- expect(gql.endpoint).toBe('/api/graphql')
137
- })
138
-
139
- it('query() posts to the endpoint and unwraps data', async () => {
140
- const c = new NodeContainer()
141
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
142
-
143
- // Mock the post method to simulate a GraphQL response
144
- spyOn(gql, 'post').mockResolvedValue({
145
- data: { user: { name: 'Jon' } },
146
- })
147
-
148
- const result = await gql.query('{ user { name } }')
149
- expect(result).toEqual({ user: { name: 'Jon' } })
150
- expect(gql.post).toHaveBeenCalledWith('/graphql', { query: '{ user { name } }' })
151
- })
152
-
153
- it('query() passes variables and operationName', async () => {
154
- const c = new NodeContainer()
155
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
156
-
157
- spyOn(gql, 'post').mockResolvedValue({
158
- data: { user: { name: 'Jon' } },
159
- })
160
-
161
- await gql.query('query GetUser($id: ID!) { user(id: $id) { name } }', { id: '1' }, 'GetUser')
162
- expect(gql.post).toHaveBeenCalledWith('/graphql', {
163
- query: 'query GetUser($id: ID!) { user(id: $id) { name } }',
164
- variables: { id: '1' },
165
- operationName: 'GetUser',
166
- })
167
- })
168
-
169
- it('mutate() posts to the endpoint and unwraps data', async () => {
170
- const c = new NodeContainer()
171
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
172
-
173
- spyOn(gql, 'post').mockResolvedValue({
174
- data: { createUser: { id: '1' } },
175
- })
176
-
177
- const result = await gql.mutate('mutation { createUser(name: "Jon") { id } }')
178
- expect(result).toEqual({ createUser: { id: '1' } })
179
- })
180
-
181
- it('emits graphqlError and failure on GraphQL-level errors', async () => {
182
- const c = new NodeContainer()
183
- const gql = c.client('graph', { baseURL: 'https://api.example.com' })
184
- const errors = [{ message: 'Not found' }]
185
-
186
- spyOn(gql, 'post').mockResolvedValue({
187
- data: null,
188
- errors,
189
- })
190
-
191
- const graphqlErrors: any[] = []
192
- const failures: any[] = []
193
- gql.on('graphqlError', (errs: any) => graphqlErrors.push(errs))
194
- gql.on('failure', (err: any) => failures.push(err))
195
-
196
- const result = await gql.query('{ user { name } }')
197
- expect(result).toBeNull()
198
- expect(graphqlErrors).toHaveLength(1)
199
- expect(graphqlErrors[0]).toEqual(errors)
200
- expect(failures).toHaveLength(1)
201
- expect(failures[0]).toEqual(errors)
202
- })
203
- })
204
-
205
- describe('Servers', () => {
206
- it('container has servers registry after construction', () => {
207
- const c = new NodeContainer()
208
- expect(c.servers).toBeDefined()
209
- expect(typeof c.servers.has).toBe('function')
210
- })
211
-
212
- it('has express and websocket servers registered', () => {
213
- const c = new NodeContainer()
214
- expect(c.servers.available).toContain('express')
215
- expect(c.servers.available).toContain('websocket')
216
- })
217
- })
@@ -1,267 +0,0 @@
1
- import { describe, it, expect } from 'bun:test'
2
- import { Command, commands } from '../src/command'
3
- import { graftModule, isNativeHelperClass } from '../src/graft'
4
- import { NodeContainer } from '../src/node/container'
5
- import { z } from 'zod'
6
- import { CommandOptionsSchema } from '../src/schemas/base'
7
- // Side-effect import to register built-in commands
8
- import '../src/commands/index'
9
-
10
- describe('graftModule', () => {
11
- it('creates a Command subclass from a run export', () => {
12
- const argsSchema = CommandOptionsSchema.extend({
13
- file: z.string(),
14
- })
15
-
16
- const Grafted = graftModule(Command as any, {
17
- description: 'Run a file',
18
- argsSchema,
19
- positionals: ['file'],
20
- run: async (args: any) => {},
21
- }, 'graft-run-test', 'commands')
22
-
23
- expect((Grafted as any).shortcut).toBe('commands.graft-run-test')
24
- expect((Grafted as any).description).toBe('Run a file')
25
- expect((Grafted as any).commandDescription).toBe('Run a file')
26
- expect((Grafted as any).positionals).toEqual(['file'])
27
- expect((Grafted as any).argsSchema).toBe(argsSchema)
28
- expect(Grafted.name).toBe('GraftRunTestCommand')
29
- })
30
-
31
- it('creates a Command subclass from a handler export (legacy)', () => {
32
- const Grafted = graftModule(Command as any, {
33
- description: 'Legacy handler',
34
- handler: async (opts: any, ctx: any) => {},
35
- }, 'graft-handler-test', 'commands')
36
-
37
- expect((Grafted as any).shortcut).toBe('commands.graft-handler-test')
38
- expect((Grafted as any).description).toBe('Legacy handler')
39
- expect(typeof (Grafted as any).prototype.run).toBe('function')
40
- })
41
-
42
- it('grafts extra exported functions as prototype methods', () => {
43
- const Grafted = graftModule(Command as any, {
44
- run: async () => {},
45
- formatOutput: function (data: any) { return JSON.stringify(data) },
46
- }, 'graft-methods-test', 'commands')
47
-
48
- expect(typeof (Grafted as any).prototype.formatOutput).toBe('function')
49
- })
50
-
51
- it('grafts getters onto the prototype', () => {
52
- const Grafted = graftModule(Command as any, {
53
- run: async () => {},
54
- getters: {
55
- isReady() { return true },
56
- },
57
- }, 'graft-getters-test', 'commands')
58
-
59
- const desc = Object.getOwnPropertyDescriptor((Grafted as any).prototype, 'isReady')
60
- expect(desc).toBeDefined()
61
- expect(typeof desc!.get).toBe('function')
62
- })
63
- })
64
-
65
- describe('isNativeHelperClass', () => {
66
- it('returns true for a direct subclass', () => {
67
- class MyCmd extends Command {}
68
- expect(isNativeHelperClass(MyCmd, Command)).toBe(true)
69
- })
70
-
71
- it('returns false for a plain function', () => {
72
- function notACommand() {}
73
- expect(isNativeHelperClass(notACommand, Command)).toBe(false)
74
- })
75
-
76
- it('returns false for null/undefined', () => {
77
- expect(isNativeHelperClass(null, Command)).toBe(false)
78
- expect(isNativeHelperClass(undefined, Command)).toBe(false)
79
- })
80
-
81
- it('returns true for the base class itself', () => {
82
- expect(isNativeHelperClass(Command, Command)).toBe(true)
83
- })
84
- })
85
-
86
- describe('Command.register', () => {
87
- it('registers a class-based command and sets shortcut', () => {
88
- class TestDeployCommand extends Command {
89
- static override description = 'Deploy to production'
90
- }
91
- Command.register(TestDeployCommand, 'test-deploy')
92
-
93
- expect(commands.has('test-deploy')).toBe(true)
94
- expect((TestDeployCommand as any).shortcut).toBe('commands.test-deploy')
95
- expect((TestDeployCommand as any).commandDescription).toBe('Deploy to production')
96
- })
97
- })
98
-
99
- describe('Command.dispatch', () => {
100
- it('calls run() with parsed args for CLI dispatch', async () => {
101
- let received: any = null
102
-
103
- const argsSchema = CommandOptionsSchema.extend({
104
- target: z.string().default('prod'),
105
- })
106
-
107
- const Grafted = graftModule(Command as any, {
108
- argsSchema,
109
- run: async (args: any, ctx: any) => { received = args },
110
- }, 'dispatch-cli-test', 'commands')
111
-
112
- commands.register('dispatch-cli-test', Grafted as any)
113
- const container = new NodeContainer()
114
- const cmd = container.command('dispatch-cli-test' as any)
115
-
116
- await cmd.dispatch({ _: ['dispatch-cli-test'], target: 'staging' }, 'cli')
117
-
118
- expect(received).toBeDefined()
119
- expect(received.target).toBe('staging')
120
- })
121
-
122
- it('maps positionals to named args for CLI dispatch', async () => {
123
- let received: any = null
124
-
125
- const argsSchema = CommandOptionsSchema.extend({
126
- file: z.string(),
127
- })
128
-
129
- const Grafted = graftModule(Command as any, {
130
- argsSchema,
131
- positionals: ['file'],
132
- run: async (args: any, ctx: any) => { received = args },
133
- }, 'dispatch-positional-test', 'commands')
134
-
135
- commands.register('dispatch-positional-test', Grafted as any)
136
- const container = new NodeContainer()
137
- const cmd = container.command('dispatch-positional-test' as any)
138
-
139
- // Simulate: luca dispatch-positional-test myfile.ts
140
- // minimist produces: { _: ['dispatch-positional-test', 'myfile.ts'] }
141
- await cmd.dispatch({ _: ['dispatch-positional-test', 'myfile.ts'] }, 'cli')
142
-
143
- expect(received).toBeDefined()
144
- expect(received.file).toBe('myfile.ts')
145
- })
146
-
147
- it('collects remaining positionals into an array when schema expects one', async () => {
148
- let received: any = null
149
-
150
- const argsSchema = CommandOptionsSchema.extend({
151
- action: z.string(),
152
- files: z.array(z.string()),
153
- })
154
-
155
- const Grafted = graftModule(Command as any, {
156
- argsSchema,
157
- positionals: ['action', 'files'],
158
- run: async (args: any, ctx: any) => { received = args },
159
- }, 'dispatch-glob-test', 'commands')
160
-
161
- commands.register('dispatch-glob-test', Grafted as any)
162
- const container = new NodeContainer()
163
- const cmd = container.command('dispatch-glob-test' as any)
164
-
165
- // Simulate: luca dispatch-glob-test process foo.md bar.md baz.md
166
- // Shell expands *.md before luca sees it
167
- await cmd.dispatch({ _: ['dispatch-glob-test', 'process', 'foo.md', 'bar.md', 'baz.md'] }, 'cli')
168
-
169
- expect(received).toBeDefined()
170
- expect(received.action).toBe('process')
171
- expect(received.files).toEqual(['foo.md', 'bar.md', 'baz.md'])
172
- })
173
-
174
- it('passes named args through for headless dispatch', async () => {
175
- let received: any = null
176
-
177
- const argsSchema = CommandOptionsSchema.extend({
178
- file: z.string(),
179
- })
180
-
181
- const Grafted = graftModule(Command as any, {
182
- argsSchema,
183
- positionals: ['file'],
184
- run: async (args: any, ctx: any) => { received = args },
185
- }, 'dispatch-headless-test', 'commands')
186
-
187
- commands.register('dispatch-headless-test', Grafted as any)
188
- const container = new NodeContainer()
189
- const cmd = container.command('dispatch-headless-test' as any)
190
-
191
- // Headless: named args directly, no positional mapping
192
- await cmd.dispatch({ file: 'script.ts' }, 'headless')
193
-
194
- expect(received).toBeDefined()
195
- expect(received.file).toBe('script.ts')
196
- })
197
-
198
- it('captures stdout/stderr for headless dispatch', async () => {
199
- const argsSchema = CommandOptionsSchema.extend({})
200
-
201
- const Grafted = graftModule(Command as any, {
202
- argsSchema,
203
- run: async (args: any, ctx: any) => {
204
- console.log('hello from command')
205
- console.error('warning: something')
206
- },
207
- }, 'dispatch-capture-test', 'commands')
208
-
209
- commands.register('dispatch-capture-test', Grafted as any)
210
- const container = new NodeContainer()
211
- const cmd = container.command('dispatch-capture-test' as any)
212
-
213
- const result = await cmd.dispatch({}, 'headless')
214
-
215
- expect(result).toBeDefined()
216
- expect(result!.exitCode).toBe(0)
217
- expect(result!.stdout).toContain('hello from command')
218
- expect(result!.stderr).toContain('warning: something')
219
- })
220
-
221
- it('captures errors for headless dispatch', async () => {
222
- const argsSchema = CommandOptionsSchema.extend({})
223
-
224
- const Grafted = graftModule(Command as any, {
225
- argsSchema,
226
- run: async () => { throw new Error('boom') },
227
- }, 'dispatch-error-test', 'commands')
228
-
229
- commands.register('dispatch-error-test', Grafted as any)
230
- const container = new NodeContainer()
231
- const cmd = container.command('dispatch-error-test' as any)
232
-
233
- const result = await cmd.dispatch({}, 'headless')
234
-
235
- expect(result).toBeDefined()
236
- expect(result!.exitCode).toBe(1)
237
- expect(result!.stderr).toContain('boom')
238
- })
239
- })
240
-
241
- describe('Command registry', () => {
242
- it('has built-in commands registered', () => {
243
- const container = new NodeContainer()
244
- expect(container.commands.has('run')).toBe(true)
245
- expect(container.commands.has('help')).toBe(true)
246
- expect(container.commands.has('eval')).toBe(true)
247
- expect(container.commands.has('chat')).toBe(true)
248
- })
249
-
250
- it('built-in commands still work through registerHandler', () => {
251
- const container = new NodeContainer()
252
- const RunClass = container.commands.lookup('run')
253
- expect(typeof RunClass).toBe('function')
254
- expect(typeof RunClass.prototype.run).toBe('function')
255
- })
256
- })
257
-
258
- describe('SimpleCommand type', () => {
259
- it('grafted commands have positionals as a static property', () => {
260
- const Grafted = graftModule(Command as any, {
261
- positionals: ['env', 'region'],
262
- run: async () => {},
263
- }, 'simple-cmd-type-test', 'commands')
264
-
265
- expect((Grafted as any).positionals).toEqual(['env', 'region'])
266
- })
267
- })