ai-code-switcher 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-code-switcher
3
+ Version: 0.1.0
4
+ Summary: Switch AI coding tool profiles and launch the correct CLI
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.8
7
+ Requires-Dist: pyyaml>=5.0
@@ -0,0 +1,98 @@
1
+ # code-ai
2
+
3
+ 一个用于切换 AI 编码工具配置文件并启动相应 CLI 的工具。
4
+
5
+ ## 功能特性
6
+
7
+ - 管理多个 AI 编码工具配置文件(Claude、Codex、Gemini)
8
+ - 快速切换不同的配置文件
9
+ - 统一的命令行接口
10
+ - 支持一键升级所有 AI CLI 工具
11
+
12
+ ## 安装
13
+
14
+ ```bash
15
+ pip install -e .
16
+ ```
17
+
18
+ ## 使用方法
19
+
20
+ ### 列出所有配置文件
21
+
22
+ ```bash
23
+ code-ai list
24
+ ```
25
+
26
+ ### 添加新配置文件
27
+
28
+ ```bash
29
+ code-ai add
30
+ ```
31
+
32
+ ### 使用指定配置文件启动
33
+
34
+ ```bash
35
+ # 使用 fox-gemini 配置启动 Gemini CLI
36
+ code-ai fox-gemini
37
+
38
+ # 使用 4399 配置启动 Claude CLI
39
+ code-ai 4399
40
+
41
+ # 传递额外参数
42
+ code-ai fox-claude -p "hi"
43
+ ```
44
+
45
+ ### 删除配置文件
46
+
47
+ ```bash
48
+ code-ai remove <profile-name>
49
+ ```
50
+
51
+ ### 升级 AI CLI 工具
52
+
53
+ ```bash
54
+ code-ai upgrade
55
+ ```
56
+
57
+ 该命令会通过 npm 升级以下工具:
58
+ - @anthropic-ai/claude-code
59
+ - @openai/codex
60
+ - @google/gemini-cli
61
+
62
+ ### 查看版本
63
+
64
+ ```bash
65
+ code-ai --version
66
+ ```
67
+
68
+ ### 查看帮助
69
+
70
+ ```bash
71
+ code-ai --help
72
+ ```
73
+
74
+ ## 配置
75
+
76
+ 配置文件存储在用户目录下,包含各个配置文件的设置信息。
77
+
78
+ ## 开发
79
+
80
+ ### 项目结构
81
+
82
+ ```
83
+ src/code_ai/
84
+ ├── __init__.py # 包初始化
85
+ ├── cli.py # 命令行入口
86
+ ├── config.py # 配置管理
87
+ ├── launcher.py # 启动器
88
+ └── profiles.py # 配置文件管理
89
+ ```
90
+
91
+ ### 依赖
92
+
93
+ - Python >= 3.8
94
+ - pyyaml >= 5.0
95
+
96
+ ## 许可证
97
+
98
+ MIT
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ai-code-switcher"
7
+ version = "0.1.0"
8
+ description = "Switch AI coding tool profiles and launch the correct CLI"
9
+ license = "MIT"
10
+ requires-python = ">=3.8"
11
+ dependencies = [
12
+ "pyyaml>=5.0",
13
+ ]
14
+
15
+ [project.scripts]
16
+ code-ai = "code_ai.cli:main"
17
+
18
+ [tool.setuptools.packages.find]
19
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-code-switcher
3
+ Version: 0.1.0
4
+ Summary: Switch AI coding tool profiles and launch the correct CLI
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.8
7
+ Requires-Dist: pyyaml>=5.0
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/ai_code_switcher.egg-info/PKG-INFO
4
+ src/ai_code_switcher.egg-info/SOURCES.txt
5
+ src/ai_code_switcher.egg-info/dependency_links.txt
6
+ src/ai_code_switcher.egg-info/entry_points.txt
7
+ src/ai_code_switcher.egg-info/requires.txt
8
+ src/ai_code_switcher.egg-info/top_level.txt
9
+ src/code_ai/__init__.py
10
+ src/code_ai/cli.py
11
+ src/code_ai/config.py
12
+ src/code_ai/launcher.py
13
+ src/code_ai/profiles.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ code-ai = code_ai.cli:main
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,77 @@
1
+ import sys
2
+ import subprocess
3
+
4
+ from .config import load_config, save_config
5
+ from .profiles import list_profiles, add_profile, remove_profile
6
+ from .launcher import launch
7
+
8
+
9
+ USAGE = """\
10
+ usage: code-ai <profile|command> [args...]
11
+
12
+ commands:
13
+ list List all profiles
14
+ add Add a new profile interactively
15
+ upgrade Upgrade claude, codex, and gemini CLI via npm
16
+ remove <name> Remove a profile
17
+ --version Show version
18
+ --help Show this help
19
+
20
+ examples:
21
+ code-ai fox-gemini Launch Gemini CLI with fox profile
22
+ code-ai 4399 Launch Claude CLI with 4399 profile
23
+ code-ai fox-claude -p "hi" Pass extra args to Claude CLI\
24
+ """
25
+
26
+
27
+ def main():
28
+ args = sys.argv[1:]
29
+
30
+ if not args or args[0] in ("-h", "--help"):
31
+ print(USAGE)
32
+ return
33
+
34
+ if args[0] == "--version":
35
+ from . import __version__
36
+ print(f"code-ai {__version__}")
37
+ return
38
+
39
+ cmd = args[0]
40
+ config = load_config()
41
+
42
+ if cmd == "list":
43
+ list_profiles(config)
44
+ elif cmd == "add":
45
+ config = add_profile(config)
46
+ save_config(config)
47
+ print("Profile added.")
48
+ elif cmd == "upgrade":
49
+ upgrade()
50
+ elif cmd == "remove":
51
+ if len(args) < 2:
52
+ print("Usage: code-ai remove <name>")
53
+ sys.exit(1)
54
+ config = remove_profile(config, args[1])
55
+ save_config(config)
56
+ else:
57
+ profiles = config.get("profiles", {})
58
+ if cmd not in profiles:
59
+ print(f"Unknown profile or command: '{cmd}'")
60
+ print("Run 'code-ai list' to see available profiles.")
61
+ sys.exit(1)
62
+ launch(profiles[cmd], args[1:])
63
+
64
+
65
+ UPGRADE_PACKAGES = [
66
+ "@anthropic-ai/claude-code",
67
+ "@openai/codex",
68
+ "@google/gemini-cli",
69
+ ]
70
+
71
+
72
+ def upgrade():
73
+ print("Upgrading claude, codex, gemini CLI...")
74
+ result = subprocess.run(
75
+ ["npm", "install", "-g"] + UPGRADE_PACKAGES,
76
+ )
77
+ sys.exit(result.returncode)
@@ -0,0 +1,56 @@
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ import yaml
6
+
7
+ CONFIG_DIR = Path.home() / ".code-ai"
8
+ CONFIG_FILE = CONFIG_DIR / "config.yaml"
9
+
10
+ DEFAULT_PROFILES = {
11
+ "fox-claude": {
12
+ "type": "claude",
13
+ "base_url": "https://code.newcli.com/claude/aws",
14
+ "token": "sk-ant-oat01-j6FU43eI3djEeLFWcw_2mtngnBqwSEsOXMYkJtidPDxeCiqIeaTtHg6p12wvi7HaYIsp7VsK5kVbdwYlBW_mCBnSYmZ-qAA",
15
+ },
16
+ "fox-gemini": {
17
+ "type": "gemini",
18
+ "base_url": "https://code.newcli.com/gemini",
19
+ "api_key": "sk-ant-oat01-j6FU43eI3djEeLFWcw_2mtngnBqwSEsOXMYkJtidPDxeCiqIeaTtHg6p12wvi7HaYIsp7VsK5kVbdwYlBW_mCBnSYmZ-qAA",
20
+ },
21
+ "fox-codex": {
22
+ "type": "codex",
23
+ "base_url": "https://code.newcli.com/codex/v1",
24
+ "api_key": "sk-ant-oat01-j6FU43eI3djEeLFWcw_2mtngnBqwSEsOXMYkJtidPDxeCiqIeaTtHg6p12wvi7HaYIsp7VsK5kVbdwYlBW_mCBnSYmZ-qAA",
25
+ },
26
+ "4399": {
27
+ "type": "claude",
28
+ "base_url": "https://4399code.com/claudecode",
29
+ "token": "sk-ant-oat01-ozUCp9rqL9sB46GoG5ISB1QPmlQPKZyk",
30
+ },
31
+ "2233": {
32
+ "type": "claude",
33
+ "base_url": "https://aicoding.2233.ai",
34
+ "token": "sk-Xn6481958ee796a17126b676467f0e06d5e6f39ac14Uusba",
35
+ },
36
+ }
37
+
38
+
39
+ def load_config():
40
+ if not CONFIG_FILE.exists():
41
+ init_config()
42
+ with open(CONFIG_FILE, "r", encoding="utf-8") as f:
43
+ data = yaml.safe_load(f)
44
+ if not data or "profiles" not in data:
45
+ data = {"profiles": {}}
46
+ return data
47
+
48
+
49
+ def save_config(data):
50
+ os.makedirs(CONFIG_DIR, exist_ok=True)
51
+ with open(CONFIG_FILE, "w", encoding="utf-8") as f:
52
+ yaml.dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
53
+
54
+
55
+ def init_config():
56
+ save_config({"profiles": DEFAULT_PROFILES})
@@ -0,0 +1,48 @@
1
+ import os
2
+ import sys
3
+ import shutil
4
+ import subprocess
5
+
6
+ ENV_MAP = {
7
+ "claude": {
8
+ "env": {"ANTHROPIC_BASE_URL": "base_url", "ANTHROPIC_AUTH_TOKEN": "token"},
9
+ "cmd": "claude",
10
+ },
11
+ "gemini": {
12
+ "env": {"GOOGLE_GEMINI_BASE_URL": "base_url", "GEMINI_API_KEY": "api_key"},
13
+ "cmd": "gemini",
14
+ },
15
+ "codex": {
16
+ "env": {"OPENAI_BASE_URL": "base_url", "OPENAI_API_KEY": "api_key"},
17
+ "cmd": "codex",
18
+ },
19
+ }
20
+
21
+
22
+ def launch(profile, extra_args):
23
+ ptype = profile["type"]
24
+ if ptype not in ENV_MAP:
25
+ print(f"Error: unknown profile type '{ptype}'.")
26
+ sys.exit(1)
27
+
28
+ spec = ENV_MAP[ptype]
29
+ cmd = spec["cmd"]
30
+
31
+ if not shutil.which(cmd):
32
+ print(f"Error: '{cmd}' not found in PATH. Install it first.")
33
+ sys.exit(1)
34
+
35
+ env = os.environ.copy()
36
+ for env_var, config_key in spec["env"].items():
37
+ value = profile.get(config_key)
38
+ if value:
39
+ env[env_var] = value
40
+
41
+ full_cmd = [cmd] + extra_args
42
+
43
+ if sys.platform == "win32":
44
+ result = subprocess.run(full_cmd, env=env)
45
+ sys.exit(result.returncode)
46
+ else:
47
+ os.environ.update(env)
48
+ os.execvp(cmd, full_cmd)
@@ -0,0 +1,61 @@
1
+ import sys
2
+
3
+
4
+ VALID_TYPES = ("claude", "gemini", "codex")
5
+
6
+
7
+ def list_profiles(config):
8
+ profiles = config.get("profiles", {})
9
+ if not profiles:
10
+ print("No profiles configured.")
11
+ return
12
+ print(f"{'Name':<20} {'Type':<10} {'Base URL'}")
13
+ print("-" * 60)
14
+ for name, p in profiles.items():
15
+ print(f"{name:<20} {p['type']:<10} {p.get('base_url', '')}")
16
+
17
+
18
+ def add_profile(config):
19
+ name = input("Profile name: ").strip()
20
+ if not name:
21
+ print("Error: name cannot be empty.")
22
+ sys.exit(1)
23
+ if name in config.get("profiles", {}):
24
+ print(f"Error: profile '{name}' already exists.")
25
+ sys.exit(1)
26
+
27
+ ptype = input(f"Type ({'/'.join(VALID_TYPES)}): ").strip().lower()
28
+ if ptype not in VALID_TYPES:
29
+ print(f"Error: type must be one of {VALID_TYPES}.")
30
+ sys.exit(1)
31
+
32
+ base_url = input("Base URL: ").strip()
33
+ if not base_url:
34
+ print("Error: base URL cannot be empty.")
35
+ sys.exit(1)
36
+
37
+ if ptype == "claude":
38
+ token = input("Auth token: ").strip()
39
+ config.setdefault("profiles", {})[name] = {
40
+ "type": ptype,
41
+ "base_url": base_url,
42
+ "token": token,
43
+ }
44
+ else:
45
+ api_key = input("API key: ").strip()
46
+ config.setdefault("profiles", {})[name] = {
47
+ "type": ptype,
48
+ "base_url": base_url,
49
+ "api_key": api_key,
50
+ }
51
+
52
+ return config
53
+
54
+
55
+ def remove_profile(config, name):
56
+ if name not in config.get("profiles", {}):
57
+ print(f"Error: profile '{name}' not found.")
58
+ sys.exit(1)
59
+ del config["profiles"][name]
60
+ print(f"Removed profile '{name}'.")
61
+ return config