@tkpdx01/ccc 1.2.7 → 1.3.1
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/Claude Code settings.txt +776 -776
- package/README.md +77 -0
- package/index.js +4 -2
- package/package.json +40 -39
- package/src/commands/delete.js +66 -66
- package/src/commands/edit.js +120 -120
- package/src/commands/help.js +61 -50
- package/src/commands/import.js +356 -356
- package/src/commands/index.js +11 -10
- package/src/commands/list.js +46 -46
- package/src/commands/new.js +109 -109
- package/src/commands/show.js +68 -68
- package/src/commands/sync.js +93 -93
- package/src/commands/use.js +19 -19
- package/src/commands/webdav.js +477 -0
- package/src/config.js +9 -9
- package/src/crypto.js +147 -0
- package/src/launch.js +69 -69
- package/src/parsers.js +154 -154
- package/src/profiles.js +182 -182
- package/src/utils.js +67 -67
- package/src/webdav.js +268 -0
- package/.claude/settings.local.json +0 -34
- package/nul +0 -1
package/src/profiles.js
CHANGED
|
@@ -1,182 +1,182 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { CONFIG_DIR, PROFILES_DIR, DEFAULT_FILE, CLAUDE_SETTINGS_PATH } from './config.js';
|
|
4
|
-
|
|
5
|
-
// 确保目录存在
|
|
6
|
-
export function ensureDirs() {
|
|
7
|
-
if (!fs.existsSync(CONFIG_DIR)) {
|
|
8
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
9
|
-
}
|
|
10
|
-
if (!fs.existsSync(PROFILES_DIR)) {
|
|
11
|
-
fs.mkdirSync(PROFILES_DIR, { recursive: true });
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// 获取所有 profiles(按 a-z 排序)
|
|
16
|
-
export function getProfiles() {
|
|
17
|
-
ensureDirs();
|
|
18
|
-
const files = fs.readdirSync(PROFILES_DIR);
|
|
19
|
-
return files
|
|
20
|
-
.filter(f => f.endsWith('.json'))
|
|
21
|
-
.map(f => f.replace('.json', ''))
|
|
22
|
-
.sort((a, b) => a.localeCompare(b, 'zh-CN', { sensitivity: 'base' }));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// 获取带序号的 profiles 映射 { 序号: profileName }
|
|
26
|
-
export function getProfilesWithIndex() {
|
|
27
|
-
const profiles = getProfiles();
|
|
28
|
-
const map = {};
|
|
29
|
-
profiles.forEach((p, i) => {
|
|
30
|
-
map[i + 1] = p;
|
|
31
|
-
});
|
|
32
|
-
return { profiles, map };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// 根据序号或名称解析 profile
|
|
36
|
-
export function resolveProfile(input) {
|
|
37
|
-
const { profiles, map } = getProfilesWithIndex();
|
|
38
|
-
|
|
39
|
-
// 尝试作为数字序号
|
|
40
|
-
const num = parseInt(input, 10);
|
|
41
|
-
if (!isNaN(num) && map[num]) {
|
|
42
|
-
return map[num];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 作为名称
|
|
46
|
-
if (profiles.includes(input)) {
|
|
47
|
-
return input;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// 获取默认 profile
|
|
54
|
-
export function getDefaultProfile() {
|
|
55
|
-
if (fs.existsSync(DEFAULT_FILE)) {
|
|
56
|
-
return fs.readFileSync(DEFAULT_FILE, 'utf-8').trim();
|
|
57
|
-
}
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// 设置默认 profile
|
|
62
|
-
export function setDefaultProfile(name) {
|
|
63
|
-
ensureDirs();
|
|
64
|
-
fs.writeFileSync(DEFAULT_FILE, name);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 获取 profile 路径
|
|
68
|
-
export function getProfilePath(name) {
|
|
69
|
-
return path.join(PROFILES_DIR, `${name}.json`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 检查 profile 是否存在
|
|
73
|
-
export function profileExists(name) {
|
|
74
|
-
return fs.existsSync(getProfilePath(name));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// 获取 Claude 默认 settings 模板
|
|
78
|
-
export function getClaudeSettingsTemplate() {
|
|
79
|
-
if (fs.existsSync(CLAUDE_SETTINGS_PATH)) {
|
|
80
|
-
try {
|
|
81
|
-
return JSON.parse(fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf-8'));
|
|
82
|
-
} catch {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// 读取 profile 配置
|
|
90
|
-
export function readProfile(name) {
|
|
91
|
-
const profilePath = getProfilePath(name);
|
|
92
|
-
if (!fs.existsSync(profilePath)) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
return JSON.parse(fs.readFileSync(profilePath, 'utf-8'));
|
|
97
|
-
} catch {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// 保存 profile 配置
|
|
103
|
-
export function saveProfile(name, settings) {
|
|
104
|
-
ensureDirs();
|
|
105
|
-
const profilePath = getProfilePath(name);
|
|
106
|
-
fs.writeFileSync(profilePath, JSON.stringify(settings, null, 2));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// 创建基于主配置的 profile(复制 ~/.claude/settings.json 并设置 env)
|
|
110
|
-
export function createProfileFromTemplate(name, apiUrl, apiKey) {
|
|
111
|
-
const template = getClaudeSettingsTemplate() || {};
|
|
112
|
-
|
|
113
|
-
// 确保 env 对象存在
|
|
114
|
-
if (!template.env) {
|
|
115
|
-
template.env = {};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// 只设置 API 凭证到 env
|
|
119
|
-
template.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
120
|
-
template.env.ANTHROPIC_BASE_URL = apiUrl;
|
|
121
|
-
|
|
122
|
-
saveProfile(name, template);
|
|
123
|
-
return template;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 同步主配置到 profile(保留 profile 的 API 凭证)
|
|
127
|
-
export function syncProfileWithTemplate(name) {
|
|
128
|
-
const template = getClaudeSettingsTemplate();
|
|
129
|
-
if (!template) {
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const currentProfile = readProfile(name);
|
|
134
|
-
if (!currentProfile) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// 保存当前 profile 的 API 凭证(支持新旧格式)
|
|
139
|
-
const currentEnv = currentProfile.env || {};
|
|
140
|
-
const apiKey = currentEnv.ANTHROPIC_AUTH_TOKEN || currentProfile.ANTHROPIC_AUTH_TOKEN || '';
|
|
141
|
-
const apiUrl = currentEnv.ANTHROPIC_BASE_URL || currentProfile.ANTHROPIC_BASE_URL || '';
|
|
142
|
-
|
|
143
|
-
// 复制主配置
|
|
144
|
-
const newProfile = { ...template };
|
|
145
|
-
|
|
146
|
-
// 确保 env 对象存在并保留 API 凭证
|
|
147
|
-
newProfile.env = { ...(template.env || {}), ANTHROPIC_AUTH_TOKEN: apiKey, ANTHROPIC_BASE_URL: apiUrl };
|
|
148
|
-
|
|
149
|
-
saveProfile(name, newProfile);
|
|
150
|
-
return newProfile;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// 从 profile 中提取 API 凭证
|
|
154
|
-
export function getProfileCredentials(name) {
|
|
155
|
-
const profile = readProfile(name);
|
|
156
|
-
if (!profile) {
|
|
157
|
-
return { apiKey: '', apiUrl: '' };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// 支持旧格式(直接在顶层)和新格式(在 env 中)
|
|
161
|
-
const env = profile.env || {};
|
|
162
|
-
return {
|
|
163
|
-
apiKey: env.ANTHROPIC_AUTH_TOKEN || profile.ANTHROPIC_AUTH_TOKEN || '',
|
|
164
|
-
apiUrl: env.ANTHROPIC_BASE_URL || profile.ANTHROPIC_BASE_URL || ''
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 删除 profile
|
|
169
|
-
export function deleteProfile(name) {
|
|
170
|
-
const profilePath = getProfilePath(name);
|
|
171
|
-
if (fs.existsSync(profilePath)) {
|
|
172
|
-
fs.unlinkSync(profilePath);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// 清除默认 profile 设置
|
|
177
|
-
export function clearDefaultProfile() {
|
|
178
|
-
if (fs.existsSync(DEFAULT_FILE)) {
|
|
179
|
-
fs.unlinkSync(DEFAULT_FILE);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { CONFIG_DIR, PROFILES_DIR, DEFAULT_FILE, CLAUDE_SETTINGS_PATH } from './config.js';
|
|
4
|
+
|
|
5
|
+
// 确保目录存在
|
|
6
|
+
export function ensureDirs() {
|
|
7
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
8
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
if (!fs.existsSync(PROFILES_DIR)) {
|
|
11
|
+
fs.mkdirSync(PROFILES_DIR, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// 获取所有 profiles(按 a-z 排序)
|
|
16
|
+
export function getProfiles() {
|
|
17
|
+
ensureDirs();
|
|
18
|
+
const files = fs.readdirSync(PROFILES_DIR);
|
|
19
|
+
return files
|
|
20
|
+
.filter(f => f.endsWith('.json'))
|
|
21
|
+
.map(f => f.replace('.json', ''))
|
|
22
|
+
.sort((a, b) => a.localeCompare(b, 'zh-CN', { sensitivity: 'base' }));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 获取带序号的 profiles 映射 { 序号: profileName }
|
|
26
|
+
export function getProfilesWithIndex() {
|
|
27
|
+
const profiles = getProfiles();
|
|
28
|
+
const map = {};
|
|
29
|
+
profiles.forEach((p, i) => {
|
|
30
|
+
map[i + 1] = p;
|
|
31
|
+
});
|
|
32
|
+
return { profiles, map };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 根据序号或名称解析 profile
|
|
36
|
+
export function resolveProfile(input) {
|
|
37
|
+
const { profiles, map } = getProfilesWithIndex();
|
|
38
|
+
|
|
39
|
+
// 尝试作为数字序号
|
|
40
|
+
const num = parseInt(input, 10);
|
|
41
|
+
if (!isNaN(num) && map[num]) {
|
|
42
|
+
return map[num];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 作为名称
|
|
46
|
+
if (profiles.includes(input)) {
|
|
47
|
+
return input;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 获取默认 profile
|
|
54
|
+
export function getDefaultProfile() {
|
|
55
|
+
if (fs.existsSync(DEFAULT_FILE)) {
|
|
56
|
+
return fs.readFileSync(DEFAULT_FILE, 'utf-8').trim();
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 设置默认 profile
|
|
62
|
+
export function setDefaultProfile(name) {
|
|
63
|
+
ensureDirs();
|
|
64
|
+
fs.writeFileSync(DEFAULT_FILE, name);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 获取 profile 路径
|
|
68
|
+
export function getProfilePath(name) {
|
|
69
|
+
return path.join(PROFILES_DIR, `${name}.json`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 检查 profile 是否存在
|
|
73
|
+
export function profileExists(name) {
|
|
74
|
+
return fs.existsSync(getProfilePath(name));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 获取 Claude 默认 settings 模板
|
|
78
|
+
export function getClaudeSettingsTemplate() {
|
|
79
|
+
if (fs.existsSync(CLAUDE_SETTINGS_PATH)) {
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf-8'));
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 读取 profile 配置
|
|
90
|
+
export function readProfile(name) {
|
|
91
|
+
const profilePath = getProfilePath(name);
|
|
92
|
+
if (!fs.existsSync(profilePath)) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
return JSON.parse(fs.readFileSync(profilePath, 'utf-8'));
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 保存 profile 配置
|
|
103
|
+
export function saveProfile(name, settings) {
|
|
104
|
+
ensureDirs();
|
|
105
|
+
const profilePath = getProfilePath(name);
|
|
106
|
+
fs.writeFileSync(profilePath, JSON.stringify(settings, null, 2));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 创建基于主配置的 profile(复制 ~/.claude/settings.json 并设置 env)
|
|
110
|
+
export function createProfileFromTemplate(name, apiUrl, apiKey) {
|
|
111
|
+
const template = getClaudeSettingsTemplate() || {};
|
|
112
|
+
|
|
113
|
+
// 确保 env 对象存在
|
|
114
|
+
if (!template.env) {
|
|
115
|
+
template.env = {};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 只设置 API 凭证到 env
|
|
119
|
+
template.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
120
|
+
template.env.ANTHROPIC_BASE_URL = apiUrl;
|
|
121
|
+
|
|
122
|
+
saveProfile(name, template);
|
|
123
|
+
return template;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 同步主配置到 profile(保留 profile 的 API 凭证)
|
|
127
|
+
export function syncProfileWithTemplate(name) {
|
|
128
|
+
const template = getClaudeSettingsTemplate();
|
|
129
|
+
if (!template) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const currentProfile = readProfile(name);
|
|
134
|
+
if (!currentProfile) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 保存当前 profile 的 API 凭证(支持新旧格式)
|
|
139
|
+
const currentEnv = currentProfile.env || {};
|
|
140
|
+
const apiKey = currentEnv.ANTHROPIC_AUTH_TOKEN || currentProfile.ANTHROPIC_AUTH_TOKEN || '';
|
|
141
|
+
const apiUrl = currentEnv.ANTHROPIC_BASE_URL || currentProfile.ANTHROPIC_BASE_URL || '';
|
|
142
|
+
|
|
143
|
+
// 复制主配置
|
|
144
|
+
const newProfile = { ...template };
|
|
145
|
+
|
|
146
|
+
// 确保 env 对象存在并保留 API 凭证
|
|
147
|
+
newProfile.env = { ...(template.env || {}), ANTHROPIC_AUTH_TOKEN: apiKey, ANTHROPIC_BASE_URL: apiUrl };
|
|
148
|
+
|
|
149
|
+
saveProfile(name, newProfile);
|
|
150
|
+
return newProfile;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 从 profile 中提取 API 凭证
|
|
154
|
+
export function getProfileCredentials(name) {
|
|
155
|
+
const profile = readProfile(name);
|
|
156
|
+
if (!profile) {
|
|
157
|
+
return { apiKey: '', apiUrl: '' };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 支持旧格式(直接在顶层)和新格式(在 env 中)
|
|
161
|
+
const env = profile.env || {};
|
|
162
|
+
return {
|
|
163
|
+
apiKey: env.ANTHROPIC_AUTH_TOKEN || profile.ANTHROPIC_AUTH_TOKEN || '',
|
|
164
|
+
apiUrl: env.ANTHROPIC_BASE_URL || profile.ANTHROPIC_BASE_URL || ''
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 删除 profile
|
|
169
|
+
export function deleteProfile(name) {
|
|
170
|
+
const profilePath = getProfilePath(name);
|
|
171
|
+
if (fs.existsSync(profilePath)) {
|
|
172
|
+
fs.unlinkSync(profilePath);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 清除默认 profile 设置
|
|
177
|
+
export function clearDefaultProfile() {
|
|
178
|
+
if (fs.existsSync(DEFAULT_FILE)) {
|
|
179
|
+
fs.unlinkSync(DEFAULT_FILE);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
package/src/utils.js
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
// 从文本中提取 URL 和 token
|
|
2
|
-
export function extractFromText(text) {
|
|
3
|
-
// 提取 URL
|
|
4
|
-
const urlRegex = /https?:\/\/[^\s"'<>]+/gi;
|
|
5
|
-
const urls = text.match(urlRegex) || [];
|
|
6
|
-
|
|
7
|
-
// 提取 sk token
|
|
8
|
-
const tokenRegex = /sk-[a-zA-Z0-9_-]+/g;
|
|
9
|
-
const tokens = text.match(tokenRegex) || [];
|
|
10
|
-
|
|
11
|
-
return { urls, tokens };
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// 从 URL 获取域名作为名称(去掉协议和www子域名)
|
|
15
|
-
export function getDomainName(url) {
|
|
16
|
-
try {
|
|
17
|
-
const urlObj = new URL(url);
|
|
18
|
-
// 获取完整域名
|
|
19
|
-
let hostname = urlObj.hostname;
|
|
20
|
-
// 移除 www. 前缀
|
|
21
|
-
hostname = hostname.replace(/^www\./, '');
|
|
22
|
-
return hostname;
|
|
23
|
-
} catch {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// 生成安全的 profile 名称
|
|
29
|
-
export function sanitizeProfileName(name) {
|
|
30
|
-
return name
|
|
31
|
-
.replace(/[<>:"/\\|?*]/g, '_') // 替换 Windows 非法字符
|
|
32
|
-
.replace(/\s+/g, '_') // 替换空格
|
|
33
|
-
.replace(/_+/g, '_') // 合并多个下划线
|
|
34
|
-
.replace(/^_|_$/g, '') // 去除首尾下划线
|
|
35
|
-
.substring(0, 50); // 限制长度
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 将导入的配置转换为影子配置格式(只包含 API 凭证)
|
|
39
|
-
export function convertToClaudeSettings(provider, template) {
|
|
40
|
-
const config = provider.settingsConfig || {};
|
|
41
|
-
|
|
42
|
-
// 从 env 中提取 API 信息
|
|
43
|
-
const env = config.env || {};
|
|
44
|
-
const apiKey = env.ANTHROPIC_AUTH_TOKEN || env.ANTHROPIC_API_KEY || config.apiKey || '';
|
|
45
|
-
const apiUrl = env.ANTHROPIC_BASE_URL || config.apiUrl || provider.websiteUrl || '';
|
|
46
|
-
|
|
47
|
-
// 影子配置只存储 API 凭证,不用 env 包裹
|
|
48
|
-
return {
|
|
49
|
-
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
50
|
-
ANTHROPIC_BASE_URL: apiUrl
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// 格式化显示配置值
|
|
55
|
-
export function formatValue(key, value) {
|
|
56
|
-
if ((key === 'apiKey' || key === 'ANTHROPIC_AUTH_TOKEN') && value) {
|
|
57
|
-
return value.substring(0, 15) + '...';
|
|
58
|
-
}
|
|
59
|
-
if (typeof value === 'boolean') {
|
|
60
|
-
return value ? 'true' : 'false';
|
|
61
|
-
}
|
|
62
|
-
if (typeof value === 'object') {
|
|
63
|
-
return JSON.stringify(value, null, 2).split('\n').join('\n ');
|
|
64
|
-
}
|
|
65
|
-
return String(value);
|
|
66
|
-
}
|
|
67
|
-
|
|
1
|
+
// 从文本中提取 URL 和 token
|
|
2
|
+
export function extractFromText(text) {
|
|
3
|
+
// 提取 URL
|
|
4
|
+
const urlRegex = /https?:\/\/[^\s"'<>]+/gi;
|
|
5
|
+
const urls = text.match(urlRegex) || [];
|
|
6
|
+
|
|
7
|
+
// 提取 sk token
|
|
8
|
+
const tokenRegex = /sk-[a-zA-Z0-9_-]+/g;
|
|
9
|
+
const tokens = text.match(tokenRegex) || [];
|
|
10
|
+
|
|
11
|
+
return { urls, tokens };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 从 URL 获取域名作为名称(去掉协议和www子域名)
|
|
15
|
+
export function getDomainName(url) {
|
|
16
|
+
try {
|
|
17
|
+
const urlObj = new URL(url);
|
|
18
|
+
// 获取完整域名
|
|
19
|
+
let hostname = urlObj.hostname;
|
|
20
|
+
// 移除 www. 前缀
|
|
21
|
+
hostname = hostname.replace(/^www\./, '');
|
|
22
|
+
return hostname;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 生成安全的 profile 名称
|
|
29
|
+
export function sanitizeProfileName(name) {
|
|
30
|
+
return name
|
|
31
|
+
.replace(/[<>:"/\\|?*]/g, '_') // 替换 Windows 非法字符
|
|
32
|
+
.replace(/\s+/g, '_') // 替换空格
|
|
33
|
+
.replace(/_+/g, '_') // 合并多个下划线
|
|
34
|
+
.replace(/^_|_$/g, '') // 去除首尾下划线
|
|
35
|
+
.substring(0, 50); // 限制长度
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 将导入的配置转换为影子配置格式(只包含 API 凭证)
|
|
39
|
+
export function convertToClaudeSettings(provider, template) {
|
|
40
|
+
const config = provider.settingsConfig || {};
|
|
41
|
+
|
|
42
|
+
// 从 env 中提取 API 信息
|
|
43
|
+
const env = config.env || {};
|
|
44
|
+
const apiKey = env.ANTHROPIC_AUTH_TOKEN || env.ANTHROPIC_API_KEY || config.apiKey || '';
|
|
45
|
+
const apiUrl = env.ANTHROPIC_BASE_URL || config.apiUrl || provider.websiteUrl || '';
|
|
46
|
+
|
|
47
|
+
// 影子配置只存储 API 凭证,不用 env 包裹
|
|
48
|
+
return {
|
|
49
|
+
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
50
|
+
ANTHROPIC_BASE_URL: apiUrl
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 格式化显示配置值
|
|
55
|
+
export function formatValue(key, value) {
|
|
56
|
+
if ((key === 'apiKey' || key === 'ANTHROPIC_AUTH_TOKEN') && value) {
|
|
57
|
+
return value.substring(0, 15) + '...';
|
|
58
|
+
}
|
|
59
|
+
if (typeof value === 'boolean') {
|
|
60
|
+
return value ? 'true' : 'false';
|
|
61
|
+
}
|
|
62
|
+
if (typeof value === 'object') {
|
|
63
|
+
return JSON.stringify(value, null, 2).split('\n').join('\n ');
|
|
64
|
+
}
|
|
65
|
+
return String(value);
|
|
66
|
+
}
|
|
67
|
+
|