coding-tool-x 3.5.9 → 3.5.11

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 (92) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +4 -25
  3. package/bin/ctx.js +1 -6
  4. package/dist/web/assets/{Analytics-C5W3axXs.js → Analytics-Bw-0r4Ys.js} +2 -2
  5. package/dist/web/assets/Analytics-RNn1BUbG.css +1 -0
  6. package/dist/web/assets/{ConfigTemplates-DzyVFDx9.js → ConfigTemplates-C6QRIeDj.js} +1 -1
  7. package/dist/web/assets/Home-BQxQ1LhR.css +1 -0
  8. package/dist/web/assets/{Home-C9TQNB6f.js → Home-B_Z9ythw.js} +1 -1
  9. package/dist/web/assets/{PluginManager-9B_brLWT.js → PluginManager-Ce-mws6Q.js} +1 -1
  10. package/dist/web/assets/ProjectList-9Z7FFCIT.js +1 -0
  11. package/dist/web/assets/ProjectList-DL4JK6ci.css +1 -0
  12. package/dist/web/assets/SessionList-CyETQcs8.js +1 -0
  13. package/dist/web/assets/SessionList-D12muXvx.css +1 -0
  14. package/dist/web/assets/{SkillManager-vST8DRRg.js → SkillManager-DSUcP1se.js} +1 -1
  15. package/dist/web/assets/{WorkspaceManager-ov1KgRXR.js → WorkspaceManager-Cvbc11bJ.js} +1 -1
  16. package/dist/web/assets/icons-lKCTySl7.js +1 -0
  17. package/dist/web/assets/index-BS7aplYp.css +1 -0
  18. package/dist/web/assets/index-CTeg1xG-.js +2 -0
  19. package/dist/web/assets/{markdown-DyTJGI4N.js → markdown-BNJfEgCA.js} +1 -1
  20. package/dist/web/assets/{naive-ui-Cg4_ZeoT.js → naive-ui-DM897mIP.js} +1 -1
  21. package/dist/web/assets/vendors-DQA4Hw9v.js +7 -0
  22. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +45 -0
  23. package/dist/web/index.html +8 -8
  24. package/package.json +1 -2
  25. package/src/commands/daemon.js +5 -33
  26. package/src/commands/export-config.js +6 -6
  27. package/src/commands/stats.js +4 -41
  28. package/src/commands/ui.js +3 -12
  29. package/src/config/channel-preset-websites.js +114 -0
  30. package/src/config/default.js +9 -5
  31. package/src/config/loader.js +2 -2
  32. package/src/config/model-metadata.json +16 -20
  33. package/src/config/paths.js +33 -166
  34. package/src/index.js +34 -125
  35. package/src/server/api/agents.js +2 -52
  36. package/src/server/api/codex-channels.js +4 -0
  37. package/src/server/api/codex-proxy.js +45 -2
  38. package/src/server/api/codex-sessions.js +89 -12
  39. package/src/server/api/commands.js +2 -38
  40. package/src/server/api/dashboard.js +1 -25
  41. package/src/server/api/gemini-proxy.js +4 -2
  42. package/src/server/api/gemini-sessions.js +86 -9
  43. package/src/server/api/hooks.js +1 -17
  44. package/src/server/api/opencode-proxy.js +7 -2
  45. package/src/server/api/opencode-sessions.js +83 -10
  46. package/src/server/api/plugins.js +34 -128
  47. package/src/server/api/proxy.js +5 -3
  48. package/src/server/api/sessions.js +181 -27
  49. package/src/server/api/workspaces.js +0 -14
  50. package/src/server/index.js +9 -31
  51. package/src/server/services/agents-service.js +62 -269
  52. package/src/server/services/base/base-channel-service.js +3 -1
  53. package/src/server/services/channels.js +5 -0
  54. package/src/server/services/codex-channels.js +2 -0
  55. package/src/server/services/codex-sessions.js +88 -108
  56. package/src/server/services/commands-service.js +81 -281
  57. package/src/server/services/config-export-service.js +7 -7
  58. package/src/server/services/config-registry-service.js +9 -8
  59. package/src/server/services/config-sync-manager.js +41 -61
  60. package/src/server/services/config-sync-service.js +3 -3
  61. package/src/server/services/gemini-channels.js +17 -6
  62. package/src/server/services/gemini-config.js +4 -3
  63. package/src/server/services/gemini-sessions.js +59 -26
  64. package/src/server/services/gemini-settings-manager.js +3 -2
  65. package/src/server/services/mcp-service.js +14 -9
  66. package/src/server/services/native-oauth-adapters.js +3 -3
  67. package/src/server/services/network-access.js +2 -61
  68. package/src/server/services/notification-hooks.js +19 -184
  69. package/src/server/services/opencode-channels.js +9 -0
  70. package/src/server/services/opencode-sessions.js +6 -16
  71. package/src/server/services/opencode-settings-manager.js +3 -3
  72. package/src/server/services/plugins-service.js +62 -996
  73. package/src/server/services/prompts-service.js +9 -5
  74. package/src/server/services/sessions.js +171 -183
  75. package/src/server/services/skill-service.js +18 -155
  76. package/src/server/websocket-server.js +4 -35
  77. package/dist/web/assets/Analytics-vQS5IWvs.css +0 -1
  78. package/dist/web/assets/Home-qzk118Of.css +0 -1
  79. package/dist/web/assets/ProjectList-Bjt6mrsV.js +0 -1
  80. package/dist/web/assets/ProjectList-GCC2QOmq.css +0 -1
  81. package/dist/web/assets/SessionList-BsHPgmUR.css +0 -1
  82. package/dist/web/assets/SessionList-DcBH13uA.js +0 -1
  83. package/dist/web/assets/icons-CEq2hYB-.js +0 -1
  84. package/dist/web/assets/index-Dih_bOsv.css +0 -1
  85. package/dist/web/assets/index-Duc7QP4e.js +0 -2
  86. package/dist/web/assets/vendors-Bsp-dq2d.js +0 -7
  87. package/dist/web/assets/vue-vendor-BxIT0uQq.js +0 -45
  88. package/docs/Caddyfile.example +0 -19
  89. package/docs/reverse-proxy-https.md +0 -57
  90. package/src/server/services/https-cert.js +0 -171
  91. package/src/server/services/session-launch-command.js +0 -58
  92. package/src/server/services/web-ui-runtime.js +0 -54
@@ -28,9 +28,6 @@ const REPOS_SKILLS_DIR = path.join(REPOS_DIR, 'skills');
28
28
  const REPOS_PLUGINS_DIR = path.join(REPOS_DIR, 'plugins');
29
29
  const LOCAL_DIR = path.join(STORAGE_DIR, 'local');
30
30
  const LOCAL_SKILLS_DIR = path.join(LOCAL_DIR, 'skills');
31
- const LOCAL_COMMANDS_DIR = path.join(LOCAL_DIR, 'commands');
32
- const LOCAL_AGENTS_DIR = path.join(LOCAL_DIR, 'agents');
33
- const LOCAL_PLUGINS_DIR = path.join(LOCAL_DIR, 'plugins');
34
31
  const REQUESTS_DIR = path.join(STORAGE_DIR, 'requests');
35
32
  const BACKUPS_DIR = path.join(STORAGE_DIR, 'backups');
36
33
  const SCRIPTS_DIR = path.join(STORAGE_DIR, 'scripts');
@@ -42,8 +39,8 @@ const LEGACY_STATS_DIR = path.join(LEGACY_DIR, 'stats');
42
39
 
43
40
  // 旧目录(升级时自动合并到 ~/.cc-tool)
44
41
  const LEGACY_BASE_DIRS = [
45
- joinNativeBasePath(HOME_DIR, '.claude', 'ctx'),
46
- joinNativeBasePath(HOME_DIR, '.claude', 'cc-tool')
42
+ path.join(HOME_DIR, '.claude', 'ctx'),
43
+ path.join(HOME_DIR, '.claude', 'cc-tool')
47
44
  ];
48
45
 
49
46
  let migrationChecked = false;
@@ -453,12 +450,6 @@ const PATHS = {
453
450
 
454
451
  // 脚本
455
452
  notifyHook: path.join(SCRIPTS_DIR, 'notify-hook.js'),
456
- https: {
457
- dir: path.join(CONFIG_DIR, 'https'),
458
- key: path.join(CONFIG_DIR, 'https', 'localhost-key.pem'),
459
- cert: path.join(CONFIG_DIR, 'https', 'localhost-cert.pem'),
460
- meta: path.join(CONFIG_DIR, 'https', 'localhost-meta.json')
461
- },
462
453
 
463
454
  // 技能与插件(cc-tool 托管部分)
464
455
  localSkills: {
@@ -467,19 +458,6 @@ const PATHS = {
467
458
  gemini: path.join(LOCAL_SKILLS_DIR, 'gemini'),
468
459
  opencode: path.join(LOCAL_SKILLS_DIR, 'opencode')
469
460
  },
470
- localCommands: {
471
- claude: path.join(LOCAL_COMMANDS_DIR, 'claude'),
472
- opencode: path.join(LOCAL_COMMANDS_DIR, 'opencode')
473
- },
474
- localAgents: {
475
- claude: path.join(LOCAL_AGENTS_DIR, 'claude'),
476
- codex: path.join(LOCAL_AGENTS_DIR, 'codex'),
477
- opencode: path.join(LOCAL_AGENTS_DIR, 'opencode')
478
- },
479
- localPlugins: {
480
- claude: path.join(LOCAL_PLUGINS_DIR, 'claude'),
481
- opencode: path.join(LOCAL_PLUGINS_DIR, 'opencode')
482
- },
483
461
  skillRepos: {
484
462
  claude: path.join(REPOS_SKILLS_DIR, 'claude.json'),
485
463
  codex: path.join(REPOS_SKILLS_DIR, 'codex.json'),
@@ -502,7 +480,7 @@ const PATHS = {
502
480
  },
503
481
 
504
482
  // 原生路径兼容
505
- skills: getNativePlatformSkillsDir('claude'),
483
+ skills: path.join(HOME_DIR, '.claude', 'skills'),
506
484
 
507
485
  // 旧版本遗留文件搬迁目标
508
486
  legacy: {
@@ -731,15 +709,15 @@ function pickExistingDir(candidates, fallback) {
731
709
  }
732
710
 
733
711
  function getClaudeConfigDir() {
734
- return resolveExistingEnvPath(process.env.CLAUDE_CONFIG_DIR) || joinNativeBasePath(HOME_DIR, '.claude');
712
+ return resolveExistingEnvPath(process.env.CLAUDE_CONFIG_DIR) || path.join(HOME_DIR, '.claude');
735
713
  }
736
714
 
737
715
  function getCodexDir() {
738
- return resolveExistingEnvPath(process.env.CODEX_HOME) || joinNativeBasePath(HOME_DIR, '.codex');
716
+ return resolveExistingEnvPath(process.env.CODEX_HOME) || path.join(HOME_DIR, '.codex');
739
717
  }
740
718
 
741
719
  function getGeminiDir() {
742
- return joinNativeBasePath(HOME_DIR, '.gemini');
720
+ return path.join(HOME_DIR, '.gemini');
743
721
  }
744
722
 
745
723
  function getOpenCodeDataDir() {
@@ -778,151 +756,49 @@ function getOpenCodeConfigDir() {
778
756
  return preferredDir;
779
757
  }
780
758
 
781
- function isWindowsAbsolutePath(value = '') {
782
- return /^[a-zA-Z]:[\\/]/.test(String(value || ''));
783
- }
784
-
785
- function isNativeAbsolutePath(value = '') {
786
- return path.isAbsolute(String(value || '')) || isWindowsAbsolutePath(value);
787
- }
788
-
789
- function joinNativeBasePath(baseDir, ...segments) {
790
- const base = String(baseDir || '');
791
- const pathModule = isWindowsAbsolutePath(base) ? path.win32 : path;
792
- return pathModule.join(base, ...segments);
793
- }
794
-
795
- function resolveNativeBasePath(baseDir, ...segments) {
796
- const base = String(baseDir || '');
797
- const pathModule = isWindowsAbsolutePath(base) ? path.win32 : path;
798
- return pathModule.resolve(base, ...segments);
799
- }
800
-
801
- function getNativePathDir(filePath = '') {
802
- const target = String(filePath || '');
803
- const pathModule = isWindowsAbsolutePath(target) ? path.win32 : path;
804
- return pathModule.dirname(target);
805
- }
806
-
807
- function getNativePlatformDir(platform) {
808
- switch (platform) {
809
- case 'claude':
810
- return getClaudeConfigDir();
811
- case 'codex':
812
- return getCodexDir();
813
- case 'gemini':
814
- return getGeminiDir();
815
- case 'opencode':
816
- return getOpenCodeConfigDir();
817
- default:
818
- return '';
819
- }
820
- }
821
-
822
- function getNativePlatformSubPath(platform, ...segments) {
823
- const baseDir = getNativePlatformDir(platform);
824
- return baseDir ? joinNativeBasePath(baseDir, ...segments) : '';
825
- }
826
-
827
- function getNativePlatformSkillsDir(platform) {
828
- return getNativePlatformSubPath(platform, 'skills');
829
- }
830
-
831
- function getNativePlatformPromptPath(platform) {
832
- if (!getNativePlatformDir(platform)) {
833
- return '';
834
- }
835
-
836
- switch (platform) {
837
- case 'claude':
838
- return getNativePlatformSubPath(platform, 'CLAUDE.md');
839
- case 'codex':
840
- return getNativePlatformSubPath(platform, 'AGENTS.md');
841
- case 'gemini':
842
- return getNativePlatformSubPath(platform, 'GEMINI.md');
843
- case 'opencode':
844
- return getNativePlatformSubPath(platform, 'AGENTS.md');
845
- default:
846
- return '';
847
- }
848
- }
849
-
850
- const CLAUDE_NATIVE_DIR = getNativePlatformDir('claude');
851
- const CODEX_NATIVE_DIR = getNativePlatformDir('codex');
852
- const GEMINI_NATIVE_DIR = getNativePlatformDir('gemini');
853
- const OPENCODE_CONFIG_DIR = getNativePlatformDir('opencode');
854
- const OPENCODE_DATA_DIR = getOpenCodeDataDir();
855
-
856
759
  // 工具特定的原生配置路径(不改变)
857
760
  const NATIVE_PATHS = {
858
761
  // Claude Code 原生配置
859
762
  claude: {
860
- dir: CLAUDE_NATIVE_DIR,
861
- settings: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'settings.json'),
862
- settingsBackup: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'settings.json.cc-tool-backup'),
863
- projects: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'projects'),
864
- commands: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'commands'),
865
- agents: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'agents'),
866
- plugins: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'plugins'),
867
- installedPlugins: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'plugins', 'installed_plugins.json'),
868
- pluginMarketplaces: joinNativeBasePath(CLAUDE_NATIVE_DIR, 'plugins', 'known_marketplaces.json'),
869
- credentials: joinNativeBasePath(CLAUDE_NATIVE_DIR, '.credentials.json'),
870
- skills: getNativePlatformSkillsDir('claude'),
871
- prompt: getNativePlatformPromptPath('claude')
763
+ dir: getClaudeConfigDir(),
764
+ settings: path.join(getClaudeConfigDir(), 'settings.json'),
765
+ settingsBackup: path.join(getClaudeConfigDir(), 'settings.json.cc-tool-backup'),
766
+ projects: path.join(getClaudeConfigDir(), 'projects'),
767
+ credentials: path.join(getClaudeConfigDir(), '.credentials.json')
872
768
  },
873
769
 
874
770
  // Codex 原生配置
875
771
  codex: {
876
- dir: CODEX_NATIVE_DIR,
877
- config: joinNativeBasePath(CODEX_NATIVE_DIR, 'config.toml'),
878
- configBackup: joinNativeBasePath(CODEX_NATIVE_DIR, 'config.toml.cc-tool-backup'),
879
- auth: joinNativeBasePath(CODEX_NATIVE_DIR, 'auth.json'),
880
- authBackup: joinNativeBasePath(CODEX_NATIVE_DIR, 'auth.json.cc-tool-backup'),
881
- sessions: joinNativeBasePath(CODEX_NATIVE_DIR, 'sessions'),
882
- projects: joinNativeBasePath(CODEX_NATIVE_DIR, 'projects'),
883
- agents: joinNativeBasePath(CODEX_NATIVE_DIR, 'agents'),
884
- prompts: joinNativeBasePath(CODEX_NATIVE_DIR, 'prompts'),
885
- skills: getNativePlatformSkillsDir('codex'),
886
- prompt: getNativePlatformPromptPath('codex')
772
+ dir: getCodexDir(),
773
+ config: path.join(getCodexDir(), 'config.toml'),
774
+ configBackup: path.join(getCodexDir(), 'config.toml.cc-tool-backup'),
775
+ auth: path.join(getCodexDir(), 'auth.json'),
776
+ authBackup: path.join(getCodexDir(), 'auth.json.cc-tool-backup'),
777
+ sessions: path.join(getCodexDir(), 'sessions')
887
778
  },
888
779
 
889
780
  // Gemini 原生配置
890
781
  gemini: {
891
- dir: GEMINI_NATIVE_DIR,
892
- env: joinNativeBasePath(GEMINI_NATIVE_DIR, '.env'),
893
- envBackup: joinNativeBasePath(GEMINI_NATIVE_DIR, '.env.cc-tool-backup'),
894
- tmp: joinNativeBasePath(GEMINI_NATIVE_DIR, 'tmp'),
895
- settings: joinNativeBasePath(GEMINI_NATIVE_DIR, 'settings.json'),
896
- settingsBackup: joinNativeBasePath(GEMINI_NATIVE_DIR, 'settings.json.cc-tool-backup'),
897
- projects: joinNativeBasePath(GEMINI_NATIVE_DIR, 'projects'),
898
- googleAccounts: joinNativeBasePath(GEMINI_NATIVE_DIR, 'google_accounts.json'),
899
- oauthCredentialsLegacy: joinNativeBasePath(GEMINI_NATIVE_DIR, 'oauth_creds.json'),
900
- oauthCredentialsEncrypted: joinNativeBasePath(GEMINI_NATIVE_DIR, 'mcp-oauth-tokens-v2.json'),
901
- skills: getNativePlatformSkillsDir('gemini'),
902
- prompt: getNativePlatformPromptPath('gemini')
782
+ dir: getGeminiDir(),
783
+ env: path.join(getGeminiDir(), '.env'),
784
+ envBackup: path.join(getGeminiDir(), '.env.cc-tool-backup'),
785
+ tmp: path.join(getGeminiDir(), 'tmp'),
786
+ settings: path.join(getGeminiDir(), 'settings.json'),
787
+ settingsBackup: path.join(getGeminiDir(), 'settings.json.cc-tool-backup'),
788
+ googleAccounts: path.join(getGeminiDir(), 'google_accounts.json'),
789
+ oauthCredentialsLegacy: path.join(getGeminiDir(), 'oauth_creds.json'),
790
+ oauthCredentialsEncrypted: path.join(getGeminiDir(), 'mcp-oauth-tokens-v2.json')
903
791
  },
904
792
 
905
793
  // OpenCode 原生配置
906
794
  opencode: {
907
- data: OPENCODE_DATA_DIR,
908
- config: OPENCODE_CONFIG_DIR,
909
- sessions: joinNativeBasePath(OPENCODE_DATA_DIR, 'storage', 'session'),
910
- projects: joinNativeBasePath(OPENCODE_DATA_DIR, 'storage', 'project'),
911
- messages: joinNativeBasePath(OPENCODE_DATA_DIR, 'storage', 'message'),
912
- log: joinNativeBasePath(OPENCODE_DATA_DIR, 'log'),
913
- auth: joinNativeBasePath(OPENCODE_DATA_DIR, 'auth.json'),
914
- commands: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'commands'),
915
- commandsLegacy: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'command'),
916
- agents: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'agents'),
917
- agentsLegacy: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'agent'),
918
- plugins: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'plugins'),
919
- pluginsLegacy: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'plugin'),
920
- pluginsConfig: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'plugins-config'),
921
- configJsonc: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'opencode.jsonc'),
922
- configJson: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'opencode.json'),
923
- configLegacy: joinNativeBasePath(OPENCODE_CONFIG_DIR, 'config.json'),
924
- skills: getNativePlatformSkillsDir('opencode'),
925
- prompt: getNativePlatformPromptPath('opencode')
795
+ data: getOpenCodeDataDir(),
796
+ config: getOpenCodeConfigDir(),
797
+ sessions: path.join(getOpenCodeDataDir(), 'storage', 'session'),
798
+ projects: path.join(getOpenCodeDataDir(), 'storage', 'project'),
799
+ messages: path.join(getOpenCodeDataDir(), 'storage', 'message'),
800
+ log: path.join(getOpenCodeDataDir(), 'log'),
801
+ auth: path.join(getOpenCodeDataDir(), 'auth.json')
926
802
  }
927
803
  };
928
804
 
@@ -941,15 +817,6 @@ module.exports = {
941
817
  getClaudeConfigDir,
942
818
  getCodexDir,
943
819
  getGeminiDir,
944
- isWindowsAbsolutePath,
945
- isNativeAbsolutePath,
946
- joinNativeBasePath,
947
- resolveNativeBasePath,
948
- getNativePathDir,
949
- getNativePlatformDir,
950
- getNativePlatformSubPath,
951
- getNativePlatformSkillsDir,
952
- getNativePlatformPromptPath,
953
820
  getOpenCodeDataDir,
954
821
  getOpenCodeConfigDir
955
822
  };
package/src/index.js CHANGED
@@ -19,7 +19,6 @@ const eventBus = require('./plugins/event-bus');
19
19
  const chalk = require('chalk');
20
20
  const path = require('path');
21
21
  const fs = require('fs');
22
- let processHandlersRegistered = false;
23
22
 
24
23
  function getInquirer() {
25
24
  return require('inquirer');
@@ -37,66 +36,34 @@ function showHelp() {
37
36
  const version = getVersion();
38
37
  console.log(chalk.cyan.bold(`\nCODING-TOOL v${version}`));
39
38
  console.log(chalk.gray('Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控\n'));
40
- console.log(chalk.gray('用法: ctx [command] [options]'));
41
- console.log(chalk.gray('不带参数时进入交互菜单;输入未知命令时会直接报错。\n'));
42
39
 
43
40
  console.log(chalk.yellow('[START] 服务管理:'));
44
41
  console.log(' ctx start 启动所有服务(后台运行)');
45
- console.log(' ctx start --host 启动所有服务(后台运行,允许 LAN 访问)');
46
- console.log(' ctx start --https 启动所有服务(后台运行,原生 HTTPS)');
47
42
  console.log(' ctx stop 停止所有服务');
48
43
  console.log(' ctx restart 重启所有服务');
49
44
  console.log(' ctx status 查看服务状态\n');
50
45
 
51
46
  console.log(chalk.yellow('[UI] UI 管理:'));
52
47
  console.log(' ctx ui 前台启动 Web UI(仅本地访问)');
53
- console.log(' ctx ui --https 前台启动 Web UI(原生 HTTPS)');
54
48
  console.log(' ctx ui --host 前台启动 Web UI(允许 LAN 访问)');
55
- console.log(' ctx ui start 后台启动 Web UI(等同于 ctx start)');
56
- console.log(' ctx ui start --https 后台启动 Web UI(原生 HTTPS)');
49
+ console.log(' ctx ui start 后台启动 Web UI');
57
50
  console.log(' ctx ui start --host 后台启动 Web UI(允许 LAN 访问)');
58
51
  console.log(' ctx ui stop 停止 Web UI');
59
52
  console.log(' ctx ui restart 重启 Web UI\n');
60
53
 
61
- console.log(chalk.yellow('[CHANNEL] 渠道代理管理:'));
54
+ console.log(chalk.yellow('[PROXY] 代理管理:'));
62
55
  console.log(' ctx claude start 启动 Claude 代理');
63
56
  console.log(' ctx claude stop 停止 Claude 代理');
64
- console.log(' ctx claude restart 重启 Claude 代理');
65
57
  console.log(' ctx claude status 查看 Claude 代理状态');
66
58
  console.log(' ctx codex start 启动 Codex 代理');
67
- console.log(' ctx codex stop 停止 Codex 代理');
68
- console.log(' ctx codex restart 重启 Codex 代理');
69
- console.log(' ctx codex status 查看 Codex 代理状态');
70
59
  console.log(' ctx gemini start 启动 Gemini 代理');
71
- console.log(' ctx gemini stop 停止 Gemini 代理');
72
- console.log(' ctx gemini restart 重启 Gemini 代理');
73
- console.log(' ctx gemini status 查看 Gemini 代理状态');
74
60
  console.log(' ctx opencode start 启动 OpenCode 代理');
75
- console.log(' ctx opencode stop 停止 OpenCode 代理');
76
- console.log(' ctx opencode restart 重启 OpenCode 代理');
77
- console.log(' ctx opencode status 查看 OpenCode 代理状态\n');
78
-
79
- console.log(chalk.yellow('[PROXY] 旧版代理命令:'));
80
- console.log(' ctx proxy 启动旧版 Claude 代理');
81
- console.log(' ctx proxy start 启动旧版 Claude 代理');
82
- console.log(' ctx proxy stop 停止旧版 Claude 代理并恢复配置');
83
- console.log(' ctx proxy status 查看旧版 Claude 代理状态\n');
84
-
85
- console.log(chalk.yellow('[COMPAT] 兼容命令:'));
86
- console.log(' ctx daemon start 等同于 ctx start');
87
- console.log(' ctx daemon stop 等同于 ctx stop');
88
- console.log(' ctx daemon restart 等同于 ctx restart');
89
- console.log(' ctx daemon status 等同于 ctx status');
90
- console.log(' ctx daemon logs 查看 UI 日志');
91
- console.log(' ctx daemon logs --follow 实时跟踪 UI 日志\n');
61
+ console.log(chalk.gray(' (codex/gemini/opencode 命令与 claude 类似)\n'));
92
62
 
93
63
  console.log(chalk.yellow('[LOG] 日志管理:'));
94
64
  console.log(' ctx logs 查看所有日志');
95
65
  console.log(' ctx logs ui 查看 UI 日志');
96
66
  console.log(' ctx logs claude 查看 Claude 日志');
97
- console.log(' ctx logs codex 查看 Codex 日志');
98
- console.log(' ctx logs gemini 查看 Gemini 日志');
99
- console.log(' ctx logs opencode 查看 OpenCode 日志');
100
67
  console.log(' ctx logs --lines 100 查看最近 100 行');
101
68
  console.log(' ctx logs --follow 实时跟踪日志');
102
69
  console.log(' ctx logs --clear 清空日志\n');
@@ -105,24 +72,18 @@ function showHelp() {
105
72
  console.log(' ctx stats 查看总体统计');
106
73
  console.log(' ctx stats claude 查看 Claude 统计');
107
74
  console.log(' ctx stats --today 查看今日统计');
108
- console.log(' ctx stats --week 查看最近 7 天统计');
109
- console.log(' ctx stats --month 查看最近 30 天统计');
110
75
  console.log(' ctx stats export 导出统计数据\n');
111
76
 
112
77
  console.log(chalk.yellow('[TOOL] 其他命令:'));
113
78
  console.log(' ctx update 检查并更新到最新版本');
114
- console.log(' ctx update --check 仅检查更新,不执行安装');
115
79
  console.log(' ctx doctor 系统诊断');
116
80
  console.log(' ctx port 配置端口');
117
81
  console.log(' ctx reset 重置配置');
118
82
  console.log(' ctx security reset 关闭访问密码');
119
- console.log(' ctx security disable 关闭访问密码(别名)');
120
- console.log(' ctx security off 关闭访问密码(别名)');
121
- console.log(' ctx help 显示帮助');
122
83
  console.log(' ctx --version, -v 显示版本');
123
84
  console.log(' ctx --help, -h 显示帮助\n');
124
85
 
125
- console.log(chalk.yellow('[PLUGIN] 插件管理:'));
86
+ console.log(chalk.yellow('[PROXY] 插件管理:'));
126
87
  console.log(' ctx plugin list 列出已安装插件');
127
88
  console.log(' ctx plugin install <url> 从 Git 安装插件');
128
89
  console.log(' ctx plugin remove <name> 卸载插件');
@@ -150,44 +111,21 @@ function showHelp() {
150
111
  console.log(chalk.gray(' 问题: https://github.com/ZeaoZhang/coding-tool/issues\n'));
151
112
  }
152
113
 
153
- function registerProcessHandlers() {
154
- if (processHandlersRegistered) {
155
- return;
156
- }
157
-
158
- processHandlersRegistered = true;
159
-
160
- process.on('uncaughtException', (err) => {
161
- // 忽略终端相关的错误(通常在 Ctrl+C 时发生)
162
- if (err.code === 'EIO' || err.code === 'ENOTTY' || err.code === 'EPIPE') {
163
- process.exit(0);
164
- }
165
- throw err;
166
- });
167
-
168
- process.on('SIGINT', async () => {
169
- eventBus.emitSync('cli:shutdown', {});
170
- PluginManager.shutdownPlugins();
114
+ // 全局错误处理
115
+ process.on('uncaughtException', (err) => {
116
+ // 忽略终端相关的错误(通常在 Ctrl+C 时发生)
117
+ if (err.code === 'EIO' || err.code === 'ENOTTY' || err.code === 'EPIPE') {
171
118
  process.exit(0);
172
- });
173
- }
174
-
175
- function exitWithError(code = 1) {
176
- process.exit(code);
177
- }
178
-
179
- function showUnknownCommand(command) {
180
- console.error(chalk.red(`\n[ERROR] 未知命令: ${command}\n`));
181
- console.log(chalk.gray('使用 ctx --help 查看完整帮助\n'));
182
- }
183
-
184
- function showUnknownSubcommand(command, subCommand, supportedText) {
185
- console.error(chalk.red(`\n[ERROR] 未知 ${command} 子命令: ${subCommand}\n`));
186
- if (supportedText) {
187
- console.log(chalk.gray(`${supportedText}\n`));
188
119
  }
189
- console.log(chalk.gray('使用 ctx --help 查看完整帮助\n'));
190
- }
120
+ throw err;
121
+ });
122
+
123
+ // 处理 SIGINT 信号(Ctrl+C)
124
+ process.on('SIGINT', async () => {
125
+ eventBus.emitSync('cli:shutdown', {});
126
+ PluginManager.shutdownPlugins();
127
+ process.exit(0);
128
+ });
191
129
 
192
130
  /**
193
131
  * 主函数
@@ -205,7 +143,7 @@ async function main() {
205
143
  }
206
144
 
207
145
  // --help 或 -h - 显示帮助信息
208
- if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
146
+ if (args[0] === '--help' || args[0] === '-h') {
209
147
  showHelp();
210
148
  return;
211
149
  }
@@ -246,8 +184,8 @@ async function main() {
246
184
  return;
247
185
  }
248
186
 
249
- showUnknownSubcommand('daemon', subCommand, '支持的命令: start, stop, restart, status, logs');
250
- exitWithError(1);
187
+ console.log(chalk.red(`\n[ERROR] 未知 daemon 子命令: ${subCommand}\n`));
188
+ console.log(chalk.gray('支持的命令: start, stop, restart, status, logs\n'));
251
189
  return;
252
190
  }
253
191
 
@@ -297,18 +235,16 @@ async function main() {
297
235
  // ui 命令 - Web UI 管理
298
236
  if (args[0] === 'ui') {
299
237
  const subCommand = args[1];
300
- if (!subCommand || subCommand.startsWith('--')) {
301
- const { handleUI } = require('./commands/ui');
302
- await handleUI();
303
- } else if (subCommand === 'start') {
238
+ if (subCommand === 'start') {
304
239
  await handleStart(); // UI start 实际上就是启动整个服务
305
240
  } else if (subCommand === 'stop') {
306
241
  await handleStop();
307
242
  } else if (subCommand === 'restart') {
308
243
  await handleRestart();
309
244
  } else {
310
- showUnknownSubcommand('ui', subCommand, '支持的命令: start, stop, restart,或直接使用 ctx ui [--host] [--https]');
311
- exitWithError(1);
245
+ // 默认前台运行
246
+ const { handleUI } = require('./commands/ui');
247
+ await handleUI();
312
248
  }
313
249
  return;
314
250
  }
@@ -335,7 +271,6 @@ async function main() {
335
271
  default:
336
272
  console.log(chalk.red(`\n[ERROR] 未知操作: ${action}\n`));
337
273
  console.log(chalk.gray('支持的操作: start, stop, restart, status\n'));
338
- exitWithError(1);
339
274
  }
340
275
  return;
341
276
  }
@@ -421,8 +356,8 @@ async function main() {
421
356
  return;
422
357
 
423
358
  default:
424
- showUnknownSubcommand('proxy', subCommand, '支持的命令: start, stop, status');
425
- exitWithError(1);
359
+ // 默认执行 start
360
+ await handleProxyStart();
426
361
  return;
427
362
  }
428
363
  }
@@ -439,17 +374,15 @@ async function main() {
439
374
 
440
375
  // 初始化插件系统
441
376
  const pluginResult = PluginManager.initializePlugins({ config, args });
442
- const isPluginCommand = args[0] && PluginManager.isPluginCommand(args[0]);
443
- const shouldShowPluginInitSummary = !args[0] || isPluginCommand;
444
- if (shouldShowPluginInitSummary && pluginResult.loaded > 0) {
377
+ if (pluginResult.loaded > 0) {
445
378
  console.log(chalk.gray(`[Plugin] 已加载 ${pluginResult.loaded} 个插件`));
446
379
  }
447
- if (shouldShowPluginInitSummary && pluginResult.failed.length > 0) {
380
+ if (pluginResult.failed.length > 0) {
448
381
  console.log(chalk.yellow(`[Plugin] ${pluginResult.failed.length} 个插件加载失败`));
449
382
  }
450
383
 
451
384
  // 检查是否为插件注册的命令
452
- if (isPluginCommand) {
385
+ if (args[0] && PluginManager.isPluginCommand(args[0])) {
453
386
  eventBus.emitSync('cli:command:before', { command: args[0], args: args.slice(1), config });
454
387
  const result = await PluginManager.executePluginCommand(args[0], args.slice(1));
455
388
  eventBus.emitSync('cli:command:after', { command: args[0], args: args.slice(1), result });
@@ -460,12 +393,6 @@ async function main() {
460
393
  return;
461
394
  }
462
395
 
463
- if (args[0]) {
464
- showUnknownCommand(args[0]);
465
- exitWithError(1);
466
- return;
467
- }
468
-
469
396
  while (true) {
470
397
  // 显示主菜单
471
398
  const { showMainMenu } = require('./ui/menu');
@@ -757,26 +684,8 @@ async function main() {
757
684
  }
758
685
  }
759
686
 
760
- async function runCli() {
761
- registerProcessHandlers();
762
- await main();
763
- }
764
-
765
- if (require.main === module) {
766
- runCli().catch((error) => {
767
- console.error('程序出错:', error);
768
- process.exit(1);
769
- });
770
- }
771
-
772
- module.exports = {
773
- main,
774
- runCli,
775
- showHelp,
776
- getVersion,
777
- _test: {
778
- showUnknownCommand,
779
- showUnknownSubcommand,
780
- registerProcessHandlers
781
- }
782
- };
687
+ // 启动应用
688
+ main().catch((error) => {
689
+ console.error('程序出错:', error);
690
+ process.exit(1);
691
+ });
@@ -228,7 +228,7 @@ router.use((req, res, next) => {
228
228
  router.get('/', (req, res) => {
229
229
  try {
230
230
  const { platform, service } = getAgentsService(req);
231
- const { projectPath, refresh } = req.query;
231
+ const { projectPath } = req.query;
232
232
  const normalizedProjectPath = normalizeOptionalProjectPath(projectPath);
233
233
  if (normalizedProjectPath.error) {
234
234
  return res.status(400).json({
@@ -236,10 +236,7 @@ router.get('/', (req, res) => {
236
236
  message: normalizedProjectPath.error
237
237
  });
238
238
  }
239
- const forceRefresh = refresh === '1';
240
- const result = service.listAgents(normalizedProjectPath.projectPath, {
241
- syncManagedLocalAgents: forceRefresh
242
- });
239
+ const result = service.listAgents(normalizedProjectPath.projectPath);
243
240
 
244
241
  res.json({
245
242
  success: true,
@@ -778,53 +775,6 @@ router.post('/install', async (req, res) => {
778
775
  }
779
776
  });
780
777
 
781
- /**
782
- * 安装本地托管代理
783
- * POST /api/agents/install-local
784
- * Body: { fileName }
785
- */
786
- router.post('/install-local', (req, res) => {
787
- try {
788
- const { platform, service } = getAgentsService(req);
789
- if (isCodexRepoOperationUnsupported(platform)) {
790
- return res.status(400).json({
791
- success: false,
792
- message: 'Codex 平台暂不支持本地托管代理安装'
793
- });
794
- }
795
-
796
- const { fileName } = req.body;
797
- if (!fileName) {
798
- return res.status(400).json({
799
- success: false,
800
- message: 'Missing fileName'
801
- });
802
- }
803
-
804
- const fileNameError = validateAgentFileName(fileName);
805
- if (fileNameError) {
806
- return res.status(400).json({
807
- success: false,
808
- message: fileNameError
809
- });
810
- }
811
-
812
- const result = service.installLocalAgent(fileName);
813
-
814
- res.json({
815
- success: true,
816
- platform,
817
- ...result
818
- });
819
- } catch (err) {
820
- console.error('[Agents API] Install local agent error:', err);
821
- res.status(500).json({
822
- success: false,
823
- message: err.message
824
- });
825
- }
826
- });
827
-
828
778
  /**
829
779
  * 卸载代理
830
780
  * POST /api/agents/uninstall
@@ -201,6 +201,10 @@ module.exports = (config) => {
201
201
  res.json(channel);
202
202
  broadcastSchedulerState('codex', getSchedulerState('codex'));
203
203
  } catch (err) {
204
+ if (err?.message === 'Channel not found') {
205
+ console.warn(`[Codex Channels API] Ignored update for missing channel: ${req.params.channelId}`);
206
+ return res.status(404).json({ error: 'Channel not found' });
207
+ }
204
208
  console.error('[Codex Channels API] Failed to update channel:', err);
205
209
  res.status(500).json({ error: err.message });
206
210
  }