ccoding 0.2.5__tar.gz → 0.4.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.
- {ccoding-0.2.5 → ccoding-0.4.0}/CLAUDE.md +3 -3
- {ccoding-0.2.5 → ccoding-0.4.0}/PKG-INFO +4 -3
- {ccoding-0.2.5 → ccoding-0.4.0}/README.md +2 -1
- {ccoding-0.2.5 → ccoding-0.4.0}/pyproject.toml +1 -1
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/__init__.py +1 -1
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/api.py +13 -6
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/config.py +19 -10
- ccoding-0.4.0/src/ccode/env_schema.json +2214 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/remote.py +1 -1
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/ui.py +24 -1
- {ccoding-0.2.5 → ccoding-0.4.0}/uv.lock +1 -1
- ccoding-0.2.5/src/ccode/env_schema.json +0 -979
- {ccoding-0.2.5 → ccoding-0.4.0}/.github/workflows/publish.yml +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/.gitignore +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/LICENSE +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/screenshot.png +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/screenshot_mobile1.jpeg +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/screenshot_mobile2.jpeg +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/__main__.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/cli.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/logo.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/remote_cli.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/remote_client.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/remote_common.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/remote_server.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/__init__.py +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/app.js +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/assets/addon-fit.js +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/assets/xterm-LICENSE +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/assets/xterm-addon-fit-LICENSE +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/assets/xterm.css +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/assets/xterm.js +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/index.html +0 -0
- {ccoding-0.2.5 → ccoding-0.4.0}/src/ccode/web/style.css +0 -0
|
@@ -24,14 +24,14 @@ uv build # 构建 wheel / sdist
|
|
|
24
24
|
- **`config.py`** — 所有持久化逻辑。配置文件路径 `~/.ccode/config.json`。`toggles` 字段存储任意环境变量键值对(`dict[str, str]`)。提供 `load_env_schema()` / `env_schema_keys()` / `env_schema_description()` / `env_schema_enum()` 四个函数,从 `env_schema.json` 读取已知变量的元数据。
|
|
25
25
|
- **`api.py`** — 无状态函数层:HTTP 拉取 `/v1/models`、构建启动环境变量 `build_env()`、调用 `subprocess.run(["claude", ...])` 启动 claude。
|
|
26
26
|
- **`logo.py`** — LOGOS 数据(3 种 ASCII 字体)及 4 种渲染风格函数(wave / pulse / glitch / rain),接收独立参数,不依赖 `CursesApp`。
|
|
27
|
-
- **`ui.py`** — `CursesApp` 类,持有全部 UI 状态。配置界面的 field 列表由 `_config_fields()` 动态构建(`base_url`、`api_key`、每个 toggle key、`__add__` 新增行),支持运行时增删 toggle。新增 toggle 时 key 输入框实时展示候选列表,Tab 键补全,候选来源为 `env_schema.json`
|
|
27
|
+
- **`ui.py`** — `CursesApp` 类,持有全部 UI 状态。配置界面的 field 列表由 `_config_fields()` 动态构建(`base_url`、`api_key`、每个 toggle key、`__add__` 新增行),支持运行时增删 toggle。新增 toggle 时 key 输入框实时展示候选列表,Tab 键补全,候选来源为 `env_schema.json` 中的已知变量。
|
|
28
28
|
- **`cli.py`** — 入口,`main(argv)` 构造 `CursesApp` 并调用 `curses.wrapper`。
|
|
29
|
-
- **`env_schema.json`** —
|
|
29
|
+
- **`env_schema.json`** — 从官方文档 `https://code.claude.com/docs/en/env-vars` 同步的 Claude Code 环境变量 JSON Schema,含 `description` 和 `enum` 字段,供 UI 补全和提示使用。更新 claude code 版本后重新抓取该页面的变量表并同步此文件的 `properties` 节(仅保留文档未收录的 `CLAUDE_CODE_AUTO_MODE_MODEL` 等本地条目)。
|
|
30
30
|
|
|
31
31
|
## 关键数据流
|
|
32
32
|
|
|
33
33
|
1. `load_config()` 读取 `~/.ccode/config.json`,toggles 值统一为字符串。
|
|
34
|
-
2. 主界面 → `fetch_models()` 拉取可用模型 → 用户选择 opus/sonnet/haiku 的 owned_by 和 model_id
|
|
34
|
+
2. 主界面 → `fetch_models()` 拉取可用模型 → 用户选择 opus/sonnet/haiku/auto 的 owned_by 和 model_id(auto 可选项,对应 `CLAUDE_CODE_AUTO_MODE_MODEL`)。
|
|
35
35
|
3. 启动时 `build_env()` 将 `base_url`、`api_key`、model id、toggles 全部注入环境变量,执行 `claude`。
|
|
36
36
|
4. 配置界面 `ESC` 自动保存后刷新模型列表。
|
|
37
37
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: ccoding
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Curses-based Claude Code launcher
|
|
5
5
|
Project-URL: Homepage, https://github.com/8DE4732A/ccode
|
|
6
6
|
Project-URL: Repository, https://github.com/8DE4732A/ccode
|
|
@@ -194,7 +194,8 @@ uv sync --extra remote # 同时安装 client/server 依赖
|
|
|
194
194
|
"models": {
|
|
195
195
|
"opus": {"owned_by": null, "id": null},
|
|
196
196
|
"sonnet": {"owned_by": null, "id": null},
|
|
197
|
-
"haiku": {"owned_by": null, "id": null}
|
|
197
|
+
"haiku": {"owned_by": null, "id": null},
|
|
198
|
+
"auto": {"owned_by": null, "id": null}
|
|
198
199
|
},
|
|
199
200
|
"toggles": {
|
|
200
201
|
"CLAUDE_CODE_ENABLE_TELEMETRY": "0",
|
|
@@ -143,7 +143,8 @@ uv sync --extra remote # 同时安装 client/server 依赖
|
|
|
143
143
|
"models": {
|
|
144
144
|
"opus": {"owned_by": null, "id": null},
|
|
145
145
|
"sonnet": {"owned_by": null, "id": null},
|
|
146
|
-
"haiku": {"owned_by": null, "id": null}
|
|
146
|
+
"haiku": {"owned_by": null, "id": null},
|
|
147
|
+
"auto": {"owned_by": null, "id": null}
|
|
147
148
|
},
|
|
148
149
|
"toggles": {
|
|
149
150
|
"CLAUDE_CODE_ENABLE_TELEMETRY": "0",
|
|
@@ -7,7 +7,7 @@ import urllib.error
|
|
|
7
7
|
import urllib.request
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
|
-
from .config import MODEL_KEYS, mask_secret
|
|
10
|
+
from .config import MODEL_ENV_VARS, MODEL_KEYS, REQUIRED_MODEL_KEYS, mask_secret
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def _truncate_body(text: str, max_len: int = 200) -> str:
|
|
@@ -107,7 +107,7 @@ def build_env(config: dict[str, Any], masked: bool = False) -> dict[str, str]:
|
|
|
107
107
|
entry = config["models"].get(key, {})
|
|
108
108
|
model_id = entry.get("id")
|
|
109
109
|
if model_id:
|
|
110
|
-
env[
|
|
110
|
+
env[MODEL_ENV_VARS[key]] = model_id
|
|
111
111
|
for key, value in config.get("toggles", {}).items():
|
|
112
112
|
env[key] = str(value)
|
|
113
113
|
return env
|
|
@@ -118,15 +118,22 @@ def validate_launch_requirements(config: dict[str, Any]) -> str | None:
|
|
|
118
118
|
api_key = config.get("api_key", "").strip()
|
|
119
119
|
if not base_url or not api_key:
|
|
120
120
|
return "Base URL and API key are required."
|
|
121
|
-
for key in
|
|
121
|
+
for key in REQUIRED_MODEL_KEYS:
|
|
122
122
|
entry = config["models"].get(key, {})
|
|
123
123
|
if not entry.get("owned_by") or not entry.get("id"):
|
|
124
124
|
return "OPUS, SONNET, and HAIKU selections are required."
|
|
125
125
|
return None
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
SKIP_PERMISSIONS_FLAG = "--allow-dangerously-skip-permissions"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def build_claude_command(config: dict[str, Any], args: list[str]) -> list[str]:
|
|
132
|
+
command = ["claude", *args]
|
|
133
|
+
# args 透传自用户命令行,可能已手动携带该 flag,去重避免重复传参
|
|
134
|
+
if config.get("skip_permissions") and SKIP_PERMISSIONS_FLAG not in command:
|
|
135
|
+
command.append(SKIP_PERMISSIONS_FLAG)
|
|
136
|
+
return command
|
|
130
137
|
|
|
131
138
|
|
|
132
139
|
def launch_claude(config: dict[str, Any], args: list[str]) -> str | None:
|
|
@@ -136,7 +143,7 @@ def launch_claude(config: dict[str, Any], args: list[str]) -> str | None:
|
|
|
136
143
|
return "Missing base URL or API key."
|
|
137
144
|
env = build_env(config, masked=False)
|
|
138
145
|
try:
|
|
139
|
-
subprocess.run(build_claude_command(args), check=True, env=env)
|
|
146
|
+
subprocess.run(build_claude_command(config, args), check=True, env=env)
|
|
140
147
|
except FileNotFoundError:
|
|
141
148
|
return "Could not find 'claude' on PATH."
|
|
142
149
|
except subprocess.CalledProcessError as exc:
|
|
@@ -11,12 +11,20 @@ from typing import Any
|
|
|
11
11
|
CONFIG_DIR = Path.home() / ".ccode"
|
|
12
12
|
CONFIG_PATH = CONFIG_DIR / "config.json"
|
|
13
13
|
DEFAULT_BASE_URL = "http://127.0.0.1:8317"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
14
|
+
# 模型 key 及其对应的环境变量,dict 顺序即主界面展示顺序。
|
|
15
|
+
# auto 对应客户端 auto mode 分类器模型,其余沿用 ANTHROPIC_DEFAULT_<KEY>_MODEL。
|
|
16
|
+
MODEL_ENV_VARS = {
|
|
17
|
+
"opus": "ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
18
|
+
"sonnet": "ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
19
|
+
"haiku": "ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
20
|
+
"auto": "CLAUDE_CODE_AUTO_MODE_MODEL",
|
|
19
21
|
}
|
|
22
|
+
MODEL_KEYS = tuple(MODEL_ENV_VARS)
|
|
23
|
+
MODEL_LABELS = {key: key.upper() for key in MODEL_KEYS}
|
|
24
|
+
|
|
25
|
+
# auto 为可选项,其余模型启动时必选
|
|
26
|
+
OPTIONAL_MODEL_KEYS = ("auto",)
|
|
27
|
+
REQUIRED_MODEL_KEYS = tuple(key for key in MODEL_KEYS if key not in OPTIONAL_MODEL_KEYS)
|
|
20
28
|
|
|
21
29
|
# toggles 的默认值:值统一用字符串存储
|
|
22
30
|
DEFAULT_TOGGLES: dict[str, str] = {
|
|
@@ -85,12 +93,9 @@ def default_config() -> dict[str, Any]:
|
|
|
85
93
|
return {
|
|
86
94
|
"base_url": DEFAULT_BASE_URL,
|
|
87
95
|
"api_key": "",
|
|
88
|
-
"models": {
|
|
89
|
-
"opus": {"owned_by": None, "id": None},
|
|
90
|
-
"sonnet": {"owned_by": None, "id": None},
|
|
91
|
-
"haiku": {"owned_by": None, "id": None},
|
|
92
|
-
},
|
|
96
|
+
"models": {key: {"owned_by": None, "id": None} for key in MODEL_KEYS},
|
|
93
97
|
"toggles": DEFAULT_TOGGLES.copy(),
|
|
98
|
+
"skip_permissions": False,
|
|
94
99
|
"remote": copy.deepcopy(DEFAULT_REMOTE),
|
|
95
100
|
}
|
|
96
101
|
|
|
@@ -223,6 +228,10 @@ def load_config() -> dict[str, Any]:
|
|
|
223
228
|
if new_toggles:
|
|
224
229
|
config["toggles"] = new_toggles
|
|
225
230
|
|
|
231
|
+
skip_permissions = data.get("skip_permissions")
|
|
232
|
+
if isinstance(skip_permissions, bool):
|
|
233
|
+
config["skip_permissions"] = skip_permissions
|
|
234
|
+
|
|
226
235
|
config["remote"] = normalize_remote(data.get("remote"))
|
|
227
236
|
|
|
228
237
|
return config
|