cade-cli 0.11.0__tar.gz → 0.13.3__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.11.0 → cade_cli-0.13.3}/PKG-INFO +34 -28
- {cade_cli-0.11.0 → cade_cli-0.13.3}/README.md +27 -20
- {cade_cli-0.11.0 → cade_cli-0.13.3}/pyproject.toml +11 -8
- cade_cli-0.13.3/src/cade_mcp_local/config.py +116 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/server.py +7 -3
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/filesystem.py +18 -14
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/utils.py +6 -2
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/app.py +76 -14
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/chat.py +26 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/context.py +24 -3
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/cron.py +39 -19
- cade_cli-0.13.3/src/cadecoder/cli/commands/mem.py +176 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/model.py +112 -12
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/persona.py +190 -24
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/tools.py +110 -8
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/config.py +47 -10
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/constants.py +1 -8
- cade_cli-0.13.3/src/cadecoder/core/frozen.py +37 -0
- cade_cli-0.13.3/src/cadecoder/core/model_specs.py +194 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/runtime.py +1 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/execution/context_window.py +4 -83
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/execution/orchestrator.py +4 -2
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/execution/tool_result_store.py +4 -2
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/execution/tool_schema_cache.py +34 -2
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/providers/__init__.py +7 -2
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/providers/anthropic.py +50 -6
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/providers/base.py +8 -1
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/providers/ollama.py +65 -23
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/providers/openai.py +68 -37
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/adapters/__init__.py +4 -1
- cade_cli-0.13.3/src/cadecoder/serve/adapters/desktop.py +408 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/allowlist.py +34 -6
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/config.py +37 -2
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/daemon.py +56 -26
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/observability.py +4 -1
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/worker.py +91 -11
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/storage/personas.py +27 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tasks/scheduler.py +90 -4
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/templates/serve/serve.toml.example +10 -1
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/manager/composite.py +41 -31
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/search/service.py +61 -12
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ui/session.py +102 -9
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ui/slash.py +1 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/voice/__init__.py +7 -1
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/voice/session.py +66 -7
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/voice/tts.py +15 -0
- cade_cli-0.11.0/src/cade_mcp_local/config.py +0 -68
- cade_cli-0.11.0/src/cadecoder/cli/commands/mem.py +0 -149
- {cade_cli-0.11.0 → cade_cli-0.13.3}/.gitignore +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/LICENSE +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/__main__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/_metadata.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/errors.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/resources.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/_read_cache.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/context.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/git.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/notifications.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/questions.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/results.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/schemas.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/search.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/shell.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/snippets.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/tasks.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/web_fetch.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/tools/web_search.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/arcade_client.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/cache.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/extract.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/markdown.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/preapproved.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/prompts.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/scrape.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/search/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/search/arcade.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/search/base.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cade_mcp_local/web/search/http.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ai/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ai/prompts.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/auth.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/account.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/auth.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/channels.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/hooks.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/mcp.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/serve.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/tasks.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/cli/commands/thread.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/errors.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/git.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/logging.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/names.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/paths.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/core/types.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/execution/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/execution/mcp_schema_index.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/execution/parallel.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/config.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/engine.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/executors/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/executors/callback.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/executors/command.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/executors/http.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/executors/prompt.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/executors/ssrf_guard.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/matchers.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/registry.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/hooks/types.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/adapters/base.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/adapters/registry.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/adapters/stub.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/adapters/telegram.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/chunker.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/commands.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/elicitation.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/format.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/install.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/lock.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/progress_sink.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/router.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/secrets.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/serve/sinks.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/storage/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/storage/threads.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tasks/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tasks/channels.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tasks/lock.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tasks/notifications.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tasks/store.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tasks/types.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/templates/login_failed.html +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/templates/login_success.html +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/templates/serve/launchd.plist.tmpl +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/templates/serve/systemd.service.tmpl +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/templates/styles.css +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/manager/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/manager/_request_ctx.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/manager/base.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/manager/config.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/manager/mcp.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/search/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/search/discovered.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/tools/search/scoring.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ui/__init__.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ui/display.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ui/elicitation.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/ui/input.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/voice/audio.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/voice/cleanup.py +0 -0
- {cade_cli-0.11.0 → cade_cli-0.13.3}/src/cadecoder/voice/stt.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cade-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.3
|
|
4
4
|
Summary: Cade - The CLI Agent from Arcade.dev
|
|
5
5
|
Project-URL: Homepage, https://arcade.dev
|
|
6
6
|
Project-URL: Documentation, https://docs.arcade.dev
|
|
@@ -43,10 +43,10 @@ Classifier: Topic :: Software Development
|
|
|
43
43
|
Classifier: Topic :: Software Development :: Code Generators
|
|
44
44
|
Classifier: Typing :: Typed
|
|
45
45
|
Requires-Python: >=3.11
|
|
46
|
-
Requires-Dist: agent-library<1.0.0,>=0.
|
|
46
|
+
Requires-Dist: agent-library<1.0.0,>=0.13.1
|
|
47
47
|
Requires-Dist: anthropic<1.0.0,>=0.34.0
|
|
48
48
|
Requires-Dist: arcade-core<5.0.0,>=4.7.0
|
|
49
|
-
Requires-Dist: arcade-mcp-server<2.0.0,>=1.
|
|
49
|
+
Requires-Dist: arcade-mcp-server<2.0.0,>=1.22.0
|
|
50
50
|
Requires-Dist: arcade-tdk<4.0.0,>=3.8.0
|
|
51
51
|
Requires-Dist: arcadepy<2.0.0,>=1.10.0
|
|
52
52
|
Requires-Dist: authlib<2.0.0,>=1.6.0
|
|
@@ -58,15 +58,14 @@ Requires-Dist: keyring<26.0,>=24.0
|
|
|
58
58
|
Requires-Dist: openai<2.0.0,>=1.0.0
|
|
59
59
|
Requires-Dist: prompt-toolkit<4.0.0,>=3.0.52
|
|
60
60
|
Requires-Dist: pydantic[email]<3.0.0,>=2.0.0
|
|
61
|
-
Requires-Dist: pyperclip<2.0.0,>=1.8.0
|
|
62
61
|
Requires-Dist: python-telegram-bot<22.0,>=21.0
|
|
63
|
-
Requires-Dist: pyyaml<7.0.0,>=6.0
|
|
64
62
|
Requires-Dist: rich<14.0.0,>=13.0.0
|
|
65
|
-
Requires-Dist: sounddevice>=0.5.5
|
|
66
|
-
Requires-Dist: tiktoken<1.0.0,>=0.11.0
|
|
67
63
|
Requires-Dist: toml<1.0.0,>=0.10.0
|
|
68
64
|
Requires-Dist: typer>0.10.0
|
|
69
65
|
Requires-Dist: ulid==1.1
|
|
66
|
+
Requires-Dist: websockets<16.0,>=14.0
|
|
67
|
+
Provides-Extra: build
|
|
68
|
+
Requires-Dist: pyinstaller<7.0.0,>=6.16.0; extra == 'build'
|
|
70
69
|
Provides-Extra: dev
|
|
71
70
|
Requires-Dist: mypy<2.0.0,>=1.10.0; extra == 'dev'
|
|
72
71
|
Requires-Dist: pytest-asyncio<1.0.0,>=0.24.0; extra == 'dev'
|
|
@@ -83,7 +82,7 @@ Provides-Extra: voice
|
|
|
83
82
|
Requires-Dist: mlx-audio<0.4.0,>=0.2.0; extra == 'voice'
|
|
84
83
|
Requires-Dist: mlx-whisper>=0.1.0; extra == 'voice'
|
|
85
84
|
Requires-Dist: numpy>=1.24.0; extra == 'voice'
|
|
86
|
-
Requires-Dist: sounddevice
|
|
85
|
+
Requires-Dist: sounddevice<1.0.0,>=0.5.5; extra == 'voice'
|
|
87
86
|
Requires-Dist: webrtcvad>=2.0.10; extra == 'voice'
|
|
88
87
|
Description-Content-Type: text/markdown
|
|
89
88
|
|
|
@@ -119,6 +118,8 @@ cade
|
|
|
119
118
|
| pip | `pip install cade-cli` |
|
|
120
119
|
| From source | `git clone https://github.com/arcadeai-labs/cade.git && cd cade && uv sync` |
|
|
121
120
|
|
|
121
|
+
Homebrew installs from a private release feed. Export `HOMEBREW_GITHUB_API_TOKEN` (a token with read access to `arcadeai-labs/cade`) before running `brew install`.
|
|
122
|
+
|
|
122
123
|
**Prerequisites:** Python 3.11+, an Arcade account ([arcade.dev](https://arcade.dev)) for cloud tools, and an LLM provider key (`OPENAI_API_KEY` or `ANTHROPIC_API_KEY`). Skip the Arcade account with `--local-only` or `CADE_LOCAL_ONLY=1`.
|
|
123
124
|
|
|
124
125
|
```bash
|
|
@@ -126,6 +127,9 @@ cade login # Arcade Cloud OAuth (skip with --local-only)
|
|
|
126
127
|
cade --version
|
|
127
128
|
```
|
|
128
129
|
|
|
130
|
+
Full install and first-run docs: [`docs/install.md`](./docs/install.md) and
|
|
131
|
+
[`docs/quickstart.md`](./docs/quickstart.md).
|
|
132
|
+
|
|
129
133
|
---
|
|
130
134
|
|
|
131
135
|
## Quick start
|
|
@@ -133,11 +137,11 @@ cade --version
|
|
|
133
137
|
```bash
|
|
134
138
|
cade # interactive chat
|
|
135
139
|
cade -m "What changed in HEAD?" # single message, then exit
|
|
136
|
-
|
|
140
|
+
cade -m "What went wrong?" < error.log # prompt + file/stdin
|
|
137
141
|
cade -r # resume the most recent thread
|
|
138
142
|
cade resume "auth-rewrite" # resume a thread by name
|
|
139
143
|
cade --persona reviewer # use a saved persona's system prompt
|
|
140
|
-
cade --voice # speak / hear (voice
|
|
144
|
+
cade --voice # speak / hear (requires cade-cli[voice])
|
|
141
145
|
```
|
|
142
146
|
|
|
143
147
|
### Top-level options
|
|
@@ -145,9 +149,9 @@ cade --voice # speak / hear (voice mode)
|
|
|
145
149
|
| Flag | Description |
|
|
146
150
|
|---|---|
|
|
147
151
|
| `-r`, `--resume` | Resume most recent thread |
|
|
148
|
-
| `-m`, `--message` | Single-message mode
|
|
152
|
+
| `-m`, `--message` | Single-message mode; piped stdin is appended to the prompt |
|
|
149
153
|
| `-P`, `--persona` | Use a saved persona |
|
|
150
|
-
| `-V`, `--voice` | Voice mode |
|
|
154
|
+
| `-V`, `--voice` | Voice mode; install `cade-cli[voice]` first |
|
|
151
155
|
| `-v`, `--verbose` | Debug logging |
|
|
152
156
|
| `--version` | Print version |
|
|
153
157
|
|
|
@@ -172,7 +176,7 @@ cade --voice # speak / hear (voice mode)
|
|
|
172
176
|
|
|
173
177
|
Tools come from three sources and are addressed uniformly by their registered name:
|
|
174
178
|
|
|
175
|
-
- **`Local_*`** — built-in: filesystem (`ReadFile`, `WriteFile`, `Edit`, `ListFiles`), shell (`Bash`
|
|
179
|
+
- **`Local_*`** — built-in: filesystem (`ReadFile`, `WriteFile`, `Edit`, `ListFiles`), shell (`Bash`), `Search`, `Git`, `Task*`, `AskUserQuestion`, `RetrieveToolResult`, `ToolSchema`, `PinContext`, `PushNotification`, `WebFetch`, and `WebSearch`.
|
|
176
180
|
- **`Memory_*`** — agent-library backed, per-persona indexed knowledge store.
|
|
177
181
|
- **Arcade Cloud + user MCP servers** — anything you register.
|
|
178
182
|
|
|
@@ -215,7 +219,7 @@ Memory is persona-scoped — each persona has its own `~/.cade/data/contexts/<co
|
|
|
215
219
|
|
|
216
220
|
## Headless daemon: `cade serve`
|
|
217
221
|
|
|
218
|
-
Run Cade as a long-lived daemon that replies
|
|
222
|
+
Run Cade as a long-lived daemon that replies through adapters. Telegram is supported for personal bot workflows, and Desktop exposes a local WebSocket for native clients. Each conversation gets its own persistent thread — persona, memory, and tools carry across messages.
|
|
219
223
|
|
|
220
224
|
```bash
|
|
221
225
|
cade serve init # wizard: bot token, allowed senders
|
|
@@ -226,9 +230,9 @@ cade serve status / stop # health, uptime; SIGTERM running daemo
|
|
|
226
230
|
|
|
227
231
|
Config lives at `~/.cade/config/contexts/<context>.toml [serve]`. Edit and `kill -HUP $(cat ~/.cade/run/serve.pid)` to reload without restart.
|
|
228
232
|
|
|
229
|
-
**Security defaults are fail-closed:** `allowed_senders = []` blocks everyone; tools are default-deny against `[tools].allow` (globs / regex / pipe lists supported); `deny` always wins.
|
|
233
|
+
**Security defaults are fail-closed:** `allowed_senders = []` blocks everyone; tools are default-deny against `[serve.tools].allow` (globs / regex / pipe lists supported); `deny` always wins.
|
|
230
234
|
|
|
231
|
-
The MCP transport is fully bidirectional, so tools running inside the daemon can elicit structured input
|
|
235
|
+
The MCP transport is fully bidirectional, so tools running inside the daemon can elicit structured input, stream live progress, and emit logs through whichever adapter is active. See [`docs/adapters/`](./docs/adapters/) for adapter details, [`docs/mcp.md`](./docs/mcp.md) for protocol details, and [`docs/configuration.md`](./docs/configuration.md) for the full daemon config reference.
|
|
232
236
|
|
|
233
237
|
---
|
|
234
238
|
|
|
@@ -252,17 +256,18 @@ See [`docs/channels.md`](./docs/channels.md) for the channels protocol; hooks an
|
|
|
252
256
|
Cade works with any OpenAI-compatible endpoint. Three ways to wire one in (CLI flag → env → config, first match wins):
|
|
253
257
|
|
|
254
258
|
```bash
|
|
255
|
-
# CLI flag
|
|
256
|
-
cade chat --endpoint http://localhost:11434
|
|
259
|
+
# CLI flag for Ollama. Use a model from `ollama list`.
|
|
260
|
+
cade chat -L --endpoint http://localhost:11434 --model qwen3:4b
|
|
257
261
|
|
|
258
|
-
# Environment
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
# Environment for one-shot mode
|
|
263
|
+
cade context create local-qwen --model qwen3:4b
|
|
264
|
+
cade context use local-qwen
|
|
265
|
+
export OLLAMA_BASE_URL="http://localhost:11434"
|
|
266
|
+
CADE_LOCAL_ONLY=1 cade -m "hello from a local model"
|
|
262
267
|
|
|
263
268
|
# Config — ~/.cade/config/cade.toml
|
|
264
269
|
[model_settings]
|
|
265
|
-
host = "http://localhost:
|
|
270
|
+
host = "http://localhost:8000/v1"
|
|
266
271
|
api_key = "ollama"
|
|
267
272
|
```
|
|
268
273
|
|
|
@@ -303,14 +308,15 @@ Full layout, env vars, and TOML schema in [`docs/configuration.md`](./docs/confi
|
|
|
303
308
|
```bash
|
|
304
309
|
git clone https://github.com/arcadeai-labs/cade.git
|
|
305
310
|
cd cade
|
|
306
|
-
uv sync --
|
|
307
|
-
|
|
308
|
-
|
|
311
|
+
uv sync --extra dev
|
|
312
|
+
uv run pytest
|
|
313
|
+
uv run ruff check src/ tests/
|
|
309
314
|
```
|
|
310
315
|
|
|
311
316
|
Style: Python 3.11+ with modern type hints (`dict`, `list`, `| None`); ruff for lint + format; pytest with `asyncio_mode = "auto"`. Public functions and classes get docstrings.
|
|
312
317
|
|
|
313
|
-
|
|
318
|
+
Build/release docs live in [`docs/development.md`](./docs/development.md). PRs
|
|
319
|
+
welcome — open an issue first for anything substantial.
|
|
314
320
|
|
|
315
321
|
---
|
|
316
322
|
|
|
@@ -318,7 +324,7 @@ PRs welcome — open an issue first for anything substantial.
|
|
|
318
324
|
|
|
319
325
|
- [arcade.dev](https://arcade.dev) — product
|
|
320
326
|
- [docs.arcade.dev](https://docs.arcade.dev) — API and tool catalog
|
|
321
|
-
- [`docs/`](./docs/) —
|
|
327
|
+
- [`docs/`](./docs/) — quickstart, examples, install, config, MCP, channels, voice, development, and adapters
|
|
322
328
|
- [Issues](https://github.com/arcadeai-labs/cade/issues) · [Releases](https://github.com/arcadeai-labs/cade/releases)
|
|
323
329
|
|
|
324
330
|
## License
|
|
@@ -30,6 +30,8 @@ cade
|
|
|
30
30
|
| pip | `pip install cade-cli` |
|
|
31
31
|
| From source | `git clone https://github.com/arcadeai-labs/cade.git && cd cade && uv sync` |
|
|
32
32
|
|
|
33
|
+
Homebrew installs from a private release feed. Export `HOMEBREW_GITHUB_API_TOKEN` (a token with read access to `arcadeai-labs/cade`) before running `brew install`.
|
|
34
|
+
|
|
33
35
|
**Prerequisites:** Python 3.11+, an Arcade account ([arcade.dev](https://arcade.dev)) for cloud tools, and an LLM provider key (`OPENAI_API_KEY` or `ANTHROPIC_API_KEY`). Skip the Arcade account with `--local-only` or `CADE_LOCAL_ONLY=1`.
|
|
34
36
|
|
|
35
37
|
```bash
|
|
@@ -37,6 +39,9 @@ cade login # Arcade Cloud OAuth (skip with --local-only)
|
|
|
37
39
|
cade --version
|
|
38
40
|
```
|
|
39
41
|
|
|
42
|
+
Full install and first-run docs: [`docs/install.md`](./docs/install.md) and
|
|
43
|
+
[`docs/quickstart.md`](./docs/quickstart.md).
|
|
44
|
+
|
|
40
45
|
---
|
|
41
46
|
|
|
42
47
|
## Quick start
|
|
@@ -44,11 +49,11 @@ cade --version
|
|
|
44
49
|
```bash
|
|
45
50
|
cade # interactive chat
|
|
46
51
|
cade -m "What changed in HEAD?" # single message, then exit
|
|
47
|
-
|
|
52
|
+
cade -m "What went wrong?" < error.log # prompt + file/stdin
|
|
48
53
|
cade -r # resume the most recent thread
|
|
49
54
|
cade resume "auth-rewrite" # resume a thread by name
|
|
50
55
|
cade --persona reviewer # use a saved persona's system prompt
|
|
51
|
-
cade --voice # speak / hear (voice
|
|
56
|
+
cade --voice # speak / hear (requires cade-cli[voice])
|
|
52
57
|
```
|
|
53
58
|
|
|
54
59
|
### Top-level options
|
|
@@ -56,9 +61,9 @@ cade --voice # speak / hear (voice mode)
|
|
|
56
61
|
| Flag | Description |
|
|
57
62
|
|---|---|
|
|
58
63
|
| `-r`, `--resume` | Resume most recent thread |
|
|
59
|
-
| `-m`, `--message` | Single-message mode
|
|
64
|
+
| `-m`, `--message` | Single-message mode; piped stdin is appended to the prompt |
|
|
60
65
|
| `-P`, `--persona` | Use a saved persona |
|
|
61
|
-
| `-V`, `--voice` | Voice mode |
|
|
66
|
+
| `-V`, `--voice` | Voice mode; install `cade-cli[voice]` first |
|
|
62
67
|
| `-v`, `--verbose` | Debug logging |
|
|
63
68
|
| `--version` | Print version |
|
|
64
69
|
|
|
@@ -83,7 +88,7 @@ cade --voice # speak / hear (voice mode)
|
|
|
83
88
|
|
|
84
89
|
Tools come from three sources and are addressed uniformly by their registered name:
|
|
85
90
|
|
|
86
|
-
- **`Local_*`** — built-in: filesystem (`ReadFile`, `WriteFile`, `Edit`, `ListFiles`), shell (`Bash`
|
|
91
|
+
- **`Local_*`** — built-in: filesystem (`ReadFile`, `WriteFile`, `Edit`, `ListFiles`), shell (`Bash`), `Search`, `Git`, `Task*`, `AskUserQuestion`, `RetrieveToolResult`, `ToolSchema`, `PinContext`, `PushNotification`, `WebFetch`, and `WebSearch`.
|
|
87
92
|
- **`Memory_*`** — agent-library backed, per-persona indexed knowledge store.
|
|
88
93
|
- **Arcade Cloud + user MCP servers** — anything you register.
|
|
89
94
|
|
|
@@ -126,7 +131,7 @@ Memory is persona-scoped — each persona has its own `~/.cade/data/contexts/<co
|
|
|
126
131
|
|
|
127
132
|
## Headless daemon: `cade serve`
|
|
128
133
|
|
|
129
|
-
Run Cade as a long-lived daemon that replies
|
|
134
|
+
Run Cade as a long-lived daemon that replies through adapters. Telegram is supported for personal bot workflows, and Desktop exposes a local WebSocket for native clients. Each conversation gets its own persistent thread — persona, memory, and tools carry across messages.
|
|
130
135
|
|
|
131
136
|
```bash
|
|
132
137
|
cade serve init # wizard: bot token, allowed senders
|
|
@@ -137,9 +142,9 @@ cade serve status / stop # health, uptime; SIGTERM running daemo
|
|
|
137
142
|
|
|
138
143
|
Config lives at `~/.cade/config/contexts/<context>.toml [serve]`. Edit and `kill -HUP $(cat ~/.cade/run/serve.pid)` to reload without restart.
|
|
139
144
|
|
|
140
|
-
**Security defaults are fail-closed:** `allowed_senders = []` blocks everyone; tools are default-deny against `[tools].allow` (globs / regex / pipe lists supported); `deny` always wins.
|
|
145
|
+
**Security defaults are fail-closed:** `allowed_senders = []` blocks everyone; tools are default-deny against `[serve.tools].allow` (globs / regex / pipe lists supported); `deny` always wins.
|
|
141
146
|
|
|
142
|
-
The MCP transport is fully bidirectional, so tools running inside the daemon can elicit structured input
|
|
147
|
+
The MCP transport is fully bidirectional, so tools running inside the daemon can elicit structured input, stream live progress, and emit logs through whichever adapter is active. See [`docs/adapters/`](./docs/adapters/) for adapter details, [`docs/mcp.md`](./docs/mcp.md) for protocol details, and [`docs/configuration.md`](./docs/configuration.md) for the full daemon config reference.
|
|
143
148
|
|
|
144
149
|
---
|
|
145
150
|
|
|
@@ -163,17 +168,18 @@ See [`docs/channels.md`](./docs/channels.md) for the channels protocol; hooks an
|
|
|
163
168
|
Cade works with any OpenAI-compatible endpoint. Three ways to wire one in (CLI flag → env → config, first match wins):
|
|
164
169
|
|
|
165
170
|
```bash
|
|
166
|
-
# CLI flag
|
|
167
|
-
cade chat --endpoint http://localhost:11434
|
|
171
|
+
# CLI flag for Ollama. Use a model from `ollama list`.
|
|
172
|
+
cade chat -L --endpoint http://localhost:11434 --model qwen3:4b
|
|
168
173
|
|
|
169
|
-
# Environment
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
# Environment for one-shot mode
|
|
175
|
+
cade context create local-qwen --model qwen3:4b
|
|
176
|
+
cade context use local-qwen
|
|
177
|
+
export OLLAMA_BASE_URL="http://localhost:11434"
|
|
178
|
+
CADE_LOCAL_ONLY=1 cade -m "hello from a local model"
|
|
173
179
|
|
|
174
180
|
# Config — ~/.cade/config/cade.toml
|
|
175
181
|
[model_settings]
|
|
176
|
-
host = "http://localhost:
|
|
182
|
+
host = "http://localhost:8000/v1"
|
|
177
183
|
api_key = "ollama"
|
|
178
184
|
```
|
|
179
185
|
|
|
@@ -214,14 +220,15 @@ Full layout, env vars, and TOML schema in [`docs/configuration.md`](./docs/confi
|
|
|
214
220
|
```bash
|
|
215
221
|
git clone https://github.com/arcadeai-labs/cade.git
|
|
216
222
|
cd cade
|
|
217
|
-
uv sync --
|
|
218
|
-
|
|
219
|
-
|
|
223
|
+
uv sync --extra dev
|
|
224
|
+
uv run pytest
|
|
225
|
+
uv run ruff check src/ tests/
|
|
220
226
|
```
|
|
221
227
|
|
|
222
228
|
Style: Python 3.11+ with modern type hints (`dict`, `list`, `| None`); ruff for lint + format; pytest with `asyncio_mode = "auto"`. Public functions and classes get docstrings.
|
|
223
229
|
|
|
224
|
-
|
|
230
|
+
Build/release docs live in [`docs/development.md`](./docs/development.md). PRs
|
|
231
|
+
welcome — open an issue first for anything substantial.
|
|
225
232
|
|
|
226
233
|
---
|
|
227
234
|
|
|
@@ -229,7 +236,7 @@ PRs welcome — open an issue first for anything substantial.
|
|
|
229
236
|
|
|
230
237
|
- [arcade.dev](https://arcade.dev) — product
|
|
231
238
|
- [docs.arcade.dev](https://docs.arcade.dev) — API and tool catalog
|
|
232
|
-
- [`docs/`](./docs/) —
|
|
239
|
+
- [`docs/`](./docs/) — quickstart, examples, install, config, MCP, channels, voice, development, and adapters
|
|
233
240
|
- [Issues](https://github.com/arcadeai-labs/cade/issues) · [Releases](https://github.com/arcadeai-labs/cade/releases)
|
|
234
241
|
|
|
235
242
|
## License
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cade-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.13.3"
|
|
4
4
|
description = "Cade - The CLI Agent from Arcade.dev"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -27,26 +27,23 @@ dependencies = [
|
|
|
27
27
|
"typer>0.10.0",
|
|
28
28
|
"pydantic[email]>=2.0.0,<3.0.0",
|
|
29
29
|
"toml>=0.10.0,<1.0.0",
|
|
30
|
-
"pyyaml>=6.0,<7.0.0",
|
|
31
30
|
"openai>=1.0.0,<2.0.0",
|
|
32
31
|
"anthropic>=0.34.0,<1.0.0",
|
|
33
32
|
"ulid==1.1",
|
|
34
33
|
"arcade-tdk>=3.8.0,<4.0.0",
|
|
35
|
-
"arcade-mcp-server>=1.
|
|
34
|
+
"arcade-mcp-server>=1.22.0,<2.0.0",
|
|
36
35
|
"arcade-core>=4.7.0,<5.0.0",
|
|
37
36
|
"arcadepy>=1.10.0,<2.0.0",
|
|
38
37
|
"authlib>=1.6.0,<2.0.0",
|
|
39
|
-
"pyperclip>=1.8.0,<2.0.0",
|
|
40
38
|
"prompt-toolkit>=3.0.52,<4.0.0",
|
|
41
|
-
"tiktoken>=0.11.0,<1.0.0",
|
|
42
39
|
"httpx>=0.27.0,<1.0.0",
|
|
43
40
|
"filelock>=3.0.0,<4.0.0",
|
|
44
|
-
"agent-library>=0.
|
|
45
|
-
"sounddevice>=0.5.5",
|
|
41
|
+
"agent-library>=0.13.1,<1.0.0",
|
|
46
42
|
"croniter>=2.0.0,<4.0.0",
|
|
47
43
|
"python-telegram-bot>=21.0,<22.0",
|
|
48
44
|
"keyring>=24.0,<26.0",
|
|
49
45
|
"html2text>=2024.2.26",
|
|
46
|
+
"websockets>=14.0,<16.0",
|
|
50
47
|
]
|
|
51
48
|
|
|
52
49
|
[project.urls]
|
|
@@ -69,10 +66,13 @@ dev = [
|
|
|
69
66
|
"pytest-cov>=4.0.0,<5.0.0",
|
|
70
67
|
"mypy>=1.10.0,<2.0.0",
|
|
71
68
|
]
|
|
69
|
+
build = [
|
|
70
|
+
"pyinstaller>=6.16.0,<7.0.0",
|
|
71
|
+
]
|
|
72
72
|
voice = [
|
|
73
73
|
"mlx-audio>=0.2.0,<0.4.0",
|
|
74
74
|
"mlx-whisper>=0.1.0",
|
|
75
|
-
"sounddevice>=0.
|
|
75
|
+
"sounddevice>=0.5.5,<1.0.0",
|
|
76
76
|
"numpy>=1.24.0",
|
|
77
77
|
"webrtcvad>=2.0.10",
|
|
78
78
|
]
|
|
@@ -100,6 +100,9 @@ packages = ["src/cadecoder", "src/cade_mcp_local"]
|
|
|
100
100
|
testpaths = ["tests"]
|
|
101
101
|
asyncio_mode = "auto"
|
|
102
102
|
asyncio_default_fixture_loop_scope = "function"
|
|
103
|
+
markers = [
|
|
104
|
+
"integration: tests that cross process or network boundaries without external services",
|
|
105
|
+
]
|
|
103
106
|
|
|
104
107
|
[tool.ruff]
|
|
105
108
|
line-length = 100
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Runtime configuration for the local MCP server.
|
|
2
|
+
|
|
3
|
+
Configuration is resolved lazily at runtime, not at import time.
|
|
4
|
+
This allows proper testing and correct behavior when installed as a package.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import pathlib
|
|
9
|
+
from functools import lru_cache
|
|
10
|
+
|
|
11
|
+
# Environment variable that disables filesystem path confinement. When set to a
|
|
12
|
+
# truthy value, filesystem tools may read/write paths outside the project root.
|
|
13
|
+
#
|
|
14
|
+
# This is intentionally a single on/off switch for now. A future iteration may
|
|
15
|
+
# replace it with a richer policy (e.g. an explicit list of additional allowed
|
|
16
|
+
# roots); keep `path_restrictions_enabled()` as the single read point so callers
|
|
17
|
+
# don't need to change when that happens.
|
|
18
|
+
PATH_RESTRICTIONS_ENV: str = "CADE_DISABLE_PATH_RESTRICTIONS"
|
|
19
|
+
|
|
20
|
+
_TRUTHY_VALUES: frozenset[str] = frozenset({"1", "true", "yes", "on"})
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def path_restrictions_enabled() -> bool:
|
|
24
|
+
"""Return whether filesystem tools must stay within the project root.
|
|
25
|
+
|
|
26
|
+
Restrictions are ON by default. They are lifted only when the
|
|
27
|
+
``CADE_DISABLE_PATH_RESTRICTIONS`` environment variable is set to a truthy
|
|
28
|
+
value (``1``, ``true``, ``yes``, or ``on``, case-insensitive).
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
True when path confinement should be enforced, False when tools may
|
|
32
|
+
access any path on the filesystem.
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
>>> import os
|
|
36
|
+
>>> os.environ.pop("CADE_DISABLE_PATH_RESTRICTIONS", None)
|
|
37
|
+
>>> path_restrictions_enabled()
|
|
38
|
+
True
|
|
39
|
+
>>> os.environ["CADE_DISABLE_PATH_RESTRICTIONS"] = "1"
|
|
40
|
+
>>> path_restrictions_enabled()
|
|
41
|
+
False
|
|
42
|
+
"""
|
|
43
|
+
raw = os.environ.get(PATH_RESTRICTIONS_ENV, "").strip().lower()
|
|
44
|
+
return raw not in _TRUTHY_VALUES
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def disable_path_restrictions() -> None:
|
|
48
|
+
"""Lift filesystem path confinement for this process and its children.
|
|
49
|
+
|
|
50
|
+
Sets ``CADE_DISABLE_PATH_RESTRICTIONS`` in the environment so that child
|
|
51
|
+
processes (notably the local-tools MCP subprocess, which inherits
|
|
52
|
+
``os.environ``) and the serve sandbox hook all observe the override.
|
|
53
|
+
|
|
54
|
+
This is the single supported way to flip the toggle on from code, keeping
|
|
55
|
+
the environment-variable name encapsulated in this module.
|
|
56
|
+
"""
|
|
57
|
+
os.environ[PATH_RESTRICTIONS_ENV] = "1"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@lru_cache(maxsize=1)
|
|
61
|
+
def get_project_root() -> pathlib.Path:
|
|
62
|
+
"""Get the project root directory.
|
|
63
|
+
|
|
64
|
+
Resolution order:
|
|
65
|
+
1. CADE_PROJECT_ROOT environment variable (set by parent process)
|
|
66
|
+
2. Current working directory
|
|
67
|
+
|
|
68
|
+
This is cached for performance but can be reset with reset_config().
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Resolved path to the project root directory.
|
|
72
|
+
"""
|
|
73
|
+
if root := os.environ.get("CADE_PROJECT_ROOT"):
|
|
74
|
+
return pathlib.Path(root).resolve()
|
|
75
|
+
return pathlib.Path.cwd().resolve()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def reset_config() -> None:
|
|
79
|
+
"""Clear cached configuration.
|
|
80
|
+
|
|
81
|
+
Call this when:
|
|
82
|
+
- The working directory has changed
|
|
83
|
+
- CADE_PROJECT_ROOT environment variable has changed
|
|
84
|
+
- During testing to ensure isolation
|
|
85
|
+
"""
|
|
86
|
+
get_project_root.cache_clear()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# Default ignore patterns for file listings and searches
|
|
90
|
+
DEFAULT_IGNORE_PATTERNS: list[str] = [
|
|
91
|
+
".git",
|
|
92
|
+
"__pycache__",
|
|
93
|
+
"node_modules",
|
|
94
|
+
".venv",
|
|
95
|
+
"venv",
|
|
96
|
+
".mypy_cache",
|
|
97
|
+
".pytest_cache",
|
|
98
|
+
"*.pyc",
|
|
99
|
+
".DS_Store",
|
|
100
|
+
"*.egg-info",
|
|
101
|
+
"dist",
|
|
102
|
+
"build",
|
|
103
|
+
".tox",
|
|
104
|
+
".coverage",
|
|
105
|
+
"htmlcov",
|
|
106
|
+
".idea",
|
|
107
|
+
".vscode",
|
|
108
|
+
".cursor",
|
|
109
|
+
".claude",
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
# File operation limits
|
|
113
|
+
MAX_LIST_DEPTH: int = 10
|
|
114
|
+
MAX_LIST_RESULTS: int = 1000
|
|
115
|
+
MAX_PREVIEW_BYTES: int = 100_000
|
|
116
|
+
DEFAULT_TIMEOUT: int = 60
|
|
@@ -13,8 +13,12 @@ os.environ.setdefault("LOGURU_LEVEL", "WARNING")
|
|
|
13
13
|
|
|
14
14
|
from arcade_mcp_server import MCPApp
|
|
15
15
|
|
|
16
|
-
from
|
|
17
|
-
|
|
16
|
+
from cadecoder.core.frozen import patch_frozen_return_detection
|
|
17
|
+
|
|
18
|
+
patch_frozen_return_detection()
|
|
19
|
+
|
|
20
|
+
from cade_mcp_local.resources import register_resources # noqa: E402
|
|
21
|
+
from cade_mcp_local.tools import ( # noqa: E402
|
|
18
22
|
ask_user_question_tool,
|
|
19
23
|
bash_tool,
|
|
20
24
|
edit_tool,
|
|
@@ -69,7 +73,7 @@ def create_app() -> MCPApp:
|
|
|
69
73
|
name="Local",
|
|
70
74
|
transport="stdio",
|
|
71
75
|
instructions=SERVER_INSTRUCTIONS,
|
|
72
|
-
log_level="
|
|
76
|
+
log_level="INFO",
|
|
73
77
|
)
|
|
74
78
|
|
|
75
79
|
# Filesystem tools
|
|
@@ -19,6 +19,7 @@ from cade_mcp_local.config import (
|
|
|
19
19
|
MAX_LIST_RESULTS,
|
|
20
20
|
MAX_PREVIEW_BYTES,
|
|
21
21
|
get_project_root,
|
|
22
|
+
path_restrictions_enabled,
|
|
22
23
|
)
|
|
23
24
|
from cade_mcp_local.errors import (
|
|
24
25
|
FileOperationError,
|
|
@@ -47,22 +48,25 @@ def _read_text_file(file_path: pathlib.Path) -> str:
|
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
def _write_text_file(file_path: pathlib.Path, content: str) -> None:
|
|
50
|
-
"""Write text content to a file, ensuring it's within project root.
|
|
51
|
-
|
|
51
|
+
"""Write text content to a file, ensuring it's within project root.
|
|
52
|
+
|
|
53
|
+
Confinement to the project root is skipped when path restrictions are
|
|
54
|
+
disabled (see `path_restrictions_enabled`).
|
|
55
|
+
"""
|
|
52
56
|
resolved = file_path.resolve()
|
|
53
|
-
resolved_root = project_root.resolve()
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
if path_restrictions_enabled():
|
|
59
|
+
resolved_root = get_project_root().resolve()
|
|
60
|
+
# Security check: must be within project root.
|
|
61
|
+
# Use string prefix check as fallback for symlink/worktree edge cases.
|
|
62
|
+
try:
|
|
63
|
+
resolved.relative_to(resolved_root)
|
|
64
|
+
except ValueError:
|
|
65
|
+
if not str(resolved).startswith(str(resolved_root) + "/"):
|
|
66
|
+
raise PathSecurityError(
|
|
67
|
+
str(file_path),
|
|
68
|
+
f"outside project root (resolved={resolved}, root={resolved_root})",
|
|
69
|
+
)
|
|
66
70
|
|
|
67
71
|
# Create parent directories if needed
|
|
68
72
|
resolved.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
import fnmatch
|
|
4
4
|
import pathlib
|
|
5
5
|
|
|
6
|
-
from cade_mcp_local.config import
|
|
6
|
+
from cade_mcp_local.config import (
|
|
7
|
+
DEFAULT_IGNORE_PATTERNS,
|
|
8
|
+
get_project_root,
|
|
9
|
+
path_restrictions_enabled,
|
|
10
|
+
)
|
|
7
11
|
|
|
8
12
|
|
|
9
13
|
def resolve_path(
|
|
@@ -46,7 +50,7 @@ def resolve_path(
|
|
|
46
50
|
else:
|
|
47
51
|
resolved = (base_dir / path).resolve()
|
|
48
52
|
|
|
49
|
-
if confine_to_root:
|
|
53
|
+
if confine_to_root and path_restrictions_enabled():
|
|
50
54
|
root = get_project_root().resolve()
|
|
51
55
|
try:
|
|
52
56
|
resolved.relative_to(root)
|