@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,154 @@
1
+ import { z } from 'zod'
2
+ import type { ContainerContext } from '@soederpop/luca'
3
+ import { CommandOptionsSchema } from '@soederpop/luca/schemas'
4
+
5
+ export const argsSchema = CommandOptionsSchema.extend({})
6
+
7
+ interface ScaffoldSection {
8
+ heading: string
9
+ code: string
10
+ }
11
+
12
+ interface ScaffoldData {
13
+ sections: ScaffoldSection[]
14
+ full: string
15
+ tutorial: string
16
+ }
17
+
18
+ /**
19
+ * Parse a markdown file to extract code blocks grouped by their nearest heading.
20
+ * Also extracts the "Complete Example" code block as the `full` template.
21
+ */
22
+ function parseScaffoldMarkdown(content: string): ScaffoldData {
23
+ const sections: ScaffoldSection[] = []
24
+ let full = ''
25
+
26
+ let currentHeading = ''
27
+ const lines = content.split('\n')
28
+ let inCodeBlock = false
29
+ let codeBlockLang = ''
30
+ let codeBlockLines: string[] = []
31
+
32
+ for (const line of lines) {
33
+ // Track headings
34
+ const headingMatch = line.match(/^##\s+(.+)/)
35
+ if (headingMatch && !inCodeBlock) {
36
+ currentHeading = headingMatch[1].trim()
37
+ continue
38
+ }
39
+
40
+ // Track code fences
41
+ const fenceMatch = line.match(/^```(\w*)/)
42
+ if (fenceMatch && !inCodeBlock) {
43
+ inCodeBlock = true
44
+ codeBlockLang = fenceMatch[1] || ''
45
+ codeBlockLines = []
46
+ continue
47
+ }
48
+
49
+ if (line.startsWith('```') && inCodeBlock) {
50
+ inCodeBlock = false
51
+ const code = codeBlockLines.join('\n')
52
+
53
+ // Only collect ts/js code blocks
54
+ if (codeBlockLang === 'ts' || codeBlockLang === 'typescript' || codeBlockLang === 'js') {
55
+ sections.push({ heading: currentHeading, code })
56
+
57
+ if (currentHeading === 'Complete Example') {
58
+ full = code
59
+ }
60
+ }
61
+ continue
62
+ }
63
+
64
+ if (inCodeBlock) {
65
+ codeBlockLines.push(line)
66
+ }
67
+ }
68
+
69
+ return { sections, full, tutorial: content }
70
+ }
71
+
72
+ async function buildScaffolds(options: z.infer<typeof argsSchema>, context: ContainerContext) {
73
+ const container = context.container as any
74
+ const fs = container.feature('fs')
75
+
76
+ const scaffoldDir = 'docs/scaffolds'
77
+ const readmePath = 'docs/mcp/readme.md'
78
+ const outputPath = 'src/scaffolds/generated.ts'
79
+
80
+ const types = ['feature', 'client', 'server', 'command', 'endpoint']
81
+ const scaffolds: Record<string, ScaffoldData> = {}
82
+
83
+ for (const type of types) {
84
+ const filePath = `${scaffoldDir}/${type}.md`
85
+ if (!fs.exists(filePath)) {
86
+ console.log(` ⏭ ${filePath} (not found, skipping)`)
87
+ continue
88
+ }
89
+
90
+ const content = fs.readFile(filePath)
91
+ scaffolds[type] = parseScaffoldMarkdown(content)
92
+ console.log(` 📄 ${type}: ${scaffolds[type].sections.length} sections, full template: ${scaffolds[type].full ? 'yes' : 'no'}`)
93
+ }
94
+
95
+ // Read the MCP readme
96
+ let mcpReadme = ''
97
+ if (fs.exists(readmePath)) {
98
+ mcpReadme = fs.readFile(readmePath)
99
+ console.log(` 📄 MCP readme: ${mcpReadme.length} chars`)
100
+ } else {
101
+ console.log(` ⚠️ ${readmePath} not found`)
102
+ }
103
+
104
+ // Generate the output file
105
+ const escapeForTemplate = (s: string) => s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${')
106
+
107
+ const scaffoldEntries = Object.entries(scaffolds).map(([type, data]) => {
108
+ const sectionsStr = data.sections.map(s =>
109
+ ` { heading: ${JSON.stringify(s.heading)}, code: \`${escapeForTemplate(s.code)}\` }`
110
+ ).join(',\n')
111
+
112
+ return ` ${type}: {
113
+ sections: [
114
+ ${sectionsStr}
115
+ ],
116
+ full: \`${escapeForTemplate(data.full)}\`,
117
+ tutorial: \`${escapeForTemplate(data.tutorial)}\`,
118
+ }`
119
+ }).join(',\n')
120
+
121
+ const output = `// Auto-generated scaffold and MCP readme content
122
+ // Generated at: ${new Date().toISOString()}
123
+ // Source: docs/scaffolds/*.md and docs/mcp/readme.md
124
+ //
125
+ // Do not edit manually. Run: luca build-scaffolds
126
+
127
+ export interface ScaffoldSection {
128
+ heading: string
129
+ code: string
130
+ }
131
+
132
+ export interface ScaffoldData {
133
+ sections: ScaffoldSection[]
134
+ full: string
135
+ tutorial: string
136
+ }
137
+
138
+ export const scaffolds: Record<string, ScaffoldData> = {
139
+ ${scaffoldEntries}
140
+ }
141
+
142
+ export const mcpReadme = \`${escapeForTemplate(mcpReadme)}\`
143
+ `
144
+
145
+ fs.ensureFolder('src/scaffolds')
146
+ await fs.writeFileAsync(outputPath, output)
147
+ console.log(`\n✨ Generated ${outputPath}`)
148
+ }
149
+
150
+ export default {
151
+ description: 'Generate scaffold templates and MCP readme from docs/scaffolds/*.md',
152
+ argsSchema,
153
+ handler: buildScaffolds,
154
+ }
@@ -0,0 +1,114 @@
1
+ import { z } from 'zod'
2
+ import type { ContainerContext } from '@soederpop/luca'
3
+ import { CommandOptionsSchema } from '@soederpop/luca/schemas'
4
+ import { AGIContainer } from '../src/agi/container.server.js'
5
+ import { __INTROSPECTION__ } from '../src/introspection/index.js'
6
+ import { presentIntrospectionAsMarkdown } from '../src/helper.js'
7
+
8
+ export const argsSchema = CommandOptionsSchema.extend({
9
+ clean: z.boolean().default(false).describe('Remove existing docs/apis folder before generating'),
10
+ })
11
+
12
+ /** Parse setBuildTimeData shortcut IDs from a generated introspection file */
13
+ function parseGeneratedIds(content: string): { features: string[]; servers: string[]; clients: string[] } {
14
+ const features: string[] = []
15
+ const servers: string[] = []
16
+ const clients: string[] = []
17
+
18
+ for (const match of content.matchAll(/setBuildTimeData\('([^']+)'/g)) {
19
+ const id = match[1]
20
+ if (id.startsWith('features.')) features.push(id.replace('features.', ''))
21
+ else if (id.startsWith('servers.')) servers.push(id.replace('servers.', ''))
22
+ else if (id.startsWith('clients.')) clients.push(id.replace('clients.', ''))
23
+ }
24
+
25
+ return { features, servers, clients }
26
+ }
27
+
28
+ async function generateApiDocs(options: z.infer<typeof argsSchema>, context: ContainerContext) {
29
+ const fs = context.container.feature('fs')
30
+ const baseDir = 'docs/apis'
31
+
32
+ if (options.clean) {
33
+ try { await fs.rmdir(baseDir) } catch {}
34
+ }
35
+
36
+ // Parse the generated introspection files to determine which helpers belong to which container
37
+ const nodeContent = fs.readFile('src/introspection/generated.node.ts')
38
+ const agiContent = fs.readFile('src/introspection/generated.agi.ts')
39
+ const webContent = fs.readFile('src/introspection/generated.web.ts')
40
+
41
+ const nodeIds = parseGeneratedIds(nodeContent)
42
+ const agiIds = parseGeneratedIds(agiContent)
43
+ const webIds = parseGeneratedIds(webContent)
44
+
45
+ // AGI-only features = features in agi that aren't in node
46
+ const nodeFeatureSet = new Set(nodeIds.features)
47
+ const agiOnlyFeatures = agiIds.features.filter(f => !nodeFeatureSet.has(f))
48
+
49
+ // Load web build-time data so __INTROSPECTION__ has web entries
50
+ await import('../src/introspection/generated.web.js')
51
+
52
+ // Use AGIContainer for rendering — it has all node+agi registries loaded
53
+ const agiContainer = new AGIContainer()
54
+
55
+ const groups: { dir: string; registryName: string; ids: string[] }[] = [
56
+ { dir: `${baseDir}/features/node`, registryName: 'features', ids: nodeIds.features },
57
+ { dir: `${baseDir}/features/agi`, registryName: 'features', ids: agiOnlyFeatures },
58
+ { dir: `${baseDir}/features/web`, registryName: 'features', ids: webIds.features },
59
+ { dir: `${baseDir}/servers`, registryName: 'servers', ids: agiIds.servers },
60
+ // Clients are registered at runtime, not in generated files — use live registry
61
+ { dir: `${baseDir}/clients`, registryName: 'clients', ids: agiContainer.clients.available },
62
+ ]
63
+
64
+ let totalFiles = 0
65
+
66
+ for (const group of groups) {
67
+ fs.ensureFolder(group.dir)
68
+ console.log(`\n📁 ${group.dir}`)
69
+
70
+ const registry = (agiContainer as any)[group.registryName]
71
+
72
+ for (const id of group.ids) {
73
+ try {
74
+ let markdown: string | undefined
75
+
76
+ if (registry.has(id)) {
77
+ markdown = registry.describe(id)
78
+ } else {
79
+ // Fallback: render from __INTROSPECTION__ map directly (e.g. web-only features)
80
+ const introspectionKey = `${group.registryName}.${id}`
81
+ const data = __INTROSPECTION__.get(introspectionKey)
82
+ if (data) {
83
+ markdown = presentIntrospectionAsMarkdown(data)
84
+ }
85
+ }
86
+
87
+ if (!markdown || !markdown.trim()) {
88
+ console.log(` ⏭ ${id} (no introspection data)`)
89
+ continue
90
+ }
91
+
92
+ const fileName = toKebab(id) + '.md'
93
+ await fs.writeFileAsync(`${group.dir}/${fileName}`, markdown)
94
+ console.log(` 📄 ${fileName}`)
95
+ totalFiles++
96
+ } catch (err: any) {
97
+ console.log(` ⚠️ ${id}: ${err.message}`)
98
+ }
99
+ }
100
+ }
101
+
102
+ console.log(`\n✨ Generated ${totalFiles} API docs in ${baseDir}/`)
103
+ }
104
+
105
+ /** Convert camelCase shortcut to kebab-case filename */
106
+ function toKebab(str: string): string {
107
+ return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
108
+ }
109
+
110
+ export default {
111
+ description: 'Generate API reference docs from introspection data for all registries.',
112
+ argsSchema,
113
+ handler: generateApiDocs,
114
+ }
@@ -0,0 +1,67 @@
1
+ import { z } from 'zod'
2
+ import type { ContainerContext } from '@soederpop/luca'
3
+ import { CommandOptionsSchema } from '@soederpop/luca/schemas'
4
+ import '../src/introspection/scan.js'
5
+ import { NodeContainer } from '../src/node/container.js'
6
+
7
+ export const argsSchema = CommandOptionsSchema.extend({})
8
+
9
+ const targets = [
10
+ {
11
+ name: 'node',
12
+ src: ['src/node/features', 'src/servers', 'src/container.ts', 'src/node/container.ts'],
13
+ outputPath: 'src/introspection/generated.node.ts',
14
+ },
15
+ {
16
+ name: 'web',
17
+ src: ['src/web/features', 'src/container.ts', 'src/web/container.ts'],
18
+ outputPath: 'src/introspection/generated.web.ts',
19
+ },
20
+ {
21
+ name: 'agi',
22
+ src: ['src/node/features', 'src/servers', 'src/agi/features', 'src/container.ts', 'src/node/container.ts', 'src/agi/container.server.ts'],
23
+ outputPath: 'src/introspection/generated.agi.ts',
24
+ },
25
+ ]
26
+
27
+ /**
28
+ * Generates per-container introspection metadata files.
29
+ *
30
+ * Each container type gets its own generated file containing only the
31
+ * metadata relevant to that environment:
32
+ *
33
+ * - generated.node.ts: node features + servers
34
+ * - generated.web.ts: web features
35
+ * - generated.agi.ts: node features + servers + agi features
36
+ */
37
+ async function updateIntrospection(options: z.infer<typeof argsSchema>, context: ContainerContext) {
38
+ const container = new NodeContainer()
39
+
40
+ for (const target of targets) {
41
+ console.log(`\n📦 Generating ${target.name} introspection data...`)
42
+ console.log(` 📁 Sources: ${target.src.join(', ')}`)
43
+ console.log(` 📄 Output: ${target.outputPath}`)
44
+
45
+ const scanner = container.feature('introspectionScanner', {
46
+ src: target.src,
47
+ outputPath: target.outputPath,
48
+ })
49
+
50
+ scanner.on('scanCompleted', (data) => {
51
+ console.log(` ✅ Found ${data.results} helpers in ${data.files} files (${data.duration}ms)`)
52
+ })
53
+
54
+ await scanner.scan()
55
+ await scanner.generateRegistryScript()
56
+
57
+ console.log(` 📝 Wrote ${target.outputPath}`)
58
+ }
59
+
60
+ console.log('\n✨ All introspection data generated.')
61
+ }
62
+
63
+ export default {
64
+ description: 'Generate per-container introspection metadata files from source.',
65
+ argsSchema,
66
+ handler: updateIntrospection,
67
+ }
package/docs/CLI.md ADDED
@@ -0,0 +1,335 @@
1
+ # Luca CLI
2
+
3
+ The `luca` command-line interface provides commands for running scripts, starting servers, inspecting the container, and interacting with AI assistants.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ luca <command|file> [options]
9
+ ```
10
+
11
+ When given a file path instead of a command name, luca delegates to `run` automatically.
12
+
13
+ ---
14
+
15
+ ## Commands
16
+
17
+ ### help
18
+
19
+ Show help for luca commands.
20
+
21
+ ```
22
+ luca help [command]
23
+ ```
24
+
25
+ With no arguments, displays the full command list. Pass a command name to see its detailed usage.
26
+
27
+ ---
28
+
29
+ ### run
30
+
31
+ Run a script or markdown file (.ts, .js, .md).
32
+
33
+ ```
34
+ luca run <file> [options]
35
+ ```
36
+
37
+ Resolves the file by trying the path as-is, then appending `.ts`, `.js`, `.md` in order. Markdown files are executed block-by-block with the container in scope. TypeScript and JavaScript files are run as standalone scripts via `proc.runScript`.
38
+
39
+ | Flag | Type | Default | Description |
40
+ |------|------|---------|-------------|
41
+ | `--safe` | boolean | `false` | Require approval before each code block (markdown mode) |
42
+ | `--console` | boolean | `false` | Start an interactive REPL after executing a markdown file, with all accumulated context |
43
+
44
+ ---
45
+
46
+ ### serve
47
+
48
+ Start the API server with file-based endpoints.
49
+
50
+ ```
51
+ luca serve [options]
52
+ ```
53
+
54
+ Discovers endpoints from `endpoints/` or `src/endpoints/`, serves static files from `public/` or the current directory (if `index.html` exists), and starts an Express server.
55
+
56
+ | Flag | Type | Default | Description |
57
+ |------|------|---------|-------------|
58
+ | `--port` | number | `3000` | Port to listen on |
59
+ | `--endpoints-dir` | string | auto | Directory to load endpoints from |
60
+ | `--static-dir` | string | auto | Directory to serve static files from |
61
+ | `--setup` | string | | Path to a TS module whose default export receives the server instance |
62
+ | `--cors` | boolean | `true` | Enable CORS |
63
+ | `--force` | boolean | `false` | Kill any process currently using the target port |
64
+ | `--any-port` | boolean | `false` | Find an available port starting above 3000 |
65
+ | `--open` | boolean | `true` | Open the server URL in Google Chrome |
66
+
67
+ #### Setup scripts
68
+
69
+ The `--setup` flag lets you customize the Express server before it starts. The module is loaded through the VM, so `container` and all features are in the global scope. The default export receives the server helper instance.
70
+
71
+ ```ts
72
+ // setup.ts
73
+ export default function (server) {
74
+ const app = server.app
75
+
76
+ app.use('/webhook', (req, res) => {
77
+ res.json({ ok: true })
78
+ })
79
+
80
+ app.get('/health', (req, res) => {
81
+ res.json({ status: 'healthy' })
82
+ })
83
+ }
84
+ ```
85
+
86
+ ```
87
+ luca serve --setup setup.ts
88
+ ```
89
+
90
+ ---
91
+
92
+ ### eval
93
+
94
+ Evaluate a JavaScript/TypeScript expression with the container in scope.
95
+
96
+ ```
97
+ luca eval "<code>" [options]
98
+ ```
99
+
100
+ All enabled features are available as top-level variables in the evaluation context.
101
+
102
+ | Flag | Type | Default | Description |
103
+ |------|------|---------|-------------|
104
+ | `--json` | boolean | `false` | Serialize output as JSON |
105
+
106
+ **Examples:**
107
+
108
+ ```
109
+ luca eval "container.features.available"
110
+ luca eval "fs.readdir('src')" --json
111
+ luca eval "networking.isPortOpen(3000)"
112
+ ```
113
+
114
+ ---
115
+
116
+ ### console
117
+
118
+ Start an interactive REPL with all container features in scope.
119
+
120
+ ```
121
+ luca console
122
+ ```
123
+
124
+ All registered features are instantiated and available as top-level variables. If a `luca.console.ts` file exists in the project root, its exports are merged into the REPL scope.
125
+
126
+ ---
127
+
128
+ ### describe
129
+
130
+ Describe the container, registries, or individual helpers.
131
+
132
+ ```
133
+ luca describe [target...] [options]
134
+ ```
135
+
136
+ Targets can be:
137
+ - Nothing — shows command usage
138
+ - `container` — full container introspection
139
+ - A registry name: `features`, `clients`, `servers`, `commands`, `endpoints`
140
+ - A helper name: `fs`, `express`, `rest`, etc. (fuzzy-matched across registries)
141
+ - A qualified name: `features.fs`, `servers.express`
142
+
143
+ | Flag | Type | Default | Description |
144
+ |------|------|---------|-------------|
145
+ | `--json` | boolean | `false` | Output introspection data as JSON instead of markdown |
146
+ | `--pretty` | boolean | `false` | Render markdown with terminal styling |
147
+ | `--no-title` | boolean | `false` | Omit the title header from output |
148
+ | `--description` | boolean | `false` | Show the description section |
149
+ | `--usage` | boolean | `false` | Show the usage section |
150
+ | `--methods` | boolean | `false` | Show the methods section |
151
+ | `--getters` | boolean | `false` | Show the getters section |
152
+ | `--events` | boolean | `false` | Show the events section |
153
+ | `--state` | boolean | `false` | Show the state section |
154
+ | `--options` | boolean | `false` | Show the options section |
155
+ | `--env-vars` | boolean | `false` | Show the envVars section |
156
+ | `--examples` | boolean | `false` | Show the examples section |
157
+
158
+ Section flags can be combined. When none are specified, all sections are shown.
159
+
160
+ **Examples:**
161
+
162
+ ```
163
+ luca describe fs
164
+ luca describe servers
165
+ luca describe features.vm --methods --pretty
166
+ luca describe rest websocket --json
167
+ ```
168
+
169
+ ---
170
+
171
+ ### chat
172
+
173
+ Start an interactive chat session with a local assistant.
174
+
175
+ ```
176
+ luca chat [name] [options]
177
+ ```
178
+
179
+ Discovers assistants from the configured folder (default `assistants/`). If multiple assistants are found and no name is given, prompts for selection.
180
+
181
+ Conversations are persisted by default using `daily` mode — the same conversation is automatically resumed throughout the day. On exit, a resume instruction is printed so you can return to any session later.
182
+
183
+ | Flag | Type | Default | Description |
184
+ |------|------|---------|-------------|
185
+ | `--model` | string | | Override the LLM model for the assistant |
186
+ | `--folder` | string | `assistants` | Directory containing assistant definitions |
187
+ | `--history-mode` | `lifecycle` \| `daily` \| `persistent` \| `session` | `daily` | Conversation persistence mode |
188
+ | `--resume` | string | | Thread ID to resume a specific conversation |
189
+ | `--list` | boolean | `false` | List recent conversations and exit |
190
+ | `--off-record` | boolean | `false` | Alias for `--history-mode lifecycle` (ephemeral, no persistence) |
191
+
192
+ #### History modes
193
+
194
+ - **lifecycle** — Ephemeral. No persistence, fresh conversation every time (the pre-existing behavior).
195
+ - **daily** — Auto-resumes today's conversation. New conversation each day. Auto-compacts when nearing context limits. This is the default for `luca chat`.
196
+ - **persistent** — Single long-running thread per assistant+project. Auto-compacts.
197
+ - **session** — Unique thread per invocation, but resumable via `--resume`.
198
+
199
+ #### Resuming conversations
200
+
201
+ On exit, non-ephemeral sessions print a resume command:
202
+
203
+ ```
204
+ Session saved. To resume this conversation:
205
+ luca chat my-assistant --resume my-assistant:a1b2c3d4:2026-03-02
206
+ ```
207
+
208
+ Use `--list` to browse recent conversations:
209
+
210
+ ```
211
+ luca chat my-assistant --list
212
+ ```
213
+
214
+ ---
215
+
216
+ ### prompt
217
+
218
+ Send a prompt file to an assistant, Claude Code, or OpenAI Codex and stream the response.
219
+
220
+ ```
221
+ luca prompt <target> <path/to/prompt.md> [options]
222
+ ```
223
+
224
+ The target can be:
225
+ - `claude` — runs the prompt through the Claude Code CLI
226
+ - `codex` — runs the prompt through the OpenAI Codex CLI
227
+ - Any other name — looks up a local assistant via `assistantsManager`
228
+
229
+ The prompt file is read as plain text and sent in full. Output streams to stdout as it arrives.
230
+
231
+ | Flag | Type | Default | Description |
232
+ |------|------|---------|-------------|
233
+ | `--model` | string | | Override the LLM model (assistant mode only) |
234
+ | `--folder` | string | `assistants` | Directory containing assistant definitions |
235
+
236
+ **Examples:**
237
+
238
+ ```
239
+ luca prompt claude prompts/refactor.md
240
+ luca prompt codex prompts/add-tests.md
241
+ luca prompt my-assistant prompts/summarize.md --model gpt-4o
242
+ ```
243
+
244
+ ---
245
+
246
+ ### mcp
247
+
248
+ Start an MCP (Model Context Protocol) server.
249
+
250
+ ```
251
+ luca mcp [options]
252
+ ```
253
+
254
+ Starts an MCP server that exposes the project's endpoints and tools to MCP-compatible clients.
255
+
256
+ | Flag | Type | Default | Description |
257
+ |------|------|---------|-------------|
258
+ | `--transport` | `stdio` \| `http` | `stdio` | Transport type |
259
+ | `--port` | number | `3001` | Port for HTTP transport |
260
+ | `--name` | string | auto | Server name reported to MCP clients |
261
+ | `--version` | string | auto | Server version reported to MCP clients |
262
+
263
+ ---
264
+
265
+ ### sandbox-mcp
266
+
267
+ Start an MCP server with a Luca container sandbox for AI agents to explore and test code.
268
+
269
+ ```
270
+ luca sandbox-mcp [options]
271
+ ```
272
+
273
+ Provides tools (`eval`, `inspect_container`, `list_registry`, `describe_helper`, `inspect_helper_instance`), prompts (`discover`, `introspect`), and resources (`luca://container/info`, `luca://features`) for AI agents to interact with the container.
274
+
275
+ | Flag | Type | Default | Description |
276
+ |------|------|---------|-------------|
277
+ | `--transport` | `stdio` \| `http` | `stdio` | Transport type |
278
+ | `--port` | number | `3002` | Port for HTTP transport |
279
+
280
+ #### Codex CLI stdio timeout workaround
281
+
282
+ If OpenAI Codex CLI reports `MCP client ... timed out after 10 seconds` for `luca_sandbox` or `contentbase`, and the same command starts fine manually, use a Node stdio bridge to launch Bun.
283
+
284
+ Create a small bridge script:
285
+
286
+ ```sh
287
+ mkdir -p ~/.codex/bin
288
+ cat > ~/.codex/bin/mcp-stdio-bridge.js <<'EOF'
289
+ #!/usr/bin/env node
290
+ const { spawn } = require('node:child_process')
291
+
292
+ const [cmd, ...args] = process.argv.slice(2)
293
+ if (!cmd) process.exit(2)
294
+
295
+ const child = spawn(cmd, args, { stdio: ['pipe', 'pipe', 'pipe'] })
296
+ process.stdin.on('data', (chunk) => child.stdin.write(chunk))
297
+ process.stdin.on('end', () => child.stdin.end())
298
+ process.stdin.on('error', () => child.stdin.end())
299
+ child.stdout.on('data', (chunk) => process.stdout.write(chunk))
300
+ child.stderr.on('data', (chunk) => process.stderr.write(chunk))
301
+ child.on('exit', (code, signal) => {
302
+ if (signal) process.kill(process.pid, signal)
303
+ process.exit(code ?? 0)
304
+ })
305
+ EOF
306
+ chmod +x ~/.codex/bin/mcp-stdio-bridge.js
307
+ ```
308
+
309
+ Then wire Codex MCP servers through the bridge:
310
+
311
+ ```toml
312
+ [mcp_servers.luca_sandbox]
313
+ command = "node"
314
+ args = ["/Users/<you>/.codex/bin/mcp-stdio-bridge.js", "/Users/<you>/.bun/bin/bun", "/absolute/path/to/luca/src/cli/cli.ts", "sandbox-mcp", "--transport", "stdio"]
315
+ cwd = "/absolute/path/to/project"
316
+ enabled = true
317
+ startup_timeout_sec = 30
318
+
319
+ [mcp_servers.contentbase]
320
+ command = "node"
321
+ args = ["/Users/<you>/.codex/bin/mcp-stdio-bridge.js", "/Users/<you>/.bun/bin/bun", "/absolute/path/to/contentbase/src/cli/index.ts", "mcp", "--transport", "stdio"]
322
+ cwd = "/absolute/path/to/project"
323
+ enabled = true
324
+ startup_timeout_sec = 30
325
+ ```
326
+
327
+ Notes:
328
+ - Prefer absolute paths in `args`.
329
+ - Avoid `bun run ...` here; pass the script path directly to Bun.
330
+
331
+ ---
332
+
333
+ ## Project Commands
334
+
335
+ Any `commands/` folder in a project (or `~/.luca/commands/` globally) extends the CLI. For example, a file `commands/deploy.ts` becomes `luca deploy`. These modules are loaded through the VM and have full container access.