coding-tool-x 3.8.6 → 3.8.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/{AgentsDrawer-Db9wAyaZ.js → AgentsDrawer-DRQuwi0m.js} +1 -1
- package/dist/web/assets/Analytics-Cf5KwEdj.js +1 -0
- package/dist/web/assets/AssetPathField-DyniM0pF.js +1 -0
- package/dist/web/assets/{ChatHistoryDrawer-CwzJHyNP.js → ChatHistoryDrawer-CrfS0KYV.js} +1 -1
- package/dist/web/assets/{CollapseItem-CTCfSiue.js → CollapseItem-ClMsJuUu.js} +1 -1
- package/dist/web/assets/{CommandsDrawer-vDghB1U9.js → CommandsDrawer-CzHelf56.js} +1 -1
- package/dist/web/assets/ConfigExportDrawer-BEZ8wTby.js +1 -0
- package/dist/web/assets/ConfigTemplates-Crg3xWe5.js +1 -0
- package/dist/web/assets/{ConfigTemplatesDrawer-CbsJp76X.js → ConfigTemplatesDrawer-BqM32Im7.js} +1 -1
- package/dist/web/assets/{ConfigTemplatesPanel-liMSTh7s.js → ConfigTemplatesPanel-lTdutC8H.js} +1 -1
- package/dist/web/assets/{Divider-D28g1gwj.js → Divider-DsdbkHrG.js} +1 -1
- package/dist/web/assets/{FavoritesDrawer-D6QSiYaL.js → FavoritesDrawer-DDyWUBJR.js} +1 -1
- package/dist/web/assets/Forward-DLCL7aMY.js +1 -0
- package/dist/web/assets/{GatewayConvertDrawer-RvET6iNG.js → GatewayConvertDrawer-Rigtt_5J.js} +1 -1
- package/dist/web/assets/Home-tCSKmSHV.js +1 -0
- package/dist/web/assets/{MarkdownEditor-CYmLGYju.js → MarkdownEditor-BMMUufSc.js} +1 -1
- package/dist/web/assets/McpDrawer-CmE-d7VW.js +1 -0
- package/dist/web/assets/{McpFormDrawer-BcTlgSpN.js → McpFormDrawer-ByvS18od.js} +1 -1
- package/dist/web/assets/{PluginManager-Dh2o0xkZ.js → PluginManager-C4kJlpVX.js} +1 -1
- package/dist/web/assets/{PluginsDrawer-deKQ5u3I.js → PluginsDrawer-05R4k15x.js} +1 -1
- package/dist/web/assets/PluginsPanel-BCoEs7Og.js +1 -0
- package/dist/web/assets/PluginsPanel-CzGMK-Ap.css +1 -0
- package/dist/web/assets/ProjectList-BJt1OIaI.js +1 -0
- package/dist/web/assets/ProjectList-DG3yu8xZ.css +1 -0
- package/dist/web/assets/PromptsDrawer-DnwBf_oW.js +1 -0
- package/dist/web/assets/RecentSessionsDrawer-B7d-38wH.js +1 -0
- package/dist/web/assets/RecentSessionsDrawer-yrAD4p1A.css +1 -0
- package/dist/web/assets/SessionCard-BUgjHQwX.js +1 -0
- package/dist/web/assets/SessionList-B-bXZRFk.js +1 -0
- package/dist/web/assets/SessionList-qG_XpPBJ.css +1 -0
- package/dist/web/assets/{SettingsDrawer-u_vwUuPS.js → SettingsDrawer-BITzjQLl.js} +1 -1
- package/dist/web/assets/SkillManager-D9jkNuRM.js +1 -0
- package/dist/web/assets/{SkillsDrawer-CkF3BpyC.js → SkillsDrawer-0Z4IefxC.js} +1 -1
- package/dist/web/assets/SkillsPanel-BKIVOj7n.js +1 -0
- package/dist/web/assets/{SkillsPanel-B3Nm5j32.css → SkillsPanel-C4ke56nF.css} +1 -1
- package/dist/web/assets/{SpeedTestDrawer-BgfG1Ked.js → SpeedTestDrawer-Bx1bYf5i.js} +1 -1
- package/dist/web/assets/Upload-CzC4rGI4.js +1 -0
- package/dist/web/assets/{WorkspaceDrawer-Br5CeCzL.js → WorkspaceDrawer-eujtWpoq.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-B2O8-qIw.js → WorkspaceManager-CQ-8Ej68.js} +1 -1
- package/dist/web/assets/{WorkspacePanel-5oDKit3c.js → WorkspacePanel-Cql5qE2R.js} +1 -1
- package/dist/web/assets/headers-BqDmkMjy.js +1 -0
- package/dist/web/assets/{icons-B2Vg-IOC.js → icons-DmFe4b5j.js} +1 -1
- package/dist/web/assets/index-Cmmwj3Fx.js +2 -0
- package/dist/web/assets/{index-Bi1MQHYX.css → index-Cnbe696C.css} +1 -1
- package/dist/web/assets/{light-Cp0t7v32.js → light-0eavxNvt.js} +1 -1
- package/dist/web/assets/platforms-BmzzwnSw.js +1 -0
- package/dist/web/assets/platforms-DWXgmy2w.js +1 -0
- package/dist/web/assets/session-visibility-BAmxh3cK.js +1 -0
- package/dist/web/assets/sessions-D4yQtfKb.js +1 -0
- package/dist/web/assets/sessions-DqlbocLJ.js +1 -0
- package/dist/web/assets/use-message-DqCwefG6.js +1 -0
- package/dist/web/assets/{useResponsiveDrawer-jbmqZuJs.js → useResponsiveDrawer-DZd5rNk5.js} +1 -1
- package/dist/web/index.html +7 -7
- package/package.json +1 -1
- package/src/commands/search.js +17 -2
- package/src/config/paths.js +2 -0
- package/src/platforms/driver-registry.js +9 -1
- package/src/platforms/drivers/claude/session-history-adapter.js +72 -1
- package/src/platforms/drivers/claude/sessions-implementation.js +49 -7
- package/src/platforms/drivers/claude/sessions.js +30 -6
- package/src/platforms/drivers/codex/parser.js +57 -1
- package/src/platforms/drivers/codex/session-history-adapter.js +8 -2
- package/src/platforms/drivers/codex/sessions-implementation.js +25 -3
- package/src/platforms/drivers/codex/sessions.js +18 -1
- package/src/platforms/drivers/dsh/api-operations.js +396 -0
- package/src/platforms/drivers/dsh/channels-implementation.js +458 -0
- package/src/platforms/drivers/dsh/channels.js +191 -0
- package/src/platforms/drivers/dsh/common.js +571 -0
- package/src/platforms/drivers/dsh/native-config.js +93 -0
- package/src/platforms/drivers/dsh/native-logs.js +116 -0
- package/src/platforms/drivers/dsh/plugin-manager.js +117 -0
- package/src/platforms/drivers/dsh/projects.js +23 -0
- package/src/platforms/drivers/dsh/proxy-implementation.js +260 -0
- package/src/platforms/drivers/dsh/proxy.js +23 -0
- package/src/platforms/drivers/dsh/resources.js +346 -0
- package/src/platforms/drivers/dsh/sessions.js +587 -0
- package/src/platforms/drivers/dsh/statistics-implementation.js +238 -0
- package/src/platforms/drivers/dsh/statistics.js +24 -0
- package/src/platforms/drivers/gemini/session-history-adapter.js +49 -1
- package/src/platforms/drivers/gemini/sessions-implementation.js +46 -1
- package/src/platforms/drivers/gemini/sessions.js +2 -1
- package/src/platforms/drivers/omp/session-history-adapter.js +42 -1
- package/src/platforms/drivers/omp/sessions-implementation.js +51 -3
- package/src/platforms/drivers/omp/sessions.js +33 -2
- package/src/platforms/drivers/opencode/sessions-implementation.js +89 -9
- package/src/platforms/drivers/opencode/sessions.js +37 -1
- package/src/platforms/manifest-schema.js +43 -3
- package/src/platforms/manifests/dsh.json +542 -0
- package/src/platforms/path-resolver.js +2 -0
- package/src/platforms/platform-path-context.js +12 -2
- package/src/platforms/registry.js +16 -1
- package/src/platforms/runtime.js +5 -0
- package/src/platforms/session-history-adapters.js +1 -0
- package/src/server/api/platform-api-config.js +23 -2
- package/src/server/api/platform-route-factory.js +9 -2
- package/src/server/api/platforms.js +19 -1
- package/src/server/api/plugins.js +108 -13
- package/src/server/services/config-registry-service.js +10 -1
- package/src/server/services/config-templates-service.js +1 -0
- package/src/server/services/plugins-service.js +474 -103
- package/src/server/services/session-history-index.js +900 -140
- package/src/server/services/session-history-worker.js +3 -1
- package/src/server/services/skill-service.js +214 -7
- package/src/server/services/usage-log-utils.js +1 -0
- package/src/server/services/workspace-service.js +39 -10
- package/src/shared/channel-driver.js +80 -5
- package/src/shared/driver-factories/api.js +22 -6
- package/src/shared/driver-factories/projects.js +8 -0
- package/dist/web/assets/Analytics-C4gMzv7g.js +0 -1
- package/dist/web/assets/AssetPathField-Bd_nMFu3.js +0 -1
- package/dist/web/assets/ConfigExportDrawer-C-XDvlHc.js +0 -1
- package/dist/web/assets/ConfigTemplates-CYY8XRED.js +0 -1
- package/dist/web/assets/Home-P8eseZcf.js +0 -1
- package/dist/web/assets/McpDrawer-Ch3bkKIq.js +0 -1
- package/dist/web/assets/PluginsPanel-BofsgQgj.js +0 -1
- package/dist/web/assets/PluginsPanel-D6ZqITcR.css +0 -1
- package/dist/web/assets/ProjectList-677RLZ8O.css +0 -1
- package/dist/web/assets/ProjectList-DhSWJHTA.js +0 -1
- package/dist/web/assets/PromptsDrawer-Cfb2FeeU.js +0 -1
- package/dist/web/assets/RecentSessionsDrawer-3eXamJhr.js +0 -1
- package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +0 -1
- package/dist/web/assets/SessionCard-CW0eHURI.js +0 -1
- package/dist/web/assets/SessionList-BpYRz1cX.css +0 -1
- package/dist/web/assets/SessionList-DQfyDGWU.js +0 -1
- package/dist/web/assets/SkillManager-DHMprJLA.js +0 -1
- package/dist/web/assets/SkillsPanel-DWE4pFGx.js +0 -1
- package/dist/web/assets/Upload-CNwaGOws.js +0 -1
- package/dist/web/assets/headers-cf-QapUq.js +0 -1
- package/dist/web/assets/index-BMAUPq5K.js +0 -2
- package/dist/web/assets/platforms-CBkB45JP.js +0 -1
- package/dist/web/assets/platforms-FTpjxAT6.js +0 -1
- package/dist/web/assets/sessions-Cmy31slD.js +0 -1
- package/dist/web/assets/sessions-yC_oVVh8.js +0 -1
- package/dist/web/assets/use-message-DoLM8C1C.js +0 -1
|
@@ -33,20 +33,41 @@ function requestContext(request, manifest, route, config) {
|
|
|
33
33
|
|
|
34
34
|
function projectPayload(data, context) {
|
|
35
35
|
if (Array.isArray(data)) {
|
|
36
|
-
return {
|
|
36
|
+
return {
|
|
37
|
+
projects: data,
|
|
38
|
+
currentProject: null,
|
|
39
|
+
pagination: { page: 1, limit: data.length || 20, total: data.length, hasMore: false },
|
|
40
|
+
meta: {}
|
|
41
|
+
};
|
|
37
42
|
}
|
|
38
43
|
const payload = cloneObject(data);
|
|
39
44
|
if (!Array.isArray(payload.projects)) payload.projects = [];
|
|
40
45
|
if (!Object.prototype.hasOwnProperty.call(payload, 'currentProject')) payload.currentProject = null;
|
|
41
46
|
if (!payload.meta || typeof payload.meta !== 'object' || Array.isArray(payload.meta)) payload.meta = {};
|
|
47
|
+
if (!payload.pagination || typeof payload.pagination !== 'object') {
|
|
48
|
+
payload.pagination = { page: 1, limit: payload.projects.length || 20, total: payload.projects.length, hasMore: false };
|
|
49
|
+
}
|
|
42
50
|
return payload;
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
function sessionPayload(data) {
|
|
46
|
-
if (Array.isArray(data))
|
|
54
|
+
if (Array.isArray(data)) {
|
|
55
|
+
return {
|
|
56
|
+
sessions: data,
|
|
57
|
+
totalSize: data.reduce((sum, session) => sum + (Number(session?.size) || 0), 0),
|
|
58
|
+
pagination: { page: 1, limit: data.length || 20, total: data.length, hasMore: false },
|
|
59
|
+
meta: {}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
47
62
|
const payload = cloneObject(data);
|
|
48
63
|
if (!Array.isArray(payload.sessions)) payload.sessions = [];
|
|
49
64
|
if (!payload.meta || typeof payload.meta !== 'object' || Array.isArray(payload.meta)) payload.meta = {};
|
|
65
|
+
if (!payload.pagination || typeof payload.pagination !== 'object') {
|
|
66
|
+
payload.pagination = { page: 1, limit: payload.sessions.length || 20, total: payload.sessions.length, hasMore: false };
|
|
67
|
+
}
|
|
68
|
+
if (!Object.prototype.hasOwnProperty.call(payload, 'totalSize')) {
|
|
69
|
+
payload.totalSize = payload.sessions.reduce((sum, session) => sum + (Number(session?.size) || 0), 0);
|
|
70
|
+
}
|
|
50
71
|
return payload;
|
|
51
72
|
}
|
|
52
73
|
|
|
@@ -63,9 +63,16 @@ function makeUnsupported(context) {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
function legacyArguments(route, request) {
|
|
66
|
-
|
|
66
|
+
const listOptions = () => {
|
|
67
|
+
const options = { force: request.query?.fresh === '1' };
|
|
68
|
+
if (request.query?.page != null) options.page = request.query.page;
|
|
69
|
+
if (request.query?.limit != null) options.limit = request.query.limit;
|
|
70
|
+
if (request.query?.q || request.query?.search) options.q = request.query.q || request.query.search;
|
|
71
|
+
return options;
|
|
72
|
+
};
|
|
73
|
+
if (route.capability === 'projects' && route.operation === 'listProjects') return [listOptions()];
|
|
67
74
|
if (route.capability === 'sessions' && route.operation === 'listSessions') {
|
|
68
|
-
return [request.params.projectName,
|
|
75
|
+
return [request.params.projectName, listOptions()];
|
|
69
76
|
}
|
|
70
77
|
if (route.capability === 'channels') {
|
|
71
78
|
if (route.method === 'POST') return [request.body || {}];
|
|
@@ -19,7 +19,8 @@ const PUBLIC_FIELDS = Object.freeze([
|
|
|
19
19
|
'apiPrefix',
|
|
20
20
|
'modelCatalogKey',
|
|
21
21
|
'promptLabel',
|
|
22
|
-
'resourceTypes'
|
|
22
|
+
'resourceTypes',
|
|
23
|
+
'resourceActions'
|
|
23
24
|
]);
|
|
24
25
|
|
|
25
26
|
function publicCapabilities(capabilities) {
|
|
@@ -41,6 +42,18 @@ function publicResourceTypes(resourceTypes) {
|
|
|
41
42
|
);
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
function publicResourceActions(resourceActions) {
|
|
46
|
+
if (!resourceActions || typeof resourceActions !== 'object' || Array.isArray(resourceActions)) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return Object.fromEntries(Object.entries(resourceActions).map(([resourceType, actions]) => [
|
|
50
|
+
resourceType,
|
|
51
|
+
actions && typeof actions === 'object' && !Array.isArray(actions)
|
|
52
|
+
? Object.fromEntries(Object.entries(actions).filter(([, value]) => typeof value === 'boolean'))
|
|
53
|
+
: {}
|
|
54
|
+
]));
|
|
55
|
+
}
|
|
56
|
+
|
|
44
57
|
function toPublicDefinition(definition) {
|
|
45
58
|
if (!definition || typeof definition !== 'object') return null;
|
|
46
59
|
const result = {};
|
|
@@ -50,6 +63,11 @@ function toPublicDefinition(definition) {
|
|
|
50
63
|
if (resourceTypes) result.resourceTypes = resourceTypes;
|
|
51
64
|
continue;
|
|
52
65
|
}
|
|
66
|
+
if (field === 'resourceActions') {
|
|
67
|
+
const resourceActions = publicResourceActions(definition.resourceActions);
|
|
68
|
+
if (resourceActions) result.resourceActions = resourceActions;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
53
71
|
if (field === 'apiPrefix') {
|
|
54
72
|
const apiPrefix = definition.apiPrefix ?? definition.api?.prefix;
|
|
55
73
|
if (apiPrefix !== undefined) result.apiPrefix = apiPrefix || null;
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const express = require('express');
|
|
8
|
+
const path = require('path');
|
|
8
9
|
const { PluginsService } = require('../services/plugins-service');
|
|
10
|
+
const { SkillRefreshTaskService } = require('../services/skill-refresh-task-service');
|
|
11
|
+
const { PATHS } = require('../../config/paths');
|
|
9
12
|
const { maskToken } = require('../services/oauth-utils');
|
|
10
13
|
const { sendApiError } = require('./validation-errors');
|
|
11
14
|
const { resolveManagedPlatform } = require('../services/platform-resolution');
|
|
@@ -13,6 +16,13 @@ const { validateKnownProjectCwd } = require('../services/project-path-validation
|
|
|
13
16
|
|
|
14
17
|
const router = express.Router();
|
|
15
18
|
const pluginServices = new Map();
|
|
19
|
+
let routerOptions = {};
|
|
20
|
+
let defaultRefreshTasks;
|
|
21
|
+
|
|
22
|
+
router.createRouter = (options = {}) => {
|
|
23
|
+
routerOptions = options;
|
|
24
|
+
return router;
|
|
25
|
+
};
|
|
16
26
|
|
|
17
27
|
function resolvePlatform(rawPlatform) {
|
|
18
28
|
return resolveManagedPlatform(rawPlatform);
|
|
@@ -35,6 +45,26 @@ function getPluginsService(req) {
|
|
|
35
45
|
};
|
|
36
46
|
}
|
|
37
47
|
|
|
48
|
+
function getPluginServiceForPlatform(platform) {
|
|
49
|
+
if (!pluginServices.has(platform)) {
|
|
50
|
+
pluginServices.set(platform, new PluginsService(platform));
|
|
51
|
+
}
|
|
52
|
+
return pluginServices.get(platform);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getRefreshTasks() {
|
|
56
|
+
if (routerOptions.refreshTasks) return routerOptions.refreshTasks;
|
|
57
|
+
if (!defaultRefreshTasks) {
|
|
58
|
+
const persistencePath = PATHS.pluginRefreshTasks
|
|
59
|
+
|| path.join(PATHS.storage || process.cwd(), 'runtime', 'plugin-refresh-tasks.json');
|
|
60
|
+
defaultRefreshTasks = new SkillRefreshTaskService({
|
|
61
|
+
persistencePath,
|
|
62
|
+
worker: context => getPluginServiceForPlatform(context.platform).refreshRemotePlugins(context)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return defaultRefreshTasks;
|
|
66
|
+
}
|
|
67
|
+
|
|
38
68
|
async function getRequestOptions(req, service) {
|
|
39
69
|
const scope = String(req.query?.scope || req.body?.scope || '').trim();
|
|
40
70
|
if (scope && scope !== 'user' && scope !== 'project') {
|
|
@@ -147,11 +177,15 @@ router.get('/', async (req, res) => {
|
|
|
147
177
|
const { platform, service, warning } = getPluginsService(req);
|
|
148
178
|
const options = await getRequestOptions(req, service);
|
|
149
179
|
const result = invokeWithOptions(service.listPlugins.bind(service), [], options);
|
|
180
|
+
const plugins = typeof service.sanitizePluginList === 'function'
|
|
181
|
+
? service.sanitizePluginList(result.plugins)
|
|
182
|
+
: result.plugins;
|
|
150
183
|
|
|
151
184
|
res.json({
|
|
152
185
|
success: true,
|
|
153
186
|
platform,
|
|
154
187
|
...result,
|
|
188
|
+
plugins,
|
|
155
189
|
...(warning ? { warnings: [warning] } : {})
|
|
156
190
|
});
|
|
157
191
|
} catch (err) {
|
|
@@ -168,12 +202,11 @@ router.get('/market', async (req, res) => {
|
|
|
168
202
|
try {
|
|
169
203
|
const { platform, service, warning } = getPluginsService(req);
|
|
170
204
|
const options = await getRequestOptions(req, service);
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
console.log(`[Plugins API] ${platform}: ${plugins.length} market plugins loaded (refresh=${forceRefresh})`);
|
|
205
|
+
const marketPlugins = await invokeWithOptions(service.getMarketPlugins.bind(service), [false], options);
|
|
206
|
+
const plugins = typeof service.sanitizePluginList === 'function'
|
|
207
|
+
? service.sanitizePluginList(marketPlugins)
|
|
208
|
+
: marketPlugins;
|
|
209
|
+
console.log(`[Plugins API] ${platform}: ${plugins.length} cached market plugins loaded`);
|
|
177
210
|
|
|
178
211
|
res.json({
|
|
179
212
|
success: true,
|
|
@@ -187,6 +220,53 @@ router.get('/market', async (req, res) => {
|
|
|
187
220
|
}
|
|
188
221
|
});
|
|
189
222
|
|
|
223
|
+
/**
|
|
224
|
+
* 启动插件远端全量缓存任务
|
|
225
|
+
* POST /api/plugins/refresh
|
|
226
|
+
*/
|
|
227
|
+
router.post('/refresh', async (req, res) => {
|
|
228
|
+
try {
|
|
229
|
+
const { platform, service } = getPluginsService(req);
|
|
230
|
+
const options = await getRequestOptions(req, service);
|
|
231
|
+
const refreshTasks = getRefreshTasks();
|
|
232
|
+
if (!refreshTasks) throw new Error('Plugin refresh task service is unavailable');
|
|
233
|
+
const task = refreshTasks.enqueue({
|
|
234
|
+
platform,
|
|
235
|
+
scope: options.scope || 'user',
|
|
236
|
+
projectPath: options.scope === 'project' ? options.cwd : null,
|
|
237
|
+
reason: 'manual'
|
|
238
|
+
});
|
|
239
|
+
res.status(202).json({ success: true, platform, task });
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error('[Plugins API] Refresh plugins error:', err);
|
|
242
|
+
sendApiError(res, err);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
router.get('/refresh/:taskId', async (req, res) => {
|
|
247
|
+
try {
|
|
248
|
+
const { platform, service } = getPluginsService(req);
|
|
249
|
+
const options = await getRequestOptions({ query: req.query }, service);
|
|
250
|
+
const refreshTasks = getRefreshTasks();
|
|
251
|
+
const task = refreshTasks?.get(req.params.taskId);
|
|
252
|
+
if (!task) return res.status(404).json({ success: false, message: 'Refresh task not found' });
|
|
253
|
+
const taskScope = task.scope || 'user';
|
|
254
|
+
const taskProjectPath = taskScope === 'project' ? (task.projectPath || null) : null;
|
|
255
|
+
const requestedProjectPath = options.scope === 'project' ? (options.cwd || null) : null;
|
|
256
|
+
if (
|
|
257
|
+
task.platform !== platform
|
|
258
|
+
|| taskScope !== (options.scope || 'user')
|
|
259
|
+
|| taskProjectPath !== requestedProjectPath
|
|
260
|
+
) {
|
|
261
|
+
return res.status(404).json({ success: false, message: 'Refresh task not found' });
|
|
262
|
+
}
|
|
263
|
+
return res.json({ success: true, task });
|
|
264
|
+
} catch (err) {
|
|
265
|
+
console.error('[Plugins API] Get refresh task error:', err);
|
|
266
|
+
return sendApiError(res, err);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
190
270
|
/**
|
|
191
271
|
* 安装插件
|
|
192
272
|
* POST /api/plugins/install
|
|
@@ -435,20 +515,26 @@ router.put('/repos/auth', (req, res) => {
|
|
|
435
515
|
});
|
|
436
516
|
|
|
437
517
|
/**
|
|
438
|
-
*
|
|
518
|
+
* Legacy alias for the explicit plugin refresh task.
|
|
439
519
|
* POST /api/plugins/repos/sync
|
|
440
520
|
*/
|
|
441
521
|
router.post('/repos/sync', async (req, res) => {
|
|
442
522
|
try {
|
|
443
523
|
const { platform, service } = getPluginsService(req);
|
|
444
524
|
const options = await getRequestOptions(req, service);
|
|
445
|
-
const
|
|
525
|
+
const refreshTasks = getRefreshTasks();
|
|
526
|
+
const task = refreshTasks.enqueue({
|
|
527
|
+
platform,
|
|
528
|
+
scope: options.scope || 'user',
|
|
529
|
+
projectPath: options.scope === 'project' ? options.cwd : null,
|
|
530
|
+
reason: 'manual'
|
|
531
|
+
});
|
|
446
532
|
|
|
447
|
-
res.json({
|
|
533
|
+
res.status(202).json({
|
|
448
534
|
success: true,
|
|
449
535
|
platform,
|
|
450
|
-
|
|
451
|
-
message: '
|
|
536
|
+
task,
|
|
537
|
+
message: 'Plugin refresh task started'
|
|
452
538
|
});
|
|
453
539
|
} catch (err) {
|
|
454
540
|
console.error('[Plugins API] Sync repos error:', err);
|
|
@@ -487,6 +573,7 @@ router.get('/:name/readme', async (req, res) => {
|
|
|
487
573
|
try {
|
|
488
574
|
const { platform, service } = getPluginsService(req);
|
|
489
575
|
const { name } = req.params;
|
|
576
|
+
const options = await getRequestOptions(req, service);
|
|
490
577
|
const {
|
|
491
578
|
repoId,
|
|
492
579
|
repoProvider,
|
|
@@ -499,7 +586,9 @@ router.get('/:name/readme', async (req, res) => {
|
|
|
499
586
|
repoUrl,
|
|
500
587
|
repoProjectPath,
|
|
501
588
|
repoLocalPath,
|
|
502
|
-
installPath
|
|
589
|
+
installPath,
|
|
590
|
+
scope: queryScope,
|
|
591
|
+
cwd: queryCwd
|
|
503
592
|
} = req.query;
|
|
504
593
|
|
|
505
594
|
const pluginInfo = {
|
|
@@ -518,7 +607,13 @@ router.get('/:name/readme', async (req, res) => {
|
|
|
518
607
|
installPath
|
|
519
608
|
};
|
|
520
609
|
|
|
521
|
-
const
|
|
610
|
+
const readmeOptions = {
|
|
611
|
+
...(options.scope || queryScope ? { scope: options.scope || queryScope } : {}),
|
|
612
|
+
...(options.cwd || queryCwd ? { cwd: options.cwd || queryCwd } : {})
|
|
613
|
+
};
|
|
614
|
+
const readme = Object.keys(readmeOptions).length > 0
|
|
615
|
+
? await service.getPluginReadme(pluginInfo, readmeOptions)
|
|
616
|
+
: await service.getPluginReadme(pluginInfo);
|
|
522
617
|
|
|
523
618
|
res.json({
|
|
524
619
|
success: true,
|
|
@@ -32,9 +32,18 @@ const CLAUDE_DIRS = {
|
|
|
32
32
|
// Valid config types
|
|
33
33
|
const CONFIG_TYPES = ['skills', 'commands', 'agents', 'plugins'];
|
|
34
34
|
|
|
35
|
+
function supportsManagedResources(platform) {
|
|
36
|
+
const resourceTypes = platform?.resourceTypes;
|
|
37
|
+
if (!resourceTypes || typeof resourceTypes !== 'object' || Array.isArray(resourceTypes)) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return CONFIG_TYPES.some(type => resourceTypes[type] !== false);
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
function getSupportedPlatforms(registry = getPlatformContext().registry) {
|
|
36
44
|
if (!registry || typeof registry.list !== 'function') return [];
|
|
37
45
|
return registry.list()
|
|
46
|
+
.filter(supportsManagedResources)
|
|
38
47
|
.map(platform => platform && platform.key)
|
|
39
48
|
.filter(Boolean);
|
|
40
49
|
}
|
|
@@ -43,7 +52,7 @@ function buildPlatformSupport(registry = getPlatformContext().registry) {
|
|
|
43
52
|
const support = Object.fromEntries(CONFIG_TYPES.map(type => [type, {}]));
|
|
44
53
|
for (const platform of (registry?.list?.() || [])) {
|
|
45
54
|
const key = platform && platform.key;
|
|
46
|
-
if (!key) continue;
|
|
55
|
+
if (!key || !supportsManagedResources(platform)) continue;
|
|
47
56
|
const resourceDriver = platform.capabilities?.resourceSync;
|
|
48
57
|
for (const type of CONFIG_TYPES) {
|
|
49
58
|
const typeCapability = platform.capabilities && Object.prototype.hasOwnProperty.call(platform.capabilities, type)
|
|
@@ -26,6 +26,7 @@ function getAiConfigMap(registry = getPlatformContext().registry) {
|
|
|
26
26
|
return Object.fromEntries(
|
|
27
27
|
registry.list({ enabledOnly: true })
|
|
28
28
|
.filter(platform => platform && platform.key)
|
|
29
|
+
.filter(platform => platform.resourceTypes?.commands !== false)
|
|
29
30
|
.map(platform => [platform.key, {
|
|
30
31
|
fileName: platform.promptFile || null,
|
|
31
32
|
name: platform.promptLabel
|