ccproxy-api 0.1.6__py3-none-any.whl → 0.2.0__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/api/__init__.py +1 -15
- ccproxy/api/app.py +439 -212
- ccproxy/api/bootstrap.py +30 -0
- ccproxy/api/decorators.py +85 -0
- ccproxy/api/dependencies.py +145 -176
- ccproxy/api/format_validation.py +54 -0
- ccproxy/api/middleware/cors.py +6 -3
- ccproxy/api/middleware/errors.py +402 -530
- ccproxy/api/middleware/hooks.py +563 -0
- ccproxy/api/middleware/normalize_headers.py +59 -0
- ccproxy/api/middleware/request_id.py +35 -16
- ccproxy/api/middleware/streaming_hooks.py +292 -0
- ccproxy/api/routes/__init__.py +5 -14
- ccproxy/api/routes/health.py +39 -672
- ccproxy/api/routes/plugins.py +277 -0
- ccproxy/auth/__init__.py +2 -19
- ccproxy/auth/bearer.py +25 -15
- ccproxy/auth/dependencies.py +123 -157
- ccproxy/auth/exceptions.py +0 -12
- ccproxy/auth/manager.py +35 -49
- ccproxy/auth/managers/__init__.py +10 -0
- ccproxy/auth/managers/base.py +523 -0
- ccproxy/auth/managers/base_enhanced.py +63 -0
- ccproxy/auth/managers/token_snapshot.py +77 -0
- ccproxy/auth/models/base.py +65 -0
- ccproxy/auth/models/credentials.py +40 -0
- ccproxy/auth/oauth/__init__.py +4 -18
- ccproxy/auth/oauth/base.py +533 -0
- ccproxy/auth/oauth/cli_errors.py +37 -0
- ccproxy/auth/oauth/flows.py +430 -0
- ccproxy/auth/oauth/protocol.py +366 -0
- ccproxy/auth/oauth/registry.py +408 -0
- ccproxy/auth/oauth/router.py +396 -0
- ccproxy/auth/oauth/routes.py +186 -113
- ccproxy/auth/oauth/session.py +151 -0
- ccproxy/auth/oauth/templates.py +342 -0
- ccproxy/auth/storage/__init__.py +2 -5
- ccproxy/auth/storage/base.py +279 -5
- ccproxy/auth/storage/generic.py +134 -0
- ccproxy/cli/__init__.py +1 -2
- ccproxy/cli/_settings_help.py +351 -0
- ccproxy/cli/commands/auth.py +1519 -793
- ccproxy/cli/commands/config/commands.py +209 -276
- ccproxy/cli/commands/plugins.py +669 -0
- ccproxy/cli/commands/serve.py +75 -810
- ccproxy/cli/commands/status.py +254 -0
- ccproxy/cli/decorators.py +83 -0
- ccproxy/cli/helpers.py +22 -60
- ccproxy/cli/main.py +359 -10
- ccproxy/cli/options/claude_options.py +0 -25
- ccproxy/config/__init__.py +7 -11
- ccproxy/config/core.py +227 -0
- ccproxy/config/env_generator.py +232 -0
- ccproxy/config/runtime.py +67 -0
- ccproxy/config/security.py +36 -3
- ccproxy/config/settings.py +382 -441
- ccproxy/config/toml_generator.py +299 -0
- ccproxy/config/utils.py +452 -0
- ccproxy/core/__init__.py +7 -271
- ccproxy/{_version.py → core/_version.py} +16 -3
- ccproxy/core/async_task_manager.py +516 -0
- ccproxy/core/async_utils.py +47 -14
- ccproxy/core/auth/__init__.py +6 -0
- ccproxy/core/constants.py +16 -50
- ccproxy/core/errors.py +53 -0
- ccproxy/core/id_utils.py +20 -0
- ccproxy/core/interfaces.py +16 -123
- ccproxy/core/logging.py +473 -18
- ccproxy/core/plugins/__init__.py +77 -0
- ccproxy/core/plugins/cli_discovery.py +211 -0
- ccproxy/core/plugins/declaration.py +455 -0
- ccproxy/core/plugins/discovery.py +604 -0
- ccproxy/core/plugins/factories.py +967 -0
- ccproxy/core/plugins/hooks/__init__.py +30 -0
- ccproxy/core/plugins/hooks/base.py +58 -0
- ccproxy/core/plugins/hooks/events.py +46 -0
- ccproxy/core/plugins/hooks/implementations/__init__.py +16 -0
- ccproxy/core/plugins/hooks/implementations/formatters/__init__.py +11 -0
- ccproxy/core/plugins/hooks/implementations/formatters/json.py +552 -0
- ccproxy/core/plugins/hooks/implementations/formatters/raw.py +370 -0
- ccproxy/core/plugins/hooks/implementations/http_tracer.py +431 -0
- ccproxy/core/plugins/hooks/layers.py +44 -0
- ccproxy/core/plugins/hooks/manager.py +186 -0
- ccproxy/core/plugins/hooks/registry.py +139 -0
- ccproxy/core/plugins/hooks/thread_manager.py +203 -0
- ccproxy/core/plugins/hooks/types.py +22 -0
- ccproxy/core/plugins/interfaces.py +416 -0
- ccproxy/core/plugins/loader.py +166 -0
- ccproxy/core/plugins/middleware.py +233 -0
- ccproxy/core/plugins/models.py +59 -0
- ccproxy/core/plugins/protocol.py +180 -0
- ccproxy/core/plugins/runtime.py +519 -0
- ccproxy/{observability/context.py → core/request_context.py} +137 -94
- ccproxy/core/status_report.py +211 -0
- ccproxy/core/transformers.py +13 -8
- ccproxy/data/claude_headers_fallback.json +558 -0
- ccproxy/data/codex_headers_fallback.json +121 -0
- ccproxy/http/__init__.py +30 -0
- ccproxy/http/base.py +95 -0
- ccproxy/http/client.py +323 -0
- ccproxy/http/hooks.py +642 -0
- ccproxy/http/pool.py +279 -0
- ccproxy/llms/formatters/__init__.py +7 -0
- ccproxy/llms/formatters/anthropic_to_openai/__init__.py +55 -0
- ccproxy/llms/formatters/anthropic_to_openai/errors.py +65 -0
- ccproxy/llms/formatters/anthropic_to_openai/requests.py +356 -0
- ccproxy/llms/formatters/anthropic_to_openai/responses.py +153 -0
- ccproxy/llms/formatters/anthropic_to_openai/streams.py +1546 -0
- ccproxy/llms/formatters/base.py +140 -0
- ccproxy/llms/formatters/base_model.py +33 -0
- ccproxy/llms/formatters/common/__init__.py +51 -0
- ccproxy/llms/formatters/common/identifiers.py +48 -0
- ccproxy/llms/formatters/common/streams.py +254 -0
- ccproxy/llms/formatters/common/thinking.py +74 -0
- ccproxy/llms/formatters/common/usage.py +135 -0
- ccproxy/llms/formatters/constants.py +55 -0
- ccproxy/llms/formatters/context.py +116 -0
- ccproxy/llms/formatters/mapping.py +33 -0
- ccproxy/llms/formatters/openai_to_anthropic/__init__.py +55 -0
- ccproxy/llms/formatters/openai_to_anthropic/_helpers.py +141 -0
- ccproxy/llms/formatters/openai_to_anthropic/errors.py +53 -0
- ccproxy/llms/formatters/openai_to_anthropic/requests.py +674 -0
- ccproxy/llms/formatters/openai_to_anthropic/responses.py +285 -0
- ccproxy/llms/formatters/openai_to_anthropic/streams.py +530 -0
- ccproxy/llms/formatters/openai_to_openai/__init__.py +53 -0
- ccproxy/llms/formatters/openai_to_openai/_helpers.py +325 -0
- ccproxy/llms/formatters/openai_to_openai/errors.py +6 -0
- ccproxy/llms/formatters/openai_to_openai/requests.py +388 -0
- ccproxy/llms/formatters/openai_to_openai/responses.py +594 -0
- ccproxy/llms/formatters/openai_to_openai/streams.py +1832 -0
- ccproxy/llms/formatters/utils.py +306 -0
- ccproxy/llms/models/__init__.py +9 -0
- ccproxy/llms/models/anthropic.py +619 -0
- ccproxy/llms/models/openai.py +844 -0
- ccproxy/llms/streaming/__init__.py +26 -0
- ccproxy/llms/streaming/accumulators.py +1074 -0
- ccproxy/llms/streaming/formatters.py +251 -0
- ccproxy/{adapters/openai/streaming.py → llms/streaming/processors.py} +193 -240
- ccproxy/models/__init__.py +8 -159
- ccproxy/models/detection.py +92 -193
- ccproxy/models/provider.py +75 -0
- ccproxy/plugins/access_log/README.md +32 -0
- ccproxy/plugins/access_log/__init__.py +20 -0
- ccproxy/plugins/access_log/config.py +33 -0
- ccproxy/plugins/access_log/formatter.py +126 -0
- ccproxy/plugins/access_log/hook.py +763 -0
- ccproxy/plugins/access_log/logger.py +254 -0
- ccproxy/plugins/access_log/plugin.py +137 -0
- ccproxy/plugins/access_log/writer.py +109 -0
- ccproxy/plugins/analytics/README.md +24 -0
- ccproxy/plugins/analytics/__init__.py +1 -0
- ccproxy/plugins/analytics/config.py +5 -0
- ccproxy/plugins/analytics/ingest.py +85 -0
- ccproxy/plugins/analytics/models.py +97 -0
- ccproxy/plugins/analytics/plugin.py +121 -0
- ccproxy/plugins/analytics/routes.py +163 -0
- ccproxy/plugins/analytics/service.py +284 -0
- ccproxy/plugins/claude_api/README.md +29 -0
- ccproxy/plugins/claude_api/__init__.py +10 -0
- ccproxy/plugins/claude_api/adapter.py +829 -0
- ccproxy/plugins/claude_api/config.py +52 -0
- ccproxy/plugins/claude_api/detection_service.py +461 -0
- ccproxy/plugins/claude_api/health.py +175 -0
- ccproxy/plugins/claude_api/hooks.py +284 -0
- ccproxy/plugins/claude_api/models.py +256 -0
- ccproxy/plugins/claude_api/plugin.py +298 -0
- ccproxy/plugins/claude_api/routes.py +118 -0
- ccproxy/plugins/claude_api/streaming_metrics.py +68 -0
- ccproxy/plugins/claude_api/tasks.py +84 -0
- ccproxy/plugins/claude_sdk/README.md +35 -0
- ccproxy/plugins/claude_sdk/__init__.py +80 -0
- ccproxy/plugins/claude_sdk/adapter.py +749 -0
- ccproxy/plugins/claude_sdk/auth.py +57 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/client.py +63 -39
- ccproxy/plugins/claude_sdk/config.py +210 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/converter.py +6 -6
- ccproxy/plugins/claude_sdk/detection_service.py +163 -0
- ccproxy/{services/claude_sdk_service.py → plugins/claude_sdk/handler.py} +123 -304
- ccproxy/plugins/claude_sdk/health.py +113 -0
- ccproxy/plugins/claude_sdk/hooks.py +115 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/manager.py +42 -32
- ccproxy/{claude_sdk → plugins/claude_sdk}/message_queue.py +8 -8
- ccproxy/{models/claude_sdk.py → plugins/claude_sdk/models.py} +64 -16
- ccproxy/plugins/claude_sdk/options.py +154 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/parser.py +23 -5
- ccproxy/plugins/claude_sdk/plugin.py +269 -0
- ccproxy/plugins/claude_sdk/routes.py +104 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/session_client.py +124 -12
- ccproxy/plugins/claude_sdk/session_pool.py +700 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_handle.py +48 -43
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_worker.py +22 -18
- ccproxy/{claude_sdk → plugins/claude_sdk}/streaming.py +50 -16
- ccproxy/plugins/claude_sdk/tasks.py +97 -0
- ccproxy/plugins/claude_shared/README.md +18 -0
- ccproxy/plugins/claude_shared/__init__.py +12 -0
- ccproxy/plugins/claude_shared/model_defaults.py +171 -0
- ccproxy/plugins/codex/README.md +35 -0
- ccproxy/plugins/codex/__init__.py +6 -0
- ccproxy/plugins/codex/adapter.py +635 -0
- ccproxy/{config/codex.py → plugins/codex/config.py} +78 -12
- ccproxy/plugins/codex/detection_service.py +544 -0
- ccproxy/plugins/codex/health.py +162 -0
- ccproxy/plugins/codex/hooks.py +263 -0
- ccproxy/plugins/codex/model_defaults.py +39 -0
- ccproxy/plugins/codex/models.py +263 -0
- ccproxy/plugins/codex/plugin.py +275 -0
- ccproxy/plugins/codex/routes.py +129 -0
- ccproxy/plugins/codex/streaming_metrics.py +324 -0
- ccproxy/plugins/codex/tasks.py +106 -0
- ccproxy/plugins/codex/utils/__init__.py +1 -0
- ccproxy/plugins/codex/utils/sse_parser.py +106 -0
- ccproxy/plugins/command_replay/README.md +34 -0
- ccproxy/plugins/command_replay/__init__.py +17 -0
- ccproxy/plugins/command_replay/config.py +133 -0
- ccproxy/plugins/command_replay/formatter.py +432 -0
- ccproxy/plugins/command_replay/hook.py +294 -0
- ccproxy/plugins/command_replay/plugin.py +161 -0
- ccproxy/plugins/copilot/README.md +39 -0
- ccproxy/plugins/copilot/__init__.py +11 -0
- ccproxy/plugins/copilot/adapter.py +465 -0
- ccproxy/plugins/copilot/config.py +155 -0
- ccproxy/plugins/copilot/data/copilot_fallback.json +41 -0
- ccproxy/plugins/copilot/detection_service.py +255 -0
- ccproxy/plugins/copilot/manager.py +275 -0
- ccproxy/plugins/copilot/model_defaults.py +284 -0
- ccproxy/plugins/copilot/models.py +148 -0
- ccproxy/plugins/copilot/oauth/__init__.py +16 -0
- ccproxy/plugins/copilot/oauth/client.py +494 -0
- ccproxy/plugins/copilot/oauth/models.py +385 -0
- ccproxy/plugins/copilot/oauth/provider.py +602 -0
- ccproxy/plugins/copilot/oauth/storage.py +170 -0
- ccproxy/plugins/copilot/plugin.py +360 -0
- ccproxy/plugins/copilot/routes.py +294 -0
- ccproxy/plugins/credential_balancer/README.md +124 -0
- ccproxy/plugins/credential_balancer/__init__.py +6 -0
- ccproxy/plugins/credential_balancer/config.py +270 -0
- ccproxy/plugins/credential_balancer/factory.py +415 -0
- ccproxy/plugins/credential_balancer/hook.py +51 -0
- ccproxy/plugins/credential_balancer/manager.py +587 -0
- ccproxy/plugins/credential_balancer/plugin.py +146 -0
- ccproxy/plugins/dashboard/README.md +25 -0
- ccproxy/plugins/dashboard/__init__.py +1 -0
- ccproxy/plugins/dashboard/config.py +8 -0
- ccproxy/plugins/dashboard/plugin.py +71 -0
- ccproxy/plugins/dashboard/routes.py +67 -0
- ccproxy/plugins/docker/README.md +32 -0
- ccproxy/{docker → plugins/docker}/__init__.py +3 -0
- ccproxy/{docker → plugins/docker}/adapter.py +108 -10
- ccproxy/plugins/docker/config.py +82 -0
- ccproxy/{docker → plugins/docker}/docker_path.py +4 -3
- ccproxy/{docker → plugins/docker}/middleware.py +2 -2
- ccproxy/plugins/docker/plugin.py +198 -0
- ccproxy/{docker → plugins/docker}/stream_process.py +3 -3
- ccproxy/plugins/duckdb_storage/README.md +26 -0
- ccproxy/plugins/duckdb_storage/__init__.py +1 -0
- ccproxy/plugins/duckdb_storage/config.py +22 -0
- ccproxy/plugins/duckdb_storage/plugin.py +128 -0
- ccproxy/plugins/duckdb_storage/routes.py +51 -0
- ccproxy/plugins/duckdb_storage/storage.py +633 -0
- ccproxy/plugins/max_tokens/README.md +38 -0
- ccproxy/plugins/max_tokens/__init__.py +12 -0
- ccproxy/plugins/max_tokens/adapter.py +235 -0
- ccproxy/plugins/max_tokens/config.py +86 -0
- ccproxy/plugins/max_tokens/models.py +53 -0
- ccproxy/plugins/max_tokens/plugin.py +200 -0
- ccproxy/plugins/max_tokens/service.py +271 -0
- ccproxy/plugins/max_tokens/token_limits.json +54 -0
- ccproxy/plugins/metrics/README.md +35 -0
- ccproxy/plugins/metrics/__init__.py +10 -0
- ccproxy/{observability/metrics.py → plugins/metrics/collector.py} +20 -153
- ccproxy/plugins/metrics/config.py +85 -0
- ccproxy/plugins/metrics/grafana/dashboards/ccproxy-dashboard.json +1720 -0
- ccproxy/plugins/metrics/hook.py +403 -0
- ccproxy/plugins/metrics/plugin.py +268 -0
- ccproxy/{observability → plugins/metrics}/pushgateway.py +57 -59
- ccproxy/plugins/metrics/routes.py +107 -0
- ccproxy/plugins/metrics/tasks.py +117 -0
- ccproxy/plugins/oauth_claude/README.md +35 -0
- ccproxy/plugins/oauth_claude/__init__.py +14 -0
- ccproxy/plugins/oauth_claude/client.py +270 -0
- ccproxy/plugins/oauth_claude/config.py +84 -0
- ccproxy/plugins/oauth_claude/manager.py +482 -0
- ccproxy/plugins/oauth_claude/models.py +266 -0
- ccproxy/plugins/oauth_claude/plugin.py +149 -0
- ccproxy/plugins/oauth_claude/provider.py +571 -0
- ccproxy/plugins/oauth_claude/storage.py +212 -0
- ccproxy/plugins/oauth_codex/README.md +38 -0
- ccproxy/plugins/oauth_codex/__init__.py +14 -0
- ccproxy/plugins/oauth_codex/client.py +224 -0
- ccproxy/plugins/oauth_codex/config.py +95 -0
- ccproxy/plugins/oauth_codex/manager.py +256 -0
- ccproxy/plugins/oauth_codex/models.py +239 -0
- ccproxy/plugins/oauth_codex/plugin.py +146 -0
- ccproxy/plugins/oauth_codex/provider.py +574 -0
- ccproxy/plugins/oauth_codex/storage.py +92 -0
- ccproxy/plugins/permissions/README.md +28 -0
- ccproxy/plugins/permissions/__init__.py +22 -0
- ccproxy/plugins/permissions/config.py +28 -0
- ccproxy/{cli/commands/permission_handler.py → plugins/permissions/handlers/cli.py} +49 -25
- ccproxy/plugins/permissions/handlers/protocol.py +33 -0
- ccproxy/plugins/permissions/handlers/terminal.py +675 -0
- ccproxy/{api/routes → plugins/permissions}/mcp.py +34 -7
- ccproxy/{models/permissions.py → plugins/permissions/models.py} +65 -1
- ccproxy/plugins/permissions/plugin.py +153 -0
- ccproxy/{api/routes/permissions.py → plugins/permissions/routes.py} +20 -16
- ccproxy/{api/services/permission_service.py → plugins/permissions/service.py} +65 -11
- ccproxy/{api → plugins/permissions}/ui/permission_handler_protocol.py +1 -1
- ccproxy/{api → plugins/permissions}/ui/terminal_permission_handler.py +66 -10
- ccproxy/plugins/pricing/README.md +34 -0
- ccproxy/plugins/pricing/__init__.py +6 -0
- ccproxy/{pricing → plugins/pricing}/cache.py +7 -6
- ccproxy/{config/pricing.py → plugins/pricing/config.py} +32 -6
- ccproxy/plugins/pricing/exceptions.py +35 -0
- ccproxy/plugins/pricing/loader.py +440 -0
- ccproxy/{pricing → plugins/pricing}/models.py +13 -23
- ccproxy/plugins/pricing/plugin.py +169 -0
- ccproxy/plugins/pricing/service.py +191 -0
- ccproxy/plugins/pricing/tasks.py +300 -0
- ccproxy/{pricing → plugins/pricing}/updater.py +86 -72
- ccproxy/plugins/pricing/utils.py +99 -0
- ccproxy/plugins/request_tracer/README.md +40 -0
- ccproxy/plugins/request_tracer/__init__.py +7 -0
- ccproxy/plugins/request_tracer/config.py +120 -0
- ccproxy/plugins/request_tracer/hook.py +415 -0
- ccproxy/plugins/request_tracer/plugin.py +255 -0
- ccproxy/scheduler/__init__.py +2 -14
- ccproxy/scheduler/core.py +26 -41
- ccproxy/scheduler/manager.py +63 -107
- ccproxy/scheduler/registry.py +6 -32
- ccproxy/scheduler/tasks.py +346 -314
- ccproxy/services/__init__.py +0 -1
- ccproxy/services/adapters/__init__.py +11 -0
- ccproxy/services/adapters/base.py +123 -0
- ccproxy/services/adapters/chain_composer.py +88 -0
- ccproxy/services/adapters/chain_validation.py +44 -0
- ccproxy/services/adapters/chat_accumulator.py +200 -0
- ccproxy/services/adapters/delta_utils.py +142 -0
- ccproxy/services/adapters/format_adapter.py +136 -0
- ccproxy/services/adapters/format_context.py +11 -0
- ccproxy/services/adapters/format_registry.py +158 -0
- ccproxy/services/adapters/http_adapter.py +1045 -0
- ccproxy/services/adapters/mock_adapter.py +118 -0
- ccproxy/services/adapters/protocols.py +35 -0
- ccproxy/services/adapters/simple_converters.py +571 -0
- ccproxy/services/auth_registry.py +180 -0
- ccproxy/services/cache/__init__.py +6 -0
- ccproxy/services/cache/response_cache.py +261 -0
- ccproxy/services/cli_detection.py +437 -0
- ccproxy/services/config/__init__.py +6 -0
- ccproxy/services/config/proxy_configuration.py +111 -0
- ccproxy/services/container.py +256 -0
- ccproxy/services/factories.py +380 -0
- ccproxy/services/handler_config.py +76 -0
- ccproxy/services/interfaces.py +298 -0
- ccproxy/services/mocking/__init__.py +6 -0
- ccproxy/services/mocking/mock_handler.py +291 -0
- ccproxy/services/tracing/__init__.py +7 -0
- ccproxy/services/tracing/interfaces.py +61 -0
- ccproxy/services/tracing/null_tracer.py +57 -0
- ccproxy/streaming/__init__.py +23 -0
- ccproxy/streaming/buffer.py +1056 -0
- ccproxy/streaming/deferred.py +897 -0
- ccproxy/streaming/handler.py +117 -0
- ccproxy/streaming/interfaces.py +77 -0
- ccproxy/streaming/simple_adapter.py +39 -0
- ccproxy/streaming/sse.py +109 -0
- ccproxy/streaming/sse_parser.py +127 -0
- ccproxy/templates/__init__.py +6 -0
- ccproxy/templates/plugin_scaffold.py +695 -0
- ccproxy/testing/endpoints/__init__.py +33 -0
- ccproxy/testing/endpoints/cli.py +215 -0
- ccproxy/testing/endpoints/config.py +874 -0
- ccproxy/testing/endpoints/console.py +57 -0
- ccproxy/testing/endpoints/models.py +100 -0
- ccproxy/testing/endpoints/runner.py +1903 -0
- ccproxy/testing/endpoints/tools.py +308 -0
- ccproxy/testing/mock_responses.py +70 -1
- ccproxy/testing/response_handlers.py +20 -0
- ccproxy/utils/__init__.py +0 -6
- ccproxy/utils/binary_resolver.py +476 -0
- ccproxy/utils/caching.py +327 -0
- ccproxy/utils/cli_logging.py +101 -0
- ccproxy/utils/command_line.py +251 -0
- ccproxy/utils/headers.py +228 -0
- ccproxy/utils/model_mapper.py +120 -0
- ccproxy/utils/startup_helpers.py +95 -342
- ccproxy/utils/version_checker.py +279 -6
- ccproxy_api-0.2.0.dist-info/METADATA +212 -0
- ccproxy_api-0.2.0.dist-info/RECORD +417 -0
- {ccproxy_api-0.1.6.dist-info → ccproxy_api-0.2.0.dist-info}/WHEEL +1 -1
- ccproxy_api-0.2.0.dist-info/entry_points.txt +24 -0
- ccproxy/__init__.py +0 -4
- ccproxy/adapters/__init__.py +0 -11
- ccproxy/adapters/base.py +0 -80
- ccproxy/adapters/codex/__init__.py +0 -11
- ccproxy/adapters/openai/__init__.py +0 -42
- ccproxy/adapters/openai/adapter.py +0 -953
- ccproxy/adapters/openai/models.py +0 -412
- ccproxy/adapters/openai/response_adapter.py +0 -355
- ccproxy/adapters/openai/response_models.py +0 -178
- ccproxy/api/middleware/headers.py +0 -49
- ccproxy/api/middleware/logging.py +0 -180
- ccproxy/api/middleware/request_content_logging.py +0 -297
- ccproxy/api/middleware/server_header.py +0 -58
- ccproxy/api/responses.py +0 -89
- ccproxy/api/routes/claude.py +0 -371
- ccproxy/api/routes/codex.py +0 -1231
- ccproxy/api/routes/metrics.py +0 -1029
- ccproxy/api/routes/proxy.py +0 -211
- ccproxy/api/services/__init__.py +0 -6
- ccproxy/auth/conditional.py +0 -84
- ccproxy/auth/credentials_adapter.py +0 -93
- ccproxy/auth/models.py +0 -118
- ccproxy/auth/oauth/models.py +0 -48
- ccproxy/auth/openai/__init__.py +0 -13
- ccproxy/auth/openai/credentials.py +0 -166
- ccproxy/auth/openai/oauth_client.py +0 -334
- ccproxy/auth/openai/storage.py +0 -184
- ccproxy/auth/storage/json_file.py +0 -158
- ccproxy/auth/storage/keyring.py +0 -189
- ccproxy/claude_sdk/__init__.py +0 -18
- ccproxy/claude_sdk/options.py +0 -194
- ccproxy/claude_sdk/session_pool.py +0 -550
- ccproxy/cli/docker/__init__.py +0 -34
- ccproxy/cli/docker/adapter_factory.py +0 -157
- ccproxy/cli/docker/params.py +0 -274
- ccproxy/config/auth.py +0 -153
- ccproxy/config/claude.py +0 -348
- ccproxy/config/cors.py +0 -79
- ccproxy/config/discovery.py +0 -95
- ccproxy/config/docker_settings.py +0 -264
- ccproxy/config/observability.py +0 -158
- ccproxy/config/reverse_proxy.py +0 -31
- ccproxy/config/scheduler.py +0 -108
- ccproxy/config/server.py +0 -86
- ccproxy/config/validators.py +0 -231
- ccproxy/core/codex_transformers.py +0 -389
- ccproxy/core/http.py +0 -328
- ccproxy/core/http_transformers.py +0 -812
- ccproxy/core/proxy.py +0 -143
- ccproxy/core/validators.py +0 -288
- ccproxy/models/errors.py +0 -42
- ccproxy/models/messages.py +0 -269
- ccproxy/models/requests.py +0 -107
- ccproxy/models/responses.py +0 -270
- ccproxy/models/types.py +0 -102
- ccproxy/observability/__init__.py +0 -51
- ccproxy/observability/access_logger.py +0 -457
- ccproxy/observability/sse_events.py +0 -303
- ccproxy/observability/stats_printer.py +0 -753
- ccproxy/observability/storage/__init__.py +0 -1
- ccproxy/observability/storage/duckdb_simple.py +0 -677
- ccproxy/observability/storage/models.py +0 -70
- ccproxy/observability/streaming_response.py +0 -107
- ccproxy/pricing/__init__.py +0 -19
- ccproxy/pricing/loader.py +0 -251
- ccproxy/services/claude_detection_service.py +0 -269
- ccproxy/services/codex_detection_service.py +0 -263
- ccproxy/services/credentials/__init__.py +0 -55
- ccproxy/services/credentials/config.py +0 -105
- ccproxy/services/credentials/manager.py +0 -561
- ccproxy/services/credentials/oauth_client.py +0 -481
- ccproxy/services/proxy_service.py +0 -1827
- ccproxy/static/.keep +0 -0
- ccproxy/utils/cost_calculator.py +0 -210
- ccproxy/utils/disconnection_monitor.py +0 -83
- ccproxy/utils/model_mapping.py +0 -199
- ccproxy/utils/models_provider.py +0 -150
- ccproxy/utils/simple_request_logger.py +0 -284
- ccproxy/utils/streaming_metrics.py +0 -199
- ccproxy_api-0.1.6.dist-info/METADATA +0 -615
- ccproxy_api-0.1.6.dist-info/RECORD +0 -189
- ccproxy_api-0.1.6.dist-info/entry_points.txt +0 -4
- /ccproxy/{api/middleware/auth.py → auth/models/__init__.py} +0 -0
- /ccproxy/{claude_sdk → plugins/claude_sdk}/exceptions.py +0 -0
- /ccproxy/{docker → plugins/docker}/models.py +0 -0
- /ccproxy/{docker → plugins/docker}/protocol.py +0 -0
- /ccproxy/{docker → plugins/docker}/validators.py +0 -0
- /ccproxy/{auth/oauth/storage.py → plugins/permissions/handlers/__init__.py} +0 -0
- /ccproxy/{api → plugins/permissions}/ui/__init__.py +0 -0
- {ccproxy_api-0.1.6.dist-info → ccproxy_api-0.2.0.dist-info}/licenses/LICENSE +0 -0
ccproxy/cli/main.py
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
"""Main entry point for CCProxy API Server.
|
|
1
|
+
"""Main entry point for CCProxy API Server.
|
|
2
2
|
|
|
3
|
+
Adds per-invocation debug logging of CLI argv and relevant environment
|
|
4
|
+
variables (masked) so every command emits its context consistently.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
3
9
|
from pathlib import Path
|
|
4
|
-
from typing import Annotated
|
|
10
|
+
from typing import Annotated, Any, cast
|
|
5
11
|
|
|
6
12
|
import typer
|
|
7
|
-
from structlog import get_logger
|
|
8
13
|
|
|
9
|
-
from ccproxy._version import __version__
|
|
10
14
|
from ccproxy.cli.helpers import (
|
|
11
15
|
get_rich_toolkit,
|
|
12
16
|
)
|
|
17
|
+
from ccproxy.core._version import __version__
|
|
18
|
+
from ccproxy.core.logging import bootstrap_cli_logging, get_logger, set_command_context
|
|
19
|
+
from ccproxy.core.plugins.cli_discovery import discover_plugin_cli_extensions
|
|
20
|
+
from ccproxy.core.plugins.declaration import CliArgumentSpec, CliCommandSpec
|
|
13
21
|
|
|
22
|
+
# from plugins.permissions.handlers.cli import app as permission_handler_app
|
|
14
23
|
from .commands.auth import app as auth_app
|
|
15
24
|
from .commands.config import app as config_app
|
|
16
|
-
from .commands.
|
|
25
|
+
from .commands.plugins import app as plugins_app
|
|
17
26
|
from .commands.serve import api
|
|
27
|
+
from .commands.status import app as status_app
|
|
18
28
|
|
|
19
29
|
|
|
20
30
|
def version_callback(value: bool) -> None:
|
|
@@ -36,6 +46,266 @@ app = typer.Typer(
|
|
|
36
46
|
# Logger will be configured by configuration manager
|
|
37
47
|
logger = get_logger(__name__)
|
|
38
48
|
|
|
49
|
+
_plugins_registered = False
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def register_plugin_cli_extensions(app: typer.Typer) -> None:
|
|
53
|
+
"""Register plugin CLI commands and arguments during app creation."""
|
|
54
|
+
try:
|
|
55
|
+
# Load settings to apply plugin filtering
|
|
56
|
+
try:
|
|
57
|
+
from ccproxy.config.settings import Settings
|
|
58
|
+
|
|
59
|
+
settings = Settings.from_config()
|
|
60
|
+
except Exception as e:
|
|
61
|
+
# Graceful degradation - use no filtering if settings fail to load
|
|
62
|
+
logger.debug("settings_load_failed_for_cli_discovery", error=str(e))
|
|
63
|
+
settings = None
|
|
64
|
+
|
|
65
|
+
plugin_manifests = discover_plugin_cli_extensions(settings)
|
|
66
|
+
|
|
67
|
+
logger.debug(
|
|
68
|
+
"plugin_cli_discovery_complete",
|
|
69
|
+
plugin_count=len(plugin_manifests),
|
|
70
|
+
plugins=[name for name, _ in plugin_manifests],
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Register new commands first
|
|
74
|
+
for plugin_name, manifest in plugin_manifests:
|
|
75
|
+
for cmd_spec in manifest.cli_commands:
|
|
76
|
+
_register_plugin_command(app, plugin_name, cmd_spec)
|
|
77
|
+
|
|
78
|
+
# Batch extend existing commands with new arguments
|
|
79
|
+
arg_batches: dict[str, list[tuple[str, CliArgumentSpec]]] = {}
|
|
80
|
+
for plugin_name, manifest in plugin_manifests:
|
|
81
|
+
for arg_spec in manifest.cli_arguments:
|
|
82
|
+
arg_batches.setdefault(arg_spec.target_command, []).append(
|
|
83
|
+
(plugin_name, arg_spec)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
for target, pairs in arg_batches.items():
|
|
87
|
+
_extend_command_with_arguments(app, target, pairs)
|
|
88
|
+
|
|
89
|
+
except Exception as e:
|
|
90
|
+
# Graceful degradation - CLI still works without plugin extensions
|
|
91
|
+
logger.debug("plugin_cli_extension_registration_failed", error=str(e))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def ensure_plugin_cli_extensions_registered(app: typer.Typer) -> None:
|
|
95
|
+
"""Register plugin CLI extensions once, after logging is configured."""
|
|
96
|
+
global _plugins_registered
|
|
97
|
+
if _plugins_registered:
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
register_plugin_cli_extensions(app)
|
|
101
|
+
_plugins_registered = True
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _register_plugin_command(
|
|
105
|
+
app: typer.Typer, plugin_name: str, cmd_spec: CliCommandSpec
|
|
106
|
+
) -> None:
|
|
107
|
+
"""Register a single plugin command."""
|
|
108
|
+
try:
|
|
109
|
+
if cmd_spec.parent_command is None:
|
|
110
|
+
# Top-level command
|
|
111
|
+
app.command(
|
|
112
|
+
name=cmd_spec.command_name,
|
|
113
|
+
help=cmd_spec.help_text or f"Command from {plugin_name} plugin",
|
|
114
|
+
)(cmd_spec.command_function)
|
|
115
|
+
logger.debug(
|
|
116
|
+
"plugin_command_registered",
|
|
117
|
+
plugin=plugin_name,
|
|
118
|
+
command=cmd_spec.command_name,
|
|
119
|
+
type="top_level",
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
# Subcommand - add to existing command groups
|
|
123
|
+
parent_app = _get_command_app(cmd_spec.parent_command)
|
|
124
|
+
if parent_app:
|
|
125
|
+
parent_app.command(
|
|
126
|
+
name=cmd_spec.command_name,
|
|
127
|
+
help=cmd_spec.help_text or f"Command from {plugin_name} plugin",
|
|
128
|
+
)(cmd_spec.command_function)
|
|
129
|
+
logger.debug(
|
|
130
|
+
"plugin_command_registered",
|
|
131
|
+
plugin=plugin_name,
|
|
132
|
+
command=cmd_spec.command_name,
|
|
133
|
+
parent=cmd_spec.parent_command,
|
|
134
|
+
type="subcommand",
|
|
135
|
+
)
|
|
136
|
+
else:
|
|
137
|
+
logger.warning(
|
|
138
|
+
"plugin_command_parent_not_found",
|
|
139
|
+
plugin=plugin_name,
|
|
140
|
+
command=cmd_spec.command_name,
|
|
141
|
+
parent=cmd_spec.parent_command,
|
|
142
|
+
)
|
|
143
|
+
except Exception as e:
|
|
144
|
+
logger.warning(
|
|
145
|
+
"plugin_command_registration_failed",
|
|
146
|
+
plugin=plugin_name,
|
|
147
|
+
command=cmd_spec.command_name,
|
|
148
|
+
error=str(e),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _extend_command_with_arguments(
|
|
153
|
+
app: typer.Typer, target_name: str, pairs: list[tuple[str, CliArgumentSpec]]
|
|
154
|
+
) -> None:
|
|
155
|
+
"""Extend an existing command with multiple new arguments at once."""
|
|
156
|
+
try:
|
|
157
|
+
# Utility: resolve a command callback by dotted path, supporting subcommands
|
|
158
|
+
def _resolve_callback(root_app: typer.Typer, dotted: str) -> Any:
|
|
159
|
+
parts = dotted.split()
|
|
160
|
+
# Allow both space-separated or colon-separated ("auth login")
|
|
161
|
+
if len(parts) == 1 and (":" in dotted or "/" in dotted):
|
|
162
|
+
# normalize common separators
|
|
163
|
+
dotted_norm = dotted.replace(":", " ").replace("/", " ")
|
|
164
|
+
parts = dotted_norm.split()
|
|
165
|
+
|
|
166
|
+
current_app: typer.Typer | None = root_app
|
|
167
|
+
callback = None
|
|
168
|
+
|
|
169
|
+
# Typer API does not expose a stable public registry; we rely on
|
|
170
|
+
# attributes commonly present on Typer instances.
|
|
171
|
+
for idx, part in enumerate(parts):
|
|
172
|
+
if current_app is None:
|
|
173
|
+
return None
|
|
174
|
+
# Try commands at this level
|
|
175
|
+
cmds = getattr(current_app, "registered_commands", [])
|
|
176
|
+
sub_app: typer.Typer | None = None
|
|
177
|
+
found = False
|
|
178
|
+
for cmd in cmds:
|
|
179
|
+
name = getattr(cmd, "name", None)
|
|
180
|
+
if name == part:
|
|
181
|
+
found = True
|
|
182
|
+
if idx == len(parts) - 1:
|
|
183
|
+
callback = getattr(cmd, "callback", None)
|
|
184
|
+
else:
|
|
185
|
+
# navigate into sub-typer if present
|
|
186
|
+
sub_app = getattr(cmd, "typer_instance", None)
|
|
187
|
+
break
|
|
188
|
+
current_app = sub_app if sub_app is not None else current_app
|
|
189
|
+
if not found and idx == len(parts) - 1:
|
|
190
|
+
# maybe the target is a top-level name even if earlier parts failed
|
|
191
|
+
pass
|
|
192
|
+
return callback
|
|
193
|
+
|
|
194
|
+
# Find existing command callback on the root app or nested apps
|
|
195
|
+
original_callback = _resolve_callback(app, target_name)
|
|
196
|
+
|
|
197
|
+
if original_callback is None:
|
|
198
|
+
logger.debug(
|
|
199
|
+
"plugin_argument_extension_target_not_found",
|
|
200
|
+
target_command=target_name,
|
|
201
|
+
)
|
|
202
|
+
return
|
|
203
|
+
# Build all options and construct wrapper
|
|
204
|
+
built: list[tuple[CliArgumentSpec, Any]] = []
|
|
205
|
+
for _, arg_spec in pairs:
|
|
206
|
+
typer_kwargs = dict(arg_spec.typer_kwargs or {})
|
|
207
|
+
option_names = typer_kwargs.pop("option", None)
|
|
208
|
+
if option_names is None:
|
|
209
|
+
option_names = [f"--{arg_spec.argument_name.replace('_', '-')}"]
|
|
210
|
+
if isinstance(option_names, str):
|
|
211
|
+
option_names = [option_names]
|
|
212
|
+
option = typer.Option(
|
|
213
|
+
*option_names,
|
|
214
|
+
help=arg_spec.help_text or "",
|
|
215
|
+
**typer_kwargs,
|
|
216
|
+
)
|
|
217
|
+
built.append((arg_spec, option))
|
|
218
|
+
|
|
219
|
+
# Preserve original options: build wrapper with original signature + injected params
|
|
220
|
+
import inspect
|
|
221
|
+
|
|
222
|
+
sig = inspect.signature(original_callback)
|
|
223
|
+
param_defs: list[str] = []
|
|
224
|
+
call_args: list[str] = []
|
|
225
|
+
annotations: dict[str, object] = {}
|
|
226
|
+
|
|
227
|
+
# Always include ctx first for our bookkeeping
|
|
228
|
+
param_defs.append("ctx: typer.Context")
|
|
229
|
+
annotations["ctx"] = typer.Context
|
|
230
|
+
|
|
231
|
+
# Mirror original parameters with their defaults in order
|
|
232
|
+
for name, param in sig.parameters.items():
|
|
233
|
+
if getattr(original_callback, "__annotations__", {}).get(name) is not None:
|
|
234
|
+
annotations[name] = original_callback.__annotations__[name]
|
|
235
|
+
if param.default is inspect._empty:
|
|
236
|
+
param_defs.append(name)
|
|
237
|
+
else:
|
|
238
|
+
param_defs.append(f"{name}={repr(param.default)}")
|
|
239
|
+
call_args.append(name)
|
|
240
|
+
|
|
241
|
+
# Append injected params
|
|
242
|
+
for arg_spec, _ in built:
|
|
243
|
+
default_expr = "..." if arg_spec.required else "None"
|
|
244
|
+
param_defs.append(f"{arg_spec.argument_name}: object = {default_expr}")
|
|
245
|
+
|
|
246
|
+
params_sig = ", ".join(param_defs)
|
|
247
|
+
|
|
248
|
+
body_lines = [
|
|
249
|
+
"ctx.ensure_object(dict)",
|
|
250
|
+
"plugin_map = ctx.obj.get('plugin_cli_args') or {}",
|
|
251
|
+
"plugin_map = plugin_map if isinstance(plugin_map, dict) else {}",
|
|
252
|
+
]
|
|
253
|
+
for arg_spec, _ in built:
|
|
254
|
+
name = arg_spec.argument_name
|
|
255
|
+
body_lines.append(f"if {name} is not None: plugin_map['{name}'] = {name}")
|
|
256
|
+
body_lines.append("ctx.obj['plugin_cli_args'] = plugin_map")
|
|
257
|
+
body_lines.append(f"return original_callback({', '.join(call_args)})")
|
|
258
|
+
|
|
259
|
+
body_src = "\n ".join(body_lines)
|
|
260
|
+
func_src = f"def _wrapped({params_sig}):\n {body_src}\n"
|
|
261
|
+
local_ns: dict[str, object] = {
|
|
262
|
+
"typer": typer,
|
|
263
|
+
"original_callback": original_callback,
|
|
264
|
+
}
|
|
265
|
+
exec(func_src, local_ns, local_ns)
|
|
266
|
+
_wrapped = local_ns["_wrapped"]
|
|
267
|
+
|
|
268
|
+
# Copy original annotations and append injected option annotations
|
|
269
|
+
for name, ann in getattr(original_callback, "__annotations__", {}).items():
|
|
270
|
+
annotations.setdefault(name, ann)
|
|
271
|
+
for arg_spec, option in built:
|
|
272
|
+
annotations[arg_spec.argument_name] = Annotated[
|
|
273
|
+
arg_spec.argument_type | None, option
|
|
274
|
+
]
|
|
275
|
+
_wrapped.__annotations__ = annotations
|
|
276
|
+
|
|
277
|
+
_wrapped.__name__ = getattr( # type: ignore[attr-defined]
|
|
278
|
+
original_callback, "__name__", f"_{target_name}_wrapped"
|
|
279
|
+
)
|
|
280
|
+
_wrapped.__doc__ = getattr(original_callback, "__doc__", None)
|
|
281
|
+
|
|
282
|
+
app.command(name=target_name)(cast(Any, _wrapped))
|
|
283
|
+
|
|
284
|
+
for plugin_name, arg_spec in pairs:
|
|
285
|
+
logger.debug(
|
|
286
|
+
"plugin_argument_extension_registered",
|
|
287
|
+
plugin=plugin_name,
|
|
288
|
+
target_command=target_name,
|
|
289
|
+
argument=arg_spec.argument_name,
|
|
290
|
+
)
|
|
291
|
+
except Exception as e:
|
|
292
|
+
logger.debug(
|
|
293
|
+
"plugin_argument_extension_failed",
|
|
294
|
+
target_command=target_name,
|
|
295
|
+
error=str(e),
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _get_command_app(command_name: str) -> typer.Typer | None:
|
|
300
|
+
"""Get the typer app for a parent command."""
|
|
301
|
+
command_apps = {
|
|
302
|
+
"auth": auth_app,
|
|
303
|
+
"config": config_app,
|
|
304
|
+
"plugins": plugins_app,
|
|
305
|
+
"status": status_app,
|
|
306
|
+
}
|
|
307
|
+
return command_apps.get(command_name)
|
|
308
|
+
|
|
39
309
|
|
|
40
310
|
# Add global options
|
|
41
311
|
@app.callback()
|
|
@@ -65,9 +335,13 @@ def app_main(
|
|
|
65
335
|
] = None,
|
|
66
336
|
) -> None:
|
|
67
337
|
"""CCProxy API Server - Anthropic and OpenAI compatible interface for Claude."""
|
|
68
|
-
# Store config path
|
|
338
|
+
# Store config path and initialize plugin arg bucket
|
|
69
339
|
ctx.ensure_object(dict)
|
|
70
340
|
ctx.obj["config_path"] = config
|
|
341
|
+
if "plugin_cli_args" not in ctx.obj or not isinstance(
|
|
342
|
+
ctx.obj.get("plugin_cli_args"), dict
|
|
343
|
+
):
|
|
344
|
+
ctx.obj["plugin_cli_args"] = {}
|
|
71
345
|
|
|
72
346
|
# If no command is invoked, run the serve command by default
|
|
73
347
|
if ctx.invoked_subcommand is None:
|
|
@@ -85,20 +359,95 @@ app.add_typer(config_app)
|
|
|
85
359
|
app.add_typer(auth_app)
|
|
86
360
|
|
|
87
361
|
# Register permission handler command
|
|
88
|
-
app.add_typer(permission_handler_app)
|
|
362
|
+
# app.add_typer(permission_handler_app)
|
|
89
363
|
|
|
364
|
+
# Register plugins command
|
|
365
|
+
app.add_typer(plugins_app)
|
|
90
366
|
|
|
91
|
-
# Register
|
|
367
|
+
# Register status command
|
|
368
|
+
app.add_typer(status_app)
|
|
369
|
+
|
|
370
|
+
# Register imported commands first
|
|
92
371
|
app.command(name="serve")(api)
|
|
372
|
+
|
|
93
373
|
# Claude command removed - functionality moved to serve command
|
|
94
374
|
|
|
95
375
|
|
|
96
376
|
def main() -> None:
|
|
97
377
|
"""Entry point for the CLI application."""
|
|
378
|
+
# Bind a command-wide correlation ID so all logs have `cmd_id`
|
|
379
|
+
set_command_context()
|
|
380
|
+
# Early logging bootstrap from env/argv; safe to reconfigure later
|
|
381
|
+
bootstrap_cli_logging()
|
|
382
|
+
# Register plugin-supplied CLI commands after logging honors env overrides
|
|
383
|
+
ensure_plugin_cli_extensions_registered(app)
|
|
384
|
+
# Log invocation context (argv + env) for all commands
|
|
385
|
+
_log_cli_invocation_context()
|
|
98
386
|
app()
|
|
99
387
|
|
|
100
388
|
|
|
101
389
|
if __name__ == "__main__":
|
|
102
|
-
|
|
390
|
+
main()
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def _mask_env_value(key: str, value: str) -> str:
|
|
394
|
+
"""Mask sensitive values based on common substrings in the key."""
|
|
395
|
+
lowered = key.lower()
|
|
396
|
+
sensitive_markers = [
|
|
397
|
+
"token",
|
|
398
|
+
"secret",
|
|
399
|
+
"password",
|
|
400
|
+
"passwd",
|
|
401
|
+
"key",
|
|
402
|
+
"api_key",
|
|
403
|
+
"bearer",
|
|
404
|
+
"auth",
|
|
405
|
+
"credential",
|
|
406
|
+
]
|
|
407
|
+
if any(m in lowered for m in sensitive_markers):
|
|
408
|
+
if not value:
|
|
409
|
+
return value
|
|
410
|
+
# keep only last 4 chars for minimal debugging
|
|
411
|
+
tail = value[-4:] if len(value) > 4 else "".join("*" for _ in value)
|
|
412
|
+
return f"***MASKED***{tail}"
|
|
413
|
+
return value
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def _collect_relevant_env() -> dict[str, str]:
|
|
417
|
+
"""Collect env vars relevant to settings/plugins and mask sensitive ones.
|
|
418
|
+
|
|
419
|
+
We include nested-style variables (containing "__") and key CCProxy groups.
|
|
420
|
+
"""
|
|
421
|
+
prefixes = (
|
|
422
|
+
"LOGGING__",
|
|
423
|
+
"PLUGINS__",
|
|
424
|
+
"SERVER__",
|
|
425
|
+
"STORAGE__",
|
|
426
|
+
"AUTH__",
|
|
427
|
+
"CCPROXY__",
|
|
428
|
+
"CCPROXY_",
|
|
429
|
+
)
|
|
430
|
+
env = {}
|
|
431
|
+
for k, v in os.environ.items():
|
|
432
|
+
# Ignore variables that start with double underscore
|
|
433
|
+
if k.startswith("__"):
|
|
434
|
+
continue
|
|
435
|
+
if "__" in k or k.startswith(prefixes):
|
|
436
|
+
env[k] = _mask_env_value(k, v)
|
|
437
|
+
# Sort for stable output
|
|
438
|
+
return dict(sorted(env.items(), key=lambda kv: kv[0]))
|
|
439
|
+
|
|
103
440
|
|
|
104
|
-
|
|
441
|
+
def _log_cli_invocation_context() -> None:
|
|
442
|
+
"""Log argv and selected env at debug level for all commands."""
|
|
443
|
+
try:
|
|
444
|
+
env = _collect_relevant_env()
|
|
445
|
+
logger.debug(
|
|
446
|
+
"cli_invocation",
|
|
447
|
+
argv=sys.argv,
|
|
448
|
+
env=env,
|
|
449
|
+
category="cli",
|
|
450
|
+
)
|
|
451
|
+
except Exception:
|
|
452
|
+
# Never let logging context fail the CLI
|
|
453
|
+
pass
|
|
@@ -31,22 +31,6 @@ def validate_max_turns(
|
|
|
31
31
|
return value
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def validate_permission_mode(
|
|
35
|
-
ctx: typer.Context, param: typer.CallbackParam, value: str | None
|
|
36
|
-
) -> str | None:
|
|
37
|
-
"""Validate permission mode."""
|
|
38
|
-
if value is None:
|
|
39
|
-
return None
|
|
40
|
-
|
|
41
|
-
valid_modes = {"default", "acceptEdits", "bypassPermissions"}
|
|
42
|
-
if value not in valid_modes:
|
|
43
|
-
raise typer.BadParameter(
|
|
44
|
-
f"Permission mode must be one of: {', '.join(valid_modes)}"
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
return value
|
|
48
|
-
|
|
49
|
-
|
|
50
34
|
def validate_claude_cli_path(
|
|
51
35
|
ctx: typer.Context, param: typer.CallbackParam, value: str | None
|
|
52
36
|
) -> str | None:
|
|
@@ -142,16 +126,13 @@ class ClaudeOptions:
|
|
|
142
126
|
disallowed_tools: str | None = None,
|
|
143
127
|
claude_cli_path: str | None = None,
|
|
144
128
|
append_system_prompt: str | None = None,
|
|
145
|
-
permission_mode: str | None = None,
|
|
146
129
|
max_turns: int | None = None,
|
|
147
130
|
cwd: str | None = None,
|
|
148
|
-
permission_prompt_tool_name: str | None = None,
|
|
149
131
|
sdk_message_mode: str | None = None,
|
|
150
132
|
sdk_pool: bool = False,
|
|
151
133
|
sdk_pool_size: int | None = None,
|
|
152
134
|
sdk_session_pool: bool = False,
|
|
153
135
|
system_prompt_injection_mode: str | None = None,
|
|
154
|
-
builtin_permissions: bool = True,
|
|
155
136
|
):
|
|
156
137
|
"""Initialize Claude options.
|
|
157
138
|
|
|
@@ -161,29 +142,23 @@ class ClaudeOptions:
|
|
|
161
142
|
disallowed_tools: List of disallowed tools (comma-separated)
|
|
162
143
|
claude_cli_path: Path to Claude CLI executable
|
|
163
144
|
append_system_prompt: Additional system prompt to append
|
|
164
|
-
permission_mode: Permission mode
|
|
165
145
|
max_turns: Maximum conversation turns
|
|
166
146
|
cwd: Working directory path
|
|
167
|
-
permission_prompt_tool_name: Permission prompt tool name
|
|
168
147
|
sdk_message_mode: SDK message handling mode
|
|
169
148
|
sdk_pool: Enable general Claude SDK client connection pooling
|
|
170
149
|
sdk_pool_size: Number of clients to maintain in the general pool
|
|
171
150
|
sdk_session_pool: Enable session-aware Claude SDK client pooling
|
|
172
151
|
system_prompt_injection_mode: System prompt injection mode
|
|
173
|
-
builtin_permissions: Enable built-in permission handling infrastructure
|
|
174
152
|
"""
|
|
175
153
|
self.max_thinking_tokens = max_thinking_tokens
|
|
176
154
|
self.allowed_tools = allowed_tools
|
|
177
155
|
self.disallowed_tools = disallowed_tools
|
|
178
156
|
self.claude_cli_path = claude_cli_path
|
|
179
157
|
self.append_system_prompt = append_system_prompt
|
|
180
|
-
self.permission_mode = permission_mode
|
|
181
158
|
self.max_turns = max_turns
|
|
182
159
|
self.cwd = cwd
|
|
183
|
-
self.permission_prompt_tool_name = permission_prompt_tool_name
|
|
184
160
|
self.sdk_message_mode = sdk_message_mode
|
|
185
161
|
self.sdk_pool = sdk_pool
|
|
186
162
|
self.sdk_pool_size = sdk_pool_size
|
|
187
163
|
self.sdk_session_pool = sdk_session_pool
|
|
188
164
|
self.system_prompt_injection_mode = system_prompt_injection_mode
|
|
189
|
-
self.builtin_permissions = builtin_permissions
|
ccproxy/config/__init__.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"""Configuration module for Claude Proxy API Server."""
|
|
2
2
|
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
5
|
-
from .
|
|
6
|
-
from .settings import Settings, get_settings
|
|
7
|
-
from .validators import (
|
|
3
|
+
from .core import CORSSettings, HTTPSettings, LoggingSettings, ServerSettings
|
|
4
|
+
from .settings import Settings
|
|
5
|
+
from .utils import (
|
|
8
6
|
ConfigValidationError,
|
|
9
7
|
validate_config_dict,
|
|
10
8
|
validate_cors_origins,
|
|
@@ -19,12 +17,6 @@ from .validators import (
|
|
|
19
17
|
|
|
20
18
|
__all__ = [
|
|
21
19
|
"Settings",
|
|
22
|
-
"get_settings",
|
|
23
|
-
"AuthSettings",
|
|
24
|
-
"OAuthSettings",
|
|
25
|
-
"CredentialStorageSettings",
|
|
26
|
-
"ReverseProxySettings",
|
|
27
|
-
"DockerSettings",
|
|
28
20
|
"ConfigValidationError",
|
|
29
21
|
"validate_config_dict",
|
|
30
22
|
"validate_cors_origins",
|
|
@@ -34,4 +26,8 @@ __all__ = [
|
|
|
34
26
|
"validate_port",
|
|
35
27
|
"validate_timeout",
|
|
36
28
|
"validate_url",
|
|
29
|
+
"ServerSettings",
|
|
30
|
+
"LoggingSettings",
|
|
31
|
+
"HTTPSettings",
|
|
32
|
+
"CORSSettings",
|
|
37
33
|
]
|