itismyskillmarket 1.3.20 → 1.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2164,7 +2164,8 @@ API_ROUTES.GET["/api/platforms"] = async (_req, res, _url) => {
2164
2164
  id: adapter.id,
2165
2165
  name: adapter.name,
2166
2166
  available: !!isAvailable,
2167
- installedCount: Array.isArray(installed) ? installed.length : 0
2167
+ installedCount: Array.isArray(installed) ? installed.length : 0,
2168
+ installedSkills: Array.isArray(installed) ? installed : []
2168
2169
  };
2169
2170
  })
2170
2171
  );
@@ -2173,6 +2174,34 @@ API_ROUTES.GET["/api/platforms"] = async (_req, res, _url) => {
2173
2174
  jsonResponse(res, 500, { error: String(err) });
2174
2175
  }
2175
2176
  };
2177
+ API_ROUTES.GET["/api/platform-info"] = async (_req, res, url) => {
2178
+ try {
2179
+ const platformId = url.searchParams.get("id") || "";
2180
+ if (!platformId) {
2181
+ jsonResponse(res, 400, { error: 'Missing "id" query parameter' });
2182
+ return;
2183
+ }
2184
+ const allAdapters = getAllAdapters();
2185
+ const adapter = allAdapters.find((a) => a.id === platformId);
2186
+ if (!adapter) {
2187
+ jsonResponse(res, 404, { error: `Platform "${platformId}" not found` });
2188
+ return;
2189
+ }
2190
+ const available = await detectPlatforms();
2191
+ const isAvailable = available.find((a) => a.id === adapter.id);
2192
+ const installed = await adapter.listInstalled();
2193
+ const installedSkills = Array.isArray(installed) ? installed : [];
2194
+ jsonResponse(res, 200, {
2195
+ id: adapter.id,
2196
+ name: adapter.name,
2197
+ available: !!isAvailable,
2198
+ installedCount: installedSkills.length,
2199
+ installedSkills
2200
+ });
2201
+ } catch (err) {
2202
+ jsonResponse(res, 500, { error: String(err) });
2203
+ }
2204
+ };
2176
2205
  API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
2177
2206
  try {
2178
2207
  const skillName = url.searchParams.get("skill") || "";
@@ -2213,6 +2242,15 @@ API_ROUTES.GET["/api/skill-info"] = async (_req, res, url) => {
2213
2242
  jsonResponse(res, 500, { error: String(err) });
2214
2243
  }
2215
2244
  };
2245
+ API_ROUTES.GET["/api/version"] = async (_req, res, _url) => {
2246
+ try {
2247
+ const pkgPath = join4(__dirname2, "..", "package.json");
2248
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
2249
+ jsonResponse(res, 200, { version: pkg.version || "1.0.0" });
2250
+ } catch {
2251
+ jsonResponse(res, 200, { version: "1.0.0" });
2252
+ }
2253
+ };
2216
2254
  API_ROUTES.GET["/api/config"] = async (_req, res, _url) => {
2217
2255
  jsonResponse(res, 200, {
2218
2256
  npmScope: NPM_SCOPE,
package/gui/app.js CHANGED
@@ -470,6 +470,23 @@ function applyI18nToStaticElements() {
470
470
  if (backBtn) backBtn.innerHTML = `← ${t('nav.back')}`;
471
471
  }
472
472
 
473
+ // -----------------------------------------------------------------------------
474
+ // 版本号加载
475
+ // -----------------------------------------------------------------------------
476
+
477
+ async function loadVersion() {
478
+ try {
479
+ const response = await fetch('/api/version');
480
+ const data = await response.json();
481
+ const el = document.getElementById('gui-version');
482
+ if (el && data.version) {
483
+ el.textContent = `v${data.version}`;
484
+ }
485
+ } catch {
486
+ // 静默失败,保留 HTML 中的占位符
487
+ }
488
+ }
489
+
473
490
  // 重新渲染当前视图
474
491
  function reRenderCurrentView() {
475
492
  // 更新语言选项
@@ -508,6 +525,7 @@ document.addEventListener('DOMContentLoaded', () => {
508
525
  initializeNavigation();
509
526
  initializeControls();
510
527
  initializeCollapsibleSections();
528
+ loadVersion();
511
529
  loadSkills();
512
530
  });
513
531
 
@@ -561,8 +579,8 @@ function switchView(view) {
561
579
  targetView.classList.add('active');
562
580
  }
563
581
 
564
- // 加载对应数据 (skill-detail 视图的数据由 showSkillDetail 加载)
565
- if (view !== 'skill-detail') {
582
+ // 加载对应数据 (skill-detail / platform-detail 视图的数据由各自函数加载)
583
+ if (view !== 'skill-detail' && view !== 'platform-detail') {
566
584
  switch(view) {
567
585
  case 'skills':
568
586
  loadSkills();
@@ -801,7 +819,7 @@ function renderPlatforms(platforms, container) {
801
819
  }
802
820
 
803
821
  container.innerHTML = platforms.map(platform => `
804
- <div class="platform-card">
822
+ <div class="platform-card" onclick="showPlatformDetail('${platform.id}')" style="cursor: pointer;">
805
823
  <div>
806
824
  <h3>${platform.name}</h3>
807
825
  <div class="status ${platform.available ? 'status-available' : 'status-unavailable'}">
@@ -809,12 +827,86 @@ function renderPlatforms(platforms, container) {
809
827
  </div>
810
828
  </div>
811
829
  <div>
812
- ${platform.installedCount ? `<span>${t('status.skillsInstalled', { count: platform.installedCount })}</span>` : ''}
830
+ ${platform.installedCount ? `<span>${t('status.skillsInstalled', { count: platform.installedCount })}</span>` : '<span style="color: var(--text-muted); font-size: 0.85rem;">0 installed</span>'}
813
831
  </div>
814
832
  </div>
815
833
  `).join('');
816
834
  }
817
835
 
836
+ // -----------------------------------------------------------------------------
837
+ // Platform 详情视图
838
+ // -----------------------------------------------------------------------------
839
+
840
+ async function showPlatformDetail(platformId) {
841
+ const content = document.getElementById('platform-detail-content');
842
+ content.innerHTML = `<div class="loading">${t('loading.generic')}</div>`;
843
+
844
+ state.previousView = state.currentView;
845
+ state.currentView = 'platform-detail';
846
+
847
+ document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));
848
+ const targetView = document.getElementById('view-platform-detail');
849
+ if (targetView) targetView.classList.add('active');
850
+
851
+ try {
852
+ const response = await fetch(`/api/platform-info?id=${encodeURIComponent(platformId)}`);
853
+ const platform = await response.json();
854
+
855
+ if (platform.error) {
856
+ content.innerHTML = `<div class="loading">${t('error.generic')}: ${platform.error}</div>`;
857
+ return;
858
+ }
859
+
860
+ const skills = platform.installedSkills || [];
861
+
862
+ content.innerHTML = `
863
+ <div class="platform-detail">
864
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
865
+ <div>
866
+ <h2 style="color: var(--accent); font-size: 1.5rem; margin: 0;">${platform.name}</h2>
867
+ <span class="status ${platform.available ? 'status-available' : 'status-unavailable'}">
868
+ ${platform.available ? t('status.available') : t('status.unavailable')}
869
+ </span>
870
+ <span style="color: var(--text-muted); font-size: 0.85rem; margin-left: 12px;">
871
+ ${t('status.skillsInstalled', { count: platform.installedCount })}
872
+ </span>
873
+ </div>
874
+ </div>
875
+ <div class="admin-skill-row" style="background: var(--bg-card); padding: 10px 16px; margin-bottom: 12px;">
876
+ <span style="color: var(--text-muted); font-size: 0.85rem;">Platform ID</span>
877
+ <span style="color: var(--text-secondary); font-size: 0.9rem; font-family: monospace;">${platform.id}</span>
878
+ </div>
879
+ <h3 style="color: var(--text-secondary); margin-bottom: 10px; font-size: 1rem;">
880
+ Installed Skills (${skills.length})
881
+ </h3>
882
+ ${skills.length === 0 ? '<div class="loading" style="padding: 20px;">No skills installed on this platform.</div>' : `
883
+ <div style="display: flex; flex-direction: column; gap: 6px;">
884
+ ${skills.map((skill, i) => `
885
+ <div class="admin-skill-row" style="cursor: pointer;" onclick="showSkillDetail('${skill.id}')">
886
+ <div class="admin-skill-info">
887
+ <h4>${skill.displayName || skill.id}</h4>
888
+ <div class="admin-skill-meta">${skill.id}@${skill.version || 'latest'}</div>
889
+ </div>
890
+ <button class="btn btn-secondary btn-sm" onclick="event.stopPropagation(); showSkillDetail('${skill.id}')">${t('btn.info')}</button>
891
+ </div>
892
+ `).join('')}
893
+ </div>
894
+ `}
895
+ </div>
896
+ `;
897
+ } catch (err) {
898
+ content.innerHTML = `<div class="loading">${t('error.generic')}: ${err.message}</div>`;
899
+ }
900
+ }
901
+
902
+ function goBackFromPlatformDetail() {
903
+ const target = state.previousView || 'platforms';
904
+ document.querySelectorAll('.nav-btn').forEach(b => {
905
+ b.classList.toggle('active', b.dataset.view === target);
906
+ });
907
+ switchView(target);
908
+ }
909
+
818
910
  // -----------------------------------------------------------------------------
819
911
  // Help 视图
820
912
  // -----------------------------------------------------------------------------
package/gui/index.html CHANGED
@@ -12,7 +12,7 @@
12
12
  <header class="topbar">
13
13
  <div class="topbar-left">
14
14
  <span class="topbar-logo">📦 SkillMarket</span>
15
- <span class="topbar-version" id="gui-version">v1.3.16</span>
15
+ <span class="topbar-version" id="gui-version">...</span>
16
16
  </div>
17
17
  <nav class="topbar-nav">
18
18
  <button class="nav-btn active" data-view="skills">📋 Skills</button>
@@ -66,6 +66,14 @@
66
66
  <div id="platforms-list" class="platforms-list"></div>
67
67
  </div>
68
68
 
69
+ <!-- Platform 详情视图 -->
70
+ <div id="view-platform-detail" class="view">
71
+ <div class="view-header">
72
+ <button class="btn btn-secondary" onclick="goBackFromPlatformDetail()">← Back to Platforms</button>
73
+ </div>
74
+ <div id="platform-detail-content"></div>
75
+ </div>
76
+
69
77
  <!-- Help 视图 -->
70
78
  <div id="view-help" class="view">
71
79
  <div class="view-header">
package/gui/style.css CHANGED
@@ -40,6 +40,13 @@ body {
40
40
  overflow: hidden;
41
41
  }
42
42
 
43
+ #app {
44
+ display: flex;
45
+ flex-direction: column;
46
+ flex: 1;
47
+ min-height: 0;
48
+ }
49
+
43
50
  /* -----------------------------------------------------------------------------
44
51
  顶部导航栏
45
52
  ----------------------------------------------------------------------------- */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itismyskillmarket",
3
- "version": "1.3.20",
3
+ "version": "1.3.21",
4
4
  "description": "Cross-platform skill manager for AI coding tools",
5
5
  "type": "module",
6
6
  "bin": {