@tkpdx01/ccc 1.3.4 → 1.3.6
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/README.md +1 -1
- package/package.json +1 -1
- package/src/commands/edit.js +5 -1
- package/src/commands/new.js +43 -3
- package/src/profiles.js +75 -0
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ ccc webdav status # View sync status / 查看同步状态
|
|
|
60
60
|
- **Template Support / 模板**: Based on `~/.claude/settings.json`
|
|
61
61
|
- **Smart Import / 智能导入**: Auto-detect API URL and token
|
|
62
62
|
- **Sync Settings / 同步**: Update from template, preserve credentials
|
|
63
|
-
- **Claude Env Defaults / Claude 环境变量默认值**: Auto-ensure `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, `CLAUDE_CODE_ATTRIBUTION_HEADER=0`,
|
|
63
|
+
- **Claude Env Defaults / Claude 环境变量默认值**: Auto-ensure these values in the `env` section of both `~/.claude/settings.json` and each profile: `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, `CLAUDE_CODE_ATTRIBUTION_HEADER=0`, `DISABLE_INSTALLATION_CHECKS=1`
|
|
64
64
|
- **WebDAV Cloud Sync / 云同步**: Encrypted sync across devices
|
|
65
65
|
|
|
66
66
|
## Sync Command / 同步命令
|
package/package.json
CHANGED
package/src/commands/edit.js
CHANGED
|
@@ -13,7 +13,9 @@ import {
|
|
|
13
13
|
resolveProfile,
|
|
14
14
|
getProfileCredentials,
|
|
15
15
|
getClaudeSettingsTemplate,
|
|
16
|
-
ensureRequiredClaudeEnvSettings
|
|
16
|
+
ensureRequiredClaudeEnvSettings,
|
|
17
|
+
ensureClaudeSettingsExtras,
|
|
18
|
+
applyClaudeSettingsExtras
|
|
17
19
|
} from '../profiles.js';
|
|
18
20
|
|
|
19
21
|
export function editCommand(program) {
|
|
@@ -98,9 +100,11 @@ export function editCommand(program) {
|
|
|
98
100
|
|
|
99
101
|
// 确保主配置(~/.claude/settings.json)与 profile 都包含必要 env 设置
|
|
100
102
|
ensureRequiredClaudeEnvSettings();
|
|
103
|
+
ensureClaudeSettingsExtras();
|
|
101
104
|
currentProfile.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
|
|
102
105
|
currentProfile.env.CLAUDE_CODE_ATTRIBUTION_HEADER = '0';
|
|
103
106
|
currentProfile.env.DISABLE_INSTALLATION_CHECKS = '1';
|
|
107
|
+
applyClaudeSettingsExtras(currentProfile);
|
|
104
108
|
|
|
105
109
|
// 如果重命名
|
|
106
110
|
if (newName && newName !== profile) {
|
package/src/commands/new.js
CHANGED
|
@@ -5,10 +5,42 @@ import {
|
|
|
5
5
|
getProfiles,
|
|
6
6
|
profileExists,
|
|
7
7
|
createProfileFromTemplate,
|
|
8
|
-
setDefaultProfile
|
|
8
|
+
setDefaultProfile,
|
|
9
|
+
ensureClaudeSettingsExtras
|
|
9
10
|
} from '../profiles.js';
|
|
10
11
|
import { launchClaude } from '../launch.js';
|
|
11
12
|
|
|
13
|
+
const RESERVED_PROFILE_NAMES = [
|
|
14
|
+
'list',
|
|
15
|
+
'ls',
|
|
16
|
+
'use',
|
|
17
|
+
'show',
|
|
18
|
+
'import',
|
|
19
|
+
'if',
|
|
20
|
+
'new',
|
|
21
|
+
'edit',
|
|
22
|
+
'delete',
|
|
23
|
+
'rm',
|
|
24
|
+
'sync',
|
|
25
|
+
'webdav',
|
|
26
|
+
'help'
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
function isReservedProfileName(name) {
|
|
30
|
+
return RESERVED_PROFILE_NAMES.includes(name);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function validateProfileName(input) {
|
|
34
|
+
const trimmed = input.trim();
|
|
35
|
+
if (!trimmed) {
|
|
36
|
+
return '请输入配置名称';
|
|
37
|
+
}
|
|
38
|
+
if (isReservedProfileName(trimmed)) {
|
|
39
|
+
return '配置名称不能使用命令关键词';
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
12
44
|
export function newCommand(program) {
|
|
13
45
|
program
|
|
14
46
|
.command('new [name]')
|
|
@@ -21,10 +53,16 @@ export function newCommand(program) {
|
|
|
21
53
|
type: 'input',
|
|
22
54
|
name: 'profileName',
|
|
23
55
|
message: '配置名称:',
|
|
24
|
-
validate:
|
|
56
|
+
validate: validateProfileName
|
|
25
57
|
}
|
|
26
58
|
]);
|
|
27
59
|
name = profileName;
|
|
60
|
+
} else {
|
|
61
|
+
const validationResult = validateProfileName(name);
|
|
62
|
+
if (validationResult !== true) {
|
|
63
|
+
console.log(chalk.red(validationResult));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
28
66
|
}
|
|
29
67
|
|
|
30
68
|
// 检查是否已存在
|
|
@@ -60,7 +98,8 @@ export function newCommand(program) {
|
|
|
60
98
|
type: 'input',
|
|
61
99
|
name: 'finalName',
|
|
62
100
|
message: 'Profile 名称:',
|
|
63
|
-
default: name
|
|
101
|
+
default: name,
|
|
102
|
+
validate: validateProfileName
|
|
64
103
|
}
|
|
65
104
|
]);
|
|
66
105
|
|
|
@@ -81,6 +120,7 @@ export function newCommand(program) {
|
|
|
81
120
|
}
|
|
82
121
|
|
|
83
122
|
ensureDirs();
|
|
123
|
+
ensureClaudeSettingsExtras();
|
|
84
124
|
createProfileFromTemplate(finalName, apiUrl, apiKey);
|
|
85
125
|
console.log(chalk.green(`\n✓ 配置 "${finalName}" 已创建(基于 ~/.claude/settings.json)`));
|
|
86
126
|
|
package/src/profiles.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
3
4
|
import { CONFIG_DIR, PROFILES_DIR, DEFAULT_FILE, CLAUDE_SETTINGS_PATH } from './config.js';
|
|
4
5
|
|
|
5
6
|
function stringifyClaudeSettings(settings) {
|
|
@@ -138,6 +139,77 @@ export function ensureRequiredClaudeEnvSettings() {
|
|
|
138
139
|
});
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
// 获取 statusLine 的 ccline 路径(适配不同操作系统)
|
|
143
|
+
function getCclineCommand() {
|
|
144
|
+
const platform = os.platform();
|
|
145
|
+
if (platform === 'win32') {
|
|
146
|
+
return '%USERPROFILE%\\.claude\\ccline\\ccline.exe';
|
|
147
|
+
} else {
|
|
148
|
+
// Linux 和 macOS
|
|
149
|
+
return '~/.claude/ccline/ccline';
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function applyClaudeSettingsExtras(target) {
|
|
154
|
+
if (!target || typeof target !== 'object') {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let changed = false;
|
|
159
|
+
|
|
160
|
+
// 确保 attribution 禁用(commit/pr 为空字符串)
|
|
161
|
+
if (!target.attribution || typeof target.attribution !== 'object' || Array.isArray(target.attribution)) {
|
|
162
|
+
target.attribution = { commit: '', pr: '' };
|
|
163
|
+
changed = true;
|
|
164
|
+
} else {
|
|
165
|
+
if (target.attribution.commit !== '' || target.attribution.pr !== '') {
|
|
166
|
+
target.attribution.commit = '';
|
|
167
|
+
target.attribution.pr = '';
|
|
168
|
+
changed = true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 兼容旧版本:确保 includeCoAuthoredBy: false
|
|
173
|
+
if (target.includeCoAuthoredBy !== false) {
|
|
174
|
+
target.includeCoAuthoredBy = false;
|
|
175
|
+
changed = true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 确保 statusLine 配置
|
|
179
|
+
const expectedCommand = getCclineCommand();
|
|
180
|
+
const expectedStatusLine = {
|
|
181
|
+
type: 'command',
|
|
182
|
+
command: expectedCommand,
|
|
183
|
+
padding: 0
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
if (!target.statusLine ||
|
|
187
|
+
target.statusLine.type !== 'command' ||
|
|
188
|
+
target.statusLine.command !== expectedCommand ||
|
|
189
|
+
target.statusLine.padding !== 0) {
|
|
190
|
+
target.statusLine = expectedStatusLine;
|
|
191
|
+
changed = true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return changed;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 确保主配置包含 attribution/includeCoAuthoredBy 和 statusLine 设置
|
|
198
|
+
export function ensureClaudeSettingsExtras() {
|
|
199
|
+
const template = getClaudeSettingsTemplate();
|
|
200
|
+
if (!template) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const changed = applyClaudeSettingsExtras(template);
|
|
205
|
+
|
|
206
|
+
if (changed) {
|
|
207
|
+
fs.writeFileSync(CLAUDE_SETTINGS_PATH, stringifyClaudeSettings(template));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return template;
|
|
211
|
+
}
|
|
212
|
+
|
|
141
213
|
// 读取 profile 配置
|
|
142
214
|
export function readProfile(name) {
|
|
143
215
|
const profilePath = getProfilePath(name);
|
|
@@ -163,6 +235,7 @@ export function createProfileFromTemplate(name, apiUrl, apiKey) {
|
|
|
163
235
|
// 先确保主配置包含必要 env 设置(也会写回 ~/.claude/settings.json)
|
|
164
236
|
const ensuredTemplate = ensureRequiredClaudeEnvSettings();
|
|
165
237
|
const template = ensuredTemplate || getClaudeSettingsTemplate() || {};
|
|
238
|
+
applyClaudeSettingsExtras(template);
|
|
166
239
|
|
|
167
240
|
// 确保 env 对象存在
|
|
168
241
|
if (!template.env) {
|
|
@@ -189,6 +262,7 @@ export function syncProfileWithTemplate(name) {
|
|
|
189
262
|
if (!template) {
|
|
190
263
|
return null;
|
|
191
264
|
}
|
|
265
|
+
applyClaudeSettingsExtras(template);
|
|
192
266
|
|
|
193
267
|
const currentProfile = readProfile(name);
|
|
194
268
|
if (!currentProfile) {
|
|
@@ -210,6 +284,7 @@ export function syncProfileWithTemplate(name) {
|
|
|
210
284
|
newProfile.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
|
|
211
285
|
newProfile.env.CLAUDE_CODE_ATTRIBUTION_HEADER = '0';
|
|
212
286
|
newProfile.env.DISABLE_INSTALLATION_CHECKS = '1';
|
|
287
|
+
applyClaudeSettingsExtras(newProfile);
|
|
213
288
|
|
|
214
289
|
saveProfile(name, newProfile);
|
|
215
290
|
return newProfile;
|