@soederpop/luca 0.0.5 → 0.0.7
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/CLAUDE.md +10 -1
- package/bun.lock +1 -1
- package/commands/build-bootstrap.ts +78 -0
- package/commands/build-scaffolds.ts +24 -2
- package/commands/try-all-challenges.ts +543 -0
- package/commands/try-challenge.ts +100 -0
- package/docs/README.md +52 -80
- package/docs/TABLE-OF-CONTENTS.md +82 -51
- package/docs/apis/clients/elevenlabs.md +232 -8
- package/docs/apis/clients/graph.md +59 -8
- package/docs/apis/clients/openai.md +362 -2
- package/docs/apis/clients/rest.md +122 -2
- package/docs/apis/clients/websocket.md +71 -17
- package/docs/apis/features/agi/assistant.md +9 -3
- package/docs/apis/features/agi/assistants-manager.md +2 -2
- package/docs/apis/features/agi/claude-code.md +153 -14
- package/docs/apis/features/agi/conversation-history.md +15 -3
- package/docs/apis/features/agi/conversation.md +133 -20
- package/docs/apis/features/agi/openai-codex.md +90 -12
- package/docs/apis/features/agi/skills-library.md +23 -5
- package/docs/apis/features/node/container-link.md +59 -0
- package/docs/apis/features/node/content-db.md +1 -1
- package/docs/apis/features/node/disk-cache.md +1 -1
- package/docs/apis/features/node/dns.md +1 -0
- package/docs/apis/features/node/docker.md +2 -1
- package/docs/apis/features/node/esbuild.md +4 -3
- package/docs/apis/features/node/file-manager.md +13 -4
- package/docs/apis/features/node/fs.md +726 -171
- package/docs/apis/features/node/git.md +1 -0
- package/docs/apis/features/node/google-auth.md +23 -4
- package/docs/apis/features/node/google-calendar.md +14 -2
- package/docs/apis/features/node/google-docs.md +15 -2
- package/docs/apis/features/node/google-drive.md +21 -3
- package/docs/apis/features/node/google-sheets.md +14 -2
- package/docs/apis/features/node/grep.md +2 -0
- package/docs/apis/features/node/helpers.md +29 -0
- package/docs/apis/features/node/ink.md +2 -2
- package/docs/apis/features/node/networking.md +39 -4
- package/docs/apis/features/node/os.md +28 -0
- package/docs/apis/features/node/postgres.md +26 -4
- package/docs/apis/features/node/proc.md +37 -28
- package/docs/apis/features/node/process-manager.md +33 -5
- package/docs/apis/features/node/repl.md +1 -1
- package/docs/apis/features/node/runpod.md +1 -0
- package/docs/apis/features/node/secure-shell.md +7 -0
- package/docs/apis/features/node/semantic-search.md +12 -5
- package/docs/apis/features/node/sqlite.md +26 -4
- package/docs/apis/features/node/telegram.md +30 -5
- package/docs/apis/features/node/tts.md +17 -2
- package/docs/apis/features/node/ui.md +1 -1
- package/docs/apis/features/node/vault.md +4 -9
- package/docs/apis/features/node/vm.md +3 -12
- package/docs/apis/features/node/window-manager.md +128 -20
- package/docs/apis/features/web/asset-loader.md +13 -1
- package/docs/apis/features/web/container-link.md +59 -0
- package/docs/apis/features/web/esbuild.md +4 -3
- package/docs/apis/features/web/helpers.md +29 -0
- package/docs/apis/features/web/network.md +16 -2
- package/docs/apis/features/web/speech.md +16 -2
- package/docs/apis/features/web/vault.md +4 -9
- package/docs/apis/features/web/vm.md +3 -12
- package/docs/apis/features/web/voice.md +18 -1
- package/docs/apis/servers/express.md +18 -2
- package/docs/apis/servers/mcp.md +29 -4
- package/docs/apis/servers/websocket.md +34 -6
- package/docs/bootstrap/CLAUDE.md +100 -0
- package/docs/bootstrap/SKILL.md +222 -0
- package/docs/bootstrap/templates/about-command.ts +41 -0
- package/docs/bootstrap/templates/docs-models.ts +22 -0
- package/docs/bootstrap/templates/docs-readme.md +43 -0
- package/docs/bootstrap/templates/example-feature.ts +53 -0
- package/docs/bootstrap/templates/health-endpoint.ts +15 -0
- package/docs/bootstrap/templates/luca-cli.ts +25 -0
- package/docs/challenges/caching-proxy.md +16 -0
- package/docs/challenges/content-db-round-trip.md +14 -0
- package/docs/challenges/custom-command.md +9 -0
- package/docs/challenges/file-watcher-pipeline.md +11 -0
- package/docs/challenges/grep-audit-report.md +15 -0
- package/docs/challenges/multi-feature-dashboard.md +14 -0
- package/docs/challenges/process-orchestrator.md +17 -0
- package/docs/challenges/rest-api-server-with-client.md +12 -0
- package/docs/challenges/script-runner-with-vm.md +11 -0
- package/docs/challenges/simple-rest-api.md +15 -0
- package/docs/challenges/websocket-serve-and-client.md +11 -0
- package/docs/challenges/yaml-config-system.md +14 -0
- package/docs/command-system-overhaul.md +94 -0
- package/docs/examples/assistant/CORE.md +18 -0
- package/docs/examples/assistant/hooks.ts +3 -0
- package/docs/examples/assistant/tools.ts +10 -0
- package/docs/examples/window-manager-layouts.md +180 -0
- package/docs/in-memory-fs.md +4 -0
- package/docs/models.ts +13 -10
- package/docs/philosophy.md +4 -3
- package/docs/reports/console-hmr-design.md +170 -0
- package/docs/reports/helper-semantic-search.md +72 -0
- package/docs/scaffolds/client.md +29 -20
- package/docs/scaffolds/command.md +64 -50
- package/docs/scaffolds/endpoint.md +31 -36
- package/docs/scaffolds/feature.md +28 -18
- package/docs/scaffolds/selector.md +91 -0
- package/docs/scaffolds/server.md +18 -9
- package/docs/selectors.md +115 -0
- package/docs/sessions/custom-command/attempt-log-2.md +195 -0
- package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +728 -0
- package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +555 -0
- package/docs/sessions/grep-audit-report/attempt-log-1.md +289 -0
- package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +679 -0
- package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +1 -0
- package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +920 -0
- package/docs/sessions/simple-rest-api/attempt-log-1.md +593 -0
- package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +995 -0
- package/docs/tutorials/00-bootstrap.md +148 -0
- package/docs/tutorials/07-endpoints.md +7 -7
- package/docs/tutorials/08-commands.md +153 -72
- package/luca.cli.ts +3 -0
- package/package.json +6 -5
- package/public/index.html +1430 -0
- package/scripts/examples/using-ollama.ts +2 -1
- package/scripts/update-introspection-data.ts +2 -2
- package/src/agi/endpoints/experts.ts +1 -1
- package/src/agi/features/assistant.ts +7 -0
- package/src/agi/features/assistants-manager.ts +5 -5
- package/src/agi/features/claude-code.ts +263 -3
- package/src/agi/features/conversation-history.ts +7 -1
- package/src/agi/features/conversation.ts +26 -3
- package/src/agi/features/openai-codex.ts +26 -2
- package/src/agi/features/openapi.ts +6 -1
- package/src/agi/features/skills-library.ts +9 -1
- package/src/bootstrap/generated.ts +540 -0
- package/src/cli/cli.ts +64 -21
- package/src/client.ts +23 -357
- package/src/clients/civitai/index.ts +1 -1
- package/src/clients/client-template.ts +1 -1
- package/src/clients/comfyui/index.ts +13 -2
- package/src/clients/elevenlabs/index.ts +2 -1
- package/src/clients/graph.ts +87 -0
- package/src/clients/openai/index.ts +10 -1
- package/src/clients/rest.ts +207 -0
- package/src/clients/websocket.ts +176 -0
- package/src/command.ts +281 -34
- package/src/commands/bootstrap.ts +181 -0
- package/src/commands/chat.ts +5 -4
- package/src/commands/describe.ts +225 -2
- package/src/commands/help.ts +35 -9
- package/src/commands/index.ts +3 -0
- package/src/commands/introspect.ts +92 -2
- package/src/commands/prompt.ts +5 -6
- package/src/commands/run.ts +33 -10
- package/src/commands/save-api-docs.ts +49 -0
- package/src/commands/scaffold.ts +169 -23
- package/src/commands/select.ts +94 -0
- package/src/commands/serve.ts +10 -1
- package/src/container.ts +15 -0
- package/src/endpoint.ts +19 -0
- package/src/graft.ts +181 -0
- package/src/introspection/generated.agi.ts +12458 -8968
- package/src/introspection/generated.node.ts +10573 -7145
- package/src/introspection/generated.web.ts +1 -1
- package/src/introspection/index.ts +26 -0
- package/src/node/container.ts +6 -7
- package/src/node/features/content-db.ts +49 -2
- package/src/node/features/disk-cache.ts +16 -9
- package/src/node/features/dns.ts +16 -3
- package/src/node/features/docker.ts +16 -4
- package/src/node/features/esbuild.ts +20 -0
- package/src/node/features/file-manager.ts +184 -29
- package/src/node/features/fs.ts +704 -248
- package/src/node/features/git.ts +21 -8
- package/src/node/features/grep.ts +23 -3
- package/src/node/features/helpers.ts +372 -43
- package/src/node/features/networking.ts +39 -4
- package/src/node/features/opener.ts +28 -15
- package/src/node/features/os.ts +76 -0
- package/src/node/features/port-exposer.ts +11 -1
- package/src/node/features/postgres.ts +17 -1
- package/src/node/features/proc.ts +4 -1
- package/src/node/features/python.ts +63 -14
- package/src/node/features/repl.ts +11 -7
- package/src/node/features/runpod.ts +16 -3
- package/src/node/features/secure-shell.ts +27 -2
- package/src/node/features/semantic-search.ts +12 -1
- package/src/node/features/ui.ts +5 -69
- package/src/node/features/vm.ts +17 -0
- package/src/node/features/window-manager.ts +68 -20
- package/src/node.ts +5 -0
- package/src/scaffolds/generated.ts +492 -290
- package/src/scaffolds/template.ts +9 -0
- package/src/schemas/base.ts +46 -5
- package/src/selector.ts +282 -0
- package/src/server.ts +11 -0
- package/src/servers/express.ts +27 -12
- package/src/servers/socket.ts +45 -11
- package/src/web/clients/socket.ts +4 -1
- package/src/web/container.ts +2 -1
- package/src/web/features/network.ts +7 -1
- package/src/web/features/voice-recognition.ts +16 -1
- package/test/clients-servers.test.ts +2 -1
- package/test/command.test.ts +267 -0
- package/test-integration/assistants-manager.test.ts +10 -20
- package/tmp/.cache/luca-disk-cache/content-v2/sha512/1b/b5/c75b28794f00f94c4d609a98978e9420e9b7146d204a7fbf5b0b30477292581705d207c0100dabaac27eef540aaaece3374af75104a93219d4ec8bfb44e7 +1 -0
- package/tmp/.cache/luca-disk-cache/content-v2/sha512/da/df/1d90ce4e042abeb035a197832c6d6893420a747a056be773eb00e4f745a037d505c8db13dde7d36b36b6b893addbb7df0f5fe9f0c13e665f20056447318b +1 -0
- package/tmp/.cache/luca-disk-cache/content-v2/sha512/ed/04/e1d0c2a58c2db29b3921ca2affb3ea4febe831c53b38ebc21019fb799823aba6ed5b4611873d2cd25d422d49955b852a9c326da0d678899bc1c2c2960901 +1 -0
- package/tmp/.cache/luca-disk-cache/index-v5/00/13/572aa4c9a94f99eda999695d050cdd0ca7fe2d23a50af03234d4c8ce0791 +2 -0
- package/tmp/.cache/luca-disk-cache/index-v5/75/a9/cb61dc0f0589e8ec10a9aca27b834bc73884c479941042d22a2b22324cd3 +2 -0
- package/tmp/.cache/luca-disk-cache/index-v5/9f/0f/8b1f915ee64cfff7667dd96acd7a5ac0a96aa91a346e19cefd45909a9c9c +2 -0
- package/docs/apis/features/node/launcher-app-command-listener.md +0 -145
- package/docs/examples/launcher-app-command-listener.md +0 -120
- package/docs/tasks/web-container-helper-discovery.md +0 -71
- package/docs/todos.md +0 -1
- package/scripts/test-command-listener.ts +0 -123
- package/src/node/features/launcher-app-command-listener.ts +0 -389
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# VM (features.vm)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Sandboxed JavaScript execution environment for the browser. Automatically injects the container's context object into the global scope, so evaluated code can use anything provided by the container. Useful for live code playgrounds, plugin systems, and dynamic script evaluation.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -69,16 +69,7 @@ container.feature('vm', {
|
|
|
69
69
|
|
|
70
70
|
```ts
|
|
71
71
|
const vm = container.feature('vm')
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
const result = vm.run('1 + 2 + 3')
|
|
75
|
-
console.log(result) // 6
|
|
76
|
-
|
|
77
|
-
// Execute code with custom context
|
|
78
|
-
const result2 = vm.run('greeting + " " + name', {
|
|
79
|
-
greeting: 'Hello',
|
|
80
|
-
name: 'World'
|
|
81
|
-
})
|
|
82
|
-
console.log(result2) // 'Hello World'
|
|
72
|
+
const result = vm.run('1 + 2 + 3') // 6
|
|
73
|
+
const greeting = vm.run('container.uuid') // accesses container globals
|
|
83
74
|
```
|
|
84
75
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# VoiceRecognition (features.voice)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Speech-to-text recognition using the Web Speech API (SpeechRecognition). Wraps the browser's built-in speech recognition, supporting continuous listening, interim results, and language selection. Recognized text is accumulated in state and emitted as events for real-time transcription UIs.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -65,3 +65,20 @@ Event emitted by VoiceRecognition
|
|
|
65
65
|
|
|
66
66
|
Event emitted by VoiceRecognition
|
|
67
67
|
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## Examples
|
|
71
|
+
|
|
72
|
+
**features.voice**
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const voice = container.feature('voice', { continuous: true, autoListen: true })
|
|
76
|
+
|
|
77
|
+
voice.on('transcript', ({ text }) => {
|
|
78
|
+
console.log('Heard:', text)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// Or start manually
|
|
82
|
+
voice.start()
|
|
83
|
+
```
|
|
84
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ExpressServer (servers.express)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Express.js HTTP server with automatic endpoint mounting, CORS, and SPA history fallback. Wraps an Express application with convention-based endpoint discovery. Endpoints defined as modules are automatically mounted as routes. Supports static file serving, CORS configuration, and single-page app history fallback out of the box.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -124,4 +124,20 @@ container.server('express', {
|
|
|
124
124
|
| `port` | `number` | The port the server is bound to |
|
|
125
125
|
| `listening` | `boolean` | Whether the server is actively listening for connections |
|
|
126
126
|
| `configured` | `boolean` | Whether the server has been configured |
|
|
127
|
-
| `stopped` | `boolean` | Whether the server has been stopped |
|
|
127
|
+
| `stopped` | `boolean` | Whether the server has been stopped |
|
|
128
|
+
|
|
129
|
+
## Examples
|
|
130
|
+
|
|
131
|
+
**servers.express**
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
const server = container.server('express', { cors: true, static: './public' })
|
|
135
|
+
await server.start({ port: 3000 })
|
|
136
|
+
|
|
137
|
+
// Mount endpoints programmatically
|
|
138
|
+
server.mount(myEndpoint)
|
|
139
|
+
|
|
140
|
+
// Access the underlying Express app
|
|
141
|
+
server.app.get('/health', (req, res) => res.json({ ok: true }))
|
|
142
|
+
```
|
|
143
|
+
|
package/docs/apis/servers/mcp.md
CHANGED
|
@@ -158,25 +158,50 @@ Stop the MCP server and close all connections.
|
|
|
158
158
|
|
|
159
159
|
### toolRegistered
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
Emitted when a tool is registered
|
|
162
|
+
|
|
163
|
+
**Event Arguments:**
|
|
164
|
+
|
|
165
|
+
| Name | Type | Description |
|
|
166
|
+
|------|------|-------------|
|
|
167
|
+
| `arg0` | `string` | Tool name |
|
|
162
168
|
|
|
163
169
|
|
|
164
170
|
|
|
165
171
|
### resourceRegistered
|
|
166
172
|
|
|
167
|
-
|
|
173
|
+
Emitted when a resource is registered
|
|
174
|
+
|
|
175
|
+
**Event Arguments:**
|
|
176
|
+
|
|
177
|
+
| Name | Type | Description |
|
|
178
|
+
|------|------|-------------|
|
|
179
|
+
| `arg0` | `string` | Resource URI |
|
|
168
180
|
|
|
169
181
|
|
|
170
182
|
|
|
171
183
|
### promptRegistered
|
|
172
184
|
|
|
173
|
-
|
|
185
|
+
Emitted when a prompt is registered
|
|
186
|
+
|
|
187
|
+
**Event Arguments:**
|
|
188
|
+
|
|
189
|
+
| Name | Type | Description |
|
|
190
|
+
|------|------|-------------|
|
|
191
|
+
| `arg0` | `string` | Prompt name |
|
|
174
192
|
|
|
175
193
|
|
|
176
194
|
|
|
177
195
|
### toolCalled
|
|
178
196
|
|
|
179
|
-
|
|
197
|
+
Emitted when a tool is called
|
|
198
|
+
|
|
199
|
+
**Event Arguments:**
|
|
200
|
+
|
|
201
|
+
| Name | Type | Description |
|
|
202
|
+
|------|------|-------------|
|
|
203
|
+
| `arg0` | `string` | Tool name |
|
|
204
|
+
| `arg1` | `any` | Arguments |
|
|
180
205
|
|
|
181
206
|
|
|
182
207
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# WebsocketServer (servers.websocket)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
WebSocket server built on the `ws` library with optional JSON message framing. Manages WebSocket connections, tracks connected clients, and bridges messages to Luca's event bus. When `json` mode is enabled, incoming messages are automatically JSON-parsed (with `.toString()` for Buffer data) and outgoing messages via `send()` / `broadcast()` are JSON-stringified. When `json` mode is disabled, raw message data is emitted as-is and `send()` / `broadcast()` still JSON-stringify for safety.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ container.server('websocket', {
|
|
|
10
10
|
port,
|
|
11
11
|
// Hostname or IP address to bind to
|
|
12
12
|
host,
|
|
13
|
-
//
|
|
13
|
+
// When enabled, incoming messages are automatically JSON-parsed before emitting the message event, and outgoing send/broadcast calls JSON-stringify the payload
|
|
14
14
|
json,
|
|
15
15
|
})
|
|
16
16
|
```
|
|
@@ -21,7 +21,7 @@ container.server('websocket', {
|
|
|
21
21
|
|----------|------|-------------|
|
|
22
22
|
| `port` | `number` | Port number to listen on |
|
|
23
23
|
| `host` | `string` | Hostname or IP address to bind to |
|
|
24
|
-
| `json` | `boolean` |
|
|
24
|
+
| `json` | `boolean` | When enabled, incoming messages are automatically JSON-parsed before emitting the message event, and outgoing send/broadcast calls JSON-stringify the payload |
|
|
25
25
|
|
|
26
26
|
## Methods
|
|
27
27
|
|
|
@@ -79,13 +79,26 @@ container.server('websocket', {
|
|
|
79
79
|
|
|
80
80
|
### connection
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
Fires when a new client connects
|
|
83
|
+
|
|
84
|
+
**Event Arguments:**
|
|
85
|
+
|
|
86
|
+
| Name | Type | Description |
|
|
87
|
+
|------|------|-------------|
|
|
88
|
+
| `arg0` | `any` | The raw WebSocket client instance from the ws library |
|
|
83
89
|
|
|
84
90
|
|
|
85
91
|
|
|
86
92
|
### message
|
|
87
93
|
|
|
88
|
-
|
|
94
|
+
Fires when a message is received from a client. Handler signature: (data, ws)
|
|
95
|
+
|
|
96
|
+
**Event Arguments:**
|
|
97
|
+
|
|
98
|
+
| Name | Type | Description |
|
|
99
|
+
|------|------|-------------|
|
|
100
|
+
| `arg0` | `any` | The message data (JSON-parsed object when json option is enabled, raw Buffer/string otherwise) |
|
|
101
|
+
| `arg1` | `any` | The WebSocket client that sent the message — use with server.send(ws, data) to reply |
|
|
89
102
|
|
|
90
103
|
|
|
91
104
|
|
|
@@ -96,4 +109,19 @@ Event emitted by WebsocketServer
|
|
|
96
109
|
| `port` | `number` | The port the server is bound to |
|
|
97
110
|
| `listening` | `boolean` | Whether the server is actively listening for connections |
|
|
98
111
|
| `configured` | `boolean` | Whether the server has been configured |
|
|
99
|
-
| `stopped` | `boolean` | Whether the server has been stopped |
|
|
112
|
+
| `stopped` | `boolean` | Whether the server has been stopped |
|
|
113
|
+
|
|
114
|
+
## Examples
|
|
115
|
+
|
|
116
|
+
**servers.websocket**
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const ws = container.server('websocket', { json: true })
|
|
120
|
+
await ws.start({ port: 8080 })
|
|
121
|
+
|
|
122
|
+
ws.on('message', (data, client) => {
|
|
123
|
+
console.log('Received:', data)
|
|
124
|
+
ws.broadcast({ echo: data })
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Luca Project
|
|
2
|
+
|
|
3
|
+
This project uses the [Luca framework](https://github.com/soederpop/luca) — Lightweight Universal Conversational Architecture.
|
|
4
|
+
|
|
5
|
+
For a deep dive into the framework internals, see the [Luca GitHub repository](https://github.com/soederpop/luca).
|
|
6
|
+
|
|
7
|
+
## Runtime
|
|
8
|
+
|
|
9
|
+
The runtime is **bun**. Use `bun run` for scripts, `bun test` for tests.
|
|
10
|
+
|
|
11
|
+
## The `luca` CLI
|
|
12
|
+
|
|
13
|
+
The `luca` binary is available in the path. Key commands:
|
|
14
|
+
|
|
15
|
+
- `luca` — list available commands (built-in + project commands)
|
|
16
|
+
- `luca eval "expression"` — evaluate JS with the container in scope
|
|
17
|
+
- `luca describe <name>` — full docs for any feature, client, or server (e.g. `luca describe fs`)
|
|
18
|
+
- `luca describe features` — index of all available features (also: `clients`, `servers`)
|
|
19
|
+
- `luca serve` — start a local server using `endpoints/` folder
|
|
20
|
+
- `luca run script.ts` — run a script with the container
|
|
21
|
+
- `luca scaffold <type> <name>` — generate boilerplate for a new helper (run `luca scaffold` for full help)
|
|
22
|
+
|
|
23
|
+
## Container Rules
|
|
24
|
+
|
|
25
|
+
- **NEVER import from `fs`, `path`, or other Node builtins.** Use `container.feature('fs')` for file operations, `container.paths` for path operations.
|
|
26
|
+
- The container should provide everything you need. If something is missing, raise the concern rather than pulling in external dependencies.
|
|
27
|
+
- Use `container.utils` for common utilities (uuid, lodash helpers, string utils).
|
|
28
|
+
|
|
29
|
+
## Learning the Framework
|
|
30
|
+
|
|
31
|
+
1. **Discover** — Run `luca describe features`, `luca describe clients`, `luca describe servers` to see what's available. Then `luca describe <name>` for full docs on any helper. This is your first move, always. (See `.claude/skills/luca-framework/SKILL.md` for the full mental model.)
|
|
32
|
+
2. **Build** — Run `luca scaffold <type> --tutorial` before creating a new helper. It covers the full guide for that type.
|
|
33
|
+
3. **Prototype** — Use `luca eval "expression"` to test container code before wiring up full handlers. Reach for eval when you're stuck — it gives you full runtime access.
|
|
34
|
+
4. **Reference** — Browse `.claude/skills/luca-framework/references/api-docs/` for pre-generated API docs
|
|
35
|
+
|
|
36
|
+
## Project Structure
|
|
37
|
+
|
|
38
|
+
- `commands/` — custom CLI commands, run via `luca <commandName>` (auto-discovered)
|
|
39
|
+
- `endpoints/` — file-based HTTP routes, served via `luca serve` (auto-discovered)
|
|
40
|
+
- `features/` — custom container features, discovered via `container.helpers.discoverAll()` (auto-discovered)
|
|
41
|
+
- `docs/` — content documents managed by the `contentDb` feature (`container.docs`). See [contentbase](https://github.com/soederpop/contentbase) for the document model system.
|
|
42
|
+
- `luca.cli.ts` — optional project-level CLI customization (runs before any command)
|
|
43
|
+
|
|
44
|
+
## Command Arguments
|
|
45
|
+
|
|
46
|
+
Command handlers receive `(options, context)`. The `options` object contains:
|
|
47
|
+
- **Named flags** from `argsSchema`: `--verbose` → `options.verbose`
|
|
48
|
+
- **Positional args** mapped via `positionals` export: `luca cmd ./src` → `options.target`
|
|
49
|
+
- **Raw positionals** in `options._`: array where `_[0]` is the command name, `_[1+]` are positional args
|
|
50
|
+
|
|
51
|
+
To accept positional arguments, export a `positionals` array that maps them to named fields in `argsSchema`:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
export const positionals = ['target'] // luca myCmd ./src => options.target === './src'
|
|
55
|
+
export const argsSchema = z.object({
|
|
56
|
+
target: z.string().optional().describe('The target to operate on'),
|
|
57
|
+
verbose: z.boolean().default(false).describe('Enable verbose output'),
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## What's Available
|
|
62
|
+
|
|
63
|
+
The container provides more than you might expect. Before importing anything external, check here:
|
|
64
|
+
|
|
65
|
+
- **YAML** — `container.feature('yaml')` wraps `js-yaml`. Use `.parse(str)` and `.stringify(obj)`.
|
|
66
|
+
- **SQLite** — `container.feature('sqlite')` for databases. Parameterized queries, tagged templates.
|
|
67
|
+
- **REST client** — `container.client('rest', { baseURL })`. Methods (`get`, `post`, etc.) return **parsed JSON directly**, not `{ data, status, headers }`. On HTTP errors, the error is returned (not thrown).
|
|
68
|
+
- **Content DB** — `container.docs` (alias for `container.feature('contentDb')`) manages markdown documents with frontmatter. Query with `docs.query(docs.models.MyModel).fetchAll()`.
|
|
69
|
+
- **Grep** — `container.feature('grep')` has `search()` and `codeAnnotations()` for finding TODOs/FIXMEs/etc.
|
|
70
|
+
- **chalk** — available as `container.feature('ui').colors`, not via `import('chalk')`.
|
|
71
|
+
- **figlet** — available as `container.feature('ui').asciiArt(text)`.
|
|
72
|
+
- **uuid** — `container.utils.uuid()`
|
|
73
|
+
- **lodash** — `container.utils.lodash` (groupBy, keyBy, pick, omit, debounce, etc.)
|
|
74
|
+
- **string utils** — `container.utils.stringUtils` (camelCase, kebabCase, pluralize, etc.)
|
|
75
|
+
|
|
76
|
+
## Known Gotchas
|
|
77
|
+
|
|
78
|
+
- **For DELETE endpoint handlers, use `export { del as delete }`** — `delete` is a JS reserved word. Define your function with any name, then re-export it as `delete`.
|
|
79
|
+
- **Bun globals (`Bun.spawn`, `Bun.serve`) are unavailable** in command/endpoint handlers. Use Node's `child_process` for spawning processes, or use `container.feature('proc').exec()`.
|
|
80
|
+
- **`ui.print.*` writes to stdout** — if your command supports `--json`, gate UI output behind `if (!options.json)`.
|
|
81
|
+
- **VM contexts start empty** — when using `container.feature('vm')`, inject globals explicitly (`console`, `Date`, `Promise`, `crypto`, `TextEncoder`, `setTimeout`).
|
|
82
|
+
- **Long-running commands** (servers, watchers) need `await new Promise(() => {})` at the end with a `process.on('SIGINT', ...)` handler for cleanup.
|
|
83
|
+
- **Shared state between endpoints**: use `ctx.request.app.locals` to share data across endpoint files.
|
|
84
|
+
- **Database init**: use `luca.cli.ts` `main()` hook for table creation and seeding — it runs before any command or server starts.
|
|
85
|
+
|
|
86
|
+
## Extending the Container
|
|
87
|
+
|
|
88
|
+
Use `luca scaffold` to generate new helpers:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
luca scaffold command myTask --description "Automate something"
|
|
92
|
+
luca scaffold feature myCache --description "Custom caching layer"
|
|
93
|
+
luca scaffold endpoint users --description "User management API"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Run `luca scaffold` with no arguments for full usage and examples.
|
|
97
|
+
|
|
98
|
+
## Git Strategy
|
|
99
|
+
|
|
100
|
+
Roll on main. Commit with good messages that explain why, not just what.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Using the luca framework
|
|
3
|
+
description: Learn the luca container — discover what's available with luca describe, build new helpers with luca scaffold, and prototype with luca eval
|
|
4
|
+
---
|
|
5
|
+
# Luca: Learning the Container
|
|
6
|
+
|
|
7
|
+
The Luca framework `@soederpop/luca` ships a `luca` binary — a bun-based CLI for a dependency injection container. This project is based on it if this skill is present. The container auto-discovers modules in `commands/`, `clients/`, `servers/`, `features/`, and `endpoints/` folders.
|
|
8
|
+
|
|
9
|
+
There are three things to learn, in this order:
|
|
10
|
+
|
|
11
|
+
1. **Discover** what the container can do — `luca describe`
|
|
12
|
+
2. **Build** new helpers when your project needs them — `luca scaffold`
|
|
13
|
+
3. **Prototype** and debug with live code — `luca eval`
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Phase 1: Discover with `luca describe`
|
|
18
|
+
|
|
19
|
+
This is your primary tool. Before reading source files, searching for APIs, or writing any code — ask describe. It outputs full documentation for any part of the container: methods, options, events, state, examples.
|
|
20
|
+
|
|
21
|
+
### See what's available
|
|
22
|
+
|
|
23
|
+
```shell
|
|
24
|
+
luca describe features # index of all available features
|
|
25
|
+
luca describe clients # index of all available clients
|
|
26
|
+
luca describe servers # index of all available servers
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Learn about specific helpers
|
|
30
|
+
|
|
31
|
+
```shell
|
|
32
|
+
luca describe fs # full docs for the fs feature
|
|
33
|
+
luca describe git # full docs for git
|
|
34
|
+
luca describe rest # full docs for the rest client
|
|
35
|
+
luca describe express # full docs for the express server
|
|
36
|
+
luca describe git fs proc # multiple helpers in one shot
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Get targeted documentation
|
|
40
|
+
|
|
41
|
+
You can filter to only the sections you need:
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
luca describe fs --methods # just the methods
|
|
45
|
+
luca describe git --events # just the events it emits
|
|
46
|
+
luca describe express --options # just the constructor options
|
|
47
|
+
luca describe fs git --examples # just examples for both
|
|
48
|
+
luca describe fs --usage --methods # combine sections
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Describe the container itself
|
|
52
|
+
|
|
53
|
+
```shell
|
|
54
|
+
luca describe # overview of the container
|
|
55
|
+
luca describe self # same thing
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Get help on any command
|
|
59
|
+
|
|
60
|
+
```shell
|
|
61
|
+
luca # list all available commands
|
|
62
|
+
luca describe --help # full flag reference for describe
|
|
63
|
+
luca help scaffold # help for any command
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Use `luca describe` liberally.** It is the fastest, safest way to understand what the container provides. Every feature, client, and server is self-describing — if you know a name, describe will tell you everything about it.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Phase 2: Build with `luca scaffold`
|
|
71
|
+
|
|
72
|
+
When your project needs a new helper, scaffold it. The `scaffold` command generates correct boilerplate — you fill in the logic.
|
|
73
|
+
|
|
74
|
+
### Learn how to build each type
|
|
75
|
+
|
|
76
|
+
Before creating anything, read the tutorial for that helper type:
|
|
77
|
+
|
|
78
|
+
```shell
|
|
79
|
+
luca scaffold feature --tutorial # how features work, full guide
|
|
80
|
+
luca scaffold command --tutorial # how commands work
|
|
81
|
+
luca scaffold endpoint --tutorial # how endpoints work
|
|
82
|
+
luca scaffold client --tutorial # how clients work
|
|
83
|
+
luca scaffold server --tutorial # how servers work
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
These tutorials are the authoritative reference for each helper type. They cover imports, schemas, class structure, registration, conventions, and complete examples.
|
|
87
|
+
|
|
88
|
+
### Generate a helper
|
|
89
|
+
|
|
90
|
+
```shell
|
|
91
|
+
luca scaffold <type> <name> --description "What it does"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The workflow after scaffolding:
|
|
95
|
+
|
|
96
|
+
```shell
|
|
97
|
+
luca scaffold command sync-data --description "Pull data from staging"
|
|
98
|
+
# edit commands/sync-data.ts — add your logic
|
|
99
|
+
luca describe sync-data # verify it shows up and reads correctly
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Every scaffolded helper is auto-discovered by the container at runtime.
|
|
103
|
+
|
|
104
|
+
### When to use each type
|
|
105
|
+
|
|
106
|
+
| You need to... | Scaffold a... | Example |
|
|
107
|
+
|----------------------------------------------------|----------------|----------------------------------------------------------------|
|
|
108
|
+
| Add a reusable local capability (caching, crypto) | **feature** | `luca scaffold feature disk-cache --description "File-backed key-value cache"` |
|
|
109
|
+
| Add a CLI task (build, deploy, generate) | **command** | `luca scaffold command deploy --description "Deploy to production"` |
|
|
110
|
+
| Talk to an external API or service | **client** | `luca scaffold client github --description "GitHub API wrapper"` |
|
|
111
|
+
| Accept incoming connections (HTTP, WS) | **server** | `luca scaffold server mqtt --description "MQTT broker"` |
|
|
112
|
+
| Add a REST route to `luca serve` | **endpoint** | `luca scaffold endpoint users --description "User management API"` |
|
|
113
|
+
|
|
114
|
+
### Scaffold options
|
|
115
|
+
|
|
116
|
+
```shell
|
|
117
|
+
luca scaffold command deploy --description "..." # writes to commands/deploy.ts
|
|
118
|
+
luca scaffold endpoint users --print # print to stdout instead of writing
|
|
119
|
+
luca scaffold feature cache --output lib/cache.ts # override output path
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Phase 3: Prototype with `luca eval`
|
|
125
|
+
|
|
126
|
+
Once you know what's available (describe) and how to build things (scaffold), use `luca eval` to test ideas, verify behavior, and debug.
|
|
127
|
+
|
|
128
|
+
```shell
|
|
129
|
+
luca eval "container.features.available"
|
|
130
|
+
luca eval "container.feature('proc').exec('ls')"
|
|
131
|
+
luca eval "container.feature('fs').readFile('package.json')"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The eval command boots a full container with all helpers discovered and registered. Core features are available as top-level shortcuts:
|
|
135
|
+
|
|
136
|
+
```shell
|
|
137
|
+
luca eval "fs.readFile('package.json')"
|
|
138
|
+
luca eval "git.branch"
|
|
139
|
+
luca eval "proc.exec('ls')"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Reach for eval when you're stuck.** It gives you full control of the container at runtime — you can test method calls, inspect state, verify event behavior, and debug issues that are hard to reason about from docs alone.
|
|
143
|
+
|
|
144
|
+
**Use eval as a testing tool.** Before wiring up a full command handler or feature, test your logic in eval first. Want to verify how `fs.moveAsync` behaves, or whether a watcher event fires the way you expect? Run it in eval. This is the fastest way to validate container code without the overhead of building the full command around it.
|
|
145
|
+
|
|
146
|
+
```shell
|
|
147
|
+
# Test file operations before building a command around them
|
|
148
|
+
luca eval "await fs.moveAsync('inbox/test.json', 'inbox/valid/test.json')"
|
|
149
|
+
|
|
150
|
+
# First: luca describe fileManager --events (to learn what events exist)
|
|
151
|
+
# Then test the behavior:
|
|
152
|
+
luca eval "const fm = container.feature('fileManager'); fm.on('file:change', (e) => console.log(e)); await fm.watch({ paths: ['inbox'] })"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### The REPL
|
|
156
|
+
|
|
157
|
+
For interactive exploration, `luca console` opens a persistent REPL with the container in scope. Useful when you need to try multiple things in sequence.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Key Concepts
|
|
162
|
+
|
|
163
|
+
### The Container
|
|
164
|
+
|
|
165
|
+
The container is a singleton that holds everything your application needs. It organizes components into **registries**: features, clients, servers, commands, and endpoints. Use the factory functions to get instances:
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
const fs = container.feature('fs')
|
|
169
|
+
const rest = container.client('rest')
|
|
170
|
+
const server = container.server('express')
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### State
|
|
174
|
+
|
|
175
|
+
Every helper and the container itself have observable state:
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
const feature = container.feature('fs')
|
|
179
|
+
|
|
180
|
+
feature.state.current // snapshot of all state
|
|
181
|
+
feature.state.get('someKey') // single value
|
|
182
|
+
feature.state.set('key', 'value') // update
|
|
183
|
+
|
|
184
|
+
// Watch for changes
|
|
185
|
+
feature.state.observe((changeType, key, value) => {
|
|
186
|
+
// changeType: 'add' | 'update' | 'delete'
|
|
187
|
+
})
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The container has state too: `container.state.current`, `container.state.observe()`.
|
|
191
|
+
|
|
192
|
+
### Events
|
|
193
|
+
|
|
194
|
+
Every helper and the container are event emitters — `on`, `once`, `emit`, `waitFor` all work as expected. Use `luca describe <name> --events` to see what a helper emits.
|
|
195
|
+
|
|
196
|
+
### Utilities
|
|
197
|
+
|
|
198
|
+
The container provides common utilities at `container.utils` — no external imports needed:
|
|
199
|
+
|
|
200
|
+
- `container.utils.uuid()` — v4 UUID
|
|
201
|
+
- `container.utils.hashObject(obj)` — deterministic hash
|
|
202
|
+
- `container.utils.stringUtils` — camelCase, kebabCase, pluralize, etc.
|
|
203
|
+
- `container.utils.lodash` — groupBy, keyBy, pick, omit, debounce, etc.
|
|
204
|
+
- `container.paths.resolve()` / `container.paths.join()` — path operations
|
|
205
|
+
|
|
206
|
+
### Programmatic introspection
|
|
207
|
+
|
|
208
|
+
Everything `luca describe` outputs is also available at runtime in code:
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
container.features.describe('fs') // markdown docs (same as the CLI)
|
|
212
|
+
feature.introspect() // structured object: { methods, events, state, options }
|
|
213
|
+
container.inspectAsText() // full container overview as markdown
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
This is useful inside commands and scripts where you need introspection data programmatically.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Reference
|
|
221
|
+
|
|
222
|
+
See `references/api-docs/` for the full pre-generated API reference for every built-in feature, client, and server.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* about — Display project information and discovered helpers.
|
|
3
|
+
* Run with: luca about
|
|
4
|
+
*
|
|
5
|
+
* Positional words after the command name are available as options._
|
|
6
|
+
* For example: `luca about commands` → options._[1] === 'commands'
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
import type { ContainerContext } from '@soederpop/luca'
|
|
10
|
+
|
|
11
|
+
export const description = 'Display project information and discovered helpers'
|
|
12
|
+
|
|
13
|
+
export const argsSchema = z.object({})
|
|
14
|
+
|
|
15
|
+
export default async function about(options: z.infer<typeof argsSchema>, context: ContainerContext) {
|
|
16
|
+
const { container } = context
|
|
17
|
+
const ui = container.feature('ui')
|
|
18
|
+
|
|
19
|
+
// Discover all project-level helpers (commands, features, endpoints, etc.)
|
|
20
|
+
const discovered = await container.helpers.discoverAll()
|
|
21
|
+
|
|
22
|
+
const projectName = container.paths.resolve('.').split('/').pop() || 'project'
|
|
23
|
+
|
|
24
|
+
ui.print.cyan(`\n ${projectName}\n`)
|
|
25
|
+
ui.print(' Powered by luca — Lightweight Universal Conversational Architecture\n')
|
|
26
|
+
|
|
27
|
+
const types = ['features', 'clients', 'servers', 'commands', 'endpoints']
|
|
28
|
+
|
|
29
|
+
for (const type of types) {
|
|
30
|
+
const names = discovered[type] || []
|
|
31
|
+
if (names.length > 0) {
|
|
32
|
+
ui.print.green(` ${type} (${names.length})`)
|
|
33
|
+
for (const name of names) {
|
|
34
|
+
ui.print(` • ${name}`)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const totalBuiltIn = types.reduce((sum: number, t: string) => sum + (container[t]?.available?.length || 0), 0)
|
|
40
|
+
ui.print.dim(`\n ${totalBuiltIn} built-in helpers available. Run \`luca describe\` for details.\n`)
|
|
41
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineModel, z } from 'contentbase'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Define your content models here. Each model maps to a folder prefix
|
|
5
|
+
* inside the docs/ directory. Documents in those folders follow the
|
|
6
|
+
* model's metadata schema.
|
|
7
|
+
*
|
|
8
|
+
* Access documents at runtime:
|
|
9
|
+
* const docs = container.docs // contentDb feature
|
|
10
|
+
* if (!docs.isLoaded) await docs.load()
|
|
11
|
+
* const notes = await docs.query(docs.models.Note).fetchAll()
|
|
12
|
+
*
|
|
13
|
+
* See https://github.com/soederpop/contentbase for full documentation.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const Note = defineModel('Note', {
|
|
17
|
+
prefix: 'notes',
|
|
18
|
+
meta: z.object({
|
|
19
|
+
tags: z.array(z.string()).default([]),
|
|
20
|
+
status: z.enum(['draft', 'published']).default('draft'),
|
|
21
|
+
}),
|
|
22
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Docs
|
|
2
|
+
|
|
3
|
+
This folder contains structured content documents managed by the [contentbase](https://github.com/soederpop/contentbase) system.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
Documents are markdown files with YAML frontmatter. Each document belongs to a **model** defined in `docs/models.ts`. Models specify:
|
|
8
|
+
- A **prefix** (subfolder name, e.g. `notes/`)
|
|
9
|
+
- A **metadata schema** (validated frontmatter fields)
|
|
10
|
+
|
|
11
|
+
## Accessing documents at runtime
|
|
12
|
+
|
|
13
|
+
The `contentDb` feature (aliased to `container.docs`) loads and queries documents:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
const docs = container.docs
|
|
17
|
+
if (!docs.isLoaded) await docs.load()
|
|
18
|
+
|
|
19
|
+
// Query all notes
|
|
20
|
+
const notes = await docs.query(docs.models.Note).fetchAll()
|
|
21
|
+
|
|
22
|
+
// Get a specific document
|
|
23
|
+
const doc = docs.collection('notes').document('my-note')
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Creating a new document
|
|
27
|
+
|
|
28
|
+
Add a markdown file in the appropriate subfolder:
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
---
|
|
32
|
+
title: My First Note
|
|
33
|
+
tags: [example]
|
|
34
|
+
status: draft
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
Content goes here.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Learn more
|
|
41
|
+
|
|
42
|
+
- [Contentbase GitHub](https://github.com/soederpop/contentbase) — full documentation and API reference
|
|
43
|
+
- `luca describe contentDb` — runtime docs for the contentDb feature
|