coding-tool-x 3.5.9 → 3.5.10
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/CHANGELOG.md +11 -0
- package/README.md +4 -25
- package/bin/ctx.js +1 -6
- package/dist/web/assets/{Analytics-C5W3axXs.js → Analytics-DPb1zErn.js} +2 -2
- package/dist/web/assets/Analytics-RNn1BUbG.css +1 -0
- package/dist/web/assets/{ConfigTemplates-DzyVFDx9.js → ConfigTemplates-Bki2k4Lo.js} +1 -1
- package/dist/web/assets/{Home-C9TQNB6f.js → Home-BKYHKSax.js} +1 -1
- package/dist/web/assets/Home-BQxQ1LhR.css +1 -0
- package/dist/web/assets/{PluginManager-9B_brLWT.js → PluginManager-jgeQOE24.js} +1 -1
- package/dist/web/assets/ProjectList-CF67RzP_.js +1 -0
- package/dist/web/assets/ProjectList-DL4JK6ci.css +1 -0
- package/dist/web/assets/SessionList-DhHsY5q9.js +1 -0
- package/dist/web/assets/SessionList-lz23U6ZJ.css +1 -0
- package/dist/web/assets/{SkillManager-vST8DRRg.js → SkillManager-CtEz5gGp.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-ov1KgRXR.js → WorkspaceManager-D3B0Y5XE.js} +1 -1
- package/dist/web/assets/icons-lKCTySl7.js +1 -0
- package/dist/web/assets/index-BS7aplYp.css +1 -0
- package/dist/web/assets/index-BnyNm74G.js +2 -0
- package/dist/web/assets/{markdown-DyTJGI4N.js → markdown-BNJfEgCA.js} +1 -1
- package/dist/web/assets/{naive-ui-Cg4_ZeoT.js → naive-ui-DM897mIP.js} +1 -1
- package/dist/web/assets/vendors-DQA4Hw9v.js +7 -0
- package/dist/web/assets/vue-vendor-B5RqjEjQ.js +45 -0
- package/dist/web/index.html +8 -8
- package/package.json +1 -2
- package/src/commands/daemon.js +5 -33
- package/src/commands/export-config.js +6 -6
- package/src/commands/stats.js +4 -41
- package/src/commands/ui.js +3 -12
- package/src/config/channel-preset-websites.js +114 -0
- package/src/config/default.js +9 -5
- package/src/config/loader.js +2 -2
- package/src/config/model-metadata.json +16 -20
- package/src/config/paths.js +33 -166
- package/src/index.js +34 -125
- package/src/server/api/agents.js +2 -52
- package/src/server/api/codex-proxy.js +4 -2
- package/src/server/api/codex-sessions.js +89 -12
- package/src/server/api/commands.js +2 -38
- package/src/server/api/dashboard.js +1 -25
- package/src/server/api/gemini-proxy.js +4 -2
- package/src/server/api/gemini-sessions.js +86 -9
- package/src/server/api/hooks.js +1 -17
- package/src/server/api/opencode-proxy.js +7 -2
- package/src/server/api/opencode-sessions.js +83 -10
- package/src/server/api/plugins.js +34 -128
- package/src/server/api/proxy.js +5 -3
- package/src/server/api/sessions.js +181 -27
- package/src/server/api/workspaces.js +0 -14
- package/src/server/index.js +9 -31
- package/src/server/services/agents-service.js +62 -269
- package/src/server/services/base/base-channel-service.js +3 -1
- package/src/server/services/channels.js +5 -0
- package/src/server/services/codex-channels.js +2 -0
- package/src/server/services/codex-sessions.js +78 -108
- package/src/server/services/commands-service.js +81 -281
- package/src/server/services/config-export-service.js +7 -7
- package/src/server/services/config-registry-service.js +9 -8
- package/src/server/services/config-sync-manager.js +41 -61
- package/src/server/services/config-sync-service.js +3 -3
- package/src/server/services/gemini-channels.js +17 -6
- package/src/server/services/gemini-config.js +4 -3
- package/src/server/services/gemini-sessions.js +51 -26
- package/src/server/services/gemini-settings-manager.js +3 -2
- package/src/server/services/mcp-service.js +14 -9
- package/src/server/services/native-oauth-adapters.js +3 -3
- package/src/server/services/network-access.js +2 -61
- package/src/server/services/notification-hooks.js +19 -184
- package/src/server/services/opencode-channels.js +9 -0
- package/src/server/services/opencode-sessions.js +6 -16
- package/src/server/services/opencode-settings-manager.js +3 -3
- package/src/server/services/plugins-service.js +62 -996
- package/src/server/services/prompts-service.js +9 -5
- package/src/server/services/sessions.js +161 -183
- package/src/server/services/skill-service.js +18 -155
- package/src/server/websocket-server.js +4 -35
- package/dist/web/assets/Analytics-vQS5IWvs.css +0 -1
- package/dist/web/assets/Home-qzk118Of.css +0 -1
- package/dist/web/assets/ProjectList-Bjt6mrsV.js +0 -1
- package/dist/web/assets/ProjectList-GCC2QOmq.css +0 -1
- package/dist/web/assets/SessionList-BsHPgmUR.css +0 -1
- package/dist/web/assets/SessionList-DcBH13uA.js +0 -1
- package/dist/web/assets/icons-CEq2hYB-.js +0 -1
- package/dist/web/assets/index-Dih_bOsv.css +0 -1
- package/dist/web/assets/index-Duc7QP4e.js +0 -2
- package/dist/web/assets/vendors-Bsp-dq2d.js +0 -7
- package/dist/web/assets/vue-vendor-BxIT0uQq.js +0 -45
- package/docs/Caddyfile.example +0 -19
- package/docs/reverse-proxy-https.md +0 -57
- package/src/server/services/https-cert.js +0 -171
- package/src/server/services/session-launch-command.js +0 -58
- package/src/server/services/web-ui-runtime.js +0 -54
package/src/config/paths.js
CHANGED
|
@@ -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
|
-
|
|
46
|
-
|
|
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:
|
|
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) ||
|
|
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) ||
|
|
716
|
+
return resolveExistingEnvPath(process.env.CODEX_HOME) || path.join(HOME_DIR, '.codex');
|
|
739
717
|
}
|
|
740
718
|
|
|
741
719
|
function getGeminiDir() {
|
|
742
|
-
return
|
|
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:
|
|
861
|
-
settings:
|
|
862
|
-
settingsBackup:
|
|
863
|
-
projects:
|
|
864
|
-
|
|
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:
|
|
877
|
-
config:
|
|
878
|
-
configBackup:
|
|
879
|
-
auth:
|
|
880
|
-
authBackup:
|
|
881
|
-
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:
|
|
892
|
-
env:
|
|
893
|
-
envBackup:
|
|
894
|
-
tmp:
|
|
895
|
-
settings:
|
|
896
|
-
settingsBackup:
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
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:
|
|
908
|
-
config:
|
|
909
|
-
sessions:
|
|
910
|
-
projects:
|
|
911
|
-
messages:
|
|
912
|
-
log:
|
|
913
|
-
auth:
|
|
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
|
|
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('[
|
|
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('
|
|
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('[
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
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'
|
|
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
|
-
|
|
250
|
-
|
|
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 (
|
|
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
|
-
|
|
311
|
-
|
|
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
|
-
|
|
425
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
761
|
-
|
|
762
|
-
|
|
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
|
+
});
|
package/src/server/api/agents.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
@@ -14,7 +14,7 @@ const {
|
|
|
14
14
|
hasBackup,
|
|
15
15
|
readConfig
|
|
16
16
|
} = require('../services/codex-settings-manager');
|
|
17
|
-
const { getChannels, getEnabledChannels } = require('../services/codex-channels');
|
|
17
|
+
const { getChannels, getEnabledChannels, markChannelAsRecentlyUsed } = require('../services/codex-channels');
|
|
18
18
|
const { clearNativeOAuth } = require('../services/native-oauth-adapters');
|
|
19
19
|
const { clearAllLogs } = require('../websocket-server');
|
|
20
20
|
const { PATHS, ensureStorageDirMigrated } = require('../../config/paths');
|
|
@@ -149,6 +149,8 @@ router.post('/start', async (req, res) => {
|
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
currentChannel = markChannelAsRecentlyUsed(currentChannel.id);
|
|
153
|
+
|
|
152
154
|
// 3. 保存当前激活渠道ID(用于代理模式)
|
|
153
155
|
saveActiveChannelId(currentChannel.id);
|
|
154
156
|
console.log(`[Codex Proxy] Saved active channel: ${currentChannel.name} (${currentChannel.id})`);
|
|
@@ -166,7 +168,7 @@ router.post('/start', async (req, res) => {
|
|
|
166
168
|
|
|
167
169
|
const updatedStatus = getCodexProxyStatus();
|
|
168
170
|
const { channels: allChannels } = getChannels();
|
|
169
|
-
const activeChannel = allChannels.
|
|
171
|
+
const activeChannel = allChannels.find(ch => ch.id === currentChannel.id) || currentChannel;
|
|
170
172
|
const { broadcastProxyState } = require('../websocket-server');
|
|
171
173
|
broadcastProxyState('codex', updatedStatus, activeChannel, allChannels);
|
|
172
174
|
|