ccproxy-api 0.1.1__py3-none-any.whl → 0.1.2__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 CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.1.1'
21
- __version_tuple__ = version_tuple = (0, 1, 1)
20
+ __version__ = version = '0.1.2'
21
+ __version_tuple__ = version_tuple = (0, 1, 2)
@@ -22,11 +22,13 @@ SettingsDep = Annotated[Settings, Depends(get_settings)]
22
22
 
23
23
 
24
24
  def get_claude_service(
25
+ settings: SettingsDep,
25
26
  auth_manager: AuthManagerDep,
26
27
  ) -> ClaudeSDKService:
27
28
  """Get Claude SDK service instance.
28
29
 
29
30
  Args:
31
+ settings: Application settings dependency
30
32
  auth_manager: Authentication manager dependency
31
33
 
32
34
  Returns:
@@ -39,6 +41,7 @@ def get_claude_service(
39
41
  return ClaudeSDKService(
40
42
  auth_manager=auth_manager,
41
43
  metrics=metrics,
44
+ settings=settings,
42
45
  )
43
46
 
44
47
 
@@ -109,7 +109,7 @@ class MessageConverter:
109
109
  for block in contents:
110
110
  text_parts.append(MessageConverter.extract_text_from_content(block))
111
111
 
112
- return " ".join(text_parts)
112
+ return "\n".join(text_parts)
113
113
 
114
114
  @staticmethod
115
115
  def convert_to_anthropic_response(
@@ -2,6 +2,7 @@
2
2
 
3
3
  from typing import Any
4
4
 
5
+ from ccproxy.config.settings import Settings
5
6
  from ccproxy.core.async_utils import patched_typing
6
7
 
7
8
 
@@ -14,8 +15,17 @@ class OptionsHandler:
14
15
  Handles creation and management of Claude SDK options.
15
16
  """
16
17
 
17
- @staticmethod
18
+ def __init__(self, settings: Settings | None = None) -> None:
19
+ """
20
+ Initialize options handler.
21
+
22
+ Args:
23
+ settings: Application settings containing default Claude options
24
+ """
25
+ self.settings = settings
26
+
18
27
  def create_options(
28
+ self,
19
29
  model: str,
20
30
  temperature: float | None = None,
21
31
  max_tokens: int | None = None,
@@ -37,6 +47,18 @@ class OptionsHandler:
37
47
  """
38
48
  options = ClaudeCodeOptions(model=model)
39
49
 
50
+ # First apply settings from configuration if available
51
+ if self.settings and self.settings.claude.code_options:
52
+ code_opts = self.settings.claude.code_options
53
+
54
+ # Apply settings from configuration
55
+ for attr_name in dir(code_opts):
56
+ if not attr_name.startswith("_"):
57
+ value = getattr(code_opts, attr_name, None)
58
+ if value is not None and hasattr(options, attr_name):
59
+ setattr(options, attr_name, value)
60
+
61
+ # Then apply API parameters (these override settings)
40
62
  if temperature is not None:
41
63
  options.temperature = temperature # type: ignore[attr-defined]
42
64
 
@@ -2,7 +2,8 @@
2
2
 
3
3
  from .auth import app as auth_app
4
4
  from .config import app as config_app
5
+ from .permission import app as permission_app
5
6
  from .serve import api
6
7
 
7
8
 
8
- __all__ = ["api", "auth_app", "config_app"]
9
+ __all__ = ["api", "auth_app", "config_app", "permission_app"]
@@ -0,0 +1,128 @@
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()
@@ -35,6 +35,7 @@ from ..options.claude_options import (
35
35
  validate_cwd,
36
36
  validate_max_thinking_tokens,
37
37
  validate_max_turns,
38
+ validate_permission_mode,
38
39
  )
39
40
  from ..options.security_options import SecurityOptions, validate_auth_token
40
41
  from ..options.server_options import (
@@ -393,6 +394,15 @@ def api(
393
394
  rich_help_panel="Claude Settings",
394
395
  ),
395
396
  ] = None,
397
+ permission_mode: Annotated[
398
+ str | None,
399
+ typer.Option(
400
+ "--permission-mode",
401
+ help="Permission mode: default, acceptEdits, or bypassPermissions",
402
+ callback=validate_permission_mode,
403
+ rich_help_panel="Claude Settings",
404
+ ),
405
+ ] = None,
396
406
  max_turns: Annotated[
397
407
  int | None,
398
408
  typer.Option(
@@ -411,6 +421,14 @@ def api(
411
421
  rich_help_panel="Claude Settings",
412
422
  ),
413
423
  ] = None,
424
+ permission_prompt_tool_name: Annotated[
425
+ str | None,
426
+ typer.Option(
427
+ "--permission-prompt-tool-name",
428
+ help="Permission prompt tool name",
429
+ rich_help_panel="Claude Settings",
430
+ ),
431
+ ] = None,
414
432
  # Core settings
415
433
  docker: Annotated[
416
434
  bool,
@@ -536,8 +554,10 @@ def api(
536
554
  disallowed_tools=disallowed_tools,
537
555
  claude_cli_path=claude_cli_path,
538
556
  append_system_prompt=append_system_prompt,
557
+ permission_mode=permission_mode,
539
558
  max_turns=max_turns,
540
559
  cwd=cwd,
560
+ permission_prompt_tool_name=permission_prompt_tool_name,
541
561
  )
542
562
 
543
563
  security_options = SecurityOptions(auth_token=auth_token)
@@ -558,7 +578,9 @@ def api(
558
578
  allowed_tools=claude_options.allowed_tools,
559
579
  disallowed_tools=claude_options.disallowed_tools,
560
580
  append_system_prompt=claude_options.append_system_prompt,
581
+ permission_mode=claude_options.permission_mode,
561
582
  max_turns=claude_options.max_turns,
583
+ permission_prompt_tool_name=claude_options.permission_prompt_tool_name,
562
584
  cwd=claude_options.cwd,
563
585
  )
564
586
 
ccproxy/cli/main.py CHANGED
@@ -28,7 +28,7 @@ from ccproxy.core.logging import setup_logging
28
28
 
29
29
  from .commands.auth import app as auth_app
30
30
  from .commands.config import app as config_app
31
- from .commands.serve import api, get_config_path_from_context
31
+ from .commands.serve import api
32
32
 
33
33
 
34
34
  def version_callback(value: bool) -> None:
@@ -32,6 +32,22 @@ def validate_max_turns(
32
32
  return value
33
33
 
34
34
 
35
+ def validate_permission_mode(
36
+ ctx: typer.Context, param: typer.CallbackParam, value: str | None
37
+ ) -> str | None:
38
+ """Validate permission mode."""
39
+ if value is None:
40
+ return None
41
+
42
+ valid_modes = {"default", "acceptEdits", "bypassPermissions"}
43
+ if value not in valid_modes:
44
+ raise typer.BadParameter(
45
+ f"Permission mode must be one of: {', '.join(valid_modes)}"
46
+ )
47
+
48
+ return value
49
+
50
+
35
51
  def validate_claude_cli_path(
36
52
  ctx: typer.Context, param: typer.CallbackParam, value: str | None
37
53
  ) -> str | None:
@@ -79,8 +95,10 @@ class ClaudeOptions:
79
95
  disallowed_tools: str | None = None,
80
96
  claude_cli_path: str | None = None,
81
97
  append_system_prompt: str | None = None,
98
+ permission_mode: str | None = None,
82
99
  max_turns: int | None = None,
83
100
  cwd: str | None = None,
101
+ permission_prompt_tool_name: str | None = None,
84
102
  ):
85
103
  """Initialize Claude options.
86
104
 
@@ -90,13 +108,17 @@ class ClaudeOptions:
90
108
  disallowed_tools: List of disallowed tools (comma-separated)
91
109
  claude_cli_path: Path to Claude CLI executable
92
110
  append_system_prompt: Additional system prompt to append
111
+ permission_mode: Permission mode
93
112
  max_turns: Maximum conversation turns
94
113
  cwd: Working directory path
114
+ permission_prompt_tool_name: Permission prompt tool name
95
115
  """
96
116
  self.max_thinking_tokens = max_thinking_tokens
97
117
  self.allowed_tools = allowed_tools
98
118
  self.disallowed_tools = disallowed_tools
99
119
  self.claude_cli_path = claude_cli_path
100
120
  self.append_system_prompt = append_system_prompt
121
+ self.permission_mode = permission_mode
101
122
  self.max_turns = max_turns
102
123
  self.cwd = cwd
124
+ self.permission_prompt_tool_name = permission_prompt_tool_name
@@ -467,9 +467,11 @@ class ConfigurationManager:
467
467
  claude_opts = {}
468
468
  for key in [
469
469
  "max_thinking_tokens",
470
+ "permission_mode",
470
471
  "cwd",
471
472
  "max_turns",
472
473
  "append_system_prompt",
474
+ "permission_prompt_tool_name",
473
475
  "continue_conversation",
474
476
  ]:
475
477
  if cli_args.get(key) is not None:
@@ -143,6 +143,42 @@ class APIError(BaseModel):
143
143
  )
144
144
 
145
145
 
146
+ class PermissionToolAllowResponse(BaseModel):
147
+ """Response model for allowed permission tool requests."""
148
+
149
+ behavior: Annotated[Literal["allow"], Field(description="Permission behavior")] = (
150
+ "allow"
151
+ )
152
+ updated_input: Annotated[
153
+ dict[str, Any],
154
+ Field(
155
+ description="Updated input parameters for the tool, or original input if unchanged",
156
+ alias="updatedInput",
157
+ ),
158
+ ]
159
+
160
+ model_config = ConfigDict(extra="forbid", populate_by_name=True)
161
+
162
+
163
+ class PermissionToolDenyResponse(BaseModel):
164
+ """Response model for denied permission tool requests."""
165
+
166
+ behavior: Annotated[Literal["deny"], Field(description="Permission behavior")] = (
167
+ "deny"
168
+ )
169
+ message: Annotated[
170
+ str,
171
+ Field(
172
+ description="Human-readable explanation of why the permission was denied"
173
+ ),
174
+ ]
175
+
176
+ model_config = ConfigDict(extra="forbid")
177
+
178
+
179
+ PermissionToolResponse = PermissionToolAllowResponse | PermissionToolDenyResponse
180
+
181
+
146
182
  class RateLimitError(APIError):
147
183
  """Rate limit error."""
148
184
 
@@ -18,6 +18,7 @@ from ccproxy.auth.manager import AuthManager
18
18
  from ccproxy.claude_sdk.client import ClaudeSDKClient
19
19
  from ccproxy.claude_sdk.converter import MessageConverter
20
20
  from ccproxy.claude_sdk.options import OptionsHandler
21
+ from ccproxy.config.settings import Settings
21
22
  from ccproxy.core.errors import (
22
23
  ClaudeProxyError,
23
24
  ServiceUnavailableError,
@@ -44,6 +45,7 @@ class ClaudeSDKService:
44
45
  sdk_client: ClaudeSDKClient | None = None,
45
46
  auth_manager: AuthManager | None = None,
46
47
  metrics: PrometheusMetrics | None = None,
48
+ settings: Settings | None = None,
47
49
  ) -> None:
48
50
  """
49
51
  Initialize Claude SDK service.
@@ -52,12 +54,14 @@ class ClaudeSDKService:
52
54
  sdk_client: Claude SDK client instance
53
55
  auth_manager: Authentication manager (optional)
54
56
  metrics: Prometheus metrics instance (optional)
57
+ settings: Application settings (optional)
55
58
  """
56
59
  self.sdk_client = sdk_client or ClaudeSDKClient()
57
60
  self.auth_manager = auth_manager
58
61
  self.metrics = metrics
62
+ self.settings = settings
59
63
  self.message_converter = MessageConverter()
60
- self.options_handler = OptionsHandler()
64
+ self.options_handler = OptionsHandler(settings=settings)
61
65
 
62
66
  async def create_completion(
63
67
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ccproxy-api
3
- Version: 0.1.1
3
+ Version: 0.1.2
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
@@ -1,6 +1,6 @@
1
1
  ccproxy/__init__.py,sha256=VrtzUTUA8MwpYqFJAiwKLPxRdMRc7UOzFi2VB_1W9qw,62
2
2
  ccproxy/__main__.py,sha256=kcejcfzAaMnFiSxEiVtNl-_TwynpntkupRxqG5XR15s,116
3
- ccproxy/_version.py,sha256=Mmxse1R0ki5tjz9qzU8AQyqUsLt8nTyCAbYQp8R87PU,511
3
+ ccproxy/_version.py,sha256=bSmADqydH8nBu-J4lG8UVuR7hnU_zcwhnSav2oQ0W0A,511
4
4
  ccproxy/adapters/__init__.py,sha256=CMr5MPIFigfazoXfhyD2eLqBrutzaSzBaEi8u2i9xJQ,206
5
5
  ccproxy/adapters/base.py,sha256=aufx8ho9LhF0kmTsCvw1a9K3lk5YyYymJV8h_wt5TpU,2191
6
6
  ccproxy/adapters/openai/__init__.py,sha256=ZBT4y3cHZHrhzsxETOJNDePDT-2rfWwsPOzDKDRZAvY,1125
@@ -9,7 +9,7 @@ ccproxy/adapters/openai/models.py,sha256=tg5NLFmTAOjLd2-gjqRQPU3IkL9ATftXv4ZugGw
9
9
  ccproxy/adapters/openai/streaming.py,sha256=y3GEGWpd_3Pyg4mclR5RB8xWMq7sYj1T4qx8eOLcJTU,15670
10
10
  ccproxy/api/__init__.py,sha256=m3t0z3_agXKDupMjmdFW1pu2_YrOTu6DKi0b1OdR-YM,558
11
11
  ccproxy/api/app.py,sha256=X7pNGqU6pUbuc86K5SMCdiInO54-UkVqfRN_7jCxZLg,10922
12
- ccproxy/api/dependencies.py,sha256=VRYA3A1Az1qglOT55anGr5WdHq4ZapdcqHK5fAMk9oo,4065
12
+ ccproxy/api/dependencies.py,sha256=4n7eO4DV44EHMnkKAthePN4iiprBPP5EvDfiB9ykaUc,4169
13
13
  ccproxy/api/responses.py,sha256=eipdbHLQcrUjBYJd-Q5bEWUoiFlmPiDB0wdySFNubx4,2905
14
14
  ccproxy/api/middleware/__init__.py,sha256=S887PXY40Tnb0IFGei4Sgs7sygkcoT0IEOciOO7IDBc,284
15
15
  ccproxy/api/middleware/auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -42,14 +42,15 @@ ccproxy/auth/storage/json_file.py,sha256=3vOHHIuUrjEQVVMOWJS8GX3EHIvQYeaUuTnlhV7
42
42
  ccproxy/auth/storage/keyring.py,sha256=GS9UZrLEXSZPwGxsik6MiDWRpZoStGs-8o30qE8T4kA,6022
43
43
  ccproxy/claude_sdk/__init__.py,sha256=HezOzX8RaTw5MTYXZu27aaQYLX9x7jrpjZuT1kwJoKc,404
44
44
  ccproxy/claude_sdk/client.py,sha256=L48FJdY3gDSrYXK88tbV5kH6z6HZsjLS_erqdN3OUFA,5500
45
- ccproxy/claude_sdk/converter.py,sha256=FaMnmvwKEuxmi-atr6zZUWLk8ILqlg2_OVPSlBPBxec,11326
46
- ccproxy/claude_sdk/options.py,sha256=IZX4yqGjfNlUUOH3XzUOVMBtgXEvk9r1MFzeeiVZihA,3516
45
+ ccproxy/claude_sdk/converter.py,sha256=u0lHOfltVgcsOBNufsVJzV1CPaSQKMmz43joy5cK3lU,11327
46
+ ccproxy/claude_sdk/options.py,sha256=uvfR_wD2TGUHEN0ar5OFTgLpwznACWOmr38ndN-8Q2Y,4398
47
47
  ccproxy/cli/__init__.py,sha256=_vISKEqzAsAYrTZ-j9ScxTUtFZp3RVRbIvGpCcu--SU,262
48
48
  ccproxy/cli/helpers.py,sha256=cEgEeXP5Qpqq7Jxqy7wagAkJH_w9jPhQACt00IzhDdQ,3874
49
- ccproxy/cli/main.py,sha256=NXxgnMxZpE_rhAtg_lXi_JcTsks2hI9HMBZc6xayxEY,2782
50
- ccproxy/cli/commands/__init__.py,sha256=k6CqHFSM-gbn-tdfjRgTkvwDhCPipZ8-4lbiRn54LPo,185
49
+ ccproxy/cli/main.py,sha256=TO9AyVC1NpXZOMgF1g6yWumqPURdHfeEk0W5yOON9Ac,2752
50
+ ccproxy/cli/commands/__init__.py,sha256=p6X5WO6r7Lik5bAi7GCetEokvTMvRTygjHMHiQe3k3g,249
51
51
  ccproxy/cli/commands/auth.py,sha256=iyRHj0eJ0VpgAqoNUD_jQEOcLvemtBp_Q7oqrBIu-PU,20797
52
- ccproxy/cli/commands/serve.py,sha256=-HhJFv1MJ2qWeldWNUqqwU8SvdffDxLaxCa5IqB4gJs,27449
52
+ ccproxy/cli/commands/permission.py,sha256=FTnthns3rwvMsiX6rXE1vL0pVmQ-hilcEAERb0StozA,3860
53
+ ccproxy/cli/commands/serve.py,sha256=FpXkDja5HSUIf6E8Yzq8WbOeUw3sfWFvRPWhI0NvzJc,28294
53
54
  ccproxy/cli/commands/config/__init__.py,sha256=uX8VewtrMu5X8VAx5ym1slwNtlICDBEs3S1HfoFe5Qo,376
54
55
  ccproxy/cli/commands/config/commands.py,sha256=ukAr55NLFTg67f5czpjbuz_Ap_mwFIMIfMGHeXv_E5c,28917
55
56
  ccproxy/cli/commands/config/schema_commands.py,sha256=ZSuK_Q1bWp8WUOSbkuwKz_4TwrxkRsA6MOt_-y1eiVs,4218
@@ -57,7 +58,7 @@ ccproxy/cli/docker/__init__.py,sha256=4x9QO8SF9aloJFs4xrUEhGcSmoosIYmjcMTk4-GnHB
57
58
  ccproxy/cli/docker/adapter_factory.py,sha256=dbO_MGrrAsyF0DDZMKbrk4oMx2xAMZPihOAviF7D5zY,5022
58
59
  ccproxy/cli/docker/params.py,sha256=2Wjn2WW7Q839QItcLQWQRgFoR8lue3GfikVstBZjTmI,7438
59
60
  ccproxy/cli/options/__init__.py,sha256=OiToWXDNOXnO-fuPz2H5qXYwp9ht7uB12-4wxqner1Q,340
60
- ccproxy/cli/options/claude_options.py,sha256=wnzQVd92jWA3DYM8YptFvpT6gXYVtNhwVy_cO4IkMUU,2911
61
+ ccproxy/cli/options/claude_options.py,sha256=uMWYPjF2LXTrd1UnfA9L7QxjP_6PnvXmbkuE6uD2JCg,3674
61
62
  ccproxy/cli/options/core_options.py,sha256=PGr3fLdPVzX4T6vbMIlpyV-NIiNgbrwX7N9EXe6FHCk,589
62
63
  ccproxy/cli/options/security_options.py,sha256=bSewHc7qldtM8Tsf4rtQ1iw4a8F4ITDnl5DB_2kQFAw,897
63
64
  ccproxy/cli/options/server_options.py,sha256=YsEk_siSdlbjSczeC_1HljzXjE4aK6Yh_JQCPOLYWbk,1722
@@ -74,7 +75,7 @@ ccproxy/config/reverse_proxy.py,sha256=hep4ubV7-4ZgdO1_WqY56b5yrYyHCdQgYayUHKH3t
74
75
  ccproxy/config/scheduler.py,sha256=7WOMJff-e_cHR72PvoJRc3w_Fu_9zPTItPr7vZIaYwM,2498
75
76
  ccproxy/config/security.py,sha256=8e8o2OsYgaOKpZoBcA4qqIcYp3NHYIR0QfM1HNUxvxg,330
76
77
  ccproxy/config/server.py,sha256=L42FUX8uEdVYP-3VP74lfTGVkzQgsv6PEOopEfHDb0U,2317
77
- ccproxy/config/settings.py,sha256=hiY05TGv_CdjhBeDhCv_Cd4BLGcbA8hzu1hrZHtK2Ik,17613
78
+ ccproxy/config/settings.py,sha256=5lNv0IovU6yE7SuHe_o_z43iwwvn_eA0icm7uNGR-rQ,17687
78
79
  ccproxy/config/validators.py,sha256=A1AIwQnpuC-FSDaZDYisgx5RgHRS9pHs1feuKQKQKrk,5771
79
80
  ccproxy/core/__init__.py,sha256=ZreOdlUlCn7R5GlS3EdpvIj5fO9sySbQKnuR8o6vwXI,6400
80
81
  ccproxy/core/async_utils.py,sha256=tWsOXYtCC_zYSzYtTFiu45wG2-1P_6RLNx4yDAkdfgg,19949
@@ -102,7 +103,7 @@ ccproxy/models/__init__.py,sha256=XOkiHVzKuMSL8v0NNdL4WxBKrgeItnCeu9p9yYphQkY,25
102
103
  ccproxy/models/errors.py,sha256=B2rbL-17ZI9emDOca2A2fLOcH1-_77t_xqDmiPf6fgY,1329
103
104
  ccproxy/models/messages.py,sha256=-Zz9E6FFQkvlBq7ldbTl6KTIMCkx5vm2x-bg8CcIeXM,7743
104
105
  ccproxy/models/requests.py,sha256=bhpxN19rvV5gyZPQxriFotJ9rwtMaZF9astMT4qnMz0,2766
105
- ccproxy/models/responses.py,sha256=ogJ-eHibOEvv1KZKLmhs2nWZGy-D0eSFDrzHFU2lRnM,6031
106
+ ccproxy/models/responses.py,sha256=PPZ1ajF8Z9anPbY04krxPnFmj-9lAEEsPgSbaoJePOc,7044
106
107
  ccproxy/models/types.py,sha256=27MUg7pVGrK5oWzcrtG_IAoScEcrF20thO94bxZXQww,2729
107
108
  ccproxy/observability/__init__.py,sha256=5n9yQBbMLAQVAEJZD-2t4CKfI0Wx2aoDH7d2ynPM4bg,1503
108
109
  ccproxy/observability/access_logger.py,sha256=hhP-dgWPmbFhviPqJhrb7AlRcvfF1uONbKlqzDvAvAI,13120
@@ -126,7 +127,7 @@ ccproxy/scheduler/manager.py,sha256=WXREf7nCUqINk5rv--l-xFiecH_qddBfXHe4BhYKDVw,
126
127
  ccproxy/scheduler/registry.py,sha256=E2636J1Pj5G9cqr3UZO4D8hVCzt3cMd8rkanvXLF72M,4062
127
128
  ccproxy/scheduler/tasks.py,sha256=y6FdhkXg7Irgf5CAqXAWlR5j2viZQKuRuG3ydtWpKdc,16058
128
129
  ccproxy/services/__init__.py,sha256=ZvnelD15eFLlWHsucYXBFGNrdT7ncdP1KLnqzJNGOCs,251
129
- ccproxy/services/claude_sdk_service.py,sha256=m1T7tJAVfxI-vV2U1zsTPv1AtDHHfh9PE6ld_w_nPos,22086
130
+ ccproxy/services/claude_sdk_service.py,sha256=6lqygBZvLmRNJgfOgZFZaeKcIUDskiclUCFsKEdbUqU,22277
130
131
  ccproxy/services/proxy_service.py,sha256=OPZRgq-jgq2pP3ZuOZ6VjSBv-mxgSZa5bcCsgPYTAwU,59244
131
132
  ccproxy/services/credentials/__init__.py,sha256=fkCWqxlUyGVA1mxGicn4cvdbYJQo09SG9NoGKzUun3s,1394
132
133
  ccproxy/services/credentials/config.py,sha256=97W3GqtxZlBv45oDHJ-plsHiSeFvNI-FTMZEw4CsPes,3221
@@ -142,8 +143,8 @@ ccproxy/testing/scenarios.py,sha256=lVTkf1TbqPnWAfY2VbXez6dSFHsohuXerDmh37iC5VU,
142
143
  ccproxy/utils/__init__.py,sha256=MBEWNgdZh4Ev-LcltUhkMBboR1QHYNeri3oOy1KQeDo,213
143
144
  ccproxy/utils/cost_calculator.py,sha256=mHquyA_1vnPVZ2smjdPwThCJtGu-rF9n8ZvIrAwTF78,7276
144
145
  ccproxy/utils/streaming_metrics.py,sha256=JkvmWJ9s1fuKi7x1NoSoderUuT-mU6MQfbnN5GmziYE,7761
145
- ccproxy_api-0.1.1.dist-info/METADATA,sha256=18zB0NzAh42NdEqQ_M0SbXvgZP3Vacv6WgkNJbLioTI,9793
146
- ccproxy_api-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
147
- ccproxy_api-0.1.1.dist-info/entry_points.txt,sha256=oFWrKNvRUIGJkbP_8cTkv6zWOh74Rw_81RCYeLWT6kQ,76
148
- ccproxy_api-0.1.1.dist-info/licenses/LICENSE,sha256=httxSCpTrEOkipisMeGXSrZhTB-4MRIorQU0hS1B6eQ,1066
149
- ccproxy_api-0.1.1.dist-info/RECORD,,
146
+ ccproxy_api-0.1.2.dist-info/METADATA,sha256=mb6SGhFGTP38JayodrZMZHoZX4gN_KHFiitHMPFJ1v8,9793
147
+ ccproxy_api-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
148
+ ccproxy_api-0.1.2.dist-info/entry_points.txt,sha256=XLke7uRmx6c1G3Ejnvm74x_eTKKtCgRRSk1dXIBFyg4,128
149
+ ccproxy_api-0.1.2.dist-info/licenses/LICENSE,sha256=httxSCpTrEOkipisMeGXSrZhTB-4MRIorQU0hS1B6eQ,1066
150
+ ccproxy_api-0.1.2.dist-info/RECORD,,
@@ -1,3 +1,4 @@
1
1
  [console_scripts]
2
2
  ccproxy = ccproxy.cli:main
3
3
  ccproxy-api = ccproxy.cli:main
4
+ ccproxy-perm = ccproxy.cli.commands.permission:main