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.
- package/.github/workflows/release.yaml +1 -0
- package/CLAUDE.md +10 -2
- package/README.md +130 -112
- package/assistants/codingAssistant/CORE.md +6 -1
- package/assistants/codingAssistant/hooks.ts +1 -1
- package/assistants/inkbot/hooks.ts +1 -1
- package/assistants/inkbot/tools.ts +1 -1
- package/bun.lock +220 -322
- package/commands/audit-docs.ts +2 -2
- package/commands/build-bootstrap.ts +2 -3
- package/commands/build-python-bridge.ts +2 -3
- package/commands/build-scaffolds.ts +2 -3
- package/commands/bundle-consumer-project.ts +521 -0
- package/commands/generate-api-docs.ts +2 -2
- package/commands/inkbot.ts +2 -2
- package/commands/release.ts +2 -2
- package/commands/try-all-challenges.ts +3 -3
- package/commands/try-challenge.ts +3 -3
- package/dist/agi/container.server.d.ts +2 -2
- package/dist/agi/features/assistant.d.ts +2 -2
- package/dist/agi/features/assistants-manager.d.ts +1 -1
- package/dist/agi/features/autonomous-assistant.d.ts +1 -1
- package/dist/agi/features/browser-use.d.ts +1 -1
- package/dist/agi/features/claude-code.d.ts +1 -1
- package/dist/agi/features/conversation-history.d.ts +2 -2
- package/dist/agi/features/conversation.d.ts +1 -1
- package/dist/agi/features/docs-reader.d.ts +1 -1
- package/dist/agi/features/file-tools.d.ts +1 -1
- package/dist/agi/features/luca-coder.d.ts +1 -1
- package/dist/agi/features/openai-codex.d.ts +1 -1
- package/dist/agi/features/skills-library.d.ts +1 -1
- package/dist/clients/civitai/index.d.ts +4 -4
- package/dist/clients/client-template.d.ts +4 -4
- package/dist/clients/comfyui/index.d.ts +2 -2
- package/dist/clients/elevenlabs/index.d.ts +2 -2
- package/dist/clients/openai/index.d.ts +2 -2
- package/dist/clients/supabase/index.d.ts +3 -3
- package/dist/command.d.ts +1 -1
- package/dist/node/container.d.ts +1 -1
- package/dist/node/features/helpers.d.ts +3 -3
- package/dist/node/features/semantic-search.d.ts +1 -1
- package/dist/node/features/vm.d.ts +3 -3
- package/dist/node.d.ts +1 -1
- package/dist/scaffolds/generated.d.ts +1 -1
- package/dist/selector.d.ts +1 -1
- package/index.html +217 -190
- package/luca.console.ts +1 -1
- package/package.json +2 -2
- package/public/index.html +217 -190
- package/public/slides-ai-native.html +1 -1
- package/public/slides-intro.html +2 -2
- package/scripts/examples/ask-luca-expert.ts +1 -1
- package/scripts/examples/assistant-questions.ts +1 -1
- package/scripts/examples/excalidraw-expert.ts +1 -1
- package/scripts/examples/file-manager.ts +1 -1
- package/scripts/examples/ideas.ts +1 -1
- package/scripts/examples/interactive-chat.ts +1 -1
- package/scripts/examples/opening-a-web-browser.ts +1 -1
- package/scripts/examples/telegram-bot.ts +1 -1
- package/scripts/examples/using-assistant-with-mcp.ts +1 -1
- package/scripts/examples/using-claude-code.ts +1 -1
- package/scripts/examples/using-contentdb.ts +2 -2
- package/scripts/examples/using-conversations.ts +1 -1
- package/scripts/examples/using-disk-cache.ts +1 -1
- package/scripts/examples/using-docker-shell.ts +1 -1
- package/scripts/examples/using-elevenlabs.ts +1 -1
- package/scripts/examples/using-google-calendar.ts +1 -1
- package/scripts/examples/using-google-docs.ts +1 -1
- package/scripts/examples/using-google-drive.ts +1 -1
- package/scripts/examples/using-google-sheets.ts +1 -1
- package/scripts/examples/using-nlp.ts +1 -1
- package/scripts/examples/using-ollama.ts +1 -1
- package/scripts/examples/using-postgres.ts +1 -1
- package/scripts/examples/using-runpod.ts +1 -1
- package/scripts/examples/using-tts.ts +1 -1
- package/scripts/scaffold.ts +5 -5
- package/scripts/scratch.ts +1 -1
- package/scripts/test-assistant-hooks.ts +1 -1
- package/scripts/test-docs-reader.ts +1 -1
- package/src/agi/container.server.ts +6 -2
- package/src/agi/features/agent-memory.ts +25 -25
- package/src/agi/features/assistant.ts +34 -5
- package/src/agi/features/assistants-manager.ts +122 -6
- package/src/agi/features/autonomous-assistant.ts +1 -1
- package/src/agi/features/browser-use.ts +20 -1
- package/src/agi/features/claude-code.ts +51 -5
- package/src/agi/features/coding-tools.ts +1 -1
- package/src/agi/features/conversation-history.ts +181 -4
- package/src/agi/features/conversation.ts +186 -15
- package/src/agi/features/docs-reader.ts +2 -2
- package/src/agi/features/file-tools.ts +49 -2
- package/src/agi/features/luca-coder.ts +7 -5
- package/src/agi/features/mcp-bridge.ts +532 -0
- package/src/agi/features/openai-codex.ts +2 -2
- package/src/agi/features/skills-library.ts +131 -52
- package/src/agi/lib/token-counter.ts +80 -0
- package/src/bootstrap/generated.ts +56 -57
- package/src/browser.ts +1 -1
- package/src/cli/build-info.ts +2 -2
- package/src/cli/cli.ts +2 -2
- package/src/clients/civitai/index.ts +5 -5
- package/src/clients/client-template.ts +4 -4
- package/src/clients/comfyui/index.ts +4 -4
- package/src/clients/elevenlabs/index.ts +4 -4
- package/src/clients/openai/index.ts +7 -7
- package/src/clients/supabase/index.ts +4 -4
- package/src/clients/voicebox/index.ts +4 -4
- package/src/command.ts +2 -1
- package/src/commands/chat.ts +1 -0
- package/src/commands/eval.ts +2 -56
- package/src/commands/introspect.ts +1 -1
- package/src/commands/prompt.ts +41 -9
- package/src/container-describer.ts +8 -1
- package/src/container.ts +13 -0
- package/src/entity.ts +2 -2
- package/src/helper.ts +1 -1
- package/src/introspection/generated.agi.ts +28563 -27571
- package/src/introspection/generated.node.ts +20281 -20194
- package/src/introspection/generated.web.ts +605 -584
- package/src/introspection/scan.ts +11 -6
- package/src/node/container.ts +1 -1
- package/src/node/features/content-db.ts +39 -2
- package/src/node/features/display-result.ts +57 -0
- package/src/node/features/helpers.ts +42 -15
- package/src/node/features/python.ts +25 -19
- package/src/node/features/repl.ts +1 -1
- package/src/node/features/secure-shell.ts +11 -17
- package/src/node/features/semantic-search.ts +2 -2
- package/src/node/features/transpiler.ts +2 -3
- package/src/node/features/ui.ts +5 -0
- package/src/node/features/vm.ts +3 -3
- package/src/node.ts +3 -3
- package/src/python/generated.ts +0 -1
- package/src/scaffolds/generated.ts +82 -83
- package/src/selector.ts +1 -1
- package/src/servers/express.ts +1 -1
- package/src/web/features/helpers.ts +22 -0
- package/tsconfig.json +12 -12
- package/docs/CLI.md +0 -335
- package/docs/CNAME +0 -1
- package/docs/README.md +0 -60
- package/docs/TABLE-OF-CONTENTS.md +0 -183
- package/docs/apis/clients/elevenlabs.md +0 -308
- package/docs/apis/clients/graph.md +0 -107
- package/docs/apis/clients/openai.md +0 -429
- package/docs/apis/clients/rest.md +0 -161
- package/docs/apis/clients/websocket.md +0 -174
- package/docs/apis/features/agi/assistant.md +0 -625
- package/docs/apis/features/agi/assistants-manager.md +0 -282
- package/docs/apis/features/agi/auto-assistant.md +0 -279
- package/docs/apis/features/agi/browser-use.md +0 -802
- package/docs/apis/features/agi/claude-code.md +0 -884
- package/docs/apis/features/agi/conversation-history.md +0 -364
- package/docs/apis/features/agi/conversation.md +0 -548
- package/docs/apis/features/agi/docs-reader.md +0 -99
- package/docs/apis/features/agi/file-tools.md +0 -163
- package/docs/apis/features/agi/luca-coder.md +0 -407
- package/docs/apis/features/agi/openai-codex.md +0 -396
- package/docs/apis/features/agi/openapi.md +0 -138
- package/docs/apis/features/agi/semantic-search.md +0 -387
- package/docs/apis/features/agi/skills-library.md +0 -239
- package/docs/apis/features/node/container-link.md +0 -192
- package/docs/apis/features/node/content-db.md +0 -450
- package/docs/apis/features/node/disk-cache.md +0 -379
- package/docs/apis/features/node/dns.md +0 -652
- package/docs/apis/features/node/docker.md +0 -706
- package/docs/apis/features/node/downloader.md +0 -81
- package/docs/apis/features/node/esbuild.md +0 -60
- package/docs/apis/features/node/file-manager.md +0 -191
- package/docs/apis/features/node/fs.md +0 -1217
- package/docs/apis/features/node/git.md +0 -371
- package/docs/apis/features/node/google-auth.md +0 -193
- package/docs/apis/features/node/google-calendar.md +0 -202
- package/docs/apis/features/node/google-docs.md +0 -173
- package/docs/apis/features/node/google-drive.md +0 -246
- package/docs/apis/features/node/google-mail.md +0 -214
- package/docs/apis/features/node/google-sheets.md +0 -194
- package/docs/apis/features/node/grep.md +0 -292
- package/docs/apis/features/node/helpers.md +0 -164
- package/docs/apis/features/node/ink.md +0 -334
- package/docs/apis/features/node/ipc-socket.md +0 -249
- package/docs/apis/features/node/json-tree.md +0 -86
- package/docs/apis/features/node/networking.md +0 -316
- package/docs/apis/features/node/nlp.md +0 -133
- package/docs/apis/features/node/opener.md +0 -97
- package/docs/apis/features/node/os.md +0 -146
- package/docs/apis/features/node/package-finder.md +0 -392
- package/docs/apis/features/node/postgres.md +0 -234
- package/docs/apis/features/node/proc.md +0 -399
- package/docs/apis/features/node/process-manager.md +0 -305
- package/docs/apis/features/node/python.md +0 -604
- package/docs/apis/features/node/redis.md +0 -380
- package/docs/apis/features/node/repl.md +0 -88
- package/docs/apis/features/node/runpod.md +0 -674
- package/docs/apis/features/node/secure-shell.md +0 -176
- package/docs/apis/features/node/semantic-search.md +0 -408
- package/docs/apis/features/node/sqlite.md +0 -233
- package/docs/apis/features/node/telegram.md +0 -279
- package/docs/apis/features/node/transpiler.md +0 -74
- package/docs/apis/features/node/tts.md +0 -133
- package/docs/apis/features/node/ui.md +0 -701
- package/docs/apis/features/node/vault.md +0 -59
- package/docs/apis/features/node/vm.md +0 -75
- package/docs/apis/features/node/yaml-tree.md +0 -85
- package/docs/apis/features/node/yaml.md +0 -176
- package/docs/apis/features/web/asset-loader.md +0 -59
- package/docs/apis/features/web/container-link.md +0 -192
- package/docs/apis/features/web/esbuild.md +0 -54
- package/docs/apis/features/web/helpers.md +0 -164
- package/docs/apis/features/web/network.md +0 -44
- package/docs/apis/features/web/speech.md +0 -69
- package/docs/apis/features/web/vault.md +0 -59
- package/docs/apis/features/web/vm.md +0 -75
- package/docs/apis/features/web/voice.md +0 -84
- package/docs/apis/servers/express.md +0 -171
- package/docs/apis/servers/mcp.md +0 -238
- package/docs/apis/servers/websocket.md +0 -170
- package/docs/bootstrap/CLAUDE.md +0 -101
- package/docs/bootstrap/SKILL.md +0 -341
- package/docs/bootstrap/templates/about-command.ts +0 -41
- package/docs/bootstrap/templates/docs-models.ts +0 -22
- package/docs/bootstrap/templates/docs-readme.md +0 -43
- package/docs/bootstrap/templates/example-feature.ts +0 -53
- package/docs/bootstrap/templates/health-endpoint.ts +0 -15
- package/docs/bootstrap/templates/luca-cli.ts +0 -30
- package/docs/bootstrap/templates/runme.md +0 -54
- package/docs/challenges/caching-proxy.md +0 -16
- package/docs/challenges/content-db-round-trip.md +0 -14
- package/docs/challenges/custom-command.md +0 -9
- package/docs/challenges/file-watcher-pipeline.md +0 -11
- package/docs/challenges/grep-audit-report.md +0 -15
- package/docs/challenges/multi-feature-dashboard.md +0 -14
- package/docs/challenges/process-orchestrator.md +0 -17
- package/docs/challenges/rest-api-server-with-client.md +0 -12
- package/docs/challenges/script-runner-with-vm.md +0 -11
- package/docs/challenges/simple-rest-api.md +0 -15
- package/docs/challenges/websocket-serve-and-client.md +0 -11
- package/docs/challenges/yaml-config-system.md +0 -14
- package/docs/command-system-overhaul.md +0 -94
- package/docs/documentation-audit.md +0 -134
- package/docs/examples/assistant/CORE.md +0 -18
- package/docs/examples/assistant/hooks.ts +0 -3
- package/docs/examples/assistant/tools.ts +0 -10
- package/docs/examples/assistant-hooks-reference.ts +0 -171
- package/docs/examples/assistant-with-process-manager.md +0 -84
- package/docs/examples/content-db.md +0 -77
- package/docs/examples/disk-cache.md +0 -83
- package/docs/examples/docker.md +0 -101
- package/docs/examples/downloader.md +0 -70
- package/docs/examples/entity.md +0 -124
- package/docs/examples/esbuild.md +0 -80
- package/docs/examples/feature-as-tool-provider.md +0 -143
- package/docs/examples/file-manager.md +0 -82
- package/docs/examples/fs.md +0 -83
- package/docs/examples/git.md +0 -85
- package/docs/examples/google-auth.md +0 -88
- package/docs/examples/google-calendar.md +0 -94
- package/docs/examples/google-docs.md +0 -82
- package/docs/examples/google-drive.md +0 -96
- package/docs/examples/google-sheets.md +0 -95
- package/docs/examples/grep.md +0 -85
- package/docs/examples/ink-blocks.md +0 -75
- package/docs/examples/ink-renderer.md +0 -41
- package/docs/examples/ink.md +0 -103
- package/docs/examples/ipc-socket.md +0 -103
- package/docs/examples/json-tree.md +0 -91
- package/docs/examples/networking.md +0 -58
- package/docs/examples/nlp.md +0 -91
- package/docs/examples/opener.md +0 -78
- package/docs/examples/os.md +0 -72
- package/docs/examples/package-finder.md +0 -89
- package/docs/examples/postgres.md +0 -91
- package/docs/examples/proc.md +0 -81
- package/docs/examples/process-manager.md +0 -79
- package/docs/examples/python.md +0 -132
- package/docs/examples/repl.md +0 -93
- package/docs/examples/runpod.md +0 -119
- package/docs/examples/secure-shell.md +0 -92
- package/docs/examples/sqlite.md +0 -86
- package/docs/examples/structured-output-with-assistants.md +0 -144
- package/docs/examples/telegram.md +0 -77
- package/docs/examples/tts.md +0 -86
- package/docs/examples/ui.md +0 -80
- package/docs/examples/vault.md +0 -70
- package/docs/examples/vm.md +0 -86
- package/docs/examples/websocket-ask-and-reply-example.md +0 -128
- package/docs/examples/yaml-tree.md +0 -93
- package/docs/examples/yaml.md +0 -104
- package/docs/ideas/assistant-factory-pattern.md +0 -142
- package/docs/in-memory-fs.md +0 -4
- package/docs/introspection-audit.md +0 -49
- package/docs/introspection.md +0 -164
- package/docs/mcp/readme.md +0 -162
- package/docs/models.ts +0 -41
- package/docs/philosophy.md +0 -86
- package/docs/principles.md +0 -7
- package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +0 -34
- package/docs/prompts/check-for-undocumented-features.md +0 -27
- package/docs/prompts/mcp-test-easy-command.md +0 -27
- package/docs/scaffolds/client.md +0 -149
- package/docs/scaffolds/command.md +0 -120
- package/docs/scaffolds/endpoint.md +0 -171
- package/docs/scaffolds/feature.md +0 -158
- package/docs/scaffolds/selector.md +0 -91
- package/docs/scaffolds/server.md +0 -196
- package/docs/selectors.md +0 -115
- package/docs/sessions/custom-command/attempt-log-2.md +0 -195
- package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +0 -728
- package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +0 -555
- package/docs/sessions/grep-audit-report/attempt-log-1.md +0 -289
- package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +0 -679
- package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +0 -1
- package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +0 -920
- package/docs/sessions/simple-rest-api/attempt-log-1.md +0 -593
- package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +0 -995
- package/docs/tutorials/00-bootstrap.md +0 -166
- package/docs/tutorials/01-getting-started.md +0 -106
- package/docs/tutorials/02-container.md +0 -210
- package/docs/tutorials/03-scripts.md +0 -194
- package/docs/tutorials/04-features-overview.md +0 -196
- package/docs/tutorials/05-state-and-events.md +0 -171
- package/docs/tutorials/06-servers.md +0 -157
- package/docs/tutorials/07-endpoints.md +0 -198
- package/docs/tutorials/08-commands.md +0 -252
- package/docs/tutorials/09-clients.md +0 -162
- package/docs/tutorials/10-creating-features.md +0 -203
- package/docs/tutorials/11-contentbase.md +0 -191
- package/docs/tutorials/12-assistants.md +0 -215
- package/docs/tutorials/13-introspection.md +0 -157
- package/docs/tutorials/14-type-system.md +0 -174
- package/docs/tutorials/15-project-patterns.md +0 -222
- package/docs/tutorials/16-google-features.md +0 -534
- package/docs/tutorials/17-tui-blocks.md +0 -530
- package/docs/tutorials/18-semantic-search.md +0 -334
- package/docs/tutorials/19-python-sessions.md +0 -401
- package/docs/tutorials/20-browser-esm.md +0 -234
- package/src/agi/endpoints/ask.ts +0 -60
- package/src/agi/endpoints/conversations/[id].ts +0 -45
- package/src/agi/endpoints/conversations.ts +0 -31
- package/src/agi/endpoints/experts.ts +0 -37
- package/test/assistant-hooks.test.ts +0 -306
- package/test/assistant.test.ts +0 -81
- package/test/bus.test.ts +0 -134
- package/test/clients-servers.test.ts +0 -217
- package/test/command.test.ts +0 -267
- package/test/container-link.test.ts +0 -274
- package/test/conversation.test.ts +0 -220
- package/test/features.test.ts +0 -160
- package/test/fork-and-research.test.ts +0 -450
- package/test/integration.test.ts +0 -787
- package/test/interceptor-chain.test.ts +0 -61
- package/test/node-container.test.ts +0 -121
- package/test/python-session.test.ts +0 -105
- package/test/rate-limit.test.ts +0 -272
- package/test/semantic-search.test.ts +0 -550
- package/test/state.test.ts +0 -121
- package/test/vm-context.test.ts +0 -146
- package/test/vm-loadmodule.test.ts +0 -213
- package/test/websocket-ask.test.ts +0 -101
- package/test-integration/assistant.test.ts +0 -138
- package/test-integration/assistants-manager.test.ts +0 -113
- package/test-integration/claude-code.test.ts +0 -98
- package/test-integration/conversation-history.test.ts +0 -205
- package/test-integration/conversation.test.ts +0 -137
- package/test-integration/elevenlabs.test.ts +0 -55
- package/test-integration/google-services.test.ts +0 -80
- package/test-integration/helpers.ts +0 -89
- package/test-integration/memory.test.ts +0 -204
- package/test-integration/openai-codex.test.ts +0 -93
- package/test-integration/runpod.test.ts +0 -58
- package/test-integration/server-endpoints.test.ts +0 -97
- 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
|
-
})
|
package/test/command.test.ts
DELETED
|
@@ -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
|
-
})
|