ccproxy-api 0.1.7__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 +434 -219
- ccproxy/api/bootstrap.py +30 -0
- ccproxy/api/decorators.py +85 -0
- ccproxy/api/dependencies.py +144 -168
- ccproxy/api/format_validation.py +54 -0
- ccproxy/api/middleware/cors.py +6 -3
- ccproxy/api/middleware/errors.py +388 -524
- 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 +540 -19
- ccproxy/data/codex_headers_fallback.json +114 -7
- 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 +61 -105
- ccproxy/scheduler/registry.py +6 -32
- ccproxy/scheduler/tasks.py +268 -276
- 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 +68 -446
- ccproxy/utils/version_checker.py +273 -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.7.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 -1251
- 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 -243
- ccproxy/services/codex_detection_service.py +0 -252
- 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.7.dist-info/METADATA +0 -615
- ccproxy_api-0.1.7.dist-info/RECORD +0 -191
- ccproxy_api-0.1.7.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.7.dist-info → ccproxy_api-0.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""Status command for displaying system information."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from rich import box
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
from rich.text import Text
|
|
9
|
+
|
|
10
|
+
from ccproxy.cli.helpers import get_rich_toolkit
|
|
11
|
+
from ccproxy.config.settings import Settings
|
|
12
|
+
from ccproxy.core._version import __version__
|
|
13
|
+
from ccproxy.core.logging import get_logger
|
|
14
|
+
from ccproxy.core.status_report import (
|
|
15
|
+
ConfigSnapshot,
|
|
16
|
+
PluginSnapshot,
|
|
17
|
+
SystemSnapshot,
|
|
18
|
+
collect_config_snapshot,
|
|
19
|
+
collect_plugin_snapshot,
|
|
20
|
+
collect_system_snapshot,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
app = typer.Typer(name="status", help="Show system status and information")
|
|
25
|
+
logger = get_logger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@app.callback(invoke_without_command=True)
|
|
29
|
+
def status_main(
|
|
30
|
+
ctx: typer.Context,
|
|
31
|
+
plugins: bool = typer.Option(
|
|
32
|
+
True, "--plugins/--no-plugins", help="Show plugin status"
|
|
33
|
+
),
|
|
34
|
+
config: bool = typer.Option(
|
|
35
|
+
True, "--config/--no-config", help="Show configuration info"
|
|
36
|
+
),
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Show CCProxy system status and configuration."""
|
|
39
|
+
if ctx.invoked_subcommand is not None:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
toolkit = get_rich_toolkit()
|
|
43
|
+
console = Console()
|
|
44
|
+
|
|
45
|
+
# Header
|
|
46
|
+
toolkit.print("[bold cyan]CCProxy Status[/bold cyan]", centered=True)
|
|
47
|
+
toolkit.print(f"Version: {__version__}", tag="info")
|
|
48
|
+
toolkit.print_line()
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
settings = Settings.from_config()
|
|
52
|
+
|
|
53
|
+
system_snapshot = collect_system_snapshot(settings)
|
|
54
|
+
_show_system_info(console, system_snapshot)
|
|
55
|
+
|
|
56
|
+
if config:
|
|
57
|
+
config_snapshot = collect_config_snapshot()
|
|
58
|
+
_show_config_info(console, config_snapshot)
|
|
59
|
+
|
|
60
|
+
if plugins:
|
|
61
|
+
plugin_snapshot = collect_plugin_snapshot(settings)
|
|
62
|
+
_show_plugin_status(console, plugin_snapshot)
|
|
63
|
+
|
|
64
|
+
except Exception as e:
|
|
65
|
+
logger.error("status_command_error", error=str(e), exc_info=e)
|
|
66
|
+
toolkit.print(f"[red]✗[/red] Error gathering status: {e}", tag="error")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _show_system_info(console: Console, snapshot: SystemSnapshot) -> None:
|
|
70
|
+
"""Show basic system information."""
|
|
71
|
+
table = Table(
|
|
72
|
+
show_header=False,
|
|
73
|
+
box=box.ROUNDED,
|
|
74
|
+
title="System Information",
|
|
75
|
+
title_style="bold white",
|
|
76
|
+
border_style="blue",
|
|
77
|
+
)
|
|
78
|
+
table.add_column("Property", style="cyan", no_wrap=True)
|
|
79
|
+
table.add_column("Value", style="white")
|
|
80
|
+
|
|
81
|
+
# Server configuration
|
|
82
|
+
table.add_row("Server Host", snapshot.host)
|
|
83
|
+
table.add_row("Server Port", str(snapshot.port))
|
|
84
|
+
table.add_row("Log Level", snapshot.log_level)
|
|
85
|
+
|
|
86
|
+
# Authentication
|
|
87
|
+
auth_token_status = (
|
|
88
|
+
"✓ Configured" if snapshot.auth_token_configured else "✗ Not set"
|
|
89
|
+
)
|
|
90
|
+
table.add_row("API Token", auth_token_status)
|
|
91
|
+
|
|
92
|
+
# Plugin directories
|
|
93
|
+
plugin_dirs = snapshot.plugin_directories
|
|
94
|
+
plugins_enabled = "✓ Enabled" if snapshot.plugins_enabled else "✗ Disabled"
|
|
95
|
+
table.add_row("Plugins", plugins_enabled)
|
|
96
|
+
|
|
97
|
+
# Show each plugin directory with existence check
|
|
98
|
+
for i, plugin_dir in enumerate(plugin_dirs):
|
|
99
|
+
dir_exists = "✓ Exists" if plugin_dir.exists else "✗ Missing"
|
|
100
|
+
dir_label = (
|
|
101
|
+
f"Plugin Directory {i + 1}" if len(plugin_dirs) > 1 else "Plugin Directory"
|
|
102
|
+
)
|
|
103
|
+
table.add_row(dir_label, f"{plugin_dir.path} ({dir_exists})")
|
|
104
|
+
|
|
105
|
+
console.print(table)
|
|
106
|
+
console.print()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _show_config_info(console: Console, snapshot: ConfigSnapshot) -> None:
|
|
110
|
+
"""Show configuration source information."""
|
|
111
|
+
if snapshot.sources:
|
|
112
|
+
info_text = Text()
|
|
113
|
+
info_text.append("Configuration Sources:\n", style="bold")
|
|
114
|
+
for source in snapshot.sources:
|
|
115
|
+
prefix = "✓" if source.exists else "✗"
|
|
116
|
+
info_text.append(f"{prefix} {source.path}\n")
|
|
117
|
+
|
|
118
|
+
console.print(Panel(info_text, title="Configuration", border_style="green"))
|
|
119
|
+
console.print()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _show_plugin_status(console: Console, snapshot: PluginSnapshot) -> None:
|
|
123
|
+
"""Show plugin discovery and status information."""
|
|
124
|
+
|
|
125
|
+
# Short-circuit if plugins are entirely disabled
|
|
126
|
+
if not snapshot.plugin_system_enabled:
|
|
127
|
+
table = Table(
|
|
128
|
+
show_header=True,
|
|
129
|
+
header_style="bold cyan",
|
|
130
|
+
box=box.ROUNDED,
|
|
131
|
+
title="Plugin Status",
|
|
132
|
+
title_style="bold white",
|
|
133
|
+
border_style="yellow",
|
|
134
|
+
)
|
|
135
|
+
table.add_column("Plugin", style="cyan", no_wrap=True)
|
|
136
|
+
table.add_column("Status", style="white", no_wrap=True)
|
|
137
|
+
table.add_column("Version", style="yellow")
|
|
138
|
+
table.add_column("Description", style="dim white")
|
|
139
|
+
|
|
140
|
+
table.add_row(
|
|
141
|
+
"Plugin System",
|
|
142
|
+
"[red]✗ Disabled[/red]",
|
|
143
|
+
"",
|
|
144
|
+
"Plugin system disabled in configuration",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
console.print(table)
|
|
148
|
+
console.print(
|
|
149
|
+
Panel(
|
|
150
|
+
"Plugin system is disabled. No plugins will be loaded or executed.",
|
|
151
|
+
title="Plugin Summary",
|
|
152
|
+
border_style="yellow",
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
if snapshot.configuration_notes:
|
|
156
|
+
_print_plugin_configuration_notes(console, snapshot.configuration_notes)
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
table = Table(
|
|
160
|
+
show_header=True,
|
|
161
|
+
header_style="bold cyan",
|
|
162
|
+
box=box.ROUNDED,
|
|
163
|
+
title="Plugin Status",
|
|
164
|
+
title_style="bold white",
|
|
165
|
+
border_style="green",
|
|
166
|
+
)
|
|
167
|
+
table.add_column("Plugin", style="cyan", no_wrap=True)
|
|
168
|
+
table.add_column("Status", style="white", no_wrap=True)
|
|
169
|
+
table.add_column("Version", style="yellow")
|
|
170
|
+
table.add_column("Description", style="dim white")
|
|
171
|
+
|
|
172
|
+
for info in snapshot.enabled_plugins:
|
|
173
|
+
status = "[green]✓ Enabled[/green]"
|
|
174
|
+
version = info.version or "unknown"
|
|
175
|
+
description = info.description or ""
|
|
176
|
+
|
|
177
|
+
if info.state == "error":
|
|
178
|
+
status = "[red]✗ Error[/red]"
|
|
179
|
+
error_message = info.error or "Unknown error"
|
|
180
|
+
preview = error_message[:50]
|
|
181
|
+
if len(error_message) > 50:
|
|
182
|
+
preview += "..."
|
|
183
|
+
description = f"Error: {preview}"
|
|
184
|
+
|
|
185
|
+
table.add_row(info.name, status, version, description)
|
|
186
|
+
|
|
187
|
+
for name in snapshot.disabled_plugins:
|
|
188
|
+
table.add_row(
|
|
189
|
+
name,
|
|
190
|
+
"[yellow]⦸ Disabled[/yellow]",
|
|
191
|
+
"unknown",
|
|
192
|
+
"Plugin disabled in configuration",
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
if not snapshot.enabled_plugins and not snapshot.disabled_plugins:
|
|
196
|
+
table.add_row("No plugins found", "[yellow]⚠ Warning[/yellow]", "", "")
|
|
197
|
+
|
|
198
|
+
console.print(table)
|
|
199
|
+
|
|
200
|
+
summary_text = Text()
|
|
201
|
+
summary_text.append(f"Total plugins: {snapshot.total_count} ", style="bold")
|
|
202
|
+
summary_text.append(f"(Enabled: {snapshot.enabled_count}, ", style="green")
|
|
203
|
+
summary_text.append(f"Disabled: {snapshot.disabled_count})", style="yellow")
|
|
204
|
+
|
|
205
|
+
console.print(Panel(summary_text, title="Plugin Summary", border_style="blue"))
|
|
206
|
+
|
|
207
|
+
if snapshot.configuration_notes:
|
|
208
|
+
_print_plugin_configuration_notes(console, snapshot.configuration_notes)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _print_plugin_configuration_notes(console: Console, notes: tuple[str, ...]) -> None:
|
|
212
|
+
config_text = Text()
|
|
213
|
+
config_text.append("Configuration: ", style="bold")
|
|
214
|
+
config_text.append(" • ".join(notes))
|
|
215
|
+
console.print(Panel(config_text, title="Plugin Configuration", border_style="blue"))
|
|
216
|
+
console.print()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@app.command()
|
|
220
|
+
def plugins() -> None:
|
|
221
|
+
"""Show detailed plugin information only."""
|
|
222
|
+
toolkit = get_rich_toolkit()
|
|
223
|
+
console = Console()
|
|
224
|
+
|
|
225
|
+
toolkit.print("[bold cyan]Plugin Status[/bold cyan]", centered=True)
|
|
226
|
+
toolkit.print_line()
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
settings = Settings.from_config()
|
|
230
|
+
plugin_snapshot = collect_plugin_snapshot(settings)
|
|
231
|
+
_show_plugin_status(console, plugin_snapshot)
|
|
232
|
+
except Exception as e:
|
|
233
|
+
logger.error("plugin_status_command_error", error=str(e), exc_info=e)
|
|
234
|
+
toolkit.print(f"[red]✗[/red] Error: {e}", tag="error")
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
@app.command()
|
|
238
|
+
def config() -> None:
|
|
239
|
+
"""Show configuration information only."""
|
|
240
|
+
toolkit = get_rich_toolkit()
|
|
241
|
+
console = Console()
|
|
242
|
+
|
|
243
|
+
toolkit.print("[bold cyan]Configuration Status[/bold cyan]", centered=True)
|
|
244
|
+
toolkit.print_line()
|
|
245
|
+
|
|
246
|
+
try:
|
|
247
|
+
settings = Settings.from_config()
|
|
248
|
+
system_snapshot = collect_system_snapshot(settings)
|
|
249
|
+
config_snapshot = collect_config_snapshot()
|
|
250
|
+
_show_system_info(console, system_snapshot)
|
|
251
|
+
_show_config_info(console, config_snapshot)
|
|
252
|
+
except Exception as e:
|
|
253
|
+
logger.error("config_status_command_error", error=str(e), exc_info=e)
|
|
254
|
+
toolkit.print(f"[red]✗[/red] Error: {e}", tag="error")
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""CLI command decorators for plugin dependency management."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from typing import Any, ParamSpec, TypeVar
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
P = ParamSpec("P")
|
|
8
|
+
R = TypeVar("R")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def needs_auth_provider() -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
12
|
+
"""Decorator to mark CLI commands that need an auth provider.
|
|
13
|
+
|
|
14
|
+
This decorator marks the command as requiring the auth provider specified
|
|
15
|
+
in the command arguments. The actual plugin loading is handled by the
|
|
16
|
+
command implementation using load_cli_plugins().
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
@app.command()
|
|
20
|
+
@needs_auth_provider()
|
|
21
|
+
async def auth_status(provider: str):
|
|
22
|
+
# Command implementation
|
|
23
|
+
pass
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def decorator(func: Callable[P, R]) -> Callable[P, R]:
|
|
27
|
+
# Add metadata to the function
|
|
28
|
+
func._needs_auth_provider = True # type: ignore
|
|
29
|
+
return func
|
|
30
|
+
|
|
31
|
+
return decorator
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def allows_plugins(
|
|
35
|
+
plugin_names: list[str],
|
|
36
|
+
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
37
|
+
"""Decorator to specify additional plugins a CLI command can use.
|
|
38
|
+
|
|
39
|
+
This decorator specifies additional CLI-safe plugins that the command
|
|
40
|
+
wants to use beyond the default set. These plugins must still be marked
|
|
41
|
+
as cli_safe = True to be loaded.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
plugin_names: List of plugin names to allow (e.g., ["request_tracer", "metrics"])
|
|
45
|
+
|
|
46
|
+
Usage:
|
|
47
|
+
@app.command()
|
|
48
|
+
@allows_plugins(["request_tracer", "metrics"])
|
|
49
|
+
async def my_command():
|
|
50
|
+
# Command implementation
|
|
51
|
+
pass
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def decorator(func: Callable[P, R]) -> Callable[P, R]:
|
|
55
|
+
# Add metadata to the function
|
|
56
|
+
func._allows_plugins = plugin_names # type: ignore
|
|
57
|
+
return func
|
|
58
|
+
|
|
59
|
+
return decorator
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_command_auth_provider(func: Callable[..., Any]) -> bool:
|
|
63
|
+
"""Check if a command needs an auth provider.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
func: Function to check
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
True if the command is decorated with @needs_auth_provider()
|
|
70
|
+
"""
|
|
71
|
+
return getattr(func, "_needs_auth_provider", False)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def get_command_allowed_plugins(func: Callable[..., Any]) -> list[str]:
|
|
75
|
+
"""Get the allowed plugins for a command.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
func: Function to check
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
List of allowed plugin names (empty list if none specified)
|
|
82
|
+
"""
|
|
83
|
+
return getattr(func, "_allows_plugins", [])
|
ccproxy/cli/helpers.py
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
+
import typer
|
|
6
7
|
from rich_toolkit import RichToolkit, RichToolkitTheme
|
|
7
8
|
from rich_toolkit.styles import TaggedStyle
|
|
8
9
|
|
|
9
|
-
from ccproxy.core.async_utils import patched_typing
|
|
10
|
-
|
|
11
10
|
|
|
12
11
|
def get_rich_toolkit() -> RichToolkit:
|
|
13
12
|
theme = RichToolkitTheme(
|
|
@@ -79,64 +78,27 @@ def link(text: str, link: str) -> str:
|
|
|
79
78
|
return f"[link={link}]{text}[/link]"
|
|
80
79
|
|
|
81
80
|
|
|
82
|
-
def
|
|
83
|
-
""
|
|
84
|
-
Create a new ClaudeCodeOptions instance by merging base options with overrides.
|
|
81
|
+
def is_running_in_docker() -> bool:
|
|
82
|
+
return Path("/.dockerenv").exists()
|
|
85
83
|
|
|
86
|
-
Args:
|
|
87
|
-
base_options: Base ClaudeCodeOptions instance to copy from
|
|
88
|
-
**overrides: Dictionary of option overrides
|
|
89
84
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"""
|
|
93
|
-
with patched_typing():
|
|
94
|
-
from claude_code_sdk import ClaudeCodeOptions
|
|
95
|
-
|
|
96
|
-
# Create a new options instance with the base values
|
|
97
|
-
options = ClaudeCodeOptions()
|
|
98
|
-
|
|
99
|
-
# Copy all attributes from base_options
|
|
100
|
-
if base_options:
|
|
101
|
-
for attr in [
|
|
102
|
-
"model",
|
|
103
|
-
"max_thinking_tokens",
|
|
104
|
-
"max_turns",
|
|
105
|
-
"cwd",
|
|
106
|
-
"system_prompt",
|
|
107
|
-
"append_system_prompt",
|
|
108
|
-
"permission_mode",
|
|
109
|
-
"permission_prompt_tool_name",
|
|
110
|
-
"continue_conversation",
|
|
111
|
-
"resume",
|
|
112
|
-
"allowed_tools",
|
|
113
|
-
"disallowed_tools",
|
|
114
|
-
"mcp_servers",
|
|
115
|
-
"mcp_tools",
|
|
116
|
-
# Anthropic API fields
|
|
117
|
-
"temperature",
|
|
118
|
-
"top_p",
|
|
119
|
-
"top_k",
|
|
120
|
-
"stop_sequences",
|
|
121
|
-
"tools",
|
|
122
|
-
"metadata",
|
|
123
|
-
"service_tier",
|
|
124
|
-
]:
|
|
125
|
-
if hasattr(base_options, attr):
|
|
126
|
-
base_value = getattr(base_options, attr)
|
|
127
|
-
if base_value is not None:
|
|
128
|
-
setattr(options, attr, base_value)
|
|
129
|
-
|
|
130
|
-
# Apply overrides
|
|
131
|
-
for key, value in overrides.items():
|
|
132
|
-
if value is not None and hasattr(options, key):
|
|
133
|
-
# Handle special type conversions for specific fields
|
|
134
|
-
if key == "cwd" and not isinstance(value, str):
|
|
135
|
-
value = str(value)
|
|
136
|
-
setattr(options, key, value)
|
|
137
|
-
|
|
138
|
-
return options
|
|
85
|
+
def get_plugin_cli_args(ctx: typer.Context | None = None) -> dict[str, Any]:
|
|
86
|
+
"""Return plugin-injected CLI args from Typer context.
|
|
139
87
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
88
|
+
Ensures a dict is returned. If no context is provided, attempts to fetch the
|
|
89
|
+
current Click/Typer context. This is safe to call from command bodies.
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
if ctx is None:
|
|
93
|
+
# Lazy import to avoid hard dependency when not in CLI execution
|
|
94
|
+
from click import get_current_context as _get_ctx
|
|
95
|
+
|
|
96
|
+
ctx = _get_ctx(silent=True) # type: ignore[assignment]
|
|
97
|
+
if ctx and getattr(ctx, "obj", None) and isinstance(ctx.obj, dict):
|
|
98
|
+
data = ctx.obj.get("plugin_cli_args")
|
|
99
|
+
if isinstance(data, dict):
|
|
100
|
+
# Only return non-None values to simplify merging
|
|
101
|
+
return {k: v for k, v in data.items() if v is not None}
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
104
|
+
return {}
|