ccproxy-api 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl
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.
- ccproxy/_version.py +2 -2
- ccproxy/adapters/openai/__init__.py +1 -2
- ccproxy/adapters/openai/adapter.py +218 -180
- ccproxy/adapters/openai/streaming.py +247 -65
- ccproxy/api/__init__.py +0 -3
- ccproxy/api/app.py +173 -40
- ccproxy/api/dependencies.py +62 -3
- ccproxy/api/middleware/errors.py +3 -7
- ccproxy/api/middleware/headers.py +0 -2
- ccproxy/api/middleware/logging.py +4 -3
- ccproxy/api/middleware/request_content_logging.py +297 -0
- ccproxy/api/middleware/request_id.py +5 -0
- ccproxy/api/middleware/server_header.py +0 -4
- ccproxy/api/routes/__init__.py +9 -1
- ccproxy/api/routes/claude.py +23 -32
- ccproxy/api/routes/health.py +58 -4
- ccproxy/api/routes/mcp.py +171 -0
- ccproxy/api/routes/metrics.py +4 -8
- ccproxy/api/routes/permissions.py +217 -0
- ccproxy/api/routes/proxy.py +0 -53
- ccproxy/api/services/__init__.py +6 -0
- ccproxy/api/services/permission_service.py +368 -0
- ccproxy/api/ui/__init__.py +6 -0
- ccproxy/api/ui/permission_handler_protocol.py +33 -0
- ccproxy/api/ui/terminal_permission_handler.py +593 -0
- ccproxy/auth/conditional.py +2 -2
- ccproxy/auth/dependencies.py +1 -1
- ccproxy/auth/oauth/models.py +0 -1
- ccproxy/auth/oauth/routes.py +1 -3
- ccproxy/auth/storage/json_file.py +0 -1
- ccproxy/auth/storage/keyring.py +0 -3
- ccproxy/claude_sdk/__init__.py +2 -0
- ccproxy/claude_sdk/client.py +91 -8
- ccproxy/claude_sdk/converter.py +405 -210
- ccproxy/claude_sdk/options.py +76 -29
- ccproxy/claude_sdk/parser.py +200 -0
- ccproxy/claude_sdk/streaming.py +286 -0
- ccproxy/cli/commands/__init__.py +5 -2
- ccproxy/cli/commands/auth.py +2 -4
- ccproxy/cli/commands/permission_handler.py +553 -0
- ccproxy/cli/commands/serve.py +30 -12
- ccproxy/cli/docker/params.py +0 -4
- ccproxy/cli/helpers.py +0 -2
- ccproxy/cli/main.py +5 -16
- ccproxy/cli/options/claude_options.py +19 -1
- ccproxy/cli/options/core_options.py +0 -3
- ccproxy/cli/options/security_options.py +0 -2
- ccproxy/cli/options/server_options.py +3 -2
- ccproxy/config/auth.py +0 -1
- ccproxy/config/claude.py +78 -2
- ccproxy/config/discovery.py +0 -1
- ccproxy/config/docker_settings.py +0 -1
- ccproxy/config/loader.py +1 -4
- ccproxy/config/scheduler.py +20 -0
- ccproxy/config/security.py +7 -2
- ccproxy/config/server.py +5 -0
- ccproxy/config/settings.py +13 -7
- ccproxy/config/validators.py +1 -1
- ccproxy/core/async_utils.py +1 -4
- ccproxy/core/errors.py +45 -1
- ccproxy/core/http_transformers.py +4 -3
- ccproxy/core/interfaces.py +2 -2
- ccproxy/core/logging.py +97 -95
- ccproxy/core/middleware.py +1 -1
- ccproxy/core/proxy.py +1 -1
- ccproxy/core/transformers.py +1 -1
- ccproxy/core/types.py +1 -1
- ccproxy/docker/models.py +1 -1
- ccproxy/docker/protocol.py +0 -3
- ccproxy/models/__init__.py +41 -0
- ccproxy/models/claude_sdk.py +420 -0
- ccproxy/models/messages.py +45 -18
- ccproxy/models/permissions.py +115 -0
- ccproxy/models/requests.py +1 -1
- ccproxy/models/responses.py +29 -2
- ccproxy/observability/access_logger.py +1 -2
- ccproxy/observability/context.py +17 -1
- ccproxy/observability/metrics.py +1 -3
- ccproxy/observability/pushgateway.py +0 -2
- ccproxy/observability/stats_printer.py +2 -4
- ccproxy/observability/storage/duckdb_simple.py +1 -1
- ccproxy/observability/storage/models.py +0 -1
- ccproxy/pricing/cache.py +0 -1
- ccproxy/pricing/loader.py +5 -21
- ccproxy/pricing/updater.py +0 -1
- ccproxy/scheduler/__init__.py +1 -0
- ccproxy/scheduler/core.py +6 -6
- ccproxy/scheduler/manager.py +35 -7
- ccproxy/scheduler/registry.py +1 -1
- ccproxy/scheduler/tasks.py +127 -2
- ccproxy/services/claude_sdk_service.py +220 -328
- ccproxy/services/credentials/manager.py +0 -1
- ccproxy/services/credentials/oauth_client.py +1 -2
- ccproxy/services/proxy_service.py +93 -222
- ccproxy/testing/config.py +1 -1
- ccproxy/testing/mock_responses.py +0 -1
- ccproxy/utils/model_mapping.py +197 -0
- ccproxy/utils/models_provider.py +150 -0
- ccproxy/utils/simple_request_logger.py +284 -0
- ccproxy/utils/version_checker.py +184 -0
- {ccproxy_api-0.1.2.dist-info → ccproxy_api-0.1.3.dist-info}/METADATA +63 -2
- ccproxy_api-0.1.3.dist-info/RECORD +166 -0
- ccproxy/cli/commands/permission.py +0 -128
- ccproxy_api-0.1.2.dist-info/RECORD +0 -150
- /ccproxy/scheduler/{exceptions.py → errors.py} +0 -0
- {ccproxy_api-0.1.2.dist-info → ccproxy_api-0.1.3.dist-info}/WHEEL +0 -0
- {ccproxy_api-0.1.2.dist-info → ccproxy_api-0.1.3.dist-info}/entry_points.txt +0 -0
- {ccproxy_api-0.1.2.dist-info → ccproxy_api-0.1.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""Version checking utilities for ccproxy."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import aiofiles
|
|
11
|
+
import httpx
|
|
12
|
+
import structlog
|
|
13
|
+
from packaging import version as pkg_version
|
|
14
|
+
from pydantic import BaseModel
|
|
15
|
+
|
|
16
|
+
from ccproxy._version import __version__
|
|
17
|
+
from ccproxy.config.discovery import get_ccproxy_config_dir
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
logger = structlog.get_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class VersionCheckState(BaseModel):
|
|
24
|
+
"""State tracking for version checks."""
|
|
25
|
+
|
|
26
|
+
last_check_at: datetime
|
|
27
|
+
latest_version_found: str | None = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def fetch_latest_github_version() -> str | None:
|
|
31
|
+
"""
|
|
32
|
+
Fetch the latest version from GitHub releases API.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Latest version string or None if unable to fetch
|
|
36
|
+
"""
|
|
37
|
+
url = "https://api.github.com/repos/CaddyGlow/ccproxy-api/releases/latest"
|
|
38
|
+
headers = {
|
|
39
|
+
"User-Agent": f"ccproxy-api/{__version__}",
|
|
40
|
+
"Accept": "application/vnd.github.v3+json",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
45
|
+
response = await client.get(url, headers=headers)
|
|
46
|
+
response.raise_for_status()
|
|
47
|
+
|
|
48
|
+
data: dict[str, Any] = response.json()
|
|
49
|
+
tag_name: str = str(data.get("tag_name", "")).lstrip("v")
|
|
50
|
+
|
|
51
|
+
if tag_name:
|
|
52
|
+
logger.debug("github_version_fetched", latest_version=tag_name)
|
|
53
|
+
return tag_name
|
|
54
|
+
|
|
55
|
+
logger.warning("github_version_missing_tag")
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
except httpx.TimeoutException:
|
|
59
|
+
logger.warning("github_version_timeout")
|
|
60
|
+
return None
|
|
61
|
+
except httpx.HTTPStatusError as e:
|
|
62
|
+
logger.warning("github_version_http_error", status_code=e.response.status_code)
|
|
63
|
+
return None
|
|
64
|
+
except Exception as e:
|
|
65
|
+
logger.warning(
|
|
66
|
+
"github_version_fetch_failed",
|
|
67
|
+
error=str(e),
|
|
68
|
+
error_type=type(e).__name__,
|
|
69
|
+
)
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_current_version() -> str:
|
|
74
|
+
"""
|
|
75
|
+
Get the current version of ccproxy.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Current version string
|
|
79
|
+
"""
|
|
80
|
+
return __version__
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def compare_versions(current: str, latest: str) -> bool:
|
|
84
|
+
"""
|
|
85
|
+
Compare version strings to determine if an update is available.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
current: Current version string
|
|
89
|
+
latest: Latest version string
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
True if latest version is newer than current
|
|
93
|
+
"""
|
|
94
|
+
try:
|
|
95
|
+
current_parsed = pkg_version.parse(current)
|
|
96
|
+
latest_parsed = pkg_version.parse(latest)
|
|
97
|
+
return latest_parsed > current_parsed
|
|
98
|
+
except Exception as e:
|
|
99
|
+
logger.error(
|
|
100
|
+
"version_comparison_failed",
|
|
101
|
+
current=current,
|
|
102
|
+
latest=latest,
|
|
103
|
+
error=str(e),
|
|
104
|
+
error_type=type(e).__name__,
|
|
105
|
+
)
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
async def load_check_state(path: Path) -> VersionCheckState | None:
|
|
110
|
+
"""
|
|
111
|
+
Load version check state from file.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
path: Path to state file
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
VersionCheckState if file exists and is valid, None otherwise
|
|
118
|
+
"""
|
|
119
|
+
if not path.exists():
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
async with aiofiles.open(path) as f:
|
|
124
|
+
content = await f.read()
|
|
125
|
+
data = json.loads(content)
|
|
126
|
+
return VersionCheckState(**data)
|
|
127
|
+
except Exception as e:
|
|
128
|
+
logger.warning(
|
|
129
|
+
"version_check_state_load_failed",
|
|
130
|
+
path=str(path),
|
|
131
|
+
error=str(e),
|
|
132
|
+
error_type=type(e).__name__,
|
|
133
|
+
)
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
async def save_check_state(path: Path, state: VersionCheckState) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Save version check state to file.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
path: Path to state file
|
|
143
|
+
state: VersionCheckState to save
|
|
144
|
+
"""
|
|
145
|
+
try:
|
|
146
|
+
# Ensure directory exists
|
|
147
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
148
|
+
|
|
149
|
+
# Convert state to dict with ISO format datetime
|
|
150
|
+
state_dict = state.model_dump()
|
|
151
|
+
state_dict["last_check_at"] = state.last_check_at.isoformat()
|
|
152
|
+
|
|
153
|
+
async with aiofiles.open(path, "w") as f:
|
|
154
|
+
await f.write(json.dumps(state_dict, indent=2))
|
|
155
|
+
|
|
156
|
+
logger.debug("version_check_state_saved", path=str(path))
|
|
157
|
+
except Exception as e:
|
|
158
|
+
logger.warning(
|
|
159
|
+
"version_check_state_save_failed",
|
|
160
|
+
path=str(path),
|
|
161
|
+
error=str(e),
|
|
162
|
+
error_type=type(e).__name__,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def get_version_check_state_path() -> Path:
|
|
167
|
+
"""
|
|
168
|
+
Get the path to the version check state file.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Path to version_check.json in ccproxy config directory
|
|
172
|
+
"""
|
|
173
|
+
return get_ccproxy_config_dir() / "version_check.json"
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
__all__ = [
|
|
177
|
+
"VersionCheckState",
|
|
178
|
+
"fetch_latest_github_version",
|
|
179
|
+
"get_current_version",
|
|
180
|
+
"compare_versions",
|
|
181
|
+
"load_check_state",
|
|
182
|
+
"save_check_state",
|
|
183
|
+
"get_version_check_state_path",
|
|
184
|
+
]
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ccproxy-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: API server that provides an Anthropic and OpenAI compatible interface over Claude Code, allowing to use your Claude OAuth account or over the API.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: aiofiles>=24.1.0
|
|
7
8
|
Requires-Dist: aiosqlite>=0.21.0
|
|
8
9
|
Requires-Dist: claude-code-sdk>=0.0.14
|
|
9
10
|
Requires-Dist: duckdb-engine>=0.17.0
|
|
10
11
|
Requires-Dist: duckdb>=1.1.0
|
|
12
|
+
Requires-Dist: fastapi-mcp
|
|
11
13
|
Requires-Dist: fastapi[standard]>=0.115.14
|
|
12
14
|
Requires-Dist: httpx-sse>=0.4.1
|
|
13
15
|
Requires-Dist: httpx>=0.28.1
|
|
@@ -21,6 +23,7 @@ Requires-Dist: rich-toolkit>=0.14.8
|
|
|
21
23
|
Requires-Dist: rich>=13.0.0
|
|
22
24
|
Requires-Dist: sqlmodel>=0.0.24
|
|
23
25
|
Requires-Dist: structlog>=25.4.0
|
|
26
|
+
Requires-Dist: textual>=3.7.1
|
|
24
27
|
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
25
28
|
Requires-Dist: typer>=0.16.0
|
|
26
29
|
Requires-Dist: typing-extensions>=4.0.0
|
|
@@ -32,7 +35,7 @@ Description-Content-Type: text/markdown
|
|
|
32
35
|
`ccproxy` is a local reverse proxy server for Anthropic Claude LLM at `api.anthropic.com/v1/messages`. It allows you to use your existing Claude Max subscription to interact with the Anthropic API, bypassing the need for separate API key billing.
|
|
33
36
|
|
|
34
37
|
The server provides two primary modes of operation:
|
|
35
|
-
* **SDK Mode (`/sdk`):** Routes requests through the local `claude-code-sdk`. This enables access to tools configured in your Claude environment.
|
|
38
|
+
* **SDK Mode (`/sdk`):** Routes requests through the local `claude-code-sdk`. This enables access to tools configured in your Claude environment and includes an integrated MCP (Model Context Protocol) server for permission management.
|
|
36
39
|
* **API Mode (`/api`):** Acts as a direct reverse proxy, injecting the necessary authentication headers. This provides full access to the underlying API features and model settings.
|
|
37
40
|
|
|
38
41
|
It includes a translation layer to support both Anthropic and OpenAI-compatible API formats for requests and responses, including streaming.
|
|
@@ -126,6 +129,59 @@ export ANTHROPIC_API_KEY="dummy-key"
|
|
|
126
129
|
```
|
|
127
130
|
|
|
128
131
|
|
|
132
|
+
## MCP Server Integration & Permission System
|
|
133
|
+
|
|
134
|
+
In SDK mode, CCProxy automatically configures an MCP (Model Context Protocol) server that provides permission checking tools for Claude Code. This enables interactive permission management for tool execution.
|
|
135
|
+
|
|
136
|
+
### Permission Management
|
|
137
|
+
|
|
138
|
+
**Starting the Permission Handler:**
|
|
139
|
+
```bash
|
|
140
|
+
# In a separate terminal, start the permission handler
|
|
141
|
+
ccproxy permission-handler
|
|
142
|
+
|
|
143
|
+
# Or with custom settings
|
|
144
|
+
ccproxy permission-handler --host 127.0.0.1 --port 8000
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The permission handler provides:
|
|
148
|
+
- **Real-time Permission Requests**: Streams permission requests via Server-Sent Events (SSE)
|
|
149
|
+
- **Interactive Approval/Denial**: Command-line interface for managing tool permissions
|
|
150
|
+
- **Automatic MCP Integration**: Works seamlessly with Claude Code SDK tools
|
|
151
|
+
|
|
152
|
+
**Working Directory Control:**
|
|
153
|
+
Control which project the Claude SDK API can access using the `--cwd` flag:
|
|
154
|
+
```bash
|
|
155
|
+
# Set working directory for Claude SDK
|
|
156
|
+
ccproxy --claude-code-options-cwd /path/to/your/project
|
|
157
|
+
|
|
158
|
+
# Example with permission bypass and formatted output
|
|
159
|
+
ccproxy --claude-code-options-cwd /tmp/tmp.AZyCo5a42N \
|
|
160
|
+
--claude-code-options-permission-mode bypassPermissions \
|
|
161
|
+
--claude-sdk-message-mode formatted
|
|
162
|
+
|
|
163
|
+
# Alternative: Change to project directory and start ccproxy
|
|
164
|
+
cd /path/to/your/project
|
|
165
|
+
ccproxy
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Claude SDK Message Formatting
|
|
169
|
+
|
|
170
|
+
CCProxy supports flexible message formatting through the `sdk_message_mode` configuration:
|
|
171
|
+
|
|
172
|
+
- **`forward`** (default): Preserves original Claude SDK content blocks with full metadata
|
|
173
|
+
- **`formatted`**: Converts content to XML tags with pretty-printed JSON data
|
|
174
|
+
- **`ignore`**: Filters out Claude SDK-specific content entirely
|
|
175
|
+
|
|
176
|
+
Configure via environment variables:
|
|
177
|
+
```bash
|
|
178
|
+
# Use formatted XML output
|
|
179
|
+
CLAUDE__SDK_MESSAGE_MODE=formatted ccproxy
|
|
180
|
+
|
|
181
|
+
# Use compact formatting without pretty-printing
|
|
182
|
+
CLAUDE__PRETTY_FORMAT=false ccproxy
|
|
183
|
+
```
|
|
184
|
+
|
|
129
185
|
## Using with Aider
|
|
130
186
|
|
|
131
187
|
CCProxy works seamlessly with Aider and other AI coding assistants:
|
|
@@ -200,6 +256,11 @@ The proxy exposes endpoints under two prefixes, corresponding to its operating m
|
|
|
200
256
|
* `GET /sdk/models`, `GET /api/models`
|
|
201
257
|
* `GET /sdk/status`, `GET /api/status`
|
|
202
258
|
* `GET /oauth/callback`
|
|
259
|
+
* **MCP & Permissions:**
|
|
260
|
+
* `POST /mcp/permission/check` - MCP permission checking endpoint
|
|
261
|
+
* `GET /permissions/stream` - SSE stream for permission requests
|
|
262
|
+
* `GET /permissions/{id}` - Get permission request details
|
|
263
|
+
* `POST /permissions/{id}/respond` - Respond to permission request
|
|
203
264
|
* **Observability (Optional):**
|
|
204
265
|
* `GET /metrics`
|
|
205
266
|
* `GET /logs/status`, `GET /logs/query`
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
ccproxy/__init__.py,sha256=VrtzUTUA8MwpYqFJAiwKLPxRdMRc7UOzFi2VB_1W9qw,62
|
|
2
|
+
ccproxy/__main__.py,sha256=kcejcfzAaMnFiSxEiVtNl-_TwynpntkupRxqG5XR15s,116
|
|
3
|
+
ccproxy/_version.py,sha256=NIzzV8ZM0W-CSLuEs1weG4zPrn_-8yr1AwwI1iuS6yo,511
|
|
4
|
+
ccproxy/adapters/__init__.py,sha256=CMr5MPIFigfazoXfhyD2eLqBrutzaSzBaEi8u2i9xJQ,206
|
|
5
|
+
ccproxy/adapters/base.py,sha256=aufx8ho9LhF0kmTsCvw1a9K3lk5YyYymJV8h_wt5TpU,2191
|
|
6
|
+
ccproxy/adapters/openai/__init__.py,sha256=CEOtyALpgaq6XT6upZKt0u_ilvnXIyH9K2hFXZJ-hOY,1063
|
|
7
|
+
ccproxy/adapters/openai/adapter.py,sha256=qjo3bbNIQKlzxLt8r51gv_Se1ShuJREisFyboOcLs-E,37958
|
|
8
|
+
ccproxy/adapters/openai/models.py,sha256=tg5NLFmTAOjLd2-gjqRQPU3IkL9ATftXv4ZugGw-rwc,11645
|
|
9
|
+
ccproxy/adapters/openai/streaming.py,sha256=9EcqK5XebN7JRpB3MddR_VYeejkIKlMVFaYxMCeiOko,23218
|
|
10
|
+
ccproxy/api/__init__.py,sha256=_u4wpzvN4Y0qS4CTaGp8nD8ZopB0HeFxnIIw9GYjvvk,527
|
|
11
|
+
ccproxy/api/app.py,sha256=sfIBoDhRw17a40qsQ6vlCgAtcJG0IOQcIMEsQCwruwg,16157
|
|
12
|
+
ccproxy/api/dependencies.py,sha256=e4vgUaRULPlOWUPF5ZcS5UJNCXdBORklfIw7-FFX4IE,6162
|
|
13
|
+
ccproxy/api/responses.py,sha256=eipdbHLQcrUjBYJd-Q5bEWUoiFlmPiDB0wdySFNubx4,2905
|
|
14
|
+
ccproxy/api/middleware/__init__.py,sha256=S887PXY40Tnb0IFGei4Sgs7sygkcoT0IEOciOO7IDBc,284
|
|
15
|
+
ccproxy/api/middleware/auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
ccproxy/api/middleware/cors.py,sha256=u8bnWmBXRG9J2etbQdNsQOTIQY6PFWawk2Oa0Ei1x3s,1666
|
|
17
|
+
ccproxy/api/middleware/errors.py,sha256=WsFLkoe3TMD5hjmhKWWcMEJVX9NAWEudOcujciL22o4,21909
|
|
18
|
+
ccproxy/api/middleware/headers.py,sha256=zGhF3F11TKeb3zY5qzblU3Sdwx1MSlqm2QSOqtVfpoY,1775
|
|
19
|
+
ccproxy/api/middleware/logging.py,sha256=NDkIjIIQlAjr4m8nCXOe9na2Intc1Q_aYQZ2zWACeZw,7069
|
|
20
|
+
ccproxy/api/middleware/request_content_logging.py,sha256=aIH1G9kjNr4-O5IFoisI9fO93rPePVWBQJM4wX1NCnY,10333
|
|
21
|
+
ccproxy/api/middleware/request_id.py,sha256=OOZh63FYP_JY3olZNzgzVdPFZUJFT_KerZxYMxsPmyQ,2538
|
|
22
|
+
ccproxy/api/middleware/server_header.py,sha256=9A3c7L12CFkQftMOZwB5JzqocGWymuV8AT_u_Y2s9RA,2329
|
|
23
|
+
ccproxy/api/routes/__init__.py,sha256=xXoslArg915ZTmN2ITQ-i3iO7fu8ZkQAMrSgC41U5oA,664
|
|
24
|
+
ccproxy/api/routes/claude.py,sha256=hA6SPyuZbkUq8JoSKnvceN1j211uGNuNdsye8dM_TXQ,6498
|
|
25
|
+
ccproxy/api/routes/health.py,sha256=6eIoZ5oCBG8npDXqTnAU-rLWgO53b4E6SA0l12bAkjA,18932
|
|
26
|
+
ccproxy/api/routes/mcp.py,sha256=-EVGid0uNOWeXP4w8F_hKUp1odkNnFXPHPmaOGC0UzQ,5389
|
|
27
|
+
ccproxy/api/routes/metrics.py,sha256=MHG2nEGu3amrU6zJCuH2RktM8kg2EFxu4xNOFCzXMn4,40813
|
|
28
|
+
ccproxy/api/routes/permissions.py,sha256=dvbWORmmAce7VZWlZPvchTCO9F6fauavmSbs8hUltKE,6231
|
|
29
|
+
ccproxy/api/routes/proxy.py,sha256=sFOS62sEqlr_xkTr9fg-eSQMuUflnnDdkEvHj4Fx8es,7373
|
|
30
|
+
ccproxy/api/services/__init__.py,sha256=_n4k1Ciao8BEbiMBSldq82nbs7N8qXu_1TcBwWLV8bE,167
|
|
31
|
+
ccproxy/api/services/permission_service.py,sha256=x7YDTsxHKSbF8QoCEUwfemPIXXOQ4mJSjXBJSSu1pBg,12022
|
|
32
|
+
ccproxy/api/ui/__init__.py,sha256=oEgfWr8pgSO7uHYQBchJ2QspFrFsqTCO8mLPlfhHTfU,147
|
|
33
|
+
ccproxy/api/ui/permission_handler_protocol.py,sha256=_jZAQ1KN5dK1Z28jqaW90Ggt8usVTR1P7pEKPWGN9SY,972
|
|
34
|
+
ccproxy/api/ui/terminal_permission_handler.py,sha256=GuD_RyQCiuxJtFJI-SKsWPvw1brz1_IGz31YjLVQ9js,20195
|
|
35
|
+
ccproxy/auth/__init__.py,sha256=frT0rDZVGs3zVgaI_z1OuEK6VqAccqRJBBmhlx8tlT4,1967
|
|
36
|
+
ccproxy/auth/bearer.py,sha256=4K9y7kG29NNEhuqqpDvNusmDNWQah90nHGRZxBA1H2o,2015
|
|
37
|
+
ccproxy/auth/conditional.py,sha256=IA5FKLiSZ6B7YnWxALhmOYTkDHk7i0vy5rPxcxswyy8,2811
|
|
38
|
+
ccproxy/auth/credentials_adapter.py,sha256=2BlihJ0KLcIq4hLVHPVaimS0JuZFINzGnBmm_SMPP6c,3279
|
|
39
|
+
ccproxy/auth/dependencies.py,sha256=LE5Wt5gX6u_OgpPU0AhlxoiqNfG41GZqu_7ZTeKeASI,7078
|
|
40
|
+
ccproxy/auth/exceptions.py,sha256=EUaT7qW0D8HHziX7HglZB-WnALQlbj1lt9OKvyZ97IA,1325
|
|
41
|
+
ccproxy/auth/manager.py,sha256=AHVK4iq3LvavZeSyAmON1ExVA3GLdphe2jO4VuMmImA,2425
|
|
42
|
+
ccproxy/auth/models.py,sha256=z2mkTc-Av2trF3fnqoBEQ7IAfgq96pRGtbjdzrXSFUI,3709
|
|
43
|
+
ccproxy/auth/oauth/__init__.py,sha256=PEymCot9_oIj2mKFIyfmIlznoKwoBuSKqfRvH9k_QR0,508
|
|
44
|
+
ccproxy/auth/oauth/models.py,sha256=CIgzXpyf5PY8vnO8jkv3cfr1W9rkT5qtkz_u2xGabV4,2007
|
|
45
|
+
ccproxy/auth/oauth/routes.py,sha256=9sWaib49v5MFv_FFsnlgTXqgwvGprWWwpJzrSihKaks,13598
|
|
46
|
+
ccproxy/auth/oauth/storage.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
+
ccproxy/auth/storage/__init__.py,sha256=5thfvXhc8HGJblQWMiG6ZPl594RpbTGdAgyAlpAe1TI,324
|
|
48
|
+
ccproxy/auth/storage/base.py,sha256=Gw20tabOKTwey6YrOm09Bxu-MYJuMIrQULLJT6RQ07E,1357
|
|
49
|
+
ccproxy/auth/storage/json_file.py,sha256=iZBFCJ5EsZeFtlT7ORTXcEdAvMADIaDTXUPEBSjMcr0,5027
|
|
50
|
+
ccproxy/auth/storage/keyring.py,sha256=qg4q-O-Y6D7y4HQfgg5g9bhUpuD9DAec9npWne0VLwg,5950
|
|
51
|
+
ccproxy/claude_sdk/__init__.py,sha256=4r3KBqL5dXo6NI6hu8RjIRMm18OkOLCVJoKgDaAZQ8A,487
|
|
52
|
+
ccproxy/claude_sdk/client.py,sha256=KxUJ80WmBNlV6HgD3GNSDf0fDOJpuZfXjKf-S3IVo4s,9397
|
|
53
|
+
ccproxy/claude_sdk/converter.py,sha256=GeU7AzbzK1ltaiUEr60mG4VYaSup95Z6OxVSG9Pu0PY,19035
|
|
54
|
+
ccproxy/claude_sdk/options.py,sha256=ClgmCHPS0nljYK3OiZx72Sq09mjUQMHS1hnOrUW7Hbs,6821
|
|
55
|
+
ccproxy/claude_sdk/parser.py,sha256=1LcZOTkaKLSxZO_iVIvpZq44vUjApvMIA8Wlv61V6Jo,7193
|
|
56
|
+
ccproxy/claude_sdk/streaming.py,sha256=n-lUoihuTcanl8E_feuQPF2-dTCfNNsf5nevLc3si-4,12581
|
|
57
|
+
ccproxy/cli/__init__.py,sha256=_vISKEqzAsAYrTZ-j9ScxTUtFZp3RVRbIvGpCcu--SU,262
|
|
58
|
+
ccproxy/cli/helpers.py,sha256=LHGh5ZSywPUY61XVaSD5mx2eaIF4bi8hzbdMCJ0YRrQ,3814
|
|
59
|
+
ccproxy/cli/main.py,sha256=QLdSbSm3PjvwluL6WO7kpe8S7qrgsw2VjMR84aZ2fsg,2452
|
|
60
|
+
ccproxy/cli/commands/__init__.py,sha256=eWugiC37ualVtsTazu7GBCV7kZ12xkAnTUztjV7kVao,200
|
|
61
|
+
ccproxy/cli/commands/auth.py,sha256=crpPeJ5Xs5I-xl5BC27HUJxlTHgcjL7GeMH0e31DXQc,20716
|
|
62
|
+
ccproxy/cli/commands/permission_handler.py,sha256=rdPxXCZ3pK6a93eKED2XFNIwtnNcTW5XjM-X7edBcb0,18463
|
|
63
|
+
ccproxy/cli/commands/serve.py,sha256=EZQCZiFWZixYA6_uY6Lthuktb50l-cx12lVn33S2rTU,29192
|
|
64
|
+
ccproxy/cli/commands/config/__init__.py,sha256=uX8VewtrMu5X8VAx5ym1slwNtlICDBEs3S1HfoFe5Qo,376
|
|
65
|
+
ccproxy/cli/commands/config/commands.py,sha256=ukAr55NLFTg67f5czpjbuz_Ap_mwFIMIfMGHeXv_E5c,28917
|
|
66
|
+
ccproxy/cli/commands/config/schema_commands.py,sha256=ZSuK_Q1bWp8WUOSbkuwKz_4TwrxkRsA6MOt_-y1eiVs,4218
|
|
67
|
+
ccproxy/cli/docker/__init__.py,sha256=4x9QO8SF9aloJFs4xrUEhGcSmoosIYmjcMTk4-GnHBE,791
|
|
68
|
+
ccproxy/cli/docker/adapter_factory.py,sha256=dbO_MGrrAsyF0DDZMKbrk4oMx2xAMZPihOAviF7D5zY,5022
|
|
69
|
+
ccproxy/cli/docker/params.py,sha256=cAkszIkS6lztpXxRuHRGBseA0n6n-huwyydDRKUHjSM,7378
|
|
70
|
+
ccproxy/cli/options/__init__.py,sha256=OiToWXDNOXnO-fuPz2H5qXYwp9ht7uB12-4wxqner1Q,340
|
|
71
|
+
ccproxy/cli/options/claude_options.py,sha256=co3kyNxjH9brYcV7xRNU38Rd7BhqwQeRnXqRM4ZJKQQ,4222
|
|
72
|
+
ccproxy/cli/options/core_options.py,sha256=80qVieUiUMYwjDKVeFfBDGjF1a8P1qB8Ppf-zSZ1eek,552
|
|
73
|
+
ccproxy/cli/options/security_options.py,sha256=95TfENdeAsDMes7SH39mQJERgrqoL4jZEKvZL7NlzJQ,873
|
|
74
|
+
ccproxy/cli/options/server_options.py,sha256=y37dtZGWuuYcDOn92zSzKwblnTgq65ZJJk2fWBA__s4,1935
|
|
75
|
+
ccproxy/config/__init__.py,sha256=RVXg7sdADdX9-Z-67OYoNlQxby6UN9tThNtg_XzjZ1I,976
|
|
76
|
+
ccproxy/config/auth.py,sha256=CDc5qiexq4jH3Ve39tnL1Vn5c5bOUBWUdi7j4VLwewU,4653
|
|
77
|
+
ccproxy/config/claude.py,sha256=2rOxpULXckJasTpeEUlUu0IAeVPAkH8XkEJRTZnmuS4,7139
|
|
78
|
+
ccproxy/config/cors.py,sha256=eNxrNuPN7Ujh9_2fIWu6kmOIeYNuqn0NTuCsBYvctFM,2505
|
|
79
|
+
ccproxy/config/discovery.py,sha256=ZwByXmmSq14ScRwXe1slHWvg5pLWFxXWxvGNFkZxRik,2255
|
|
80
|
+
ccproxy/config/docker_settings.py,sha256=5D8eBSyWActgBGE7cIb4HObqlvE-7jxylmUBn5UxLM4,8390
|
|
81
|
+
ccproxy/config/loader.py,sha256=kgeShuaeNjTHI7lX2VWSFlE4ugOJW9HAT-FJesKLegE,3100
|
|
82
|
+
ccproxy/config/observability.py,sha256=5AwQFEFxJLUStGP5gjL_5i8Hk8KdrXKY7ocITYg8jZQ,5466
|
|
83
|
+
ccproxy/config/pricing.py,sha256=RzsNQHYmv5P-BcRDV4GSkSIDImFIFEEC7roFu5jeocE,2613
|
|
84
|
+
ccproxy/config/reverse_proxy.py,sha256=hep4ubV7-4ZgdO1_WqY56b5yrYyHCdQgYayUHKH3tfo,866
|
|
85
|
+
ccproxy/config/scheduler.py,sha256=RNexGYY2yUg7rt1jgmMAfLg-1dT3YejTl2qNIsp8w2U,3060
|
|
86
|
+
ccproxy/config/security.py,sha256=luNy1J6xXSKPRjAVTmF1mqSpN4h0I_1CllBJfaYbq0Q,493
|
|
87
|
+
ccproxy/config/server.py,sha256=71Ih6huVn52demV6jNrixM8jqXVqfFrBpIvWIlmhlww,2527
|
|
88
|
+
ccproxy/config/settings.py,sha256=jTo3nXMaePKCJqAV4Ejv9-q39t4fKxAUHsssxSMOf6I,17798
|
|
89
|
+
ccproxy/config/validators.py,sha256=EciRiEF7qGBcDp2Ms10VXyfAWXY_2uPPglvGh7EVLDs,5754
|
|
90
|
+
ccproxy/core/__init__.py,sha256=ZreOdlUlCn7R5GlS3EdpvIj5fO9sySbQKnuR8o6vwXI,6400
|
|
91
|
+
ccproxy/core/async_utils.py,sha256=slRQkIGctjZb6ZxridoJscFKVbyW2SYREieQjkpP_e8,19855
|
|
92
|
+
ccproxy/core/constants.py,sha256=mmkcOfKNnvu3h5paZ6GL72ecAK4XdBI4tXlmgImGyzI,2735
|
|
93
|
+
ccproxy/core/errors.py,sha256=gP1rh-k-KpE5OcVbFcdMdZSmDshvcoXdbVynIx864gc,8459
|
|
94
|
+
ccproxy/core/http.py,sha256=pj3UM9TDL13_sU0ULGuA2wvVg58uxOCy-ib3zugjelo,9317
|
|
95
|
+
ccproxy/core/http_transformers.py,sha256=jx4mcK6mAw9-Y4IkQGlW_S6L2sg1230y2pchJwztlas,16324
|
|
96
|
+
ccproxy/core/interfaces.py,sha256=zzucgNTvui7fGQ8vjLzCba-itJZh0Fs6GrDAZNJfGXo,6366
|
|
97
|
+
ccproxy/core/logging.py,sha256=_KdCkabhJmPjapxenJcXNHsSybzPboSqASGem1bcKGY,6801
|
|
98
|
+
ccproxy/core/middleware.py,sha256=libv7wo-y9nni9hp7GCkYUKlIKihAwG0iHvjcv_RTs8,3355
|
|
99
|
+
ccproxy/core/proxy.py,sha256=6lFqNiGFQFlh61q32imbUD-RJAK2RJHJNyYLwAmUYr0,4615
|
|
100
|
+
ccproxy/core/system.py,sha256=91rMtlRtY4yxSsnPV5qZJaXHNFzvcrRZ1nQwS4CwG68,1019
|
|
101
|
+
ccproxy/core/transformers.py,sha256=Ubv6Vcq_q1Myrn-mns06AkBRt4kiTid2Ww_cmv2DPVA,7699
|
|
102
|
+
ccproxy/core/types.py,sha256=kGRMzb6VI5KWa3aFKWgQ3gChqdHPrPoOyZ0QPT1m18E,3554
|
|
103
|
+
ccproxy/core/validators.py,sha256=k2z71lz-zKhRdtx3tYgJllqFnEcQ-eivj1kf3aVej0s,7367
|
|
104
|
+
ccproxy/docker/__init__.py,sha256=gO9FJepIWneXPANgsAJKx_VL9rt7pcX3hbRcwnSyzJk,1833
|
|
105
|
+
ccproxy/docker/adapter.py,sha256=P-GeLVu5hl4oMHQrQJU3AHnUxrps-iUd06r7IVnncoY,21176
|
|
106
|
+
ccproxy/docker/docker_path.py,sha256=U_Di1bJDxDZNHW0cxGL31PD6RGKS9Sngs6_D7burmd0,6419
|
|
107
|
+
ccproxy/docker/middleware.py,sha256=hFSvTf77zrOWTH_T3lAk_O7jNSnYDPV_YQoQ82deBsM,3282
|
|
108
|
+
ccproxy/docker/models.py,sha256=3xCwOhfpUohINIG2QBoUKlQU1Ry1g-JV6HujhsoRtzM,7491
|
|
109
|
+
ccproxy/docker/protocol.py,sha256=uFJvKfTYhO8ROUo_tcMIuXYqhjK-eFIJV-U5Bora-jA,6520
|
|
110
|
+
ccproxy/docker/stream_process.py,sha256=XahXegGG6B-7RsZAb9J8OA7sz7xi8CmRzEI4vBJLwTI,9071
|
|
111
|
+
ccproxy/docker/validators.py,sha256=OY-dkU88CLIeMBfv4P5QoVB7miQ8BD7kIgaMHxF7TsU,5764
|
|
112
|
+
ccproxy/models/__init__.py,sha256=yaz9lC0roh0u7C33rHrGW46lrwbyyAa_evpAlA5BzYw,3548
|
|
113
|
+
ccproxy/models/claude_sdk.py,sha256=iUACoZQS_29OjjG-A6FNslL_J_IKFtJdgabxs3FIhNk,13893
|
|
114
|
+
ccproxy/models/errors.py,sha256=B2rbL-17ZI9emDOca2A2fLOcH1-_77t_xqDmiPf6fgY,1329
|
|
115
|
+
ccproxy/models/messages.py,sha256=halc96Yxx3R5Xa9F5Q53iFZs0MJMDRfAA0fSxaij51U,8013
|
|
116
|
+
ccproxy/models/permissions.py,sha256=uhlzHc56rDzekjQMN8ITPCrh-0lamcgzTwx1OA2y67w,3612
|
|
117
|
+
ccproxy/models/requests.py,sha256=k4oeGbSCsbm3E5_3JT4h7hjrkSsgNgLIlb99BypSoHk,2738
|
|
118
|
+
ccproxy/models/responses.py,sha256=4rJNCbCoQtjiRzwoQLwK-sVJT2HFsZ2U6Vw63CZ1ztw,7820
|
|
119
|
+
ccproxy/models/types.py,sha256=27MUg7pVGrK5oWzcrtG_IAoScEcrF20thO94bxZXQww,2729
|
|
120
|
+
ccproxy/observability/__init__.py,sha256=5n9yQBbMLAQVAEJZD-2t4CKfI0Wx2aoDH7d2ynPM4bg,1503
|
|
121
|
+
ccproxy/observability/access_logger.py,sha256=q6-5pdzZzW-jAZPIaiAeqoYXp8HrCw93F80OoM0XJZU,13095
|
|
122
|
+
ccproxy/observability/context.py,sha256=sfOdhgLY6LxLzOkJuzjqBsZV2e8ozAiYp79bhE2oqG4,14581
|
|
123
|
+
ccproxy/observability/metrics.py,sha256=4D4cz9Ns8JjAX9_RHo7Z7bQA9xfeEZkUL7T9HMy4OTg,16150
|
|
124
|
+
ccproxy/observability/pushgateway.py,sha256=t7jGCP7dQirBjQyX-nz4S6MKKIHErU9yQMqgfCiP0BQ,12708
|
|
125
|
+
ccproxy/observability/sse_events.py,sha256=CVumUxVlXV5tpqVozymaLW4pBTEM90KBYWS9jAJ6Dzk,10697
|
|
126
|
+
ccproxy/observability/stats_printer.py,sha256=-QSiAMiurQlMzdMQcS0bNcswm5dDaIzTeS1bUqMeVQY,30110
|
|
127
|
+
ccproxy/observability/storage/__init__.py,sha256=iAnhODA2PD3PxheoRgJv5KFCTUK_QwxxFa2Ne230RTg,47
|
|
128
|
+
ccproxy/observability/storage/duckdb_simple.py,sha256=lnENvs8p1OMaicsYLn8U5lPeCd0pOhjvNUN_HFqRekA,24789
|
|
129
|
+
ccproxy/observability/storage/models.py,sha256=6q5yuVwHXZZfXdT9VDYOevgi8psLBMJnuCVHKBc4TTk,1423
|
|
130
|
+
ccproxy/pricing/__init__.py,sha256=8EKUTusWT_URBO8_jzHQ2JWIv11JYZxiyk1WoA_slHE,450
|
|
131
|
+
ccproxy/pricing/cache.py,sha256=j0X0VWICAV2WPWSY8TQTsRZ04fX0_tuegJRp9Lw7Dgk,6506
|
|
132
|
+
ccproxy/pricing/loader.py,sha256=F7Ciu39xBdY6QqUbDNNM2FmX0zqFhrMCed_-YLkLdvI,8633
|
|
133
|
+
ccproxy/pricing/models.py,sha256=Sl4rQJyQ9x_-UqGzXItomnURtAGAWtLUHdTdjRKW6pM,3572
|
|
134
|
+
ccproxy/pricing/updater.py,sha256=OKbozb2SIe4yrwWVsQd5ryopZrJ06mIDP6y166-l_tg,10185
|
|
135
|
+
ccproxy/scheduler/__init__.py,sha256=qVe6NeKPn6NgMqEaG4_K4cYZBCpbFM7g6ptNPEzhi8c,1160
|
|
136
|
+
ccproxy/scheduler/core.py,sha256=Lvhc3i2bfbEnX-2n8lgDBM7YG7TKEnZC3tf8KC5u67M,10344
|
|
137
|
+
ccproxy/scheduler/errors.py,sha256=k7dcid0_te7IwwQaad-Jkj7MWFBgIOdgD_y_n5joio0,817
|
|
138
|
+
ccproxy/scheduler/manager.py,sha256=-A6y9ANFHcQeGIlb9ABY4jGBxwPZbdxLPQDpLvKuQew,6879
|
|
139
|
+
ccproxy/scheduler/registry.py,sha256=MaCuOEiJiYjlKS2Yqp3PxeWXpf8AqNPCQ_qeWbWtBCw,4058
|
|
140
|
+
ccproxy/scheduler/tasks.py,sha256=JJoG9zfdI8jg53xy-9iUaFdM5pD1E1Z-j8S6OHXl0BI,20595
|
|
141
|
+
ccproxy/services/__init__.py,sha256=ZvnelD15eFLlWHsucYXBFGNrdT7ncdP1KLnqzJNGOCs,251
|
|
142
|
+
ccproxy/services/claude_sdk_service.py,sha256=2yRc1uN4fQQjIynJo2Ur0d7o1ds46mEH5GwKyAFupTQ,17748
|
|
143
|
+
ccproxy/services/proxy_service.py,sha256=2QSQ92uag5j2NFxgcHVuxFVK3SlmiufqVWaWpyK5VaM,55650
|
|
144
|
+
ccproxy/services/credentials/__init__.py,sha256=fkCWqxlUyGVA1mxGicn4cvdbYJQo09SG9NoGKzUun3s,1394
|
|
145
|
+
ccproxy/services/credentials/config.py,sha256=97W3GqtxZlBv45oDHJ-plsHiSeFvNI-FTMZEw4CsPes,3221
|
|
146
|
+
ccproxy/services/credentials/manager.py,sha256=AnRvl1_v-eSbAEcmHMcUMmo7UpvTnAHe9QO5caL1JMY,19905
|
|
147
|
+
ccproxy/services/credentials/oauth_client.py,sha256=lLHWRrTrbgX63Ew8rD-CnvMnYoRFZkfD7QOVtuBNARs,16583
|
|
148
|
+
ccproxy/static/.keep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
149
|
+
ccproxy/testing/__init__.py,sha256=-W01VLA1RfopmwVaeWH32gstERNsjFcNIIynZjZjzls,1071
|
|
150
|
+
ccproxy/testing/config.py,sha256=tE-88piIIbUxXI1DkTs15KUAvHyHfcRaovBeQCXCZG4,4870
|
|
151
|
+
ccproxy/testing/content_generation.py,sha256=in2F_W1RSnQYKXYCavMrYXPLBrqVn_Bogx84oF242iY,8585
|
|
152
|
+
ccproxy/testing/mock_responses.py,sha256=GaegneKCVJSxoptLCUseriZ_wV_TfRnpD-vB0t60N3M,9200
|
|
153
|
+
ccproxy/testing/response_handlers.py,sha256=TSfBHzHLw8d3Y95zJ8wYewU9f5Wh89bl7DRfa-49ze0,6311
|
|
154
|
+
ccproxy/testing/scenarios.py,sha256=lVTkf1TbqPnWAfY2VbXez6dSFHsohuXerDmh37iC5VU,9200
|
|
155
|
+
ccproxy/utils/__init__.py,sha256=MBEWNgdZh4Ev-LcltUhkMBboR1QHYNeri3oOy1KQeDo,213
|
|
156
|
+
ccproxy/utils/cost_calculator.py,sha256=mHquyA_1vnPVZ2smjdPwThCJtGu-rF9n8ZvIrAwTF78,7276
|
|
157
|
+
ccproxy/utils/model_mapping.py,sha256=7TA3Jew_lg4IqMvoOvalDo1Vzozjb_Zq4749hPgPZGA,6602
|
|
158
|
+
ccproxy/utils/models_provider.py,sha256=F0_nwNsx-gGhobdTnPQh9zfrhOfw7cBrW2RR09SYY3Q,4434
|
|
159
|
+
ccproxy/utils/simple_request_logger.py,sha256=d54aXW_0P7zewGRzjwDu7QfJ-DGn4zJXu2R5hGXh-rU,8223
|
|
160
|
+
ccproxy/utils/streaming_metrics.py,sha256=JkvmWJ9s1fuKi7x1NoSoderUuT-mU6MQfbnN5GmziYE,7761
|
|
161
|
+
ccproxy/utils/version_checker.py,sha256=D-6a5qV9sPTqkTZHucHZ-xCd8Wdy29lxnVgcvdBs10w,4839
|
|
162
|
+
ccproxy_api-0.1.3.dist-info/METADATA,sha256=yBFMjRfCIDm5YKswyxjLNAGB9q04yTSQQNL_l25deno,12170
|
|
163
|
+
ccproxy_api-0.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
164
|
+
ccproxy_api-0.1.3.dist-info/entry_points.txt,sha256=XLke7uRmx6c1G3Ejnvm74x_eTKKtCgRRSk1dXIBFyg4,128
|
|
165
|
+
ccproxy_api-0.1.3.dist-info/licenses/LICENSE,sha256=httxSCpTrEOkipisMeGXSrZhTB-4MRIorQU0hS1B6eQ,1066
|
|
166
|
+
ccproxy_api-0.1.3.dist-info/RECORD,,
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
"""MCP permission prompt tool for Claude Code SDK."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import Annotated, Any, Optional
|
|
6
|
-
|
|
7
|
-
import typer
|
|
8
|
-
from structlog import get_logger
|
|
9
|
-
|
|
10
|
-
from ccproxy.config.settings import config_manager
|
|
11
|
-
from ccproxy.models.responses import (
|
|
12
|
-
PermissionToolAllowResponse,
|
|
13
|
-
PermissionToolDenyResponse,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
app = typer.Typer(
|
|
18
|
-
rich_markup_mode="rich",
|
|
19
|
-
add_completion=False,
|
|
20
|
-
no_args_is_help=False,
|
|
21
|
-
pretty_exceptions_enable=False,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
logger = get_logger(__name__)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@app.command()
|
|
28
|
-
def permission_tool(
|
|
29
|
-
tool_name: Annotated[
|
|
30
|
-
str, typer.Argument(help="Name of the tool to check permissions for")
|
|
31
|
-
],
|
|
32
|
-
tool_input: Annotated[str, typer.Argument(help="JSON string of the tool input")],
|
|
33
|
-
config: Annotated[
|
|
34
|
-
Path | None,
|
|
35
|
-
typer.Option(
|
|
36
|
-
"--config",
|
|
37
|
-
"-c",
|
|
38
|
-
help="Path to configuration file (TOML, JSON, or YAML)",
|
|
39
|
-
exists=True,
|
|
40
|
-
file_okay=True,
|
|
41
|
-
dir_okay=False,
|
|
42
|
-
readable=True,
|
|
43
|
-
),
|
|
44
|
-
] = None,
|
|
45
|
-
) -> None:
|
|
46
|
-
"""
|
|
47
|
-
MCP permission prompt tool for Claude Code SDK.
|
|
48
|
-
|
|
49
|
-
This tool is used by the Claude Code SDK to check permissions for tool calls.
|
|
50
|
-
It returns a JSON response indicating whether the tool call should be allowed or denied.
|
|
51
|
-
|
|
52
|
-
Response format:
|
|
53
|
-
- Allow: {"behavior": "allow", "updatedInput": {...}}
|
|
54
|
-
- Deny: {"behavior": "deny", "message": "reason"}
|
|
55
|
-
|
|
56
|
-
Examples:
|
|
57
|
-
ccproxy-perm "bash" '{"command": "ls -la"}'
|
|
58
|
-
ccproxy-perm "edit_file" '{"path": "/etc/passwd", "content": "..."}'
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
try:
|
|
62
|
-
# Parse the tool input JSON
|
|
63
|
-
try:
|
|
64
|
-
input_data = json.loads(tool_input)
|
|
65
|
-
except json.JSONDecodeError as e:
|
|
66
|
-
response = PermissionToolDenyResponse(message=f"Invalid JSON input: {e}")
|
|
67
|
-
print(response.model_dump_json(by_alias=True))
|
|
68
|
-
raise typer.Exit(1) from e
|
|
69
|
-
|
|
70
|
-
# Load settings to get permission configuration
|
|
71
|
-
settings = config_manager.load_settings(config_path=config)
|
|
72
|
-
|
|
73
|
-
# Basic permission checking logic
|
|
74
|
-
# This can be extended with more sophisticated rules
|
|
75
|
-
|
|
76
|
-
# Check for potentially dangerous commands
|
|
77
|
-
dangerous_patterns = [
|
|
78
|
-
"rm -rf",
|
|
79
|
-
"sudo",
|
|
80
|
-
"passwd",
|
|
81
|
-
"chmod 777",
|
|
82
|
-
"/etc/passwd",
|
|
83
|
-
"/etc/shadow",
|
|
84
|
-
"format",
|
|
85
|
-
"mkfs",
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
# Convert input to string for pattern matching
|
|
89
|
-
input_str = json.dumps(input_data).lower()
|
|
90
|
-
|
|
91
|
-
# Check for dangerous patterns
|
|
92
|
-
for pattern in dangerous_patterns:
|
|
93
|
-
if pattern in input_str:
|
|
94
|
-
response = PermissionToolDenyResponse(
|
|
95
|
-
message=f"Tool call contains potentially dangerous pattern: {pattern}"
|
|
96
|
-
)
|
|
97
|
-
print(response.model_dump_json(by_alias=True))
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
# Check for specific tool restrictions
|
|
101
|
-
restricted_tools = {"exec", "system", "shell", "subprocess"}
|
|
102
|
-
|
|
103
|
-
if tool_name.lower() in restricted_tools:
|
|
104
|
-
response = PermissionToolDenyResponse(
|
|
105
|
-
message=f"Tool {tool_name} is restricted for security reasons"
|
|
106
|
-
)
|
|
107
|
-
print(response.model_dump_json(by_alias=True))
|
|
108
|
-
return
|
|
109
|
-
|
|
110
|
-
# Allow the tool call with original input
|
|
111
|
-
allow_response = PermissionToolAllowResponse(updated_input=input_data)
|
|
112
|
-
print(allow_response.model_dump_json(by_alias=True))
|
|
113
|
-
|
|
114
|
-
except Exception as e:
|
|
115
|
-
error_response = PermissionToolDenyResponse(
|
|
116
|
-
message=f"Error processing permission request: {e}"
|
|
117
|
-
)
|
|
118
|
-
print(error_response.model_dump_json(by_alias=True))
|
|
119
|
-
raise typer.Exit(1) from e
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def main() -> None:
|
|
123
|
-
"""Entry point for ccproxy-perm command."""
|
|
124
|
-
app()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if __name__ == "__main__":
|
|
128
|
-
main()
|