dsh-plugin-manager-plus 1.3.2 → 1.3.3

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/lib/client.js CHANGED
@@ -264,6 +264,16 @@ window.__ModuleLoader__.load({
264
264
  }
265
265
  }
266
266
 
267
+ /** star 数格式化:>=1000 → 1.2k */
268
+ function formatStars(n) {
269
+ if (typeof n !== 'number' || !isFinite(n)) return "";
270
+ if (n >= 1000) {
271
+ const v = n / 1000;
272
+ return `⭐ ${(v >= 10 ? Math.round(v) : Math.round(v * 10) / 10)}k`;
273
+ }
274
+ return `⭐ ${n}`;
275
+ }
276
+
267
277
  /** 路由+版本徽章小工具(市场搜索结果与已安装列表共用) */
268
278
  function badgePair(t, pkg, options) {
269
279
  return [
@@ -1252,6 +1262,24 @@ window.__ModuleLoader__.load({
1252
1262
  children: `v${pkg.version}`
1253
1263
  }),
1254
1264
  ...badgePair(t, pkg),
1265
+ // GitHub star(社区热度,点击打开仓库)
1266
+ typeof pkg.stars === "number" ? _jsx("a", {
1267
+ href: pkg.repoUrl || `https://github.com/${pkg.name}`,
1268
+ target: "_blank",
1269
+ rel: "noreferrer",
1270
+ title: pkg.repoUrl || "",
1271
+ style: {
1272
+ fontSize: "11px",
1273
+ padding: "1px 5px",
1274
+ borderRadius: "4px",
1275
+ color: "#e3b341",
1276
+ background: "rgba(227,179,65,0.12)",
1277
+ border: "1px solid rgba(227,179,65,0.25)",
1278
+ textDecoration: "none",
1279
+ cursor: "pointer"
1280
+ },
1281
+ children: formatStars(pkg.stars)
1282
+ }, "s") : null,
1255
1283
  pkg.date ? _jsx("span", {
1256
1284
  style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)" },
1257
1285
  children: pkg.date.slice(0, 10)
package/lib/index.mjs CHANGED
@@ -15,7 +15,7 @@ import { homedir } from 'node:os';
15
15
  export const name = 'dsh-plugin-manager-plus';
16
16
  export const inject = ['loader', 'webServer'];
17
17
 
18
- const PLUGIN_VERSION = '1.3.2';
18
+ const PLUGIN_VERSION = '1.3.3';
19
19
 
20
20
  /** 读取宿主 dsh 包版本(后端进程 argv[1] 即 dsh 的 bin.js,其上级即包根) */
21
21
  function readHostDshVersion() {
@@ -201,6 +201,88 @@ function readInstalledPkg(moduleName) {
201
201
  } catch { return null; }
202
202
  }
203
203
 
204
+ // =========================================================================
205
+ // GitHub star 数(社区热度)查询:metadata 的 repository 字段 → GitHub API。
206
+ // 内存缓存 30 分钟 + 并发池 6 + 失败静默降级(不阻塞搜索结果)。
207
+ // =========================================================================
208
+
209
+ const GITHUB_STAR_CACHE = new Map();
210
+ const STAR_TTL_MS = 30 * 60 * 1000;
211
+
212
+ /** 从 package.json 的 repository 字段提取 GitHub 仓库 'owner/name',非 GitHub 返回 null */
213
+ function extractGitHubRepo(pkg) {
214
+ if (!pkg || typeof pkg !== 'object') return null;
215
+ let raw = pkg.repository;
216
+ if (raw && typeof raw === 'object') raw = raw.url || raw.repository || '';
217
+ if (!raw || typeof raw !== 'string') {
218
+ // 部分包只写了 homepage (github 链接)
219
+ raw = typeof pkg.homepage === 'string' ? pkg.homepage : '';
220
+ }
221
+ raw = raw.trim();
222
+ if (!raw) return null;
223
+ let m = /^github:([^/\s]+\/[^/\s]+)/.exec(raw);
224
+ if (m) return m[1];
225
+ m = /^([\w.-]+\/[\w.-]+)$/.exec(raw); // npm 短格式 owner/repo
226
+ if (m) return m[1];
227
+ try {
228
+ const u = new URL(raw);
229
+ if (u.hostname === 'github.com') {
230
+ const parts = u.pathname.split('/').filter(Boolean);
231
+ if (parts.length >= 2) return parts[0] + '/' + parts[1].replace(/\.git$/i, '');
232
+ }
233
+ } catch {}
234
+ return null;
235
+ }
236
+
237
+ /** 组装 GitHub 仓库主页 URL(供客户端跳转);非 GitHub 返回 null */
238
+ function gitHubRepoUrl(pkg) {
239
+ const repo = extractGitHubRepo(pkg);
240
+ if (!repo) return null;
241
+ return 'https://github.com/' + repo;
242
+ }
243
+
244
+ /** 查询 GitHub star 数(带缓存;失败返回 null 且短暂缓存避免反复打 API) */
245
+ async function fetchGitHubStars(repo) {
246
+ const key = String(repo).toLowerCase();
247
+ const hit = GITHUB_STAR_CACHE.get(key);
248
+ if (hit && Date.now() - hit.at < STAR_TTL_MS) return hit.stars;
249
+ try {
250
+ const enc = String(repo).split('/').map(encodeURIComponent).join('/'); // 斜杠必须保留,%2F 会 404
251
+ const resp = await fetch(`https://api.github.com/repos/${enc}`, {
252
+ headers: {
253
+ Accept: 'application/vnd.github+json',
254
+ 'User-Agent': 'dsh-plugin-manager-plus',
255
+ 'X-GitHub-Api-Version': '2022-11-28'
256
+ },
257
+ signal: AbortSignal.timeout(6000)
258
+ });
259
+ let stars = null;
260
+ if (resp.ok) {
261
+ const j = await resp.json();
262
+ if (typeof j.stargazers_count === 'number') stars = j.stargazers_count;
263
+ }
264
+ GITHUB_STAR_CACHE.set(key, { stars, at: Date.now() });
265
+ return stars;
266
+ } catch {
267
+ GITHUB_STAR_CACHE.set(key, { stars: null, at: Date.now() });
268
+ return null;
269
+ }
270
+ }
271
+
272
+ /** 简单并发池:最多 limit 个并发执行 fn */
273
+ async function mapPool(items, limit, fn) {
274
+ const results = new Array(items.length);
275
+ let i = 0;
276
+ async function worker() {
277
+ while (i < items.length) {
278
+ const idx = i++;
279
+ try { results[idx] = await fn(items[idx], idx); } catch { results[idx] = undefined; }
280
+ }
281
+ }
282
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));
283
+ return results;
284
+ }
285
+
204
286
  /** Fiber 状态常量映射 */
205
287
  const FIBER_PHASE = {
206
288
  0: 'pending',
@@ -1235,6 +1317,17 @@ export function apply(ctx) {
1235
1317
  } catch {}
1236
1318
  }));
1237
1319
 
1320
+ // GitHub star 数(社区热度):从 repo 字段提取 GitHub 仓库,
1321
+ // 走 GitHub API + 内存缓存 + 并发池;限流/无 repo/失败一律静默降级。
1322
+ const starBy = new Map();
1323
+ await mapPool(NAMES, 6, async (n) => {
1324
+ const meta = metaBy.get(n);
1325
+ const repo = meta ? extractGitHubRepo(meta) : null;
1326
+ if (!repo) return;
1327
+ const stars = await fetchGitHubStars(repo);
1328
+ if (typeof stars === 'number') starBy.set(n, stars);
1329
+ });
1330
+
1238
1331
  const results = rawResults.map((item) => {
1239
1332
  const pkg = item.package || {};
1240
1333
  const isInstalled = installedNames.has(pkg.name);
@@ -1250,7 +1343,9 @@ export function apply(ctx) {
1250
1343
  verdict: assess.verdict,
1251
1344
  dshRange: assess.dshRange,
1252
1345
  tested: assess.tested,
1253
- enginesNode: assess.enginesNode
1346
+ enginesNode: assess.enginesNode,
1347
+ stars: starBy.get(pkg.name) ?? null,
1348
+ repoUrl: meta ? gitHubRepoUrl(meta) : null
1254
1349
  };
1255
1350
  });
1256
1351
 
@@ -1463,5 +1558,6 @@ export function apply(ctx) {
1463
1558
  }
1464
1559
 
1465
1560
  // 工具函数导出(供单测/外部复用;cordis 插件加载仅取 name/inject/apply,额外导出无害)
1466
- export { versionSatisfies, extractDshRange, assessPackage, parseSemver };
1561
+ export { versionSatisfies, extractDshRange, assessPackage, parseSemver, extractGitHubRepo, fetchGitHubStars, mapPool };
1467
1562
 
1563
+
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-plugin-manager-plus",
3
3
  "description": "DeepSeek Harness (DSH) 插件管理器:设置面板内的社区插件市场(npm 搜索一键安装)+ 已安装插件管理(来源/用途/状态三维筛选、启停热重载、一键卸载、持久化)。Plugin manager & marketplace for DeepSeek Harness.",
4
- "version": "1.3.2",
4
+ "version": "1.3.3",
5
5
  "type": "module",
6
6
  "main": "./lib/index.mjs",
7
7
  "exports": {
@@ -53,3 +53,4 @@
53
53
  },
54
54
  "license": "MIT"
55
55
  }
56
+