From 1c72b4b8d5bf783bc3c6306d687065ac8eac9922 Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Wed, 29 Apr 2026 17:06:39 -0400 Subject: [PATCH] refactor(cliproxy): flatten module structure and colocate tests (#1135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Split types.ts (331 LOC) into 4 concern-based files under types/: platform-types, binary-types, provider-types, config-types - Preserve backward compat via barrel re-export (types.ts → types/index) - Reorganize 53 root-level files into 8 subdirectories: accounts/, ai-providers/, auth/, binary/, config/, executor/, management/, proxy/, quota/, routing/, services/, sync/ - Reduce src/cliproxy/ root from 65 to 8 files (target: ≤10) - Colocate 87 unit tests from tests/unit/cliproxy/ into src/cliproxy/*/__tests__/ (13 colocated test directories) - Update import paths across 40+ consumer files - Add TDD backward-compat test for types split Refs #1135 --- src/api/services/cliproxy-profile-bridge.ts | 8 +- .../services/profile-lifecycle-validation.ts | 2 +- src/api/services/profile-writer.ts | 2 +- .../ai-provider-service-stable-id.test.ts | 0 .../__tests__}/model-catalog-compat.test.ts | 4 +- .../cliproxy/__tests__}/model-catalog.test.js | 0 .../cliproxy/__tests__}/model-config.test.js | 0 .../__tests__}/provider-capabilities.test.ts | 6 +- .../__tests__}/session-tracker-port.test.js | 0 .../__tests__}/session-tracker-target.test.ts | 0 .../__tests__}/session-tracker.test.js | 0 .../__tests__}/thinking-arg-parser.test.ts | 2 +- .../thinking-override-resolver.test.ts | 4 +- .../__tests__}/thinking-validator.test.ts | 2 +- .../account-manager-discover.test.js | 38 +- .../account-registry-integrity.test.ts | 6 +- ...account-registry-optional-nickname.test.ts | 4 +- .../account-safety-quota-exhaustion.test.ts | 36 +- .../__tests__}/account-safety.test.ts | 2 +- .../{ => accounts}/account-manager.ts | 4 +- src/cliproxy/{ => accounts}/account-safety.ts | 12 +- .../{ => accounts}/account-stats-key.ts | 0 src/cliproxy/accounts/registry.ts | 2 +- src/cliproxy/accounts/token-file-ops.ts | 2 +- ...codex-plan-compatibility-reconcile.test.ts | 4 +- .../codex-plan-compatibility.test.ts | 4 +- ...x-reasoning-proxy-extended-context.test.ts | 4 +- .../__tests__}/codex-reasoning-proxy.test.js | 2 +- .../extended-context-config.test.ts | 2 +- .../__tests__}/managed-model-prefixes.test.ts | 2 +- .../__tests__}/model-id-normalizer.test.ts | 2 +- .../__tests__}/model-routing-hints.test.ts | 2 +- .../__tests__}/openai-compat-manager.test.js | 10 +- .../__tests__}/schema-sanitizer.test.ts | 2 +- .../__tests__}/tool-name-mapper.test.js | 2 +- .../__tests__}/tool-name-sanitizer.test.js | 2 +- .../codex-plan-compatibility.ts | 12 +- .../codex-reasoning-proxy.ts | 2 +- src/cliproxy/ai-providers/config-store.ts | 6 +- .../managed-model-prefixes.ts | 8 +- .../{ => ai-providers}/model-id-normalizer.ts | 4 +- .../openai-compat-manager.ts | 5 +- .../{ => ai-providers}/schema-sanitizer.ts | 0 .../{ => ai-providers}/tool-name-mapper.ts | 0 .../{ => ai-providers}/tool-name-sanitizer.ts | 0 .../antigravity-responsibility.test.ts | 2 +- .../__tests__}/auth-token-manager.test.js | 8 +- .../auth-types-management-path.test.ts | 2 +- .../auth/__tests__}/auth-utils.test.ts | 2 +- .../gemini-refresh-delegation.test.ts | 0 .../__tests__}/gitlab-pat-response.test.ts | 2 +- .../oauth-handler-paste-callback.test.ts | 40 +-- .../oauth-process-error-parser.test.ts | 2 +- .../auth/__tests__}/profile-mapper.test.ts | 4 +- .../auth/__tests__}/skip-local-auth.test.ts | 0 .../{ => auth}/antigravity-responsibility.ts | 4 +- src/cliproxy/{ => auth}/auth-handler.ts | 12 +- .../{ => auth}/auth-session-manager.ts | 0 src/cliproxy/{ => auth}/auth-token-manager.ts | 4 +- src/cliproxy/auth/auth-types.ts | 2 +- src/cliproxy/{ => auth}/auth-utils.ts | 0 .../{ => auth}/device-code-handler.ts | 0 src/cliproxy/auth/kiro-import.ts | 2 +- src/cliproxy/auth/oauth-handler.ts | 10 +- src/cliproxy/auth/oauth-process.ts | 8 +- .../{ => auth}/project-selection-handler.ts | 0 .../provider-entitlement-evidence.ts | 2 +- .../{ => auth}/provider-entitlement-types.ts | 2 +- .../auth/provider-refreshers/index.ts | 2 +- src/cliproxy/auth/token-expiry-checker.ts | 2 +- src/cliproxy/auth/token-manager.ts | 10 +- src/cliproxy/binary-manager.ts | 4 +- .../binary-downloader-proxy.test.ts | 2 +- .../binary-installer-etxtbsy.test.ts | 2 +- .../__tests__}/binary-manager-install.test.ts | 28 +- .../version-checker-stale-cache.test.ts | 0 src/cliproxy/binary/extractor.ts | 2 +- src/cliproxy/binary/installer.ts | 2 +- src/cliproxy/binary/lifecycle.ts | 6 +- .../{ => binary}/platform-detector.ts | 2 +- src/cliproxy/binary/tar-extractor.ts | 2 +- src/cliproxy/binary/version-cache.ts | 4 +- src/cliproxy/binary/version-checker.ts | 2 +- src/cliproxy/binary/zip-extractor.ts | 2 +- .../__tests__}/backend-selection.test.js | 4 +- .../backend-ui-default-ports-sync.test.ts | 12 +- .../backend-ui-provider-arrays-sync.test.ts | 4 +- .../__tests__}/base-config-loader.test.ts | 2 +- .../__tests__}/composite-validator.test.ts | 2 +- .../__tests__}/config-generator-port.test.js | 2 +- .../__tests__}/config-generator.test.js | 20 +- .../__tests__}/env-builder-migration.test.ts | 0 .../env-builder-provider-url.test.ts | 2 +- .../config/__tests__}/port-validation.test.ts | 4 +- .../{ => config}/base-config-loader.ts | 2 +- .../{ => config}/composite-validator.ts | 8 +- src/cliproxy/{ => config}/config-generator.ts | 2 +- src/cliproxy/config/env-builder.ts | 6 +- src/cliproxy/config/generator.ts | 6 +- src/cliproxy/{ => config}/model-config.ts | 12 +- src/cliproxy/config/thinking-config.ts | 2 +- .../__tests__}/composite-env-routing.test.ts | 2 +- .../__tests__}/composite-fallback.test.ts | 6 +- .../__tests__}/composite-thinking.test.ts | 4 +- .../composite-variant-service.test.ts | 6 +- .../env-resolver-codex-fallback.test.ts | 4 +- .../__tests__}/executor-option-value.test.ts | 2 +- .../variant-port-allocation.test.js | 4 +- .../variant-port-edge-cases.test.js | 6 +- .../variant-port-integration.test.js | 6 +- .../{ => executor}/cliproxy-executor.ts | 4 +- src/cliproxy/executor/env-resolver.ts | 14 +- src/cliproxy/executor/index.ts | 36 +- src/cliproxy/executor/lifecycle-manager.ts | 2 +- src/cliproxy/executor/retry-handler.ts | 6 +- src/cliproxy/executor/session-bridge.ts | 6 +- src/cliproxy/index.ts | 62 ++-- .../__tests__}/management-api-client.test.ts | 4 +- .../{ => management}/management-api-client.ts | 4 +- .../{ => management}/management-api-types.ts | 0 .../{ => management}/remote-token-uploader.ts | 4 +- src/cliproxy/model-catalog.ts | 2 +- .../__tests__}/https-tunnel-policy.test.ts | 2 +- .../__tests__}/https-tunnel-proxy.test.ts | 2 +- .../__tests__}/proxy-config-resolver.test.js | 2 +- .../__tests__}/proxy-detector-port.test.ts | 4 +- ...ool-sanitization-proxy-integration.test.ts | 2 +- .../{ => proxy}/https-tunnel-proxy.ts | 0 .../{ => proxy}/proxy-config-resolver.ts | 4 +- src/cliproxy/{ => proxy}/proxy-detector.ts | 10 +- .../{ => proxy}/proxy-target-resolver.ts | 8 +- .../{ => proxy}/tool-sanitization-proxy.ts | 12 +- .../quota-caching-integration.test.ts | 6 +- .../quota-fetcher-antigravity-failure.test.ts | 14 +- .../__tests__}/quota-fetcher-claude.test.ts | 4 +- .../__tests__}/quota-fetcher-codex.test.ts | 20 +- .../quota-fetcher-gemini-cli.test.ts | 16 +- .../__tests__}/quota-fetcher-ghcp.test.ts | 2 +- .../__tests__}/quota-monitor-runtime.test.ts | 4 +- .../__tests__}/quota-response-cache.test.ts | 2 +- .../gemini-cli-quota-normalizer.ts | 0 .../quota-fetcher-claude-normalizer.ts | 2 +- .../{ => quota}/quota-fetcher-claude.ts | 6 +- .../{ => quota}/quota-fetcher-codex.ts | 8 +- .../{ => quota}/quota-fetcher-gemini-cli.ts | 14 +- .../{ => quota}/quota-fetcher-ghcp.ts | 4 +- src/cliproxy/{ => quota}/quota-fetcher.ts | 14 +- src/cliproxy/{ => quota}/quota-manager.ts | 18 +- .../{ => quota}/quota-response-cache.ts | 0 src/cliproxy/{ => quota}/quota-types.ts | 2 +- .../__tests__}/routing-strategy-http.test.ts | 6 +- .../__tests__}/routing-strategy.test.ts | 4 +- .../{ => routing}/routing-strategy-http.ts | 2 +- .../{ => routing}/routing-strategy.ts | 8 +- src/cliproxy/service-manager.ts | 10 +- .../__tests__}/auto-sync-watcher.test.ts | 2 +- .../__tests__}/local-config-sync.test.ts | 2 +- .../__tests__}/remote-auth-fetcher.test.ts | 4 +- .../remote-proxy-chain-regression.test.ts | 4 +- .../__tests__}/remote-proxy-client.test.ts | 2 +- .../__tests__}/remote-token-uploader.test.ts | 2 +- .../service-manager-startup.test.ts | 2 +- .../__tests__}/stats-transformer.test.ts | 4 +- .../__tests__}/variant-update-service.test.ts | 4 +- src/cliproxy/services/binary-service.ts | 2 +- src/cliproxy/{ => services}/catalog-cache.ts | 14 +- .../{ => services}/catalog-routing.ts | 6 +- .../services/proxy-lifecycle-service.ts | 2 +- .../{ => services}/remote-auth-fetcher.ts | 6 +- .../{ => services}/remote-proxy-client.ts | 2 +- src/cliproxy/{ => services}/startup-lock.ts | 4 +- src/cliproxy/{ => services}/stats-fetcher.ts | 4 +- .../{ => services}/stats-transformer.ts | 6 +- .../services/variant-config-adapter.ts | 2 +- src/cliproxy/services/variant-service.ts | 6 +- src/cliproxy/services/variant-settings.ts | 6 +- src/cliproxy/session-tracker.ts | 4 +- src/cliproxy/sync/local-config-sync.ts | 4 +- src/cliproxy/sync/profile-mapper.ts | 2 +- src/cliproxy/types.ts | 333 +----------------- .../__tests__/types-backward-compat.test.ts | 127 +++++++ src/cliproxy/types/binary-types.ts | 59 ++++ src/cliproxy/types/config-types.ts | 92 +++++ src/cliproxy/types/index.ts | 4 + src/cliproxy/types/platform-types.ts | 20 ++ src/cliproxy/types/provider-types.ts | 52 +++ src/commands/cleanup-command.ts | 2 +- src/commands/cliproxy/auth-subcommand.ts | 2 +- src/commands/cliproxy/catalog-subcommand.ts | 10 +- src/commands/cliproxy/help-subcommand.ts | 2 +- src/commands/cliproxy/install-subcommand.ts | 2 +- .../cliproxy/proxy-lifecycle-subcommand.ts | 2 +- src/commands/cliproxy/quota-subcommand.ts | 18 +- src/commands/cliproxy/routing-subcommand.ts | 2 +- src/commands/cliproxy/variant-subcommand.ts | 8 +- src/commands/config-command.ts | 2 +- src/commands/tokens-command.ts | 2 +- src/config/unified-config-loader.ts | 2 +- src/copilot/copilot-executor.ts | 2 +- src/docker/docker-bootstrap.ts | 2 +- src/management/checks/image-analysis-check.ts | 4 +- src/shared/claude-extension-setup.ts | 2 +- .../hooks/get-image-analysis-hook-env.ts | 4 +- .../hooks/image-analysis-backend-resolver.ts | 2 +- .../hooks/image-analysis-runtime-status.ts | 10 +- src/web-server/health/cliproxy-checks.ts | 4 +- src/web-server/index.ts | 4 +- src/web-server/overview-routes.ts | 2 +- src/web-server/routes/account-routes.ts | 2 +- src/web-server/routes/catalog-routes.ts | 2 +- src/web-server/routes/cliproxy-auth-routes.ts | 20 +- .../routes/cliproxy-routing-routes.ts | 2 +- .../routes/cliproxy-stats-routes.ts | 24 +- .../routes/image-analysis-routes.ts | 2 +- src/web-server/routes/provider-routes.ts | 2 +- src/web-server/routes/proxy-routes.ts | 4 +- src/web-server/routes/route-helpers.ts | 2 +- src/web-server/routes/settings-routes.ts | 4 +- src/web-server/routes/variant-routes.ts | 2 +- .../cliproxy-dashboard-install-service.ts | 2 +- src/web-server/usage/cliproxy-usage-syncer.ts | 2 +- .../usage/cliproxy-usage-transformer.ts | 2 +- src/web-server/websocket.ts | 4 +- tests/unit/commands/cleanup-command.test.ts | 2 +- ...runtime-status-circular-dependency.test.ts | 12 +- 225 files changed, 935 insertions(+), 905 deletions(-) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/ai-provider-service-stable-id.test.ts (100%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/model-catalog-compat.test.ts (95%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/model-catalog.test.js (100%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/model-config.test.js (100%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/provider-capabilities.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/session-tracker-port.test.js (100%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/session-tracker-target.test.ts (100%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/session-tracker.test.js (100%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/thinking-arg-parser.test.ts (96%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/thinking-override-resolver.test.ts (94%) rename {tests/unit/cliproxy => src/cliproxy/__tests__}/thinking-validator.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/accounts/__tests__}/account-manager-discover.test.js (89%) rename {tests/unit/cliproxy => src/cliproxy/accounts/__tests__}/account-registry-integrity.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/accounts/__tests__}/account-registry-optional-nickname.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/accounts/__tests__}/account-safety-quota-exhaustion.test.ts (96%) rename {tests/unit/cliproxy => src/cliproxy/accounts/__tests__}/account-safety.test.ts (99%) rename src/cliproxy/{ => accounts}/account-manager.ts (97%) rename src/cliproxy/{ => accounts}/account-safety.ts (98%) rename src/cliproxy/{ => accounts}/account-stats-key.ts (100%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/codex-plan-compatibility-reconcile.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/codex-plan-compatibility.test.ts (95%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/codex-reasoning-proxy-extended-context.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/codex-reasoning-proxy.test.js (99%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/extended-context-config.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/managed-model-prefixes.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/model-id-normalizer.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/model-routing-hints.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/openai-compat-manager.test.js (89%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/schema-sanitizer.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/tool-name-mapper.test.js (98%) rename {tests/unit/cliproxy => src/cliproxy/ai-providers/__tests__}/tool-name-sanitizer.test.js (98%) rename src/cliproxy/{ => ai-providers}/codex-plan-compatibility.ts (93%) rename src/cliproxy/{ => ai-providers}/codex-reasoning-proxy.ts (99%) rename src/cliproxy/{ => ai-providers}/managed-model-prefixes.ts (94%) rename src/cliproxy/{ => ai-providers}/model-id-normalizer.ts (98%) rename src/cliproxy/{ => ai-providers}/openai-compat-manager.ts (96%) rename src/cliproxy/{ => ai-providers}/schema-sanitizer.ts (100%) rename src/cliproxy/{ => ai-providers}/tool-name-mapper.ts (100%) rename src/cliproxy/{ => ai-providers}/tool-name-sanitizer.ts (100%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/antigravity-responsibility.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/auth-token-manager.test.js (97%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/auth-types-management-path.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/auth-utils.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/gemini-refresh-delegation.test.ts (100%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/gitlab-pat-response.test.ts (94%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/oauth-handler-paste-callback.test.ts (86%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/oauth-process-error-parser.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/profile-mapper.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/auth/__tests__}/skip-local-auth.test.ts (100%) rename src/cliproxy/{ => auth}/antigravity-responsibility.ts (98%) rename src/cliproxy/{ => auth}/auth-handler.ts (90%) rename src/cliproxy/{ => auth}/auth-session-manager.ts (100%) rename src/cliproxy/{ => auth}/auth-token-manager.ts (98%) rename src/cliproxy/{ => auth}/auth-utils.ts (100%) rename src/cliproxy/{ => auth}/device-code-handler.ts (100%) rename src/cliproxy/{ => auth}/project-selection-handler.ts (100%) rename src/cliproxy/{ => auth}/provider-entitlement-evidence.ts (97%) rename src/cliproxy/{ => auth}/provider-entitlement-types.ts (93%) rename {tests/unit/cliproxy => src/cliproxy/binary/__tests__}/binary-downloader-proxy.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/binary/__tests__}/binary-installer-etxtbsy.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/binary/__tests__}/binary-manager-install.test.ts (84%) rename {tests/unit/cliproxy => src/cliproxy/binary/__tests__}/version-checker-stale-cache.test.ts (100%) rename src/cliproxy/{ => binary}/platform-detector.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/backend-selection.test.js (97%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/backend-ui-default-ports-sync.test.ts (90%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/backend-ui-provider-arrays-sync.test.ts (84%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/base-config-loader.test.ts (92%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/composite-validator.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/config-generator-port.test.js (99%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/config-generator.test.js (98%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/env-builder-migration.test.ts (100%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/env-builder-provider-url.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/config/__tests__}/port-validation.test.ts (97%) rename src/cliproxy/{ => config}/base-config-loader.ts (97%) rename src/cliproxy/{ => config}/composite-validator.ts (93%) rename src/cliproxy/{ => config}/config-generator.ts (95%) rename src/cliproxy/{ => config}/model-config.ts (96%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/composite-env-routing.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/composite-fallback.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/composite-thinking.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/composite-variant-service.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/env-resolver-codex-fallback.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/executor-option-value.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/variant-port-allocation.test.js (98%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/variant-port-edge-cases.test.js (98%) rename {tests/unit/cliproxy => src/cliproxy/executor/__tests__}/variant-port-integration.test.js (99%) rename src/cliproxy/{ => executor}/cliproxy-executor.ts (90%) rename {tests/unit/cliproxy => src/cliproxy/management/__tests__}/management-api-client.test.ts (99%) rename src/cliproxy/{ => management}/management-api-client.ts (99%) rename src/cliproxy/{ => management}/management-api-types.ts (100%) rename src/cliproxy/{ => management}/remote-token-uploader.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/proxy/__tests__}/https-tunnel-policy.test.ts (93%) rename {tests/unit/cliproxy => src/cliproxy/proxy/__tests__}/https-tunnel-proxy.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/proxy/__tests__}/proxy-config-resolver.test.js (99%) rename {tests/unit/cliproxy => src/cliproxy/proxy/__tests__}/proxy-detector-port.test.ts (93%) rename {tests/unit/cliproxy => src/cliproxy/proxy/__tests__}/tool-sanitization-proxy-integration.test.ts (99%) rename src/cliproxy/{ => proxy}/https-tunnel-proxy.ts (100%) rename src/cliproxy/{ => proxy}/proxy-config-resolver.ts (98%) rename src/cliproxy/{ => proxy}/proxy-detector.ts (97%) rename src/cliproxy/{ => proxy}/proxy-target-resolver.ts (94%) rename src/cliproxy/{ => proxy}/tool-sanitization-proxy.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-caching-integration.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-fetcher-antigravity-failure.test.ts (92%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-fetcher-claude.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-fetcher-codex.test.ts (96%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-fetcher-gemini-cli.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-fetcher-ghcp.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-monitor-runtime.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/quota/__tests__}/quota-response-cache.test.ts (99%) rename src/cliproxy/{ => quota}/gemini-cli-quota-normalizer.ts (100%) rename src/cliproxy/{ => quota}/quota-fetcher-claude-normalizer.ts (99%) rename src/cliproxy/{ => quota}/quota-fetcher-claude.ts (97%) rename src/cliproxy/{ => quota}/quota-fetcher-codex.ts (99%) rename src/cliproxy/{ => quota}/quota-fetcher-gemini-cli.ts (98%) rename src/cliproxy/{ => quota}/quota-fetcher-ghcp.ts (98%) rename src/cliproxy/{ => quota}/quota-fetcher.ts (98%) rename src/cliproxy/{ => quota}/quota-manager.ts (97%) rename src/cliproxy/{ => quota}/quota-response-cache.ts (100%) rename src/cliproxy/{ => quota}/quota-types.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/routing/__tests__}/routing-strategy-http.test.ts (81%) rename {tests/unit/cliproxy => src/cliproxy/routing/__tests__}/routing-strategy.test.ts (98%) rename src/cliproxy/{ => routing}/routing-strategy-http.ts (98%) rename src/cliproxy/{ => routing}/routing-strategy.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/auto-sync-watcher.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/local-config-sync.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/remote-auth-fetcher.test.ts (90%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/remote-proxy-chain-regression.test.ts (97%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/remote-proxy-client.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/remote-token-uploader.test.ts (99%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/service-manager-startup.test.ts (94%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/stats-transformer.test.ts (98%) rename {tests/unit/cliproxy => src/cliproxy/services/__tests__}/variant-update-service.test.ts (97%) rename src/cliproxy/{ => services}/catalog-cache.ts (96%) rename src/cliproxy/{ => services}/catalog-routing.ts (86%) rename src/cliproxy/{ => services}/remote-auth-fetcher.ts (98%) rename src/cliproxy/{ => services}/remote-proxy-client.ts (99%) rename src/cliproxy/{ => services}/startup-lock.ts (98%) rename src/cliproxy/{ => services}/stats-fetcher.ts (99%) rename src/cliproxy/{ => services}/stats-transformer.ts (96%) create mode 100644 src/cliproxy/types/__tests__/types-backward-compat.test.ts create mode 100644 src/cliproxy/types/binary-types.ts create mode 100644 src/cliproxy/types/config-types.ts create mode 100644 src/cliproxy/types/index.ts create mode 100644 src/cliproxy/types/platform-types.ts create mode 100644 src/cliproxy/types/provider-types.ts diff --git a/src/api/services/cliproxy-profile-bridge.ts b/src/api/services/cliproxy-profile-bridge.ts index e903d222..dc936c23 100644 --- a/src/api/services/cliproxy-profile-bridge.ts +++ b/src/api/services/cliproxy-profile-bridge.ts @@ -1,16 +1,16 @@ import * as fs from 'fs'; import * as path from 'path'; import { getCcsDir, loadConfigSafe } from '../../utils/config-manager'; -import { buildProxyUrl, getProxyTarget } from '../../cliproxy/proxy-target-resolver'; -import { getEffectiveApiKey } from '../../cliproxy/auth-token-manager'; -import { getModelMappingFromConfig } from '../../cliproxy/base-config-loader'; +import { buildProxyUrl, getProxyTarget } from '../../cliproxy/proxy/proxy-target-resolver'; +import { getEffectiveApiKey } from '../../cliproxy/auth/auth-token-manager'; +import { getModelMappingFromConfig } from '../../cliproxy/config/base-config-loader'; import { CLIPROXY_PROVIDER_IDS, getProviderDescription, getProviderDisplayName, mapExternalProviderName, } from '../../cliproxy/provider-capabilities'; -import { extractProviderFromPathname } from '../../cliproxy/model-id-normalizer'; +import { extractProviderFromPathname } from '../../cliproxy/ai-providers/model-id-normalizer'; import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; import type { TargetType } from '../../targets/target-adapter'; import type { Settings } from '../../types/config'; diff --git a/src/api/services/profile-lifecycle-validation.ts b/src/api/services/profile-lifecycle-validation.ts index 4ae697dc..7ff09654 100644 --- a/src/api/services/profile-lifecycle-validation.ts +++ b/src/api/services/profile-lifecycle-validation.ts @@ -7,7 +7,7 @@ import { extractProviderFromPathname, getDeniedModelIdReasonForProvider, -} from '../../cliproxy/model-id-normalizer'; +} from '../../cliproxy/ai-providers/model-id-normalizer'; import { mapExternalProviderName } from '../../cliproxy/provider-capabilities'; import type { CLIProxyProvider } from '../../cliproxy/types'; import type { ProfileValidationIssue, ProfileValidationSummary } from './profile-types'; diff --git a/src/api/services/profile-writer.ts b/src/api/services/profile-writer.ts index b7c00ac7..0e267160 100644 --- a/src/api/services/profile-writer.ts +++ b/src/api/services/profile-writer.ts @@ -17,7 +17,7 @@ import { mapExternalProviderName } from '../../cliproxy/provider-capabilities'; import { extractProviderFromPathname, getDeniedModelIdReasonForProvider, -} from '../../cliproxy/model-id-normalizer'; +} from '../../cliproxy/ai-providers/model-id-normalizer'; import type { CLIProxyProvider } from '../../cliproxy/types'; import type { ModelMapping, diff --git a/tests/unit/cliproxy/ai-provider-service-stable-id.test.ts b/src/cliproxy/__tests__/ai-provider-service-stable-id.test.ts similarity index 100% rename from tests/unit/cliproxy/ai-provider-service-stable-id.test.ts rename to src/cliproxy/__tests__/ai-provider-service-stable-id.test.ts diff --git a/tests/unit/cliproxy/model-catalog-compat.test.ts b/src/cliproxy/__tests__/model-catalog-compat.test.ts similarity index 95% rename from tests/unit/cliproxy/model-catalog-compat.test.ts rename to src/cliproxy/__tests__/model-catalog-compat.test.ts index 0590a44b..632ee896 100644 --- a/tests/unit/cliproxy/model-catalog-compat.test.ts +++ b/src/cliproxy/__tests__/model-catalog-compat.test.ts @@ -1,10 +1,10 @@ import { describe, it, expect } from 'bun:test'; -import { findModel, supportsThinking } from '../../../src/cliproxy/model-catalog'; +import { findModel, supportsThinking } from '../model-catalog'; import { PROVIDER_TO_CHANNEL, SYNCABLE_PROVIDERS, mergeCatalog, -} from '../../../src/cliproxy/catalog-cache'; +} from '../services/catalog-cache'; describe('model-catalog compatibility lookups', () => { it('finds agy Claude models using dotted major.minor IDs', () => { diff --git a/tests/unit/cliproxy/model-catalog.test.js b/src/cliproxy/__tests__/model-catalog.test.js similarity index 100% rename from tests/unit/cliproxy/model-catalog.test.js rename to src/cliproxy/__tests__/model-catalog.test.js diff --git a/tests/unit/cliproxy/model-config.test.js b/src/cliproxy/__tests__/model-config.test.js similarity index 100% rename from tests/unit/cliproxy/model-config.test.js rename to src/cliproxy/__tests__/model-config.test.js diff --git a/tests/unit/cliproxy/provider-capabilities.test.ts b/src/cliproxy/__tests__/provider-capabilities.test.ts similarity index 97% rename from tests/unit/cliproxy/provider-capabilities.test.ts rename to src/cliproxy/__tests__/provider-capabilities.test.ts index 7c462b6d..c1f2f04c 100644 --- a/tests/unit/cliproxy/provider-capabilities.test.ts +++ b/src/cliproxy/__tests__/provider-capabilities.test.ts @@ -13,11 +13,11 @@ import { isQuotaSupportedProvider, QUOTA_PROVIDER_OPTION_VALUES, QUOTA_PROVIDER_HELP_TEXT, -} from '../../../src/cliproxy/provider-capabilities'; +} from '../provider-capabilities'; import { OAUTH_CALLBACK_PORTS as DIAGNOSTIC_CALLBACK_PORTS, OAUTH_FLOW_TYPES, -} from '../../../src/management/oauth-port-diagnostics'; +} from '../../management/oauth-port-diagnostics'; import { DEFAULT_KIRO_AUTH_METHOD, getKiroCallbackPort, @@ -27,7 +27,7 @@ import { normalizeKiroAuthMethod, OAUTH_CALLBACK_PORTS as AUTH_CALLBACK_PORTS, toKiroManagementMethod, -} from '../../../src/cliproxy/auth/auth-types'; +} from '../auth/auth-types'; describe('provider-capabilities', () => { it('keeps canonical provider IDs backward-compatible', () => { diff --git a/tests/unit/cliproxy/session-tracker-port.test.js b/src/cliproxy/__tests__/session-tracker-port.test.js similarity index 100% rename from tests/unit/cliproxy/session-tracker-port.test.js rename to src/cliproxy/__tests__/session-tracker-port.test.js diff --git a/tests/unit/cliproxy/session-tracker-target.test.ts b/src/cliproxy/__tests__/session-tracker-target.test.ts similarity index 100% rename from tests/unit/cliproxy/session-tracker-target.test.ts rename to src/cliproxy/__tests__/session-tracker-target.test.ts diff --git a/tests/unit/cliproxy/session-tracker.test.js b/src/cliproxy/__tests__/session-tracker.test.js similarity index 100% rename from tests/unit/cliproxy/session-tracker.test.js rename to src/cliproxy/__tests__/session-tracker.test.js diff --git a/tests/unit/cliproxy/thinking-arg-parser.test.ts b/src/cliproxy/__tests__/thinking-arg-parser.test.ts similarity index 96% rename from tests/unit/cliproxy/thinking-arg-parser.test.ts rename to src/cliproxy/__tests__/thinking-arg-parser.test.ts index 13310906..c2d8dc5b 100644 --- a/tests/unit/cliproxy/thinking-arg-parser.test.ts +++ b/src/cliproxy/__tests__/thinking-arg-parser.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'bun:test'; -import { parseThinkingOverride } from '../../../src/cliproxy/executor/thinking-arg-parser'; +import { parseThinkingOverride } from '../executor/thinking-arg-parser'; describe('parseThinkingOverride', () => { it('parses --thinking with separate value', () => { diff --git a/tests/unit/cliproxy/thinking-override-resolver.test.ts b/src/cliproxy/__tests__/thinking-override-resolver.test.ts similarity index 94% rename from tests/unit/cliproxy/thinking-override-resolver.test.ts rename to src/cliproxy/__tests__/thinking-override-resolver.test.ts index 7a86c1d8..a8453443 100644 --- a/tests/unit/cliproxy/thinking-override-resolver.test.ts +++ b/src/cliproxy/__tests__/thinking-override-resolver.test.ts @@ -1,11 +1,11 @@ import { describe, expect, it } from 'bun:test'; -import type { ThinkingConfig } from '../../../src/config/unified-config-types'; +import type { ThinkingConfig } from '../../config/unified-config-types'; import { buildThinkingStartupStatus, parseEnvThinkingOverride, resolveRuntimeThinkingOverride, shouldDisableCodexReasoning, -} from '../../../src/cliproxy/executor/thinking-override-resolver'; +} from '../executor/thinking-override-resolver'; const baseConfig: ThinkingConfig = { mode: 'auto', diff --git a/tests/unit/cliproxy/thinking-validator.test.ts b/src/cliproxy/__tests__/thinking-validator.test.ts similarity index 99% rename from tests/unit/cliproxy/thinking-validator.test.ts rename to src/cliproxy/__tests__/thinking-validator.test.ts index 59dfccbd..c1c21ebf 100644 --- a/tests/unit/cliproxy/thinking-validator.test.ts +++ b/src/cliproxy/__tests__/thinking-validator.test.ts @@ -13,7 +13,7 @@ import { THINKING_BUDGET_MIN, THINKING_BUDGET_MAX, THINKING_BUDGET_DEFAULT_MIN, -} from '../../../src/cliproxy/thinking-validator'; +} from '../thinking-validator'; describe('Thinking Validator', () => { describe('Constants', () => { diff --git a/tests/unit/cliproxy/account-manager-discover.test.js b/src/cliproxy/accounts/__tests__/account-manager-discover.test.js similarity index 89% rename from tests/unit/cliproxy/account-manager-discover.test.js rename to src/cliproxy/accounts/__tests__/account-manager-discover.test.js index 6bad8c5e..1179abff 100644 --- a/tests/unit/cliproxy/account-manager-discover.test.js +++ b/src/cliproxy/accounts/__tests__/account-manager-discover.test.js @@ -29,18 +29,18 @@ describe('Account Manager - discoverExistingAccounts', () => { process.env.CCS_HOME = testDir; // Clear cache and reload - must clear all modular submodules too - delete require.cache[require.resolve('../../../dist/cliproxy/account-manager')]; - delete require.cache[require.resolve('../../../dist/cliproxy/config-generator')]; - delete require.cache[require.resolve('../../../dist/utils/config-manager')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/account-manager')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/config-generator')]; + delete require.cache[require.resolve('../../../../dist/utils/config-manager')]; // Clear new modular structure (accounts/ and config/ submodules) - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/index')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/registry')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/token-file-ops')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/query')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/types')]; - delete require.cache[require.resolve('../../../dist/cliproxy/config/index')]; - delete require.cache[require.resolve('../../../dist/cliproxy/config/path-resolver')]; - accountManager = require('../../../dist/cliproxy/account-manager'); + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/index')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/registry')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/token-file-ops')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/query')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/types')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/config/index')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/config/path-resolver')]; + accountManager = require('../../../../dist/cliproxy/account-manager'); }); afterEach(() => { @@ -269,10 +269,10 @@ describe('Account Manager - discoverExistingAccounts', () => { }); // Reload module to clear in-memory cache (including all submodules) - delete require.cache[require.resolve('../../../dist/cliproxy/account-manager')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/index')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/registry')]; - accountManager = require('../../../dist/cliproxy/account-manager'); + delete require.cache[require.resolve('../../../../dist/cliproxy/account-manager')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/index')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/registry')]; + accountManager = require('../../../../dist/cliproxy/account-manager'); accountManager.discoverExistingAccounts(); const accounts = getAccountsFile(); @@ -353,10 +353,10 @@ describe('Account Manager - discoverExistingAccounts', () => { }); // Reload module to pick up pre-existing accounts.json (including all submodules) - delete require.cache[require.resolve('../../../dist/cliproxy/account-manager')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/index')]; - delete require.cache[require.resolve('../../../dist/cliproxy/accounts/registry')]; - accountManager = require('../../../dist/cliproxy/account-manager'); + delete require.cache[require.resolve('../../../../dist/cliproxy/account-manager')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/index')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/accounts/registry')]; + accountManager = require('../../../../dist/cliproxy/account-manager'); accountManager.discoverExistingAccounts(); const accounts = getAccountsFile(); diff --git a/tests/unit/cliproxy/account-registry-integrity.test.ts b/src/cliproxy/accounts/__tests__/account-registry-integrity.test.ts similarity index 98% rename from tests/unit/cliproxy/account-registry-integrity.test.ts rename to src/cliproxy/accounts/__tests__/account-registry-integrity.test.ts index 441e94d0..6f0ed7bb 100644 --- a/tests/unit/cliproxy/account-registry-integrity.test.ts +++ b/src/cliproxy/accounts/__tests__/account-registry-integrity.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it, spyOn } from 'bun:test'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { runWithScopedCcsHome } from '../../../src/utils/config-manager'; +import { runWithScopedCcsHome } from '../../../utils/config-manager'; async function withIsolatedHome(fn: (homeDir: string) => Promise | T): Promise { const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-account-registry-')); @@ -14,11 +14,11 @@ async function withIsolatedHome(fn: (homeDir: string) => Promise | T): Pro } async function loadRegistryModule() { - return import(`../../../src/cliproxy/accounts/registry?registry-integrity=${Date.now()}`); + return import(`../registry?registry-integrity=${Date.now()}`); } async function loadAccountManager() { - return import(`../../../src/cliproxy/account-manager?account-registry-integrity=${Date.now()}`); + return import(`../account-manager?account-registry-integrity=${Date.now()}`); } async function captureConsoleError(fn: () => Promise | T): Promise<{ result: T; messages: string[] }> { diff --git a/tests/unit/cliproxy/account-registry-optional-nickname.test.ts b/src/cliproxy/accounts/__tests__/account-registry-optional-nickname.test.ts similarity index 97% rename from tests/unit/cliproxy/account-registry-optional-nickname.test.ts rename to src/cliproxy/accounts/__tests__/account-registry-optional-nickname.test.ts index 44ddd005..f549e788 100644 --- a/tests/unit/cliproxy/account-registry-optional-nickname.test.ts +++ b/src/cliproxy/accounts/__tests__/account-registry-optional-nickname.test.ts @@ -2,10 +2,10 @@ import { describe, expect, it } from 'bun:test'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { runWithScopedCcsHome } from '../../../src/utils/config-manager'; +import { runWithScopedCcsHome } from '../../../utils/config-manager'; async function loadAccountManager() { - return import(`../../../src/cliproxy/account-manager?optional-nickname=${Date.now()}`); + return import(`../account-manager?optional-nickname=${Date.now()}`); } function writeTokenFile(homeDir: string, tokenFile: string): void { diff --git a/tests/unit/cliproxy/account-safety-quota-exhaustion.test.ts b/src/cliproxy/accounts/__tests__/account-safety-quota-exhaustion.test.ts similarity index 96% rename from tests/unit/cliproxy/account-safety-quota-exhaustion.test.ts rename to src/cliproxy/accounts/__tests__/account-safety-quota-exhaustion.test.ts index a0ce2238..f316feff 100644 --- a/tests/unit/cliproxy/account-safety-quota-exhaustion.test.ts +++ b/src/cliproxy/accounts/__tests__/account-safety-quota-exhaustion.test.ts @@ -19,8 +19,8 @@ import { maskEmail, pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses, -} from '../../../src/cliproxy/account-safety'; -import { sanitizeEmail } from '../../../src/cliproxy/auth-utils'; +} from '../../accounts/account-safety'; +import { sanitizeEmail } from '../../auth/auth-utils'; // Setup test isolation let tmpDir: string; @@ -243,7 +243,7 @@ describe('Quota Exhaustion Handlers', () => { }, }); - const { isOnCooldown } = await import('../../../src/cliproxy/quota-manager'); + const { isOnCooldown } = await import('../../quota/quota-manager'); const result = await handleQuotaExhaustion('agy', 'exhausted@gmail.com', 10); @@ -285,7 +285,7 @@ describe('Quota Exhaustion Handlers', () => { }); const result = await handleQuotaExhaustion('agy', 'only@gmail.com', 10); - const { getAccount } = await import('../../../src/cliproxy/account-manager'); + const { getAccount } = await import('../account-manager'); // Should return gracefully with null switched expect(result.switchedTo).toBeNull(); @@ -343,7 +343,7 @@ describe('Quota Exhaustion Handlers', () => { const result = await handleQuotaExhaustion('claude', 'exhausted@example.com', 10); const { getAccount, getDefaultAccount } = await import( - '../../../src/cliproxy/account-manager' + '../account-manager' ); expect(result.switchedTo).toBe('fallback@example.com'); @@ -430,7 +430,7 @@ describe('Quota Exhaustion Handlers', () => { const result = await handleQuotaExhaustion('codex', 'exhausted@example.com', 10); const { getAccount, getDefaultAccount } = await import( - '../../../src/cliproxy/account-manager' + '../account-manager' ); expect(result.switchedTo).toBe('fallback@example.com'); @@ -490,9 +490,9 @@ describe('Quota Exhaustion Handlers', () => { ) ) as typeof fetch; - const { preflightCheck } = await import('../../../src/cliproxy/quota-manager'); + const { preflightCheck } = await import('../../quota/quota-manager'); const result = await preflightCheck('codex'); - const { getAccount } = await import('../../../src/cliproxy/account-manager'); + const { getAccount } = await import('../account-manager'); expect(result.accountId).toBe('only-codex@example.com'); expect(result.switchedFrom).toBeUndefined(); @@ -567,10 +567,10 @@ describe('Quota Exhaustion Handlers', () => { ); }) as typeof fetch; - const { preflightCheck } = await import('../../../src/cliproxy/quota-manager'); + const { preflightCheck } = await import('../../quota/quota-manager'); const result = await preflightCheck('codex'); const { getAccount, getDefaultAccount } = await import( - '../../../src/cliproxy/account-manager' + '../account-manager' ); expect(result.switchedFrom).toBe('preflight-exhausted@example.com'); @@ -647,10 +647,10 @@ describe('Quota Exhaustion Handlers', () => { ); }) as typeof fetch; - const { preflightCheck } = await import('../../../src/cliproxy/quota-manager'); + const { preflightCheck } = await import('../../quota/quota-manager'); const result = await preflightCheck('codex'); const { getAccount, getDefaultAccount } = await import( - '../../../src/cliproxy/account-manager' + '../account-manager' ); expect(result.switchedFrom).toBe('preflight-unknown-exhausted@example.com'); @@ -737,7 +737,7 @@ describe('Quota Exhaustion Handlers', () => { const result = await handleQuotaExhaustion('gemini', 'gemini-exhausted@example.com', 10); const { getAccount, getDefaultAccount } = await import( - '../../../src/cliproxy/account-manager' + '../account-manager' ); expect(result.switchedTo).toBe('gemini-fallback@example.com'); @@ -805,7 +805,7 @@ describe('Quota Exhaustion Handlers', () => { const result = await handleQuotaExhaustion('ghcp', 'ghcp-exhausted', 10); const { getAccount, getDefaultAccount } = await import( - '../../../src/cliproxy/account-manager' + '../account-manager' ); expect(result.switchedTo).toBe('ghcp-fallback'); @@ -869,7 +869,7 @@ describe('Quota Exhaustion Handlers', () => { const result = await handleQuotaExhaustion('ghcp', 'ghcp-partial-exhausted', 10); const { getAccount, getDefaultAccount } = await import( - '../../../src/cliproxy/account-manager' + '../account-manager' ); expect(result.switchedTo).toBe('ghcp-partial-fallback'); @@ -986,7 +986,7 @@ describe('Quota Exhaustion Handlers', () => { const now = Date.now(); expect(pauseAccountForQuotaCooldown('agy', 'cooldown@gmail.com', 5, now)).toBe(true); - const { getAccount } = await import('../../../src/cliproxy/account-manager'); + const { getAccount } = await import('../account-manager'); expect(getAccount('agy', 'cooldown@gmail.com')?.paused).toBe(true); const resumed = restoreExpiredQuotaPauses(now + 6 * 60 * 1000); @@ -1030,7 +1030,7 @@ describe('Quota Exhaustion Handlers', () => { fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2)); const resumed = restoreExpiredQuotaPauses(now + 6 * 60 * 1000); - const { getAccount } = await import('../../../src/cliproxy/account-manager'); + const { getAccount } = await import('../account-manager'); expect(resumed).toBe(0); expect(getAccount('agy', 'cooldown@gmail.com')?.paused).toBe(true); @@ -1067,7 +1067,7 @@ describe('Quota Exhaustion Handlers', () => { }); const resumed = restoreExpiredQuotaPauses(now + 6 * 60 * 1000); - const { getAccount } = await import('../../../src/cliproxy/account-manager'); + const { getAccount } = await import('../account-manager'); const quotaPausedPath = path.join(tmpDir, '.ccs', 'cliproxy', 'quota-paused.json'); const quotaPaused = JSON.parse(fs.readFileSync(quotaPausedPath, 'utf8')) as { entries?: Array<{ accountId?: string }>; diff --git a/tests/unit/cliproxy/account-safety.test.ts b/src/cliproxy/accounts/__tests__/account-safety.test.ts similarity index 99% rename from tests/unit/cliproxy/account-safety.test.ts rename to src/cliproxy/accounts/__tests__/account-safety.test.ts index 48c7234e..542e4e84 100644 --- a/tests/unit/cliproxy/account-safety.test.ts +++ b/src/cliproxy/accounts/__tests__/account-safety.test.ts @@ -19,7 +19,7 @@ import { checkNewAccountConflict, handleBanDetection, warnCrossProviderDuplicates, -} from '../../../src/cliproxy/account-safety'; +} from '../../accounts/account-safety'; // --- Test isolation: use temp CCS_HOME --- diff --git a/src/cliproxy/account-manager.ts b/src/cliproxy/accounts/account-manager.ts similarity index 97% rename from src/cliproxy/account-manager.ts rename to src/cliproxy/accounts/account-manager.ts index bb1b8a07..15530108 100644 --- a/src/cliproxy/account-manager.ts +++ b/src/cliproxy/accounts/account-manager.ts @@ -20,7 +20,7 @@ export type { ProviderAccounts, BulkOperationResult, SoloOperationResult, -} from './accounts'; +} from '.'; export { PROVIDERS_WITHOUT_EMAIL, @@ -56,4 +56,4 @@ export { bulkPauseAccounts, bulkResumeAccounts, soloAccount, -} from './accounts'; +} from '.'; diff --git a/src/cliproxy/account-safety.ts b/src/cliproxy/accounts/account-safety.ts similarity index 98% rename from src/cliproxy/account-safety.ts rename to src/cliproxy/accounts/account-safety.ts index b1435913..f4b826f3 100644 --- a/src/cliproxy/account-safety.ts +++ b/src/cliproxy/accounts/account-safety.ts @@ -11,10 +11,10 @@ import * as fs from 'fs'; import * as path from 'path'; -import { warn, info } from '../utils/ui'; -import { CLIProxyProvider } from './types'; -import { loadAccountsRegistry, pauseAccount, resumeAccount } from './accounts/registry'; -import { getCcsDir } from '../utils/config-manager'; +import { warn, info } from '../../utils/ui'; +import { CLIProxyProvider } from '../types'; +import { loadAccountsRegistry, pauseAccount, resumeAccount } from './registry'; +import { getCcsDir } from '../../utils/config-manager'; const ISSUE_509_URL = 'https://github.com/kaitranntt/ccs/issues/509'; @@ -688,9 +688,9 @@ export async function handleQuotaExhaustion( cooldownMinutes: number ): Promise<{ switchedTo: string | null; reason: string }> { // Dynamic imports to avoid circular dependencies - const { applyCooldown, findHealthyAccount } = await import('./quota-manager'); + const { applyCooldown, findHealthyAccount } = await import('../quota/quota-manager'); const { setDefaultAccount, touchAccount } = await import('./account-manager'); - const { loadOrCreateUnifiedConfig } = await import('../config/unified-config-loader'); + const { loadOrCreateUnifiedConfig } = await import('../../config/unified-config-loader'); const config = loadOrCreateUnifiedConfig(); const threshold = config.quota_management?.auto?.exhaustion_threshold ?? 5; diff --git a/src/cliproxy/account-stats-key.ts b/src/cliproxy/accounts/account-stats-key.ts similarity index 100% rename from src/cliproxy/account-stats-key.ts rename to src/cliproxy/accounts/account-stats-key.ts diff --git a/src/cliproxy/accounts/registry.ts b/src/cliproxy/accounts/registry.ts index 7d755229..fb688341 100644 --- a/src/cliproxy/accounts/registry.ts +++ b/src/cliproxy/accounts/registry.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import * as lockfile from 'proper-lockfile'; import { CLIProxyProvider } from '../types'; import { PROVIDER_TYPE_VALUES } from '../auth/auth-types'; -import { getAuthDir, getCliproxyDir } from '../config-generator'; +import { getAuthDir, getCliproxyDir } from '../config/config-generator'; import { AccountsRegistry, AccountInfo, PROVIDERS_WITHOUT_EMAIL } from './types'; import { getAccountsRegistryPath, diff --git a/src/cliproxy/accounts/token-file-ops.ts b/src/cliproxy/accounts/token-file-ops.ts index 4df792fe..50f70d19 100644 --- a/src/cliproxy/accounts/token-file-ops.ts +++ b/src/cliproxy/accounts/token-file-ops.ts @@ -4,7 +4,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCliproxyDir, getAuthDir } from '../config-generator'; +import { getCliproxyDir, getAuthDir } from '../config/config-generator'; import type { CLIProxyProvider } from '../types'; import { AccountInfo } from './types'; diff --git a/tests/unit/cliproxy/codex-plan-compatibility-reconcile.test.ts b/src/cliproxy/ai-providers/__tests__/codex-plan-compatibility-reconcile.test.ts similarity index 98% rename from tests/unit/cliproxy/codex-plan-compatibility-reconcile.test.ts rename to src/cliproxy/ai-providers/__tests__/codex-plan-compatibility-reconcile.test.ts index 97ae8940..622bfdce 100644 --- a/tests/unit/cliproxy/codex-plan-compatibility-reconcile.test.ts +++ b/src/cliproxy/ai-providers/__tests__/codex-plan-compatibility-reconcile.test.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { afterEach, describe, expect, it, mock, spyOn } from 'bun:test'; -import { clearQuotaCache } from '../../../src/cliproxy/quota-response-cache'; +import { clearQuotaCache } from '../../quota/quota-response-cache'; afterEach(() => { clearQuotaCache(); @@ -39,7 +39,7 @@ function createCodexSettingsFixture(haikuModel: string = 'gpt-5.4-mini'): { } async function importCompatibilityModule(cacheTag: string) { - return import(`../../../src/cliproxy/codex-plan-compatibility?${cacheTag}=${Date.now()}`); + return import(`../../codex-plan-compatibility?${cacheTag}=${Date.now()}`); } const identity = (message: string) => message; diff --git a/tests/unit/cliproxy/codex-plan-compatibility.test.ts b/src/cliproxy/ai-providers/__tests__/codex-plan-compatibility.test.ts similarity index 95% rename from tests/unit/cliproxy/codex-plan-compatibility.test.ts rename to src/cliproxy/ai-providers/__tests__/codex-plan-compatibility.test.ts index 41f52c68..dd4833e0 100644 --- a/tests/unit/cliproxy/codex-plan-compatibility.test.ts +++ b/src/cliproxy/ai-providers/__tests__/codex-plan-compatibility.test.ts @@ -1,11 +1,11 @@ import { describe, expect, it } from 'bun:test'; -import { getProviderCatalog, getModelMaxLevel } from '../../../src/cliproxy/model-catalog'; +import { getProviderCatalog, getModelMaxLevel } from '../../model-catalog'; import { getDefaultCodexModel, getFreePlanFallbackCodexModel, parseCodexUnsupportedModelError, resolveRuntimeCodexFallbackModel, -} from '../../../src/cliproxy/codex-plan-compatibility'; +} from '../../ai-providers/codex-plan-compatibility'; describe('codex plan compatibility', () => { it('uses a cross-plan safe Codex default', () => { diff --git a/tests/unit/cliproxy/codex-reasoning-proxy-extended-context.test.ts b/src/cliproxy/ai-providers/__tests__/codex-reasoning-proxy-extended-context.test.ts similarity index 99% rename from tests/unit/cliproxy/codex-reasoning-proxy-extended-context.test.ts rename to src/cliproxy/ai-providers/__tests__/codex-reasoning-proxy-extended-context.test.ts index 569b9dc3..f0cfd728 100644 --- a/tests/unit/cliproxy/codex-reasoning-proxy-extended-context.test.ts +++ b/src/cliproxy/ai-providers/__tests__/codex-reasoning-proxy-extended-context.test.ts @@ -4,12 +4,12 @@ import { buildCodexModelEffortMap, CodexReasoningProxy, getEffortForModel, -} from '../../../src/cliproxy/codex-reasoning-proxy'; +} from '../../ai-providers/codex-reasoning-proxy'; import { parseEnvThinkingOverride, resolveRuntimeThinkingOverride, shouldDisableCodexReasoning, -} from '../../../src/cliproxy/executor/thinking-override-resolver'; +} from '../../executor/thinking-override-resolver'; type JsonRecord = Record; diff --git a/tests/unit/cliproxy/codex-reasoning-proxy.test.js b/src/cliproxy/ai-providers/__tests__/codex-reasoning-proxy.test.js similarity index 99% rename from tests/unit/cliproxy/codex-reasoning-proxy.test.js rename to src/cliproxy/ai-providers/__tests__/codex-reasoning-proxy.test.js index f08bd33f..0aababe8 100644 --- a/tests/unit/cliproxy/codex-reasoning-proxy.test.js +++ b/src/cliproxy/ai-providers/__tests__/codex-reasoning-proxy.test.js @@ -4,7 +4,7 @@ const { buildCodexModelEffortMap, getEffortForModel, injectReasoningEffortIntoBody, -} = require('../../../dist/cliproxy/codex-reasoning-proxy'); +} = require('../../../../dist/cliproxy/codex-reasoning-proxy'); describe('Codex Reasoning Proxy', () => { describe('buildCodexModelEffortMap', () => { diff --git a/tests/unit/cliproxy/extended-context-config.test.ts b/src/cliproxy/ai-providers/__tests__/extended-context-config.test.ts similarity index 99% rename from tests/unit/cliproxy/extended-context-config.test.ts rename to src/cliproxy/ai-providers/__tests__/extended-context-config.test.ts index 0de42ab0..9d241a3a 100644 --- a/tests/unit/cliproxy/extended-context-config.test.ts +++ b/src/cliproxy/ai-providers/__tests__/extended-context-config.test.ts @@ -7,7 +7,7 @@ import { applyExtendedContextSuffix, shouldApplyExtendedContext, applyExtendedContextConfig, -} from '../../../src/cliproxy/config/extended-context-config'; +} from '../../config/extended-context-config'; describe('applyExtendedContextSuffix', () => { it('appends [1m] to model without suffix', () => { diff --git a/tests/unit/cliproxy/managed-model-prefixes.test.ts b/src/cliproxy/ai-providers/__tests__/managed-model-prefixes.test.ts similarity index 98% rename from tests/unit/cliproxy/managed-model-prefixes.test.ts rename to src/cliproxy/ai-providers/__tests__/managed-model-prefixes.test.ts index cb2e12d9..a3b3e2a1 100644 --- a/tests/unit/cliproxy/managed-model-prefixes.test.ts +++ b/src/cliproxy/ai-providers/__tests__/managed-model-prefixes.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, mock } from 'bun:test'; -import { ensureManagedModelPrefixes } from '../../../src/cliproxy/managed-model-prefixes'; +import { ensureManagedModelPrefixes } from '../managed-model-prefixes'; const originalFetch = global.fetch; diff --git a/tests/unit/cliproxy/model-id-normalizer.test.ts b/src/cliproxy/ai-providers/__tests__/model-id-normalizer.test.ts similarity index 99% rename from tests/unit/cliproxy/model-id-normalizer.test.ts rename to src/cliproxy/ai-providers/__tests__/model-id-normalizer.test.ts index 638ad419..4a3dadb3 100644 --- a/tests/unit/cliproxy/model-id-normalizer.test.ts +++ b/src/cliproxy/ai-providers/__tests__/model-id-normalizer.test.ts @@ -12,7 +12,7 @@ import { normalizeModelIdForProvider, normalizeModelIdForRouting, normalizeModelEnvVarsForProvider, -} from '../../../src/cliproxy/model-id-normalizer'; +} from '../model-id-normalizer'; describe('model-id-normalizer', () => { describe('provider parsing', () => { diff --git a/tests/unit/cliproxy/model-routing-hints.test.ts b/src/cliproxy/ai-providers/__tests__/model-routing-hints.test.ts similarity index 98% rename from tests/unit/cliproxy/model-routing-hints.test.ts rename to src/cliproxy/ai-providers/__tests__/model-routing-hints.test.ts index a9033769..b3670f4d 100644 --- a/tests/unit/cliproxy/model-routing-hints.test.ts +++ b/src/cliproxy/ai-providers/__tests__/model-routing-hints.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'bun:test'; import { buildCliproxyRoutingHints, getManagedModelPrefix, -} from '../../../src/shared/cliproxy-model-routing'; +} from '../../../shared/cliproxy-model-routing'; describe('cliproxy model routing hints', () => { it('uses short managed prefixes for overlapping Gemini and Antigravity models', () => { diff --git a/tests/unit/cliproxy/openai-compat-manager.test.js b/src/cliproxy/ai-providers/__tests__/openai-compat-manager.test.js similarity index 89% rename from tests/unit/cliproxy/openai-compat-manager.test.js rename to src/cliproxy/ai-providers/__tests__/openai-compat-manager.test.js index 817e5ab3..2f09e026 100644 --- a/tests/unit/cliproxy/openai-compat-manager.test.js +++ b/src/cliproxy/ai-providers/__tests__/openai-compat-manager.test.js @@ -17,12 +17,12 @@ describe('openai-compat manager', () => { process.env.CCS_HOME = testDir; process.env.CCS_DIR = path.join(testDir, '.ccs'); - delete require.cache[require.resolve('../../../dist/cliproxy/config-generator')]; - delete require.cache[require.resolve('../../../dist/cliproxy/openai-compat-manager')]; - delete require.cache[require.resolve('../../../dist/utils/config-manager')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/config-generator')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/openai-compat-manager')]; + delete require.cache[require.resolve('../../../../dist/utils/config-manager')]; - configGenerator = require('../../../dist/cliproxy/config-generator'); - openAICompatManager = require('../../../dist/cliproxy/openai-compat-manager'); + configGenerator = require('../../../../dist/cliproxy/config-generator'); + openAICompatManager = require('../../../../dist/cliproxy/openai-compat-manager'); }); afterEach(() => { diff --git a/tests/unit/cliproxy/schema-sanitizer.test.ts b/src/cliproxy/ai-providers/__tests__/schema-sanitizer.test.ts similarity index 99% rename from tests/unit/cliproxy/schema-sanitizer.test.ts rename to src/cliproxy/ai-providers/__tests__/schema-sanitizer.test.ts index 9d555269..2a8f2cbe 100644 --- a/tests/unit/cliproxy/schema-sanitizer.test.ts +++ b/src/cliproxy/ai-providers/__tests__/schema-sanitizer.test.ts @@ -6,7 +6,7 @@ */ import { describe, expect, test } from 'bun:test'; -import { sanitizeInputSchema, sanitizeToolSchemas } from '../../../src/cliproxy/schema-sanitizer'; +import { sanitizeInputSchema, sanitizeToolSchemas } from '../schema-sanitizer'; describe('sanitizeInputSchema', () => { test('preserves Gemini-supported properties', () => { diff --git a/tests/unit/cliproxy/tool-name-mapper.test.js b/src/cliproxy/ai-providers/__tests__/tool-name-mapper.test.js similarity index 98% rename from tests/unit/cliproxy/tool-name-mapper.test.js rename to src/cliproxy/ai-providers/__tests__/tool-name-mapper.test.js index ee37f2f0..2b5ae189 100644 --- a/tests/unit/cliproxy/tool-name-mapper.test.js +++ b/src/cliproxy/ai-providers/__tests__/tool-name-mapper.test.js @@ -4,7 +4,7 @@ const assert = require('assert'); -const { ToolNameMapper } = require('../../../dist/cliproxy/tool-name-mapper'); +const { ToolNameMapper } = require('../../../../dist/cliproxy/tool-name-mapper'); describe('Tool Name Mapper', () => { describe('registerTools', () => { diff --git a/tests/unit/cliproxy/tool-name-sanitizer.test.js b/src/cliproxy/ai-providers/__tests__/tool-name-sanitizer.test.js similarity index 98% rename from tests/unit/cliproxy/tool-name-sanitizer.test.js rename to src/cliproxy/ai-providers/__tests__/tool-name-sanitizer.test.js index 0f77af5a..342ddbe8 100644 --- a/tests/unit/cliproxy/tool-name-sanitizer.test.js +++ b/src/cliproxy/ai-providers/__tests__/tool-name-sanitizer.test.js @@ -10,7 +10,7 @@ const { smartTruncate, sanitizeToolName, GEMINI_MAX_TOOL_NAME_LENGTH, -} = require('../../../dist/cliproxy/tool-name-sanitizer'); +} = require('../../../../dist/cliproxy/tool-name-sanitizer'); describe('Tool Name Sanitizer', () => { describe('GEMINI_MAX_TOOL_NAME_LENGTH', () => { diff --git a/src/cliproxy/codex-plan-compatibility.ts b/src/cliproxy/ai-providers/codex-plan-compatibility.ts similarity index 93% rename from src/cliproxy/codex-plan-compatibility.ts rename to src/cliproxy/ai-providers/codex-plan-compatibility.ts index 73cd82c8..3205b069 100644 --- a/src/cliproxy/codex-plan-compatibility.ts +++ b/src/cliproxy/ai-providers/codex-plan-compatibility.ts @@ -1,10 +1,10 @@ -import { getDefaultAccount } from './account-manager'; -import { getProviderCatalog } from './model-catalog'; +import { getDefaultAccount } from '../accounts/account-manager'; +import { getProviderCatalog } from '../model-catalog'; import { normalizeModelIdForProvider } from './model-id-normalizer'; -import { fetchCodexQuota } from './quota-fetcher-codex'; -import { getCachedQuota, setCachedQuota } from './quota-response-cache'; -import type { CodexQuotaResult } from './quota-types'; -import { info, warn } from '../utils/ui'; +import { fetchCodexQuota } from '../quota/quota-fetcher-codex'; +import { getCachedQuota, setCachedQuota } from '../quota/quota-response-cache'; +import type { CodexQuotaResult } from '../quota/quota-types'; +import { info, warn } from '../../utils/ui'; export type CodexPlanType = CodexQuotaResult['planType']; diff --git a/src/cliproxy/codex-reasoning-proxy.ts b/src/cliproxy/ai-providers/codex-reasoning-proxy.ts similarity index 99% rename from src/cliproxy/codex-reasoning-proxy.ts rename to src/cliproxy/ai-providers/codex-reasoning-proxy.ts index e3f98907..f79dec22 100644 --- a/src/cliproxy/codex-reasoning-proxy.ts +++ b/src/cliproxy/ai-providers/codex-reasoning-proxy.ts @@ -6,7 +6,7 @@ import { parseCodexUnsupportedModelError, resolveRuntimeCodexFallbackModel, } from './codex-plan-compatibility'; -import { getModelMaxLevel } from './model-catalog'; +import { getModelMaxLevel } from '../model-catalog'; export type CodexReasoningEffort = 'medium' | 'high' | 'xhigh'; diff --git a/src/cliproxy/ai-providers/config-store.ts b/src/cliproxy/ai-providers/config-store.ts index e1d1f79d..869458f4 100644 --- a/src/cliproxy/ai-providers/config-store.ts +++ b/src/cliproxy/ai-providers/config-store.ts @@ -1,9 +1,9 @@ import { randomUUID } from 'crypto'; import * as fs from 'fs'; import * as yaml from 'js-yaml'; -import { configExists, getCliproxyConfigPath, regenerateConfig } from '../config-generator'; -import { getProxyTarget } from '../proxy-target-resolver'; -import { createManagementClient } from '../management-api-client'; +import { configExists, getCliproxyConfigPath, regenerateConfig } from '../config/config-generator'; +import { getProxyTarget } from '../proxy/proxy-target-resolver'; +import { createManagementClient } from '../management/management-api-client'; import { rewriteTopLevelYamlSection } from './config-yaml-sections'; import type { AiProviderApiKeyEntry, diff --git a/src/cliproxy/managed-model-prefixes.ts b/src/cliproxy/ai-providers/managed-model-prefixes.ts similarity index 94% rename from src/cliproxy/managed-model-prefixes.ts rename to src/cliproxy/ai-providers/managed-model-prefixes.ts index 54a97e6d..bc9af505 100644 --- a/src/cliproxy/managed-model-prefixes.ts +++ b/src/cliproxy/ai-providers/managed-model-prefixes.ts @@ -1,7 +1,7 @@ -import { getManagedModelPrefix } from '../shared/cliproxy-model-routing'; -import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from './proxy-target-resolver'; -import { mapExternalProviderName } from './provider-capabilities'; -import type { CLIProxyProvider } from './types'; +import { getManagedModelPrefix } from '../../shared/cliproxy-model-routing'; +import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver'; +import { mapExternalProviderName } from '../provider-capabilities'; +import type { CLIProxyProvider } from '../types'; const MANAGED_PREFIX_REQUEST_TIMEOUT_MS = 3000; diff --git a/src/cliproxy/model-id-normalizer.ts b/src/cliproxy/ai-providers/model-id-normalizer.ts similarity index 98% rename from src/cliproxy/model-id-normalizer.ts rename to src/cliproxy/ai-providers/model-id-normalizer.ts index 7bdaf503..3c1c6ffa 100644 --- a/src/cliproxy/model-id-normalizer.ts +++ b/src/cliproxy/ai-providers/model-id-normalizer.ts @@ -5,8 +5,8 @@ * model version formats (e.g., 4.6 vs 4-6). */ -import type { CLIProxyProvider } from './types'; -import { ANTHROPIC_MODEL_ENV_KEYS } from '../shared/extended-context-utils'; +import type { CLIProxyProvider } from '../types'; +import { ANTHROPIC_MODEL_ENV_KEYS } from '../../shared/extended-context-utils'; /** Env vars that carry model identifiers. */ export const MODEL_ENV_VAR_KEYS = ANTHROPIC_MODEL_ENV_KEYS; diff --git a/src/cliproxy/openai-compat-manager.ts b/src/cliproxy/ai-providers/openai-compat-manager.ts similarity index 96% rename from src/cliproxy/openai-compat-manager.ts rename to src/cliproxy/ai-providers/openai-compat-manager.ts index cdf1511e..1e87884b 100644 --- a/src/cliproxy/openai-compat-manager.ts +++ b/src/cliproxy/ai-providers/openai-compat-manager.ts @@ -7,8 +7,9 @@ import * as fs from 'fs'; import * as yaml from 'js-yaml'; -import { configExists, getCliproxyConfigPath, regenerateConfig } from './config-generator'; -import { rewriteTopLevelYamlSection } from './ai-providers/config-yaml-sections'; +import { configExists, regenerateConfig } from '../config/generator'; +import { getCliproxyConfigPath } from '../config/path-resolver'; +import { rewriteTopLevelYamlSection } from './config-yaml-sections'; /** Model alias configuration */ export interface OpenAICompatModel { diff --git a/src/cliproxy/schema-sanitizer.ts b/src/cliproxy/ai-providers/schema-sanitizer.ts similarity index 100% rename from src/cliproxy/schema-sanitizer.ts rename to src/cliproxy/ai-providers/schema-sanitizer.ts diff --git a/src/cliproxy/tool-name-mapper.ts b/src/cliproxy/ai-providers/tool-name-mapper.ts similarity index 100% rename from src/cliproxy/tool-name-mapper.ts rename to src/cliproxy/ai-providers/tool-name-mapper.ts diff --git a/src/cliproxy/tool-name-sanitizer.ts b/src/cliproxy/ai-providers/tool-name-sanitizer.ts similarity index 100% rename from src/cliproxy/tool-name-sanitizer.ts rename to src/cliproxy/ai-providers/tool-name-sanitizer.ts diff --git a/tests/unit/cliproxy/antigravity-responsibility.test.ts b/src/cliproxy/auth/__tests__/antigravity-responsibility.test.ts similarity index 98% rename from tests/unit/cliproxy/antigravity-responsibility.test.ts rename to src/cliproxy/auth/__tests__/antigravity-responsibility.test.ts index 0777a60d..5202d7a8 100644 --- a/tests/unit/cliproxy/antigravity-responsibility.test.ts +++ b/src/cliproxy/auth/__tests__/antigravity-responsibility.test.ts @@ -8,7 +8,7 @@ import { hasAntigravityRiskAcceptanceFlag, isAntigravityResponsibilityBypassEnabled, validateAntigravityRiskAcknowledgement, -} from '../../../src/cliproxy/antigravity-responsibility'; +} from '../../auth/antigravity-responsibility'; describe('antigravity-responsibility', () => { let tempHome = ''; diff --git a/tests/unit/cliproxy/auth-token-manager.test.js b/src/cliproxy/auth/__tests__/auth-token-manager.test.js similarity index 97% rename from tests/unit/cliproxy/auth-token-manager.test.js rename to src/cliproxy/auth/__tests__/auth-token-manager.test.js index 00dfd04b..8c30a462 100644 --- a/tests/unit/cliproxy/auth-token-manager.test.js +++ b/src/cliproxy/auth/__tests__/auth-token-manager.test.js @@ -19,8 +19,8 @@ describe('Auth Token Manager', () => { beforeEach(() => { // Clear cache and reload - delete require.cache[require.resolve('../../../dist/cliproxy/auth-token-manager')]; - const authTokenManager = require('../../../dist/cliproxy/auth-token-manager'); + delete require.cache[require.resolve('../../../../dist/cliproxy/auth-token-manager')]; + const authTokenManager = require('../../../../dist/cliproxy/auth-token-manager'); generateSecureToken = authTokenManager.generateSecureToken; }); @@ -398,8 +398,8 @@ describe('Auth Token Manager', () => { let CCS_CONTROL_PANEL_SECRET; beforeEach(() => { - delete require.cache[require.resolve('../../../dist/cliproxy/config-generator')]; - const configGenerator = require('../../../dist/cliproxy/config-generator'); + delete require.cache[require.resolve('../../../../dist/cliproxy/config-generator')]; + const configGenerator = require('../../../../dist/cliproxy/config-generator'); CCS_INTERNAL_API_KEY = configGenerator.CCS_INTERNAL_API_KEY; CCS_CONTROL_PANEL_SECRET = configGenerator.CCS_CONTROL_PANEL_SECRET; }); diff --git a/tests/unit/cliproxy/auth-types-management-path.test.ts b/src/cliproxy/auth/__tests__/auth-types-management-path.test.ts similarity index 97% rename from tests/unit/cliproxy/auth-types-management-path.test.ts rename to src/cliproxy/auth/__tests__/auth-types-management-path.test.ts index 160070b4..221f0f57 100644 --- a/tests/unit/cliproxy/auth-types-management-path.test.ts +++ b/src/cliproxy/auth/__tests__/auth-types-management-path.test.ts @@ -3,7 +3,7 @@ import { getManagementAuthUrlPath, getPasteCallbackStartPath, getManagementOAuthCallbackPath, -} from '../../../src/cliproxy/auth/auth-types'; +} from '../auth-types'; describe('auth-types paste-callback start path', () => { it('maps providers to CLIProxyAPI management auth-url routes', () => { diff --git a/tests/unit/cliproxy/auth-utils.test.ts b/src/cliproxy/auth/__tests__/auth-utils.test.ts similarity index 98% rename from tests/unit/cliproxy/auth-utils.test.ts rename to src/cliproxy/auth/__tests__/auth-utils.test.ts index f6944882..e76b3d73 100644 --- a/tests/unit/cliproxy/auth-utils.test.ts +++ b/src/cliproxy/auth/__tests__/auth-utils.test.ts @@ -9,7 +9,7 @@ import { getTokenExpiryTimestamp, isTokenExpired, sanitizeEmail, -} from '../../../src/cliproxy/auth-utils'; +} from '../../auth/auth-utils'; describe('Auth Utilities', () => { describe('sanitizeEmail', () => { diff --git a/tests/unit/cliproxy/gemini-refresh-delegation.test.ts b/src/cliproxy/auth/__tests__/gemini-refresh-delegation.test.ts similarity index 100% rename from tests/unit/cliproxy/gemini-refresh-delegation.test.ts rename to src/cliproxy/auth/__tests__/gemini-refresh-delegation.test.ts diff --git a/tests/unit/cliproxy/gitlab-pat-response.test.ts b/src/cliproxy/auth/__tests__/gitlab-pat-response.test.ts similarity index 94% rename from tests/unit/cliproxy/gitlab-pat-response.test.ts rename to src/cliproxy/auth/__tests__/gitlab-pat-response.test.ts index 029a276b..00c522a6 100644 --- a/tests/unit/cliproxy/gitlab-pat-response.test.ts +++ b/src/cliproxy/auth/__tests__/gitlab-pat-response.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'bun:test'; -import { parseGitLabPatAuthResponse } from '../../../src/cliproxy/auth/gitlab-pat-response'; +import { parseGitLabPatAuthResponse } from '../gitlab-pat-response'; describe('parseGitLabPatAuthResponse', () => { it('sanitizes HTML error bodies for non-ok responses', () => { diff --git a/tests/unit/cliproxy/oauth-handler-paste-callback.test.ts b/src/cliproxy/auth/__tests__/oauth-handler-paste-callback.test.ts similarity index 86% rename from tests/unit/cliproxy/oauth-handler-paste-callback.test.ts rename to src/cliproxy/auth/__tests__/oauth-handler-paste-callback.test.ts index 91b21a20..ac1bda2e 100644 --- a/tests/unit/cliproxy/oauth-handler-paste-callback.test.ts +++ b/src/cliproxy/auth/__tests__/oauth-handler-paste-callback.test.ts @@ -2,9 +2,9 @@ import { afterEach, describe, expect, it, mock, spyOn } from 'bun:test'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import type { ProxyTarget } from '../../../src/cliproxy/proxy-target-resolver'; -import { InteractivePrompt } from '../../../src/utils/prompt'; -import { getCapturedFetchRequests, mockFetch, restoreFetch } from '../../mocks'; +import type { ProxyTarget } from '../../proxy/proxy-target-resolver'; +import { InteractivePrompt } from '../../../utils/prompt'; +import { getCapturedFetchRequests, mockFetch, restoreFetch } from '../../../../tests/mocks'; const remoteTarget: ProxyTarget = { host: 'proxy.example.com', @@ -28,7 +28,7 @@ describe('requestPasteCallbackStart', () => { ]); const { requestPasteCallbackStart } = await import( - `../../../src/cliproxy/auth/oauth-handler?request-claude-start=${Date.now()}` + `../oauth-handler?request-claude-start=${Date.now()}` ); const startData = await requestPasteCallbackStart('claude', remoteTarget); @@ -52,7 +52,7 @@ describe('requestPasteCallbackStart', () => { ]); const { requestPasteCallbackStart } = await import( - `../../../src/cliproxy/auth/oauth-handler?request-kiro-start=${Date.now()}` + `../oauth-handler?request-kiro-start=${Date.now()}` ); const startData = await requestPasteCallbackStart('kiro', remoteTarget, { kiroMethod: 'aws', @@ -71,7 +71,7 @@ describe('requestPasteCallbackStart', () => { it('throws for Kiro methods that require the local callback server flow', async () => { const { requestPasteCallbackStart } = await import( - `../../../src/cliproxy/auth/oauth-handler?request-kiro-authcode-start=${Date.now()}` + `../oauth-handler?request-kiro-authcode-start=${Date.now()}` ); await expect( @@ -83,7 +83,7 @@ describe('requestPasteCallbackStart', () => { describe('usesKiroLocalCallbackReplay', () => { it('limits local callback replay to CLI auth-code flows', async () => { const { usesKiroLocalCallbackReplay } = await import( - `../../../src/cliproxy/auth/oauth-handler?kiro-local-callback-mode=${Date.now()}` + `../oauth-handler?kiro-local-callback-mode=${Date.now()}` ); expect(usesKiroLocalCallbackReplay('aws-authcode', 'authcode')).toBe(true); @@ -97,7 +97,7 @@ describe('usesKiroLocalCallbackReplay', () => { describe('resolvePasteCallbackAuthUrl', () => { it('returns the immediate auth URL without polling', async () => { const { resolvePasteCallbackAuthUrl } = await import( - `../../../src/cliproxy/auth/oauth-handler?resolve-immediate-auth-url=${Date.now()}` + `../oauth-handler?resolve-immediate-auth-url=${Date.now()}` ); const authUrl = await resolvePasteCallbackAuthUrl( remoteTarget, @@ -119,7 +119,7 @@ describe('resolvePasteCallbackAuthUrl', () => { ]); const { resolvePasteCallbackAuthUrl } = await import( - `../../../src/cliproxy/auth/oauth-handler?resolve-polled-auth-url=${Date.now()}` + `../oauth-handler?resolve-polled-auth-url=${Date.now()}` ); const authUrl = await resolvePasteCallbackAuthUrl(remoteTarget, { state: 'state-123' }, 50, 0); @@ -142,7 +142,7 @@ describe('findNewTokenSnapshotForManualAuth', () => { const existingMtimeMs = fs.statSync(existingFile).mtimeMs; const { findNewTokenSnapshotForManualAuth } = await import( - `../../../src/cliproxy/auth/oauth-handler?manual-auth-new-token=${Date.now()}` + `../oauth-handler?manual-auth-new-token=${Date.now()}` ); const newFile = path.join(tokenDir, 'kiro-new.json'); @@ -165,7 +165,7 @@ describe('findNewTokenSnapshotForManualAuth', () => { const existingMtimeMs = fs.statSync(tokenFile).mtimeMs; const { findNewTokenSnapshotForManualAuth } = await import( - `../../../src/cliproxy/auth/oauth-handler?manual-auth-updated-token=${Date.now()}` + `../oauth-handler?manual-auth-updated-token=${Date.now()}` ); fs.writeFileSync(tokenFile, JSON.stringify({ type: 'kiro', email: 'existing@example.com', refreshed: true })); @@ -187,7 +187,7 @@ describe('findNewTokenSnapshotForManualAuth', () => { describe('getCliAuthNicknameError', () => { it('allows omitted nicknames for no-email providers', async () => { const { getCliAuthNicknameError } = await import( - `../../../src/cliproxy/auth/oauth-handler?cli-nickname-empty=${Date.now()}` + `../oauth-handler?cli-nickname-empty=${Date.now()}` ); expect(getCliAuthNicknameError('kiro', undefined, [])).toBeNull(); @@ -196,7 +196,7 @@ describe('getCliAuthNicknameError', () => { it('rejects invalid supplied nicknames before OAuth starts', async () => { const { getCliAuthNicknameError } = await import( - `../../../src/cliproxy/auth/oauth-handler?cli-nickname-invalid=${Date.now()}` + `../oauth-handler?cli-nickname-invalid=${Date.now()}` ); expect(getCliAuthNicknameError('kiro', 'bad nickname', [])).toBe( @@ -206,7 +206,7 @@ describe('getCliAuthNicknameError', () => { it('rejects supplied nicknames that collide with existing ids or nicknames', async () => { const { getCliAuthNicknameError } = await import( - `../../../src/cliproxy/auth/oauth-handler?cli-nickname-conflict=${Date.now()}` + `../oauth-handler?cli-nickname-conflict=${Date.now()}` ); const existingAccounts = [ { id: 'github-ABC123', nickname: 'work' }, @@ -223,7 +223,7 @@ describe('getCliAuthNicknameError', () => { it('allows reauth when the supplied nickname already belongs to the same account', async () => { const { getCliAuthNicknameError } = await import( - `../../../src/cliproxy/auth/oauth-handler?cli-nickname-reauth=${Date.now()}` + `../oauth-handler?cli-nickname-reauth=${Date.now()}` ); const existingAccounts = [ { id: 'github-ABC123', nickname: 'work' }, @@ -242,7 +242,7 @@ describe('promptGitLabPersonalAccessToken', () => { ); const { promptGitLabPersonalAccessToken } = await import( - `../../../src/cliproxy/auth/oauth-handler?gitlab-pat-prompt=${Date.now()}` + `../oauth-handler?gitlab-pat-prompt=${Date.now()}` ); await expect(promptGitLabPersonalAccessToken()).resolves.toBe('glpat-secret-token'); @@ -255,7 +255,7 @@ describe('promptGitLabPersonalAccessToken', () => { ); const { promptGitLabPersonalAccessToken } = await import( - `../../../src/cliproxy/auth/oauth-handler?gitlab-pat-prompt-blank=${Date.now()}` + `../oauth-handler?gitlab-pat-prompt-blank=${Date.now()}` ); await expect(promptGitLabPersonalAccessToken()).resolves.toBeNull(); @@ -266,7 +266,7 @@ describe('promptGitLabPersonalAccessToken', () => { describe('normalizeGitLabBaseUrl', () => { it('returns undefined for blank values', async () => { const { normalizeGitLabBaseUrl } = await import( - `../../../src/cliproxy/auth/oauth-handler?gitlab-url-empty=${Date.now()}` + `../oauth-handler?gitlab-url-empty=${Date.now()}` ); expect(normalizeGitLabBaseUrl(undefined)).toBeUndefined(); @@ -275,7 +275,7 @@ describe('normalizeGitLabBaseUrl', () => { it('normalizes whitespace and trailing slashes for self-hosted URLs', async () => { const { normalizeGitLabBaseUrl } = await import( - `../../../src/cliproxy/auth/oauth-handler?gitlab-url-normalize=${Date.now()}` + `../oauth-handler?gitlab-url-normalize=${Date.now()}` ); expect(normalizeGitLabBaseUrl(' https://gitlab.example.com/custom/ ')).toBe( @@ -285,7 +285,7 @@ describe('normalizeGitLabBaseUrl', () => { it('rejects malformed or scheme-less URLs before hitting CLIProxy', async () => { const { normalizeGitLabBaseUrl } = await import( - `../../../src/cliproxy/auth/oauth-handler?gitlab-url-invalid=${Date.now()}` + `../oauth-handler?gitlab-url-invalid=${Date.now()}` ); expect(() => normalizeGitLabBaseUrl('gitlab.example.com')).toThrow( diff --git a/tests/unit/cliproxy/oauth-process-error-parser.test.ts b/src/cliproxy/auth/__tests__/oauth-process-error-parser.test.ts similarity index 99% rename from tests/unit/cliproxy/oauth-process-error-parser.test.ts rename to src/cliproxy/auth/__tests__/oauth-process-error-parser.test.ts index 4c3c7573..87756f16 100644 --- a/tests/unit/cliproxy/oauth-process-error-parser.test.ts +++ b/src/cliproxy/auth/__tests__/oauth-process-error-parser.test.ts @@ -7,7 +7,7 @@ import { getExpectedLocalCallback, getKiroBuilderIdSelectionInput, validateManualCallbackUrl, -} from '../../../src/cliproxy/auth/oauth-process'; +} from '../oauth-process'; describe('oauth-process stderr parsing', () => { it('does not match provider-specific patterns for other providers', () => { diff --git a/tests/unit/cliproxy/profile-mapper.test.ts b/src/cliproxy/auth/__tests__/profile-mapper.test.ts similarity index 98% rename from tests/unit/cliproxy/profile-mapper.test.ts rename to src/cliproxy/auth/__tests__/profile-mapper.test.ts index 92f688ff..7baf1166 100644 --- a/tests/unit/cliproxy/profile-mapper.test.ts +++ b/src/cliproxy/auth/__tests__/profile-mapper.test.ts @@ -7,8 +7,8 @@ import * as assert from 'assert'; const fs = require('fs'); describe('Profile Mapper', () => { - const profileMapper = require('../../../dist/cliproxy/sync/profile-mapper'); - const profileReader = require('../../../dist/api/services/profile-reader'); + const profileMapper = require('../../../../dist/cliproxy/sync/profile-mapper'); + const profileReader = require('../../../../dist/api/services/profile-reader'); describe('mapProfileToClaudeKey', () => { it('returns null when env is missing', () => { diff --git a/tests/unit/cliproxy/skip-local-auth.test.ts b/src/cliproxy/auth/__tests__/skip-local-auth.test.ts similarity index 100% rename from tests/unit/cliproxy/skip-local-auth.test.ts rename to src/cliproxy/auth/__tests__/skip-local-auth.test.ts diff --git a/src/cliproxy/antigravity-responsibility.ts b/src/cliproxy/auth/antigravity-responsibility.ts similarity index 98% rename from src/cliproxy/antigravity-responsibility.ts rename to src/cliproxy/auth/antigravity-responsibility.ts index c16722cd..62f8e9a2 100644 --- a/src/cliproxy/antigravity-responsibility.ts +++ b/src/cliproxy/auth/antigravity-responsibility.ts @@ -9,8 +9,8 @@ */ import { createInterface, Interface } from 'readline'; -import { fail, info, ok, warn } from '../utils/ui'; -import { getCliproxySafetyConfig } from '../config/unified-config-loader'; +import { fail, info, ok, warn } from '../../utils/ui'; +import { getCliproxySafetyConfig } from '../../config/unified-config-loader'; export const ANTIGRAVITY_RISK_ISSUE_URL = 'https://github.com/kaitranntt/ccs/issues/509'; export const ANTIGRAVITY_ACK_VERSION = '2026-02-24-antigravity-oauth-v2'; diff --git a/src/cliproxy/auth-handler.ts b/src/cliproxy/auth/auth-handler.ts similarity index 90% rename from src/cliproxy/auth-handler.ts rename to src/cliproxy/auth/auth-handler.ts index a7b3528f..debc0c42 100644 --- a/src/cliproxy/auth-handler.ts +++ b/src/cliproxy/auth/auth-handler.ts @@ -20,7 +20,7 @@ */ // Re-export types -export type { AuthStatus, ProviderOAuthConfig, OAuthOptions } from './auth'; +export type { AuthStatus, ProviderOAuthConfig, OAuthOptions } from '.'; // Re-export configurations export { @@ -29,7 +29,7 @@ export { PROVIDER_AUTH_PREFIXES, PROVIDER_TYPE_VALUES, getOAuthConfig, -} from './auth'; +} from '.'; // Re-export token management functions export { @@ -40,7 +40,7 @@ export { getAllAuthStatus, clearAuth, displayAuthStatus, -} from './auth'; +} from '.'; // Re-export environment detection functions export { @@ -48,13 +48,13 @@ export { killProcessOnPort, getTimeoutTroubleshooting, showStep, -} from './auth'; +} from '.'; // Re-export OAuth handling functions -export { triggerOAuth, ensureAuth } from './auth'; +export { triggerOAuth, ensureAuth } from '.'; // Re-export account management initialization -import { discoverExistingAccounts } from './account-manager'; +import { discoverExistingAccounts } from '../accounts/account-manager'; /** * Initialize accounts registry from existing tokens diff --git a/src/cliproxy/auth-session-manager.ts b/src/cliproxy/auth/auth-session-manager.ts similarity index 100% rename from src/cliproxy/auth-session-manager.ts rename to src/cliproxy/auth/auth-session-manager.ts diff --git a/src/cliproxy/auth-token-manager.ts b/src/cliproxy/auth/auth-token-manager.ts similarity index 98% rename from src/cliproxy/auth-token-manager.ts rename to src/cliproxy/auth/auth-token-manager.ts index ead0ce99..7ace9252 100644 --- a/src/cliproxy/auth-token-manager.ts +++ b/src/cliproxy/auth/auth-token-manager.ts @@ -8,8 +8,8 @@ */ import { randomBytes } from 'crypto'; -import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../config/unified-config-loader'; -import { CCS_INTERNAL_API_KEY, CCS_CONTROL_PANEL_SECRET } from './config-generator'; +import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; +import { CCS_INTERNAL_API_KEY, CCS_CONTROL_PANEL_SECRET } from '../config/generator'; /** * Generate a cryptographically secure token. diff --git a/src/cliproxy/auth/auth-types.ts b/src/cliproxy/auth/auth-types.ts index 3f28ce46..231ab850 100644 --- a/src/cliproxy/auth/auth-types.ts +++ b/src/cliproxy/auth/auth-types.ts @@ -5,7 +5,7 @@ */ import { CLIProxyProvider } from '../types'; -import type { AccountInfo } from '../account-manager'; +import type { AccountInfo } from '../accounts/account-manager'; import { buildProviderMap, CLIPROXY_PROVIDER_IDS, diff --git a/src/cliproxy/auth-utils.ts b/src/cliproxy/auth/auth-utils.ts similarity index 100% rename from src/cliproxy/auth-utils.ts rename to src/cliproxy/auth/auth-utils.ts diff --git a/src/cliproxy/device-code-handler.ts b/src/cliproxy/auth/device-code-handler.ts similarity index 100% rename from src/cliproxy/device-code-handler.ts rename to src/cliproxy/auth/device-code-handler.ts diff --git a/src/cliproxy/auth/kiro-import.ts b/src/cliproxy/auth/kiro-import.ts index 9e83facd..b0a547c7 100644 --- a/src/cliproxy/auth/kiro-import.ts +++ b/src/cliproxy/auth/kiro-import.ts @@ -8,7 +8,7 @@ import { spawn } from 'child_process'; import { info, ok, fail } from '../../utils/ui'; import { ensureCLIProxyBinary } from '../binary-manager'; -import { generateConfig } from '../config-generator'; +import { generateConfig } from '../config/config-generator'; import { getProviderTokenDir } from './token-manager'; export interface KiroImportResult { diff --git a/src/cliproxy/auth/oauth-handler.ts b/src/cliproxy/auth/oauth-handler.ts index 7b1482fa..78a3ea6a 100644 --- a/src/cliproxy/auth/oauth-handler.ts +++ b/src/cliproxy/auth/oauth-handler.ts @@ -13,7 +13,7 @@ import * as fs from 'fs'; import { fail, info, warn, color, ok } from '../../utils/ui'; import { ensureCLIProxyBinary } from '../binary-manager'; -import { generateConfig } from '../config-generator'; +import { generateConfig } from '../config/config-generator'; import { CLIProxyProvider } from '../types'; import { AccountInfo, @@ -24,7 +24,7 @@ import { findAccountNameMatch, PROVIDERS_WITHOUT_EMAIL, validateNickname, -} from '../account-manager'; +} from '../accounts/account-manager'; import { enhancedPreflightOAuthCheck, OAUTH_CALLBACK_PORTS as OAUTH_PORTS, @@ -62,14 +62,14 @@ import { buildProxyUrl, buildManagementHeaders, type ProxyTarget, -} from '../proxy-target-resolver'; +} from '../proxy/proxy-target-resolver'; import { checkNewAccountConflict, warnNewAccountConflict, warnOAuthBanRisk, warnPossible403Ban, -} from '../account-safety'; -import { ensureCliAntigravityResponsibility } from '../antigravity-responsibility'; +} from '../accounts/account-safety'; +import { ensureCliAntigravityResponsibility } from '../auth/antigravity-responsibility'; import { InteractivePrompt } from '../../utils/prompt'; interface PasteCallbackStartData { diff --git a/src/cliproxy/auth/oauth-process.ts b/src/cliproxy/auth/oauth-process.ts index 689b93b3..2557fcb7 100644 --- a/src/cliproxy/auth/oauth-process.ts +++ b/src/cliproxy/auth/oauth-process.ts @@ -10,7 +10,7 @@ import { ok, fail, info, warn } from '../../utils/ui'; import { killWithEscalation } from '../../utils/process-utils'; import { tryKiroImport } from './kiro-import'; import { CLIProxyProvider } from '../types'; -import { AccountInfo } from '../account-manager'; +import { AccountInfo } from '../accounts/account-manager'; import { parseProjectList, parseDefaultProject, @@ -21,7 +21,7 @@ import { cancelProjectSelection, type GCloudProject, type ProjectSelectionPrompt, -} from '../project-selection-handler'; +} from '../auth/project-selection-handler'; import { KiroAuthMethod, ProviderOAuthConfig } from './auth-types'; import { getTimeoutTroubleshooting, showStep } from './environment-detector'; import { @@ -34,14 +34,14 @@ import { deviceCodeEvents, DEVICE_CODE_TIMEOUT_MS, type DeviceCodePrompt, -} from '../device-code-handler'; +} from '../auth/device-code-handler'; import { OAUTH_FLOW_TYPES } from '../../management'; import { registerAuthSession, attachProcessToSession, unregisterAuthSession, authSessionEvents, -} from '../auth-session-manager'; +} from '../auth/auth-session-manager'; /** Options for OAuth process execution */ export interface OAuthProcessOptions { diff --git a/src/cliproxy/project-selection-handler.ts b/src/cliproxy/auth/project-selection-handler.ts similarity index 100% rename from src/cliproxy/project-selection-handler.ts rename to src/cliproxy/auth/project-selection-handler.ts diff --git a/src/cliproxy/provider-entitlement-evidence.ts b/src/cliproxy/auth/provider-entitlement-evidence.ts similarity index 97% rename from src/cliproxy/provider-entitlement-evidence.ts rename to src/cliproxy/auth/provider-entitlement-evidence.ts index 9b36576e..dea4bf20 100644 --- a/src/cliproxy/provider-entitlement-evidence.ts +++ b/src/cliproxy/auth/provider-entitlement-evidence.ts @@ -1,4 +1,4 @@ -import type { AccountTier } from './accounts/types'; +import type { AccountTier } from '../accounts/types'; import type { ProviderAccessState, ProviderCapacityState, diff --git a/src/cliproxy/provider-entitlement-types.ts b/src/cliproxy/auth/provider-entitlement-types.ts similarity index 93% rename from src/cliproxy/provider-entitlement-types.ts rename to src/cliproxy/auth/provider-entitlement-types.ts index ef07b8db..375f7f08 100644 --- a/src/cliproxy/provider-entitlement-types.ts +++ b/src/cliproxy/auth/provider-entitlement-types.ts @@ -1,4 +1,4 @@ -import type { AccountTier } from './accounts/types'; +import type { AccountTier } from '../accounts/types'; export type ProviderEntitlementSource = | 'runtime_api' diff --git a/src/cliproxy/auth/provider-refreshers/index.ts b/src/cliproxy/auth/provider-refreshers/index.ts index d5cfea3b..ea85348a 100644 --- a/src/cliproxy/auth/provider-refreshers/index.ts +++ b/src/cliproxy/auth/provider-refreshers/index.ts @@ -10,7 +10,7 @@ */ import { CLIProxyProvider } from '../../types'; -import { getProviderAccounts } from '../../account-manager'; +import { getProviderAccounts } from '../../accounts/account-manager'; import { getTokenRefreshOwnership, isRefreshDelegatedToCLIProxy, diff --git a/src/cliproxy/auth/token-expiry-checker.ts b/src/cliproxy/auth/token-expiry-checker.ts index a8f13177..c2740fee 100644 --- a/src/cliproxy/auth/token-expiry-checker.ts +++ b/src/cliproxy/auth/token-expiry-checker.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { CLIProxyProvider } from '../types'; import { CLIPROXY_PROFILES } from '../../auth/profile-detector'; -import { getProviderAccounts, getAccountTokenPath } from '../account-manager'; +import { getProviderAccounts, getAccountTokenPath } from '../accounts/account-manager'; import { isRefreshDelegated } from './provider-refreshers'; /** Preemptive refresh time: refresh tokens 45 minutes before expiry */ diff --git a/src/cliproxy/auth/token-manager.ts b/src/cliproxy/auth/token-manager.ts index a41ae62b..511aead1 100644 --- a/src/cliproxy/auth/token-manager.ts +++ b/src/cliproxy/auth/token-manager.ts @@ -10,8 +10,8 @@ import * as path from 'path'; import { createHash } from 'crypto'; import { CLIProxyProvider } from '../types'; import { CLIPROXY_PROFILES } from '../../auth/profile-detector'; -import { getProviderAuthDir } from '../config-generator'; -import { getProviderAccounts, getDefaultAccount } from '../account-manager'; +import { getProviderAuthDir } from '../config/config-generator'; +import { getProviderAccounts, getDefaultAccount } from '../accounts/account-manager'; import { deleteTokenFile, extractAccountIdFromTokenFile } from '../accounts/token-file-ops'; import { buildEmailBackedAccountId } from '../accounts/email-account-identity'; import { getTokenRefreshOwnership } from '../provider-capabilities'; @@ -367,8 +367,8 @@ export function registerAccountFromToken( nickname?: string, verbose = false, expectedAccountId?: string -): import('../account-manager').AccountInfo | null { - const { registerAccount } = require('../account-manager'); +): import('../accounts/account-manager').AccountInfo | null { + const { registerAccount } = require('../accounts/account-manager'); let selectedCandidate: Omit | null = null; try { const candidates = listTokenCandidates(provider, tokenDir); @@ -438,7 +438,7 @@ export function registerAccountFromToken( */ function uploadTokenToRemoteAsync(tokenPath: string, verbose: boolean): void { // Dynamic import to avoid circular dependencies - import('../remote-token-uploader') + import('../management/remote-token-uploader') .then(({ uploadTokenToRemote, isRemoteUploadEnabled }) => { if (isRemoteUploadEnabled()) { // uploadTokenToRemote handles its own success/failure logging diff --git a/src/cliproxy/binary-manager.ts b/src/cliproxy/binary-manager.ts index 95c486b3..baa11726 100644 --- a/src/cliproxy/binary-manager.ts +++ b/src/cliproxy/binary-manager.ts @@ -8,14 +8,14 @@ import * as fs from 'fs'; import * as path from 'path'; import { info, warn } from '../utils/ui'; -import { getBinDir, CLIPROXY_DEFAULT_PORT } from './config-generator'; +import { getBinDir, CLIPROXY_DEFAULT_PORT } from './config/config-generator'; import { BinaryInfo, BinaryManagerConfig } from './types'; import { BACKEND_CONFIG, DEFAULT_BACKEND, CLIPROXY_MAX_STABLE_VERSION, getExecutableName, -} from './platform-detector'; +} from './binary/platform-detector'; import { stopProxy } from './services/proxy-lifecycle-service'; import { waitForPortFree } from '../utils/port-utils'; import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; diff --git a/tests/unit/cliproxy/binary-downloader-proxy.test.ts b/src/cliproxy/binary/__tests__/binary-downloader-proxy.test.ts similarity index 99% rename from tests/unit/cliproxy/binary-downloader-proxy.test.ts rename to src/cliproxy/binary/__tests__/binary-downloader-proxy.test.ts index 6531a3d5..26f78682 100644 --- a/tests/unit/cliproxy/binary-downloader-proxy.test.ts +++ b/src/cliproxy/binary/__tests__/binary-downloader-proxy.test.ts @@ -5,7 +5,7 @@ */ import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; -import { __testExports } from '../../../src/cliproxy/binary/downloader'; +import { __testExports } from '../downloader'; const { getProxyUrl, shouldBypassProxy, getHostname, getProxyAgent } = __testExports; diff --git a/tests/unit/cliproxy/binary-installer-etxtbsy.test.ts b/src/cliproxy/binary/__tests__/binary-installer-etxtbsy.test.ts similarity index 97% rename from tests/unit/cliproxy/binary-installer-etxtbsy.test.ts rename to src/cliproxy/binary/__tests__/binary-installer-etxtbsy.test.ts index 8f51d769..8d606bfa 100644 --- a/tests/unit/cliproxy/binary-installer-etxtbsy.test.ts +++ b/src/cliproxy/binary/__tests__/binary-installer-etxtbsy.test.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; -import { deleteBinary } from '../../../src/cliproxy/binary/installer'; +import { deleteBinary } from '../installer'; describe('deleteBinary ETXTBSY guard', () => { let tmpDir: string; diff --git a/tests/unit/cliproxy/binary-manager-install.test.ts b/src/cliproxy/binary/__tests__/binary-manager-install.test.ts similarity index 84% rename from tests/unit/cliproxy/binary-manager-install.test.ts rename to src/cliproxy/binary/__tests__/binary-manager-install.test.ts index dfe781f5..d6f89631 100644 --- a/tests/unit/cliproxy/binary-manager-install.test.ts +++ b/src/cliproxy/binary/__tests__/binary-manager-install.test.ts @@ -29,7 +29,7 @@ describe('installCliproxyVersion', () => { let seenBackend: string | undefined; const binaryManager = await import( - `../../../src/cliproxy/binary-manager?binary-manager-explicit-plus=${Date.now()}` + `../../binary-manager?binary-manager-explicit-plus=${Date.now()}` ); await binaryManager.installCliproxyVersion('6.7.1', false, 'plus', { @@ -53,7 +53,7 @@ describe('installCliproxyVersion', () => { it('returns plus and emits an informational notice when plus backend is resolved locally', async () => { const binaryManager = await import( - `../../../src/cliproxy/binary-manager?binary-manager-warning=${Date.now()}` + `../../binary-manager?binary-manager-warning=${Date.now()}` ); const writes: string[] = []; @@ -75,12 +75,12 @@ describe('installCliproxyVersion', () => { }); it('uses plus binary and pin state when local runtime is configured for plus', async () => { - const { createEmptyUnifiedConfig } = await import('../../../src/config/unified-config-types'); - const { saveUnifiedConfig } = await import('../../../src/config/unified-config-loader'); - const { savePinnedVersion } = await import('../../../src/cliproxy/binary/version-cache'); - const { getExecutableName } = await import('../../../src/cliproxy/platform-detector'); + const { createEmptyUnifiedConfig } = await import('../../../config/unified-config-types'); + const { saveUnifiedConfig } = await import('../../../config/unified-config-loader'); + const { savePinnedVersion } = await import('../version-cache'); + const { getExecutableName } = await import('../platform-detector'); const binaryService = await import( - `../../../src/cliproxy/services/binary-service?binary-service-plus-migration=${Date.now()}` + `../../services/binary-service?binary-service-plus-migration=${Date.now()}` ); const config = createEmptyUnifiedConfig(); @@ -101,12 +101,12 @@ describe('installCliproxyVersion', () => { }); it('copies plus binary and pin state when legacy deleted upstream fallback is active', async () => { - const { createEmptyUnifiedConfig } = await import('../../../src/config/unified-config-types'); - const { saveUnifiedConfig } = await import('../../../src/config/unified-config-loader'); - const { savePinnedVersion } = await import('../../../src/cliproxy/binary/version-cache'); - const platformDetector = await import('../../../src/cliproxy/platform-detector'); + const { createEmptyUnifiedConfig } = await import('../../../config/unified-config-types'); + const { saveUnifiedConfig } = await import('../../../config/unified-config-loader'); + const { savePinnedVersion } = await import('../version-cache'); + const platformDetector = await import('../platform-detector'); const binaryService = await import( - `../../../src/cliproxy/services/binary-service?binary-service-legacy-plus-fallback=${Date.now()}` + `../../services/binary-service?binary-service-legacy-plus-fallback=${Date.now()}` ); const plusConfig = platformDetector.BACKEND_CONFIG.plus as unknown as { repo: string }; @@ -147,7 +147,7 @@ describe('installCliproxyVersion', () => { }; const binaryManager = await import( - `../../../src/cliproxy/binary-manager?binary-manager-install=${Date.now()}` + `../../binary-manager?binary-manager-install=${Date.now()}` ); await binaryManager.installCliproxyVersion('6.7.1', false, 'plus', { @@ -182,7 +182,7 @@ describe('installCliproxyVersion', () => { it('fails fast when runtime startup forbids installing a missing binary', async () => { const binaryManager = await import( - `../../../src/cliproxy/binary-manager?binary-manager-runtime=${Date.now()}` + `../../binary-manager?binary-manager-runtime=${Date.now()}` ); await expect( diff --git a/tests/unit/cliproxy/version-checker-stale-cache.test.ts b/src/cliproxy/binary/__tests__/version-checker-stale-cache.test.ts similarity index 100% rename from tests/unit/cliproxy/version-checker-stale-cache.test.ts rename to src/cliproxy/binary/__tests__/version-checker-stale-cache.test.ts diff --git a/src/cliproxy/binary/extractor.ts b/src/cliproxy/binary/extractor.ts index 28905f3f..6b35d1bb 100644 --- a/src/cliproxy/binary/extractor.ts +++ b/src/cliproxy/binary/extractor.ts @@ -4,7 +4,7 @@ */ import { ArchiveExtension, CLIProxyBackend } from '../types'; -import { DEFAULT_BACKEND } from '../platform-detector'; +import { DEFAULT_BACKEND } from '../binary/platform-detector'; import { extractTarGz } from './tar-extractor'; import { extractZip } from './zip-extractor'; diff --git a/src/cliproxy/binary/installer.ts b/src/cliproxy/binary/installer.ts index 2ce8c8d9..68be9dca 100644 --- a/src/cliproxy/binary/installer.ts +++ b/src/cliproxy/binary/installer.ts @@ -12,7 +12,7 @@ import { getChecksumsUrl, getExecutableName, DEFAULT_BACKEND, -} from '../platform-detector'; +} from '../binary/platform-detector'; import { downloadWithRetry } from './downloader'; import { verifyChecksum, computeChecksum } from './verifier'; import { extractArchive } from './extractor'; diff --git a/src/cliproxy/binary/lifecycle.ts b/src/cliproxy/binary/lifecycle.ts index 81e0d677..737354e0 100644 --- a/src/cliproxy/binary/lifecycle.ts +++ b/src/cliproxy/binary/lifecycle.ts @@ -13,13 +13,13 @@ import { } from './version-checker'; import { downloadAndInstall, deleteBinary, getBinaryPath } from './installer'; import { info, warn } from '../../utils/ui'; -import { isCliproxyRunning } from '../stats-fetcher'; -import { CLIPROXY_DEFAULT_PORT } from '../config-generator'; +import { isCliproxyRunning } from '../services/stats-fetcher'; +import { CLIPROXY_DEFAULT_PORT } from '../config/config-generator'; import { CLIPROXY_MAX_STABLE_VERSION, CLIPROXY_FAULTY_RANGE, DEFAULT_BACKEND, -} from '../platform-detector'; +} from '../binary/platform-detector'; /** Log helper */ function log(message: string, verbose: boolean): void { diff --git a/src/cliproxy/platform-detector.ts b/src/cliproxy/binary/platform-detector.ts similarity index 99% rename from src/cliproxy/platform-detector.ts rename to src/cliproxy/binary/platform-detector.ts index 8a75dc4e..4b5e38f5 100644 --- a/src/cliproxy/platform-detector.ts +++ b/src/cliproxy/binary/platform-detector.ts @@ -11,7 +11,7 @@ import { SupportedArch, ArchiveExtension, CLIProxyBackend, -} from './types'; +} from '../types'; /** Backend configuration */ export const BACKEND_CONFIG = { diff --git a/src/cliproxy/binary/tar-extractor.ts b/src/cliproxy/binary/tar-extractor.ts index 540a805f..2000dd9e 100644 --- a/src/cliproxy/binary/tar-extractor.ts +++ b/src/cliproxy/binary/tar-extractor.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as zlib from 'zlib'; -import { getExecutableName, getArchiveBinaryName, DEFAULT_BACKEND } from '../platform-detector'; +import { getExecutableName, getArchiveBinaryName, DEFAULT_BACKEND } from '../binary/platform-detector'; import type { CLIProxyBackend } from '../types'; /** diff --git a/src/cliproxy/binary/version-cache.ts b/src/cliproxy/binary/version-cache.ts index cf39c211..3b009425 100644 --- a/src/cliproxy/binary/version-cache.ts +++ b/src/cliproxy/binary/version-cache.ts @@ -5,14 +5,14 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getBinDir } from '../config-generator'; +import { getBinDir } from '../config/config-generator'; import { VersionCache, VERSION_CACHE_DURATION_MS, VERSION_PIN_FILE, VersionListCache, } from './types'; -import { DEFAULT_BACKEND } from '../platform-detector'; +import { DEFAULT_BACKEND } from '../binary/platform-detector'; import type { CLIProxyBackend } from '../types'; /** diff --git a/src/cliproxy/binary/version-checker.ts b/src/cliproxy/binary/version-checker.ts index 7c11a0b2..cfade244 100644 --- a/src/cliproxy/binary/version-checker.ts +++ b/src/cliproxy/binary/version-checker.ts @@ -18,7 +18,7 @@ import { CLIPROXY_MAX_STABLE_VERSION, CLIPROXY_FAULTY_RANGE, DEFAULT_BACKEND, -} from '../platform-detector'; +} from '../binary/platform-detector'; import type { CLIProxyBackend } from '../types'; interface FetchLatestVersionDeps { diff --git a/src/cliproxy/binary/zip-extractor.ts b/src/cliproxy/binary/zip-extractor.ts index 43d95fc8..e54d4bbd 100644 --- a/src/cliproxy/binary/zip-extractor.ts +++ b/src/cliproxy/binary/zip-extractor.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as zlib from 'zlib'; -import { getExecutableName, getArchiveBinaryName, DEFAULT_BACKEND } from '../platform-detector'; +import { getExecutableName, getArchiveBinaryName, DEFAULT_BACKEND } from '../binary/platform-detector'; import type { CLIProxyBackend } from '../types'; /** diff --git a/tests/unit/cliproxy/backend-selection.test.js b/src/cliproxy/config/__tests__/backend-selection.test.js similarity index 97% rename from tests/unit/cliproxy/backend-selection.test.js rename to src/cliproxy/config/__tests__/backend-selection.test.js index 8f46fb3a..50e5f2df 100644 --- a/tests/unit/cliproxy/backend-selection.test.js +++ b/src/cliproxy/config/__tests__/backend-selection.test.js @@ -6,8 +6,8 @@ const assert = require('assert'); describe('Backend Selection', () => { - const platformDetector = require('../../../dist/cliproxy/platform-detector'); - const types = require('../../../dist/cliproxy/types'); + const platformDetector = require('../../../../dist/cliproxy/platform-detector'); + const types = require('../../../../dist/cliproxy/types'); describe('BACKEND_CONFIG', () => { it('has correct configuration for original backend', () => { diff --git a/tests/unit/cliproxy/backend-ui-default-ports-sync.test.ts b/src/cliproxy/config/__tests__/backend-ui-default-ports-sync.test.ts similarity index 90% rename from tests/unit/cliproxy/backend-ui-default-ports-sync.test.ts rename to src/cliproxy/config/__tests__/backend-ui-default-ports-sync.test.ts index 5670eecf..26e68a6a 100644 --- a/tests/unit/cliproxy/backend-ui-default-ports-sync.test.ts +++ b/src/cliproxy/config/__tests__/backend-ui-default-ports-sync.test.ts @@ -5,26 +5,26 @@ */ import { describe, expect, test } from 'bun:test'; -import { CLIPROXY_DEFAULT_PORT as BACKEND_CLIPROXY_DEFAULT_PORT } from '../../../src/cliproxy/config/port-manager'; -import { DEFAULT_CURSOR_PORT as BACKEND_CURSOR_DEFAULT_PORT } from '../../../src/cursor/cursor-models'; +import { CLIPROXY_DEFAULT_PORT as BACKEND_CLIPROXY_DEFAULT_PORT } from '../port-manager'; +import { DEFAULT_CURSOR_PORT as BACKEND_CURSOR_DEFAULT_PORT } from '../../../cursor/cursor-models'; import { CLIPROXY_PROVIDER_IDS as BACKEND_CLIPROXY_PROVIDER_IDS, getProviderDescription as getBackendProviderDescription, getProviderDisplayName as getBackendProviderDisplayName, getProvidersByOAuthFlow, -} from '../../../src/cliproxy/provider-capabilities'; +} from '../../provider-capabilities'; import { CLIPROXY_DEFAULT_PORT as UI_CLIPROXY_DEFAULT_PORT, DEFAULT_CURSOR_PORT as UI_CURSOR_DEFAULT_PORT, -} from '../../../ui/src/lib/default-ports'; +} from '../../../../ui/src/lib/default-ports'; import { CLIPROXY_PROVIDERS as UI_CLIPROXY_PROVIDERS, CORE_CLIPROXY_PROVIDERS as UI_CORE_CLIPROXY_PROVIDERS, DEVICE_CODE_PROVIDERS as UI_DEVICE_CODE_PROVIDERS, PLUS_EXTRA_CLIPROXY_PROVIDERS as UI_PLUS_EXTRA_CLIPROXY_PROVIDERS, PROVIDER_METADATA as UI_PROVIDER_METADATA, -} from '../../../ui/src/lib/provider-config'; -import { PLUS_ONLY_PROVIDERS as BACKEND_PLUS_ONLY_PROVIDERS } from '../../../src/cliproxy/types'; +} from '../../../../ui/src/lib/provider-config'; +import { PLUS_ONLY_PROVIDERS as BACKEND_PLUS_ONLY_PROVIDERS } from '../../types/index'; function sorted(values: readonly string[]): string[] { return [...values].sort((a, b) => a.localeCompare(b)); diff --git a/tests/unit/cliproxy/backend-ui-provider-arrays-sync.test.ts b/src/cliproxy/config/__tests__/backend-ui-provider-arrays-sync.test.ts similarity index 84% rename from tests/unit/cliproxy/backend-ui-provider-arrays-sync.test.ts rename to src/cliproxy/config/__tests__/backend-ui-provider-arrays-sync.test.ts index 15b6d489..95b5fa1d 100644 --- a/tests/unit/cliproxy/backend-ui-provider-arrays-sync.test.ts +++ b/src/cliproxy/config/__tests__/backend-ui-provider-arrays-sync.test.ts @@ -6,8 +6,8 @@ */ import { describe, expect, test } from 'bun:test'; -import { CLIPROXY_PROFILES } from '../../../src/auth/profile-detector'; -import { CLIPROXY_PROVIDERS } from '../../../ui/src/lib/provider-config'; +import { CLIPROXY_PROFILES } from '../../../auth/profile-detector'; +import { CLIPROXY_PROVIDERS } from '../../../../ui/src/lib/provider-config'; describe('Provider Sync', () => { test('backend CLIPROXY_PROFILES matches UI CLIPROXY_PROVIDERS', () => { diff --git a/tests/unit/cliproxy/base-config-loader.test.ts b/src/cliproxy/config/__tests__/base-config-loader.test.ts similarity index 92% rename from tests/unit/cliproxy/base-config-loader.test.ts rename to src/cliproxy/config/__tests__/base-config-loader.test.ts index 528d9106..88a74338 100644 --- a/tests/unit/cliproxy/base-config-loader.test.ts +++ b/src/cliproxy/config/__tests__/base-config-loader.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'bun:test'; -import { loadBaseConfig } from '../../../src/cliproxy/base-config-loader'; +import { loadBaseConfig } from '../../config/base-config-loader'; describe('base-config-loader new providers', () => { it.each([ diff --git a/tests/unit/cliproxy/composite-validator.test.ts b/src/cliproxy/config/__tests__/composite-validator.test.ts similarity index 97% rename from tests/unit/cliproxy/composite-validator.test.ts rename to src/cliproxy/config/__tests__/composite-validator.test.ts index d762294d..90348f07 100644 --- a/tests/unit/cliproxy/composite-validator.test.ts +++ b/src/cliproxy/config/__tests__/composite-validator.test.ts @@ -6,7 +6,7 @@ import { describe, it, expect } from 'bun:test'; import { validateCompositeDefaultTier, validateCompositeTiers, -} from '../../../src/cliproxy/composite-validator'; +} from '../../config/composite-validator'; const validTier = { provider: 'agy', diff --git a/tests/unit/cliproxy/config-generator-port.test.js b/src/cliproxy/config/__tests__/config-generator-port.test.js similarity index 99% rename from tests/unit/cliproxy/config-generator-port.test.js rename to src/cliproxy/config/__tests__/config-generator-port.test.js index af291d00..3fc7f60b 100644 --- a/tests/unit/cliproxy/config-generator-port.test.js +++ b/src/cliproxy/config/__tests__/config-generator-port.test.js @@ -26,7 +26,7 @@ const { deleteConfigForPort, deleteConfig, CLIPROXY_DEFAULT_PORT, -} = require('../../../dist/cliproxy/config-generator'); +} = require('../../../../dist/cliproxy/config-generator'); describe('Config Generator Port', function () { let cliproxyDir; diff --git a/tests/unit/cliproxy/config-generator.test.js b/src/cliproxy/config/__tests__/config-generator.test.js similarity index 98% rename from tests/unit/cliproxy/config-generator.test.js rename to src/cliproxy/config/__tests__/config-generator.test.js index 277ca2dd..4ac1eeaf 100644 --- a/tests/unit/cliproxy/config-generator.test.js +++ b/src/cliproxy/config/__tests__/config-generator.test.js @@ -7,7 +7,7 @@ const assert = require('assert'); const path = require('path'); // Mock the config-manager module to provide test paths -const originalModule = require.cache[require.resolve('../../../dist/utils/config-manager')]; +const originalModule = require.cache[require.resolve('../../../../dist/utils/config-manager')]; describe('Config Generator', () => { let configGenerator; @@ -15,7 +15,7 @@ describe('Config Generator', () => { beforeEach(() => { // Clear the require cache to reload module with fresh mocks - delete require.cache[require.resolve('../../../dist/cliproxy/config-generator')]; + delete require.cache[require.resolve('../../../../dist/cliproxy/config-generator')]; // Set up a temporary test directory as CCS_HOME mockCcsDir = '/test/home/.ccs'; @@ -174,8 +174,8 @@ describe('Config Generator', () => { beforeEach(() => { // Clear cache and reload module - delete require.cache[require.resolve('../../../dist/cliproxy/config-generator')]; - const configGenerator = require('../../../dist/cliproxy/config-generator'); + delete require.cache[require.resolve('../../../../dist/cliproxy/config-generator')]; + const configGenerator = require('../../../../dist/cliproxy/config-generator'); parseUserApiKeys = configGenerator.parseUserApiKeys; }); @@ -374,9 +374,9 @@ auth-dir: "/test" process.env.CCS_HOME = testDir; // Clear cache and reload module - delete require.cache[require.resolve('../../../dist/cliproxy/config-generator')]; - delete require.cache[require.resolve('../../../dist/utils/config-manager')]; - const configGenerator = require('../../../dist/cliproxy/config-generator'); + delete require.cache[require.resolve('../../../../dist/cliproxy/config-generator')]; + delete require.cache[require.resolve('../../../../dist/utils/config-manager')]; + const configGenerator = require('../../../../dist/cliproxy/config-generator'); regenerateConfig = configGenerator.regenerateConfig; getCliproxyConfigPath = configGenerator.getCliproxyConfigPath; }); @@ -596,9 +596,9 @@ auth-dir: "${cliproxyDir.replace(/\\/g, '/')}/auth" originalCcsHome = process.env.CCS_HOME; process.env.CCS_HOME = testDir; - delete require.cache[require.resolve('../../../dist/cliproxy/config-generator')]; - delete require.cache[require.resolve('../../../dist/utils/config-manager')]; - const configGenerator = require('../../../dist/cliproxy/config-generator'); + delete require.cache[require.resolve('../../../../dist/cliproxy/config-generator')]; + delete require.cache[require.resolve('../../../../dist/utils/config-manager')]; + const configGenerator = require('../../../../dist/cliproxy/config-generator'); regenerateConfig = configGenerator.regenerateConfig; }); diff --git a/tests/unit/cliproxy/env-builder-migration.test.ts b/src/cliproxy/config/__tests__/env-builder-migration.test.ts similarity index 100% rename from tests/unit/cliproxy/env-builder-migration.test.ts rename to src/cliproxy/config/__tests__/env-builder-migration.test.ts diff --git a/tests/unit/cliproxy/env-builder-provider-url.test.ts b/src/cliproxy/config/__tests__/env-builder-provider-url.test.ts similarity index 99% rename from tests/unit/cliproxy/env-builder-provider-url.test.ts rename to src/cliproxy/config/__tests__/env-builder-provider-url.test.ts index acb41cca..247a2717 100644 --- a/tests/unit/cliproxy/env-builder-provider-url.test.ts +++ b/src/cliproxy/config/__tests__/env-builder-provider-url.test.ts @@ -5,7 +5,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { ensureProviderSettings, getEffectiveEnvVars, -} from '../../../src/cliproxy/config/env-builder'; +} from '../env-builder'; interface EnvSettings { ANTHROPIC_BASE_URL: string; diff --git a/tests/unit/cliproxy/port-validation.test.ts b/src/cliproxy/config/__tests__/port-validation.test.ts similarity index 97% rename from tests/unit/cliproxy/port-validation.test.ts rename to src/cliproxy/config/__tests__/port-validation.test.ts index 9fb39153..8dea0517 100644 --- a/tests/unit/cliproxy/port-validation.test.ts +++ b/src/cliproxy/config/__tests__/port-validation.test.ts @@ -12,8 +12,8 @@ */ import { describe, it, expect } from 'bun:test'; -import { validatePort, CLIPROXY_DEFAULT_PORT } from '../../../src/cliproxy/config-generator'; -import { resolveProxyConfig } from '../../../src/cliproxy/proxy-config-resolver'; +import { validatePort, CLIPROXY_DEFAULT_PORT } from '../config-generator'; +import { resolveProxyConfig } from '../../proxy/proxy-config-resolver'; describe('Port Validation', () => { describe('validatePort()', () => { diff --git a/src/cliproxy/base-config-loader.ts b/src/cliproxy/config/base-config-loader.ts similarity index 97% rename from src/cliproxy/base-config-loader.ts rename to src/cliproxy/config/base-config-loader.ts index ab774d06..9e59131a 100644 --- a/src/cliproxy/base-config-loader.ts +++ b/src/cliproxy/config/base-config-loader.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import type { CLIProxyProvider, ProviderModelMapping } from './types'; +import type { CLIProxyProvider, ProviderModelMapping } from '../types'; /** Base settings file structure */ interface BaseSettings { diff --git a/src/cliproxy/composite-validator.ts b/src/cliproxy/config/composite-validator.ts similarity index 93% rename from src/cliproxy/composite-validator.ts rename to src/cliproxy/config/composite-validator.ts index e2e24a53..a5ae864d 100644 --- a/src/cliproxy/composite-validator.ts +++ b/src/cliproxy/config/composite-validator.ts @@ -3,10 +3,10 @@ * Used by API routes, service layer, and config loader to avoid contract drift. */ -import { CLIPROXY_SUPPORTED_PROVIDERS } from '../config/unified-config-types'; -import type { CompositeTierConfig } from '../config/unified-config-types'; -import type { CLIProxyProvider } from './types'; -import { getDeniedModelIdReasonForProvider } from './model-id-normalizer'; +import { CLIPROXY_SUPPORTED_PROVIDERS } from '../../config/unified-config-types'; +import type { CompositeTierConfig } from '../../config/unified-config-types'; +import type { CLIProxyProvider } from '../types'; +import { getDeniedModelIdReasonForProvider } from '../ai-providers/model-id-normalizer'; export const VALID_COMPOSITE_TIERS = ['opus', 'sonnet', 'haiku'] as const; export type CompositeTierName = (typeof VALID_COMPOSITE_TIERS)[number]; diff --git a/src/cliproxy/config-generator.ts b/src/cliproxy/config/config-generator.ts similarity index 95% rename from src/cliproxy/config-generator.ts rename to src/cliproxy/config/config-generator.ts index 9e51ed91..60c66028 100644 --- a/src/cliproxy/config-generator.ts +++ b/src/cliproxy/config/config-generator.ts @@ -13,4 +13,4 @@ */ // Re-export all modules for backwards compatibility -export * from './config'; +export * from '.'; diff --git a/src/cliproxy/config/env-builder.ts b/src/cliproxy/config/env-builder.ts index 417d5f04..ec0d5c00 100644 --- a/src/cliproxy/config/env-builder.ts +++ b/src/cliproxy/config/env-builder.ts @@ -6,9 +6,9 @@ import * as fs from 'fs'; import * as path from 'path'; import type { CLIProxyProvider, ProviderModelMapping } from '../types'; -import { getModelMappingFromConfig, getEnvVarsFromConfig } from '../base-config-loader'; +import { getModelMappingFromConfig, getEnvVarsFromConfig } from '../config/base-config-loader'; import { getGlobalEnvConfig } from '../../config/unified-config-loader'; -import { getEffectiveApiKey } from '../auth-token-manager'; +import { getEffectiveApiKey } from '../auth/auth-token-manager'; import { expandPath } from '../../utils/helpers'; import { warn } from '../../utils/ui'; import type { CompositeTierConfig } from '../../config/unified-config-types'; @@ -30,7 +30,7 @@ import { normalizeModelEnvVarsForProvider, normalizeIFlowLegacyModelAliases, normalizeModelIdForProvider, -} from '../model-id-normalizer'; +} from '../ai-providers/model-id-normalizer'; /** Settings file structure for user overrides */ interface ProviderSettings { diff --git a/src/cliproxy/config/generator.ts b/src/cliproxy/config/generator.ts index 3b4f7803..3578c316 100644 --- a/src/cliproxy/config/generator.ts +++ b/src/cliproxy/config/generator.ts @@ -7,11 +7,11 @@ import * as fs from 'fs'; import * as path from 'path'; import type { CLIProxyProvider, ProviderConfig } from '../types'; import { getProviderDisplayName } from '../provider-capabilities'; -import { getModelMappingFromConfig } from '../base-config-loader'; +import { getModelMappingFromConfig } from '../config/base-config-loader'; import { AI_PROVIDER_FAMILY_IDS } from '../ai-providers/types'; import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; -import { getEffectiveApiKey, getEffectiveManagementSecret } from '../auth-token-manager'; -import { getDeniedModelIdReasonForProvider } from '../model-id-normalizer'; +import { getEffectiveApiKey, getEffectiveManagementSecret } from '../auth/auth-token-manager'; +import { getDeniedModelIdReasonForProvider } from '../ai-providers/model-id-normalizer'; import { getAuthDir, getProviderAuthDir, getConfigPathForPort } from './path-resolver'; import { CLIPROXY_DEFAULT_PORT } from './port-manager'; diff --git a/src/cliproxy/model-config.ts b/src/cliproxy/config/model-config.ts similarity index 96% rename from src/cliproxy/model-config.ts rename to src/cliproxy/config/model-config.ts index 843bfa1b..9c782d84 100644 --- a/src/cliproxy/model-config.ts +++ b/src/cliproxy/config/model-config.ts @@ -7,13 +7,13 @@ import * as fs from 'fs'; import * as os from 'os'; -import { InteractivePrompt } from '../utils/prompt'; -import { getProviderCatalog, supportsModelConfig, ModelEntry } from './model-catalog'; +import { InteractivePrompt } from '../../utils/prompt'; +import { getProviderCatalog, supportsModelConfig, ModelEntry } from '../model-catalog'; import { getClaudeEnvVars, resolveProviderSettingsPath } from './config-generator'; -import { CLIProxyProvider } from './types'; -import { initUI, color, bold, dim, ok, info, header } from '../utils/ui'; -import { getCcsDir } from '../utils/config-manager'; -import { normalizeModelIdForProvider } from './model-id-normalizer'; +import { CLIProxyProvider } from '../types'; +import { initUI, color, bold, dim, ok, info, header } from '../../utils/ui'; +import { getCcsDir } from '../../utils/config-manager'; +import { normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer'; function canonicalizeModelForProvider(provider: CLIProxyProvider, model: string): string { return normalizeModelIdForProvider(model, provider); diff --git a/src/cliproxy/config/thinking-config.ts b/src/cliproxy/config/thinking-config.ts index ef98234e..7e1eba81 100644 --- a/src/cliproxy/config/thinking-config.ts +++ b/src/cliproxy/config/thinking-config.ts @@ -9,7 +9,7 @@ import type { ThinkingConfig } from '../../config/unified-config-types'; import { getThinkingConfig } from '../../config/unified-config-loader'; import { getModelThinkingSupport, supportsThinking } from '../model-catalog'; import { isThinkingOffValue, validateThinking } from '../thinking-validator'; -import { normalizeModelIdForProvider } from '../model-id-normalizer'; +import { normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer'; import { warn } from '../../utils/ui'; /** Model tier types for thinking budget defaults */ diff --git a/tests/unit/cliproxy/composite-env-routing.test.ts b/src/cliproxy/executor/__tests__/composite-env-routing.test.ts similarity index 97% rename from tests/unit/cliproxy/composite-env-routing.test.ts rename to src/cliproxy/executor/__tests__/composite-env-routing.test.ts index 3bd86e6c..4cf3ba3c 100644 --- a/tests/unit/cliproxy/composite-env-routing.test.ts +++ b/src/cliproxy/executor/__tests__/composite-env-routing.test.ts @@ -3,7 +3,7 @@ */ import { describe, it, expect } from 'bun:test'; -import { buildClaudeEnvironment } from '../../../src/cliproxy/executor/env-resolver'; +import { buildClaudeEnvironment } from '../env-resolver'; const tiers = { opus: { provider: 'agy' as const, model: 'claude-opus-4-6-thinking' }, diff --git a/tests/unit/cliproxy/composite-fallback.test.ts b/src/cliproxy/executor/__tests__/composite-fallback.test.ts similarity index 98% rename from tests/unit/cliproxy/composite-fallback.test.ts rename to src/cliproxy/executor/__tests__/composite-fallback.test.ts index 33a5f5d3..313d65e1 100644 --- a/tests/unit/cliproxy/composite-fallback.test.ts +++ b/src/cliproxy/executor/__tests__/composite-fallback.test.ts @@ -9,9 +9,9 @@ import { isProviderError, detectFailedTier, PROVIDER_ERROR_PATTERNS, -} from '../../../src/cliproxy/executor/retry-handler'; -import { applyFallback } from '../../../src/cliproxy/executor/env-resolver'; -import { CompositeTierConfig } from '../../../src/config/unified-config-types'; +} from '../retry-handler'; +import { applyFallback } from '../env-resolver'; +import { CompositeTierConfig } from '../../../config/unified-config-types'; // ======================================== // isProviderError diff --git a/tests/unit/cliproxy/composite-thinking.test.ts b/src/cliproxy/executor/__tests__/composite-thinking.test.ts similarity index 99% rename from tests/unit/cliproxy/composite-thinking.test.ts rename to src/cliproxy/executor/__tests__/composite-thinking.test.ts index 6a9de3fd..5cc2b0f7 100644 --- a/tests/unit/cliproxy/composite-thinking.test.ts +++ b/src/cliproxy/executor/__tests__/composite-thinking.test.ts @@ -10,8 +10,8 @@ import { applyThinkingSuffix, detectTierFromModel, getThinkingValueForTier, -} from '../../../src/cliproxy/config/thinking-config'; -import { CLIProxyProvider } from '../../../src/cliproxy/types'; +} from '../../config/thinking-config'; +import { CLIProxyProvider } from '../types'; // ======================================== // applyThinkingSuffix diff --git a/tests/unit/cliproxy/composite-variant-service.test.ts b/src/cliproxy/executor/__tests__/composite-variant-service.test.ts similarity index 98% rename from tests/unit/cliproxy/composite-variant-service.test.ts rename to src/cliproxy/executor/__tests__/composite-variant-service.test.ts index ccc47fda..89768942 100644 --- a/tests/unit/cliproxy/composite-variant-service.test.ts +++ b/src/cliproxy/executor/__tests__/composite-variant-service.test.ts @@ -9,12 +9,12 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; import { createCompositeVariant, updateCompositeVariant, -} from '../../../src/cliproxy/services/variant-service'; +} from '../../services/variant-service'; import { saveCompositeVariantUnified, listVariantsFromConfig, -} from '../../../src/cliproxy/services/variant-config-adapter'; -import { CompositeVariantConfig } from '../../../src/config/unified-config-types'; +} from '../../services/variant-config-adapter'; +import { CompositeVariantConfig } from '../../../config/unified-config-types'; describe('updateCompositeVariant', () => { let tmpDir: string; diff --git a/tests/unit/cliproxy/env-resolver-codex-fallback.test.ts b/src/cliproxy/executor/__tests__/env-resolver-codex-fallback.test.ts similarity index 99% rename from tests/unit/cliproxy/env-resolver-codex-fallback.test.ts rename to src/cliproxy/executor/__tests__/env-resolver-codex-fallback.test.ts index 2d8dee54..d0359ed9 100644 --- a/tests/unit/cliproxy/env-resolver-codex-fallback.test.ts +++ b/src/cliproxy/executor/__tests__/env-resolver-codex-fallback.test.ts @@ -5,8 +5,8 @@ import { afterEach, describe, expect, it } from 'bun:test'; import { buildClaudeEnvironment, resolveCliproxyImageAnalysisEnv, -} from '../../../src/cliproxy/executor/env-resolver'; -import type { ImageAnalysisStatus } from '../../../src/utils/hooks'; +} from '../env-resolver'; +import type { ImageAnalysisStatus } from '../../../utils/hooks'; const tempDirs: string[] = []; diff --git a/tests/unit/cliproxy/executor-option-value.test.ts b/src/cliproxy/executor/__tests__/executor-option-value.test.ts similarity index 98% rename from tests/unit/cliproxy/executor-option-value.test.ts rename to src/cliproxy/executor/__tests__/executor-option-value.test.ts index d8259047..6b32dddd 100644 --- a/tests/unit/cliproxy/executor-option-value.test.ts +++ b/src/cliproxy/executor/__tests__/executor-option-value.test.ts @@ -6,7 +6,7 @@ import { execClaudeWithCLIProxy, hasGitLabTokenLoginFlag, readOptionValue, -} from '../../../src/cliproxy/executor/index'; +} from '../index'; describe('readOptionValue', () => { it('parses split-token option values', () => { diff --git a/tests/unit/cliproxy/variant-port-allocation.test.js b/src/cliproxy/executor/__tests__/variant-port-allocation.test.js similarity index 98% rename from tests/unit/cliproxy/variant-port-allocation.test.js rename to src/cliproxy/executor/__tests__/variant-port-allocation.test.js index 363f856d..bf111521 100644 --- a/tests/unit/cliproxy/variant-port-allocation.test.js +++ b/src/cliproxy/executor/__tests__/variant-port-allocation.test.js @@ -24,8 +24,8 @@ const { listVariantsFromConfig, saveVariantLegacy, removeVariantFromLegacyConfig, -} = require('../../../dist/cliproxy/services/variant-config-adapter'); -const { CLIPROXY_DEFAULT_PORT } = require('../../../dist/cliproxy/config-generator'); +} = require('../../../../dist/cliproxy/services/variant-config-adapter'); +const { CLIPROXY_DEFAULT_PORT } = require('../../../../dist/cliproxy/config-generator'); describe('Variant Port Allocation', function () { let configPath; diff --git a/tests/unit/cliproxy/variant-port-edge-cases.test.js b/src/cliproxy/executor/__tests__/variant-port-edge-cases.test.js similarity index 98% rename from tests/unit/cliproxy/variant-port-edge-cases.test.js rename to src/cliproxy/executor/__tests__/variant-port-edge-cases.test.js index 6bad40ec..63b691ef 100644 --- a/tests/unit/cliproxy/variant-port-edge-cases.test.js +++ b/src/cliproxy/executor/__tests__/variant-port-edge-cases.test.js @@ -25,7 +25,7 @@ const { listVariantsFromConfig, saveVariantLegacy, removeVariantFromLegacyConfig, -} = require('../../../dist/cliproxy/services/variant-config-adapter'); +} = require('../../../../dist/cliproxy/services/variant-config-adapter'); const { getExistingProxy, registerSession, @@ -33,12 +33,12 @@ const { cleanupOrphanedSessions, deleteSessionLockForPort, getProxyStatus, -} = require('../../../dist/cliproxy/session-tracker'); +} = require('../../../../dist/cliproxy/session-tracker'); const { deleteConfigForPort, configExists, generateConfig, -} = require('../../../dist/cliproxy/config-generator'); +} = require('../../../../dist/cliproxy/config-generator'); describe('Variant Port Edge Cases', function () { let configPath; diff --git a/tests/unit/cliproxy/variant-port-integration.test.js b/src/cliproxy/executor/__tests__/variant-port-integration.test.js similarity index 99% rename from tests/unit/cliproxy/variant-port-integration.test.js rename to src/cliproxy/executor/__tests__/variant-port-integration.test.js index bfb03828..4936f971 100644 --- a/tests/unit/cliproxy/variant-port-integration.test.js +++ b/src/cliproxy/executor/__tests__/variant-port-integration.test.js @@ -29,21 +29,21 @@ const { listVariantsFromConfig, saveVariantLegacy, removeVariantFromLegacyConfig, -} = require('../../../dist/cliproxy/services/variant-config-adapter'); +} = require('../../../../dist/cliproxy/services/variant-config-adapter'); const { getExistingProxy, registerSession, unregisterSession, getProxyStatus, deleteSessionLockForPort, -} = require('../../../dist/cliproxy/session-tracker'); +} = require('../../../../dist/cliproxy/session-tracker'); const { generateConfig, configExists, deleteConfigForPort, getConfigPathForPort, CLIPROXY_DEFAULT_PORT, -} = require('../../../dist/cliproxy/config-generator'); +} = require('../../../../dist/cliproxy/config-generator'); describe('PR #184: Variant Port Isolation Integration', function () { let configPath; diff --git a/src/cliproxy/cliproxy-executor.ts b/src/cliproxy/executor/cliproxy-executor.ts similarity index 90% rename from src/cliproxy/cliproxy-executor.ts rename to src/cliproxy/executor/cliproxy-executor.ts index d51e3e9a..1ccf9602 100644 --- a/src/cliproxy/cliproxy-executor.ts +++ b/src/cliproxy/executor/cliproxy-executor.ts @@ -12,6 +12,6 @@ * @deprecated Import from './executor' instead */ // Re-export from modular structure -export { execClaudeWithCLIProxy, isPortAvailable, findAvailablePort } from './executor'; +export { execClaudeWithCLIProxy, isPortAvailable, findAvailablePort } from '.'; -export { default } from './executor'; +export { default } from '.'; diff --git a/src/cliproxy/executor/env-resolver.ts b/src/cliproxy/executor/env-resolver.ts index b5872947..d47c9251 100644 --- a/src/cliproxy/executor/env-resolver.ts +++ b/src/cliproxy/executor/env-resolver.ts @@ -15,7 +15,7 @@ import { getRemoteEnvVars, getCompositeEnvVars, applyThinkingConfig, -} from '../config-generator'; +} from '../config/config-generator'; import { applyExtendedContextConfig } from '../config/extended-context-config'; import { CLIProxyProvider } from '../types'; import { CompositeTierConfig } from '../../config/unified-config-types'; @@ -29,12 +29,12 @@ import { resolveImageAnalysisRuntimeStatus } from '../../utils/hooks/image-analy import { hasImageAnalysisProfileHook } from '../../utils/hooks/image-analyzer-profile-hook-injector'; import { hasImageAnalyzerHook } from '../../utils/hooks/image-analyzer-hook-installer'; import { stripBrowserEnv, stripClaudeCodeEnv } from '../../utils/shell-executor'; -import { CodexReasoningProxy } from '../codex-reasoning-proxy'; -import { ToolSanitizationProxy } from '../tool-sanitization-proxy'; -import { HttpsTunnelProxy } from '../https-tunnel-proxy'; -import { MODEL_ENV_VAR_KEYS, normalizeModelIdForProvider } from '../model-id-normalizer'; -import type { ProxyTarget } from '../proxy-target-resolver'; -import { getEffectiveApiKey } from '../auth-token-manager'; +import { CodexReasoningProxy } from '../ai-providers/codex-reasoning-proxy'; +import { ToolSanitizationProxy } from '../proxy/tool-sanitization-proxy'; +import { HttpsTunnelProxy } from '../proxy/https-tunnel-proxy'; +import { MODEL_ENV_VAR_KEYS, normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer'; +import type { ProxyTarget } from '../proxy/proxy-target-resolver'; +import { getEffectiveApiKey } from '../auth/auth-token-manager'; import { isSettings, type Settings } from '../../types/config'; export interface RemoteProxyConfig { diff --git a/src/cliproxy/executor/index.ts b/src/cliproxy/executor/index.ts index f673bcb5..80ca3088 100644 --- a/src/cliproxy/executor/index.ts +++ b/src/cliproxy/executor/index.ts @@ -30,13 +30,13 @@ import { getProviderSettingsPath, CLIPROXY_DEFAULT_PORT, validatePort, -} from '../config-generator'; -import { checkRemoteProxy } from '../remote-proxy-client'; -import { isAuthenticated } from '../auth-handler'; +} from '../config/config-generator'; +import { checkRemoteProxy } from '../services/remote-proxy-client'; +import { isAuthenticated } from '../auth/auth-handler'; import { CLIProxyProvider, CLIProxyBackend, PLUS_ONLY_PROVIDERS, ExecutorConfig } from '../types'; -import { configureProviderModel, getCurrentModel } from '../model-config'; -import { reconcileCodexModelForActivePlan } from '../codex-plan-compatibility'; -import { resolveProxyConfig, PROXY_CLI_FLAGS } from '../proxy-config-resolver'; +import { configureProviderModel, getCurrentModel } from '../config/model-config'; +import { reconcileCodexModelForActivePlan } from '../ai-providers/codex-plan-compatibility'; +import { resolveProxyConfig, PROXY_CLI_FLAGS } from '../proxy/proxy-config-resolver'; import { supportsModelConfig, isModelBroken, @@ -44,8 +44,8 @@ import { findModel, getSuggestedReplacementModel, } from '../model-catalog'; -import { CodexReasoningProxy } from '../codex-reasoning-proxy'; -import { ToolSanitizationProxy } from '../tool-sanitization-proxy'; +import { CodexReasoningProxy } from '../ai-providers/codex-reasoning-proxy'; +import { ToolSanitizationProxy } from '../proxy/tool-sanitization-proxy'; import { findAccountByQuery, getProviderAccounts, @@ -53,7 +53,7 @@ import { touchAccount, renameAccount, getDefaultAccount, -} from '../account-manager'; +} from '../accounts/account-manager'; import { formatAccountDisplayName } from '../accounts/email-account-identity'; import { ensureWebSearchMcpOrThrow, @@ -82,7 +82,7 @@ import { loadOrCreateUnifiedConfig, getThinkingConfig, } from '../../config/unified-config-loader'; -import { HttpsTunnelProxy } from '../https-tunnel-proxy'; +import { HttpsTunnelProxy } from '../proxy/https-tunnel-proxy'; import { isKiroAuthMethod, isKiroIDCFlow, @@ -106,7 +106,7 @@ import { handleTokenExpiration, handleQuotaCheck, } from './retry-handler'; -import { MANAGED_QUOTA_PROVIDERS, type ManagedQuotaProvider } from '../quota-manager'; +import { MANAGED_QUOTA_PROVIDERS, type ManagedQuotaProvider } from '../quota/quota-manager'; import { checkOrJoinProxy, registerProxySession, setupCleanupHandlers } from './session-bridge'; import { parseThinkingOverride } from './thinking-arg-parser'; import { @@ -115,12 +115,12 @@ import { cleanupStaleAutoPauses, enforceProviderIsolation, restoreAutoPausedAccounts, -} from '../account-safety'; +} from '../accounts/account-safety'; import { ensureCliAntigravityResponsibility, hasAntigravityRiskAcceptanceFlag, ANTIGRAVITY_ACCEPT_RISK_FLAGS, -} from '../antigravity-responsibility'; +} from '../auth/antigravity-responsibility'; import { getWebSearchHookEnv } from '../../utils/websearch-manager'; import { buildThinkingStartupStatus, @@ -722,7 +722,7 @@ export async function execClaudeWithCLIProxy( // Handle --logout if (forceLogout) { - const { clearAuth } = await import('../auth-handler'); + const { clearAuth } = await import('../auth/auth-handler'); if (clearAuth(provider)) { console.log(ok(`Logged out from ${providerConfig.displayName}`)); } else { @@ -748,7 +748,7 @@ export async function execClaudeWithCLIProxy( console.error(fail('Cannot use --import with --logout')); process.exit(1); } - const { triggerOAuth } = await import('../auth-handler'); + const { triggerOAuth } = await import('../auth/auth-handler'); const authSuccess = await triggerOAuth(provider, { verbose, import: true, @@ -812,7 +812,7 @@ export async function execClaudeWithCLIProxy( if (compositeProviders.length > 0) { // Handle forceAuth for composite providers if (forceAuth) { - const { triggerOAuth } = await import('../auth-handler'); + const { triggerOAuth } = await import('../auth/auth-handler'); const failures: string[] = []; for (const p of compositeProviders) { const authSuccess = await triggerOAuth(p, { @@ -861,7 +861,7 @@ export async function execClaudeWithCLIProxy( process.exit(1); } } else if (forceAuth || !isAuthenticated(provider)) { - const { triggerOAuth } = await import('../auth-handler'); + const { triggerOAuth } = await import('../auth/auth-handler'); const authSuccess = await triggerOAuth(provider, { verbose, add: addAccount, @@ -1394,7 +1394,7 @@ export async function execClaudeWithCLIProxy( // 12b. Start runtime quota monitor (adaptive polling during session) if (!skipLocalAuth) { - const { startQuotaMonitor } = await import('../quota-manager'); + const { startQuotaMonitor } = await import('../quota/quota-manager'); for (const monitorProvider of resolveRuntimeQuotaMonitorProviders( provider, compositeProviders diff --git a/src/cliproxy/executor/lifecycle-manager.ts b/src/cliproxy/executor/lifecycle-manager.ts index b5657754..d5b335dc 100644 --- a/src/cliproxy/executor/lifecycle-manager.ts +++ b/src/cliproxy/executor/lifecycle-manager.ts @@ -11,7 +11,7 @@ import { spawn, ChildProcess } from 'child_process'; import * as net from 'net'; import { ProgressIndicator } from '../../utils/progress-indicator'; import { fail } from '../../utils/ui'; -import { getCliproxyWritablePath } from '../config-generator'; +import { getCliproxyWritablePath } from '../config/config-generator'; import { getPortCheckCommand, getCatCommand } from '../../utils/platform-commands'; import { CLIProxyBackend } from '../types'; diff --git a/src/cliproxy/executor/retry-handler.ts b/src/cliproxy/executor/retry-handler.ts index 7135a9d0..9fcc9115 100644 --- a/src/cliproxy/executor/retry-handler.ts +++ b/src/cliproxy/executor/retry-handler.ts @@ -10,7 +10,7 @@ import { fail, warn, info } from '../../utils/ui'; import { CLIProxyProvider } from '../types'; -import { handleBanDetection, warnPossible403Ban } from '../account-safety'; +import { handleBanDetection, warnPossible403Ban } from '../accounts/account-safety'; import { CompositeTierConfig } from '../../config/unified-config-types'; /** @@ -54,7 +54,7 @@ export async function handleTokenExpiration( if (!tokenResult.valid) { // Check if this is an account ban/disable before generic error if (tokenResult.error) { - const { getDefaultAccount } = await import('../account-manager'); + const { getDefaultAccount } = await import('../accounts/account-manager'); const account = getDefaultAccount(provider); if (account) { handleBanDetection(provider, account.id, tokenResult.error); @@ -80,7 +80,7 @@ export async function handleTokenExpiration( * Handle quota check and auto-switching for providers with quota-based rotation. */ export async function handleQuotaCheck(provider: CLIProxyProvider): Promise { - const { isManagedQuotaProvider, preflightCheck } = await import('../quota-manager'); + const { isManagedQuotaProvider, preflightCheck } = await import('../quota/quota-manager'); if (!isManagedQuotaProvider(provider)) return; const preflight = await preflightCheck(provider); diff --git a/src/cliproxy/executor/session-bridge.ts b/src/cliproxy/executor/session-bridge.ts index c8bc65e4..0c3c64d5 100644 --- a/src/cliproxy/executor/session-bridge.ts +++ b/src/cliproxy/executor/session-bridge.ts @@ -18,10 +18,10 @@ import { unregisterSession, stopProxy, } from '../session-tracker'; -import { detectRunningProxy, waitForProxyHealthy, reclaimOrphanedProxy } from '../proxy-detector'; -import { withStartupLock } from '../startup-lock'; +import { detectRunningProxy, waitForProxyHealthy, reclaimOrphanedProxy } from '../proxy/proxy-detector'; +import { withStartupLock } from '../services/startup-lock'; import { killProcessOnPort } from '../../utils/platform-commands'; -import { stopQuotaMonitor } from '../quota-manager'; +import { stopQuotaMonitor } from '../quota/quota-manager'; export interface ProxySessionResult { sessionId?: string; diff --git a/src/cliproxy/index.ts b/src/cliproxy/index.ts index a2862c51..4552c3ec 100644 --- a/src/cliproxy/index.ts +++ b/src/cliproxy/index.ts @@ -33,7 +33,7 @@ export { isPlatformSupported, getPlatformDescription, CLIPROXY_VERSION, -} from './platform-detector'; +} from './binary/platform-detector'; // Binary management export { @@ -72,7 +72,7 @@ export { deleteConfig, CLIPROXY_DEFAULT_PORT, CLIPROXY_CONFIG_VERSION, -} from './config-generator'; +} from './config/config-generator'; // Base config loader (for reading config/base-*.settings.json) export { @@ -80,7 +80,7 @@ export { getModelMappingFromConfig, getEnvVarsFromConfig, clearConfigCache, -} from './base-config-loader'; +} from './config/base-config-loader'; // Model catalog and configuration export type { ModelEntry, ProviderCatalog } from './model-catalog'; @@ -94,24 +94,24 @@ export { normalizeModelIdForProvider, normalizeModelIdForRouting, normalizeModelEnvVarsForProvider, -} from './model-id-normalizer'; +} from './ai-providers/model-id-normalizer'; export { hasUserSettings, getCurrentModel, configureProviderModel, showCurrentConfig, -} from './model-config'; +} from './config/model-config'; export { getDefaultCodexModel, getFreePlanFallbackCodexModel, reconcileCodexModelForActivePlan, -} from './codex-plan-compatibility'; +} from './ai-providers/codex-plan-compatibility'; // Executor -export { execClaudeWithCLIProxy, isPortAvailable, findAvailablePort } from './cliproxy-executor'; +export { execClaudeWithCLIProxy, isPortAvailable, findAvailablePort } from './executor/cliproxy-executor'; // Authentication -export type { AuthStatus } from './auth-handler'; +export type { AuthStatus } from './auth/auth-handler'; export { isAuthenticated, getAuthStatus, @@ -122,18 +122,18 @@ export { getOAuthConfig, getProviderTokenDir, displayAuthStatus, -} from './auth-handler'; +} from './auth/auth-handler'; // Stats fetcher -export type { CliproxyStats } from './stats-fetcher'; -export { fetchCliproxyStats, isCliproxyRunning } from './stats-fetcher'; +export type { CliproxyStats } from './services/stats-fetcher'; +export { fetchCliproxyStats, isCliproxyRunning } from './services/stats-fetcher'; // Quota fetcher -export type { ModelQuota, QuotaResult } from './quota-fetcher'; -export { fetchAccountQuota } from './quota-fetcher'; +export type { ModelQuota, QuotaResult } from './quota/quota-fetcher'; +export { fetchAccountQuota } from './quota/quota-fetcher'; // OpenAI compatibility layer -export type { OpenAICompatProvider, OpenAICompatModel } from './openai-compat-manager'; +export type { OpenAICompatProvider, OpenAICompatModel } from './ai-providers/openai-compat-manager'; export { listOpenAICompatProviders, getOpenAICompatProvider, @@ -142,7 +142,7 @@ export { removeOpenAICompatProvider, OPENROUTER_TEMPLATE, TOGETHER_TEMPLATE, -} from './openai-compat-manager'; +} from './ai-providers/openai-compat-manager'; // AI provider management export type { @@ -166,12 +166,12 @@ export type { ServiceStartResult } from './service-manager'; export { ensureCliproxyService, stopCliproxyService, getServiceStatus } from './service-manager'; // Proxy detector (unified detection with multiple fallbacks) -export type { ProxyStatus, DetectionMethod } from './proxy-detector'; -export { detectRunningProxy, waitForProxyHealthy, reclaimOrphanedProxy } from './proxy-detector'; +export type { ProxyStatus, DetectionMethod } from './proxy/proxy-detector'; +export { detectRunningProxy, waitForProxyHealthy, reclaimOrphanedProxy } from './proxy/proxy-detector'; // Startup lock (prevents race conditions between CCS processes) -export type { LockResult } from './startup-lock'; -export { acquireStartupLock, withStartupLock } from './startup-lock'; +export type { LockResult } from './services/startup-lock'; +export { acquireStartupLock, withStartupLock } from './services/startup-lock'; // Auth token manager (customizable API key and management secret) export { @@ -184,7 +184,7 @@ export { setVariantApiKey, resetAuthToDefaults, getAuthSummary, -} from './auth-token-manager'; +} from './auth/auth-token-manager'; // Thinking validator export type { ThinkingValidationResult } from './thinking-validator'; @@ -211,8 +211,8 @@ export type { SyncStatus, RemoteModelInfo, RemoteThinkingSupport, -} from './management-api-types'; -export { ManagementApiClient, createManagementClient } from './management-api-client'; +} from './management/management-api-types'; +export { ManagementApiClient, createManagementClient } from './management/management-api-client'; // Catalog cache (model catalog sync with CLIProxyAPI) export { @@ -223,7 +223,7 @@ export { setCachedCatalog, SYNCABLE_PROVIDERS, PROVIDER_TO_CHANNEL, -} from './catalog-cache'; +} from './services/catalog-cache'; // Sync module (profile sync to remote CLIProxy) export type { SyncableProfile, SyncPreviewItem } from './sync'; @@ -237,21 +237,21 @@ export { } from './sync'; // Tool name sanitization (for Gemini 64-char limit compliance) -export type { SanitizeResult } from './tool-name-sanitizer'; +export type { SanitizeResult } from './ai-providers/tool-name-sanitizer'; export { sanitizeToolName, isValidToolName, removeDuplicateSegments, smartTruncate, GEMINI_MAX_TOOL_NAME_LENGTH, -} from './tool-name-sanitizer'; +} from './ai-providers/tool-name-sanitizer'; -export type { Tool, ToolUseBlock, ContentBlock, SanitizationChange } from './tool-name-mapper'; -export { ToolNameMapper } from './tool-name-mapper'; +export type { Tool, ToolUseBlock, ContentBlock, SanitizationChange } from './ai-providers/tool-name-mapper'; +export { ToolNameMapper } from './ai-providers/tool-name-mapper'; -export type { ToolSanitizationProxyConfig } from './tool-sanitization-proxy'; -export { ToolSanitizationProxy } from './tool-sanitization-proxy'; +export type { ToolSanitizationProxyConfig } from './proxy/tool-sanitization-proxy'; +export { ToolSanitizationProxy } from './proxy/tool-sanitization-proxy'; // Schema sanitization (for MCP input_schema non-standard property removal) -export type { SchemaSanitizationResult } from './schema-sanitizer'; -export { sanitizeInputSchema, sanitizeToolSchemas } from './schema-sanitizer'; +export type { SchemaSanitizationResult } from './ai-providers/schema-sanitizer'; +export { sanitizeInputSchema, sanitizeToolSchemas } from './ai-providers/schema-sanitizer'; diff --git a/tests/unit/cliproxy/management-api-client.test.ts b/src/cliproxy/management/__tests__/management-api-client.test.ts similarity index 99% rename from tests/unit/cliproxy/management-api-client.test.ts rename to src/cliproxy/management/__tests__/management-api-client.test.ts index df498534..a109e02f 100644 --- a/tests/unit/cliproxy/management-api-client.test.ts +++ b/src/cliproxy/management/__tests__/management-api-client.test.ts @@ -2,12 +2,12 @@ * Unit tests for management-api-client module */ import { describe, it, expect, beforeEach, mock, spyOn } from 'bun:test'; -import { ManagementApiClient } from '../../../src/cliproxy/management-api-client'; +import { ManagementApiClient } from '../management-api-client'; import type { ManagementClientConfig, ManagementHealthStatus, ClaudeKey, -} from '../../../src/cliproxy/management-api-types'; +} from '../management-api-types'; describe('management-api-client', () => { describe('ManagementApiClient', () => { diff --git a/src/cliproxy/management-api-client.ts b/src/cliproxy/management/management-api-client.ts similarity index 99% rename from src/cliproxy/management-api-client.ts rename to src/cliproxy/management/management-api-client.ts index f7d5c9d7..f193de81 100644 --- a/src/cliproxy/management-api-client.ts +++ b/src/cliproxy/management/management-api-client.ts @@ -15,8 +15,8 @@ import type { RemoteModelInfo, GetModelDefinitionsResponse, } from './management-api-types'; -import { CLIPROXY_DEFAULT_PORT } from './config/port-manager'; -import type { CliproxyRoutingStrategy } from './types'; +import { CLIPROXY_DEFAULT_PORT } from '../config/port-manager'; +import type { CliproxyRoutingStrategy } from '../types'; /** Default timeout for management operations (longer than health check) */ const DEFAULT_TIMEOUT_MS = 5000; diff --git a/src/cliproxy/management-api-types.ts b/src/cliproxy/management/management-api-types.ts similarity index 100% rename from src/cliproxy/management-api-types.ts rename to src/cliproxy/management/management-api-types.ts diff --git a/src/cliproxy/remote-token-uploader.ts b/src/cliproxy/management/remote-token-uploader.ts similarity index 97% rename from src/cliproxy/remote-token-uploader.ts rename to src/cliproxy/management/remote-token-uploader.ts index dd50324a..9d2b27b4 100644 --- a/src/cliproxy/remote-token-uploader.ts +++ b/src/cliproxy/management/remote-token-uploader.ts @@ -7,8 +7,8 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getProxyTarget, buildProxyUrl } from './proxy-target-resolver'; -import { info, ok, fail, warn } from '../utils/ui'; +import { getProxyTarget, buildProxyUrl } from '../proxy/proxy-target-resolver'; +import { info, ok, fail, warn } from '../../utils/ui'; /** Timeout for upload requests (ms) */ const UPLOAD_TIMEOUT_MS = 10000; diff --git a/src/cliproxy/model-catalog.ts b/src/cliproxy/model-catalog.ts index 1f37537b..3317f96d 100644 --- a/src/cliproxy/model-catalog.ts +++ b/src/cliproxy/model-catalog.ts @@ -10,7 +10,7 @@ import { isAntigravityProvider, migrateDeniedAntigravityModelAliases, normalizeModelIdForProvider, -} from './model-id-normalizer'; +} from './ai-providers/model-id-normalizer'; import { AGY_GEMINI_PRO_COMPATIBILITY_IDS, AGY_GEMINI_PRO_HIGH_ID, diff --git a/tests/unit/cliproxy/https-tunnel-policy.test.ts b/src/cliproxy/proxy/__tests__/https-tunnel-policy.test.ts similarity index 93% rename from tests/unit/cliproxy/https-tunnel-policy.test.ts rename to src/cliproxy/proxy/__tests__/https-tunnel-policy.test.ts index a0beaa13..d3a219dd 100644 --- a/tests/unit/cliproxy/https-tunnel-policy.test.ts +++ b/src/cliproxy/proxy/__tests__/https-tunnel-policy.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'bun:test'; -import { shouldStartHttpsTunnel } from '../../../src/cliproxy/executor/https-tunnel-policy'; +import { shouldStartHttpsTunnel } from '../executor/https-tunnel-policy'; describe('HTTPS tunnel startup policy', () => { it('skips the tunnel for single-provider Codex remote HTTPS launches', () => { diff --git a/tests/unit/cliproxy/https-tunnel-proxy.test.ts b/src/cliproxy/proxy/__tests__/https-tunnel-proxy.test.ts similarity index 99% rename from tests/unit/cliproxy/https-tunnel-proxy.test.ts rename to src/cliproxy/proxy/__tests__/https-tunnel-proxy.test.ts index 81e85324..71f4e840 100644 --- a/tests/unit/cliproxy/https-tunnel-proxy.test.ts +++ b/src/cliproxy/proxy/__tests__/https-tunnel-proxy.test.ts @@ -8,7 +8,7 @@ import { describe, it, expect, afterEach } from 'bun:test'; import * as http from 'http'; // Import the class under test -import { HttpsTunnelProxy, type HttpsTunnelConfig } from '../../../src/cliproxy/https-tunnel-proxy'; +import { HttpsTunnelProxy, type HttpsTunnelConfig } from '../https-tunnel-proxy'; describe('HttpsTunnelProxy', () => { let tunnel: HttpsTunnelProxy | null = null; diff --git a/tests/unit/cliproxy/proxy-config-resolver.test.js b/src/cliproxy/proxy/__tests__/proxy-config-resolver.test.js similarity index 99% rename from tests/unit/cliproxy/proxy-config-resolver.test.js rename to src/cliproxy/proxy/__tests__/proxy-config-resolver.test.js index 0ebc8ebc..8eede5c1 100644 --- a/tests/unit/cliproxy/proxy-config-resolver.test.js +++ b/src/cliproxy/proxy/__tests__/proxy-config-resolver.test.js @@ -11,7 +11,7 @@ const { hasProxyFlags, PROXY_CLI_FLAGS, PROXY_ENV_VARS, -} = require('../../../dist/cliproxy/proxy-config-resolver'); +} = require('../../../../dist/cliproxy/proxy-config-resolver'); describe('proxy-config-resolver', () => { describe('PROXY_CLI_FLAGS', () => { diff --git a/tests/unit/cliproxy/proxy-detector-port.test.ts b/src/cliproxy/proxy/__tests__/proxy-detector-port.test.ts similarity index 93% rename from tests/unit/cliproxy/proxy-detector-port.test.ts rename to src/cliproxy/proxy/__tests__/proxy-detector-port.test.ts index 1ed10431..f1dbe871 100644 --- a/tests/unit/cliproxy/proxy-detector-port.test.ts +++ b/src/cliproxy/proxy/__tests__/proxy-detector-port.test.ts @@ -6,8 +6,8 @@ */ import { describe, it, expect } from 'bun:test'; -import { detectRunningProxy } from '../../../src/cliproxy/proxy-detector'; -import { CLIPROXY_DEFAULT_PORT } from '../../../src/cliproxy/config-generator'; +import { detectRunningProxy } from '../proxy-detector'; +import { CLIPROXY_DEFAULT_PORT } from '../config/config-generator'; describe('Proxy Detector Port Validation', () => { describe('detectRunningProxy with invalid ports', () => { diff --git a/tests/unit/cliproxy/tool-sanitization-proxy-integration.test.ts b/src/cliproxy/proxy/__tests__/tool-sanitization-proxy-integration.test.ts similarity index 99% rename from tests/unit/cliproxy/tool-sanitization-proxy-integration.test.ts rename to src/cliproxy/proxy/__tests__/tool-sanitization-proxy-integration.test.ts index e92a56a3..6da226e2 100644 --- a/tests/unit/cliproxy/tool-sanitization-proxy-integration.test.ts +++ b/src/cliproxy/proxy/__tests__/tool-sanitization-proxy-integration.test.ts @@ -6,7 +6,7 @@ import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'bun:test'; import * as http from 'http'; -import { ToolSanitizationProxy } from '../../../src/cliproxy/tool-sanitization-proxy'; +import { ToolSanitizationProxy } from '../tool-sanitization-proxy'; // Mock upstream server that echoes requests let mockUpstream: http.Server; diff --git a/src/cliproxy/https-tunnel-proxy.ts b/src/cliproxy/proxy/https-tunnel-proxy.ts similarity index 100% rename from src/cliproxy/https-tunnel-proxy.ts rename to src/cliproxy/proxy/https-tunnel-proxy.ts diff --git a/src/cliproxy/proxy-config-resolver.ts b/src/cliproxy/proxy/proxy-config-resolver.ts similarity index 98% rename from src/cliproxy/proxy-config-resolver.ts rename to src/cliproxy/proxy/proxy-config-resolver.ts index 9f36232a..e4e229b2 100644 --- a/src/cliproxy/proxy-config-resolver.ts +++ b/src/cliproxy/proxy/proxy-config-resolver.ts @@ -7,8 +7,8 @@ * Supports both local (spawn CLIProxyAPI) and remote (connect to external) modes. */ -import type { ResolvedProxyConfig } from './types'; -import { CLIPROXY_DEFAULT_PORT, validatePort } from './config-generator'; +import type { ResolvedProxyConfig } from '../types'; +import { CLIPROXY_DEFAULT_PORT, validatePort } from '../config/port-manager'; /** CLI flags for proxy configuration */ export const PROXY_CLI_FLAGS = [ diff --git a/src/cliproxy/proxy-detector.ts b/src/cliproxy/proxy/proxy-detector.ts similarity index 97% rename from src/cliproxy/proxy-detector.ts rename to src/cliproxy/proxy/proxy-detector.ts index 8aae527f..9d428eeb 100644 --- a/src/cliproxy/proxy-detector.ts +++ b/src/cliproxy/proxy/proxy-detector.ts @@ -15,11 +15,11 @@ * Solves race conditions between cliproxy-executor.ts and service-manager.ts */ -import { getExistingProxy, registerSession, getRunningProxyVersion } from './session-tracker'; -import { isCliproxyRunning } from './stats-fetcher'; -import { getPortProcess, isCLIProxyProcess, PortProcess } from '../utils/port-utils'; -import { CLIPROXY_DEFAULT_PORT } from './config-generator'; -import { createLogger } from '../services/logging'; +import { getExistingProxy, registerSession, getRunningProxyVersion } from '../session-tracker'; +import { isCliproxyRunning } from '../services/stats-fetcher'; +import { getPortProcess, isCLIProxyProcess, PortProcess } from '../../utils/port-utils'; +import { CLIPROXY_DEFAULT_PORT } from '../config/port-manager'; +import { createLogger } from '../../services/logging'; /** Detection method used to find the proxy */ export type DetectionMethod = 'http' | 'session-lock' | 'port-process' | 'http-retry'; diff --git a/src/cliproxy/proxy-target-resolver.ts b/src/cliproxy/proxy/proxy-target-resolver.ts similarity index 94% rename from src/cliproxy/proxy-target-resolver.ts rename to src/cliproxy/proxy/proxy-target-resolver.ts index c6cfa966..0f6e0e01 100644 --- a/src/cliproxy/proxy-target-resolver.ts +++ b/src/cliproxy/proxy/proxy-target-resolver.ts @@ -5,16 +5,16 @@ * based on unified config. Used by stats-fetcher, auth-routes, and UI. */ -import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; -import type { CliproxyServerConfig } from '../config/unified-config-types'; +import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; +import type { CliproxyServerConfig } from '../../config/unified-config-types'; import { CLIPROXY_DEFAULT_PORT, getRemoteDefaultPort, normalizeProtocol, validateRemotePort, -} from './config-generator'; +} from '../config/port-manager'; import { getProxyEnvVars } from './proxy-config-resolver'; -import { getEffectiveManagementSecret } from './auth-token-manager'; +import { getEffectiveManagementSecret } from '../auth/auth-token-manager'; /** Resolved proxy target for making requests */ export interface ProxyTarget { diff --git a/src/cliproxy/tool-sanitization-proxy.ts b/src/cliproxy/proxy/tool-sanitization-proxy.ts similarity index 98% rename from src/cliproxy/tool-sanitization-proxy.ts rename to src/cliproxy/proxy/tool-sanitization-proxy.ts index c839f7ab..bb3d99dd 100644 --- a/src/cliproxy/tool-sanitization-proxy.ts +++ b/src/cliproxy/proxy/tool-sanitization-proxy.ts @@ -16,17 +16,17 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import { URL } from 'url'; -import { ToolNameMapper, type Tool, type ContentBlock } from './tool-name-mapper'; -import { sanitizeToolSchemas } from './schema-sanitizer'; +import { ToolNameMapper, type Tool, type ContentBlock } from '../ai-providers/tool-name-mapper'; +import { sanitizeToolSchemas } from '../ai-providers/schema-sanitizer'; import { extractProviderFromPathname, getDeniedModelIdReasonForProvider, normalizeModelIdForRouting, stripCodexEffortSuffix, -} from './model-id-normalizer'; -import { getModelMaxLevel } from './model-catalog'; -import { getCcsDir } from '../utils/config-manager'; -import { createLogger } from '../services/logging'; +} from '../ai-providers/model-id-normalizer'; +import { getModelMaxLevel } from '../model-catalog'; +import { getCcsDir } from '../../utils/config-manager'; +import { createLogger } from '../../services/logging'; export interface ToolSanitizationProxyConfig { /** Upstream CLIProxy URL */ diff --git a/tests/unit/cliproxy/quota-caching-integration.test.ts b/src/cliproxy/quota/__tests__/quota-caching-integration.test.ts similarity index 98% rename from tests/unit/cliproxy/quota-caching-integration.test.ts rename to src/cliproxy/quota/__tests__/quota-caching-integration.test.ts index 4e956689..69378398 100644 --- a/tests/unit/cliproxy/quota-caching-integration.test.ts +++ b/src/cliproxy/quota/__tests__/quota-caching-integration.test.ts @@ -16,9 +16,9 @@ import { clearQuotaCache, getQuotaCacheStats, QUOTA_CACHE_TTL_MS, -} from '../../../src/cliproxy/quota-response-cache'; -import { shouldCacheQuotaResult } from '../../../src/web-server/routes/cliproxy-stats-routes'; -import type { GeminiCliQuotaResult, CodexQuotaResult } from '../../../src/cliproxy/quota-types'; +} from '../quota-response-cache'; +import { shouldCacheQuotaResult } from '../../../web-server/routes/cliproxy-stats-routes'; +import type { GeminiCliQuotaResult, CodexQuotaResult } from '../quota-types'; describe('Quota Caching Integration', () => { beforeEach(() => { diff --git a/tests/unit/cliproxy/quota-fetcher-antigravity-failure.test.ts b/src/cliproxy/quota/__tests__/quota-fetcher-antigravity-failure.test.ts similarity index 92% rename from tests/unit/cliproxy/quota-fetcher-antigravity-failure.test.ts rename to src/cliproxy/quota/__tests__/quota-fetcher-antigravity-failure.test.ts index fd2363ed..0de35f5d 100644 --- a/tests/unit/cliproxy/quota-fetcher-antigravity-failure.test.ts +++ b/src/cliproxy/quota/__tests__/quota-fetcher-antigravity-failure.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'bun:test'; async function loadAntigravityQuotaTestExports() { const moduleId = Date.now() + Math.random(); - const mod = await import(`../../../src/cliproxy/quota-fetcher?agy-quota-fetcher=${moduleId}`); + const mod = await import(`../quota-fetcher?agy-quota-fetcher=${moduleId}`); return mod.__testExports; } @@ -31,9 +31,9 @@ describe('Antigravity quota failure metadata', () => { it('preserves entitlement evidence when project lookup fails before quota fetch', async () => { const moduleId = Date.now() + Math.random(); - const { fetchAccountQuota } = await import(`../../../src/cliproxy/quota-fetcher?agy-early=${moduleId}`); + const { fetchAccountQuota } = await import(`../../quota-fetcher?agy-early=${moduleId}`); const { getProviderAuthDir } = await import( - `../../../src/cliproxy/config-generator?agy-config=${moduleId}` + `../../config-generator?agy-config=${moduleId}` ); const fs = await import('node:fs'); const os = await import('node:os'); @@ -86,10 +86,10 @@ describe('Antigravity quota failure metadata', () => { it('attaches entitlement evidence when project lookup returns an invalid 2xx payload', async () => { const moduleId = Date.now() + Math.random(); const { fetchAccountQuota } = await import( - `../../../src/cliproxy/quota-fetcher?agy-invalid-project=${moduleId}` + `../../quota-fetcher?agy-invalid-project=${moduleId}` ); const { getProviderAuthDir } = await import( - `../../../src/cliproxy/config-generator?agy-config=${moduleId}` + `../../config-generator?agy-config=${moduleId}` ); const fs = await import('node:fs'); const os = await import('node:os'); @@ -142,10 +142,10 @@ describe('Antigravity quota failure metadata', () => { it('preserves live tier evidence when quota fetch fails after a successful project lookup', async () => { const moduleId = Date.now() + Math.random(); const { fetchAccountQuota } = await import( - `../../../src/cliproxy/quota-fetcher?agy-invalid-models=${moduleId}` + `../../quota-fetcher?agy-invalid-models=${moduleId}` ); const { getProviderAuthDir } = await import( - `../../../src/cliproxy/config-generator?agy-config=${moduleId}` + `../../config-generator?agy-config=${moduleId}` ); const fs = await import('node:fs'); const os = await import('node:os'); diff --git a/tests/unit/cliproxy/quota-fetcher-claude.test.ts b/src/cliproxy/quota/__tests__/quota-fetcher-claude.test.ts similarity index 99% rename from tests/unit/cliproxy/quota-fetcher-claude.test.ts rename to src/cliproxy/quota/__tests__/quota-fetcher-claude.test.ts index cdfbddaf..07f5d3b3 100644 --- a/tests/unit/cliproxy/quota-fetcher-claude.test.ts +++ b/src/cliproxy/quota/__tests__/quota-fetcher-claude.test.ts @@ -13,8 +13,8 @@ import { buildClaudeCoreUsageSummary, fetchClaudeQuota, fetchAllClaudeQuotas, -} from '../../../src/cliproxy/quota-fetcher-claude'; -import { sanitizeEmail } from '../../../src/cliproxy/auth-utils'; +} from '../quota-fetcher-claude'; +import { sanitizeEmail } from '../auth/auth-utils'; let tmpDir: string; let originalCcsHome: string | undefined; diff --git a/tests/unit/cliproxy/quota-fetcher-codex.test.ts b/src/cliproxy/quota/__tests__/quota-fetcher-codex.test.ts similarity index 96% rename from tests/unit/cliproxy/quota-fetcher-codex.test.ts rename to src/cliproxy/quota/__tests__/quota-fetcher-codex.test.ts index 4bf3e689..d03b09ab 100644 --- a/tests/unit/cliproxy/quota-fetcher-codex.test.ts +++ b/src/cliproxy/quota/__tests__/quota-fetcher-codex.test.ts @@ -13,11 +13,11 @@ let tmpDir: string; let originalCcsHome: string | undefined; let originalFetch: typeof fetch; let moduleVersion = 0; -let buildCodexQuotaWindows: typeof import('../../../src/cliproxy/quota-fetcher-codex').buildCodexQuotaWindows; -let buildCodexCoreUsageSummary: typeof import('../../../src/cliproxy/quota-fetcher-codex').buildCodexCoreUsageSummary; -let fetchCodexQuota: typeof import('../../../src/cliproxy/quota-fetcher-codex').fetchCodexQuota; -let getUnknownCodexWindowLabels: typeof import('../../../src/cliproxy/quota-fetcher-codex').getUnknownCodexWindowLabels; -let registerAccount: typeof import('../../../src/cliproxy/account-manager').registerAccount; +let buildCodexQuotaWindows: typeof import('../quota-fetcher-codex').buildCodexQuotaWindows; +let buildCodexCoreUsageSummary: typeof import('../quota-fetcher-codex').buildCodexCoreUsageSummary; +let fetchCodexQuota: typeof import('../quota-fetcher-codex').fetchCodexQuota; +let getUnknownCodexWindowLabels: typeof import('../quota-fetcher-codex').getUnknownCodexWindowLabels; +let registerAccount: typeof import('../accounts/account-manager').registerAccount; function createCodexAccount( accountId: string, @@ -34,13 +34,13 @@ beforeEach(async () => { mock.restore(); const configGenerator = await import( - `../../../src/cliproxy/config-generator?codex-config-generator=${moduleVersion}` + `../config/config-generator?codex-config-generator=${moduleVersion}` ); const accountManager = await import( - `../../../src/cliproxy/account-manager?codex-account-manager=${moduleVersion}` + `../accounts/account-manager?codex-account-manager=${moduleVersion}` ); - mock.module('../../../src/cliproxy/config-generator', () => configGenerator); - mock.module('../../../src/cliproxy/account-manager', () => accountManager); + mock.module('../config/config-generator', () => configGenerator); + mock.module('../accounts/account-manager', () => accountManager); ({ registerAccount } = accountManager); ({ @@ -48,7 +48,7 @@ beforeEach(async () => { buildCodexCoreUsageSummary, fetchCodexQuota, getUnknownCodexWindowLabels, - } = await import(`../../../src/cliproxy/quota-fetcher-codex?codex-fetcher=${moduleVersion}`)); + } = await import(`../quota-fetcher-codex?codex-fetcher=${moduleVersion}`)); tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-codex-quota-test-')); originalCcsHome = process.env.CCS_HOME; diff --git a/tests/unit/cliproxy/quota-fetcher-gemini-cli.test.ts b/src/cliproxy/quota/__tests__/quota-fetcher-gemini-cli.test.ts similarity index 97% rename from tests/unit/cliproxy/quota-fetcher-gemini-cli.test.ts rename to src/cliproxy/quota/__tests__/quota-fetcher-gemini-cli.test.ts index 63c4672b..dafe57e0 100644 --- a/tests/unit/cliproxy/quota-fetcher-gemini-cli.test.ts +++ b/src/cliproxy/quota/__tests__/quota-fetcher-gemini-cli.test.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; -import { getCapturedFetchRequests, mockFetch, restoreFetch } from '../../mocks'; +import { getCapturedFetchRequests, mockFetch, restoreFetch } from '../../../../tests/unit/mocks'; describe('Gemini CLI Quota Fetcher', () => { const GEMINI_QUOTA_URL = 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota'; @@ -19,11 +19,11 @@ describe('Gemini CLI Quota Fetcher', () => { let originalCcsHome: string | undefined; let originalCcsDir: string | undefined; let moduleVersion = 0; - let buildGeminiCliBuckets: typeof import('../../../src/cliproxy/quota-fetcher-gemini-cli').buildGeminiCliBuckets; - let fetchGeminiCliQuota: typeof import('../../../src/cliproxy/quota-fetcher-gemini-cli').fetchGeminiCliQuota; - let resolveGeminiCliProjectId: typeof import('../../../src/cliproxy/quota-fetcher-gemini-cli').resolveGeminiCliProjectId; - let geminiTestExports: typeof import('../../../src/cliproxy/quota-fetcher-gemini-cli').__testExports; - let getProviderAuthDir: typeof import('../../../src/cliproxy/config-generator').getProviderAuthDir; + let buildGeminiCliBuckets: typeof import('../quota-fetcher-gemini-cli').buildGeminiCliBuckets; + let fetchGeminiCliQuota: typeof import('../quota-fetcher-gemini-cli').fetchGeminiCliQuota; + let resolveGeminiCliProjectId: typeof import('../quota-fetcher-gemini-cli').resolveGeminiCliProjectId; + let geminiTestExports: typeof import('../quota-fetcher-gemini-cli').__testExports; + let getProviderAuthDir: typeof import('../config/config-generator').getProviderAuthDir; function writeGeminiToken(token: Record, filename = 'gemini-test.json'): string { const authDir = getProviderAuthDir('gemini'); @@ -59,7 +59,7 @@ describe('Gemini CLI Quota Fetcher', () => { delete process.env.CCS_DIR; const configGenerator = await import( - `../../../src/cliproxy/config-generator?gemini-config-generator=${moduleVersion}` + `../config/config-generator?gemini-config-generator=${moduleVersion}` ); ({ buildGeminiCliBuckets, @@ -67,7 +67,7 @@ describe('Gemini CLI Quota Fetcher', () => { resolveGeminiCliProjectId, __testExports: geminiTestExports, } = await import( - `../../../src/cliproxy/quota-fetcher-gemini-cli?gemini-quota-fetcher=${moduleVersion}` + `../quota-fetcher-gemini-cli?gemini-quota-fetcher=${moduleVersion}` )); ({ getProviderAuthDir } = configGenerator); }); diff --git a/tests/unit/cliproxy/quota-fetcher-ghcp.test.ts b/src/cliproxy/quota/__tests__/quota-fetcher-ghcp.test.ts similarity index 99% rename from tests/unit/cliproxy/quota-fetcher-ghcp.test.ts rename to src/cliproxy/quota/__tests__/quota-fetcher-ghcp.test.ts index 37d19010..b988233f 100644 --- a/tests/unit/cliproxy/quota-fetcher-ghcp.test.ts +++ b/src/cliproxy/quota/__tests__/quota-fetcher-ghcp.test.ts @@ -12,7 +12,7 @@ import { normalizeGhcpSnapshot, extractGhcpAccessToken, fetchGhcpQuota, -} from '../../../src/cliproxy/quota-fetcher-ghcp'; +} from '../quota-fetcher-ghcp'; let tmpDir: string; let originalCcsHome: string | undefined; diff --git a/tests/unit/cliproxy/quota-monitor-runtime.test.ts b/src/cliproxy/quota/__tests__/quota-monitor-runtime.test.ts similarity index 98% rename from tests/unit/cliproxy/quota-monitor-runtime.test.ts rename to src/cliproxy/quota/__tests__/quota-monitor-runtime.test.ts index 3436c6db..5254c085 100644 --- a/tests/unit/cliproxy/quota-monitor-runtime.test.ts +++ b/src/cliproxy/quota/__tests__/quota-monitor-runtime.test.ts @@ -15,8 +15,8 @@ import { startQuotaMonitor, stopQuotaMonitor, clearQuotaCache, -} from '../../../src/cliproxy/quota-manager'; -import { __testExports as executorTestExports } from '../../../src/cliproxy/executor'; +} from '../quota-manager'; +import { __testExports as executorTestExports } from '../executor'; // Setup test isolation let tmpDir: string; diff --git a/tests/unit/cliproxy/quota-response-cache.test.ts b/src/cliproxy/quota/__tests__/quota-response-cache.test.ts similarity index 99% rename from tests/unit/cliproxy/quota-response-cache.test.ts rename to src/cliproxy/quota/__tests__/quota-response-cache.test.ts index b05741ba..625c8d78 100644 --- a/tests/unit/cliproxy/quota-response-cache.test.ts +++ b/src/cliproxy/quota/__tests__/quota-response-cache.test.ts @@ -13,7 +13,7 @@ import { clearQuotaCache, getQuotaCacheStats, QUOTA_CACHE_TTL_MS, -} from '../../../src/cliproxy/quota-response-cache'; +} from '../quota-response-cache'; interface TestQuota { success: boolean; diff --git a/src/cliproxy/gemini-cli-quota-normalizer.ts b/src/cliproxy/quota/gemini-cli-quota-normalizer.ts similarity index 100% rename from src/cliproxy/gemini-cli-quota-normalizer.ts rename to src/cliproxy/quota/gemini-cli-quota-normalizer.ts diff --git a/src/cliproxy/quota-fetcher-claude-normalizer.ts b/src/cliproxy/quota/quota-fetcher-claude-normalizer.ts similarity index 99% rename from src/cliproxy/quota-fetcher-claude-normalizer.ts rename to src/cliproxy/quota/quota-fetcher-claude-normalizer.ts index b064d8a2..5a50634f 100644 --- a/src/cliproxy/quota-fetcher-claude-normalizer.ts +++ b/src/cliproxy/quota/quota-fetcher-claude-normalizer.ts @@ -5,7 +5,7 @@ */ import type { ClaudeCoreUsageSummary, ClaudeQuotaWindow } from './quota-types'; -import { clampPercent } from '../utils/percentage'; +import { clampPercent } from '../../utils/percentage'; // Distinguishes epoch milliseconds from seconds (1e12 ~= 2001-09-09T01:46:40Z). const EPOCH_MS_THRESHOLD = 1e12; diff --git a/src/cliproxy/quota-fetcher-claude.ts b/src/cliproxy/quota/quota-fetcher-claude.ts similarity index 97% rename from src/cliproxy/quota-fetcher-claude.ts rename to src/cliproxy/quota/quota-fetcher-claude.ts index 62ce4b35..89e08249 100644 --- a/src/cliproxy/quota-fetcher-claude.ts +++ b/src/cliproxy/quota/quota-fetcher-claude.ts @@ -6,9 +6,9 @@ import * as path from 'node:path'; import * as fsp from 'node:fs/promises'; -import { getAuthDir } from './config-generator'; -import { getPausedDir, getProviderAccounts } from './account-manager'; -import { sanitizeEmail, isTokenExpired } from './auth-utils'; +import { getAuthDir } from '../config/config-generator'; +import { getPausedDir, getProviderAccounts } from '../accounts/account-manager'; +import { sanitizeEmail, isTokenExpired } from '../auth/auth-utils'; import type { ClaudeQuotaResult } from './quota-types'; import { buildClaudeQuotaWindows, diff --git a/src/cliproxy/quota-fetcher-codex.ts b/src/cliproxy/quota/quota-fetcher-codex.ts similarity index 99% rename from src/cliproxy/quota-fetcher-codex.ts rename to src/cliproxy/quota/quota-fetcher-codex.ts index c0c4940b..82cf99ed 100644 --- a/src/cliproxy/quota-fetcher-codex.ts +++ b/src/cliproxy/quota/quota-fetcher-codex.ts @@ -7,11 +7,11 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; -import { getAuthDir } from './config-generator'; -import { getAccount, getProviderAccounts, getPausedDir } from './account-manager'; -import { sanitizeEmail, isTokenExpired } from './auth-utils'; +import { getAuthDir } from '../config/config-generator'; +import { getAccount, getProviderAccounts, getPausedDir } from '../accounts/account-manager'; +import { sanitizeEmail, isTokenExpired } from '../auth/auth-utils'; import type { CodexQuotaResult, CodexQuotaWindow, CodexCoreUsageSummary } from './quota-types'; -import { extractCanonicalEmailFromAccountId } from './accounts/email-account-identity'; +import { extractCanonicalEmailFromAccountId } from '../accounts/email-account-identity'; /** ChatGPT backend API base URL */ const CODEX_API_BASE = 'https://chatgpt.com/backend-api'; diff --git a/src/cliproxy/quota-fetcher-gemini-cli.ts b/src/cliproxy/quota/quota-fetcher-gemini-cli.ts similarity index 98% rename from src/cliproxy/quota-fetcher-gemini-cli.ts rename to src/cliproxy/quota/quota-fetcher-gemini-cli.ts index ad88b9c9..f202b2a1 100644 --- a/src/cliproxy/quota-fetcher-gemini-cli.ts +++ b/src/cliproxy/quota/quota-fetcher-gemini-cli.ts @@ -7,23 +7,23 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; -import { getAuthDir } from './config-generator'; -import { getProviderAccounts, getPausedDir, setAccountTier } from './account-manager'; -import { getTokenExpiryTimestamp, sanitizeEmail, isTokenExpired } from './auth-utils'; +import { getAuthDir } from '../config/config-generator'; +import { getProviderAccounts, getPausedDir, setAccountTier } from '../accounts/account-manager'; +import { getTokenExpiryTimestamp, sanitizeEmail, isTokenExpired } from '../auth/auth-utils'; import { buildGeminiCliBucketsFromParsedBuckets, type GeminiCliParsedBucket, } from './gemini-cli-quota-normalizer'; -import { mapExternalProviderName } from './provider-capabilities'; -import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from './proxy-target-resolver'; +import { mapExternalProviderName } from '../provider-capabilities'; +import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver'; import type { GeminiCliQuotaResult, GeminiCliBucket } from './quota-types'; import { buildProviderEntitlementEvidence, getProviderTierLabel, isModelCapacityExhausted, normalizeProviderTierId, -} from './provider-entitlement-evidence'; -import type { ProviderEntitlementEvidence } from './provider-entitlement-types'; +} from '../auth/provider-entitlement-evidence'; +import type { ProviderEntitlementEvidence } from '../auth/provider-entitlement-types'; /** Google Cloud Code API endpoints */ const GEMINI_CLI_API_BASE = 'https://cloudcode-pa.googleapis.com'; diff --git a/src/cliproxy/quota-fetcher-ghcp.ts b/src/cliproxy/quota/quota-fetcher-ghcp.ts similarity index 98% rename from src/cliproxy/quota-fetcher-ghcp.ts rename to src/cliproxy/quota/quota-fetcher-ghcp.ts index 96f4450b..1a3e89d8 100644 --- a/src/cliproxy/quota-fetcher-ghcp.ts +++ b/src/cliproxy/quota/quota-fetcher-ghcp.ts @@ -6,9 +6,9 @@ */ import * as fs from 'node:fs'; -import { getAccountTokenPath, getProviderAccounts } from './account-manager'; +import { getAccountTokenPath, getProviderAccounts } from '../accounts/account-manager'; import type { GhcpQuotaResult, GhcpQuotaSnapshot } from './quota-types'; -import { clampPercent } from '../utils/percentage'; +import { clampPercent } from '../../utils/percentage'; const GHCP_USAGE_URL = 'https://api.github.com/copilot_internal/user'; const GHCP_USAGE_TIMEOUT_MS = 10000; diff --git a/src/cliproxy/quota-fetcher.ts b/src/cliproxy/quota/quota-fetcher.ts similarity index 98% rename from src/cliproxy/quota-fetcher.ts rename to src/cliproxy/quota/quota-fetcher.ts index dbe30a75..96effcae 100644 --- a/src/cliproxy/quota-fetcher.ts +++ b/src/cliproxy/quota/quota-fetcher.ts @@ -7,23 +7,23 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; -import { getAuthDir } from './config-generator'; -import { CLIProxyProvider } from './types'; +import { getAuthDir } from '../config/config-generator'; +import { CLIProxyProvider } from '../types'; import { getProviderAccounts, getPausedDir, setAccountTier, type AccountInfo, type AccountTier, -} from './account-manager'; -import { sanitizeEmail, isTokenExpired } from './auth-utils'; +} from '../accounts/account-manager'; +import { sanitizeEmail, isTokenExpired } from '../auth/auth-utils'; import { buildProviderEntitlementEvidence, getProviderTierLabel, normalizeProviderTierId, -} from './provider-entitlement-evidence'; -import type { ProviderEntitlementEvidence } from './provider-entitlement-types'; -import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from './proxy-target-resolver'; +} from '../auth/provider-entitlement-evidence'; +import type { ProviderEntitlementEvidence } from '../auth/provider-entitlement-types'; +import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver'; /** Individual model quota info */ export interface ModelQuota { diff --git a/src/cliproxy/quota-manager.ts b/src/cliproxy/quota/quota-manager.ts similarity index 97% rename from src/cliproxy/quota-manager.ts rename to src/cliproxy/quota/quota-manager.ts index 6c5b46d6..f715ee47 100644 --- a/src/cliproxy/quota-manager.ts +++ b/src/cliproxy/quota/quota-manager.ts @@ -12,7 +12,7 @@ * - Graceful degradation on API failures */ -import { CLIProxyProvider } from './types'; +import { CLIProxyProvider } from '../types'; import { QuotaResult, fetchAccountQuota } from './quota-fetcher'; import { fetchClaudeQuota } from './quota-fetcher-claude'; import { fetchCodexQuota } from './quota-fetcher-codex'; @@ -31,9 +31,9 @@ import { setDefaultAccount, touchAccount, type AccountInfo, -} from './account-manager'; -import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; -import type { RuntimeMonitorConfig } from '../config/unified-config-types'; +} from '../accounts/account-manager'; +import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; +import type { RuntimeMonitorConfig } from '../../config/unified-config-types'; export type ManagedQuotaProvider = 'agy' | 'claude' | 'codex' | 'gemini' | 'ghcp'; type ManagedQuotaResult = @@ -418,7 +418,7 @@ export async function findHealthyAccount( return null; } - const { restoreExpiredQuotaPauses } = await import('./account-safety'); + const { restoreExpiredQuotaPauses } = await import('../accounts/account-safety'); restoreExpiredQuotaPauses(); const config = loadOrCreateUnifiedConfig(); @@ -524,7 +524,7 @@ export async function preflightCheck(provider: CLIProxyProvider): Promise; }> { - const { restoreExpiredQuotaPauses } = await import('./account-safety'); + const { restoreExpiredQuotaPauses } = await import('../accounts/account-safety'); restoreExpiredQuotaPauses(); const accounts = getProviderAccounts(provider); @@ -713,7 +713,7 @@ function scheduleNextPoll( // NOTE: Monitor stops here intentionally. The current session continues // on the exhausted account (can't hot-swap mid-session). The switched // default only takes effect on next session start via preflightCheck(). - const { handleQuotaExhaustion } = await import('./account-safety'); + const { handleQuotaExhaustion } = await import('../accounts/account-safety'); await handleQuotaExhaustion(provider, accountId, monitorConfig.cooldown_minutes); state.stopped = true; state.timer = null; @@ -724,7 +724,7 @@ function scheduleNextPoll( if (avgQuota <= monitorConfig.warn_threshold) { // WARNING: switch to critical interval, warn once if (!state.hasWarnedThisSession) { - const { writeQuotaWarning } = await import('./account-safety'); + const { writeQuotaWarning } = await import('../accounts/account-safety'); writeQuotaWarning(accountId, avgQuota); state.hasWarnedThisSession = true; } diff --git a/src/cliproxy/quota-response-cache.ts b/src/cliproxy/quota/quota-response-cache.ts similarity index 100% rename from src/cliproxy/quota-response-cache.ts rename to src/cliproxy/quota/quota-response-cache.ts diff --git a/src/cliproxy/quota-types.ts b/src/cliproxy/quota/quota-types.ts similarity index 99% rename from src/cliproxy/quota-types.ts rename to src/cliproxy/quota/quota-types.ts index 5fee4d88..5f248d33 100644 --- a/src/cliproxy/quota-types.ts +++ b/src/cliproxy/quota/quota-types.ts @@ -5,7 +5,7 @@ * Supports Antigravity, Codex, Claude, Gemini CLI, and GitHub Copilot OAuth providers. */ -import type { ProviderEntitlementEvidence } from './provider-entitlement-types'; +import type { ProviderEntitlementEvidence } from '../auth/provider-entitlement-types'; /** Supported quota providers */ export type QuotaProvider = 'agy' | 'codex' | 'claude' | 'gemini' | 'ghcp'; diff --git a/tests/unit/cliproxy/routing-strategy-http.test.ts b/src/cliproxy/routing/__tests__/routing-strategy-http.test.ts similarity index 81% rename from tests/unit/cliproxy/routing-strategy-http.test.ts rename to src/cliproxy/routing/__tests__/routing-strategy-http.test.ts index c3edf31d..4e995ab0 100644 --- a/tests/unit/cliproxy/routing-strategy-http.test.ts +++ b/src/cliproxy/routing/__tests__/routing-strategy-http.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from 'bun:test'; -import type { ProxyTarget } from '../../../src/cliproxy/proxy-target-resolver'; +import type { ProxyTarget } from '../proxy/proxy-target-resolver'; async function loadRoutingHttpModule() { return import( - `../../../src/cliproxy/routing-strategy-http?test=${Date.now()}-${Math.random()}` - ) as Promise; + `../routing-strategy-http?test=${Date.now()}-${Math.random()}` + ) as Promise; } describe('routing-strategy-http', () => { diff --git a/tests/unit/cliproxy/routing-strategy.test.ts b/src/cliproxy/routing/__tests__/routing-strategy.test.ts similarity index 98% rename from tests/unit/cliproxy/routing-strategy.test.ts rename to src/cliproxy/routing/__tests__/routing-strategy.test.ts index 73f959f4..a4e8e977 100644 --- a/tests/unit/cliproxy/routing-strategy.test.ts +++ b/src/cliproxy/routing/__tests__/routing-strategy.test.ts @@ -60,7 +60,7 @@ describe('cliproxy routing strategy service', () => { } async function loadRoutingModule() { - mock.module('../../../src/cliproxy/routing-strategy-http', () => ({ + mock.module('../routing-strategy-http', () => ({ getCliproxyRoutingTarget: () => routingTarget, fetchCliproxyRoutingResponse: () => { if (!responseFactory) { @@ -74,7 +74,7 @@ describe('cliproxy routing strategy service', () => { }, })); - return import(`../../../src/cliproxy/routing-strategy?test=${Date.now()}-${Math.random()}`); + return import(`../routing-strategy?test=${Date.now()}-${Math.random()}`); } it('normalizes canonical and shorthand strategy values', async () => { diff --git a/src/cliproxy/routing-strategy-http.ts b/src/cliproxy/routing/routing-strategy-http.ts similarity index 98% rename from src/cliproxy/routing-strategy-http.ts rename to src/cliproxy/routing/routing-strategy-http.ts index 81eeb558..6fdaa37d 100644 --- a/src/cliproxy/routing-strategy-http.ts +++ b/src/cliproxy/routing/routing-strategy-http.ts @@ -4,7 +4,7 @@ import { buildProxyUrl, getProxyTarget, type ProxyTarget, -} from './proxy-target-resolver'; +} from '../proxy/proxy-target-resolver'; const ROUTING_TIMEOUT_MS = 5000; const CLIPROXY_ROUTING_MANAGEMENT_PATH = '/v0/management/routing/strategy'; diff --git a/src/cliproxy/routing-strategy.ts b/src/cliproxy/routing/routing-strategy.ts similarity index 97% rename from src/cliproxy/routing-strategy.ts rename to src/cliproxy/routing/routing-strategy.ts index 5cc97735..65c44d86 100644 --- a/src/cliproxy/routing-strategy.ts +++ b/src/cliproxy/routing/routing-strategy.ts @@ -1,12 +1,12 @@ -import { mutateUnifiedConfig, loadOrCreateUnifiedConfig } from '../config/unified-config-loader'; -import { regenerateConfig } from './config/generator'; -import { getAuthDir, getConfigPathForPort } from './config/path-resolver'; +import { mutateUnifiedConfig, loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; +import { regenerateConfig } from '../config/generator'; +import { getAuthDir, getConfigPathForPort } from '../config/path-resolver'; import { fetchCliproxyRoutingResponse, getCliproxyRoutingTarget, getRoutingErrorMessage, } from './routing-strategy-http'; -import type { CliproxyRoutingStrategy } from './types'; +import type { CliproxyRoutingStrategy } from '../types'; export const DEFAULT_CLIPROXY_ROUTING_STRATEGY: CliproxyRoutingStrategy = 'round-robin'; export const DEFAULT_CLIPROXY_SESSION_AFFINITY_ENABLED = false; diff --git a/src/cliproxy/service-manager.ts b/src/cliproxy/service-manager.ts index 7b1612e6..74dd2f39 100644 --- a/src/cliproxy/service-manager.ts +++ b/src/cliproxy/service-manager.ts @@ -20,11 +20,11 @@ import { configNeedsRegeneration, CLIPROXY_DEFAULT_PORT, getCliproxyWritablePath, -} from './config-generator'; +} from './config/config-generator'; import { registerSession } from './session-tracker'; -import { detectRunningProxy, waitForProxyHealthy } from './proxy-detector'; -import { withStartupLock } from './startup-lock'; -import { isCliproxyRunning } from './stats-fetcher'; +import { detectRunningProxy, waitForProxyHealthy } from './proxy/proxy-detector'; +import { withStartupLock } from './services/startup-lock'; +import { isCliproxyRunning } from './services/stats-fetcher'; import { TokenRefreshWorker, type RefreshResult } from './auth/token-refresh-worker'; import { getTokenRefreshConfig } from './auth/token-refresh-config'; @@ -301,7 +301,7 @@ export async function ensureCliproxyService( // Get backend label for error message const { loadOrCreateUnifiedConfig } = await import('../config/unified-config-loader'); - const { DEFAULT_BACKEND } = await import('./platform-detector'); + const { DEFAULT_BACKEND } = await import('./binary/platform-detector'); const config = loadOrCreateUnifiedConfig(); const backendLabel = (config.cliproxy?.backend ?? DEFAULT_BACKEND) === 'plus' ? 'CLIProxy Plus' : 'CLIProxy'; diff --git a/tests/unit/cliproxy/auto-sync-watcher.test.ts b/src/cliproxy/services/__tests__/auto-sync-watcher.test.ts similarity index 97% rename from tests/unit/cliproxy/auto-sync-watcher.test.ts rename to src/cliproxy/services/__tests__/auto-sync-watcher.test.ts index 416fa401..b3824c01 100644 --- a/tests/unit/cliproxy/auto-sync-watcher.test.ts +++ b/src/cliproxy/services/__tests__/auto-sync-watcher.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; describe('Auto-Sync Watcher', () => { - const autoSyncWatcher = require('../../../dist/cliproxy/sync/auto-sync-watcher'); + const autoSyncWatcher = require('../../../../dist/cliproxy/sync/auto-sync-watcher'); beforeEach(async () => { // Ensure clean state before each test diff --git a/tests/unit/cliproxy/local-config-sync.test.ts b/src/cliproxy/services/__tests__/local-config-sync.test.ts similarity index 97% rename from tests/unit/cliproxy/local-config-sync.test.ts rename to src/cliproxy/services/__tests__/local-config-sync.test.ts index 687d879f..2d8c3721 100644 --- a/tests/unit/cliproxy/local-config-sync.test.ts +++ b/src/cliproxy/services/__tests__/local-config-sync.test.ts @@ -9,7 +9,7 @@ import * as path from 'path'; import * as os from 'os'; describe('Local Config Sync', () => { - const localConfigSync = require('../../../dist/cliproxy/sync/local-config-sync'); + const localConfigSync = require('../../../../dist/cliproxy/sync/local-config-sync'); describe('syncToLocalConfig', () => { it('returns success with zero count when no profiles', () => { diff --git a/tests/unit/cliproxy/remote-auth-fetcher.test.ts b/src/cliproxy/services/__tests__/remote-auth-fetcher.test.ts similarity index 90% rename from tests/unit/cliproxy/remote-auth-fetcher.test.ts rename to src/cliproxy/services/__tests__/remote-auth-fetcher.test.ts index d7103d6c..6cb11d59 100644 --- a/tests/unit/cliproxy/remote-auth-fetcher.test.ts +++ b/src/cliproxy/services/__tests__/remote-auth-fetcher.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test'; -import { fetchRemoteAuthStatus } from '../../../src/cliproxy/remote-auth-fetcher'; -import type { ProxyTarget } from '../../../src/cliproxy/proxy-target-resolver'; +import { fetchRemoteAuthStatus } from '../../services/remote-auth-fetcher'; +import type { ProxyTarget } from '../../proxy/proxy-target-resolver'; describe('remote-auth-fetcher', () => { let originalFetch: typeof fetch; diff --git a/tests/unit/cliproxy/remote-proxy-chain-regression.test.ts b/src/cliproxy/services/__tests__/remote-proxy-chain-regression.test.ts similarity index 97% rename from tests/unit/cliproxy/remote-proxy-chain-regression.test.ts rename to src/cliproxy/services/__tests__/remote-proxy-chain-regression.test.ts index b7e64245..b89aec81 100644 --- a/tests/unit/cliproxy/remote-proxy-chain-regression.test.ts +++ b/src/cliproxy/services/__tests__/remote-proxy-chain-regression.test.ts @@ -2,8 +2,8 @@ import { describe, expect, it } from 'bun:test'; import * as http from 'http'; import * as https from 'https'; import type { AddressInfo } from 'net'; -import { CodexReasoningProxy } from '../../../src/cliproxy/codex-reasoning-proxy'; -import { ToolSanitizationProxy } from '../../../src/cliproxy/tool-sanitization-proxy'; +import { CodexReasoningProxy } from '../../ai-providers/codex-reasoning-proxy'; +import { ToolSanitizationProxy } from '../../proxy/tool-sanitization-proxy'; const SELF_SIGNED_KEY = `-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGH5Akfta94U5O diff --git a/tests/unit/cliproxy/remote-proxy-client.test.ts b/src/cliproxy/services/__tests__/remote-proxy-client.test.ts similarity index 99% rename from tests/unit/cliproxy/remote-proxy-client.test.ts rename to src/cliproxy/services/__tests__/remote-proxy-client.test.ts index 3a4c8c5a..572cc8e6 100644 --- a/tests/unit/cliproxy/remote-proxy-client.test.ts +++ b/src/cliproxy/services/__tests__/remote-proxy-client.test.ts @@ -5,7 +5,7 @@ import { describe, it, expect } from 'bun:test'; import { type RemoteProxyClientConfig, type RemoteProxyStatus, -} from '../../../src/cliproxy/remote-proxy-client'; +} from '../../services/remote-proxy-client'; // We test the module's type exports and error handling logic // Actual HTTP calls are not mocked in this unit test - use integration tests for that diff --git a/tests/unit/cliproxy/remote-token-uploader.test.ts b/src/cliproxy/services/__tests__/remote-token-uploader.test.ts similarity index 99% rename from tests/unit/cliproxy/remote-token-uploader.test.ts rename to src/cliproxy/services/__tests__/remote-token-uploader.test.ts index 429b2a66..f9abacc3 100644 --- a/tests/unit/cliproxy/remote-token-uploader.test.ts +++ b/src/cliproxy/services/__tests__/remote-token-uploader.test.ts @@ -8,7 +8,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { mockFetch, restoreFetch, getCapturedFetchRequests } from '../../mocks'; +import { mockFetch, restoreFetch, getCapturedFetchRequests } from '../../../../tests/unit/mocks'; describe('remote-token-uploader', () => { let tempDir: string; diff --git a/tests/unit/cliproxy/service-manager-startup.test.ts b/src/cliproxy/services/__tests__/service-manager-startup.test.ts similarity index 94% rename from tests/unit/cliproxy/service-manager-startup.test.ts rename to src/cliproxy/services/__tests__/service-manager-startup.test.ts index 5fb4818e..15971f3e 100644 --- a/tests/unit/cliproxy/service-manager-startup.test.ts +++ b/src/cliproxy/services/__tests__/service-manager-startup.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'bun:test'; -import { ensureCliproxyService } from '../../../src/cliproxy/service-manager'; +import { ensureCliproxyService } from '../../service-manager'; describe('ensureCliproxyService', () => { it('fails fast without attempting a runtime install when the local binary is missing', async () => { diff --git a/tests/unit/cliproxy/stats-transformer.test.ts b/src/cliproxy/services/__tests__/stats-transformer.test.ts similarity index 98% rename from tests/unit/cliproxy/stats-transformer.test.ts rename to src/cliproxy/services/__tests__/stats-transformer.test.ts index dd32aeab..dcf5466a 100644 --- a/tests/unit/cliproxy/stats-transformer.test.ts +++ b/src/cliproxy/services/__tests__/stats-transformer.test.ts @@ -3,8 +3,8 @@ import type { CliproxyManagementAuthFile, CliproxyRequestDetail, CliproxyUsageApiResponse, -} from '../../../src/cliproxy/stats-fetcher'; -import { buildCliproxyStatsFromUsageResponse } from '../../../src/cliproxy/stats-transformer'; +} from '../../services/stats-fetcher'; +import { buildCliproxyStatsFromUsageResponse } from '../../services/stats-transformer'; function createDetail(overrides: Partial = {}): CliproxyRequestDetail { return { diff --git a/tests/unit/cliproxy/variant-update-service.test.ts b/src/cliproxy/services/__tests__/variant-update-service.test.ts similarity index 97% rename from tests/unit/cliproxy/variant-update-service.test.ts rename to src/cliproxy/services/__tests__/variant-update-service.test.ts index 96df7f0e..d87e5689 100644 --- a/tests/unit/cliproxy/variant-update-service.test.ts +++ b/src/cliproxy/services/__tests__/variant-update-service.test.ts @@ -9,8 +9,8 @@ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { updateVariant, validateProviderBackend, -} from '../../../src/cliproxy/services/variant-service'; -import { loadOrCreateUnifiedConfig } from '../../../src/config/unified-config-loader'; +} from '../variant-service'; +import { loadOrCreateUnifiedConfig } from '../../../config/unified-config-loader'; describe('updateVariant - provider/model consistency', () => { let tmpDir: string; diff --git a/src/cliproxy/services/binary-service.ts b/src/cliproxy/services/binary-service.ts index c3457552..530571ce 100644 --- a/src/cliproxy/services/binary-service.ts +++ b/src/cliproxy/services/binary-service.ts @@ -20,7 +20,7 @@ import { isVersionPinned, resolveLocalBackend, } from '../binary-manager'; -import { BACKEND_CONFIG, DEFAULT_BACKEND } from '../platform-detector'; +import { BACKEND_CONFIG, DEFAULT_BACKEND } from '../binary/platform-detector'; import { CLIProxyBackend } from '../types'; import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; diff --git a/src/cliproxy/catalog-cache.ts b/src/cliproxy/services/catalog-cache.ts similarity index 96% rename from src/cliproxy/catalog-cache.ts rename to src/cliproxy/services/catalog-cache.ts index 998c86c3..55374584 100644 --- a/src/cliproxy/catalog-cache.ts +++ b/src/cliproxy/services/catalog-cache.ts @@ -1,16 +1,16 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCcsDir } from '../utils/config-manager'; -import type { CLIProxyProvider } from './types'; -import type { ModelEntry, ProviderCatalog, ThinkingSupport } from './model-catalog'; -import { MODEL_CATALOG } from './model-catalog'; +import { getCcsDir } from '../../utils/config-manager'; +import type { CLIProxyProvider } from '../types'; +import type { ModelEntry, ProviderCatalog, ThinkingSupport } from '../model-catalog'; +import { MODEL_CATALOG } from '../model-catalog'; import type { GetModelDefinitionsResponse, RemoteModelInfo, RemoteThinkingSupport, -} from './management-api-types'; -import { getDeniedModelIdReasonForProvider } from './model-id-normalizer'; -import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from './proxy-target-resolver'; +} from '../management/management-api-types'; +import { getDeniedModelIdReasonForProvider } from '../ai-providers/model-id-normalizer'; +import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver'; const CACHE_FILE_NAME = 'model-catalog-cache.json'; const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours diff --git a/src/cliproxy/catalog-routing.ts b/src/cliproxy/services/catalog-routing.ts similarity index 86% rename from src/cliproxy/catalog-routing.ts rename to src/cliproxy/services/catalog-routing.ts index 93973777..ca8e3a85 100644 --- a/src/cliproxy/catalog-routing.ts +++ b/src/cliproxy/services/catalog-routing.ts @@ -1,15 +1,15 @@ import { buildCliproxyRoutingHints, type CliproxyProviderRoutingHints, -} from '../shared/cliproxy-model-routing'; +} from '../../shared/cliproxy-model-routing'; import { fetchCliproxyModels } from './stats-fetcher'; import { getResolvedCatalogSnapshot, type CatalogSource, type ResolvedCatalogSnapshot, } from './catalog-cache'; -import type { ProviderCatalog } from './model-catalog'; -import type { CLIProxyProvider } from './types'; +import type { ProviderCatalog } from '../model-catalog'; +import type { CLIProxyProvider } from '../types'; export interface CatalogRoutingSnapshot { catalogs: Partial>; diff --git a/src/cliproxy/services/proxy-lifecycle-service.ts b/src/cliproxy/services/proxy-lifecycle-service.ts index 4c140262..dc4e818b 100644 --- a/src/cliproxy/services/proxy-lifecycle-service.ts +++ b/src/cliproxy/services/proxy-lifecycle-service.ts @@ -10,7 +10,7 @@ import { getProxyStatus as getProxyStatusSession, } from '../session-tracker'; import { ensureCliproxyService } from '../service-manager'; -import { CLIPROXY_DEFAULT_PORT } from '../config-generator'; +import { CLIPROXY_DEFAULT_PORT } from '../config/config-generator'; /** Proxy status result */ export interface ProxyStatusResult { diff --git a/src/cliproxy/remote-auth-fetcher.ts b/src/cliproxy/services/remote-auth-fetcher.ts similarity index 98% rename from src/cliproxy/remote-auth-fetcher.ts rename to src/cliproxy/services/remote-auth-fetcher.ts index b1e81e55..3e17ed5f 100644 --- a/src/cliproxy/remote-auth-fetcher.ts +++ b/src/cliproxy/services/remote-auth-fetcher.ts @@ -9,9 +9,9 @@ import { buildProxyUrl, buildManagementHeaders, ProxyTarget, -} from './proxy-target-resolver'; -import { getProviderDisplayName, mapExternalProviderName } from './provider-capabilities'; -import type { CLIProxyProvider } from './types'; +} from '../proxy/proxy-target-resolver'; +import { getProviderDisplayName, mapExternalProviderName } from '../provider-capabilities'; +import type { CLIProxyProvider } from '../types'; /** Timeout for remote fetch requests (ms) */ const REMOTE_FETCH_TIMEOUT_MS = 5000; diff --git a/src/cliproxy/remote-proxy-client.ts b/src/cliproxy/services/remote-proxy-client.ts similarity index 99% rename from src/cliproxy/remote-proxy-client.ts rename to src/cliproxy/services/remote-proxy-client.ts index 838a7bff..a93b1de7 100644 --- a/src/cliproxy/remote-proxy-client.ts +++ b/src/cliproxy/services/remote-proxy-client.ts @@ -6,7 +6,7 @@ */ import * as https from 'https'; -import { getRemoteDefaultPort, validateRemotePort } from './config-generator'; +import { getRemoteDefaultPort, validateRemotePort } from '../config/config-generator'; /** Error codes for remote proxy status */ export type RemoteProxyErrorCode = diff --git a/src/cliproxy/startup-lock.ts b/src/cliproxy/services/startup-lock.ts similarity index 98% rename from src/cliproxy/startup-lock.ts rename to src/cliproxy/services/startup-lock.ts index 1bf6b569..2b7195d7 100644 --- a/src/cliproxy/startup-lock.ts +++ b/src/cliproxy/services/startup-lock.ts @@ -24,8 +24,8 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCliproxyDir } from './config-generator'; -import { createLogger } from '../services/logging'; +import { getCliproxyDir } from '../config/config-generator'; +import { createLogger } from '../../services/logging'; /** Lock file structure */ interface LockData { diff --git a/src/cliproxy/stats-fetcher.ts b/src/cliproxy/services/stats-fetcher.ts similarity index 99% rename from src/cliproxy/stats-fetcher.ts rename to src/cliproxy/services/stats-fetcher.ts index ce3f82e1..7448dadd 100644 --- a/src/cliproxy/stats-fetcher.ts +++ b/src/cliproxy/services/stats-fetcher.ts @@ -5,13 +5,13 @@ * Requires usage-statistics-enabled: true in config.yaml. */ -import { getEffectiveApiKey, getEffectiveManagementSecret } from './auth-token-manager'; +import { getEffectiveApiKey, getEffectiveManagementSecret } from '../auth/auth-token-manager'; import { getProxyTarget, buildProxyUrl, buildProxyHeaders, buildManagementHeaders, -} from './proxy-target-resolver'; +} from '../proxy/proxy-target-resolver'; import { buildCliproxyStatsFromUsageResponse } from './stats-transformer'; /** Per-account usage statistics */ diff --git a/src/cliproxy/stats-transformer.ts b/src/cliproxy/services/stats-transformer.ts similarity index 96% rename from src/cliproxy/stats-transformer.ts rename to src/cliproxy/services/stats-transformer.ts index a525b1d8..ed2be0ea 100644 --- a/src/cliproxy/stats-transformer.ts +++ b/src/cliproxy/services/stats-transformer.ts @@ -1,6 +1,6 @@ -import { buildQualifiedAccountStatsKey } from './account-stats-key'; -import { mapExternalProviderName } from './provider-capabilities'; -import { buildEmailBackedAccountId } from './accounts/email-account-identity'; +import { buildQualifiedAccountStatsKey } from '../accounts/account-stats-key'; +import { mapExternalProviderName } from '../provider-capabilities'; +import { buildEmailBackedAccountId } from '../accounts/email-account-identity'; import type { AccountUsageStats, CliproxyManagementAuthFile, diff --git a/src/cliproxy/services/variant-config-adapter.ts b/src/cliproxy/services/variant-config-adapter.ts index 2f4814f4..2425cec1 100644 --- a/src/cliproxy/services/variant-config-adapter.ts +++ b/src/cliproxy/services/variant-config-adapter.ts @@ -13,7 +13,7 @@ import { mutateUnifiedConfig, isUnifiedMode, } from '../../config/unified-config-loader'; -import { CLIPROXY_DEFAULT_PORT } from '../config-generator'; +import { CLIPROXY_DEFAULT_PORT } from '../config/config-generator'; export const VARIANT_PORT_BASE = CLIPROXY_DEFAULT_PORT + 1; export const VARIANT_PORT_MAX_OFFSET = 100; diff --git a/src/cliproxy/services/variant-service.ts b/src/cliproxy/services/variant-service.ts index b5019e90..629d9a09 100644 --- a/src/cliproxy/services/variant-service.ts +++ b/src/cliproxy/services/variant-service.ts @@ -13,15 +13,15 @@ import { CompositeTierConfig, CompositeVariantConfig } from '../../config/unifie import type { TargetType } from '../../targets/target-adapter'; import { isReservedName, isWindowsReservedName } from '../../config/reserved-names'; import { isUnifiedMode } from '../../config/unified-config-loader'; -import { deleteConfigForPort } from '../config-generator'; +import { deleteConfigForPort } from '../config/config-generator'; import { hasActiveSessions, deleteSessionLockForPort } from '../session-tracker'; import { warn } from '../../utils/ui'; import { getCcsDir } from '../../utils/config-manager'; -import { validateCompositeTiers } from '../composite-validator'; +import { validateCompositeTiers } from '../config/composite-validator'; import { canonicalizeModelIdForProvider, getDeniedModelIdReasonForProvider, -} from '../model-id-normalizer'; +} from '../ai-providers/model-id-normalizer'; import { createSettingsFile, createSettingsFileUnified, diff --git a/src/cliproxy/services/variant-settings.ts b/src/cliproxy/services/variant-settings.ts index 3b22998d..88b9c6a0 100644 --- a/src/cliproxy/services/variant-settings.ts +++ b/src/cliproxy/services/variant-settings.ts @@ -11,7 +11,7 @@ import * as os from 'os'; import { CLIProxyProfileName } from '../../auth/profile-detector'; import { getCcsDir } from '../../utils/config-manager'; import { expandPath } from '../../utils/helpers'; -import { getClaudeEnvVars, CLIPROXY_DEFAULT_PORT } from '../config-generator'; +import { getClaudeEnvVars, CLIPROXY_DEFAULT_PORT } from '../config/config-generator'; import { CLIProxyProvider } from '../types'; import { CompositeTierConfig } from '../../config/unified-config-types'; import { ensureWebSearchMcpOrThrow } from '../../utils/websearch-manager'; @@ -21,9 +21,9 @@ import { removeImageAnalysisProfileHook, } from '../../utils/hooks/image-analyzer-profile-hook-injector'; import { prepareImageAnalysisFallbackHook } from '../../utils/hooks'; -import { getEffectiveApiKey } from '../auth-token-manager'; +import { getEffectiveApiKey } from '../auth/auth-token-manager'; import { warn } from '../../utils/ui'; -import { normalizeModelIdForProvider } from '../model-id-normalizer'; +import { normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer'; /** Environment settings structure */ interface SettingsEnv { diff --git a/src/cliproxy/session-tracker.ts b/src/cliproxy/session-tracker.ts index 5ec19009..b2e93276 100644 --- a/src/cliproxy/session-tracker.ts +++ b/src/cliproxy/session-tracker.ts @@ -18,9 +18,9 @@ import * as fs from 'fs'; import * as path from 'path'; import * as crypto from 'crypto'; import * as lockfile from 'proper-lockfile'; -import { getCliproxyDir } from './config-generator'; +import { getCliproxyDir } from './config/config-generator'; import { getPortProcess, isCLIProxyProcess } from '../utils/port-utils'; -import { CLIPROXY_DEFAULT_PORT } from './config-generator'; +import { CLIPROXY_DEFAULT_PORT } from './config/config-generator'; /** Session lock file structure */ interface SessionLock { diff --git a/src/cliproxy/sync/local-config-sync.ts b/src/cliproxy/sync/local-config-sync.ts index 1d980033..4a1e8053 100644 --- a/src/cliproxy/sync/local-config-sync.ts +++ b/src/cliproxy/sync/local-config-sync.ts @@ -7,9 +7,9 @@ import * as fs from 'fs'; import * as yaml from 'js-yaml'; -import { getCliproxyConfigPath } from '../config-generator'; +import { getCliproxyConfigPath } from '../config/config-generator'; import { generateSyncPayload } from './profile-mapper'; -import type { ClaudeKey } from '../management-api-types'; +import type { ClaudeKey } from '../management/management-api-types'; /** * Sync profiles to local CLIProxy config.yaml. diff --git a/src/cliproxy/sync/profile-mapper.ts b/src/cliproxy/sync/profile-mapper.ts index 3a4a120c..a092c982 100644 --- a/src/cliproxy/sync/profile-mapper.ts +++ b/src/cliproxy/sync/profile-mapper.ts @@ -9,7 +9,7 @@ import * as path from 'path'; import { getCcsDir } from '../../utils/config-manager'; import { expandPath } from '../../utils/helpers'; import { listApiProfiles, isApiProfileConfigured } from '../../api/services/profile-reader'; -import type { ClaudeKey } from '../management-api-types'; +import type { ClaudeKey } from '../management/management-api-types'; /** * Profile info with settings for sync. diff --git a/src/cliproxy/types.ts b/src/cliproxy/types.ts index 2abd2052..0780dcb7 100644 --- a/src/cliproxy/types.ts +++ b/src/cliproxy/types.ts @@ -1,331 +1,6 @@ /** - * CLIProxy Type Definitions - * Types for CLIProxyAPI binary management and execution + * CLIProxy Type Definitions — barrel re-export + * All types are now organized in ./types/ by concern. + * This file preserves backward compatibility for existing imports. */ - -import type { CompositeTierConfig } from '../config/unified-config-types'; -import type { UpdateCheckResult } from './binary/types'; - -/** - * Supported operating systems - */ -export type SupportedOS = 'darwin' | 'linux' | 'windows'; - -/** - * Supported CPU architectures - */ -export type SupportedArch = 'amd64' | 'arm64'; - -/** - * Archive extension based on platform - */ -export type ArchiveExtension = 'tar.gz' | 'zip'; - -/** - * Platform detection result - */ -export interface PlatformInfo { - /** Operating system (darwin, linux, windows) */ - os: SupportedOS; - /** CPU architecture (amd64, arm64) */ - arch: SupportedArch; - /** Full binary archive name (e.g., CLIProxyAPI_6.5.27_linux_amd64.tar.gz) */ - binaryName: string; - /** Archive extension (tar.gz for Unix, zip for Windows) */ - extension: ArchiveExtension; -} - -/** - * Binary manager configuration - */ -export interface BinaryManagerConfig { - /** CLIProxyAPI version to download */ - version: string; - /** GitHub releases base URL */ - releaseUrl: string; - /** Local binary storage path (~/.ccs/bin/) */ - binPath: string; - /** Maximum download retry attempts */ - maxRetries: number; - /** Enable verbose logging */ - verbose: boolean; - /** Force specific version (skip auto-upgrade to latest) */ - forceVersion: boolean; - /** Skip background update checks on runtime bootstrap paths */ - skipAutoUpdate: boolean; - /** Allow downloading/installing the binary when it is missing */ - allowInstall: boolean; - /** Backend variant (original vs plus) */ - backend?: CLIProxyBackend; - /** - * Test-only seam: override the auto-update check. When omitted, the real - * `checkForUpdates` from ./binary/version-checker is used. Provided so tests - * can verify "skipAutoUpdate respected" without resorting to bun's - * `mock.module()`, which leaks across test files in the same process. - */ - checkForUpdatesFn?: ( - binPath: string, - configVersion: string, - verbose?: boolean, - backend?: CLIProxyBackend - ) => Promise; -} - -/** - * Download progress callback - */ -export interface DownloadProgress { - /** Total bytes to download */ - total: number; - /** Bytes downloaded so far */ - downloaded: number; - /** Download percentage (0-100) */ - percentage: number; -} - -/** - * Download progress callback function type - */ -export type ProgressCallback = (progress: DownloadProgress) => void; - -/** - * Binary info after successful download/verification - */ -export interface BinaryInfo { - /** Full path to executable */ - path: string; - /** CLIProxyAPI version */ - version: string; - /** Platform info */ - platform: PlatformInfo; - /** SHA256 checksum (verified) */ - checksum: string; -} - -/** - * Checksum verification result - */ -export interface ChecksumResult { - /** Whether checksum matched */ - valid: boolean; - /** Expected checksum from checksums.txt */ - expected: string; - /** Actual computed checksum */ - actual: string; -} - -/** - * Download result - */ -export interface DownloadResult { - /** Whether download succeeded */ - success: boolean; - /** Path to downloaded file */ - filePath?: string; - /** Error message if failed */ - error?: string; - /** Number of retries attempted */ - retries: number; -} - -/** - * Supported CLIProxy providers - * - gemini: Google Gemini via OAuth - * - codex: OpenAI Codex via OAuth - * - agy: Antigravity via OAuth (short name for easy usage) - * - qwen: Qwen Code via OAuth (qwen3-coder) - * - iflow: iFlow via OAuth - * - kiro: Kiro (AWS CodeWhisperer) via OAuth - * - ghcp: GitHub Copilot via Device Code (OAuth through CLIProxyAPIPlus) - * - claude: Claude (Anthropic) via OAuth - * - kimi: Kimi (Moonshot AI) via Device Code OAuth - * - cursor: Cursor via PKCE browser polling - * - gitlab: GitLab Duo via OAuth or PAT - * - codebuddy: Tencent CodeBuddy via browser polling - * - kilo: Kilo AI via device flow - */ -export type CLIProxyProvider = - | 'gemini' - | 'codex' - | 'agy' - | 'qwen' - | 'iflow' - | 'kiro' - | 'ghcp' - | 'claude' - | 'kimi' - | 'cursor' - | 'gitlab' - | 'codebuddy' - | 'kilo'; - -/** - * CLIProxy backend selection - * - original: CLIProxyAPI (default; upstream maintained by router-for-me) - * - plus: CCS-maintained CLIProxyAPIPlus community fork for opt-in providers - * that are not available in the original backend - */ -export type CLIProxyBackend = 'original' | 'plus'; - -/** - * Credential routing strategy for matching CLIProxy accounts. - */ -export type CliproxyRoutingStrategy = 'round-robin' | 'fill-first'; - -/** - * Providers that require CLIProxyAPIPlus backend - */ -export const PLUS_ONLY_PROVIDERS: CLIProxyProvider[] = [ - 'kiro', - 'ghcp', - 'cursor', - 'gitlab', - 'codebuddy', - 'kilo', -]; - -/** - * CLIProxy config.yaml structure (minimal) - */ -export interface CLIProxyConfig { - port: number; - 'api-keys': string[]; - 'auth-dir': string; - debug: boolean; - routing?: { - strategy?: CliproxyRoutingStrategy; - 'session-affinity'?: boolean; - 'session-affinity-ttl'?: string; - 'claude-code-session-affinity'?: boolean; - }; - 'gemini-api-key'?: Array<{ - 'api-key': string; - 'base-url'?: string; - }>; - 'codex-api-key'?: Array<{ - 'api-key': string; - 'base-url'?: string; - }>; - 'claude-api-key'?: Array<{ - 'api-key': string; - 'base-url'?: string; - 'proxy-url'?: string; - prefix?: string; - headers?: Record; - 'excluded-models'?: string[]; - models?: Array<{ - name: string; - alias: string; - }>; - }>; - 'vertex-api-key'?: Array<{ - 'api-key': string; - 'base-url'?: string; - }>; - 'openai-compatibility'?: Array<{ - name: string; - 'base-url': string; - headers?: Record; - 'api-key-entries': Array<{ - 'api-key': string; - 'proxy-url'?: string; - }>; - models?: Array<{ - name: string; - alias: string; - }>; - }>; -} - -/** - * Executor configuration - */ -export interface ExecutorConfig { - /** Port for CLIProxyAPI (default: 8317) */ - port: number; - /** Timeout for proxy readiness in ms (default: 5000) */ - timeout: number; - /** Enable verbose logging */ - verbose: boolean; - /** Poll interval for port check in ms (default: 100) */ - pollInterval: number; - /** Custom settings path for user-defined CLIProxy variants */ - customSettingsPath?: string; - /** Composite variant: true when mixing providers per tier */ - isComposite?: boolean; - /** Composite variant: per-tier provider+model mappings */ - compositeTiers?: { - opus: CompositeTierConfig; - sonnet: CompositeTierConfig; - haiku: CompositeTierConfig; - }; - /** Composite variant: which tier is the default */ - compositeDefaultTier?: 'opus' | 'sonnet' | 'haiku'; - /** Original profile/variant name (e.g., "my-mix" for composite variants) */ - profileName?: string; - /** Optional inherited continuity directory from mapped account profile */ - claudeConfigDir?: string; - /** Optional browser runtime env for Claude browser MCP reuse. */ - browserRuntimeEnv?: Record; -} - -/** - * Model mapping for each provider - */ -export interface ProviderModelMapping { - /** Default model for requests */ - defaultModel: string; - /** Model for Claude CLI's ANTHROPIC_MODEL */ - claudeModel: string; - /** Model for Claude CLI's ANTHROPIC_DEFAULT_OPUS_MODEL */ - opusModel?: string; - /** Model for Claude CLI's ANTHROPIC_DEFAULT_SONNET_MODEL */ - sonnetModel?: string; - /** Model for Claude CLI's ANTHROPIC_DEFAULT_HAIKU_MODEL */ - haikuModel?: string; -} - -/** - * Provider configuration - */ -export interface ProviderConfig { - /** Provider name */ - name: CLIProxyProvider; - /** Display name for UI */ - displayName: string; - /** Model configuration */ - models: ProviderModelMapping; - /** Whether OAuth is required */ - requiresOAuth: boolean; -} - -/** - * Resolved proxy configuration after merging CLI > ENV > config.yaml > defaults. - * Used by executor to determine local vs remote proxy mode. - */ -export interface ResolvedProxyConfig { - /** Proxy mode: 'local' spawns CLIProxyAPI locally, 'remote' connects to external server */ - mode: 'local' | 'remote'; - /** Remote proxy hostname/IP (only for remote mode) */ - host?: string; - /** Proxy port (default: 8317) */ - port: number; - /** Protocol for remote connection (default: http) */ - protocol: 'http' | 'https'; - /** Auth token for remote proxy authentication */ - authToken?: string; - /** Management key for remote management endpoints */ - managementKey?: string; - /** Enable fallback to local when remote unreachable (default: true) */ - fallbackEnabled: boolean; - /** Auto-start local proxy if not running (default: true) */ - autoStartLocal: boolean; - /** --remote-only flag: fail if remote unreachable, no fallback */ - remoteOnly: boolean; - /** --local-proxy flag: force local mode, ignore remote config */ - forceLocal: boolean; - /** Remote proxy connection timeout in ms (default: 2000) */ - timeout?: number; - /** Allow self-signed certificates for HTTPS connections (default: true) */ - allowSelfSigned?: boolean; -} +export * from './types/index'; diff --git a/src/cliproxy/types/__tests__/types-backward-compat.test.ts b/src/cliproxy/types/__tests__/types-backward-compat.test.ts new file mode 100644 index 00000000..b7f356f5 --- /dev/null +++ b/src/cliproxy/types/__tests__/types-backward-compat.test.ts @@ -0,0 +1,127 @@ +import { describe, it, expect } from 'bun:test'; + +/** + * TDD: backward-compat test for types.ts split. + * Verifies all 19 types are still accessible from the original path + * AND from the new concern-based files. + */ + +// Import from OLD path (must keep working — backward compat) +import type { + SupportedOS, + SupportedArch, + ArchiveExtension, + PlatformInfo, + BinaryManagerConfig, + DownloadProgress, + ProgressCallback, + BinaryInfo, + ChecksumResult, + DownloadResult, + CLIProxyProvider, + CLIProxyBackend, + CliproxyRoutingStrategy, + CLIProxyConfig, + ExecutorConfig, + ProviderConfig, + ProviderModelMapping, + ResolvedProxyConfig, +} from '../../types'; + +// Import constant from OLD path +import { PLUS_ONLY_PROVIDERS } from '../../types'; + +describe('types.ts backward compatibility', () => { + it('exports all platform types', () => { + const os: SupportedOS = 'darwin'; + const arch: SupportedArch = 'arm64'; + const ext: ArchiveExtension = 'tar.gz'; + const info: PlatformInfo = { + os, + arch, + binaryName: 'test.tar.gz', + extension: ext, + }; + expect(info.os).toBe('darwin'); + expect(info.arch).toBe('arm64'); + }); + + it('exports all binary types', () => { + const cfg: BinaryManagerConfig = { + version: '1.0.0', releaseUrl: '', binPath: '/tmp', + maxRetries: 3, verbose: false, forceVersion: false, + skipAutoUpdate: false, allowInstall: true, + }; + expect(cfg.version).toBe('1.0.0'); + const progress: DownloadProgress = { total: 100, downloaded: 50, percentage: 50 }; + const cb: ProgressCallback = (p) => p.percentage; + cb(progress); + const bin: BinaryInfo = { + path: '/usr/local/bin/cli-proxy', + version: '1.0.0', + platform: { os: 'linux', arch: 'amd64', binaryName: 'test.tar.gz', extension: 'tar.gz' }, + checksum: 'abc123', + }; + const check: ChecksumResult = { valid: true, expected: 'abc', actual: 'abc' }; + const dl: DownloadResult = { success: true, filePath: '/tmp/test', retries: 0 }; + expect(check.valid).toBe(true); + expect(dl.success).toBe(true); + expect(bin.version).toBe('1.0.0'); + }); + + it('exports all provider types', () => { + const provider: CLIProxyProvider = 'gemini'; + const backend: CLIProxyBackend = 'original'; + const strategy: CliproxyRoutingStrategy = 'round-robin'; + expect(provider).toBe('gemini'); + expect(backend).toBe('original'); + expect(strategy).toBe('round-robin'); + }); + + it('exports PLUS_ONLY_PROVIDERS constant', () => { + expect(Array.isArray(PLUS_ONLY_PROVIDERS)).toBe(true); + expect(PLUS_ONLY_PROVIDERS).toContain('ghcp'); + expect(PLUS_ONLY_PROVIDERS).toContain('cursor'); + expect(PLUS_ONLY_PROVIDERS).toContain('kiro'); + }); + + it('exports config types', () => { + const config: CLIProxyConfig = { port: 8317, 'api-keys': [], 'auth-dir': '/tmp', debug: false }; + expect(config.port).toBe(8317); + + const executor: ExecutorConfig = { + port: 8317, + timeout: 5000, + verbose: false, + pollInterval: 100, + }; + expect(executor.timeout).toBe(5000); + + const resolved: ResolvedProxyConfig = { + mode: 'local', + port: 8317, + protocol: 'http', + fallbackEnabled: true, + autoStartLocal: true, + remoteOnly: false, + forceLocal: false, + }; + expect(resolved.mode).toBe('local'); + }); + + it('exports provider config types', () => { + const mapping: ProviderModelMapping = { + defaultModel: 'gpt-4', + claudeModel: 'claude-3-opus', + }; + expect(mapping.defaultModel).toBe('gpt-4'); + + const provider: ProviderConfig = { + name: 'gemini', + displayName: 'Google Gemini', + models: mapping, + requiresOAuth: true, + }; + expect(provider.name).toBe('gemini'); + }); +}); diff --git a/src/cliproxy/types/binary-types.ts b/src/cliproxy/types/binary-types.ts new file mode 100644 index 00000000..86bdbcb1 --- /dev/null +++ b/src/cliproxy/types/binary-types.ts @@ -0,0 +1,59 @@ +/** + * Binary management, download, and verification types + */ + +import type { CLIProxyBackend } from './provider-types'; +import type { PlatformInfo } from './platform-types'; +import type { UpdateCheckResult } from '../binary/types'; + +/** Binary manager configuration */ +export interface BinaryManagerConfig { + version: string; + releaseUrl: string; + binPath: string; + maxRetries: number; + verbose: boolean; + forceVersion: boolean; + skipAutoUpdate: boolean; + allowInstall: boolean; + backend?: CLIProxyBackend; + checkForUpdatesFn?: ( + binPath: string, + configVersion: string, + verbose?: boolean, + backend?: CLIProxyBackend + ) => Promise; +} + +/** Download progress callback data */ +export interface DownloadProgress { + total: number; + downloaded: number; + percentage: number; +} + +/** Download progress callback function type */ +export type ProgressCallback = (progress: DownloadProgress) => void; + +/** Binary info after successful download/verification */ +export interface BinaryInfo { + path: string; + version: string; + platform: PlatformInfo; + checksum: string; +} + +/** Checksum verification result */ +export interface ChecksumResult { + valid: boolean; + expected: string; + actual: string; +} + +/** Download result */ +export interface DownloadResult { + success: boolean; + filePath?: string; + error?: string; + retries: number; +} diff --git a/src/cliproxy/types/config-types.ts b/src/cliproxy/types/config-types.ts new file mode 100644 index 00000000..bf873439 --- /dev/null +++ b/src/cliproxy/types/config-types.ts @@ -0,0 +1,92 @@ +/** + * CLIProxy configuration types (config.yaml, executor, proxy resolution) + */ + +import type { CompositeTierConfig } from '../../config/unified-config-types'; +import type { CliproxyRoutingStrategy } from './provider-types'; + +/** CLIProxy config.yaml structure (minimal) */ +export interface CLIProxyConfig { + port: number; + 'api-keys': string[]; + 'auth-dir': string; + debug: boolean; + routing?: { + strategy?: CliproxyRoutingStrategy; + 'session-affinity'?: boolean; + 'session-affinity-ttl'?: string; + 'claude-code-session-affinity'?: boolean; + }; + 'gemini-api-key'?: Array<{ + 'api-key': string; + 'base-url'?: string; + }>; + 'codex-api-key'?: Array<{ + 'api-key': string; + 'base-url'?: string; + }>; + 'claude-api-key'?: Array<{ + 'api-key': string; + 'base-url'?: string; + 'proxy-url'?: string; + prefix?: string; + headers?: Record; + 'excluded-models'?: string[]; + models?: Array<{ + name: string; + alias: string; + }>; + }>; + 'vertex-api-key'?: Array<{ + 'api-key': string; + 'base-url'?: string; + }>; + 'openai-compatibility'?: Array<{ + name: string; + 'base-url': string; + headers?: Record; + 'api-key-entries': Array<{ + 'api-key': string; + 'proxy-url'?: string; + }>; + models?: Array<{ + name: string; + alias: string; + }>; + }>; +} + +/** Executor configuration */ +export interface ExecutorConfig { + port: number; + timeout: number; + verbose: boolean; + pollInterval: number; + customSettingsPath?: string; + isComposite?: boolean; + compositeTiers?: { + opus: CompositeTierConfig; + sonnet: CompositeTierConfig; + haiku: CompositeTierConfig; + }; + compositeDefaultTier?: 'opus' | 'sonnet' | 'haiku'; + profileName?: string; + claudeConfigDir?: string; + browserRuntimeEnv?: Record; +} + +/** Resolved proxy configuration after merging CLI > ENV > config.yaml > defaults */ +export interface ResolvedProxyConfig { + mode: 'local' | 'remote'; + host?: string; + port: number; + protocol: 'http' | 'https'; + authToken?: string; + managementKey?: string; + fallbackEnabled: boolean; + autoStartLocal: boolean; + remoteOnly: boolean; + forceLocal: boolean; + timeout?: number; + allowSelfSigned?: boolean; +} diff --git a/src/cliproxy/types/index.ts b/src/cliproxy/types/index.ts new file mode 100644 index 00000000..a0dacd4b --- /dev/null +++ b/src/cliproxy/types/index.ts @@ -0,0 +1,4 @@ +export * from './platform-types'; +export * from './binary-types'; +export * from './provider-types'; +export * from './config-types'; diff --git a/src/cliproxy/types/platform-types.ts b/src/cliproxy/types/platform-types.ts new file mode 100644 index 00000000..0fdd0f65 --- /dev/null +++ b/src/cliproxy/types/platform-types.ts @@ -0,0 +1,20 @@ +/** + * Platform detection and binary archive types + */ + +/** Supported operating systems */ +export type SupportedOS = 'darwin' | 'linux' | 'windows'; + +/** Supported CPU architectures */ +export type SupportedArch = 'amd64' | 'arm64'; + +/** Archive extension based on platform */ +export type ArchiveExtension = 'tar.gz' | 'zip'; + +/** Platform detection result */ +export interface PlatformInfo { + os: SupportedOS; + arch: SupportedArch; + binaryName: string; + extension: ArchiveExtension; +} diff --git a/src/cliproxy/types/provider-types.ts b/src/cliproxy/types/provider-types.ts new file mode 100644 index 00000000..8aa97976 --- /dev/null +++ b/src/cliproxy/types/provider-types.ts @@ -0,0 +1,52 @@ +/** + * CLIProxy provider, backend, and routing types + */ + +/** Supported CLIProxy providers */ +export type CLIProxyProvider = + | 'gemini' + | 'codex' + | 'agy' + | 'qwen' + | 'iflow' + | 'kiro' + | 'ghcp' + | 'claude' + | 'kimi' + | 'cursor' + | 'gitlab' + | 'codebuddy' + | 'kilo'; + +/** CLIProxy backend selection */ +export type CLIProxyBackend = 'original' | 'plus'; + +/** Credential routing strategy for matching CLIProxy accounts */ +export type CliproxyRoutingStrategy = 'round-robin' | 'fill-first'; + +/** Providers that require CLIProxyAPIPlus backend */ +export const PLUS_ONLY_PROVIDERS: CLIProxyProvider[] = [ + 'kiro', + 'ghcp', + 'cursor', + 'gitlab', + 'codebuddy', + 'kilo', +]; + +/** Model mapping for each provider */ +export interface ProviderModelMapping { + defaultModel: string; + claudeModel: string; + opusModel?: string; + sonnetModel?: string; + haikuModel?: string; +} + +/** Provider configuration */ +export interface ProviderConfig { + name: CLIProxyProvider; + displayName: string; + models: ProviderModelMapping; + requiresOAuth: boolean; +} diff --git a/src/commands/cleanup-command.ts b/src/commands/cleanup-command.ts index 223ae502..47bc4ac2 100644 --- a/src/commands/cleanup-command.ts +++ b/src/commands/cleanup-command.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { getCliproxyDir } from '../cliproxy/config-generator'; +import { getCliproxyDir } from '../cliproxy/config/config-generator'; import { getLogArchiveDir, getNativeLogsDir } from '../services/logging'; import { info, ok, warn } from '../utils/ui'; diff --git a/src/commands/cliproxy/auth-subcommand.ts b/src/commands/cliproxy/auth-subcommand.ts index b856f278..0d336b32 100644 --- a/src/commands/cliproxy/auth-subcommand.ts +++ b/src/commands/cliproxy/auth-subcommand.ts @@ -7,7 +7,7 @@ * - Built-in profile authentication status */ -import { getAllAuthStatus, getOAuthConfig } from '../../cliproxy/auth-handler'; +import { getAllAuthStatus, getOAuthConfig } from '../../cliproxy/auth/auth-handler'; import { listVariants } from '../../cliproxy/services'; import { initUI, header, subheader, color, dim, ok, warn, table } from '../../utils/ui'; diff --git a/src/commands/cliproxy/catalog-subcommand.ts b/src/commands/cliproxy/catalog-subcommand.ts index adcdb5e5..10449eb9 100644 --- a/src/commands/cliproxy/catalog-subcommand.ts +++ b/src/commands/cliproxy/catalog-subcommand.ts @@ -6,13 +6,13 @@ import { getResolvedCatalog, refreshCatalogFromProxy, getAllResolvedCatalogs, -} from '../../cliproxy/catalog-cache'; -import { getCatalogRoutingSnapshot } from '../../cliproxy/catalog-routing'; -import { ensureManagedModelPrefixes } from '../../cliproxy/managed-model-prefixes'; -import { getProxyTarget } from '../../cliproxy/proxy-target-resolver'; +} from '../../cliproxy/services/catalog-cache'; +import { getCatalogRoutingSnapshot } from '../../cliproxy/services/catalog-routing'; +import { ensureManagedModelPrefixes } from '../../cliproxy/ai-providers/managed-model-prefixes'; +import { getProxyTarget } from '../../cliproxy/proxy/proxy-target-resolver'; import type { ThinkingSupport } from '../../cliproxy/model-catalog'; import type { CLIProxyProvider } from '../../cliproxy/types'; -import type { RemoteModelInfo } from '../../cliproxy/management-api-types'; +import type { RemoteModelInfo } from '../../cliproxy/management/management-api-types'; import type { CliproxyProviderRoutingHints } from '../../shared/cliproxy-model-routing'; /** Fetch model definitions from CLIProxyAPI for all syncable providers */ diff --git a/src/commands/cliproxy/help-subcommand.ts b/src/commands/cliproxy/help-subcommand.ts index f349be7e..a7ec3fd4 100644 --- a/src/commands/cliproxy/help-subcommand.ts +++ b/src/commands/cliproxy/help-subcommand.ts @@ -10,7 +10,7 @@ import { DEFAULT_BACKEND, getFallbackVersion, BACKEND_CONFIG, -} from '../../cliproxy/platform-detector'; +} from '../../cliproxy/binary/platform-detector'; import { QUOTA_PROVIDER_HELP_TEXT } from '../../cliproxy/provider-capabilities'; export async function showHelp(): Promise { diff --git a/src/commands/cliproxy/install-subcommand.ts b/src/commands/cliproxy/install-subcommand.ts index 2e898063..9b4dcd15 100644 --- a/src/commands/cliproxy/install-subcommand.ts +++ b/src/commands/cliproxy/install-subcommand.ts @@ -15,7 +15,7 @@ import { installVersion, installLatest, } from '../../cliproxy/services'; -import { DEFAULT_BACKEND, BACKEND_CONFIG } from '../../cliproxy/platform-detector'; +import { DEFAULT_BACKEND, BACKEND_CONFIG } from '../../cliproxy/binary/platform-detector'; import { CLIProxyBackend } from '../../cliproxy/types'; function getBackendLabel(backend: CLIProxyBackend): string { diff --git a/src/commands/cliproxy/proxy-lifecycle-subcommand.ts b/src/commands/cliproxy/proxy-lifecycle-subcommand.ts index 1d289475..747cadb0 100644 --- a/src/commands/cliproxy/proxy-lifecycle-subcommand.ts +++ b/src/commands/cliproxy/proxy-lifecycle-subcommand.ts @@ -10,7 +10,7 @@ import { initUI, header, color, dim, ok, warn, info } from '../../utils/ui'; import { getProxyStatus, startProxy, stopProxy } from '../../cliproxy/services'; -import { detectRunningProxy } from '../../cliproxy/proxy-detector'; +import { detectRunningProxy } from '../../cliproxy/proxy/proxy-detector'; import { resolveLifecyclePort } from './resolve-lifecycle-port'; export async function handleStart(verbose = false): Promise { diff --git a/src/commands/cliproxy/quota-subcommand.ts b/src/commands/cliproxy/quota-subcommand.ts index e41fab95..b53dd770 100644 --- a/src/commands/cliproxy/quota-subcommand.ts +++ b/src/commands/cliproxy/quota-subcommand.ts @@ -15,21 +15,21 @@ import { pauseAccount, resumeAccount, findAccountByQuery, -} from '../../cliproxy/account-manager'; -import { fetchAllProviderQuotas } from '../../cliproxy/quota-fetcher'; -import { fetchAllCodexQuotas } from '../../cliproxy/quota-fetcher-codex'; -import { fetchAllClaudeQuotas } from '../../cliproxy/quota-fetcher-claude'; -import { pickMostRestrictiveClaudeWeeklyWindow } from '../../cliproxy/quota-fetcher-claude-normalizer'; -import { fetchAllGeminiCliQuotas } from '../../cliproxy/quota-fetcher-gemini-cli'; -import { fetchAllGhcpQuotas } from '../../cliproxy/quota-fetcher-ghcp'; +} from '../../cliproxy/accounts/account-manager'; +import { fetchAllProviderQuotas } from '../../cliproxy/quota/quota-fetcher'; +import { fetchAllCodexQuotas } from '../../cliproxy/quota/quota-fetcher-codex'; +import { fetchAllClaudeQuotas } from '../../cliproxy/quota/quota-fetcher-claude'; +import { pickMostRestrictiveClaudeWeeklyWindow } from '../../cliproxy/quota/quota-fetcher-claude-normalizer'; +import { fetchAllGeminiCliQuotas } from '../../cliproxy/quota/quota-fetcher-gemini-cli'; +import { fetchAllGhcpQuotas } from '../../cliproxy/quota/quota-fetcher-ghcp'; import type { CodexQuotaResult, ClaudeQuotaResult, GeminiCliQuotaResult, GhcpQuotaResult, QuotaErrorMetadata, -} from '../../cliproxy/quota-types'; -import { isOnCooldown } from '../../cliproxy/quota-manager'; +} from '../../cliproxy/quota/quota-types'; +import { isOnCooldown } from '../../cliproxy/quota/quota-manager'; import { CLIProxyProvider } from '../../cliproxy/types'; import { QUOTA_SUPPORTED_PROVIDER_IDS, diff --git a/src/commands/cliproxy/routing-subcommand.ts b/src/commands/cliproxy/routing-subcommand.ts index 45fcfd14..6e0b9895 100644 --- a/src/commands/cliproxy/routing-subcommand.ts +++ b/src/commands/cliproxy/routing-subcommand.ts @@ -8,7 +8,7 @@ import { normalizeCliproxySessionAffinityTtl, readCliproxyRoutingState, readCliproxySessionAffinityState, -} from '../../cliproxy/routing-strategy'; +} from '../../cliproxy/routing/routing-strategy'; function printStrategyGuide(): void { console.log(subheader('Routing Modes:')); diff --git a/src/commands/cliproxy/variant-subcommand.ts b/src/commands/cliproxy/variant-subcommand.ts index bacc9c73..1c8b7833 100644 --- a/src/commands/cliproxy/variant-subcommand.ts +++ b/src/commands/cliproxy/variant-subcommand.ts @@ -7,12 +7,12 @@ */ import * as path from 'path'; -import { getProviderAccounts } from '../../cliproxy/account-manager'; +import { getProviderAccounts } from '../../cliproxy/accounts/account-manager'; import { triggerOAuth } from '../../cliproxy/auth/oauth-handler'; import { CLIProxyProfileName, CLIPROXY_PROFILES } from '../../auth/profile-detector'; -import { getCatalogRoutingSnapshot } from '../../cliproxy/catalog-routing'; +import { getCatalogRoutingSnapshot } from '../../cliproxy/services/catalog-routing'; import { supportsModelConfig, getProviderCatalog, ModelEntry } from '../../cliproxy/model-catalog'; -import { ensureManagedModelPrefixes } from '../../cliproxy/managed-model-prefixes'; +import { ensureManagedModelPrefixes } from '../../cliproxy/ai-providers/managed-model-prefixes'; import type { CliproxyProviderRoutingHints } from '../../shared/cliproxy-model-routing'; import { CLIProxyProvider, CLIProxyBackend } from '../../cliproxy/types'; import type { TargetType } from '../../targets/target-adapter'; @@ -29,7 +29,7 @@ import { updateCompositeVariant, removeVariant, } from '../../cliproxy/services'; -import { DEFAULT_BACKEND } from '../../cliproxy/platform-detector'; +import { DEFAULT_BACKEND } from '../../cliproxy/binary/platform-detector'; import { CompositeTierConfig } from '../../config/unified-config-types'; import { formatAccountDisplayName } from '../../cliproxy/accounts/email-account-identity'; diff --git a/src/commands/config-command.ts b/src/commands/config-command.ts index 952dd81f..bf47b324 100644 --- a/src/commands/config-command.ts +++ b/src/commands/config-command.ts @@ -11,7 +11,7 @@ import open from 'open'; import { startServer } from '../web-server'; import { setupGracefulShutdown } from '../web-server/shutdown'; import { ensureCliproxyService } from '../cliproxy/service-manager'; -import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config-generator'; +import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/config-generator'; import { getDashboardAuthConfig } from '../config/unified-config-loader'; import { initUI, header, ok, info, warn, fail } from '../utils/ui'; import { resolveNamedCommand, type NamedCommandRoute } from './named-command-router'; diff --git a/src/commands/tokens-command.ts b/src/commands/tokens-command.ts index 9b5657e8..7d3f06cf 100644 --- a/src/commands/tokens-command.ts +++ b/src/commands/tokens-command.ts @@ -23,7 +23,7 @@ import { resetAuthToDefaults, getAuthSummary, } from '../cliproxy'; -import { regenerateConfig } from '../cliproxy/config-generator'; +import { regenerateConfig } from '../cliproxy/config/config-generator'; /** * Display current auth status diff --git a/src/config/unified-config-loader.ts b/src/config/unified-config-loader.ts index 16c2efb2..bca681f8 100644 --- a/src/config/unified-config-loader.ts +++ b/src/config/unified-config-loader.ts @@ -44,7 +44,7 @@ import type { CursorConfig, ContinuityConfig, } from './unified-config-types'; -import { validateCompositeTiers } from '../cliproxy/composite-validator'; +import { validateCompositeTiers } from '../cliproxy/config/composite-validator'; import { isUnifiedConfigEnabled } from './feature-flags'; import { isOfficialChannelId, diff --git a/src/copilot/copilot-executor.ts b/src/copilot/copilot-executor.ts index f8e8a1e0..b1ed44b4 100644 --- a/src/copilot/copilot-executor.ts +++ b/src/copilot/copilot-executor.ts @@ -9,7 +9,7 @@ import { spawn } from 'child_process'; import { CopilotConfig } from '../config/unified-config-types'; import { getGlobalEnvConfig } from '../config/unified-config-loader'; import { ensureCliproxyService } from '../cliproxy'; -import { getEffectiveApiKey } from '../cliproxy/auth-token-manager'; +import { getEffectiveApiKey } from '../cliproxy/auth/auth-token-manager'; import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager'; import { checkAuthStatus, isCopilotApiInstalled } from './copilot-auth'; import { isDaemonRunning, startDaemon } from './copilot-daemon'; diff --git a/src/docker/docker-bootstrap.ts b/src/docker/docker-bootstrap.ts index 52c0bb80..775ed64d 100644 --- a/src/docker/docker-bootstrap.ts +++ b/src/docker/docker-bootstrap.ts @@ -6,7 +6,7 @@ import { generateConfig, getCliproxyWritablePath, regenerateConfig, -} from '../cliproxy/config-generator'; +} from '../cliproxy/config/config-generator'; import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager'; import { getCliproxyConfigPath } from '../cliproxy/config/path-resolver'; import { registerSession, unregisterSession } from '../cliproxy/session-tracker'; diff --git a/src/management/checks/image-analysis-check.ts b/src/management/checks/image-analysis-check.ts index 52f5233c..85fe7e3a 100644 --- a/src/management/checks/image-analysis-check.ts +++ b/src/management/checks/image-analysis-check.ts @@ -13,8 +13,8 @@ import { repairImageAnalysisRuntimeState, } from '../../utils/image-analysis'; import { ok, warn, dim } from '../../utils/ui'; -import { isCliproxyRunning } from '../../cliproxy/stats-fetcher'; -import { CLIPROXY_DEFAULT_PORT } from '../../cliproxy/config-generator'; +import { isCliproxyRunning } from '../../cliproxy/services/stats-fetcher'; +import { CLIPROXY_DEFAULT_PORT } from '../../cliproxy/config/config-generator'; import type { HealthCheck } from './types'; import { hasImageAnalyzerHook } from '../../utils/hooks/image-analyzer-hook-installer'; diff --git a/src/shared/claude-extension-setup.ts b/src/shared/claude-extension-setup.ts index 22c6304f..9f1a860e 100644 --- a/src/shared/claude-extension-setup.ts +++ b/src/shared/claude-extension-setup.ts @@ -9,7 +9,7 @@ import { getCompositeEnvVars, } from '../cliproxy/config/env-builder'; import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager'; -import { getProxyTarget } from '../cliproxy/proxy-target-resolver'; +import { getProxyTarget } from '../cliproxy/proxy/proxy-target-resolver'; import { generateCopilotEnv } from '../copilot/copilot-executor'; import { generateCursorEnv } from '../cursor'; import InstanceManager from '../management/instance-manager'; diff --git a/src/utils/hooks/get-image-analysis-hook-env.ts b/src/utils/hooks/get-image-analysis-hook-env.ts index d45b218d..8c1777a6 100644 --- a/src/utils/hooks/get-image-analysis-hook-env.ts +++ b/src/utils/hooks/get-image-analysis-hook-env.ts @@ -9,13 +9,13 @@ import { getImageAnalysisConfig } from '../../config/unified-config-loader'; import { resolveCliproxyBridgeProfile } from '../../api/services/cliproxy-profile-bridge'; -import { getEffectiveApiKey } from '../../cliproxy/auth-token-manager'; +import { getEffectiveApiKey } from '../../cliproxy/auth/auth-token-manager'; import { mapExternalProviderName } from '../../cliproxy/provider-capabilities'; import { buildProxyUrl, getProxyTarget, type ProxyTarget, -} from '../../cliproxy/proxy-target-resolver'; +} from '../../cliproxy/proxy/proxy-target-resolver'; import { getPromptsDir } from '../image-analysis/hook-installer'; import { resolveImageAnalysisStatus, diff --git a/src/utils/hooks/image-analysis-backend-resolver.ts b/src/utils/hooks/image-analysis-backend-resolver.ts index 5f04ed4a..229d6e11 100644 --- a/src/utils/hooks/image-analysis-backend-resolver.ts +++ b/src/utils/hooks/image-analysis-backend-resolver.ts @@ -8,7 +8,7 @@ import { mapExternalProviderName, } from '../../cliproxy/provider-capabilities'; import { getProviderCatalog, supportsNativeImageInput } from '../../cliproxy/model-catalog'; -import { extractProviderFromPathname } from '../../cliproxy/model-id-normalizer'; +import { extractProviderFromPathname } from '../../cliproxy/ai-providers/model-id-normalizer'; import type { CliproxyBridgeMetadata } from '../../api/services/profile-types'; import type { Settings } from '../../types/config'; import type { ProfileType } from '../../types/profile'; diff --git a/src/utils/hooks/image-analysis-runtime-status.ts b/src/utils/hooks/image-analysis-runtime-status.ts index 5a4d938e..4d5c7028 100644 --- a/src/utils/hooks/image-analysis-runtime-status.ts +++ b/src/utils/hooks/image-analysis-runtime-status.ts @@ -1,13 +1,13 @@ -import { getAuthStatus, initializeAccounts, type AuthStatus } from '../../cliproxy/auth-handler'; +import { getAuthStatus, initializeAccounts, type AuthStatus } from '../../cliproxy/auth/auth-handler'; import { checkRemoteProxy, type RemoteProxyClientConfig, type RemoteProxyStatus, -} from '../../cliproxy/remote-proxy-client'; -import { fetchRemoteAuthStatus, type RemoteAuthStatus } from '../../cliproxy/remote-auth-fetcher'; -import { getProxyTarget, type ProxyTarget } from '../../cliproxy/proxy-target-resolver'; +} from '../../cliproxy/services/remote-proxy-client'; +import { fetchRemoteAuthStatus, type RemoteAuthStatus } from '../../cliproxy/services/remote-auth-fetcher'; +import { getProxyTarget, type ProxyTarget } from '../../cliproxy/proxy/proxy-target-resolver'; import { getProviderDisplayName, isCLIProxyProvider } from '../../cliproxy/provider-capabilities'; -import { isCliproxyRunning } from '../../cliproxy/stats-fetcher'; +import { isCliproxyRunning } from '../../cliproxy/services/stats-fetcher'; import type { CLIProxyProvider } from '../../cliproxy/types'; import { DEFAULT_IMAGE_ANALYSIS_CONFIG, diff --git a/src/web-server/health/cliproxy-checks.ts b/src/web-server/health/cliproxy-checks.ts index 92335d6a..6ac21b2e 100644 --- a/src/web-server/health/cliproxy-checks.ts +++ b/src/web-server/health/cliproxy-checks.ts @@ -13,9 +13,9 @@ import { getAllAuthStatus, CLIPROXY_DEFAULT_PORT, } from '../../cliproxy'; -import { detectRunningProxy } from '../../cliproxy/proxy-detector'; +import { detectRunningProxy } from '../../cliproxy/proxy/proxy-detector'; import type { HealthCheck } from './types'; -import { CLIPROXY_MAX_STABLE_VERSION } from '../../cliproxy/platform-detector'; +import { CLIPROXY_MAX_STABLE_VERSION } from '../../cliproxy/binary/platform-detector'; import { isNewerVersion, isVersionFaulty } from '../../cliproxy/binary/version-checker'; /** diff --git a/src/web-server/index.ts b/src/web-server/index.ts index 9f5ff51f..c00b5ae5 100644 --- a/src/web-server/index.ts +++ b/src/web-server/index.ts @@ -13,8 +13,8 @@ import { WebSocketServer } from 'ws'; import { setupWebSocket } from './websocket'; import { createSessionMiddleware, authMiddleware } from './middleware/auth-middleware'; import { requestLoggingMiddleware } from './middleware/request-logging-middleware'; -import { ensureManagedModelPrefixes } from '../cliproxy/managed-model-prefixes'; -import { getProxyTarget } from '../cliproxy/proxy-target-resolver'; +import { ensureManagedModelPrefixes } from '../cliproxy/ai-providers/managed-model-prefixes'; +import { getProxyTarget } from '../cliproxy/proxy/proxy-target-resolver'; import { startAutoSyncWatcher, stopAutoSyncWatcher } from '../cliproxy/sync'; import { shutdownUsageAggregator } from './usage/aggregator'; import { createLogger } from '../services/logging'; diff --git a/src/web-server/overview-routes.ts b/src/web-server/overview-routes.ts index 2b064ce8..d0c0586f 100644 --- a/src/web-server/overview-routes.ts +++ b/src/web-server/overview-routes.ts @@ -7,7 +7,7 @@ import { Router, Request, Response } from 'express'; import { loadConfigSafe } from '../utils/config-manager'; import { runHealthChecks } from './health-service'; -import { getAllAuthStatus, initializeAccounts } from '../cliproxy/auth-handler'; +import { getAllAuthStatus, initializeAccounts } from '../cliproxy/auth/auth-handler'; import { getVersion } from '../utils/version'; import ProfileRegistry from '../auth/profile-registry'; diff --git a/src/web-server/routes/account-routes.ts b/src/web-server/routes/account-routes.ts index 07137831..0ae56c1d 100644 --- a/src/web-server/routes/account-routes.ts +++ b/src/web-server/routes/account-routes.ts @@ -17,7 +17,7 @@ import { bulkPauseAccounts, bulkResumeAccounts, soloAccount, -} from '../../cliproxy/account-manager'; +} from '../../cliproxy/accounts/account-manager'; import { formatAccountDisplayName } from '../../cliproxy/accounts/email-account-identity'; import { isCLIProxyProvider } from '../../cliproxy/provider-capabilities'; import { diff --git a/src/web-server/routes/catalog-routes.ts b/src/web-server/routes/catalog-routes.ts index ea27811b..b0771e9f 100644 --- a/src/web-server/routes/catalog-routes.ts +++ b/src/web-server/routes/catalog-routes.ts @@ -1,5 +1,5 @@ import { Router, Request, Response } from 'express'; -import { getCatalogRoutingSnapshot } from '../../cliproxy/catalog-routing'; +import { getCatalogRoutingSnapshot } from '../../cliproxy/services/catalog-routing'; const router = Router(); diff --git a/src/web-server/routes/cliproxy-auth-routes.ts b/src/web-server/routes/cliproxy-auth-routes.ts index 6e12f5fa..009ac005 100644 --- a/src/web-server/routes/cliproxy-auth-routes.ts +++ b/src/web-server/routes/cliproxy-auth-routes.ts @@ -4,16 +4,16 @@ import { getOAuthConfig, initializeAccounts, triggerOAuth, -} from '../../cliproxy/auth-handler'; +} from '../../cliproxy/auth/auth-handler'; import { submitProjectSelection, getPendingSelection, -} from '../../cliproxy/project-selection-handler'; +} from '../../cliproxy/auth/project-selection-handler'; import { cancelAllSessionsForProvider, hasActiveSession, -} from '../../cliproxy/auth-session-manager'; -import { fetchCliproxyStats } from '../../cliproxy/stats-fetcher'; +} from '../../cliproxy/auth/auth-session-manager'; +import { fetchCliproxyStats } from '../../cliproxy/services/stats-fetcher'; import { getAllAccountsSummary, getProviderAccounts, @@ -25,15 +25,15 @@ import { hasAccountNameConflict, PROVIDERS_WITHOUT_EMAIL, validateNickname, -} from '../../cliproxy/account-manager'; +} from '../../cliproxy/accounts/account-manager'; import { getProxyTarget, buildProxyUrl, buildManagementHeaders, -} from '../../cliproxy/proxy-target-resolver'; -import { fetchRemoteAuthStatus } from '../../cliproxy/remote-auth-fetcher'; -import { ensureManagedModelPrefixes } from '../../cliproxy/managed-model-prefixes'; -import { invalidateQuotaCache } from '../../cliproxy/quota-response-cache'; +} from '../../cliproxy/proxy/proxy-target-resolver'; +import { fetchRemoteAuthStatus } from '../../cliproxy/services/remote-auth-fetcher'; +import { ensureManagedModelPrefixes } from '../../cliproxy/ai-providers/managed-model-prefixes'; +import { invalidateQuotaCache } from '../../cliproxy/quota/quota-response-cache'; import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader'; import { tryKiroImport } from '../../cliproxy/auth/kiro-import'; import { @@ -62,7 +62,7 @@ import { CLIPROXY_PROFILES } from '../../auth/profile-detector'; import { validateAntigravityRiskAcknowledgement, isAntigravityResponsibilityBypassEnabled, -} from '../../cliproxy/antigravity-responsibility'; +} from '../../cliproxy/auth/antigravity-responsibility'; import { createRouteErrorHelpers } from './route-helpers'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; diff --git a/src/web-server/routes/cliproxy-routing-routes.ts b/src/web-server/routes/cliproxy-routing-routes.ts index 0fa1c987..e9bf9e22 100644 --- a/src/web-server/routes/cliproxy-routing-routes.ts +++ b/src/web-server/routes/cliproxy-routing-routes.ts @@ -7,7 +7,7 @@ import { normalizeCliproxySessionAffinityTtl, readCliproxyRoutingState, readCliproxySessionAffinityState, -} from '../../cliproxy/routing-strategy'; +} from '../../cliproxy/routing/routing-strategy'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; const router = Router(); diff --git a/src/web-server/routes/cliproxy-stats-routes.ts b/src/web-server/routes/cliproxy-stats-routes.ts index 2bf87cc6..f9430e8c 100644 --- a/src/web-server/routes/cliproxy-stats-routes.ts +++ b/src/web-server/routes/cliproxy-stats-routes.ts @@ -15,27 +15,27 @@ import { isCliproxyRunning, fetchCliproxyErrorLogs, fetchCliproxyErrorLogContent, -} from '../../cliproxy/stats-fetcher'; -import { fetchAccountQuota } from '../../cliproxy/quota-fetcher'; -import { fetchCodexQuota } from '../../cliproxy/quota-fetcher-codex'; -import { fetchClaudeQuota } from '../../cliproxy/quota-fetcher-claude'; -import { fetchGeminiCliQuota } from '../../cliproxy/quota-fetcher-gemini-cli'; -import { fetchGhcpQuota } from '../../cliproxy/quota-fetcher-ghcp'; -import { getCachedQuota, setCachedQuota } from '../../cliproxy/quota-response-cache'; +} from '../../cliproxy/services/stats-fetcher'; +import { fetchAccountQuota } from '../../cliproxy/quota/quota-fetcher'; +import { fetchCodexQuota } from '../../cliproxy/quota/quota-fetcher-codex'; +import { fetchClaudeQuota } from '../../cliproxy/quota/quota-fetcher-claude'; +import { fetchGeminiCliQuota } from '../../cliproxy/quota/quota-fetcher-gemini-cli'; +import { fetchGhcpQuota } from '../../cliproxy/quota/quota-fetcher-ghcp'; +import { getCachedQuota, setCachedQuota } from '../../cliproxy/quota/quota-response-cache'; import type { CodexQuotaResult, ClaudeQuotaResult, GeminiCliQuotaResult, GhcpQuotaResult, -} from '../../cliproxy/quota-types'; -import type { QuotaResult } from '../../cliproxy/quota-fetcher'; +} from '../../cliproxy/quota/quota-types'; +import type { QuotaResult } from '../../cliproxy/quota/quota-fetcher'; import type { CLIProxyProvider } from '../../cliproxy/types'; import { CLIPROXY_PROFILES } from '../../auth/profile-detector'; import { getCliproxyWritablePath, getCliproxyConfigPath, getAuthDir, -} from '../../cliproxy/config-generator'; +} from '../../cliproxy/config/config-generator'; import { getProxyStatus as getProxyProcessStatus, stopProxy } from '../../cliproxy/session-tracker'; import { ensureCliproxyService } from '../../cliproxy/service-manager'; import { @@ -51,13 +51,13 @@ import { import { CLIPROXY_MAX_STABLE_VERSION, CLIPROXY_FAULTY_RANGE, -} from '../../cliproxy/platform-detector'; +} from '../../cliproxy/binary/platform-detector'; import { CLIPROXY_DEFAULT_PORT } from '../../cliproxy/config/port-manager'; import { MODEL_ENV_VAR_KEYS, canonicalizeModelIdForProvider, getDeniedModelIdReasonForProvider, -} from '../../cliproxy/model-id-normalizer'; +} from '../../cliproxy/ai-providers/model-id-normalizer'; import { installDashboardCliproxyVersion } from '../services/cliproxy-dashboard-install-service'; import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware'; diff --git a/src/web-server/routes/image-analysis-routes.ts b/src/web-server/routes/image-analysis-routes.ts index 70a76480..22f21c47 100644 --- a/src/web-server/routes/image-analysis-routes.ts +++ b/src/web-server/routes/image-analysis-routes.ts @@ -12,7 +12,7 @@ import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middlewar import { expandPath } from '../../utils/helpers'; import { loadSettings } from '../../utils/config-manager'; import type { Settings } from '../../types/config'; -import { extractProviderFromPathname } from '../../cliproxy/model-id-normalizer'; +import { extractProviderFromPathname } from '../../cliproxy/ai-providers/model-id-normalizer'; import { normalizeImageAnalysisBackendId, resolveImageAnalysisRuntimeStatus, diff --git a/src/web-server/routes/provider-routes.ts b/src/web-server/routes/provider-routes.ts index 4b91125c..2f3f4600 100644 --- a/src/web-server/routes/provider-routes.ts +++ b/src/web-server/routes/provider-routes.ts @@ -11,7 +11,7 @@ import { removeOpenAICompatProvider, OPENROUTER_TEMPLATE, TOGETHER_TEMPLATE, -} from '../../cliproxy/openai-compat-manager'; +} from '../../cliproxy/ai-providers/openai-compat-manager'; import { isReservedName, RESERVED_PROFILE_NAMES } from '../../config/reserved-names'; const router = Router(); diff --git a/src/web-server/routes/proxy-routes.ts b/src/web-server/routes/proxy-routes.ts index 3b6a34d7..22100e42 100644 --- a/src/web-server/routes/proxy-routes.ts +++ b/src/web-server/routes/proxy-routes.ts @@ -9,9 +9,9 @@ import { Router, Request, Response } from 'express'; import { loadOrCreateUnifiedConfig, mutateUnifiedConfig } from '../../config/unified-config-loader'; -import { testConnection } from '../../cliproxy/remote-proxy-client'; +import { testConnection } from '../../cliproxy/services/remote-proxy-client'; import { isProxyRunning } from '../../cliproxy/services/proxy-lifecycle-service'; -import { DEFAULT_BACKEND } from '../../cliproxy/platform-detector'; +import { DEFAULT_BACKEND } from '../../cliproxy/binary/platform-detector'; import { DEFAULT_CLIPROXY_SERVER_CONFIG, CliproxyServerConfig, diff --git a/src/web-server/routes/route-helpers.ts b/src/web-server/routes/route-helpers.ts index 3836711f..3251a064 100644 --- a/src/web-server/routes/route-helpers.ts +++ b/src/web-server/routes/route-helpers.ts @@ -14,7 +14,7 @@ import { canonicalizeModelIdForProvider, extractProviderFromPathname, getDeniedModelIdReasonForProvider, -} from '../../cliproxy/model-id-normalizer'; +} from '../../cliproxy/ai-providers/model-id-normalizer'; import type { CLIProxyProvider } from '../../cliproxy/types'; import type { Config, Settings } from '../../types/config'; import type { TargetType } from '../../targets/target-adapter'; diff --git a/src/web-server/routes/settings-routes.ts b/src/web-server/routes/settings-routes.ts index 6ffbed54..0bed44be 100644 --- a/src/web-server/routes/settings-routes.ts +++ b/src/web-server/routes/settings-routes.ts @@ -17,7 +17,7 @@ import { setGlobalManagementSecret, resetAuthToDefaults, } from '../../cliproxy'; -import { regenerateConfig } from '../../cliproxy/config-generator'; +import { regenerateConfig } from '../../cliproxy/config/config-generator'; import { deduplicateCcsHooks } from '../../utils/websearch/hook-utils'; import { removeCcsImageAnalyzerHooks } from '../../utils/hooks/image-analyzer-hook-utils'; import { resolveCliproxyBridgeMetadata } from '../../api/services'; @@ -36,7 +36,7 @@ import { canonicalizeModelIdForProvider, extractProviderFromPathname, getDeniedModelIdReasonForProvider, -} from '../../cliproxy/model-id-normalizer'; +} from '../../cliproxy/ai-providers/model-id-normalizer'; import { createRouteErrorHelpers } from './route-helpers'; import { getImageAnalysisProfileSettingsPath, diff --git a/src/web-server/routes/variant-routes.ts b/src/web-server/routes/variant-routes.ts index c67d3858..caace760 100644 --- a/src/web-server/routes/variant-routes.ts +++ b/src/web-server/routes/variant-routes.ts @@ -21,7 +21,7 @@ import { import { validateCompositeDefaultTier, validateCompositeTiers, -} from '../../cliproxy/composite-validator'; +} from '../../cliproxy/config/composite-validator'; const router = Router(); diff --git a/src/web-server/services/cliproxy-dashboard-install-service.ts b/src/web-server/services/cliproxy-dashboard-install-service.ts index f6b9b361..725c6389 100644 --- a/src/web-server/services/cliproxy-dashboard-install-service.ts +++ b/src/web-server/services/cliproxy-dashboard-install-service.ts @@ -1,7 +1,7 @@ import { installCliproxyVersion, resolveLocalBackend } from '../../cliproxy/binary-manager'; import { ensureCliproxyService, type ServiceStartResult } from '../../cliproxy/service-manager'; import { getProxyStatus as getProxyProcessStatus } from '../../cliproxy/session-tracker'; -import { isCliproxyRunning } from '../../cliproxy/stats-fetcher'; +import { isCliproxyRunning } from '../../cliproxy/services/stats-fetcher'; import type { CLIProxyBackend } from '../../cliproxy/types'; import { isRunningUnderSupervisord, diff --git a/src/web-server/usage/cliproxy-usage-syncer.ts b/src/web-server/usage/cliproxy-usage-syncer.ts index db0ad837..6ab48cc7 100644 --- a/src/web-server/usage/cliproxy-usage-syncer.ts +++ b/src/web-server/usage/cliproxy-usage-syncer.ts @@ -10,7 +10,7 @@ import * as fs from 'fs'; import * as path from 'path'; -import { fetchCliproxyUsageRaw } from '../../cliproxy/stats-fetcher'; +import { fetchCliproxyUsageRaw } from '../../cliproxy/services/stats-fetcher'; import { buildCliproxyUsageHistoryAggregates, extractCliproxyUsageHistoryDetails, diff --git a/src/web-server/usage/cliproxy-usage-transformer.ts b/src/web-server/usage/cliproxy-usage-transformer.ts index 92ddbfbb..8b9c59b4 100644 --- a/src/web-server/usage/cliproxy-usage-transformer.ts +++ b/src/web-server/usage/cliproxy-usage-transformer.ts @@ -5,7 +5,7 @@ * types compatible with the CCS analytics dashboard. */ -import type { CliproxyUsageApiResponse, CliproxyRequestDetail } from '../../cliproxy/stats-fetcher'; +import type { CliproxyUsageApiResponse, CliproxyRequestDetail } from '../../cliproxy/services/stats-fetcher'; import { calculateCost } from '../model-pricing'; import type { ModelBreakdown, DailyUsage, HourlyUsage, MonthlyUsage } from './types'; import { getModelsUsed, normalizeUsageProvider } from './model-identity'; diff --git a/src/web-server/websocket.ts b/src/web-server/websocket.ts index b99710ce..2246299c 100644 --- a/src/web-server/websocket.ts +++ b/src/web-server/websocket.ts @@ -10,8 +10,8 @@ import { createFileWatcher, FileChangeEvent } from './file-watcher'; import { projectSelectionEvents, type ProjectSelectionPrompt, -} from '../cliproxy/project-selection-handler'; -import { deviceCodeEvents, type DeviceCodePrompt } from '../cliproxy/device-code-handler'; +} from '../cliproxy/auth/project-selection-handler'; +import { deviceCodeEvents, type DeviceCodePrompt } from '../cliproxy/auth/device-code-handler'; import { createLogger } from '../services/logging'; const logger = createLogger('web-server:websocket'); diff --git a/tests/unit/commands/cleanup-command.test.ts b/tests/unit/commands/cleanup-command.test.ts index 1c560762..7f234dae 100644 --- a/tests/unit/commands/cleanup-command.test.ts +++ b/tests/unit/commands/cleanup-command.test.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { handleCleanupCommand } from '../../../src/commands/cleanup-command'; -import { getCliproxyDir } from '../../../src/cliproxy/config-generator'; +import { getCliproxyDir } from '../../../src/cliproxy/config/config-generator'; import { getLogArchiveDir, getNativeLogsDir } from '../../../src/services/logging'; describe('cleanup command', () => { diff --git a/tests/unit/utils/hooks/image-analysis-runtime-status-circular-dependency.test.ts b/tests/unit/utils/hooks/image-analysis-runtime-status-circular-dependency.test.ts index d0b669fd..d6060612 100644 --- a/tests/unit/utils/hooks/image-analysis-runtime-status-circular-dependency.test.ts +++ b/tests/unit/utils/hooks/image-analysis-runtime-status-circular-dependency.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'bun:test'; import { readFileSync } from 'fs'; import { dirname } from 'path'; import type { ImageAnalysisStatus } from '../../../../src/utils/hooks/image-analysis-backend-resolver'; -import type { AuthStatus } from '../../../../src/cliproxy/auth-handler'; +import type { AuthStatus } from '../../../../src/cliproxy/auth/auth-handler'; import { ModuleKind, ScriptTarget, @@ -67,14 +67,14 @@ describe('image-analysis-runtime-status circular dependency regression', () => { const module = { exports: {} as Record }; const requireMap: Record = { - '../../cliproxy/auth-handler': authHandlerModule, - '../../cliproxy/remote-proxy-client': { + '../../cliproxy/auth/auth-handler': authHandlerModule, + '../../cliproxy/services/remote-proxy-client': { checkRemoteProxy: async () => ({ reachable: false, error: 'not-used' }), }, - '../../cliproxy/remote-auth-fetcher': { + '../../cliproxy/services/remote-auth-fetcher': { fetchRemoteAuthStatus: async () => [], }, - '../../cliproxy/proxy-target-resolver': { + '../../cliproxy/proxy/proxy-target-resolver': { getProxyTarget: () => ({ host: '127.0.0.1', port: 8317, @@ -86,7 +86,7 @@ describe('image-analysis-runtime-status circular dependency regression', () => { getProviderDisplayName: () => 'GitHub Copilot (OAuth)', isCLIProxyProvider: () => true, }, - '../../cliproxy/stats-fetcher': { + '../../cliproxy/services/stats-fetcher': { isCliproxyRunning: async () => true, }, '../../config/unified-config-types': {