@adversity/coding-tool-x 3.1.0 → 3.1.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.
Files changed (137) hide show
  1. package/CHANGELOG.md +15 -18
  2. package/README.md +8 -8
  3. package/dist/web/assets/ConfigTemplates-Bidwfdf2.css +1 -0
  4. package/dist/web/assets/ConfigTemplates-ZrK_s7ma.js +1 -0
  5. package/dist/web/assets/Home-B8YfhZ3c.js +1 -0
  6. package/dist/web/assets/Home-Di2qsylF.css +1 -0
  7. package/dist/web/assets/PluginManager-BD7QUZbU.js +1 -0
  8. package/dist/web/assets/PluginManager-ROyoZ-6m.css +1 -0
  9. package/dist/web/assets/ProjectList-C1fQb9OW.css +1 -0
  10. package/dist/web/assets/ProjectList-DRb1DuHV.js +1 -0
  11. package/dist/web/assets/SessionList-BGJWyneI.css +1 -0
  12. package/dist/web/assets/SessionList-lZ0LKzfT.js +1 -0
  13. package/dist/web/assets/SkillManager-C1xG5B4Q.js +1 -0
  14. package/dist/web/assets/SkillManager-D7pd-d_P.css +1 -0
  15. package/dist/web/assets/Terminal-DGNJeVtc.css +1 -0
  16. package/dist/web/assets/Terminal-DksBo_lM.js +1 -0
  17. package/dist/web/assets/WorkspaceManager-Burx7XOo.js +1 -0
  18. package/dist/web/assets/WorkspaceManager-CrwgQgmP.css +1 -0
  19. package/dist/web/assets/icons-kcfLIMBB.js +1 -0
  20. package/dist/web/assets/index-Ufv5rCa5.css +1 -0
  21. package/dist/web/assets/index-lAkrRC3h.js +2 -0
  22. package/dist/web/assets/markdown-BfC0goYb.css +10 -0
  23. package/dist/web/assets/markdown-C9MYpaSi.js +1 -0
  24. package/dist/web/assets/naive-ui-CSrLusZZ.js +1 -0
  25. package/dist/web/assets/{vendors-D2HHw_aW.js → vendors-CO3Upi1d.js} +2 -2
  26. package/dist/web/assets/vue-vendor-DqyWIXEb.js +45 -0
  27. package/dist/web/assets/xterm-6GBZ9nXN.css +32 -0
  28. package/dist/web/assets/xterm-BJzAjXCH.js +13 -0
  29. package/dist/web/index.html +8 -6
  30. package/package.json +4 -2
  31. package/src/commands/channels.js +48 -1
  32. package/src/commands/cli-type.js +4 -2
  33. package/src/commands/daemon.js +81 -12
  34. package/src/commands/doctor.js +10 -9
  35. package/src/commands/list.js +1 -1
  36. package/src/commands/logs.js +6 -4
  37. package/src/commands/port-config.js +24 -4
  38. package/src/commands/proxy-control.js +12 -6
  39. package/src/commands/search.js +1 -1
  40. package/src/commands/security.js +3 -2
  41. package/src/commands/stats.js +226 -52
  42. package/src/commands/switch.js +1 -1
  43. package/src/commands/toggle-proxy.js +31 -6
  44. package/src/commands/update.js +97 -0
  45. package/src/commands/workspace.js +1 -1
  46. package/src/config/default.js +39 -2
  47. package/src/config/loader.js +74 -8
  48. package/src/config/paths.js +105 -33
  49. package/src/index.js +64 -3
  50. package/src/plugins/constants.js +3 -2
  51. package/src/plugins/plugin-api.js +1 -1
  52. package/src/reset-config.js +4 -2
  53. package/src/server/api/agents.js +57 -14
  54. package/src/server/api/channels.js +112 -33
  55. package/src/server/api/codex-channels.js +111 -18
  56. package/src/server/api/codex-proxy.js +14 -8
  57. package/src/server/api/commands.js +71 -18
  58. package/src/server/api/config-export.js +0 -6
  59. package/src/server/api/config-registry.js +11 -3
  60. package/src/server/api/config.js +376 -5
  61. package/src/server/api/convert.js +133 -0
  62. package/src/server/api/dashboard.js +22 -6
  63. package/src/server/api/gemini-channels.js +107 -18
  64. package/src/server/api/gemini-proxy.js +14 -8
  65. package/src/server/api/gemini-sessions.js +1 -1
  66. package/src/server/api/health-check.js +4 -3
  67. package/src/server/api/mcp.js +3 -3
  68. package/src/server/api/opencode-channels.js +419 -0
  69. package/src/server/api/opencode-projects.js +99 -0
  70. package/src/server/api/opencode-proxy.js +198 -0
  71. package/src/server/api/opencode-sessions.js +403 -0
  72. package/src/server/api/opencode-statistics.js +57 -0
  73. package/src/server/api/plugins.js +66 -19
  74. package/src/server/api/prompts.js +2 -2
  75. package/src/server/api/proxy.js +7 -4
  76. package/src/server/api/sessions.js +3 -0
  77. package/src/server/api/skills.js +69 -18
  78. package/src/server/api/workspaces.js +78 -6
  79. package/src/server/codex-proxy-server.js +30 -18
  80. package/src/server/dev-server.js +1 -1
  81. package/src/server/gemini-proxy-server.js +15 -3
  82. package/src/server/index.js +165 -58
  83. package/src/server/opencode-proxy-server.js +4375 -0
  84. package/src/server/proxy-server.js +27 -18
  85. package/src/server/services/agents-service.js +61 -24
  86. package/src/server/services/channel-scheduler.js +9 -5
  87. package/src/server/services/channels.js +64 -37
  88. package/src/server/services/codex-channels.js +56 -43
  89. package/src/server/services/codex-settings-manager.js +271 -49
  90. package/src/server/services/codex-statistics-service.js +2 -2
  91. package/src/server/services/commands-service.js +84 -25
  92. package/src/server/services/config-export-service.js +7 -45
  93. package/src/server/services/config-registry-service.js +63 -17
  94. package/src/server/services/config-sync-manager.js +160 -7
  95. package/src/server/services/config-templates-service.js +204 -51
  96. package/src/server/services/env-checker.js +26 -12
  97. package/src/server/services/env-manager.js +126 -18
  98. package/src/server/services/favorites.js +5 -3
  99. package/src/server/services/gemini-channels.js +33 -44
  100. package/src/server/services/gemini-statistics-service.js +2 -2
  101. package/src/server/services/mcp-service.js +350 -9
  102. package/src/server/services/model-detector.js +707 -221
  103. package/src/server/services/network-access.js +80 -0
  104. package/src/server/services/opencode-channels.js +206 -0
  105. package/src/server/services/opencode-gateway-converter.js +639 -0
  106. package/src/server/services/opencode-sessions.js +663 -0
  107. package/src/server/services/opencode-settings-manager.js +342 -0
  108. package/src/server/services/opencode-statistics-service.js +255 -0
  109. package/src/server/services/plugins-service.js +479 -22
  110. package/src/server/services/prompts-service.js +53 -11
  111. package/src/server/services/proxy-runtime.js +1 -1
  112. package/src/server/services/repo-scanner-base.js +1 -1
  113. package/src/server/services/security-config.js +1 -1
  114. package/src/server/services/session-cache.js +1 -1
  115. package/src/server/services/skill-service.js +300 -46
  116. package/src/server/services/speed-test.js +464 -186
  117. package/src/server/services/statistics-service.js +2 -2
  118. package/src/server/services/terminal-commands.js +10 -3
  119. package/src/server/services/terminal-config.js +1 -1
  120. package/src/server/services/ui-config.js +1 -1
  121. package/src/server/services/workspace-service.js +57 -100
  122. package/src/server/websocket-server.js +132 -3
  123. package/src/ui/menu.js +49 -40
  124. package/src/utils/port-helper.js +22 -8
  125. package/src/utils/session.js +5 -4
  126. package/dist/web/assets/icons-CO_2OFES.js +0 -1
  127. package/dist/web/assets/index-DI8QOi-E.js +0 -14
  128. package/dist/web/assets/index-uLHGdeZh.css +0 -41
  129. package/dist/web/assets/naive-ui-B1re3c-e.js +0 -1
  130. package/dist/web/assets/vue-vendor-6JaYHOiI.js +0 -44
  131. package/src/server/api/oauth.js +0 -294
  132. package/src/server/api/permissions.js +0 -385
  133. package/src/server/config/oauth-providers.js +0 -68
  134. package/src/server/services/oauth-callback-server.js +0 -284
  135. package/src/server/services/oauth-service.js +0 -378
  136. package/src/server/services/oauth-token-storage.js +0 -135
  137. package/src/server/services/permission-templates-service.js +0 -308
@@ -3,9 +3,18 @@ const fs = require('fs');
3
3
  const path = require('path');
4
4
  const os = require('os');
5
5
  const DEFAULT_CONFIG = require('./default');
6
+ const { PATHS, ensureStorageDirMigrated } = require('./paths');
6
7
  const eventBus = require('../plugins/event-bus');
7
8
 
8
- const CONFIG_FILE = path.join(__dirname, '../../config.json');
9
+ const LEGACY_CONFIG_FILES = [
10
+ path.join(__dirname, '../../config.json'),
11
+ path.join(os.homedir(), '.claude', 'config.json')
12
+ ];
13
+
14
+ function getConfigFilePath() {
15
+ ensureStorageDirMigrated();
16
+ return PATHS.configFile;
17
+ }
9
18
 
10
19
  /**
11
20
  * 展开 ~ 为用户主目录
@@ -31,19 +40,66 @@ function mergePricing(defaultPricing, overrides = {}) {
31
40
  return merged;
32
41
  }
33
42
 
43
+ function mergeDefaultModels(defaultModels, overrides = {}) {
44
+ const merged = {};
45
+ Object.keys(defaultModels).forEach((key) => {
46
+ // If user config has this tool type, use it; otherwise use default
47
+ merged[key] = (overrides && overrides[key]) ? overrides[key] : defaultModels[key];
48
+ });
49
+ return merged;
50
+ }
51
+
52
+ function mergeModelDiscovery(defaultModelDiscovery, overrides = {}) {
53
+ return {
54
+ ...defaultModelDiscovery,
55
+ ...(overrides || {})
56
+ };
57
+ }
58
+
59
+ function readJsonFile(filePath) {
60
+ const content = fs.readFileSync(filePath, 'utf8');
61
+ return JSON.parse(content);
62
+ }
63
+
64
+ function migrateLegacyConfigIfNeeded(configFilePath) {
65
+ if (fs.existsSync(configFilePath)) return;
66
+
67
+ for (const legacyPath of LEGACY_CONFIG_FILES) {
68
+ try {
69
+ if (!legacyPath || legacyPath === configFilePath) continue;
70
+ if (!fs.existsSync(legacyPath)) continue;
71
+ const legacyConfig = readJsonFile(legacyPath);
72
+ const dir = path.dirname(configFilePath);
73
+ if (!fs.existsSync(dir)) {
74
+ fs.mkdirSync(dir, { recursive: true });
75
+ }
76
+ fs.writeFileSync(configFilePath, JSON.stringify(legacyConfig, null, 2), 'utf8');
77
+ console.log(`[Config] 已迁移历史配置: ${legacyPath} -> ${configFilePath}`);
78
+ return;
79
+ } catch (error) {
80
+ console.warn(`[Config] 迁移历史配置失败: ${legacyPath}`, error.message);
81
+ }
82
+ }
83
+ }
84
+
34
85
  /**
35
86
  * 加载配置
36
87
  */
37
88
  function loadConfig() {
89
+ const configFilePath = getConfigFilePath();
90
+ migrateLegacyConfigIfNeeded(configFilePath);
91
+
38
92
  try {
39
- if (fs.existsSync(CONFIG_FILE)) {
40
- const userConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
93
+ if (fs.existsSync(configFilePath)) {
94
+ const userConfig = readJsonFile(configFilePath);
41
95
  const config = { ...DEFAULT_CONFIG, ...userConfig };
42
- config.projectsDir = expandHome(config.projectsDir);
96
+ config.projectsDir = expandHome(config.projectsDir || DEFAULT_CONFIG.projectsDir);
43
97
 
44
98
  // 合并 ports 配置
45
99
  config.ports = { ...DEFAULT_CONFIG.ports, ...userConfig.ports };
46
100
  config.pricing = mergePricing(DEFAULT_CONFIG.pricing, userConfig.pricing);
101
+ config.defaultModels = mergeDefaultModels(DEFAULT_CONFIG.defaultModels, userConfig.defaultModels);
102
+ config.modelDiscovery = mergeModelDiscovery(DEFAULT_CONFIG.modelDiscovery, userConfig.modelDiscovery);
47
103
 
48
104
  // 确保有 currentProject,使用 defaultProject 作为 currentProject
49
105
  if (!config.currentProject && config.defaultProject) {
@@ -54,9 +110,13 @@ function loadConfig() {
54
110
  return config;
55
111
  }
56
112
  } catch (error) {
57
- console.error('加载配置文件失败,使用默认配置');
113
+ console.error(`加载配置文件失败,使用默认配置: ${configFilePath}`);
58
114
  }
59
- const defaultConfig = { ...DEFAULT_CONFIG, currentProject: DEFAULT_CONFIG.defaultProject };
115
+ const defaultConfig = {
116
+ ...DEFAULT_CONFIG,
117
+ projectsDir: expandHome(DEFAULT_CONFIG.projectsDir),
118
+ currentProject: DEFAULT_CONFIG.defaultProject
119
+ };
60
120
  eventBus.emitSync('config:loaded', { config: defaultConfig });
61
121
  return defaultConfig;
62
122
  }
@@ -65,11 +125,16 @@ function loadConfig() {
65
125
  * 保存配置
66
126
  */
67
127
  function saveConfig(config) {
128
+ const configFilePath = getConfigFilePath();
68
129
  try {
69
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
130
+ const dir = path.dirname(configFilePath);
131
+ if (!fs.existsSync(dir)) {
132
+ fs.mkdirSync(dir, { recursive: true });
133
+ }
134
+ fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2), 'utf8');
70
135
  eventBus.emitSync('config:saved', { config });
71
136
  } catch (error) {
72
- console.error('保存配置失败:', error.message);
137
+ console.error(`保存配置失败 (${configFilePath}):`, error.message);
73
138
  }
74
139
  }
75
140
 
@@ -77,4 +142,5 @@ module.exports = {
77
142
  loadConfig,
78
143
  saveConfig,
79
144
  expandHome,
145
+ getConfigFilePath
80
146
  };
@@ -1,90 +1,149 @@
1
1
  // CTX 工具路径配置
2
- // 所有路径统一使用 ~/.claude/ctx 目录,避免与原始 cc-tool 冲突
2
+ // 所有路径统一使用 ~/.cc-tool 目录
3
+ const fs = require('fs');
3
4
  const path = require('path');
4
5
  const os = require('os');
5
6
 
6
7
  // 基础目录
7
- const CTX_BASE_DIR = path.join(os.homedir(), '.claude', 'ctx');
8
+ const CC_TOOL_BASE_DIR = path.join(os.homedir(), '.cc-tool');
9
+ // 兼容旧变量名,避免外部调用方断裂
10
+ const CTX_BASE_DIR = CC_TOOL_BASE_DIR;
11
+
12
+ // 旧目录(升级时自动合并到 ~/.cc-tool)
13
+ const LEGACY_BASE_DIRS = [
14
+ path.join(os.homedir(), '.claude', 'ctx'),
15
+ path.join(os.homedir(), '.claude', 'cc-tool')
16
+ ];
17
+
18
+ let migrationChecked = false;
19
+
20
+ function mergeDirectory(sourceDir, targetDir) {
21
+ if (!fs.existsSync(sourceDir)) return;
22
+
23
+ const sourceStat = fs.statSync(sourceDir);
24
+ if (sourceStat.isDirectory()) {
25
+ if (!fs.existsSync(targetDir)) {
26
+ fs.mkdirSync(targetDir, { recursive: true });
27
+ }
28
+
29
+ const entries = fs.readdirSync(sourceDir);
30
+ entries.forEach((entry) => {
31
+ mergeDirectory(path.join(sourceDir, entry), path.join(targetDir, entry));
32
+ });
33
+ return;
34
+ }
35
+
36
+ if (!fs.existsSync(targetDir)) {
37
+ fs.copyFileSync(sourceDir, targetDir);
38
+ }
39
+ }
40
+
41
+ function ensureStorageDirMigrated() {
42
+ if (migrationChecked) {
43
+ return CC_TOOL_BASE_DIR;
44
+ }
45
+ migrationChecked = true;
46
+
47
+ if (!fs.existsSync(CC_TOOL_BASE_DIR)) {
48
+ fs.mkdirSync(CC_TOOL_BASE_DIR, { recursive: true });
49
+ }
50
+
51
+ LEGACY_BASE_DIRS.forEach((legacyDir) => {
52
+ if (!fs.existsSync(legacyDir)) return;
53
+ try {
54
+ mergeDirectory(legacyDir, CC_TOOL_BASE_DIR);
55
+ } catch (error) {
56
+ console.warn(`[paths] 迁移目录失败: ${legacyDir} -> ${CC_TOOL_BASE_DIR}`, error.message);
57
+ }
58
+ });
59
+
60
+ return CC_TOOL_BASE_DIR;
61
+ }
8
62
 
9
63
  // 路径配置
10
64
  const PATHS = {
11
65
  // 基础目录
12
- base: CTX_BASE_DIR,
66
+ base: CC_TOOL_BASE_DIR,
13
67
 
14
68
  // 项目目录(存储项目配置和会话)
15
- projects: path.join(CTX_BASE_DIR, 'projects'),
69
+ projects: path.join(CC_TOOL_BASE_DIR, 'projects'),
16
70
 
17
71
  // 配置文件目录
18
- config: path.join(CTX_BASE_DIR, 'config'),
19
- configFile: path.join(CTX_BASE_DIR, 'config.json'),
72
+ config: path.join(CC_TOOL_BASE_DIR, 'config'),
73
+ configFile: path.join(CC_TOOL_BASE_DIR, 'config.json'),
20
74
 
21
75
  // 日志目录
22
- logs: path.join(CTX_BASE_DIR, 'logs'),
76
+ logs: path.join(CC_TOOL_BASE_DIR, 'logs'),
23
77
 
24
78
  // 别名存储
25
- aliases: path.join(CTX_BASE_DIR, 'aliases.json'),
79
+ aliases: path.join(CC_TOOL_BASE_DIR, 'aliases.json'),
26
80
 
27
81
  // 收藏夹存储
28
- favorites: path.join(CTX_BASE_DIR, 'favorites.json'),
82
+ favorites: path.join(CC_TOOL_BASE_DIR, 'favorites.json'),
29
83
 
30
84
  // 渠道配置
31
85
  channels: {
32
- claude: path.join(CTX_BASE_DIR, 'channels.json'),
33
- codex: path.join(CTX_BASE_DIR, 'codex-channels.json'),
34
- gemini: path.join(CTX_BASE_DIR, 'gemini-channels.json')
86
+ claude: path.join(CC_TOOL_BASE_DIR, 'channels.json'),
87
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-channels.json'),
88
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-channels.json'),
89
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-channels.json')
35
90
  },
36
91
 
37
92
  // 激活渠道标记
38
93
  activeChannel: {
39
- claude: path.join(CTX_BASE_DIR, 'active-channel.json'),
40
- codex: path.join(CTX_BASE_DIR, 'codex-active-channel.json'),
41
- gemini: path.join(CTX_BASE_DIR, 'gemini-active-channel.json')
94
+ claude: path.join(CC_TOOL_BASE_DIR, 'active-channel.json'),
95
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-active-channel.json'),
96
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-active-channel.json'),
97
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-active-channel.json')
42
98
  },
43
99
 
44
100
  // 统计数据
45
101
  statistics: {
46
- claude: path.join(CTX_BASE_DIR, 'statistics.json'),
47
- codex: path.join(CTX_BASE_DIR, 'codex-statistics.json'),
48
- gemini: path.join(CTX_BASE_DIR, 'gemini-statistics.json'),
102
+ claude: path.join(CC_TOOL_BASE_DIR, 'statistics.json'),
103
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-statistics.json'),
104
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-statistics.json'),
105
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-statistics.json'),
49
106
  dailyStats: {
50
- claude: path.join(CTX_BASE_DIR, 'daily-stats'),
51
- codex: path.join(CTX_BASE_DIR, 'codex-daily-stats'),
52
- gemini: path.join(CTX_BASE_DIR, 'gemini-daily-stats')
107
+ claude: path.join(CC_TOOL_BASE_DIR, 'daily-stats'),
108
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-daily-stats'),
109
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-daily-stats'),
110
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-daily-stats')
53
111
  }
54
112
  },
55
113
 
56
114
  // 会话缓存
57
- sessionCache: path.join(CTX_BASE_DIR, 'session-cache.json'),
115
+ sessionCache: path.join(CC_TOOL_BASE_DIR, 'session-cache.json'),
58
116
 
59
117
  // 项目顺序
60
- projectOrder: path.join(CTX_BASE_DIR, 'project-order.json'),
118
+ projectOrder: path.join(CC_TOOL_BASE_DIR, 'project-order.json'),
61
119
 
62
120
  // 环境备份
63
- envBackups: path.join(CTX_BASE_DIR, 'env-backups'),
121
+ envBackups: path.join(CC_TOOL_BASE_DIR, 'env-backups'),
64
122
 
65
123
  // UI 配置
66
- uiConfig: path.join(CTX_BASE_DIR, 'ui-config.json'),
124
+ uiConfig: path.join(CC_TOOL_BASE_DIR, 'ui-config.json'),
67
125
 
68
126
  // 飞书通知脚本
69
- notifyHook: path.join(CTX_BASE_DIR, 'notify-hook.js'),
127
+ notifyHook: path.join(CC_TOOL_BASE_DIR, 'notify-hook.js'),
70
128
 
71
129
  // Skills 安装目录(注意:这个仍使用 Claude 原生路径)
72
130
  skills: path.join(os.homedir(), '.claude', 'skills'),
73
131
 
74
132
  // MCP 配置(注意:这个仍使用 Claude 原生路径)
75
- mcpConfig: path.join(CTX_BASE_DIR, 'mcp-config.json'),
133
+ mcpConfig: path.join(CC_TOOL_BASE_DIR, 'mcp-config.json'),
76
134
 
77
135
  // Terminal 配置
78
- terminalConfig: path.join(CTX_BASE_DIR, 'terminal-config.json'),
136
+ terminalConfig: path.join(CC_TOOL_BASE_DIR, 'terminal-config.json'),
79
137
 
80
138
  // Prompts
81
- prompts: path.join(CTX_BASE_DIR, 'prompts.json'),
139
+ prompts: path.join(CC_TOOL_BASE_DIR, 'prompts.json'),
82
140
 
83
141
  // 代理运行时状态
84
142
  proxyRuntime: {
85
- claude: path.join(CTX_BASE_DIR, 'proxy-runtime.json'),
86
- codex: path.join(CTX_BASE_DIR, 'codex-proxy-runtime.json'),
87
- gemini: path.join(CTX_BASE_DIR, 'gemini-proxy-runtime.json')
143
+ claude: path.join(CC_TOOL_BASE_DIR, 'proxy-runtime.json'),
144
+ codex: path.join(CC_TOOL_BASE_DIR, 'codex-proxy-runtime.json'),
145
+ gemini: path.join(CC_TOOL_BASE_DIR, 'gemini-proxy-runtime.json'),
146
+ opencode: path.join(CC_TOOL_BASE_DIR, 'opencode-proxy-runtime.json')
88
147
  }
89
148
  };
90
149
 
@@ -111,11 +170,24 @@ const NATIVE_PATHS = {
111
170
  env: path.join(os.homedir(), '.gemini', '.env'),
112
171
  envBackup: path.join(os.homedir(), '.gemini', '.env.cc-tool-backup'),
113
172
  tmp: path.join(os.homedir(), '.gemini', 'tmp')
173
+ },
174
+
175
+ // OpenCode 原生配置
176
+ opencode: {
177
+ data: path.join(os.homedir(), '.local', 'share', 'opencode'),
178
+ config: path.join(os.homedir(), '.config', 'opencode'),
179
+ sessions: path.join(os.homedir(), '.local', 'share', 'opencode', 'storage', 'session'),
180
+ projects: path.join(os.homedir(), '.local', 'share', 'opencode', 'storage', 'project'),
181
+ messages: path.join(os.homedir(), '.local', 'share', 'opencode', 'storage', 'message'),
182
+ log: path.join(os.homedir(), '.local', 'share', 'opencode', 'log')
114
183
  }
115
184
  };
116
185
 
117
186
  module.exports = {
118
187
  PATHS,
119
188
  NATIVE_PATHS,
120
- CTX_BASE_DIR
189
+ CTX_BASE_DIR,
190
+ CC_TOOL_BASE_DIR,
191
+ LEGACY_BASE_DIRS,
192
+ ensureStorageDirMigrated
121
193
  };
package/src/index.js CHANGED
@@ -20,7 +20,9 @@ const { handleProxyStart: proxyStart, handleProxyStop: proxyStop, handleProxyRes
20
20
  const { handleLogs } = require('./commands/logs');
21
21
  const { handleStats, handleStatsExport } = require('./commands/stats');
22
22
  const { handleDoctor } = require('./commands/doctor');
23
+ const { handleUpdate } = require('./commands/update');
23
24
  const { workspaceMenu } = require('./commands/workspace');
25
+ const { ensureStorageDirMigrated } = require('./config/paths');
24
26
  const PluginManager = require('./plugins/plugin-manager');
25
27
  const eventBus = require('./plugins/event-bus');
26
28
  const chalk = require('chalk');
@@ -61,7 +63,8 @@ function showHelp() {
61
63
  console.log(' ctx claude status 查看 Claude 代理状态');
62
64
  console.log(' ctx codex start 启动 Codex 代理');
63
65
  console.log(' ctx gemini start 启动 Gemini 代理');
64
- console.log(chalk.gray(' (codex/gemini 命令与 claude 类似)\n'));
66
+ console.log(' ctx opencode start 启动 OpenCode 代理');
67
+ console.log(chalk.gray(' (codex/gemini/opencode 命令与 claude 类似)\n'));
65
68
 
66
69
  console.log(chalk.yellow('📋 日志管理:'));
67
70
  console.log(' ctx logs 查看所有日志');
@@ -78,7 +81,9 @@ function showHelp() {
78
81
  console.log(' ctx stats export 导出统计数据\n');
79
82
 
80
83
  console.log(chalk.yellow('🛠️ 其他命令:'));
84
+ console.log(' ctx update 检查并更新到最新版本');
81
85
  console.log(' ctx doctor 系统诊断');
86
+ console.log(' ctx port 配置端口');
82
87
  console.log(' ctx reset 重置配置');
83
88
  console.log(' ctx security reset 关闭访问密码');
84
89
  console.log(' ctx --version, -v 显示版本');
@@ -132,6 +137,8 @@ process.on('SIGINT', async () => {
132
137
  * 主函数
133
138
  */
134
139
  async function main() {
140
+ ensureStorageDirMigrated();
141
+
135
142
  // 处理命令行参数
136
143
  const args = process.argv.slice(2);
137
144
 
@@ -147,6 +154,47 @@ async function main() {
147
154
  return;
148
155
  }
149
156
 
157
+ // daemon 命令兼容(保持与 README 中旧命令一致)
158
+ if (args[0] === 'daemon') {
159
+ const subCommand = args[1] || 'status';
160
+
161
+ if (subCommand === 'start') {
162
+ await handleStart();
163
+ return;
164
+ }
165
+ if (subCommand === 'stop') {
166
+ await handleStop();
167
+ return;
168
+ }
169
+ if (subCommand === 'restart') {
170
+ await handleRestart();
171
+ return;
172
+ }
173
+ if (subCommand === 'status') {
174
+ await handleStatus();
175
+ return;
176
+ }
177
+ if (subCommand === 'logs') {
178
+ const options = {};
179
+ for (let i = 2; i < args.length; i++) {
180
+ if (args[i] === '--lines' && args[i + 1]) {
181
+ options.lines = parseInt(args[i + 1], 10);
182
+ i++;
183
+ } else if (args[i] === '--follow' || args[i] === '-f') {
184
+ options.follow = true;
185
+ } else if (args[i] === '--clear') {
186
+ options.clear = true;
187
+ }
188
+ }
189
+ await handleLogs('ui', options);
190
+ return;
191
+ }
192
+
193
+ console.log(chalk.red(`\n❌ 未知 daemon 子命令: ${subCommand}\n`));
194
+ console.log(chalk.gray('支持的命令: start, stop, restart, status, logs\n'));
195
+ return;
196
+ }
197
+
150
198
  // reset 命令 - 恢复默认配置
151
199
  if (args[0] === 'reset') {
152
200
  await resetConfig();
@@ -207,8 +255,8 @@ async function main() {
207
255
  return;
208
256
  }
209
257
 
210
- // claude/codex/gemini 代理管理命令
211
- const channels = ['claude', 'codex', 'gemini'];
258
+ // claude/codex/gemini/opencode 代理管理命令
259
+ const channels = ['claude', 'codex', 'gemini', 'opencode'];
212
260
  if (channels.includes(args[0])) {
213
261
  const channel = args[0];
214
262
  const action = args[1] || 'status';
@@ -281,6 +329,19 @@ async function main() {
281
329
  return;
282
330
  }
283
331
 
332
+ // update 命令 - 检查并更新到最新版本
333
+ if (args[0] === 'update') {
334
+ const checkOnly = args.includes('--check');
335
+ await handleUpdate({ checkOnly });
336
+ return;
337
+ }
338
+
339
+ // port 命令 - 配置端口
340
+ if (args[0] === 'port') {
341
+ await handlePortConfig();
342
+ return;
343
+ }
344
+
284
345
  // 代理命令
285
346
  if (args[0] === 'proxy') {
286
347
  const { handleProxyStart, handleProxyStop, handleProxyStatus } = require('./commands/proxy');
@@ -1,7 +1,8 @@
1
1
  const path = require('path');
2
- const os = require('os');
2
+ const { PATHS, ensureStorageDirMigrated } = require('../config/paths');
3
3
 
4
- const PLUGINS_DIR = path.join(os.homedir(), '.claude', 'cc-tool', 'plugins');
4
+ ensureStorageDirMigrated();
5
+ const PLUGINS_DIR = path.join(PATHS.base, 'plugins');
5
6
  const REGISTRY_FILE = path.join(PLUGINS_DIR, 'registry.json');
6
7
  const CONFIG_DIR = path.join(PLUGINS_DIR, 'config');
7
8
  const INSTALLED_DIR = path.join(PLUGINS_DIR, 'installed');
@@ -15,7 +15,7 @@ const packageJson = require('../../package.json');
15
15
  function createPluginContext(pluginName, pluginConfig, pluginDir) {
16
16
  const commandRegistry = new Map();
17
17
 
18
- // Storage API - persists plugin data to ~/.claude/cc-tool/plugins/config/<plugin-name>.json
18
+ // Storage API - persists plugin data to ~/.cc-tool/plugins/config/<plugin-name>.json
19
19
  const storage = createStorageAPI(pluginName);
20
20
 
21
21
  // Logger API - prefixed logging
@@ -1,10 +1,12 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const os = require('os');
4
+ const { PATHS, ensureStorageDirMigrated } = require('./config/paths');
4
5
 
5
6
  // 恢复配置到默认状态
6
7
  async function resetConfig() {
7
8
  console.log('\n开始恢复默认配置...\n');
9
+ ensureStorageDirMigrated();
8
10
 
9
11
  try {
10
12
  // 1. 尝试停止代理服务器(如果正在运行)
@@ -42,10 +44,10 @@ async function resetConfig() {
42
44
  console.log('检测到代理配置,尝试恢复到正常渠道...');
43
45
 
44
46
  // 读取激活的渠道
45
- const activeChannelPath = path.join(os.homedir(), '.claude', 'cc-tool', 'active-channel.json');
47
+ const activeChannelPath = PATHS.activeChannel.claude;
46
48
  if (fs.existsSync(activeChannelPath)) {
47
49
  const activeChannelData = JSON.parse(fs.readFileSync(activeChannelPath, 'utf8'));
48
- const channelsPath = path.join(os.homedir(), '.claude', 'cc-tool', 'channels.json');
50
+ const channelsPath = PATHS.channels.claude;
49
51
 
50
52
  if (fs.existsSync(channelsPath)) {
51
53
  const channelsData = JSON.parse(fs.readFileSync(channelsPath, 'utf8'));