coding-tool-x 3.8.8 → 3.8.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +56 -388
  2. package/dist/web/assets/AgentsDrawer-Bam7kBjG.js +1 -0
  3. package/dist/web/assets/Analytics-D5dUWXEa.js +1 -0
  4. package/dist/web/assets/AssetPathField-CLqalYv-.js +1 -0
  5. package/dist/web/assets/{ChatHistoryDrawer-CrfS0KYV.js → ChatHistoryDrawer-C1At65O3.js} +1 -1
  6. package/dist/web/assets/{CollapseItem-ClMsJuUu.js → CollapseItem-CVWojShK.js} +1 -1
  7. package/dist/web/assets/CommandsDrawer-BEoypGBf.js +1 -0
  8. package/dist/web/assets/ConfigExportDrawer-DBvFDDWK.js +1 -0
  9. package/dist/web/assets/ConfigTemplates-BpaWG-iC.js +1 -0
  10. package/dist/web/assets/{ConfigTemplatesDrawer-BqM32Im7.js → ConfigTemplatesDrawer-C2lvyKMf.js} +1 -1
  11. package/dist/web/assets/ConfigTemplatesPanel-CorOY7kY.js +1 -0
  12. package/dist/web/assets/{Divider-DsdbkHrG.js → Divider-BLLhMTSt.js} +1 -1
  13. package/dist/web/assets/FavoritesDrawer-uW88N6te.js +1 -0
  14. package/dist/web/assets/GatewayConvertDrawer-i5Wt9Dd9.js +1 -0
  15. package/dist/web/assets/Home-BIxWvm29.js +1 -0
  16. package/dist/web/assets/{MarkdownEditor-BMMUufSc.js → MarkdownEditor-Ul0bSGj-.js} +1 -1
  17. package/dist/web/assets/McpDrawer-Cc2xq77I.js +1 -0
  18. package/dist/web/assets/McpFormDrawer-DLHX_nrI.js +1 -0
  19. package/dist/web/assets/{PluginManager-C4kJlpVX.js → PluginManager-BGQ0xF2F.js} +1 -1
  20. package/dist/web/assets/{PluginsDrawer-05R4k15x.js → PluginsDrawer-STwHEqiF.js} +1 -1
  21. package/dist/web/assets/PluginsPanel-1zuNP7da.js +1 -0
  22. package/dist/web/assets/ProjectList-VbIYSHbH.css +1 -0
  23. package/dist/web/assets/ProjectList-_pe2nk9c.js +1 -0
  24. package/dist/web/assets/PromptsDrawer-CJN1xZk7.js +1 -0
  25. package/dist/web/assets/RecentSessionsDrawer-DX1HI8Nm.js +1 -0
  26. package/dist/web/assets/SessionCard-Op6PHvi0.js +1 -0
  27. package/dist/web/assets/SessionList-Da_TAEYr.js +1 -0
  28. package/dist/web/assets/SettingsDrawer-DKLd4Sjy.js +1 -0
  29. package/dist/web/assets/{SkillManager-D9jkNuRM.js → SkillManager-PcAa5EbF.js} +1 -1
  30. package/dist/web/assets/{SkillsDrawer-0Z4IefxC.js → SkillsDrawer-DPdU4p6C.js} +1 -1
  31. package/dist/web/assets/SkillsPanel-B9qzRqjd.js +1 -0
  32. package/dist/web/assets/Upload-e1M9Yp5z.js +1 -0
  33. package/dist/web/assets/{WorkspaceDrawer-eujtWpoq.js → WorkspaceDrawer-oS6mB1VZ.js} +1 -1
  34. package/dist/web/assets/{WorkspaceManager-CQ-8Ej68.js → WorkspaceManager-6VvRWe3r.js} +1 -1
  35. package/dist/web/assets/WorkspacePanel-CYq0Z8iY.js +1 -0
  36. package/dist/web/assets/client-BgcNg4Bt.js +1 -0
  37. package/dist/web/assets/headers-DbowkmZJ.js +1 -0
  38. package/dist/web/assets/{icons-DmFe4b5j.js → icons-B-AzZoeE.js} +1 -1
  39. package/dist/web/assets/index-BlUXw84U.js +2 -0
  40. package/dist/web/assets/index-Bn8BUnwP.css +1 -0
  41. package/dist/web/assets/{light-0eavxNvt.js → light-C2X7hegj.js} +1 -1
  42. package/dist/web/assets/platforms-DrzAtnjY.js +1 -0
  43. package/dist/web/assets/platforms-mqqe_82d.js +1 -0
  44. package/dist/web/assets/project-config-BVt5s-pH.js +1 -0
  45. package/dist/web/assets/sessions-53-Fr68H.js +1 -0
  46. package/dist/web/assets/{sessions-D4yQtfKb.js → sessions-CaWUaysM.js} +1 -1
  47. package/dist/web/assets/use-message-DBsCm7FJ.js +1 -0
  48. package/dist/web/assets/{useResponsiveDrawer-DZd5rNk5.js → useResponsiveDrawer-ChHZrTfl.js} +1 -1
  49. package/dist/web/assets/{workspaces-mjyPVGS8.js → workspaces-DQuZd4qw.js} +1 -1
  50. package/dist/web/index.html +8 -8
  51. package/package.json +4 -2
  52. package/src/commands/daemon.js +27 -4
  53. package/src/commands/export-config.js +17 -211
  54. package/src/config/model-metadata.json +180 -16
  55. package/src/platforms/channel-auth-registry.js +36 -6
  56. package/src/platforms/channel-auth-service.js +13 -3
  57. package/src/platforms/commands-service.js +28 -0
  58. package/src/platforms/driver-registry.js +1 -0
  59. package/src/platforms/drivers/claude/channels-implementation.js +79 -90
  60. package/src/platforms/drivers/claude/native-config-implementation.js +3 -4
  61. package/src/platforms/drivers/codex/channels-implementation.js +34 -49
  62. package/src/platforms/drivers/codex/native-config-implementation.js +3 -51
  63. package/src/platforms/drivers/dsh/api-operations.js +1 -1
  64. package/src/platforms/drivers/dsh/channels-implementation.js +28 -8
  65. package/src/platforms/drivers/dsh/channels.js +0 -18
  66. package/src/platforms/drivers/dsh/common.js +7 -0
  67. package/src/platforms/drivers/dsh/native-config.js +7 -2
  68. package/src/platforms/drivers/gemini/channels-implementation.js +47 -55
  69. package/src/platforms/drivers/gemini/native-config-implementation.js +8 -20
  70. package/src/platforms/drivers/generic-native-config.js +20 -0
  71. package/src/platforms/drivers/native-config-snapshot.js +30 -4
  72. package/src/platforms/drivers/omp/channels-implementation.js +51 -17
  73. package/src/platforms/drivers/omp/native-config-implementation.js +10 -17
  74. package/src/platforms/drivers/omp/prompts.js +58 -2
  75. package/src/platforms/drivers/omp/proxy-implementation.js +25 -1
  76. package/src/platforms/drivers/opencode/channels-implementation.js +31 -22
  77. package/src/platforms/drivers/opencode/channels.js +6 -1
  78. package/src/platforms/drivers/opencode/native-config-implementation.js +3 -67
  79. package/src/platforms/manifest-schema.js +35 -2
  80. package/src/platforms/manifests/claude.json +0 -8
  81. package/src/platforms/manifests/codex.json +0 -8
  82. package/src/platforms/manifests/dsh.json +6 -9
  83. package/src/platforms/manifests/gemini.json +0 -8
  84. package/src/platforms/manifests/omp.json +2 -9
  85. package/src/platforms/manifests/opencode.json +28 -8
  86. package/src/platforms/native-oauth-adapters.js +351 -51
  87. package/src/platforms/oauth-credentials-service.js +344 -13
  88. package/src/server/index.js +37 -1
  89. package/src/server/services/bounded-content.js +60 -0
  90. package/src/server/services/channel-balance.js +10 -4
  91. package/src/server/services/config-export-service.js +2 -2
  92. package/src/server/services/config-templates-service.js +5 -1
  93. package/src/server/services/plugins-service.js +162 -85
  94. package/src/server/services/session-history-maintenance-worker.js +71 -0
  95. package/src/server/services/session-history-maintenance.js +166 -0
  96. package/src/server/services/skill-service.js +23 -3
  97. package/src/server/services/speed-test.js +0 -72
  98. package/src/shared/channel-driver.js +16 -0
  99. package/src/shared/driver-factories/api.js +1 -0
  100. package/src/utils/native-config-patcher.js +474 -0
  101. package/dist/web/assets/AgentsDrawer-DRQuwi0m.js +0 -1
  102. package/dist/web/assets/Analytics-Cf5KwEdj.js +0 -1
  103. package/dist/web/assets/AssetPathField-DyniM0pF.js +0 -1
  104. package/dist/web/assets/CommandsDrawer-CzHelf56.js +0 -1
  105. package/dist/web/assets/ConfigExportDrawer-BEZ8wTby.js +0 -1
  106. package/dist/web/assets/ConfigTemplates-Crg3xWe5.js +0 -1
  107. package/dist/web/assets/ConfigTemplatesPanel-lTdutC8H.js +0 -1
  108. package/dist/web/assets/FavoritesDrawer-DDyWUBJR.js +0 -1
  109. package/dist/web/assets/GatewayConvertDrawer-Rigtt_5J.js +0 -1
  110. package/dist/web/assets/Home-tCSKmSHV.js +0 -1
  111. package/dist/web/assets/McpDrawer-CmE-d7VW.js +0 -1
  112. package/dist/web/assets/McpFormDrawer-ByvS18od.js +0 -1
  113. package/dist/web/assets/PluginsPanel-BCoEs7Og.js +0 -1
  114. package/dist/web/assets/ProjectList-BJt1OIaI.js +0 -1
  115. package/dist/web/assets/ProjectList-DG3yu8xZ.css +0 -1
  116. package/dist/web/assets/PromptsDrawer-DnwBf_oW.js +0 -1
  117. package/dist/web/assets/RecentSessionsDrawer-B7d-38wH.js +0 -1
  118. package/dist/web/assets/SessionCard-BUgjHQwX.js +0 -1
  119. package/dist/web/assets/SessionList-B-bXZRFk.js +0 -1
  120. package/dist/web/assets/SettingsDrawer-BITzjQLl.js +0 -1
  121. package/dist/web/assets/SkillsPanel-BKIVOj7n.js +0 -1
  122. package/dist/web/assets/SpeedTestDrawer-Bx1bYf5i.js +0 -1
  123. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +0 -1
  124. package/dist/web/assets/Upload-CzC4rGI4.js +0 -1
  125. package/dist/web/assets/WorkspacePanel-Cql5qE2R.js +0 -1
  126. package/dist/web/assets/client-UDwXBP9i.js +0 -1
  127. package/dist/web/assets/headers-BqDmkMjy.js +0 -1
  128. package/dist/web/assets/index-Cmmwj3Fx.js +0 -2
  129. package/dist/web/assets/index-Cnbe696C.css +0 -1
  130. package/dist/web/assets/platforms-BmzzwnSw.js +0 -1
  131. package/dist/web/assets/platforms-DWXgmy2w.js +0 -1
  132. package/dist/web/assets/project-config-B2baPzYL.js +0 -1
  133. package/dist/web/assets/sessions-DqlbocLJ.js +0 -1
  134. package/dist/web/assets/use-message-DqCwefG6.js +0 -1
@@ -0,0 +1,474 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const crypto = require('crypto');
6
+ const jsonc = require('jsonc-parser');
7
+ const YAML = require('yaml');
8
+ const toml = require('toml');
9
+ const tomlStringify = require('@iarna/toml').stringify;
10
+
11
+ function isPlainObject(value) {
12
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
13
+ }
14
+
15
+ function valuesEqual(left, right) {
16
+ if (left === right) return true;
17
+ if (left instanceof Date || right instanceof Date) {
18
+ if (left instanceof Date && right instanceof Date) return left.getTime() === right.getTime();
19
+ const date = left instanceof Date ? left : right;
20
+ const scalar = left instanceof Date ? right : left;
21
+ return typeof scalar === 'string'
22
+ && Number.isFinite(Date.parse(scalar))
23
+ && Date.parse(scalar) === date.getTime();
24
+ }
25
+ if (Array.isArray(left) || Array.isArray(right)) {
26
+ return Array.isArray(left) && Array.isArray(right)
27
+ && left.length === right.length
28
+ && left.every((value, index) => valuesEqual(value, right[index]));
29
+ }
30
+ if (isPlainObject(left) || isPlainObject(right)) {
31
+ if (!isPlainObject(left) || !isPlainObject(right)) return false;
32
+ const leftKeys = Object.keys(left);
33
+ const rightKeys = Object.keys(right);
34
+ return leftKeys.length === rightKeys.length
35
+ && leftKeys.every(key => Object.prototype.hasOwnProperty.call(right, key)
36
+ && valuesEqual(left[key], right[key]));
37
+ }
38
+ return false;
39
+ }
40
+
41
+ function cloneConfigValue(value) {
42
+ if (value instanceof Date) return new Date(value.getTime());
43
+ if (Array.isArray(value)) return value.map(cloneConfigValue);
44
+ if (isPlainObject(value)) {
45
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, cloneConfigValue(entry)]));
46
+ }
47
+ return value;
48
+ }
49
+
50
+ function ensureParent(filePath) {
51
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
52
+ }
53
+
54
+ function writeContent(filePath, content, options = {}) {
55
+ ensureParent(filePath);
56
+ if (!options.atomic) {
57
+ fs.writeFileSync(filePath, content, 'utf8');
58
+ } else {
59
+ const mode = options.mode !== undefined
60
+ ? options.mode
61
+ : (fs.existsSync(filePath) ? fs.statSync(filePath).mode & 0o777 : 0o600);
62
+ const temporary = `${filePath}.ctx-tmp-${process.pid}-${crypto.randomBytes(6).toString('hex')}`;
63
+ try {
64
+ fs.writeFileSync(temporary, content, { encoding: 'utf8', mode });
65
+ if (process.platform !== 'win32') fs.chmodSync(temporary, mode);
66
+ fs.renameSync(temporary, filePath);
67
+ } finally {
68
+ try { if (fs.existsSync(temporary)) fs.unlinkSync(temporary); } catch (_) {}
69
+ }
70
+ }
71
+ if (options.mode !== undefined && process.platform !== 'win32') {
72
+ fs.chmodSync(filePath, options.mode);
73
+ }
74
+ }
75
+
76
+ function parseJsonc(content, filePath = 'config.json') {
77
+ const errors = [];
78
+ const value = jsonc.parse(content, errors, { allowTrailingComma: true, disallowComments: false });
79
+ if (errors.length > 0) {
80
+ const details = errors.map(error => jsonc.printParseErrorCode(error.error)).join(', ');
81
+ throw new Error(`Failed to parse ${path.basename(filePath)}: ${details}`);
82
+ }
83
+ if (!isPlainObject(value)) {
84
+ throw new Error(`${path.basename(filePath)} must contain a JSON object`);
85
+ }
86
+ return value;
87
+ }
88
+
89
+ function reconcileJsonc(content, current, desired, filePath) {
90
+ let output = content;
91
+ const changes = [];
92
+
93
+ function visit(before, after, nodePath) {
94
+ if (valuesEqual(before, after)) return;
95
+ if (isPlainObject(before) && isPlainObject(after)) {
96
+ Object.keys(before).forEach((key) => {
97
+ if (!Object.prototype.hasOwnProperty.call(after, key)) {
98
+ changes.push({ path: [...nodePath, key], value: undefined });
99
+ }
100
+ });
101
+ Object.keys(after).forEach((key) => {
102
+ if (!Object.prototype.hasOwnProperty.call(before, key)) {
103
+ changes.push({ path: [...nodePath, key], value: after[key] });
104
+ } else {
105
+ visit(before[key], after[key], [...nodePath, key]);
106
+ }
107
+ });
108
+ return;
109
+ }
110
+ changes.push({ path: nodePath, value: after });
111
+ }
112
+
113
+ visit(current, desired, []);
114
+ for (const change of changes) {
115
+ const edits = jsonc.modify(output, change.path, change.value, {
116
+ formattingOptions: {
117
+ insertSpaces: true,
118
+ tabSize: 2,
119
+ eol: output.includes('\r\n') ? '\r\n' : '\n'
120
+ }
121
+ });
122
+ output = jsonc.applyEdits(output, edits);
123
+ }
124
+ return output;
125
+ }
126
+
127
+ function updateJsoncFile(filePath, mutate, options = {}) {
128
+ const exists = fs.existsSync(filePath);
129
+ const original = exists ? fs.readFileSync(filePath, 'utf8') : '{}\n';
130
+ const current = original.trim() ? parseJsonc(original, filePath) : {};
131
+ const desired = cloneConfigValue(current);
132
+ mutate(desired);
133
+ const output = reconcileJsonc(original, current, desired, filePath);
134
+ if (output !== original) {
135
+ writeContent(filePath, output, options);
136
+ }
137
+ return desired;
138
+ }
139
+
140
+ function readJsoncFile(filePath, fallback = {}) {
141
+ if (!fs.existsSync(filePath)) return JSON.parse(JSON.stringify(fallback));
142
+ const original = fs.readFileSync(filePath, 'utf8');
143
+ if (!original.trim()) return JSON.parse(JSON.stringify(fallback));
144
+ return parseJsonc(original, filePath);
145
+ }
146
+
147
+ function writeJsoncFile(filePath, value, options = {}) {
148
+ return updateJsoncFile(filePath, (current) => {
149
+ Object.keys(current).forEach(key => delete current[key]);
150
+ Object.assign(current, cloneConfigValue(value || {}));
151
+ }, options);
152
+ }
153
+
154
+ function reconcileYamlDocument(document, current, desired, nodePath = []) {
155
+ if (valuesEqual(current, desired)) return;
156
+ if (isPlainObject(current) && isPlainObject(desired)) {
157
+ Object.keys(current).forEach((key) => {
158
+ if (!Object.prototype.hasOwnProperty.call(desired, key)) {
159
+ document.deleteIn([...nodePath, key]);
160
+ }
161
+ });
162
+ Object.keys(desired).forEach((key) => {
163
+ if (!Object.prototype.hasOwnProperty.call(current, key)) {
164
+ document.setIn([...nodePath, key], desired[key]);
165
+ } else {
166
+ reconcileYamlDocument(document, current[key], desired[key], [...nodePath, key]);
167
+ }
168
+ });
169
+ return;
170
+ }
171
+ document.setIn(nodePath, desired);
172
+ }
173
+
174
+ function updateYamlFile(filePath, mutate, options = {}) {
175
+ const exists = fs.existsSync(filePath);
176
+ const original = exists ? fs.readFileSync(filePath, 'utf8') : '{}\n';
177
+ const document = YAML.parseDocument(original, {
178
+ keepSourceTokens: true,
179
+ prettyErrors: true,
180
+ customTags: options.customTags
181
+ });
182
+ if (document.errors.length > 0) {
183
+ throw new Error(`Failed to parse ${path.basename(filePath)}: ${document.errors[0].message}`);
184
+ }
185
+ let current = document.toJS({ mapAsMap: false });
186
+ if (current === undefined || current === null) current = {};
187
+ else if (!isPlainObject(current)) {
188
+ throw new Error(`${path.basename(filePath)} must contain a YAML mapping`);
189
+ }
190
+ const desired = cloneConfigValue(current);
191
+ mutate(desired);
192
+ if (valuesEqual(current, desired)) return desired;
193
+ reconcileYamlDocument(document, current, desired);
194
+ const output = document.toString({ lineWidth: 120 });
195
+ writeContent(filePath, output, options);
196
+ return desired;
197
+ }
198
+
199
+ function writeYamlFile(filePath, value, options = {}) {
200
+ return updateYamlFile(filePath, (current) => {
201
+ Object.keys(current).forEach(key => delete current[key]);
202
+ Object.assign(current, cloneConfigValue(value || {}));
203
+ }, options);
204
+ }
205
+
206
+ function findTomlCommentStart(line) {
207
+ let quote = '';
208
+ let escaped = false;
209
+ for (let index = 0; index < line.length; index += 1) {
210
+ const char = line[index];
211
+ if (escaped) { escaped = false; continue; }
212
+ if (char === '\\' && quote === '"') { escaped = true; continue; }
213
+ if ((char === '"' || char === "'") && (!quote || quote === char)) {
214
+ quote = quote ? '' : char;
215
+ continue;
216
+ }
217
+ if (char === '#' && !quote) return index;
218
+ }
219
+ return -1;
220
+ }
221
+
222
+ function stripTomlComment(line) {
223
+ const commentIndex = findTomlCommentStart(line);
224
+ return commentIndex < 0 ? line : line.slice(0, commentIndex);
225
+ }
226
+
227
+ function tomlHeaderProviderKey(line) {
228
+ const header = stripTomlComment(line).trim();
229
+ const match = header.match(/^\[\s*model_providers\s*\.\s*(?:"((?:\\.|[^"\\])*)"|'([^']*)'|([A-Za-z0-9_-]+))\s*\]$/);
230
+ if (!match) return null;
231
+ if (match[1] !== undefined) {
232
+ try { return JSON.parse(`"${match[1]}"`); } catch (_) { return null; }
233
+ }
234
+ return match[2] !== undefined ? match[2] : match[3];
235
+ }
236
+
237
+ function isNestedTomlProviderSection(line, providerKey) {
238
+ const escaped = String(providerKey).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
239
+ return new RegExp(`^\\s*\\[\\s*model_providers\\s*\\.\\s*(?:"${escaped}"|'${escaped}'|${escaped})\\s*\\.`)
240
+ .test(stripTomlComment(line).trimEnd());
241
+ }
242
+
243
+ function preserveTomlSectionPreamble(lines, sectionStart, nextSectionStart) {
244
+ let boundary = nextSectionStart;
245
+ while (boundary > sectionStart + 1) {
246
+ const line = lines[boundary - 1].trim();
247
+ if (line === '' || line.startsWith('#')) boundary -= 1;
248
+ else break;
249
+ }
250
+ return boundary;
251
+ }
252
+
253
+ function patchTomlProvider(content, providerKey, providerValue, eol) {
254
+ const lines = content.split(/(?<=\n)/);
255
+ const starts = [];
256
+ lines.forEach((line, index) => {
257
+ const parsedKey = tomlHeaderProviderKey(line.replace(/\r?\n$/, ''));
258
+ if (parsedKey === providerKey) starts.push(index);
259
+ });
260
+ const start = starts[0];
261
+
262
+ if (providerValue === undefined) {
263
+ if (start === undefined) return content;
264
+ let end = start + 1;
265
+ while (end < lines.length) {
266
+ if (!/^\s*\[(?!\[).+\]\s*(?:#.*)?(?:\r?\n)?$/.test(lines[end])) {
267
+ end += 1;
268
+ continue;
269
+ }
270
+ if (isNestedTomlProviderSection(lines[end], providerKey)) {
271
+ end += 1;
272
+ continue;
273
+ }
274
+ break;
275
+ }
276
+ end = preserveTomlSectionPreamble(lines, start, end);
277
+ lines.splice(start, end - start);
278
+ return lines.join('');
279
+ }
280
+
281
+ const generated = tomlStringify({ model_providers: { [providerKey]: providerValue } });
282
+ const generatedLines = generated.split(/(?<=\n)/);
283
+ const sectionStart = generatedLines.findIndex(line => tomlHeaderProviderKey(line.replace(/\r?\n$/, '')) === providerKey);
284
+ if (sectionStart < 0) throw new Error(`Failed to serialize Codex provider ${providerKey}`);
285
+ const section = generatedLines.slice(sectionStart).join('').trimEnd();
286
+
287
+ if (start !== undefined) {
288
+ let end = start + 1;
289
+ while (end < lines.length) {
290
+ if (!/^\s*\[(?!\[).+\]\s*(?:#.*)?(?:\r?\n)?$/.test(lines[end])) {
291
+ end += 1;
292
+ continue;
293
+ }
294
+ if (isNestedTomlProviderSection(lines[end], providerKey)) {
295
+ end += 1;
296
+ continue;
297
+ }
298
+ break;
299
+ }
300
+ const replaceEnd = preserveTomlSectionPreamble(lines, start, end);
301
+ const preservedComments = lines.slice(start, replaceEnd)
302
+ .map((line) => {
303
+ const withoutNewline = line.replace(/\r?\n$/, '');
304
+ const commentIndex = findTomlCommentStart(withoutNewline);
305
+ return commentIndex < 0 ? '' : withoutNewline.slice(commentIndex).trim();
306
+ })
307
+ .filter(Boolean);
308
+ const commentText = preservedComments.length > 0
309
+ ? `${eol}${preservedComments.join(eol)}`
310
+ : '';
311
+ lines.splice(start, replaceEnd - start, `${section}${commentText}${eol}`);
312
+ return lines.join('');
313
+ }
314
+
315
+ let output = content;
316
+ if (output && !output.endsWith('\n')) output += eol;
317
+ if (output && !output.endsWith(`${eol}${eol}`)) output += eol;
318
+ return `${output}${section}${eol}`;
319
+ }
320
+
321
+ function writeTomlFile(filePath, desired, options = {}) {
322
+ const exists = fs.existsSync(filePath);
323
+ const original = exists ? fs.readFileSync(filePath, 'utf8') : '';
324
+ let current = {};
325
+ if (original.trim()) {
326
+ try {
327
+ current = toml.parse(original);
328
+ } catch (error) {
329
+ throw new Error(`Failed to parse ${path.basename(filePath)}: ${error.message}`);
330
+ }
331
+ }
332
+ const before = current && typeof current === 'object' ? current : {};
333
+ const after = desired && typeof desired === 'object' ? desired : {};
334
+ const allowed = new Set(['model_provider', 'model_providers']);
335
+ const otherKeys = new Set([...Object.keys(before), ...Object.keys(after)]);
336
+ otherKeys.forEach(key => {
337
+ if (!allowed.has(key) && !valuesEqual(before[key], after[key])) {
338
+ throw new Error(`Refusing to rewrite unrelated TOML field "${key}" in ${path.basename(filePath)}`);
339
+ }
340
+ });
341
+
342
+ const eol = original.includes('\r\n') ? '\r\n' : '\n';
343
+ let output = original;
344
+ const hasCurrentProvider = Object.prototype.hasOwnProperty.call(before, 'model_provider');
345
+ const hasDesiredProvider = Object.prototype.hasOwnProperty.call(after, 'model_provider');
346
+ const providerChanged = hasCurrentProvider !== hasDesiredProvider
347
+ || (hasCurrentProvider && before.model_provider !== after.model_provider);
348
+ if (providerChanged) {
349
+ const rootLines = output.split(/(?<=\n)/);
350
+ const headerIndex = rootLines.findIndex(line => /^\s*\[(?!\[).+\]/.test(line));
351
+ const rootEnd = headerIndex < 0 ? rootLines.length : headerIndex;
352
+ const settingIndex = rootLines.slice(0, rootEnd).findIndex(line => /^\s*model_provider\s*=/.test(line));
353
+ if (hasDesiredProvider) {
354
+ const serialized = tomlStringify({ model_provider: after.model_provider }).trimEnd();
355
+ if (settingIndex >= 0) {
356
+ const line = rootLines[settingIndex];
357
+ const newline = line.match(/\r?\n$/)?.[0] || '';
358
+ const assignment = line.replace(/\r?\n$/, '');
359
+ let commentIndex = -1;
360
+ let quoted = false;
361
+ let escaped = false;
362
+ for (let index = 0; index < assignment.length; index += 1) {
363
+ const char = assignment[index];
364
+ if (escaped) { escaped = false; continue; }
365
+ if (char === '\\' && quoted) { escaped = true; continue; }
366
+ if (char === '"') { quoted = !quoted; continue; }
367
+ if (char === '#' && !quoted) { commentIndex = index; break; }
368
+ }
369
+ const suffix = commentIndex >= 0 ? ` ${assignment.slice(commentIndex)}` : '';
370
+ const prefix = assignment.slice(0, assignment.indexOf('=') + 1);
371
+ rootLines[settingIndex] = `${prefix} ${serialized.slice(serialized.indexOf('=') + 1).trim()}${suffix}${newline}`;
372
+ } else {
373
+ const insertion = `${serialized}${eol}`;
374
+ rootLines.splice(rootEnd, 0, `${insertion}${rootEnd < rootLines.length ? eol : ''}`);
375
+ }
376
+ } else if (settingIndex >= 0) {
377
+ const line = rootLines[settingIndex];
378
+ const commentIndex = line.indexOf('#');
379
+ if (commentIndex >= 0) rootLines[settingIndex] = `${line.slice(commentIndex).trimStart()}`;
380
+ else rootLines.splice(settingIndex, 1);
381
+ }
382
+ output = rootLines.join('');
383
+ }
384
+
385
+ const currentProviders = isPlainObject(before.model_providers) ? before.model_providers : {};
386
+ const desiredProviders = isPlainObject(after.model_providers) ? after.model_providers : {};
387
+ const providerKeys = new Set([...Object.keys(currentProviders), ...Object.keys(desiredProviders)]);
388
+ for (const key of providerKeys) {
389
+ if (valuesEqual(currentProviders[key], desiredProviders[key])) continue;
390
+ output = patchTomlProvider(output, key, Object.prototype.hasOwnProperty.call(desiredProviders, key)
391
+ ? desiredProviders[key]
392
+ : undefined, eol);
393
+ }
394
+ if (output !== original) writeContent(filePath, output, options);
395
+ return after;
396
+ }
397
+
398
+ function encodeEnvValue(value) {
399
+ const text = String(value ?? '');
400
+ if (!/[\s#'"\\]/.test(text) && !text.startsWith('=') && !text.endsWith('\r')) return text;
401
+ return JSON.stringify(text);
402
+ }
403
+
404
+ function findEnvComment(value) {
405
+ let quote = '';
406
+ let escaped = false;
407
+ for (let index = 0; index < value.length; index += 1) {
408
+ const char = value[index];
409
+ if (escaped) { escaped = false; continue; }
410
+ if (char === '\\' && quote === '"') { escaped = true; continue; }
411
+ if ((char === '"' || char === "'") && (!quote || quote === char)) {
412
+ quote = quote ? '' : char;
413
+ continue;
414
+ }
415
+ if (char === '#' && !quote && index > 0 && /\s/.test(value[index - 1])) {
416
+ let start = index;
417
+ while (start > 0 && /\s/.test(value[start - 1])) start -= 1;
418
+ return value.slice(start);
419
+ }
420
+ }
421
+ return '';
422
+ }
423
+
424
+ function updateEnvFile(filePath, updates, options = {}) {
425
+ const exists = fs.existsSync(filePath);
426
+ const original = exists ? fs.readFileSync(filePath, 'utf8') : '';
427
+ const eol = original.includes('\r\n') ? '\r\n' : '\n';
428
+ const lines = original.split(/\r?\n/);
429
+ const keys = new Set(Object.keys(updates || {}));
430
+ const seen = new Set();
431
+ const output = [];
432
+
433
+ for (const line of lines) {
434
+ const match = line.match(/^(\s*(?:export\s+)?)([A-Za-z_][A-Za-z0-9_]*)\s*=([^\r\n]*)$/);
435
+ if (!match || !keys.has(match[2])) {
436
+ output.push(line);
437
+ continue;
438
+ }
439
+ const [, prefix, key] = match;
440
+ const value = updates[key];
441
+ const rawValue = match[3];
442
+ const comment = findEnvComment(rawValue);
443
+ if (value === undefined || value === null) {
444
+ if (comment) output.push(comment.trimStart());
445
+ continue;
446
+ }
447
+ output.push(`${prefix}${key}=${encodeEnvValue(value)}${comment ? ` ${comment.trimStart()}` : ''}`);
448
+ seen.add(key);
449
+ }
450
+
451
+ const missing = [...keys].filter(key => updates[key] !== undefined && updates[key] !== null && !seen.has(key));
452
+ if (missing.length > 0) {
453
+ while (output.length > 0 && output[output.length - 1] === '') output.pop();
454
+ output.push(...missing.map(key => `${key}=${encodeEnvValue(updates[key])}`));
455
+ }
456
+
457
+ let content = output.join(eol);
458
+ if (content && !content.endsWith(eol) && (original.endsWith('\n') || missing.length > 0)) content += eol;
459
+ if (content !== original) {
460
+ writeContent(filePath, content, options);
461
+ }
462
+ return content;
463
+ }
464
+
465
+ module.exports = {
466
+ parseJsonc,
467
+ readJsoncFile,
468
+ writeJsoncFile,
469
+ updateJsoncFile,
470
+ updateYamlFile,
471
+ writeYamlFile,
472
+ writeTomlFile,
473
+ updateEnvFile
474
+ };
@@ -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 c,Y as d,Z as r,_t as p,b as v,et as f,g,ht as m,m as y,mt as h,r as b,st as k,w as _,x as w}from"./vue-vendor-BqZbbXHA.js";import{n as C}from"./client-UDwXBP9i.js";import{r as j,s as x,t as M}from"./platforms-DWXgmy2w.js";import{C as z,H as P,M as N,Pt as U,_ as F,et as I,h as $,jt as O,k as B,p as D,v as L,z as S}from"./icons-DmFe4b5j.js";import{l as q}from"./light-0eavxNvt.js";import{a as R,c as A,i as T,o as E,r as V,s as H,t as G}from"./AssetPathField-DyniM0pF.js";import{n as W,t as Y}from"./useResponsiveDrawer-DZd5rNk5.js";import{t as K}from"./DrawerContent-ChXgZ1Xm.js";import{$ as Z,B as J,F as Q,I as X,N as ee,O as ae,V as le,dt as te,et as se,ft as ne,gt as ie,jt as oe,k as ue,mt as ce,rt as de,tt as re}from"./index-Cmmwj3Fx.js";import{t as pe}from"./MarkdownEditor-BMMUufSc.js";async function ve(e=null,a="claude",l={}){const t=ae("agents",a,l.scope||"",e||"");return ue(t,l=>C.get("/agents",{params:e?{projectPath:e,platform:a}:{platform:a},signal:l}).then(e=>e.data),"agents",`agents:${a}`)}var fe={class:"asset-card-main"},ge={class:"asset-card-top"},me={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"},_e={class:"asset-meta"},we={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 r=l,b=u,{byCapability:k}=oe(),C=v(()=>k("agents"));return(u,v)=>{return c(),_("div",{class:m(["agent-card asset-card",{"is-project":"project"===l.agent.scope,"is-managed":l.registryInfo}]),onClick:v[4]||(v[4]=e=>b("click",l.agent))},[w("div",fe,[w("div",ge,[w("div",me,[w("div",ye,[w("span",{class:m(["asset-status-dot",{active:l.registryInfo?.enabled||"project"===l.agent.scope}])},null,2),w("span",he,p(l.agent.name),1)]),w("div",be,[i(h(ce),{type:"user"===l.agent.scope?"info":"success",size:"tiny",bordered:!1},{default:f(()=>[s(p("user"===l.agent.scope?"用户级":"项目级"),1)]),_:1},8,["type"]),l.registryInfo?(c(),o(h(ce),{key:0,type:"success",size:"tiny",bordered:!1},{default:f(()=>[...v[5]||(v[5]=[s("托管",-1)])]),_:1})):t("",!0),l.agent.model?(c(),o(h(ce),{key:1,type:"warning",size:"tiny",bordered:!1},{default:f(()=>[s(p(l.agent.model),1)]),_:1})):t("",!0)])])]),l.agent.description?(c(),_("div",ke,p((j=l.agent.description,j?j.length>80?j.slice(0,80)+"...":j:"")),1)):t("",!0),w("div",_e,[l.agent.tools?(c(),_("span",we,[i(h(e),{size:"12"},{default:f(()=>[i(h(P))]),_:1}),s(" "+p((k=l.agent.tools,k?k.length>30?k.slice(0,30)+"...":k:"")),1)])):t("",!0),l.agent.permissionMode?(c(),_("span",Ce,[i(h(e),{size:"12"},{default:f(()=>[i(h(D))]),_:1}),s(" "+p(l.agent.permissionMode),1)])):t("",!0)])]),w("div",je,[l.registryInfo?(c(),_(g,{key:0},[i(h(Z),{trigger:"hover"},{trigger:f(()=>[i(h(Q),{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:f(()=>[s(" "+p(l.registryInfo.enabled?"已启用":"已禁用"),1)]),_:1}),w("div",xe,[(c(!0),_(g,null,n(C.value,a=>(c(),o(h(Z),{key:a.key,trigger:"hover"},{trigger:f(()=>[w("span",{class:m(["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:f(()=>[(c(),o(d(a.icon)))]),_:2},1024)],10,Me)]),default:f(()=>[s(" "+p(a.label||a.title||a.key)+" "+p(l.registryInfo.platforms?.[a.key]?"已启用":"未启用"),1)]),_:2},1024))),128))])],64)):(c(),_(g,{key:1},[i(h(a),{size:"tiny",tertiary:"",onClick:v[2]||(v[2]=y(e=>b("edit",l.agent),["stop"]))},{default:f(()=>[...v[6]||(v[6]=[s(" 编辑 ",-1)])]),_:1}),i(h(a),{size:"tiny",tertiary:"",type:"error",loading:r.deleting,onClick:v[3]||(v[3]=y(e=>b("delete",l.agent),["stop"]))},{default:f(()=>[...v[7]||(v[7]=[s(" 删除 ",-1)])]),_:1},8,["loading"])],64))])],2);var k,j}}},[["__scopeId","data-v-044e4192"]]),Pe={class:"asset-detail-drawer-header"},Ne={class:"asset-detail-identity"},Ue={class:"asset-detail-heading"},Fe={class:"asset-detail-name"},Ie={class:"asset-detail-meta"},$e={key:2,class:"asset-detail-subtle"},Oe={class:"asset-detail-body"},Be={key:0,class:"asset-detail-loading"},De={class:"asset-detail-container"},Le={class:"asset-detail-info-section"},Se={class:"asset-detail-description"},qe={class:"asset-detail-info-section"},Re={class:"asset-detail-list"},Ae={class:"asset-detail-row"},Te={class:"asset-detail-value"},Ee={key:0,class:"asset-detail-row"},Ve={class:"asset-detail-value mono"},He={key:1,class:"asset-detail-row"},Ge={class:"asset-detail-value mono"},We={key:2,class:"asset-detail-row"},Ye={class:"asset-detail-value"},Ke={key:3,class:"asset-detail-row"},Ze={class:"asset-detail-value"},Je={key:4,class:"asset-detail-row"},Qe={class:"asset-detail-value"},Xe={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,d=l,r=v({get:()=>u.visible,set:e=>d("update:visible",e)}),g={height:"100%",minHeight:0,overflow:"hidden"},m=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)=>(c(),o(h(W),{show:r.value,"onUpdate:show":u[0]||(u[0]=e=>r.value=e),width:h(n),placement:"right","show-mask":!0},{default:f(()=>[i(h(K),{closable:"","native-scrollbar":!1,"body-content-style":g},{header:f(()=>[w("div",Pe,[w("div",Ne,[i(h(e),{size:20,class:"asset-detail-icon"},{default:f(()=>[i(h(B))]),_:1}),w("div",Ue,[w("span",Fe,p(a.agent?.name||"代理详情"),1),w("div",Ie,[a.agent?.scope?(c(),o(h(ce),{key:0,type:"project"===a.agent.scope?"success":"info",size:"tiny",bordered:!1},{default:f(()=>[s(p(C(a.agent.scope)),1)]),_:1},8,["type"])):t("",!0),a.agent?.model?(c(),o(h(ce),{key:1,type:"warning",size:"tiny",bordered:!1},{default:f(()=>[s(p(a.agent.model),1)]),_:1})):t("",!0),m.value?(c(),_("span",$e,p(m.value),1)):t("",!0)])])])])]),default:f(()=>[w("div",Oe,[a.loading&&!a.agent?(c(),_("div",Be,[i(h(X),{size:"medium"}),u[1]||(u[1]=w("p",null,"加载代理详情中...",-1))])):a.agent?(c(),o(h(H),{key:1,type:"line",animated:"",class:"asset-detail-tabs"},{default:f(()=>[i(h(A),{name:"overview",tab:"概览"},{default:f(()=>[w("div",De,["codex"===a.platform&&a.agent.configReadError?(c(),o(h(ne),{key:0,type:"warning",bordered:!1},{default:f(()=>[s(p(a.agent.configReadError),1)]),_:1})):t("",!0),w("div",Le,[u[2]||(u[2]=w("h3",{class:"asset-detail-section-title"},"描述",-1)),w("p",Se,p(a.agent.description||"暂无描述"),1)]),w("div",qe,[u[9]||(u[9]=w("h3",{class:"asset-detail-section-title"},"基础信息",-1)),w("div",Re,[w("div",Ae,[u[3]||(u[3]=w("span",{class:"asset-detail-label"},"作用域",-1)),w("span",Te,p(C(a.agent.scope)),1)]),a.agent.fileName?(c(),_("div",Ee,[u[4]||(u[4]=w("span",{class:"asset-detail-label"},"文件名",-1)),w("span",Ve,p(y.value),1)])):t("",!0),"codex"===a.platform&&a.agent.configFile?(c(),_("div",He,[u[5]||(u[5]=w("span",{class:"asset-detail-label"},"config_file",-1)),w("span",Ge,p(a.agent.configFile),1)])):t("",!0),a.agent.model?(c(),_("div",We,[u[6]||(u[6]=w("span",{class:"asset-detail-label"},"模型",-1)),w("span",Ye,p(a.agent.model),1)])):t("",!0),a.agent.permissionMode?(c(),_("div",Ke,[u[7]||(u[7]=w("span",{class:"asset-detail-label"},"权限模式",-1)),w("span",Ze,p(a.agent.permissionMode),1)])):t("",!0),a.agent.skills?(c(),_("div",Je,[u[8]||(u[8]=w("span",{class:"asset-detail-label"},"技能",-1)),w("span",Qe,p(a.agent.skills),1)])):t("",!0)])]),a.agent.tools?(c(),_("div",Xe,[u[10]||(u[10]=w("h3",{class:"asset-detail-section-title"},"可用工具",-1)),w("div",ea,[i(h(e),{size:16},{default:f(()=>[i(h(P))]),_:1}),w("code",null,p(a.agent.tools),1)])])):t("",!0),i(G,{path:k.value},null,8,["path"])])]),_:1}),i(h(A),{name:"content",tab:"codex"===a.platform?"配置":"提示词"},{default:f(()=>[w("pre",aa,p(b.value),1)]),_:1},8,["tab"])]),_:1})):(c(),_("div",la,[i(h(e),{size:44,class:"asset-detail-empty-icon"},{default:f(()=>[i(h(I))]),_:1}),u[11]||(u[11]=w("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"},ca={class:"config-edit-title"},da={class:"config-edit-badges"},ra={class:"config-edit-section"},pa={class:"section-heading"},va={class:"field-grid"},fa={class:"scope-option"},ga={class:"scope-path"},ma={class:"scope-option"},ya={class:"scope-path"},ha={key:0,class:"platform-note"},ba={class:"config-edit-section"},ka={class:"section-heading"},_a={key:1,class:"empty-config-box"},wa={class:"field-grid"},Ca={key:0,class:"config-edit-section content-section"},ja={class:"section-heading"},xa={class:"modal-footer"},Ma=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,d=n,y=v({get:()=>u.visible,set:e=>d("update:visible",e)}),b=v(()=>!!u.agent),j=v(()=>"codex"===u.platform),x=v(()=>"claude"===u.platform),M=v(()=>"codex"===u.platform||"opencode"===u.platform),z=v(()=>b.value?"编辑代理":"创建代理"),P=v(()=>({claude:"Claude Code",codex:"Codex CLI",gemini:"Gemini CLI",opencode:"OpenCode"}[u.platform]||"Claude Code")),U=v(()=>"codex"===u.platform?"~/.codex/config.toml":"opencode"===u.platform?"~/.config/opencode/agents/":"gemini"===u.platform?"~/.gemini/agents/":"~/.claude/agents/"),F=v(()=>"opencode"===u.platform?".opencode/agents/":"gemini"===u.platform?".gemini/agents/":".claude/agents/"),O=v(()=>"project"===G.value.scope?"项目级":"用户级"),D=v(()=>H.find(e=>e.value===G.value.configMode)?.label||"配置"),R=k(null),A=k(!1),T={maxHeight:"calc(92vh - 134px)",overflowY:"auto",paddingBottom:"18px"},E=[{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"}],H=[{label:"仅描述",value:"none"},{label:"托管 TOML",value:"managed"},{label:"自定义路径",value:"custom"}],G=k({fileName:"",scope:"user",name:"",description:"",configMode:"none",configFile:"",configContent:"",tools:"",model:"",permissionMode:"",skills:"",systemPrompt:""}),W=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"===G.value.configMode,message:"请输入自定义配置文件路径",trigger:"blur"}),e});function Y(){G.value={fileName:"",scope:"user",name:"",description:"",configMode:"none",configFile:"",configContent:"",tools:"",model:"",permissionMode:"",skills:"",systemPrompt:""}}function K(){y.value=!1,Y()}async function Z(){try{await(R.value?.validate())}catch{return}A.value=!0;try{const e={...G.value,projectPath:u.projectPath};j.value?("custom"===G.value.configMode?e.configFile=G.value.configFile:delete e.configFile,"managed"===G.value.configMode||"custom"===G.value.configMode?e.configContent=G.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}(G.value.fileName,G.value.scope,e,u.platform),ee.success("代理更新成功")):(await async function(e,a="claude"){return(await C.post("/agents",{...e,platform:a})).data}(e,u.platform),ee.success("代理创建成功")),d("saved"),y.value=!1,Y()}catch(e){ee.error("操作失败: "+e.message)}finally{A.value=!1}}return r(()=>u.agent,e=>{if(e){const a=e.configMode||(e.configFile?String(e.configFile).includes("/.codex/agents/")?"managed":"custom":"none");G.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||"",permissionMode:e.permissionMode||"",skills:e.skills||"",systemPrompt:e.systemPrompt||""}}else Y()},{immediate:!0}),r(()=>u.platform,e=>{"codex"===e&&(G.value.scope="user",G.value.configMode||(G.value.configMode="none"))},{immediate:!0}),(l,n)=>(c(),o(h(q),{show:y.value,"onUpdate:show":n[13]||(n[13]=e=>y.value=e),preset:"card",title:z.value,style:{width:"min(940px, 96vw)","max-height":"92vh"},"content-style":T,"mask-closable":!1,class:"config-edit-modal"},{footer:f(()=>[w("div",xa,[i(h(a),{onClick:K},{default:f(()=>[...n[21]||(n[21]=[s("取消",-1)])]),_:1}),i(h(a),{type:"primary",loading:A.value,onClick:Z},{icon:f(()=>[i(h(e),null,{default:f(()=>[i(h(L))]),_:1})]),default:f(()=>[s(" "+p(b.value?"保存":"创建"),1)]),_:1},8,["loading"])])]),default:f(()=>[w("div",sa,[w("div",na,[w("span",ia,[i(h(e),{size:22},{default:f(()=>[i(h(B))]),_:1})]),w("div",oa,[w("span",ua,p(P.value),1),w("span",ca,p(b.value?G.value.fileName||"编辑代理":"创建新代理"),1)])]),w("div",da,[i(h(ce),{size:"small",bordered:!1,type:"info"},{default:f(()=>[s(p(O.value),1)]),_:1}),j.value?(c(),o(h(ce),{key:0,size:"small",bordered:!1,type:"success"},{default:f(()=>[...n[14]||(n[14]=[s("Codex 用户级",-1)])]),_:1})):t("",!0),j.value&&"none"!==G.value.configMode?(c(),o(h(ce),{key:1,size:"small",bordered:!1,type:"warning"},{default:f(()=>[s(p(D.value),1)]),_:1})):t("",!0)])]),i(h(le),{ref_key:"formRef",ref:R,model:G.value,rules:W.value,"label-placement":"top","require-mark-placement":"right-hanging",class:"config-edit-form"},{default:f(()=>[w("div",{class:m(["config-edit-grid",{"is-codex":j.value}])},[w("section",ra,[w("div",pa,[i(h(e),{size:16},{default:f(()=>[i(h(N))]),_:1}),n[15]||(n[15]=w("span",null,"基础信息",-1))]),w("div",va,[i(h(J),{label:"文件名",path:"fileName"},{default:f(()=>[i(h(te),{value:G.value.fileName,"onUpdate:value":n[0]||(n[0]=e=>G.value.fileName=e),disabled:b.value,placeholder:"code-reviewer"},null,8,["value","disabled"])]),_:1}),x.value?(c(),o(h(J),{key:0,label:"显示名称",path:"name"},{default:f(()=>[i(h(te),{value:G.value.name,"onUpdate:value":n[1]||(n[1]=e=>G.value.name=e),placeholder:"代理的显示名称"},null,8,["value"])]),_:1})):t("",!0)]),i(h(J),{label:"作用域",path:"scope"},{default:f(()=>[i(h(se),{value:G.value.scope,"onUpdate:value":n[2]||(n[2]=e=>G.value.scope=e),disabled:b.value,class:m(["scope-picker",{"single-option":j.value}])},{default:f(()=>[i(h(re),{value:"user"},{default:f(()=>[w("span",fa,[n[16]||(n[16]=w("span",{class:"scope-title"},"用户级",-1)),w("span",ga,p(U.value),1)])]),_:1}),j.value?t("",!0):(c(),o(h(re),{key:0,value:"project"},{default:f(()=>[w("span",ma,[n[17]||(n[17]=w("span",{class:"scope-title"},"项目级",-1)),w("span",ya,p(F.value),1)])]),_:1}))]),_:1},8,["value","disabled","class"])]),_:1}),i(h(J),{label:"描述",path:"description"},{default:f(()=>[i(h(te),{value:G.value.description,"onUpdate:value":n[3]||(n[3]=e=>G.value.description=e),type:"textarea",autosize:{minRows:3,maxRows:5},placeholder:"一句话说明这个代理什么时候该被调用"},null,8,["value"])]),_:1}),j.value?(c(),_("div",ha,[i(h(e),{size:16},{default:f(()=>[i(h(S))]),_:1}),n[18]||(n[18]=w("span",null,[s("Codex agents 写入用户级配置。描述会进入 "),w("code",null,"~/.codex/config.toml"),s(",TOML 配置可托管到 "),w("code",null,"~/.codex/agents/"),s("。")],-1))])):t("",!0)]),w("section",ba,[w("div",ka,[i(h(e),{size:16},{default:f(()=>[i(h($))]),_:1}),w("span",null,p(j.value?"运行配置":"模型与权限"),1)]),j.value?(c(),_(g,{key:0},[i(h(J),{label:"配置模式",path:"configMode"},{default:f(()=>[i(h(de),{value:G.value.configMode,"onUpdate:value":n[4]||(n[4]=e=>G.value.configMode=e),options:H,placeholder:"选择配置模式"},null,8,["value"])]),_:1}),"custom"===G.value.configMode?(c(),o(h(J),{key:0,label:"配置文件路径",path:"configFile"},{default:f(()=>[i(h(te),{value:G.value.configFile,"onUpdate:value":n[5]||(n[5]=e=>G.value.configFile=e),placeholder:"~/.omx/agents/my-agent.toml"},null,8,["value"])]),_:1})):t("",!0),"none"===G.value.configMode?(c(),_("div",_a,[i(h(e),{size:18},{default:f(()=>[i(h(I))]),_:1}),n[19]||(n[19]=w("span",null,"仅保存代理描述,不额外写入模型或工具配置。",-1))])):(c(),o(h(J),{key:2,label:"Agent Config (TOML)",path:"configContent",class:"editor-form-item"},{default:f(()=>[i(h(te),{value:G.value.configContent,"onUpdate:value":n[6]||(n[6]=e=>G.value.configContent=e),type:"textarea",autosize:{minRows:14,maxRows:22},class:"toml-editor",placeholder:'model = "gpt-5.4"'},null,8,["value"])]),_:1}))],64)):(c(),_(g,{key:1},[i(h(J),{label:"可用工具",path:"tools"},{default:f(()=>[i(h(te),{value:G.value.tools,"onUpdate:value":n[7]||(n[7]=e=>G.value.tools=e),placeholder:"Read, Edit, Bash"},null,8,["value"])]),_:1}),i(h(J),{label:"模型",path:"model"},{default:f(()=>[M.value?(c(),o(h(te),{key:0,value:G.value.model,"onUpdate:value":n[8]||(n[8]=e=>G.value.model=e),placeholder:"gpt-5, claude-sonnet-4, openrouter/model"},null,8,["value"])):(c(),o(h(de),{key:1,value:G.value.model,"onUpdate:value":n[9]||(n[9]=e=>G.value.model=e),options:E,placeholder:"选择模型",clearable:""},null,8,["value"]))]),_:1}),w("div",wa,["opencode"!==u.platform?(c(),o(h(J),{key:0,label:"权限模式",path:"permissionMode"},{default:f(()=>[i(h(de),{value:G.value.permissionMode,"onUpdate:value":n[10]||(n[10]=e=>G.value.permissionMode=e),options:V,placeholder:"选择权限模式",clearable:""},null,8,["value"])]),_:1})):t("",!0),"opencode"!==u.platform?(c(),o(h(J),{key:1,label:"技能",path:"skills"},{default:f(()=>[i(h(te),{value:G.value.skills,"onUpdate:value":n[11]||(n[11]=e=>G.value.skills=e),placeholder:"自动加载的技能,逗号分隔"},null,8,["value"])]),_:1})):t("",!0)])],64))]),j.value?t("",!0):(c(),_("section",Ca,[w("div",ja,[i(h(e),{size:16},{default:f(()=>[i(h(I))]),_:1}),n[20]||(n[20]=w("span",null,"系统提示词",-1))]),i(h(J),{path:"systemPrompt","show-label":!1,class:"editor-form-item"},{default:f(()=>[i(pe,{modelValue:G.value.systemPrompt,"onUpdate:modelValue":n[12]||(n[12]=e=>G.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-00915421"]]),za={key:0,class:"asset-panel-header"},Pa={class:"asset-title-group"},Na={class:"asset-heading"},Ua={class:"asset-title-row"},Fa={class:"asset-platform-pill"},Ia={key:0,class:"asset-action-row"},$a={key:1,class:"asset-drawer-toolbar"},Oa={key:0,class:"asset-action-row"},Ba={class:"asset-summary"},Da={class:"asset-summary-item"},La={class:"asset-summary-value"},Sa={class:"asset-summary-item"},qa={class:"asset-summary-value"},Ra={class:"asset-summary-item"},Aa={class:"asset-summary-value"},Ta={class:"asset-summary-item"},Ea={class:"asset-summary-value"},Va={class:"asset-filter-bar"},Ha={class:"asset-panel-content"},Ga={key:0,class:"asset-empty"},Wa={key:1,class:"asset-list"},Ya={class:"asset-footer"},Ka=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:d}){const y=l,P=d,N=M(),I=b(),$=k([]),D=k(!1),L=k(""),q=k("all"),A=k(!1),H=k(!1),G=k(null),W=k(!1),Y=k(null),K=k({}),Z=k({}),J=k({});let Q=0;const{byCapability:le}=oe(),se=v(()=>le("agents").map(e=>e.key)),ne=v(()=>se.value.includes(ce.value)),ce=v(()=>String(y.platform||j(I)||"").trim().toLowerCase()),re=v(()=>"opencode"===ce.value?"使用 @agent 或 Task 在 OpenCode 中调用":"gemini"===ce.value?"使用 @agent 调用 Gemini 自定义代理":"使用 Task tool 调用自定义代理"),pe=v(()=>{const e=N.get(ce.value)||x(ce.value);return e.label||e.title||"Claude Code"}),fe=[{label:"全部",value:"all"},{label:"用户级",value:"user"},{label:"项目级",value:"project"},{label:"已托管",value:"managed"}],ge=v(()=>$.value.filter(e=>"user"===e.scope).length),me=v(()=>$.value.filter(e=>"project"===e.scope).length),ye=v(()=>Object.keys(Z.value).length);function he(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 be(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(Z.value[l])return l;return a[0]||""}const ke=v(()=>{let e=$.value;if("user"===q.value?e=e.filter(e=>"user"===e.scope):"project"===q.value?e=e.filter(e=>"project"===e.scope):"managed"===q.value&&(e=e.filter(e=>Z.value[be(e)])),L.value.trim()){const a=L.value.toLowerCase();e=e.filter(e=>e.name?.toLowerCase().includes(a)||e.description?.toLowerCase().includes(a)||e.fileName?.toLowerCase().includes(a))}return e}),_e=v(()=>L.value?"没有匹配的代理":"user"===q.value?"暂无用户级代理":"project"===q.value?"暂无项目级代理":"managed"===q.value?"暂无托管的代理":ne.value?"暂无自定义代理":`${pe.value} 暂未提供 Agents 能力`);async function we(){if(!ne.value)return $.value=[],Z.value={},void(D.value=!1);D.value=!0;try{const[e,a]=await Promise.all([ve(y.projectPath,ce.value),V("agents",{platform:ce.value,projectPath:y.projectPath})]);if(e.success&&($.value=e.agents||[]),a.success){Z.value={};for(const[e,l]of Object.entries(a.items||{}))Z.value[e]=l}}catch(e){ee.error("加载代理列表失败: "+e.message)}finally{D.value=!1}}async function Ce(e,a){const l=be(e);if(l){J.value[l]=!0;try{(await R("agents",l,a)).success&&(ee.success(a?"已启用":"已禁用"),await we())}catch(t){ee.error("切换失败: "+t.message)}finally{delete J.value[l]}}else ee.error("未找到代理对应的托管配置键")}async function je(e,a,l){const t=be(e);if(t){J.value[t]=!0;try{(await E("agents",t,a,l)).success&&(ee.success(`${a} ${l?"已启用":"已禁用"}`),await we())}catch(s){ee.error("切换失败: "+s.message)}finally{delete J.value[t]}}else ee.error("未找到代理对应的托管配置键")}async function xe(){D.value=!0;try{const e=await T("agents");e?.success||ee.warning(e?.message||"同步失败,已继续刷新列表")}catch(e){ee.warning("同步失败,已继续刷新列表: "+e.message)}await we()}function Me(){Y.value=null,A.value=!0}function Pe(e){A.value=e,e||(Y.value=null)}function Ne(e){Fe(e,!0)}async function Ue(e){const a=he(e);K.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,ce.value)).success&&(ee.success("代理已删除"),await we(),P("updated"))}catch(l){ee.error("删除失败: "+l.message)}finally{delete K.value[a]}}async function Fe(e,a=!1){if(!e)return;const l=++Q;W.value=!0,a||(G.value=null,H.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=ae(`agent-detail:${e}`,t,a||"",l||"");return ue(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,ce.value);if(l!==Q)return;const s=t?.agent||e;a?(Y.value=s,A.value=!0):G.value=s}catch(t){if(l!==Q)return;ee.error("加载代理详情失败: "+t.message),a?(Y.value=e,A.value=!0):G.value=e}finally{l===Q&&(W.value=!1)}}function Ie(e){Fe(e,!1)}function $e(){Y.value=null,we(),P("updated")}function Oe(){P("back")}return u(()=>{we()}),r(ce,()=>{Q+=1,W.value=!1,G.value=null,we()}),(u,d)=>(c(),_("div",{class:m(["agents-panel asset-panel",{"in-drawer":y.inDrawer}])},[y.inDrawer?t("",!0):(c(),_("div",za,[w("div",Pa,[y.hideBack?t("",!0):(c(),o(h(a),{key:0,text:"",onClick:Oe,class:"back-btn"},{icon:f(()=>[i(h(e),null,{default:f(()=>[i(h(O))]),_:1})]),_:1})),w("div",Na,[w("div",Ua,[d[3]||(d[3]=w("span",{class:"asset-title"},"代理管理",-1)),w("span",Fa,p(pe.value),1)]),d[4]||(d[4]=w("div",{class:"asset-subtitle"},"维护自定义代理、工具权限和平台启用状态",-1))])]),ne.value?(c(),_("div",Ia,[i(h(a),{text:"",onClick:Me,class:"action-btn"},{icon:f(()=>[i(h(e),null,{default:f(()=>[i(h(U))]),_:1})]),default:f(()=>[d[5]||(d[5]=s(" 创建 ",-1))]),_:1}),i(h(a),{text:"",onClick:xe,loading:D.value,class:"action-btn"},{icon:f(()=>[i(h(e),null,{default:f(()=>[i(h(z))]),_:1})]),default:f(()=>[d[6]||(d[6]=s(" 刷新 ",-1))]),_:1},8,["loading"])])):t("",!0)])),y.inDrawer?(c(),_("div",$a,[ne.value?(c(),_("div",Oa,[i(h(a),{text:"",onClick:Me,class:"action-btn"},{icon:f(()=>[i(h(e),null,{default:f(()=>[i(h(U))]),_:1})]),default:f(()=>[d[7]||(d[7]=s(" 创建 ",-1))]),_:1}),i(h(a),{text:"",onClick:xe,loading:D.value,class:"action-btn"},{icon:f(()=>[i(h(e),null,{default:f(()=>[i(h(z))]),_:1})]),default:f(()=>[d[8]||(d[8]=s(" 刷新 ",-1))]),_:1},8,["loading"])])):t("",!0)])):t("",!0),w("div",Ba,[w("span",Da,[d[9]||(d[9]=w("span",{class:"asset-summary-label"},"全部",-1)),w("span",La,p($.value.length),1)]),w("span",Sa,[d[10]||(d[10]=w("span",{class:"asset-summary-label"},"用户级",-1)),w("span",qa,p(ge.value),1)]),w("span",Ra,[d[11]||(d[11]=w("span",{class:"asset-summary-label"},"项目级",-1)),w("span",Aa,p(me.value),1)]),w("span",Ta,[d[12]||(d[12]=w("span",{class:"asset-summary-label"},"托管",-1)),w("span",Ea,p(ye.value),1)])]),w("div",Va,[i(h(te),{value:L.value,"onUpdate:value":d[0]||(d[0]=e=>L.value=e),placeholder:"搜索代理、描述或文件名",clearable:"",size:"small",class:"asset-search"},{prefix:f(()=>[i(h(e),null,{default:f(()=>[i(h(F))]),_:1})]),_:1},8,["value"]),i(h(de),{value:q.value,"onUpdate:value":d[1]||(d[1]=e=>q.value=e),options:fe,size:"small",class:"asset-filter"},null,8,["value"])]),w("div",Ha,[i(h(X),{show:D.value},{default:f(()=>[0!==ke.value.length||D.value?(c(),_("div",Wa,[(c(!0),_(g,null,n(ke.value,e=>(c(),o(ze,{key:he(e),agent:e,deleting:!!K.value[he(e)],"registry-info":Z.value[be(e)],toggling:!!J.value[be(e)],onEdit:Ne,onDelete:Ue,onClick:Ie,onToggleEnabled:Ce,onTogglePlatform:je},null,8,["agent","deleting","registry-info","toggling"]))),128))])):(c(),_("div",Ga,[i(h(ie),{description:_e.value},{icon:f(()=>[i(h(e),{size:"48",color:"var(--text-quaternary)"},{default:f(()=>[i(h(B))]),_:1})]),extra:f(()=>[ne.value?(c(),o(h(a),{key:0,size:"small",onClick:Me},{default:f(()=>[...d[13]||(d[13]=[s(" 创建第一个代理 ",-1)])]),_:1})):t("",!0)]),_:1},8,["description"])]))]),_:1},8,["show"])]),w("div",Ya,[i(h(e),{size:"14",class:"asset-info-icon"},{default:f(()=>[i(h(S))]),_:1}),w("span",null,p(re.value),1)]),i(Ma,{visible:A.value,"onUpdate:visible":Pe,agent:Y.value,"project-path":l.projectPath,platform:ce.value,onSaved:$e},null,8,["visible","agent","project-path","platform"]),i(ta,{visible:H.value,"onUpdate:visible":d[2]||(d[2]=e=>H.value=e),agent:G.value,platform:ce.value,loading:W.value},null,8,["visible","agent","platform","loading"])],2))}},[["__scopeId","data-v-b673c699"]]),Za=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)=>(c(),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:f(()=>[i(h(K),{closable:"","native-scrollbar":!1,"body-content-style":u},{header:f(()=>[...a[2]||(a[2]=[w("div",{class:"drawer-header"},[w("span",null,"代理管理")],-1)])]),default:f(()=>[i(Ka,{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{Za as default};