coding-tool-x 3.5.7 → 3.5.8
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/dist/web/assets/{Analytics-C6DEmD3D.js → Analytics-BzoNzfbi.js} +2 -2
- package/dist/web/assets/Analytics-vQS5IWvs.css +1 -0
- package/dist/web/assets/{ConfigTemplates-Cf_iTpC4.js → ConfigTemplates-O4ikBt1o.js} +1 -1
- package/dist/web/assets/{Home-BtBmYLJ1.js → Home-BQjsnblU.js} +1 -1
- package/dist/web/assets/Home-qzk118Of.css +1 -0
- package/dist/web/assets/{PluginManager-DEk8vSw5.js → PluginManager-DS_DJnVc.js} +1 -1
- package/dist/web/assets/ProjectList-CqYDtsHx.js +1 -0
- package/dist/web/assets/ProjectList-GCC2QOmq.css +1 -0
- package/dist/web/assets/SessionList-CfPtcq6Y.css +1 -0
- package/dist/web/assets/SessionList-DMlLtMCz.js +1 -0
- package/dist/web/assets/{SkillManager-DcZOiiSf.js → SkillManager-DpNE02r0.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-BHqI8aGV.js → WorkspaceManager-DMY7_SHh.js} +1 -1
- package/dist/web/assets/icons-CEq2hYB-.js +1 -0
- package/dist/web/assets/index-Clf0l3wc.js +2 -0
- package/dist/web/assets/index-Dih_bOsv.css +1 -0
- package/dist/web/assets/{naive-ui-BaTCPPL5.js → naive-ui-Cg4_ZeoT.js} +1 -1
- package/dist/web/assets/{vendors-Fza9uSYn.js → vendors-Bsp-dq2d.js} +1 -1
- package/dist/web/assets/vue-vendor-BxIT0uQq.js +45 -0
- package/dist/web/index.html +7 -7
- package/package.json +1 -1
- package/src/commands/export-config.js +6 -6
- package/src/config/default.js +2 -6
- package/src/config/loader.js +2 -2
- package/src/config/paths.js +160 -33
- package/src/server/api/agents.js +52 -2
- package/src/server/api/commands.js +38 -2
- package/src/server/api/plugins.js +104 -1
- package/src/server/api/sessions.js +5 -5
- package/src/server/services/agents-service.js +269 -62
- package/src/server/services/commands-service.js +281 -81
- package/src/server/services/config-export-service.js +7 -7
- package/src/server/services/config-registry-service.js +4 -5
- package/src/server/services/config-sync-manager.js +61 -41
- package/src/server/services/config-sync-service.js +3 -3
- package/src/server/services/gemini-channels.js +5 -5
- package/src/server/services/gemini-config.js +3 -4
- package/src/server/services/gemini-sessions.js +23 -20
- package/src/server/services/gemini-settings-manager.js +2 -3
- package/src/server/services/mcp-service.js +9 -14
- package/src/server/services/native-oauth-adapters.js +3 -3
- package/src/server/services/notification-hooks.js +3 -3
- package/src/server/services/opencode-sessions.js +4 -4
- package/src/server/services/opencode-settings-manager.js +3 -3
- package/src/server/services/plugins-service.js +499 -23
- package/src/server/services/prompts-service.js +5 -9
- package/src/server/services/sessions.js +2 -2
- package/src/server/services/skill-service.js +155 -18
- package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
- package/dist/web/assets/Home-BQxQ1LhR.css +0 -1
- package/dist/web/assets/ProjectList-BMVhA_Kh.js +0 -1
- package/dist/web/assets/ProjectList-DL4JK6ci.css +0 -1
- package/dist/web/assets/SessionList-B5ioAXxg.js +0 -1
- package/dist/web/assets/SessionList-B8dXVXfi.css +0 -1
- package/dist/web/assets/icons-CQuif85v.js +0 -1
- package/dist/web/assets/index-CtByKdkA.js +0 -2
- package/dist/web/assets/index-VGAxnLqi.css +0 -1
- package/dist/web/assets/vue-vendor-aWwwFAao.js +0 -45
package/src/config/paths.js
CHANGED
|
@@ -28,6 +28,9 @@ 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');
|
|
31
34
|
const REQUESTS_DIR = path.join(STORAGE_DIR, 'requests');
|
|
32
35
|
const BACKUPS_DIR = path.join(STORAGE_DIR, 'backups');
|
|
33
36
|
const SCRIPTS_DIR = path.join(STORAGE_DIR, 'scripts');
|
|
@@ -39,8 +42,8 @@ const LEGACY_STATS_DIR = path.join(LEGACY_DIR, 'stats');
|
|
|
39
42
|
|
|
40
43
|
// 旧目录(升级时自动合并到 ~/.cc-tool)
|
|
41
44
|
const LEGACY_BASE_DIRS = [
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
joinNativeBasePath(HOME_DIR, '.claude', 'ctx'),
|
|
46
|
+
joinNativeBasePath(HOME_DIR, '.claude', 'cc-tool')
|
|
44
47
|
];
|
|
45
48
|
|
|
46
49
|
let migrationChecked = false;
|
|
@@ -464,6 +467,19 @@ const PATHS = {
|
|
|
464
467
|
gemini: path.join(LOCAL_SKILLS_DIR, 'gemini'),
|
|
465
468
|
opencode: path.join(LOCAL_SKILLS_DIR, 'opencode')
|
|
466
469
|
},
|
|
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
|
+
},
|
|
467
483
|
skillRepos: {
|
|
468
484
|
claude: path.join(REPOS_SKILLS_DIR, 'claude.json'),
|
|
469
485
|
codex: path.join(REPOS_SKILLS_DIR, 'codex.json'),
|
|
@@ -486,7 +502,7 @@ const PATHS = {
|
|
|
486
502
|
},
|
|
487
503
|
|
|
488
504
|
// 原生路径兼容
|
|
489
|
-
skills:
|
|
505
|
+
skills: getNativePlatformSkillsDir('claude'),
|
|
490
506
|
|
|
491
507
|
// 旧版本遗留文件搬迁目标
|
|
492
508
|
legacy: {
|
|
@@ -715,15 +731,15 @@ function pickExistingDir(candidates, fallback) {
|
|
|
715
731
|
}
|
|
716
732
|
|
|
717
733
|
function getClaudeConfigDir() {
|
|
718
|
-
return resolveExistingEnvPath(process.env.CLAUDE_CONFIG_DIR) ||
|
|
734
|
+
return resolveExistingEnvPath(process.env.CLAUDE_CONFIG_DIR) || joinNativeBasePath(HOME_DIR, '.claude');
|
|
719
735
|
}
|
|
720
736
|
|
|
721
737
|
function getCodexDir() {
|
|
722
|
-
return resolveExistingEnvPath(process.env.CODEX_HOME) ||
|
|
738
|
+
return resolveExistingEnvPath(process.env.CODEX_HOME) || joinNativeBasePath(HOME_DIR, '.codex');
|
|
723
739
|
}
|
|
724
740
|
|
|
725
741
|
function getGeminiDir() {
|
|
726
|
-
return
|
|
742
|
+
return joinNativeBasePath(HOME_DIR, '.gemini');
|
|
727
743
|
}
|
|
728
744
|
|
|
729
745
|
function getOpenCodeDataDir() {
|
|
@@ -762,49 +778,151 @@ function getOpenCodeConfigDir() {
|
|
|
762
778
|
return preferredDir;
|
|
763
779
|
}
|
|
764
780
|
|
|
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
|
+
|
|
765
856
|
// 工具特定的原生配置路径(不改变)
|
|
766
857
|
const NATIVE_PATHS = {
|
|
767
858
|
// Claude Code 原生配置
|
|
768
859
|
claude: {
|
|
769
|
-
dir:
|
|
770
|
-
settings:
|
|
771
|
-
settingsBackup:
|
|
772
|
-
projects:
|
|
773
|
-
|
|
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')
|
|
774
872
|
},
|
|
775
873
|
|
|
776
874
|
// Codex 原生配置
|
|
777
875
|
codex: {
|
|
778
|
-
dir:
|
|
779
|
-
config:
|
|
780
|
-
configBackup:
|
|
781
|
-
auth:
|
|
782
|
-
authBackup:
|
|
783
|
-
sessions:
|
|
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')
|
|
784
887
|
},
|
|
785
888
|
|
|
786
889
|
// Gemini 原生配置
|
|
787
890
|
gemini: {
|
|
788
|
-
dir:
|
|
789
|
-
env:
|
|
790
|
-
envBackup:
|
|
791
|
-
tmp:
|
|
792
|
-
settings:
|
|
793
|
-
settingsBackup:
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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')
|
|
797
903
|
},
|
|
798
904
|
|
|
799
905
|
// OpenCode 原生配置
|
|
800
906
|
opencode: {
|
|
801
|
-
data:
|
|
802
|
-
config:
|
|
803
|
-
sessions:
|
|
804
|
-
projects:
|
|
805
|
-
messages:
|
|
806
|
-
log:
|
|
807
|
-
auth:
|
|
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')
|
|
808
926
|
}
|
|
809
927
|
};
|
|
810
928
|
|
|
@@ -823,6 +941,15 @@ module.exports = {
|
|
|
823
941
|
getClaudeConfigDir,
|
|
824
942
|
getCodexDir,
|
|
825
943
|
getGeminiDir,
|
|
944
|
+
isWindowsAbsolutePath,
|
|
945
|
+
isNativeAbsolutePath,
|
|
946
|
+
joinNativeBasePath,
|
|
947
|
+
resolveNativeBasePath,
|
|
948
|
+
getNativePathDir,
|
|
949
|
+
getNativePlatformDir,
|
|
950
|
+
getNativePlatformSubPath,
|
|
951
|
+
getNativePlatformSkillsDir,
|
|
952
|
+
getNativePlatformPromptPath,
|
|
826
953
|
getOpenCodeDataDir,
|
|
827
954
|
getOpenCodeConfigDir
|
|
828
955
|
};
|
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 } = req.query;
|
|
231
|
+
const { projectPath, refresh } = req.query;
|
|
232
232
|
const normalizedProjectPath = normalizeOptionalProjectPath(projectPath);
|
|
233
233
|
if (normalizedProjectPath.error) {
|
|
234
234
|
return res.status(400).json({
|
|
@@ -236,7 +236,10 @@ router.get('/', (req, res) => {
|
|
|
236
236
|
message: normalizedProjectPath.error
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
|
-
const
|
|
239
|
+
const forceRefresh = refresh === '1';
|
|
240
|
+
const result = service.listAgents(normalizedProjectPath.projectPath, {
|
|
241
|
+
syncManagedLocalAgents: forceRefresh
|
|
242
|
+
});
|
|
240
243
|
|
|
241
244
|
res.json({
|
|
242
245
|
success: true,
|
|
@@ -775,6 +778,53 @@ router.post('/install', async (req, res) => {
|
|
|
775
778
|
}
|
|
776
779
|
});
|
|
777
780
|
|
|
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
|
+
|
|
778
828
|
/**
|
|
779
829
|
* 卸载代理
|
|
780
830
|
* POST /api/agents/uninstall
|
|
@@ -35,8 +35,11 @@ function getCommandsService(req) {
|
|
|
35
35
|
router.get('/', (req, res) => {
|
|
36
36
|
try {
|
|
37
37
|
const { platform, service } = getCommandsService(req);
|
|
38
|
-
const { projectPath } = req.query;
|
|
39
|
-
const
|
|
38
|
+
const { projectPath, refresh } = req.query;
|
|
39
|
+
const forceRefresh = refresh === '1';
|
|
40
|
+
const result = service.listCommands(projectPath || null, {
|
|
41
|
+
syncManagedLocalCommands: forceRefresh
|
|
42
|
+
});
|
|
40
43
|
|
|
41
44
|
res.json({
|
|
42
45
|
success: true,
|
|
@@ -446,6 +449,39 @@ router.post('/install', async (req, res) => {
|
|
|
446
449
|
}
|
|
447
450
|
});
|
|
448
451
|
|
|
452
|
+
/**
|
|
453
|
+
* 安装本地托管命令
|
|
454
|
+
* POST /api/commands/install-local
|
|
455
|
+
* Body: { path }
|
|
456
|
+
*/
|
|
457
|
+
router.post('/install-local', (req, res) => {
|
|
458
|
+
try {
|
|
459
|
+
const { platform, service } = getCommandsService(req);
|
|
460
|
+
const { path } = req.body;
|
|
461
|
+
|
|
462
|
+
if (!path) {
|
|
463
|
+
return res.status(400).json({
|
|
464
|
+
success: false,
|
|
465
|
+
message: 'Missing path'
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const result = service.installLocalCommand(path);
|
|
470
|
+
|
|
471
|
+
res.json({
|
|
472
|
+
success: true,
|
|
473
|
+
platform,
|
|
474
|
+
...result
|
|
475
|
+
});
|
|
476
|
+
} catch (err) {
|
|
477
|
+
console.error('[Commands API] Install local command error:', err);
|
|
478
|
+
res.status(500).json({
|
|
479
|
+
success: false,
|
|
480
|
+
message: err.message
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
|
|
449
485
|
/**
|
|
450
486
|
* 卸载命令
|
|
451
487
|
* POST /api/commands/uninstall
|
|
@@ -88,7 +88,10 @@ function sanitizeRepos(service, repos = []) {
|
|
|
88
88
|
router.get('/', (req, res) => {
|
|
89
89
|
try {
|
|
90
90
|
const { platform, service } = getPluginsService(req);
|
|
91
|
-
const
|
|
91
|
+
const forceRefresh = req.query.refresh === '1';
|
|
92
|
+
const result = service.listPlugins({
|
|
93
|
+
syncManagedLocalPlugins: forceRefresh
|
|
94
|
+
});
|
|
92
95
|
|
|
93
96
|
res.json({
|
|
94
97
|
success: true,
|
|
@@ -189,6 +192,46 @@ router.post('/install', async (req, res) => {
|
|
|
189
192
|
}
|
|
190
193
|
});
|
|
191
194
|
|
|
195
|
+
/**
|
|
196
|
+
* 安装本地托管插件
|
|
197
|
+
* POST /api/plugins/install-local
|
|
198
|
+
* Body: { name }
|
|
199
|
+
*/
|
|
200
|
+
router.post('/install-local', (req, res) => {
|
|
201
|
+
try {
|
|
202
|
+
const { platform, service } = getPluginsService(req);
|
|
203
|
+
const { name } = req.body;
|
|
204
|
+
|
|
205
|
+
if (!name) {
|
|
206
|
+
return res.status(400).json({
|
|
207
|
+
success: false,
|
|
208
|
+
message: 'name is required'
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const result = service.installLocalPlugin(name);
|
|
213
|
+
if (!result.success) {
|
|
214
|
+
return res.status(400).json({
|
|
215
|
+
success: false,
|
|
216
|
+
message: result.error || result.message || 'Install failed'
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
res.json({
|
|
221
|
+
success: true,
|
|
222
|
+
platform,
|
|
223
|
+
plugin: result.plugin,
|
|
224
|
+
message: result.message || `Plugin "${result.plugin?.name || name}" installed successfully`
|
|
225
|
+
});
|
|
226
|
+
} catch (err) {
|
|
227
|
+
console.error('[Plugins API] Install local plugin error:', err);
|
|
228
|
+
res.status(500).json({
|
|
229
|
+
success: false,
|
|
230
|
+
message: err.message
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
192
235
|
// ==================== 仓库管理 API ====================
|
|
193
236
|
|
|
194
237
|
/**
|
|
@@ -440,6 +483,66 @@ router.post('/sync', async (req, res) => {
|
|
|
440
483
|
}
|
|
441
484
|
});
|
|
442
485
|
|
|
486
|
+
/**
|
|
487
|
+
* 获取插件文件列表
|
|
488
|
+
* GET /api/plugins/:name/files
|
|
489
|
+
*/
|
|
490
|
+
router.get('/:name/files', async (req, res) => {
|
|
491
|
+
try {
|
|
492
|
+
const { platform, service } = getPluginsService(req);
|
|
493
|
+
const { name } = req.params;
|
|
494
|
+
const pluginInfo = extractPluginQueryInfo(name, req.query);
|
|
495
|
+
const result = await service.getPluginFiles(pluginInfo);
|
|
496
|
+
|
|
497
|
+
res.json({
|
|
498
|
+
success: true,
|
|
499
|
+
platform,
|
|
500
|
+
...result
|
|
501
|
+
});
|
|
502
|
+
} catch (err) {
|
|
503
|
+
console.error('[Plugins API] Get plugin files error:', err);
|
|
504
|
+
res.status(500).json({
|
|
505
|
+
success: false,
|
|
506
|
+
message: err.message,
|
|
507
|
+
files: []
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* 获取插件单个文件内容
|
|
514
|
+
* GET /api/plugins/:name/file/*
|
|
515
|
+
*/
|
|
516
|
+
router.get('/:name/file/*', async (req, res) => {
|
|
517
|
+
try {
|
|
518
|
+
const { platform, service } = getPluginsService(req);
|
|
519
|
+
const { name } = req.params;
|
|
520
|
+
const filePath = req.params[0];
|
|
521
|
+
|
|
522
|
+
if (!filePath) {
|
|
523
|
+
return res.status(400).json({
|
|
524
|
+
success: false,
|
|
525
|
+
message: '请指定文件路径'
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const pluginInfo = extractPluginQueryInfo(name, req.query);
|
|
530
|
+
const result = await service.getPluginFileContent(pluginInfo, filePath);
|
|
531
|
+
|
|
532
|
+
res.json({
|
|
533
|
+
success: true,
|
|
534
|
+
platform,
|
|
535
|
+
...result
|
|
536
|
+
});
|
|
537
|
+
} catch (err) {
|
|
538
|
+
console.error('[Plugins API] Get plugin file content error:', err);
|
|
539
|
+
res.status(500).json({
|
|
540
|
+
success: false,
|
|
541
|
+
message: err.message
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
443
546
|
/**
|
|
444
547
|
* 获取插件 README
|
|
445
548
|
* GET /api/plugins/:name/readme
|
|
@@ -7,7 +7,7 @@ const { getSessionsForProject, deleteSession, forkSession, saveSessionOrder, par
|
|
|
7
7
|
const { loadAliases } = require('../services/alias');
|
|
8
8
|
const { broadcastLog } = require('../websocket-server');
|
|
9
9
|
const { buildLaunchCommand } = require('../services/session-launch-command');
|
|
10
|
-
const { NATIVE_PATHS } = require('../../config/paths');
|
|
10
|
+
const { NATIVE_PATHS, joinNativeBasePath } = require('../../config/paths');
|
|
11
11
|
const CLAUDE_PROJECTS_DIR = NATIVE_PATHS.claude.projects;
|
|
12
12
|
|
|
13
13
|
module.exports = (config) => {
|
|
@@ -171,13 +171,13 @@ module.exports = (config) => {
|
|
|
171
171
|
const year = now.getFullYear();
|
|
172
172
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
173
173
|
const day = String(now.getDate()).padStart(2, '0');
|
|
174
|
-
sessionDir =
|
|
175
|
-
sessionFile =
|
|
174
|
+
sessionDir = joinNativeBasePath(NATIVE_PATHS.codex.sessions, String(year), month, day);
|
|
175
|
+
sessionFile = joinNativeBasePath(sessionDir, `${newSessionId}.jsonl`);
|
|
176
176
|
} else if (toolType === 'gemini') {
|
|
177
177
|
// Gemini: ~/.gemini/tmp/{hash}/chats/{sessionId}.json
|
|
178
178
|
const pathHash = crypto.createHash('sha256').update(fullPath).digest('hex');
|
|
179
|
-
sessionDir =
|
|
180
|
-
sessionFile =
|
|
179
|
+
sessionDir = joinNativeBasePath(NATIVE_PATHS.gemini.tmp, pathHash, 'chats');
|
|
180
|
+
sessionFile = joinNativeBasePath(sessionDir, `${newSessionId}.json`);
|
|
181
181
|
} else {
|
|
182
182
|
return res.status(400).json({ error: 'Invalid toolType. Must be claude, codex, or gemini' });
|
|
183
183
|
}
|