luca 3.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 (372) 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 +220 -322
  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/try-all-challenges.ts +3 -3
  18. package/commands/try-challenge.ts +3 -3
  19. package/dist/agi/container.server.d.ts +2 -2
  20. package/dist/agi/features/assistant.d.ts +2 -2
  21. package/dist/agi/features/assistants-manager.d.ts +1 -1
  22. package/dist/agi/features/autonomous-assistant.d.ts +1 -1
  23. package/dist/agi/features/browser-use.d.ts +1 -1
  24. package/dist/agi/features/claude-code.d.ts +1 -1
  25. package/dist/agi/features/conversation-history.d.ts +2 -2
  26. package/dist/agi/features/conversation.d.ts +1 -1
  27. package/dist/agi/features/docs-reader.d.ts +1 -1
  28. package/dist/agi/features/file-tools.d.ts +1 -1
  29. package/dist/agi/features/luca-coder.d.ts +1 -1
  30. package/dist/agi/features/openai-codex.d.ts +1 -1
  31. package/dist/agi/features/skills-library.d.ts +1 -1
  32. package/dist/clients/civitai/index.d.ts +4 -4
  33. package/dist/clients/client-template.d.ts +4 -4
  34. package/dist/clients/comfyui/index.d.ts +2 -2
  35. package/dist/clients/elevenlabs/index.d.ts +2 -2
  36. package/dist/clients/openai/index.d.ts +2 -2
  37. package/dist/clients/supabase/index.d.ts +3 -3
  38. package/dist/command.d.ts +1 -1
  39. package/dist/node/container.d.ts +1 -1
  40. package/dist/node/features/helpers.d.ts +3 -3
  41. package/dist/node/features/semantic-search.d.ts +1 -1
  42. package/dist/node/features/vm.d.ts +3 -3
  43. package/dist/node.d.ts +1 -1
  44. package/dist/scaffolds/generated.d.ts +1 -1
  45. package/dist/selector.d.ts +1 -1
  46. package/index.html +217 -190
  47. package/luca.console.ts +1 -1
  48. package/package.json +2 -2
  49. package/public/index.html +217 -190
  50. package/public/slides-ai-native.html +1 -1
  51. package/public/slides-intro.html +2 -2
  52. package/scripts/examples/ask-luca-expert.ts +1 -1
  53. package/scripts/examples/assistant-questions.ts +1 -1
  54. package/scripts/examples/excalidraw-expert.ts +1 -1
  55. package/scripts/examples/file-manager.ts +1 -1
  56. package/scripts/examples/ideas.ts +1 -1
  57. package/scripts/examples/interactive-chat.ts +1 -1
  58. package/scripts/examples/opening-a-web-browser.ts +1 -1
  59. package/scripts/examples/telegram-bot.ts +1 -1
  60. package/scripts/examples/using-assistant-with-mcp.ts +1 -1
  61. package/scripts/examples/using-claude-code.ts +1 -1
  62. package/scripts/examples/using-contentdb.ts +2 -2
  63. package/scripts/examples/using-conversations.ts +1 -1
  64. package/scripts/examples/using-disk-cache.ts +1 -1
  65. package/scripts/examples/using-docker-shell.ts +1 -1
  66. package/scripts/examples/using-elevenlabs.ts +1 -1
  67. package/scripts/examples/using-google-calendar.ts +1 -1
  68. package/scripts/examples/using-google-docs.ts +1 -1
  69. package/scripts/examples/using-google-drive.ts +1 -1
  70. package/scripts/examples/using-google-sheets.ts +1 -1
  71. package/scripts/examples/using-nlp.ts +1 -1
  72. package/scripts/examples/using-ollama.ts +1 -1
  73. package/scripts/examples/using-postgres.ts +1 -1
  74. package/scripts/examples/using-runpod.ts +1 -1
  75. package/scripts/examples/using-tts.ts +1 -1
  76. package/scripts/scaffold.ts +5 -5
  77. package/scripts/scratch.ts +1 -1
  78. package/scripts/test-assistant-hooks.ts +1 -1
  79. package/scripts/test-docs-reader.ts +1 -1
  80. package/src/agi/container.server.ts +6 -2
  81. package/src/agi/features/agent-memory.ts +25 -25
  82. package/src/agi/features/assistant.ts +34 -5
  83. package/src/agi/features/assistants-manager.ts +122 -6
  84. package/src/agi/features/autonomous-assistant.ts +1 -1
  85. package/src/agi/features/browser-use.ts +20 -1
  86. package/src/agi/features/claude-code.ts +51 -5
  87. package/src/agi/features/coding-tools.ts +1 -1
  88. package/src/agi/features/conversation-history.ts +181 -4
  89. package/src/agi/features/conversation.ts +186 -15
  90. package/src/agi/features/docs-reader.ts +2 -2
  91. package/src/agi/features/file-tools.ts +49 -2
  92. package/src/agi/features/luca-coder.ts +7 -5
  93. package/src/agi/features/mcp-bridge.ts +532 -0
  94. package/src/agi/features/openai-codex.ts +2 -2
  95. package/src/agi/features/skills-library.ts +131 -52
  96. package/src/agi/lib/token-counter.ts +80 -0
  97. package/src/bootstrap/generated.ts +56 -57
  98. package/src/browser.ts +1 -1
  99. package/src/cli/build-info.ts +2 -2
  100. package/src/cli/cli.ts +2 -2
  101. package/src/clients/civitai/index.ts +5 -5
  102. package/src/clients/client-template.ts +4 -4
  103. package/src/clients/comfyui/index.ts +4 -4
  104. package/src/clients/elevenlabs/index.ts +4 -4
  105. package/src/clients/openai/index.ts +7 -7
  106. package/src/clients/supabase/index.ts +4 -4
  107. package/src/clients/voicebox/index.ts +4 -4
  108. package/src/command.ts +2 -1
  109. package/src/commands/chat.ts +1 -0
  110. package/src/commands/eval.ts +2 -56
  111. package/src/commands/introspect.ts +1 -1
  112. package/src/commands/prompt.ts +41 -9
  113. package/src/container-describer.ts +8 -1
  114. package/src/container.ts +13 -0
  115. package/src/entity.ts +2 -2
  116. package/src/helper.ts +1 -1
  117. package/src/introspection/generated.agi.ts +28563 -27571
  118. package/src/introspection/generated.node.ts +20281 -20194
  119. package/src/introspection/generated.web.ts +605 -584
  120. package/src/introspection/scan.ts +11 -6
  121. package/src/node/container.ts +1 -1
  122. package/src/node/features/content-db.ts +39 -2
  123. package/src/node/features/display-result.ts +57 -0
  124. package/src/node/features/helpers.ts +42 -15
  125. package/src/node/features/python.ts +25 -19
  126. package/src/node/features/repl.ts +1 -1
  127. package/src/node/features/secure-shell.ts +11 -17
  128. package/src/node/features/semantic-search.ts +2 -2
  129. package/src/node/features/transpiler.ts +2 -3
  130. package/src/node/features/ui.ts +5 -0
  131. package/src/node/features/vm.ts +3 -3
  132. package/src/node.ts +3 -3
  133. package/src/python/generated.ts +0 -1
  134. package/src/scaffolds/generated.ts +82 -83
  135. package/src/selector.ts +1 -1
  136. package/src/servers/express.ts +1 -1
  137. package/src/web/features/helpers.ts +22 -0
  138. package/tsconfig.json +12 -12
  139. package/docs/CLI.md +0 -335
  140. package/docs/CNAME +0 -1
  141. package/docs/README.md +0 -60
  142. package/docs/TABLE-OF-CONTENTS.md +0 -183
  143. package/docs/apis/clients/elevenlabs.md +0 -308
  144. package/docs/apis/clients/graph.md +0 -107
  145. package/docs/apis/clients/openai.md +0 -429
  146. package/docs/apis/clients/rest.md +0 -161
  147. package/docs/apis/clients/websocket.md +0 -174
  148. package/docs/apis/features/agi/assistant.md +0 -625
  149. package/docs/apis/features/agi/assistants-manager.md +0 -282
  150. package/docs/apis/features/agi/auto-assistant.md +0 -279
  151. package/docs/apis/features/agi/browser-use.md +0 -802
  152. package/docs/apis/features/agi/claude-code.md +0 -884
  153. package/docs/apis/features/agi/conversation-history.md +0 -364
  154. package/docs/apis/features/agi/conversation.md +0 -548
  155. package/docs/apis/features/agi/docs-reader.md +0 -99
  156. package/docs/apis/features/agi/file-tools.md +0 -163
  157. package/docs/apis/features/agi/luca-coder.md +0 -407
  158. package/docs/apis/features/agi/openai-codex.md +0 -396
  159. package/docs/apis/features/agi/openapi.md +0 -138
  160. package/docs/apis/features/agi/semantic-search.md +0 -387
  161. package/docs/apis/features/agi/skills-library.md +0 -239
  162. package/docs/apis/features/node/container-link.md +0 -192
  163. package/docs/apis/features/node/content-db.md +0 -450
  164. package/docs/apis/features/node/disk-cache.md +0 -379
  165. package/docs/apis/features/node/dns.md +0 -652
  166. package/docs/apis/features/node/docker.md +0 -706
  167. package/docs/apis/features/node/downloader.md +0 -81
  168. package/docs/apis/features/node/esbuild.md +0 -60
  169. package/docs/apis/features/node/file-manager.md +0 -191
  170. package/docs/apis/features/node/fs.md +0 -1217
  171. package/docs/apis/features/node/git.md +0 -371
  172. package/docs/apis/features/node/google-auth.md +0 -193
  173. package/docs/apis/features/node/google-calendar.md +0 -202
  174. package/docs/apis/features/node/google-docs.md +0 -173
  175. package/docs/apis/features/node/google-drive.md +0 -246
  176. package/docs/apis/features/node/google-mail.md +0 -214
  177. package/docs/apis/features/node/google-sheets.md +0 -194
  178. package/docs/apis/features/node/grep.md +0 -292
  179. package/docs/apis/features/node/helpers.md +0 -164
  180. package/docs/apis/features/node/ink.md +0 -334
  181. package/docs/apis/features/node/ipc-socket.md +0 -249
  182. package/docs/apis/features/node/json-tree.md +0 -86
  183. package/docs/apis/features/node/networking.md +0 -316
  184. package/docs/apis/features/node/nlp.md +0 -133
  185. package/docs/apis/features/node/opener.md +0 -97
  186. package/docs/apis/features/node/os.md +0 -146
  187. package/docs/apis/features/node/package-finder.md +0 -392
  188. package/docs/apis/features/node/postgres.md +0 -234
  189. package/docs/apis/features/node/proc.md +0 -399
  190. package/docs/apis/features/node/process-manager.md +0 -305
  191. package/docs/apis/features/node/python.md +0 -604
  192. package/docs/apis/features/node/redis.md +0 -380
  193. package/docs/apis/features/node/repl.md +0 -88
  194. package/docs/apis/features/node/runpod.md +0 -674
  195. package/docs/apis/features/node/secure-shell.md +0 -176
  196. package/docs/apis/features/node/semantic-search.md +0 -408
  197. package/docs/apis/features/node/sqlite.md +0 -233
  198. package/docs/apis/features/node/telegram.md +0 -279
  199. package/docs/apis/features/node/transpiler.md +0 -74
  200. package/docs/apis/features/node/tts.md +0 -133
  201. package/docs/apis/features/node/ui.md +0 -701
  202. package/docs/apis/features/node/vault.md +0 -59
  203. package/docs/apis/features/node/vm.md +0 -75
  204. package/docs/apis/features/node/yaml-tree.md +0 -85
  205. package/docs/apis/features/node/yaml.md +0 -176
  206. package/docs/apis/features/web/asset-loader.md +0 -59
  207. package/docs/apis/features/web/container-link.md +0 -192
  208. package/docs/apis/features/web/esbuild.md +0 -54
  209. package/docs/apis/features/web/helpers.md +0 -164
  210. package/docs/apis/features/web/network.md +0 -44
  211. package/docs/apis/features/web/speech.md +0 -69
  212. package/docs/apis/features/web/vault.md +0 -59
  213. package/docs/apis/features/web/vm.md +0 -75
  214. package/docs/apis/features/web/voice.md +0 -84
  215. package/docs/apis/servers/express.md +0 -171
  216. package/docs/apis/servers/mcp.md +0 -238
  217. package/docs/apis/servers/websocket.md +0 -170
  218. package/docs/bootstrap/CLAUDE.md +0 -101
  219. package/docs/bootstrap/SKILL.md +0 -341
  220. package/docs/bootstrap/templates/about-command.ts +0 -41
  221. package/docs/bootstrap/templates/docs-models.ts +0 -22
  222. package/docs/bootstrap/templates/docs-readme.md +0 -43
  223. package/docs/bootstrap/templates/example-feature.ts +0 -53
  224. package/docs/bootstrap/templates/health-endpoint.ts +0 -15
  225. package/docs/bootstrap/templates/luca-cli.ts +0 -30
  226. package/docs/bootstrap/templates/runme.md +0 -54
  227. package/docs/challenges/caching-proxy.md +0 -16
  228. package/docs/challenges/content-db-round-trip.md +0 -14
  229. package/docs/challenges/custom-command.md +0 -9
  230. package/docs/challenges/file-watcher-pipeline.md +0 -11
  231. package/docs/challenges/grep-audit-report.md +0 -15
  232. package/docs/challenges/multi-feature-dashboard.md +0 -14
  233. package/docs/challenges/process-orchestrator.md +0 -17
  234. package/docs/challenges/rest-api-server-with-client.md +0 -12
  235. package/docs/challenges/script-runner-with-vm.md +0 -11
  236. package/docs/challenges/simple-rest-api.md +0 -15
  237. package/docs/challenges/websocket-serve-and-client.md +0 -11
  238. package/docs/challenges/yaml-config-system.md +0 -14
  239. package/docs/command-system-overhaul.md +0 -94
  240. package/docs/documentation-audit.md +0 -134
  241. package/docs/examples/assistant/CORE.md +0 -18
  242. package/docs/examples/assistant/hooks.ts +0 -3
  243. package/docs/examples/assistant/tools.ts +0 -10
  244. package/docs/examples/assistant-hooks-reference.ts +0 -171
  245. package/docs/examples/assistant-with-process-manager.md +0 -84
  246. package/docs/examples/content-db.md +0 -77
  247. package/docs/examples/disk-cache.md +0 -83
  248. package/docs/examples/docker.md +0 -101
  249. package/docs/examples/downloader.md +0 -70
  250. package/docs/examples/entity.md +0 -124
  251. package/docs/examples/esbuild.md +0 -80
  252. package/docs/examples/feature-as-tool-provider.md +0 -143
  253. package/docs/examples/file-manager.md +0 -82
  254. package/docs/examples/fs.md +0 -83
  255. package/docs/examples/git.md +0 -85
  256. package/docs/examples/google-auth.md +0 -88
  257. package/docs/examples/google-calendar.md +0 -94
  258. package/docs/examples/google-docs.md +0 -82
  259. package/docs/examples/google-drive.md +0 -96
  260. package/docs/examples/google-sheets.md +0 -95
  261. package/docs/examples/grep.md +0 -85
  262. package/docs/examples/ink-blocks.md +0 -75
  263. package/docs/examples/ink-renderer.md +0 -41
  264. package/docs/examples/ink.md +0 -103
  265. package/docs/examples/ipc-socket.md +0 -103
  266. package/docs/examples/json-tree.md +0 -91
  267. package/docs/examples/networking.md +0 -58
  268. package/docs/examples/nlp.md +0 -91
  269. package/docs/examples/opener.md +0 -78
  270. package/docs/examples/os.md +0 -72
  271. package/docs/examples/package-finder.md +0 -89
  272. package/docs/examples/postgres.md +0 -91
  273. package/docs/examples/proc.md +0 -81
  274. package/docs/examples/process-manager.md +0 -79
  275. package/docs/examples/python.md +0 -132
  276. package/docs/examples/repl.md +0 -93
  277. package/docs/examples/runpod.md +0 -119
  278. package/docs/examples/secure-shell.md +0 -92
  279. package/docs/examples/sqlite.md +0 -86
  280. package/docs/examples/structured-output-with-assistants.md +0 -144
  281. package/docs/examples/telegram.md +0 -77
  282. package/docs/examples/tts.md +0 -86
  283. package/docs/examples/ui.md +0 -80
  284. package/docs/examples/vault.md +0 -70
  285. package/docs/examples/vm.md +0 -86
  286. package/docs/examples/websocket-ask-and-reply-example.md +0 -128
  287. package/docs/examples/yaml-tree.md +0 -93
  288. package/docs/examples/yaml.md +0 -104
  289. package/docs/ideas/assistant-factory-pattern.md +0 -142
  290. package/docs/in-memory-fs.md +0 -4
  291. package/docs/introspection-audit.md +0 -49
  292. package/docs/introspection.md +0 -164
  293. package/docs/mcp/readme.md +0 -162
  294. package/docs/models.ts +0 -41
  295. package/docs/philosophy.md +0 -86
  296. package/docs/principles.md +0 -7
  297. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +0 -34
  298. package/docs/prompts/check-for-undocumented-features.md +0 -27
  299. package/docs/prompts/mcp-test-easy-command.md +0 -27
  300. package/docs/scaffolds/client.md +0 -149
  301. package/docs/scaffolds/command.md +0 -120
  302. package/docs/scaffolds/endpoint.md +0 -171
  303. package/docs/scaffolds/feature.md +0 -158
  304. package/docs/scaffolds/selector.md +0 -91
  305. package/docs/scaffolds/server.md +0 -196
  306. package/docs/selectors.md +0 -115
  307. package/docs/sessions/custom-command/attempt-log-2.md +0 -195
  308. package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +0 -728
  309. package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +0 -555
  310. package/docs/sessions/grep-audit-report/attempt-log-1.md +0 -289
  311. package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +0 -679
  312. package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +0 -1
  313. package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +0 -920
  314. package/docs/sessions/simple-rest-api/attempt-log-1.md +0 -593
  315. package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +0 -995
  316. package/docs/tutorials/00-bootstrap.md +0 -166
  317. package/docs/tutorials/01-getting-started.md +0 -106
  318. package/docs/tutorials/02-container.md +0 -210
  319. package/docs/tutorials/03-scripts.md +0 -194
  320. package/docs/tutorials/04-features-overview.md +0 -196
  321. package/docs/tutorials/05-state-and-events.md +0 -171
  322. package/docs/tutorials/06-servers.md +0 -157
  323. package/docs/tutorials/07-endpoints.md +0 -198
  324. package/docs/tutorials/08-commands.md +0 -252
  325. package/docs/tutorials/09-clients.md +0 -162
  326. package/docs/tutorials/10-creating-features.md +0 -203
  327. package/docs/tutorials/11-contentbase.md +0 -191
  328. package/docs/tutorials/12-assistants.md +0 -215
  329. package/docs/tutorials/13-introspection.md +0 -157
  330. package/docs/tutorials/14-type-system.md +0 -174
  331. package/docs/tutorials/15-project-patterns.md +0 -222
  332. package/docs/tutorials/16-google-features.md +0 -534
  333. package/docs/tutorials/17-tui-blocks.md +0 -530
  334. package/docs/tutorials/18-semantic-search.md +0 -334
  335. package/docs/tutorials/19-python-sessions.md +0 -401
  336. package/docs/tutorials/20-browser-esm.md +0 -234
  337. package/src/agi/endpoints/ask.ts +0 -60
  338. package/src/agi/endpoints/conversations/[id].ts +0 -45
  339. package/src/agi/endpoints/conversations.ts +0 -31
  340. package/src/agi/endpoints/experts.ts +0 -37
  341. package/test/assistant-hooks.test.ts +0 -306
  342. package/test/assistant.test.ts +0 -81
  343. package/test/bus.test.ts +0 -134
  344. package/test/clients-servers.test.ts +0 -217
  345. package/test/command.test.ts +0 -267
  346. package/test/container-link.test.ts +0 -274
  347. package/test/conversation.test.ts +0 -220
  348. package/test/features.test.ts +0 -160
  349. package/test/fork-and-research.test.ts +0 -450
  350. package/test/integration.test.ts +0 -787
  351. package/test/interceptor-chain.test.ts +0 -61
  352. package/test/node-container.test.ts +0 -121
  353. package/test/python-session.test.ts +0 -105
  354. package/test/rate-limit.test.ts +0 -272
  355. package/test/semantic-search.test.ts +0 -550
  356. package/test/state.test.ts +0 -121
  357. package/test/vm-context.test.ts +0 -146
  358. package/test/vm-loadmodule.test.ts +0 -213
  359. package/test/websocket-ask.test.ts +0 -101
  360. package/test-integration/assistant.test.ts +0 -138
  361. package/test-integration/assistants-manager.test.ts +0 -113
  362. package/test-integration/claude-code.test.ts +0 -98
  363. package/test-integration/conversation-history.test.ts +0 -205
  364. package/test-integration/conversation.test.ts +0 -137
  365. package/test-integration/elevenlabs.test.ts +0 -55
  366. package/test-integration/google-services.test.ts +0 -80
  367. package/test-integration/helpers.ts +0 -89
  368. package/test-integration/memory.test.ts +0 -204
  369. package/test-integration/openai-codex.test.ts +0 -93
  370. package/test-integration/runpod.test.ts +0 -58
  371. package/test-integration/server-endpoints.test.ts +0 -97
  372. 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
- })