coding-tool-x 3.9.1 → 3.9.2
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/README.md +1 -1
- package/dist/web/assets/{AgentsDrawer-CobzHziM.css → AgentsDrawer-Dubq1kQI.css} +1 -1
- package/dist/web/assets/AgentsDrawer-x29vGIIi.js +1 -0
- package/dist/web/assets/{Analytics-DTIvvMXu.js → Analytics-BJbR6XJO.js} +1 -1
- package/dist/web/assets/{AssetPathField-jv-lopQ3.js → AssetPathField-2W-16zgR.js} +1 -1
- package/dist/web/assets/{ChatHistoryDrawer-T4OVnJzM.js → ChatHistoryDrawer-C1URzQ_4.js} +1 -1
- package/dist/web/assets/{CollapseItem-P6BvSxEu.js → CollapseItem-DjkOkbwE.js} +1 -1
- package/dist/web/assets/{CommandsDrawer-DtFJRtow.js → CommandsDrawer-DcnfrHC4.js} +1 -1
- package/dist/web/assets/{ConfigExportDrawer-Di7KXhVS.js → ConfigExportDrawer-CKwG_RGJ.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-VdKE5Kp0.js → ConfigTemplates-C1tNpfzi.js} +1 -1
- package/dist/web/assets/{ConfigTemplatesDrawer-bQvPnUQ0.js → ConfigTemplatesDrawer-gZNPbcUR.js} +1 -1
- package/dist/web/assets/{ConfigTemplatesPanel-ChdyQ3C6.js → ConfigTemplatesPanel-C-Fy53Qo.js} +1 -1
- package/dist/web/assets/{FavoritesDrawer-A25XfI7C.js → FavoritesDrawer-Bp8FYHPk.js} +1 -1
- package/dist/web/assets/GatewayConvertDrawer-CvUkvNQy.css +1 -0
- package/dist/web/assets/GatewayConvertDrawer-j5IJzb2Y.js +1 -0
- package/dist/web/assets/Home-2MAvBnml.js +1 -0
- package/dist/web/assets/Home-BRNWE0Qy.css +1 -0
- package/dist/web/assets/{MarkdownEditor-BXwTqbMo.js → MarkdownEditor-BA_PcLed.js} +1 -1
- package/dist/web/assets/{McpDrawer-DIaiFq4R.js → McpDrawer-DAep5PP_.js} +1 -1
- package/dist/web/assets/{McpFormDrawer-CQgTYAux.js → McpFormDrawer-BRm-hzv1.js} +1 -1
- package/dist/web/assets/{PluginManager-BkGrr21J.js → PluginManager-C2yY8-FP.js} +1 -1
- package/dist/web/assets/{PluginsDrawer-Bq1JkM5r.js → PluginsDrawer-CxKnWzTO.js} +1 -1
- package/dist/web/assets/{PluginsPanel-CzGMK-Ap.css → PluginsPanel-DsmiW9TU.css} +1 -1
- package/dist/web/assets/PluginsPanel-DtbXSoXu.js +1 -0
- package/dist/web/assets/{ProjectList-QIC7-9ic.js → ProjectList-Cb25pa2s.js} +1 -1
- package/dist/web/assets/{PromptsDrawer-BLeUYZWW.js → PromptsDrawer-D39OJVRP.js} +1 -1
- package/dist/web/assets/{RecentSessionsDrawer-yOpScIwI.js → RecentSessionsDrawer-DkCjc4kS.js} +1 -1
- package/dist/web/assets/{SessionCard-DeKRHAzu.js → SessionCard-5Mwig8zy.js} +1 -1
- package/dist/web/assets/{SessionList-B0fPT_VB.js → SessionList-DVkIlraF.js} +1 -1
- package/dist/web/assets/{SettingsDrawer-DpZoDj3M.js → SettingsDrawer-Cr9qZDgO.js} +1 -1
- package/dist/web/assets/{SkillManager-BpPqV2o4.js → SkillManager-D935sPSV.js} +1 -1
- package/dist/web/assets/{SkillsDrawer-BgMlJbgS.js → SkillsDrawer-D1_3j74b.js} +1 -1
- package/dist/web/assets/{SkillsPanel-CK-pSSHU.js → SkillsPanel-6SehnNG8.js} +1 -1
- package/dist/web/assets/{Upload-DtuQ7ady.js → Upload-38eKB6wv.js} +1 -1
- package/dist/web/assets/{WorkspaceDrawer-Bu5mOGsF.js → WorkspaceDrawer-Bkfmlr5M.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-D1mhnNV-.js → WorkspaceManager-DFVQ5YoE.js} +1 -1
- package/dist/web/assets/{WorkspacePanel-BIrkMC_5.js → WorkspacePanel-CEnogXEv.js} +1 -1
- package/dist/web/assets/client-oU6RT-6I.js +1 -0
- package/dist/web/assets/dsh-agent-presets-DjJRVMT6.js +1 -0
- package/dist/web/assets/index-CCATqHAD.js +2 -0
- package/dist/web/assets/index-p-yggtLj.css +1 -0
- package/dist/web/assets/{platforms-DrzAtnjY.js → platforms-DILqyP72.js} +1 -1
- package/dist/web/assets/platforms-JV36QBCw.js +1 -0
- package/dist/web/assets/{project-config-BVt5s-pH.js → project-config-CzFKBw_m.js} +1 -1
- package/dist/web/assets/{sessions-CaWUaysM.js → sessions-WXODMvLY.js} +1 -1
- package/dist/web/assets/{sessions-53-Fr68H.js → sessions-wvj5oaYr.js} +1 -1
- package/dist/web/assets/{useResponsiveDrawer-C-UacYVP.js → useResponsiveDrawer-BWRBXImg.js} +1 -1
- package/dist/web/assets/{workspaces-DQuZd4qw.js → workspaces-D2yLnT-B.js} +1 -1
- package/dist/web/index.html +5 -5
- package/package.json +4 -4
- package/src/platforms/drivers/dsh/api-operations.js +60 -2
- package/src/platforms/drivers/dsh/common.js +222 -11
- package/src/platforms/drivers/dsh/native-config.js +2 -2
- package/src/platforms/drivers/dsh/native-logs.js +16 -1
- package/src/platforms/drivers/dsh/plugin-manager.js +64 -6
- package/src/platforms/drivers/omp/gateway.js +27 -1
- package/src/platforms/drivers/opencode/conversion.js +60 -8
- package/src/platforms/manifest-schema.js +4 -0
- package/src/platforms/manifests/dsh.json +29 -4
- package/src/platforms/manifests/omp.json +2 -1
- package/src/platforms/registry.js +1 -0
- package/src/server/api/convert.js +26 -76
- package/src/server/api/platforms.js +1 -0
- package/src/server/services/model-detector.js +13 -22
- package/src/server/services/native-log-observer.js +1 -0
- package/src/server/services/plugins-service.js +13 -14
- package/src/server/services/request-logger.js +95 -0
- package/src/server/services/usage-log-utils.js +2 -1
- package/dist/web/assets/AgentsDrawer-MeGfH4I0.js +0 -1
- package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +0 -1
- package/dist/web/assets/GatewayConvertDrawer-TSJPvY4f.js +0 -1
- package/dist/web/assets/Home-CSuFuJ9Y.css +0 -1
- package/dist/web/assets/Home-CzB85lKE.js +0 -1
- package/dist/web/assets/PluginsPanel-Clz1r67v.js +0 -1
- package/dist/web/assets/client-BgcNg4Bt.js +0 -1
- package/dist/web/assets/index-B86H0_5y.css +0 -1
- package/dist/web/assets/index-Bw6YXbBA.js +0 -2
- package/dist/web/assets/platforms-mqqe_82d.js +0 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"command": "dsh",
|
|
6
6
|
"iconToken": "terminal",
|
|
7
7
|
"color": "#2563eb",
|
|
8
|
+
"logLayout": "basic",
|
|
8
9
|
"defaultVisible": true,
|
|
9
10
|
"defaultEnabled": false,
|
|
10
11
|
"sortOrder": 50,
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
"resourceTypes": {
|
|
26
27
|
"skills": true,
|
|
27
28
|
"commands": false,
|
|
28
|
-
"agents":
|
|
29
|
+
"agents": true,
|
|
29
30
|
"plugins": true,
|
|
30
31
|
"mcp": true,
|
|
31
32
|
"prompts": true
|
|
@@ -38,10 +39,10 @@
|
|
|
38
39
|
"refresh": true
|
|
39
40
|
},
|
|
40
41
|
"plugins": {
|
|
41
|
-
"repositories":
|
|
42
|
+
"repositories": false,
|
|
42
43
|
"market": false,
|
|
43
|
-
"install":
|
|
44
|
-
"uninstall":
|
|
44
|
+
"install": true,
|
|
45
|
+
"uninstall": true,
|
|
45
46
|
"import": false,
|
|
46
47
|
"syncRepos": false
|
|
47
48
|
}
|
|
@@ -477,6 +478,30 @@
|
|
|
477
478
|
"request": "default",
|
|
478
479
|
"response": "default"
|
|
479
480
|
},
|
|
481
|
+
{
|
|
482
|
+
"method": "GET",
|
|
483
|
+
"path": "/profiles/:profileName/agent-presets",
|
|
484
|
+
"capability": "api",
|
|
485
|
+
"operation": "listProfileAgentPresets",
|
|
486
|
+
"request": "default",
|
|
487
|
+
"response": "default"
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
"method": "POST",
|
|
491
|
+
"path": "/profiles/:profileName/agent-presets",
|
|
492
|
+
"capability": "api",
|
|
493
|
+
"operation": "upsertAgentPreset",
|
|
494
|
+
"request": "default",
|
|
495
|
+
"response": "default"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"method": "DELETE",
|
|
499
|
+
"path": "/profiles/:profileName/agent-presets/:presetId",
|
|
500
|
+
"capability": "api",
|
|
501
|
+
"operation": "deleteAgentPreset",
|
|
502
|
+
"request": "default",
|
|
503
|
+
"response": "default"
|
|
504
|
+
},
|
|
480
505
|
{
|
|
481
506
|
"method": "GET",
|
|
482
507
|
"path": "/skills",
|
|
@@ -188,6 +188,7 @@ function createPlatformRegistry({
|
|
|
188
188
|
portLabel: platform.portLabel || null,
|
|
189
189
|
apiPrefix: platform.api?.prefix || null,
|
|
190
190
|
modelCatalogKey: platform.modelConfig?.catalogKey || platform.key,
|
|
191
|
+
...(platform.logLayout ? { logLayout: platform.logLayout } : {}),
|
|
191
192
|
capabilities
|
|
192
193
|
};
|
|
193
194
|
const resourceTypes = publicResourceTypes(platform.resourceTypes);
|
|
@@ -1,40 +1,28 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const router = express.Router();
|
|
3
3
|
const { getPlatformCatalog } = require('../services/platform-catalog');
|
|
4
|
+
const { createSameOriginGuard } = require('../services/network-access');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
router.use(createSameOriginGuard({
|
|
7
|
+
message: '禁止跨站访问请求转换接口'
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
function getConversionDriver(target) {
|
|
11
|
+
return getPlatformCatalog().driver(target, 'conversion');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getConversionFormats(driver) {
|
|
11
15
|
const formats = driver?.formats?.() || driver?.getFormats?.();
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
const sourceTypes = formats.sourceTypes || [];
|
|
16
|
-
res.json({
|
|
17
|
-
formats: sourceTypes.map(type => ({
|
|
18
|
-
id: type,
|
|
19
|
-
name: (formats.formats || []).find(item => item.id === type)?.name
|
|
20
|
-
|| String(type).replace(/[-_]/g, ' ').replace(/\b\w/g, char => char.toUpperCase()),
|
|
21
|
-
description: `${type} session format`,
|
|
22
|
-
extension: '.jsonl',
|
|
23
|
-
icon: type
|
|
24
|
-
})),
|
|
25
|
-
conversions: sourceTypes.flatMap(sourceType => sourceTypes
|
|
26
|
-
.filter(targetType => targetType !== sourceType)
|
|
27
|
-
.map(targetType => ({ from: sourceType, to: targetType })))
|
|
28
|
-
});
|
|
29
|
-
});
|
|
16
|
+
return formats;
|
|
17
|
+
}
|
|
30
18
|
|
|
31
19
|
/**
|
|
32
|
-
*
|
|
33
|
-
* GET /api/convert/
|
|
20
|
+
* Read conversion capabilities for a target CLI.
|
|
21
|
+
* GET /api/convert/:target/formats
|
|
34
22
|
*/
|
|
35
|
-
router.get('/
|
|
36
|
-
const driver = getConversionDriver();
|
|
37
|
-
const formats =
|
|
23
|
+
router.get('/:target/formats', (req, res) => {
|
|
24
|
+
const driver = getConversionDriver(req.params.target);
|
|
25
|
+
const formats = getConversionFormats(driver);
|
|
38
26
|
if (!formats) {
|
|
39
27
|
return res.status(404).json({ success: false, error: 'Conversion is not supported' });
|
|
40
28
|
}
|
|
@@ -45,62 +33,24 @@ router.get('/opencode/formats', (req, res) => {
|
|
|
45
33
|
name: (formats.formats || []).find(item => item.id === type)?.name
|
|
46
34
|
|| String(type).replace(/[-_]/g, ' ').replace(/\b\w/g, char => char.toUpperCase())
|
|
47
35
|
})),
|
|
48
|
-
target:
|
|
36
|
+
target: req.params.target,
|
|
49
37
|
targetApis: formats.targetApis || [],
|
|
50
38
|
defaultTargetApi: formats.defaultTargetApi,
|
|
51
|
-
endpoints: formats.endpoints || {}
|
|
52
|
-
sourceEndpoints: Object.fromEntries(sourceTypes.map(type => [type, `/api/convert/opencode/${type}`]))
|
|
39
|
+
endpoints: formats.endpoints || {}
|
|
53
40
|
});
|
|
54
41
|
});
|
|
55
42
|
|
|
56
|
-
function getConversionDriver() {
|
|
57
|
-
return getPlatformCatalog().driver('opencode', 'conversion');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function handleOpenCodeConvert(req, res, sourceType) {
|
|
61
|
-
try {
|
|
62
|
-
const { payload, options = {} } = req.body || {};
|
|
63
|
-
const driver = getConversionDriver();
|
|
64
|
-
|
|
65
|
-
if (!driver) {
|
|
66
|
-
return res.status(404).json({ success: false, error: 'Conversion is not supported' });
|
|
67
|
-
}
|
|
68
|
-
if (!payload) {
|
|
69
|
-
return res.status(400).json({
|
|
70
|
-
success: false,
|
|
71
|
-
error: 'Missing required parameters: payload'
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
const result = driver.convertSource
|
|
75
|
-
? driver.convertSource(sourceType, payload, options)
|
|
76
|
-
: driver.convert({ sourceType, payload, options });
|
|
77
|
-
return res.json({
|
|
78
|
-
success: true,
|
|
79
|
-
...result
|
|
80
|
-
});
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error(`[Convert API] OpenCode ${sourceType} convert error:`, error);
|
|
83
|
-
return res.status(500).json({
|
|
84
|
-
success: false,
|
|
85
|
-
error: error.message
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
router.post('/opencode/:sourceType', (req, res) => {
|
|
91
|
-
return handleOpenCodeConvert(req, res, req.params.sourceType);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
43
|
/**
|
|
95
|
-
*
|
|
96
|
-
* POST /api/convert
|
|
44
|
+
* Online conversion to a CLI-compatible request format.
|
|
45
|
+
* POST /api/convert/:target
|
|
97
46
|
* Body: { sourceType, payload, options? }
|
|
98
47
|
*/
|
|
99
|
-
router.post('
|
|
48
|
+
router.post('/:target', (req, res) => {
|
|
100
49
|
try {
|
|
101
50
|
const { sourceType, payload, options = {} } = req.body || {};
|
|
102
|
-
const driver = getConversionDriver();
|
|
103
|
-
const
|
|
51
|
+
const driver = getConversionDriver(req.params.target);
|
|
52
|
+
const formats = getConversionFormats(driver);
|
|
53
|
+
const sourceTypes = formats?.sourceTypes || [];
|
|
104
54
|
const normalized = driver?.normalizeSourceType?.(sourceType) || sourceType;
|
|
105
55
|
|
|
106
56
|
if (!driver) {
|
|
@@ -124,7 +74,7 @@ router.post('/opencode', (req, res) => {
|
|
|
124
74
|
...driver.convert({ sourceType: normalized, payload, options })
|
|
125
75
|
});
|
|
126
76
|
} catch (error) {
|
|
127
|
-
console.error(
|
|
77
|
+
console.error(`[Convert API] ${req.params.target} convert error:`, error);
|
|
128
78
|
return res.status(500).json({
|
|
129
79
|
success: false,
|
|
130
80
|
error: error.message
|
|
@@ -330,32 +330,29 @@ function buildRequestHeaders(channelType, channel) {
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
function buildOpenAiCompatibleUrl(baseUrl, endpoint) {
|
|
333
|
-
const
|
|
334
|
-
if (!
|
|
333
|
+
const rawBaseUrl = String(baseUrl || '').trim();
|
|
334
|
+
if (!rawBaseUrl) {
|
|
335
335
|
throw new Error('Invalid baseUrl');
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
const parsed = new URL(rawBaseUrl);
|
|
339
|
+
const basePath = parsed.pathname.replace(/\/+$/, '');
|
|
338
340
|
const normalizedEndpoint = String(endpoint || '').startsWith('/')
|
|
339
341
|
? String(endpoint)
|
|
340
342
|
: `/${endpoint}`;
|
|
341
|
-
|
|
342
|
-
if (trimmed.endsWith(normalizedEndpoint)) {
|
|
343
|
-
return trimmed;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
343
|
const endpointWithoutV1 = normalizedEndpoint.startsWith('/v1/')
|
|
347
344
|
? normalizedEndpoint.slice(3)
|
|
348
345
|
: normalizedEndpoint;
|
|
349
346
|
|
|
350
|
-
if (
|
|
351
|
-
|
|
352
|
-
}
|
|
347
|
+
if (basePath.endsWith(normalizedEndpoint)) return parsed.toString();
|
|
348
|
+
if (basePath.endsWith(endpointWithoutV1)) return parsed.toString();
|
|
353
349
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
350
|
+
const suffix = /\/v1$/.test(basePath) && normalizedEndpoint.startsWith('/v1/')
|
|
351
|
+
? normalizedEndpoint.slice(3)
|
|
352
|
+
: normalizedEndpoint;
|
|
353
|
+
parsed.pathname = `${basePath}${suffix}` || '/';
|
|
354
|
+
parsed.hash = '';
|
|
355
|
+
return parsed.toString();
|
|
359
356
|
}
|
|
360
357
|
|
|
361
358
|
|
|
@@ -1044,14 +1041,8 @@ async function fetchModelsFromProvider(channel, channelType, options = {}) {
|
|
|
1044
1041
|
resolve(result);
|
|
1045
1042
|
};
|
|
1046
1043
|
try {
|
|
1047
|
-
const baseUrl = channel.baseUrl.trim().replace(/\/+$/, '');
|
|
1048
1044
|
const endpoint = capability.modelListEndpoint; // e.g. '/v1/models'
|
|
1049
|
-
|
|
1050
|
-
const requestUrl = baseUrl.endsWith('/v1') && endpoint.startsWith('/v1/')
|
|
1051
|
-
? `${baseUrl}${endpoint.slice(3)}`
|
|
1052
|
-
: `${baseUrl}${endpoint}`;
|
|
1053
|
-
|
|
1054
|
-
const parsedUrl = new URL(requestUrl);
|
|
1045
|
+
const parsedUrl = new URL(buildOpenAiCompatibleUrl(channel.baseUrl, endpoint));
|
|
1055
1046
|
const isHttps = parsedUrl.protocol === 'https:';
|
|
1056
1047
|
const httpModule = isHttps ? https : http;
|
|
1057
1048
|
|
|
@@ -140,6 +140,7 @@ function recordEvent(platform, event, runtime = getPlatformRuntime(), channelCac
|
|
|
140
140
|
channel,
|
|
141
141
|
model: event.model || '',
|
|
142
142
|
tokens,
|
|
143
|
+
cacheUsageAvailable: event.cacheUsageAvailable,
|
|
143
144
|
cost: Number(event.cost) || 0,
|
|
144
145
|
timestamp,
|
|
145
146
|
usageMissing: false
|
|
@@ -117,6 +117,18 @@ const PLATFORM_CAPABILITIES = {
|
|
|
117
117
|
import: false,
|
|
118
118
|
syncRepos: false
|
|
119
119
|
},
|
|
120
|
+
dsh: {
|
|
121
|
+
platform: 'dsh',
|
|
122
|
+
supportsPlugins: true,
|
|
123
|
+
repositories: false,
|
|
124
|
+
market: false,
|
|
125
|
+
install: true,
|
|
126
|
+
uninstall: true,
|
|
127
|
+
toggle: false,
|
|
128
|
+
config: false,
|
|
129
|
+
import: false,
|
|
130
|
+
syncRepos: false
|
|
131
|
+
},
|
|
120
132
|
omp: {
|
|
121
133
|
platform: 'omp',
|
|
122
134
|
supportsPlugins: true,
|
|
@@ -134,19 +146,6 @@ const PLATFORM_CAPABILITIES = {
|
|
|
134
146
|
repositoryAuth: false,
|
|
135
147
|
installMetadataMode: 'omp'
|
|
136
148
|
},
|
|
137
|
-
dsh: {
|
|
138
|
-
platform: 'dsh',
|
|
139
|
-
supportsPlugins: true,
|
|
140
|
-
repositories: true,
|
|
141
|
-
market: false,
|
|
142
|
-
install: false,
|
|
143
|
-
uninstall: false,
|
|
144
|
-
toggle: false,
|
|
145
|
-
config: false,
|
|
146
|
-
import: false,
|
|
147
|
-
syncRepos: false,
|
|
148
|
-
disabledReason: 'DSH 插件由 profile 管理,当前面板仅提供只读查看'
|
|
149
|
-
}
|
|
150
149
|
};
|
|
151
150
|
|
|
152
151
|
function cloneRepos(repos = []) {
|
|
@@ -1670,7 +1669,7 @@ class PluginsService {
|
|
|
1670
1669
|
source: 'dsh-profile',
|
|
1671
1670
|
pluginType: 'dsh-profile',
|
|
1672
1671
|
enabled: true,
|
|
1673
|
-
readonly: true,
|
|
1672
|
+
readonly: plugin.builtIn === true,
|
|
1674
1673
|
description: plugin.description || '',
|
|
1675
1674
|
directory: plugin.name || name
|
|
1676
1675
|
});
|
|
@@ -21,6 +21,21 @@ const { PATHS } = pathsModule;
|
|
|
21
21
|
const getPlatformStatePath = typeof pathsModule.getPlatformStatePath === 'function'
|
|
22
22
|
? pathsModule.getPlatformStatePath
|
|
23
23
|
: (category, platform) => PATHS[category]?.[platform];
|
|
24
|
+
const latestProxyRequestSnapshots = new Map();
|
|
25
|
+
|
|
26
|
+
function compactProxyRequestSnapshot(payload = {}) {
|
|
27
|
+
const request = payload.request && typeof payload.request === 'object' ? payload.request : {};
|
|
28
|
+
const route = payload.route && typeof payload.route === 'object' ? payload.route : undefined;
|
|
29
|
+
return {
|
|
30
|
+
...(payload.timestamp !== undefined ? { timestamp: payload.timestamp } : {}),
|
|
31
|
+
...(payload.source ? { source: payload.source } : {}),
|
|
32
|
+
request: {
|
|
33
|
+
...(request.method ? { method: request.method } : {}),
|
|
34
|
+
...(request.headers && typeof request.headers === 'object' ? { headers: request.headers } : {})
|
|
35
|
+
},
|
|
36
|
+
...(route ? { route: { ...route } } : {})
|
|
37
|
+
};
|
|
38
|
+
}
|
|
24
39
|
|
|
25
40
|
function ensureDir(dir) {
|
|
26
41
|
if (!fs.existsSync(dir)) {
|
|
@@ -57,6 +72,10 @@ function persistProxyRequestSnapshot(source, payload) {
|
|
|
57
72
|
if (!isProxyRequestLoggingEnabled()) return;
|
|
58
73
|
|
|
59
74
|
try {
|
|
75
|
+
latestProxyRequestSnapshots.set(
|
|
76
|
+
String(source || '').trim().toLowerCase(),
|
|
77
|
+
compactProxyRequestSnapshot(payload)
|
|
78
|
+
);
|
|
60
79
|
const logPath = getPlatformStatePath('requestSnapshots', source);
|
|
61
80
|
if (!logPath) return;
|
|
62
81
|
ensureDir(path.dirname(logPath));
|
|
@@ -70,6 +89,80 @@ function persistProxyRequestSnapshot(source, payload) {
|
|
|
70
89
|
}
|
|
71
90
|
}
|
|
72
91
|
|
|
92
|
+
function loadLatestProxyRequestSnapshot(source) {
|
|
93
|
+
const normalizedSource = String(source || '').trim().toLowerCase();
|
|
94
|
+
if (latestProxyRequestSnapshots.has(normalizedSource)) {
|
|
95
|
+
return latestProxyRequestSnapshots.get(normalizedSource);
|
|
96
|
+
}
|
|
97
|
+
const logPath = getPlatformStatePath('requestSnapshots', normalizedSource);
|
|
98
|
+
if (!logPath) return {};
|
|
99
|
+
|
|
100
|
+
let fd;
|
|
101
|
+
try {
|
|
102
|
+
fd = fs.openSync(logPath, 'r');
|
|
103
|
+
const fileSize = fs.fstatSync(fd).size;
|
|
104
|
+
const chunkSize = 1024 * 1024;
|
|
105
|
+
let position = fileSize;
|
|
106
|
+
let parts = [];
|
|
107
|
+
let bytesScanned = 0;
|
|
108
|
+
while (position > 0) {
|
|
109
|
+
const bytesToRead = Math.min(position, chunkSize);
|
|
110
|
+
position -= bytesToRead;
|
|
111
|
+
bytesScanned += bytesToRead;
|
|
112
|
+
const chunk = Buffer.alloc(bytesToRead);
|
|
113
|
+
fs.readSync(fd, chunk, 0, bytesToRead, position);
|
|
114
|
+
let segmentEnd = chunk.length;
|
|
115
|
+
for (let index = chunk.length - 1; index >= 0; index -= 1) {
|
|
116
|
+
if (chunk[index] !== 10) continue;
|
|
117
|
+
if (segmentEnd > index + 1) parts.push(chunk.subarray(index + 1, segmentEnd));
|
|
118
|
+
const line = Buffer.concat(parts.reverse()).toString('utf8');
|
|
119
|
+
parts = [];
|
|
120
|
+
segmentEnd = index;
|
|
121
|
+
if (!line.trim()) continue;
|
|
122
|
+
try {
|
|
123
|
+
const entry = JSON.parse(line);
|
|
124
|
+
if (entry && typeof entry === 'object') {
|
|
125
|
+
const compact = compactProxyRequestSnapshot(entry);
|
|
126
|
+
latestProxyRequestSnapshots.set(normalizedSource, compact);
|
|
127
|
+
return compact;
|
|
128
|
+
}
|
|
129
|
+
} catch {
|
|
130
|
+
// Ignore malformed records and continue scanning older complete lines.
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (segmentEnd > 0) parts.push(chunk.subarray(0, segmentEnd));
|
|
134
|
+
if (bytesScanned > 128 * 1024 * 1024) break;
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
// Request snapshots are optional and may not exist yet.
|
|
138
|
+
} finally {
|
|
139
|
+
if (fd !== undefined) fs.closeSync(fd);
|
|
140
|
+
}
|
|
141
|
+
return {};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function loadLatestProxyRequestHeaders(source) {
|
|
145
|
+
const headers = loadLatestProxyRequestSnapshot(source)?.request?.headers;
|
|
146
|
+
if (!headers || typeof headers !== 'object' || Array.isArray(headers)) return {};
|
|
147
|
+
|
|
148
|
+
const hopByHopHeaders = new Set([
|
|
149
|
+
'connection',
|
|
150
|
+
'content-length',
|
|
151
|
+
'host',
|
|
152
|
+
'keep-alive',
|
|
153
|
+
'proxy-connection',
|
|
154
|
+
'te',
|
|
155
|
+
'trailer',
|
|
156
|
+
'transfer-encoding',
|
|
157
|
+
'upgrade'
|
|
158
|
+
]);
|
|
159
|
+
const sensitiveHeaderName = /(auth|cookie|session|token|secret|credential|api[-_]?key|password|signature|\bjwt\b|capability)/i;
|
|
160
|
+
|
|
161
|
+
return Object.fromEntries(Object.entries(headers).filter(([name]) => (
|
|
162
|
+
!hopByHopHeaders.has(name.toLowerCase()) && !sensitiveHeaderName.test(name)
|
|
163
|
+
)));
|
|
164
|
+
}
|
|
165
|
+
|
|
73
166
|
/**
|
|
74
167
|
* 创建 Express 中间件,用于记录 REST API 请求
|
|
75
168
|
* 仅当 CC_TOOL_LOG_API_REQUESTS=true 时生效
|
|
@@ -317,6 +410,8 @@ module.exports = {
|
|
|
317
410
|
isProxyRequestLoggingEnabled,
|
|
318
411
|
isApiRequestLoggingEnabled,
|
|
319
412
|
persistProxyRequestSnapshot,
|
|
413
|
+
loadLatestProxyRequestSnapshot,
|
|
414
|
+
loadLatestProxyRequestHeaders,
|
|
320
415
|
persistClaudeRequestTemplate,
|
|
321
416
|
loadClaudeRequestTemplate,
|
|
322
417
|
createApiRequestLogger
|
|
@@ -73,7 +73,7 @@ function formatRealtimeTime(timestamp = Date.now()) {
|
|
|
73
73
|
return new Date(timestamp).toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
function buildSuccessLogPayload({ source, requestId, channel, model, originalModel, redirectedModel, tokens, cost = 0, timestamp = Date.now(), usageMissing = false }) {
|
|
76
|
+
function buildSuccessLogPayload({ source, requestId, channel, model, originalModel, redirectedModel, tokens, cacheUsageAvailable, cost = 0, timestamp = Date.now(), usageMissing = false }) {
|
|
77
77
|
const normalized = normalizeUsageTokens(source, tokens);
|
|
78
78
|
const payload = {
|
|
79
79
|
type: 'log', status: 'success', id: requestId, time: formatRealtimeTime(timestamp), channel,
|
|
@@ -82,6 +82,7 @@ function buildSuccessLogPayload({ source, requestId, channel, model, originalMod
|
|
|
82
82
|
reasoningTokens: normalized.reasoning, totalTokens: normalized.total, cost,
|
|
83
83
|
source: normalizeToolSource(source), timestamp, usageMissing: Boolean(usageMissing)
|
|
84
84
|
};
|
|
85
|
+
if (typeof cacheUsageAvailable === 'boolean') payload.cacheUsageAvailable = cacheUsageAvailable;
|
|
85
86
|
if (originalModel) payload.originalModel = originalModel;
|
|
86
87
|
if (redirectedModel) payload.redirectedModel = redirectedModel;
|
|
87
88
|
return payload;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e,s as a,t as l}from"./_plugin-vue_export-helper-BeLZJZij.js";import{C as t,D as s,K as n,O as i,S as o,V as u,W as d,Y as r,Z as c,_t as p,b as v,et as m,g,ht as f,m as y,mt as h,r as b,st as k,w,x as _}from"./vue-vendor-BqZbbXHA.js";import{t as C}from"./client-BgcNg4Bt.js";import{r as j,s as x,t as M}from"./platforms-mqqe_82d.js";import{$ as z,At as P,Nt as O,O as L,R as U,S as N,V as $,_ as I,f as A,g as F,j as S,m as R}from"./icons-B-AzZoeE.js";import{l as B}from"./light-C2X7hegj.js";import{a as D,c as q,i as E,o as T,r as H,s as V,t as G}from"./AssetPathField-jv-lopQ3.js";import{n as W,t as Y}from"./useResponsiveDrawer-C-UacYVP.js";import{t as J}from"./DrawerContent-ChXgZ1Xm.js";import{$ as X,Et as Z,I as K,L as Q,M as ee,T as ae,X as le,Y as te,Z as se,ct as ne,ft as ie,j as oe,k as ue,st as de,ut as re,w as ce}from"./index-Bw6YXbBA.js";import{t as pe}from"./MarkdownEditor-BXwTqbMo.js";async function ve(e=null,a="claude",l={}){const t=ce("agents",a,l.scope||"",e||"");return ae(t,l=>C.get("/agents",{params:e?{projectPath:e,platform:a}:{platform:a},signal:l}).then(e=>e.data),"agents",`agents:${a}`)}var me={class:"asset-card-main"},ge={class:"asset-card-top"},fe={class:"asset-card-title-stack"},ye={class:"asset-card-title-row"},he={class:"asset-name"},be={class:"asset-tags"},ke={key:0,class:"asset-description"},we={class:"asset-meta"},_e={key:0,class:"asset-meta-item"},Ce={key:1,class:"asset-meta-item"},je={class:"asset-card-actions"},xe={class:"asset-platform-strip"},Me=["onClick"],ze=l({__name:"AgentCard",props:{agent:{type:Object,required:!0},deleting:{type:Boolean,default:!1},registryInfo:{type:Object,default:null},toggling:{type:Boolean,default:!1}},emits:["click","edit","delete","toggle-enabled","toggle-platform"],setup(l,{emit:u}){const c=l,b=u,{byCapability:k}=Z(),C=v(()=>k("agents"));return(u,v)=>{return d(),w("div",{class:f(["agent-card asset-card",{"is-project":"project"===l.agent.scope,"is-managed":l.registryInfo}]),onClick:v[4]||(v[4]=e=>b("click",l.agent))},[_("div",me,[_("div",ge,[_("div",fe,[_("div",ye,[_("span",{class:f(["asset-status-dot",{active:l.registryInfo?.enabled||"project"===l.agent.scope}])},null,2),_("span",he,p(l.agent.name),1)]),_("div",be,[i(h(re),{type:"user"===l.agent.scope?"info":"success",size:"tiny",bordered:!1},{default:m(()=>[s(p("user"===l.agent.scope?"用户级":"项目级"),1)]),_:1},8,["type"]),l.registryInfo?(d(),o(h(re),{key:0,type:"success",size:"tiny",bordered:!1},{default:m(()=>[...v[5]||(v[5]=[s("托管",-1)])]),_:1})):t("",!0),l.agent.model?(d(),o(h(re),{key:1,type:"warning",size:"tiny",bordered:!1},{default:m(()=>[s(p(l.agent.model),1)]),_:1})):t("",!0)])])]),l.agent.description?(d(),w("div",ke,p((j=l.agent.description,j?j.length>80?j.slice(0,80)+"...":j:"")),1)):t("",!0),_("div",we,[l.agent.tools?(d(),w("span",_e,[i(h(e),{size:"12"},{default:m(()=>[i(h($))]),_:1}),s(" "+p((k=l.agent.tools,k?k.length>30?k.slice(0,30)+"...":k:"")),1)])):t("",!0),l.agent.permissionMode?(d(),w("span",Ce,[i(h(e),{size:"12"},{default:m(()=>[i(h(A))]),_:1}),s(" "+p(l.agent.permissionMode),1)])):t("",!0)])]),_("div",je,[l.registryInfo?(d(),w(g,{key:0},[i(h(te),{trigger:"hover"},{trigger:m(()=>[i(h(oe),{value:l.registryInfo.enabled,size:"small",loading:l.toggling,"onUpdate:value":v[0]||(v[0]=e=>b("toggle-enabled",l.agent,e)),onClick:v[1]||(v[1]=y(()=>{},["stop"]))},null,8,["value","loading"])]),default:m(()=>[s(" "+p(l.registryInfo.enabled?"已启用":"已禁用"),1)]),_:1}),_("div",xe,[(d(!0),w(g,null,n(C.value,a=>(d(),o(h(te),{key:a.key,trigger:"hover"},{trigger:m(()=>[_("span",{class:f(["asset-platform-icon",{active:l.registryInfo.platforms?.[a.key]}]),onClick:y(e=>b("toggle-platform",l.agent,a.key,!l.registryInfo.platforms?.[a.key]),["stop"])},[i(h(e),{size:"14"},{default:m(()=>[(d(),o(r(a.icon)))]),_:2},1024)],10,Me)]),default:m(()=>[s(" "+p(a.label||a.title||a.key)+" "+p(l.registryInfo.platforms?.[a.key]?"已启用":"未启用"),1)]),_:2},1024))),128))])],64)):(d(),w(g,{key:1},[i(h(a),{size:"tiny",tertiary:"",onClick:v[2]||(v[2]=y(e=>b("edit",l.agent),["stop"]))},{default:m(()=>[...v[6]||(v[6]=[s(" 编辑 ",-1)])]),_:1}),i(h(a),{size:"tiny",tertiary:"",type:"error",loading:c.deleting,onClick:v[3]||(v[3]=y(e=>b("delete",l.agent),["stop"]))},{default:m(()=>[...v[7]||(v[7]=[s(" 删除 ",-1)])]),_:1},8,["loading"])],64))])],2);var k,j}}},[["__scopeId","data-v-044e4192"]]),Pe={class:"asset-detail-drawer-header"},Oe={class:"asset-detail-identity"},Le={class:"asset-detail-heading"},Ue={class:"asset-detail-name"},Ne={class:"asset-detail-meta"},$e={key:2,class:"asset-detail-subtle"},Ie={class:"asset-detail-body"},Ae={key:0,class:"asset-detail-loading"},Fe={class:"asset-detail-container"},Se={class:"asset-detail-info-section"},Re={class:"asset-detail-description"},Be={class:"asset-detail-info-section"},De={class:"asset-detail-list"},qe={class:"asset-detail-row"},Ee={class:"asset-detail-value"},Te={key:0,class:"asset-detail-row"},He={class:"asset-detail-value mono"},Ve={key:1,class:"asset-detail-row"},Ge={class:"asset-detail-value mono"},We={key:2,class:"asset-detail-row"},Ye={class:"asset-detail-value"},Je={key:3,class:"asset-detail-row"},Xe={class:"asset-detail-value"},Ze={key:4,class:"asset-detail-row"},Ke={class:"asset-detail-value"},Qe={key:1,class:"asset-detail-info-section"},ea={class:"asset-detail-box"},aa={class:"asset-detail-code"},la={key:2,class:"asset-detail-empty"},ta={__name:"AgentDetailDrawer",props:{visible:{type:Boolean,default:!1},agent:{type:Object,default:null},platform:{type:String,default:"claude"},loading:{type:Boolean,default:!1}},emits:["update:visible"],setup(a,{emit:l}){const{drawerWidth:n}=Y(600),u=a,r=l,c=v({get:()=>u.visible,set:e=>r("update:visible",e)}),g={height:"100%",minHeight:0,overflow:"hidden"},f=v(()=>({claude:"Claude Code",codex:"Codex CLI",gemini:"Gemini CLI",opencode:"OpenCode"}[u.platform]||"")),y=v(()=>u.agent?.fileName?"codex"===u.platform?`[agents.${u.agent.fileName}]`:`${u.agent.fileName}.md`:""),b=v(()=>u.agent?"codex"===u.platform?u.agent.fullContent||"(无内容)":u.agent.systemPrompt||"(无内容)":"(无内容)"),k=v(()=>u.agent?.fullPath||u.agent?.path||"");function C(e){return"project"===e?"项目级":"用户级"}return(l,u)=>(d(),o(h(W),{show:c.value,"onUpdate:show":u[0]||(u[0]=e=>c.value=e),width:h(n),placement:"right","show-mask":!0},{default:m(()=>[i(h(J),{closable:"","native-scrollbar":!1,"body-content-style":g},{header:m(()=>[_("div",Pe,[_("div",Oe,[i(h(e),{size:20,class:"asset-detail-icon"},{default:m(()=>[i(h(L))]),_:1}),_("div",Le,[_("span",Ue,p(a.agent?.name||"代理详情"),1),_("div",Ne,[a.agent?.scope?(d(),o(h(re),{key:0,type:"project"===a.agent.scope?"success":"info",size:"tiny",bordered:!1},{default:m(()=>[s(p(C(a.agent.scope)),1)]),_:1},8,["type"])):t("",!0),a.agent?.model?(d(),o(h(re),{key:1,type:"warning",size:"tiny",bordered:!1},{default:m(()=>[s(p(a.agent.model),1)]),_:1})):t("",!0),f.value?(d(),w("span",$e,p(f.value),1)):t("",!0)])])])])]),default:m(()=>[_("div",Ie,[a.loading&&!a.agent?(d(),w("div",Ae,[i(h(ee),{size:"medium"}),u[1]||(u[1]=_("p",null,"加载代理详情中...",-1))])):a.agent?(d(),o(h(V),{key:1,type:"line",animated:"",class:"asset-detail-tabs"},{default:m(()=>[i(h(q),{name:"overview",tab:"概览"},{default:m(()=>[_("div",Fe,["codex"===a.platform&&a.agent.configReadError?(d(),o(h(ne),{key:0,type:"warning",bordered:!1},{default:m(()=>[s(p(a.agent.configReadError),1)]),_:1})):t("",!0),_("div",Se,[u[2]||(u[2]=_("h3",{class:"asset-detail-section-title"},"描述",-1)),_("p",Re,p(a.agent.description||"暂无描述"),1)]),_("div",Be,[u[9]||(u[9]=_("h3",{class:"asset-detail-section-title"},"基础信息",-1)),_("div",De,[_("div",qe,[u[3]||(u[3]=_("span",{class:"asset-detail-label"},"作用域",-1)),_("span",Ee,p(C(a.agent.scope)),1)]),a.agent.fileName?(d(),w("div",Te,[u[4]||(u[4]=_("span",{class:"asset-detail-label"},"文件名",-1)),_("span",He,p(y.value),1)])):t("",!0),"codex"===a.platform&&a.agent.configFile?(d(),w("div",Ve,[u[5]||(u[5]=_("span",{class:"asset-detail-label"},"config_file",-1)),_("span",Ge,p(a.agent.configFile),1)])):t("",!0),a.agent.model?(d(),w("div",We,[u[6]||(u[6]=_("span",{class:"asset-detail-label"},"模型",-1)),_("span",Ye,p(a.agent.model),1)])):t("",!0),a.agent.permissionMode?(d(),w("div",Je,[u[7]||(u[7]=_("span",{class:"asset-detail-label"},"权限模式",-1)),_("span",Xe,p(a.agent.permissionMode),1)])):t("",!0),a.agent.skills?(d(),w("div",Ze,[u[8]||(u[8]=_("span",{class:"asset-detail-label"},"技能",-1)),_("span",Ke,p(a.agent.skills),1)])):t("",!0)])]),a.agent.tools?(d(),w("div",Qe,[u[10]||(u[10]=_("h3",{class:"asset-detail-section-title"},"可用工具",-1)),_("div",ea,[i(h(e),{size:16},{default:m(()=>[i(h($))]),_:1}),_("code",null,p(a.agent.tools),1)])])):t("",!0),i(G,{path:k.value},null,8,["path"])])]),_:1}),i(h(q),{name:"content",tab:"codex"===a.platform?"配置":"提示词"},{default:m(()=>[_("pre",aa,p(b.value),1)]),_:1},8,["tab"])]),_:1})):(d(),w("div",la,[i(h(e),{size:44,class:"asset-detail-empty-icon"},{default:m(()=>[i(h(z))]),_:1}),u[11]||(u[11]=_("p",null,"未选择代理",-1))]))])]),_:1})]),_:1},8,["show","width"]))}},sa={class:"config-edit-header"},na={class:"config-edit-identity"},ia={class:"config-edit-icon"},oa={class:"config-edit-title-stack"},ua={class:"config-edit-kicker"},da={class:"config-edit-title"},ra={class:"config-edit-badges"},ca={class:"config-edit-section"},pa={class:"section-heading"},va={class:"field-grid"},ma={class:"scope-option"},ga={class:"scope-path"},fa={class:"scope-option"},ya={class:"scope-path"},ha={key:0,class:"platform-note"},ba={class:"config-edit-section"},ka={class:"section-heading"},wa={key:1,class:"empty-config-box"},_a={key:0,class:"field-grid"},Ca={class:"field-grid"},ja={key:0,class:"config-edit-section content-section"},xa={class:"section-heading"},Ma={class:"modal-footer"},za=l({__name:"AgentFormModal",props:{visible:{type:Boolean,default:!1},agent:{type:Object,default:null},projectPath:{type:String,default:null},platform:{type:String,default:"claude"}},emits:["update:visible","saved"],setup(l,{emit:n}){const u=l,r=n,y=v({get:()=>u.visible,set:e=>r("update:visible",e)}),b=v(()=>!!u.agent),j=v(()=>"codex"===u.platform),x=v(()=>"claude"===u.platform),M=v(()=>"omp"===u.platform),P=v(()=>["codex","opencode","omp"].includes(u.platform)),O=v(()=>b.value?"编辑代理":"创建代理"),N=v(()=>({claude:"Claude Code",codex:"Codex CLI",gemini:"Gemini CLI",opencode:"OpenCode",omp:"OMP"}[u.platform]||"Claude Code")),$=v(()=>"codex"===u.platform?"~/.codex/config.toml":"opencode"===u.platform?"~/.config/opencode/agents/":"gemini"===u.platform?"~/.gemini/agents/":"omp"===u.platform?"~/.omp/agent/agents/":"~/.claude/agents/"),A=v(()=>"opencode"===u.platform?".opencode/agents/":"gemini"===u.platform?".gemini/agents/":"omp"===u.platform?".omp/agents/":".claude/agents/"),F=v(()=>"project"===Y.value.scope?"项目级":"用户级"),D=v(()=>W.find(e=>e.value===Y.value.configMode)?.label||"配置"),q=k(null),E=k(!1),T={maxHeight:"calc(92vh - 134px)",overflowY:"auto",paddingBottom:"18px"},H=[{label:"Sonnet",value:"sonnet"},{label:"Opus",value:"opus"},{label:"Haiku",value:"haiku"},{label:"继承 (inherit)",value:"inherit"}],V=[{label:"默认 (default)",value:"default"},{label:"宽松 (permissive)",value:"permissive"},{label:"严格 (strict)",value:"strict"}],G=[{label:"Off",value:"off"},{label:"Minimal",value:"minimal"},{label:"Low",value:"low"},{label:"Medium",value:"medium"},{label:"High",value:"high"},{label:"XHigh",value:"xhigh"},{label:"Max",value:"max"}],W=[{label:"仅描述",value:"none"},{label:"托管 TOML",value:"managed"},{label:"自定义路径",value:"custom"}],Y=k({fileName:"",scope:"user",name:"",description:"",configMode:"none",configFile:"",configContent:"",tools:"",model:"",thinkingLevel:"",spawns:"",permissionMode:"",skills:"",systemPrompt:""}),J=v(()=>{const e={fileName:{required:!0,message:"请输入文件名",trigger:"blur"},scope:{required:!0,message:"请选择作用域",trigger:"change"},description:{required:!0,message:"请输入代理描述",trigger:"blur"}};return x.value&&(e.name={required:!0,message:"请输入代理名称",trigger:"blur"}),j.value&&(e.configMode={required:!0,message:"请选择配置模式",trigger:"change"},e.configFile={required:"custom"===Y.value.configMode,message:"请输入自定义配置文件路径",trigger:"blur"}),e});function Z(){Y.value={fileName:"",scope:"user",name:"",description:"",configMode:"none",configFile:"",configContent:"",tools:"",model:"",thinkingLevel:"",spawns:"",permissionMode:"",skills:"",systemPrompt:""}}function ee(){y.value=!1,Z()}async function ae(){try{await(q.value?.validate())}catch{return}E.value=!0;try{const e={...Y.value,projectPath:u.projectPath};j.value?("custom"===Y.value.configMode?e.configFile=Y.value.configFile:delete e.configFile,"managed"===Y.value.configMode||"custom"===Y.value.configMode?e.configContent=Y.value.configContent||"":delete e.configContent):(delete e.configMode,delete e.configFile,delete e.configContent),b.value?(await async function(e,a,l,t="claude"){return(await C.put(`/agents/${a}/${e}`,{...l,platform:t})).data}(Y.value.fileName,Y.value.scope,e,u.platform),ue.success("代理更新成功")):(await async function(e,a="claude"){return(await C.post("/agents",{...e,platform:a})).data}(e,u.platform),ue.success("代理创建成功")),r("saved"),y.value=!1,Z()}catch(e){ue.error("操作失败: "+e.message)}finally{E.value=!1}}return c(()=>u.agent,e=>{if(e){const a=e.configMode||(e.configFile?String(e.configFile).includes("/.codex/agents/")?"managed":"custom":"none");Y.value={fileName:e.fileName||"",scope:e.scope||"user",name:e.name||"",description:e.description||"",configMode:a,configFile:e.configFile||"",configContent:e.fullContent||"",tools:e.tools||"",model:e.model||"",thinkingLevel:e.thinkingLevel||"",spawns:e.spawns||"",permissionMode:e.permissionMode||"",skills:e.skills||"",systemPrompt:e.systemPrompt||""}}else Z()},{immediate:!0}),c(()=>u.platform,e=>{"codex"===e&&(Y.value.scope="user",Y.value.configMode||(Y.value.configMode="none"))},{immediate:!0}),(l,n)=>(d(),o(h(B),{show:y.value,"onUpdate:show":n[15]||(n[15]=e=>y.value=e),preset:"card",title:O.value,style:{width:"min(940px, 96vw)","max-height":"92vh"},"content-style":T,"mask-closable":!1,class:"config-edit-modal"},{footer:m(()=>[_("div",Ma,[i(h(a),{onClick:ee},{default:m(()=>[...n[23]||(n[23]=[s("取消",-1)])]),_:1}),i(h(a),{type:"primary",loading:E.value,onClick:ae},{icon:m(()=>[i(h(e),null,{default:m(()=>[i(h(I))]),_:1})]),default:m(()=>[s(" "+p(b.value?"保存":"创建"),1)]),_:1},8,["loading"])])]),default:m(()=>[_("div",sa,[_("div",na,[_("span",ia,[i(h(e),{size:22},{default:m(()=>[i(h(L))]),_:1})]),_("div",oa,[_("span",ua,p(N.value),1),_("span",da,p(b.value?Y.value.fileName||"编辑代理":"创建新代理"),1)])]),_("div",ra,[i(h(re),{size:"small",bordered:!1,type:"info"},{default:m(()=>[s(p(F.value),1)]),_:1}),j.value?(d(),o(h(re),{key:0,size:"small",bordered:!1,type:"success"},{default:m(()=>[...n[16]||(n[16]=[s("Codex 用户级",-1)])]),_:1})):t("",!0),j.value&&"none"!==Y.value.configMode?(d(),o(h(re),{key:1,size:"small",bordered:!1,type:"warning"},{default:m(()=>[s(p(D.value),1)]),_:1})):t("",!0)])]),i(h(Q),{ref_key:"formRef",ref:q,model:Y.value,rules:J.value,"label-placement":"top","require-mark-placement":"right-hanging",class:"config-edit-form"},{default:m(()=>[_("div",{class:f(["config-edit-grid",{"is-codex":j.value}])},[_("section",ca,[_("div",pa,[i(h(e),{size:16},{default:m(()=>[i(h(S))]),_:1}),n[17]||(n[17]=_("span",null,"基础信息",-1))]),_("div",va,[i(h(K),{label:"文件名",path:"fileName"},{default:m(()=>[i(h(de),{value:Y.value.fileName,"onUpdate:value":n[0]||(n[0]=e=>Y.value.fileName=e),disabled:b.value,placeholder:"code-reviewer"},null,8,["value","disabled"])]),_:1}),x.value?(d(),o(h(K),{key:0,label:"显示名称",path:"name"},{default:m(()=>[i(h(de),{value:Y.value.name,"onUpdate:value":n[1]||(n[1]=e=>Y.value.name=e),placeholder:"代理的显示名称"},null,8,["value"])]),_:1})):t("",!0)]),i(h(K),{label:"作用域",path:"scope"},{default:m(()=>[i(h(le),{value:Y.value.scope,"onUpdate:value":n[2]||(n[2]=e=>Y.value.scope=e),disabled:b.value,class:f(["scope-picker",{"single-option":j.value}])},{default:m(()=>[i(h(se),{value:"user"},{default:m(()=>[_("span",ma,[n[18]||(n[18]=_("span",{class:"scope-title"},"用户级",-1)),_("span",ga,p($.value),1)])]),_:1}),j.value?t("",!0):(d(),o(h(se),{key:0,value:"project"},{default:m(()=>[_("span",fa,[n[19]||(n[19]=_("span",{class:"scope-title"},"项目级",-1)),_("span",ya,p(A.value),1)])]),_:1}))]),_:1},8,["value","disabled","class"])]),_:1}),i(h(K),{label:"描述",path:"description"},{default:m(()=>[i(h(de),{value:Y.value.description,"onUpdate:value":n[3]||(n[3]=e=>Y.value.description=e),type:"textarea",autosize:{minRows:3,maxRows:5},placeholder:"一句话说明这个代理什么时候该被调用"},null,8,["value"])]),_:1}),j.value?(d(),w("div",ha,[i(h(e),{size:16},{default:m(()=>[i(h(U))]),_:1}),n[20]||(n[20]=_("span",null,[s("Codex agents 写入用户级配置。描述会进入 "),_("code",null,"~/.codex/config.toml"),s(",TOML 配置可托管到 "),_("code",null,"~/.codex/agents/"),s("。")],-1))])):t("",!0)]),_("section",ba,[_("div",ka,[i(h(e),{size:16},{default:m(()=>[i(h(R))]),_:1}),_("span",null,p(j.value?"运行配置":"模型与权限"),1)]),j.value?(d(),w(g,{key:0},[i(h(K),{label:"配置模式",path:"configMode"},{default:m(()=>[i(h(X),{value:Y.value.configMode,"onUpdate:value":n[4]||(n[4]=e=>Y.value.configMode=e),options:W,placeholder:"选择配置模式"},null,8,["value"])]),_:1}),"custom"===Y.value.configMode?(d(),o(h(K),{key:0,label:"配置文件路径",path:"configFile"},{default:m(()=>[i(h(de),{value:Y.value.configFile,"onUpdate:value":n[5]||(n[5]=e=>Y.value.configFile=e),placeholder:"~/.omx/agents/my-agent.toml"},null,8,["value"])]),_:1})):t("",!0),"none"===Y.value.configMode?(d(),w("div",wa,[i(h(e),{size:18},{default:m(()=>[i(h(z))]),_:1}),n[21]||(n[21]=_("span",null,"仅保存代理描述,不额外写入模型或工具配置。",-1))])):(d(),o(h(K),{key:2,label:"Agent Config (TOML)",path:"configContent",class:"editor-form-item"},{default:m(()=>[i(h(de),{value:Y.value.configContent,"onUpdate:value":n[6]||(n[6]=e=>Y.value.configContent=e),type:"textarea",autosize:{minRows:14,maxRows:22},class:"toml-editor",placeholder:'model = "gpt-5.4"'},null,8,["value"])]),_:1}))],64)):(d(),w(g,{key:1},[i(h(K),{label:"可用工具",path:"tools"},{default:m(()=>[i(h(de),{value:Y.value.tools,"onUpdate:value":n[7]||(n[7]=e=>Y.value.tools=e),placeholder:M.value?"read, edit, bash(逗号分隔)":"Read, Edit, Bash"},null,8,["value","placeholder"])]),_:1}),i(h(K),{label:"模型",path:"model"},{default:m(()=>[P.value?(d(),o(h(de),{key:0,value:Y.value.model,"onUpdate:value":n[8]||(n[8]=e=>Y.value.model=e),placeholder:M.value?"@default、@review 或 provider/model;多个候选用逗号分隔":"gpt-5, claude-sonnet-4, openrouter/model"},null,8,["value","placeholder"])):(d(),o(h(X),{key:1,value:Y.value.model,"onUpdate:value":n[9]||(n[9]=e=>Y.value.model=e),options:H,placeholder:"选择模型",clearable:""},null,8,["value"]))]),_:1}),M.value?(d(),w("div",_a,[i(h(K),{label:"思考级别",path:"thinkingLevel"},{default:m(()=>[i(h(X),{value:Y.value.thinkingLevel,"onUpdate:value":n[10]||(n[10]=e=>Y.value.thinkingLevel=e),options:G,placeholder:"使用模型默认级别",clearable:""},null,8,["value"])]),_:1}),i(h(K),{label:"可调用的子 Agent",path:"spawns"},{default:m(()=>[i(h(de),{value:Y.value.spawns,"onUpdate:value":n[11]||(n[11]=e=>Y.value.spawns=e),placeholder:"* 或 reviewer, scout"},null,8,["value"])]),_:1})])):t("",!0),_("div",Ca,["opencode"===u.platform||M.value?t("",!0):(d(),o(h(K),{key:0,label:"权限模式",path:"permissionMode"},{default:m(()=>[i(h(X),{value:Y.value.permissionMode,"onUpdate:value":n[12]||(n[12]=e=>Y.value.permissionMode=e),options:V,placeholder:"选择权限模式",clearable:""},null,8,["value"])]),_:1})),"opencode"===u.platform||M.value?t("",!0):(d(),o(h(K),{key:1,label:"技能",path:"skills"},{default:m(()=>[i(h(de),{value:Y.value.skills,"onUpdate:value":n[13]||(n[13]=e=>Y.value.skills=e),placeholder:"自动加载的技能,逗号分隔"},null,8,["value"])]),_:1}))])],64))]),j.value?t("",!0):(d(),w("section",ja,[_("div",xa,[i(h(e),{size:16},{default:m(()=>[i(h(z))]),_:1}),n[22]||(n[22]=_("span",null,"系统提示词",-1))]),i(h(K),{path:"systemPrompt","show-label":!1,class:"editor-form-item"},{default:m(()=>[i(pe,{modelValue:Y.value.systemPrompt,"onUpdate:modelValue":n[14]||(n[14]=e=>Y.value.systemPrompt=e),rows:10,"min-height":240,placeholder:"定义代理的行为、边界和输出要求","default-editing":!b.value},null,8,["modelValue","default-editing"])]),_:1})]))],2)]),_:1},8,["model","rules"])]),_:1},8,["show","title"]))}},[["__scopeId","data-v-ea89272f"]]),Pa={key:0,class:"asset-panel-header"},Oa={class:"asset-title-group"},La={class:"asset-heading"},Ua={class:"asset-title-row"},Na={class:"asset-platform-pill"},$a={key:0,class:"asset-action-row"},Ia={key:1,class:"asset-drawer-toolbar"},Aa={key:0,class:"asset-action-row"},Fa={key:2,class:"omp-model-roles"},Sa={class:"omp-model-roles-toolbar"},Ra={class:"omp-model-roles-copy"},Ba={key:0,class:"omp-model-roles-stale"},Da={key:1,class:"omp-model-roles-error"},qa={class:"asset-summary"},Ea={class:"asset-summary-item"},Ta={class:"asset-summary-value"},Ha={class:"asset-summary-item"},Va={class:"asset-summary-value"},Ga={class:"asset-summary-item"},Wa={class:"asset-summary-value"},Ya={class:"asset-summary-item"},Ja={class:"asset-summary-value"},Xa={class:"asset-filter-bar"},Za={class:"asset-panel-content"},Ka={key:0,class:"asset-empty"},Qa={key:1,class:"asset-list"},el={class:"asset-footer"},al=l({__name:"AgentsPanel",props:{hideBack:{type:Boolean,default:!1},inDrawer:{type:Boolean,default:!1},projectPath:{type:String,default:null},platform:{type:String,default:""}},emits:["back","updated"],setup(l,{emit:r}){const y=l,z=r,$=M(),I=b(),A=k([]),S=k(!1),R=k(""),B=k("all"),q=k(!1),V=k(!1),G=k(null),W=k(!1),Y=k(null),J=k({}),K=k({}),Q=k({}),le=k([]),te=k(""),se=k([]),ne=k([]),oe=v(()=>new Set(se.value.map(e=>e.value))),re=k(!1),pe=k(!1),me=k(""),ge=v(()=>JSON.stringify(_e())!==te.value);let fe=0;const{byCapability:ye}=Z(),he=v(()=>ye("agents").map(e=>e.key)),be=v(()=>he.value.includes(xe.value)),ke=["default","smol","slow","plan","commit","vision","designer","task","advisor","tiny"],we=["minimal","low","medium","high","xhigh","max"].map(e=>({label:e,value:e}));function _e(){return Object.fromEntries(le.value.map(e=>[e.key,{model:e.model||"",thinkingLevel:e.thinkingLevel||""}]))}function Ce(e={}){const a=e.roles&&"object"==typeof e.roles?e.roles:{};le.value=ke.map(e=>({key:e,model:"string"==typeof a[e]?.model?a[e].model:"",thinkingLevel:"string"==typeof a[e]?.thinkingLevel?a[e].thinkingLevel:""})),te.value=JSON.stringify(_e()),se.value=(Array.isArray(e.modelOptions)?e.modelOptions:[]).filter(e=>"string"==typeof e&&e.trim()).map(e=>({label:e,value:e})),ne.value=e.unavailableRoles&&"object"==typeof e.unavailableRoles?Object.keys(e.unavailableRoles).filter(a=>!0===e.unavailableRoles[a]):[]}function je(e,a){return e?.data?.error||e?.response?.data?.error||e?.message||a}const xe=v(()=>String(y.platform||j(I)||"").trim().toLowerCase()),Me=v(()=>"opencode"===xe.value?"使用 @agent 或 Task 在 OpenCode 中调用":"omp"===xe.value?"OMP Agent 由 task 工具按名称调用;模型可在 Agent 配置中单独指定":"gemini"===xe.value?"使用 @agent 调用 Gemini 自定义代理":"使用 Task tool 调用自定义代理"),Pe=v(()=>{const e=$.get(xe.value)||x(xe.value);return e.label||e.title||"Claude Code"}),Oe=[{label:"全部",value:"all"},{label:"用户级",value:"user"},{label:"项目级",value:"project"},{label:"已托管",value:"managed"}],Le=v(()=>A.value.filter(e=>"user"===e.scope).length),Ue=v(()=>A.value.filter(e=>"project"===e.scope).length),Ne=v(()=>Object.keys(K.value).length);function $e(e){if(!e)return"";const a="string"==typeof e.scope&&e.scope.trim()?e.scope.trim():"unknown",l="string"==typeof e.path&&e.path.trim()?e.path.trim():"",t="string"==typeof e.fileName&&e.fileName.trim()?e.fileName.trim():"";return`${a}:${l||t}`}function Ie(e){if(!e)return"";const a=[];if("string"==typeof e.path&&e.path.trim()&&a.push(e.path.trim()),"string"==typeof e.fileName&&e.fileName.trim()){const l=e.fileName.trim();a.push(`${l}.md`,l)}"string"==typeof e.name&&e.name.trim()&&a.push(e.name.trim());for(const l of a)if(K.value[l])return l;return a[0]||""}const Ae=v(()=>{let e=A.value;if("user"===B.value?e=e.filter(e=>"user"===e.scope):"project"===B.value?e=e.filter(e=>"project"===e.scope):"managed"===B.value&&(e=e.filter(e=>K.value[Ie(e)])),R.value.trim()){const a=R.value.toLowerCase();e=e.filter(e=>e.name?.toLowerCase().includes(a)||e.description?.toLowerCase().includes(a)||e.fileName?.toLowerCase().includes(a))}return e}),Fe=v(()=>R.value?"没有匹配的代理":"user"===B.value?"暂无用户级代理":"project"===B.value?"暂无项目级代理":"managed"===B.value?"暂无托管的代理":be.value?"暂无自定义代理":`${Pe.value} 暂未提供 Agents 能力`);async function Se(){if(!be.value)return A.value=[],K.value={},void(S.value=!1);S.value=!0;try{const[e,a]=await Promise.all([ve(y.projectPath,xe.value),H("agents",{platform:xe.value,projectPath:y.projectPath})]);if(e.success&&(A.value=e.agents||[]),a.success){K.value={};for(const[e,l]of Object.entries(a.items||{}))K.value[e]=l}}catch(e){ue.error("加载代理列表失败: "+e.message)}finally{S.value=!1}}async function Re(e,a){const l=Ie(e);if(l){Q.value[l]=!0;try{(await D("agents",l,a)).success&&(ue.success(a?"已启用":"已禁用"),await Se())}catch(t){ue.error("切换失败: "+t.message)}finally{delete Q.value[l]}}else ue.error("未找到代理对应的托管配置键")}async function Be(e,a,l){const t=Ie(e);if(t){Q.value[t]=!0;try{(await T("agents",t,a,l)).success&&(ue.success(`${a} ${l?"已启用":"已禁用"}`),await Se())}catch(s){ue.error("切换失败: "+s.message)}finally{delete Q.value[t]}}else ue.error("未找到代理对应的托管配置键")}async function De(){S.value=!0;try{const e=await E("agents");e?.success||ue.warning(e?.message||"同步失败,已继续刷新列表")}catch(e){ue.warning("同步失败,已继续刷新列表: "+e.message)}await Se()}async function qe(){if("omp"===xe.value){re.value=!0,me.value="";try{const{data:e}=await C.get("/settings/omp-model-roles");Ce(e)}catch(e){me.value=`加载 OMP 角色配置失败:${je(e,"未知错误")}`}finally{re.value=!1}}}async function Ee(){if(!(re.value||pe.value||me.value)){pe.value=!0;try{const{data:e}=await C.put("/settings/omp-model-roles",{roles:_e()});Ce(e),ue.success("OMP 模型角色配置已保存")}catch(e){ue.error(`保存 OMP 角色配置失败:${je(e,"未知错误")}`)}finally{pe.value=!1}}}function Te(){Y.value=null,q.value=!0}function He(e){q.value=e,e||(Y.value=null)}function Ve(e){We(e,!0)}async function Ge(e){const a=$e(e);J.value[a]=!0;try{(await async function(e,a,l=null,t="claude"){const s={};return t&&(s.platform=t),l&&(s.projectPath=l),(await C.delete(`/agents/${a}/${e}`,{params:s})).data}(e.fileName,e.scope,y.projectPath,xe.value)).success&&(ue.success("代理已删除"),await Se(),z("updated"))}catch(l){ue.error("删除失败: "+l.message)}finally{delete J.value[a]}}async function We(e,a=!1){if(!e)return;const l=++fe;W.value=!0,a||(G.value=null,V.value=!0);try{const t=await async function(e,a,l=null,t="claude"){const s={};t&&(s.platform=t),l&&(s.projectPath=l);const n=ce(`agent-detail:${e}`,t,a||"",l||"");return ae(n,l=>C.get(`/agents/${a}/${e}`,{params:s,signal:l}).then(e=>e.data),"agent-detail",`agent-detail:${t}`)}(e.fileName,e.scope,y.projectPath,xe.value);if(l!==fe)return;const s=t?.agent||e;a?(Y.value=s,q.value=!0):G.value=s}catch(t){if(l!==fe)return;ue.error("加载代理详情失败: "+t.message),a?(Y.value=e,q.value=!0):G.value=e}finally{l===fe&&(W.value=!1)}}function Ye(e){We(e,!1)}function Je(){Y.value=null,Se(),z("updated")}function Xe(){z("back")}return u(()=>{Se(),qe()}),c(xe,()=>{fe+=1,W.value=!1,G.value=null,Se(),qe()}),(u,r)=>(d(),w("div",{class:f(["agents-panel asset-panel",{"in-drawer":y.inDrawer}])},[y.inDrawer?t("",!0):(d(),w("div",Pa,[_("div",Oa,[y.hideBack?t("",!0):(d(),o(h(a),{key:0,text:"",onClick:Xe,class:"back-btn"},{icon:m(()=>[i(h(e),null,{default:m(()=>[i(h(P))]),_:1})]),_:1})),_("div",La,[_("div",Ua,[r[3]||(r[3]=_("span",{class:"asset-title"},"代理管理",-1)),_("span",Na,p(Pe.value),1)]),r[4]||(r[4]=_("div",{class:"asset-subtitle"},"维护自定义代理、工具权限和平台启用状态",-1))])]),be.value?(d(),w("div",$a,[i(h(a),{text:"",onClick:Te,class:"action-btn"},{icon:m(()=>[i(h(e),null,{default:m(()=>[i(h(O))]),_:1})]),default:m(()=>[r[5]||(r[5]=s(" 创建 ",-1))]),_:1}),i(h(a),{text:"",onClick:De,loading:S.value,class:"action-btn"},{icon:m(()=>[i(h(e),null,{default:m(()=>[i(h(N))]),_:1})]),default:m(()=>[r[6]||(r[6]=s(" 刷新 ",-1))]),_:1},8,["loading"])])):t("",!0)])),y.inDrawer?(d(),w("div",Ia,[be.value?(d(),w("div",Aa,[i(h(a),{text:"",onClick:Te,class:"action-btn"},{icon:m(()=>[i(h(e),null,{default:m(()=>[i(h(O))]),_:1})]),default:m(()=>[r[7]||(r[7]=s(" 创建 ",-1))]),_:1}),i(h(a),{text:"",onClick:De,loading:S.value,class:"action-btn"},{icon:m(()=>[i(h(e),null,{default:m(()=>[i(h(N))]),_:1})]),default:m(()=>[r[8]||(r[8]=s(" 刷新 ",-1))]),_:1},8,["loading"])])):t("",!0)])):t("",!0),"omp"===xe.value?(d(),w("div",Fa,[_("div",Sa,[_("div",Ra,[r[10]||(r[10]=_("strong",null,"OMP 模型角色",-1)),r[11]||(r[11]=_("span",null,"候选模型只取当前启用渠道。原生 OAuth 渠道读取允许模型列表(未设置时读取已声明模型),并使用 OAuth provider ID 作为前缀;OAuth Auth Gateway 使用该托管渠道的模型配置。思考强度会写入选择器后缀,例如 :high。",-1)),ne.value.length?(d(),w("span",Ba," 以下角色当前指向未启用渠道模型:"+p(ne.value.join("、"))+"。请切换到已启用渠道中的模型,或清空对应角色。 ",1)):t("",!0),me.value?(d(),w("div",Da,[_("span",null,p(me.value),1),i(h(a),{text:"",size:"tiny",disabled:re.value,onClick:qe},{default:m(()=>[...r[9]||(r[9]=[s("重试",-1)])]),_:1},8,["disabled"])])):t("",!0)]),i(h(a),{type:"primary",size:"small",loading:pe.value,disabled:re.value||!!me.value||pe.value||!ge.value,onClick:Ee},{default:m(()=>[...r[12]||(r[12]=[s(" 保存角色配置 ",-1)])]),_:1},8,["loading","disabled"])]),r[13]||(r[13]=_("div",{class:"omp-model-roles-header"},[_("span",null,"角色"),_("span",null,"模型"),_("span",null,"思考强度")],-1)),(d(!0),w(g,null,n(le.value,e=>(d(),w("div",{key:e.key,class:"omp-model-role-row"},[_("strong",null,p(e.key),1),i(h(X),{value:e.model,"onUpdate:value":a=>e.model=a,options:se.value,placeholder:"请选择已启用渠道模型",filterable:"",clearable:"",size:"small",disabled:re.value||!!me.value||pe.value},null,8,["value","onUpdate:value","options","disabled"]),i(h(X),{value:e.thinkingLevel,"onUpdate:value":a=>e.thinkingLevel=a,options:h(we),placeholder:"跟随默认",clearable:"",size:"small",disabled:re.value||!!me.value||pe.value||!oe.value.has(e.model)},null,8,["value","onUpdate:value","options","disabled"])]))),128))])):t("",!0),_("div",qa,[_("span",Ea,[r[14]||(r[14]=_("span",{class:"asset-summary-label"},"全部",-1)),_("span",Ta,p(A.value.length),1)]),_("span",Ha,[r[15]||(r[15]=_("span",{class:"asset-summary-label"},"用户级",-1)),_("span",Va,p(Le.value),1)]),_("span",Ga,[r[16]||(r[16]=_("span",{class:"asset-summary-label"},"项目级",-1)),_("span",Wa,p(Ue.value),1)]),_("span",Ya,[r[17]||(r[17]=_("span",{class:"asset-summary-label"},"托管",-1)),_("span",Ja,p(Ne.value),1)])]),_("div",Xa,[i(h(de),{value:R.value,"onUpdate:value":r[0]||(r[0]=e=>R.value=e),placeholder:"搜索代理、描述或文件名",clearable:"",size:"small",class:"asset-search"},{prefix:m(()=>[i(h(e),null,{default:m(()=>[i(h(F))]),_:1})]),_:1},8,["value"]),i(h(X),{value:B.value,"onUpdate:value":r[1]||(r[1]=e=>B.value=e),options:Oe,size:"small",class:"asset-filter"},null,8,["value"])]),_("div",Za,[i(h(ee),{show:S.value},{default:m(()=>[0!==Ae.value.length||S.value?(d(),w("div",Qa,[(d(!0),w(g,null,n(Ae.value,e=>(d(),o(ze,{key:$e(e),agent:e,deleting:!!J.value[$e(e)],"registry-info":K.value[Ie(e)],toggling:!!Q.value[Ie(e)],onEdit:Ve,onDelete:Ge,onClick:Ye,onToggleEnabled:Re,onTogglePlatform:Be},null,8,["agent","deleting","registry-info","toggling"]))),128))])):(d(),w("div",Ka,[i(h(ie),{description:Fe.value},{icon:m(()=>[i(h(e),{size:"48",color:"var(--text-quaternary)"},{default:m(()=>[i(h(L))]),_:1})]),extra:m(()=>[be.value?(d(),o(h(a),{key:0,size:"small",onClick:Te},{default:m(()=>[...r[18]||(r[18]=[s(" 创建第一个代理 ",-1)])]),_:1})):t("",!0)]),_:1},8,["description"])]))]),_:1},8,["show"])]),_("div",el,[i(h(e),{size:"14",class:"asset-info-icon"},{default:m(()=>[i(h(U))]),_:1}),_("span",null,p(Me.value),1)]),i(za,{visible:q.value,"onUpdate:visible":He,agent:Y.value,"project-path":l.projectPath,platform:xe.value,onSaved:Je},null,8,["visible","agent","project-path","platform"]),i(ta,{visible:V.value,"onUpdate:visible":r[2]||(r[2]=e=>V.value=e),agent:G.value,platform:xe.value,loading:W.value},null,8,["visible","agent","platform","loading"])],2))}},[["__scopeId","data-v-393fa5d6"]]),ll=l({__name:"AgentsDrawer",props:{visible:Boolean,platform:{type:String,default:""}},emits:["update:visible"],setup(e,{emit:a}){const l=e,t=a,{drawerWidth:s}=Y(720),n=v({get:()=>l.visible,set:e=>t("update:visible",e)}),u={padding:0,display:"flex",flexDirection:"column",overflow:"hidden"};return(e,a)=>(d(),o(h(W),{show:n.value,"onUpdate:show":a[1]||(a[1]=e=>n.value=e),width:h(s),placement:"right","mask-closable":!0},{default:m(()=>[i(h(J),{closable:"","native-scrollbar":!1,"body-content-style":u},{header:m(()=>[...a[2]||(a[2]=[_("div",{class:"drawer-header"},[_("span",null,"代理管理")],-1)])]),default:m(()=>[i(al,{onBack:a[0]||(a[0]=e=>n.value=!1),"hide-back":!0,"in-drawer":!0,platform:l.platform},null,8,["platform"])]),_:1})]),_:1},8,["show","width"]))}},[["__scopeId","data-v-b9b7a7fa"]]);export{ll as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.drawer-header[data-v-27295eec]{align-items:center;gap:8px;display:flex}.header-icon-wrapper[data-v-27295eec]{background:var(--bg-secondary);border:1px solid var(--border-primary);width:28px;height:28px;color:var(--primary-color);border-radius:6px;justify-content:center;align-items:center;display:flex}.convert-container[data-v-27295eec]{flex-direction:column;gap:10px;padding-bottom:8px;display:flex}.action-row[data-v-27295eec]{justify-content:space-between;align-items:center;gap:8px;display:flex}.result-section[data-v-27295eec]{border:1px solid var(--border-primary);background:var(--bg-secondary);border-radius:8px;padding:12px}.result-meta[data-v-27295eec]{flex-wrap:wrap;gap:10px 14px;display:flex}.meta-row[data-v-27295eec]{align-items:center;gap:6px;display:flex}.meta-label[data-v-27295eec]{color:var(--text-secondary);font-size:12px}.warning-title[data-v-27295eec]{margin-bottom:4px;font-size:12px;font-weight:600}.warning-list[data-v-27295eec]{margin:0;padding-left:16px;font-size:12px;line-height:1.5}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e,s as a,t}from"./_plugin-vue_export-helper-BeLZJZij.js";import{C as s,D as l,K as o,O as n,S as r,W as u,Z as i,_t as c,b as p,et as d,g as v,mt as m,st as y,w as f,x as w}from"./vue-vendor-BqZbbXHA.js";import{n as g}from"./vendors-D0c_0KLP.js";import{H as h}from"./icons-B-AzZoeE.js";import{n as x,t as b}from"./useResponsiveDrawer-C-UacYVP.js";import{t as _}from"./DrawerContent-ChXgZ1Xm.js";import{$ as C,H as A,I as k,L as O,ct as S,k as j,st as J,ut as N}from"./index-Bw6YXbBA.js";var T="http://localhost:19999";async function z(e){return(await g.post(`${T}/api/convert/opencode/claude`,e)).data}async function R(e){return(await g.post(`${T}/api/convert/opencode/codex`,e)).data}async function I(e){return(await g.post(`${T}/api/convert/opencode/gemini`,e)).data}var $={class:"drawer-header"},q={class:"header-icon-wrapper"},B={class:"convert-container"},U={class:"action-row"},D={key:1,class:"result-section"},P={class:"result-meta"},Y={class:"meta-row"},E={class:"meta-row"},G={class:"meta-row"},H={class:"warning-list"},W={class:"action-row"},K=t({__name:"GatewayConvertDrawer",props:{visible:{type:Boolean,default:!1}},emits:["update:visible"],setup(t,{emit:K}){const{drawerWidth:L}=b(620,520),Z=t,F=K,M=p({get:()=>Z.visible,set:e=>F("update:visible",e)}),Q=y([{label:"Claude Code",value:"claude"},{label:"Codex",value:"codex"},{label:"Gemini",value:"gemini"}]),V=y([{label:"Responses API (/v1/responses)",value:"responses"},{label:"Chat Completions (/v1/chat/completions)",value:"chat.completions"}]),X=y("claude"),ee=y("responses"),ae=y(""),te=y(!1),se=y(null),le=y(""),oe=y(!1),ne={claude:{model:"claude-sonnet-4-5",system:[{type:"text",text:"You are a concise assistant."}],messages:[{role:"user",content:[{type:"text",text:"请用三点总结这个需求。"}]}],max_tokens:256,stream:!1},codex:{model:"gpt-5-codex",instructions:"You are Codex.",input:[{type:"message",role:"user",content:[{type:"input_text",text:"ping"}]}],stream:!1,store:!1},gemini:{model:"gemini-2.5-pro",system_instruction:{parts:[{text:"You are a concise assistant."}]},contents:[{role:"user",parts:[{text:"请将以下文本转换为要点列表。"}]}],generationConfig:{maxOutputTokens:256,temperature:.2}}},re=p(()=>se.value?.requestBody?JSON.stringify(se.value.requestBody,null,2):"");function ue(){const e=ne[X.value]||ne.claude;ae.value=JSON.stringify(e,null,2)}async function ie(){if(!oe.value)try{const e=await async function(){return(await g.get(`${T}/api/convert/opencode/formats`)).data}();Array.isArray(e.sourceTypes)&&e.sourceTypes.length>0&&(Q.value=e.sourceTypes.map(e=>({label:e.name||e.id,value:e.id}))),Array.isArray(e.targetApis)&&e.targetApis.length>0&&(V.value=e.targetApis.map(e=>"chat.completions"===e?{label:"Chat Completions (/v1/chat/completions)",value:e}:{label:"Responses API (/v1/responses)",value:e})),e.defaultTargetApi&&(ee.value=e.defaultTargetApi),oe.value=!0}catch(e){}}function ce(){le.value="",se.value=null}async function pe(){let e;le.value="",se.value=null;try{e=JSON.parse(ae.value||"{}")}catch(a){return void(le.value="原始请求 JSON 解析失败,请检查格式")}te.value=!0;try{const a={claude:z,codex:R,gemini:I}[X.value];if(!a)throw new Error(`Unsupported sourceType: ${X.value}`);const t=await a({payload:e,options:{targetApi:ee.value}});if(!1===t.success)throw new Error(t.error||"转换失败");se.value=t,j.success("转换完成")}catch(a){const e=a.response?.data?.error||a.message||"转换失败";le.value=e}finally{te.value=!1}}async function de(){if(!se.value)return;const e={endpoint:se.value.endpoint,requestBody:se.value.requestBody};try{await navigator.clipboard.writeText(JSON.stringify(e,null,2)),j.success("已复制转换结果")}catch(a){j.error("复制失败,请手动复制")}}return i(()=>X.value,()=>{ue()}),i(()=>Z.visible,async e=>{e&&(await ie(),ae.value||ue())},{immediate:!0}),(t,i)=>(u(),r(m(x),{show:M.value,"onUpdate:show":i[3]||(i[3]=e=>M.value=e),width:m(L),placement:"right","show-mask":!0},{default:d(()=>[n(m(_),{closable:"","native-scrollbar":!1},{header:d(()=>[w("div",$,[w("div",q,[n(m(e),{size:18},{default:d(()=>[n(m(h))]),_:1})]),i[4]||(i[4]=w("span",null,"OpenCode 请求转换",-1))])]),default:d(()=>[w("div",B,[n(m(O),{"label-placement":"top"},{default:d(()=>[n(m(k),{label:"来源渠道"},{default:d(()=>[n(m(C),{value:X.value,"onUpdate:value":i[0]||(i[0]=e=>X.value=e),options:Q.value,placeholder:"选择来源渠道"},null,8,["value","options"])]),_:1}),n(m(k),{label:"目标 API"},{default:d(()=>[n(m(C),{value:ee.value,"onUpdate:value":i[1]||(i[1]=e=>ee.value=e),options:V.value,placeholder:"选择目标 API"},null,8,["value","options"])]),_:1}),n(m(k),{label:"原始请求 JSON"},{default:d(()=>[n(m(J),{value:ae.value,"onUpdate:value":i[2]||(i[2]=e=>ae.value=e),type:"textarea",autosize:{minRows:10,maxRows:18},placeholder:"粘贴原始请求 JSON"},null,8,["value"])]),_:1})]),_:1}),w("div",U,[n(m(a),{quaternary:"",onClick:ue},{default:d(()=>[...i[5]||(i[5]=[l("填充示例",-1)])]),_:1}),n(m(A),null,{default:d(()=>[n(m(a),{onClick:ce},{default:d(()=>[...i[6]||(i[6]=[l("清空结果",-1)])]),_:1}),n(m(a),{type:"primary",loading:te.value,onClick:pe},{default:d(()=>[...i[7]||(i[7]=[l("开始转换",-1)])]),_:1},8,["loading"])]),_:1})]),le.value?(u(),r(m(S),{key:0,type:"error","show-icon":!0,style:{"margin-top":"12px"}},{default:d(()=>[l(c(le.value),1)]),_:1})):s("",!0),se.value?(u(),f("div",D,[w("div",P,[w("div",Y,[i[8]||(i[8]=w("span",{class:"meta-label"},"转换端点",-1)),n(m(N),{type:"success",size:"small",bordered:!1},{default:d(()=>[l(c(se.value.endpoint),1)]),_:1})]),w("div",E,[i[9]||(i[9]=w("span",{class:"meta-label"},"目标协议",-1)),n(m(N),{type:"info",size:"small",bordered:!1},{default:d(()=>[l(c(se.value.targetApi),1)]),_:1})]),w("div",G,[i[10]||(i[10]=w("span",{class:"meta-label"},"消息数量",-1)),n(m(N),{size:"small",bordered:!1},{default:d(()=>[l(c(se.value.meta?.messageCount??0),1)]),_:1})])]),Array.isArray(se.value.warnings)&&se.value.warnings.length>0?(u(),r(m(S),{key:0,type:"warning","show-icon":!0,style:{"margin-top":"12px"}},{default:d(()=>[i[11]||(i[11]=w("div",{class:"warning-title"},"转换警告",-1)),w("ul",H,[(u(!0),f(v,null,o(se.value.warnings,(e,a)=>(u(),f("li",{key:a},c(e),1))),128))])]),_:1})):s("",!0),n(m(k),{label:"转换后请求 JSON",style:{"margin-top":"12px"}},{default:d(()=>[n(m(J),{value:re.value,type:"textarea",readonly:"",autosize:{minRows:10,maxRows:18}},null,8,["value"])]),_:1}),w("div",W,[i[13]||(i[13]=w("div",null,null,-1)),n(m(a),{size:"small",onClick:de},{default:d(()=>[...i[12]||(i[12]=[l("复制转换结果",-1)])]),_:1})])])):s("",!0)])]),_:1})]),_:1},8,["show","width"]))}},[["__scopeId","data-v-27295eec"]]);export{K as default};
|