luca 3.0.0 → 3.1.0

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 (388) hide show
  1. package/.github/workflows/release.yaml +1 -0
  2. package/CLAUDE.md +10 -2
  3. package/README.md +130 -112
  4. package/assistants/codingAssistant/CORE.md +6 -1
  5. package/assistants/codingAssistant/hooks.ts +1 -1
  6. package/assistants/inkbot/hooks.ts +1 -1
  7. package/assistants/inkbot/tools.ts +1 -1
  8. package/bun.lock +264 -321
  9. package/commands/audit-docs.ts +2 -2
  10. package/commands/build-bootstrap.ts +2 -3
  11. package/commands/build-python-bridge.ts +2 -3
  12. package/commands/build-scaffolds.ts +2 -3
  13. package/commands/bundle-consumer-project.ts +521 -0
  14. package/commands/generate-api-docs.ts +2 -2
  15. package/commands/inkbot.ts +2 -2
  16. package/commands/release.ts +2 -2
  17. package/commands/social.ts +137 -0
  18. package/commands/try-all-challenges.ts +3 -3
  19. package/commands/try-challenge.ts +3 -3
  20. package/datasets/lora/agentic-loop-session-candidates.jsonl +91 -0
  21. package/datasets/lora/agentic-loop-session-curation-summary.json +123 -0
  22. package/datasets/lora/luca-session-candidates.jsonl +29 -0
  23. package/datasets/lora/luca-session-curation-summary.json +121 -0
  24. package/datasets/lora/review-batch-1.jsonl +30 -0
  25. package/datasets/lora/review-manifest.json +41 -0
  26. package/datasets/lora/review-queue.jsonl +120 -0
  27. package/datasets/lora/review-schema.json +134 -0
  28. package/datasets/lora/review-template.jsonl +2 -0
  29. package/datasets/lora/review-ui.html +725 -0
  30. package/dist/agi/container.server.d.ts +2 -2
  31. package/dist/agi/features/assistant.d.ts +2 -2
  32. package/dist/agi/features/assistants-manager.d.ts +1 -1
  33. package/dist/agi/features/autonomous-assistant.d.ts +1 -1
  34. package/dist/agi/features/browser-use.d.ts +1 -1
  35. package/dist/agi/features/claude-code.d.ts +1 -1
  36. package/dist/agi/features/conversation-history.d.ts +2 -2
  37. package/dist/agi/features/conversation.d.ts +1 -1
  38. package/dist/agi/features/docs-reader.d.ts +1 -1
  39. package/dist/agi/features/file-tools.d.ts +1 -1
  40. package/dist/agi/features/luca-coder.d.ts +1 -1
  41. package/dist/agi/features/openai-codex.d.ts +1 -1
  42. package/dist/agi/features/skills-library.d.ts +1 -1
  43. package/dist/clients/civitai/index.d.ts +4 -4
  44. package/dist/clients/client-template.d.ts +4 -4
  45. package/dist/clients/comfyui/index.d.ts +2 -2
  46. package/dist/clients/elevenlabs/index.d.ts +2 -2
  47. package/dist/clients/openai/index.d.ts +2 -2
  48. package/dist/clients/supabase/index.d.ts +3 -3
  49. package/dist/command.d.ts +1 -1
  50. package/dist/node/container.d.ts +1 -1
  51. package/dist/node/features/helpers.d.ts +3 -3
  52. package/dist/node/features/semantic-search.d.ts +1 -1
  53. package/dist/node/features/vm.d.ts +3 -3
  54. package/dist/node.d.ts +1 -1
  55. package/dist/scaffolds/generated.d.ts +1 -1
  56. package/dist/selector.d.ts +1 -1
  57. package/features/cipher-social.ts +493 -0
  58. package/index.html +217 -190
  59. package/luca.console.ts +1 -1
  60. package/package.json +7 -2
  61. package/public/index.html +217 -190
  62. package/public/slides-ai-native.html +1 -1
  63. package/public/slides-intro.html +2 -2
  64. package/scripts/curate-claude-sessions.ts +561 -0
  65. package/scripts/examples/ask-luca-expert.ts +1 -1
  66. package/scripts/examples/assistant-questions.ts +1 -1
  67. package/scripts/examples/excalidraw-expert.ts +1 -1
  68. package/scripts/examples/file-manager.ts +1 -1
  69. package/scripts/examples/ideas.ts +1 -1
  70. package/scripts/examples/interactive-chat.ts +1 -1
  71. package/scripts/examples/opening-a-web-browser.ts +1 -1
  72. package/scripts/examples/telegram-bot.ts +1 -1
  73. package/scripts/examples/using-assistant-with-mcp.ts +1 -1
  74. package/scripts/examples/using-claude-code.ts +1 -1
  75. package/scripts/examples/using-contentdb.ts +2 -2
  76. package/scripts/examples/using-conversations.ts +1 -1
  77. package/scripts/examples/using-disk-cache.ts +1 -1
  78. package/scripts/examples/using-docker-shell.ts +1 -1
  79. package/scripts/examples/using-elevenlabs.ts +1 -1
  80. package/scripts/examples/using-google-calendar.ts +1 -1
  81. package/scripts/examples/using-google-docs.ts +1 -1
  82. package/scripts/examples/using-google-drive.ts +1 -1
  83. package/scripts/examples/using-google-sheets.ts +1 -1
  84. package/scripts/examples/using-nlp.ts +1 -1
  85. package/scripts/examples/using-ollama.ts +1 -1
  86. package/scripts/examples/using-postgres.ts +1 -1
  87. package/scripts/examples/using-runpod.ts +1 -1
  88. package/scripts/examples/using-tts.ts +1 -1
  89. package/scripts/scaffold.ts +5 -5
  90. package/scripts/scratch.ts +1 -1
  91. package/scripts/test-assistant-hooks.ts +1 -1
  92. package/scripts/test-docs-reader.ts +1 -1
  93. package/src/agi/container.server.ts +6 -2
  94. package/src/agi/features/agent-memory.ts +25 -25
  95. package/src/agi/features/assistant.ts +34 -5
  96. package/src/agi/features/assistants-manager.ts +122 -6
  97. package/src/agi/features/autonomous-assistant.ts +1 -1
  98. package/src/agi/features/browser-use.ts +20 -1
  99. package/src/agi/features/claude-code.ts +51 -5
  100. package/src/agi/features/coding-tools.ts +1 -1
  101. package/src/agi/features/conversation-history.ts +181 -4
  102. package/src/agi/features/conversation.ts +186 -15
  103. package/src/agi/features/docs-reader.ts +2 -2
  104. package/src/agi/features/file-tools.ts +49 -2
  105. package/src/agi/features/luca-coder.ts +7 -5
  106. package/src/agi/features/mcp-bridge.ts +532 -0
  107. package/src/agi/features/openai-codex.ts +2 -2
  108. package/src/agi/features/skills-library.ts +131 -52
  109. package/src/agi/lib/token-counter.ts +80 -0
  110. package/src/bootstrap/generated.ts +56 -57
  111. package/src/browser.ts +1 -1
  112. package/src/cli/build-info.ts +2 -2
  113. package/src/cli/cli.ts +2 -2
  114. package/src/clients/civitai/index.ts +5 -5
  115. package/src/clients/client-template.ts +4 -4
  116. package/src/clients/comfyui/index.ts +4 -4
  117. package/src/clients/elevenlabs/index.ts +4 -4
  118. package/src/clients/openai/index.ts +7 -7
  119. package/src/clients/supabase/index.ts +4 -4
  120. package/src/clients/voicebox/index.ts +4 -4
  121. package/src/command.ts +2 -1
  122. package/src/commands/chat.ts +1 -0
  123. package/src/commands/eval.ts +2 -56
  124. package/src/commands/introspect.ts +1 -1
  125. package/src/commands/prompt.ts +41 -9
  126. package/src/container-describer.ts +8 -1
  127. package/src/container.ts +13 -0
  128. package/src/entity.ts +2 -2
  129. package/src/helper.ts +1 -1
  130. package/src/introspection/generated.agi.ts +29596 -27654
  131. package/src/introspection/generated.node.ts +20284 -19247
  132. package/src/introspection/generated.web.ts +605 -584
  133. package/src/introspection/scan.ts +11 -6
  134. package/src/node/container.ts +9 -1
  135. package/src/node/features/content-db.ts +39 -2
  136. package/src/node/features/display-result.ts +57 -0
  137. package/src/node/features/helpers.ts +46 -7
  138. package/src/node/features/python.ts +25 -19
  139. package/src/node/features/repl.ts +1 -1
  140. package/src/node/features/secure-shell.ts +11 -17
  141. package/src/node/features/semantic-search.ts +2 -2
  142. package/src/node/features/socket-repl.ts +336 -0
  143. package/src/node/features/telnyx-assistant-connector.ts +1206 -0
  144. package/src/node/features/transpiler.ts +2 -3
  145. package/src/node/features/ui.ts +5 -0
  146. package/src/node/features/vm.ts +20 -3
  147. package/src/node.ts +3 -3
  148. package/src/python/generated.ts +0 -1
  149. package/src/scaffolds/generated.ts +82 -83
  150. package/src/selector.ts +1 -1
  151. package/src/servers/express.ts +1 -1
  152. package/src/web/features/helpers.ts +22 -0
  153. package/tsconfig.json +12 -12
  154. package/docs/CLI.md +0 -335
  155. package/docs/CNAME +0 -1
  156. package/docs/README.md +0 -60
  157. package/docs/TABLE-OF-CONTENTS.md +0 -183
  158. package/docs/apis/clients/elevenlabs.md +0 -308
  159. package/docs/apis/clients/graph.md +0 -107
  160. package/docs/apis/clients/openai.md +0 -429
  161. package/docs/apis/clients/rest.md +0 -161
  162. package/docs/apis/clients/websocket.md +0 -174
  163. package/docs/apis/features/agi/assistant.md +0 -625
  164. package/docs/apis/features/agi/assistants-manager.md +0 -282
  165. package/docs/apis/features/agi/auto-assistant.md +0 -279
  166. package/docs/apis/features/agi/browser-use.md +0 -802
  167. package/docs/apis/features/agi/claude-code.md +0 -884
  168. package/docs/apis/features/agi/conversation-history.md +0 -364
  169. package/docs/apis/features/agi/conversation.md +0 -548
  170. package/docs/apis/features/agi/docs-reader.md +0 -99
  171. package/docs/apis/features/agi/file-tools.md +0 -163
  172. package/docs/apis/features/agi/luca-coder.md +0 -407
  173. package/docs/apis/features/agi/openai-codex.md +0 -396
  174. package/docs/apis/features/agi/openapi.md +0 -138
  175. package/docs/apis/features/agi/semantic-search.md +0 -387
  176. package/docs/apis/features/agi/skills-library.md +0 -239
  177. package/docs/apis/features/node/container-link.md +0 -192
  178. package/docs/apis/features/node/content-db.md +0 -450
  179. package/docs/apis/features/node/disk-cache.md +0 -379
  180. package/docs/apis/features/node/dns.md +0 -652
  181. package/docs/apis/features/node/docker.md +0 -706
  182. package/docs/apis/features/node/downloader.md +0 -81
  183. package/docs/apis/features/node/esbuild.md +0 -60
  184. package/docs/apis/features/node/file-manager.md +0 -191
  185. package/docs/apis/features/node/fs.md +0 -1217
  186. package/docs/apis/features/node/git.md +0 -371
  187. package/docs/apis/features/node/google-auth.md +0 -193
  188. package/docs/apis/features/node/google-calendar.md +0 -202
  189. package/docs/apis/features/node/google-docs.md +0 -173
  190. package/docs/apis/features/node/google-drive.md +0 -246
  191. package/docs/apis/features/node/google-mail.md +0 -214
  192. package/docs/apis/features/node/google-sheets.md +0 -194
  193. package/docs/apis/features/node/grep.md +0 -292
  194. package/docs/apis/features/node/helpers.md +0 -164
  195. package/docs/apis/features/node/ink.md +0 -334
  196. package/docs/apis/features/node/ipc-socket.md +0 -249
  197. package/docs/apis/features/node/json-tree.md +0 -86
  198. package/docs/apis/features/node/networking.md +0 -316
  199. package/docs/apis/features/node/nlp.md +0 -133
  200. package/docs/apis/features/node/opener.md +0 -97
  201. package/docs/apis/features/node/os.md +0 -146
  202. package/docs/apis/features/node/package-finder.md +0 -392
  203. package/docs/apis/features/node/postgres.md +0 -234
  204. package/docs/apis/features/node/proc.md +0 -399
  205. package/docs/apis/features/node/process-manager.md +0 -305
  206. package/docs/apis/features/node/python.md +0 -604
  207. package/docs/apis/features/node/redis.md +0 -380
  208. package/docs/apis/features/node/repl.md +0 -88
  209. package/docs/apis/features/node/runpod.md +0 -674
  210. package/docs/apis/features/node/secure-shell.md +0 -176
  211. package/docs/apis/features/node/semantic-search.md +0 -408
  212. package/docs/apis/features/node/sqlite.md +0 -233
  213. package/docs/apis/features/node/telegram.md +0 -279
  214. package/docs/apis/features/node/transpiler.md +0 -74
  215. package/docs/apis/features/node/tts.md +0 -133
  216. package/docs/apis/features/node/ui.md +0 -701
  217. package/docs/apis/features/node/vault.md +0 -59
  218. package/docs/apis/features/node/vm.md +0 -75
  219. package/docs/apis/features/node/yaml-tree.md +0 -85
  220. package/docs/apis/features/node/yaml.md +0 -176
  221. package/docs/apis/features/web/asset-loader.md +0 -59
  222. package/docs/apis/features/web/container-link.md +0 -192
  223. package/docs/apis/features/web/esbuild.md +0 -54
  224. package/docs/apis/features/web/helpers.md +0 -164
  225. package/docs/apis/features/web/network.md +0 -44
  226. package/docs/apis/features/web/speech.md +0 -69
  227. package/docs/apis/features/web/vault.md +0 -59
  228. package/docs/apis/features/web/vm.md +0 -75
  229. package/docs/apis/features/web/voice.md +0 -84
  230. package/docs/apis/servers/express.md +0 -171
  231. package/docs/apis/servers/mcp.md +0 -238
  232. package/docs/apis/servers/websocket.md +0 -170
  233. package/docs/bootstrap/CLAUDE.md +0 -101
  234. package/docs/bootstrap/SKILL.md +0 -341
  235. package/docs/bootstrap/templates/about-command.ts +0 -41
  236. package/docs/bootstrap/templates/docs-models.ts +0 -22
  237. package/docs/bootstrap/templates/docs-readme.md +0 -43
  238. package/docs/bootstrap/templates/example-feature.ts +0 -53
  239. package/docs/bootstrap/templates/health-endpoint.ts +0 -15
  240. package/docs/bootstrap/templates/luca-cli.ts +0 -30
  241. package/docs/bootstrap/templates/runme.md +0 -54
  242. package/docs/challenges/caching-proxy.md +0 -16
  243. package/docs/challenges/content-db-round-trip.md +0 -14
  244. package/docs/challenges/custom-command.md +0 -9
  245. package/docs/challenges/file-watcher-pipeline.md +0 -11
  246. package/docs/challenges/grep-audit-report.md +0 -15
  247. package/docs/challenges/multi-feature-dashboard.md +0 -14
  248. package/docs/challenges/process-orchestrator.md +0 -17
  249. package/docs/challenges/rest-api-server-with-client.md +0 -12
  250. package/docs/challenges/script-runner-with-vm.md +0 -11
  251. package/docs/challenges/simple-rest-api.md +0 -15
  252. package/docs/challenges/websocket-serve-and-client.md +0 -11
  253. package/docs/challenges/yaml-config-system.md +0 -14
  254. package/docs/command-system-overhaul.md +0 -94
  255. package/docs/documentation-audit.md +0 -134
  256. package/docs/examples/assistant/CORE.md +0 -18
  257. package/docs/examples/assistant/hooks.ts +0 -3
  258. package/docs/examples/assistant/tools.ts +0 -10
  259. package/docs/examples/assistant-hooks-reference.ts +0 -171
  260. package/docs/examples/assistant-with-process-manager.md +0 -84
  261. package/docs/examples/content-db.md +0 -77
  262. package/docs/examples/disk-cache.md +0 -83
  263. package/docs/examples/docker.md +0 -101
  264. package/docs/examples/downloader.md +0 -70
  265. package/docs/examples/entity.md +0 -124
  266. package/docs/examples/esbuild.md +0 -80
  267. package/docs/examples/feature-as-tool-provider.md +0 -143
  268. package/docs/examples/file-manager.md +0 -82
  269. package/docs/examples/fs.md +0 -83
  270. package/docs/examples/git.md +0 -85
  271. package/docs/examples/google-auth.md +0 -88
  272. package/docs/examples/google-calendar.md +0 -94
  273. package/docs/examples/google-docs.md +0 -82
  274. package/docs/examples/google-drive.md +0 -96
  275. package/docs/examples/google-sheets.md +0 -95
  276. package/docs/examples/grep.md +0 -85
  277. package/docs/examples/ink-blocks.md +0 -75
  278. package/docs/examples/ink-renderer.md +0 -41
  279. package/docs/examples/ink.md +0 -103
  280. package/docs/examples/ipc-socket.md +0 -103
  281. package/docs/examples/json-tree.md +0 -91
  282. package/docs/examples/networking.md +0 -58
  283. package/docs/examples/nlp.md +0 -91
  284. package/docs/examples/opener.md +0 -78
  285. package/docs/examples/os.md +0 -72
  286. package/docs/examples/package-finder.md +0 -89
  287. package/docs/examples/postgres.md +0 -91
  288. package/docs/examples/proc.md +0 -81
  289. package/docs/examples/process-manager.md +0 -79
  290. package/docs/examples/python.md +0 -132
  291. package/docs/examples/repl.md +0 -93
  292. package/docs/examples/runpod.md +0 -119
  293. package/docs/examples/secure-shell.md +0 -92
  294. package/docs/examples/sqlite.md +0 -86
  295. package/docs/examples/structured-output-with-assistants.md +0 -144
  296. package/docs/examples/telegram.md +0 -77
  297. package/docs/examples/tts.md +0 -86
  298. package/docs/examples/ui.md +0 -80
  299. package/docs/examples/vault.md +0 -70
  300. package/docs/examples/vm.md +0 -86
  301. package/docs/examples/websocket-ask-and-reply-example.md +0 -128
  302. package/docs/examples/yaml-tree.md +0 -93
  303. package/docs/examples/yaml.md +0 -104
  304. package/docs/ideas/assistant-factory-pattern.md +0 -142
  305. package/docs/in-memory-fs.md +0 -4
  306. package/docs/introspection-audit.md +0 -49
  307. package/docs/introspection.md +0 -164
  308. package/docs/mcp/readme.md +0 -162
  309. package/docs/models.ts +0 -41
  310. package/docs/philosophy.md +0 -86
  311. package/docs/principles.md +0 -7
  312. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +0 -34
  313. package/docs/prompts/check-for-undocumented-features.md +0 -27
  314. package/docs/prompts/mcp-test-easy-command.md +0 -27
  315. package/docs/scaffolds/client.md +0 -149
  316. package/docs/scaffolds/command.md +0 -120
  317. package/docs/scaffolds/endpoint.md +0 -171
  318. package/docs/scaffolds/feature.md +0 -158
  319. package/docs/scaffolds/selector.md +0 -91
  320. package/docs/scaffolds/server.md +0 -196
  321. package/docs/selectors.md +0 -115
  322. package/docs/sessions/custom-command/attempt-log-2.md +0 -195
  323. package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +0 -728
  324. package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +0 -555
  325. package/docs/sessions/grep-audit-report/attempt-log-1.md +0 -289
  326. package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +0 -679
  327. package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +0 -1
  328. package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +0 -920
  329. package/docs/sessions/simple-rest-api/attempt-log-1.md +0 -593
  330. package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +0 -995
  331. package/docs/tutorials/00-bootstrap.md +0 -166
  332. package/docs/tutorials/01-getting-started.md +0 -106
  333. package/docs/tutorials/02-container.md +0 -210
  334. package/docs/tutorials/03-scripts.md +0 -194
  335. package/docs/tutorials/04-features-overview.md +0 -196
  336. package/docs/tutorials/05-state-and-events.md +0 -171
  337. package/docs/tutorials/06-servers.md +0 -157
  338. package/docs/tutorials/07-endpoints.md +0 -198
  339. package/docs/tutorials/08-commands.md +0 -252
  340. package/docs/tutorials/09-clients.md +0 -162
  341. package/docs/tutorials/10-creating-features.md +0 -203
  342. package/docs/tutorials/11-contentbase.md +0 -191
  343. package/docs/tutorials/12-assistants.md +0 -215
  344. package/docs/tutorials/13-introspection.md +0 -157
  345. package/docs/tutorials/14-type-system.md +0 -174
  346. package/docs/tutorials/15-project-patterns.md +0 -222
  347. package/docs/tutorials/16-google-features.md +0 -534
  348. package/docs/tutorials/17-tui-blocks.md +0 -530
  349. package/docs/tutorials/18-semantic-search.md +0 -334
  350. package/docs/tutorials/19-python-sessions.md +0 -401
  351. package/docs/tutorials/20-browser-esm.md +0 -234
  352. package/index.ts +0 -1
  353. package/src/agi/endpoints/ask.ts +0 -60
  354. package/src/agi/endpoints/conversations/[id].ts +0 -45
  355. package/src/agi/endpoints/conversations.ts +0 -31
  356. package/src/agi/endpoints/experts.ts +0 -37
  357. package/test/assistant-hooks.test.ts +0 -306
  358. package/test/assistant.test.ts +0 -81
  359. package/test/bus.test.ts +0 -134
  360. package/test/clients-servers.test.ts +0 -217
  361. package/test/command.test.ts +0 -267
  362. package/test/container-link.test.ts +0 -274
  363. package/test/conversation.test.ts +0 -220
  364. package/test/features.test.ts +0 -160
  365. package/test/fork-and-research.test.ts +0 -450
  366. package/test/integration.test.ts +0 -787
  367. package/test/interceptor-chain.test.ts +0 -61
  368. package/test/node-container.test.ts +0 -121
  369. package/test/python-session.test.ts +0 -105
  370. package/test/rate-limit.test.ts +0 -272
  371. package/test/semantic-search.test.ts +0 -550
  372. package/test/state.test.ts +0 -121
  373. package/test/vm-context.test.ts +0 -146
  374. package/test/vm-loadmodule.test.ts +0 -213
  375. package/test/websocket-ask.test.ts +0 -101
  376. package/test-integration/assistant.test.ts +0 -138
  377. package/test-integration/assistants-manager.test.ts +0 -113
  378. package/test-integration/claude-code.test.ts +0 -98
  379. package/test-integration/conversation-history.test.ts +0 -205
  380. package/test-integration/conversation.test.ts +0 -137
  381. package/test-integration/elevenlabs.test.ts +0 -55
  382. package/test-integration/google-services.test.ts +0 -80
  383. package/test-integration/helpers.ts +0 -89
  384. package/test-integration/memory.test.ts +0 -204
  385. package/test-integration/openai-codex.test.ts +0 -93
  386. package/test-integration/runpod.test.ts +0 -58
  387. package/test-integration/server-endpoints.test.ts +0 -97
  388. package/test-integration/telegram.test.ts +0 -46
@@ -1,158 +0,0 @@
1
- # Building a Feature
2
-
3
- A feature is a container-managed capability — something your application needs that lives on the machine (file I/O, caching, encryption, etc). Features are lazy-loaded, observable, and self-documenting.
4
-
5
- When to build a feature:
6
- - You need a reusable local capability (not a network call — that's a client)
7
- - You want state management, events, and introspection for free
8
- - You're wrapping a library so the rest of the codebase uses a uniform interface
9
-
10
- ## Imports
11
-
12
- ```ts
13
- import { z } from 'zod'
14
- import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '@soederpop/luca'
15
- import { Feature } from '@soederpop/luca'
16
- ```
17
-
18
- These are the only imports your feature file needs from luca. If your feature wraps a third-party library, import it here too — feature implementations are the ONE place where direct library imports are allowed.
19
-
20
- The use of dynamic imports is encouraged here, only import libraries you need when the feature is used, and only when necessary in the lifecycle of the feature if it can be done.
21
-
22
- feature's have built in ways to check if their requirements are supported and can be enabled cautiously.
23
-
24
- ## Schemas
25
-
26
- Define the shape of your feature's state, options, and events using Zod. Every field must have a `.describe()` — this becomes the documentation.
27
-
28
- ```ts
29
- export const {{PascalName}}StateSchema = FeatureStateSchema.extend({
30
- // Add your state fields here. These are observable — changes emit events.
31
- // Example: itemCount: z.number().default(0).describe('Number of items stored'),
32
- })
33
- export type {{PascalName}}State = z.infer<typeof {{PascalName}}StateSchema>
34
-
35
- export const {{PascalName}}OptionsSchema = FeatureOptionsSchema.extend({
36
- // Add constructor options here. Validated when the feature is created.
37
- // Example: directory: z.string().optional().describe('Storage directory path'),
38
- })
39
- export type {{PascalName}}Options = z.infer<typeof {{PascalName}}OptionsSchema>
40
-
41
- export const {{PascalName}}EventsSchema = FeatureEventsSchema.extend({
42
- // Each key is an event name. Value is z.tuple() of listener arguments.
43
- // Example: itemAdded: z.tuple([z.string().describe('Item key')]).describe('Emitted when an item is added'),
44
- })
45
- ```
46
-
47
- ## Class
48
-
49
- The class extends `Feature` with your state and options types. Static properties drive registration and introspection. Every public method needs a JSDoc block with `@param`, `@returns`, and `@example`.
50
-
51
- Running `luca introspect` captures JSDoc blocks and Zod schemas and includes them in the description whenever somebody calls `container.features.describe('{{camelName}}')` or `luca describe {{camelName}}`.
52
-
53
- ```ts
54
- /**
55
- * {{description}}
56
- * ```typescript
57
- * const {{camelName}} = container.feature('{{camelName}}')
58
- * ```
59
- *
60
- * @extends Feature
61
- */
62
- export class {{PascalName}} extends Feature<{{PascalName}}State, {{PascalName}}Options> {
63
- static override shortcut = 'features.{{camelName}}' as const
64
- static override stateSchema = {{PascalName}}StateSchema
65
- static override optionsSchema = {{PascalName}}OptionsSchema
66
- static override eventsSchema = {{PascalName}}EventsSchema
67
-
68
- static { Feature.register(this, '{{camelName}}') }
69
-
70
- /**
71
- * Called after the feature is initialized. Use this for any setup logic
72
- * instead of overriding the constructor.
73
- */
74
- async afterInitialize() {
75
- // Set up initial state, start background tasks, etc.
76
- }
77
- }
78
- ```
79
-
80
- **Important**: You almost never need to override the constructor. Use `afterInitialize()` for any setup logic — it runs after the feature is fully wired into the container and has access to `this.container`, `this.options`, `this.state`, etc.
81
-
82
- ## Module Augmentation
83
-
84
- This is what gives `container.feature('yourName')` TypeScript autocomplete. Without it, the feature works but TypeScript won't know about it.
85
-
86
- ```ts
87
- declare module '@soederpop/luca' {
88
- interface AvailableFeatures {
89
- {{camelName}}: typeof {{PascalName}}
90
- }
91
- }
92
- ```
93
-
94
- ## Registration
95
-
96
- Registration happens inside the class body using a static block. The default export is just the class itself.
97
-
98
- ```ts
99
- // Inside the class:
100
- static { Feature.register(this, '{{camelName}}') }
101
-
102
- // At module level:
103
- export default {{PascalName}}
104
- ```
105
-
106
- ## Complete Example
107
-
108
- Here's a minimal but complete feature. This is what a real feature file looks like:
109
-
110
- ```ts
111
- import { z } from 'zod'
112
- import { FeatureStateSchema, FeatureOptionsSchema } from '@soederpop/luca'
113
- import { Feature } from '@soederpop/luca'
114
-
115
- declare module '@soederpop/luca' {
116
- interface AvailableFeatures {
117
- {{camelName}}: typeof {{PascalName}}
118
- }
119
- }
120
-
121
- export const {{PascalName}}StateSchema = FeatureStateSchema.extend({})
122
- export type {{PascalName}}State = z.infer<typeof {{PascalName}}StateSchema>
123
-
124
- export const {{PascalName}}OptionsSchema = FeatureOptionsSchema.extend({})
125
- export type {{PascalName}}Options = z.infer<typeof {{PascalName}}OptionsSchema>
126
-
127
- /**
128
- * {{description}}
129
- *
130
- * @example
131
- * ```typescript
132
- * const {{camelName}} = container.feature('{{camelName}}')
133
- * ```
134
- *
135
- * @extends Feature
136
- */
137
- export class {{PascalName}} extends Feature<{{PascalName}}State, {{PascalName}}Options> {
138
- static override shortcut = 'features.{{camelName}}' as const
139
- static override stateSchema = {{PascalName}}StateSchema
140
- static override optionsSchema = {{PascalName}}OptionsSchema
141
- static { Feature.register(this, '{{camelName}}') }
142
-
143
- async afterInitialize() {
144
- // Setup logic goes here — not in the constructor
145
- }
146
- }
147
-
148
- export default {{PascalName}}
149
- ```
150
-
151
- ## Conventions
152
-
153
- - **Naming**: PascalCase for class, camelCase for registration ID. The file name should be kebab-case (e.g. `disk-cache.ts`).
154
- - **JSDoc**: Every public method, getter, and the class itself needs a JSDoc block. Include `@example` with working code.
155
- - **Describe everything**: Every Zod field needs `.describe()`. Every event tuple argument needs `.describe()`. This IS the documentation.
156
- - **No Node builtins in consumer code**: If your feature wraps `fs` or `crypto`, that's fine inside the feature. But code that USES your feature should never import those directly.
157
- - **State is observable**: Use `this.state.set()` and `this.state.get()`. Don't use plain instance properties for data that should be reactive.
158
- - **Events for lifecycle**: Emit events for significant state changes so consumers can react.
@@ -1,91 +0,0 @@
1
- # Building a Selector
2
-
3
- A selector returns data. Where commands perform actions, selectors query and return structured results with built-in caching. Selectors live in a project's `selectors/` folder and are automatically discovered.
4
-
5
- When to build a selector:
6
- - You need to query project data (package info, file listings, config values)
7
- - The result benefits from caching (keyed by git SHA or custom key)
8
- - You want the data available via `container.select('name')` or `luca select name`
9
-
10
- ## Imports
11
-
12
- ```ts
13
- import { z } from 'zod'
14
- import type { ContainerContext } from '@soederpop/luca'
15
- ```
16
-
17
- ## Args Schema
18
-
19
- Define the selector's input arguments with Zod.
20
-
21
- ```ts
22
- export const argsSchema = z.object({
23
- // Add your input arguments here.
24
- // Example: field: z.string().optional().describe('Specific field to return'),
25
- })
26
- ```
27
-
28
- ## Description
29
-
30
- Export a description string for discoverability:
31
-
32
- ```ts
33
- export const description = '{{description}}'
34
- ```
35
-
36
- ## Caching
37
-
38
- Selectors cache by default. The default cache key is `hashObject({ selectorName, args, gitSha })` — same args + same commit = cache hit.
39
-
40
- To customize the cache key:
41
-
42
- ```ts
43
- export function cacheKey(args: z.infer<typeof argsSchema>, context: ContainerContext) {
44
- return context.container.git.currentCommitSha
45
- }
46
- ```
47
-
48
- To disable caching:
49
-
50
- ```ts
51
- export const cacheable = false
52
- ```
53
-
54
- ## Handler
55
-
56
- Export a `run` function that returns data. It receives parsed args and the container context.
57
-
58
- ```ts
59
- export async function run(args: z.infer<typeof argsSchema>, context: ContainerContext) {
60
- const { container } = context
61
- // Query and return your data
62
- return { /* your data */ }
63
- }
64
- ```
65
-
66
- ## Complete Example
67
-
68
- ```ts
69
- import { z } from 'zod'
70
- import type { ContainerContext } from '@soederpop/luca'
71
-
72
- export const description = '{{description}}'
73
-
74
- export const argsSchema = z.object({})
75
-
76
- export async function run(args: z.infer<typeof argsSchema>, context: ContainerContext) {
77
- const { container } = context
78
-
79
- // Return your data here
80
- return {}
81
- }
82
- ```
83
-
84
- ## Conventions
85
-
86
- - **File location**: `selectors/{{kebabName}}.ts` in the project root. Discovered automatically.
87
- - **Naming**: kebab-case for filename. `luca select {{kebabName}}` maps to `selectors/{{kebabName}}.ts`.
88
- - **Use the container**: Never import `fs`, `path` directly. Use `container.feature('fs')`, `container.paths`.
89
- - **Return data**: The `run` function must return the data. It gets wrapped in `{ data, cached, cacheKey }` by the framework.
90
- - **Caching**: On by default. Override `cacheKey()` for custom invalidation, or set `cacheable = false` to skip.
91
- - **CLI**: `luca select {{kebabName}}` runs the selector and prints JSON. Use `--json` for data only, `--no-cache` to force fresh.
@@ -1,196 +0,0 @@
1
- # Building a Server
2
-
3
- A server is a container-managed listener — something that accepts connections and handles requests. Servers manage their own lifecycle (configure, start, stop) and expose observable state.
4
-
5
- When to build a server:
6
- - You need to accept incoming connections (HTTP, WebSocket, custom protocol)
7
- - You want lifecycle management, port handling, and observability for free
8
- - You're wrapping a server library so the codebase uses `container.server('name')`
9
-
10
- ## Imports
11
-
12
- ```ts
13
- import { z } from 'zod'
14
- import { Server } from '@soederpop/luca'
15
- import { ServerStateSchema, ServerOptionsSchema, ServerEventsSchema } from '@soederpop/luca'
16
- import type { NodeContainer } from '@soederpop/luca'
17
- import type { ServersInterface } from '@soederpop/luca'
18
- ```
19
-
20
- ## Schemas
21
-
22
- ```ts
23
- export const {{PascalName}}StateSchema = ServerStateSchema.extend({
24
- // Add your state fields here.
25
- // Example: connectionCount: z.number().default(0).describe('Active connections'),
26
- })
27
- export type {{PascalName}}State = z.infer<typeof {{PascalName}}StateSchema>
28
-
29
- export const {{PascalName}}OptionsSchema = ServerOptionsSchema.extend({
30
- // Add constructor options here. port and host come from ServerOptionsSchema.
31
- // Example: cors: z.boolean().default(true).describe('Enable CORS'),
32
- })
33
- export type {{PascalName}}Options = z.infer<typeof {{PascalName}}OptionsSchema>
34
-
35
- export const {{PascalName}}EventsSchema = ServerEventsSchema.extend({
36
- // Add your events here.
37
- // Example: connection: z.tuple([z.string().describe('Client ID')]).describe('New client connected'),
38
- })
39
- ```
40
-
41
- ## Class
42
-
43
- Running `luca introspect` captures JSDoc blocks and Zod schemas and includes them in the description whenever somebody calls `container.servers.describe('{{camelName}}')` or `luca describe {{camelName}}`.
44
-
45
- ```ts
46
- /**
47
- * {{description}}
48
- *
49
- * @example
50
- * ```typescript
51
- * const {{camelName}} = container.server('{{camelName}}', { port: 3000 })
52
- * await {{camelName}}.start()
53
- * ```
54
- *
55
- * @extends Server
56
- */
57
- export class {{PascalName}} extends Server<{{PascalName}}State, {{PascalName}}Options> {
58
- static override shortcut = 'servers.{{camelName}}' as const
59
- static override stateSchema = {{PascalName}}StateSchema
60
- static override optionsSchema = {{PascalName}}OptionsSchema
61
- static override eventsSchema = {{PascalName}}EventsSchema
62
- static { Server.register(this, '{{camelName}}') }
63
-
64
- static override attach(container: NodeContainer & ServersInterface) {
65
- return container
66
- }
67
-
68
- override async configure() {
69
- if (this.isConfigured) return this
70
- // Set up the underlying server here
71
- this.state.set('configured', true)
72
- return this
73
- }
74
-
75
- override async start(options?: { port?: number }) {
76
- if (this.isListening) return this
77
- if (!this.isConfigured) await this.configure()
78
-
79
- const port = options?.port || this.options.port || 3000
80
- // Start listening here
81
- this.state.set('port', port)
82
- this.state.set('listening', true)
83
- return this
84
- }
85
-
86
- override async stop() {
87
- if (this.isStopped) return this
88
- // Clean up connections here
89
- this.state.set('listening', false)
90
- this.state.set('stopped', true)
91
- return this
92
- }
93
- }
94
- ```
95
-
96
- ## Module Augmentation
97
-
98
- ```ts
99
- declare module '@soederpop/luca' {
100
- interface AvailableServers {
101
- {{camelName}}: typeof {{PascalName}}
102
- }
103
- }
104
- ```
105
-
106
- ## Registration
107
-
108
- Registration happens inside the class body using a static block. The default export is just the class itself.
109
-
110
- ```ts
111
- // Inside the class:
112
- static { Server.register(this, '{{camelName}}') }
113
-
114
- // At module level:
115
- export default {{PascalName}}
116
- ```
117
-
118
- ## Complete Example
119
-
120
- ```ts
121
- import { z } from 'zod'
122
- import { Server } from '@soederpop/luca'
123
- import { ServerStateSchema, ServerOptionsSchema, ServerEventsSchema } from '@soederpop/luca'
124
- import type { NodeContainer } from '@soederpop/luca'
125
- import type { ServersInterface } from '@soederpop/luca'
126
-
127
- declare module '@soederpop/luca' {
128
- interface AvailableServers {
129
- {{camelName}}: typeof {{PascalName}}
130
- }
131
- }
132
-
133
- export const {{PascalName}}StateSchema = ServerStateSchema.extend({})
134
- export type {{PascalName}}State = z.infer<typeof {{PascalName}}StateSchema>
135
-
136
- export const {{PascalName}}OptionsSchema = ServerOptionsSchema.extend({})
137
- export type {{PascalName}}Options = z.infer<typeof {{PascalName}}OptionsSchema>
138
-
139
- export const {{PascalName}}EventsSchema = ServerEventsSchema.extend({})
140
-
141
- /**
142
- * {{description}}
143
- *
144
- * @example
145
- * ```typescript
146
- * const {{camelName}} = container.server('{{camelName}}', { port: 3000 })
147
- * await {{camelName}}.start()
148
- * ```
149
- *
150
- * @extends Server
151
- */
152
- export class {{PascalName}} extends Server<{{PascalName}}State, {{PascalName}}Options> {
153
- static override shortcut = 'servers.{{camelName}}' as const
154
- static override stateSchema = {{PascalName}}StateSchema
155
- static override optionsSchema = {{PascalName}}OptionsSchema
156
- static override eventsSchema = {{PascalName}}EventsSchema
157
- static { Server.register(this, '{{camelName}}') }
158
-
159
- static override attach(container: NodeContainer & ServersInterface) {
160
- return container
161
- }
162
-
163
- override async configure() {
164
- if (this.isConfigured) return this
165
- this.state.set('configured', true)
166
- return this
167
- }
168
-
169
- override async start(options?: { port?: number }) {
170
- if (this.isListening) return this
171
- if (!this.isConfigured) await this.configure()
172
- const port = options?.port || this.options.port || 3000
173
- this.state.set('port', port)
174
- this.state.set('listening', true)
175
- return this
176
- }
177
-
178
- override async stop() {
179
- if (this.isStopped) return this
180
- this.state.set('listening', false)
181
- this.state.set('stopped', true)
182
- return this
183
- }
184
- }
185
-
186
- export default {{PascalName}}
187
- ```
188
-
189
- ## Conventions
190
-
191
- - **Lifecycle**: Implement `configure()`, `start()`, and `stop()`. Check guards (`isConfigured`, `isListening`, `isStopped`) at the top of each.
192
- - **Use `afterInitialize()`**: For any setup logic instead of overriding the constructor. Lifecycle methods (`configure`, `start`, `stop`) handle the server's runtime phases.
193
- - **State tracking**: Set `configured`, `listening`, `stopped`, and `port` on the state. This powers the introspection system.
194
- - **attach() is static**: It runs when the container first loads the server class. Use it for container-level setup if needed.
195
- - **Port from options**: Accept port via options schema and respect it in `start()`. Allow override via start options.
196
- - **JSDoc everything**: Every public method needs `@param`, `@returns`, `@example`. Run `luca introspect` after changes to update generated docs.
package/docs/selectors.md DELETED
@@ -1,115 +0,0 @@
1
- # Selector System
2
-
3
- ## Vision
4
-
5
- Commands perform actions. Selectors return data. Together they form a complete agent tool interface — pick which commands and selectors you need and you get free assistant tools. Agents only need to know the external APIs of features, servers, and clients already in the container (which can be learned from `luca describe`).
6
-
7
- ## What Is a Selector?
8
-
9
- A Selector is a new helper type (like Feature, Client, Server, Command) that:
10
-
11
- - Extends `Helper` with a `select(options)` method that **returns data**
12
- - Lives in a `SelectorsRegistry`, queryable via `container.selectors`
13
- - Is instantiated via `container.selector('name', options)` factory
14
- - Supports **caching** via `diskCache` — many selector values don't change if git SHAs don't change, so SHA makes a great cache key
15
- - Is discoverable from a `selectors/` folder in projects, just like `commands/`
16
- - Supports both **class-based** and **module-based** (export a `select` function) patterns
17
-
18
- ## Architecture — How It Maps to Existing Patterns
19
-
20
- The implementation follows the exact same pattern as `Command`:
21
-
22
- ### Files to Create/Modify
23
-
24
- 1. **`src/schemas/base.ts`** — Add `SelectorStateSchema`, `SelectorOptionsSchema`, `SelectorEventsSchema`
25
- 2. **`src/selector.ts`** — New file mirroring `src/command.ts`:
26
- - `Selector` class extending `Helper` with `select()` method
27
- - `SelectorsRegistry` extending `Registry` with `discover()` support
28
- - `selectors` singleton, `helperCache`, `Selector.register()`, `Selector.attach()`
29
- - `AvailableSelectors` interface, `SelectorsInterface`, `SelectorFactory` type
30
- - Module-based pattern: `SimpleSelector` type for graft compatibility
31
- 3. **`src/node/container.ts`** — Import `Selector` + `SelectorsInterface`, add to `ClientsAndServersInterface`, wire `this.use(Selector)`
32
- 4. **`src/node/features/helpers.ts`** — Add `selectors` to `registryMap` and `RegistryType`, add to `discoverAll()` iteration
33
-
34
- ### Selector Base Class Shape
35
-
36
- ```typescript
37
- class Selector<T, K> extends Helper<T, K> {
38
- static shortcut = 'selectors.base'
39
- static argsSchema: z.ZodType // schema for select() input
40
- static cacheable: boolean = true // opt-out of caching
41
-
42
- // The core method — override in subclass or graft from module export
43
- async select(args, context): Promise<any> {}
44
-
45
- // Dispatch normalizer (like Command.execute)
46
- async resolve(args?, source?): Promise<SelectorResult> {}
47
- }
48
- ```
49
-
50
- ### Module-Based Pattern (selectors/ folder)
51
-
52
- ```typescript
53
- // selectors/package-info.ts
54
- export const description = 'Returns parsed package.json data'
55
- export const argsSchema = z.object({ field: z.string().optional() })
56
- export const cacheable = true
57
-
58
- export function cacheKey(args, context) {
59
- // return a string key — if unchanged, cached value is returned
60
- return context.container.git.sha
61
- }
62
-
63
- export async function select(args, context) {
64
- const manifest = context.container.manifest
65
- return args.field ? manifest[args.field] : manifest
66
- }
67
- ```
68
-
69
- ### Caching Strategy
70
-
71
- - Built into the `Selector` base class, powered by `diskCache` feature
72
- - Subclasses/modules can export a `cacheKey(args, context)` function
73
- - Default cache key strategy: `hashObject({ selectorName, args, gitSha })`
74
- - `cacheable: false` opts out entirely
75
- - Cache is key-invalidated (key changes = miss), no TTL by default
76
- - The `resolve()` method checks cache before calling `select()`
77
-
78
- ## Open Questions (Needs Decision)
79
-
80
- ### 1. Return Shape
81
- Should `select()` return data directly, or a wrapped result like `{ data, metadata, cached }`?
82
-
83
- **Leaning toward:** data directly from `select()`, but `resolve()` (the dispatch method) returns `{ data, cached, cacheKey }` so callers know if it was a cache hit.
84
-
85
- ### 2. CLI Integration
86
- Should there be a `luca select <name>` CLI command? Would make selectors usable from the terminal, printing JSON output.
87
-
88
- ### 3. Cache TTL
89
- Is pure key-invalidation enough, or do some selectors need time-based expiry?
90
-
91
- ### 4. Scope of First Delivery
92
-
93
- Proposed skateboard:
94
- - `Selector` base class with `select()` and `resolve()` (cached dispatch)
95
- - `SelectorsRegistry` with `discover()`
96
- - Container wiring (`container.selectors`, `container.selector()`)
97
- - Schemas in `schemas/base.ts`
98
- - `selectors/` folder discovery via `Helpers` feature
99
- - Caching integration with `diskCache`
100
- - Module-based pattern support (export `select` + optional `cacheKey`)
101
- - `Selector` + `selectors` exported from `@soederpop/luca` barrel + seeded in VM virtual modules
102
-
103
- ## Codebase Exploration Notes
104
-
105
- These are the key files that were studied to inform this design:
106
-
107
- - `src/command.ts` — The primary pattern to mirror. `Command` extends `Helper`, has `CommandsRegistry`, `commands` singleton, `Command.register()`, `Command.attach()`, `execute()`/`run()` split, headless capture, `graftModule` support.
108
- - `src/helper.ts` — Base class providing state, events, options (Zod-validated), introspection, `afterInitialize()` hook.
109
- - `src/registry.ts` — Abstract `Registry<T>` with `register()`, `lookup()`, `has()`, `available`, `describe()`, `describeAll()`, event bus.
110
- - `src/graft.ts` — `graftModule()` synthesizes a class from plain module exports. `RESERVED_EXPORTS` list determines what becomes static vs prototype methods.
111
- - `src/schemas/base.ts` — All Zod schemas. Each helper type has State/Options/Events schemas.
112
- - `src/node/container.ts` — `NodeContainer` wires everything: side-effect imports, `NodeFeatures` interface, `ClientsAndServersInterface`, `this.use(Command)` pattern.
113
- - `src/node/features/helpers.ts` — `Helpers` feature: `registryMap`, `RegistryType`, `discoverAll()`, class-based vs config-based discovery, VM module seeding.
114
- - `src/node/features/disk-cache.ts` — `DiskCache` feature: `get/set/has/rm`, `cacache`-backed, per-project cache dir, `container.utils.hashObject()` for keys.
115
- - `src/container.ts` — Base `Container`: `createHelperInstance()` with `helperCache` Map, `use()` plugin system, `registerHelperType()`.