luca 1.1.2 → 3.0.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.
- package/.github/workflows/release.yaml +169 -0
- package/AGENTS.md +99 -0
- package/CLAUDE.md +115 -0
- package/CNAME +1 -0
- package/README.md +257 -8
- package/RUNME.md +56 -0
- package/assistants/codingAssistant/ABOUT.md +5 -0
- package/assistants/codingAssistant/CORE.md +28 -0
- package/assistants/codingAssistant/hooks.ts +21 -0
- package/assistants/codingAssistant/tools.ts +12 -0
- package/assistants/inkbot/ABOUT.md +16 -0
- package/assistants/inkbot/CORE.md +330 -0
- package/assistants/inkbot/hooks.ts +6 -0
- package/assistants/inkbot/tools.ts +53 -0
- package/assistants/researcher/ABOUT.md +5 -0
- package/assistants/researcher/CORE.md +46 -0
- package/assistants/researcher/hooks.ts +16 -0
- package/assistants/researcher/tools.ts +237 -0
- package/bun.lock +2769 -0
- package/bunfig.toml +3 -0
- package/commands/audit-docs.ts +740 -0
- package/commands/build-bootstrap.ts +118 -0
- package/commands/build-python-bridge.ts +43 -0
- package/commands/build-scaffolds.ts +176 -0
- package/commands/generate-api-docs.ts +114 -0
- package/commands/inkbot.ts +874 -0
- package/commands/release.ts +80 -0
- package/commands/try-all-challenges.ts +543 -0
- package/commands/try-challenge.ts +100 -0
- package/dist/agi/container.server.d.ts +63 -0
- package/dist/agi/container.server.d.ts.map +1 -0
- package/dist/agi/endpoints/ask.d.ts +20 -0
- package/dist/agi/endpoints/ask.d.ts.map +1 -0
- package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
- package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
- package/dist/agi/endpoints/conversations.d.ts +18 -0
- package/dist/agi/endpoints/conversations.d.ts.map +1 -0
- package/dist/agi/endpoints/experts.d.ts +8 -0
- package/dist/agi/endpoints/experts.d.ts.map +1 -0
- package/dist/agi/feature.d.ts +9 -0
- package/dist/agi/feature.d.ts.map +1 -0
- package/dist/agi/features/assistant.d.ts +509 -0
- package/dist/agi/features/assistant.d.ts.map +1 -0
- package/dist/agi/features/assistants-manager.d.ts +236 -0
- package/dist/agi/features/assistants-manager.d.ts.map +1 -0
- package/dist/agi/features/autonomous-assistant.d.ts +281 -0
- package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
- package/dist/agi/features/browser-use.d.ts +479 -0
- package/dist/agi/features/browser-use.d.ts.map +1 -0
- package/dist/agi/features/claude-code.d.ts +824 -0
- package/dist/agi/features/claude-code.d.ts.map +1 -0
- package/dist/agi/features/conversation-history.d.ts +245 -0
- package/dist/agi/features/conversation-history.d.ts.map +1 -0
- package/dist/agi/features/conversation.d.ts +464 -0
- package/dist/agi/features/conversation.d.ts.map +1 -0
- package/dist/agi/features/docs-reader.d.ts +72 -0
- package/dist/agi/features/docs-reader.d.ts.map +1 -0
- package/dist/agi/features/file-tools.d.ts +110 -0
- package/dist/agi/features/file-tools.d.ts.map +1 -0
- package/dist/agi/features/luca-coder.d.ts +323 -0
- package/dist/agi/features/luca-coder.d.ts.map +1 -0
- package/dist/agi/features/openai-codex.d.ts +381 -0
- package/dist/agi/features/openai-codex.d.ts.map +1 -0
- package/dist/agi/features/openapi.d.ts +200 -0
- package/dist/agi/features/openapi.d.ts.map +1 -0
- package/dist/agi/features/skills-library.d.ts +167 -0
- package/dist/agi/features/skills-library.d.ts.map +1 -0
- package/dist/agi/index.d.ts +5 -0
- package/dist/agi/index.d.ts.map +1 -0
- package/dist/agi/lib/interceptor-chain.d.ts +44 -0
- package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
- package/dist/agi/lib/token-counter.d.ts +13 -0
- package/dist/agi/lib/token-counter.d.ts.map +1 -0
- package/dist/bootstrap/generated.d.ts +5 -0
- package/dist/bootstrap/generated.d.ts.map +1 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/bus.d.ts +29 -0
- package/dist/bus.d.ts.map +1 -0
- package/dist/cli/build-info.d.ts +4 -0
- package/dist/cli/build-info.d.ts.map +1 -0
- package/dist/cli/cli.d.ts +3 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/client.d.ts +60 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/clients/civitai/index.d.ts +472 -0
- package/dist/clients/civitai/index.d.ts.map +1 -0
- package/dist/clients/client-template.d.ts +30 -0
- package/dist/clients/client-template.d.ts.map +1 -0
- package/dist/clients/comfyui/index.d.ts +281 -0
- package/dist/clients/comfyui/index.d.ts.map +1 -0
- package/dist/clients/elevenlabs/index.d.ts +197 -0
- package/dist/clients/elevenlabs/index.d.ts.map +1 -0
- package/dist/clients/graph.d.ts +64 -0
- package/dist/clients/graph.d.ts.map +1 -0
- package/dist/clients/openai/index.d.ts +247 -0
- package/dist/clients/openai/index.d.ts.map +1 -0
- package/dist/clients/rest.d.ts +92 -0
- package/dist/clients/rest.d.ts.map +1 -0
- package/dist/clients/supabase/index.d.ts +176 -0
- package/dist/clients/supabase/index.d.ts.map +1 -0
- package/dist/clients/websocket.d.ts +127 -0
- package/dist/clients/websocket.d.ts.map +1 -0
- package/dist/command.d.ts +163 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/commands/bootstrap.d.ts +20 -0
- package/dist/commands/bootstrap.d.ts.map +1 -0
- package/dist/commands/chat.d.ts +37 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/code.d.ts +28 -0
- package/dist/commands/code.d.ts.map +1 -0
- package/dist/commands/console.d.ts +22 -0
- package/dist/commands/console.d.ts.map +1 -0
- package/dist/commands/describe.d.ts +50 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/eval.d.ts +23 -0
- package/dist/commands/eval.d.ts.map +1 -0
- package/dist/commands/help.d.ts +25 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/index.d.ts +18 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/introspect.d.ts +24 -0
- package/dist/commands/introspect.d.ts.map +1 -0
- package/dist/commands/mcp.d.ts +35 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/prompt.d.ts +38 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/run.d.ts +24 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/sandbox-mcp.d.ts +34 -0
- package/dist/commands/sandbox-mcp.d.ts.map +1 -0
- package/dist/commands/save-api-docs.d.ts +21 -0
- package/dist/commands/save-api-docs.d.ts.map +1 -0
- package/dist/commands/scaffold.d.ts +24 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/select.d.ts +22 -0
- package/dist/commands/select.d.ts.map +1 -0
- package/dist/commands/serve.d.ts +29 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/container-describer.d.ts +144 -0
- package/dist/container-describer.d.ts.map +1 -0
- package/dist/container.d.ts +451 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/endpoint.d.ts +113 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/feature.d.ts +47 -0
- package/dist/feature.d.ts.map +1 -0
- package/dist/graft.d.ts +29 -0
- package/dist/graft.d.ts.map +1 -0
- package/dist/hash-object.d.ts +8 -0
- package/dist/hash-object.d.ts.map +1 -0
- package/dist/helper.d.ts +209 -0
- package/dist/helper.d.ts.map +1 -0
- package/dist/introspection/generated.node.d.ts +44623 -0
- package/dist/introspection/generated.node.d.ts.map +1 -0
- package/dist/introspection/generated.web.d.ts +1412 -0
- package/dist/introspection/generated.web.d.ts.map +1 -0
- package/dist/introspection/index.d.ts +156 -0
- package/dist/introspection/index.d.ts.map +1 -0
- package/dist/introspection/scan.d.ts +147 -0
- package/dist/introspection/scan.d.ts.map +1 -0
- package/dist/node/container.d.ts +256 -0
- package/dist/node/container.d.ts.map +1 -0
- package/dist/node/feature.d.ts +9 -0
- package/dist/node/feature.d.ts.map +1 -0
- package/dist/node/features/container-link.d.ts +213 -0
- package/dist/node/features/container-link.d.ts.map +1 -0
- package/dist/node/features/content-db.d.ts +354 -0
- package/dist/node/features/content-db.d.ts.map +1 -0
- package/dist/node/features/disk-cache.d.ts +236 -0
- package/dist/node/features/disk-cache.d.ts.map +1 -0
- package/dist/node/features/dns.d.ts +511 -0
- package/dist/node/features/dns.d.ts.map +1 -0
- package/dist/node/features/docker.d.ts +485 -0
- package/dist/node/features/docker.d.ts.map +1 -0
- package/dist/node/features/downloader.d.ts +73 -0
- package/dist/node/features/downloader.d.ts.map +1 -0
- package/dist/node/features/figlet-fonts.d.ts +4 -0
- package/dist/node/features/figlet-fonts.d.ts.map +1 -0
- package/dist/node/features/file-manager.d.ts +177 -0
- package/dist/node/features/file-manager.d.ts.map +1 -0
- package/dist/node/features/fs.d.ts +635 -0
- package/dist/node/features/fs.d.ts.map +1 -0
- package/dist/node/features/git.d.ts +329 -0
- package/dist/node/features/git.d.ts.map +1 -0
- package/dist/node/features/google-auth.d.ts +200 -0
- package/dist/node/features/google-auth.d.ts.map +1 -0
- package/dist/node/features/google-calendar.d.ts +194 -0
- package/dist/node/features/google-calendar.d.ts.map +1 -0
- package/dist/node/features/google-docs.d.ts +138 -0
- package/dist/node/features/google-docs.d.ts.map +1 -0
- package/dist/node/features/google-drive.d.ts +202 -0
- package/dist/node/features/google-drive.d.ts.map +1 -0
- package/dist/node/features/google-mail.d.ts +221 -0
- package/dist/node/features/google-mail.d.ts.map +1 -0
- package/dist/node/features/google-sheets.d.ts +157 -0
- package/dist/node/features/google-sheets.d.ts.map +1 -0
- package/dist/node/features/grep.d.ts +207 -0
- package/dist/node/features/grep.d.ts.map +1 -0
- package/dist/node/features/helpers.d.ts +236 -0
- package/dist/node/features/helpers.d.ts.map +1 -0
- package/dist/node/features/ink.d.ts +332 -0
- package/dist/node/features/ink.d.ts.map +1 -0
- package/dist/node/features/ipc-socket.d.ts +298 -0
- package/dist/node/features/ipc-socket.d.ts.map +1 -0
- package/dist/node/features/json-tree.d.ts +140 -0
- package/dist/node/features/json-tree.d.ts.map +1 -0
- package/dist/node/features/networking.d.ts +373 -0
- package/dist/node/features/networking.d.ts.map +1 -0
- package/dist/node/features/nlp.d.ts +125 -0
- package/dist/node/features/nlp.d.ts.map +1 -0
- package/dist/node/features/opener.d.ts +93 -0
- package/dist/node/features/opener.d.ts.map +1 -0
- package/dist/node/features/os.d.ts +168 -0
- package/dist/node/features/os.d.ts.map +1 -0
- package/dist/node/features/package-finder.d.ts +419 -0
- package/dist/node/features/package-finder.d.ts.map +1 -0
- package/dist/node/features/postgres.d.ts +173 -0
- package/dist/node/features/postgres.d.ts.map +1 -0
- package/dist/node/features/proc.d.ts +285 -0
- package/dist/node/features/proc.d.ts.map +1 -0
- package/dist/node/features/process-manager.d.ts +427 -0
- package/dist/node/features/process-manager.d.ts.map +1 -0
- package/dist/node/features/python.d.ts +477 -0
- package/dist/node/features/python.d.ts.map +1 -0
- package/dist/node/features/redis.d.ts +247 -0
- package/dist/node/features/redis.d.ts.map +1 -0
- package/dist/node/features/repl.d.ts +84 -0
- package/dist/node/features/repl.d.ts.map +1 -0
- package/dist/node/features/runpod.d.ts +527 -0
- package/dist/node/features/runpod.d.ts.map +1 -0
- package/dist/node/features/secure-shell.d.ts +145 -0
- package/dist/node/features/secure-shell.d.ts.map +1 -0
- package/dist/node/features/semantic-search.d.ts +207 -0
- package/dist/node/features/semantic-search.d.ts.map +1 -0
- package/dist/node/features/sqlite.d.ts +180 -0
- package/dist/node/features/sqlite.d.ts.map +1 -0
- package/dist/node/features/telegram.d.ts +173 -0
- package/dist/node/features/telegram.d.ts.map +1 -0
- package/dist/node/features/transpiler.d.ts +51 -0
- package/dist/node/features/transpiler.d.ts.map +1 -0
- package/dist/node/features/tts.d.ts +108 -0
- package/dist/node/features/tts.d.ts.map +1 -0
- package/dist/node/features/ui.d.ts +562 -0
- package/dist/node/features/ui.d.ts.map +1 -0
- package/dist/node/features/vault.d.ts +90 -0
- package/dist/node/features/vault.d.ts.map +1 -0
- package/dist/node/features/vm.d.ts +285 -0
- package/dist/node/features/vm.d.ts.map +1 -0
- package/dist/node/features/yaml-tree.d.ts +118 -0
- package/dist/node/features/yaml-tree.d.ts.map +1 -0
- package/dist/node/features/yaml.d.ts +127 -0
- package/dist/node/features/yaml.d.ts.map +1 -0
- package/dist/node.d.ts +67 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/python/generated.d.ts +2 -0
- package/dist/python/generated.d.ts.map +1 -0
- package/dist/react/index.d.ts +36 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/registry.d.ts +97 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/scaffolds/generated.d.ts +13 -0
- package/dist/scaffolds/generated.d.ts.map +1 -0
- package/dist/scaffolds/template.d.ts +11 -0
- package/dist/scaffolds/template.d.ts.map +1 -0
- package/dist/schemas/base.d.ts +254 -0
- package/dist/schemas/base.d.ts.map +1 -0
- package/dist/selector.d.ts +130 -0
- package/dist/selector.d.ts.map +1 -0
- package/dist/server.d.ts +89 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/servers/express.d.ts +104 -0
- package/dist/servers/express.d.ts.map +1 -0
- package/dist/servers/mcp.d.ts +201 -0
- package/dist/servers/mcp.d.ts.map +1 -0
- package/dist/servers/socket.d.ts +121 -0
- package/dist/servers/socket.d.ts.map +1 -0
- package/dist/state.d.ts +24 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/web/clients/socket.d.ts +37 -0
- package/dist/web/clients/socket.d.ts.map +1 -0
- package/dist/web/container.d.ts +55 -0
- package/dist/web/container.d.ts.map +1 -0
- package/dist/web/extension.d.ts +4 -0
- package/dist/web/extension.d.ts.map +1 -0
- package/dist/web/feature.d.ts +8 -0
- package/dist/web/feature.d.ts.map +1 -0
- package/dist/web/features/asset-loader.d.ts +35 -0
- package/dist/web/features/asset-loader.d.ts.map +1 -0
- package/dist/web/features/container-link.d.ts +167 -0
- package/dist/web/features/container-link.d.ts.map +1 -0
- package/dist/web/features/esbuild.d.ts +51 -0
- package/dist/web/features/esbuild.d.ts.map +1 -0
- package/dist/web/features/helpers.d.ts +140 -0
- package/dist/web/features/helpers.d.ts.map +1 -0
- package/dist/web/features/network.d.ts +69 -0
- package/dist/web/features/network.d.ts.map +1 -0
- package/dist/web/features/speech.d.ts +71 -0
- package/dist/web/features/speech.d.ts.map +1 -0
- package/dist/web/features/vault.d.ts +62 -0
- package/dist/web/features/vault.d.ts.map +1 -0
- package/dist/web/features/vm.d.ts +48 -0
- package/dist/web/features/vm.d.ts.map +1 -0
- package/dist/web/features/voice-recognition.d.ts +96 -0
- package/dist/web/features/voice-recognition.d.ts.map +1 -0
- package/dist/web/shims/isomorphic-vm.d.ts +22 -0
- package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
- package/docs/CLI.md +335 -0
- package/docs/CNAME +1 -0
- package/docs/README.md +60 -0
- package/docs/TABLE-OF-CONTENTS.md +183 -0
- package/docs/apis/clients/elevenlabs.md +308 -0
- package/docs/apis/clients/graph.md +107 -0
- package/docs/apis/clients/openai.md +429 -0
- package/docs/apis/clients/rest.md +161 -0
- package/docs/apis/clients/websocket.md +174 -0
- package/docs/apis/features/agi/assistant.md +625 -0
- package/docs/apis/features/agi/assistants-manager.md +282 -0
- package/docs/apis/features/agi/auto-assistant.md +279 -0
- package/docs/apis/features/agi/browser-use.md +802 -0
- package/docs/apis/features/agi/claude-code.md +884 -0
- package/docs/apis/features/agi/conversation-history.md +364 -0
- package/docs/apis/features/agi/conversation.md +548 -0
- package/docs/apis/features/agi/docs-reader.md +99 -0
- package/docs/apis/features/agi/file-tools.md +163 -0
- package/docs/apis/features/agi/luca-coder.md +407 -0
- package/docs/apis/features/agi/openai-codex.md +396 -0
- package/docs/apis/features/agi/openapi.md +138 -0
- package/docs/apis/features/agi/semantic-search.md +387 -0
- package/docs/apis/features/agi/skills-library.md +239 -0
- package/docs/apis/features/node/container-link.md +192 -0
- package/docs/apis/features/node/content-db.md +450 -0
- package/docs/apis/features/node/disk-cache.md +379 -0
- package/docs/apis/features/node/dns.md +652 -0
- package/docs/apis/features/node/docker.md +706 -0
- package/docs/apis/features/node/downloader.md +81 -0
- package/docs/apis/features/node/esbuild.md +60 -0
- package/docs/apis/features/node/file-manager.md +191 -0
- package/docs/apis/features/node/fs.md +1217 -0
- package/docs/apis/features/node/git.md +371 -0
- package/docs/apis/features/node/google-auth.md +193 -0
- package/docs/apis/features/node/google-calendar.md +202 -0
- package/docs/apis/features/node/google-docs.md +173 -0
- package/docs/apis/features/node/google-drive.md +246 -0
- package/docs/apis/features/node/google-mail.md +214 -0
- package/docs/apis/features/node/google-sheets.md +194 -0
- package/docs/apis/features/node/grep.md +292 -0
- package/docs/apis/features/node/helpers.md +164 -0
- package/docs/apis/features/node/ink.md +334 -0
- package/docs/apis/features/node/ipc-socket.md +249 -0
- package/docs/apis/features/node/json-tree.md +86 -0
- package/docs/apis/features/node/networking.md +316 -0
- package/docs/apis/features/node/nlp.md +133 -0
- package/docs/apis/features/node/opener.md +97 -0
- package/docs/apis/features/node/os.md +146 -0
- package/docs/apis/features/node/package-finder.md +392 -0
- package/docs/apis/features/node/postgres.md +234 -0
- package/docs/apis/features/node/proc.md +399 -0
- package/docs/apis/features/node/process-manager.md +305 -0
- package/docs/apis/features/node/python.md +604 -0
- package/docs/apis/features/node/redis.md +380 -0
- package/docs/apis/features/node/repl.md +88 -0
- package/docs/apis/features/node/runpod.md +674 -0
- package/docs/apis/features/node/secure-shell.md +176 -0
- package/docs/apis/features/node/semantic-search.md +408 -0
- package/docs/apis/features/node/sqlite.md +233 -0
- package/docs/apis/features/node/telegram.md +279 -0
- package/docs/apis/features/node/transpiler.md +74 -0
- package/docs/apis/features/node/tts.md +133 -0
- package/docs/apis/features/node/ui.md +701 -0
- package/docs/apis/features/node/vault.md +59 -0
- package/docs/apis/features/node/vm.md +75 -0
- package/docs/apis/features/node/yaml-tree.md +85 -0
- package/docs/apis/features/node/yaml.md +176 -0
- package/docs/apis/features/web/asset-loader.md +59 -0
- package/docs/apis/features/web/container-link.md +192 -0
- package/docs/apis/features/web/esbuild.md +54 -0
- package/docs/apis/features/web/helpers.md +164 -0
- package/docs/apis/features/web/network.md +44 -0
- package/docs/apis/features/web/speech.md +69 -0
- package/docs/apis/features/web/vault.md +59 -0
- package/docs/apis/features/web/vm.md +75 -0
- package/docs/apis/features/web/voice.md +84 -0
- package/docs/apis/servers/express.md +171 -0
- package/docs/apis/servers/mcp.md +238 -0
- package/docs/apis/servers/websocket.md +170 -0
- package/docs/bootstrap/CLAUDE.md +101 -0
- package/docs/bootstrap/SKILL.md +341 -0
- package/docs/bootstrap/templates/about-command.ts +41 -0
- package/docs/bootstrap/templates/docs-models.ts +22 -0
- package/docs/bootstrap/templates/docs-readme.md +43 -0
- package/docs/bootstrap/templates/example-feature.ts +53 -0
- package/docs/bootstrap/templates/health-endpoint.ts +15 -0
- package/docs/bootstrap/templates/luca-cli.ts +30 -0
- package/docs/bootstrap/templates/runme.md +54 -0
- package/docs/challenges/caching-proxy.md +16 -0
- package/docs/challenges/content-db-round-trip.md +14 -0
- package/docs/challenges/custom-command.md +9 -0
- package/docs/challenges/file-watcher-pipeline.md +11 -0
- package/docs/challenges/grep-audit-report.md +15 -0
- package/docs/challenges/multi-feature-dashboard.md +14 -0
- package/docs/challenges/process-orchestrator.md +17 -0
- package/docs/challenges/rest-api-server-with-client.md +12 -0
- package/docs/challenges/script-runner-with-vm.md +11 -0
- package/docs/challenges/simple-rest-api.md +15 -0
- package/docs/challenges/websocket-serve-and-client.md +11 -0
- package/docs/challenges/yaml-config-system.md +14 -0
- package/docs/command-system-overhaul.md +94 -0
- package/docs/documentation-audit.md +134 -0
- package/docs/examples/assistant/CORE.md +18 -0
- package/docs/examples/assistant/hooks.ts +3 -0
- package/docs/examples/assistant/tools.ts +10 -0
- package/docs/examples/assistant-hooks-reference.ts +171 -0
- package/docs/examples/assistant-with-process-manager.md +84 -0
- package/docs/examples/content-db.md +77 -0
- package/docs/examples/disk-cache.md +83 -0
- package/docs/examples/docker.md +101 -0
- package/docs/examples/downloader.md +70 -0
- package/docs/examples/entity.md +124 -0
- package/docs/examples/esbuild.md +80 -0
- package/docs/examples/feature-as-tool-provider.md +143 -0
- package/docs/examples/file-manager.md +82 -0
- package/docs/examples/fs.md +83 -0
- package/docs/examples/git.md +85 -0
- package/docs/examples/google-auth.md +88 -0
- package/docs/examples/google-calendar.md +94 -0
- package/docs/examples/google-docs.md +82 -0
- package/docs/examples/google-drive.md +96 -0
- package/docs/examples/google-sheets.md +95 -0
- package/docs/examples/grep.md +85 -0
- package/docs/examples/ink-blocks.md +75 -0
- package/docs/examples/ink-renderer.md +41 -0
- package/docs/examples/ink.md +103 -0
- package/docs/examples/ipc-socket.md +103 -0
- package/docs/examples/json-tree.md +91 -0
- package/docs/examples/networking.md +58 -0
- package/docs/examples/nlp.md +91 -0
- package/docs/examples/opener.md +78 -0
- package/docs/examples/os.md +72 -0
- package/docs/examples/package-finder.md +89 -0
- package/docs/examples/postgres.md +91 -0
- package/docs/examples/proc.md +81 -0
- package/docs/examples/process-manager.md +79 -0
- package/docs/examples/python.md +132 -0
- package/docs/examples/repl.md +93 -0
- package/docs/examples/runpod.md +119 -0
- package/docs/examples/secure-shell.md +92 -0
- package/docs/examples/sqlite.md +86 -0
- package/docs/examples/structured-output-with-assistants.md +144 -0
- package/docs/examples/telegram.md +77 -0
- package/docs/examples/tts.md +86 -0
- package/docs/examples/ui.md +80 -0
- package/docs/examples/vault.md +70 -0
- package/docs/examples/vm.md +86 -0
- package/docs/examples/websocket-ask-and-reply-example.md +128 -0
- package/docs/examples/yaml-tree.md +93 -0
- package/docs/examples/yaml.md +104 -0
- package/docs/ideas/assistant-factory-pattern.md +142 -0
- package/docs/in-memory-fs.md +4 -0
- package/docs/introspection-audit.md +49 -0
- package/docs/introspection.md +164 -0
- package/docs/mcp/readme.md +162 -0
- package/docs/models.ts +41 -0
- package/docs/philosophy.md +86 -0
- package/docs/principles.md +7 -0
- package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
- package/docs/prompts/check-for-undocumented-features.md +27 -0
- package/docs/prompts/mcp-test-easy-command.md +27 -0
- package/docs/scaffolds/client.md +149 -0
- package/docs/scaffolds/command.md +120 -0
- package/docs/scaffolds/endpoint.md +171 -0
- package/docs/scaffolds/feature.md +158 -0
- package/docs/scaffolds/selector.md +91 -0
- package/docs/scaffolds/server.md +196 -0
- package/docs/selectors.md +115 -0
- package/docs/sessions/custom-command/attempt-log-2.md +195 -0
- package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +728 -0
- package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +555 -0
- package/docs/sessions/grep-audit-report/attempt-log-1.md +289 -0
- package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +679 -0
- package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +1 -0
- package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +920 -0
- package/docs/sessions/simple-rest-api/attempt-log-1.md +593 -0
- package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +995 -0
- package/docs/tutorials/00-bootstrap.md +166 -0
- package/docs/tutorials/01-getting-started.md +106 -0
- package/docs/tutorials/02-container.md +210 -0
- package/docs/tutorials/03-scripts.md +194 -0
- package/docs/tutorials/04-features-overview.md +196 -0
- package/docs/tutorials/05-state-and-events.md +171 -0
- package/docs/tutorials/06-servers.md +157 -0
- package/docs/tutorials/07-endpoints.md +198 -0
- package/docs/tutorials/08-commands.md +252 -0
- package/docs/tutorials/09-clients.md +162 -0
- package/docs/tutorials/10-creating-features.md +203 -0
- package/docs/tutorials/11-contentbase.md +191 -0
- package/docs/tutorials/12-assistants.md +215 -0
- package/docs/tutorials/13-introspection.md +157 -0
- package/docs/tutorials/14-type-system.md +174 -0
- package/docs/tutorials/15-project-patterns.md +222 -0
- package/docs/tutorials/16-google-features.md +534 -0
- package/docs/tutorials/17-tui-blocks.md +530 -0
- package/docs/tutorials/18-semantic-search.md +334 -0
- package/docs/tutorials/19-python-sessions.md +401 -0
- package/docs/tutorials/20-browser-esm.md +234 -0
- package/index.html +1430 -0
- package/index.ts +1 -0
- package/install.sh +84 -0
- package/luca.cli.ts +16 -0
- package/luca.console.ts +9 -0
- package/main.py +6 -0
- package/package.json +219 -66
- package/public/index.html +1430 -0
- package/public/slides-ai-native.html +902 -0
- package/public/slides-intro.html +974 -0
- package/pyproject.toml +7 -0
- package/scripts/build-web.ts +28 -0
- package/scripts/examples/ask-luca-expert.ts +42 -0
- package/scripts/examples/assistant-questions.ts +12 -0
- package/scripts/examples/excalidraw-expert.ts +75 -0
- package/scripts/examples/expert-chat.ts +0 -0
- package/scripts/examples/file-manager.ts +14 -0
- package/scripts/examples/ideas.ts +12 -0
- package/scripts/examples/interactive-chat.ts +20 -0
- package/scripts/examples/openai-tool-calls.ts +113 -0
- package/scripts/examples/opening-a-web-browser.ts +5 -0
- package/scripts/examples/telegram-bot.ts +79 -0
- package/scripts/examples/using-assistant-with-mcp.ts +555 -0
- package/scripts/examples/using-claude-code.ts +10 -0
- package/scripts/examples/using-contentdb.ts +35 -0
- package/scripts/examples/using-conversations.ts +35 -0
- package/scripts/examples/using-disk-cache.ts +10 -0
- package/scripts/examples/using-docker-shell.ts +75 -0
- package/scripts/examples/using-elevenlabs.ts +25 -0
- package/scripts/examples/using-google-calendar.ts +57 -0
- package/scripts/examples/using-google-docs.ts +74 -0
- package/scripts/examples/using-google-drive.ts +74 -0
- package/scripts/examples/using-google-sheets.ts +89 -0
- package/scripts/examples/using-nlp.ts +55 -0
- package/scripts/examples/using-ollama.ts +11 -0
- package/scripts/examples/using-postgres.ts +55 -0
- package/scripts/examples/using-runpod.ts +32 -0
- package/scripts/examples/using-tts.ts +40 -0
- package/scripts/scaffold.ts +391 -0
- package/scripts/scratch.ts +15 -0
- package/scripts/stamp-build.sh +12 -0
- package/scripts/test-assistant-hooks.ts +13 -0
- package/scripts/test-docs-reader.ts +10 -0
- package/scripts/test-linux-binary.sh +80 -0
- package/scripts/update-introspection-data.ts +58 -0
- package/src/agi/README.md +14 -0
- package/src/agi/container.server.ts +152 -0
- package/src/agi/endpoints/ask.ts +60 -0
- package/src/agi/endpoints/conversations/[id].ts +45 -0
- package/src/agi/endpoints/conversations.ts +31 -0
- package/src/agi/endpoints/experts.ts +37 -0
- package/src/agi/feature.ts +13 -0
- package/src/agi/features/agent-memory.ts +694 -0
- package/src/agi/features/assistant.ts +1624 -0
- package/src/agi/features/assistants-manager.ts +418 -0
- package/src/agi/features/autonomous-assistant.ts +431 -0
- package/src/agi/features/browser-use.ts +653 -0
- package/src/agi/features/claude-code.ts +1538 -0
- package/src/agi/features/coding-tools.ts +175 -0
- package/src/agi/features/conversation-history.ts +495 -0
- package/src/agi/features/conversation.ts +1323 -0
- package/src/agi/features/docs-reader.ts +167 -0
- package/src/agi/features/file-tools.ts +293 -0
- package/src/agi/features/luca-coder.ts +639 -0
- package/src/agi/features/openai-codex.ts +651 -0
- package/src/agi/features/openapi.ts +445 -0
- package/src/agi/features/skills-library.ts +478 -0
- package/src/agi/index.ts +6 -0
- package/src/agi/lib/interceptor-chain.ts +89 -0
- package/src/agi/lib/token-counter.ts +122 -0
- package/src/bootstrap/generated.ts +9792 -0
- package/src/browser.ts +25 -0
- package/src/bus.ts +122 -0
- package/src/cli/build-info.ts +4 -0
- package/src/cli/cli.ts +355 -0
- package/src/client.ts +170 -0
- package/src/clients/civitai/index.ts +537 -0
- package/src/clients/client-template.ts +41 -0
- package/src/clients/comfyui/index.ts +604 -0
- package/src/clients/elevenlabs/index.ts +317 -0
- package/src/clients/graph.ts +87 -0
- package/src/clients/openai/index.ts +456 -0
- package/src/clients/rest.ts +207 -0
- package/src/clients/supabase/index.ts +357 -0
- package/src/clients/voicebox/index.ts +300 -0
- package/src/clients/websocket.ts +251 -0
- package/src/command.ts +505 -0
- package/src/commands/bootstrap.ts +244 -0
- package/src/commands/chat.ts +308 -0
- package/src/commands/code.ts +371 -0
- package/src/commands/console.ts +189 -0
- package/src/commands/describe.ts +243 -0
- package/src/commands/eval.ts +121 -0
- package/src/commands/help.ts +240 -0
- package/src/commands/index.ts +19 -0
- package/src/commands/introspect.ts +218 -0
- package/src/commands/mcp.ts +64 -0
- package/src/commands/prompt.ts +982 -0
- package/src/commands/run.ts +278 -0
- package/src/commands/sandbox-mcp.ts +343 -0
- package/src/commands/save-api-docs.ts +51 -0
- package/src/commands/scaffold.ts +225 -0
- package/src/commands/select.ts +99 -0
- package/src/commands/serve.ts +208 -0
- package/src/container-describer.ts +1084 -0
- package/src/container.ts +1186 -0
- package/src/endpoint.ts +365 -0
- package/src/entity.ts +173 -0
- package/src/feature.ts +118 -0
- package/src/graft.ts +181 -0
- package/src/hash-object.ts +97 -0
- package/src/helper.ts +849 -0
- package/src/introspection/generated.agi.ts +40208 -0
- package/src/introspection/generated.node.ts +28686 -0
- package/src/introspection/generated.web.ts +2251 -0
- package/src/introspection/index.ts +296 -0
- package/src/introspection/scan.ts +1131 -0
- package/src/node/container.ts +409 -0
- package/src/node/feature.ts +13 -0
- package/src/node/features/container-link.ts +559 -0
- package/src/node/features/content-db.ts +812 -0
- package/src/node/features/disk-cache.ts +388 -0
- package/src/node/features/dns.ts +669 -0
- package/src/node/features/docker.ts +921 -0
- package/src/node/features/downloader.ts +79 -0
- package/src/node/features/figlet-fonts.ts +600 -0
- package/src/node/features/file-manager.ts +535 -0
- package/src/node/features/fs.ts +1050 -0
- package/src/node/features/git.ts +592 -0
- package/src/node/features/google-auth.ts +504 -0
- package/src/node/features/google-calendar.ts +306 -0
- package/src/node/features/google-docs.ts +412 -0
- package/src/node/features/google-drive.ts +346 -0
- package/src/node/features/google-mail.ts +540 -0
- package/src/node/features/google-sheets.ts +286 -0
- package/src/node/features/grep.ts +427 -0
- package/src/node/features/helpers.ts +735 -0
- package/src/node/features/ink.ts +490 -0
- package/src/node/features/ipc-socket.ts +649 -0
- package/src/node/features/json-tree.ts +170 -0
- package/src/node/features/networking.ts +961 -0
- package/src/node/features/nlp.ts +212 -0
- package/src/node/features/opener.ts +180 -0
- package/src/node/features/os.ts +403 -0
- package/src/node/features/package-finder.ts +540 -0
- package/src/node/features/postgres.ts +289 -0
- package/src/node/features/proc.ts +503 -0
- package/src/node/features/process-manager.ts +844 -0
- package/src/node/features/python.ts +906 -0
- package/src/node/features/redis.ts +446 -0
- package/src/node/features/repl.ts +212 -0
- package/src/node/features/runpod.ts +811 -0
- package/src/node/features/secure-shell.ts +267 -0
- package/src/node/features/semantic-search.ts +935 -0
- package/src/node/features/sqlite.ts +289 -0
- package/src/node/features/telegram.ts +343 -0
- package/src/node/features/transpiler.ts +161 -0
- package/src/node/features/tts.ts +185 -0
- package/src/node/features/ui.ts +786 -0
- package/src/node/features/vault.ts +153 -0
- package/src/node/features/vm.ts +462 -0
- package/src/node/features/yaml-tree.ts +148 -0
- package/src/node/features/yaml.ts +133 -0
- package/src/node.ts +76 -0
- package/src/python/bridge.py +220 -0
- package/src/python/generated.ts +227 -0
- package/src/react/index.ts +175 -0
- package/src/registry.ts +210 -0
- package/src/scaffolds/generated.ts +1815 -0
- package/src/scaffolds/template.ts +46 -0
- package/src/schemas/base.ts +296 -0
- package/src/selector.ts +352 -0
- package/src/server.ts +229 -0
- package/src/servers/express.ts +283 -0
- package/src/servers/mcp.ts +802 -0
- package/src/servers/socket.ts +258 -0
- package/src/state.ts +101 -0
- package/src/web/clients/socket.ts +99 -0
- package/src/web/container.ts +75 -0
- package/src/web/extension.ts +30 -0
- package/src/web/feature.ts +12 -0
- package/src/web/features/asset-loader.ts +72 -0
- package/src/web/features/container-link.ts +382 -0
- package/src/web/features/esbuild.ts +93 -0
- package/src/web/features/helpers.ts +269 -0
- package/src/web/features/network.ts +85 -0
- package/src/web/features/speech.ts +104 -0
- package/src/web/features/vault.ts +207 -0
- package/src/web/features/vm.ts +85 -0
- package/src/web/features/voice-recognition.ts +161 -0
- package/src/web/shims/isomorphic-vm.ts +149 -0
- package/test/assistant-hooks.test.ts +306 -0
- package/test/assistant.test.ts +81 -0
- package/test/bus.test.ts +134 -0
- package/test/clients-servers.test.ts +217 -0
- package/test/command.test.ts +267 -0
- package/test/container-link.test.ts +274 -0
- package/test/conversation.test.ts +220 -0
- package/test/features.test.ts +160 -0
- package/test/fork-and-research.test.ts +450 -0
- package/test/integration.test.ts +787 -0
- package/test/interceptor-chain.test.ts +61 -0
- package/test/node-container.test.ts +121 -0
- package/test/python-session.test.ts +105 -0
- package/test/rate-limit.test.ts +272 -0
- package/test/semantic-search.test.ts +550 -0
- package/test/state.test.ts +121 -0
- package/test/vm-context.test.ts +146 -0
- package/test/vm-loadmodule.test.ts +213 -0
- package/test/websocket-ask.test.ts +101 -0
- package/test-integration/assistant.test.ts +138 -0
- package/test-integration/assistants-manager.test.ts +113 -0
- package/test-integration/claude-code.test.ts +98 -0
- package/test-integration/conversation-history.test.ts +205 -0
- package/test-integration/conversation.test.ts +137 -0
- package/test-integration/elevenlabs.test.ts +55 -0
- package/test-integration/google-services.test.ts +80 -0
- package/test-integration/helpers.ts +89 -0
- package/test-integration/memory.test.ts +204 -0
- package/test-integration/openai-codex.test.ts +93 -0
- package/test-integration/runpod.test.ts +58 -0
- package/test-integration/server-endpoints.test.ts +97 -0
- package/test-integration/telegram.test.ts +46 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +58 -0
- package/uv.lock +8 -0
- package/LICENSE +0 -21
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -5
- package/dist/cli/run.d.ts +0 -12
- package/dist/cli/run.js +0 -42
- package/dist/config/consts.d.ts +0 -2
- package/dist/config/consts.js +0 -29
- package/dist/config/default.d.ts +0 -8
- package/dist/config/default.js +0 -15
- package/dist/config/initConfig.d.ts +0 -1
- package/dist/config/initConfig.js +0 -52
- package/dist/config/openConfig.d.ts +0 -2
- package/dist/config/openConfig.js +0 -24
- package/dist/config/runConfig.d.ts +0 -3
- package/dist/config/runConfig.js +0 -117
- package/dist/config/types.d.ts +0 -13
- package/dist/config/types.js +0 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -5
- package/dist/utils/common.d.ts +0 -2
- package/dist/utils/common.js +0 -52
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -17
package/src/container.ts
ADDED
|
@@ -0,0 +1,1186 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { Bus } from './bus'
|
|
3
|
+
import { SetStateValue, State } from './state'
|
|
4
|
+
import { AvailableFeatures, features, Feature, FeaturesRegistry } from './feature'
|
|
5
|
+
import { Helper, normalizeTypeString, renderTypeScriptParams, isGenericObjectType } from './helper'
|
|
6
|
+
import uuid from 'node-uuid'
|
|
7
|
+
import hashObject from './hash-object'
|
|
8
|
+
import { uniq, keyBy, uniqBy, groupBy, debounce, throttle, mapValues, mapKeys, pick, get, set, omit, kebabCase, camelCase, upperFirst, lowerFirst } from 'lodash-es'
|
|
9
|
+
import { pluralize, singularize } from 'inflect'
|
|
10
|
+
import { z } from 'zod'
|
|
11
|
+
import { ContainerStateSchema, describeZodShape } from './schemas/base'
|
|
12
|
+
import { getContainerBuildTimeData, type ContainerIntrospection, type RegistryIntrospection, type IntrospectionSection } from './introspection/index'
|
|
13
|
+
import { ContainerDescriber } from './container-describer'
|
|
14
|
+
import { createEntityObject, type Entity, type EventMap as EntityEventMap } from './entity'
|
|
15
|
+
|
|
16
|
+
export { z }
|
|
17
|
+
|
|
18
|
+
const { v4 } = uuid
|
|
19
|
+
|
|
20
|
+
const stringUtils = { kebabCase, camelCase, upperFirst, lowerFirst, pluralize, singularize }
|
|
21
|
+
|
|
22
|
+
export type { AvailableFeatures }
|
|
23
|
+
|
|
24
|
+
// I want the InstanceType of each value of AvailableFeatures, AvailableClients, whatever
|
|
25
|
+
export type AvailableInstanceTypes<T> = {
|
|
26
|
+
[K in keyof T]: T[K] extends new (...args: any) => any ? InstanceType<T[K]> : never
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Maps a feature registry to the INPUT type of each feature's optionsSchema.
|
|
31
|
+
* This allows feature() to accept partial/optional options (e.g. omitting fields
|
|
32
|
+
* that have .default() on them) rather than requiring the fully-parsed OUTPUT type.
|
|
33
|
+
*
|
|
34
|
+
* For any feature class that exposes a static `optionsSchema`, we use `z.input<S>` so
|
|
35
|
+
* that callers can omit fields that have `.default(...)` — Zod's output type marks
|
|
36
|
+
* defaulted fields as required, but the input type correctly makes them optional.
|
|
37
|
+
*/
|
|
38
|
+
export type FeatureInputOptions<Features> = {
|
|
39
|
+
[K in keyof Features]: Features[K] extends { optionsSchema: infer S extends z.ZodType }
|
|
40
|
+
? z.input<S>
|
|
41
|
+
: Features[K] extends new (options: infer O, ...args: any[]) => any
|
|
42
|
+
? O
|
|
43
|
+
: Record<string, unknown>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* You'll want to use module augmentation to add your own options to the ContainerArgv interface
|
|
48
|
+
*/
|
|
49
|
+
export interface ContainerArgv {
|
|
50
|
+
_?: string[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type ContainerState = z.infer<typeof ContainerStateSchema>
|
|
54
|
+
|
|
55
|
+
export interface Plugin<T> {
|
|
56
|
+
attach?: (container: Container<any> & T, options?: any) => any
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type Extension<T> = 'string' | keyof AvailableFeatures | Plugin<T> | { attach: (container: Container<any>, options?: any) => T}
|
|
60
|
+
|
|
61
|
+
export interface ContainerUtils {
|
|
62
|
+
/** Generate a v4 UUID */
|
|
63
|
+
uuid: () => string
|
|
64
|
+
/** Deterministic hash of any object */
|
|
65
|
+
hashObject: (obj: any) => string
|
|
66
|
+
/** String case conversion and inflection utilities */
|
|
67
|
+
stringUtils: { kebabCase: typeof kebabCase; camelCase: typeof camelCase; upperFirst: typeof upperFirst; lowerFirst: typeof lowerFirst; pluralize: typeof pluralize; singularize: typeof singularize }
|
|
68
|
+
/** Lodash utility subset */
|
|
69
|
+
lodash: { uniq: typeof uniq; keyBy: typeof keyBy; uniqBy: typeof uniqBy; groupBy: typeof groupBy; debounce: typeof debounce; throttle: typeof throttle; mapValues: typeof mapValues; mapKeys: typeof mapKeys; pick: typeof pick; get: typeof get; set: typeof set; omit: typeof omit }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ContainerContext<T extends AvailableFeatures = any> {
|
|
73
|
+
container: Container<T>
|
|
74
|
+
[key: string]: unknown
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The Container is the core runtime object in Luca. It is a singleton per process that acts as an
|
|
79
|
+
* event bus, state machine, and dependency injector. It holds registries of helpers (features, clients,
|
|
80
|
+
* servers, commands, endpoints) and provides factory methods to create instances from them.
|
|
81
|
+
*
|
|
82
|
+
* All helper instances share the container's context, enabling them to communicate and coordinate.
|
|
83
|
+
* The container detects its runtime environment (Node, Bun, browser, Electron) and can load
|
|
84
|
+
* platform-specific feature implementations accordingly.
|
|
85
|
+
*
|
|
86
|
+
* Use `container.feature('name')` to create feature instances, `container.use(Plugin)` to extend
|
|
87
|
+
* the container with new capabilities, and `container.on('event', handler)` to react to lifecycle events.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* // Create a feature instance (cached — same args return same instance)
|
|
92
|
+
* const fs = container.feature('fs')
|
|
93
|
+
* const content = fs.readFile('README.md')
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* // Listen for state changes
|
|
99
|
+
* container.on('stateChange', (state) => console.log('State changed:', state))
|
|
100
|
+
* container.setState({ started: true })
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* // Extend with a plugin
|
|
106
|
+
* container.use(MyClient) // calls MyClient.attach(container)
|
|
107
|
+
* container.use('contentDb') // enable a feature by name
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export class Container<Features extends AvailableFeatures = AvailableFeatures, ContainerState extends ContainerState = ContainerState > {
|
|
111
|
+
static stateSchema = ContainerStateSchema
|
|
112
|
+
|
|
113
|
+
readonly uuid = v4()
|
|
114
|
+
private readonly _events = new Bus()
|
|
115
|
+
private readonly _state: State<ContainerState>
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* You can use module augmentation to define the starting interface for your container
|
|
119
|
+
* whether it is process.argv, process.env, or some combination thereof
|
|
120
|
+
*/
|
|
121
|
+
readonly options: ContainerArgv
|
|
122
|
+
|
|
123
|
+
constructor(options: ContainerArgv) {
|
|
124
|
+
this.options = options
|
|
125
|
+
this._state = new State<ContainerState>()
|
|
126
|
+
this.z = z
|
|
127
|
+
this.state
|
|
128
|
+
.set('enabledFeatures', [])
|
|
129
|
+
.set('started', false)
|
|
130
|
+
.set('registries', ['features'])
|
|
131
|
+
.set('factories', ['feature'])
|
|
132
|
+
|
|
133
|
+
this._hide('options', '_state', '_events', 'uuid', '_plugins', 'z')
|
|
134
|
+
|
|
135
|
+
this.on('featureEnabled', (featureId: string, feature: any) => {
|
|
136
|
+
const featureKey = featureId.replace(/^features\./,'')
|
|
137
|
+
const mapKey = `${this.uuid}/${featureKey}`
|
|
138
|
+
featureIdToHelperCacheKeyMap.set(mapKey, feature.cacheKey)
|
|
139
|
+
this.state.set('enabledFeatures', uniq([
|
|
140
|
+
...this.state.get('enabledFeatures')!,
|
|
141
|
+
featureKey
|
|
142
|
+
]))
|
|
143
|
+
this.addContext(featureKey, feature)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
this.state.observe(() => {
|
|
147
|
+
this.emit('stateChange', this.state.current)
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Creates a new subcontainer instance of the same concrete Container subclass.
|
|
153
|
+
* The new instance is constructed with the same options as this container,
|
|
154
|
+
* shallow-merged with any overrides you provide. This preserves the runtime
|
|
155
|
+
* container type (e.g. NodeContainer, AGIContainer, etc.).
|
|
156
|
+
*
|
|
157
|
+
* @param options - Options to override for the new container instance
|
|
158
|
+
* @returns A new container instance of the same subclass
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* const child = container.subcontainer({ cwd: '/tmp/workspace' })
|
|
163
|
+
* child.cwd // '/tmp/workspace'
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
subcontainer<This extends Container<any, any>>(
|
|
167
|
+
this: This,
|
|
168
|
+
options: ConstructorParameters<This['constructor']>[0]
|
|
169
|
+
): This {
|
|
170
|
+
const Ctor = this.constructor as new (options: ConstructorParameters<This['constructor']>[0]) => This
|
|
171
|
+
const mergedOptions = {
|
|
172
|
+
...(this as any).options || {},
|
|
173
|
+
...(options || {}),
|
|
174
|
+
}
|
|
175
|
+
return new Ctor(mergedOptions)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
z!: typeof z
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
/** The observable state object for this container instance. */
|
|
182
|
+
get state(): State<ContainerState> {
|
|
183
|
+
return this._state
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Returns the list of shortcut IDs for all currently enabled features. */
|
|
187
|
+
get enabledFeatureIds(): string[] {
|
|
188
|
+
return this.state.get('enabledFeatures') || []
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Returns a map of enabled feature shortcut IDs to their instances. */
|
|
192
|
+
get enabledFeatures() : Partial<AvailableInstanceTypes<Features>> {
|
|
193
|
+
return Object.fromEntries(
|
|
194
|
+
this.enabledFeatureIds.map((featureId) => [featureId, (this as any)[featureId]])
|
|
195
|
+
) as AvailableInstanceTypes<Features>
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Common utilities available on every container. Provides UUID generation, object hashing,
|
|
200
|
+
* string case conversion, and lodash helpers — no imports needed.
|
|
201
|
+
*
|
|
202
|
+
* - `utils.uuid()` — generate a v4 UUID
|
|
203
|
+
* - `utils.hashObject(obj)` — deterministic hash of any object
|
|
204
|
+
* - `utils.stringUtils` — `{ kebabCase, camelCase, upperFirst, lowerFirst, pluralize, singularize }`
|
|
205
|
+
* - `utils.lodash` — `{ uniq, keyBy, uniqBy, groupBy, debounce, throttle, mapValues, mapKeys, pick, get, set, omit }`
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* const id = container.utils.uuid()
|
|
210
|
+
* const hash = container.utils.hashObject({ foo: 'bar' })
|
|
211
|
+
* const name = container.utils.stringUtils.camelCase('my-feature')
|
|
212
|
+
* const unique = container.utils.lodash.uniq([1, 2, 2, 3])
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
get utils(): ContainerUtils {
|
|
216
|
+
return {
|
|
217
|
+
hashObject: (obj: any) => hashObject(obj),
|
|
218
|
+
get stringUtils() { return stringUtils },
|
|
219
|
+
uuid: () => v4(),
|
|
220
|
+
lodash: {
|
|
221
|
+
uniq, keyBy, uniqBy, groupBy, debounce, throttle, mapValues, mapKeys, pick, get, set, omit,
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private _describer?: ContainerDescriber
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Lazy-initialized ContainerDescriber for introspecting registries, helpers, and members.
|
|
230
|
+
* @internal
|
|
231
|
+
*/
|
|
232
|
+
get describer(): ContainerDescriber {
|
|
233
|
+
if (!this._describer) {
|
|
234
|
+
this._describer = new ContainerDescriber(this)
|
|
235
|
+
}
|
|
236
|
+
return this._describer
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
addContext<K extends keyof ContainerContext>(key: K, value: ContainerContext[K]): this
|
|
240
|
+
addContext(context: Partial<ContainerContext>): this
|
|
241
|
+
/**
|
|
242
|
+
* Add a value to the container's shared context, which is passed to all helper instances.
|
|
243
|
+
* Accepts either a key and value, or an object of key-value pairs to merge in.
|
|
244
|
+
*
|
|
245
|
+
* @param key - The context key, or an object of key-value pairs to merge
|
|
246
|
+
* @param value - The context value (omit when passing an object)
|
|
247
|
+
* @returns The container instance (for chaining)
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```ts
|
|
251
|
+
* container.addContext('db', dbConnection)
|
|
252
|
+
* container.addContext({ db: dbConnection, cache: redisClient })
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
addContext(keyOrContext: keyof ContainerContext | Partial<ContainerContext>, value?: ContainerContext[keyof ContainerContext]): this {
|
|
256
|
+
if (arguments.length === 1 && typeof keyOrContext === 'object' && keyOrContext !== null) {
|
|
257
|
+
for (const [k, v] of Object.entries(keyOrContext)) {
|
|
258
|
+
if (v !== undefined) {
|
|
259
|
+
this.addContext(k as keyof ContainerContext, v as ContainerContext[keyof ContainerContext])
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return this
|
|
263
|
+
}
|
|
264
|
+
const contexts = contextMap.get(this) || new Map()
|
|
265
|
+
contexts.set(keyOrContext as keyof ContainerContext, value)
|
|
266
|
+
contextMap.set(this, contexts)
|
|
267
|
+
return this
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* The Container's context is an object that contains the enabled features, the container itself, and any additional context that has been added to the container.
|
|
272
|
+
*
|
|
273
|
+
* All helper instances that are created by the container will have access to the shared context.
|
|
274
|
+
*/
|
|
275
|
+
get context(): ContainerContext<Features> & Partial<AvailableInstanceTypes<AvailableFeatures>> {
|
|
276
|
+
const contexts = contextMap.get(this) || new Map()
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
...this.enabledFeatures,
|
|
280
|
+
...Object.fromEntries(Array.from(contexts.entries())) as ContainerContext<Features>,
|
|
281
|
+
container: this as Container<Features>,
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* The current state of the container.
|
|
287
|
+
*
|
|
288
|
+
* This is a snapshot of the container's state at the time this method is called.
|
|
289
|
+
*
|
|
290
|
+
* @returns The current state of the container.
|
|
291
|
+
*/
|
|
292
|
+
get currentState(): ContainerState {
|
|
293
|
+
return this.state.current
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Sets the state of the container. Accepts a partial state object to merge, or a function
|
|
298
|
+
* that receives the current state and returns the new state.
|
|
299
|
+
*
|
|
300
|
+
* @param newState - A partial state object to merge, or a function `(current) => newState`
|
|
301
|
+
* @returns The container instance (for chaining)
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```ts
|
|
305
|
+
* container.setState({ started: true })
|
|
306
|
+
* container.setState((prev) => ({ ...prev, started: true }))
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
setState(newState: SetStateValue<ContainerState>): this {
|
|
310
|
+
this.state.setState(newState)
|
|
311
|
+
return this
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
get Feature() {
|
|
315
|
+
return Feature
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
get Helper() {
|
|
319
|
+
return Helper
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
get State() {
|
|
323
|
+
return State
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* The features registry. Use it to check what features are available, look up feature classes,
|
|
328
|
+
* or check if a feature is registered.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```ts
|
|
332
|
+
* container.features.available // ['fs', 'git', 'grep', ...]
|
|
333
|
+
* container.features.has('fs') // true
|
|
334
|
+
* container.features.lookup('fs') // FS class
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
get features(): FeaturesRegistry {
|
|
338
|
+
return features
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Create a new standalone event bus instance. Useful when you need a scoped event channel
|
|
343
|
+
* that is independent of the container's own event bus.
|
|
344
|
+
*
|
|
345
|
+
* @returns A new Bus instance
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* const myBus = container.bus()
|
|
350
|
+
* myBus.on('data', (payload) => console.log(payload))
|
|
351
|
+
* myBus.emit('data', { count: 42 })
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
354
|
+
bus(): Bus {
|
|
355
|
+
return new Bus()
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Create a new standalone observable State object. Useful when you need reactive state
|
|
360
|
+
* that is independent of the container's own state.
|
|
361
|
+
*
|
|
362
|
+
* @param initialState - The initial state object (defaults to empty)
|
|
363
|
+
* @returns A new State instance
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```ts
|
|
367
|
+
* const myState = container.newState({ count: 0, loading: false })
|
|
368
|
+
* myState.observe(() => console.log('Changed:', myState.current))
|
|
369
|
+
* myState.set('count', 1)
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
372
|
+
newState<T extends object = any>(initialState: T = {} as T): State<T> {
|
|
373
|
+
return new State<T>({ initialState })
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Parse helper options through the helper's static options schema so defaults are materialized.
|
|
378
|
+
* @internal
|
|
379
|
+
*/
|
|
380
|
+
normalizeHelperOptions(BaseClass: any, options: any, fallbackName?: string) {
|
|
381
|
+
const candidate = { ...(options || {}) }
|
|
382
|
+
|
|
383
|
+
if (fallbackName && (candidate.name === undefined || candidate.name === null || candidate.name === '')) {
|
|
384
|
+
candidate.name = fallbackName
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const schema = BaseClass?.optionsSchema
|
|
388
|
+
if (!schema || typeof schema.safeParse !== 'function') {
|
|
389
|
+
return candidate
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const parsed = schema.safeParse(candidate)
|
|
393
|
+
if (parsed.success) {
|
|
394
|
+
return parsed.data
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const target = BaseClass?.shortcut || BaseClass?.name || 'helper'
|
|
398
|
+
const details = parsed.error.issues
|
|
399
|
+
.map((issue: any) => `${issue.path?.join('.') || 'options'}: ${issue.message}`)
|
|
400
|
+
.join('; ')
|
|
401
|
+
throw new Error(`Invalid options for ${target}: ${details || parsed.error.message}`)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/** @internal */
|
|
405
|
+
buildHelperCacheKey(type: string, id: string, options: any, omitOptionKeys: string[] = []) {
|
|
406
|
+
const hashableOptions = omit(options || {}, uniq(['_cacheKey', ...omitOptionKeys]))
|
|
407
|
+
|
|
408
|
+
return hashObject({
|
|
409
|
+
__type: type,
|
|
410
|
+
id,
|
|
411
|
+
options: hashableOptions,
|
|
412
|
+
uuid: this.uuid,
|
|
413
|
+
})
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/** @internal */
|
|
417
|
+
createHelperInstance({
|
|
418
|
+
cache,
|
|
419
|
+
type,
|
|
420
|
+
id,
|
|
421
|
+
BaseClass,
|
|
422
|
+
options,
|
|
423
|
+
fallbackName,
|
|
424
|
+
omitOptionKeys = [],
|
|
425
|
+
context,
|
|
426
|
+
}: {
|
|
427
|
+
cache: Map<string, any>
|
|
428
|
+
type: string
|
|
429
|
+
id: string
|
|
430
|
+
BaseClass: any
|
|
431
|
+
options?: any
|
|
432
|
+
fallbackName?: string
|
|
433
|
+
omitOptionKeys?: string[]
|
|
434
|
+
context?: any
|
|
435
|
+
}) {
|
|
436
|
+
const normalizedOptions = this.normalizeHelperOptions(BaseClass, options, fallbackName || id)
|
|
437
|
+
const cacheKey = this.buildHelperCacheKey(type, id, normalizedOptions, omitOptionKeys)
|
|
438
|
+
const cached = cache.get(cacheKey)
|
|
439
|
+
|
|
440
|
+
if (cached) {
|
|
441
|
+
return cached
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const helperOptions = {
|
|
445
|
+
...normalizedOptions,
|
|
446
|
+
_cacheKey: normalizedOptions._cacheKey || cacheKey,
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const instance = new (BaseClass as any)(helperOptions, context || this.context)
|
|
450
|
+
cache.set(cacheKey, instance)
|
|
451
|
+
uuidCache.set(instance.uuid, instance)
|
|
452
|
+
return instance
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Creates a new instance of a feature.
|
|
457
|
+
*
|
|
458
|
+
* If you pass the same arguments, it will return the same instance as last time you created that.
|
|
459
|
+
*
|
|
460
|
+
* If you need the ability to create fresh instances, it is up to you how you define your options to support that.
|
|
461
|
+
*
|
|
462
|
+
* @param id - The id of the feature to create.
|
|
463
|
+
* @param options - The options to pass to the feature constructor.
|
|
464
|
+
* @returns The new feature instance.
|
|
465
|
+
*/
|
|
466
|
+
feature<T extends keyof Features>(
|
|
467
|
+
id: T,
|
|
468
|
+
options?: FeatureInputOptions<Features>[T] | Record<string, unknown>
|
|
469
|
+
): InstanceType<Features[T]> {
|
|
470
|
+
const BaseClass = this.features.lookup(id as string) as Features[T]
|
|
471
|
+
|
|
472
|
+
return this.createHelperInstance({
|
|
473
|
+
cache: helperCache,
|
|
474
|
+
type: 'feature',
|
|
475
|
+
id: String(id),
|
|
476
|
+
BaseClass,
|
|
477
|
+
options,
|
|
478
|
+
omitOptionKeys: ['enable'],
|
|
479
|
+
context: { container: this },
|
|
480
|
+
}) as InstanceType<Features[T]>
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Creates a lightweight entity object with observable state, a typed event bus, and
|
|
485
|
+
* access to the container. Same id + options always returns the same cached base instance.
|
|
486
|
+
*
|
|
487
|
+
* An optional third argument auto-extends the entity with functions and getters.
|
|
488
|
+
* All extended methods and getters can access the entity (state, options, container,
|
|
489
|
+
* on/off/emit, etc.) via `this`.
|
|
490
|
+
*
|
|
491
|
+
* @param id - Stable identifier for this entity (included in cache key)
|
|
492
|
+
* @param options - Arbitrary options stored on `entity.options` (included in cache key)
|
|
493
|
+
* @param extensions - Optional object of functions/getters to graft onto the entity
|
|
494
|
+
*
|
|
495
|
+
* @example
|
|
496
|
+
* ```ts
|
|
497
|
+
* // Basic entity with typed state and events
|
|
498
|
+
* const counter = container.entity<{ count: number }>('counter')
|
|
499
|
+
* counter.setState({ count: 0 })
|
|
500
|
+
* counter.on('tick', () => counter.setState(s => ({ count: s.count + 1 })))
|
|
501
|
+
*
|
|
502
|
+
* // With options and auto-extension
|
|
503
|
+
* const user = container.entity('user:42', { name: 'Alice' }, {
|
|
504
|
+
* greet() { return `Hello ${this.options.name}` },
|
|
505
|
+
* get label() { return `User: ${this.options.name}` },
|
|
506
|
+
* })
|
|
507
|
+
* user.greet() // "Hello Alice"
|
|
508
|
+
* ```
|
|
509
|
+
*/
|
|
510
|
+
entity<
|
|
511
|
+
TState extends Record<string, any> = Record<string, any>,
|
|
512
|
+
TOptions extends Record<string, any> = Record<string, any>,
|
|
513
|
+
TEvents extends EntityEventMap = EntityEventMap,
|
|
514
|
+
Ext extends Record<string, any> = {},
|
|
515
|
+
>(
|
|
516
|
+
id: string,
|
|
517
|
+
options?: TOptions,
|
|
518
|
+
extensions?: Ext & ThisType<Entity<TState, TOptions, TEvents> & Ext>
|
|
519
|
+
): Entity<TState, TOptions, TEvents> & Ext {
|
|
520
|
+
const normalizedOptions = (options || {}) as TOptions
|
|
521
|
+
const cacheKey = this.buildHelperCacheKey('entity', id, normalizedOptions)
|
|
522
|
+
|
|
523
|
+
let base = entityCache.get(cacheKey)
|
|
524
|
+
if (!base) {
|
|
525
|
+
base = createEntityObject<TState, TOptions, TEvents>(id, this, normalizedOptions)
|
|
526
|
+
entityCache.set(cacheKey, base)
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return extensions ? base.extend(extensions) : base
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Look up any helper instance (feature, client, server) by its UUID.
|
|
534
|
+
* Returns undefined if the UUID is unknown or the instance was never created.
|
|
535
|
+
*
|
|
536
|
+
* @param uuid - The `instance.uuid` value assigned at construction time
|
|
537
|
+
* @returns The helper instance, or undefined
|
|
538
|
+
*
|
|
539
|
+
* @example
|
|
540
|
+
* ```ts
|
|
541
|
+
* const assistant = container.feature('assistant')
|
|
542
|
+
* const { uuid } = assistant
|
|
543
|
+
* // ... later ...
|
|
544
|
+
* const same = container.getHelperByUUID(uuid) // === assistant
|
|
545
|
+
* ```
|
|
546
|
+
*/
|
|
547
|
+
getHelperByUUID(uuid: string): Helper | undefined {
|
|
548
|
+
return uuidCache.get(uuid)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Start the container. Emits the 'started' event and sets `state.started` to true.
|
|
553
|
+
* Plugins and features can listen for this event to perform initialization.
|
|
554
|
+
*
|
|
555
|
+
* @returns The container instance
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```ts
|
|
559
|
+
* container.on('started', () => console.log('Ready'))
|
|
560
|
+
* await container.start()
|
|
561
|
+
* ```
|
|
562
|
+
*/
|
|
563
|
+
async start(): Promise<this> {
|
|
564
|
+
this.emit('started', this as Container<Features>)
|
|
565
|
+
this.state.set('started', true)
|
|
566
|
+
return this
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* ENVIRONMENT DETECTION METHODS
|
|
571
|
+
*
|
|
572
|
+
* One of the ideas of the container is that it can detect what kind of environment it is running in and
|
|
573
|
+
* e.g. perhaps load different versions of features to provide the same API with different implementations.
|
|
574
|
+
*
|
|
575
|
+
*/
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Returns true if the container is running in a browser.
|
|
579
|
+
*/
|
|
580
|
+
get isBrowser(): boolean {
|
|
581
|
+
return typeof window !== 'undefined' && typeof document !== 'undefined'
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Returns true if the container is running in Bun.
|
|
586
|
+
*/
|
|
587
|
+
get isBun(): boolean {
|
|
588
|
+
return this.isNode && typeof Bun !== 'undefined'
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Returns true if the container is running in Node.
|
|
593
|
+
*/
|
|
594
|
+
get isNode(): boolean {
|
|
595
|
+
return typeof process !== 'undefined' && typeof process.versions !== 'undefined' && typeof process.versions.node !== 'undefined'
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Returns true if the container is running in Electron.
|
|
600
|
+
*/
|
|
601
|
+
get isElectron(): boolean {
|
|
602
|
+
return typeof process !== 'undefined' && typeof process.versions !== 'undefined' && typeof process.versions.electron !== 'undefined'
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Returns true if the container is running in development mode.
|
|
607
|
+
*/
|
|
608
|
+
get isDevelopment(): boolean {
|
|
609
|
+
return typeof process !== 'undefined' && process.env.NODE_ENV === 'development'
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Returns true if the container is running in production mode.
|
|
614
|
+
*/
|
|
615
|
+
get isProduction(): boolean {
|
|
616
|
+
return typeof process !== 'undefined' && process.env.NODE_ENV === 'production'
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Returns true if the container is running in a CI environment.
|
|
621
|
+
*/
|
|
622
|
+
get isCI(): boolean {
|
|
623
|
+
return typeof process !== 'undefined' && process.env.CI !== undefined && String(process.env.CI).length > 0
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Emit an event on the container's event bus.
|
|
628
|
+
*
|
|
629
|
+
* @param event - The event name
|
|
630
|
+
* @param args - Arguments to pass to listeners
|
|
631
|
+
* @returns The container instance (for chaining)
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```ts
|
|
635
|
+
* container.emit('taskCompleted', { id: 'abc', result: 42 })
|
|
636
|
+
* ```
|
|
637
|
+
*/
|
|
638
|
+
emit(event: string, ...args: any[]): this {
|
|
639
|
+
this._events.emit(event, ...args)
|
|
640
|
+
return this
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Subscribe to an event on the container's event bus.
|
|
645
|
+
*
|
|
646
|
+
* @param event - The event name
|
|
647
|
+
* @param listener - The callback function
|
|
648
|
+
* @returns The container instance (for chaining)
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* container.on('featureEnabled', (id, feature) => {
|
|
653
|
+
* console.log(`Feature ${id} enabled`)
|
|
654
|
+
* })
|
|
655
|
+
* ```
|
|
656
|
+
*/
|
|
657
|
+
on(event: string, listener: (...args: any[]) => void): this {
|
|
658
|
+
this._events.on(event, listener)
|
|
659
|
+
return this
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Unsubscribe a listener from an event on the container's event bus.
|
|
664
|
+
*
|
|
665
|
+
* @param event - The event name
|
|
666
|
+
* @param listener - The listener to remove
|
|
667
|
+
* @returns The container instance (for chaining)
|
|
668
|
+
*/
|
|
669
|
+
off(event: string, listener?: (...args: any[]) => void): this {
|
|
670
|
+
this._events.off(event, listener)
|
|
671
|
+
return this
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Subscribe to an event on the container's event bus, but only fire once.
|
|
676
|
+
*
|
|
677
|
+
* @param event - The event name
|
|
678
|
+
* @param listener - The callback function (invoked at most once)
|
|
679
|
+
* @returns The container instance (for chaining)
|
|
680
|
+
*/
|
|
681
|
+
once(event: string, listener: (...args: any[]) => void): this {
|
|
682
|
+
this._events.once(event, listener)
|
|
683
|
+
return this
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Returns a promise that resolves the next time the given event is emitted.
|
|
688
|
+
* Useful for awaiting one-time lifecycle transitions.
|
|
689
|
+
*
|
|
690
|
+
* @param event - The event name to wait for
|
|
691
|
+
* @returns A promise that resolves with the event arguments
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```ts
|
|
695
|
+
* await container.waitFor('started')
|
|
696
|
+
* console.log('Container is ready')
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
699
|
+
async waitFor(event: string): Promise<any> {
|
|
700
|
+
const resp = await this._events.waitFor(event)
|
|
701
|
+
return resp
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Register a helper type (registry + factory pair) on this container.
|
|
706
|
+
* Called automatically by Helper.attach() methods (e.g. Client.attach, Server.attach).
|
|
707
|
+
* @internal
|
|
708
|
+
*/
|
|
709
|
+
registerHelperType(registryName: string, factoryName: string) {
|
|
710
|
+
const registries = uniq([...this.state.get('registries')!, registryName])
|
|
711
|
+
const factories = uniq([...this.state.get('factories')!, factoryName])
|
|
712
|
+
this.state.set('registries', registries)
|
|
713
|
+
this.state.set('factories', factories)
|
|
714
|
+
return this
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/** Returns the names of all attached registries (e.g. ["features", "clients", "servers"]). */
|
|
718
|
+
get registryNames(): string[] {
|
|
719
|
+
return this.state.get('registries') || ['features']
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/** Returns the names of all available factory methods (e.g. ["feature", "client", "server"]). */
|
|
723
|
+
get factoryNames(): string[] {
|
|
724
|
+
return this.state.get('factories') || ['feature']
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Returns a full introspection object for this container, merging build-time AST data
|
|
729
|
+
* (JSDoc descriptions, methods, getters) with runtime data (registries, factories, state, environment).
|
|
730
|
+
*
|
|
731
|
+
* @returns The complete introspection data as a structured object
|
|
732
|
+
*
|
|
733
|
+
* @example
|
|
734
|
+
* ```ts
|
|
735
|
+
* const info = container.introspect()
|
|
736
|
+
* console.log(info.methods) // all public methods with descriptions
|
|
737
|
+
* console.log(info.getters) // all getters with return types
|
|
738
|
+
* console.log(info.registries) // features, clients, servers, etc.
|
|
739
|
+
* ```
|
|
740
|
+
*/
|
|
741
|
+
introspect(): ContainerIntrospection {
|
|
742
|
+
const className = this.constructor.name
|
|
743
|
+
const buildTimeData = getContainerBuildTimeData(className) || {}
|
|
744
|
+
|
|
745
|
+
// Walk up the prototype chain to merge inherited build-time data
|
|
746
|
+
let mergedMethods = { ...(buildTimeData.methods || {}) }
|
|
747
|
+
let mergedGetters = { ...(buildTimeData.getters || {}) }
|
|
748
|
+
let mergedEvents = { ...(buildTimeData.events || {}) }
|
|
749
|
+
let mergedDescription = buildTimeData.description || ''
|
|
750
|
+
|
|
751
|
+
let proto = Object.getPrototypeOf(this.constructor)
|
|
752
|
+
while (proto && proto.name) {
|
|
753
|
+
const parentData = getContainerBuildTimeData(proto.name)
|
|
754
|
+
if (parentData) {
|
|
755
|
+
mergedMethods = { ...parentData.methods, ...mergedMethods }
|
|
756
|
+
mergedGetters = { ...parentData.getters, ...mergedGetters }
|
|
757
|
+
mergedEvents = { ...parentData.events, ...mergedEvents }
|
|
758
|
+
if (!mergedDescription && parentData.description) {
|
|
759
|
+
mergedDescription = parentData.description
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
proto = Object.getPrototypeOf(proto)
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Build registry introspection from runtime data
|
|
766
|
+
const registryNames = this.registryNames
|
|
767
|
+
const registries: RegistryIntrospection[] = registryNames.map((name) => {
|
|
768
|
+
const registry = (this as any)[name]
|
|
769
|
+
return {
|
|
770
|
+
name,
|
|
771
|
+
baseClass: registry?.baseClass?.name || 'Helper',
|
|
772
|
+
available: registry?.available || []
|
|
773
|
+
}
|
|
774
|
+
})
|
|
775
|
+
|
|
776
|
+
// Get state description from the Zod schema
|
|
777
|
+
const stateSchema = (this.constructor as any).stateSchema
|
|
778
|
+
const stateDescription = stateSchema ? describeZodShape(stateSchema) : {}
|
|
779
|
+
|
|
780
|
+
return {
|
|
781
|
+
className,
|
|
782
|
+
uuid: this.uuid,
|
|
783
|
+
description: mergedDescription,
|
|
784
|
+
registries,
|
|
785
|
+
factories: this.factoryNames,
|
|
786
|
+
methods: mergedMethods,
|
|
787
|
+
getters: mergedGetters,
|
|
788
|
+
events: mergedEvents,
|
|
789
|
+
state: stateDescription,
|
|
790
|
+
enabledFeatures: this.enabledFeatureIds,
|
|
791
|
+
environment: {
|
|
792
|
+
isBrowser: this.isBrowser,
|
|
793
|
+
isNode: this.isNode,
|
|
794
|
+
isBun: this.isBun,
|
|
795
|
+
isElectron: this.isElectron,
|
|
796
|
+
isDevelopment: this.isDevelopment,
|
|
797
|
+
isProduction: this.isProduction,
|
|
798
|
+
isCI: this.isCI
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Returns a human-readable markdown representation of this container's introspection data.
|
|
805
|
+
* Useful in REPLs, AI agent contexts, or documentation generation. Pass a section name
|
|
806
|
+
* to render only that section (e.g. 'methods', 'getters', 'events', 'state').
|
|
807
|
+
*
|
|
808
|
+
* @param sectionOrDepth - A section name to render, or heading depth number
|
|
809
|
+
* @param startHeadingDepth - Starting markdown heading depth (default 1)
|
|
810
|
+
* @returns Markdown-formatted introspection text
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* ```ts
|
|
814
|
+
* console.log(container.introspectAsText()) // full description
|
|
815
|
+
* console.log(container.introspectAsText('methods')) // just methods
|
|
816
|
+
* ```
|
|
817
|
+
*/
|
|
818
|
+
introspectAsText(sectionOrDepth?: IntrospectionSection | number, startHeadingDepth?: number): string {
|
|
819
|
+
let section: IntrospectionSection | undefined
|
|
820
|
+
let depth = 1
|
|
821
|
+
|
|
822
|
+
if (typeof sectionOrDepth === 'string') {
|
|
823
|
+
section = sectionOrDepth
|
|
824
|
+
depth = startHeadingDepth ?? 1
|
|
825
|
+
} else if (typeof sectionOrDepth === 'number') {
|
|
826
|
+
depth = sectionOrDepth
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const data = this.introspect()
|
|
830
|
+
return presentContainerIntrospectionAsMarkdown(data, depth, section)
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/** Returns JSON introspection data. */
|
|
834
|
+
introspectAsJSON(): ContainerIntrospection {
|
|
835
|
+
return this.introspect()
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Returns the container's introspection data formatted as a TypeScript interface declaration.
|
|
840
|
+
* Includes the container's own methods, getters, factories, and registered helper types.
|
|
841
|
+
*
|
|
842
|
+
* @example
|
|
843
|
+
* ```ts
|
|
844
|
+
* console.log(container.introspectAsType())
|
|
845
|
+
* // interface NodeContainer {
|
|
846
|
+
* // feature<T>(id: string, options?: object): T;
|
|
847
|
+
* // readonly uuid: string;
|
|
848
|
+
* // ...
|
|
849
|
+
* // }
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
852
|
+
introspectAsType(): string {
|
|
853
|
+
const data = this.introspect()
|
|
854
|
+
return presentContainerIntrospectionAsTypeScript(data)
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/** Make a property non-enumerable, which is nice for inspecting it in the REPL */
|
|
858
|
+
_hide(...propNames: string[]) {
|
|
859
|
+
propNames.map((propName) => {
|
|
860
|
+
Object.defineProperty(this, propName, { enumerable: false })
|
|
861
|
+
})
|
|
862
|
+
|
|
863
|
+
return this
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/** Sleep for the specified number of milliseconds. Useful for scripting and sequencing. */
|
|
867
|
+
async sleep(ms: number = 1000): Promise<this> {
|
|
868
|
+
await new Promise((res) => setTimeout(res,ms))
|
|
869
|
+
return this
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
_plugins: (() => void)[] = []
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Apply a plugin or enable a feature by string name. Plugins are classes with a static `attach(container)` method
|
|
876
|
+
* that extend the container with new registries, factories, or capabilities.
|
|
877
|
+
*
|
|
878
|
+
* @param plugin - A feature name string, or a class/object with a static attach method
|
|
879
|
+
* @param options - Options to pass to the plugin's attach method
|
|
880
|
+
* @returns The container instance (with the plugin's type merged in)
|
|
881
|
+
*
|
|
882
|
+
* @example
|
|
883
|
+
* ```ts
|
|
884
|
+
* // Enable a feature by name
|
|
885
|
+
* container.use('contentDb')
|
|
886
|
+
*
|
|
887
|
+
* // Attach a plugin class (e.g. Client, Server, or custom)
|
|
888
|
+
* container.use(Client) // registers the clients registry + client() factory
|
|
889
|
+
* container.use(Server) // registers the servers registry + server() factory
|
|
890
|
+
* ```
|
|
891
|
+
*/
|
|
892
|
+
use<T = {}>(plugin: Extension<T>, options: any = {}) : this & T {
|
|
893
|
+
const container = this
|
|
894
|
+
|
|
895
|
+
if(typeof plugin === 'string' && features.has(plugin)) {
|
|
896
|
+
const featureId = plugin as keyof AvailableFeatures
|
|
897
|
+
this.feature(featureId, {
|
|
898
|
+
...options,
|
|
899
|
+
enable: true
|
|
900
|
+
})
|
|
901
|
+
} else if (typeof plugin === 'string' && !features.has(plugin)) {
|
|
902
|
+
throw new Error(`Feature ${plugin} is not available.`)
|
|
903
|
+
} else if ((typeof plugin === 'object' || typeof plugin === 'function') && typeof plugin?.attach === 'function') {
|
|
904
|
+
// This is like using a Helper or Feature subclass which declares a static attach method
|
|
905
|
+
plugin.attach(container as this & T, options)
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
return this as (this & T)
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
const helperCache = new Map()
|
|
913
|
+
const entityCache = new Map()
|
|
914
|
+
const uuidCache = new Map<string, Helper>()
|
|
915
|
+
const featureIdToHelperCacheKeyMap= new Map()
|
|
916
|
+
const contextMap = new WeakMap()
|
|
917
|
+
|
|
918
|
+
function presentContainerIntrospectionAsMarkdown(data: ContainerIntrospection, startHeadingDepth: number = 1, section?: IntrospectionSection): string {
|
|
919
|
+
const sections: string[] = []
|
|
920
|
+
const heading = (level: number) => '#'.repeat(Math.max(1, startHeadingDepth + level - 1))
|
|
921
|
+
|
|
922
|
+
const shouldRender = (name: IntrospectionSection | string) => !section || section === name
|
|
923
|
+
|
|
924
|
+
if (!section) {
|
|
925
|
+
// Header
|
|
926
|
+
sections.push(`${heading(1)} ${data.className}\n\n${data.description || ''}`)
|
|
927
|
+
|
|
928
|
+
// Container Properties section — dynamic from getters data, not hardcoded
|
|
929
|
+
// (cwd, paths, manifest, argv, utils etc. come through as getters from the introspection scanner)
|
|
930
|
+
|
|
931
|
+
// Registries section
|
|
932
|
+
if (data.registries && data.registries.length > 0) {
|
|
933
|
+
sections.push(`${heading(2)} Registries`)
|
|
934
|
+
|
|
935
|
+
for (const reg of data.registries) {
|
|
936
|
+
sections.push(`${heading(3)} ${reg.name} (${reg.baseClass})`)
|
|
937
|
+
if (reg.available.length > 0) {
|
|
938
|
+
sections.push(reg.available.map(a => `- \`${a}\``).join('\n'))
|
|
939
|
+
} else {
|
|
940
|
+
sections.push('_No members registered_')
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Factories section
|
|
946
|
+
if (data.factories && data.factories.length > 0) {
|
|
947
|
+
sections.push(`${heading(2)} Factory Methods`)
|
|
948
|
+
sections.push(data.factories.map(f => `- \`${f}()\``).join('\n'))
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Methods section
|
|
953
|
+
if (shouldRender('methods') && data.methods && Object.keys(data.methods).length > 0) {
|
|
954
|
+
sections.push(`${heading(2)} Methods`)
|
|
955
|
+
|
|
956
|
+
for (const [methodName, methodInfo] of Object.entries(data.methods)) {
|
|
957
|
+
sections.push(`${heading(3)} ${methodName}`)
|
|
958
|
+
|
|
959
|
+
if (methodInfo.description) {
|
|
960
|
+
sections.push(methodInfo.description)
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
if (methodInfo.parameters && Object.keys(methodInfo.parameters).length > 0) {
|
|
964
|
+
const tableRows = [
|
|
965
|
+
`**Parameters:**`,
|
|
966
|
+
'',
|
|
967
|
+
`| Name | Type | Required | Description |`,
|
|
968
|
+
`|------|------|----------|-------------|`,
|
|
969
|
+
]
|
|
970
|
+
|
|
971
|
+
for (const [paramName, paramInfo] of Object.entries(methodInfo.parameters)) {
|
|
972
|
+
const isRequired = methodInfo.required?.includes(paramName) ? '✓' : ''
|
|
973
|
+
tableRows.push(`| \`${paramName}\` | \`${paramInfo.type || 'any'}\` | ${isRequired} | ${paramInfo.description || ''} |`)
|
|
974
|
+
|
|
975
|
+
if (paramInfo.properties && Object.keys(paramInfo.properties).length > 0) {
|
|
976
|
+
tableRows.push('')
|
|
977
|
+
tableRows.push(`\`${paramInfo.type}\` properties:`)
|
|
978
|
+
tableRows.push('')
|
|
979
|
+
tableRows.push(`| Property | Type | Description |`)
|
|
980
|
+
tableRows.push(`|----------|------|-------------|`)
|
|
981
|
+
|
|
982
|
+
for (const [propName, propInfo] of Object.entries(paramInfo.properties)) {
|
|
983
|
+
tableRows.push(`| \`${propName}\` | \`${propInfo.type || 'any'}\` | ${propInfo.description || ''} |`)
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
sections.push(tableRows.join('\n'))
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if (methodInfo.returns) {
|
|
991
|
+
sections.push(`**Returns:** \`${methodInfo.returns}\``)
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if ((methodInfo as any).examples && (methodInfo as any).examples.length > 0) {
|
|
995
|
+
for (const example of (methodInfo as any).examples) {
|
|
996
|
+
if (example.title) {
|
|
997
|
+
sections.push(`**Example: ${example.title}**`)
|
|
998
|
+
}
|
|
999
|
+
sections.push(`\`\`\`${example.language || 'ts'}\n${example.code}\n\`\`\``)
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
sections.push('')
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// Getters section
|
|
1008
|
+
if (shouldRender('getters') && data.getters && Object.keys(data.getters).length > 0) {
|
|
1009
|
+
const getterTableRows = [
|
|
1010
|
+
`${heading(2)} Getters`,
|
|
1011
|
+
'',
|
|
1012
|
+
`| Property | Type | Description |`,
|
|
1013
|
+
`|----------|------|-------------|`,
|
|
1014
|
+
]
|
|
1015
|
+
|
|
1016
|
+
const gettersWithExamples: [string, any][] = []
|
|
1017
|
+
|
|
1018
|
+
for (const [getterName, getterInfo] of Object.entries(data.getters)) {
|
|
1019
|
+
// Truncate long descriptions in the table
|
|
1020
|
+
const desc = getterInfo.description || ''
|
|
1021
|
+
const shortDesc = desc.length > 120 ? desc.slice(0, 117) + '...' : desc
|
|
1022
|
+
getterTableRows.push(`| \`${getterName}\` | \`${getterInfo.returns || 'any'}\` | ${shortDesc} |`)
|
|
1023
|
+
if ((getterInfo as any).examples && (getterInfo as any).examples.length > 0) {
|
|
1024
|
+
gettersWithExamples.push([getterName, getterInfo])
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
sections.push(getterTableRows.join('\n'))
|
|
1028
|
+
|
|
1029
|
+
// Render examples for getters that have them
|
|
1030
|
+
if (gettersWithExamples.length > 0) {
|
|
1031
|
+
for (const [getterName, getterInfo] of gettersWithExamples) {
|
|
1032
|
+
for (const example of (getterInfo as any).examples) {
|
|
1033
|
+
sections.push(`\`\`\`${example.language || 'ts'}\n${example.code}\n\`\`\``)
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// Events section
|
|
1040
|
+
if (shouldRender('events') && data.events && Object.keys(data.events).length > 0) {
|
|
1041
|
+
sections.push(`${heading(2)} Events`)
|
|
1042
|
+
|
|
1043
|
+
for (const [eventName, eventInfo] of Object.entries(data.events)) {
|
|
1044
|
+
sections.push(`${heading(3)} ${eventName}`)
|
|
1045
|
+
|
|
1046
|
+
if (eventInfo.description) {
|
|
1047
|
+
sections.push(eventInfo.description)
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
if (eventInfo.arguments && Object.keys(eventInfo.arguments).length > 0) {
|
|
1051
|
+
const tableRows = [
|
|
1052
|
+
`**Event Arguments:**`,
|
|
1053
|
+
'',
|
|
1054
|
+
`| Name | Type | Description |`,
|
|
1055
|
+
`|------|------|-------------|`,
|
|
1056
|
+
]
|
|
1057
|
+
|
|
1058
|
+
for (const [argName, argInfo] of Object.entries(eventInfo.arguments)) {
|
|
1059
|
+
tableRows.push(`| \`${argName}\` | \`${argInfo.type || 'any'}\` | ${argInfo.description || ''} |`)
|
|
1060
|
+
}
|
|
1061
|
+
sections.push(tableRows.join('\n'))
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
sections.push('')
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// State section
|
|
1069
|
+
if (shouldRender('state') && data.state && Object.keys(data.state).length > 0) {
|
|
1070
|
+
const stateTableRows = [
|
|
1071
|
+
`${heading(2)} State`,
|
|
1072
|
+
'',
|
|
1073
|
+
`| Property | Type | Description |`,
|
|
1074
|
+
`|----------|------|-------------|`,
|
|
1075
|
+
]
|
|
1076
|
+
|
|
1077
|
+
for (const [stateName, stateInfo] of Object.entries(data.state)) {
|
|
1078
|
+
stateTableRows.push(`| \`${stateName}\` | \`${stateInfo.type || 'any'}\` | ${stateInfo.description || ''} |`)
|
|
1079
|
+
}
|
|
1080
|
+
sections.push(stateTableRows.join('\n'))
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
if (!section) {
|
|
1084
|
+
// Enabled features section
|
|
1085
|
+
if (data.enabledFeatures && data.enabledFeatures.length > 0) {
|
|
1086
|
+
sections.push(`${heading(2)} Enabled Features`)
|
|
1087
|
+
sections.push(data.enabledFeatures.map(f => `- \`${f}\``).join('\n'))
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// Environment section
|
|
1091
|
+
if (data.environment) {
|
|
1092
|
+
const envTableRows = [
|
|
1093
|
+
`${heading(2)} Environment`,
|
|
1094
|
+
'',
|
|
1095
|
+
`| Flag | Value |`,
|
|
1096
|
+
`|------|-------|`,
|
|
1097
|
+
]
|
|
1098
|
+
for (const [key, value] of Object.entries(data.environment)) {
|
|
1099
|
+
envTableRows.push(`| \`${key}\` | ${value} |`)
|
|
1100
|
+
}
|
|
1101
|
+
sections.push(envTableRows.join('\n'))
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
return sections.join('\n\n')
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
function presentContainerIntrospectionAsTypeScript(data: ContainerIntrospection): string {
|
|
1109
|
+
const members: string[] = []
|
|
1110
|
+
|
|
1111
|
+
// Getters
|
|
1112
|
+
if (data.getters && Object.keys(data.getters).length > 0) {
|
|
1113
|
+
for (const [name, info] of Object.entries(data.getters)) {
|
|
1114
|
+
if (info.description) {
|
|
1115
|
+
members.push(` /** ${info.description} */`)
|
|
1116
|
+
}
|
|
1117
|
+
members.push(` readonly ${name}: ${normalizeTypeString(info.returns || 'any')};`)
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// Methods
|
|
1122
|
+
if (data.methods && Object.keys(data.methods).length > 0) {
|
|
1123
|
+
if (members.length > 0) members.push('')
|
|
1124
|
+
for (const [name, info] of Object.entries(data.methods)) {
|
|
1125
|
+
if (info.description) {
|
|
1126
|
+
members.push(` /** ${info.description} */`)
|
|
1127
|
+
}
|
|
1128
|
+
const params = renderTypeScriptParams(info)
|
|
1129
|
+
members.push(` ${name}(${params}): ${normalizeTypeString(info.returns || 'void')};`)
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// Factory methods
|
|
1134
|
+
if (data.factories && data.factories.length > 0) {
|
|
1135
|
+
if (members.length > 0) members.push('')
|
|
1136
|
+
members.push(' // Factory methods')
|
|
1137
|
+
for (const factory of data.factories) {
|
|
1138
|
+
members.push(` ${factory}(id: string, options?: Record<string, any>): any;`)
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Registries
|
|
1143
|
+
if (data.registries && data.registries.length > 0) {
|
|
1144
|
+
if (members.length > 0) members.push('')
|
|
1145
|
+
members.push(' // Registries')
|
|
1146
|
+
for (const reg of data.registries) {
|
|
1147
|
+
const available = reg.available.length > 0
|
|
1148
|
+
? reg.available.map(a => `'${a}'`).join(' | ')
|
|
1149
|
+
: 'string'
|
|
1150
|
+
members.push(` readonly ${reg.name}: { available: (${available})[]; lookup(id: string): any; };`)
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// Events — as on() overloads
|
|
1155
|
+
if (data.events && Object.keys(data.events).length > 0) {
|
|
1156
|
+
if (members.length > 0) members.push('')
|
|
1157
|
+
for (const [eventName, eventInfo] of Object.entries(data.events)) {
|
|
1158
|
+
const args = Object.entries(eventInfo.arguments || {})
|
|
1159
|
+
const listenerParams = args.length > 0
|
|
1160
|
+
? args.map(([argName, argInfo]) => `${argName}: ${normalizeTypeString(argInfo.type || 'any')}`).join(', ')
|
|
1161
|
+
: ''
|
|
1162
|
+
if (eventInfo.description) {
|
|
1163
|
+
members.push(` /** ${eventInfo.description} */`)
|
|
1164
|
+
}
|
|
1165
|
+
members.push(` on(event: '${eventName}', listener: (${listenerParams}) => void): this;`)
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// State
|
|
1170
|
+
if (data.state && Object.keys(data.state).length > 0) {
|
|
1171
|
+
if (members.length > 0) members.push('')
|
|
1172
|
+
const stateMembers = Object.entries(data.state)
|
|
1173
|
+
.map(([name, info]) => {
|
|
1174
|
+
const comment = info.description ? ` /** ${info.description} */\n` : ''
|
|
1175
|
+
return `${comment} ${name}: ${normalizeTypeString(info.type || 'any')};`
|
|
1176
|
+
})
|
|
1177
|
+
.join('\n')
|
|
1178
|
+
members.push(` state: {\n${stateMembers}\n };`)
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
const description = data.description
|
|
1182
|
+
? `/**\n * ${data.description.split('\n').join('\n * ')}\n */\n`
|
|
1183
|
+
: ''
|
|
1184
|
+
|
|
1185
|
+
return `${description}interface ${data.className} {\n${members.join('\n')}\n}`
|
|
1186
|
+
}
|