codexmate 0.0.17 → 0.0.19

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.
@@ -1,11 +1,98 @@
1
- export function createSkillsMethods({ api }) {
1
+ function createUnsupportedSkillsTargetAppError(app) {
2
+ return new Error(`Unsupported skills target app: ${String(app)}`);
3
+ }
4
+
5
+ function showUnsupportedSkillsTargetMessage(vm, app) {
6
+ vm.showMessage(`不支持的 Skills 安装目标:${String(app)}`, 'error');
7
+ }
8
+
9
+ export function createSkillsMethods({ api }) {
2
10
  return {
3
- async openSkillsManager() {
11
+ normalizeSkillsTargetApp(app) {
12
+ if (app == null) {
13
+ return 'codex';
14
+ }
15
+ if (app === 'codex' || app === 'claude') {
16
+ return app;
17
+ }
18
+ throw createUnsupportedSkillsTargetAppError(app);
19
+ },
20
+
21
+ resetSkillsTargetState() {
4
22
  this.skillsSelectedNames = [];
5
23
  this.skillsKeyword = '';
6
24
  this.skillsStatusFilter = 'all';
25
+ this.skillsRootPath = '';
26
+ this.skillsList = [];
7
27
  this.skillsImportList = [];
8
28
  this.skillsImportSelectedKeys = [];
29
+ this.skillsMarketLocalLoadedOnce = false;
30
+ this.skillsMarketImportLoadedOnce = false;
31
+ },
32
+
33
+ async setSkillsTargetApp(app, options = {}) {
34
+ if (
35
+ this.skillsLoading
36
+ || this.skillsDeleting
37
+ || this.skillsScanningImports
38
+ || this.skillsImporting
39
+ || this.skillsZipImporting
40
+ || this.skillsExporting
41
+ || this.skillsMarketLoading
42
+ ) {
43
+ return false;
44
+ }
45
+ let nextTarget;
46
+ try {
47
+ nextTarget = this.normalizeSkillsTargetApp(app);
48
+ } catch (error) {
49
+ showUnsupportedSkillsTargetMessage(this, app);
50
+ return false;
51
+ }
52
+ const refresh = !(options && options.refresh === false);
53
+ const silent = !!(options && options.silent);
54
+ if (nextTarget !== this.skillsTargetApp) {
55
+ this.skillsTargetApp = nextTarget;
56
+ this.resetSkillsTargetState();
57
+ }
58
+ if (!refresh) {
59
+ return true;
60
+ }
61
+ return await this.loadSkillsMarketOverview({
62
+ forceRefresh: true,
63
+ silent
64
+ });
65
+ },
66
+
67
+ async openSkillsManager(options = {}) {
68
+ if (
69
+ this.skillsLoading
70
+ || this.skillsDeleting
71
+ || this.skillsScanningImports
72
+ || this.skillsImporting
73
+ || this.skillsZipImporting
74
+ || this.skillsExporting
75
+ || this.skillsMarketLoading
76
+ ) {
77
+ return false;
78
+ }
79
+ let targetApp;
80
+ try {
81
+ targetApp = this.normalizeSkillsTargetApp(options && options.targetApp ? options.targetApp : this.skillsTargetApp);
82
+ } catch (error) {
83
+ showUnsupportedSkillsTargetMessage(this, options && options.targetApp);
84
+ return false;
85
+ }
86
+ const targetChanged = targetApp !== this.skillsTargetApp;
87
+ if (targetChanged) {
88
+ this.skillsTargetApp = targetApp;
89
+ this.resetSkillsTargetState();
90
+ } else {
91
+ this.skillsSelectedNames = [];
92
+ this.skillsKeyword = '';
93
+ this.skillsStatusFilter = 'all';
94
+ this.skillsImportSelectedKeys = [];
95
+ }
9
96
  this.showSkillsModal = true;
10
97
  await this.refreshSkillsList({ silent: false });
11
98
  },
@@ -28,23 +115,25 @@
28
115
  async refreshSkillsList(options = {}) {
29
116
  this.skillsLoading = true;
30
117
  try {
31
- const res = await api('list-codex-skills');
118
+ const res = await api('list-skills', {
119
+ targetApp: this.skillsTargetApp
120
+ });
32
121
  if (res.error) {
33
122
  this.skillsRootPath = '';
34
123
  this.skillsList = [];
35
124
  this.skillsSelectedNames = [];
36
125
  this.showMessage(res.error, 'error');
37
- return;
126
+ return false;
38
127
  }
39
128
  const exists = res.exists !== false;
40
129
  if (!exists) {
41
- this.skillsRootPath = '';
130
+ this.skillsRootPath = res.root || '';
42
131
  this.skillsList = [];
43
132
  this.skillsSelectedNames = [];
44
133
  if (!options.silent) {
45
- this.showMessage('skills 目录不存在,已按空列表显示', 'info');
134
+ this.showMessage(`${this.skillsTargetLabel} skills 目录不存在,已按空列表显示`, 'info');
46
135
  }
47
- return;
136
+ return true;
48
137
  }
49
138
  this.skillsRootPath = res.root || '';
50
139
  this.skillsList = Array.isArray(res.items) ? res.items : [];
@@ -53,16 +142,40 @@
53
142
  .filter(Boolean));
54
143
  this.skillsSelectedNames = (Array.isArray(this.skillsSelectedNames) ? this.skillsSelectedNames : [])
55
144
  .filter((name) => currentNames.has(name));
145
+ return true;
56
146
  } catch (e) {
57
147
  this.skillsRootPath = '';
58
148
  this.skillsList = [];
59
149
  this.skillsSelectedNames = [];
60
150
  this.showMessage('加载 skills 失败', 'error');
151
+ return false;
61
152
  } finally {
62
153
  this.skillsLoading = false;
63
154
  }
64
155
  },
65
156
 
157
+ async loadSkillsMarketOverview(options = {}) {
158
+ if (this.skillsMarketLoading) return false;
159
+ const silent = !!(options && options.silent);
160
+ const forceRefresh = !!(options && options.forceRefresh);
161
+ this.skillsMarketLoading = true;
162
+ let localLoaded = this.skillsMarketLocalLoadedOnce === true;
163
+ let importLoaded = this.skillsMarketImportLoadedOnce === true;
164
+ try {
165
+ if (forceRefresh || !localLoaded) {
166
+ localLoaded = await this.refreshSkillsList({ silent });
167
+ this.skillsMarketLocalLoadedOnce = localLoaded;
168
+ }
169
+ if (forceRefresh || !importLoaded) {
170
+ importLoaded = await this.scanImportableSkills({ silent });
171
+ this.skillsMarketImportLoadedOnce = importLoaded;
172
+ }
173
+ return !!(localLoaded && importLoaded);
174
+ } finally {
175
+ this.skillsMarketLoading = false;
176
+ }
177
+ },
178
+
66
179
  resetSkillsFilters() {
67
180
  this.skillsKeyword = '';
68
181
  this.skillsStatusFilter = 'all';
@@ -99,18 +212,20 @@
99
212
  },
100
213
 
101
214
  async scanImportableSkills(options = {}) {
102
- if (this.skillsScanningImports || this.skillsImporting || this.skillsZipImporting || this.skillsExporting) return;
215
+ if (this.skillsDeleting || this.skillsScanningImports || this.skillsImporting || this.skillsZipImporting || this.skillsExporting) return false;
103
216
  const silent = !!(options && options.silent);
104
217
  this.skillsScanningImports = true;
105
218
  try {
106
- const res = await api('scan-unmanaged-codex-skills');
219
+ const res = await api('scan-unmanaged-skills', {
220
+ targetApp: this.skillsTargetApp
221
+ });
107
222
  if (res.error) {
108
223
  this.skillsImportList = [];
109
224
  this.skillsImportSelectedKeys = [];
110
225
  if (!silent) {
111
226
  this.showMessage(res.error, 'error');
112
227
  }
113
- return;
228
+ return false;
114
229
  }
115
230
  this.skillsImportList = Array.isArray(res.items) ? res.items : [];
116
231
  const availableKeys = new Set(this.skillsImportSelectableKeys);
@@ -121,19 +236,21 @@
121
236
  } else if (!silent) {
122
237
  this.showMessage(`扫描到 ${this.skillsImportList.length} 个可导入 skill`, 'success');
123
238
  }
239
+ return true;
124
240
  } catch (e) {
125
241
  this.skillsImportList = [];
126
242
  this.skillsImportSelectedKeys = [];
127
243
  if (!silent) {
128
244
  this.showMessage('扫描可导入 skill 失败', 'error');
129
245
  }
246
+ return false;
130
247
  } finally {
131
248
  this.skillsScanningImports = false;
132
249
  }
133
250
  },
134
251
 
135
252
  async importSelectedSkills() {
136
- if (this.skillsImporting || this.skillsZipImporting || this.skillsExporting) return;
253
+ if (this.skillsDeleting || this.skillsScanningImports || this.skillsImporting || this.skillsZipImporting || this.skillsExporting) return;
137
254
  const selectedSet = new Set(Array.isArray(this.skillsImportSelectedKeys) ? this.skillsImportSelectedKeys : []);
138
255
  const selectedItems = (Array.isArray(this.skillsImportList) ? this.skillsImportList : [])
139
256
  .filter((item) => selectedSet.has(this.buildSkillImportKey(item)))
@@ -148,7 +265,10 @@
148
265
 
149
266
  this.skillsImporting = true;
150
267
  try {
151
- const res = await api('import-codex-skills', { items: selectedItems });
268
+ const res = await api('import-skills', {
269
+ targetApp: this.skillsTargetApp,
270
+ items: selectedItems
271
+ });
152
272
  if (res.error) {
153
273
  this.showMessage(res.error, 'error');
154
274
  return;
@@ -161,7 +281,7 @@
161
281
  const first = res.failed[0] && res.failed[0].error ? res.failed[0].error : '导入失败';
162
282
  this.showMessage(first, 'error');
163
283
  } else {
164
- this.showMessage(`已导入 ${importedCount} 个 skill`, 'success');
284
+ this.showMessage(`已导入 ${importedCount} 个 skill 到 ${this.skillsTargetLabel}`, 'success');
165
285
  }
166
286
  await this.refreshSkillsList({ silent: true });
167
287
  } catch (e) {
@@ -197,8 +317,8 @@
197
317
  async uploadSkillsZipStream(file) {
198
318
  const fileName = (file && typeof file.name === 'string' && file.name.trim())
199
319
  ? file.name.trim()
200
- : 'codex-skills.zip';
201
- const response = await fetch('/api/import-codex-skills-zip', {
320
+ : `${this.skillsTargetApp}-skills.zip`;
321
+ const response = await fetch(`/api/import-skills-zip?targetApp=${encodeURIComponent(this.skillsTargetApp)}`, {
202
322
  method: 'POST',
203
323
  headers: {
204
324
  'x-codexmate-file-name': encodeURIComponent(fileName)
@@ -222,7 +342,7 @@
222
342
  },
223
343
 
224
344
  async importSkillsFromZipFile(file) {
225
- if (this.skillsZipImporting || this.skillsImporting || this.skillsExporting) return;
345
+ if (this.skillsDeleting || this.skillsScanningImports || this.skillsZipImporting || this.skillsImporting || this.skillsExporting) return;
226
346
  const maxSize = 20 * 1024 * 1024;
227
347
  if (file.size > maxSize) {
228
348
  this.showMessage('ZIP 文件过大,限制 20MB', 'error');
@@ -244,7 +364,7 @@
244
364
  const first = res.failed[0] && res.failed[0].error ? res.failed[0].error : '导入失败';
245
365
  this.showMessage(first, 'error');
246
366
  } else {
247
- this.showMessage(`已导入 ${importedCount} 个 skill`, 'success');
367
+ this.showMessage(`已导入 ${importedCount} 个 skill 到 ${this.skillsTargetLabel}`, 'success');
248
368
  }
249
369
  await this.refreshSkillsList({ silent: true });
250
370
  } catch (e) {
@@ -257,7 +377,7 @@
257
377
  },
258
378
 
259
379
  async exportSelectedSkills() {
260
- if (this.skillsExporting || this.skillsZipImporting || this.skillsImporting) return;
380
+ if (this.skillsDeleting || this.skillsExporting || this.skillsZipImporting || this.skillsImporting) return;
261
381
  const selected = Array.isArray(this.skillsSelectedNames)
262
382
  ? Array.from(new Set(this.skillsSelectedNames.map((item) => String(item || '').trim()).filter(Boolean)))
263
383
  : [];
@@ -267,7 +387,10 @@
267
387
  }
268
388
  this.skillsExporting = true;
269
389
  try {
270
- const res = await api('export-codex-skills', { names: selected });
390
+ const res = await api('export-skills', {
391
+ targetApp: this.skillsTargetApp,
392
+ names: selected
393
+ });
271
394
  if (res && res.error) {
272
395
  this.showMessage(res.error, 'error');
273
396
  return;
@@ -290,7 +413,7 @@
290
413
  if (failedCount > 0) {
291
414
  this.showMessage(`已导出 ${exportedCount} 个,失败 ${failedCount} 个`, 'error');
292
415
  } else {
293
- this.showMessage(`已导出 ${exportedCount} 个 skill`, 'success');
416
+ this.showMessage(`已从 ${this.skillsTargetLabel} 导出 ${exportedCount} 个 skill`, 'success');
294
417
  }
295
418
  } catch (e) {
296
419
  this.showMessage('导出 skill 失败', 'error');
@@ -301,6 +424,10 @@
301
424
 
302
425
  async deleteSelectedSkills() {
303
426
  if (this.skillsDeleting || this.skillsZipImporting || this.skillsExporting || this.skillsImporting) return;
427
+ if (this.skillsScanningImports) {
428
+ this.showMessage('正在扫描导入源,请稍后再试', 'error');
429
+ return;
430
+ }
304
431
  const selected = Array.isArray(this.skillsSelectedNames)
305
432
  ? Array.from(new Set(this.skillsSelectedNames.map((item) => String(item || '').trim()).filter(Boolean)))
306
433
  : [];
@@ -308,14 +435,24 @@
308
435
  this.showMessage('请先选择要删除的 skill', 'error');
309
436
  return;
310
437
  }
311
- const confirmed = window.confirm(`确认删除 ${selected.length} 个 skill 吗?此操作不可撤销。`);
438
+ const confirmed = await this.requestConfirmDialog({
439
+ title: '删除 Skills',
440
+ message: `确认从 ${this.skillsTargetLabel} 删除 ${selected.length} 个 skill 吗?此操作不可撤销。`,
441
+ confirmText: '删除',
442
+ cancelText: '取消',
443
+ confirmDisabled: () => this.skillsDeleting || this.skillsScanningImports,
444
+ danger: true
445
+ });
312
446
  if (!confirmed) {
313
447
  return;
314
448
  }
315
449
 
316
450
  this.skillsDeleting = true;
317
451
  try {
318
- const res = await api('delete-codex-skills', { names: selected });
452
+ const res = await api('delete-skills', {
453
+ targetApp: this.skillsTargetApp,
454
+ names: selected
455
+ });
319
456
  if (res.error) {
320
457
  this.showMessage(res.error, 'error');
321
458
  return;
@@ -330,7 +467,7 @@
330
467
  const first = failedList[0] && failedList[0].error ? failedList[0].error : '删除失败';
331
468
  this.showMessage(first, 'error');
332
469
  } else {
333
- this.showMessage(`已删除 ${deletedCount} 个 skill`, 'success');
470
+ this.showMessage(`已从 ${this.skillsTargetLabel} 删除 ${deletedCount} 个 skill`, 'success');
334
471
  }
335
472
  await this.refreshSkillsList({ silent: true });
336
473
  } catch (e) {