coding-tool-x 3.3.4 → 3.3.5
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/package.json +2 -1
- package/src/commands/doctor.js +3 -3
- package/src/commands/export-config.js +2 -2
- package/src/commands/logs.js +42 -9
- package/src/commands/port-config.js +2 -2
- package/src/commands/switch.js +2 -2
- package/src/config/default.js +4 -1
- package/src/config/loader.js +5 -2
- package/src/config/paths.js +25 -21
- package/src/reset-config.js +3 -5
- package/src/server/api/agents.js +2 -3
- package/src/server/api/claude-hooks.js +67 -10
- package/src/server/api/opencode-sessions.js +2 -2
- package/src/server/api/pm2-autostart.js +20 -8
- package/src/server/api/proxy.js +2 -3
- package/src/server/api/sessions.js +6 -6
- package/src/server/index.js +5 -9
- package/src/server/services/agents-service.js +6 -3
- package/src/server/services/channels.js +6 -7
- package/src/server/services/codex-channels.js +4 -1
- package/src/server/services/codex-config.js +4 -1
- package/src/server/services/codex-settings-manager.js +18 -9
- package/src/server/services/commands-service.js +2 -2
- package/src/server/services/config-export-service.js +7 -6
- package/src/server/services/config-registry-service.js +7 -6
- package/src/server/services/config-sync-manager.js +2 -2
- package/src/server/services/config-sync-service.js +2 -2
- package/src/server/services/env-checker.js +2 -2
- package/src/server/services/favorites.js +3 -4
- package/src/server/services/gemini-channels.js +4 -4
- package/src/server/services/gemini-config.js +2 -2
- package/src/server/services/gemini-sessions.js +3 -3
- package/src/server/services/gemini-settings-manager.js +5 -5
- package/src/server/services/mcp-service.js +7 -4
- package/src/server/services/model-detector.js +2 -2
- package/src/server/services/opencode-channels.js +5 -5
- package/src/server/services/plugins-service.js +3 -4
- package/src/server/services/prompts-service.js +7 -4
- package/src/server/services/proxy-runtime.js +2 -2
- package/src/server/services/repo-scanner-base.js +2 -2
- package/src/server/services/request-logger.js +2 -2
- package/src/server/services/security-config.js +2 -2
- package/src/server/services/session-cache.js +2 -2
- package/src/server/services/session-converter.js +9 -4
- package/src/server/services/sessions.js +8 -5
- package/src/server/services/settings-manager.js +3 -4
- package/src/server/services/skill-service.js +5 -5
- package/src/server/services/statistics-service.js +2 -2
- package/src/server/services/ui-config.js +3 -4
- package/src/server/websocket-server.js +2 -2
- package/src/utils/home-dir.js +82 -0
- package/src/utils/port-helper.js +34 -12
package/src/server/index.js
CHANGED
|
@@ -3,7 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
5
|
const { loadConfig } = require('../config/loader');
|
|
6
|
-
const { ensureStorageDirMigrated } = require('../config/paths');
|
|
6
|
+
const { PATHS, ensureStorageDirMigrated } = require('../config/paths');
|
|
7
7
|
const { startWebSocketServer: attachWebSocketServer } = require('./websocket-server');
|
|
8
8
|
const { isPortInUse, killProcessByPort, waitForPortRelease } = require('../utils/port-helper');
|
|
9
9
|
const { isProxyConfig } = require('./services/settings-manager');
|
|
@@ -266,14 +266,10 @@ async function startServer(port, host = '127.0.0.1', options = {}) {
|
|
|
266
266
|
// 自动恢复代理状态
|
|
267
267
|
function autoRestoreProxies() {
|
|
268
268
|
const config = loadConfig();
|
|
269
|
-
const os = require('os');
|
|
270
269
|
const fs = require('fs');
|
|
271
|
-
const path = require('path');
|
|
272
|
-
|
|
273
|
-
const ccToolDir = path.join(os.homedir(), '.cc-tool');
|
|
274
270
|
|
|
275
271
|
// 检查 Claude 代理状态文件
|
|
276
|
-
const claudeActiveFile =
|
|
272
|
+
const claudeActiveFile = PATHS.activeChannel.claude;
|
|
277
273
|
if (fs.existsSync(claudeActiveFile)) {
|
|
278
274
|
console.log(chalk.cyan('\n🔄 检测到 Claude 代理状态文件,正在自动启动...'));
|
|
279
275
|
const proxyPort = config.ports?.proxy || 20088;
|
|
@@ -287,7 +283,7 @@ function autoRestoreProxies() {
|
|
|
287
283
|
}
|
|
288
284
|
|
|
289
285
|
// 检查 Codex 代理状态文件
|
|
290
|
-
const codexActiveFile =
|
|
286
|
+
const codexActiveFile = PATHS.activeChannel.codex;
|
|
291
287
|
if (fs.existsSync(codexActiveFile)) {
|
|
292
288
|
console.log(chalk.cyan('\n🔄 检测到 Codex 代理状态文件,正在自动启动...'));
|
|
293
289
|
const codexProxyPort = config.ports?.codexProxy || 20089;
|
|
@@ -312,7 +308,7 @@ function autoRestoreProxies() {
|
|
|
312
308
|
}
|
|
313
309
|
|
|
314
310
|
// 检查 Gemini 代理状态文件
|
|
315
|
-
const geminiActiveFile =
|
|
311
|
+
const geminiActiveFile = PATHS.activeChannel.gemini;
|
|
316
312
|
if (fs.existsSync(geminiActiveFile)) {
|
|
317
313
|
console.log(chalk.cyan('\n🔄 检测到 Gemini 代理状态文件,正在自动启动...'));
|
|
318
314
|
const geminiProxyPort = config.ports?.geminiProxy || 20090;
|
|
@@ -332,7 +328,7 @@ function autoRestoreProxies() {
|
|
|
332
328
|
}
|
|
333
329
|
|
|
334
330
|
// 检查 OpenCode 代理状态文件
|
|
335
|
-
const opencodeActiveFile =
|
|
331
|
+
const opencodeActiveFile = PATHS.activeChannel.opencode;
|
|
336
332
|
if (fs.existsSync(opencodeActiveFile)) {
|
|
337
333
|
console.log(chalk.cyan('\n🔄 检测到 OpenCode 代理状态文件,正在自动启动...'));
|
|
338
334
|
const opencodeProxyPort = config.ports?.opencodeProxy || 20091;
|
|
@@ -12,18 +12,21 @@ const toml = require('toml');
|
|
|
12
12
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
13
13
|
const { RepoScannerBase } = require('./repo-scanner-base');
|
|
14
14
|
const { NATIVE_PATHS } = require('../../config/paths');
|
|
15
|
+
const { resolvePreferredHomeDir } = require('../../utils/home-dir');
|
|
15
16
|
|
|
16
17
|
// 默认仓库源
|
|
17
18
|
const DEFAULT_REPOS = [];
|
|
18
19
|
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'opencode'];
|
|
19
20
|
const OPENCODE_CONFIG_DIR = NATIVE_PATHS.opencode.config;
|
|
20
21
|
const CODEX_CONFIG_PATH = NATIVE_PATHS.codex.config;
|
|
21
|
-
const
|
|
22
|
+
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
23
|
+
const CODEX_AGENTS_DIR = path.join(path.dirname(CODEX_CONFIG_PATH), 'agents');
|
|
24
|
+
const CLAUDE_AGENTS_DIR = path.join(path.dirname(NATIVE_PATHS.claude.settings), 'agents');
|
|
22
25
|
const CODEX_CONFIG_MODES = new Set(['none', 'managed', 'custom']);
|
|
23
26
|
|
|
24
27
|
const PLATFORM_CONFIG = {
|
|
25
28
|
claude: {
|
|
26
|
-
userAgentsDir:
|
|
29
|
+
userAgentsDir: CLAUDE_AGENTS_DIR,
|
|
27
30
|
projectAgentsDir: (projectPath) => path.join(projectPath, '.claude', 'agents'),
|
|
28
31
|
repoType: 'agents'
|
|
29
32
|
},
|
|
@@ -206,7 +209,7 @@ function resolveCodexConfigPath(configPath) {
|
|
|
206
209
|
if (!normalized) return '';
|
|
207
210
|
|
|
208
211
|
if (normalized.startsWith('~/')) {
|
|
209
|
-
return path.join(
|
|
212
|
+
return path.join(HOME_DIR, normalized.slice(2));
|
|
210
213
|
}
|
|
211
214
|
|
|
212
215
|
if (path.isAbsolute(normalized)) {
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const os = require('os');
|
|
4
2
|
const { isProxyConfig } = require('./settings-manager');
|
|
3
|
+
const { PATHS, NATIVE_PATHS } = require('../../config/paths');
|
|
5
4
|
|
|
6
5
|
function getChannelsFilePath() {
|
|
7
|
-
const dir =
|
|
6
|
+
const dir = PATHS.base;
|
|
8
7
|
if (!fs.existsSync(dir)) {
|
|
9
8
|
fs.mkdirSync(dir, { recursive: true });
|
|
10
9
|
}
|
|
11
|
-
return
|
|
10
|
+
return PATHS.channels.claude;
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
function getActiveChannelIdPath() {
|
|
15
|
-
const dir =
|
|
14
|
+
const dir = PATHS.base;
|
|
16
15
|
if (!fs.existsSync(dir)) {
|
|
17
16
|
fs.mkdirSync(dir, { recursive: true });
|
|
18
17
|
}
|
|
19
|
-
return
|
|
18
|
+
return PATHS.activeChannel.claude;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
function getClaudeSettingsPath() {
|
|
23
|
-
return
|
|
22
|
+
return NATIVE_PATHS.claude.settings;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
function saveActiveChannelId(channelId) {
|
|
@@ -4,9 +4,12 @@ const os = require('os');
|
|
|
4
4
|
const crypto = require('crypto');
|
|
5
5
|
const toml = require('toml');
|
|
6
6
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
7
|
+
const { resolvePreferredHomeDir } = require('../../utils/home-dir');
|
|
7
8
|
const { getCodexDir } = require('./codex-config');
|
|
8
9
|
const { injectEnvToShell, removeEnvFromShell, isProxyConfig } = require('./codex-settings-manager');
|
|
9
10
|
|
|
11
|
+
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
12
|
+
|
|
10
13
|
/**
|
|
11
14
|
* Codex 渠道管理服务(多渠道架构)
|
|
12
15
|
*
|
|
@@ -30,7 +33,7 @@ function normalizeGatewaySourceType(value, fallback = 'codex') {
|
|
|
30
33
|
|
|
31
34
|
// 获取渠道存储文件路径
|
|
32
35
|
function getChannelsFilePath() {
|
|
33
|
-
const ccToolDir = path.join(
|
|
36
|
+
const ccToolDir = path.join(HOME_DIR, '.cc-tool');
|
|
34
37
|
if (!fs.existsSync(ccToolDir)) {
|
|
35
38
|
fs.mkdirSync(ccToolDir, { recursive: true });
|
|
36
39
|
}
|
|
@@ -2,12 +2,15 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const toml = require('toml');
|
|
5
|
+
const { resolvePreferredHomeDir } = require('../../utils/home-dir');
|
|
6
|
+
|
|
7
|
+
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* 获取 Codex 配置目录
|
|
8
11
|
*/
|
|
9
12
|
function getCodexDir() {
|
|
10
|
-
return path.join(
|
|
13
|
+
return path.join(HOME_DIR, '.codex');
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
/**
|
|
@@ -3,23 +3,26 @@ const path = require('path');
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const toml = require('toml');
|
|
5
5
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
6
|
+
const { resolvePreferredHomeDir, isWindowsLikePlatform } = require('../../utils/home-dir');
|
|
7
|
+
|
|
8
|
+
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
6
9
|
|
|
7
10
|
// Codex 配置文件路径
|
|
8
11
|
function getConfigPath() {
|
|
9
|
-
return path.join(
|
|
12
|
+
return path.join(HOME_DIR, '.codex', 'config.toml');
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
function getAuthPath() {
|
|
13
|
-
return path.join(
|
|
16
|
+
return path.join(HOME_DIR, '.codex', 'auth.json');
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
// 备份文件路径
|
|
17
20
|
function getConfigBackupPath() {
|
|
18
|
-
return path.join(
|
|
21
|
+
return path.join(HOME_DIR, '.codex', 'config.toml.cc-tool-backup');
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
function getAuthBackupPath() {
|
|
22
|
-
return path.join(
|
|
25
|
+
return path.join(HOME_DIR, '.codex', 'auth.json.cc-tool-backup');
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
// 检查配置文件是否存在
|
|
@@ -74,7 +77,7 @@ function writeFileAtomic(filePath, content) {
|
|
|
74
77
|
|
|
75
78
|
function normalizeHomePath(filePath) {
|
|
76
79
|
const normalizedPath = String(filePath || '').replace(/\\/g, '/');
|
|
77
|
-
const normalizedHome =
|
|
80
|
+
const normalizedHome = HOME_DIR.replace(/\\/g, '/');
|
|
78
81
|
if (normalizedPath.startsWith(normalizedHome)) {
|
|
79
82
|
return `~${normalizedPath.slice(normalizedHome.length)}`;
|
|
80
83
|
}
|
|
@@ -111,11 +114,13 @@ function isPowerShellProfile(filePath) {
|
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
function getShellConfigCandidates() {
|
|
114
|
-
const homeDir =
|
|
117
|
+
const homeDir = HOME_DIR;
|
|
115
118
|
const shell = String(process.env.SHELL || '').toLowerCase();
|
|
116
119
|
const candidates = [];
|
|
117
120
|
|
|
118
|
-
if (process.platform
|
|
121
|
+
if (isWindowsLikePlatform(process.platform, process.env)) {
|
|
122
|
+
const oneDriveDir = process.env.OneDrive || process.env.ONEDRIVE || '';
|
|
123
|
+
|
|
119
124
|
if (shell.includes('zsh')) {
|
|
120
125
|
candidates.push(path.join(homeDir, '.zshrc'));
|
|
121
126
|
}
|
|
@@ -127,6 +132,10 @@ function getShellConfigCandidates() {
|
|
|
127
132
|
|
|
128
133
|
candidates.push(path.join(homeDir, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1'));
|
|
129
134
|
candidates.push(path.join(homeDir, 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1'));
|
|
135
|
+
if (oneDriveDir) {
|
|
136
|
+
candidates.push(path.join(oneDriveDir, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1'));
|
|
137
|
+
candidates.push(path.join(oneDriveDir, 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1'));
|
|
138
|
+
}
|
|
130
139
|
candidates.push(path.join(homeDir, '.bashrc'));
|
|
131
140
|
candidates.push(path.join(homeDir, '.profile'));
|
|
132
141
|
} else if (shell.includes('zsh')) {
|
|
@@ -154,7 +163,7 @@ function getShellConfigCandidates() {
|
|
|
154
163
|
|
|
155
164
|
function getShellReloadCommand(configPath) {
|
|
156
165
|
if (!configPath) {
|
|
157
|
-
return process.platform
|
|
166
|
+
return isWindowsLikePlatform(process.platform, process.env) ? '重启终端' : 'source ~/.zshrc';
|
|
158
167
|
}
|
|
159
168
|
|
|
160
169
|
const displayPath = normalizeHomePath(configPath);
|
|
@@ -176,7 +185,7 @@ function getShellReloadCommand(configPath) {
|
|
|
176
185
|
return 'source ~/.profile';
|
|
177
186
|
}
|
|
178
187
|
|
|
179
|
-
if (process.platform
|
|
188
|
+
if (isWindowsLikePlatform(process.platform, process.env)) {
|
|
180
189
|
return '. $PROFILE';
|
|
181
190
|
}
|
|
182
191
|
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
|
-
const os = require('os');
|
|
11
10
|
const { RepoScannerBase } = require('./repo-scanner-base');
|
|
12
11
|
const { NATIVE_PATHS } = require('../../config/paths');
|
|
13
12
|
const {
|
|
@@ -19,10 +18,11 @@ const {
|
|
|
19
18
|
const DEFAULT_REPOS = [];
|
|
20
19
|
const SUPPORTED_PLATFORMS = ['claude', 'opencode'];
|
|
21
20
|
const OPENCODE_CONFIG_DIR = NATIVE_PATHS.opencode.config;
|
|
21
|
+
const CLAUDE_COMMANDS_DIR = path.join(path.dirname(NATIVE_PATHS.claude.settings), 'commands');
|
|
22
22
|
|
|
23
23
|
const PLATFORM_CONFIG = {
|
|
24
24
|
claude: {
|
|
25
|
-
userCommandsDir:
|
|
25
|
+
userCommandsDir: CLAUDE_COMMANDS_DIR,
|
|
26
26
|
projectCommandsDir: (projectPath) => path.join(projectPath, '.claude', 'commands'),
|
|
27
27
|
repoType: 'commands'
|
|
28
28
|
},
|
|
@@ -5,24 +5,25 @@
|
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
-
const os = require('os');
|
|
9
8
|
const AdmZip = require('adm-zip');
|
|
10
9
|
const configTemplatesService = require('./config-templates-service');
|
|
11
10
|
const channelsService = require('./channels');
|
|
12
11
|
const { AgentsService } = require('./agents-service');
|
|
13
12
|
const { CommandsService } = require('./commands-service');
|
|
14
13
|
const { SkillService } = require('./skill-service');
|
|
14
|
+
const { PATHS, NATIVE_PATHS } = require('../../config/paths');
|
|
15
15
|
|
|
16
16
|
const CONFIG_VERSION = '1.2.0';
|
|
17
17
|
const SKILL_FILE_ENCODING = 'base64';
|
|
18
18
|
const SKILL_IGNORE_DIRS = new Set(['.git']);
|
|
19
19
|
const SKILL_IGNORE_FILES = new Set(['.DS_Store']);
|
|
20
|
-
const CC_TOOL_DIR =
|
|
21
|
-
const LEGACY_CC_TOOL_DIR =
|
|
22
|
-
const CLAUDE_SETTINGS_PATH =
|
|
20
|
+
const CC_TOOL_DIR = PATHS.base;
|
|
21
|
+
const LEGACY_CC_TOOL_DIR = PATHS.base;
|
|
22
|
+
const CLAUDE_SETTINGS_PATH = NATIVE_PATHS.claude.settings;
|
|
23
23
|
const LEGACY_PLUGINS_DIR = path.join(LEGACY_CC_TOOL_DIR, 'plugins', 'installed');
|
|
24
24
|
const LEGACY_PLUGINS_REGISTRY = path.join(LEGACY_CC_TOOL_DIR, 'plugins', 'registry.json');
|
|
25
|
-
const
|
|
25
|
+
const CLAUDE_PLUGINS_DIR = path.join(path.dirname(NATIVE_PATHS.claude.settings), 'plugins');
|
|
26
|
+
const NATIVE_PLUGINS_REGISTRY = path.join(CLAUDE_PLUGINS_DIR, 'installed_plugins.json');
|
|
26
27
|
const PLUGIN_IGNORE_DIRS = new Set(['.git', 'node_modules', '.DS_Store']);
|
|
27
28
|
const PLUGIN_IGNORE_FILES = new Set(['.DS_Store']);
|
|
28
29
|
const PLUGIN_SENSITIVE_PATTERNS = [
|
|
@@ -799,7 +800,7 @@ async function importConfigs(importData, options = {}) {
|
|
|
799
800
|
results.plugins.failed++;
|
|
800
801
|
continue;
|
|
801
802
|
}
|
|
802
|
-
targetDir = path.join(
|
|
803
|
+
targetDir = path.join(CLAUDE_PLUGINS_DIR, pluginId);
|
|
803
804
|
registryPath = NATIVE_PLUGINS_REGISTRY;
|
|
804
805
|
} else {
|
|
805
806
|
console.warn(`[ConfigImport] Unknown plugin type: ${pluginType}`);
|
|
@@ -9,19 +9,20 @@
|
|
|
9
9
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
|
-
const
|
|
12
|
+
const { PATHS, NATIVE_PATHS } = require('../../config/paths');
|
|
13
13
|
|
|
14
14
|
// Configuration paths
|
|
15
|
-
const CC_TOOL_DIR =
|
|
15
|
+
const CC_TOOL_DIR = PATHS.base;
|
|
16
16
|
const REGISTRY_FILE = path.join(CC_TOOL_DIR, 'config-registry.json');
|
|
17
17
|
const CONFIGS_DIR = path.join(CC_TOOL_DIR, 'configs');
|
|
18
18
|
|
|
19
19
|
// Claude Code native directories
|
|
20
|
+
const CLAUDE_HOME_DIR = path.dirname(NATIVE_PATHS.claude.settings);
|
|
20
21
|
const CLAUDE_DIRS = {
|
|
21
|
-
skills: path.join(
|
|
22
|
-
commands: path.join(
|
|
23
|
-
agents: path.join(
|
|
24
|
-
plugins: path.join(
|
|
22
|
+
skills: path.join(CLAUDE_HOME_DIR, 'skills'),
|
|
23
|
+
commands: path.join(CLAUDE_HOME_DIR, 'commands'),
|
|
24
|
+
agents: path.join(CLAUDE_HOME_DIR, 'agents'),
|
|
25
|
+
plugins: path.join(CLAUDE_HOME_DIR, 'plugins')
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
// Valid config types
|
|
@@ -20,10 +20,10 @@ const os = require('os');
|
|
|
20
20
|
const toml = require('toml');
|
|
21
21
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
22
22
|
const { convertSkillToCodex, convertCommandToCodex } = require('./format-converter');
|
|
23
|
-
const { PATHS, NATIVE_PATHS, ensureStorageDirMigrated } = require('../../config/paths');
|
|
23
|
+
const { PATHS, NATIVE_PATHS, HOME_DIR, ensureStorageDirMigrated } = require('../../config/paths');
|
|
24
24
|
|
|
25
25
|
// Paths
|
|
26
|
-
const HOME = os.homedir();
|
|
26
|
+
const HOME = HOME_DIR || os.homedir();
|
|
27
27
|
const CC_TOOL_CONFIGS = path.join(PATHS.base, 'configs');
|
|
28
28
|
const CLAUDE_CODE_DIR = path.join(HOME, '.claude');
|
|
29
29
|
const CODEX_DIR = path.join(HOME, '.codex');
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
|
-
const
|
|
18
|
+
const { HOME_DIR } = require('../../config/paths');
|
|
19
19
|
|
|
20
20
|
// 全局配置目录
|
|
21
|
-
const GLOBAL_CONFIG_DIR = path.join(
|
|
21
|
+
const GLOBAL_CONFIG_DIR = path.join(HOME_DIR, '.claude');
|
|
22
22
|
|
|
23
23
|
// 配置类型定义
|
|
24
24
|
const CONFIG_TYPES = {
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
|
-
const os = require('os');
|
|
11
10
|
const crypto = require('crypto');
|
|
11
|
+
const { HOME_DIR } = require('../../config/paths');
|
|
12
12
|
|
|
13
13
|
// 各平台需要检测的环境变量关键词
|
|
14
14
|
const PLATFORM_KEYWORDS = {
|
|
@@ -141,7 +141,7 @@ function checkProcessEnv(keywords) {
|
|
|
141
141
|
*/
|
|
142
142
|
function checkShellConfigs(keywords) {
|
|
143
143
|
const conflicts = [];
|
|
144
|
-
const homeDir =
|
|
144
|
+
const homeDir = HOME_DIR;
|
|
145
145
|
|
|
146
146
|
for (const fileName of SHELL_CONFIG_FILES) {
|
|
147
147
|
const filePath = path.isAbsolute(fileName) ? fileName : path.join(homeDir, fileName);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const
|
|
3
|
-
const os = require('os');
|
|
2
|
+
const { PATHS } = require('../../config/paths');
|
|
4
3
|
|
|
5
|
-
const FAVORITES_DIR =
|
|
6
|
-
const FAVORITES_FILE =
|
|
4
|
+
const FAVORITES_DIR = PATHS.base;
|
|
5
|
+
const FAVORITES_FILE = PATHS.favorites;
|
|
7
6
|
|
|
8
7
|
// 内存缓存
|
|
9
8
|
let favoritesCache = null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const os = require('os');
|
|
4
3
|
const crypto = require('crypto');
|
|
4
|
+
const { PATHS, NATIVE_PATHS } = require('../../config/paths');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Gemini 渠道管理服务(多渠道架构)
|
|
@@ -26,16 +26,16 @@ function normalizeGatewaySourceType(value, fallback = 'gemini') {
|
|
|
26
26
|
|
|
27
27
|
// 获取 Gemini 配置目录
|
|
28
28
|
function getGeminiDir() {
|
|
29
|
-
return path.
|
|
29
|
+
return path.dirname(NATIVE_PATHS.gemini.env);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// 获取渠道存储文件路径
|
|
33
33
|
function getChannelsFilePath() {
|
|
34
|
-
const ccToolDir =
|
|
34
|
+
const ccToolDir = PATHS.base;
|
|
35
35
|
if (!fs.existsSync(ccToolDir)) {
|
|
36
36
|
fs.mkdirSync(ccToolDir, { recursive: true });
|
|
37
37
|
}
|
|
38
|
-
return
|
|
38
|
+
return PATHS.channels.gemini;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// 检查是否在代理模式
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const
|
|
3
|
+
const { NATIVE_PATHS } = require('../../config/paths');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* 获取 Gemini 配置目录
|
|
7
7
|
*/
|
|
8
8
|
function getGeminiDir() {
|
|
9
|
-
return path.
|
|
9
|
+
return path.dirname(NATIVE_PATHS.gemini.env);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const crypto = require('crypto');
|
|
4
|
-
const
|
|
4
|
+
const { HOME_DIR } = require('../../config/paths');
|
|
5
5
|
const { getGeminiDir } = require('./gemini-config');
|
|
6
6
|
|
|
7
7
|
// 路径映射缓存
|
|
@@ -102,7 +102,7 @@ function buildPathMapping() {
|
|
|
102
102
|
|
|
103
103
|
const targetHashes = new Set(projectHashes);
|
|
104
104
|
const results = new Map();
|
|
105
|
-
const homeDir =
|
|
105
|
+
const homeDir = HOME_DIR;
|
|
106
106
|
|
|
107
107
|
// 定义要扫描的目录及其最大深度
|
|
108
108
|
// 深度说明:depth=3 表示可以扫描到 Desktop/a/b/c 这样的 4 层目录
|
|
@@ -362,7 +362,7 @@ function getProjects() {
|
|
|
362
362
|
if (projectPath) {
|
|
363
363
|
displayName = path.basename(projectPath);
|
|
364
364
|
// 如果是 home 目录,显示 ~
|
|
365
|
-
if (projectPath ===
|
|
365
|
+
if (projectPath === HOME_DIR) {
|
|
366
366
|
displayName = '~';
|
|
367
367
|
}
|
|
368
368
|
} else {
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const
|
|
3
|
+
const { NATIVE_PATHS } = require('../../config/paths');
|
|
4
4
|
|
|
5
5
|
// Gemini 配置文件路径
|
|
6
6
|
function getEnvPath() {
|
|
7
|
-
return
|
|
7
|
+
return NATIVE_PATHS.gemini.env;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
function getSettingsPath() {
|
|
11
|
-
return path.join(
|
|
11
|
+
return path.join(path.dirname(NATIVE_PATHS.gemini.env), 'settings.json');
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// 备份文件路径
|
|
15
15
|
function getEnvBackupPath() {
|
|
16
|
-
return
|
|
16
|
+
return NATIVE_PATHS.gemini.envBackup;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function getSettingsBackupPath() {
|
|
20
|
-
return path.join(
|
|
20
|
+
return path.join(path.dirname(NATIVE_PATHS.gemini.env), 'settings.json.cc-tool-backup');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// 检查配置文件是否存在
|
|
@@ -13,15 +13,18 @@ const http = require('http');
|
|
|
13
13
|
const https = require('https');
|
|
14
14
|
const { McpClient } = require('./mcp-client');
|
|
15
15
|
const { NATIVE_PATHS } = require('../../config/paths');
|
|
16
|
+
const { resolvePreferredHomeDir } = require('../../utils/home-dir');
|
|
17
|
+
|
|
18
|
+
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
16
19
|
|
|
17
20
|
// MCP 配置文件路径
|
|
18
|
-
const CC_TOOL_DIR = path.join(
|
|
21
|
+
const CC_TOOL_DIR = path.join(HOME_DIR, '.cc-tool');
|
|
19
22
|
const MCP_SERVERS_FILE = path.join(CC_TOOL_DIR, 'mcp-servers.json');
|
|
20
23
|
|
|
21
24
|
// 各平台配置文件路径
|
|
22
|
-
const CLAUDE_CONFIG_PATH = path.join(
|
|
23
|
-
const CODEX_CONFIG_PATH =
|
|
24
|
-
const GEMINI_CONFIG_PATH = path.join(
|
|
25
|
+
const CLAUDE_CONFIG_PATH = path.join(HOME_DIR, '.claude.json');
|
|
26
|
+
const CODEX_CONFIG_PATH = NATIVE_PATHS.codex.config;
|
|
27
|
+
const GEMINI_CONFIG_PATH = path.join(path.dirname(NATIVE_PATHS.gemini.env), 'settings.json');
|
|
25
28
|
const OPENCODE_CONFIG_DIR = NATIVE_PATHS.opencode.config;
|
|
26
29
|
const OPENCODE_CONFIG_PATHS = {
|
|
27
30
|
jsonc: path.join(OPENCODE_CONFIG_DIR, 'opencode.jsonc'),
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
-
const os = require('os');
|
|
9
8
|
const https = require('https');
|
|
10
9
|
const http = require('http');
|
|
11
10
|
const { URL } = require('url');
|
|
12
11
|
const crypto = require('crypto');
|
|
13
12
|
const zlib = require('zlib');
|
|
14
13
|
const { loadConfig } = require('../../config/loader');
|
|
14
|
+
const { HOME_DIR } = require('../../config/paths');
|
|
15
15
|
|
|
16
16
|
// 内置模型优先级(当配置缺失时兜底)
|
|
17
17
|
const MODEL_PRIORITY = {
|
|
@@ -668,7 +668,7 @@ function collectResponseBody(res) {
|
|
|
668
668
|
* Get cache file path
|
|
669
669
|
*/
|
|
670
670
|
function getCacheFilePath() {
|
|
671
|
-
const dir = path.join(
|
|
671
|
+
const dir = path.join(HOME_DIR, '.cc-tool');
|
|
672
672
|
if (!fs.existsSync(dir)) {
|
|
673
673
|
fs.mkdirSync(dir, { recursive: true });
|
|
674
674
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const os = require('os');
|
|
4
3
|
const crypto = require('crypto');
|
|
4
|
+
const { PATHS } = require('../../config/paths');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* OpenCode 渠道管理服务
|
|
@@ -41,19 +41,19 @@ function normalizeChannelName(value) {
|
|
|
41
41
|
|
|
42
42
|
// 获取渠道存储文件路径
|
|
43
43
|
function getChannelsFilePath() {
|
|
44
|
-
const ccToolDir =
|
|
44
|
+
const ccToolDir = PATHS.base;
|
|
45
45
|
if (!fs.existsSync(ccToolDir)) {
|
|
46
46
|
fs.mkdirSync(ccToolDir, { recursive: true });
|
|
47
47
|
}
|
|
48
|
-
return
|
|
48
|
+
return PATHS.channels.opencode;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function getCodexChannelsFilePath() {
|
|
52
|
-
const ccToolDir =
|
|
52
|
+
const ccToolDir = PATHS.base;
|
|
53
53
|
if (!fs.existsSync(ccToolDir)) {
|
|
54
54
|
fs.mkdirSync(ccToolDir, { recursive: true });
|
|
55
55
|
}
|
|
56
|
-
return
|
|
56
|
+
return PATHS.channels.codex;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// 读取所有渠道
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
-
const os = require('os');
|
|
10
9
|
const { listPlugins, getPlugin, updatePlugin: updatePluginRegistry } = require('../../plugins/registry');
|
|
11
10
|
const { installPlugin: installPluginCore, uninstallPlugin: uninstallPluginCore } = require('../../plugins/plugin-installer');
|
|
12
11
|
const { initializePlugins, shutdownPlugins } = require('../../plugins/plugin-manager');
|
|
13
12
|
const { INSTALLED_DIR, CONFIG_DIR } = require('../../plugins/constants');
|
|
14
|
-
const { NATIVE_PATHS } = require('../../config/paths');
|
|
13
|
+
const { NATIVE_PATHS, HOME_DIR } = require('../../config/paths');
|
|
15
14
|
|
|
16
|
-
const CLAUDE_PLUGINS_DIR = path.join(
|
|
15
|
+
const CLAUDE_PLUGINS_DIR = path.join(path.dirname(NATIVE_PATHS.claude.settings), 'plugins');
|
|
17
16
|
const CLAUDE_INSTALLED_FILE = path.join(CLAUDE_PLUGINS_DIR, 'installed_plugins.json');
|
|
18
17
|
const CLAUDE_MARKETPLACES_FILE = path.join(CLAUDE_PLUGINS_DIR, 'known_marketplaces.json');
|
|
19
18
|
const OPENCODE_CONFIG_DIR = NATIVE_PATHS.opencode.config;
|
|
@@ -107,7 +106,7 @@ function stripJsonComments(input = '') {
|
|
|
107
106
|
class PluginsService {
|
|
108
107
|
constructor(platform = 'claude') {
|
|
109
108
|
this.platform = ['claude', 'opencode'].includes(platform) ? platform : 'claude';
|
|
110
|
-
this.ccToolConfigDir = path.join(
|
|
109
|
+
this.ccToolConfigDir = path.join(HOME_DIR, '.cc-tool');
|
|
111
110
|
this.opencodePluginsDir = path.join(OPENCODE_CONFIG_DIR, 'plugins');
|
|
112
111
|
this.opencodeLegacyPluginsDir = path.join(OPENCODE_CONFIG_DIR, 'plugin');
|
|
113
112
|
}
|
|
@@ -8,15 +8,18 @@ const fs = require('fs');
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const os = require('os');
|
|
10
10
|
const { NATIVE_PATHS } = require('../../config/paths');
|
|
11
|
+
const { resolvePreferredHomeDir } = require('../../utils/home-dir');
|
|
12
|
+
|
|
13
|
+
const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
|
|
11
14
|
|
|
12
15
|
// Prompts 配置文件路径
|
|
13
|
-
const CC_TOOL_DIR = path.join(
|
|
16
|
+
const CC_TOOL_DIR = path.join(HOME_DIR, '.cc-tool');
|
|
14
17
|
const PROMPTS_FILE = path.join(CC_TOOL_DIR, 'prompts.json');
|
|
15
18
|
|
|
16
19
|
// 各平台提示词文件路径
|
|
17
|
-
const CLAUDE_PROMPT_PATH = path.join(
|
|
18
|
-
const CODEX_PROMPT_PATH = path.join(
|
|
19
|
-
const GEMINI_PROMPT_PATH = path.join(
|
|
20
|
+
const CLAUDE_PROMPT_PATH = path.join(HOME_DIR, '.claude', 'CLAUDE.md');
|
|
21
|
+
const CODEX_PROMPT_PATH = path.join(HOME_DIR, '.codex', 'AGENTS.md');
|
|
22
|
+
const GEMINI_PROMPT_PATH = path.join(HOME_DIR, '.gemini', 'GEMINI.md');
|
|
20
23
|
const OPENCODE_PROMPT_PATH = path.join(NATIVE_PATHS.opencode.config, 'AGENTS.md');
|
|
21
24
|
|
|
22
25
|
function normalizeApps(apps = {}, defaults = { claude: true, codex: true, gemini: true, opencode: false }) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const
|
|
3
|
+
const { PATHS } = require('../../config/paths');
|
|
4
4
|
|
|
5
5
|
function getRuntimeFilePath(proxyType) {
|
|
6
|
-
const ccToolDir =
|
|
6
|
+
const ccToolDir = PATHS.base;
|
|
7
7
|
if (!fs.existsSync(ccToolDir)) {
|
|
8
8
|
fs.mkdirSync(ccToolDir, { recursive: true });
|
|
9
9
|
}
|