@cc-claw/code 0.6.78 → 0.6.79

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.
package/install.js CHANGED
@@ -122,29 +122,8 @@ function extractZip(buffer, dest) {
122
122
  zip.extractAllTo(dest, true);
123
123
  }
124
124
 
125
- function migrateFromClaudeCode(home = homedir()) {
126
- const claudeSettingsPath = join(home, ".claude", "settings.json");
127
- const ccCodeDir = join(home, ".cc-code");
128
- const ccCodeSettingsPath = join(ccCodeDir, "settings.json");
129
-
130
- // 已有 cc-code 配置,跳过
131
- if (existsSync(ccCodeSettingsPath)) {
132
- return true;
133
- }
134
-
135
- // 无 Claude Code 配置
136
- if (!existsSync(claudeSettingsPath)) {
137
- return false;
138
- }
139
-
140
- let claudeSettings;
141
- try {
142
- claudeSettings = JSON.parse(require("fs").readFileSync(claudeSettingsPath, "utf-8"));
143
- } catch {
144
- return false;
145
- }
146
-
147
- const env = claudeSettings.env || {};
125
+ // 从 Claude Code env 推导应迁移的 provider 列表(含各档模型别名)
126
+ function detectProvidersFromEnv(env) {
148
127
  const providers = [];
149
128
 
150
129
  // 检测 Anthropic
@@ -155,6 +134,7 @@ function migrateFromClaudeCode(home = homedir()) {
155
134
  if (env.ANTHROPIC_DEFAULT_OPUS_MODEL) models.opus = env.ANTHROPIC_DEFAULT_OPUS_MODEL;
156
135
  if (env.ANTHROPIC_DEFAULT_SONNET_MODEL) models.sonnet = env.ANTHROPIC_DEFAULT_SONNET_MODEL;
157
136
  if (env.ANTHROPIC_DEFAULT_HAIKU_MODEL) models.haiku = env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
137
+ if (env.ANTHROPIC_DEFAULT_FABLE_MODEL) models.fable = env.ANTHROPIC_DEFAULT_FABLE_MODEL;
158
138
  const p = {
159
139
  id: "anthropic",
160
140
  type: "anthropic",
@@ -181,8 +161,80 @@ function migrateFromClaudeCode(home = homedir()) {
181
161
  providers.push(p);
182
162
  }
183
163
 
164
+ return providers;
165
+ }
166
+
167
+ // 已有 ~/.cc-code/settings.json 时,按 provider id 增量补齐缺失的模型别名。
168
+ // 只补空缺(undefined / null / 空串),绝不覆盖用户已有值,也不新增 provider。
169
+ // 这样新版本新增的别名(如 fable)能自动补进老配置,而用户的改动(key、baseUrl、
170
+ // thinking 等)与已填别名一律保持原样。
171
+ function backfillModels(ccCodeSettingsPath, detected) {
172
+ let existing;
173
+ try {
174
+ existing = JSON.parse(require("fs").readFileSync(ccCodeSettingsPath, "utf-8"));
175
+ } catch {
176
+ return true; // 读不动就保持原样,不破坏用户配置
177
+ }
178
+
179
+ const providers = existing && existing.config && existing.config.providers;
180
+ if (!Array.isArray(providers)) {
181
+ return true;
182
+ }
183
+
184
+ let changed = false;
185
+ for (const det of detected) {
186
+ if (!det.models) continue;
187
+ const target = providers.find((p) => p && p.id === det.id);
188
+ if (!target) continue; // 找不到同 id provider → 不动(不新增)
189
+ if (!target.models || typeof target.models !== "object") {
190
+ target.models = {};
191
+ }
192
+ for (const alias of Object.keys(det.models)) {
193
+ const cur = target.models[alias];
194
+ if (cur === undefined || cur === null || cur === "") {
195
+ target.models[alias] = det.models[alias];
196
+ changed = true;
197
+ }
198
+ }
199
+ }
200
+
201
+ if (changed) {
202
+ writeFileSync(ccCodeSettingsPath, JSON.stringify(existing, null, 2) + "\n");
203
+ console.log("");
204
+ console.log(" Backfilled new model aliases into ~/.cc-code/settings.json");
205
+ }
206
+ return true;
207
+ }
208
+
209
+ function migrateFromClaudeCode(home = homedir()) {
210
+ const claudeSettingsPath = join(home, ".claude", "settings.json");
211
+ const ccCodeDir = join(home, ".cc-code");
212
+ const ccCodeSettingsPath = join(ccCodeDir, "settings.json");
213
+
214
+ const hasCcCode = existsSync(ccCodeSettingsPath);
215
+
216
+ // 无 Claude Code 配置:已有 cc-code 视为成功(无需 Quick Start),否则失败
217
+ if (!existsSync(claudeSettingsPath)) {
218
+ return hasCcCode;
219
+ }
220
+
221
+ let claudeSettings;
222
+ try {
223
+ claudeSettings = JSON.parse(require("fs").readFileSync(claudeSettingsPath, "utf-8"));
224
+ } catch {
225
+ return hasCcCode;
226
+ }
227
+
228
+ const env = claudeSettings.env || {};
229
+ const providers = detectProvidersFromEnv(env);
230
+
184
231
  if (providers.length === 0) {
185
- return false;
232
+ return hasCcCode;
233
+ }
234
+
235
+ // 已有 cc-code 配置 → 增量补齐缺失别名(不覆盖、不新增 provider)
236
+ if (hasCcCode) {
237
+ return backfillModels(ccCodeSettingsPath, providers);
186
238
  }
187
239
 
188
240
  if (!existsSync(ccCodeDir)) {
package/install.test.js CHANGED
@@ -43,17 +43,68 @@ test("migrateFromClaudeCode returns false when no claude settings exist", (home)
43
43
  if (result !== false) throw new Error("expected false");
44
44
  });
45
45
 
46
- test("migrateFromClaudeCode skips when cc-code settings already exist", (home) => {
46
+ test("migrateFromClaudeCode backfills missing aliases when cc-code settings already exist", (home) => {
47
47
  const ccCodeDir = join(home, ".cc-code");
48
48
  fs.mkdirSync(ccCodeDir, { recursive: true });
49
- fs.writeFileSync(join(ccCodeDir, "settings.json"), JSON.stringify({ config: {} }));
50
- writeClaudeSettings(home, { env: { ANTHROPIC_API_KEY: "sk-ant" } });
49
+ // 已有配置:anthropic provider,缺少 fable 别名,且 opus 是用户手改过的值
50
+ const existing = {
51
+ config: {
52
+ active_alias: "haiku",
53
+ providers: [
54
+ {
55
+ id: "anthropic",
56
+ type: "anthropic",
57
+ apiKey: "sk-user-own-key",
58
+ models: { opus: "claude-opus-user-custom", sonnet: "claude-sonnet-4-6", haiku: "claude-haiku-4-5" },
59
+ },
60
+ ],
61
+ },
62
+ };
63
+ fs.writeFileSync(join(ccCodeDir, "settings.json"), JSON.stringify(existing, null, 2));
64
+ writeClaudeSettings(home, {
65
+ env: {
66
+ ANTHROPIC_API_KEY: "sk-ant",
67
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "claude-opus-4-7",
68
+ ANTHROPIC_DEFAULT_FABLE_MODEL: "claude-fable-5",
69
+ },
70
+ });
51
71
  const result = migrateFromClaudeCode(home);
52
72
  if (result !== true) throw new Error("expected true");
53
- const content = fs.readFileSync(join(ccCodeDir, "settings.json"), "utf-8");
54
- if (content !== JSON.stringify({ config: {} })) {
55
- throw new Error("should not overwrite existing settings");
56
- }
73
+ const cfg = readCcCodeSettings(home);
74
+ const p = cfg.config.providers[0];
75
+ // 缺失的 fable 被补上
76
+ if (p.models.fable !== "claude-fable-5") throw new Error("expected fable backfilled");
77
+ // 用户已有的 opus 值不被覆盖
78
+ if (p.models.opus !== "claude-opus-user-custom") throw new Error("must not overwrite existing opus");
79
+ // 用户已有值不被 env 覆盖
80
+ if (p.apiKey !== "sk-user-own-key") throw new Error("must not overwrite user apiKey");
81
+ // active_alias 保持原样
82
+ if (cfg.config.active_alias !== "haiku") throw new Error("must not change active_alias");
83
+ });
84
+
85
+ test("migrateFromClaudeCode backfill leaves unknown provider ids untouched", (home) => {
86
+ const ccCodeDir = join(home, ".cc-code");
87
+ fs.mkdirSync(ccCodeDir, { recursive: true });
88
+ const existing = {
89
+ config: {
90
+ providers: [{ id: "my-custom-id", type: "anthropic", apiKey: "sk-x", models: {} }],
91
+ },
92
+ };
93
+ fs.writeFileSync(join(ccCodeDir, "settings.json"), JSON.stringify(existing));
94
+ writeClaudeSettings(home, { env: { ANTHROPIC_API_KEY: "sk-ant", ANTHROPIC_DEFAULT_FABLE_MODEL: "claude-fable-5" } });
95
+ const result = migrateFromClaudeCode(home);
96
+ if (result !== true) throw new Error("expected true");
97
+ const cfg = readCcCodeSettings(home);
98
+ if (cfg.config.providers.length !== 1) throw new Error("must not add providers");
99
+ if (cfg.config.providers[0].models.fable !== undefined) throw new Error("must not touch unknown provider id");
100
+ });
101
+
102
+ test("migrateFromClaudeCode returns true when cc-code exists but no claude settings", (home) => {
103
+ const ccCodeDir = join(home, ".cc-code");
104
+ fs.mkdirSync(ccCodeDir, { recursive: true });
105
+ fs.writeFileSync(join(ccCodeDir, "settings.json"), JSON.stringify({ config: {} }));
106
+ const result = migrateFromClaudeCode(home);
107
+ if (result !== true) throw new Error("expected true (has cc-code, no quick start)");
57
108
  });
58
109
 
59
110
  test("migrateFromClaudeCode produces camelCase provider config for Anthropic", (home) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cc-claw/code",
3
- "version": "0.6.78",
3
+ "version": "0.6.79",
4
4
  "description": "cc-code — Terminal coding agent powered by open-source models — Rust-built, Claude Code compatible",
5
5
  "keywords": [
6
6
  "agent",