@cc-claw/code 0.6.78 → 0.6.80
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 +76 -24
- package/install.test.js +58 -7
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -122,29 +122,8 @@ function extractZip(buffer, dest) {
|
|
|
122
122
|
zip.extractAllTo(dest, true);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
50
|
-
|
|
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
|
|
54
|
-
|
|
55
|
-
|
|
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) => {
|