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/helper.ts
ADDED
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
import { Bus, type EventMap } from "./bus.js";
|
|
2
|
+
import { type SetStateValue, State } from "./state.js";
|
|
3
|
+
import type { ContainerContext } from './container.js'
|
|
4
|
+
import uuid from 'node-uuid'
|
|
5
|
+
import { get } from 'lodash-es'
|
|
6
|
+
import { introspect, type HelperIntrospection, type IntrospectionSection, type ExampleIntrospection } from "./introspection/index.js";
|
|
7
|
+
import { z } from 'zod'
|
|
8
|
+
import { HelperStateSchema, HelperOptionsSchema, HelperEventsSchema } from './schemas/base.js'
|
|
9
|
+
|
|
10
|
+
export type HelperState = z.infer<typeof HelperStateSchema>
|
|
11
|
+
export type HelperOptions = z.infer<typeof HelperOptionsSchema>
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Helpers are used to represent types of modules.
|
|
15
|
+
*
|
|
16
|
+
* You don't create instances of helpers directly, the container creates instances through
|
|
17
|
+
* factory functions that use the subclasses of Helper as a template. The container
|
|
18
|
+
* provides dependency injection and injects a context object into the Helper constructor.
|
|
19
|
+
*
|
|
20
|
+
* A Helper is something that can be introspected at runtime to learn about the interface.
|
|
21
|
+
*
|
|
22
|
+
* A helper has state.
|
|
23
|
+
*
|
|
24
|
+
* A helper is an event bus.
|
|
25
|
+
*
|
|
26
|
+
* A helper is connected to the container and can access the container's state, events, shared context, or
|
|
27
|
+
* other helpers and features in the container's registry.
|
|
28
|
+
*/
|
|
29
|
+
export abstract class Helper<T extends HelperState = HelperState, K extends HelperOptions = any, E extends EventMap = EventMap> {
|
|
30
|
+
static shortcut: string = "unspecified"
|
|
31
|
+
|
|
32
|
+
static description: string = "No description provided"
|
|
33
|
+
static envVars: string[] = []
|
|
34
|
+
|
|
35
|
+
static stateSchema: z.ZodType = HelperStateSchema
|
|
36
|
+
static optionsSchema: z.ZodType = HelperOptionsSchema
|
|
37
|
+
static eventsSchema: z.ZodType = HelperEventsSchema
|
|
38
|
+
static tools: Record<string, { schema: z.ZodType, handler?: Function }> = {}
|
|
39
|
+
|
|
40
|
+
protected readonly _context: ContainerContext
|
|
41
|
+
protected readonly _events = new Bus<E>()
|
|
42
|
+
protected readonly _options: K
|
|
43
|
+
protected readonly _instanceTools: Record<string, { schema: z.ZodType, handler?: Function }> = {}
|
|
44
|
+
|
|
45
|
+
readonly state: State<T>
|
|
46
|
+
|
|
47
|
+
readonly uuid = uuid.v4()
|
|
48
|
+
|
|
49
|
+
get initialState() : T {
|
|
50
|
+
return {} as T
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static introspect(section?: IntrospectionSection) : HelperIntrospection | undefined {
|
|
54
|
+
const data = introspect((this as any).shortcut || '')
|
|
55
|
+
if (!data || !section) return data
|
|
56
|
+
return filterIntrospection(data, section)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static introspectAsText(sectionOrDepth?: IntrospectionSection | number, startHeadingDepth?: number) : string {
|
|
60
|
+
const { section, depth } = resolveIntrospectAsTextArgs(sectionOrDepth, startHeadingDepth)
|
|
61
|
+
const introspection = this.introspect()
|
|
62
|
+
if (!introspection) return ''
|
|
63
|
+
return presentIntrospectionJSONAsMarkdown(introspection, depth, section)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Returns the introspection data formatted as a TypeScript interface declaration.
|
|
68
|
+
* Useful for AI agents that reason better with structured type information,
|
|
69
|
+
* or for generating `.d.ts` files that accurately describe a helper's public API.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* console.log(container.feature('fs').introspectAsType())
|
|
74
|
+
* // interface FS {
|
|
75
|
+
* // readonly cwd: string;
|
|
76
|
+
* // readFile(path: string): Promise<string>;
|
|
77
|
+
* // ...
|
|
78
|
+
* // }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
static introspectAsType(section?: IntrospectionSection) : string {
|
|
82
|
+
const introspection = this.introspect()
|
|
83
|
+
if (!introspection) return ''
|
|
84
|
+
return presentIntrospectionAsTypeScript(introspection, section)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* All Helpers can be introspect()ed and, assuming the introspection data has been loaded into the registry,
|
|
90
|
+
* will report information about the Helper that can only get extracted by reading the code, e.g. the type interfaces
|
|
91
|
+
* for the helper's options, state, and the events it emits, as well as the documentation from the helpers code for
|
|
92
|
+
* each of the methods and properties.
|
|
93
|
+
*
|
|
94
|
+
* Pass a section name to get only that section: `'methods'`, `'getters'`, `'events'`, `'state'`, `'options'`, `'envVars'`
|
|
95
|
+
*/
|
|
96
|
+
introspect(section?: IntrospectionSection) : HelperIntrospection | undefined {
|
|
97
|
+
const base = (this.constructor as any).introspect()
|
|
98
|
+
if (!base || !section) return base
|
|
99
|
+
return filterIntrospection(base, section)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Returns the introspection data formatted as a markdown string.
|
|
104
|
+
*
|
|
105
|
+
* The first argument can be a section name (`'methods'`, `'getters'`, etc.) to render only
|
|
106
|
+
* that section, or a number for the starting heading depth (backward compatible).
|
|
107
|
+
*/
|
|
108
|
+
introspectAsText(sectionOrDepth?: IntrospectionSection | number, startHeadingDepth?: number) : string {
|
|
109
|
+
const { section, depth } = resolveIntrospectAsTextArgs(sectionOrDepth, startHeadingDepth)
|
|
110
|
+
const introspection = this.introspect()
|
|
111
|
+
if (!introspection) return ''
|
|
112
|
+
return presentIntrospectionJSONAsMarkdown(introspection, depth, section)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns the introspection data formatted as a TypeScript interface declaration.
|
|
117
|
+
* Useful for AI agents that reason better with structured type information,
|
|
118
|
+
* or for generating `.d.ts` files that accurately describe a helper's public API.
|
|
119
|
+
*/
|
|
120
|
+
introspectAsType(section?: IntrospectionSection) : string {
|
|
121
|
+
const introspection = this.introspect()
|
|
122
|
+
if (!introspection) return ''
|
|
123
|
+
return presentIntrospectionAsTypeScript(introspection, section)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
constructor(options: K, context: ContainerContext) {
|
|
127
|
+
const optionSchema = (this.constructor as any).optionsSchema
|
|
128
|
+
if (optionSchema && typeof optionSchema.safeParse === 'function') {
|
|
129
|
+
const parsed = optionSchema.safeParse(options || {})
|
|
130
|
+
if (parsed.success) {
|
|
131
|
+
this._options = parsed.data as K
|
|
132
|
+
} else {
|
|
133
|
+
const details = parsed.error.issues.map((issue: any) => `${issue.path?.join('.') || 'options'}: ${issue.message}`).join('; ')
|
|
134
|
+
throw new Error(`Invalid options for ${(this.constructor as any).shortcut || this.constructor.name}: ${details || parsed.error.message}`)
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
this._options = options
|
|
138
|
+
}
|
|
139
|
+
this._context = context;
|
|
140
|
+
this.state = new State<T>({ initialState: this.initialState });
|
|
141
|
+
|
|
142
|
+
this.hide('_context', '_state', '_options', '_events', '_instanceTools', 'uuid')
|
|
143
|
+
|
|
144
|
+
this.state.observe(() => {
|
|
145
|
+
(this as any).emit('stateChange', this.state.current)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
this.afterInitialize()
|
|
149
|
+
|
|
150
|
+
this.container.emit('helperInitialized', this)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Returns the names of the methods for this helper.
|
|
155
|
+
*/
|
|
156
|
+
get $methods() : string[] {
|
|
157
|
+
return Object.keys((this.introspect() || {}).methods || [])
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Returns the names of the getters for this helper.
|
|
162
|
+
*/
|
|
163
|
+
get $getters() : string[] {
|
|
164
|
+
return Object.keys((this.introspect() || {}).getters || [])
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The static shortcut identifier for this helper type, e.g. "features.assistant".
|
|
169
|
+
*/
|
|
170
|
+
get shortcut(): string {
|
|
171
|
+
return (this.constructor as any).shortcut || ''
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Every helper has a cache key which is computed at the time it is created through the container.
|
|
176
|
+
*
|
|
177
|
+
* This ensures only a single instance of the helper exists for the requested options.
|
|
178
|
+
*/
|
|
179
|
+
get cacheKey() {
|
|
180
|
+
return this._options._cacheKey
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* This method will get called in the constructor and can be used instead of overriding the constructor
|
|
185
|
+
* in your helper subclases.
|
|
186
|
+
*/
|
|
187
|
+
afterInitialize() {
|
|
188
|
+
// override this method to do something after the helper is initialized
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
setState(newState: SetStateValue<T>) {
|
|
192
|
+
this.state.setState(newState)
|
|
193
|
+
return this
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Convenience method for putting properties on the helper that aren't enumerable,
|
|
198
|
+
* which is a convenience for the REPL mainly.
|
|
199
|
+
*/
|
|
200
|
+
hide(...propNames: string[]) {
|
|
201
|
+
propNames.map((propName) => {
|
|
202
|
+
Object.defineProperty(this, propName, { enumerable: false })
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
return this
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* python / lodash style get method, which will get a value from the container using dot notation
|
|
210
|
+
* and will return a default value if the value is not found.
|
|
211
|
+
*/
|
|
212
|
+
tryGet<K extends (string | string[]), T extends object = any>(key: K, defaultValue?: T) {
|
|
213
|
+
return get(this, key, defaultValue)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Register a tool on this instance at runtime. Instance tools take precedence
|
|
218
|
+
* over class-level static tools in toTools().
|
|
219
|
+
*/
|
|
220
|
+
tool(name: string, options: { schema: z.ZodType, handler?: Function }): this {
|
|
221
|
+
this._instanceTools[name] = options
|
|
222
|
+
return this
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Called when another helper (e.g. an assistant) consumes this helper's
|
|
227
|
+
* tools via `use()`. Override this to detect the consumer type and react —
|
|
228
|
+
* for example, adding system prompt extensions to an assistant.
|
|
229
|
+
*
|
|
230
|
+
* Use `consumer.shortcut` to identify the consumer type:
|
|
231
|
+
* ```typescript
|
|
232
|
+
* override setupToolsConsumer(consumer: Helper) {
|
|
233
|
+
* if (consumer.shortcut === 'features.assistant') {
|
|
234
|
+
* (consumer as any).addSystemPromptExtension('myFeature', 'usage hints here')
|
|
235
|
+
* }
|
|
236
|
+
* }
|
|
237
|
+
* ```
|
|
238
|
+
*
|
|
239
|
+
* The default implementation is a no-op.
|
|
240
|
+
*
|
|
241
|
+
* @param consumer - The helper instance that is consuming this helper's tools
|
|
242
|
+
*/
|
|
243
|
+
setupToolsConsumer(consumer: Helper): void {}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Collect all tools from the inheritance chain and instance, returning
|
|
247
|
+
* { schemas, handlers } with matching keys. Walks the prototype chain
|
|
248
|
+
* so subclass tools override parent tools. Instance tools win over all.
|
|
249
|
+
*
|
|
250
|
+
* If a tool has no explicit handler but this instance has a method with
|
|
251
|
+
* the same name, a handler is auto-generated that delegates to that method.
|
|
252
|
+
*/
|
|
253
|
+
toTools(options?: { only?: string[], except?: string[] }): { schemas: Record<string, z.ZodType>, handlers: Record<string, Function>, setup?: (consumer: Helper) => void } {
|
|
254
|
+
// Walk the prototype chain collecting static tools (parent-first, child overwrites)
|
|
255
|
+
const merged: Record<string, { schema: z.ZodType, description?: string, handler?: Function }> = {}
|
|
256
|
+
const chain: Function[] = []
|
|
257
|
+
|
|
258
|
+
let current = this.constructor as any
|
|
259
|
+
while (current && current !== Object) {
|
|
260
|
+
if (Object.hasOwn(current, 'tools') && current.tools) {
|
|
261
|
+
chain.unshift(current)
|
|
262
|
+
}
|
|
263
|
+
current = Object.getPrototypeOf(current)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (const ctor of chain) {
|
|
267
|
+
Object.assign(merged, (ctor as any).tools)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Instance tools win over static
|
|
271
|
+
Object.assign(merged, this._instanceTools)
|
|
272
|
+
|
|
273
|
+
// Filter tools by only/except before building schemas and handlers
|
|
274
|
+
let names = Object.keys(merged)
|
|
275
|
+
if (options?.only) names = names.filter(n => options.only!.includes(n))
|
|
276
|
+
if (options?.except) names = names.filter(n => !options.except!.includes(n))
|
|
277
|
+
|
|
278
|
+
const schemas: Record<string, z.ZodType> = {}
|
|
279
|
+
const handlers: Record<string, Function> = {}
|
|
280
|
+
|
|
281
|
+
for (const name of names) {
|
|
282
|
+
const entry = merged[name]!
|
|
283
|
+
// If the tool entry has a description but the schema doesn't, attach it
|
|
284
|
+
// so addTool() picks it up from jsonSchema.description.
|
|
285
|
+
schemas[name] = entry.description && !entry.schema.description
|
|
286
|
+
? entry.schema.describe(entry.description)
|
|
287
|
+
: entry.schema
|
|
288
|
+
if (entry.handler) {
|
|
289
|
+
handlers[name] = (args: any) => entry.handler!(args, this)
|
|
290
|
+
} else if (typeof (this as any)[name] === 'function') {
|
|
291
|
+
handlers[name] = (args: any) => (this as any)[name](args)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const result: { schemas: Record<string, z.ZodType>, handlers: Record<string, Function>, setup?: (consumer: Helper) => void } = { schemas, handlers }
|
|
296
|
+
|
|
297
|
+
// If this helper has a setupToolsConsumer override, package it as a setup
|
|
298
|
+
// function so consumers of toTools() can call it without needing the helper ref
|
|
299
|
+
const proto = Object.getPrototypeOf(this)
|
|
300
|
+
if (proto && proto.constructor !== Helper && typeof this.setupToolsConsumer === 'function' && this.setupToolsConsumer !== Helper.prototype.setupToolsConsumer) {
|
|
301
|
+
result.setup = (consumer: Helper) => this.setupToolsConsumer(consumer)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return result
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* The options passed to the helper when it was created.
|
|
309
|
+
*/
|
|
310
|
+
get options() {
|
|
311
|
+
return this._options;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* The context object that was passed to the helper when it was created, this is decided by the container
|
|
316
|
+
* and not something you would manipulate.
|
|
317
|
+
*/
|
|
318
|
+
get context() {
|
|
319
|
+
return this._context;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* The container that the helper is connected to.
|
|
324
|
+
*/
|
|
325
|
+
get container() {
|
|
326
|
+
return this.context.container;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
emit<Ev extends string & keyof E>(event: Ev, ...args: E[Ev]) {
|
|
330
|
+
this._events.emit(event, ...args)
|
|
331
|
+
return this
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
on(event: '*', listener: (event: string, ...args: any[]) => void): this
|
|
335
|
+
on<Ev extends string & keyof E>(event: Ev, listener: (...args: E[Ev]) => void): this
|
|
336
|
+
on<Ev extends string & keyof E>(event: Ev | '*', listener: any) {
|
|
337
|
+
this._events.on(event as any, listener)
|
|
338
|
+
return this
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
off(event: '*', listener?: (event: string, ...args: any[]) => void): this
|
|
342
|
+
off<Ev extends string & keyof E>(event: Ev, listener?: (...args: E[Ev]) => void): this
|
|
343
|
+
off<Ev extends string & keyof E>(event: Ev | '*', listener?: any) {
|
|
344
|
+
this._events.off(event as any, listener)
|
|
345
|
+
return this
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
once<Ev extends string & keyof E>(event: Ev, listener: (...args: E[Ev]) => void) {
|
|
349
|
+
this._events.once(event, listener)
|
|
350
|
+
return this
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async waitFor<Ev extends string & keyof E>(event: Ev) {
|
|
354
|
+
const resp = await this._events.waitFor(event)
|
|
355
|
+
return resp
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const INTROSPECTION_SECTIONS: IntrospectionSection[] = ['methods', 'getters', 'events', 'state', 'options', 'envVars', 'examples', 'usage']
|
|
360
|
+
|
|
361
|
+
function filterIntrospection(data: HelperIntrospection, section: IntrospectionSection): HelperIntrospection {
|
|
362
|
+
const filtered: HelperIntrospection = {
|
|
363
|
+
id: data.id,
|
|
364
|
+
description: data.description,
|
|
365
|
+
shortcut: data.shortcut,
|
|
366
|
+
methods: {},
|
|
367
|
+
getters: {},
|
|
368
|
+
events: {},
|
|
369
|
+
state: {},
|
|
370
|
+
options: {},
|
|
371
|
+
envVars: [],
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (section === 'examples') {
|
|
375
|
+
// For examples section, include class-level examples and full methods/getters (they carry inline examples)
|
|
376
|
+
filtered.examples = data.examples
|
|
377
|
+
filtered.methods = data.methods
|
|
378
|
+
filtered.getters = data.getters
|
|
379
|
+
} else if (section === 'usage') {
|
|
380
|
+
// Usage is derived from options + shortcut, so pass those through
|
|
381
|
+
filtered.options = data.options
|
|
382
|
+
} else {
|
|
383
|
+
filtered[section] = data[section] as any
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return filtered
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function resolveIntrospectAsTextArgs(sectionOrDepth?: IntrospectionSection | number, startHeadingDepth?: number) {
|
|
390
|
+
let section: IntrospectionSection | undefined
|
|
391
|
+
let depth = 1
|
|
392
|
+
|
|
393
|
+
if (typeof sectionOrDepth === 'string') {
|
|
394
|
+
section = sectionOrDepth
|
|
395
|
+
depth = startHeadingDepth ?? 1
|
|
396
|
+
} else if (typeof sectionOrDepth === 'number') {
|
|
397
|
+
depth = sectionOrDepth
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return { section, depth }
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function renderMethodsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
404
|
+
const sections: string[] = []
|
|
405
|
+
if (!introspection.methods || Object.keys(introspection.methods).length === 0) return sections
|
|
406
|
+
|
|
407
|
+
sections.push(`${heading(2)} Methods`)
|
|
408
|
+
|
|
409
|
+
for (const [methodName, methodInfo] of Object.entries(introspection.methods)) {
|
|
410
|
+
sections.push(`${heading(3)} ${methodName}`)
|
|
411
|
+
|
|
412
|
+
if (methodInfo.description) {
|
|
413
|
+
sections.push(methodInfo.description)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (methodInfo.parameters && Object.keys(methodInfo.parameters).length > 0) {
|
|
417
|
+
const tableRows = [
|
|
418
|
+
`**Parameters:**`,
|
|
419
|
+
'',
|
|
420
|
+
`| Name | Type | Required | Description |`,
|
|
421
|
+
`|------|------|----------|-------------|`,
|
|
422
|
+
]
|
|
423
|
+
|
|
424
|
+
for (const [paramName, paramInfo] of Object.entries(methodInfo.parameters)) {
|
|
425
|
+
const isRequired = methodInfo.required?.includes(paramName) ? '✓' : ''
|
|
426
|
+
const type = paramInfo.type || 'any'
|
|
427
|
+
const description = paramInfo.description || ''
|
|
428
|
+
tableRows.push(`| \`${paramName}\` | \`${type}\` | ${isRequired} | ${description} |`)
|
|
429
|
+
|
|
430
|
+
// Render expanded type properties if available
|
|
431
|
+
if (paramInfo.properties && Object.keys(paramInfo.properties).length > 0) {
|
|
432
|
+
tableRows.push('')
|
|
433
|
+
tableRows.push(`\`${type}\` properties:`)
|
|
434
|
+
tableRows.push('')
|
|
435
|
+
tableRows.push(`| Property | Type | Description |`)
|
|
436
|
+
tableRows.push(`|----------|------|-------------|`)
|
|
437
|
+
|
|
438
|
+
for (const [propName, propInfo] of Object.entries(paramInfo.properties)) {
|
|
439
|
+
tableRows.push(`| \`${propName}\` | \`${propInfo.type || 'any'}\` | ${propInfo.description || ''} |`)
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
sections.push(tableRows.join('\n'))
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (methodInfo.returns) {
|
|
447
|
+
sections.push(`**Returns:** \`${methodInfo.returns}\``)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (methodInfo.examples && methodInfo.examples.length > 0) {
|
|
451
|
+
for (const example of methodInfo.examples) {
|
|
452
|
+
sections.push(`\`\`\`${normalizeLang(example.language)}\n${example.code}\n\`\`\``)
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
sections.push('')
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return sections
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function renderGettersSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
463
|
+
const sections: string[] = []
|
|
464
|
+
if (!introspection.getters || Object.keys(introspection.getters).length === 0) return sections
|
|
465
|
+
|
|
466
|
+
const tableRows = [
|
|
467
|
+
`${heading(2)} Getters`,
|
|
468
|
+
'',
|
|
469
|
+
`| Property | Type | Description |`,
|
|
470
|
+
`|----------|------|-------------|`,
|
|
471
|
+
]
|
|
472
|
+
|
|
473
|
+
for (const [getterName, getterInfo] of Object.entries(introspection.getters)) {
|
|
474
|
+
const type = getterInfo.returns || 'any'
|
|
475
|
+
const description = getterInfo.description || ''
|
|
476
|
+
tableRows.push(`| \`${getterName}\` | \`${type}\` | ${description} |`)
|
|
477
|
+
}
|
|
478
|
+
sections.push(tableRows.join('\n'))
|
|
479
|
+
|
|
480
|
+
return sections
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function renderEventsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
484
|
+
const sections: string[] = []
|
|
485
|
+
if (!introspection.events || Object.keys(introspection.events).length === 0) return sections
|
|
486
|
+
|
|
487
|
+
sections.push(`${heading(2)} Events (Zod v4 schema)`)
|
|
488
|
+
|
|
489
|
+
for (const [eventName, eventInfo] of Object.entries(introspection.events)) {
|
|
490
|
+
sections.push(`${heading(3)} ${eventName}`)
|
|
491
|
+
|
|
492
|
+
if (eventInfo.description) {
|
|
493
|
+
sections.push(eventInfo.description)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (eventInfo.arguments && Object.keys(eventInfo.arguments).length > 0) {
|
|
497
|
+
const tableRows = [
|
|
498
|
+
`**Event Arguments:**`,
|
|
499
|
+
'',
|
|
500
|
+
`| Name | Type | Description |`,
|
|
501
|
+
`|------|------|-------------|`,
|
|
502
|
+
]
|
|
503
|
+
|
|
504
|
+
for (const [argName, argInfo] of Object.entries(eventInfo.arguments)) {
|
|
505
|
+
tableRows.push(`| \`${argName}\` | \`${argInfo.type || 'any'}\` | ${argInfo.description || ''} |`)
|
|
506
|
+
}
|
|
507
|
+
sections.push(tableRows.join('\n'))
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
sections.push('')
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return sections
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function renderStateSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
517
|
+
const sections: string[] = []
|
|
518
|
+
if (!introspection.state || Object.keys(introspection.state).length === 0) return sections
|
|
519
|
+
|
|
520
|
+
const tableRows = [
|
|
521
|
+
`${heading(2)} State (Zod v4 schema)`,
|
|
522
|
+
'',
|
|
523
|
+
`| Property | Type | Description |`,
|
|
524
|
+
`|----------|------|-------------|`,
|
|
525
|
+
]
|
|
526
|
+
|
|
527
|
+
for (const [stateName, stateInfo] of Object.entries(introspection.state)) {
|
|
528
|
+
tableRows.push(`| \`${stateName}\` | \`${stateInfo.type || 'any'}\` | ${stateInfo.description || ''} |`)
|
|
529
|
+
}
|
|
530
|
+
sections.push(tableRows.join('\n'))
|
|
531
|
+
|
|
532
|
+
return sections
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function renderOptionsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
536
|
+
const sections: string[] = []
|
|
537
|
+
if (!introspection.options || Object.keys(introspection.options).length === 0) return sections
|
|
538
|
+
|
|
539
|
+
const tableRows = [
|
|
540
|
+
`${heading(2)} Options (Zod v4 schema)`,
|
|
541
|
+
'',
|
|
542
|
+
`| Property | Type | Description |`,
|
|
543
|
+
`|----------|------|-------------|`,
|
|
544
|
+
]
|
|
545
|
+
|
|
546
|
+
for (const [optName, optInfo] of Object.entries(introspection.options)) {
|
|
547
|
+
tableRows.push(`| \`${optName}\` | \`${optInfo.type || 'any'}\` | ${optInfo.description || ''} |`)
|
|
548
|
+
}
|
|
549
|
+
sections.push(tableRows.join('\n'))
|
|
550
|
+
|
|
551
|
+
return sections
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function renderUsageSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
555
|
+
const sections: string[] = []
|
|
556
|
+
|
|
557
|
+
// Derive the factory method from the shortcut, e.g. "features.diskCache" -> container.feature('diskCache', { ... })
|
|
558
|
+
const shortcut = introspection.shortcut || introspection.id || ''
|
|
559
|
+
const parts = shortcut.split('.')
|
|
560
|
+
if (parts.length < 2) return sections
|
|
561
|
+
|
|
562
|
+
const scope = parts[0]! // e.g. "features"
|
|
563
|
+
const name = parts.slice(1).join('.') // e.g. "diskCache"
|
|
564
|
+
// Singular form: features -> feature, clients -> client, servers -> server, commands -> command, endpoints -> endpoint
|
|
565
|
+
const factoryMethod = scope.endsWith('s') ? scope.slice(0, -1) : scope
|
|
566
|
+
|
|
567
|
+
const options = introspection.options || {}
|
|
568
|
+
const optionEntries = Object.entries(options)
|
|
569
|
+
|
|
570
|
+
sections.push(`${heading(2)} Usage`)
|
|
571
|
+
|
|
572
|
+
if (optionEntries.length === 0) {
|
|
573
|
+
sections.push(`\`\`\`ts\ncontainer.${factoryMethod}('${name}')\n\`\`\``)
|
|
574
|
+
} else {
|
|
575
|
+
const optionLines = optionEntries.map(([optName, optInfo]) => {
|
|
576
|
+
const desc = optInfo.description ? `// ${optInfo.description}` : ''
|
|
577
|
+
return ` ${desc}\n ${optName},`
|
|
578
|
+
}).join('\n')
|
|
579
|
+
|
|
580
|
+
sections.push(`\`\`\`ts\ncontainer.${factoryMethod}('${name}', {\n${optionLines}\n})\n\`\`\``)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return sections
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function renderEnvVarsSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
587
|
+
const sections: string[] = []
|
|
588
|
+
if (!introspection.envVars || introspection.envVars.length === 0) return sections
|
|
589
|
+
|
|
590
|
+
sections.push(`${heading(2)} Environment Variables`)
|
|
591
|
+
sections.push(introspection.envVars.map((envVar) => `- \`${envVar}\``).join('\n'))
|
|
592
|
+
|
|
593
|
+
return sections
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function renderExamplesSection(introspection: HelperIntrospection, heading: (level: number) => string): string[] {
|
|
597
|
+
const sections: string[] = []
|
|
598
|
+
|
|
599
|
+
// Collect all examples: class-level, method-level, getter-level
|
|
600
|
+
const allExamples: { source: string; examples: ExampleIntrospection[] }[] = []
|
|
601
|
+
|
|
602
|
+
if (introspection.examples && introspection.examples.length > 0) {
|
|
603
|
+
allExamples.push({ source: introspection.id, examples: introspection.examples })
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
for (const [name, method] of Object.entries(introspection.methods || {})) {
|
|
607
|
+
if (method.examples && method.examples.length > 0) {
|
|
608
|
+
allExamples.push({ source: name, examples: method.examples })
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
for (const [name, getter] of Object.entries(introspection.getters || {})) {
|
|
613
|
+
if (getter.examples && getter.examples.length > 0) {
|
|
614
|
+
allExamples.push({ source: name, examples: getter.examples })
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (allExamples.length === 0) return sections
|
|
619
|
+
|
|
620
|
+
sections.push(`${heading(2)} Examples`)
|
|
621
|
+
|
|
622
|
+
for (const { source, examples } of allExamples) {
|
|
623
|
+
sections.push(`**${source}**`)
|
|
624
|
+
for (const example of examples) {
|
|
625
|
+
sections.push(`\`\`\`${normalizeLang(example.language)}\n${example.code}\n\`\`\``)
|
|
626
|
+
}
|
|
627
|
+
sections.push('')
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
return sections
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** Normalize verbose language names to short tags for code fences */
|
|
634
|
+
function normalizeLang(lang: string): string {
|
|
635
|
+
if (lang === 'typescript') return 'ts'
|
|
636
|
+
if (lang === 'javascript') return 'js'
|
|
637
|
+
return lang
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
export { presentIntrospectionJSONAsMarkdown as presentIntrospectionAsMarkdown }
|
|
641
|
+
export { presentIntrospectionAsTypeScript, renderTypeScriptParams, normalizeTypeString, isGenericObjectType }
|
|
642
|
+
|
|
643
|
+
function presentIntrospectionJSONAsMarkdown(introspection: HelperIntrospection, startHeadingDepth: number = 1, section?: IntrospectionSection) {
|
|
644
|
+
const sections: string[] = []
|
|
645
|
+
const heading = (level: number) => '#'.repeat(Math.max(1, startHeadingDepth + level - 1))
|
|
646
|
+
|
|
647
|
+
if (!section) {
|
|
648
|
+
const title = introspection.className
|
|
649
|
+
? `${heading(1)} ${introspection.className} (${introspection.id})`
|
|
650
|
+
: `${heading(1)} ${introspection.id}`
|
|
651
|
+
sections.push(`${title}\n\n${introspection.description}`)
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const renderers: Record<IntrospectionSection, () => string[]> = {
|
|
655
|
+
usage: () => renderUsageSection(introspection, heading),
|
|
656
|
+
options: () => renderOptionsSection(introspection, heading),
|
|
657
|
+
methods: () => renderMethodsSection(introspection, heading),
|
|
658
|
+
getters: () => renderGettersSection(introspection, heading),
|
|
659
|
+
events: () => renderEventsSection(introspection, heading),
|
|
660
|
+
state: () => renderStateSection(introspection, heading),
|
|
661
|
+
envVars: () => renderEnvVarsSection(introspection, heading),
|
|
662
|
+
examples: () => renderExamplesSection(introspection, heading),
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (section) {
|
|
666
|
+
sections.push(...renderers[section]())
|
|
667
|
+
} else {
|
|
668
|
+
for (const renderer of Object.values(renderers)) {
|
|
669
|
+
sections.push(...renderer())
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return sections.join('\n\n')
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Renders introspection data as a TypeScript interface declaration.
|
|
678
|
+
* Produces a valid interface string that describes the helper's public API —
|
|
679
|
+
* getters, methods, state shape, options shape, and event listener signatures.
|
|
680
|
+
*/
|
|
681
|
+
function presentIntrospectionAsTypeScript(introspection: HelperIntrospection, section?: IntrospectionSection): string {
|
|
682
|
+
const interfaceName = introspection.className || introspection.id.split('.').pop() || 'Unknown'
|
|
683
|
+
const members: string[] = []
|
|
684
|
+
|
|
685
|
+
const shouldRender = (s: IntrospectionSection) => !section || section === s
|
|
686
|
+
|
|
687
|
+
// Getters
|
|
688
|
+
if (shouldRender('getters') && introspection.getters && Object.keys(introspection.getters).length > 0) {
|
|
689
|
+
for (const [name, info] of Object.entries(introspection.getters)) {
|
|
690
|
+
const returnType = normalizeTypeString(info.returns || 'any')
|
|
691
|
+
if (info.description) {
|
|
692
|
+
members.push(` /** ${info.description} */`)
|
|
693
|
+
}
|
|
694
|
+
members.push(` readonly ${name}: ${returnType};`)
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Methods
|
|
699
|
+
if (shouldRender('methods') && introspection.methods && Object.keys(introspection.methods).length > 0) {
|
|
700
|
+
if (members.length > 0) members.push('')
|
|
701
|
+
for (const [name, info] of Object.entries(introspection.methods)) {
|
|
702
|
+
if (info.description) {
|
|
703
|
+
members.push(` /** ${info.description} */`)
|
|
704
|
+
}
|
|
705
|
+
const params = renderTypeScriptParams(info)
|
|
706
|
+
const returnType = normalizeTypeString(info.returns || 'void')
|
|
707
|
+
members.push(` ${name}(${params}): ${returnType};`)
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// State — render as the observable State<T> object, not just currentState
|
|
712
|
+
if (shouldRender('state') && introspection.state && Object.keys(introspection.state).length > 0) {
|
|
713
|
+
if (members.length > 0) members.push('')
|
|
714
|
+
const stateMembers = Object.entries(introspection.state)
|
|
715
|
+
.map(([name, info]) => {
|
|
716
|
+
const comment = info.description ? ` /** ${info.description} */\n` : ''
|
|
717
|
+
return `${comment} ${name}: ${normalizeTypeString(info.type || 'any')};`
|
|
718
|
+
})
|
|
719
|
+
.join('\n')
|
|
720
|
+
const stateShape = `{\n${stateMembers}\n }`
|
|
721
|
+
members.push(` state: {`)
|
|
722
|
+
members.push(` /** The current version number, incremented on each change */`)
|
|
723
|
+
members.push(` readonly version: number;`)
|
|
724
|
+
members.push(` /** Get the value of a state key */`)
|
|
725
|
+
members.push(` get<K extends keyof T>(key: K): T[K] | undefined;`)
|
|
726
|
+
members.push(` /** Set a state key to a new value, notifying observers */`)
|
|
727
|
+
members.push(` set<K extends keyof T>(key: K, value: T[K]): this;`)
|
|
728
|
+
members.push(` /** Delete a state key, notifying observers */`)
|
|
729
|
+
members.push(` delete<K extends keyof T>(key: K): this;`)
|
|
730
|
+
members.push(` /** Check if a state key exists */`)
|
|
731
|
+
members.push(` has<K extends keyof T>(key: K): boolean;`)
|
|
732
|
+
members.push(` /** Get all state keys */`)
|
|
733
|
+
members.push(` keys(): string[];`)
|
|
734
|
+
members.push(` /** Get the current state snapshot */`)
|
|
735
|
+
members.push(` readonly current: ${stateShape};`)
|
|
736
|
+
members.push(` /** Get all entries as [key, value] pairs */`)
|
|
737
|
+
members.push(` entries(): [string, any][];`)
|
|
738
|
+
members.push(` /** Get all state values */`)
|
|
739
|
+
members.push(` values(): any[];`)
|
|
740
|
+
members.push(` /** Register an observer callback for state changes. Returns an unsubscribe function. */`)
|
|
741
|
+
members.push(` observe(callback: (changeType: 'add' | 'update' | 'delete', key: string, value?: any) => void): () => void;`)
|
|
742
|
+
members.push(` /** Merge partial state, notifying observers for each changed key */`)
|
|
743
|
+
members.push(` setState(value: Partial<${stateShape}> | ((current: ${stateShape}, state: this) => Partial<${stateShape}>)): void;`)
|
|
744
|
+
members.push(` /** Clear all state, notifying observers */`)
|
|
745
|
+
members.push(` clear(): void;`)
|
|
746
|
+
members.push(` };`)
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// Options
|
|
750
|
+
if (shouldRender('options') && introspection.options && Object.keys(introspection.options).length > 0) {
|
|
751
|
+
if (members.length > 0) members.push('')
|
|
752
|
+
const optionMembers = Object.entries(introspection.options)
|
|
753
|
+
.map(([name, info]) => {
|
|
754
|
+
const comment = info.description ? ` /** ${info.description} */\n` : ''
|
|
755
|
+
return `${comment} ${name}?: ${normalizeTypeString(info.type || 'any')};`
|
|
756
|
+
})
|
|
757
|
+
.join('\n')
|
|
758
|
+
members.push(` options: {\n${optionMembers}\n };`)
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Events — rendered as on() overloads
|
|
762
|
+
if (shouldRender('events') && introspection.events && Object.keys(introspection.events).length > 0) {
|
|
763
|
+
if (members.length > 0) members.push('')
|
|
764
|
+
for (const [eventName, eventInfo] of Object.entries(introspection.events)) {
|
|
765
|
+
const args = Object.entries(eventInfo.arguments || {})
|
|
766
|
+
const listenerParams = args.length > 0
|
|
767
|
+
? args.map(([argName, argInfo]) => `${argName}: ${normalizeTypeString(argInfo.type || 'any')}`).join(', ')
|
|
768
|
+
: ''
|
|
769
|
+
if (eventInfo.description) {
|
|
770
|
+
members.push(` /** ${eventInfo.description} */`)
|
|
771
|
+
}
|
|
772
|
+
members.push(` on(event: '${eventName}', listener: (${listenerParams}) => void): this;`)
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const description = introspection.description
|
|
777
|
+
? `/**\n * ${introspection.description.split('\n').join('\n * ')}\n */\n`
|
|
778
|
+
: ''
|
|
779
|
+
|
|
780
|
+
const mainInterface = `${description}interface ${interfaceName} {\n${members.join('\n')}\n}`
|
|
781
|
+
|
|
782
|
+
// Emit referenced type declarations above the main interface
|
|
783
|
+
const types = introspection.types
|
|
784
|
+
if (types && Object.keys(types).length > 0) {
|
|
785
|
+
const typeDeclarations = Object.entries(types).map(([typeName, typeInfo]) => {
|
|
786
|
+
const typeDesc = typeInfo.description
|
|
787
|
+
? `/**\n * ${typeInfo.description.split('\n').join('\n * ')}\n */\n`
|
|
788
|
+
: ''
|
|
789
|
+
const props = Object.entries(typeInfo.properties)
|
|
790
|
+
.map(([propName, propInfo]) => {
|
|
791
|
+
const comment = propInfo.description ? ` /** ${propInfo.description} */\n` : ''
|
|
792
|
+
const opt = propInfo.optional ? '?' : ''
|
|
793
|
+
return `${comment} ${propName}${opt}: ${normalizeTypeString(propInfo.type || 'any')};`
|
|
794
|
+
})
|
|
795
|
+
.join('\n')
|
|
796
|
+
return `${typeDesc}interface ${typeName} {\n${props}\n}`
|
|
797
|
+
})
|
|
798
|
+
|
|
799
|
+
return typeDeclarations.join('\n\n') + '\n\n' + mainInterface
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
return mainInterface
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/** Build a TypeScript parameter list string from method introspection */
|
|
806
|
+
function renderTypeScriptParams(method: { parameters: Record<string, { type: string, description?: string, properties?: Record<string, { type: string, description?: string }> }>, required: string[] }): string {
|
|
807
|
+
const entries = Object.entries(method.parameters || {})
|
|
808
|
+
if (entries.length === 0) return ''
|
|
809
|
+
|
|
810
|
+
return entries.map(([name, info]) => {
|
|
811
|
+
const isRequired = (method.required || []).includes(name)
|
|
812
|
+
let type = normalizeTypeString(info.type || 'any')
|
|
813
|
+
|
|
814
|
+
// If the parameter has expanded sub-properties but a generic type string,
|
|
815
|
+
// render an inline object type from those properties instead
|
|
816
|
+
if (info.properties && Object.keys(info.properties).length > 0 && isGenericObjectType(type)) {
|
|
817
|
+
const props = Object.entries(info.properties)
|
|
818
|
+
.map(([propName, propInfo]) => `${propName}?: ${normalizeTypeString(propInfo.type || 'any')}`)
|
|
819
|
+
.join('; ')
|
|
820
|
+
type = `{ ${props} }`
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
return `${name}${isRequired ? '' : '?'}: ${type}`
|
|
824
|
+
}).join(', ')
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/** Returns true if the type string looks like a generic object type that sub-properties would refine */
|
|
828
|
+
function isGenericObjectType(type: string): boolean {
|
|
829
|
+
const lower = type.toLowerCase()
|
|
830
|
+
return lower === 'object' || lower === 'any' || lower === 'record<string, any>' || lower === '{}'
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/** Clean up type strings from introspection data for use in interface declarations */
|
|
834
|
+
function normalizeTypeString(type: string): string {
|
|
835
|
+
if (!type) return 'any'
|
|
836
|
+
// The AST scanner sometimes wraps types in quotes
|
|
837
|
+
type = type.replace(/^["']|["']$/g, '')
|
|
838
|
+
// Convert internal ReturnType<typeof this.container.feature<'name'>> to a clean import reference
|
|
839
|
+
// e.g. ReturnType<typeof this.container.feature<'proc'>> → import('luca').Proc
|
|
840
|
+
type = type.replace(
|
|
841
|
+
/ReturnType<typeof this\.container\.(feature|client|server)<'([^']+)'>>/g,
|
|
842
|
+
(_match, _kind, name) => {
|
|
843
|
+
// Convert shortcut name to PascalCase class name
|
|
844
|
+
const className = name.replace(/(^|[-_])(\w)/g, (_: string, _sep: string, ch: string) => ch.toUpperCase())
|
|
845
|
+
return `import('@soederpop/luca').${className}`
|
|
846
|
+
}
|
|
847
|
+
)
|
|
848
|
+
return type
|
|
849
|
+
}
|