@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,116 @@
1
+ import { z } from 'zod'
2
+ import { inspect } from 'util'
3
+ import { commands } from '../command.js'
4
+ import { CommandOptionsSchema } from '../schemas/base.js'
5
+ import type { ContainerContext } from '../container.js'
6
+
7
+ declare module '../command.js' {
8
+ interface AvailableCommands {
9
+ eval: ReturnType<typeof commands.registerHandler>
10
+ }
11
+ }
12
+
13
+ export const argsSchema = CommandOptionsSchema.extend({
14
+ json: z.boolean().default(false).describe('Serialize output as JSON'),
15
+ enable: z.string().optional().describe('Enable a feature before evaluating (e.g. --enable diskCache)'),
16
+ })
17
+
18
+ export default async function evalCommand(options: z.infer<typeof argsSchema>, context: ContainerContext) {
19
+ const container = context.container as any
20
+
21
+ container.addContext('feature', (...args: any) => container.feature(...args))
22
+
23
+ await container.helpers.discoverAll()
24
+
25
+ const args = container.argv._ as string[]
26
+ // args[0] is "eval", the rest is the code snippet
27
+ const code = args.slice(1).join(' ')
28
+
29
+ if (!code.trim()) {
30
+ console.error('Usage: luca eval "<code>" [--json]')
31
+ return
32
+ }
33
+
34
+ const vm = container.feature('vm')
35
+
36
+ // HACK
37
+ Array(container.argv.enable).map((id) => {
38
+ container.feature(id, { ...container.argv, enable: true }).enable()
39
+ })
40
+
41
+ // Build context with container and all enabled feature instances
42
+ const ctx: Record<string, any> = { container }
43
+ for (const [name, instance] of Object.entries(container.enabledFeatures ?? {})) {
44
+ ctx[name] = instance
45
+ }
46
+
47
+ const result = await vm.run(code, ctx)
48
+
49
+ if (options.json) {
50
+ console.log(JSON.stringify(result, null, 2))
51
+ } else {
52
+ displayResult(result)
53
+ }
54
+ }
55
+
56
+ const BUILTIN_TYPES = new Set(['Object', 'Array', 'Map', 'Set', 'Date', 'RegExp', 'Promise', 'Error', 'Number', 'String', 'Boolean'])
57
+
58
+ export function displayResult(value: any) {
59
+ if (typeof value !== 'object' || value === null) {
60
+ console.log(value)
61
+ return
62
+ }
63
+
64
+ const hasCustomInspect = typeof value[Symbol.for('nodejs.util.inspect.custom')] === 'function'
65
+ const ctorName = value.constructor?.name
66
+ const isClassInstance = ctorName && !BUILTIN_TYPES.has(ctorName)
67
+
68
+ // Objects with custom inspect or builtins: use standard inspect
69
+ if (hasCustomInspect || !isClassInstance) {
70
+ console.log(inspect(value, { colors: true, depth: 4 }))
71
+ return
72
+ }
73
+
74
+ // Class instances: show clean data (no _ props, no functions)
75
+ const data: Record<string, any> = {}
76
+ for (const [k, v] of Object.entries(value)) {
77
+ if (k.startsWith('_') || typeof v === 'function') continue
78
+ data[k] = v
79
+ }
80
+ const body = inspect(data, { colors: true, depth: 3 })
81
+ console.log(`${ctorName} ${body}`)
82
+
83
+ // Collect methods and getters from own + prototype chain
84
+ const methods: string[] = []
85
+ const getters: string[] = []
86
+
87
+ for (const [k, v] of Object.entries(value)) {
88
+ if (k.startsWith('_')) continue
89
+ if (typeof v === 'function') methods.push(k)
90
+ }
91
+
92
+ let proto = Object.getPrototypeOf(value)
93
+ while (proto && proto !== Object.prototype) {
94
+ for (const k of Object.getOwnPropertyNames(proto)) {
95
+ if (k === 'constructor' || k.startsWith('_')) continue
96
+ const desc = Object.getOwnPropertyDescriptor(proto, k)
97
+ if (!desc) continue
98
+ if (desc.get && !getters.includes(k)) getters.push(k)
99
+ else if (typeof desc.value === 'function' && !methods.includes(k)) methods.push(k)
100
+ }
101
+ proto = Object.getPrototypeOf(proto)
102
+ }
103
+
104
+ if (getters.length || methods.length) {
105
+ const parts: string[] = []
106
+ if (getters.length) parts.push(` \x1b[36mgetters:\x1b[0m ${getters.sort().join(', ')}`)
107
+ if (methods.length) parts.push(` \x1b[36mmethods:\x1b[0m ${methods.sort().map(m => m + '()').join(', ')}`)
108
+ console.log(parts.join('\n'))
109
+ }
110
+ }
111
+
112
+ commands.registerHandler('eval', {
113
+ description: 'Evaluate a JavaScript/TypeScript expression with the container in scope',
114
+ argsSchema,
115
+ handler: evalCommand,
116
+ })
@@ -0,0 +1,214 @@
1
+ import { z } from 'zod'
2
+ import { commands } from '../command.js'
3
+ import { CommandOptionsSchema } from '../schemas/base.js'
4
+ import type { ContainerContext } from '../container.js'
5
+
6
+ declare module '../command.js' {
7
+ interface AvailableCommands {
8
+ help: ReturnType<typeof commands.registerHandler>
9
+ }
10
+ }
11
+
12
+ export const argsSchema = CommandOptionsSchema.extend({})
13
+
14
+ /** Hidden option prefixes — legacy aliases that shouldn't clutter help output. */
15
+ const HIDDEN_PREFIXES = ['only-']
16
+ const HIDDEN_KEYS = new Set(['_', 'name', '_cacheKey'])
17
+
18
+ /**
19
+ * Extract CLI option info from a Zod schema.
20
+ * Walks through Zod v4 wrapper types (default, optional) to find descriptions, types, and defaults.
21
+ */
22
+ function extractOptions(schema: any): Array<{ flag: string; description: string; type: string; defaultValue?: any }> {
23
+ if (!schema?.shape) return []
24
+
25
+ const options: Array<{ flag: string; description: string; type: string; defaultValue?: any }> = []
26
+
27
+ for (const [key, field] of Object.entries(schema.shape)) {
28
+ if (HIDDEN_KEYS.has(key)) continue
29
+ if (HIDDEN_PREFIXES.some((p) => key.startsWith(p))) continue
30
+
31
+ const f = field as any
32
+ // In Zod v4, description lives on the schema object itself
33
+ const description = f.description || ''
34
+ let type = 'string'
35
+ let defaultValue: any = undefined
36
+
37
+ // Walk through wrapper types to find leaf type and default
38
+ let current = f
39
+ while (current) {
40
+ const defType = current._def?.type || current.type
41
+ if (defType === 'default') {
42
+ defaultValue = current._def?.defaultValue
43
+ if (typeof defaultValue === 'function') defaultValue = defaultValue()
44
+ }
45
+ if (defType === 'boolean') { type = 'boolean'; break }
46
+ if (defType === 'string') { type = 'string'; break }
47
+ if (defType === 'number') { type = 'number'; break }
48
+ if (defType === 'enum') { type = current.options?.join(' | ') || 'enum'; break }
49
+ // Unwrap
50
+ current = current._def?.innerType
51
+ }
52
+
53
+ options.push({ flag: key, description, type, defaultValue })
54
+ }
55
+
56
+ return options
57
+ }
58
+
59
+ /**
60
+ * Format CLI-oriented help text for a single command.
61
+ * Exported so other commands (like describe) can reuse it.
62
+ */
63
+ export function formatCommandHelp(name: string, Cmd: any, colors: any): string {
64
+ const desc = Cmd.commandDescription || ''
65
+ const schema = Cmd.argsSchema
66
+ const lines: string[] = []
67
+
68
+ lines.push('')
69
+ lines.push(` ${colors.cyan.bold(`luca ${name}`)} ${desc ? `${colors.dim('—')} ${desc}` : ''}`)
70
+ lines.push('')
71
+
72
+ const options = extractOptions(schema)
73
+
74
+ if (options.length === 0) {
75
+ lines.push(` ${colors.white('Usage:')} ${colors.cyan(`luca ${name}`)}`)
76
+ } else {
77
+ const booleans = options.filter((o) => o.type === 'boolean')
78
+ const valued = options.filter((o) => o.type !== 'boolean')
79
+
80
+ lines.push(` ${colors.white('Usage:')} ${colors.cyan(`luca ${name}`)} ${colors.dim('[options]')}`)
81
+ lines.push('')
82
+
83
+ if (valued.length > 0) {
84
+ lines.push(` ${colors.white('Options:')}`)
85
+ lines.push('')
86
+ const maxLen = Math.max(...valued.map((o) => `--${o.flag} <${o.type}>`.length))
87
+ for (const opt of valued) {
88
+ const flag = `--${opt.flag} <${opt.type}>`
89
+ let line = ` ${colors.green(flag.padEnd(maxLen + 2))} ${opt.description}`
90
+ if (opt.defaultValue !== undefined && opt.defaultValue !== false) {
91
+ line += ` ${colors.dim(`(default: ${opt.defaultValue})`)}`
92
+ }
93
+ lines.push(line)
94
+ }
95
+ lines.push('')
96
+ }
97
+
98
+ if (booleans.length > 0) {
99
+ lines.push(` ${colors.white('Flags:')}`)
100
+ lines.push('')
101
+ const maxLen = Math.max(...booleans.map((o) => `--${o.flag}`.length))
102
+ for (const opt of booleans) {
103
+ const flag = `--${opt.flag}`
104
+ let line = ` ${colors.green(flag.padEnd(maxLen + 2))} ${opt.description}`
105
+ if (opt.defaultValue === true) {
106
+ line += ` ${colors.dim('(default: true)')}`
107
+ }
108
+ lines.push(line)
109
+ }
110
+ lines.push('')
111
+ }
112
+ }
113
+
114
+ return lines.join('\n')
115
+ }
116
+
117
+ /** Strip ANSI escape codes for visible width calculation. */
118
+ function stripAnsi(s: string): string {
119
+ return s.replace(/\x1B\[[0-9;]*m/g, '')
120
+ }
121
+
122
+ /** Merge two multi-line blocks side by side with a gap. */
123
+ function sideBySide(left: string[], right: string[], gap = 3): string[] {
124
+ const maxLeftWidth = Math.max(...left.map((l) => stripAnsi(l).length))
125
+ const maxLines = Math.max(left.length, right.length)
126
+ const result: string[] = []
127
+
128
+ for (let i = 0; i < maxLines; i++) {
129
+ const l = left[i] || ''
130
+ const r = right[i] || ''
131
+ const visLen = stripAnsi(l).length
132
+ const pad = Math.max(0, maxLeftWidth - visLen) + gap
133
+ result.push(l + ' '.repeat(pad) + r)
134
+ }
135
+
136
+ return result
137
+ }
138
+
139
+ const LEGO_ROBOT = [
140
+ ' ┌─○○─┐ ',
141
+ ' │ ●● │ ',
142
+ ' ├○──○┤ ',
143
+ ' └─╨╨─┘ ',
144
+ ]
145
+
146
+ const BANNER_COLORS: string[] = ['cyan', 'blue', 'magenta']
147
+
148
+ export default async function help(_options: z.infer<typeof argsSchema>, context: ContainerContext) {
149
+ const container = context.container as any
150
+ const ui = container.feature('ui') as any
151
+ const c = ui.colors
152
+
153
+ const args = container.argv._ as string[]
154
+ const target = args[1] as string
155
+
156
+ if (!target) {
157
+ // Robot (left) + banner (right), same height — direct 1:1 alignment
158
+ const banner = ui.banner('luca', { font: 'Small Slant', colors: BANNER_COLORS })
159
+ const bannerLines = banner.split('\n').filter((l: string) => l.trim())
160
+ const coloredRobot = ui.applyGradient(LEGO_ROBOT.join('\n'), BANNER_COLORS)
161
+ const robotLines = coloredRobot.split('\n') as string[]
162
+ const robotWidth = Math.max(...LEGO_ROBOT.map((l: string) => l.length))
163
+
164
+ const headerLines: string[] = []
165
+ const maxLines = Math.max(robotLines.length, bannerLines.length)
166
+ for (let i = 0; i < maxLines; i++) {
167
+ const rLine = robotLines[i] || ''
168
+ const rPad = robotWidth - stripAnsi(rLine).length
169
+ const bLine = bannerLines[i] || ''
170
+ headerLines.push(rLine + ' '.repeat(rPad + 2) + bLine)
171
+ }
172
+
173
+ console.log('\n')
174
+ console.log(headerLines.join('\n'))
175
+ console.log(c.dim(' Lightweight Universal Conversational Architecture'))
176
+ console.log()
177
+ console.log(c.white(' Usage: ') + c.cyan('luca') + c.dim(' <command|file> [options]'))
178
+ console.log()
179
+ console.log(c.white(' Commands:'))
180
+ console.log()
181
+
182
+ // Dynamic padding based on longest command name
183
+ const commandNames = (container.commands.available as string[]).filter((n: string) => n !== 'help')
184
+ const maxNameLen = Math.max(...commandNames.map((n: string) => n.length)) + 2
185
+
186
+ for (const name of commandNames) {
187
+ const Cmd = container.commands.lookup(name) as any
188
+ const desc = Cmd.commandDescription || ''
189
+ console.log(` ${c.cyan(name.padEnd(maxNameLen))} ${c.dim(desc)}`)
190
+ }
191
+
192
+ console.log()
193
+ console.log(c.dim(' Run ') + c.cyan('luca <file>') + c.dim(' to execute a script or markdown (.ts, .js, .md)'))
194
+ console.log(c.dim(' Run ') + c.cyan('luca help <command>') + c.dim(' for detailed usage of a command'))
195
+ console.log()
196
+ return
197
+ }
198
+
199
+ if (!container.commands.has(target)) {
200
+ console.error(` Unknown command: ${c.red(target)}`)
201
+ console.error()
202
+ console.error(` Run ${c.cyan('luca help')} to see available commands.`)
203
+ return
204
+ }
205
+
206
+ const Cmd = container.commands.lookup(target) as any
207
+ console.log(formatCommandHelp(target, Cmd, c))
208
+ }
209
+
210
+ commands.registerHandler('help', {
211
+ description: 'Show help for luca commands',
212
+ argsSchema,
213
+ handler: help,
214
+ })
@@ -0,0 +1,14 @@
1
+ export { Command, commands, CommandsRegistry, type AvailableCommands, type CommandsInterface, type CommandHandler, type CommandState, type CommandOptions } from '../command.js'
2
+
3
+ // Side-effect imports register each command
4
+ import './run.js'
5
+ import './console.js'
6
+ import './serve.js'
7
+ import './chat.js'
8
+ import './prompt.js'
9
+ import './mcp.js'
10
+ import './sandbox-mcp.js'
11
+ import './describe.js'
12
+ import './eval.js'
13
+ import './help.js'
14
+ import './scaffold.js'
@@ -0,0 +1,64 @@
1
+ import { z } from 'zod'
2
+ import { commands } from '../command.js'
3
+ import { CommandOptionsSchema } from '../schemas/base.js'
4
+ import type { ContainerContext } from '../container.js'
5
+ import type { MCPServer } from '../servers/mcp.js'
6
+
7
+ declare module '../command.js' {
8
+ interface AvailableCommands {
9
+ mcp: ReturnType<typeof commands.registerHandler>
10
+ }
11
+ }
12
+
13
+ export const argsSchema = CommandOptionsSchema.extend({
14
+ transport: z.enum(['stdio', 'http']).default('stdio').describe('Transport type (stdio or http)'),
15
+ port: z.number().default(3001).describe('Port for HTTP transport'),
16
+ name: z.string().optional().describe('Server name reported to MCP clients'),
17
+ version: z.string().optional().describe('Server version reported to MCP clients'),
18
+ mcpCompat: z.enum(['standard', 'codex']).optional()
19
+ .describe('HTTP compatibility profile. Defaults to standard. Can also be set via MCP_HTTP_COMPAT.'),
20
+ stdioCompat: z.enum(['standard', 'codex', 'auto']).optional()
21
+ .describe('Stdio framing compatibility profile. Defaults to standard. Can also be set via MCP_STDIO_COMPAT.'),
22
+ })
23
+
24
+ export default async function mcp(options: z.infer<typeof argsSchema>, context: ContainerContext) {
25
+ const container = context.container as any
26
+ const envCompat = process.env.MCP_HTTP_COMPAT?.toLowerCase()
27
+ const resolvedCompat = options.mcpCompat || (envCompat === 'codex' ? 'codex' : 'standard')
28
+ const envStdioCompat = process.env.MCP_STDIO_COMPAT?.toLowerCase()
29
+ const resolvedStdioCompat = options.stdioCompat
30
+ || (envStdioCompat === 'codex' || envStdioCompat === 'auto' ? envStdioCompat : 'standard')
31
+
32
+ const mcpServer = container.server('mcp', {
33
+ transport: options.transport,
34
+ port: options.port,
35
+ serverName: options.name || container.manifest?.name || 'luca-mcp',
36
+ serverVersion: options.version || container.manifest?.version || '1.0.0',
37
+ mcpCompat: options.mcpCompat,
38
+ stdioCompat: options.stdioCompat,
39
+ }) as MCPServer
40
+
41
+ await mcpServer.start({
42
+ transport: options.transport,
43
+ port: options.port,
44
+ mcpCompat: options.mcpCompat,
45
+ stdioCompat: options.stdioCompat,
46
+ })
47
+
48
+ if (options.transport === 'http') {
49
+ const name = options.name || container.manifest?.name || 'MCP Server'
50
+ console.log(`\n${name} listening on http://localhost:${options.port}/mcp`)
51
+ console.log(`Transport: HTTP (Streamable)`)
52
+ console.log(`Compatibility: ${resolvedCompat}`)
53
+ } else {
54
+ // stdio mode — don't print to stdout as it's used for the protocol
55
+ console.error(`MCP server started (stdio transport)`)
56
+ console.error(`Stdio Compatibility: ${resolvedStdioCompat}`)
57
+ }
58
+ }
59
+
60
+ commands.registerHandler('mcp', {
61
+ description: 'Start an MCP (Model Context Protocol) server',
62
+ argsSchema,
63
+ handler: mcp,
64
+ })