@shuyhere/takotako 0.0.1
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/CONTRIBUTING.md +84 -0
- package/LICENSE +21 -0
- package/README.md +171 -0
- package/dist/agents/communication.d.ts +48 -0
- package/dist/agents/communication.d.ts.map +1 -0
- package/dist/agents/communication.js +123 -0
- package/dist/agents/communication.js.map +1 -0
- package/dist/agents/config.d.ts +52 -0
- package/dist/agents/config.d.ts.map +1 -0
- package/dist/agents/config.js +65 -0
- package/dist/agents/config.js.map +1 -0
- package/dist/agents/model-catalog.d.ts +49 -0
- package/dist/agents/model-catalog.d.ts.map +1 -0
- package/dist/agents/model-catalog.js +79 -0
- package/dist/agents/model-catalog.js.map +1 -0
- package/dist/agents/registry.d.ts +71 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +297 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/roles.d.ts +79 -0
- package/dist/agents/roles.d.ts.map +1 -0
- package/dist/agents/roles.js +174 -0
- package/dist/agents/roles.js.map +1 -0
- package/dist/agents/subagent.d.ts +124 -0
- package/dist/agents/subagent.d.ts.map +1 -0
- package/dist/agents/subagent.js +352 -0
- package/dist/agents/subagent.js.map +1 -0
- package/dist/agents/templates.d.ts +18 -0
- package/dist/agents/templates.d.ts.map +1 -0
- package/dist/agents/templates.js +341 -0
- package/dist/agents/templates.js.map +1 -0
- package/dist/agents/thread-binding.d.ts +77 -0
- package/dist/agents/thread-binding.d.ts.map +1 -0
- package/dist/agents/thread-binding.js +167 -0
- package/dist/agents/thread-binding.js.map +1 -0
- package/dist/auth/agent-profiles.d.ts +46 -0
- package/dist/auth/agent-profiles.d.ts.map +1 -0
- package/dist/auth/agent-profiles.js +97 -0
- package/dist/auth/agent-profiles.js.map +1 -0
- package/dist/auth/allow-from.d.ts +27 -0
- package/dist/auth/allow-from.d.ts.map +1 -0
- package/dist/auth/allow-from.js +118 -0
- package/dist/auth/allow-from.js.map +1 -0
- package/dist/auth/oauth.d.ts +66 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +253 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/storage.d.ts +69 -0
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js +157 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/cache/file-cache.d.ts +68 -0
- package/dist/cache/file-cache.d.ts.map +1 -0
- package/dist/cache/file-cache.js +176 -0
- package/dist/cache/file-cache.js.map +1 -0
- package/dist/cache/manager.d.ts +69 -0
- package/dist/cache/manager.d.ts.map +1 -0
- package/dist/cache/manager.js +117 -0
- package/dist/cache/manager.js.map +1 -0
- package/dist/cache/symbol-index.d.ts +75 -0
- package/dist/cache/symbol-index.d.ts.map +1 -0
- package/dist/cache/symbol-index.js +267 -0
- package/dist/cache/symbol-index.js.map +1 -0
- package/dist/cache/tool-cache.d.ts +75 -0
- package/dist/cache/tool-cache.d.ts.map +1 -0
- package/dist/cache/tool-cache.js +173 -0
- package/dist/cache/tool-cache.js.map +1 -0
- package/dist/channels/channel.d.ts +156 -0
- package/dist/channels/channel.d.ts.map +1 -0
- package/dist/channels/channel.js +25 -0
- package/dist/channels/channel.js.map +1 -0
- package/dist/channels/cli.d.ts +35 -0
- package/dist/channels/cli.d.ts.map +1 -0
- package/dist/channels/cli.js +94 -0
- package/dist/channels/cli.js.map +1 -0
- package/dist/channels/delivery-queue.d.ts +31 -0
- package/dist/channels/delivery-queue.d.ts.map +1 -0
- package/dist/channels/delivery-queue.js +127 -0
- package/dist/channels/delivery-queue.js.map +1 -0
- package/dist/channels/discord.d.ts +124 -0
- package/dist/channels/discord.d.ts.map +1 -0
- package/dist/channels/discord.js +664 -0
- package/dist/channels/discord.js.map +1 -0
- package/dist/channels/retry.d.ts +31 -0
- package/dist/channels/retry.d.ts.map +1 -0
- package/dist/channels/retry.js +94 -0
- package/dist/channels/retry.js.map +1 -0
- package/dist/channels/telegram.d.ts +69 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +499 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/tui.d.ts +42 -0
- package/dist/channels/tui.d.ts.map +1 -0
- package/dist/channels/tui.js +126 -0
- package/dist/channels/tui.js.map +1 -0
- package/dist/cli/acp.d.ts +10 -0
- package/dist/cli/acp.d.ts.map +1 -0
- package/dist/cli/acp.js +69 -0
- package/dist/cli/acp.js.map +1 -0
- package/dist/cli/audit.d.ts +11 -0
- package/dist/cli/audit.d.ts.map +1 -0
- package/dist/cli/audit.js +55 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/cache.d.ts +10 -0
- package/dist/cli/cache.d.ts.map +1 -0
- package/dist/cli/cache.js +77 -0
- package/dist/cli/cache.js.map +1 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +168 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/cron.d.ts +5 -0
- package/dist/cli/cron.d.ts.map +1 -0
- package/dist/cli/cron.js +192 -0
- package/dist/cli/cron.js.map +1 -0
- package/dist/cli/extensions.d.ts +5 -0
- package/dist/cli/extensions.d.ts.map +1 -0
- package/dist/cli/extensions.js +53 -0
- package/dist/cli/extensions.js.map +1 -0
- package/dist/cli/logs.d.ts +5 -0
- package/dist/cli/logs.d.ts.map +1 -0
- package/dist/cli/logs.js +49 -0
- package/dist/cli/logs.js.map +1 -0
- package/dist/cli/memory.d.ts +5 -0
- package/dist/cli/memory.d.ts.map +1 -0
- package/dist/cli/memory.js +78 -0
- package/dist/cli/memory.js.map +1 -0
- package/dist/cli/message.d.ts +5 -0
- package/dist/cli/message.d.ts.map +1 -0
- package/dist/cli/message.js +69 -0
- package/dist/cli/message.js.map +1 -0
- package/dist/cli/service.d.ts +14 -0
- package/dist/cli/service.d.ts.map +1 -0
- package/dist/cli/service.js +181 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/symphony.d.ts +5 -0
- package/dist/cli/symphony.d.ts.map +1 -0
- package/dist/cli/symphony.js +114 -0
- package/dist/cli/symphony.js.map +1 -0
- package/dist/cli/update.d.ts +5 -0
- package/dist/cli/update.d.ts.map +1 -0
- package/dist/cli/update.js +48 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/commands/channel-setup.d.ts +31 -0
- package/dist/commands/channel-setup.d.ts.map +1 -0
- package/dist/commands/channel-setup.js +138 -0
- package/dist/commands/channel-setup.js.map +1 -0
- package/dist/commands/dispatch.d.ts +48 -0
- package/dist/commands/dispatch.d.ts.map +1 -0
- package/dist/commands/dispatch.js +68 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/model-picker.d.ts +16 -0
- package/dist/commands/model-picker.d.ts.map +1 -0
- package/dist/commands/model-picker.js +120 -0
- package/dist/commands/model-picker.js.map +1 -0
- package/dist/commands/parser.d.ts +32 -0
- package/dist/commands/parser.d.ts.map +1 -0
- package/dist/commands/parser.js +39 -0
- package/dist/commands/parser.js.map +1 -0
- package/dist/commands/registry.d.ts +76 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +351 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/skill-commands.d.ts +35 -0
- package/dist/commands/skill-commands.d.ts.map +1 -0
- package/dist/commands/skill-commands.js +61 -0
- package/dist/commands/skill-commands.js.map +1 -0
- package/dist/config/resolve.d.ts +25 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +289 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/config/schema.d.ts +520 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +123 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/agent-loop.d.ts +137 -0
- package/dist/core/agent-loop.d.ts.map +1 -0
- package/dist/core/agent-loop.js +700 -0
- package/dist/core/agent-loop.js.map +1 -0
- package/dist/core/audit.d.ts +87 -0
- package/dist/core/audit.d.ts.map +1 -0
- package/dist/core/audit.js +224 -0
- package/dist/core/audit.js.map +1 -0
- package/dist/core/bootstrap.d.ts +23 -0
- package/dist/core/bootstrap.d.ts.map +1 -0
- package/dist/core/bootstrap.js +162 -0
- package/dist/core/bootstrap.js.map +1 -0
- package/dist/core/context.d.ts +44 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +65 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/cron.d.ts +111 -0
- package/dist/core/cron.d.ts.map +1 -0
- package/dist/core/cron.js +284 -0
- package/dist/core/cron.js.map +1 -0
- package/dist/core/exec-approvals.d.ts +50 -0
- package/dist/core/exec-approvals.d.ts.map +1 -0
- package/dist/core/exec-approvals.js +187 -0
- package/dist/core/exec-approvals.js.map +1 -0
- package/dist/core/heartbeat.d.ts +71 -0
- package/dist/core/heartbeat.d.ts.map +1 -0
- package/dist/core/heartbeat.js +214 -0
- package/dist/core/heartbeat.js.map +1 -0
- package/dist/core/message-queue.d.ts +60 -0
- package/dist/core/message-queue.d.ts.map +1 -0
- package/dist/core/message-queue.js +182 -0
- package/dist/core/message-queue.js.map +1 -0
- package/dist/core/network-policy.d.ts +39 -0
- package/dist/core/network-policy.d.ts.map +1 -0
- package/dist/core/network-policy.js +121 -0
- package/dist/core/network-policy.js.map +1 -0
- package/dist/core/progress.d.ts +48 -0
- package/dist/core/progress.d.ts.map +1 -0
- package/dist/core/progress.js +81 -0
- package/dist/core/progress.js.map +1 -0
- package/dist/core/prompt.d.ts +105 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +411 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/pruning.d.ts +40 -0
- package/dist/core/pruning.d.ts.map +1 -0
- package/dist/core/pruning.js +165 -0
- package/dist/core/pruning.js.map +1 -0
- package/dist/core/rate-limiter.d.ts +64 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js +142 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/reactions.d.ts +31 -0
- package/dist/core/reactions.d.ts.map +1 -0
- package/dist/core/reactions.js +67 -0
- package/dist/core/reactions.js.map +1 -0
- package/dist/core/retry-queue.d.ts +56 -0
- package/dist/core/retry-queue.d.ts.map +1 -0
- package/dist/core/retry-queue.js +106 -0
- package/dist/core/retry-queue.js.map +1 -0
- package/dist/core/sanitizer.d.ts +38 -0
- package/dist/core/sanitizer.d.ts.map +1 -0
- package/dist/core/sanitizer.js +181 -0
- package/dist/core/sanitizer.js.map +1 -0
- package/dist/core/secret-scanner.d.ts +39 -0
- package/dist/core/secret-scanner.d.ts.map +1 -0
- package/dist/core/secret-scanner.js +96 -0
- package/dist/core/secret-scanner.js.map +1 -0
- package/dist/core/secrets.d.ts +38 -0
- package/dist/core/secrets.d.ts.map +1 -0
- package/dist/core/secrets.js +137 -0
- package/dist/core/secrets.js.map +1 -0
- package/dist/core/security.d.ts +58 -0
- package/dist/core/security.d.ts.map +1 -0
- package/dist/core/security.js +120 -0
- package/dist/core/security.js.map +1 -0
- package/dist/core/self-awareness.d.ts +19 -0
- package/dist/core/self-awareness.d.ts.map +1 -0
- package/dist/core/self-awareness.js +124 -0
- package/dist/core/self-awareness.js.map +1 -0
- package/dist/core/session-init.d.ts +34 -0
- package/dist/core/session-init.d.ts.map +1 -0
- package/dist/core/session-init.js +68 -0
- package/dist/core/session-init.js.map +1 -0
- package/dist/core/streaming.d.ts +82 -0
- package/dist/core/streaming.d.ts.map +1 -0
- package/dist/core/streaming.js +264 -0
- package/dist/core/streaming.js.map +1 -0
- package/dist/core/symphony/orchestrator.d.ts +61 -0
- package/dist/core/symphony/orchestrator.d.ts.map +1 -0
- package/dist/core/symphony/orchestrator.js +476 -0
- package/dist/core/symphony/orchestrator.js.map +1 -0
- package/dist/core/symphony/status.d.ts +11 -0
- package/dist/core/symphony/status.d.ts.map +1 -0
- package/dist/core/symphony/status.js +133 -0
- package/dist/core/symphony/status.js.map +1 -0
- package/dist/core/symphony/types.d.ts +84 -0
- package/dist/core/symphony/types.d.ts.map +1 -0
- package/dist/core/symphony/types.js +5 -0
- package/dist/core/symphony/types.js.map +1 -0
- package/dist/core/symphony/workflow.d.ts +18 -0
- package/dist/core/symphony/workflow.d.ts.map +1 -0
- package/dist/core/symphony/workflow.js +149 -0
- package/dist/core/symphony/workflow.js.map +1 -0
- package/dist/core/symphony/workspace.d.ts +24 -0
- package/dist/core/symphony/workspace.d.ts.map +1 -0
- package/dist/core/symphony/workspace.js +94 -0
- package/dist/core/symphony/workspace.js.map +1 -0
- package/dist/core/thinking.d.ts +27 -0
- package/dist/core/thinking.d.ts.map +1 -0
- package/dist/core/thinking.js +83 -0
- package/dist/core/thinking.js.map +1 -0
- package/dist/core/thread-bindings.d.ts +47 -0
- package/dist/core/thread-bindings.d.ts.map +1 -0
- package/dist/core/thread-bindings.js +94 -0
- package/dist/core/thread-bindings.js.map +1 -0
- package/dist/core/timezone.d.ts +28 -0
- package/dist/core/timezone.d.ts.map +1 -0
- package/dist/core/timezone.js +72 -0
- package/dist/core/timezone.js.map +1 -0
- package/dist/core/tool-loop-detector.d.ts +41 -0
- package/dist/core/tool-loop-detector.d.ts.map +1 -0
- package/dist/core/tool-loop-detector.js +83 -0
- package/dist/core/tool-loop-detector.js.map +1 -0
- package/dist/core/tool-validator.d.ts +44 -0
- package/dist/core/tool-validator.d.ts.map +1 -0
- package/dist/core/tool-validator.js +175 -0
- package/dist/core/tool-validator.js.map +1 -0
- package/dist/core/typing.d.ts +25 -0
- package/dist/core/typing.d.ts.map +1 -0
- package/dist/core/typing.js +48 -0
- package/dist/core/typing.js.map +1 -0
- package/dist/core/usage-tracker.d.ts +66 -0
- package/dist/core/usage-tracker.d.ts.map +1 -0
- package/dist/core/usage-tracker.js +163 -0
- package/dist/core/usage-tracker.js.map +1 -0
- package/dist/daemon/commands.d.ts +16 -0
- package/dist/daemon/commands.d.ts.map +1 -0
- package/dist/daemon/commands.js +445 -0
- package/dist/daemon/commands.js.map +1 -0
- package/dist/daemon/pid.d.ts +30 -0
- package/dist/daemon/pid.d.ts.map +1 -0
- package/dist/daemon/pid.js +62 -0
- package/dist/daemon/pid.js.map +1 -0
- package/dist/doctor/checks/browser.d.ts +9 -0
- package/dist/doctor/checks/browser.d.ts.map +1 -0
- package/dist/doctor/checks/browser.js +54 -0
- package/dist/doctor/checks/browser.js.map +1 -0
- package/dist/doctor/checks/channels.d.ts +9 -0
- package/dist/doctor/checks/channels.d.ts.map +1 -0
- package/dist/doctor/checks/channels.js +90 -0
- package/dist/doctor/checks/channels.js.map +1 -0
- package/dist/doctor/checks/config.d.ts +10 -0
- package/dist/doctor/checks/config.d.ts.map +1 -0
- package/dist/doctor/checks/config.js +89 -0
- package/dist/doctor/checks/config.js.map +1 -0
- package/dist/doctor/checks/memory.d.ts +10 -0
- package/dist/doctor/checks/memory.d.ts.map +1 -0
- package/dist/doctor/checks/memory.js +82 -0
- package/dist/doctor/checks/memory.js.map +1 -0
- package/dist/doctor/checks/permissions.d.ts +9 -0
- package/dist/doctor/checks/permissions.d.ts.map +1 -0
- package/dist/doctor/checks/permissions.js +53 -0
- package/dist/doctor/checks/permissions.js.map +1 -0
- package/dist/doctor/checks/providers.d.ts +10 -0
- package/dist/doctor/checks/providers.d.ts.map +1 -0
- package/dist/doctor/checks/providers.js +93 -0
- package/dist/doctor/checks/providers.js.map +1 -0
- package/dist/doctor/checks/sessions.d.ts +10 -0
- package/dist/doctor/checks/sessions.d.ts.map +1 -0
- package/dist/doctor/checks/sessions.js +86 -0
- package/dist/doctor/checks/sessions.js.map +1 -0
- package/dist/doctor/doctor.d.ts +35 -0
- package/dist/doctor/doctor.d.ts.map +1 -0
- package/dist/doctor/doctor.js +51 -0
- package/dist/doctor/doctor.js.map +1 -0
- package/dist/doctor/repairs.d.ts +14 -0
- package/dist/doctor/repairs.d.ts.map +1 -0
- package/dist/doctor/repairs.js +34 -0
- package/dist/doctor/repairs.js.map +1 -0
- package/dist/gateway/compaction.d.ts +63 -0
- package/dist/gateway/compaction.d.ts.map +1 -0
- package/dist/gateway/compaction.js +235 -0
- package/dist/gateway/compaction.js.map +1 -0
- package/dist/gateway/gateway.d.ts +94 -0
- package/dist/gateway/gateway.d.ts.map +1 -0
- package/dist/gateway/gateway.js +466 -0
- package/dist/gateway/gateway.js.map +1 -0
- package/dist/gateway/lock.d.ts +24 -0
- package/dist/gateway/lock.d.ts.map +1 -0
- package/dist/gateway/lock.js +88 -0
- package/dist/gateway/lock.js.map +1 -0
- package/dist/gateway/protocol.d.ts +117 -0
- package/dist/gateway/protocol.d.ts.map +1 -0
- package/dist/gateway/protocol.js +5 -0
- package/dist/gateway/protocol.js.map +1 -0
- package/dist/gateway/session.d.ts +123 -0
- package/dist/gateway/session.d.ts.map +1 -0
- package/dist/gateway/session.js +573 -0
- package/dist/gateway/session.js.map +1 -0
- package/dist/hooks/hooks.d.ts +18 -0
- package/dist/hooks/hooks.d.ts.map +1 -0
- package/dist/hooks/hooks.js +45 -0
- package/dist/hooks/hooks.js.map +1 -0
- package/dist/hooks/types.d.ts +112 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +23 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2900 -0
- package/dist/index.js.map +1 -0
- package/dist/media/storage.d.ts +25 -0
- package/dist/media/storage.d.ts.map +1 -0
- package/dist/media/storage.js +97 -0
- package/dist/media/storage.js.map +1 -0
- package/dist/memory/embeddings.d.ts +46 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +118 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/hybrid.d.ts +35 -0
- package/dist/memory/hybrid.d.ts.map +1 -0
- package/dist/memory/hybrid.js +156 -0
- package/dist/memory/hybrid.js.map +1 -0
- package/dist/memory/markdown.d.ts +48 -0
- package/dist/memory/markdown.d.ts.map +1 -0
- package/dist/memory/markdown.js +228 -0
- package/dist/memory/markdown.js.map +1 -0
- package/dist/memory/store.d.ts +88 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +21 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/vector.d.ts +24 -0
- package/dist/memory/vector.d.ts.map +1 -0
- package/dist/memory/vector.js +63 -0
- package/dist/memory/vector.js.map +1 -0
- package/dist/mods/mod.d.ts +100 -0
- package/dist/mods/mod.d.ts.map +1 -0
- package/dist/mods/mod.js +242 -0
- package/dist/mods/mod.js.map +1 -0
- package/dist/onboard/channels.d.ts +12 -0
- package/dist/onboard/channels.d.ts.map +1 -0
- package/dist/onboard/channels.js +283 -0
- package/dist/onboard/channels.js.map +1 -0
- package/dist/onboard/models.d.ts +13 -0
- package/dist/onboard/models.d.ts.map +1 -0
- package/dist/onboard/models.js +491 -0
- package/dist/onboard/models.js.map +1 -0
- package/dist/onboard/onboard.d.ts +12 -0
- package/dist/onboard/onboard.d.ts.map +1 -0
- package/dist/onboard/onboard.js +1137 -0
- package/dist/onboard/onboard.js.map +1 -0
- package/dist/providers/anthropic.d.ts +83 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +583 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/failover.d.ts +46 -0
- package/dist/providers/failover.d.ts.map +1 -0
- package/dist/providers/failover.js +149 -0
- package/dist/providers/failover.js.map +1 -0
- package/dist/providers/litellm.d.ts +38 -0
- package/dist/providers/litellm.d.ts.map +1 -0
- package/dist/providers/litellm.js +349 -0
- package/dist/providers/litellm.js.map +1 -0
- package/dist/providers/openai.d.ts +28 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +321 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/prompt-cache.d.ts +50 -0
- package/dist/providers/prompt-cache.d.ts.map +1 -0
- package/dist/providers/prompt-cache.js +96 -0
- package/dist/providers/prompt-cache.js.map +1 -0
- package/dist/providers/provider.d.ts +173 -0
- package/dist/providers/provider.d.ts.map +1 -0
- package/dist/providers/provider.js +22 -0
- package/dist/providers/provider.js.map +1 -0
- package/dist/sandbox/config.d.ts +42 -0
- package/dist/sandbox/config.d.ts.map +1 -0
- package/dist/sandbox/config.js +20 -0
- package/dist/sandbox/config.js.map +1 -0
- package/dist/sandbox/container.d.ts +71 -0
- package/dist/sandbox/container.d.ts.map +1 -0
- package/dist/sandbox/container.js +193 -0
- package/dist/sandbox/container.js.map +1 -0
- package/dist/sandbox/sandbox.d.ts +82 -0
- package/dist/sandbox/sandbox.d.ts.map +1 -0
- package/dist/sandbox/sandbox.js +176 -0
- package/dist/sandbox/sandbox.js.map +1 -0
- package/dist/skills/channel-loader.d.ts +18 -0
- package/dist/skills/channel-loader.d.ts.map +1 -0
- package/dist/skills/channel-loader.js +35 -0
- package/dist/skills/channel-loader.js.map +1 -0
- package/dist/skills/extension-loader.d.ts +15 -0
- package/dist/skills/extension-loader.d.ts.map +1 -0
- package/dist/skills/extension-loader.js +63 -0
- package/dist/skills/extension-loader.js.map +1 -0
- package/dist/skills/extension-registry.d.ts +32 -0
- package/dist/skills/extension-registry.d.ts.map +1 -0
- package/dist/skills/extension-registry.js +57 -0
- package/dist/skills/extension-registry.js.map +1 -0
- package/dist/skills/extensions.d.ts +91 -0
- package/dist/skills/extensions.d.ts.map +1 -0
- package/dist/skills/extensions.js +14 -0
- package/dist/skills/extensions.js.map +1 -0
- package/dist/skills/loader.d.ts +64 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +382 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/marketplace.d.ts +56 -0
- package/dist/skills/marketplace.d.ts.map +1 -0
- package/dist/skills/marketplace.js +183 -0
- package/dist/skills/marketplace.js.map +1 -0
- package/dist/skills/types.d.ts +94 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +9 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/acp-sessions.d.ts +89 -0
- package/dist/tools/acp-sessions.d.ts.map +1 -0
- package/dist/tools/acp-sessions.js +391 -0
- package/dist/tools/acp-sessions.js.map +1 -0
- package/dist/tools/acp.d.ts +18 -0
- package/dist/tools/acp.d.ts.map +1 -0
- package/dist/tools/acp.js +102 -0
- package/dist/tools/acp.js.map +1 -0
- package/dist/tools/agent-tools.d.ts +24 -0
- package/dist/tools/agent-tools.d.ts.map +1 -0
- package/dist/tools/agent-tools.js +611 -0
- package/dist/tools/agent-tools.js.map +1 -0
- package/dist/tools/browser.d.ts +26 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +242 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/comms.d.ts +8 -0
- package/dist/tools/comms.d.ts.map +1 -0
- package/dist/tools/comms.js +39 -0
- package/dist/tools/comms.js.map +1 -0
- package/dist/tools/cron-tools.d.ts +9 -0
- package/dist/tools/cron-tools.d.ts.map +1 -0
- package/dist/tools/cron-tools.js +117 -0
- package/dist/tools/cron-tools.js.map +1 -0
- package/dist/tools/exec-safety.d.ts +71 -0
- package/dist/tools/exec-safety.d.ts.map +1 -0
- package/dist/tools/exec-safety.js +141 -0
- package/dist/tools/exec-safety.js.map +1 -0
- package/dist/tools/exec.d.ts +24 -0
- package/dist/tools/exec.d.ts.map +1 -0
- package/dist/tools/exec.js +191 -0
- package/dist/tools/exec.js.map +1 -0
- package/dist/tools/fs.d.ts +15 -0
- package/dist/tools/fs.d.ts.map +1 -0
- package/dist/tools/fs.js +249 -0
- package/dist/tools/fs.js.map +1 -0
- package/dist/tools/git.d.ts +9 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +56 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/image.d.ts +15 -0
- package/dist/tools/image.d.ts.map +1 -0
- package/dist/tools/image.js +106 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/introspect.d.ts +22 -0
- package/dist/tools/introspect.d.ts.map +1 -0
- package/dist/tools/introspect.js +223 -0
- package/dist/tools/introspect.js.map +1 -0
- package/dist/tools/memory.d.ts +11 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +101 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/message.d.ts +24 -0
- package/dist/tools/message.d.ts.map +1 -0
- package/dist/tools/message.js +205 -0
- package/dist/tools/message.js.map +1 -0
- package/dist/tools/model.d.ts +14 -0
- package/dist/tools/model.d.ts.map +1 -0
- package/dist/tools/model.js +62 -0
- package/dist/tools/model.js.map +1 -0
- package/dist/tools/policy.d.ts +101 -0
- package/dist/tools/policy.d.ts.map +1 -0
- package/dist/tools/policy.js +168 -0
- package/dist/tools/policy.js.map +1 -0
- package/dist/tools/registry.d.ts +52 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +154 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/search.d.ts +10 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +78 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/session.d.ts +13 -0
- package/dist/tools/session.d.ts.map +1 -0
- package/dist/tools/session.js +142 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/tools/spawn.d.ts +10 -0
- package/dist/tools/spawn.d.ts.map +1 -0
- package/dist/tools/spawn.js +72 -0
- package/dist/tools/spawn.js.map +1 -0
- package/dist/tools/symphony.d.ts +12 -0
- package/dist/tools/symphony.d.ts.map +1 -0
- package/dist/tools/symphony.js +142 -0
- package/dist/tools/symphony.js.map +1 -0
- package/dist/tools/system-tools.d.ts +11 -0
- package/dist/tools/system-tools.d.ts.map +1 -0
- package/dist/tools/system-tools.js +39 -0
- package/dist/tools/system-tools.js.map +1 -0
- package/dist/tools/tool.d.ts +119 -0
- package/dist/tools/tool.d.ts.map +1 -0
- package/dist/tools/tool.js +29 -0
- package/dist/tools/tool.js.map +1 -0
- package/dist/tools/web.d.ts +10 -0
- package/dist/tools/web.d.ts.map +1 -0
- package/dist/tools/web.js +105 -0
- package/dist/tools/web.js.map +1 -0
- package/dist/tui/App.d.ts +43 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +265 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/bridge.d.ts +40 -0
- package/dist/tui/bridge.d.ts.map +1 -0
- package/dist/tui/bridge.js +29 -0
- package/dist/tui/bridge.js.map +1 -0
- package/dist/tui/components/Header.d.ts +14 -0
- package/dist/tui/components/Header.d.ts.map +1 -0
- package/dist/tui/components/Header.js +7 -0
- package/dist/tui/components/Header.js.map +1 -0
- package/dist/tui/components/InputBar.d.ts +10 -0
- package/dist/tui/components/InputBar.d.ts.map +1 -0
- package/dist/tui/components/InputBar.js +121 -0
- package/dist/tui/components/InputBar.js.map +1 -0
- package/dist/tui/components/MessageList.d.ts +18 -0
- package/dist/tui/components/MessageList.d.ts.map +1 -0
- package/dist/tui/components/MessageList.js +34 -0
- package/dist/tui/components/MessageList.js.map +1 -0
- package/dist/tui/components/Spinner.d.ts +9 -0
- package/dist/tui/components/Spinner.d.ts.map +1 -0
- package/dist/tui/components/Spinner.js +18 -0
- package/dist/tui/components/Spinner.js.map +1 -0
- package/dist/tui/components/StatusBar.d.ts +16 -0
- package/dist/tui/components/StatusBar.d.ts.map +1 -0
- package/dist/tui/components/StatusBar.js +15 -0
- package/dist/tui/components/StatusBar.js.map +1 -0
- package/dist/tui/components/ToolCallBox.d.ts +12 -0
- package/dist/tui/components/ToolCallBox.d.ts.map +1 -0
- package/dist/tui/components/ToolCallBox.js +12 -0
- package/dist/tui/components/ToolCallBox.js.map +1 -0
- package/dist/tui/theme.d.ts +58 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +80 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +70 -0
- package/dist/utils/logger.js.map +1 -0
- package/docs/DEVELOPMENT.md +74 -0
- package/docs/INSTALL.md +161 -0
- package/docs/USAGE.md +94 -0
- package/docs/architecture.md +128 -0
- package/docs/channels.md +140 -0
- package/docs/configuration.md +209 -0
- package/docs/io-system.md +430 -0
- package/docs/providers.md +99 -0
- package/docs/skill-channels.md +113 -0
- package/docs/skills.md +246 -0
- package/package.json +89 -0
- package/skills/acp-router/SKILL.md +41 -0
- package/skills/acp-router/tools/acp-router.mjs +239 -0
- package/skills/find-skills/SKILL.md +133 -0
- package/skills/security-audit/SKILL.md +181 -0
- package/skills/security-audit/audit.sh +67 -0
- package/skills/skill-creator/SKILL.md +479 -0
- package/skills/skill-security-audit/.clawhub/origin.json +7 -0
- package/skills/skill-security-audit/SKILL.md +196 -0
- package/skills/skill-security-audit/_meta.json +6 -0
- package/skills/skill-security-audit/references/prompt-injection-patterns.md +276 -0
- package/skills/skill-security-audit/references/vulnerability-patterns.md +348 -0
- package/skills/symphony/README.md +53 -0
- package/skills/symphony/SKILL.md +75 -0
- package/skills/symphony/tools/symphony-orchestrator.ts +8 -0
- package/tako.example.json +33 -0
|
@@ -0,0 +1,1137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tako 🐙 Interactive Onboarding Wizard
|
|
3
|
+
*
|
|
4
|
+
* Multi-provider setup with fallback chain and conversational identity builder:
|
|
5
|
+
* 1. Provider dashboard — configure multiple providers
|
|
6
|
+
* 2. Fallback model chain — up to 4 models
|
|
7
|
+
* 3. Identity builder — conversational SOUL/IDENTITY/USER generation
|
|
8
|
+
* 4. Channel setup — Discord / Telegram (integrated)
|
|
9
|
+
* 5. Write config + workspace files
|
|
10
|
+
*/
|
|
11
|
+
import * as p from '@clack/prompts';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { mkdir, writeFile, readFile } from 'node:fs/promises';
|
|
15
|
+
import { existsSync } from 'node:fs';
|
|
16
|
+
import { DEFAULT_CONFIG } from '../config/schema.js';
|
|
17
|
+
import { writeAuthCredential, getAuthStatus } from '../auth/storage.js';
|
|
18
|
+
import { validateAnthropicSetupToken, runOAuthFlow, OAUTH_PROVIDERS } from '../auth/oauth.js';
|
|
19
|
+
import { LiteLLMProvider } from '../providers/litellm.js';
|
|
20
|
+
const PROVIDERS = [
|
|
21
|
+
{
|
|
22
|
+
id: 'anthropic',
|
|
23
|
+
label: 'Anthropic (Claude)',
|
|
24
|
+
hint: 'API key or setup-token',
|
|
25
|
+
envVar: 'ANTHROPIC_API_KEY',
|
|
26
|
+
authMethods: [
|
|
27
|
+
{ value: 'api_key', label: 'API Key', hint: 'paste ANTHROPIC_API_KEY' },
|
|
28
|
+
{ value: 'setup_token', label: 'Setup Token', hint: 'from `claude setup-token`' },
|
|
29
|
+
],
|
|
30
|
+
models: [
|
|
31
|
+
// Fallback models if API fetch fails
|
|
32
|
+
{ value: 'anthropic/claude-sonnet-4-6', label: 'claude-sonnet-4-6', hint: 'fast, recommended' },
|
|
33
|
+
{ value: 'anthropic/claude-opus-4-6', label: 'claude-opus-4-6', hint: 'powerful, slower' },
|
|
34
|
+
{ value: 'anthropic/claude-haiku-4-5', label: 'claude-haiku-4-5', hint: 'fastest, cheapest' },
|
|
35
|
+
],
|
|
36
|
+
verify: async (apiKey) => {
|
|
37
|
+
const extractError = (body) => {
|
|
38
|
+
if (!body || typeof body !== 'object')
|
|
39
|
+
return 'unknown error';
|
|
40
|
+
const b = body;
|
|
41
|
+
const e = b.error;
|
|
42
|
+
if (typeof e === 'string')
|
|
43
|
+
return e;
|
|
44
|
+
if (e && typeof e === 'object') {
|
|
45
|
+
const m = e.message;
|
|
46
|
+
if (typeof m === 'string')
|
|
47
|
+
return m;
|
|
48
|
+
return JSON.stringify(e);
|
|
49
|
+
}
|
|
50
|
+
if (typeof b.message === 'string')
|
|
51
|
+
return b.message;
|
|
52
|
+
return 'unknown error';
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
const headers = {
|
|
56
|
+
'anthropic-version': '2023-06-01',
|
|
57
|
+
};
|
|
58
|
+
// Detect OAuth token vs API key
|
|
59
|
+
if (apiKey.includes('sk-ant-oat')) {
|
|
60
|
+
headers['authorization'] = `Bearer ${apiKey}`;
|
|
61
|
+
headers['anthropic-beta'] = 'claude-code-20250219,oauth-2025-04-20';
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
headers['x-api-key'] = apiKey;
|
|
65
|
+
}
|
|
66
|
+
// reference runtime-style: verify key with /v1/models first (not model-dependent)
|
|
67
|
+
const modelsRes = await fetch('https://api.anthropic.com/v1/models', { headers });
|
|
68
|
+
if (modelsRes.ok)
|
|
69
|
+
return { ok: true };
|
|
70
|
+
if (modelsRes.status === 401 || modelsRes.status === 403) {
|
|
71
|
+
return { ok: false, error: 'Invalid API key' };
|
|
72
|
+
}
|
|
73
|
+
// Fallback probe: /v1/messages to differentiate auth vs payload issues
|
|
74
|
+
const msgRes = await fetch('https://api.anthropic.com/v1/messages', {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers: { ...headers, 'content-type': 'application/json' },
|
|
77
|
+
body: JSON.stringify({
|
|
78
|
+
model: 'claude-sonnet-4-6',
|
|
79
|
+
max_tokens: 1,
|
|
80
|
+
messages: [{ role: 'user', content: 'hi' }],
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
if (msgRes.ok)
|
|
84
|
+
return { ok: true };
|
|
85
|
+
if (msgRes.status === 401 || msgRes.status === 403) {
|
|
86
|
+
return { ok: false, error: 'Invalid API key' };
|
|
87
|
+
}
|
|
88
|
+
if (msgRes.status === 400) {
|
|
89
|
+
// Auth is valid; request payload/model may be wrong
|
|
90
|
+
return { ok: true };
|
|
91
|
+
}
|
|
92
|
+
const body = await msgRes.json().catch(() => ({}));
|
|
93
|
+
return { ok: false, error: `API returned ${msgRes.status}: ${extractError(body)}` };
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return { ok: false, error: `Connection failed: ${err.message}` };
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
fetchModels: async (apiKey) => {
|
|
100
|
+
try {
|
|
101
|
+
const headers = { 'anthropic-version': '2023-06-01' };
|
|
102
|
+
if (apiKey.includes('sk-ant-oat')) {
|
|
103
|
+
headers['authorization'] = `Bearer ${apiKey}`;
|
|
104
|
+
headers['anthropic-beta'] = 'claude-code-20250219,oauth-2025-04-20';
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
headers['x-api-key'] = apiKey;
|
|
108
|
+
}
|
|
109
|
+
const res = await fetch('https://api.anthropic.com/v1/models', { headers });
|
|
110
|
+
if (!res.ok)
|
|
111
|
+
return [];
|
|
112
|
+
const data = await res.json();
|
|
113
|
+
return (data.data ?? []).map((m) => m.id).filter((id) => id.includes('claude'));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'openai',
|
|
122
|
+
label: 'OpenAI (GPT)',
|
|
123
|
+
hint: 'API key or OAuth',
|
|
124
|
+
envVar: 'OPENAI_API_KEY',
|
|
125
|
+
authMethods: [
|
|
126
|
+
{ value: 'api_key', label: 'API Key', hint: 'paste OPENAI_API_KEY' },
|
|
127
|
+
{ value: 'oauth', label: 'OAuth (Codex)', hint: 'browser login to ChatGPT' },
|
|
128
|
+
],
|
|
129
|
+
models: [
|
|
130
|
+
// Fallback models if API fetch fails
|
|
131
|
+
{ value: 'openai/gpt-5.2', label: 'gpt-5.2', hint: 'latest' },
|
|
132
|
+
{ value: 'openai/gpt-5-mini', label: 'gpt-5-mini', hint: 'fast' },
|
|
133
|
+
{ value: 'openai-codex/gpt-5.3-codex', label: 'gpt-5.3-codex', hint: 'Codex OAuth, most powerful' },
|
|
134
|
+
{ value: 'openai-codex/gpt-5.2-codex', label: 'gpt-5.2-codex', hint: 'Codex OAuth' },
|
|
135
|
+
],
|
|
136
|
+
verify: async (apiKey) => {
|
|
137
|
+
try {
|
|
138
|
+
const res = await fetch('https://api.openai.com/v1/models', {
|
|
139
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
140
|
+
});
|
|
141
|
+
if (res.ok)
|
|
142
|
+
return { ok: true };
|
|
143
|
+
if (res.status === 401)
|
|
144
|
+
return { ok: false, error: 'Invalid API key' };
|
|
145
|
+
return { ok: false, error: `API returned ${res.status}` };
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
return { ok: false, error: `Connection failed: ${err.message}` };
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
fetchModels: async (apiKey) => {
|
|
152
|
+
try {
|
|
153
|
+
const res = await fetch('https://api.openai.com/v1/models', {
|
|
154
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
155
|
+
});
|
|
156
|
+
if (!res.ok)
|
|
157
|
+
return [];
|
|
158
|
+
const data = await res.json();
|
|
159
|
+
const NON_CHAT = ['dall-e', 'davinci', 'babbage', 'whisper', 'tts-', 'text-embedding', 'text-moderation', 'canary', 'audio'];
|
|
160
|
+
return (data.data ?? [])
|
|
161
|
+
.map((m) => m.id)
|
|
162
|
+
.filter((id) => !NON_CHAT.some((prefix) => id.startsWith(prefix)))
|
|
163
|
+
.sort((a, b) => {
|
|
164
|
+
// Priority sort: gpt-5 first, then codex, then gpt-4, then rest
|
|
165
|
+
const priority = (m) => {
|
|
166
|
+
if (m.includes('gpt-5'))
|
|
167
|
+
return 0;
|
|
168
|
+
if (m.includes('codex'))
|
|
169
|
+
return 1;
|
|
170
|
+
if (m.includes('gpt-4o'))
|
|
171
|
+
return 2;
|
|
172
|
+
if (m.includes('gpt-4'))
|
|
173
|
+
return 3;
|
|
174
|
+
if (m.includes('o3') || m.includes('o4'))
|
|
175
|
+
return 4;
|
|
176
|
+
return 5;
|
|
177
|
+
};
|
|
178
|
+
return priority(a) - priority(b) || a.localeCompare(b);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: 'litellm',
|
|
188
|
+
label: 'LiteLLM (proxy to 100+ providers)',
|
|
189
|
+
hint: 'OpenAI-compatible proxy',
|
|
190
|
+
envVar: 'LITELLM_API_KEY',
|
|
191
|
+
authMethods: [
|
|
192
|
+
{ value: 'proxy', label: 'Proxy connection', hint: 'base URL + optional API key' },
|
|
193
|
+
],
|
|
194
|
+
models: [],
|
|
195
|
+
verify: async (_apiKey) => ({ ok: true }),
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: 'custom',
|
|
199
|
+
label: 'Custom (OpenAI-compatible endpoint)',
|
|
200
|
+
hint: 'Any OpenAI-compatible API',
|
|
201
|
+
envVar: 'CUSTOM_API_KEY',
|
|
202
|
+
authMethods: [
|
|
203
|
+
{ value: 'api_key', label: 'API Key', hint: 'paste API key' },
|
|
204
|
+
],
|
|
205
|
+
models: [],
|
|
206
|
+
verify: async (_apiKey) => ({ ok: true }),
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
// ─── Main onboard flow ──────────────────────────────────────────────
|
|
210
|
+
export async function runOnboard() {
|
|
211
|
+
const takoDir = join(homedir(), '.tako');
|
|
212
|
+
const configPath = join(takoDir, 'tako.json');
|
|
213
|
+
p.intro('◉‿◉ Tako Setup');
|
|
214
|
+
// Load existing config if re-running
|
|
215
|
+
let existingConfig = {};
|
|
216
|
+
if (existsSync(configPath)) {
|
|
217
|
+
try {
|
|
218
|
+
existingConfig = JSON.parse(await readFile(configPath, 'utf-8'));
|
|
219
|
+
}
|
|
220
|
+
catch { /* ignore invalid config */ }
|
|
221
|
+
p.log.info('Found existing config at ~/.tako/tako.json — you can update it.');
|
|
222
|
+
}
|
|
223
|
+
// ── Step 1: Multi-provider dashboard ──────────────────────────────
|
|
224
|
+
const configured = [];
|
|
225
|
+
// Pre-populate from existing config
|
|
226
|
+
if (existingConfig.providers?.primary) {
|
|
227
|
+
const existingPrimary = existingConfig.providers.primary.split('/')[0];
|
|
228
|
+
if (PROVIDERS.some((prov) => prov.id === existingPrimary) && !configured.some((c) => c.id === existingPrimary)) {
|
|
229
|
+
configured.push({ id: existingPrimary });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (existingConfig.providers?.fallback) {
|
|
233
|
+
for (const fb of existingConfig.providers.fallback) {
|
|
234
|
+
const fbProvider = fb.split('/')[0];
|
|
235
|
+
if (PROVIDERS.some((prov) => prov.id === fbProvider) && !configured.some((c) => c.id === fbProvider)) {
|
|
236
|
+
configured.push({ id: fbProvider });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Restore LiteLLM config from existing tako.json
|
|
241
|
+
const existingLitellm = existingConfig.providers?.litellm;
|
|
242
|
+
if (existingLitellm?.baseUrl) {
|
|
243
|
+
const existing = configured.find((c) => c.id === 'litellm');
|
|
244
|
+
if (existing) {
|
|
245
|
+
// Merge litellm-specific fields into the bare entry added from primary/fallback
|
|
246
|
+
existing.litellmEndpointName = existing.litellmEndpointName ?? existingLitellm.name;
|
|
247
|
+
existing.litellmBaseUrl = existing.litellmBaseUrl ?? existingLitellm.baseUrl;
|
|
248
|
+
existing.apiKey = existing.apiKey ?? existingLitellm.apiKey;
|
|
249
|
+
existing.litellmModel = existing.litellmModel ?? existingLitellm.model;
|
|
250
|
+
existing.litellmModels = existing.litellmModels ?? existingLitellm.models;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
configured.push({
|
|
254
|
+
id: 'litellm',
|
|
255
|
+
litellmEndpointName: existingLitellm.name,
|
|
256
|
+
apiKey: existingLitellm.apiKey,
|
|
257
|
+
litellmBaseUrl: existingLitellm.baseUrl,
|
|
258
|
+
litellmModel: existingLitellm.model,
|
|
259
|
+
litellmModels: existingLitellm.models,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Also check auth status for all providers
|
|
264
|
+
for (const prov of PROVIDERS) {
|
|
265
|
+
const status = await getAuthStatus(prov.id);
|
|
266
|
+
if (status.authenticated && !configured.some((c) => c.id === prov.id)) {
|
|
267
|
+
const sourceLabel = status.source === 'env' ? 'env var'
|
|
268
|
+
: status.method === 'oauth' ? 'OAuth'
|
|
269
|
+
: status.method === 'setup_token' ? 'setup token'
|
|
270
|
+
: status.method === 'api_key' ? 'API key'
|
|
271
|
+
: 'auth file';
|
|
272
|
+
configured.push({ id: prov.id, source: sourceLabel });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Provider dashboard loop
|
|
276
|
+
let providersDone = false;
|
|
277
|
+
while (!providersDone) {
|
|
278
|
+
// Build dashboard display
|
|
279
|
+
const dashLines = PROVIDERS.map((prov) => {
|
|
280
|
+
const conf = configured.find((c) => c.id === prov.id);
|
|
281
|
+
const icon = conf ? '✅' : '⬜';
|
|
282
|
+
const status = conf
|
|
283
|
+
? `configured (${conf.source ?? 'API key'})`
|
|
284
|
+
: 'not configured';
|
|
285
|
+
return ` ${prov.label.padEnd(35)} ${icon} ${status}`;
|
|
286
|
+
});
|
|
287
|
+
p.log.message(['', '◉‿◉ Tako Provider Setup', '', ' Provider Status', ' ' + '─'.repeat(50), ...dashLines, ''].join('\n'));
|
|
288
|
+
const action = await p.select({
|
|
289
|
+
message: 'What would you like to do?',
|
|
290
|
+
options: [
|
|
291
|
+
...PROVIDERS.map((prov) => {
|
|
292
|
+
const isConfigured = configured.some((c) => c.id === prov.id);
|
|
293
|
+
return {
|
|
294
|
+
value: prov.id,
|
|
295
|
+
label: isConfigured ? `Re-configure ${prov.label}` : `Configure ${prov.label}`,
|
|
296
|
+
hint: prov.hint,
|
|
297
|
+
};
|
|
298
|
+
}),
|
|
299
|
+
{ value: '__continue__', label: 'Continue →', hint: configured.length > 0 ? `${configured.length} provider(s) ready` : 'at least 1 provider required' },
|
|
300
|
+
],
|
|
301
|
+
});
|
|
302
|
+
if (p.isCancel(action)) {
|
|
303
|
+
p.cancel('Setup cancelled.');
|
|
304
|
+
process.exit(0);
|
|
305
|
+
}
|
|
306
|
+
if (action === '__continue__') {
|
|
307
|
+
if (configured.length === 0) {
|
|
308
|
+
p.log.warn('You need at least one configured provider to continue.');
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
providersDone = true;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
const result = await configureProvider(action);
|
|
315
|
+
if (result) {
|
|
316
|
+
// Replace or add
|
|
317
|
+
const idx = configured.findIndex((c) => c.id === result.id);
|
|
318
|
+
if (idx >= 0)
|
|
319
|
+
configured[idx] = result;
|
|
320
|
+
else
|
|
321
|
+
configured.push(result);
|
|
322
|
+
// Debug: show what was saved
|
|
323
|
+
if (result.id === 'litellm') {
|
|
324
|
+
p.log.info(`[debug] LiteLLM saved to configured: baseUrl=${result.litellmBaseUrl}, models=${result.litellmModels?.join(', ')}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// ── Step 2: Fallback model chain ──────────────────────────────────
|
|
330
|
+
// Collect all available models from configured providers
|
|
331
|
+
const modelSpinner = p.spinner();
|
|
332
|
+
modelSpinner.start('Fetching available models from configured providers...');
|
|
333
|
+
const availableModels = await collectAvailableModels(configured);
|
|
334
|
+
modelSpinner.stop(`Found ${availableModels.length} models from ${configured.length} provider(s).`);
|
|
335
|
+
const modelChain = existingConfig.providers?.primary
|
|
336
|
+
? [existingConfig.providers.primary, ...(existingConfig.providers.fallback ?? [])]
|
|
337
|
+
: [];
|
|
338
|
+
// Filter out models from providers that are no longer configured
|
|
339
|
+
const configuredIds = new Set(configured.map((c) => c.id));
|
|
340
|
+
const validChain = modelChain.filter((m) => configuredIds.has(m.split('/')[0]));
|
|
341
|
+
// Initialize chain
|
|
342
|
+
const chain = [
|
|
343
|
+
validChain[0] ?? null,
|
|
344
|
+
validChain[1] ?? null,
|
|
345
|
+
validChain[2] ?? null,
|
|
346
|
+
validChain[3] ?? null,
|
|
347
|
+
];
|
|
348
|
+
let chainDone = false;
|
|
349
|
+
while (!chainDone) {
|
|
350
|
+
const labels = ['Primary', 'Fallback', 'Fallback', 'Fallback'];
|
|
351
|
+
const chainLines = chain.map((model, i) => {
|
|
352
|
+
const num = i + 1;
|
|
353
|
+
const label = labels[i];
|
|
354
|
+
const display = model ?? '(none)';
|
|
355
|
+
const icon = model ? '✅' : '';
|
|
356
|
+
return ` ${num}. ${label.padEnd(10)} ${display.padEnd(35)} ${icon}`;
|
|
357
|
+
});
|
|
358
|
+
p.log.message(['', 'Set up your model fallback chain (up to 4):', '', ...chainLines, ''].join('\n'));
|
|
359
|
+
const slotOptions = chain.map((model, i) => ({
|
|
360
|
+
value: String(i),
|
|
361
|
+
label: model ? `Change slot ${i + 1}: ${model}` : `Set slot ${i + 1} (${labels[i]})`,
|
|
362
|
+
}));
|
|
363
|
+
const chainAction = await p.select({
|
|
364
|
+
message: 'What would you like to do?',
|
|
365
|
+
options: [
|
|
366
|
+
...slotOptions,
|
|
367
|
+
{ value: '__continue__', label: 'Continue →', hint: chain[0] ? 'primary model set' : 'primary model required' },
|
|
368
|
+
],
|
|
369
|
+
});
|
|
370
|
+
if (p.isCancel(chainAction)) {
|
|
371
|
+
p.cancel('Setup cancelled.');
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
if (chainAction === '__continue__') {
|
|
375
|
+
if (!chain[0]) {
|
|
376
|
+
p.log.warn('A primary model is required.');
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
chainDone = true;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
const slotIdx = parseInt(chainAction, 10);
|
|
383
|
+
const modelOptions = availableModels.map((m) => ({
|
|
384
|
+
value: m.value,
|
|
385
|
+
label: m.label,
|
|
386
|
+
hint: m.hint,
|
|
387
|
+
}));
|
|
388
|
+
if (slotIdx > 0) {
|
|
389
|
+
modelOptions.push({ value: '__clear__', label: '(none) — remove this fallback', hint: '' });
|
|
390
|
+
}
|
|
391
|
+
const chosen = await p.select({
|
|
392
|
+
message: `Choose model for slot ${slotIdx + 1}:`,
|
|
393
|
+
options: modelOptions,
|
|
394
|
+
});
|
|
395
|
+
if (p.isCancel(chosen))
|
|
396
|
+
continue;
|
|
397
|
+
if (chosen === '__clear__') {
|
|
398
|
+
chain[slotIdx] = null;
|
|
399
|
+
}
|
|
400
|
+
else if (chosen === '__custom__') {
|
|
401
|
+
const customId = await p.text({
|
|
402
|
+
message: 'Enter model ID (e.g. anthropic/claude-sonnet-4-6):',
|
|
403
|
+
validate: (val) => val?.includes('/') ? undefined : 'Format: provider/model-name',
|
|
404
|
+
});
|
|
405
|
+
if (p.isCancel(customId))
|
|
406
|
+
continue;
|
|
407
|
+
chain[slotIdx] = customId;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
chain[slotIdx] = chosen;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const primaryModel = chain[0];
|
|
415
|
+
const fallbackModels = chain.slice(1).filter((m) => m !== null);
|
|
416
|
+
// ── Step 3: Conversational identity builder ───────────────────────
|
|
417
|
+
p.log.message('\n◉‿◉ Let\'s get to know each other!\n');
|
|
418
|
+
const ownerName = await p.text({
|
|
419
|
+
message: 'What\'s your name?',
|
|
420
|
+
placeholder: 'Your name',
|
|
421
|
+
validate: (val) => val ? undefined : 'Name is required',
|
|
422
|
+
});
|
|
423
|
+
if (p.isCancel(ownerName)) {
|
|
424
|
+
p.cancel('Setup cancelled.');
|
|
425
|
+
process.exit(0);
|
|
426
|
+
}
|
|
427
|
+
p.log.info(`Nice to meet you, ${ownerName}!`);
|
|
428
|
+
const agentName = await p.text({
|
|
429
|
+
message: 'What should I call myself?',
|
|
430
|
+
placeholder: 'Tako',
|
|
431
|
+
defaultValue: 'Tako',
|
|
432
|
+
validate: (val) => val ? undefined : 'Name is required',
|
|
433
|
+
});
|
|
434
|
+
if (p.isCancel(agentName)) {
|
|
435
|
+
p.cancel('Setup cancelled.');
|
|
436
|
+
process.exit(0);
|
|
437
|
+
}
|
|
438
|
+
const personality = await p.text({
|
|
439
|
+
message: 'Any personality traits you\'d like me to have? (Enter to skip)',
|
|
440
|
+
placeholder: 'e.g. Direct, nerdy, proactive',
|
|
441
|
+
defaultValue: '',
|
|
442
|
+
});
|
|
443
|
+
if (p.isCancel(personality)) {
|
|
444
|
+
p.cancel('Setup cancelled.');
|
|
445
|
+
process.exit(0);
|
|
446
|
+
}
|
|
447
|
+
// ── Step 4: Channel setup ─────────────────────────────────────────
|
|
448
|
+
// Detect existing channel config
|
|
449
|
+
const hasExistingDiscord = !!existingConfig.channels?.discord;
|
|
450
|
+
const hasExistingTelegram = !!existingConfig.channels?.telegram;
|
|
451
|
+
const existingChannels = [
|
|
452
|
+
...(hasExistingDiscord ? ['Discord'] : []),
|
|
453
|
+
...(hasExistingTelegram ? ['Telegram'] : []),
|
|
454
|
+
];
|
|
455
|
+
let discordConfig = hasExistingDiscord ? existingConfig.channels.discord : undefined;
|
|
456
|
+
let telegramConfig = hasExistingTelegram ? existingConfig.channels.telegram : undefined;
|
|
457
|
+
// Build options based on existing config
|
|
458
|
+
const channelOptions = [
|
|
459
|
+
{ value: 'keep', label: `Keep current (${existingChannels.length > 0 ? existingChannels.join(' + ') : 'CLI only'})`, hint: 'no changes' },
|
|
460
|
+
{ value: 'cli', label: 'CLI only', hint: existingChannels.length > 0 ? 'removes existing channels' : 'start chatting right away' },
|
|
461
|
+
{ value: 'discord', label: 'Discord bot', hint: hasExistingDiscord ? 'reconfigure' : 'requires bot token' },
|
|
462
|
+
{ value: 'telegram', label: 'Telegram bot', hint: hasExistingTelegram ? 'reconfigure' : 'requires bot token from @BotFather' },
|
|
463
|
+
{ value: 'both', label: 'Discord + Telegram', hint: 'set up both' },
|
|
464
|
+
];
|
|
465
|
+
// Remove 'keep' option if no existing config
|
|
466
|
+
if (!hasExistingDiscord && !hasExistingTelegram) {
|
|
467
|
+
channelOptions.shift();
|
|
468
|
+
}
|
|
469
|
+
const channelChoice = await p.select({
|
|
470
|
+
message: 'Set up messaging channels?',
|
|
471
|
+
options: channelOptions,
|
|
472
|
+
});
|
|
473
|
+
if (p.isCancel(channelChoice)) {
|
|
474
|
+
p.cancel('Setup cancelled.');
|
|
475
|
+
process.exit(0);
|
|
476
|
+
}
|
|
477
|
+
if (channelChoice === 'keep') {
|
|
478
|
+
// Keep existing — do nothing
|
|
479
|
+
}
|
|
480
|
+
else if (channelChoice === 'cli') {
|
|
481
|
+
discordConfig = undefined;
|
|
482
|
+
telegramConfig = undefined;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
if (channelChoice === 'discord' || channelChoice === 'both') {
|
|
486
|
+
const result = await setupDiscord();
|
|
487
|
+
if (!result) {
|
|
488
|
+
p.cancel('Setup cancelled.');
|
|
489
|
+
process.exit(0);
|
|
490
|
+
}
|
|
491
|
+
discordConfig = result;
|
|
492
|
+
}
|
|
493
|
+
if (channelChoice === 'telegram' || channelChoice === 'both') {
|
|
494
|
+
const result = await setupTelegram();
|
|
495
|
+
if (!result) {
|
|
496
|
+
p.cancel('Setup cancelled.');
|
|
497
|
+
process.exit(0);
|
|
498
|
+
}
|
|
499
|
+
telegramConfig = result;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
// ── Step 5: Deployment mode ─────────────────────────────────────
|
|
503
|
+
const deployMode = await p.select({
|
|
504
|
+
message: 'How will you run Tako?',
|
|
505
|
+
options: [
|
|
506
|
+
{ value: 'local', label: 'Locally', hint: 'recommended for development' },
|
|
507
|
+
{ value: 'docker', label: 'Docker', hint: 'recommended for production/servers' },
|
|
508
|
+
],
|
|
509
|
+
});
|
|
510
|
+
if (p.isCancel(deployMode)) {
|
|
511
|
+
p.cancel('Setup cancelled.');
|
|
512
|
+
process.exit(0);
|
|
513
|
+
}
|
|
514
|
+
// ── Step 6: Build config ──────────────────────────────────────────
|
|
515
|
+
// Find litellm config if litellm is configured
|
|
516
|
+
const litellmConfigured = configured.find((c) => c.id === 'litellm');
|
|
517
|
+
// Debug: log litellm config detection
|
|
518
|
+
if (litellmConfigured) {
|
|
519
|
+
p.log.info(`LiteLLM config found: baseUrl=${litellmConfigured.litellmBaseUrl ?? '(none)'}, endpoint=${litellmConfigured.litellmEndpointName ?? '(none)'}, models=${litellmConfigured.litellmModels?.join(', ') ?? '(none)'}`);
|
|
520
|
+
}
|
|
521
|
+
else if (primaryModel.startsWith('litellm/')) {
|
|
522
|
+
p.log.warn('Primary model uses litellm/ prefix but no LiteLLM provider was configured!');
|
|
523
|
+
p.log.warn('The LiteLLM endpoint config will NOT be saved. Please configure LiteLLM first.');
|
|
524
|
+
}
|
|
525
|
+
// Also scan configured array for any litellm entries with models but no baseUrl
|
|
526
|
+
// This catches the case where litellm models were selected from collectAvailableModels
|
|
527
|
+
// but the user didn't explicitly configure litellm as a provider
|
|
528
|
+
const litellmFromModels = primaryModel.startsWith('litellm/') || fallbackModels.some((m) => m.startsWith('litellm/'));
|
|
529
|
+
if (litellmFromModels && !litellmConfigured?.litellmBaseUrl) {
|
|
530
|
+
p.log.warn('⚠ LiteLLM models are in your chain but no LiteLLM endpoint is configured.');
|
|
531
|
+
p.log.warn(' These models will NOT work without a LiteLLM proxy endpoint.');
|
|
532
|
+
p.log.warn(' Go back and configure LiteLLM first, or change your primary model.');
|
|
533
|
+
}
|
|
534
|
+
const config = {
|
|
535
|
+
...DEFAULT_CONFIG,
|
|
536
|
+
providers: {
|
|
537
|
+
primary: primaryModel,
|
|
538
|
+
...(fallbackModels.length > 0 ? { fallback: fallbackModels } : {}),
|
|
539
|
+
...(litellmConfigured?.litellmBaseUrl ? {
|
|
540
|
+
litellm: {
|
|
541
|
+
name: litellmConfigured.litellmEndpointName || 'LiteLLM',
|
|
542
|
+
baseUrl: litellmConfigured.litellmBaseUrl,
|
|
543
|
+
apiKey: litellmConfigured.apiKey || undefined,
|
|
544
|
+
model: litellmConfigured.litellmModel ?? 'default',
|
|
545
|
+
...(litellmConfigured.litellmModels && litellmConfigured.litellmModels.length > 1
|
|
546
|
+
? { models: litellmConfigured.litellmModels }
|
|
547
|
+
: {}),
|
|
548
|
+
},
|
|
549
|
+
} : {}),
|
|
550
|
+
},
|
|
551
|
+
channels: {
|
|
552
|
+
...(discordConfig ? { discord: discordConfig } : {}),
|
|
553
|
+
...(telegramConfig ? { telegram: telegramConfig } : {}),
|
|
554
|
+
},
|
|
555
|
+
memory: {
|
|
556
|
+
workspace: '~/.tako/workspace',
|
|
557
|
+
},
|
|
558
|
+
};
|
|
559
|
+
// ── Validate: ensure litellm config is present if litellm models are used ──
|
|
560
|
+
if (config.providers.primary.startsWith('litellm/') && !config.providers.litellm) {
|
|
561
|
+
p.log.error('Your primary model uses LiteLLM but no LiteLLM endpoint was configured!');
|
|
562
|
+
p.log.error('This would result in a broken config. Please go back and configure LiteLLM first.');
|
|
563
|
+
p.log.info(`Debug: configured providers = [${configured.map((c) => `${c.id}(baseUrl=${c.litellmBaseUrl ?? 'none'})`).join(', ')}]`);
|
|
564
|
+
p.cancel('Config validation failed.');
|
|
565
|
+
process.exit(1);
|
|
566
|
+
}
|
|
567
|
+
// ── Step 6: Write config + workspace files ────────────────────────
|
|
568
|
+
const writeSpinner = p.spinner();
|
|
569
|
+
writeSpinner.start('Writing configuration...');
|
|
570
|
+
await mkdir(takoDir, { recursive: true });
|
|
571
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
572
|
+
// Bootstrap workspace
|
|
573
|
+
const workspaceDir = join(takoDir, 'workspace');
|
|
574
|
+
await mkdir(workspaceDir, { recursive: true });
|
|
575
|
+
await mkdir(join(workspaceDir, 'memory', 'daily'), { recursive: true });
|
|
576
|
+
await mkdir(join(workspaceDir, '.sessions'), { recursive: true });
|
|
577
|
+
// Generate SOUL.md
|
|
578
|
+
const traits = personality ? personality.split(',').map((t) => t.trim()).filter(Boolean) : [];
|
|
579
|
+
const traitSection = traits.length > 0
|
|
580
|
+
? `\n## Personality\n\n${traits.map((t) => `- **${t}**`).join('\n')}\n`
|
|
581
|
+
: '';
|
|
582
|
+
const soulMd = `# Soul
|
|
583
|
+
|
|
584
|
+
You are ${agentName} 🐙, a general-purpose AI agent. You can do anything — research, coding, writing, analysis, automation. You're the core OS agent with pluggable skill arms for any task.
|
|
585
|
+
|
|
586
|
+
Use your name "${agentName}" when introducing yourself. Avoid using emojis excessively — use them sparingly if at all.
|
|
587
|
+
${traitSection}
|
|
588
|
+
## Approach
|
|
589
|
+
|
|
590
|
+
- Think step-by-step before multi-step actions
|
|
591
|
+
- Use the right tool for each task — don't over-engineer
|
|
592
|
+
- Learn from mistakes, store the lesson in memory
|
|
593
|
+
- Keep responses focused and relevant
|
|
594
|
+
- When uncertain, ask rather than guess
|
|
595
|
+
`;
|
|
596
|
+
// Generate IDENTITY.md
|
|
597
|
+
const identityMd = `# Identity
|
|
598
|
+
|
|
599
|
+
- **Name:** ${agentName}
|
|
600
|
+
- **Version:** 0.0.1
|
|
601
|
+
- **Type:** Agent OS (Agent-as-CPU architecture)
|
|
602
|
+
- **Owner:** ${ownerName}
|
|
603
|
+
- **Providers:** ${configured.map((c) => c.id).join(', ')}
|
|
604
|
+
- **Primary Model:** ${primaryModel}
|
|
605
|
+
- **Channels:** ${['CLI', ...(discordConfig ? ['Discord'] : []), ...(telegramConfig ? ['Telegram'] : [])].join(', ')}
|
|
606
|
+
- **Architecture:** Provider → Agent Loop → Tools/Skills → Channel
|
|
607
|
+
`;
|
|
608
|
+
// Generate USER.md
|
|
609
|
+
const userMd = `# User Profile
|
|
610
|
+
|
|
611
|
+
## Owner
|
|
612
|
+
|
|
613
|
+
- **Name:** ${ownerName}
|
|
614
|
+
|
|
615
|
+
## Preferences
|
|
616
|
+
|
|
617
|
+
- (populated over time)
|
|
618
|
+
`;
|
|
619
|
+
await writeFile(join(workspaceDir, 'SOUL.md'), soulMd, 'utf-8');
|
|
620
|
+
await writeFile(join(workspaceDir, 'IDENTITY.md'), identityMd, 'utf-8');
|
|
621
|
+
await writeFile(join(workspaceDir, 'USER.md'), userMd, 'utf-8');
|
|
622
|
+
writeSpinner.stop('Config saved to ~/.tako/tako.json');
|
|
623
|
+
// ── Welcome outro ─────────────────────────────────────────────────
|
|
624
|
+
const channels = ['CLI', ...(discordConfig ? ['Discord'] : []), ...(telegramConfig ? ['Telegram'] : [])];
|
|
625
|
+
const fallbackDisplay = fallbackModels.length > 0 ? fallbackModels.join(' → ') : '(none)';
|
|
626
|
+
p.note([
|
|
627
|
+
`Name: ${agentName}`,
|
|
628
|
+
`Owner: ${ownerName}`,
|
|
629
|
+
`Model: ${primaryModel}`,
|
|
630
|
+
`Fallback: ${fallbackDisplay}`,
|
|
631
|
+
`Channels: ${channels.join(', ')}`,
|
|
632
|
+
].join('\n'), '◉‿◉ All set! Here\'s your Tako:');
|
|
633
|
+
if (deployMode === 'docker') {
|
|
634
|
+
p.outro([
|
|
635
|
+
'To run with Docker:',
|
|
636
|
+
' 1. cd to the tako project directory',
|
|
637
|
+
' 2. ./docker-setup.sh (or: docker compose up -d)',
|
|
638
|
+
'',
|
|
639
|
+
'Gateway will be at http://127.0.0.1:18790',
|
|
640
|
+
].join('\n'));
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
p.outro("Run 'tako start' to begin chatting! 🐙");
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
// ─── Provider configuration ──────────────────────────────────────────
|
|
647
|
+
async function configureProvider(providerId) {
|
|
648
|
+
const provider = PROVIDERS.find((prov) => prov.id === providerId);
|
|
649
|
+
p.log.info(`Configuring ${provider.label}...`);
|
|
650
|
+
if (provider.id === 'litellm') {
|
|
651
|
+
const result = await setupLiteLLM();
|
|
652
|
+
if (!result)
|
|
653
|
+
return null;
|
|
654
|
+
return { id: 'litellm', apiKey: result.apiKey, litellmEndpointName: result.endpointName, litellmBaseUrl: result.baseUrl, litellmModel: result.model, litellmModels: result.models };
|
|
655
|
+
}
|
|
656
|
+
if (provider.id === 'custom') {
|
|
657
|
+
const baseUrl = await p.text({
|
|
658
|
+
message: 'Enter your API base URL:',
|
|
659
|
+
placeholder: 'https://api.example.com/v1',
|
|
660
|
+
validate: (val) => {
|
|
661
|
+
if (!val)
|
|
662
|
+
return 'URL is required';
|
|
663
|
+
try {
|
|
664
|
+
new URL(val);
|
|
665
|
+
}
|
|
666
|
+
catch {
|
|
667
|
+
return 'Invalid URL';
|
|
668
|
+
}
|
|
669
|
+
return undefined;
|
|
670
|
+
},
|
|
671
|
+
});
|
|
672
|
+
if (p.isCancel(baseUrl))
|
|
673
|
+
return null;
|
|
674
|
+
const keyInput = await p.password({
|
|
675
|
+
message: 'API key (leave empty if none):',
|
|
676
|
+
});
|
|
677
|
+
if (p.isCancel(keyInput))
|
|
678
|
+
return null;
|
|
679
|
+
if (keyInput) {
|
|
680
|
+
const credential = {
|
|
681
|
+
provider: 'custom',
|
|
682
|
+
auth_method: 'api_key',
|
|
683
|
+
api_key: keyInput,
|
|
684
|
+
created_at: Date.now(),
|
|
685
|
+
};
|
|
686
|
+
await writeAuthCredential(credential);
|
|
687
|
+
}
|
|
688
|
+
p.log.success(`Custom provider configured (${baseUrl}).`);
|
|
689
|
+
return { id: 'custom', customBaseUrl: baseUrl };
|
|
690
|
+
}
|
|
691
|
+
// Standard provider (Anthropic, OpenAI)
|
|
692
|
+
let apiKey = '';
|
|
693
|
+
let authMethod = 'api_key';
|
|
694
|
+
if (provider.authMethods.length > 1) {
|
|
695
|
+
const choice = await p.select({
|
|
696
|
+
message: 'How do you want to authenticate?',
|
|
697
|
+
options: provider.authMethods.map((m) => ({
|
|
698
|
+
value: m.value,
|
|
699
|
+
label: m.label,
|
|
700
|
+
hint: m.hint,
|
|
701
|
+
})),
|
|
702
|
+
});
|
|
703
|
+
if (p.isCancel(choice))
|
|
704
|
+
return null;
|
|
705
|
+
authMethod = choice;
|
|
706
|
+
}
|
|
707
|
+
if (authMethod === 'oauth') {
|
|
708
|
+
const oauthProviderKey = provider.id === 'openai' ? 'openai-codex' : provider.id;
|
|
709
|
+
if (OAUTH_PROVIDERS[oauthProviderKey]) {
|
|
710
|
+
const result = await runOAuthFlow(oauthProviderKey, {
|
|
711
|
+
log: (msg) => p.log.info(msg),
|
|
712
|
+
prompt: async (message) => {
|
|
713
|
+
const code = await p.text({ message, validate: (v) => v ? undefined : 'Required' });
|
|
714
|
+
if (p.isCancel(code))
|
|
715
|
+
return null;
|
|
716
|
+
return code;
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
if (!result)
|
|
720
|
+
return null;
|
|
721
|
+
p.log.success('OAuth authentication successful! Token stored.');
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
p.log.error(`OAuth not configured for ${provider.id}.`);
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
else if (authMethod === 'setup_token') {
|
|
729
|
+
p.log.info('Run `claude setup-token` in another terminal to get a setup token.');
|
|
730
|
+
const tokenInput = await p.password({
|
|
731
|
+
message: 'Paste your setup token:',
|
|
732
|
+
validate: (val) => validateAnthropicSetupToken(val ?? ''),
|
|
733
|
+
});
|
|
734
|
+
if (p.isCancel(tokenInput))
|
|
735
|
+
return null;
|
|
736
|
+
const credential = {
|
|
737
|
+
provider: 'anthropic',
|
|
738
|
+
auth_method: 'setup_token',
|
|
739
|
+
setup_token: tokenInput.trim(),
|
|
740
|
+
created_at: Date.now(),
|
|
741
|
+
};
|
|
742
|
+
await writeAuthCredential(credential);
|
|
743
|
+
apiKey = tokenInput.trim(); // Store for dynamic model fetching
|
|
744
|
+
p.log.success('Setup token stored.');
|
|
745
|
+
}
|
|
746
|
+
else {
|
|
747
|
+
// API key flow
|
|
748
|
+
apiKey = process.env[provider.envVar] ?? '';
|
|
749
|
+
if (apiKey) {
|
|
750
|
+
const useExisting = await p.confirm({
|
|
751
|
+
message: `Found ${provider.envVar} in environment. Use it?`,
|
|
752
|
+
initialValue: true,
|
|
753
|
+
});
|
|
754
|
+
if (p.isCancel(useExisting))
|
|
755
|
+
return null;
|
|
756
|
+
if (!useExisting)
|
|
757
|
+
apiKey = '';
|
|
758
|
+
}
|
|
759
|
+
if (!apiKey) {
|
|
760
|
+
const keyInput = await p.password({
|
|
761
|
+
message: `Paste your ${provider.label} API key:`,
|
|
762
|
+
validate: (val) => {
|
|
763
|
+
if (!val || val.trim().length === 0)
|
|
764
|
+
return 'API key is required';
|
|
765
|
+
return undefined;
|
|
766
|
+
},
|
|
767
|
+
});
|
|
768
|
+
if (p.isCancel(keyInput))
|
|
769
|
+
return null;
|
|
770
|
+
apiKey = keyInput;
|
|
771
|
+
}
|
|
772
|
+
// Verify key
|
|
773
|
+
const verifySpinner = p.spinner();
|
|
774
|
+
verifySpinner.start('Verifying API key...');
|
|
775
|
+
const verification = await provider.verify(apiKey);
|
|
776
|
+
if (!verification.ok) {
|
|
777
|
+
verifySpinner.stop(`Key verification failed: ${verification.error}`);
|
|
778
|
+
const continueAnyway = await p.confirm({
|
|
779
|
+
message: 'Continue with this key anyway?',
|
|
780
|
+
initialValue: false,
|
|
781
|
+
});
|
|
782
|
+
if (p.isCancel(continueAnyway) || !continueAnyway)
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
else {
|
|
786
|
+
verifySpinner.stop(`Key verified! Connected to ${provider.label}.`);
|
|
787
|
+
}
|
|
788
|
+
// Store credential
|
|
789
|
+
const credential = {
|
|
790
|
+
provider: provider.id,
|
|
791
|
+
auth_method: 'api_key',
|
|
792
|
+
api_key: apiKey,
|
|
793
|
+
created_at: Date.now(),
|
|
794
|
+
};
|
|
795
|
+
await writeAuthCredential(credential);
|
|
796
|
+
// Also write to .env for backward compat
|
|
797
|
+
const takoDir = join(homedir(), '.tako');
|
|
798
|
+
const envPath = join(takoDir, '.env');
|
|
799
|
+
let envContent = '';
|
|
800
|
+
if (existsSync(envPath)) {
|
|
801
|
+
envContent = await readFile(envPath, 'utf-8');
|
|
802
|
+
}
|
|
803
|
+
const envLine = `${provider.envVar}=${apiKey}`;
|
|
804
|
+
const regex = new RegExp(`^${provider.envVar}=.*$`, 'm');
|
|
805
|
+
if (regex.test(envContent)) {
|
|
806
|
+
envContent = envContent.replace(regex, envLine);
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
envContent = envContent ? envContent.trimEnd() + '\n' + envLine + '\n' : envLine + '\n';
|
|
810
|
+
}
|
|
811
|
+
await mkdir(takoDir, { recursive: true });
|
|
812
|
+
await writeFile(envPath, envContent, 'utf-8');
|
|
813
|
+
}
|
|
814
|
+
p.log.success(`${provider.label} configured.`);
|
|
815
|
+
return { id: provider.id, apiKey: apiKey || undefined };
|
|
816
|
+
}
|
|
817
|
+
// ─── Model collection ────────────────────────────────────────────────
|
|
818
|
+
async function collectAvailableModels(configured) {
|
|
819
|
+
const models = [];
|
|
820
|
+
for (const cp of configured) {
|
|
821
|
+
const prov = PROVIDERS.find((p) => p.id === cp.id);
|
|
822
|
+
if (!prov)
|
|
823
|
+
continue;
|
|
824
|
+
// Try to fetch models dynamically from the API
|
|
825
|
+
if (prov.fetchModels && cp.apiKey) {
|
|
826
|
+
try {
|
|
827
|
+
const fetched = await prov.fetchModels(cp.apiKey);
|
|
828
|
+
if (fetched.length > 0) {
|
|
829
|
+
models.push(...fetched.map((m) => ({
|
|
830
|
+
value: `${cp.id}/${m}`,
|
|
831
|
+
label: m,
|
|
832
|
+
hint: cp.id,
|
|
833
|
+
})));
|
|
834
|
+
continue; // Skip hardcoded fallback
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
catch {
|
|
838
|
+
// Fall through to hardcoded models
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
// Fallback to hardcoded model list
|
|
842
|
+
if (prov.models.length > 0) {
|
|
843
|
+
models.push(...prov.models);
|
|
844
|
+
}
|
|
845
|
+
else if (cp.id === 'litellm' && (cp.litellmModels?.length || cp.litellmModel)) {
|
|
846
|
+
const litellmModels = cp.litellmModels ?? (cp.litellmModel ? [cp.litellmModel] : []);
|
|
847
|
+
for (const lm of litellmModels) {
|
|
848
|
+
models.push({ value: `litellm/${lm}`, label: lm, hint: 'LiteLLM proxy' });
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
else if (cp.id === 'custom') {
|
|
852
|
+
models.push({ value: 'custom/default', label: 'custom model', hint: 'custom endpoint' });
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
// Add Codex OAuth models if authenticated
|
|
856
|
+
const codexAuth = await getAuthStatus('openai-codex');
|
|
857
|
+
if (codexAuth.authenticated && !models.some((m) => m.value.includes('codex'))) {
|
|
858
|
+
models.push({ value: 'openai-codex/gpt-5.3-codex', label: 'gpt-5.3-codex', hint: 'Codex OAuth' }, { value: 'openai-codex/gpt-5.2-codex', label: 'gpt-5.2-codex', hint: 'Codex OAuth' });
|
|
859
|
+
}
|
|
860
|
+
// Add a "custom model" option at the end
|
|
861
|
+
models.push({ value: '__custom__', label: 'Enter model ID manually', hint: 'provider/model-name' });
|
|
862
|
+
return models;
|
|
863
|
+
}
|
|
864
|
+
// ─── LiteLLM setup ──────────────────────────────────────────────────
|
|
865
|
+
async function setupLiteLLM() {
|
|
866
|
+
// Step 1: Choose endpoint preset or enter custom
|
|
867
|
+
const PRESETS = [
|
|
868
|
+
{ value: 'local', label: 'Local LiteLLM (localhost:4000)', hint: 'self-hosted proxy' },
|
|
869
|
+
{ value: 'ohmygpt', label: 'OhMyGPT', hint: 'https://api.ohmygpt.com' },
|
|
870
|
+
{ value: 'openrouter', label: 'OpenRouter', hint: 'https://openrouter.ai/api' },
|
|
871
|
+
{ value: 'together', label: 'Together AI', hint: 'https://api.together.xyz' },
|
|
872
|
+
{ value: 'custom', label: 'Custom endpoint...', hint: 'enter URL manually' },
|
|
873
|
+
];
|
|
874
|
+
const PRESET_URLS = {
|
|
875
|
+
local: 'http://localhost:4000',
|
|
876
|
+
ohmygpt: 'https://api.ohmygpt.com',
|
|
877
|
+
openrouter: 'https://openrouter.ai/api',
|
|
878
|
+
together: 'https://api.together.xyz',
|
|
879
|
+
};
|
|
880
|
+
const endpointChoice = await p.select({
|
|
881
|
+
message: 'Choose an endpoint:',
|
|
882
|
+
options: PRESETS,
|
|
883
|
+
});
|
|
884
|
+
if (p.isCancel(endpointChoice))
|
|
885
|
+
return null;
|
|
886
|
+
let baseUrl;
|
|
887
|
+
let endpointName;
|
|
888
|
+
if (endpointChoice === 'custom') {
|
|
889
|
+
const customUrl = await p.text({
|
|
890
|
+
message: 'Endpoint URL:',
|
|
891
|
+
placeholder: 'https://api.example.com/v1',
|
|
892
|
+
validate: (val) => {
|
|
893
|
+
if (!val)
|
|
894
|
+
return 'URL is required';
|
|
895
|
+
try {
|
|
896
|
+
new URL(val);
|
|
897
|
+
}
|
|
898
|
+
catch {
|
|
899
|
+
return 'Invalid URL';
|
|
900
|
+
}
|
|
901
|
+
return undefined;
|
|
902
|
+
},
|
|
903
|
+
});
|
|
904
|
+
if (p.isCancel(customUrl))
|
|
905
|
+
return null;
|
|
906
|
+
baseUrl = customUrl;
|
|
907
|
+
const customName = await p.text({
|
|
908
|
+
message: 'Endpoint name (for display):',
|
|
909
|
+
placeholder: 'my-proxy',
|
|
910
|
+
validate: (val) => val ? undefined : 'Name is required',
|
|
911
|
+
});
|
|
912
|
+
if (p.isCancel(customName))
|
|
913
|
+
return null;
|
|
914
|
+
endpointName = customName;
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
baseUrl = PRESET_URLS[endpointChoice];
|
|
918
|
+
endpointName = PRESETS.find((p) => p.value === endpointChoice).label;
|
|
919
|
+
}
|
|
920
|
+
// Strip trailing /v1 to avoid double path
|
|
921
|
+
baseUrl = baseUrl.replace(/\/+$/, '').replace(/\/v1$/, '');
|
|
922
|
+
// Step 2: API key
|
|
923
|
+
const apiKey = await p.text({
|
|
924
|
+
message: `API key for ${endpointName} (leave empty if none):`,
|
|
925
|
+
placeholder: '',
|
|
926
|
+
defaultValue: '',
|
|
927
|
+
});
|
|
928
|
+
if (p.isCancel(apiKey))
|
|
929
|
+
return null;
|
|
930
|
+
// Test connection
|
|
931
|
+
const testSpinner = p.spinner();
|
|
932
|
+
testSpinner.start('Testing connection...');
|
|
933
|
+
const litellm = new LiteLLMProvider({ baseUrl, apiKey: apiKey || undefined });
|
|
934
|
+
const result = await litellm.testConnection();
|
|
935
|
+
if (result.ok) {
|
|
936
|
+
testSpinner.stop(`Connected! Found ${result.models?.length ?? 0} models on proxy.`);
|
|
937
|
+
if (result.models && result.models.length > 0) {
|
|
938
|
+
p.log.info(`Available models: ${result.models.slice(0, 10).join(', ')}${(result.models.length > 10 ? '...' : '')}`);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
testSpinner.stop(`Connection test failed: ${result.error}`);
|
|
943
|
+
const continueAnyway = await p.confirm({
|
|
944
|
+
message: 'Continue anyway?',
|
|
945
|
+
initialValue: false,
|
|
946
|
+
});
|
|
947
|
+
if (p.isCancel(continueAnyway) || !continueAnyway)
|
|
948
|
+
return null;
|
|
949
|
+
}
|
|
950
|
+
// Choose or enter model name — filter to chat-capable models, show all
|
|
951
|
+
let model;
|
|
952
|
+
const NON_CHAT_PREFIXES = ['dall-e', 'davinci', 'babbage', 'whisper', 'tts-', 'text-embedding', 'text-moderation'];
|
|
953
|
+
const chatModels = (result.ok && result.models)
|
|
954
|
+
? result.models.filter((m) => !NON_CHAT_PREFIXES.some((prefix) => m.startsWith(prefix)))
|
|
955
|
+
: [];
|
|
956
|
+
if (chatModels.length > 0) {
|
|
957
|
+
// Sort: gpt-4o and claude models first, then alphabetical
|
|
958
|
+
const priority = (m) => {
|
|
959
|
+
if (m.includes('gpt-4o'))
|
|
960
|
+
return 0;
|
|
961
|
+
if (m.includes('claude'))
|
|
962
|
+
return 1;
|
|
963
|
+
if (m.includes('gpt-4'))
|
|
964
|
+
return 2;
|
|
965
|
+
return 3;
|
|
966
|
+
};
|
|
967
|
+
chatModels.sort((a, b) => priority(a) - priority(b) || a.localeCompare(b));
|
|
968
|
+
const modelChoice = await p.select({
|
|
969
|
+
message: `Choose a model (${chatModels.length} chat models found):`,
|
|
970
|
+
options: [
|
|
971
|
+
...chatModels.map((m) => ({ value: m, label: m })),
|
|
972
|
+
{ value: '__custom__', label: 'Enter model name manually' },
|
|
973
|
+
],
|
|
974
|
+
});
|
|
975
|
+
if (p.isCancel(modelChoice))
|
|
976
|
+
return null;
|
|
977
|
+
if (modelChoice === '__custom__') {
|
|
978
|
+
const customModel = await p.text({
|
|
979
|
+
message: 'Model name:',
|
|
980
|
+
validate: (val) => val ? undefined : 'Model name is required',
|
|
981
|
+
});
|
|
982
|
+
if (p.isCancel(customModel))
|
|
983
|
+
return null;
|
|
984
|
+
model = customModel;
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
model = modelChoice;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
const customModel = await p.text({
|
|
992
|
+
message: 'Model name:',
|
|
993
|
+
placeholder: 'gpt-4o',
|
|
994
|
+
validate: (val) => val ? undefined : 'Model name is required',
|
|
995
|
+
});
|
|
996
|
+
if (p.isCancel(customModel))
|
|
997
|
+
return null;
|
|
998
|
+
model = customModel;
|
|
999
|
+
}
|
|
1000
|
+
// Multi-model selection: ask to add more models from the proxy
|
|
1001
|
+
const allModels = [model];
|
|
1002
|
+
if (chatModels.length > 1) {
|
|
1003
|
+
let addMore = true;
|
|
1004
|
+
while (addMore) {
|
|
1005
|
+
const wantMore = await p.confirm({
|
|
1006
|
+
message: 'Add more models from this proxy?',
|
|
1007
|
+
initialValue: false,
|
|
1008
|
+
});
|
|
1009
|
+
if (p.isCancel(wantMore) || !wantMore) {
|
|
1010
|
+
addMore = false;
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
const remaining = chatModels.filter((m) => !allModels.includes(m));
|
|
1014
|
+
if (remaining.length === 0) {
|
|
1015
|
+
p.log.info('No more models available.');
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1018
|
+
const extraModel = await p.select({
|
|
1019
|
+
message: `Add another model (${allModels.length} selected so far):`,
|
|
1020
|
+
options: [
|
|
1021
|
+
...remaining.map((m) => ({ value: m, label: m })),
|
|
1022
|
+
{ value: '__done__', label: 'Done — no more models' },
|
|
1023
|
+
],
|
|
1024
|
+
});
|
|
1025
|
+
if (p.isCancel(extraModel) || extraModel === '__done__') {
|
|
1026
|
+
addMore = false;
|
|
1027
|
+
}
|
|
1028
|
+
else {
|
|
1029
|
+
allModels.push(extraModel);
|
|
1030
|
+
p.log.info(`Added: ${extraModel} (${allModels.length} total)`);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
const modelDisplay = allModels.length > 1
|
|
1035
|
+
? `${allModels.length} models: ${allModels.join(', ')}`
|
|
1036
|
+
: `model: ${model}`;
|
|
1037
|
+
p.log.success(`${endpointName} configured (${baseUrl}, ${modelDisplay}).`);
|
|
1038
|
+
return { endpointName, baseUrl, apiKey: apiKey ?? '', model, models: allModels };
|
|
1039
|
+
}
|
|
1040
|
+
// ─── Channel setup helpers ──────────────────────────────────────────
|
|
1041
|
+
async function setupDiscord() {
|
|
1042
|
+
p.log.info([
|
|
1043
|
+
'Discord Bot Setup',
|
|
1044
|
+
'',
|
|
1045
|
+
' 1. Go to https://discord.com/developers/applications',
|
|
1046
|
+
' 2. Create a New Application → Bot tab → Copy token',
|
|
1047
|
+
'',
|
|
1048
|
+
' Required Bot Permissions (OAuth2 → URL Generator):',
|
|
1049
|
+
' ✦ Send Messages ✦ Read Message History',
|
|
1050
|
+
' ✦ Create Public Threads ✦ Send Messages in Threads',
|
|
1051
|
+
' ✦ Manage Channels ✦ Embed Links',
|
|
1052
|
+
' ✦ Attach Files ✦ Add Reactions',
|
|
1053
|
+
' ✦ Use Slash Commands ✦ Read Messages/View Channels',
|
|
1054
|
+
'',
|
|
1055
|
+
' Required Privileged Intents (Bot tab → toggle ON):',
|
|
1056
|
+
' ✦ MESSAGE CONTENT INTENT (required to read messages)',
|
|
1057
|
+
' ✦ SERVER MEMBERS INTENT (optional, for member info)',
|
|
1058
|
+
'',
|
|
1059
|
+
' Adding bot to server:',
|
|
1060
|
+
' Go to OAuth2 → URL Generator → check "bot" + "applications.commands"',
|
|
1061
|
+
' → select the permissions above → copy the invite URL → open in browser',
|
|
1062
|
+
].join('\n'));
|
|
1063
|
+
const token = await p.password({
|
|
1064
|
+
message: 'Discord bot token:',
|
|
1065
|
+
validate: (val) => val ? undefined : 'Token is required',
|
|
1066
|
+
});
|
|
1067
|
+
if (p.isCancel(token))
|
|
1068
|
+
return null;
|
|
1069
|
+
// Verify Discord token
|
|
1070
|
+
const spinner = p.spinner();
|
|
1071
|
+
spinner.start('Verifying Discord token...');
|
|
1072
|
+
try {
|
|
1073
|
+
const res = await fetch('https://discord.com/api/v10/users/@me', {
|
|
1074
|
+
headers: { Authorization: `Bot ${token}` },
|
|
1075
|
+
});
|
|
1076
|
+
if (res.ok) {
|
|
1077
|
+
const bot = await res.json();
|
|
1078
|
+
spinner.stop(`Connected! Bot: ${bot.username}#${bot.discriminator}`);
|
|
1079
|
+
}
|
|
1080
|
+
else {
|
|
1081
|
+
spinner.stop('Token verification failed. You can fix this later.');
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
catch {
|
|
1085
|
+
spinner.stop('Could not reach Discord API. Token saved anyway.');
|
|
1086
|
+
}
|
|
1087
|
+
const guilds = await p.text({
|
|
1088
|
+
message: 'Restrict to specific guild IDs? (comma-separated, or leave empty for all)',
|
|
1089
|
+
placeholder: 'Leave empty for all guilds',
|
|
1090
|
+
defaultValue: '',
|
|
1091
|
+
});
|
|
1092
|
+
if (p.isCancel(guilds))
|
|
1093
|
+
return null;
|
|
1094
|
+
return {
|
|
1095
|
+
token,
|
|
1096
|
+
...(guilds && guilds.trim() ? { guilds: guilds.split(',').map((g) => g.trim()) } : {}),
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
async function setupTelegram() {
|
|
1100
|
+
p.log.info('Telegram Bot Setup — get a token from @BotFather on Telegram');
|
|
1101
|
+
const token = await p.password({
|
|
1102
|
+
message: 'Telegram bot token:',
|
|
1103
|
+
validate: (val) => val ? undefined : 'Token is required',
|
|
1104
|
+
});
|
|
1105
|
+
if (p.isCancel(token))
|
|
1106
|
+
return null;
|
|
1107
|
+
// Verify Telegram token
|
|
1108
|
+
const spinner = p.spinner();
|
|
1109
|
+
spinner.start('Verifying Telegram token...');
|
|
1110
|
+
try {
|
|
1111
|
+
const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);
|
|
1112
|
+
if (res.ok) {
|
|
1113
|
+
const data = await res.json();
|
|
1114
|
+
spinner.stop(`Connected! Bot: @${data.result.username}`);
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
spinner.stop('Token verification failed. You can fix this later.');
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
catch {
|
|
1121
|
+
spinner.stop('Could not reach Telegram API. Token saved anyway.');
|
|
1122
|
+
}
|
|
1123
|
+
const allowedUsers = await p.text({
|
|
1124
|
+
message: 'Restrict to specific user IDs? (comma-separated, or leave empty for all)',
|
|
1125
|
+
placeholder: 'Leave empty to allow all users',
|
|
1126
|
+
defaultValue: '',
|
|
1127
|
+
});
|
|
1128
|
+
if (p.isCancel(allowedUsers))
|
|
1129
|
+
return null;
|
|
1130
|
+
return {
|
|
1131
|
+
token,
|
|
1132
|
+
...(allowedUsers && allowedUsers.trim()
|
|
1133
|
+
? { allowedUsers: allowedUsers.split(',').map((u) => u.trim()) }
|
|
1134
|
+
: {}),
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
//# sourceMappingURL=onboard.js.map
|