@soederpop/luca 0.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 (358) hide show
  1. package/CLAUDE.md +71 -0
  2. package/README.md +78 -0
  3. package/bun.lock +2928 -0
  4. package/bunfig.toml +3 -0
  5. package/commands/audit-docs.ts +740 -0
  6. package/commands/build-scaffolds.ts +154 -0
  7. package/commands/generate-api-docs.ts +114 -0
  8. package/commands/update-introspection.ts +67 -0
  9. package/docs/CLI.md +335 -0
  10. package/docs/README.md +88 -0
  11. package/docs/TABLE-OF-CONTENTS.md +157 -0
  12. package/docs/apis/clients/elevenlabs.md +84 -0
  13. package/docs/apis/clients/graph.md +56 -0
  14. package/docs/apis/clients/openai.md +69 -0
  15. package/docs/apis/clients/rest.md +41 -0
  16. package/docs/apis/clients/websocket.md +107 -0
  17. package/docs/apis/features/agi/assistant.md +471 -0
  18. package/docs/apis/features/agi/assistants-manager.md +154 -0
  19. package/docs/apis/features/agi/claude-code.md +602 -0
  20. package/docs/apis/features/agi/conversation-history.md +352 -0
  21. package/docs/apis/features/agi/conversation.md +333 -0
  22. package/docs/apis/features/agi/docs-reader.md +121 -0
  23. package/docs/apis/features/agi/openai-codex.md +318 -0
  24. package/docs/apis/features/agi/openapi.md +138 -0
  25. package/docs/apis/features/agi/semantic-search.md +387 -0
  26. package/docs/apis/features/agi/skills-library.md +216 -0
  27. package/docs/apis/features/node/container-link.md +133 -0
  28. package/docs/apis/features/node/content-db.md +313 -0
  29. package/docs/apis/features/node/disk-cache.md +379 -0
  30. package/docs/apis/features/node/dns.md +651 -0
  31. package/docs/apis/features/node/docker.md +705 -0
  32. package/docs/apis/features/node/downloader.md +81 -0
  33. package/docs/apis/features/node/esbuild.md +59 -0
  34. package/docs/apis/features/node/file-manager.md +182 -0
  35. package/docs/apis/features/node/fs.md +581 -0
  36. package/docs/apis/features/node/git.md +330 -0
  37. package/docs/apis/features/node/google-auth.md +174 -0
  38. package/docs/apis/features/node/google-calendar.md +187 -0
  39. package/docs/apis/features/node/google-docs.md +151 -0
  40. package/docs/apis/features/node/google-drive.md +225 -0
  41. package/docs/apis/features/node/google-sheets.md +179 -0
  42. package/docs/apis/features/node/grep.md +290 -0
  43. package/docs/apis/features/node/helpers.md +135 -0
  44. package/docs/apis/features/node/ink.md +334 -0
  45. package/docs/apis/features/node/ipc-socket.md +260 -0
  46. package/docs/apis/features/node/json-tree.md +86 -0
  47. package/docs/apis/features/node/launcher-app-command-listener.md +145 -0
  48. package/docs/apis/features/node/networking.md +281 -0
  49. package/docs/apis/features/node/nlp.md +133 -0
  50. package/docs/apis/features/node/opener.md +97 -0
  51. package/docs/apis/features/node/os.md +118 -0
  52. package/docs/apis/features/node/package-finder.md +402 -0
  53. package/docs/apis/features/node/postgres.md +212 -0
  54. package/docs/apis/features/node/proc.md +430 -0
  55. package/docs/apis/features/node/process-manager.md +210 -0
  56. package/docs/apis/features/node/python.md +278 -0
  57. package/docs/apis/features/node/repl.md +88 -0
  58. package/docs/apis/features/node/runpod.md +673 -0
  59. package/docs/apis/features/node/secure-shell.md +169 -0
  60. package/docs/apis/features/node/semantic-search.md +401 -0
  61. package/docs/apis/features/node/sqlite.md +211 -0
  62. package/docs/apis/features/node/telegram.md +254 -0
  63. package/docs/apis/features/node/tts.md +118 -0
  64. package/docs/apis/features/node/ui.md +703 -0
  65. package/docs/apis/features/node/vault.md +64 -0
  66. package/docs/apis/features/node/vm.md +84 -0
  67. package/docs/apis/features/node/window-manager.md +337 -0
  68. package/docs/apis/features/node/yaml-tree.md +85 -0
  69. package/docs/apis/features/node/yaml.md +176 -0
  70. package/docs/apis/features/web/asset-loader.md +47 -0
  71. package/docs/apis/features/web/container-link.md +133 -0
  72. package/docs/apis/features/web/esbuild.md +59 -0
  73. package/docs/apis/features/web/helpers.md +135 -0
  74. package/docs/apis/features/web/network.md +30 -0
  75. package/docs/apis/features/web/speech.md +55 -0
  76. package/docs/apis/features/web/vault.md +64 -0
  77. package/docs/apis/features/web/vm.md +84 -0
  78. package/docs/apis/features/web/voice.md +67 -0
  79. package/docs/apis/servers/express.md +127 -0
  80. package/docs/apis/servers/mcp.md +213 -0
  81. package/docs/apis/servers/websocket.md +99 -0
  82. package/docs/documentation-audit.md +134 -0
  83. package/docs/examples/content-db.md +77 -0
  84. package/docs/examples/disk-cache.md +83 -0
  85. package/docs/examples/docker.md +101 -0
  86. package/docs/examples/downloader.md +70 -0
  87. package/docs/examples/esbuild.md +80 -0
  88. package/docs/examples/file-manager.md +82 -0
  89. package/docs/examples/fs.md +83 -0
  90. package/docs/examples/git.md +85 -0
  91. package/docs/examples/google-auth.md +88 -0
  92. package/docs/examples/google-calendar.md +94 -0
  93. package/docs/examples/google-docs.md +82 -0
  94. package/docs/examples/google-drive.md +96 -0
  95. package/docs/examples/google-sheets.md +95 -0
  96. package/docs/examples/grep.md +85 -0
  97. package/docs/examples/ink-blocks.md +75 -0
  98. package/docs/examples/ink-renderer.md +41 -0
  99. package/docs/examples/ink.md +103 -0
  100. package/docs/examples/ipc-socket.md +103 -0
  101. package/docs/examples/json-tree.md +91 -0
  102. package/docs/examples/launcher-app-command-listener.md +120 -0
  103. package/docs/examples/networking.md +58 -0
  104. package/docs/examples/nlp.md +91 -0
  105. package/docs/examples/opener.md +78 -0
  106. package/docs/examples/os.md +72 -0
  107. package/docs/examples/package-finder.md +89 -0
  108. package/docs/examples/port-exposer.md +89 -0
  109. package/docs/examples/postgres.md +91 -0
  110. package/docs/examples/proc.md +81 -0
  111. package/docs/examples/process-manager.md +79 -0
  112. package/docs/examples/python.md +91 -0
  113. package/docs/examples/repl.md +93 -0
  114. package/docs/examples/runpod.md +119 -0
  115. package/docs/examples/secure-shell.md +92 -0
  116. package/docs/examples/sqlite.md +86 -0
  117. package/docs/examples/telegram.md +77 -0
  118. package/docs/examples/tts.md +86 -0
  119. package/docs/examples/ui.md +80 -0
  120. package/docs/examples/vault.md +70 -0
  121. package/docs/examples/vm.md +86 -0
  122. package/docs/examples/window-manager.md +125 -0
  123. package/docs/examples/yaml-tree.md +93 -0
  124. package/docs/examples/yaml.md +104 -0
  125. package/docs/ideas/class-registration-refactor-possibilities.md +197 -0
  126. package/docs/ideas/container-use-api.md +9 -0
  127. package/docs/ideas/easy-auth-for-express-servers-and-luca-serve.md +0 -0
  128. package/docs/ideas/feature-stacks.md +22 -0
  129. package/docs/ideas/luca-cli-self-sufficiency-demo.md +23 -0
  130. package/docs/ideas/mcp-design.md +9 -0
  131. package/docs/ideas/web-container-debugging-feature.md +13 -0
  132. package/docs/introspection-audit.md +49 -0
  133. package/docs/introspection.md +154 -0
  134. package/docs/mcp/readme.md +162 -0
  135. package/docs/models.ts +38 -0
  136. package/docs/philosophy.md +85 -0
  137. package/docs/principles.md +7 -0
  138. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
  139. package/docs/prompts/mcp-test-easy-command.md +27 -0
  140. package/docs/reports/assistant-bugs.md +38 -0
  141. package/docs/reports/attach-pattern-usage.md +18 -0
  142. package/docs/reports/code-audit-results.md +391 -0
  143. package/docs/reports/introspection-audit-tasks.md +378 -0
  144. package/docs/reports/luca-mcp-improvements.md +128 -0
  145. package/docs/scaffolds/client.md +140 -0
  146. package/docs/scaffolds/command.md +106 -0
  147. package/docs/scaffolds/endpoint.md +176 -0
  148. package/docs/scaffolds/feature.md +148 -0
  149. package/docs/scaffolds/server.md +187 -0
  150. package/docs/tasks/web-container-helper-discovery.md +71 -0
  151. package/docs/todos.md +1 -0
  152. package/docs/tutorials/01-getting-started.md +106 -0
  153. package/docs/tutorials/02-container.md +210 -0
  154. package/docs/tutorials/03-scripts.md +194 -0
  155. package/docs/tutorials/04-features-overview.md +196 -0
  156. package/docs/tutorials/05-state-and-events.md +171 -0
  157. package/docs/tutorials/06-servers.md +157 -0
  158. package/docs/tutorials/07-endpoints.md +198 -0
  159. package/docs/tutorials/08-commands.md +171 -0
  160. package/docs/tutorials/09-clients.md +162 -0
  161. package/docs/tutorials/10-creating-features.md +198 -0
  162. package/docs/tutorials/11-contentbase.md +191 -0
  163. package/docs/tutorials/12-assistants.md +215 -0
  164. package/docs/tutorials/13-introspection.md +147 -0
  165. package/docs/tutorials/14-type-system.md +174 -0
  166. package/docs/tutorials/15-project-patterns.md +222 -0
  167. package/docs/tutorials/16-google-features.md +534 -0
  168. package/docs/tutorials/17-tui-blocks.md +530 -0
  169. package/docs/tutorials/18-semantic-search.md +334 -0
  170. package/index.ts +1 -0
  171. package/luca.console.ts +9 -0
  172. package/main.py +6 -0
  173. package/package.json +154 -0
  174. package/pyproject.toml +7 -0
  175. package/scripts/animations/chrome-glitch.ts +55 -0
  176. package/scripts/animations/index.ts +16 -0
  177. package/scripts/animations/neon-pulse.ts +64 -0
  178. package/scripts/animations/types.ts +6 -0
  179. package/scripts/build-web.ts +28 -0
  180. package/scripts/examples/ask-luca-expert.ts +42 -0
  181. package/scripts/examples/assistant-questions.ts +12 -0
  182. package/scripts/examples/excalidraw-expert.ts +75 -0
  183. package/scripts/examples/expert-chat.ts +0 -0
  184. package/scripts/examples/file-manager.ts +14 -0
  185. package/scripts/examples/ideas.ts +12 -0
  186. package/scripts/examples/interactive-chat.ts +20 -0
  187. package/scripts/examples/openai-tool-calls.ts +113 -0
  188. package/scripts/examples/opening-a-web-browser.ts +5 -0
  189. package/scripts/examples/telegram-bot.ts +79 -0
  190. package/scripts/examples/telegram-ink-ui.ts +302 -0
  191. package/scripts/examples/using-assistant-with-mcp.ts +560 -0
  192. package/scripts/examples/using-claude-code.ts +10 -0
  193. package/scripts/examples/using-contentdb.ts +35 -0
  194. package/scripts/examples/using-conversations.ts +35 -0
  195. package/scripts/examples/using-disk-cache.ts +10 -0
  196. package/scripts/examples/using-docker-shell.ts +75 -0
  197. package/scripts/examples/using-elevenlabs.ts +25 -0
  198. package/scripts/examples/using-google-calendar.ts +57 -0
  199. package/scripts/examples/using-google-docs.ts +74 -0
  200. package/scripts/examples/using-google-drive.ts +74 -0
  201. package/scripts/examples/using-google-sheets.ts +89 -0
  202. package/scripts/examples/using-nlp.ts +55 -0
  203. package/scripts/examples/using-ollama.ts +10 -0
  204. package/scripts/examples/using-openai-codex.ts +23 -0
  205. package/scripts/examples/using-postgres.ts +55 -0
  206. package/scripts/examples/using-runpod.ts +32 -0
  207. package/scripts/examples/using-tts.ts +40 -0
  208. package/scripts/examples/vm-loading-esm-modules.ts +16 -0
  209. package/scripts/scaffold.ts +391 -0
  210. package/scripts/scratch.ts +15 -0
  211. package/scripts/test-command-listener.ts +123 -0
  212. package/scripts/test-window-manager-lifecycle.ts +86 -0
  213. package/scripts/test-window-manager.ts +43 -0
  214. package/scripts/update-introspection-data.ts +58 -0
  215. package/src/agi/README.md +14 -0
  216. package/src/agi/container.server.ts +114 -0
  217. package/src/agi/endpoints/ask.ts +60 -0
  218. package/src/agi/endpoints/conversations/[id].ts +45 -0
  219. package/src/agi/endpoints/conversations.ts +31 -0
  220. package/src/agi/endpoints/experts.ts +37 -0
  221. package/src/agi/features/assistant.ts +767 -0
  222. package/src/agi/features/assistants-manager.ts +260 -0
  223. package/src/agi/features/claude-code.ts +1111 -0
  224. package/src/agi/features/conversation-history.ts +497 -0
  225. package/src/agi/features/conversation.ts +799 -0
  226. package/src/agi/features/openai-codex.ts +631 -0
  227. package/src/agi/features/openapi.ts +438 -0
  228. package/src/agi/features/skills-library.ts +425 -0
  229. package/src/agi/index.ts +6 -0
  230. package/src/agi/lib/token-counter.ts +122 -0
  231. package/src/browser.ts +25 -0
  232. package/src/bus.ts +100 -0
  233. package/src/cli/cli.ts +70 -0
  234. package/src/client.ts +461 -0
  235. package/src/clients/civitai/index.ts +541 -0
  236. package/src/clients/client-template.ts +41 -0
  237. package/src/clients/comfyui/index.ts +597 -0
  238. package/src/clients/elevenlabs/index.ts +291 -0
  239. package/src/clients/openai/index.ts +451 -0
  240. package/src/clients/supabase/index.ts +366 -0
  241. package/src/command.ts +164 -0
  242. package/src/commands/chat.ts +182 -0
  243. package/src/commands/console.ts +192 -0
  244. package/src/commands/describe.ts +433 -0
  245. package/src/commands/eval.ts +116 -0
  246. package/src/commands/help.ts +214 -0
  247. package/src/commands/index.ts +14 -0
  248. package/src/commands/mcp.ts +64 -0
  249. package/src/commands/prompt.ts +807 -0
  250. package/src/commands/run.ts +257 -0
  251. package/src/commands/sandbox-mcp.ts +439 -0
  252. package/src/commands/scaffold.ts +79 -0
  253. package/src/commands/serve.ts +172 -0
  254. package/src/container.ts +781 -0
  255. package/src/endpoint.ts +340 -0
  256. package/src/feature.ts +75 -0
  257. package/src/hash-object.ts +97 -0
  258. package/src/helper.ts +543 -0
  259. package/src/introspection/generated.agi.ts +23388 -0
  260. package/src/introspection/generated.node.ts +18899 -0
  261. package/src/introspection/generated.web.ts +2021 -0
  262. package/src/introspection/index.ts +256 -0
  263. package/src/introspection/scan.ts +912 -0
  264. package/src/node/container.ts +354 -0
  265. package/src/node/feature.ts +13 -0
  266. package/src/node/features/container-link.ts +558 -0
  267. package/src/node/features/content-db.ts +475 -0
  268. package/src/node/features/disk-cache.ts +382 -0
  269. package/src/node/features/dns.ts +655 -0
  270. package/src/node/features/docker.ts +912 -0
  271. package/src/node/features/downloader.ts +92 -0
  272. package/src/node/features/esbuild.ts +68 -0
  273. package/src/node/features/file-manager.ts +357 -0
  274. package/src/node/features/fs.ts +534 -0
  275. package/src/node/features/git.ts +492 -0
  276. package/src/node/features/google-auth.ts +502 -0
  277. package/src/node/features/google-calendar.ts +300 -0
  278. package/src/node/features/google-docs.ts +404 -0
  279. package/src/node/features/google-drive.ts +339 -0
  280. package/src/node/features/google-sheets.ts +279 -0
  281. package/src/node/features/grep.ts +406 -0
  282. package/src/node/features/helpers.ts +374 -0
  283. package/src/node/features/ink.ts +490 -0
  284. package/src/node/features/ipc-socket.ts +459 -0
  285. package/src/node/features/json-tree.ts +188 -0
  286. package/src/node/features/launcher-app-command-listener.ts +388 -0
  287. package/src/node/features/networking.ts +925 -0
  288. package/src/node/features/nlp.ts +211 -0
  289. package/src/node/features/opener.ts +166 -0
  290. package/src/node/features/os.ts +157 -0
  291. package/src/node/features/package-finder.ts +539 -0
  292. package/src/node/features/port-exposer.ts +342 -0
  293. package/src/node/features/postgres.ts +273 -0
  294. package/src/node/features/proc.ts +502 -0
  295. package/src/node/features/process-manager.ts +542 -0
  296. package/src/node/features/python.ts +444 -0
  297. package/src/node/features/repl.ts +194 -0
  298. package/src/node/features/runpod.ts +802 -0
  299. package/src/node/features/secure-shell.ts +248 -0
  300. package/src/node/features/semantic-search.ts +924 -0
  301. package/src/node/features/sqlite.ts +289 -0
  302. package/src/node/features/telegram.ts +342 -0
  303. package/src/node/features/tts.ts +184 -0
  304. package/src/node/features/ui.ts +857 -0
  305. package/src/node/features/vault.ts +164 -0
  306. package/src/node/features/vm.ts +312 -0
  307. package/src/node/features/window-manager.ts +804 -0
  308. package/src/node/features/yaml-tree.ts +149 -0
  309. package/src/node/features/yaml.ts +132 -0
  310. package/src/node.ts +70 -0
  311. package/src/react/index.ts +175 -0
  312. package/src/registry.ts +199 -0
  313. package/src/scaffolds/generated.ts +1613 -0
  314. package/src/scaffolds/template.ts +37 -0
  315. package/src/schemas/base.ts +255 -0
  316. package/src/server.ts +135 -0
  317. package/src/servers/express.ts +209 -0
  318. package/src/servers/mcp.ts +805 -0
  319. package/src/servers/socket.ts +120 -0
  320. package/src/state.ts +101 -0
  321. package/src/web/clients/socket.ts +82 -0
  322. package/src/web/container.ts +74 -0
  323. package/src/web/extension.ts +30 -0
  324. package/src/web/feature.ts +12 -0
  325. package/src/web/features/asset-loader.ts +64 -0
  326. package/src/web/features/container-link.ts +385 -0
  327. package/src/web/features/esbuild.ts +79 -0
  328. package/src/web/features/helpers.ts +267 -0
  329. package/src/web/features/network.ts +61 -0
  330. package/src/web/features/speech.ts +87 -0
  331. package/src/web/features/vault.ts +189 -0
  332. package/src/web/features/vm.ts +78 -0
  333. package/src/web/features/voice-recognition.ts +129 -0
  334. package/src/web/shims/isomorphic-vm.ts +149 -0
  335. package/test/bus.test.ts +134 -0
  336. package/test/clients-servers.test.ts +216 -0
  337. package/test/container-link.test.ts +274 -0
  338. package/test/features.test.ts +160 -0
  339. package/test/integration.test.ts +787 -0
  340. package/test/node-container.test.ts +121 -0
  341. package/test/rate-limit.test.ts +272 -0
  342. package/test/semantic-search.test.ts +550 -0
  343. package/test/state.test.ts +121 -0
  344. package/test-integration/assistant.test.ts +138 -0
  345. package/test-integration/assistants-manager.test.ts +123 -0
  346. package/test-integration/claude-code.test.ts +98 -0
  347. package/test-integration/conversation-history.test.ts +205 -0
  348. package/test-integration/conversation.test.ts +137 -0
  349. package/test-integration/elevenlabs.test.ts +55 -0
  350. package/test-integration/google-services.test.ts +80 -0
  351. package/test-integration/helpers.ts +89 -0
  352. package/test-integration/openai-codex.test.ts +93 -0
  353. package/test-integration/runpod.test.ts +58 -0
  354. package/test-integration/server-endpoints.test.ts +97 -0
  355. package/test-integration/skills-library.test.ts +157 -0
  356. package/test-integration/telegram.test.ts +46 -0
  357. package/tsconfig.json +58 -0
  358. package/uv.lock +8 -0
@@ -0,0 +1,171 @@
1
+ ---
2
+ title: State and Events
3
+ tags: [state, events, observable, reactive, bus, emit, on, once, waitFor]
4
+ ---
5
+
6
+ # State and Events
7
+
8
+ Every container and helper in Luca has observable state and a typed event bus. These are the core primitives for building reactive applications.
9
+
10
+ ## Observable State
11
+
12
+ State is a key-value store that notifies observers when values change.
13
+
14
+ ### Basic Usage
15
+
16
+ ```typescript
17
+ // Every helper has state
18
+ const feature = container.feature('myFeature')
19
+
20
+ feature.state.set('loading', true)
21
+ feature.state.get('loading') // true
22
+ feature.state.current // Snapshot: { loading: true, ... }
23
+ feature.state.version // Number, increments on every change
24
+ ```
25
+
26
+ ### Observing Changes
27
+
28
+ ```typescript
29
+ // Watch all state changes
30
+ const dispose = feature.state.observe((changeType, key, value) => {
31
+ // changeType: 'add' | 'update' | 'delete'
32
+ console.log(`${key} was ${changeType}d:`, value)
33
+ })
34
+
35
+ // Later, stop observing
36
+ dispose()
37
+ ```
38
+
39
+ ### Container State
40
+
41
+ The container itself tracks important state:
42
+
43
+ ```typescript
44
+ container.state.get('started') // boolean
45
+ container.state.get('enabledFeatures') // string[]
46
+ container.state.get('registries') // string[]
47
+ ```
48
+
49
+ ### State in Custom Features
50
+
51
+ Define your feature's state shape with a Zod schema:
52
+
53
+ ```typescript
54
+ const TaskStateSchema = FeatureStateSchema.extend({
55
+ tasks: z.array(z.object({
56
+ id: z.string(),
57
+ title: z.string(),
58
+ done: z.boolean(),
59
+ })).default([]).describe('List of tasks'),
60
+ filter: z.enum(['all', 'active', 'done']).default('all').describe('Current filter'),
61
+ })
62
+
63
+ class TaskManager extends Feature<z.infer<typeof TaskStateSchema>> {
64
+ static override stateSchema = TaskStateSchema
65
+
66
+ addTask(title: string) {
67
+ const tasks = this.state.get('tasks') || []
68
+ const task = { id: crypto.randomUUID(), title, done: false }
69
+ this.state.set('tasks', [...tasks, task])
70
+ this.emit('taskAdded', task)
71
+ }
72
+
73
+ get activeTasks() {
74
+ return (this.state.get('tasks') || []).filter(t => !t.done)
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## Event Bus
80
+
81
+ The event bus enables decoupled communication between components.
82
+
83
+ ### Emitting and Listening
84
+
85
+ ```typescript
86
+ // Listen for an event
87
+ feature.on('taskCompleted', (task) => {
88
+ console.log(`Task "${task.title}" is done!`)
89
+ })
90
+
91
+ // Emit an event
92
+ feature.emit('taskCompleted', { id: '1', title: 'Write docs', done: true })
93
+ ```
94
+
95
+ ### One-Time Listeners
96
+
97
+ ```typescript
98
+ feature.once('initialized', () => {
99
+ console.log('Feature is ready (this runs once)')
100
+ })
101
+ ```
102
+
103
+ ### Waiting for Events (Promise-Based)
104
+
105
+ ```typescript
106
+ // Block until an event fires
107
+ await feature.waitFor('ready')
108
+ console.log('Feature is now ready')
109
+
110
+ // Useful for initialization sequences
111
+ const server = container.server('express', { port: 3000 })
112
+ await server.start()
113
+ console.log('Server is accepting connections on port', server.state.get('port'))
114
+ ```
115
+
116
+ ### Container Events
117
+
118
+ The container emits events for lifecycle moments:
119
+
120
+ ```typescript
121
+ container.on('featureEnabled', (featureId, feature) => {
122
+ console.log(`Feature ${featureId} was enabled`)
123
+ })
124
+ ```
125
+
126
+ ## Patterns
127
+
128
+ ### Coordinating Between Features
129
+
130
+ ```typescript
131
+ const auth = container.feature('auth')
132
+ const analytics = container.feature('analytics')
133
+
134
+ // Analytics reacts to auth events
135
+ auth.on('userLoggedIn', (user) => {
136
+ analytics.logEvent('login', { userId: user.id })
137
+ })
138
+
139
+ auth.on('userLoggedOut', (user) => {
140
+ analytics.logEvent('logout', { userId: user.id })
141
+ })
142
+ ```
143
+
144
+ ### State-Driven UI Updates
145
+
146
+ ```typescript
147
+ const cart = container.feature('cart')
148
+
149
+ cart.state.observe((type, key, value) => {
150
+ if (key === 'items') {
151
+ renderCartBadge(value.length)
152
+ }
153
+ if (key === 'total') {
154
+ renderCartTotal(value)
155
+ }
156
+ })
157
+ ```
158
+
159
+ ### Initialization Gates
160
+
161
+ ```typescript
162
+ // Wait for multiple features to be ready
163
+ await Promise.all([
164
+ container.feature('db').waitFor('connected'),
165
+ container.feature('cache').waitFor('ready'),
166
+ container.feature('auth').waitFor('initialized'),
167
+ ])
168
+
169
+ console.log('All systems ready, starting server...')
170
+ await container.server('express', { port: 3000 }).start()
171
+ ```
@@ -0,0 +1,157 @@
1
+ ---
2
+ title: Servers
3
+ tags: [servers, express, websocket, start, stop, middleware, static]
4
+ ---
5
+
6
+ # Servers
7
+
8
+ Servers are helpers that listen for connections. Luca provides Express and WebSocket servers out of the box.
9
+
10
+ ## Express Server
11
+
12
+ ### Basic Setup
13
+
14
+ ```typescript
15
+ const server = container.server('express', {
16
+ port: 3000,
17
+ cors: true,
18
+ })
19
+
20
+ await server.start()
21
+ console.log('Listening on http://localhost:3000')
22
+ ```
23
+
24
+ ### With Endpoints
25
+
26
+ The most common pattern is file-based endpoints:
27
+
28
+ ```typescript
29
+ const server = container.server('express', { port: 3000, cors: true })
30
+
31
+ // Auto-discover and mount endpoint files
32
+ await server.useEndpoints('./endpoints')
33
+
34
+ // Generate OpenAPI spec
35
+ server.serveOpenAPISpec({
36
+ title: 'My API',
37
+ version: '1.0.0',
38
+ description: 'An awesome API built with Luca',
39
+ })
40
+
41
+ await server.start()
42
+ ```
43
+
44
+ ### Static Files
45
+
46
+ ```typescript
47
+ const server = container.server('express', {
48
+ port: 3000,
49
+ static: './public', // Serve files from public/ directory
50
+ })
51
+ ```
52
+
53
+ ### Port Auto-Discovery
54
+
55
+ If the requested port is taken, `configure()` can find an open one:
56
+
57
+ ```typescript
58
+ const server = container.server('express', { port: 3000 })
59
+ await server.configure() // Finds port 3000 or next available
60
+ await server.start()
61
+ console.log(`Listening on port ${server.state.get('port')}`)
62
+ ```
63
+
64
+ ### Server State
65
+
66
+ ```typescript
67
+ // After starting, check server state
68
+ await server.start()
69
+ server.state.get('listening') // true
70
+ server.state.get('port') // 3000
71
+
72
+ // Watch for state changes
73
+ server.state.observe((type, key, value) => {
74
+ if (key === 'listening' && value) {
75
+ console.log('Server is now listening')
76
+ }
77
+ })
78
+ ```
79
+
80
+ ### Accessing the Express App
81
+
82
+ For custom middleware or routes beyond file-based endpoints:
83
+
84
+ ```typescript
85
+ const server = container.server('express', { port: 3000 })
86
+
87
+ // Access the underlying express app
88
+ const app = server.app
89
+
90
+ app.use((req, res, next) => {
91
+ console.log(`${req.method} ${req.url}`)
92
+ next()
93
+ })
94
+
95
+ app.get('/custom', (req, res) => {
96
+ res.json({ message: 'Custom route' })
97
+ })
98
+
99
+ await server.start()
100
+ ```
101
+
102
+ ## WebSocket Server
103
+
104
+ ```typescript
105
+ const ws = container.server('websocket', { port: 8080 })
106
+
107
+ ws.on('connection', (socket) => {
108
+ console.log('Client connected')
109
+
110
+ socket.on('message', (data) => {
111
+ console.log('Received:', data)
112
+ socket.send(JSON.stringify({ echo: data }))
113
+ })
114
+ })
115
+
116
+ await ws.start()
117
+ ```
118
+
119
+ ## Combining Servers
120
+
121
+ Run HTTP and WebSocket together:
122
+
123
+ ```typescript
124
+ const http = container.server('express', { port: 3000 })
125
+ const ws = container.server('websocket', { port: 8080 })
126
+
127
+ await http.useEndpoints('./endpoints')
128
+
129
+ await Promise.all([
130
+ http.start(),
131
+ ws.start(),
132
+ ])
133
+
134
+ console.log('HTTP on :3000, WebSocket on :8080')
135
+ ```
136
+
137
+ ## Discovering Servers
138
+
139
+ ```typescript
140
+ container.servers.available // ['express', 'websocket']
141
+ container.servers.describe('express')
142
+ ```
143
+
144
+ ## The `luca serve` Command
145
+
146
+ For most projects, you don't need to set up the server manually. The built-in `luca serve` command does it for you:
147
+
148
+ ```bash
149
+ luca serve --port 3000
150
+ ```
151
+
152
+ It automatically:
153
+ - Finds your `endpoints/` directory
154
+ - Mounts all endpoint files
155
+ - Serves `public/` as static files
156
+ - Generates the OpenAPI spec
157
+ - Prints all routes
@@ -0,0 +1,198 @@
1
+ ---
2
+ title: Writing Endpoints
3
+ tags: [endpoints, routes, api, express, openapi, rest, http, server]
4
+ ---
5
+
6
+ # Writing Endpoints
7
+
8
+ Endpoints are file-based HTTP routes. Each file in your `endpoints/` directory becomes an API route. Luca auto-discovers them when you run `luca serve`.
9
+
10
+ ## Basic Endpoint
11
+
12
+ ```typescript
13
+ // endpoints/health.ts
14
+ export const path = '/health'
15
+ export const description = 'Health check endpoint'
16
+
17
+ export async function get() {
18
+ return { status: 'ok', uptime: process.uptime() }
19
+ }
20
+ ```
21
+
22
+ That's it. `luca serve` will mount `GET /health` and include it in the auto-generated OpenAPI spec.
23
+
24
+ ## Request Validation with Zod
25
+
26
+ Define schemas for your handlers. Parameters are validated automatically:
27
+
28
+ ```typescript
29
+ // endpoints/users.ts
30
+ import { z } from 'zod'
31
+ import type { EndpointContext } from '@soederpop/luca'
32
+
33
+ export const path = '/api/users'
34
+ export const description = 'User management'
35
+ export const tags = ['users']
36
+
37
+ // GET /api/users?role=admin&limit=10
38
+ export const getSchema = z.object({
39
+ role: z.string().optional().describe('Filter by role'),
40
+ limit: z.number().default(50).describe('Max results'),
41
+ })
42
+
43
+ export async function get(params: z.infer<typeof getSchema>, ctx: EndpointContext) {
44
+ // params.role and params.limit are validated and typed
45
+ return { users: [], total: 0 }
46
+ }
47
+
48
+ // POST /api/users
49
+ export const postSchema = z.object({
50
+ name: z.string().describe('Full name'),
51
+ email: z.string().email().describe('Email address'),
52
+ role: z.enum(['user', 'admin']).default('user').describe('User role'),
53
+ })
54
+
55
+ export async function post(params: z.infer<typeof postSchema>, ctx: EndpointContext) {
56
+ // params are validated
57
+ return { user: { id: '1', ...params }, message: 'User created' }
58
+ }
59
+ ```
60
+
61
+ ## URL Parameters
62
+
63
+ Use `:param` in the path or bracket-based file naming:
64
+
65
+ ```typescript
66
+ // endpoints/users/[id].ts
67
+ import { z } from 'zod'
68
+ import type { EndpointContext } from '@soederpop/luca'
69
+
70
+ export const path = '/api/users/:id'
71
+ export const description = 'Get, update, or delete a specific user'
72
+ export const tags = ['users']
73
+
74
+ export async function get(_params: any, ctx: EndpointContext) {
75
+ const { id } = ctx.params // From the URL
76
+ return { user: { id, name: 'Example' } }
77
+ }
78
+
79
+ export const putSchema = z.object({
80
+ name: z.string().optional(),
81
+ email: z.string().email().optional(),
82
+ })
83
+
84
+ export async function put(params: z.infer<typeof putSchema>, ctx: EndpointContext) {
85
+ const { id } = ctx.params
86
+ return { user: { id, ...params }, message: 'Updated' }
87
+ }
88
+
89
+ // Use a named const + re-export for delete (reserved word)
90
+ const del = async (_params: any, ctx: EndpointContext) => {
91
+ const { id } = ctx.params
92
+ return { message: `User ${id} deleted` }
93
+ }
94
+ export { del as delete }
95
+ ```
96
+
97
+ ## The EndpointContext
98
+
99
+ Every handler receives `(params, ctx)`. The context gives you access to:
100
+
101
+ ```typescript
102
+ export async function post(params: any, ctx: EndpointContext) {
103
+ const {
104
+ container, // The Luca container -- access any feature from here
105
+ request, // Express request object
106
+ response, // Express response object
107
+ query, // Parsed query string
108
+ body, // Parsed request body
109
+ params: urlParams, // URL parameters (:id, etc.)
110
+ } = ctx
111
+
112
+ // Use container features
113
+ const data = container.fs.readJson('./data/config.json')
114
+
115
+ return { success: true }
116
+ }
117
+ ```
118
+
119
+ ## Supported HTTP Methods
120
+
121
+ Export any of these handler functions:
122
+
123
+ - `get` -- GET requests
124
+ - `post` -- POST requests
125
+ - `put` -- PUT requests
126
+ - `patch` -- PATCH requests
127
+ - `delete` -- DELETE requests
128
+
129
+ Each can have a corresponding schema export: `getSchema`, `postSchema`, `putSchema`, `patchSchema`, `deleteSchema`.
130
+
131
+ ## What Gets Exported
132
+
133
+ | Export | Required | Description |
134
+ |--------|----------|-------------|
135
+ | `path` | Yes | The route path (e.g. `/api/users`, `/api/users/:id`) |
136
+ | `description` | No | Human-readable description (used in OpenAPI spec) |
137
+ | `tags` | No | Array of tags for OpenAPI grouping |
138
+ | `get`, `post`, etc. | At least one | Handler functions |
139
+ | `getSchema`, `postSchema`, etc. | No | Zod schemas for request validation |
140
+
141
+ ## Starting the Server
142
+
143
+ ```bash
144
+ # Default: looks for endpoints/ or src/endpoints/, serves on port 3000
145
+ luca serve
146
+
147
+ # Custom port and directories
148
+ luca serve --port 4000 --endpointsDir src/routes --staticDir public
149
+ ```
150
+
151
+ The server automatically:
152
+ - Discovers and mounts all endpoint files
153
+ - Generates an OpenAPI spec at `/openapi.json`
154
+ - Serves static files from `public/` if it exists
155
+ - Enables CORS by default
156
+ - Prints all mounted routes to the console
157
+
158
+ ## Programmatic Server Setup
159
+
160
+ You can also set up the server in a script:
161
+
162
+ ```typescript
163
+ import container from '@soederpop/luca'
164
+
165
+ const server = container.server('express', { port: 3000, cors: true })
166
+
167
+ await server.useEndpoints('./endpoints')
168
+
169
+ server.serveOpenAPISpec({
170
+ title: 'My API',
171
+ version: '1.0.0',
172
+ description: 'My awesome API',
173
+ })
174
+
175
+ await server.start()
176
+ console.log('Server running on http://localhost:3000')
177
+ ```
178
+
179
+ ## Streaming Responses
180
+
181
+ For endpoints that need to stream (e.g. AI responses), you can write directly to the response:
182
+
183
+ ```typescript
184
+ export const path = '/api/stream'
185
+
186
+ export async function post(params: any, ctx: EndpointContext) {
187
+ const { response } = ctx
188
+
189
+ response.setHeader('Content-Type', 'text/event-stream')
190
+ response.setHeader('Cache-Control', 'no-cache')
191
+
192
+ for (const chunk of data) {
193
+ response.write(`data: ${JSON.stringify(chunk)}\n\n`)
194
+ }
195
+
196
+ response.end()
197
+ }
198
+ ```
@@ -0,0 +1,171 @@
1
+ ---
2
+ title: Writing Commands
3
+ tags: [commands, cli, luca-cli, scripts, args]
4
+ ---
5
+
6
+ # Writing Commands
7
+
8
+ Commands are CLI actions that the `luca` command discovers and runs. Projects can define their own commands in a `commands/` directory at the project root.
9
+
10
+ ## Basic Command
11
+
12
+ ```typescript
13
+ // commands/seed.ts
14
+ import { z } from 'zod'
15
+ import type { ContainerContext } from '@soederpop/luca'
16
+
17
+ export const description = 'Seed the database with sample data'
18
+
19
+ export const argsSchema = z.object({
20
+ count: z.number().default(10).describe('Number of records to seed'),
21
+ table: z.string().optional().describe('Specific table to seed'),
22
+ })
23
+
24
+ export async function handler(options: z.infer<typeof argsSchema>, context: ContainerContext) {
25
+ const { container } = context
26
+
27
+ console.log(`Seeding ${options.count} records...`)
28
+
29
+ for (let i = 0; i < options.count; i++) {
30
+ console.log(` Created record ${i + 1}`)
31
+ }
32
+
33
+ console.log('Done.')
34
+ }
35
+ ```
36
+
37
+ Run it:
38
+
39
+ ```bash
40
+ luca seed --count 20 --table users
41
+ ```
42
+
43
+ ## How Discovery Works
44
+
45
+ When you run `luca <command>`, the CLI:
46
+
47
+ 1. Loads built-in commands (serve, run, etc.)
48
+ 2. Looks for a `commands/` directory in your project root
49
+ 3. Scans for `.ts` files and registers them as commands
50
+ 4. The filename becomes the command name: `commands/seed.ts` -> `luca seed`
51
+
52
+ ## Command File Structure
53
+
54
+ | Export | Required | Description |
55
+ |--------|----------|-------------|
56
+ | `handler` | Yes | Async function that runs the command |
57
+ | `argsSchema` | No | Zod schema defining accepted arguments |
58
+ | `description` | No | Help text for the command |
59
+
60
+ ## Arguments and the Schema
61
+
62
+ The `argsSchema` uses Zod to define what flags your command accepts. These are parsed from the command line automatically:
63
+
64
+ ```typescript
65
+ export const argsSchema = z.object({
66
+ // String flag: --name "John"
67
+ name: z.string().describe('User name'),
68
+
69
+ // Number flag: --port 3000
70
+ port: z.number().default(3000).describe('Port number'),
71
+
72
+ // Boolean flag: --verbose
73
+ verbose: z.boolean().default(false).describe('Enable verbose logging'),
74
+
75
+ // Optional flag: --output file.json
76
+ output: z.string().optional().describe('Output file path'),
77
+
78
+ // Enum flag: --format json
79
+ format: z.enum(['json', 'csv', 'table']).default('table').describe('Output format'),
80
+ })
81
+ ```
82
+
83
+ ## Using the Container in Commands
84
+
85
+ Commands receive a context with the full container:
86
+
87
+ ```typescript
88
+ export async function handler(options: any, context: ContainerContext) {
89
+ const { container } = context
90
+
91
+ // File system operations
92
+ const config = container.fs.readJson('./config.json')
93
+
94
+ // Git info (these are getters, not methods)
95
+ const branch = container.git.branch
96
+ const sha = container.git.sha
97
+
98
+ // Terminal UI
99
+ container.ui.colors.green('Success!')
100
+
101
+ // Run external processes (synchronous, returns string)
102
+ const result = container.proc.exec('ls -la')
103
+
104
+ // Use any feature
105
+ const cache = container.feature('diskCache', { path: './.cache' })
106
+ }
107
+ ```
108
+
109
+ ## Examples
110
+
111
+ ### Database Migration Command
112
+
113
+ ```typescript
114
+ // commands/migrate.ts
115
+ import { z } from 'zod'
116
+ import type { ContainerContext } from '@soederpop/luca'
117
+
118
+ export const description = 'Run database migrations'
119
+
120
+ export const argsSchema = z.object({
121
+ direction: z.enum(['up', 'down']).default('up').describe('Migration direction'),
122
+ steps: z.number().default(1).describe('Number of migrations to run'),
123
+ })
124
+
125
+ export async function handler(options: z.infer<typeof argsSchema>, context: ContainerContext) {
126
+ const { container } = context
127
+ const { files } = container.fs.walk('./migrations', { include: ['*.sql'] })
128
+
129
+ console.log(`Running ${options.steps} migration(s) ${options.direction}...`)
130
+
131
+ for (const file of files.slice(0, options.steps)) {
132
+ console.log(` Applying: ${file}`)
133
+ const sql = container.fs.readFile(file)
134
+ // ... execute sql
135
+ }
136
+
137
+ console.log('Migrations complete.')
138
+ }
139
+ ```
140
+
141
+ ### Deploy Command
142
+
143
+ ```typescript
144
+ // commands/deploy.ts
145
+ import { z } from 'zod'
146
+ import type { ContainerContext } from '@soederpop/luca'
147
+
148
+ export const description = 'Deploy the application'
149
+
150
+ export const argsSchema = z.object({
151
+ env: z.enum(['staging', 'production']).describe('Target environment'),
152
+ dryRun: z.boolean().default(false).describe('Preview without deploying'),
153
+ })
154
+
155
+ export async function handler(options: z.infer<typeof argsSchema>, context: ContainerContext) {
156
+ const { container } = context
157
+
158
+ if (options.dryRun) {
159
+ console.log(`[DRY RUN] Would deploy to ${options.env}`)
160
+ return
161
+ }
162
+
163
+ const sha = container.git.sha
164
+ console.log(`Deploying ${sha} to ${options.env}...`)
165
+
166
+ container.proc.exec('bun run build')
167
+ // ... deployment logic
168
+
169
+ console.log('Deployed successfully.')
170
+ }
171
+ ```