itismyskillmarket 1.3.6 → 1.3.7

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 (63) hide show
  1. package/README.md +10 -5
  2. package/dist/index.js +440 -11
  3. package/gui/app.js +415 -0
  4. package/gui/index.html +84 -0
  5. package/gui/style.css +454 -0
  6. package/package.json +6 -2
  7. package/.github/workflows/publish-npm.yml +0 -59
  8. package/.github/workflows/publish-skill.yml +0 -72
  9. package/5e51cb7aa8b8e60d49d86f4689f5d4d1.png +0 -0
  10. package/CHANGELOG.md +0 -639
  11. package/DEVELOPMENT.md +0 -376
  12. package/SKILLMARKET-GUIDE.md +0 -288
  13. package/docs/WEEKLY-UPDATE-2026-04-23.md +0 -43
  14. package/docs/plans/2026-04-01-skillmarket-design.md +0 -267
  15. package/docs/plans/2026-04-01-skillmarket-implementation.md +0 -1031
  16. package/docs/plans/2026-04-15-cross-platform-adapter-design.md +0 -416
  17. package/docs/plans/2026-04-15-cross-platform-adapter-plan.md +0 -833
  18. package/docs/plans/2026-04-16-keyword-search-design.md +0 -143
  19. package/docs/plans/2026-04-29-weekly-update.md +0 -57
  20. package/skills/README.md +0 -54
  21. package/skills/test-skill/SKILL.md +0 -25
  22. package/skills/test-skill/index.js +0 -66
  23. package/skills/test-skill/metadata.json +0 -9
  24. package/skills/test-skill/package.json +0 -19
  25. package/skills/test-skill-1/SKILL.md +0 -24
  26. package/skills/test-skill-1/index.js +0 -13
  27. package/skills/test-skill-1/metadata.json +0 -9
  28. package/skills/test-skill-1/package.json +0 -16
  29. package/skills/test-skill-2/SKILL.md +0 -25
  30. package/skills/test-skill-2/index.js +0 -13
  31. package/skills/test-skill-2/metadata.json +0 -9
  32. package/skills/test-skill-2/package.json +0 -16
  33. package/src/adapters/base.ts +0 -87
  34. package/src/adapters/claude.ts +0 -31
  35. package/src/adapters/hermes.test.ts +0 -39
  36. package/src/adapters/hermes.ts +0 -77
  37. package/src/adapters/index.ts +0 -11
  38. package/src/adapters/openclaw.test.ts +0 -40
  39. package/src/adapters/openclaw.ts +0 -69
  40. package/src/adapters/opencode.ts +0 -40
  41. package/src/adapters/registry.test.ts +0 -29
  42. package/src/adapters/registry.ts +0 -85
  43. package/src/adapters/vscode.ts +0 -62
  44. package/src/cli.ts +0 -463
  45. package/src/commands/github-install.ts +0 -538
  46. package/src/commands/info.ts +0 -143
  47. package/src/commands/install.ts +0 -312
  48. package/src/commands/ls.ts +0 -307
  49. package/src/commands/npm.ts +0 -353
  50. package/src/commands/registry.ts +0 -159
  51. package/src/commands/search.ts +0 -103
  52. package/src/commands/sync.ts +0 -196
  53. package/src/commands/uninstall.ts +0 -400
  54. package/src/commands/update.ts +0 -113
  55. package/src/constants.test.ts +0 -18
  56. package/src/constants.ts +0 -128
  57. package/src/index.ts +0 -62
  58. package/src/types.ts +0 -172
  59. package/src/utils/dirs.ts +0 -166
  60. package/src/utils/platform.ts +0 -139
  61. package/tsconfig.json +0 -10
  62. package/tsup.config.ts +0 -22
  63. package/wanxuchen-skillmarket-1.0.1.tgz +0 -0
package/gui/app.js ADDED
@@ -0,0 +1,415 @@
1
+ /* =============================================================================
2
+ SkillMarket GUI - 前端逻辑
3
+ ============================================================================= */
4
+
5
+ // -----------------------------------------------------------------------------
6
+ // 全局状态
7
+ // -----------------------------------------------------------------------------
8
+
9
+ const state = {
10
+ currentView: 'skills',
11
+ currentPage: 1,
12
+ pageSize: 20,
13
+ searchQuery: '',
14
+ totalPages: 1,
15
+ };
16
+
17
+ // -----------------------------------------------------------------------------
18
+ // 初始化
19
+ // -----------------------------------------------------------------------------
20
+
21
+ document.addEventListener('DOMContentLoaded', () => {
22
+ initializeNavigation();
23
+ initializeControls();
24
+ loadSkills();
25
+ });
26
+
27
+ // -----------------------------------------------------------------------------
28
+ // 导航切换
29
+ // -----------------------------------------------------------------------------
30
+
31
+ function initializeNavigation() {
32
+ const navBtns = document.querySelectorAll('.nav-btn');
33
+
34
+ navBtns.forEach(btn => {
35
+ btn.addEventListener('click', () => {
36
+ const view = btn.dataset.view;
37
+
38
+ // 更新按钮状态
39
+ navBtns.forEach(b => b.classList.remove('active'));
40
+ btn.classList.add('active');
41
+
42
+ // 切换视图
43
+ switchView(view);
44
+ });
45
+ });
46
+ }
47
+
48
+ function switchView(view) {
49
+ state.currentView = view;
50
+
51
+ // 隐藏所有视图
52
+ document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));
53
+
54
+ // 显示目标视图
55
+ const targetView = document.getElementById(`view-${view}`);
56
+ if (targetView) {
57
+ targetView.classList.add('active');
58
+ }
59
+
60
+ // 加载对应数据
61
+ switch(view) {
62
+ case 'skills':
63
+ loadSkills();
64
+ break;
65
+ case 'installed':
66
+ loadInstalled();
67
+ break;
68
+ case 'platforms':
69
+ loadPlatforms();
70
+ break;
71
+ }
72
+ }
73
+
74
+ // -----------------------------------------------------------------------------
75
+ // 控件初始化
76
+ // -----------------------------------------------------------------------------
77
+
78
+ function initializeControls() {
79
+ // 搜索
80
+ const searchInput = document.getElementById('search-input');
81
+ let searchTimeout;
82
+ searchInput.addEventListener('input', () => {
83
+ clearTimeout(searchTimeout);
84
+ searchTimeout = setTimeout(() => {
85
+ state.searchQuery = searchInput.value;
86
+ state.currentPage = 1;
87
+ loadSkills();
88
+ }, 300);
89
+ });
90
+
91
+ // 分页大小
92
+ const pageSizeSelect = document.getElementById('page-size');
93
+ pageSizeSelect.addEventListener('change', () => {
94
+ state.pageSize = parseInt(pageSizeSelect.value);
95
+ state.currentPage = 1;
96
+ loadSkills();
97
+ });
98
+
99
+ // 刷新按钮
100
+ document.getElementById('refresh-skills').addEventListener('click', () => loadSkills());
101
+ document.getElementById('update-all').addEventListener('click', updateAllSkills);
102
+
103
+ // 模态框关闭
104
+ document.querySelector('.modal-close').addEventListener('click', closeModal);
105
+ document.getElementById('modal').addEventListener('click', (e) => {
106
+ if (e.target.id === 'modal') closeModal();
107
+ });
108
+ }
109
+
110
+ // -----------------------------------------------------------------------------
111
+ // Skills 列表
112
+ // -----------------------------------------------------------------------------
113
+
114
+ async function loadSkills() {
115
+ const container = document.getElementById('skills-list');
116
+ container.innerHTML = '<div class="loading">Loading skills...</div>';
117
+
118
+ try {
119
+ const params = new URLSearchParams({
120
+ page: state.currentPage.toString(),
121
+ limit: state.pageSize.toString(),
122
+ });
123
+
124
+ if (state.searchQuery) {
125
+ params.append('search', state.searchQuery);
126
+ }
127
+
128
+ const response = await fetch(`/api/skills?${params}`);
129
+ const data = await response.json();
130
+
131
+ if (data.error) {
132
+ container.innerHTML = `<div class="loading">Error: ${data.error}</div>`;
133
+ return;
134
+ }
135
+
136
+ renderSkills(data.skills || data, container);
137
+ renderPagination(data.page, data.totalPages || 1);
138
+ } catch (err) {
139
+ container.innerHTML = `<div class="loading">Error: ${err.message}</div>`;
140
+ }
141
+ }
142
+
143
+ async function loadInstalled() {
144
+ const container = document.getElementById('installed-list');
145
+ container.innerHTML = '<div class="loading">Loading...</div>';
146
+
147
+ try {
148
+ const response = await fetch('/api/installed');
149
+ const skills = await response.json();
150
+
151
+ if (skills.error) {
152
+ container.innerHTML = `<div class="loading">Error: ${skills.error}</div>`;
153
+ return;
154
+ }
155
+
156
+ renderSkills(skills, container, true);
157
+ } catch (err) {
158
+ container.innerHTML = `<div class="loading">Error: ${err.message}</div>`;
159
+ }
160
+ }
161
+
162
+ function renderSkills(skills, container, isInstalled = false) {
163
+ if (!skills || skills.length === 0) {
164
+ container.innerHTML = '<div class="loading">No skills found</div>';
165
+ return;
166
+ }
167
+
168
+ container.innerHTML = skills.map(skill => createSkillCard(skill, isInstalled)).join('');
169
+ }
170
+
171
+ function createSkillCard(skill, isInstalled) {
172
+ const platforms = skill.platforms || [];
173
+ const platformTags = platforms.map(p => `<span class="platform-tag">${p}</span>`).join('');
174
+
175
+ return `
176
+ <div class="skill-card">
177
+ <h3>${skill.displayName || skill.id}</h3>
178
+ <div class="skill-id">${skill.id}@${skill.version || 'latest'}</div>
179
+ <p>${skill.description || 'No description'}</p>
180
+ <div class="platforms">${platformTags}</div>
181
+ <div class="actions">
182
+ ${isInstalled ? `
183
+ <button class="btn btn-danger btn-sm" onclick="uninstallSkill('${skill.id}')">Uninstall</button>
184
+ <button class="btn btn-primary btn-sm" onclick="updateSkill('${skill.id}')">Update</button>
185
+ ` : `
186
+ <button class="btn btn-success btn-sm" onclick="installSkill('${skill.id}')">Install</button>
187
+ <button class="btn btn-secondary btn-sm" onclick="showSkillInfo('${skill.id}')">Info</button>
188
+ `}
189
+ </div>
190
+ </div>
191
+ `;
192
+ }
193
+
194
+ // -----------------------------------------------------------------------------
195
+ // 分页
196
+ // -----------------------------------------------------------------------------
197
+
198
+ function renderPagination(currentPage, totalPages) {
199
+ state.currentPage = currentPage;
200
+ state.totalPages = totalPages;
201
+
202
+ const container = document.getElementById('pagination');
203
+
204
+ if (totalPages <= 1) {
205
+ container.innerHTML = '';
206
+ return;
207
+ }
208
+
209
+ let html = `
210
+ <button ${currentPage <= 1 ? 'disabled' : ''} onclick="changePage(${currentPage - 1})">← Prev</button>
211
+ <span class="page-info">Page ${currentPage} of ${totalPages}</span>
212
+ <button ${currentPage >= totalPages ? 'disabled' : ''} onclick="changePage(${currentPage + 1})">Next →</button>
213
+ `;
214
+
215
+ container.innerHTML = html;
216
+ }
217
+
218
+ function changePage(page) {
219
+ if (page < 1 || page > state.totalPages) return;
220
+ state.currentPage = page;
221
+ loadSkills();
222
+ }
223
+
224
+ // -----------------------------------------------------------------------------
225
+ // Platforms
226
+ // -----------------------------------------------------------------------------
227
+
228
+ async function loadPlatforms() {
229
+ const container = document.getElementById('platforms-list');
230
+ container.innerHTML = '<div class="loading">Loading platforms...</div>';
231
+
232
+ try {
233
+ const response = await fetch('/api/platforms');
234
+ const platforms = await response.json();
235
+
236
+ if (platforms.error) {
237
+ container.innerHTML = `<div class="loading">Error: ${platforms.error}</div>`;
238
+ return;
239
+ }
240
+
241
+ renderPlatforms(platforms, container);
242
+ } catch (err) {
243
+ container.innerHTML = `<div class="loading">Error: ${err.message}</div>`;
244
+ }
245
+ }
246
+
247
+ function renderPlatforms(platforms, container) {
248
+ if (!platforms || platforms.length === 0) {
249
+ container.innerHTML = '<div class="loading">No platforms found</div>';
250
+ return;
251
+ }
252
+
253
+ container.innerHTML = platforms.map(platform => `
254
+ <div class="platform-card">
255
+ <div>
256
+ <h3>${platform.name}</h3>
257
+ <div class="status ${platform.available ? 'status-available' : 'status-unavailable'}">
258
+ ${platform.available ? '✅ Available' : '❌ Not detected'}
259
+ </div>
260
+ </div>
261
+ <div>
262
+ ${platform.installedCount ? `<span>${platform.installedCount} skills installed</span>` : ''}
263
+ </div>
264
+ </div>
265
+ `).join('');
266
+ }
267
+
268
+ // -----------------------------------------------------------------------------
269
+ // 操作函数
270
+ // -----------------------------------------------------------------------------
271
+
272
+ async function installSkill(skillId) {
273
+ try {
274
+ showToast(`Installing ${skillId}...`, 'info');
275
+ const response = await fetch('/api/install', {
276
+ method: 'POST',
277
+ headers: { 'Content-Type': 'application/json' },
278
+ body: JSON.stringify({ skillId })
279
+ });
280
+
281
+ const result = await response.json();
282
+
283
+ if (result.error) {
284
+ showToast(`Error: ${result.error}`, 'error');
285
+ } else {
286
+ showToast(`✅ ${skillId} installed successfully!`, 'success');
287
+ if (state.currentView === 'installed') loadInstalled();
288
+ }
289
+ } catch (err) {
290
+ showToast(`Error: ${err.message}`, 'error');
291
+ }
292
+ }
293
+
294
+ async function uninstallSkill(skillId) {
295
+ if (!confirm(`Are you sure you want to uninstall ${skillId}?`)) return;
296
+
297
+ try {
298
+ showToast(`Uninstalling ${skillId}...`, 'info');
299
+ const response = await fetch('/api/uninstall', {
300
+ method: 'POST',
301
+ headers: { 'Content-Type': 'application/json' },
302
+ body: JSON.stringify({ skillId })
303
+ });
304
+
305
+ const result = await response.json();
306
+
307
+ if (result.error) {
308
+ showToast(`Error: ${result.error}`, 'error');
309
+ } else {
310
+ showToast(`✅ ${skillId} uninstalled!`, 'success');
311
+ loadInstalled();
312
+ }
313
+ } catch (err) {
314
+ showToast(`Error: ${err.message}`, 'error');
315
+ }
316
+ }
317
+
318
+ async function updateSkill(skillId) {
319
+ try {
320
+ showToast(`Updating ${skillId}...`, 'info');
321
+ const response = await fetch('/api/update', {
322
+ method: 'POST',
323
+ headers: { 'Content-Type': 'application/json' },
324
+ body: JSON.stringify({ skillId })
325
+ });
326
+
327
+ const result = await response.json();
328
+
329
+ if (result.error) {
330
+ showToast(`Error: ${result.error}`, 'error');
331
+ } else {
332
+ showToast(`✅ ${skillId} updated!`, 'success');
333
+ if (state.currentView === 'installed') loadInstalled();
334
+ }
335
+ } catch (err) {
336
+ showToast(`Error: ${err.message}`, 'error');
337
+ }
338
+ }
339
+
340
+ async function updateAllSkills() {
341
+ if (!confirm('Update all installed skills?')) return;
342
+
343
+ try {
344
+ showToast('Updating all skills...', 'info');
345
+ const response = await fetch('/api/update', {
346
+ method: 'POST',
347
+ headers: { 'Content-Type': 'application/json' },
348
+ body: JSON.stringify({})
349
+ });
350
+
351
+ const result = await response.json();
352
+
353
+ if (result.error) {
354
+ showToast(`Error: ${result.error}`, 'error');
355
+ } else {
356
+ showToast('✅ All skills updated!', 'success');
357
+ loadInstalled();
358
+ }
359
+ } catch (err) {
360
+ showToast(`Error: ${err.message}`, 'error');
361
+ }
362
+ }
363
+
364
+ async function showSkillInfo(skillId) {
365
+ const modal = document.getElementById('modal');
366
+ const modalBody = document.getElementById('modal-body');
367
+
368
+ modalBody.innerHTML = '<div class="loading">Loading...</div>';
369
+ modal.classList.remove('hidden');
370
+
371
+ try {
372
+ const response = await fetch(`/api/skills?search=${skillId}`);
373
+ const data = await response.json();
374
+ const skills = data.skills || data;
375
+ const skill = Array.isArray(skills) ? skills.find(s => s.id === skillId) : skills;
376
+
377
+ if (!skill) {
378
+ modalBody.innerHTML = '<div class="loading">Skill not found</div>';
379
+ return;
380
+ }
381
+
382
+ modalBody.innerHTML = `
383
+ <h2>${skill.displayName || skill.id}</h2>
384
+ <div class="detail-row"><strong>ID:</strong> ${skill.id}</div>
385
+ <div class="detail-row"><strong>Version:</strong> ${skill.version || 'latest'}</div>
386
+ <div class="detail-row"><strong>Description:</strong> ${skill.description || 'No description'}</div>
387
+ <div class="detail-row"><strong>Platforms:</strong> ${(skill.platforms || []).join(', ') || 'None'}</div>
388
+ ${skill.link ? `<div class="detail-row"><strong>Link:</strong> <a href="${skill.link}" target="_blank">${skill.link}</a></div>` : ''}
389
+ <div class="actions" style="margin-top: 20px;">
390
+ <button class="btn btn-success" onclick="installSkill('${skill.id}'); closeModal();">Install</button>
391
+ </div>
392
+ `;
393
+ } catch (err) {
394
+ modalBody.innerHTML = `<div class="loading">Error: ${err.message}</div>`;
395
+ }
396
+ }
397
+
398
+ function closeModal() {
399
+ document.getElementById('modal').classList.add('hidden');
400
+ }
401
+
402
+ // -----------------------------------------------------------------------------
403
+ // Toast 通知
404
+ // -----------------------------------------------------------------------------
405
+
406
+ function showToast(message, type = 'info') {
407
+ const toast = document.getElementById('toast');
408
+ toast.textContent = message;
409
+ toast.className = `toast ${type}`;
410
+ toast.classList.remove('hidden');
411
+
412
+ setTimeout(() => {
413
+ toast.classList.add('hidden');
414
+ }, 3000);
415
+ }
package/gui/index.html ADDED
@@ -0,0 +1,84 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SkillMarket GUI</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ </head>
9
+ <body>
10
+ <div id="app">
11
+ <!-- 侧边栏 -->
12
+ <aside class="sidebar">
13
+ <div class="logo">
14
+ <h1>📦 SkillMarket</h1>
15
+ </div>
16
+ <nav>
17
+ <button class="nav-btn active" data-view="skills">
18
+ <span class="icon">📋</span> Skills
19
+ </button>
20
+ <button class="nav-btn" data-view="installed">
21
+ <span class="icon">✅</span> Installed
22
+ </button>
23
+ <button class="nav-btn" data-view="platforms">
24
+ <span class="icon">💻</span> Platforms
25
+ </button>
26
+ </nav>
27
+ <div class="sidebar-footer">
28
+ <span class="version">v1.3.6</span>
29
+ </div>
30
+ </aside>
31
+
32
+ <!-- 主内容区 -->
33
+ <main class="main-content">
34
+ <!-- Skills 视图 -->
35
+ <div id="view-skills" class="view active">
36
+ <div class="view-header">
37
+ <h2>Available Skills</h2>
38
+ <div class="controls">
39
+ <input type="text" id="search-input" placeholder="🔍 Search skills...">
40
+ <select id="page-size">
41
+ <option value="10">10 per page</option>
42
+ <option value="20" selected>20 per page</option>
43
+ <option value="50">50 per page</option>
44
+ </select>
45
+ <button id="refresh-skills" class="btn btn-secondary">🔄 Refresh</button>
46
+ </div>
47
+ </div>
48
+ <div id="skills-list" class="skills-grid"></div>
49
+ <div id="pagination" class="pagination"></div>
50
+ </div>
51
+
52
+ <!-- Installed 视图 -->
53
+ <div id="view-installed" class="view">
54
+ <div class="view-header">
55
+ <h2>Installed Skills</h2>
56
+ <button id="update-all" class="btn btn-primary">🔄 Update All</button>
57
+ </div>
58
+ <div id="installed-list" class="skills-grid"></div>
59
+ </div>
60
+
61
+ <!-- Platforms 视图 -->
62
+ <div id="view-platforms" class="view">
63
+ <div class="view-header">
64
+ <h2>Available Platforms</h2>
65
+ </div>
66
+ <div id="platforms-list" class="platforms-list"></div>
67
+ </div>
68
+ </main>
69
+
70
+ <!-- Skill 详情模态框 -->
71
+ <div id="modal" class="modal hidden">
72
+ <div class="modal-content">
73
+ <button class="modal-close">&times;</button>
74
+ <div id="modal-body"></div>
75
+ </div>
76
+ </div>
77
+
78
+ <!-- Toast 通知 -->
79
+ <div id="toast" class="toast hidden"></div>
80
+ </div>
81
+
82
+ <script src="app.js"></script>
83
+ </body>
84
+ </html>