cade-cli 0.16.0__tar.gz → 0.16.2__tar.gz
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.
- {cade_cli-0.16.0 → cade_cli-0.16.2}/PKG-INFO +32 -16
- {cade_cli-0.16.0 → cade_cli-0.16.2}/README.md +28 -13
- {cade_cli-0.16.0 → cade_cli-0.16.2}/pyproject.toml +4 -3
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/app.py +18 -12
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/auth.py +6 -6
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/mcp.py +51 -19
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/onboarding.py +173 -15
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/app.py +6 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/server.py +6 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/manager/__init__.py +4 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/manager/config.py +32 -12
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ui/session.py +3 -1
- {cade_cli-0.16.0 → cade_cli-0.16.2}/.gitignore +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/LICENSE +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/__main__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/_metadata.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/config.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/errors.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/grants.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/resources.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/sandbox.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/server.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/_read_cache.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/access.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/agents.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/context.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/filesystem.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/git.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/notifications.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/questions.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/results.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/schemas.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/search.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/shell.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/snippets.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/tasks.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/web_fetch.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/tools/web_search.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/utils.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/arcade_client.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/cache.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/extract.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/markdown.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/preapproved.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/prompts.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/scrape.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/search/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/search/arcade.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/search/base.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cade_mcp_local/web/search/http.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ai/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ai/prompts.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/auth.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/account.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/agents.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/chat.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/cron.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/daemon.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/grant.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/hooks.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/mem.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/tasks.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/thread.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/cli/commands/tools.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/agent.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/comms.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/config.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/constants.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/errors.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/frozen.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/git.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/inbox.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/logging.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/memory.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/model_specs.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/names.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/paths.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/runtime.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/secrets.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/spawn.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/core/types.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/adapters/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/adapters/base.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/adapters/factory.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/adapters/imessage.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/adapters/registry.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/adapters/stub.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/adapters/telegram.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/allowlist.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/attach.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/chunker.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/client.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/commands.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/config.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/control.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/cron.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/elicitation.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/ensure.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/format.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/arcade_export.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/auth.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/constants.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/elicitation.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/exposure.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/limits.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/middleware.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/resources.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/subscriptions.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/gateway/turn_bridge.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/grants.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/inbox_cron.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/install.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/live.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/lock.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/mesh.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/message_pump.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/observability.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/owner.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/progress_sink.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/registry.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/router.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/runner.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/runner_main.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/secrets.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/secrets_broker.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/services.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/shim.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/sinks.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/supervisor.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/tokens.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/traffic.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/turns.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/daemon/wake.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/execution/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/execution/context_window.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/execution/mcp_schema_index.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/execution/orchestrator.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/execution/parallel.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/execution/tool_result_store.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/execution/tool_schema_cache.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/config.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/engine.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/executors/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/executors/callback.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/executors/command.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/executors/http.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/executors/prompt.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/executors/ssrf_guard.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/matchers.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/registry.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/hooks/types.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/providers/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/providers/anthropic.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/providers/base.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/providers/ollama.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/providers/openai.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/serve/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/storage/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/storage/threads.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tasks/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tasks/scheduler.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tasks/store.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tasks/types.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/templates/login_failed.html +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/templates/login_success.html +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/templates/serve/launchd.plist.tmpl +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/templates/serve/serve.toml.example +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/templates/serve/systemd.service.tmpl +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/templates/styles.css +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/manager/_request_ctx.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/manager/base.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/manager/composite.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/manager/mcp.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/search/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/search/discovered.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/search/scoring.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/tools/search/service.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ui/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ui/completion.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ui/display.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ui/elicitation.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ui/input.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/ui/slash.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/voice/__init__.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/voice/audio.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/voice/cleanup.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/voice/session.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/voice/stt.py +0 -0
- {cade_cli-0.16.0 → cade_cli-0.16.2}/src/cadecoder/voice/tts.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cade-cli
|
|
3
|
-
Version: 0.16.
|
|
4
|
-
Summary: Cade - The CLI Agent from Arcade.dev
|
|
3
|
+
Version: 0.16.2
|
|
4
|
+
Summary: Cade - The CLI Agent from Arcade.dev (install: curl -fsSL https://arcadeagent.dev/install | sh)
|
|
5
5
|
Project-URL: Homepage, https://arcade.dev
|
|
6
|
-
Project-URL: Documentation, https://
|
|
6
|
+
Project-URL: Documentation, https://arcadeagent.dev/docs
|
|
7
|
+
Project-URL: Install, https://arcadeagent.dev/install
|
|
7
8
|
Project-URL: Repository, https://github.com/arcadeai-labs/cade
|
|
8
9
|
Project-URL: Issues, https://github.com/arcadeai-labs/cade/issues
|
|
9
10
|
Project-URL: Changelog, https://github.com/arcadeai-labs/cade/releases
|
|
@@ -93,11 +94,15 @@ Description-Content-Type: text/markdown
|
|
|
93
94
|
The CLI agent from [Arcade.dev](https://arcade.dev). Coding, research, and everyday automation — driven from a terminal, a single shell pipe, or a long-lived daemon that replies over Telegram.
|
|
94
95
|
|
|
95
96
|
```bash
|
|
96
|
-
curl -fsSL https://arcadeagent.dev/install | sh
|
|
97
|
-
cade login
|
|
97
|
+
curl -fsSL https://arcadeagent.dev/install | sh
|
|
98
98
|
cade
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
That is the **recommended install** — a prebuilt binary from
|
|
102
|
+
[arcadeagent.dev](https://arcadeagent.dev/install). No GitHub token, no Python
|
|
103
|
+
toolchain. First `cade` walks you through model setup, Arcade login, and the
|
|
104
|
+
[Arcade Agent Hub](https://hub.arcade.dev). Re-run the same curl to upgrade.
|
|
105
|
+
|
|
101
106
|
---
|
|
102
107
|
|
|
103
108
|
## Highlights
|
|
@@ -113,19 +118,18 @@ cade
|
|
|
113
118
|
|
|
114
119
|
## Install
|
|
115
120
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
| From source | `git clone https://github.com/arcadeai-labs/cade.git && cd cade && uv sync` |
|
|
121
|
+
### Recommended (macOS + Linux)
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
curl -fsSL https://arcadeagent.dev/install | sh
|
|
125
|
+
```
|
|
122
126
|
|
|
123
|
-
The
|
|
127
|
+
The script detects your OS/arch, downloads the matching prebuilt binary
|
|
124
128
|
(macOS arm64, Linux x64), verifies its checksum, and drops `cade` in
|
|
125
|
-
`~/.local/bin
|
|
129
|
+
`~/.local/bin`. Pin a version or install location:
|
|
126
130
|
|
|
127
131
|
```bash
|
|
128
|
-
CADE_VERSION=0.
|
|
132
|
+
CADE_VERSION=0.16.2 CADE_INSTALL_DIR=/usr/local/bin \
|
|
129
133
|
sh -c "$(curl -fsSL https://arcadeagent.dev/install)"
|
|
130
134
|
```
|
|
131
135
|
|
|
@@ -133,9 +137,21 @@ On Linux the installer auto-picks a **cpu** or **gpu** build (GPU when
|
|
|
133
137
|
`nvidia-smi` detects a card; the GPU build bundles the CUDA stack and is a much
|
|
134
138
|
larger download). Force it with `CADE_VARIANT=cpu` or `CADE_VARIANT=gpu`.
|
|
135
139
|
|
|
136
|
-
|
|
140
|
+
### Alternatives
|
|
141
|
+
|
|
142
|
+
| Source | Command | When |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| uv | `uv tool install cade-cli` | Prefer a PyPI-managed tool venv |
|
|
145
|
+
| pip | `pip install cade-cli` | Windows, or no curl install |
|
|
146
|
+
| From source | `git clone … && uv sync` | Contributing / hacking on Cade |
|
|
147
|
+
|
|
148
|
+
(Windows: grab the `.zip` from the [releases](https://github.com/arcadeai-labs/cade/releases) page, or `pip install cade-cli`.)
|
|
137
149
|
|
|
138
|
-
**Prerequisites
|
|
150
|
+
**Prerequisites to run Cade:** an LLM provider key (`OPENAI_API_KEY` or
|
|
151
|
+
`ANTHROPIC_API_KEY`), and an Arcade account ([arcade.dev](https://arcade.dev))
|
|
152
|
+
for cloud tools. Skip Arcade with `--local-only` or `CADE_LOCAL_ONLY=1`. The
|
|
153
|
+
curl installer does **not** require a local Python — Python 3.11+ is only needed
|
|
154
|
+
for the uv / pip / from-source paths.
|
|
139
155
|
|
|
140
156
|
The first run walks you through picking a model provider and key (stored in your
|
|
141
157
|
OS keyring); re-run it any time with `cade init`.
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
The CLI agent from [Arcade.dev](https://arcade.dev). Coding, research, and everyday automation — driven from a terminal, a single shell pipe, or a long-lived daemon that replies over Telegram.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
curl -fsSL https://arcadeagent.dev/install | sh
|
|
7
|
-
cade login
|
|
6
|
+
curl -fsSL https://arcadeagent.dev/install | sh
|
|
8
7
|
cade
|
|
9
8
|
```
|
|
10
9
|
|
|
10
|
+
That is the **recommended install** — a prebuilt binary from
|
|
11
|
+
[arcadeagent.dev](https://arcadeagent.dev/install). No GitHub token, no Python
|
|
12
|
+
toolchain. First `cade` walks you through model setup, Arcade login, and the
|
|
13
|
+
[Arcade Agent Hub](https://hub.arcade.dev). Re-run the same curl to upgrade.
|
|
14
|
+
|
|
11
15
|
---
|
|
12
16
|
|
|
13
17
|
## Highlights
|
|
@@ -23,19 +27,18 @@ cade
|
|
|
23
27
|
|
|
24
28
|
## Install
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| From source | `git clone https://github.com/arcadeai-labs/cade.git && cd cade && uv sync` |
|
|
30
|
+
### Recommended (macOS + Linux)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
curl -fsSL https://arcadeagent.dev/install | sh
|
|
34
|
+
```
|
|
32
35
|
|
|
33
|
-
The
|
|
36
|
+
The script detects your OS/arch, downloads the matching prebuilt binary
|
|
34
37
|
(macOS arm64, Linux x64), verifies its checksum, and drops `cade` in
|
|
35
|
-
`~/.local/bin
|
|
38
|
+
`~/.local/bin`. Pin a version or install location:
|
|
36
39
|
|
|
37
40
|
```bash
|
|
38
|
-
CADE_VERSION=0.
|
|
41
|
+
CADE_VERSION=0.16.2 CADE_INSTALL_DIR=/usr/local/bin \
|
|
39
42
|
sh -c "$(curl -fsSL https://arcadeagent.dev/install)"
|
|
40
43
|
```
|
|
41
44
|
|
|
@@ -43,9 +46,21 @@ On Linux the installer auto-picks a **cpu** or **gpu** build (GPU when
|
|
|
43
46
|
`nvidia-smi` detects a card; the GPU build bundles the CUDA stack and is a much
|
|
44
47
|
larger download). Force it with `CADE_VARIANT=cpu` or `CADE_VARIANT=gpu`.
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
### Alternatives
|
|
50
|
+
|
|
51
|
+
| Source | Command | When |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| uv | `uv tool install cade-cli` | Prefer a PyPI-managed tool venv |
|
|
54
|
+
| pip | `pip install cade-cli` | Windows, or no curl install |
|
|
55
|
+
| From source | `git clone … && uv sync` | Contributing / hacking on Cade |
|
|
56
|
+
|
|
57
|
+
(Windows: grab the `.zip` from the [releases](https://github.com/arcadeai-labs/cade/releases) page, or `pip install cade-cli`.)
|
|
47
58
|
|
|
48
|
-
**Prerequisites
|
|
59
|
+
**Prerequisites to run Cade:** an LLM provider key (`OPENAI_API_KEY` or
|
|
60
|
+
`ANTHROPIC_API_KEY`), and an Arcade account ([arcade.dev](https://arcade.dev))
|
|
61
|
+
for cloud tools. Skip Arcade with `--local-only` or `CADE_LOCAL_ONLY=1`. The
|
|
62
|
+
curl installer does **not** require a local Python — Python 3.11+ is only needed
|
|
63
|
+
for the uv / pip / from-source paths.
|
|
49
64
|
|
|
50
65
|
The first run walks you through picking a model provider and key (stored in your
|
|
51
66
|
OS keyring); re-run it any time with `cade init`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cade-cli"
|
|
3
|
-
version = "0.16.
|
|
4
|
-
description = "Cade - The CLI Agent from Arcade.dev"
|
|
3
|
+
version = "0.16.2"
|
|
4
|
+
description = "Cade - The CLI Agent from Arcade.dev (install: curl -fsSL https://arcadeagent.dev/install | sh)"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
7
7
|
license = {file = "LICENSE"}
|
|
@@ -47,7 +47,8 @@ dependencies = [
|
|
|
47
47
|
|
|
48
48
|
[project.urls]
|
|
49
49
|
Homepage = "https://arcade.dev"
|
|
50
|
-
Documentation = "https://
|
|
50
|
+
Documentation = "https://arcadeagent.dev/docs"
|
|
51
|
+
Install = "https://arcadeagent.dev/install"
|
|
51
52
|
Repository = "https://github.com/arcadeai-labs/cade"
|
|
52
53
|
Issues = "https://github.com/arcadeai-labs/cade/issues"
|
|
53
54
|
Changelog = "https://github.com/arcadeai-labs/cade/releases"
|
|
@@ -304,7 +304,7 @@ def _doctor_paths(runtime: Any) -> dict[str, Any]:
|
|
|
304
304
|
rich_help_panel=PANEL_SETUP,
|
|
305
305
|
)
|
|
306
306
|
def init_cmd() -> None:
|
|
307
|
-
from cadecoder.cli.onboarding import can_prompt, run_onboarding
|
|
307
|
+
from cadecoder.cli.onboarding import can_prompt, finish_first_run_cloud, run_onboarding
|
|
308
308
|
|
|
309
309
|
if not can_prompt():
|
|
310
310
|
console.print(
|
|
@@ -312,7 +312,11 @@ def init_cmd() -> None:
|
|
|
312
312
|
"Set OPENAI_API_KEY or ANTHROPIC_API_KEY instead."
|
|
313
313
|
)
|
|
314
314
|
raise typer.Exit(1)
|
|
315
|
-
run_onboarding(console, force=True)
|
|
315
|
+
result = run_onboarding(console, force=True)
|
|
316
|
+
if result:
|
|
317
|
+
runtime = build_runtime()
|
|
318
|
+
set_runtime(runtime)
|
|
319
|
+
finish_first_run_cloud(console, prefer_skip_login=result.chose_local)
|
|
316
320
|
|
|
317
321
|
|
|
318
322
|
@app.command(
|
|
@@ -484,11 +488,16 @@ def main_callback(
|
|
|
484
488
|
# provider + model before we build the runtime, so the first session uses
|
|
485
489
|
# what they chose (not the hardcoded default). No-ops when already set up or
|
|
486
490
|
# when not attached to an interactive terminal (piped/CI).
|
|
487
|
-
from cadecoder.cli.onboarding import
|
|
488
|
-
|
|
489
|
-
|
|
491
|
+
from cadecoder.cli.onboarding import (
|
|
492
|
+
finish_first_run_cloud,
|
|
493
|
+
needs_onboarding,
|
|
494
|
+
run_onboarding,
|
|
495
|
+
)
|
|
496
|
+
from cadecoder.cli.onboarding import OnboardingResult
|
|
497
|
+
|
|
498
|
+
onboard_result = OnboardingResult()
|
|
490
499
|
if needs_onboarding():
|
|
491
|
-
|
|
500
|
+
onboard_result = run_onboarding(console)
|
|
492
501
|
|
|
493
502
|
# Interaction + runtime-backed commands run as the current agent, auto-creating
|
|
494
503
|
# a `default` agent on first run via build_runtime → ensure_current_agent.
|
|
@@ -496,13 +505,10 @@ def main_callback(
|
|
|
496
505
|
set_runtime(runtime)
|
|
497
506
|
ctx.obj["runtime"] = runtime
|
|
498
507
|
|
|
499
|
-
#
|
|
500
|
-
|
|
501
|
-
if did_onboard:
|
|
508
|
+
# After runtime is up: Arcade login (if needed) + Arcade Agent Hub connect.
|
|
509
|
+
if onboard_result:
|
|
502
510
|
try:
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
offer_connect_omni(console)
|
|
511
|
+
finish_first_run_cloud(console, prefer_skip_login=onboard_result.chose_local)
|
|
506
512
|
except Exception: # noqa: BLE001
|
|
507
513
|
pass
|
|
508
514
|
|
|
@@ -86,15 +86,15 @@ def login(
|
|
|
86
86
|
|
|
87
87
|
log.info(f"User {whoami.email} logged in via OAuth.")
|
|
88
88
|
|
|
89
|
-
# Offer to connect Arcade
|
|
90
|
-
# (Gmail, Slack, web search, …) without a separate API key.
|
|
91
|
-
# non-interactive or already authorized.
|
|
89
|
+
# Offer to connect the Arcade Agent Hub so the agent can use external
|
|
90
|
+
# tools (Gmail, Slack, web search, …) without a separate API key.
|
|
91
|
+
# No-op when non-interactive or already authorized.
|
|
92
92
|
try:
|
|
93
|
-
from cadecoder.cli.commands.mcp import
|
|
93
|
+
from cadecoder.cli.commands.mcp import offer_connect_hub
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
offer_connect_hub(console)
|
|
96
96
|
except Exception as e: # noqa: BLE001
|
|
97
|
-
log.debug(f"
|
|
97
|
+
log.debug(f"hub connect offer skipped: {e}")
|
|
98
98
|
|
|
99
99
|
except OAuthLoginError as e:
|
|
100
100
|
console.print(f"\n[red]✗ Login failed:[/red] {escape(str(e))}")
|
|
@@ -372,22 +372,26 @@ def run_mcp_authorization(
|
|
|
372
372
|
"""Run the MCP OAuth authorization flow for a server. Returns success.
|
|
373
373
|
|
|
374
374
|
If ``name`` isn't configured yet but is a built-in known server (e.g.
|
|
375
|
-
``
|
|
375
|
+
``hub``), it's added in a disabled state first and only enabled once
|
|
376
376
|
authorization succeeds — so a cancelled/failed flow never leaves a broken
|
|
377
|
-
server that would error during chat.
|
|
377
|
+
server that would error during chat. The legacy name ``omni`` resolves to
|
|
378
|
+
the Arcade Agent Hub.
|
|
378
379
|
"""
|
|
379
380
|
global _oauth_result
|
|
380
381
|
_oauth_result = {"code": None, "error": None}
|
|
381
382
|
|
|
382
383
|
store = MCPServerStore()
|
|
383
|
-
|
|
384
|
+
# Resolve aliases (omni → hub) before looking up a stored config.
|
|
385
|
+
known = known_server_config(name)
|
|
386
|
+
lookup_name = known.name if known is not None else name
|
|
387
|
+
server = store.get(lookup_name) or store.get(name)
|
|
384
388
|
if server is None:
|
|
385
|
-
server =
|
|
389
|
+
server = known
|
|
386
390
|
if server is None:
|
|
387
391
|
console.print(f"[red]Server '{name}' not found.[/red]")
|
|
388
392
|
console.print(
|
|
389
393
|
"[dim]Add it with 'cade mcp add <name> <url>', "
|
|
390
|
-
"or authorize a known server like '
|
|
394
|
+
"or authorize a known server like 'hub'.[/dim]"
|
|
391
395
|
)
|
|
392
396
|
return False
|
|
393
397
|
store.add(server) # persisted disabled; enabled on success
|
|
@@ -515,16 +519,17 @@ def run_mcp_authorization(
|
|
|
515
519
|
return asyncio.run(run_oauth_flow())
|
|
516
520
|
|
|
517
521
|
|
|
518
|
-
def
|
|
519
|
-
"""Offer to connect Arcade
|
|
522
|
+
def offer_connect_hub(target_console: Console | None = None) -> None:
|
|
523
|
+
"""Offer to connect the Arcade Agent Hub if not already authorized.
|
|
520
524
|
|
|
521
525
|
Called after ``cade login`` and after first-run onboarding. No-op when the
|
|
522
|
-
terminal isn't interactive or when
|
|
523
|
-
blocks scripted/CI use.
|
|
526
|
+
terminal isn't interactive or when the Hub is already authorized, so it
|
|
527
|
+
never blocks scripted/CI use.
|
|
524
528
|
"""
|
|
525
529
|
con = target_console or console
|
|
526
530
|
|
|
527
|
-
from cadecoder.cli.onboarding import can_prompt
|
|
531
|
+
from cadecoder.cli.onboarding import can_prompt, is_arcade_logged_in, offer_arcade_login
|
|
532
|
+
from cadecoder.tools.manager.config import HUB_SERVER_NAME
|
|
528
533
|
|
|
529
534
|
if not can_prompt():
|
|
530
535
|
return
|
|
@@ -534,30 +539,57 @@ def offer_connect_omni(target_console: Console | None = None) -> None:
|
|
|
534
539
|
except Exception: # noqa: BLE001
|
|
535
540
|
return
|
|
536
541
|
|
|
537
|
-
existing = store.get("omni")
|
|
542
|
+
existing = store.get(HUB_SERVER_NAME) or store.get("omni")
|
|
538
543
|
if existing is not None and existing.oauth_tokens is not None:
|
|
539
544
|
return # already connected
|
|
540
545
|
|
|
546
|
+
if not is_arcade_logged_in():
|
|
547
|
+
con.print()
|
|
548
|
+
con.print(
|
|
549
|
+
"[bold]Arcade login required[/bold] before connecting the "
|
|
550
|
+
"[cyan]Arcade Agent Hub[/cyan]."
|
|
551
|
+
)
|
|
552
|
+
if not offer_arcade_login(con, prefer_skip=False):
|
|
553
|
+
con.print(
|
|
554
|
+
"[dim]Skipped. Log in later with [bold]cade login[/bold], then "
|
|
555
|
+
"[bold]cade mcp authorize hub[/bold].[/dim]"
|
|
556
|
+
)
|
|
557
|
+
return
|
|
558
|
+
|
|
541
559
|
from rich.prompt import Confirm
|
|
542
560
|
|
|
543
561
|
con.print()
|
|
544
562
|
con.print(
|
|
545
|
-
"[bold]Connect external tools?[/bold]
|
|
546
|
-
"
|
|
547
|
-
"
|
|
563
|
+
"[bold]Connect external tools?[/bold] The [cyan]Arcade Agent Hub[/cyan] "
|
|
564
|
+
"([link=https://hub.arcade.dev]hub.arcade.dev[/link]) lets Cade use "
|
|
565
|
+
"Gmail, Slack, GitHub, web search and more — authorized with your Arcade "
|
|
566
|
+
"login (no API key needed)."
|
|
548
567
|
)
|
|
549
568
|
try:
|
|
550
|
-
proceed = Confirm.ask(
|
|
569
|
+
proceed = Confirm.ask(
|
|
570
|
+
"Authorize Arcade Agent Hub now? (opens your browser)",
|
|
571
|
+
default=True,
|
|
572
|
+
console=con,
|
|
573
|
+
)
|
|
551
574
|
except (KeyboardInterrupt, EOFError):
|
|
552
575
|
con.print()
|
|
553
576
|
return
|
|
554
577
|
|
|
555
578
|
if not proceed:
|
|
556
|
-
con.print(
|
|
579
|
+
con.print(
|
|
580
|
+
"[dim]Skipped. Connect anytime with [bold]cade mcp authorize hub[/bold].[/dim]"
|
|
581
|
+
)
|
|
557
582
|
return
|
|
558
583
|
|
|
559
|
-
if not run_mcp_authorization(
|
|
560
|
-
con.print(
|
|
584
|
+
if not run_mcp_authorization(HUB_SERVER_NAME):
|
|
585
|
+
con.print(
|
|
586
|
+
"[dim]You can retry later with [bold]cade mcp authorize hub[/bold].[/dim]"
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def offer_connect_omni(target_console: Console | None = None) -> None:
|
|
591
|
+
"""Deprecated alias for :func:`offer_connect_hub`."""
|
|
592
|
+
offer_connect_hub(target_console)
|
|
561
593
|
|
|
562
594
|
|
|
563
595
|
@mcp_app.command("authorize")
|
|
@@ -579,7 +611,7 @@ def authorize_server(
|
|
|
579
611
|
"""Authorize an MCP server over OAuth (browser flow).
|
|
580
612
|
|
|
581
613
|
Works with any configured server, or a built-in known server by name
|
|
582
|
-
(e.g. ``cade mcp authorize
|
|
614
|
+
(e.g. ``cade mcp authorize hub`` to connect the Arcade Agent Hub).
|
|
583
615
|
"""
|
|
584
616
|
if not run_mcp_authorization(name, client_id=client_id, scope=scope, skip_dcr=skip_dcr):
|
|
585
617
|
raise typer.Exit(1)
|
|
@@ -3,14 +3,18 @@
|
|
|
3
3
|
A brand-new install has no obvious way to pick a model provider, and the silent
|
|
4
4
|
provider fallback used to log a GPT model even when only an Anthropic key was
|
|
5
5
|
set. This wizard runs once on first launch (and on demand via ``cade init``):
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
1. Model provider + API key + default model
|
|
8
|
+
2. Arcade Cloud login (browser OAuth) — skipped only if the user opts out
|
|
9
|
+
3. Arcade Agent Hub connect (after the runtime is up)
|
|
10
|
+
|
|
11
|
+
Step 3 is :func:`finish_first_run_cloud` and must run after ``build_runtime``.
|
|
9
12
|
"""
|
|
10
13
|
|
|
11
14
|
from __future__ import annotations
|
|
12
15
|
|
|
13
16
|
import os
|
|
17
|
+
from dataclasses import dataclass
|
|
14
18
|
|
|
15
19
|
from rich.console import Console
|
|
16
20
|
from rich.panel import Panel
|
|
@@ -28,6 +32,17 @@ _PROVIDER_LOCAL = "local"
|
|
|
28
32
|
_KEYRING_SERVICE = "cade/model"
|
|
29
33
|
|
|
30
34
|
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class OnboardingResult:
|
|
37
|
+
"""Outcome of the model-setup half of first-run onboarding."""
|
|
38
|
+
|
|
39
|
+
configured: bool = False
|
|
40
|
+
chose_local: bool = False
|
|
41
|
+
|
|
42
|
+
def __bool__(self) -> bool:
|
|
43
|
+
return self.configured
|
|
44
|
+
|
|
45
|
+
|
|
31
46
|
def _marker_path():
|
|
32
47
|
"""Path to the sentinel that records onboarding has completed."""
|
|
33
48
|
return get_paths().state_dir / "onboarded"
|
|
@@ -168,28 +183,170 @@ class OnboardingAborted(Exception):
|
|
|
168
183
|
"""Raised when the user cancels onboarding (Ctrl-C / empty required input)."""
|
|
169
184
|
|
|
170
185
|
|
|
171
|
-
def
|
|
172
|
-
"""
|
|
186
|
+
def is_arcade_logged_in() -> bool:
|
|
187
|
+
"""Return True when Arcade Cloud credentials are present and usable."""
|
|
188
|
+
try:
|
|
189
|
+
from cadecoder.cli.auth import check_existing_login
|
|
190
|
+
|
|
191
|
+
return check_existing_login(suppress_message=True)
|
|
192
|
+
except Exception: # noqa: BLE001
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def offer_arcade_login(console: Console, *, prefer_skip: bool = False) -> bool:
|
|
197
|
+
"""Offer Arcade Cloud OAuth during first-run / init.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
console: Rich console for prompts.
|
|
201
|
+
prefer_skip: When True (local model path), default the confirm to No.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
True if the user is logged in when this returns (already was, or just did).
|
|
205
|
+
"""
|
|
206
|
+
if not can_prompt():
|
|
207
|
+
return is_arcade_logged_in()
|
|
208
|
+
|
|
209
|
+
if is_arcade_logged_in():
|
|
210
|
+
console.print()
|
|
211
|
+
console.print("[green]✓[/green] Already logged in to Arcade Cloud.")
|
|
212
|
+
return True
|
|
213
|
+
|
|
214
|
+
console.print()
|
|
215
|
+
console.print(
|
|
216
|
+
Panel.fit(
|
|
217
|
+
"[bold]Step 2 of 3 — Arcade Cloud[/bold]\n\n"
|
|
218
|
+
"Log in so Cade can use Gmail, Slack, GitHub, calendars, and the\n"
|
|
219
|
+
"rest of the Arcade catalogue. Opens your browser (free account).\n\n"
|
|
220
|
+
"[dim]Skip only if you want local tools + your model — nothing else.[/dim]",
|
|
221
|
+
border_style="cyan",
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
try:
|
|
225
|
+
proceed = Confirm.ask(
|
|
226
|
+
"Log in to Arcade Cloud now?",
|
|
227
|
+
default=not prefer_skip,
|
|
228
|
+
console=console,
|
|
229
|
+
)
|
|
230
|
+
except (KeyboardInterrupt, EOFError):
|
|
231
|
+
console.print()
|
|
232
|
+
proceed = False
|
|
233
|
+
|
|
234
|
+
if not proceed:
|
|
235
|
+
console.print(
|
|
236
|
+
"[dim]Skipped. Chat still works with your model and local tools.\n"
|
|
237
|
+
"Run [bold]cade login[/bold] anytime for cloud apps "
|
|
238
|
+
"(or [bold]cade --local-only[/bold] to stay offline).[/dim]"
|
|
239
|
+
)
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
return try_interactive_login(console)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def try_interactive_login(console: Console) -> bool:
|
|
246
|
+
"""Run browser OAuth login; return True on success. Never raises Exit."""
|
|
247
|
+
from arcade_core.constants import PROD_COORDINATOR_HOST
|
|
248
|
+
from rich.markup import escape
|
|
249
|
+
|
|
250
|
+
from cadecoder.cli.auth import (
|
|
251
|
+
OAuthLoginError,
|
|
252
|
+
build_coordinator_url,
|
|
253
|
+
perform_oauth_login,
|
|
254
|
+
save_credentials_from_whoami,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
coordinator_url = build_coordinator_url(PROD_COORDINATOR_HOST, None)
|
|
259
|
+
|
|
260
|
+
def on_status(msg: str) -> None:
|
|
261
|
+
console.print(f"[dim]{msg}[/dim]")
|
|
262
|
+
|
|
263
|
+
tokens, whoami, client_id = perform_oauth_login(coordinator_url, on_status=on_status)
|
|
264
|
+
save_credentials_from_whoami(tokens, whoami, coordinator_url, client_id)
|
|
265
|
+
console.print("\n[green]✓ Login successful![/green]")
|
|
266
|
+
console.print(f" Email: {whoami.email}")
|
|
267
|
+
org = whoami.get_selected_org()
|
|
268
|
+
project = whoami.get_selected_project()
|
|
269
|
+
if org and project:
|
|
270
|
+
console.print(
|
|
271
|
+
f" Active: {org.get('name', 'unknown')} / {project.get('name', 'unknown')}"
|
|
272
|
+
)
|
|
273
|
+
return True
|
|
274
|
+
except OAuthLoginError as e:
|
|
275
|
+
console.print(f"\n[red]✗ Login failed:[/red] {escape(str(e))}")
|
|
276
|
+
console.print(
|
|
277
|
+
"[dim]Continue without cloud tools for now — "
|
|
278
|
+
"retry with [bold]cade login[/bold].[/dim]"
|
|
279
|
+
)
|
|
280
|
+
return False
|
|
281
|
+
except (KeyboardInterrupt, EOFError):
|
|
282
|
+
console.print("\n[yellow]Login cancelled.[/yellow]")
|
|
283
|
+
return False
|
|
284
|
+
except Exception as e: # noqa: BLE001
|
|
285
|
+
console.print(f"\n[red]✗ Login failed:[/red] {escape(str(e))}")
|
|
286
|
+
console.print("[dim]Retry anytime with [bold]cade login[/bold].[/dim]")
|
|
287
|
+
return False
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def finish_first_run_cloud(console: Console, *, prefer_skip_login: bool = False) -> None:
|
|
291
|
+
"""After runtime is ready: Arcade login (if needed), then Agent Hub connect.
|
|
292
|
+
|
|
293
|
+
Call this only after ``build_runtime()`` / ``set_runtime()`` so the Hub
|
|
294
|
+
MCP store can resolve the current agent.
|
|
295
|
+
"""
|
|
296
|
+
if not can_prompt():
|
|
297
|
+
return
|
|
298
|
+
|
|
299
|
+
logged_in = offer_arcade_login(console, prefer_skip=prefer_skip_login)
|
|
300
|
+
if not logged_in:
|
|
301
|
+
return
|
|
302
|
+
|
|
303
|
+
try:
|
|
304
|
+
from cadecoder.cli.commands.mcp import offer_connect_hub
|
|
305
|
+
|
|
306
|
+
console.print()
|
|
307
|
+
console.print("[bold]Step 3 of 3 — Arcade Agent Hub[/bold] ([cyan]hub.arcade.dev[/cyan])")
|
|
308
|
+
offer_connect_hub(console)
|
|
309
|
+
except Exception: # noqa: BLE001
|
|
310
|
+
console.print(
|
|
311
|
+
"[dim]Skipped Arcade Agent Hub. Connect later with "
|
|
312
|
+
"[bold]cade mcp authorize hub[/bold].[/dim]"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def run_onboarding(console: Console, *, force: bool = False) -> OnboardingResult:
|
|
317
|
+
"""Run the interactive model-setup wizard (step 1 of first-run).
|
|
173
318
|
|
|
174
319
|
Args:
|
|
175
320
|
console: Rich console (stderr) to render prompts on.
|
|
176
321
|
force: Re-run even if already onboarded (``cade init``).
|
|
177
322
|
|
|
178
323
|
Returns:
|
|
179
|
-
|
|
324
|
+
:class:`OnboardingResult` (truthy when a provider was configured).
|
|
325
|
+
Call :func:`finish_first_run_cloud` after the runtime is built for
|
|
326
|
+
steps 2–3 (login + Arcade Agent Hub).
|
|
180
327
|
"""
|
|
181
328
|
if not force and not needs_onboarding():
|
|
182
|
-
return
|
|
329
|
+
return OnboardingResult()
|
|
183
330
|
|
|
184
331
|
if not can_prompt():
|
|
185
332
|
# Non-interactive (piped/CI). Don't block; the provider error path will
|
|
186
333
|
# guide the user if nothing is configured.
|
|
187
|
-
return
|
|
334
|
+
return OnboardingResult()
|
|
188
335
|
|
|
189
336
|
console.print(
|
|
190
337
|
Panel.fit(
|
|
191
|
-
"Welcome to [bold]Cade[/bold] —
|
|
192
|
-
"
|
|
338
|
+
"Welcome to [bold]Cade[/bold] — three quick steps:\n"
|
|
339
|
+
" [bold]1.[/bold] Pick a model provider\n"
|
|
340
|
+
" [bold]2.[/bold] Log in to Arcade Cloud (cloud apps)\n"
|
|
341
|
+
" [bold]3.[/bold] Connect the Arcade Agent Hub\n\n"
|
|
342
|
+
"You can re-run this anytime with [bold]cade init[/bold].",
|
|
343
|
+
border_style="cyan",
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
console.print()
|
|
347
|
+
console.print(
|
|
348
|
+
Panel.fit(
|
|
349
|
+
"[bold]Step 1 of 3 — Model provider[/bold]",
|
|
193
350
|
border_style="cyan",
|
|
194
351
|
)
|
|
195
352
|
)
|
|
@@ -238,10 +395,10 @@ def run_onboarding(console: Console, *, force: bool = False) -> bool:
|
|
|
238
395
|
model = Prompt.ask("Model", default=default_model, console=console).strip() or default_model
|
|
239
396
|
except (KeyboardInterrupt, EOFError):
|
|
240
397
|
console.print("\n[yellow]Setup cancelled.[/yellow]")
|
|
241
|
-
return
|
|
398
|
+
return OnboardingResult()
|
|
242
399
|
except OnboardingAborted as e:
|
|
243
400
|
console.print(f"[yellow]Setup cancelled: {e}[/yellow]")
|
|
244
|
-
return
|
|
401
|
+
return OnboardingResult()
|
|
245
402
|
|
|
246
403
|
_persist(
|
|
247
404
|
provider=provider,
|
|
@@ -257,15 +414,16 @@ def run_onboarding(console: Console, *, force: bool = False) -> bool:
|
|
|
257
414
|
console.print()
|
|
258
415
|
console.print(
|
|
259
416
|
Panel.fit(
|
|
260
|
-
f"[bold]
|
|
417
|
+
f"[bold]Step 1 done.[/bold]\n"
|
|
261
418
|
f"Model: [cyan]{model}[/cyan]\n"
|
|
262
419
|
f"Provider: [cyan]{label}[/cyan]\n\n"
|
|
263
|
-
"
|
|
420
|
+
"Next: Arcade login + Arcade Agent Hub (cloud apps).\n"
|
|
421
|
+
"Change the model later with [bold]cade init[/bold] or edit "
|
|
264
422
|
f"[dim]{get_paths().global_config}[/dim].",
|
|
265
423
|
border_style="green",
|
|
266
424
|
)
|
|
267
425
|
)
|
|
268
|
-
return True
|
|
426
|
+
return OnboardingResult(configured=True, chose_local=(choice == "3"))
|
|
269
427
|
|
|
270
428
|
|
|
271
429
|
def _persist(
|
|
@@ -151,6 +151,12 @@ def build_gateway_app(
|
|
|
151
151
|
Returns:
|
|
152
152
|
A configured MCPApp with ``Cade_Ask`` registered.
|
|
153
153
|
"""
|
|
154
|
+
# Idempotent; required for curl/PyInstaller installs where tool source
|
|
155
|
+
# text is unavailable to arcade-core's return-value introspection.
|
|
156
|
+
from cadecoder.core.frozen import patch_frozen_return_detection
|
|
157
|
+
|
|
158
|
+
patch_frozen_return_detection()
|
|
159
|
+
|
|
154
160
|
validator = CadeTokenValidator(token_store) if require_auth else None
|
|
155
161
|
# Exposure enforcement runs as MCP middleware (forwarded to MCPServer via
|
|
156
162
|
# server_kwargs): it hides/blocks tools the principal's groups exclude.
|
|
@@ -92,6 +92,12 @@ async def run_daemon(
|
|
|
92
92
|
seam: an async ``(app, host, port)`` callable used instead of the real
|
|
93
93
|
uvicorn server so the wiring can be exercised without binding a socket.
|
|
94
94
|
"""
|
|
95
|
+
# Frozen/PyInstaller builds have no .py source for inspect.getsource();
|
|
96
|
+
# arcade-core needs this patch before any MCPApp.add_tool (Cade_Ask).
|
|
97
|
+
from cadecoder.core.frozen import patch_frozen_return_detection
|
|
98
|
+
|
|
99
|
+
patch_frozen_return_detection()
|
|
100
|
+
|
|
95
101
|
host, port = _parse_bind(bind)
|
|
96
102
|
_guard_auth_bind(host, require_auth)
|
|
97
103
|
prewarm = prewarm or []
|