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/commands/serve.py
CHANGED
|
@@ -1,48 +1,20 @@
|
|
|
1
1
|
"""Serve command for CCProxy API server - consolidates server-related commands."""
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
|
-
import os
|
|
5
3
|
from pathlib import Path
|
|
6
4
|
from typing import Annotated, Any
|
|
7
5
|
|
|
8
6
|
import typer
|
|
9
7
|
import uvicorn
|
|
10
8
|
from click import get_current_context
|
|
11
|
-
from
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.syntax import Syntax
|
|
12
11
|
|
|
13
|
-
from ccproxy.
|
|
14
|
-
from ccproxy.
|
|
15
|
-
|
|
16
|
-
is_running_in_docker,
|
|
17
|
-
warning,
|
|
18
|
-
)
|
|
19
|
-
from ccproxy.config.settings import (
|
|
20
|
-
ConfigurationError,
|
|
21
|
-
Settings,
|
|
22
|
-
config_manager,
|
|
23
|
-
)
|
|
24
|
-
from ccproxy.core.async_utils import get_root_package_name
|
|
25
|
-
from ccproxy.docker import (
|
|
26
|
-
create_docker_adapter,
|
|
27
|
-
)
|
|
12
|
+
from ccproxy.cli.helpers import get_rich_toolkit
|
|
13
|
+
from ccproxy.config.settings import ConfigurationError, Settings
|
|
14
|
+
from ccproxy.core.logging import get_logger, setup_logging
|
|
28
15
|
|
|
29
|
-
from ..
|
|
30
|
-
_create_docker_adapter_from_settings,
|
|
31
|
-
)
|
|
32
|
-
from ..options.claude_options import (
|
|
33
|
-
ClaudeOptions,
|
|
34
|
-
validate_claude_cli_path,
|
|
35
|
-
validate_cwd,
|
|
36
|
-
validate_max_thinking_tokens,
|
|
37
|
-
validate_max_turns,
|
|
38
|
-
validate_permission_mode,
|
|
39
|
-
validate_pool_size,
|
|
40
|
-
validate_sdk_message_mode,
|
|
41
|
-
validate_system_prompt_injection_mode,
|
|
42
|
-
)
|
|
43
|
-
from ..options.security_options import SecurityOptions, validate_auth_token
|
|
16
|
+
from ..options.security_options import validate_auth_token
|
|
44
17
|
from ..options.server_options import (
|
|
45
|
-
ServerOptions,
|
|
46
18
|
validate_log_level,
|
|
47
19
|
validate_port,
|
|
48
20
|
)
|
|
@@ -56,203 +28,42 @@ def get_config_path_from_context() -> Path | None:
|
|
|
56
28
|
config_path = ctx.obj["config_path"]
|
|
57
29
|
return config_path if config_path is None else Path(config_path)
|
|
58
30
|
except RuntimeError:
|
|
59
|
-
# No active click context (e.g., in tests)
|
|
60
31
|
pass
|
|
61
32
|
return None
|
|
62
33
|
|
|
63
34
|
|
|
64
35
|
def _show_api_usage_info(toolkit: Any, settings: Settings) -> None:
|
|
65
36
|
"""Show API usage information when auth token is configured."""
|
|
66
|
-
from rich.console import Console
|
|
67
|
-
from rich.syntax import Syntax
|
|
68
37
|
|
|
69
38
|
toolkit.print_title("API Client Configuration", tag="config")
|
|
70
39
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
openai_base_url = f"http://{settings.server.host}:{settings.server.port}/openai"
|
|
40
|
+
anthropic_base_url = f"http://{settings.server.host}:{settings.server.port}/claude"
|
|
41
|
+
openai_base_url = f"http://{settings.server.host}:{settings.server.port}/codex"
|
|
74
42
|
|
|
75
|
-
# Show environment variable exports using code blocks
|
|
76
43
|
toolkit.print("Environment Variables for API Clients:", tag="info")
|
|
77
44
|
toolkit.print_line()
|
|
78
45
|
|
|
79
|
-
# Use rich console for code blocks
|
|
80
46
|
console = Console()
|
|
81
47
|
|
|
82
|
-
|
|
48
|
+
auth_token = "YOUR_AUTH_TOKEN" if settings.security.auth_token else "NOT_SET"
|
|
49
|
+
exports = f"""export ANTHROPIC_API_KEY={auth_token}
|
|
83
50
|
export ANTHROPIC_BASE_URL={anthropic_base_url}
|
|
84
|
-
export OPENAI_API_KEY={
|
|
51
|
+
export OPENAI_API_KEY={auth_token}
|
|
85
52
|
export OPENAI_BASE_URL={openai_base_url}"""
|
|
86
53
|
|
|
87
54
|
console.print(Syntax(exports, "bash", theme="monokai", background_color="default"))
|
|
88
55
|
toolkit.print_line()
|
|
89
56
|
|
|
90
57
|
|
|
91
|
-
def
|
|
92
|
-
settings: Settings,
|
|
93
|
-
docker_image: str | None = None,
|
|
94
|
-
docker_env: list[str] | None = None,
|
|
95
|
-
docker_volume: list[str] | None = None,
|
|
96
|
-
docker_arg: list[str] | None = None,
|
|
97
|
-
docker_home: str | None = None,
|
|
98
|
-
docker_workspace: str | None = None,
|
|
99
|
-
user_mapping_enabled: bool | None = None,
|
|
100
|
-
user_uid: int | None = None,
|
|
101
|
-
user_gid: int | None = None,
|
|
102
|
-
) -> None:
|
|
103
|
-
"""Run the server using Docker."""
|
|
104
|
-
toolkit = get_rich_toolkit()
|
|
105
|
-
logger = get_logger(__name__)
|
|
106
|
-
|
|
107
|
-
docker_env = docker_env or []
|
|
108
|
-
docker_volume = docker_volume or []
|
|
109
|
-
docker_arg = docker_arg or []
|
|
110
|
-
|
|
111
|
-
docker_env_dict = {}
|
|
112
|
-
for env_var in docker_env:
|
|
113
|
-
if "=" in env_var:
|
|
114
|
-
key, value = env_var.split("=", 1)
|
|
115
|
-
docker_env_dict[key] = value
|
|
116
|
-
|
|
117
|
-
# Add server configuration to Docker environment
|
|
118
|
-
if settings.server.reload:
|
|
119
|
-
docker_env_dict["RELOAD"] = "true"
|
|
120
|
-
docker_env_dict["PORT"] = str(settings.server.port)
|
|
121
|
-
docker_env_dict["HOST"] = "0.0.0.0"
|
|
122
|
-
|
|
123
|
-
# Display startup information
|
|
124
|
-
# toolkit.print_title(
|
|
125
|
-
# "Starting CCProxy API server with Docker", tag="docker"
|
|
126
|
-
# )
|
|
127
|
-
# toolkit.print(
|
|
128
|
-
# f"Server will be available at: http://{settings.server.host}:{settings.server.port}",
|
|
129
|
-
# tag="info",
|
|
130
|
-
# )
|
|
131
|
-
toolkit.print_line()
|
|
132
|
-
|
|
133
|
-
# Show Docker configuration summary
|
|
134
|
-
toolkit.print_title("Docker Configuration Summary", tag="config")
|
|
135
|
-
|
|
136
|
-
# Determine effective directories for volume mapping
|
|
137
|
-
home_dir = docker_home or settings.docker.docker_home_directory
|
|
138
|
-
workspace_dir = docker_workspace or settings.docker.docker_workspace_directory
|
|
139
|
-
|
|
140
|
-
# Show volume information
|
|
141
|
-
toolkit.print("Volumes:", tag="config")
|
|
142
|
-
if home_dir:
|
|
143
|
-
toolkit.print(f" Home: {home_dir} → /data/home", tag="volume")
|
|
144
|
-
if workspace_dir:
|
|
145
|
-
toolkit.print(f" Workspace: {workspace_dir} → /data/workspace", tag="volume")
|
|
146
|
-
if docker_volume:
|
|
147
|
-
for vol in docker_volume:
|
|
148
|
-
toolkit.print(f" Additional: {vol}", tag="volume")
|
|
149
|
-
toolkit.print_line()
|
|
150
|
-
|
|
151
|
-
# Show environment information
|
|
152
|
-
toolkit.print("Environment Variables:", tag="config")
|
|
153
|
-
key_env_vars = {
|
|
154
|
-
"CLAUDE_HOME": "/data/home",
|
|
155
|
-
"CLAUDE_WORKSPACE": "/data/workspace",
|
|
156
|
-
"PORT": str(settings.server.port),
|
|
157
|
-
"HOST": "0.0.0.0",
|
|
158
|
-
}
|
|
159
|
-
if settings.server.reload:
|
|
160
|
-
key_env_vars["RELOAD"] = "true"
|
|
161
|
-
|
|
162
|
-
for key, value in key_env_vars.items():
|
|
163
|
-
toolkit.print(f" {key}={value}", tag="env")
|
|
164
|
-
|
|
165
|
-
# Show additional environment variables from CLI
|
|
166
|
-
for env_var in docker_env:
|
|
167
|
-
toolkit.print(f" {env_var}", tag="env")
|
|
168
|
-
|
|
169
|
-
# Show debug environment information if log level is DEBUG
|
|
170
|
-
if settings.server.log_level == "DEBUG":
|
|
171
|
-
toolkit.print_line()
|
|
172
|
-
toolkit.print_title("Debug: All Environment Variables", tag="debug")
|
|
173
|
-
all_env = {**docker_env_dict}
|
|
174
|
-
for key, value in sorted(all_env.items()):
|
|
175
|
-
toolkit.print(f" {key}={value}", tag="debug")
|
|
176
|
-
|
|
177
|
-
toolkit.print_line()
|
|
178
|
-
|
|
179
|
-
toolkit.print_line()
|
|
180
|
-
|
|
181
|
-
# Show API usage information if auth token is configured
|
|
182
|
-
if settings.security.auth_token:
|
|
183
|
-
_show_api_usage_info(toolkit, settings)
|
|
184
|
-
|
|
185
|
-
# Execute using the new Docker adapter
|
|
186
|
-
image, volumes, environment, command, user_context, additional_args = (
|
|
187
|
-
_create_docker_adapter_from_settings(
|
|
188
|
-
settings,
|
|
189
|
-
command=["ccproxy", "serve"],
|
|
190
|
-
docker_image=docker_image,
|
|
191
|
-
docker_env=[f"{k}={v}" for k, v in docker_env_dict.items()],
|
|
192
|
-
docker_volume=docker_volume,
|
|
193
|
-
docker_arg=docker_arg,
|
|
194
|
-
docker_home=docker_home,
|
|
195
|
-
docker_workspace=docker_workspace,
|
|
196
|
-
user_mapping_enabled=user_mapping_enabled,
|
|
197
|
-
user_uid=user_uid,
|
|
198
|
-
user_gid=user_gid,
|
|
199
|
-
)
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
logger.info(
|
|
203
|
-
"docker_server_config",
|
|
204
|
-
configured_image=settings.docker.docker_image,
|
|
205
|
-
effective_image=image,
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
# Add port mapping
|
|
209
|
-
ports = [f"{settings.server.port}:{settings.server.port}"]
|
|
210
|
-
|
|
211
|
-
# Create Docker adapter and execute
|
|
212
|
-
adapter = create_docker_adapter()
|
|
213
|
-
adapter.exec_container(
|
|
214
|
-
image=image,
|
|
215
|
-
volumes=volumes,
|
|
216
|
-
environment=environment,
|
|
217
|
-
command=command,
|
|
218
|
-
user_context=user_context,
|
|
219
|
-
ports=ports,
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def _run_local_server(settings: Settings, cli_overrides: dict[str, Any]) -> None:
|
|
58
|
+
def _run_local_server(settings: Settings) -> None:
|
|
224
59
|
"""Run the server locally."""
|
|
225
|
-
in_docker = is_running_in_docker()
|
|
60
|
+
# in_docker = is_running_in_docker()
|
|
226
61
|
toolkit = get_rich_toolkit()
|
|
227
62
|
logger = get_logger(__name__)
|
|
228
63
|
|
|
229
|
-
if in_docker:
|
|
230
|
-
toolkit.print_title(
|
|
231
|
-
f"Starting CCProxy API server in {warning('docker')}",
|
|
232
|
-
tag="docker",
|
|
233
|
-
)
|
|
234
|
-
toolkit.print(
|
|
235
|
-
f"uid={warning(str(os.getuid()))} gid={warning(str(os.getgid()))}"
|
|
236
|
-
)
|
|
237
|
-
toolkit.print(f"HOME={os.environ['HOME']}")
|
|
238
|
-
# else:
|
|
239
|
-
# toolkit.print_title("Starting CCProxy API server", tag="local")
|
|
240
|
-
|
|
241
|
-
# toolkit.print(
|
|
242
|
-
# f"Server will be available at: http://{settings.server.host}:{settings.server.port}",
|
|
243
|
-
# tag="info",
|
|
244
|
-
# )
|
|
245
|
-
|
|
246
|
-
# toolkit.print_line()
|
|
247
|
-
|
|
248
|
-
# Show API usage information if auth token is configured
|
|
249
64
|
if settings.security.auth_token:
|
|
250
65
|
_show_api_usage_info(toolkit, settings)
|
|
251
66
|
|
|
252
|
-
# Set environment variables for server to access CLI overrides
|
|
253
|
-
if cli_overrides:
|
|
254
|
-
os.environ["CCPROXY_CONFIG_OVERRIDES"] = json.dumps(cli_overrides)
|
|
255
|
-
|
|
256
67
|
logger.debug(
|
|
257
68
|
"server_starting",
|
|
258
69
|
host=settings.server.host,
|
|
@@ -262,26 +73,27 @@ def _run_local_server(settings: Settings, cli_overrides: dict[str, Any]) -> None
|
|
|
262
73
|
|
|
263
74
|
reload_includes = None
|
|
264
75
|
if settings.server.reload:
|
|
265
|
-
reload_includes = ["ccproxy", "pyproject.toml", "uv.lock"]
|
|
76
|
+
reload_includes = ["ccproxy", "pyproject.toml", "uv.lock", "plugins"]
|
|
77
|
+
|
|
78
|
+
# container = create_service_container(settings)
|
|
266
79
|
|
|
267
|
-
# Run uvicorn with our already configured logging
|
|
268
80
|
uvicorn.run(
|
|
269
|
-
app=
|
|
81
|
+
# app=create_app(container),
|
|
82
|
+
app="ccproxy.api.app:create_app",
|
|
270
83
|
factory=True,
|
|
271
84
|
host=settings.server.host,
|
|
272
85
|
port=settings.server.port,
|
|
273
86
|
reload=settings.server.reload,
|
|
274
|
-
workers=
|
|
87
|
+
workers=settings.server.workers,
|
|
275
88
|
log_config=None,
|
|
276
|
-
access_log=False,
|
|
277
|
-
server_header=False,
|
|
89
|
+
access_log=False,
|
|
90
|
+
server_header=False,
|
|
91
|
+
date_header=False,
|
|
278
92
|
reload_includes=reload_includes,
|
|
279
|
-
# log_config=get_uvicorn_log_config(),
|
|
280
93
|
)
|
|
281
94
|
|
|
282
95
|
|
|
283
96
|
def api(
|
|
284
|
-
# Configuration
|
|
285
97
|
config: Annotated[
|
|
286
98
|
Path | None,
|
|
287
99
|
typer.Option(
|
|
@@ -295,7 +107,6 @@ def api(
|
|
|
295
107
|
rich_help_panel="Configuration",
|
|
296
108
|
),
|
|
297
109
|
] = None,
|
|
298
|
-
# Server options
|
|
299
110
|
port: Annotated[
|
|
300
111
|
int | None,
|
|
301
112
|
typer.Option(
|
|
@@ -340,15 +151,6 @@ def api(
|
|
|
340
151
|
rich_help_panel="Server Settings",
|
|
341
152
|
),
|
|
342
153
|
] = None,
|
|
343
|
-
use_terminal_permission_handler: Annotated[
|
|
344
|
-
bool,
|
|
345
|
-
typer.Option(
|
|
346
|
-
"--terminal-permission-handler",
|
|
347
|
-
help="Enable terminal permission terminal handler",
|
|
348
|
-
rich_help_panel="Server Settings",
|
|
349
|
-
),
|
|
350
|
-
] = False,
|
|
351
|
-
# Security options
|
|
352
154
|
auth_token: Annotated[
|
|
353
155
|
str | None,
|
|
354
156
|
typer.Option(
|
|
@@ -358,629 +160,92 @@ def api(
|
|
|
358
160
|
rich_help_panel="Security Settings",
|
|
359
161
|
),
|
|
360
162
|
] = None,
|
|
361
|
-
|
|
362
|
-
max_thinking_tokens: Annotated[
|
|
363
|
-
int | None,
|
|
364
|
-
typer.Option(
|
|
365
|
-
"--max-thinking-tokens",
|
|
366
|
-
help="Maximum thinking tokens for Claude Code",
|
|
367
|
-
callback=validate_max_thinking_tokens,
|
|
368
|
-
rich_help_panel="Claude Settings",
|
|
369
|
-
),
|
|
370
|
-
] = None,
|
|
371
|
-
allowed_tools: Annotated[
|
|
372
|
-
str | None,
|
|
373
|
-
typer.Option(
|
|
374
|
-
"--allowed-tools",
|
|
375
|
-
help="List of allowed tools (comma-separated)",
|
|
376
|
-
rich_help_panel="Claude Settings",
|
|
377
|
-
),
|
|
378
|
-
] = None,
|
|
379
|
-
disallowed_tools: Annotated[
|
|
380
|
-
str | None,
|
|
381
|
-
typer.Option(
|
|
382
|
-
"--disallowed-tools",
|
|
383
|
-
help="List of disallowed tools (comma-separated)",
|
|
384
|
-
rich_help_panel="Claude Settings",
|
|
385
|
-
),
|
|
386
|
-
] = None,
|
|
387
|
-
claude_cli_path: Annotated[
|
|
388
|
-
str | None,
|
|
389
|
-
typer.Option(
|
|
390
|
-
"--claude-cli-path",
|
|
391
|
-
help="Path to Claude CLI executable",
|
|
392
|
-
callback=validate_claude_cli_path,
|
|
393
|
-
rich_help_panel="Claude Settings",
|
|
394
|
-
),
|
|
395
|
-
] = None,
|
|
396
|
-
append_system_prompt: Annotated[
|
|
397
|
-
str | None,
|
|
398
|
-
typer.Option(
|
|
399
|
-
"--append-system-prompt",
|
|
400
|
-
help="Additional system prompt to append",
|
|
401
|
-
rich_help_panel="Claude Settings",
|
|
402
|
-
),
|
|
403
|
-
] = None,
|
|
404
|
-
permission_mode: Annotated[
|
|
405
|
-
str | None,
|
|
406
|
-
typer.Option(
|
|
407
|
-
"--permission-mode",
|
|
408
|
-
help="Permission mode: default, acceptEdits, or bypassPermissions",
|
|
409
|
-
callback=validate_permission_mode,
|
|
410
|
-
rich_help_panel="Claude Settings",
|
|
411
|
-
),
|
|
412
|
-
] = None,
|
|
413
|
-
max_turns: Annotated[
|
|
414
|
-
int | None,
|
|
415
|
-
typer.Option(
|
|
416
|
-
"--max-turns",
|
|
417
|
-
help="Maximum conversation turns",
|
|
418
|
-
callback=validate_max_turns,
|
|
419
|
-
rich_help_panel="Claude Settings",
|
|
420
|
-
),
|
|
421
|
-
] = None,
|
|
422
|
-
cwd: Annotated[
|
|
423
|
-
str | None,
|
|
424
|
-
typer.Option(
|
|
425
|
-
"--cwd",
|
|
426
|
-
help="Working directory path",
|
|
427
|
-
callback=validate_cwd,
|
|
428
|
-
rich_help_panel="Claude Settings",
|
|
429
|
-
),
|
|
430
|
-
] = None,
|
|
431
|
-
permission_prompt_tool_name: Annotated[
|
|
432
|
-
str | None,
|
|
433
|
-
typer.Option(
|
|
434
|
-
"--permission-prompt-tool-name",
|
|
435
|
-
help="Permission prompt tool name",
|
|
436
|
-
rich_help_panel="Claude Settings",
|
|
437
|
-
),
|
|
438
|
-
] = None,
|
|
439
|
-
sdk_message_mode: Annotated[
|
|
440
|
-
str | None,
|
|
441
|
-
typer.Option(
|
|
442
|
-
"--sdk-message-mode",
|
|
443
|
-
help="SDK message handling mode: forward (direct SDK blocks), ignore (skip blocks), formatted (XML tags with JSON data)",
|
|
444
|
-
callback=validate_sdk_message_mode,
|
|
445
|
-
rich_help_panel="Claude Settings",
|
|
446
|
-
),
|
|
447
|
-
] = None,
|
|
448
|
-
sdk_pool: Annotated[
|
|
449
|
-
bool,
|
|
450
|
-
typer.Option(
|
|
451
|
-
"--sdk-pool/--no-sdk-pool",
|
|
452
|
-
help="Enable/disable general Claude SDK client connection pooling",
|
|
453
|
-
rich_help_panel="Claude Settings",
|
|
454
|
-
),
|
|
455
|
-
] = False,
|
|
456
|
-
sdk_pool_size: Annotated[
|
|
457
|
-
int | None,
|
|
458
|
-
typer.Option(
|
|
459
|
-
"--sdk-pool-size",
|
|
460
|
-
help="Number of clients to maintain in the general pool (1-20)",
|
|
461
|
-
callback=validate_pool_size,
|
|
462
|
-
rich_help_panel="Claude Settings",
|
|
463
|
-
),
|
|
464
|
-
] = None,
|
|
465
|
-
sdk_session_pool: Annotated[
|
|
466
|
-
bool,
|
|
467
|
-
typer.Option(
|
|
468
|
-
"--sdk-session-pool/--no-sdk-session-pool",
|
|
469
|
-
help="Enable/disable session-aware Claude SDK client pooling",
|
|
470
|
-
rich_help_panel="Claude Settings",
|
|
471
|
-
),
|
|
472
|
-
] = False,
|
|
473
|
-
system_prompt_injection_mode: Annotated[
|
|
474
|
-
str | None,
|
|
475
|
-
typer.Option(
|
|
476
|
-
"--system-prompt-injection-mode",
|
|
477
|
-
help="System prompt injection mode: minimal (Claude Code ID only), full (all detected system messages)",
|
|
478
|
-
callback=validate_system_prompt_injection_mode,
|
|
479
|
-
rich_help_panel="Claude Settings",
|
|
480
|
-
),
|
|
481
|
-
] = None,
|
|
482
|
-
builtin_permissions: Annotated[
|
|
483
|
-
bool,
|
|
484
|
-
typer.Option(
|
|
485
|
-
"--builtin-permissions/--no-builtin-permissions",
|
|
486
|
-
help="Enable built-in permission handling infrastructure (MCP server and SSE endpoints). When disabled, users can configure custom MCP servers and permission tools.",
|
|
487
|
-
rich_help_panel="Claude Settings",
|
|
488
|
-
),
|
|
489
|
-
] = True,
|
|
490
|
-
# Core settings
|
|
491
|
-
docker: Annotated[
|
|
492
|
-
bool,
|
|
493
|
-
typer.Option(
|
|
494
|
-
"--docker",
|
|
495
|
-
"-d",
|
|
496
|
-
help="Run API server using Docker instead of local execution",
|
|
497
|
-
),
|
|
498
|
-
] = False,
|
|
499
|
-
# Docker settings using shared parameters
|
|
500
|
-
docker_image: Annotated[
|
|
501
|
-
str | None,
|
|
502
|
-
typer.Option(
|
|
503
|
-
"--docker-image",
|
|
504
|
-
help="Docker image to use (overrides configuration)",
|
|
505
|
-
rich_help_panel="Docker Settings",
|
|
506
|
-
),
|
|
507
|
-
] = None,
|
|
508
|
-
docker_env: Annotated[
|
|
509
|
-
list[str] | None,
|
|
510
|
-
typer.Option(
|
|
511
|
-
"--docker-env",
|
|
512
|
-
"-e",
|
|
513
|
-
help="Environment variables to pass to Docker container",
|
|
514
|
-
rich_help_panel="Docker Settings",
|
|
515
|
-
),
|
|
516
|
-
] = None,
|
|
517
|
-
docker_volume: Annotated[
|
|
163
|
+
enable_plugin: Annotated[
|
|
518
164
|
list[str] | None,
|
|
519
165
|
typer.Option(
|
|
520
|
-
"--
|
|
521
|
-
"
|
|
522
|
-
|
|
523
|
-
rich_help_panel="Docker Settings",
|
|
166
|
+
"--enable-plugin",
|
|
167
|
+
help="Enable a plugin by name (repeatable)",
|
|
168
|
+
rich_help_panel="Plugin Settings",
|
|
524
169
|
),
|
|
525
170
|
] = None,
|
|
526
|
-
|
|
171
|
+
disable_plugin: Annotated[
|
|
527
172
|
list[str] | None,
|
|
528
173
|
typer.Option(
|
|
529
|
-
"--
|
|
530
|
-
help="
|
|
531
|
-
rich_help_panel="
|
|
532
|
-
),
|
|
533
|
-
] = None,
|
|
534
|
-
docker_home: Annotated[
|
|
535
|
-
str | None,
|
|
536
|
-
typer.Option(
|
|
537
|
-
"--docker-home",
|
|
538
|
-
help="Override the home directory for Docker",
|
|
539
|
-
rich_help_panel="Docker Settings",
|
|
174
|
+
"--disable-plugin",
|
|
175
|
+
help="Disable a plugin by name (repeatable)",
|
|
176
|
+
rich_help_panel="Plugin Settings",
|
|
540
177
|
),
|
|
541
178
|
] = None,
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
typer.Option(
|
|
545
|
-
"--docker-workspace",
|
|
546
|
-
help="Override the workspace directory for Docker",
|
|
547
|
-
rich_help_panel="Docker Settings",
|
|
548
|
-
),
|
|
549
|
-
] = None,
|
|
550
|
-
user_mapping_enabled: Annotated[
|
|
551
|
-
bool | None,
|
|
552
|
-
typer.Option(
|
|
553
|
-
"--user-mapping/--no-user-mapping",
|
|
554
|
-
help="Enable user mapping for Docker",
|
|
555
|
-
rich_help_panel="Docker Settings",
|
|
556
|
-
),
|
|
557
|
-
] = None,
|
|
558
|
-
user_uid: Annotated[
|
|
559
|
-
int | None,
|
|
560
|
-
typer.Option(
|
|
561
|
-
"--user-uid",
|
|
562
|
-
help="User UID for Docker user mapping",
|
|
563
|
-
rich_help_panel="Docker Settings",
|
|
564
|
-
),
|
|
565
|
-
] = None,
|
|
566
|
-
user_gid: Annotated[
|
|
567
|
-
int | None,
|
|
568
|
-
typer.Option(
|
|
569
|
-
"--user-gid",
|
|
570
|
-
help="User GID for Docker user mapping",
|
|
571
|
-
rich_help_panel="Docker Settings",
|
|
572
|
-
),
|
|
573
|
-
] = None,
|
|
574
|
-
# Network control flags
|
|
575
|
-
no_network_calls: Annotated[
|
|
576
|
-
bool,
|
|
577
|
-
typer.Option(
|
|
578
|
-
"--no-network-calls",
|
|
579
|
-
help="Disable all network calls (version checks and pricing updates)",
|
|
580
|
-
rich_help_panel="Privacy Settings",
|
|
581
|
-
),
|
|
582
|
-
] = False,
|
|
583
|
-
disable_version_check: Annotated[
|
|
584
|
-
bool,
|
|
585
|
-
typer.Option(
|
|
586
|
-
"--disable-version-check",
|
|
587
|
-
help="Disable version update checks (prevents calls to GitHub API)",
|
|
588
|
-
rich_help_panel="Privacy Settings",
|
|
589
|
-
),
|
|
590
|
-
] = False,
|
|
591
|
-
disable_pricing_updates: Annotated[
|
|
592
|
-
bool,
|
|
593
|
-
typer.Option(
|
|
594
|
-
"--disable-pricing-updates",
|
|
595
|
-
help="Disable pricing data updates (prevents downloads from GitHub)",
|
|
596
|
-
rich_help_panel="Privacy Settings",
|
|
597
|
-
),
|
|
598
|
-
] = False,
|
|
179
|
+
# Removed unused flags: plugin_setting, no_network_calls,
|
|
180
|
+
# disable_version_check, disable_pricing_updates
|
|
599
181
|
) -> None:
|
|
600
|
-
"""
|
|
601
|
-
Start the CCProxy API server.
|
|
602
|
-
|
|
603
|
-
This command starts the API server either locally or in Docker.
|
|
604
|
-
The server provides both Anthropic and OpenAI-compatible endpoints.
|
|
605
|
-
|
|
606
|
-
All configuration options can be provided via CLI parameters,
|
|
607
|
-
which override values from configuration files and environment variables.
|
|
608
|
-
|
|
609
|
-
Examples:
|
|
610
|
-
ccproxy serve
|
|
611
|
-
ccproxy serve --port 8080 --reload
|
|
612
|
-
ccproxy serve --docker
|
|
613
|
-
ccproxy serve --docker --docker-image custom:latest --port 8080
|
|
614
|
-
ccproxy serve --max-thinking-tokens 10000 --allowed-tools Read,Write,Bash
|
|
615
|
-
ccproxy serve --port 8080 --workers 4
|
|
616
|
-
"""
|
|
182
|
+
"""Start the CCProxy API server."""
|
|
617
183
|
try:
|
|
618
|
-
# Early logging - use basic print until logging is configured
|
|
619
|
-
# We'll log this properly after logging is configured
|
|
620
|
-
|
|
621
|
-
# Get config path from context if not provided directly
|
|
622
184
|
if config is None:
|
|
623
185
|
config = get_config_path_from_context()
|
|
624
186
|
|
|
625
|
-
#
|
|
626
|
-
|
|
627
|
-
port
|
|
628
|
-
host
|
|
629
|
-
reload
|
|
630
|
-
log_level
|
|
631
|
-
log_file
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
system_prompt_injection_mode=system_prompt_injection_mode,
|
|
650
|
-
builtin_permissions=builtin_permissions,
|
|
651
|
-
)
|
|
652
|
-
|
|
653
|
-
security_options = SecurityOptions(auth_token=auth_token)
|
|
654
|
-
|
|
655
|
-
# Handle network control flags
|
|
656
|
-
scheduler_overrides = {}
|
|
657
|
-
if no_network_calls:
|
|
658
|
-
# Disable both network features
|
|
659
|
-
scheduler_overrides["pricing_update_enabled"] = False
|
|
660
|
-
scheduler_overrides["version_check_enabled"] = False
|
|
661
|
-
else:
|
|
662
|
-
# Handle individual flags
|
|
663
|
-
if disable_pricing_updates:
|
|
664
|
-
scheduler_overrides["pricing_update_enabled"] = False
|
|
665
|
-
if disable_version_check:
|
|
666
|
-
scheduler_overrides["version_check_enabled"] = False
|
|
667
|
-
|
|
668
|
-
# Extract CLI overrides from structured option containers
|
|
669
|
-
cli_overrides = config_manager.get_cli_overrides_from_args(
|
|
670
|
-
# Server options
|
|
671
|
-
host=server_options.host,
|
|
672
|
-
port=server_options.port,
|
|
673
|
-
reload=server_options.reload,
|
|
674
|
-
log_level=server_options.log_level,
|
|
675
|
-
log_file=server_options.log_file,
|
|
676
|
-
use_terminal_confirmation_handler=server_options.use_terminal_confirmation_handler,
|
|
677
|
-
# Security options
|
|
678
|
-
auth_token=security_options.auth_token,
|
|
679
|
-
# Claude options
|
|
680
|
-
claude_cli_path=claude_options.claude_cli_path,
|
|
681
|
-
max_thinking_tokens=claude_options.max_thinking_tokens,
|
|
682
|
-
allowed_tools=claude_options.allowed_tools,
|
|
683
|
-
disallowed_tools=claude_options.disallowed_tools,
|
|
684
|
-
append_system_prompt=claude_options.append_system_prompt,
|
|
685
|
-
permission_mode=claude_options.permission_mode,
|
|
686
|
-
max_turns=claude_options.max_turns,
|
|
687
|
-
permission_prompt_tool_name=claude_options.permission_prompt_tool_name,
|
|
688
|
-
cwd=claude_options.cwd,
|
|
689
|
-
sdk_message_mode=claude_options.sdk_message_mode,
|
|
690
|
-
sdk_pool=claude_options.sdk_pool,
|
|
691
|
-
sdk_pool_size=claude_options.sdk_pool_size,
|
|
692
|
-
sdk_session_pool=claude_options.sdk_session_pool,
|
|
693
|
-
system_prompt_injection_mode=claude_options.system_prompt_injection_mode,
|
|
694
|
-
builtin_permissions=claude_options.builtin_permissions,
|
|
695
|
-
)
|
|
696
|
-
|
|
697
|
-
# Add scheduler overrides if any
|
|
698
|
-
if scheduler_overrides:
|
|
699
|
-
cli_overrides["scheduler"] = scheduler_overrides
|
|
700
|
-
|
|
701
|
-
# Load settings with CLI overrides
|
|
702
|
-
settings = config_manager.load_settings(
|
|
703
|
-
config_path=config, cli_overrides=cli_overrides
|
|
704
|
-
)
|
|
187
|
+
# Base CLI context; plugin-injected args merged below
|
|
188
|
+
cli_context = {
|
|
189
|
+
"port": port,
|
|
190
|
+
"host": host,
|
|
191
|
+
"reload": reload,
|
|
192
|
+
"log_level": log_level,
|
|
193
|
+
"log_file": log_file,
|
|
194
|
+
"auth_token": auth_token,
|
|
195
|
+
"enabled_plugins": enable_plugin,
|
|
196
|
+
"disabled_plugins": disable_plugin,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
# Merge plugin-provided CLI args via helper
|
|
200
|
+
try:
|
|
201
|
+
from ccproxy.cli.helpers import get_plugin_cli_args
|
|
202
|
+
|
|
203
|
+
plugin_args = get_plugin_cli_args()
|
|
204
|
+
if plugin_args:
|
|
205
|
+
cli_context.update(plugin_args)
|
|
206
|
+
except Exception:
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
# Pass CLI context to settings creation
|
|
210
|
+
settings = Settings.from_config(config_path=config, cli_context=cli_context)
|
|
705
211
|
|
|
706
|
-
# Set up logging once with the effective log level
|
|
707
|
-
# Import here to avoid circular import
|
|
708
|
-
|
|
709
|
-
from ccproxy.core.logging import setup_logging
|
|
710
|
-
|
|
711
|
-
# Always reconfigure logging to ensure log level changes are picked up
|
|
712
|
-
# Use JSON logs if explicitly requested via env var
|
|
713
212
|
setup_logging(
|
|
714
|
-
json_logs=settings.
|
|
715
|
-
log_level_name=settings.
|
|
716
|
-
log_file=settings.
|
|
213
|
+
json_logs=settings.logging.format == "json",
|
|
214
|
+
log_level_name=settings.logging.level,
|
|
215
|
+
log_file=settings.logging.file,
|
|
717
216
|
)
|
|
718
217
|
|
|
719
|
-
# Re-get logger after logging is configured
|
|
720
218
|
logger = get_logger(__name__)
|
|
721
219
|
|
|
722
|
-
# Test debug logging
|
|
723
|
-
logger.debug(
|
|
724
|
-
"Debug logging is enabled",
|
|
725
|
-
effective_log_level=server_options.log_level or settings.server.log_level,
|
|
726
|
-
)
|
|
727
|
-
|
|
728
|
-
# Log CLI command that was deferred
|
|
729
|
-
logger.info(
|
|
730
|
-
"cli_command_starting",
|
|
731
|
-
command="serve",
|
|
732
|
-
version=__version__,
|
|
733
|
-
docker=docker,
|
|
734
|
-
port=server_options.port,
|
|
735
|
-
host=server_options.host,
|
|
736
|
-
config_path=str(config) if config else None,
|
|
737
|
-
)
|
|
738
|
-
|
|
739
|
-
# Log effective configuration
|
|
740
220
|
logger.debug(
|
|
741
221
|
"configuration_loaded",
|
|
742
222
|
host=settings.server.host,
|
|
743
223
|
port=settings.server.port,
|
|
744
|
-
log_level=settings.
|
|
745
|
-
log_file=settings.
|
|
746
|
-
docker_mode=docker,
|
|
747
|
-
docker_image=settings.docker.docker_image if docker else None,
|
|
224
|
+
log_level=settings.logging.level,
|
|
225
|
+
log_file=settings.logging.file,
|
|
748
226
|
auth_enabled=bool(settings.security.auth_token),
|
|
749
|
-
duckdb_enabled=
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
else None,
|
|
753
|
-
claude_cli_path=settings.claude.cli_path,
|
|
227
|
+
duckdb_enabled=bool(
|
|
228
|
+
(settings.plugins.get("duckdb_storage") or {}).get("enabled", False)
|
|
229
|
+
),
|
|
754
230
|
)
|
|
755
231
|
|
|
756
|
-
|
|
757
|
-
_run_docker_server(
|
|
758
|
-
settings,
|
|
759
|
-
docker_image=docker_image,
|
|
760
|
-
docker_env=docker_env,
|
|
761
|
-
docker_volume=docker_volume,
|
|
762
|
-
docker_arg=docker_arg,
|
|
763
|
-
docker_home=docker_home,
|
|
764
|
-
docker_workspace=docker_workspace,
|
|
765
|
-
user_mapping_enabled=user_mapping_enabled,
|
|
766
|
-
user_uid=user_uid,
|
|
767
|
-
user_gid=user_gid,
|
|
768
|
-
)
|
|
769
|
-
else:
|
|
770
|
-
_run_local_server(settings, cli_overrides)
|
|
232
|
+
_run_local_server(settings)
|
|
771
233
|
|
|
772
234
|
except ConfigurationError as e:
|
|
773
235
|
toolkit = get_rich_toolkit()
|
|
774
236
|
toolkit.print(f"Configuration error: {e}", tag="error")
|
|
775
237
|
raise typer.Exit(1) from e
|
|
776
|
-
except
|
|
238
|
+
except OSError as e:
|
|
777
239
|
toolkit = get_rich_toolkit()
|
|
778
|
-
toolkit.print(
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
def claude(
|
|
783
|
-
args: Annotated[
|
|
784
|
-
list[str] | None,
|
|
785
|
-
typer.Argument(
|
|
786
|
-
help="Arguments to pass to claude CLI (e.g. --version, doctor, config)",
|
|
787
|
-
),
|
|
788
|
-
] = None,
|
|
789
|
-
docker: Annotated[
|
|
790
|
-
bool,
|
|
791
|
-
typer.Option(
|
|
792
|
-
"--docker",
|
|
793
|
-
"-d",
|
|
794
|
-
help="Run claude command from docker image instead of local CLI",
|
|
795
|
-
),
|
|
796
|
-
] = False,
|
|
797
|
-
# Docker settings using shared parameters
|
|
798
|
-
docker_image: Annotated[
|
|
799
|
-
str | None,
|
|
800
|
-
typer.Option(
|
|
801
|
-
"--docker-image",
|
|
802
|
-
help="Docker image to use (overrides configuration)",
|
|
803
|
-
rich_help_panel="Docker Settings",
|
|
804
|
-
),
|
|
805
|
-
] = None,
|
|
806
|
-
docker_env: Annotated[
|
|
807
|
-
list[str] | None,
|
|
808
|
-
typer.Option(
|
|
809
|
-
"--docker-env",
|
|
810
|
-
"-e",
|
|
811
|
-
help="Environment variables to pass to Docker container",
|
|
812
|
-
rich_help_panel="Docker Settings",
|
|
813
|
-
),
|
|
814
|
-
] = None,
|
|
815
|
-
docker_volume: Annotated[
|
|
816
|
-
list[str] | None,
|
|
817
|
-
typer.Option(
|
|
818
|
-
"--docker-volume",
|
|
819
|
-
"-v",
|
|
820
|
-
help="Volume mounts for Docker container",
|
|
821
|
-
rich_help_panel="Docker Settings",
|
|
822
|
-
),
|
|
823
|
-
] = None,
|
|
824
|
-
docker_arg: Annotated[
|
|
825
|
-
list[str] | None,
|
|
826
|
-
typer.Option(
|
|
827
|
-
"--docker-arg",
|
|
828
|
-
help="Additional arguments to pass to docker run",
|
|
829
|
-
rich_help_panel="Docker Settings",
|
|
830
|
-
),
|
|
831
|
-
] = None,
|
|
832
|
-
docker_home: Annotated[
|
|
833
|
-
str | None,
|
|
834
|
-
typer.Option(
|
|
835
|
-
"--docker-home",
|
|
836
|
-
help="Override the home directory for Docker",
|
|
837
|
-
rich_help_panel="Docker Settings",
|
|
838
|
-
),
|
|
839
|
-
] = None,
|
|
840
|
-
docker_workspace: Annotated[
|
|
841
|
-
str | None,
|
|
842
|
-
typer.Option(
|
|
843
|
-
"--docker-workspace",
|
|
844
|
-
help="Override the workspace directory for Docker",
|
|
845
|
-
rich_help_panel="Docker Settings",
|
|
846
|
-
),
|
|
847
|
-
] = None,
|
|
848
|
-
user_mapping_enabled: Annotated[
|
|
849
|
-
bool | None,
|
|
850
|
-
typer.Option(
|
|
851
|
-
"--user-mapping/--no-user-mapping",
|
|
852
|
-
help="Enable user mapping for Docker",
|
|
853
|
-
rich_help_panel="Docker Settings",
|
|
854
|
-
),
|
|
855
|
-
] = None,
|
|
856
|
-
user_uid: Annotated[
|
|
857
|
-
int | None,
|
|
858
|
-
typer.Option(
|
|
859
|
-
"--user-uid",
|
|
860
|
-
help="User UID for Docker user mapping",
|
|
861
|
-
rich_help_panel="Docker Settings",
|
|
862
|
-
),
|
|
863
|
-
] = None,
|
|
864
|
-
user_gid: Annotated[
|
|
865
|
-
int | None,
|
|
866
|
-
typer.Option(
|
|
867
|
-
"--user-gid",
|
|
868
|
-
help="User GID for Docker user mapping",
|
|
869
|
-
rich_help_panel="Docker Settings",
|
|
870
|
-
),
|
|
871
|
-
] = None,
|
|
872
|
-
) -> None:
|
|
873
|
-
"""
|
|
874
|
-
Execute claude CLI commands directly.
|
|
875
|
-
|
|
876
|
-
This is a simple pass-through to the claude CLI executable
|
|
877
|
-
found by the settings system or run from docker image.
|
|
878
|
-
|
|
879
|
-
Examples:
|
|
880
|
-
ccproxy claude -- --version
|
|
881
|
-
ccproxy claude -- doctor
|
|
882
|
-
ccproxy claude -- config
|
|
883
|
-
ccproxy claude --docker -- --version
|
|
884
|
-
ccproxy claude --docker --docker-image custom:latest -- --version
|
|
885
|
-
ccproxy claude --docker --docker-env API_KEY=sk-... --docker-volume ./data:/data -- chat
|
|
886
|
-
"""
|
|
887
|
-
# Handle None args case
|
|
888
|
-
if args is None:
|
|
889
|
-
args = []
|
|
890
|
-
|
|
891
|
-
toolkit = get_rich_toolkit()
|
|
892
|
-
|
|
893
|
-
try:
|
|
894
|
-
# Logger will be configured by configuration manager
|
|
895
|
-
logger = get_logger(__name__)
|
|
896
|
-
# Log CLI command execution start
|
|
897
|
-
logger.info(
|
|
898
|
-
"cli_command_starting",
|
|
899
|
-
command="claude",
|
|
900
|
-
version=__version__,
|
|
901
|
-
docker=docker,
|
|
902
|
-
args=args if args else [],
|
|
903
|
-
)
|
|
904
|
-
|
|
905
|
-
# Load settings using configuration manager
|
|
906
|
-
settings = config_manager.load_settings(
|
|
907
|
-
config_path=get_config_path_from_context()
|
|
240
|
+
toolkit.print(
|
|
241
|
+
f"Server startup failed (port/permission issue): {e}", tag="error"
|
|
908
242
|
)
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
toolkit.print_title(f"image {settings.docker.docker_image}", tag="docker")
|
|
914
|
-
image, volumes, environment, command, user_context, additional_args = (
|
|
915
|
-
_create_docker_adapter_from_settings(
|
|
916
|
-
settings,
|
|
917
|
-
docker_image=docker_image,
|
|
918
|
-
docker_env=docker_env,
|
|
919
|
-
docker_volume=docker_volume,
|
|
920
|
-
docker_arg=docker_arg,
|
|
921
|
-
docker_home=docker_home,
|
|
922
|
-
docker_workspace=docker_workspace,
|
|
923
|
-
user_mapping_enabled=user_mapping_enabled,
|
|
924
|
-
user_uid=user_uid,
|
|
925
|
-
user_gid=user_gid,
|
|
926
|
-
command=["claude"],
|
|
927
|
-
cmd_args=args,
|
|
928
|
-
)
|
|
929
|
-
)
|
|
930
|
-
|
|
931
|
-
cmd_str = " ".join(command or [])
|
|
932
|
-
logger.info(
|
|
933
|
-
"docker_execution",
|
|
934
|
-
image=image,
|
|
935
|
-
command=" ".join(command or []),
|
|
936
|
-
volumes_count=len(volumes),
|
|
937
|
-
env_vars_count=len(environment),
|
|
938
|
-
)
|
|
939
|
-
toolkit.print(f"Executing: docker run ... {image} {cmd_str}", tag="docker")
|
|
940
|
-
toolkit.print_line()
|
|
941
|
-
|
|
942
|
-
# Execute using the new Docker adapter
|
|
943
|
-
adapter = create_docker_adapter()
|
|
944
|
-
adapter.exec_container(
|
|
945
|
-
image=image,
|
|
946
|
-
volumes=volumes,
|
|
947
|
-
environment=environment,
|
|
948
|
-
command=command,
|
|
949
|
-
user_context=user_context,
|
|
950
|
-
)
|
|
951
|
-
else:
|
|
952
|
-
# Get claude path from settings
|
|
953
|
-
claude_path = settings.claude.cli_path
|
|
954
|
-
if not claude_path:
|
|
955
|
-
toolkit.print("Error: Claude CLI not found.", tag="error")
|
|
956
|
-
toolkit.print(
|
|
957
|
-
"Please install Claude CLI or configure claude_cli_path.",
|
|
958
|
-
tag="error",
|
|
959
|
-
)
|
|
960
|
-
raise typer.Exit(1)
|
|
961
|
-
|
|
962
|
-
# Resolve to absolute path
|
|
963
|
-
if not Path(claude_path).is_absolute():
|
|
964
|
-
claude_path = str(Path(claude_path).resolve())
|
|
965
|
-
|
|
966
|
-
logger.info("local_claude_execution", claude_path=claude_path, args=args)
|
|
967
|
-
toolkit.print(f"Executing: {claude_path} {' '.join(args)}", tag="claude")
|
|
968
|
-
toolkit.print_line()
|
|
969
|
-
|
|
970
|
-
# Execute command directly
|
|
971
|
-
try:
|
|
972
|
-
# Use os.execvp to replace current process with claude
|
|
973
|
-
# This hands over full control to claude, including signal handling
|
|
974
|
-
os.execvp(claude_path, [claude_path] + args)
|
|
975
|
-
except OSError as e:
|
|
976
|
-
toolkit.print(f"Failed to execute command: {e}", tag="error")
|
|
977
|
-
raise typer.Exit(1) from e
|
|
978
|
-
|
|
979
|
-
except ConfigurationError as e:
|
|
980
|
-
logger.error("cli_configuration_error", error=str(e), command="claude")
|
|
981
|
-
toolkit.print(f"Configuration error: {e}", tag="error")
|
|
243
|
+
raise typer.Exit(1) from e
|
|
244
|
+
except ImportError as e:
|
|
245
|
+
toolkit = get_rich_toolkit()
|
|
246
|
+
toolkit.print(f"Import error during server startup: {e}", tag="error")
|
|
982
247
|
raise typer.Exit(1) from e
|
|
983
248
|
except Exception as e:
|
|
984
|
-
|
|
985
|
-
toolkit.print(f"Error
|
|
249
|
+
toolkit = get_rich_toolkit()
|
|
250
|
+
toolkit.print(f"Error starting server: {e}", tag="error")
|
|
986
251
|
raise typer.Exit(1) from e
|