dshmarket 1.3.0 → 1.3.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 fkysly and dsh-market contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -51,6 +51,10 @@ Installs prefer npm tarballs over full-repo GitHub downloads whenever a plugin p
51
51
  - For terminal-attached launches, the detached replacement keeps running after the original terminal closes
52
52
  - Listing ≠ endorsement: plugins are third-party code, install sources you trust
53
53
 
54
+ ## Submit your plugin
55
+
56
+ **This repo is the market app, not the catalog.** The plugin list comes from the curated [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) registry — to get your plugin listed in the market, open a PR **there** (one entry in the list; the site and this market pick it up automatically, usually within a day). Please don't PR plugin entries against this repo.
57
+
54
58
  ## Data source
55
59
 
56
60
  Live from [awesome-dsh-plugin.com/plugins.json](https://awesome-dsh-plugin.com/plugins.json) — curated entries, npm mapping, and star counts refreshed daily by CI — with a bundled snapshot as offline fallback.
package/README.zh.md CHANGED
@@ -51,6 +51,10 @@ dsh plugin --profile web add dshmarket
51
51
  - 从终端启动时,替代进程脱离原终端,关闭原终端后仍会继续运行
52
52
  - 收录 ≠ 背书:插件是第三方代码,请只安装你信任的来源
53
53
 
54
+ ## 提交你的插件
55
+
56
+ **这个仓库是市场应用本身,不是插件目录。** 市场里的插件列表来自精选列表 [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)——想让你的插件上架,请去**那边**提 PR(在列表里加一条即可,站点和本市场会自动收录,通常一天内生效)。请不要往本仓库提插件条目。
57
+
54
58
  ## 数据源
55
59
 
56
60
  实时来自 [awesome-dsh-plugin.com/plugins.json](https://awesome-dsh-plugin.com/plugins.json)——精选条目、npm 映射、star 数由 CI 每日刷新——内置快照做离线兜底。
package/client/client.js CHANGED
@@ -235,10 +235,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
235
235
  return matchInstalledName(plugin, installed) !== null;
236
236
  }
237
237
  /**
238
- * The brand mark (assets/logo.svg shared block-grid mark with
239
- * awesome-dsh-plugin), inlined so the header needs no extra request.
238
+ * The header brand mark now lives in MarketSection.tsx as an inline SVG
239
+ * (official-style monochrome glyph, fill="currentColor") so it follows the
240
+ * active theme; the colored assets/logo.svg tile is no longer inlined here.
240
241
  */
241
- const LOGO_URI = "data:image/svg+xml," + encodeURIComponent("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\"><rect width=\"128\" height=\"128\" rx=\"28\" fill=\"#f6f2ea\"/><g transform=\"translate(15.7 16.7) scale(0.3) translate(-112 -78)\"><g fill=\"#2b2620\"><rect x=\"112\" y=\"112\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"112\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"112\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"112\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"312\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"312\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/></g><rect x=\"346\" y=\"78\" width=\"88\" height=\"88\" rx=\"14\" fill=\"#c0392b\" transform=\"rotate(9 390 122)\"/></g></svg>");
242
242
  /** Four representative colors for a theme card's preview strip. */
243
243
  function themeSwatch(def) {
244
244
  const tk = def.tokens || {};
@@ -292,62 +292,62 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
292
292
  document.head.appendChild(tag);
293
293
  }
294
294
  var Market_module_css_default = {
295
- "dangerBtn": "eGUBIq_dangerBtn",
296
- "top": "eGUBIq_top",
295
+ "warnBtn": "eGUBIq_warnBtn",
296
+ "star": "eGUBIq_star",
297
297
  "catsWrap": "eGUBIq_catsWrap",
298
- "catsToggle": "eGUBIq_catsToggle",
299
- "grid": "eGUBIq_grid",
298
+ "row1": "eGUBIq_row1",
299
+ "owner": "eGUBIq_owner",
300
+ "spin": "eGUBIq_spin",
301
+ "empty": "eGUBIq_empty",
302
+ "sub": "eGUBIq_sub",
303
+ "dangerArmed": "eGUBIq_dangerArmed",
304
+ "warnLine": "eGUBIq_warnLine",
305
+ "tabs": "eGUBIq_tabs",
306
+ "title": "eGUBIq_title",
307
+ "sort": "eGUBIq_sort",
308
+ "tab": "eGUBIq_tab",
309
+ "themesGrid": "eGUBIq_themesGrid",
310
+ "root": "eGUBIq_root",
300
311
  "grow": "eGUBIq_grow",
301
- "titleRow": "eGUBIq_titleRow",
302
312
  "staleAction": "eGUBIq_staleAction",
303
- "modalNote": "eGUBIq_modalNote",
304
- "star": "eGUBIq_star",
305
- "sect": "eGUBIq_sect",
306
- "row1": "eGUBIq_row1",
307
- "av": "eGUBIq_av",
308
- "warnBtn": "eGUBIq_warnBtn",
309
- "pct": "eGUBIq_pct",
310
- "loading": "eGUBIq_loading",
313
+ "cmdDetails": "eGUBIq_cmdDetails",
311
314
  "cancelBtn": "eGUBIq_cancelBtn",
312
- "spec": "eGUBIq_spec",
315
+ "nm": "eGUBIq_nm",
316
+ "desc": "eGUBIq_desc",
317
+ "catsToggle": "eGUBIq_catsToggle",
318
+ "irow": "eGUBIq_irow",
319
+ "loading": "eGUBIq_loading",
320
+ "cmd": "eGUBIq_cmd",
321
+ "restart": "eGUBIq_restart",
322
+ "sect": "eGUBIq_sect",
323
+ "titleRow": "eGUBIq_titleRow",
313
324
  "catsRow": "eGUBIq_catsRow",
325
+ "dangerBtn": "eGUBIq_dangerBtn",
326
+ "dot": "eGUBIq_dot",
314
327
  "cats": "eGUBIq_cats",
315
- "themesGrid": "eGUBIq_themesGrid",
316
328
  "progress": "eGUBIq_progress",
317
- "descTight": "eGUBIq_descTight",
318
- "irow": "eGUBIq_irow",
319
- "card": "eGUBIq_card",
320
- "owner": "eGUBIq_owner",
321
- "warnLine": "eGUBIq_warnLine",
322
- "nm": "eGUBIq_nm",
323
- "dangerArmed": "eGUBIq_dangerArmed",
324
- "desc": "eGUBIq_desc",
325
- "empty": "eGUBIq_empty",
326
- "src": "eGUBIq_src",
327
- "body": "eGUBIq_body",
329
+ "sp": "eGUBIq_sp",
328
330
  "err": "eGUBIq_err",
331
+ "spec": "eGUBIq_spec",
332
+ "pct": "eGUBIq_pct",
333
+ "tag": "eGUBIq_tag",
329
334
  "catsCollapsed": "eGUBIq_catsCollapsed",
330
- "tab": "eGUBIq_tab",
335
+ "src": "eGUBIq_src",
336
+ "cmdSummary": "eGUBIq_cmdSummary",
331
337
  "on": "eGUBIq_on",
332
- "sort": "eGUBIq_sort",
333
- "cmd": "eGUBIq_cmd",
334
- "tag": "eGUBIq_tag",
335
- "head": "eGUBIq_head",
336
- "okState": "eGUBIq_okState",
337
- "root": "eGUBIq_root",
338
- "tabs": "eGUBIq_tabs",
339
- "dot": "eGUBIq_dot",
340
- "title": "eGUBIq_title",
341
- "sp": "eGUBIq_sp",
342
- "sub": "eGUBIq_sub",
343
- "restart": "eGUBIq_restart",
344
- "swatches": "eGUBIq_swatches",
345
- "cmdDetails": "eGUBIq_cmdDetails",
346
- "foot": "eGUBIq_foot",
347
- "spin": "eGUBIq_spin",
348
338
  "sentinel": "eGUBIq_sentinel",
349
- "cmdSummary": "eGUBIq_cmdSummary",
350
- "searchInline": "eGUBIq_searchInline"
339
+ "searchInline": "eGUBIq_searchInline",
340
+ "foot": "eGUBIq_foot",
341
+ "swatches": "eGUBIq_swatches",
342
+ "modalNote": "eGUBIq_modalNote",
343
+ "body": "eGUBIq_body",
344
+ "descTight": "eGUBIq_descTight",
345
+ "av": "eGUBIq_av",
346
+ "top": "eGUBIq_top",
347
+ "okState": "eGUBIq_okState",
348
+ "card": "eGUBIq_card",
349
+ "head": "eGUBIq_head",
350
+ "grid": "eGUBIq_grid"
351
351
  };
352
352
  //#endregion
353
353
  //#region src/client/MarketSection.tsx
@@ -376,6 +376,31 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
376
376
  });
377
377
  }
378
378
  /**
379
+ * Official-style market glyph: the shared block-grid brand mark converted to
380
+ * the official monochrome icon form (16×16, fill="currentColor") so it
381
+ * follows the active theme. Mirrors the settings-nav glyph used for the
382
+ * "market" section id.
383
+ */
384
+ function MarketLogo({ size = 16, style }) {
385
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
386
+ width: size,
387
+ height: size,
388
+ viewBox: "0 0 16 16",
389
+ fill: "none",
390
+ xmlns: "http://www.w3.org/2000/svg",
391
+ "aria-hidden": "true",
392
+ style,
393
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
394
+ fill: "currentColor",
395
+ d: "M2.35 1.75H4.95A0.6 0.6 0 0 1 5.55 2.35V4.95A0.6 0.6 0 0 1 4.95 5.55H2.35A0.6 0.6 0 0 1 1.75 4.95V2.35A0.6 0.6 0 0 1 2.35 1.75ZM6.7 1.75H9.3A0.6 0.6 0 0 1 9.9 2.35V4.95A0.6 0.6 0 0 1 9.3 5.55H6.7A0.6 0.6 0 0 1 6.1 4.95V2.35A0.6 0.6 0 0 1 6.7 1.75ZM2.35 6.1H4.95A0.6 0.6 0 0 1 5.55 6.7V9.3A0.6 0.6 0 0 1 4.95 9.9H2.35A0.6 0.6 0 0 1 1.75 9.3V6.7A0.6 0.6 0 0 1 2.35 6.1ZM6.7 6.1H9.3A0.6 0.6 0 0 1 9.9 6.7V9.3A0.6 0.6 0 0 1 9.3 9.9H6.7A0.6 0.6 0 0 1 6.1 9.3V6.7A0.6 0.6 0 0 1 6.7 6.1ZM11.05 6.1H13.65A0.6 0.6 0 0 1 14.25 6.7V9.3A0.6 0.6 0 0 1 13.65 9.9H11.05A0.6 0.6 0 0 1 10.45 9.3V6.7A0.6 0.6 0 0 1 11.05 6.1ZM2.35 10.45H4.95A0.6 0.6 0 0 1 5.55 11.05V13.65A0.6 0.6 0 0 1 4.95 14.25H2.35A0.6 0.6 0 0 1 1.75 13.65V11.05A0.6 0.6 0 0 1 2.35 10.45ZM6.7 10.45H9.3A0.6 0.6 0 0 1 9.9 11.05V13.65A0.6 0.6 0 0 1 9.3 14.25H6.7A0.6 0.6 0 0 1 6.1 13.65V11.05A0.6 0.6 0 0 1 6.7 10.45ZM11.05 10.45H13.65A0.6 0.6 0 0 1 14.25 11.05V13.65A0.6 0.6 0 0 1 13.65 14.25H11.05A0.6 0.6 0 0 1 10.45 13.65V11.05A0.6 0.6 0 0 1 11.05 10.45Z"
396
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
397
+ fill: "currentColor",
398
+ d: "M11.05 1.75H13.65A0.6 0.6 0 0 1 14.25 2.35V4.95A0.6 0.6 0 0 1 13.65 5.55H11.05A0.6 0.6 0 0 1 10.45 4.95V2.35A0.6 0.6 0 0 1 11.05 1.75Z",
399
+ transform: "rotate(9 12.35 3.65)"
400
+ })]
401
+ });
402
+ }
403
+ /**
379
404
  * Module-scope caches so re-entering the section renders instantly instead
380
405
  * of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
381
406
  * state survives section switches; a background refetch keeps it current.
@@ -404,6 +429,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
404
429
  const [cat, setCat] = (0, react.useState)("all");
405
430
  const [confirming, setConfirming] = (0, react.useState)(null);
406
431
  const [busyUrl, setBusyUrl] = (0, react.useState)(null);
432
+ /** Consecutive idle polls with a pending install that never landed (#32). */
433
+ const idleStrikes = (0, react.useRef)(0);
407
434
  const [doneUrls, setDoneUrls] = (0, react.useState)([]);
408
435
  const [installError, setInstallError] = (0, react.useState)(null);
409
436
  const [updates, setUpdates] = (0, react.useState)({});
@@ -504,7 +531,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
504
531
  body: "{}"
505
532
  }).then((res) => res.json()).then((body) => {
506
533
  if (body.ok) setEnvReady(true);
507
- else setEnvFailed(true);
534
+ else {
535
+ setEnvFailed(true);
536
+ if (typeof body.error === "string") setInstallError(body.error);
537
+ }
508
538
  }).catch(() => setEnvFailed(true)).finally(() => setEnvFixing(false));
509
539
  }, []);
510
540
  (0, react.useEffect)(() => {
@@ -531,9 +561,15 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
531
561
  setInstalled(status.installed || {});
532
562
  if (readSession("dshm-pending") !== null && busyUrl !== null) {
533
563
  if (data !== null && data.plugins.some((p) => p.url === busyUrl && isInstalled(p, status.installed || {}))) {
564
+ idleStrikes.current = 0;
534
565
  sessionStorage.removeItem("dshm-pending");
535
566
  setDoneUrls((urls) => urls.includes(busyUrl) ? urls : urls.concat(busyUrl));
536
567
  setBusyUrl(null);
568
+ } else if (++idleStrikes.current >= 2) {
569
+ idleStrikes.current = 0;
570
+ sessionStorage.removeItem("dshm-pending");
571
+ setBusyUrl(null);
572
+ setInstallError(t("installFail") + " — " + t("exportLog"));
537
573
  }
538
574
  }
539
575
  }
@@ -1014,15 +1050,9 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
1014
1050
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1015
1051
  className: Market_module_css_default.titleRow,
1016
1052
  children: [
1017
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1018
- src: LOGO_URI,
1019
- width: 22,
1020
- height: 22,
1021
- alt: "",
1022
- style: {
1023
- borderRadius: "5px",
1024
- flexShrink: 0
1025
- }
1053
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketLogo, {
1054
+ size: 22,
1055
+ style: { flexShrink: 0 }
1026
1056
  }),
1027
1057
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
1028
1058
  className: Market_module_css_default.title,
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","Toast","useState","css","useSyncExternalStore","useCallback","useRef","useMemo","themePlugins","themePluginsOf","Button","StateDot","Input","IconSearchOutline16","Pill","IconChevronUpOutline14","IconChevronDownOutline14","Modal","h"],"sources":["../src/client/locales.ts","../src/client/market-data.ts","../src/client/InstallToast.tsx","../src/client/MarketSection.tsx","../src/client/index.ts"],"sourcesContent":["/** zh/en dictionaries for the Market settings section and install toast. */\n\nexport const zh = {\n nav: '插件市场',\n subtitle: '发现社区为 DeepSeek Harness 打造的能力',\n searchPh: '搜索插件,比如:通知、终端、记忆…',\n tabDiscover: '发现',\n tabInstalled: '已安装',\n all: '全部',\n install: '安装',\n installing: '安装中…',\n installedBadge: '✓ 已装好',\n alreadyInstalled: '✓ 已安装',\n restartBanner: '项变更完成,重启 DeepSeek Harness 后生效',\n uninstall: '卸载',\n confirmRemove: '确认卸载?',\n uninstalling: '卸载中…',\n restartHint: '重启方式:关闭当前 dsh 进程后重新运行(例如 dsh web)',\n confirmTitle: '安装',\n confirmWarn: '插件是社区第三方代码。安装即表示你信任该来源;构建脚本默认被禁止执行。',\n cancel: '取消',\n empty: '没有匹配的插件',\n installedEmpty: '还没有装过社区插件,去「发现」页逛逛吧',\n loadFail: '插件目录加载失败,请稍后重试',\n installFail: '安装失败',\n viewSource: '源码',\n hotBanner: '个新插件已装好,刷新页面即可使用',\n refresh: '刷新页面',\n update: '更新',\n updating: '更新中…',\n updated: '✓ 已更新,重启后生效',\n cancelOp: '取消',\n cancelled: '已取消',\n busyWait: '已有操作正在进行,请等它结束(同一时间只执行一个安装/更新/卸载)',\n approveBuilds: '放行构建脚本并重试',\n buildsSkipped: '该插件需要运行构建脚本才能工作,出于安全默认被拦下。点击下方按钮为它放行并重装:',\n restartNow: '立即重启',\n restarting: '正在重启…',\n restartFail: '重启失败',\n restartTimeout: '等待 DeepSeek Harness 启动超时',\n updateNow: '立即更新',\n updateFail: '更新失败',\n upToDate: '已是最新',\n linkedDev: '本地开发链接',\n exportLog: '导出日志',\n readme: '使用说明',\n terminalWarn: '这看起来是终端/命令行插件:装进网页版可能无效,甚至导致 DeepSeek Harness 无法启动。建议先看它的使用说明,按说明装进对应的 profile。',\n envMissing: '还差一个小组件才能安装插件',\n envFix: '自动装好',\n envFixing: '正在准备…',\n envFixFail: '自动准备没成功,请点\"导出日志\"把文件发给我们反馈',\n loading: '正在加载插件目录…',\n backTop: '回到顶部',\n confirm: '确认',\n cmdDetails: '安装命令',\n catsMore: '更多分类',\n catsLess: '收起',\n sortHot: '最热',\n sortNew: '最新',\n marketUpdate: '市场有新版本,升级',\n updateAll: '全部更新',\n tabThemes: '主题',\n themeApply: '使用',\n themeActive: '使用中',\n themeEmpty: '目录里暂时还没有主题,敬请期待',\n progressHint: '首次安装需要下载与解析依赖,大插件可能要 1-3 分钟',\n toastReady: '已装好并已生效',\n toastTheme: '已启用。到 设置 → 插件市场 → 主题 可随时切换',\n gotIt: '知道了',\n}\n\n/** A dictionary key; zh is the source of truth, en mirrors it 1:1. */\nexport type MarketKey = keyof typeof zh\n\nexport const en: Record<MarketKey, string> = {\n nav: 'Plugin Market',\n subtitle: 'Discover community plugins for DeepSeek Harness',\n searchPh: 'Search plugins: notify, terminal, memory…',\n tabDiscover: 'Discover',\n tabInstalled: 'Installed',\n all: 'All',\n install: 'Install',\n installing: 'Installing…',\n installedBadge: '✓ Installed',\n alreadyInstalled: '✓ Installed',\n restartBanner: 'change(s) done — restart DeepSeek Harness to apply',\n uninstall: 'Uninstall',\n confirmRemove: 'Confirm?',\n uninstalling: 'Removing…',\n restartHint: 'To restart: stop the current dsh process and run it again (e.g. dsh web)',\n confirmTitle: 'Install',\n confirmWarn: 'Plugins are third-party community code. Installing means you trust this source; build scripts are blocked by default.',\n cancel: 'Cancel',\n empty: 'No plugins match',\n installedEmpty: 'No community plugins yet — browse the Discover tab',\n loadFail: 'Failed to load the plugin catalog, please retry later',\n installFail: 'Install failed',\n viewSource: 'Source',\n hotBanner: 'new plugin(s) ready — refresh the page to use them',\n refresh: 'Refresh',\n update: 'Update',\n updating: 'Updating…',\n updated: '✓ Updated — restart to apply',\n cancelOp: 'Cancel',\n cancelled: 'Cancelled',\n busyWait: 'Another operation is already running — please wait for it to finish (one install/update/uninstall at a time)',\n approveBuilds: 'Allow build scripts and retry',\n buildsSkipped: 'This plugin needs its build scripts to run; they are blocked by default for safety. Click below to allow them and reinstall:',\n restartNow: 'Restart now',\n restarting: 'Restarting…',\n restartFail: 'Restart failed',\n restartTimeout: 'Timed out waiting for DeepSeek Harness to start',\n updateNow: 'Update now',\n updateFail: 'Update failed',\n upToDate: 'Up to date',\n linkedDev: 'linked (dev)',\n exportLog: 'Export log',\n readme: 'README',\n terminalWarn: 'This looks like a terminal/CLI plugin: installing it into the web profile may do nothing, or even break DeepSeek Harness startup. Read its README and install it into the profile it targets.',\n envMissing: 'One small component is needed before installing plugins',\n envFix: 'Set up automatically',\n envFixing: 'Setting up…',\n envFixFail: 'Automatic setup failed — please use \"Export log\" and send us the file',\n loading: 'Loading the catalog…',\n backTop: 'Back to top',\n confirm: 'Confirm',\n cmdDetails: 'Install command',\n catsMore: 'More',\n catsLess: 'Less',\n sortHot: 'Top',\n sortNew: 'New',\n marketUpdate: 'Market update available — upgrade',\n updateAll: 'Update all',\n tabThemes: 'Themes',\n themeApply: 'Use',\n themeActive: 'Active',\n themeEmpty: 'No more theme plugins in the catalog yet — stay tuned',\n progressHint: 'First installs download and resolve dependencies — large plugins can take 1-3 minutes',\n toastReady: 'installed and live',\n toastTheme: 'is now active. Switch any time in Settings → Plugin Market → Themes',\n gotIt: 'Got it',\n}\n","/**\n * Response shapes of the /dsh-market/* host routes plus the pure helpers the\n * Market UI shares between its section and toast components.\n */\n\n/** Localized text keyed by language ('zh' / 'en'). */\nexport type LocalizedText = Record<string, string | undefined>\n\n/** One registry entry from /dsh-market/registry. */\nexport interface RegistryPlugin {\n name: string\n owner: string\n url: string\n npm?: string\n category: string\n description?: LocalizedText\n stars?: number\n added?: string\n install?: string\n}\n\n/** The catalog payload under `registry` in /dsh-market/registry. */\nexport interface Registry {\n count: number\n categories: Record<string, LocalizedText>\n plugins: RegistryPlugin[]\n}\n\n/** Profile dependency map: package name → install spec. */\nexport type InstalledMap = Record<string, string>\n\n/** Per-package update status from /dsh-market/updates. */\nexport interface UpdateStatus {\n updateAvailable?: boolean\n version?: string\n kind?: string\n}\n\n/** Poll payload from /dsh-market/status. */\nexport interface MarketStatus {\n active?: boolean\n lastLine?: string\n seconds?: number\n installed?: InstalledMap\n pnpm?: boolean\n boot?: string\n}\n\n/** Registered theme definition surfaced by the theme service snapshot. */\nexport interface ThemeDef {\n id: string\n colorScheme?: string\n tokens?: Record<string, string | undefined>\n}\n\n/** Theme service snapshot; null when the composition has no theme service. */\nexport interface ThemeSnapshot {\n preference: string\n themes: ThemeDef[]\n}\n\n/** Bound locale translator for the dsh-market namespace. */\nexport type Translate = (key: string) => string\n\nexport function avatarColor(name: string): string {\n let hash = 0\n for (let i = 0; i < name.length; i++) hash = (hash * 31 + name.charCodeAt(i)) | 0\n return 'hsl(' + (((hash % 360) + 360) % 360) + ' 55% 52%)'\n}\n\nexport function repoOf(url: string): string | null {\n // Plain repo urls plus /tree/<branch>/<subpath> monorepo links.\n const m = /^https:\\/\\/github\\.com\\/([^/]+\\/[^/]+?)(?:\\/tree\\/.+)?\\/?$/.exec(url)\n return m ? m[1]! : null\n}\n\nexport function readSession(key: string): any {\n try { return JSON.parse(sessionStorage.getItem(key) || 'null') } catch { return null }\n}\n\n/** Heuristic: plugins that target a terminal surface rather than the web UI. */\nexport function looksTerminal(plugin: RegistryPlugin, lang: string): boolean {\n const desc = (plugin.description && (plugin.description[lang] || plugin.description.en)) || ''\n return /\\b(tui|cli|tty|terminal)\\b|终端|命令行/i.test(plugin.name + ' ' + desc)\n}\n\n/** Filters and sort order driving the discover list. */\nexport interface ListQuery {\n /** Active category id, or 'all'. */\n category: string\n /** Raw search input (trimmed and lowercased internally). */\n query: string\n /** UI language for description matching ('zh' / 'en'). */\n lang: string\n /** 'hot' (stars desc), 'new' (added desc), anything else keeps registry order. */\n sort: string\n}\n\n/**\n * The discover list: category filter, then search across name / owner /\n * localized description, then the selected sort. Pure — the section renders\n * exactly this.\n */\nexport function visiblePlugins(plugins: RegistryPlugin[], options: ListQuery): RegistryPlugin[] {\n const query = options.query.trim().toLowerCase()\n const list = plugins.filter((p) => {\n if (options.category !== 'all' && p.category !== options.category) return false\n if (query === '') return true\n const desc = (p.description && (p.description[options.lang] || p.description.en)) || ''\n return p.name.toLowerCase().includes(query)\n || p.owner.toLowerCase().includes(query)\n || desc.toLowerCase().includes(query)\n })\n if (options.sort === 'hot') {\n return [...list].sort((a, b) => (b.stars ?? -1) - (a.stars ?? -1))\n }\n if (options.sort === 'new') {\n return [...list].sort((a, b) => String(b.added).localeCompare(String(a.added)))\n }\n return list\n}\n\n/** The themes tab listing: theme category only, most-starred first. */\nexport function themePlugins(plugins: RegistryPlugin[]): RegistryPlugin[] {\n return plugins.filter(p => p.category === 'theme').sort((a, b) => (b.stars || 0) - (a.stars || 0))\n}\n\n/**\n * Category chip order: collapsed with an active non-'all' chip, the active\n * one moves to the front so it stays visible inside the two-row clip.\n */\nexport function orderedCategories(categories: string[], active: string, open: boolean): string[] {\n return open || active === 'all' ? categories : [active, ...categories.filter(id => id !== active)]\n}\n\n/**\n * Unified installed-state matching (#15): both sides collapse to lowercase\n * identity sets — the registry entry contributes its bare name, npm name and\n * owner/repo; the dependency contributes its key and the repo inside its\n * spec — and any exact intersection counts. Exact equality, not substrings,\n * so prefix-related repo names cannot cross-match.\n */\nfunction entryIdentities(plugin: RegistryPlugin): Set<string> {\n const ids = new Set<string>([plugin.name.toLowerCase()])\n if (plugin.npm) ids.add(plugin.npm.toLowerCase())\n // Subpath-aware: a /tree/ entry identifies as repo#path:/sub, never the\n // bare repo — two subpackages of one monorepo must not cross-match.\n const m = /^https:\\/\\/github\\.com\\/([^/]+\\/[^/]+?)(?:\\/tree\\/[^/]+\\/(.+?))?\\/?$/.exec(plugin.url)\n if (m !== null) {\n ids.add(m[2] !== undefined ? `${m[1]!.toLowerCase()}#path:/${m[2].toLowerCase()}` : m[1]!.toLowerCase())\n }\n return ids\n}\n\nfunction depIdentities(name: string, spec: string): Set<string> {\n const ids = new Set<string>([name.toLowerCase()])\n // A scoped npm key usually mirrors owner/repo — expose that identity so an\n // npm-installed plugin still matches an entry whose npm field is unset.\n const scoped = /^@([^/]+)\\/(.+)$/.exec(name)\n if (scoped !== null) ids.add(`${scoped[1]!.toLowerCase()}/${scoped[2]!.toLowerCase()}`)\n const match = /github:([A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+)(?:#path:\\/([A-Za-z0-9_./-]+))?/i.exec(spec)\n if (match !== null) {\n ids.add(match[1]!.toLowerCase())\n if (match[2] !== undefined) ids.add(`${match[1]!.toLowerCase()}#path:/${match[2].toLowerCase()}`)\n }\n return ids\n}\n\n/** The installed dependency name a registry entry corresponds to, or null. */\nexport function matchInstalledName(plugin: RegistryPlugin, installed: InstalledMap): string | null {\n const ids = entryIdentities(plugin)\n for (const [name, spec] of Object.entries(installed)) {\n for (const id of depIdentities(name, String(spec))) {\n if (ids.has(id)) return name\n }\n }\n return null\n}\n\n/** The registry entry an installed dependency corresponds to, or undefined. */\nexport function entryForDep(plugins: RegistryPlugin[], name: string, spec: string): RegistryPlugin | undefined {\n const ids = depIdentities(name, String(spec))\n return plugins.find((plugin) => {\n for (const id of entryIdentities(plugin)) if (ids.has(id)) return true\n return false\n })\n}\n\nexport function isInstalled(plugin: RegistryPlugin, installed: InstalledMap): boolean {\n return matchInstalledName(plugin, installed) !== null\n}\n\n/**\n * The brand mark (assets/logo.svg — shared block-grid mark with\n * awesome-dsh-plugin), inlined so the header needs no extra request.\n */\nexport const LOGO_URI = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\"><rect width=\"128\" height=\"128\" rx=\"28\" fill=\"#f6f2ea\"/><g transform=\"translate(15.7 16.7) scale(0.3) translate(-112 -78)\"><g fill=\"#2b2620\"><rect x=\"112\" y=\"112\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"112\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"112\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"112\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"212\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"312\" y=\"212\" width=\"88\" height=\"88\" rx=\"14\"/><rect x=\"312\" y=\"312\" width=\"88\" height=\"88\" rx=\"14\"/></g><rect x=\"346\" y=\"78\" width=\"88\" height=\"88\" rx=\"14\" fill=\"#c0392b\" transform=\"rotate(9 390 122)\"/></g></svg>')\n\n/** Four representative colors for a theme card's preview strip. */\nexport function themeSwatch(def: ThemeDef): string[] {\n const tk = def.tokens || {}\n const pick = (names: string[]) => { for (const n of names) { if (tk[n]) return tk[n]! } return null }\n const dark = def.colorScheme === 'dark'\n return [\n pick(['--dsw-alias-bg-base', '--dsw-alias-bg-layer-1']) || (dark ? '#0f1115' : '#ffffff'),\n pick(['--dsw-alias-bg-layer-2', '--dsw-alias-bg-overlay']) || (dark ? '#1a1d23' : '#f3f4f6'),\n pick(['--dsw-alias-brand-primary']) || '#4f6ef7',\n pick(['--dsw-alias-label-primary']) || (dark ? '#e5e7eb' : '#1f2328'),\n ]\n}\n","/**\n * Post-reload confirmation via the official Toast primitive: shown once after\n * the refresh that follows a hot install or theme switch, so the user lands\n * back in their flow with visible proof.\n */\nimport { useState } from 'react'\nimport { Toast } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { readSession } from './market-data.ts'\nimport type { Translate } from './market-data.ts'\n\nexport function InstallToast(props: { t: Translate }) {\n const t = props.t\n const [mode] = useState(() => {\n const value = sessionStorage.getItem('dshm-toast-mode')\n sessionStorage.removeItem('dshm-toast-mode')\n return value\n })\n const [names, setNames] = useState<string[]>(() => {\n const value = readSession('dshm-toast')\n sessionStorage.removeItem('dshm-toast')\n return Array.isArray(value) ? value : []\n })\n if (names.length === 0) return null\n return (\n <Toast\n text={names.join(', ') + ' ' + t(mode === 'theme' ? 'toastTheme' : 'toastReady')}\n icon={<span>✨</span>}\n onDone={() => setNames([])}\n />\n )\n}\n","/**\n * The Market settings section: Discover / Themes / Installed tabs over the\n * /dsh-market/* host routes, with install/update/uninstall flows and the\n * pending-restart bookkeeping in sessionStorage.\n */\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport { Button, IconChevronDownOutline14, IconChevronUpOutline14, IconSearchOutline16, Input, Modal, Pill, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'\nimport css from './Market.module.css'\nimport {\n avatarColor, entryForDep, isInstalled, LOGO_URI, looksTerminal, matchInstalledName, orderedCategories,\n readSession, repoOf, themePlugins as themePluginsOf, themeSwatch, visiblePlugins,\n} from './market-data.ts'\nimport type {\n InstalledMap, Registry, RegistryPlugin, ThemeSnapshot, Translate, UpdateStatus,\n} from './market-data.ts'\n\n/**\n * Card avatar: the plugin owner's GitHub avatar (no API, browser-cached),\n * falling back to the initial-letter tile when it can't load.\n */\nfunction OwnerAvatar({ name, owner }: { name: string; owner: string }) {\n const [failed, setFailed] = useState(false)\n if (failed || owner === '') {\n return (\n <div className={css.av} style={{ background: avatarColor(name) }}>\n {name.replace(/^dsh[-_]/i, '').charAt(0).toUpperCase() || 'P'}\n </div>\n )\n }\n return (\n <img\n className={css.av}\n src={`https://github.com/${encodeURIComponent(owner)}.png?size=96`}\n alt=\"\"\n loading=\"lazy\"\n onError={() => setFailed(true)}\n />\n )\n}\n\n/**\n * Module-scope caches so re-entering the section renders instantly instead\n * of refetching and rebuilding from a spinner (#30 by @StarsTom). Module\n * state survives section switches; a background refetch keeps it current.\n */\nlet cachedRegistry: Registry | null = null\nlet cachedInstalled: InstalledMap | null = null\n\nexport interface MarketSectionProps {\n t: Translate\n locale: {\n subscribe(callback: () => void): () => void\n getSnapshot(): { active: string }\n }\n theme: { setTheme(id: string): void }\n themeStore: {\n subscribe(callback: () => void): () => void\n getSnapshot(): ThemeSnapshot | null\n }\n}\n\nexport function MarketSection(props: MarketSectionProps) {\n const t = props.t\n const localeSnap = useSyncExternalStore(\n cb => props.locale.subscribe(cb),\n () => props.locale.getSnapshot(),\n )\n const lang = String(localeSnap.active).toLowerCase().startsWith('zh') ? 'zh' : 'en'\n // null when the composition has no theme service — the Themes tab hides.\n const themeSnap = useSyncExternalStore(\n props.themeStore.subscribe,\n props.themeStore.getSnapshot,\n )\n const [data, setData] = useState<Registry | null>(cachedRegistry)\n const [loadError, setLoadError] = useState(false)\n const [installed, setInstalledState] = useState<InstalledMap>(cachedInstalled ?? {})\n const setInstalled = useCallback((value: InstalledMap) => { cachedInstalled = value; setInstalledState(value) }, [])\n const [skins, setSkins] = useState<string[]>([])\n const [tab, setTab] = useState(() => {\n const saved = sessionStorage.getItem('dshm-tab')\n if (saved !== null) sessionStorage.removeItem('dshm-tab')\n return saved || 'discover'\n })\n const [q, setQ] = useState('')\n const [cat, setCat] = useState('all')\n const [confirming, setConfirming] = useState<RegistryPlugin | null>(null)\n const [busyUrl, setBusyUrl] = useState<string | null>(null)\n const [doneUrls, setDoneUrls] = useState<string[]>([])\n const [installError, setInstallError] = useState<string | null>(null)\n const [updates, setUpdates] = useState<Record<string, UpdateStatus>>({})\n const [updatingName, setUpdatingName] = useState<string | null>(null)\n // Plugin blocked by pnpm's fresh-release safety wait; arms the update-now button.\n const [staleName, setStaleName] = useState<string | null>(null)\n /**\n * Cards rendered so far — the discover grid renders incrementally (60,\n * then +120 as the sentinel scrolls into view) instead of all 400+ at\n * once, which built a ~70k px DOM and made section switches lag (#30).\n */\n const [visibleCount, setVisibleCount] = useState(60)\n const sentinelRef = useCallback((node: HTMLDivElement | null) => {\n if (node === null) return\n const observer = new IntersectionObserver((entries) => {\n if (entries.some(entry => entry.isIntersecting)) setVisibleCount(count => count + 120)\n }, { rootMargin: '600px' })\n observer.observe(node)\n // Cleanup runs when React detaches the node and calls back with null;\n // the observer dies with the node, so a one-shot observe suffices.\n }, [])\n\n /** Determinate percent parsed from pnpm's Progress line, when available. */\n const [progressPct, setProgressPct] = useState<number | null>(null)\n /** Blocked build scripts from the last install: enables approve-and-retry (#6). */\n const [buildsSkipped, setBuildsSkipped] = useState<{ plugin: RegistryPlugin; names: string[] } | null>(null)\n const [updatingAll, setUpdatingAll] = useState(false)\n const [updatedNames, setUpdatedNames] = useState<string[]>([])\n const [hotUrls, setHotUrls] = useState<string[]>([])\n const [hotNames, setHotNames] = useState<string[]>([])\n const [progressLine, setProgressLine] = useState<string | null>(null)\n const [removeArmed, setRemoveArmed] = useState<string | null>(null)\n const [removingName, setRemovingName] = useState<string | null>(null)\n const [removedCount, setRemovedCount] = useState(0)\n const [envReady, setEnvReady] = useState(true)\n const [envFixing, setEnvFixing] = useState(false)\n const [envFailed, setEnvFailed] = useState(false)\n const [bootId, setBootId] = useState<string | null>(null)\n /** One-click restart (#14 by @ysyyhhh): server capability + in-flight state. */\n const [restartEnabled, setRestartEnabled] = useState(false)\n const [restarting, setRestarting] = useState(false)\n const [showTop, setShowTop] = useState(false)\n const bodyRef = useRef<HTMLDivElement | null>(null)\n const [sort, setSort] = useState('hot')\n const [catsOpen, setCatsOpen] = useState(false)\n // How many category pills fit in the two collapsed rows (measured once —\n // the settings panel width is fixed); null = measuring render with all\n // pills clamped, then slice so the chevron flows inline after the last one.\n const [visibleCats, setVisibleCats] = useState<number | null>(null)\n const catsWrapRef = useRef<HTMLDivElement | null>(null)\n\n const refreshInstalled = useCallback((force?: boolean) => {\n fetch('/dsh-market/installed', { cache: 'no-store' })\n .then(res => res.json())\n .then(body => {\n setInstalled(body.installed || {})\n setSkins(body.live || [])\n })\n .catch(() => {})\n fetch('/dsh-market/updates' + (force === true ? '?force=1' : ''), { cache: 'no-store' })\n .then(res => res.json())\n .then(body => setUpdates(body.updates || {}))\n .catch(() => {})\n }, [])\n\n useEffect(() => {\n fetch('/dsh-market/registry', { cache: 'no-store' })\n .then(res => { if (!res.ok) throw new Error('HTTP ' + res.status); return res.json() })\n .then(body => { cachedRegistry = body.registry; setData(body.registry) })\n .catch(() => setLoadError(true))\n fetch('/dsh-market/status', { cache: 'no-store' })\n .then(res => res.json())\n .then(status => {\n setEnvReady(status.pnpm !== false)\n if (typeof status.boot === 'string') setBootId(status.boot)\n setRestartEnabled(status.restart === true)\n })\n .catch(() => {})\n refreshInstalled()\n }, [refreshInstalled])\n\n // Pending-restart flags survive tab switches and page reloads, scoped to\n // one host process: a different boot id means the restart happened and the\n // stale banner must not resurrect.\n useEffect(() => {\n if (bootId === null) return\n const saved = readSession('dshm-restart')\n if (saved === null) return\n if (saved.boot !== bootId) {\n sessionStorage.removeItem('dshm-restart')\n return\n }\n if (Array.isArray(saved.doneUrls) && saved.doneUrls.length > 0) setDoneUrls(saved.doneUrls)\n if (Array.isArray(saved.updated) && saved.updated.length > 0) setUpdatedNames(saved.updated)\n if (typeof saved.removed === 'number' && saved.removed > 0) setRemovedCount(saved.removed)\n }, [bootId])\n\n useEffect(() => {\n if (bootId === null) return\n if (doneUrls.length === 0 && updatedNames.length === 0 && removedCount === 0) return\n sessionStorage.setItem('dshm-restart', JSON.stringify({\n boot: bootId,\n doneUrls,\n updated: updatedNames,\n removed: removedCount,\n }))\n }, [bootId, doneUrls, updatedNames, removedCount])\n\n const fixEnv = useCallback(() => {\n setEnvFixing(true)\n setEnvFailed(false)\n fetch('/dsh-market/setup-pnpm', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })\n .then(res => res.json())\n .then(body => {\n if (body.ok) setEnvReady(true)\n else setEnvFailed(true)\n })\n .catch(() => setEnvFailed(true))\n .finally(() => setEnvFixing(false))\n }, [])\n\n // Recover an install whose HTTP response was lost (page navigated away or\n // the connection dropped): the pending marker survives in sessionStorage and\n // the poll below converges the button state from the host's ground truth.\n useEffect(() => {\n const pending = readSession('dshm-pending')\n if (pending !== null && typeof pending.url === 'string') setBusyUrl(pending.url)\n }, [])\n\n useEffect(() => {\n if (busyUrl === null && updatingName === null) {\n setProgressLine(null)\n return\n }\n const timer = setInterval(() => {\n fetch('/dsh-market/status', { cache: 'no-store' })\n .then(res => res.json())\n .then(status => {\n if (status.active) {\n setProgressLine((status.lastLine || '…') + ' (' + status.seconds + 's)')\n const m = /resolved (\\d+), reused (\\d+), downloaded (\\d+), added (\\d+)/.exec(status.lastLine || '')\n if (m !== null && Number(m[1]) > 0) {\n const done = Number(m[2]) + Number(m[3]) + Number(m[4])\n setProgressPct(Math.max(4, Math.min(96, Math.round(done / Number(m[1]) * 100))))\n }\n } else {\n setProgressLine(null)\n setProgressPct(null)\n setInstalled(status.installed || {})\n const pending = readSession('dshm-pending')\n if (pending !== null && busyUrl !== null) {\n const nowInstalled = data !== null && data.plugins.some(p =>\n p.url === busyUrl && isInstalled(p, status.installed || {}))\n if (nowInstalled) {\n sessionStorage.removeItem('dshm-pending')\n setDoneUrls(urls => urls.includes(busyUrl) ? urls : urls.concat(busyUrl))\n setBusyUrl(null)\n }\n }\n }\n })\n .catch(() => {})\n }, 2000)\n return () => clearInterval(timer)\n }, [busyUrl, updatingName, data])\n\n const plugins = useMemo(\n () => (data === null ? [] : visiblePlugins(data.plugins, { category: cat, query: q, lang, sort })),\n [data, q, cat, lang, sort])\n\n useEffect(() => { setVisibleCount(60) }, [q, cat, sort])\n\n const doInstall = useCallback((plugin: RegistryPlugin) => {\n setBuildsSkipped(null)\n setConfirming(null)\n setInstallError(null)\n setBusyUrl(plugin.url)\n sessionStorage.setItem('dshm-pending', JSON.stringify({ url: plugin.url }))\n fetch('/dsh-market/install', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ url: plugin.url }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n sessionStorage.removeItem('dshm-pending')\n if (status === 200 && body.ok && body.hot && plugin.category === 'theme') {\n // Themes auto-activate on install; reload straight into the Themes\n // tab so the new look is on screen immediately.\n sessionStorage.setItem('dshm-toast', JSON.stringify([plugin.name]))\n sessionStorage.setItem('dshm-tab', 'themes')\n location.reload()\n return\n }\n if (body.cancelled === true) {\n // User-cancelled: quiet reset, nothing to report.\n refreshInstalled()\n return\n }\n if (status === 200 && body.ok) {\n sessionStorage.setItem('dshm-tab', 'installed')\n if (body.hot) {\n setHotUrls(urls => urls.includes(plugin.url) ? urls : urls.concat(plugin.url))\n setHotNames(names => names.includes(plugin.name) ? names : names.concat(plugin.name))\n } else {\n setDoneUrls(urls => urls.includes(plugin.url) ? urls : urls.concat(plugin.url))\n }\n refreshInstalled()\n } else {\n if (status === 409) {\n setInstallError(t('busyWait'))\n return\n }\n if (Array.isArray(body.ignoredBuilds) && body.ignoredBuilds.length > 0) {\n setBuildsSkipped({ plugin, names: body.ignoredBuilds.map(String) })\n }\n const text = (v: unknown) => typeof v === 'string' ? v : (v && typeof (v as any).text === 'string') ? (v as any).text : v == null ? '' : JSON.stringify(v)\n const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join('\\n').trim() || ('exit ' + body.exitCode)\n setInstallError(t('installFail') + ': ' + plugin.name + ' — ' + detail.trim().slice(-600))\n }\n })\n .catch(error => {\n sessionStorage.removeItem('dshm-pending')\n setInstallError(t('installFail') + ': ' + String(error))\n })\n .finally(() => setBusyUrl(null))\n }, [refreshInstalled, t])\n\n /**\n * Restart the host and reload once the boot id changes (#14 by @ysyyhhh).\n * The 202 races the process's SIGTERM, so network errors on the initial\n * request are expected and treated as \"restart under way\".\n */\n const doRestart = useCallback(() => {\n if (bootId === null || restarting) return\n const previousBoot = bootId\n setRestarting(true)\n setInstallError(null)\n const awaitNewBoot = () => {\n const deadline = Date.now() + 60000\n const poll = () => {\n fetch('/dsh-market/status', { cache: 'no-store' })\n .then(res => res.json())\n .then((next) => {\n if (typeof next.boot === 'string' && next.boot !== previousBoot) {\n location.reload()\n return\n }\n retry()\n })\n .catch(retry)\n }\n const retry = () => {\n if (Date.now() > deadline) {\n setRestarting(false)\n setInstallError(t('restartTimeout'))\n return\n }\n setTimeout(poll, 1500)\n }\n poll()\n }\n fetch('/dsh-market/restart', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (status !== 202 || body.ok !== true) {\n setRestarting(false)\n setInstallError(t('restartFail') + ': ' + String(body.error || ('HTTP ' + String(status))))\n return\n }\n awaitNewBoot()\n })\n .catch(awaitNewBoot) // the host may die mid-response; keep polling\n }, [bootId, restarting, t])\n\n /** Cancel the running plugin command (#6 by @qichuang321). */\n const doCancel = useCallback(() => {\n fetch('/dsh-market/cancel', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })\n .catch(() => {})\n }, [])\n\n const doUpdate = useCallback((name: string, force = false) => {\n setInstallError(null)\n setStaleName(null)\n setUpdatingName(name)\n return fetch('/dsh-market/update', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(force ? { name, force: true } : { name }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (body.cancelled === true) {\n refreshInstalled()\n return\n }\n if (status === 200 && body.ok) {\n setUpdatedNames(names => names.concat(name))\n refreshInstalled()\n } else {\n if (status === 409) { setInstallError(t('busyWait')); return }\n if (body.stale === true) setStaleName(name)\n const text = (v: unknown) => typeof v === 'string' ? v : (v && typeof (v as any).text === 'string') ? (v as any).text : v == null ? '' : JSON.stringify(v)\n const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join('\\n').trim() || ('exit ' + body.exitCode)\n setInstallError(t('updateFail') + ': ' + name + ' — ' + detail.trim().slice(-600))\n }\n })\n .catch(error => setInstallError(t('updateFail') + ': ' + String(error)))\n .finally(() => setUpdatingName(null))\n }, [refreshInstalled, t])\n\n const doUseSkin = useCallback((name: string) => {\n setInstallError(null)\n fetch('/dsh-market/use-skin', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (status === 200 && body.ok) {\n sessionStorage.setItem('dshm-toast', JSON.stringify([name]))\n sessionStorage.setItem('dshm-toast-mode', 'theme')\n sessionStorage.setItem('dshm-tab', 'themes')\n location.reload()\n } else {\n setInstallError(String(body.error || 'failed'))\n }\n })\n .catch(error => setInstallError(String(error)))\n }, [])\n\n const doUninstall = useCallback((name: string) => {\n setRemoveArmed(null)\n setInstallError(null)\n setRemovingName(name)\n return fetch('/dsh-market/uninstall', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (status === 200 && body.ok) {\n if (!body.hot) setRemovedCount(n => n + 1)\n refreshInstalled()\n } else {\n const text = (v: unknown) => typeof v === 'string' ? v : (v && typeof (v as any).text === 'string') ? (v as any).text : v == null ? '' : JSON.stringify(v)\n setInstallError((text(body.error) || text(body.stderr) || 'error').trim().slice(-600))\n }\n })\n .catch(error => setInstallError(String(error)))\n .finally(() => setRemovingName(null))\n }, [refreshInstalled])\n\n // The market itself stays out of the batch: its update reloads this page\n // mid-run, which would strand the remaining items.\n const selfName = installed['dshmarket'] !== undefined ? 'dshmarket' : 'dsh-market'\n const updatableNames = Object.keys(installed).filter(\n name => name !== selfName && !updatedNames.includes(name) && updates[name] && updates[name].updateAvailable,\n )\n\n const doUpdateAll = useCallback(() => {\n const names = updatableNames.slice()\n setUpdatingAll(true)\n const next = () => {\n const name = names.shift()\n if (name === undefined) {\n setUpdatingAll(false)\n return\n }\n doUpdate(name).then(next, next)\n }\n next()\n }, [updatableNames, doUpdate])\n\n const pendingRestart = doneUrls.length + updatedNames.length + removedCount\n const hasUpdates = Object.keys(installed).some(\n name => !updatedNames.includes(name) && updates[name] && updates[name].updateAvailable,\n )\n\n const themePlugins = data === null ? [] : themePluginsOf(data.plugins)\n\n const pluginCard = (p: RegistryPlugin) => {\n const desc = (p.description && (p.description[lang] || p.description.en)) || ''\n const done = doneUrls.includes(p.url) || hotUrls.includes(p.url)\n const already = isInstalled(p, installed)\n const busy = busyUrl === p.url\n return (\n <div key={p.url} className={css.card}>\n <div className={css.row1}>\n <OwnerAvatar name={p.name} owner={p.owner || ''} />\n <div style={{ minWidth: 0 }}>\n <div className={css.nm}>{p.name}</div>\n <div className={css.owner}>\n {p.owner}\n {typeof p.stars === 'number' && <span className={css.star}>{' · ★ ' + p.stars}</span>}\n </div>\n </div>\n <span className={css.grow} />\n <a className={css.src} href={p.url} target=\"_blank\" rel=\"noreferrer\" style={{ alignSelf: 'flex-start', flexShrink: 0 }}>{t('viewSource')}</a>\n </div>\n <div className={css.desc}>{desc}</div>\n <div className={css.foot}>\n <span className={css.tag}>\n {(data!.categories[p.category] && (data!.categories[p.category]![lang] || data!.categories[p.category]!.en)) || p.category}\n </span>\n <span className={css.grow} />\n {done\n ? <span className={css.okState}>{t('installedBadge')}</span>\n : already\n ? <span className={css.okState}>{t('alreadyInstalled')}</span>\n : busy\n ? <Button variant=\"primary\" size=\"sm\" disabled>{t('installing')}</Button>\n : (\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={busyUrl !== null || !envReady}\n onClick={() => setConfirming(p)}\n >{t('install')}</Button>\n )}\n </div>\n {busy && (\n <div className={css.progress}>\n <span className={css.spin} />\n <code className={css.grow}>{progressLine || t('progressHint')}</code>\n {progressPct !== null && <span className={css.pct}>{progressPct}%</span>}\n <button type=\"button\" className={css.cancelBtn} onClick={doCancel}>{t('cancelOp')}</button>\n </div>\n )}\n </div>\n )\n }\n\n const installedNameOf = (p: RegistryPlugin) => matchInstalledName(p, installed)\n\n // Plugins loaded at boot (bundle-layer skins) aren't in the shim list but\n // are just as live; the boot manifest is the page's own record of them.\n const bootEntries = (typeof window !== 'undefined' && window.__DSH_BOOT__ && Array.isArray(window.__DSH_BOOT__.entries))\n ? window.__DSH_BOOT__.entries\n : []\n\n // Unified card for the Themes tab: install → use/in-use → uninstall.\n const themePluginCard = (p: RegistryPlugin) => {\n const instName = installedNameOf(p)\n if (instName === null) return pluginCard(p)\n const mounted = skins.includes(instName) || bootEntries.some(e => e.id === instName)\n const desc = (p.description && (p.description[lang] || p.description.en)) || ''\n return (\n <div key={p.url} className={css.card}>\n <div className={css.row1}>\n <OwnerAvatar name={p.name} owner={p.owner || ''} />\n <div style={{ minWidth: 0 }}>\n <div className={css.nm}>{p.name}</div>\n <div className={css.owner}>\n {p.owner}\n {typeof p.stars === 'number' && <span className={css.star}>{' · ★ ' + p.stars}</span>}\n </div>\n </div>\n <span className={css.grow} />\n <a className={css.src} href={p.url} target=\"_blank\" rel=\"noreferrer\" style={{ alignSelf: 'flex-start', flexShrink: 0 }}>{t('viewSource')}</a>\n </div>\n <div className={css.desc}>{desc}</div>\n <div className={css.foot}>\n <span className={css.grow} />\n {removingName === instName\n ? <Button variant=\"outline\" size=\"sm\" className={css.dangerBtn} disabled>{t('uninstalling')}</Button>\n : removeArmed === instName\n ? (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.dangerArmed}\n onClick={() => doUninstall(instName).then(() => {\n if (mounted) {\n sessionStorage.setItem('dshm-tab', 'themes')\n location.reload()\n }\n })}\n >{t('confirmRemove')}</Button>\n )\n : <Button variant=\"outline\" size=\"sm\" className={css.dangerBtn} onClick={() => setRemoveArmed(instName)}>{t('uninstall')}</Button>}\n {mounted\n ? <span className={css.okState}>{t('themeActive')}</span>\n : <Button variant=\"primary\" size=\"sm\" onClick={() => doUseSkin(instName)}>{t('themeApply')}</Button>}\n </div>\n </div>\n )\n }\n\n const themeCard = (id: string, label: string, swatch: string[]) => {\n const active = themeSnap !== null && themeSnap.preference === id\n return (\n <div key={'th-' + id} className={css.card}>\n <div className={css.swatches}>{swatch.map((c, i) => <i key={i} style={{ background: c }} />)}</div>\n <div className={css.foot}>\n <span className={css.nm}>{label}</span>\n <span className={css.grow} />\n {active\n ? <span className={css.okState}>{t('themeActive')}</span>\n : (\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => { try { props.theme.setTheme(id) } catch (error) { setInstallError(String(error)) } }}\n >{t('themeApply')}</Button>\n )}\n </div>\n </div>\n )\n }\n\n const categories = data === null ? [] : Object.keys(data.categories)\n\n useLayoutEffect(() => { setVisibleCats(null) }, [lang, categories.length])\n useLayoutEffect(() => {\n if (catsOpen || visibleCats !== null) return\n const el = catsWrapRef.current\n if (el === null) return\n const chips = [...el.children].filter((c): c is HTMLElement => (c as HTMLElement).dataset?.chip === '1')\n if (chips.length === 0) return\n const first = chips[0]!\n const rowThreeTop = first.offsetTop + (first.offsetHeight + 6) * 2 - 3\n let fits = 0\n for (const chip of chips) { if (chip.offsetTop < rowThreeTop) fits += 1 }\n // Reserve the tail slot of row two for the chevron itself.\n setVisibleCats(fits >= chips.length ? fits : Math.max(1, fits - 1))\n }, [catsOpen, visibleCats, data])\n\n return (\n <div className={css.root}>\n <div className={css.head}>\n <div className={css.titleRow}>\n <img src={LOGO_URI} width={22} height={22} alt=\"\" style={{ borderRadius: '5px', flexShrink: 0 }} />\n <h2 className={css.title}>{t('nav')}</h2>\n {(() => {\n const self = installed['dshmarket'] !== undefined ? 'dshmarket' : 'dsh-market'\n return updates[self] && updates[self].updateAvailable && !updatedNames.includes(self)\n && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.warnBtn}\n disabled={updatingName !== null || busyUrl !== null}\n onClick={() => { setTab('installed'); doUpdate(self) }}\n >{updatingName === self ? t('updating') : t('marketUpdate')}</Button>\n )\n })()}\n {updatableNames.length >= 2 && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.warnBtn}\n disabled={updatingAll || updatingName !== null || busyUrl !== null || removingName !== null}\n onClick={() => { setTab('installed'); doUpdateAll() }}\n >{updatingAll ? t('updating') : t('updateAll') + ' (' + updatableNames.length + ')'}</Button>\n )}\n </div>\n <div className={css.sub}>\n {t('subtitle') + (data ? ' · ' + data.count : '') + ' · '}\n <a className={css.src} href=\"/dsh-market/logs\" download=\"dsh-market-log.txt\">{t('exportLog')}</a>\n </div>\n <div className={css.tabs}>\n <button className={tab === 'discover' ? `${css.tab} ${css.on}` : css.tab} onClick={() => setTab('discover')}>{t('tabDiscover')}</button>\n {themeSnap !== null && <button className={tab === 'themes' ? `${css.tab} ${css.on}` : css.tab} onClick={() => setTab('themes')}>{t('tabThemes')}</button>}\n <button className={tab === 'installed' ? `${css.tab} ${css.on}` : css.tab} onClick={() => { setTab('installed'); refreshInstalled(true) }}>\n {t('tabInstalled') + (Object.keys(installed).length > 0 ? ' (' + Object.keys(installed).length + ')' : '')}\n {hasUpdates && <StateDot state=\"error\" size={7} className={css.dot} />}\n </button>\n <span className={css.grow} />\n <Input className={css.searchInline} icon={<IconSearchOutline16 size={14} />} placeholder={t('searchPh')} value={q} onChange={e => setQ(e.target.value)} />\n </div>\n {!envReady && (\n <div className={css.restart}>\n <span>🧩</span>\n <span className={css.grow}>{envFailed ? t('envFixFail') : t('envMissing')}</span>\n {!envFailed && (\n <Button variant=\"primary\" size=\"sm\" disabled={envFixing} onClick={fixEnv}>\n {envFixing ? t('envFixing') : t('envFix')}\n </Button>\n )}\n </div>\n )}\n {hotUrls.length > 0 && (\n <div className={css.restart}>\n <span>✨</span>\n <span className={css.grow}><b>{hotUrls.length}</b> {t('hotBanner')}</span>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => {\n sessionStorage.setItem('dshm-toast', JSON.stringify(hotNames))\n sessionStorage.setItem('dshm-tab', 'installed')\n location.reload()\n }}\n >{t('refresh')}</Button>\n </div>\n )}\n {pendingRestart > 0 && (\n <div className={css.restart}>\n <span>🔄</span>\n <span className={css.grow}><b>{pendingRestart}</b> {t('restartBanner')}</span>\n <span title={t('restartHint')}>ℹ️</span>\n {restartEnabled && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={restarting || busyUrl !== null || updatingName !== null || removingName !== null}\n onClick={doRestart}\n >{restarting ? t('restarting') : t('restartNow')}</Button>\n )}\n </div>\n )}\n </div>\n {buildsSkipped !== null && (\n <div className={css.restart}>\n <span className={css.grow}>{t('buildsSkipped')} {buildsSkipped.names.join(', ')}</span>\n <Button\n size=\"sm\"\n disabled={busyUrl !== null}\n onClick={() => {\n const { plugin, names } = buildsSkipped\n setBuildsSkipped(null)\n fetch('/dsh-market/approve-builds', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ packages: names }),\n })\n .then(res => res.json())\n .then((body) => {\n if (body.ok) doInstall(plugin)\n else setInstallError(String(body.error || 'approve failed'))\n })\n .catch(error => setInstallError(String(error)))\n }}\n >{t('approveBuilds')}</Button>\n </div>\n )}\n {installError !== null && (\n <div className={css.err}>\n {installError}\n {staleName !== null && (\n <div className={css.staleAction}>\n <Button size=\"sm\" onClick={() => doUpdate(staleName, true)}>{t('updateNow')}</Button>\n </div>\n )}\n </div>\n )}\n <div\n className={css.body}\n ref={bodyRef}\n onScroll={e => setShowTop(e.currentTarget.scrollTop > 400)}\n >\n {tab === 'discover'\n ? loadError\n ? <div className={css.empty}>{t('loadFail')}</div>\n : data === null\n ? <div className={css.loading}><span className={css.spin} />{t('loading')}</div>\n : (\n <>\n <div className={css.cats}>\n <div className={css.catsRow}>\n <div ref={catsWrapRef} className={catsOpen || visibleCats === null ? `${css.catsWrap} ${css.catsCollapsed}` : css.catsWrap}>\n {(() => {\n // Collapsed, the selected category is pulled to the front so it never hides.\n const ordered = orderedCategories(categories, cat, catsOpen)\n const shown = catsOpen || visibleCats === null ? ordered : ordered.slice(0, Math.max(0, visibleCats - 1))\n return (\n <>\n <Pill data-chip=\"1\" active={cat === 'all'} onClick={() => setCat('all')}>{t('all')}</Pill>\n {shown.map(id => (\n <Pill\n key={id}\n data-chip=\"1\"\n active={cat === id}\n onClick={() => setCat(id)}\n >{(data.categories[id] && (data.categories[id]![lang] || data.categories[id]!.en)) || id}</Pill>\n ))}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={css.catsToggle}\n icon={catsOpen ? <IconChevronUpOutline14 size={14} /> : <IconChevronDownOutline14 size={14} />}\n aria-label={catsOpen ? t('catsLess') : t('catsMore')}\n onClick={() => setCatsOpen(o => !o)}\n />\n </>\n )\n })()}\n </div>\n <div className={css.sort}>\n {['hot', 'new'].map(key => (\n <button\n key={key}\n className={sort === key ? css.on : ''}\n onClick={() => setSort(key)}\n >{t(key === 'hot' ? 'sortHot' : 'sortNew')}</button>\n ))}\n </div>\n </div>\n </div>\n {plugins.length === 0\n ? <div className={css.empty}>{t('empty')}</div>\n : (\n <>\n <div className={css.grid}>{plugins.slice(0, visibleCount).map(pluginCard)}</div>\n {plugins.length > visibleCount && <div ref={sentinelRef} className={css.sentinel} />}\n </>\n )}\n </>\n )\n : tab === 'themes' && themeSnap !== null\n ? (\n <>\n {/* Light/dark/system live in the official Appearance setting; this\n tab only shows what that setting can't: registered third-party\n palettes (none in the wild yet) and installable theme plugins. */}\n {(() => {\n const extra = themeSnap.themes.filter(def => def.id !== 'light' && def.id !== 'dark')\n return extra.length > 0 && (\n <div className={`${css.grid} ${css.themesGrid}`}>\n {extra.map(def => themeCard(def.id, def.id, themeSwatch(def)))}\n </div>\n )\n })()}\n {data === null\n ? <div className={css.loading}><span className={css.spin} />{t('loading')}</div>\n : themePlugins.length === 0\n ? <div className={css.empty}>{t('themeEmpty')}</div>\n : <div className={css.grid}>{themePlugins.map(themePluginCard)}</div>}\n </>\n )\n : Object.keys(installed).length === 0\n ? <div className={css.empty}>{t('installedEmpty')}</div>\n : Object.entries(installed).map(([name, spec]) => {\n const entry = data === null ? undefined : entryForDep(data.plugins, name, String(spec))\n const status = updates[name]\n const version = status && status.version ? 'v' + status.version : ''\n const specText = String(spec)\n const ghSpec = /^github:([A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+?)(?:#|$)/.exec(specText)\n const repoUrl = entry !== undefined ? entry.url : ghSpec !== null ? 'https://github.com/' + ghSpec[1] : null\n return (\n <div key={name} className={css.irow}>\n <div style={{ minWidth: 0 }}>\n <div className={css.nm}>{name}{version && <span className={css.owner}>{' ' + version}</span>}</div>\n {repoUrl !== null\n ? <a className={`${css.spec} ${css.src}`} href={repoUrl} target=\"_blank\" rel=\"noreferrer\" style={{ display: 'inline-block' }}>{specText}</a>\n : <div className={css.spec}>{specText}</div>}\n {entry !== undefined && (\n <div className={`${css.desc} ${css.descTight}`}>\n {(entry.description && (entry.description[lang] || entry.description.en)) || ''}\n </div>\n )}\n {updatingName === name && (\n <div className={css.progress}>\n <span className={css.spin} />\n <code className={css.grow}>{progressLine || t('progressHint')}</code>\n {progressPct !== null && <span className={css.pct}>{progressPct}%</span>}\n <button type=\"button\" className={css.cancelBtn} onClick={doCancel}>{t('cancelOp')}</button>\n </div>\n )}\n </div>\n <span className={css.grow} />\n {repoUrl !== null && <a className={css.src} href={repoUrl + '#readme'} target=\"_blank\" rel=\"noreferrer\">{t('readme')}</a>}\n {updatedNames.includes(name)\n ? <span className={css.okState}>{t('updated')}</span>\n : updatingName === name\n ? <Button variant=\"primary\" size=\"sm\" className={css.warnBtn} disabled>{t('updating')}</Button>\n : status && status.updateAvailable\n ? (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.warnBtn}\n disabled={updatingName !== null}\n onClick={() => doUpdate(name)}\n >{t('update')}</Button>\n )\n : status && status.kind === 'linked'\n ? <span className={css.owner}>{t('linkedDev')}</span>\n : <span className={css.owner}>{t('upToDate')}</span>}\n {name !== 'dsh-market' && name !== 'dshmarket' && (\n removingName === name\n ? <Button variant=\"outline\" size=\"sm\" className={css.dangerBtn} disabled>{t('uninstalling')}</Button>\n : removeArmed === name\n ? (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.dangerArmed}\n onClick={() => doUninstall(name)}\n onMouseLeave={() => setRemoveArmed(null)}\n >{t('confirmRemove')}</Button>\n )\n : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className={css.dangerBtn}\n disabled={removingName !== null || busyUrl !== null || updatingName !== null}\n onClick={() => setRemoveArmed(name)}\n >{t('uninstall')}</Button>\n )\n )}\n </div>\n )\n })}\n </div>\n {showTop && (\n <button\n className={css.top}\n title={t('backTop')}\n onClick={() => { const el = bodyRef.current; if (el) el.scrollTo({ top: 0, behavior: 'smooth' }) }}\n >↑</button>\n )}\n {confirming !== null && (\n <Modal\n open\n onClose={() => setConfirming(null)}\n title={t('confirmTitle') + ' ' + confirming.name + '?'}\n description={(confirming.description && (confirming.description[lang] || confirming.description.en)) || ''}\n footer={(\n <>\n <Button variant=\"ghost\" onClick={() => setConfirming(null)}>{t('cancel')}</Button>\n <Button variant=\"primary\" onClick={() => doInstall(confirming)}>{t('confirm')}</Button>\n </>\n )}\n >\n <details className={css.cmdDetails}>\n <summary className={css.cmdSummary}>{t('cmdDetails')}</summary>\n <div className={css.cmd}>{confirming.install}</div>\n </details>\n {looksTerminal(confirming, lang) && (\n <p className={css.warnLine}>\n {'🖥️ ' + t('terminalWarn') + ' '}\n <a className={css.src} href={confirming.url + '#readme'} target=\"_blank\" rel=\"noreferrer\">{t('readme')}</a>\n </p>\n )}\n <p className={css.modalNote}>{'⚠️ ' + t('confirmWarn')}</p>\n </Modal>\n )}\n </div>\n )\n}\n","/**\n * dsh-market client: registers a \"Market\" settings section rendering the\n * plugin market UI, plus the post-install toast in the shell overlay layer.\n * Built by tsdown into the __ModuleLoader__ factory bundle at\n * client/client.js; the only externals are the loader module table's react\n * entries.\n */\nimport { createElement as h } from 'react'\nimport { en, zh } from './locales.ts'\nimport { InstallToast } from './InstallToast.tsx'\nimport { MarketSection } from './MarketSection.tsx'\nimport type { ThemeSnapshot, Translate } from './market-data.ts'\n\nconst NS = 'dsh-market'\n\n/** The subset of the theme service this plugin touches. */\ninterface ThemeService {\n getTheme(): ThemeSnapshot | null\n setTheme(id: string): void\n}\n\n/** The subset of the locale service this plugin touches. */\ninterface LocaleService {\n register(namespace: string, dicts: { zh: Record<string, string>; en: Record<string, string> }): unknown\n bind(namespace: string): Translate\n subscribe(callback: () => void): () => void\n getSnapshot(): { active: string }\n}\n\n/** The subset of the slots service this plugin touches. */\ninterface SlotsService {\n inject(slot: string, register: () => unknown): void\n register(meta: Record<string, unknown>, component: () => unknown): unknown\n}\n\n/** The client cordis context shape this plugin relies on (structural: the\n * host provides the real Context; typing the touched surface keeps this\n * external package free of monorepo-internal type dependencies). */\ninterface MarketClientContext {\n effect(callback: () => unknown, label?: string): void\n on(event: string, callback: () => void): () => void\n locale: LocaleService\n slots: SlotsService\n theme: ThemeService\n}\n\nexport const name = 'dsh-market'\n// 'theme' is safe to require: ui-layout (mandatory in every web composition)\n// already hard-depends on it. This cordis's object-form inject means\n// intercept config, NOT {required,optional} — do not use it here.\nexport const inject = ['slots', 'locale', 'theme']\nexport function apply(ctx: MarketClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-market: dictionaries')\n const t = ctx.locale.bind(NS)\n\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'market',\n order: 40,\n label: () => t('nav'),\n locale: NS,\n inject: () => ({ t }),\n }, () => h(MarketSection, {\n t,\n locale: ctx.locale,\n theme: ctx.theme,\n themeStore: {\n subscribe: (cb: () => void) => ctx.on('theme/change', cb),\n getSnapshot: () => ctx.theme.getTheme(),\n },\n })))\n\n const Toast = () => h(InstallToast, { t })\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\n id: 'dsh-market-toast',\n label: () => 'dsh-market',\n }, Toast))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useState","Toast","useState","css","useSyncExternalStore","useCallback","useRef","useMemo","themePlugins","themePluginsOf","Button","StateDot","Input","IconSearchOutline16","Pill","IconChevronUpOutline14","IconChevronDownOutline14","Modal","h"],"sources":["../src/client/locales.ts","../src/client/market-data.ts","../src/client/InstallToast.tsx","../src/client/MarketSection.tsx","../src/client/index.ts"],"sourcesContent":["/** zh/en dictionaries for the Market settings section and install toast. */\n\nexport const zh = {\n nav: '插件市场',\n subtitle: '发现社区为 DeepSeek Harness 打造的能力',\n searchPh: '搜索插件,比如:通知、终端、记忆…',\n tabDiscover: '发现',\n tabInstalled: '已安装',\n all: '全部',\n install: '安装',\n installing: '安装中…',\n installedBadge: '✓ 已装好',\n alreadyInstalled: '✓ 已安装',\n restartBanner: '项变更完成,重启 DeepSeek Harness 后生效',\n uninstall: '卸载',\n confirmRemove: '确认卸载?',\n uninstalling: '卸载中…',\n restartHint: '重启方式:关闭当前 dsh 进程后重新运行(例如 dsh web)',\n confirmTitle: '安装',\n confirmWarn: '插件是社区第三方代码。安装即表示你信任该来源;构建脚本默认被禁止执行。',\n cancel: '取消',\n empty: '没有匹配的插件',\n installedEmpty: '还没有装过社区插件,去「发现」页逛逛吧',\n loadFail: '插件目录加载失败,请稍后重试',\n installFail: '安装失败',\n viewSource: '源码',\n hotBanner: '个新插件已装好,刷新页面即可使用',\n refresh: '刷新页面',\n update: '更新',\n updating: '更新中…',\n updated: '✓ 已更新,重启后生效',\n cancelOp: '取消',\n cancelled: '已取消',\n busyWait: '已有操作正在进行,请等它结束(同一时间只执行一个安装/更新/卸载)',\n approveBuilds: '放行构建脚本并重试',\n buildsSkipped: '该插件需要运行构建脚本才能工作,出于安全默认被拦下。点击下方按钮为它放行并重装:',\n restartNow: '立即重启',\n restarting: '正在重启…',\n restartFail: '重启失败',\n restartTimeout: '等待 DeepSeek Harness 启动超时',\n updateNow: '立即更新',\n updateFail: '更新失败',\n upToDate: '已是最新',\n linkedDev: '本地开发链接',\n exportLog: '导出日志',\n readme: '使用说明',\n terminalWarn: '这看起来是终端/命令行插件:装进网页版可能无效,甚至导致 DeepSeek Harness 无法启动。建议先看它的使用说明,按说明装进对应的 profile。',\n envMissing: '还差一个小组件才能安装插件',\n envFix: '自动装好',\n envFixing: '正在准备…',\n envFixFail: '自动准备没成功,请点\"导出日志\"把文件发给我们反馈',\n loading: '正在加载插件目录…',\n backTop: '回到顶部',\n confirm: '确认',\n cmdDetails: '安装命令',\n catsMore: '更多分类',\n catsLess: '收起',\n sortHot: '最热',\n sortNew: '最新',\n marketUpdate: '市场有新版本,升级',\n updateAll: '全部更新',\n tabThemes: '主题',\n themeApply: '使用',\n themeActive: '使用中',\n themeEmpty: '目录里暂时还没有主题,敬请期待',\n progressHint: '首次安装需要下载与解析依赖,大插件可能要 1-3 分钟',\n toastReady: '已装好并已生效',\n toastTheme: '已启用。到 设置 → 插件市场 → 主题 可随时切换',\n gotIt: '知道了',\n}\n\n/** A dictionary key; zh is the source of truth, en mirrors it 1:1. */\nexport type MarketKey = keyof typeof zh\n\nexport const en: Record<MarketKey, string> = {\n nav: 'Plugin Market',\n subtitle: 'Discover community plugins for DeepSeek Harness',\n searchPh: 'Search plugins: notify, terminal, memory…',\n tabDiscover: 'Discover',\n tabInstalled: 'Installed',\n all: 'All',\n install: 'Install',\n installing: 'Installing…',\n installedBadge: '✓ Installed',\n alreadyInstalled: '✓ Installed',\n restartBanner: 'change(s) done — restart DeepSeek Harness to apply',\n uninstall: 'Uninstall',\n confirmRemove: 'Confirm?',\n uninstalling: 'Removing…',\n restartHint: 'To restart: stop the current dsh process and run it again (e.g. dsh web)',\n confirmTitle: 'Install',\n confirmWarn: 'Plugins are third-party community code. Installing means you trust this source; build scripts are blocked by default.',\n cancel: 'Cancel',\n empty: 'No plugins match',\n installedEmpty: 'No community plugins yet — browse the Discover tab',\n loadFail: 'Failed to load the plugin catalog, please retry later',\n installFail: 'Install failed',\n viewSource: 'Source',\n hotBanner: 'new plugin(s) ready — refresh the page to use them',\n refresh: 'Refresh',\n update: 'Update',\n updating: 'Updating…',\n updated: '✓ Updated — restart to apply',\n cancelOp: 'Cancel',\n cancelled: 'Cancelled',\n busyWait: 'Another operation is already running — please wait for it to finish (one install/update/uninstall at a time)',\n approveBuilds: 'Allow build scripts and retry',\n buildsSkipped: 'This plugin needs its build scripts to run; they are blocked by default for safety. Click below to allow them and reinstall:',\n restartNow: 'Restart now',\n restarting: 'Restarting…',\n restartFail: 'Restart failed',\n restartTimeout: 'Timed out waiting for DeepSeek Harness to start',\n updateNow: 'Update now',\n updateFail: 'Update failed',\n upToDate: 'Up to date',\n linkedDev: 'linked (dev)',\n exportLog: 'Export log',\n readme: 'README',\n terminalWarn: 'This looks like a terminal/CLI plugin: installing it into the web profile may do nothing, or even break DeepSeek Harness startup. Read its README and install it into the profile it targets.',\n envMissing: 'One small component is needed before installing plugins',\n envFix: 'Set up automatically',\n envFixing: 'Setting up…',\n envFixFail: 'Automatic setup failed — please use \"Export log\" and send us the file',\n loading: 'Loading the catalog…',\n backTop: 'Back to top',\n confirm: 'Confirm',\n cmdDetails: 'Install command',\n catsMore: 'More',\n catsLess: 'Less',\n sortHot: 'Top',\n sortNew: 'New',\n marketUpdate: 'Market update available — upgrade',\n updateAll: 'Update all',\n tabThemes: 'Themes',\n themeApply: 'Use',\n themeActive: 'Active',\n themeEmpty: 'No more theme plugins in the catalog yet — stay tuned',\n progressHint: 'First installs download and resolve dependencies — large plugins can take 1-3 minutes',\n toastReady: 'installed and live',\n toastTheme: 'is now active. Switch any time in Settings → Plugin Market → Themes',\n gotIt: 'Got it',\n}\n","/**\n * Response shapes of the /dsh-market/* host routes plus the pure helpers the\n * Market UI shares between its section and toast components.\n */\n\n/** Localized text keyed by language ('zh' / 'en'). */\nexport type LocalizedText = Record<string, string | undefined>\n\n/** One registry entry from /dsh-market/registry. */\nexport interface RegistryPlugin {\n name: string\n owner: string\n url: string\n npm?: string\n category: string\n description?: LocalizedText\n stars?: number\n added?: string\n install?: string\n}\n\n/** The catalog payload under `registry` in /dsh-market/registry. */\nexport interface Registry {\n count: number\n categories: Record<string, LocalizedText>\n plugins: RegistryPlugin[]\n}\n\n/** Profile dependency map: package name → install spec. */\nexport type InstalledMap = Record<string, string>\n\n/** Per-package update status from /dsh-market/updates. */\nexport interface UpdateStatus {\n updateAvailable?: boolean\n version?: string\n kind?: string\n}\n\n/** Poll payload from /dsh-market/status. */\nexport interface MarketStatus {\n active?: boolean\n lastLine?: string\n seconds?: number\n installed?: InstalledMap\n pnpm?: boolean\n boot?: string\n}\n\n/** Registered theme definition surfaced by the theme service snapshot. */\nexport interface ThemeDef {\n id: string\n colorScheme?: string\n tokens?: Record<string, string | undefined>\n}\n\n/** Theme service snapshot; null when the composition has no theme service. */\nexport interface ThemeSnapshot {\n preference: string\n themes: ThemeDef[]\n}\n\n/** Bound locale translator for the dsh-market namespace. */\nexport type Translate = (key: string) => string\n\nexport function avatarColor(name: string): string {\n let hash = 0\n for (let i = 0; i < name.length; i++) hash = (hash * 31 + name.charCodeAt(i)) | 0\n return 'hsl(' + (((hash % 360) + 360) % 360) + ' 55% 52%)'\n}\n\nexport function repoOf(url: string): string | null {\n // Plain repo urls plus /tree/<branch>/<subpath> monorepo links.\n const m = /^https:\\/\\/github\\.com\\/([^/]+\\/[^/]+?)(?:\\/tree\\/.+)?\\/?$/.exec(url)\n return m ? m[1]! : null\n}\n\nexport function readSession(key: string): any {\n try { return JSON.parse(sessionStorage.getItem(key) || 'null') } catch { return null }\n}\n\n/** Heuristic: plugins that target a terminal surface rather than the web UI. */\nexport function looksTerminal(plugin: RegistryPlugin, lang: string): boolean {\n const desc = (plugin.description && (plugin.description[lang] || plugin.description.en)) || ''\n return /\\b(tui|cli|tty|terminal)\\b|终端|命令行/i.test(plugin.name + ' ' + desc)\n}\n\n/** Filters and sort order driving the discover list. */\nexport interface ListQuery {\n /** Active category id, or 'all'. */\n category: string\n /** Raw search input (trimmed and lowercased internally). */\n query: string\n /** UI language for description matching ('zh' / 'en'). */\n lang: string\n /** 'hot' (stars desc), 'new' (added desc), anything else keeps registry order. */\n sort: string\n}\n\n/**\n * The discover list: category filter, then search across name / owner /\n * localized description, then the selected sort. Pure — the section renders\n * exactly this.\n */\nexport function visiblePlugins(plugins: RegistryPlugin[], options: ListQuery): RegistryPlugin[] {\n const query = options.query.trim().toLowerCase()\n const list = plugins.filter((p) => {\n if (options.category !== 'all' && p.category !== options.category) return false\n if (query === '') return true\n const desc = (p.description && (p.description[options.lang] || p.description.en)) || ''\n return p.name.toLowerCase().includes(query)\n || p.owner.toLowerCase().includes(query)\n || desc.toLowerCase().includes(query)\n })\n if (options.sort === 'hot') {\n return [...list].sort((a, b) => (b.stars ?? -1) - (a.stars ?? -1))\n }\n if (options.sort === 'new') {\n return [...list].sort((a, b) => String(b.added).localeCompare(String(a.added)))\n }\n return list\n}\n\n/** The themes tab listing: theme category only, most-starred first. */\nexport function themePlugins(plugins: RegistryPlugin[]): RegistryPlugin[] {\n return plugins.filter(p => p.category === 'theme').sort((a, b) => (b.stars || 0) - (a.stars || 0))\n}\n\n/**\n * Category chip order: collapsed with an active non-'all' chip, the active\n * one moves to the front so it stays visible inside the two-row clip.\n */\nexport function orderedCategories(categories: string[], active: string, open: boolean): string[] {\n return open || active === 'all' ? categories : [active, ...categories.filter(id => id !== active)]\n}\n\n/**\n * Unified installed-state matching (#15): both sides collapse to lowercase\n * identity sets — the registry entry contributes its bare name, npm name and\n * owner/repo; the dependency contributes its key and the repo inside its\n * spec — and any exact intersection counts. Exact equality, not substrings,\n * so prefix-related repo names cannot cross-match.\n */\nfunction entryIdentities(plugin: RegistryPlugin): Set<string> {\n const ids = new Set<string>([plugin.name.toLowerCase()])\n if (plugin.npm) ids.add(plugin.npm.toLowerCase())\n // Subpath-aware: a /tree/ entry identifies as repo#path:/sub, never the\n // bare repo — two subpackages of one monorepo must not cross-match.\n const m = /^https:\\/\\/github\\.com\\/([^/]+\\/[^/]+?)(?:\\/tree\\/[^/]+\\/(.+?))?\\/?$/.exec(plugin.url)\n if (m !== null) {\n ids.add(m[2] !== undefined ? `${m[1]!.toLowerCase()}#path:/${m[2].toLowerCase()}` : m[1]!.toLowerCase())\n }\n return ids\n}\n\nfunction depIdentities(name: string, spec: string): Set<string> {\n const ids = new Set<string>([name.toLowerCase()])\n // A scoped npm key usually mirrors owner/repo — expose that identity so an\n // npm-installed plugin still matches an entry whose npm field is unset.\n const scoped = /^@([^/]+)\\/(.+)$/.exec(name)\n if (scoped !== null) ids.add(`${scoped[1]!.toLowerCase()}/${scoped[2]!.toLowerCase()}`)\n const match = /github:([A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+)(?:#path:\\/([A-Za-z0-9_./-]+))?/i.exec(spec)\n if (match !== null) {\n ids.add(match[1]!.toLowerCase())\n if (match[2] !== undefined) ids.add(`${match[1]!.toLowerCase()}#path:/${match[2].toLowerCase()}`)\n }\n return ids\n}\n\n/** The installed dependency name a registry entry corresponds to, or null. */\nexport function matchInstalledName(plugin: RegistryPlugin, installed: InstalledMap): string | null {\n const ids = entryIdentities(plugin)\n for (const [name, spec] of Object.entries(installed)) {\n for (const id of depIdentities(name, String(spec))) {\n if (ids.has(id)) return name\n }\n }\n return null\n}\n\n/** The registry entry an installed dependency corresponds to, or undefined. */\nexport function entryForDep(plugins: RegistryPlugin[], name: string, spec: string): RegistryPlugin | undefined {\n const ids = depIdentities(name, String(spec))\n return plugins.find((plugin) => {\n for (const id of entryIdentities(plugin)) if (ids.has(id)) return true\n return false\n })\n}\n\nexport function isInstalled(plugin: RegistryPlugin, installed: InstalledMap): boolean {\n return matchInstalledName(plugin, installed) !== null\n}\n\n/**\n * The header brand mark now lives in MarketSection.tsx as an inline SVG\n * (official-style monochrome glyph, fill=\"currentColor\") so it follows the\n * active theme; the colored assets/logo.svg tile is no longer inlined here.\n */\n\n/** Four representative colors for a theme card's preview strip. */\nexport function themeSwatch(def: ThemeDef): string[] {\n const tk = def.tokens || {}\n const pick = (names: string[]) => { for (const n of names) { if (tk[n]) return tk[n]! } return null }\n const dark = def.colorScheme === 'dark'\n return [\n pick(['--dsw-alias-bg-base', '--dsw-alias-bg-layer-1']) || (dark ? '#0f1115' : '#ffffff'),\n pick(['--dsw-alias-bg-layer-2', '--dsw-alias-bg-overlay']) || (dark ? '#1a1d23' : '#f3f4f6'),\n pick(['--dsw-alias-brand-primary']) || '#4f6ef7',\n pick(['--dsw-alias-label-primary']) || (dark ? '#e5e7eb' : '#1f2328'),\n ]\n}\n","/**\n * Post-reload confirmation via the official Toast primitive: shown once after\n * the refresh that follows a hot install or theme switch, so the user lands\n * back in their flow with visible proof.\n */\nimport { useState } from 'react'\nimport { Toast } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { readSession } from './market-data.ts'\nimport type { Translate } from './market-data.ts'\n\nexport function InstallToast(props: { t: Translate }) {\n const t = props.t\n const [mode] = useState(() => {\n const value = sessionStorage.getItem('dshm-toast-mode')\n sessionStorage.removeItem('dshm-toast-mode')\n return value\n })\n const [names, setNames] = useState<string[]>(() => {\n const value = readSession('dshm-toast')\n sessionStorage.removeItem('dshm-toast')\n return Array.isArray(value) ? value : []\n })\n if (names.length === 0) return null\n return (\n <Toast\n text={names.join(', ') + ' ' + t(mode === 'theme' ? 'toastTheme' : 'toastReady')}\n icon={<span>✨</span>}\n onDone={() => setNames([])}\n />\n )\n}\n","/**\n * The Market settings section: Discover / Themes / Installed tabs over the\n * /dsh-market/* host routes, with install/update/uninstall flows and the\n * pending-restart bookkeeping in sessionStorage.\n */\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, type CSSProperties } from 'react'\nimport { Button, IconChevronDownOutline14, IconChevronUpOutline14, IconSearchOutline16, Input, Modal, Pill, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'\nimport css from './Market.module.css'\nimport {\n avatarColor, entryForDep, isInstalled, looksTerminal, matchInstalledName, orderedCategories,\n readSession, repoOf, themePlugins as themePluginsOf, themeSwatch, visiblePlugins,\n} from './market-data.ts'\nimport type {\n InstalledMap, Registry, RegistryPlugin, ThemeSnapshot, Translate, UpdateStatus,\n} from './market-data.ts'\n\n/**\n * Card avatar: the plugin owner's GitHub avatar (no API, browser-cached),\n * falling back to the initial-letter tile when it can't load.\n */\nfunction OwnerAvatar({ name, owner }: { name: string; owner: string }) {\n const [failed, setFailed] = useState(false)\n if (failed || owner === '') {\n return (\n <div className={css.av} style={{ background: avatarColor(name) }}>\n {name.replace(/^dsh[-_]/i, '').charAt(0).toUpperCase() || 'P'}\n </div>\n )\n }\n return (\n <img\n className={css.av}\n src={`https://github.com/${encodeURIComponent(owner)}.png?size=96`}\n alt=\"\"\n loading=\"lazy\"\n onError={() => setFailed(true)}\n />\n )\n}\n\n/**\n * Official-style market glyph: the shared block-grid brand mark converted to\n * the official monochrome icon form (16×16, fill=\"currentColor\") so it\n * follows the active theme. Mirrors the settings-nav glyph used for the\n * \"market\" section id.\n */\nfunction MarketLogo({ size = 16, style }: { size?: number; style?: CSSProperties }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" style={style}>\n <path fill=\"currentColor\" d=\"M2.35 1.75H4.95A0.6 0.6 0 0 1 5.55 2.35V4.95A0.6 0.6 0 0 1 4.95 5.55H2.35A0.6 0.6 0 0 1 1.75 4.95V2.35A0.6 0.6 0 0 1 2.35 1.75ZM6.7 1.75H9.3A0.6 0.6 0 0 1 9.9 2.35V4.95A0.6 0.6 0 0 1 9.3 5.55H6.7A0.6 0.6 0 0 1 6.1 4.95V2.35A0.6 0.6 0 0 1 6.7 1.75ZM2.35 6.1H4.95A0.6 0.6 0 0 1 5.55 6.7V9.3A0.6 0.6 0 0 1 4.95 9.9H2.35A0.6 0.6 0 0 1 1.75 9.3V6.7A0.6 0.6 0 0 1 2.35 6.1ZM6.7 6.1H9.3A0.6 0.6 0 0 1 9.9 6.7V9.3A0.6 0.6 0 0 1 9.3 9.9H6.7A0.6 0.6 0 0 1 6.1 9.3V6.7A0.6 0.6 0 0 1 6.7 6.1ZM11.05 6.1H13.65A0.6 0.6 0 0 1 14.25 6.7V9.3A0.6 0.6 0 0 1 13.65 9.9H11.05A0.6 0.6 0 0 1 10.45 9.3V6.7A0.6 0.6 0 0 1 11.05 6.1ZM2.35 10.45H4.95A0.6 0.6 0 0 1 5.55 11.05V13.65A0.6 0.6 0 0 1 4.95 14.25H2.35A0.6 0.6 0 0 1 1.75 13.65V11.05A0.6 0.6 0 0 1 2.35 10.45ZM6.7 10.45H9.3A0.6 0.6 0 0 1 9.9 11.05V13.65A0.6 0.6 0 0 1 9.3 14.25H6.7A0.6 0.6 0 0 1 6.1 13.65V11.05A0.6 0.6 0 0 1 6.7 10.45ZM11.05 10.45H13.65A0.6 0.6 0 0 1 14.25 11.05V13.65A0.6 0.6 0 0 1 13.65 14.25H11.05A0.6 0.6 0 0 1 10.45 13.65V11.05A0.6 0.6 0 0 1 11.05 10.45Z\" />\n <path fill=\"currentColor\" d=\"M11.05 1.75H13.65A0.6 0.6 0 0 1 14.25 2.35V4.95A0.6 0.6 0 0 1 13.65 5.55H11.05A0.6 0.6 0 0 1 10.45 4.95V2.35A0.6 0.6 0 0 1 11.05 1.75Z\" transform=\"rotate(9 12.35 3.65)\" />\n </svg>\n )\n}\n\n/**\n * Module-scope caches so re-entering the section renders instantly instead\n * of refetching and rebuilding from a spinner (#30 by @StarsTom). Module\n * state survives section switches; a background refetch keeps it current.\n */\nlet cachedRegistry: Registry | null = null\nlet cachedInstalled: InstalledMap | null = null\n\nexport interface MarketSectionProps {\n t: Translate\n locale: {\n subscribe(callback: () => void): () => void\n getSnapshot(): { active: string }\n }\n theme: { setTheme(id: string): void }\n themeStore: {\n subscribe(callback: () => void): () => void\n getSnapshot(): ThemeSnapshot | null\n }\n}\n\nexport function MarketSection(props: MarketSectionProps) {\n const t = props.t\n const localeSnap = useSyncExternalStore(\n cb => props.locale.subscribe(cb),\n () => props.locale.getSnapshot(),\n )\n const lang = String(localeSnap.active).toLowerCase().startsWith('zh') ? 'zh' : 'en'\n // null when the composition has no theme service — the Themes tab hides.\n const themeSnap = useSyncExternalStore(\n props.themeStore.subscribe,\n props.themeStore.getSnapshot,\n )\n const [data, setData] = useState<Registry | null>(cachedRegistry)\n const [loadError, setLoadError] = useState(false)\n const [installed, setInstalledState] = useState<InstalledMap>(cachedInstalled ?? {})\n const setInstalled = useCallback((value: InstalledMap) => { cachedInstalled = value; setInstalledState(value) }, [])\n const [skins, setSkins] = useState<string[]>([])\n const [tab, setTab] = useState(() => {\n const saved = sessionStorage.getItem('dshm-tab')\n if (saved !== null) sessionStorage.removeItem('dshm-tab')\n return saved || 'discover'\n })\n const [q, setQ] = useState('')\n const [cat, setCat] = useState('all')\n const [confirming, setConfirming] = useState<RegistryPlugin | null>(null)\n const [busyUrl, setBusyUrl] = useState<string | null>(null)\n /** Consecutive idle polls with a pending install that never landed (#32). */\n const idleStrikes = useRef(0)\n const [doneUrls, setDoneUrls] = useState<string[]>([])\n const [installError, setInstallError] = useState<string | null>(null)\n const [updates, setUpdates] = useState<Record<string, UpdateStatus>>({})\n const [updatingName, setUpdatingName] = useState<string | null>(null)\n // Plugin blocked by pnpm's fresh-release safety wait; arms the update-now button.\n const [staleName, setStaleName] = useState<string | null>(null)\n /**\n * Cards rendered so far — the discover grid renders incrementally (60,\n * then +120 as the sentinel scrolls into view) instead of all 400+ at\n * once, which built a ~70k px DOM and made section switches lag (#30).\n */\n const [visibleCount, setVisibleCount] = useState(60)\n const sentinelRef = useCallback((node: HTMLDivElement | null) => {\n if (node === null) return\n const observer = new IntersectionObserver((entries) => {\n if (entries.some(entry => entry.isIntersecting)) setVisibleCount(count => count + 120)\n }, { rootMargin: '600px' })\n observer.observe(node)\n // Cleanup runs when React detaches the node and calls back with null;\n // the observer dies with the node, so a one-shot observe suffices.\n }, [])\n\n /** Determinate percent parsed from pnpm's Progress line, when available. */\n const [progressPct, setProgressPct] = useState<number | null>(null)\n /** Blocked build scripts from the last install: enables approve-and-retry (#6). */\n const [buildsSkipped, setBuildsSkipped] = useState<{ plugin: RegistryPlugin; names: string[] } | null>(null)\n const [updatingAll, setUpdatingAll] = useState(false)\n const [updatedNames, setUpdatedNames] = useState<string[]>([])\n const [hotUrls, setHotUrls] = useState<string[]>([])\n const [hotNames, setHotNames] = useState<string[]>([])\n const [progressLine, setProgressLine] = useState<string | null>(null)\n const [removeArmed, setRemoveArmed] = useState<string | null>(null)\n const [removingName, setRemovingName] = useState<string | null>(null)\n const [removedCount, setRemovedCount] = useState(0)\n const [envReady, setEnvReady] = useState(true)\n const [envFixing, setEnvFixing] = useState(false)\n const [envFailed, setEnvFailed] = useState(false)\n const [bootId, setBootId] = useState<string | null>(null)\n /** One-click restart (#14 by @ysyyhhh): server capability + in-flight state. */\n const [restartEnabled, setRestartEnabled] = useState(false)\n const [restarting, setRestarting] = useState(false)\n const [showTop, setShowTop] = useState(false)\n const bodyRef = useRef<HTMLDivElement | null>(null)\n const [sort, setSort] = useState('hot')\n const [catsOpen, setCatsOpen] = useState(false)\n // How many category pills fit in the two collapsed rows (measured once —\n // the settings panel width is fixed); null = measuring render with all\n // pills clamped, then slice so the chevron flows inline after the last one.\n const [visibleCats, setVisibleCats] = useState<number | null>(null)\n const catsWrapRef = useRef<HTMLDivElement | null>(null)\n\n const refreshInstalled = useCallback((force?: boolean) => {\n fetch('/dsh-market/installed', { cache: 'no-store' })\n .then(res => res.json())\n .then(body => {\n setInstalled(body.installed || {})\n setSkins(body.live || [])\n })\n .catch(() => {})\n fetch('/dsh-market/updates' + (force === true ? '?force=1' : ''), { cache: 'no-store' })\n .then(res => res.json())\n .then(body => setUpdates(body.updates || {}))\n .catch(() => {})\n }, [])\n\n useEffect(() => {\n fetch('/dsh-market/registry', { cache: 'no-store' })\n .then(res => { if (!res.ok) throw new Error('HTTP ' + res.status); return res.json() })\n .then(body => { cachedRegistry = body.registry; setData(body.registry) })\n .catch(() => setLoadError(true))\n fetch('/dsh-market/status', { cache: 'no-store' })\n .then(res => res.json())\n .then(status => {\n setEnvReady(status.pnpm !== false)\n if (typeof status.boot === 'string') setBootId(status.boot)\n setRestartEnabled(status.restart === true)\n })\n .catch(() => {})\n refreshInstalled()\n }, [refreshInstalled])\n\n // Pending-restart flags survive tab switches and page reloads, scoped to\n // one host process: a different boot id means the restart happened and the\n // stale banner must not resurrect.\n useEffect(() => {\n if (bootId === null) return\n const saved = readSession('dshm-restart')\n if (saved === null) return\n if (saved.boot !== bootId) {\n sessionStorage.removeItem('dshm-restart')\n return\n }\n if (Array.isArray(saved.doneUrls) && saved.doneUrls.length > 0) setDoneUrls(saved.doneUrls)\n if (Array.isArray(saved.updated) && saved.updated.length > 0) setUpdatedNames(saved.updated)\n if (typeof saved.removed === 'number' && saved.removed > 0) setRemovedCount(saved.removed)\n }, [bootId])\n\n useEffect(() => {\n if (bootId === null) return\n if (doneUrls.length === 0 && updatedNames.length === 0 && removedCount === 0) return\n sessionStorage.setItem('dshm-restart', JSON.stringify({\n boot: bootId,\n doneUrls,\n updated: updatedNames,\n removed: removedCount,\n }))\n }, [bootId, doneUrls, updatedNames, removedCount])\n\n const fixEnv = useCallback(() => {\n setEnvFixing(true)\n setEnvFailed(false)\n fetch('/dsh-market/setup-pnpm', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })\n .then(res => res.json())\n .then(body => {\n if (body.ok) {\n setEnvReady(true)\n } else {\n setEnvFailed(true)\n if (typeof body.error === 'string') setInstallError(body.error)\n }\n })\n .catch(() => setEnvFailed(true))\n .finally(() => setEnvFixing(false))\n }, [])\n\n // Recover an install whose HTTP response was lost (page navigated away or\n // the connection dropped): the pending marker survives in sessionStorage and\n // the poll below converges the button state from the host's ground truth.\n useEffect(() => {\n const pending = readSession('dshm-pending')\n if (pending !== null && typeof pending.url === 'string') setBusyUrl(pending.url)\n }, [])\n\n useEffect(() => {\n if (busyUrl === null && updatingName === null) {\n setProgressLine(null)\n return\n }\n const timer = setInterval(() => {\n fetch('/dsh-market/status', { cache: 'no-store' })\n .then(res => res.json())\n .then(status => {\n if (status.active) {\n setProgressLine((status.lastLine || '…') + ' (' + status.seconds + 's)')\n const m = /resolved (\\d+), reused (\\d+), downloaded (\\d+), added (\\d+)/.exec(status.lastLine || '')\n if (m !== null && Number(m[1]) > 0) {\n const done = Number(m[2]) + Number(m[3]) + Number(m[4])\n setProgressPct(Math.max(4, Math.min(96, Math.round(done / Number(m[1]) * 100))))\n }\n } else {\n setProgressLine(null)\n setProgressPct(null)\n setInstalled(status.installed || {})\n const pending = readSession('dshm-pending')\n if (pending !== null && busyUrl !== null) {\n const nowInstalled = data !== null && data.plugins.some(p =>\n p.url === busyUrl && isInstalled(p, status.installed || {}))\n if (nowInstalled) {\n idleStrikes.current = 0\n sessionStorage.removeItem('dshm-pending')\n setDoneUrls(urls => urls.includes(busyUrl) ? urls : urls.concat(busyUrl))\n setBusyUrl(null)\n } else if (++idleStrikes.current >= 2) {\n // Host is idle and the plugin never landed: the install died\n // (e.g. exit 127) with its response lost. Without this the\n // button says \"installing\" forever — across reloads (#32).\n idleStrikes.current = 0\n sessionStorage.removeItem('dshm-pending')\n setBusyUrl(null)\n setInstallError(t('installFail') + ' — ' + t('exportLog'))\n }\n }\n }\n })\n .catch(() => {})\n }, 2000)\n return () => clearInterval(timer)\n }, [busyUrl, updatingName, data])\n\n const plugins = useMemo(\n () => (data === null ? [] : visiblePlugins(data.plugins, { category: cat, query: q, lang, sort })),\n [data, q, cat, lang, sort])\n\n useEffect(() => { setVisibleCount(60) }, [q, cat, sort])\n\n const doInstall = useCallback((plugin: RegistryPlugin) => {\n setBuildsSkipped(null)\n setConfirming(null)\n setInstallError(null)\n setBusyUrl(plugin.url)\n sessionStorage.setItem('dshm-pending', JSON.stringify({ url: plugin.url }))\n fetch('/dsh-market/install', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ url: plugin.url }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n sessionStorage.removeItem('dshm-pending')\n if (status === 200 && body.ok && body.hot && plugin.category === 'theme') {\n // Themes auto-activate on install; reload straight into the Themes\n // tab so the new look is on screen immediately.\n sessionStorage.setItem('dshm-toast', JSON.stringify([plugin.name]))\n sessionStorage.setItem('dshm-tab', 'themes')\n location.reload()\n return\n }\n if (body.cancelled === true) {\n // User-cancelled: quiet reset, nothing to report.\n refreshInstalled()\n return\n }\n if (status === 200 && body.ok) {\n sessionStorage.setItem('dshm-tab', 'installed')\n if (body.hot) {\n setHotUrls(urls => urls.includes(plugin.url) ? urls : urls.concat(plugin.url))\n setHotNames(names => names.includes(plugin.name) ? names : names.concat(plugin.name))\n } else {\n setDoneUrls(urls => urls.includes(plugin.url) ? urls : urls.concat(plugin.url))\n }\n refreshInstalled()\n } else {\n if (status === 409) {\n setInstallError(t('busyWait'))\n return\n }\n if (Array.isArray(body.ignoredBuilds) && body.ignoredBuilds.length > 0) {\n setBuildsSkipped({ plugin, names: body.ignoredBuilds.map(String) })\n }\n const text = (v: unknown) => typeof v === 'string' ? v : (v && typeof (v as any).text === 'string') ? (v as any).text : v == null ? '' : JSON.stringify(v)\n const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join('\\n').trim() || ('exit ' + body.exitCode)\n setInstallError(t('installFail') + ': ' + plugin.name + ' — ' + detail.trim().slice(-600))\n }\n })\n .catch(error => {\n sessionStorage.removeItem('dshm-pending')\n setInstallError(t('installFail') + ': ' + String(error))\n })\n .finally(() => setBusyUrl(null))\n }, [refreshInstalled, t])\n\n /**\n * Restart the host and reload once the boot id changes (#14 by @ysyyhhh).\n * The 202 races the process's SIGTERM, so network errors on the initial\n * request are expected and treated as \"restart under way\".\n */\n const doRestart = useCallback(() => {\n if (bootId === null || restarting) return\n const previousBoot = bootId\n setRestarting(true)\n setInstallError(null)\n const awaitNewBoot = () => {\n const deadline = Date.now() + 60000\n const poll = () => {\n fetch('/dsh-market/status', { cache: 'no-store' })\n .then(res => res.json())\n .then((next) => {\n if (typeof next.boot === 'string' && next.boot !== previousBoot) {\n location.reload()\n return\n }\n retry()\n })\n .catch(retry)\n }\n const retry = () => {\n if (Date.now() > deadline) {\n setRestarting(false)\n setInstallError(t('restartTimeout'))\n return\n }\n setTimeout(poll, 1500)\n }\n poll()\n }\n fetch('/dsh-market/restart', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (status !== 202 || body.ok !== true) {\n setRestarting(false)\n setInstallError(t('restartFail') + ': ' + String(body.error || ('HTTP ' + String(status))))\n return\n }\n awaitNewBoot()\n })\n .catch(awaitNewBoot) // the host may die mid-response; keep polling\n }, [bootId, restarting, t])\n\n /** Cancel the running plugin command (#6 by @qichuang321). */\n const doCancel = useCallback(() => {\n fetch('/dsh-market/cancel', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })\n .catch(() => {})\n }, [])\n\n const doUpdate = useCallback((name: string, force = false) => {\n setInstallError(null)\n setStaleName(null)\n setUpdatingName(name)\n return fetch('/dsh-market/update', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(force ? { name, force: true } : { name }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (body.cancelled === true) {\n refreshInstalled()\n return\n }\n if (status === 200 && body.ok) {\n setUpdatedNames(names => names.concat(name))\n refreshInstalled()\n } else {\n if (status === 409) { setInstallError(t('busyWait')); return }\n if (body.stale === true) setStaleName(name)\n const text = (v: unknown) => typeof v === 'string' ? v : (v && typeof (v as any).text === 'string') ? (v as any).text : v == null ? '' : JSON.stringify(v)\n const detail = text(body.error) || [text(body.stderr), text(body.stdout)].filter(Boolean).join('\\n').trim() || ('exit ' + body.exitCode)\n setInstallError(t('updateFail') + ': ' + name + ' — ' + detail.trim().slice(-600))\n }\n })\n .catch(error => setInstallError(t('updateFail') + ': ' + String(error)))\n .finally(() => setUpdatingName(null))\n }, [refreshInstalled, t])\n\n const doUseSkin = useCallback((name: string) => {\n setInstallError(null)\n fetch('/dsh-market/use-skin', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (status === 200 && body.ok) {\n sessionStorage.setItem('dshm-toast', JSON.stringify([name]))\n sessionStorage.setItem('dshm-toast-mode', 'theme')\n sessionStorage.setItem('dshm-tab', 'themes')\n location.reload()\n } else {\n setInstallError(String(body.error || 'failed'))\n }\n })\n .catch(error => setInstallError(String(error)))\n }, [])\n\n const doUninstall = useCallback((name: string) => {\n setRemoveArmed(null)\n setInstallError(null)\n setRemovingName(name)\n return fetch('/dsh-market/uninstall', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name }),\n })\n .then(res => res.json().then(body => ({ status: res.status, body })))\n .then(({ status, body }) => {\n if (status === 200 && body.ok) {\n if (!body.hot) setRemovedCount(n => n + 1)\n refreshInstalled()\n } else {\n const text = (v: unknown) => typeof v === 'string' ? v : (v && typeof (v as any).text === 'string') ? (v as any).text : v == null ? '' : JSON.stringify(v)\n setInstallError((text(body.error) || text(body.stderr) || 'error').trim().slice(-600))\n }\n })\n .catch(error => setInstallError(String(error)))\n .finally(() => setRemovingName(null))\n }, [refreshInstalled])\n\n // The market itself stays out of the batch: its update reloads this page\n // mid-run, which would strand the remaining items.\n const selfName = installed['dshmarket'] !== undefined ? 'dshmarket' : 'dsh-market'\n const updatableNames = Object.keys(installed).filter(\n name => name !== selfName && !updatedNames.includes(name) && updates[name] && updates[name].updateAvailable,\n )\n\n const doUpdateAll = useCallback(() => {\n const names = updatableNames.slice()\n setUpdatingAll(true)\n const next = () => {\n const name = names.shift()\n if (name === undefined) {\n setUpdatingAll(false)\n return\n }\n doUpdate(name).then(next, next)\n }\n next()\n }, [updatableNames, doUpdate])\n\n const pendingRestart = doneUrls.length + updatedNames.length + removedCount\n const hasUpdates = Object.keys(installed).some(\n name => !updatedNames.includes(name) && updates[name] && updates[name].updateAvailable,\n )\n\n const themePlugins = data === null ? [] : themePluginsOf(data.plugins)\n\n const pluginCard = (p: RegistryPlugin) => {\n const desc = (p.description && (p.description[lang] || p.description.en)) || ''\n const done = doneUrls.includes(p.url) || hotUrls.includes(p.url)\n const already = isInstalled(p, installed)\n const busy = busyUrl === p.url\n return (\n <div key={p.url} className={css.card}>\n <div className={css.row1}>\n <OwnerAvatar name={p.name} owner={p.owner || ''} />\n <div style={{ minWidth: 0 }}>\n <div className={css.nm}>{p.name}</div>\n <div className={css.owner}>\n {p.owner}\n {typeof p.stars === 'number' && <span className={css.star}>{' · ★ ' + p.stars}</span>}\n </div>\n </div>\n <span className={css.grow} />\n <a className={css.src} href={p.url} target=\"_blank\" rel=\"noreferrer\" style={{ alignSelf: 'flex-start', flexShrink: 0 }}>{t('viewSource')}</a>\n </div>\n <div className={css.desc}>{desc}</div>\n <div className={css.foot}>\n <span className={css.tag}>\n {(data!.categories[p.category] && (data!.categories[p.category]![lang] || data!.categories[p.category]!.en)) || p.category}\n </span>\n <span className={css.grow} />\n {done\n ? <span className={css.okState}>{t('installedBadge')}</span>\n : already\n ? <span className={css.okState}>{t('alreadyInstalled')}</span>\n : busy\n ? <Button variant=\"primary\" size=\"sm\" disabled>{t('installing')}</Button>\n : (\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={busyUrl !== null || !envReady}\n onClick={() => setConfirming(p)}\n >{t('install')}</Button>\n )}\n </div>\n {busy && (\n <div className={css.progress}>\n <span className={css.spin} />\n <code className={css.grow}>{progressLine || t('progressHint')}</code>\n {progressPct !== null && <span className={css.pct}>{progressPct}%</span>}\n <button type=\"button\" className={css.cancelBtn} onClick={doCancel}>{t('cancelOp')}</button>\n </div>\n )}\n </div>\n )\n }\n\n const installedNameOf = (p: RegistryPlugin) => matchInstalledName(p, installed)\n\n // Plugins loaded at boot (bundle-layer skins) aren't in the shim list but\n // are just as live; the boot manifest is the page's own record of them.\n const bootEntries = (typeof window !== 'undefined' && window.__DSH_BOOT__ && Array.isArray(window.__DSH_BOOT__.entries))\n ? window.__DSH_BOOT__.entries\n : []\n\n // Unified card for the Themes tab: install → use/in-use → uninstall.\n const themePluginCard = (p: RegistryPlugin) => {\n const instName = installedNameOf(p)\n if (instName === null) return pluginCard(p)\n const mounted = skins.includes(instName) || bootEntries.some(e => e.id === instName)\n const desc = (p.description && (p.description[lang] || p.description.en)) || ''\n return (\n <div key={p.url} className={css.card}>\n <div className={css.row1}>\n <OwnerAvatar name={p.name} owner={p.owner || ''} />\n <div style={{ minWidth: 0 }}>\n <div className={css.nm}>{p.name}</div>\n <div className={css.owner}>\n {p.owner}\n {typeof p.stars === 'number' && <span className={css.star}>{' · ★ ' + p.stars}</span>}\n </div>\n </div>\n <span className={css.grow} />\n <a className={css.src} href={p.url} target=\"_blank\" rel=\"noreferrer\" style={{ alignSelf: 'flex-start', flexShrink: 0 }}>{t('viewSource')}</a>\n </div>\n <div className={css.desc}>{desc}</div>\n <div className={css.foot}>\n <span className={css.grow} />\n {removingName === instName\n ? <Button variant=\"outline\" size=\"sm\" className={css.dangerBtn} disabled>{t('uninstalling')}</Button>\n : removeArmed === instName\n ? (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.dangerArmed}\n onClick={() => doUninstall(instName).then(() => {\n if (mounted) {\n sessionStorage.setItem('dshm-tab', 'themes')\n location.reload()\n }\n })}\n >{t('confirmRemove')}</Button>\n )\n : <Button variant=\"outline\" size=\"sm\" className={css.dangerBtn} onClick={() => setRemoveArmed(instName)}>{t('uninstall')}</Button>}\n {mounted\n ? <span className={css.okState}>{t('themeActive')}</span>\n : <Button variant=\"primary\" size=\"sm\" onClick={() => doUseSkin(instName)}>{t('themeApply')}</Button>}\n </div>\n </div>\n )\n }\n\n const themeCard = (id: string, label: string, swatch: string[]) => {\n const active = themeSnap !== null && themeSnap.preference === id\n return (\n <div key={'th-' + id} className={css.card}>\n <div className={css.swatches}>{swatch.map((c, i) => <i key={i} style={{ background: c }} />)}</div>\n <div className={css.foot}>\n <span className={css.nm}>{label}</span>\n <span className={css.grow} />\n {active\n ? <span className={css.okState}>{t('themeActive')}</span>\n : (\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => { try { props.theme.setTheme(id) } catch (error) { setInstallError(String(error)) } }}\n >{t('themeApply')}</Button>\n )}\n </div>\n </div>\n )\n }\n\n const categories = data === null ? [] : Object.keys(data.categories)\n\n useLayoutEffect(() => { setVisibleCats(null) }, [lang, categories.length])\n useLayoutEffect(() => {\n if (catsOpen || visibleCats !== null) return\n const el = catsWrapRef.current\n if (el === null) return\n const chips = [...el.children].filter((c): c is HTMLElement => (c as HTMLElement).dataset?.chip === '1')\n if (chips.length === 0) return\n const first = chips[0]!\n const rowThreeTop = first.offsetTop + (first.offsetHeight + 6) * 2 - 3\n let fits = 0\n for (const chip of chips) { if (chip.offsetTop < rowThreeTop) fits += 1 }\n // Reserve the tail slot of row two for the chevron itself.\n setVisibleCats(fits >= chips.length ? fits : Math.max(1, fits - 1))\n }, [catsOpen, visibleCats, data])\n\n return (\n <div className={css.root}>\n <div className={css.head}>\n <div className={css.titleRow}>\n <MarketLogo size={22} style={{ flexShrink: 0 }} />\n <h2 className={css.title}>{t('nav')}</h2>\n {(() => {\n const self = installed['dshmarket'] !== undefined ? 'dshmarket' : 'dsh-market'\n return updates[self] && updates[self].updateAvailable && !updatedNames.includes(self)\n && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.warnBtn}\n disabled={updatingName !== null || busyUrl !== null}\n onClick={() => { setTab('installed'); doUpdate(self) }}\n >{updatingName === self ? t('updating') : t('marketUpdate')}</Button>\n )\n })()}\n {updatableNames.length >= 2 && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.warnBtn}\n disabled={updatingAll || updatingName !== null || busyUrl !== null || removingName !== null}\n onClick={() => { setTab('installed'); doUpdateAll() }}\n >{updatingAll ? t('updating') : t('updateAll') + ' (' + updatableNames.length + ')'}</Button>\n )}\n </div>\n <div className={css.sub}>\n {t('subtitle') + (data ? ' · ' + data.count : '') + ' · '}\n <a className={css.src} href=\"/dsh-market/logs\" download=\"dsh-market-log.txt\">{t('exportLog')}</a>\n </div>\n <div className={css.tabs}>\n <button className={tab === 'discover' ? `${css.tab} ${css.on}` : css.tab} onClick={() => setTab('discover')}>{t('tabDiscover')}</button>\n {themeSnap !== null && <button className={tab === 'themes' ? `${css.tab} ${css.on}` : css.tab} onClick={() => setTab('themes')}>{t('tabThemes')}</button>}\n <button className={tab === 'installed' ? `${css.tab} ${css.on}` : css.tab} onClick={() => { setTab('installed'); refreshInstalled(true) }}>\n {t('tabInstalled') + (Object.keys(installed).length > 0 ? ' (' + Object.keys(installed).length + ')' : '')}\n {hasUpdates && <StateDot state=\"error\" size={7} className={css.dot} />}\n </button>\n <span className={css.grow} />\n <Input className={css.searchInline} icon={<IconSearchOutline16 size={14} />} placeholder={t('searchPh')} value={q} onChange={e => setQ(e.target.value)} />\n </div>\n {!envReady && (\n <div className={css.restart}>\n <span>🧩</span>\n <span className={css.grow}>{envFailed ? t('envFixFail') : t('envMissing')}</span>\n {!envFailed && (\n <Button variant=\"primary\" size=\"sm\" disabled={envFixing} onClick={fixEnv}>\n {envFixing ? t('envFixing') : t('envFix')}\n </Button>\n )}\n </div>\n )}\n {hotUrls.length > 0 && (\n <div className={css.restart}>\n <span>✨</span>\n <span className={css.grow}><b>{hotUrls.length}</b> {t('hotBanner')}</span>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => {\n sessionStorage.setItem('dshm-toast', JSON.stringify(hotNames))\n sessionStorage.setItem('dshm-tab', 'installed')\n location.reload()\n }}\n >{t('refresh')}</Button>\n </div>\n )}\n {pendingRestart > 0 && (\n <div className={css.restart}>\n <span>🔄</span>\n <span className={css.grow}><b>{pendingRestart}</b> {t('restartBanner')}</span>\n <span title={t('restartHint')}>ℹ️</span>\n {restartEnabled && (\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={restarting || busyUrl !== null || updatingName !== null || removingName !== null}\n onClick={doRestart}\n >{restarting ? t('restarting') : t('restartNow')}</Button>\n )}\n </div>\n )}\n </div>\n {buildsSkipped !== null && (\n <div className={css.restart}>\n <span className={css.grow}>{t('buildsSkipped')} {buildsSkipped.names.join(', ')}</span>\n <Button\n size=\"sm\"\n disabled={busyUrl !== null}\n onClick={() => {\n const { plugin, names } = buildsSkipped\n setBuildsSkipped(null)\n fetch('/dsh-market/approve-builds', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ packages: names }),\n })\n .then(res => res.json())\n .then((body) => {\n if (body.ok) doInstall(plugin)\n else setInstallError(String(body.error || 'approve failed'))\n })\n .catch(error => setInstallError(String(error)))\n }}\n >{t('approveBuilds')}</Button>\n </div>\n )}\n {installError !== null && (\n <div className={css.err}>\n {installError}\n {staleName !== null && (\n <div className={css.staleAction}>\n <Button size=\"sm\" onClick={() => doUpdate(staleName, true)}>{t('updateNow')}</Button>\n </div>\n )}\n </div>\n )}\n <div\n className={css.body}\n ref={bodyRef}\n onScroll={e => setShowTop(e.currentTarget.scrollTop > 400)}\n >\n {tab === 'discover'\n ? loadError\n ? <div className={css.empty}>{t('loadFail')}</div>\n : data === null\n ? <div className={css.loading}><span className={css.spin} />{t('loading')}</div>\n : (\n <>\n <div className={css.cats}>\n <div className={css.catsRow}>\n <div ref={catsWrapRef} className={catsOpen || visibleCats === null ? `${css.catsWrap} ${css.catsCollapsed}` : css.catsWrap}>\n {(() => {\n // Collapsed, the selected category is pulled to the front so it never hides.\n const ordered = orderedCategories(categories, cat, catsOpen)\n const shown = catsOpen || visibleCats === null ? ordered : ordered.slice(0, Math.max(0, visibleCats - 1))\n return (\n <>\n <Pill data-chip=\"1\" active={cat === 'all'} onClick={() => setCat('all')}>{t('all')}</Pill>\n {shown.map(id => (\n <Pill\n key={id}\n data-chip=\"1\"\n active={cat === id}\n onClick={() => setCat(id)}\n >{(data.categories[id] && (data.categories[id]![lang] || data.categories[id]!.en)) || id}</Pill>\n ))}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={css.catsToggle}\n icon={catsOpen ? <IconChevronUpOutline14 size={14} /> : <IconChevronDownOutline14 size={14} />}\n aria-label={catsOpen ? t('catsLess') : t('catsMore')}\n onClick={() => setCatsOpen(o => !o)}\n />\n </>\n )\n })()}\n </div>\n <div className={css.sort}>\n {['hot', 'new'].map(key => (\n <button\n key={key}\n className={sort === key ? css.on : ''}\n onClick={() => setSort(key)}\n >{t(key === 'hot' ? 'sortHot' : 'sortNew')}</button>\n ))}\n </div>\n </div>\n </div>\n {plugins.length === 0\n ? <div className={css.empty}>{t('empty')}</div>\n : (\n <>\n <div className={css.grid}>{plugins.slice(0, visibleCount).map(pluginCard)}</div>\n {plugins.length > visibleCount && <div ref={sentinelRef} className={css.sentinel} />}\n </>\n )}\n </>\n )\n : tab === 'themes' && themeSnap !== null\n ? (\n <>\n {/* Light/dark/system live in the official Appearance setting; this\n tab only shows what that setting can't: registered third-party\n palettes (none in the wild yet) and installable theme plugins. */}\n {(() => {\n const extra = themeSnap.themes.filter(def => def.id !== 'light' && def.id !== 'dark')\n return extra.length > 0 && (\n <div className={`${css.grid} ${css.themesGrid}`}>\n {extra.map(def => themeCard(def.id, def.id, themeSwatch(def)))}\n </div>\n )\n })()}\n {data === null\n ? <div className={css.loading}><span className={css.spin} />{t('loading')}</div>\n : themePlugins.length === 0\n ? <div className={css.empty}>{t('themeEmpty')}</div>\n : <div className={css.grid}>{themePlugins.map(themePluginCard)}</div>}\n </>\n )\n : Object.keys(installed).length === 0\n ? <div className={css.empty}>{t('installedEmpty')}</div>\n : Object.entries(installed).map(([name, spec]) => {\n const entry = data === null ? undefined : entryForDep(data.plugins, name, String(spec))\n const status = updates[name]\n const version = status && status.version ? 'v' + status.version : ''\n const specText = String(spec)\n const ghSpec = /^github:([A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+?)(?:#|$)/.exec(specText)\n const repoUrl = entry !== undefined ? entry.url : ghSpec !== null ? 'https://github.com/' + ghSpec[1] : null\n return (\n <div key={name} className={css.irow}>\n <div style={{ minWidth: 0 }}>\n <div className={css.nm}>{name}{version && <span className={css.owner}>{' ' + version}</span>}</div>\n {repoUrl !== null\n ? <a className={`${css.spec} ${css.src}`} href={repoUrl} target=\"_blank\" rel=\"noreferrer\" style={{ display: 'inline-block' }}>{specText}</a>\n : <div className={css.spec}>{specText}</div>}\n {entry !== undefined && (\n <div className={`${css.desc} ${css.descTight}`}>\n {(entry.description && (entry.description[lang] || entry.description.en)) || ''}\n </div>\n )}\n {updatingName === name && (\n <div className={css.progress}>\n <span className={css.spin} />\n <code className={css.grow}>{progressLine || t('progressHint')}</code>\n {progressPct !== null && <span className={css.pct}>{progressPct}%</span>}\n <button type=\"button\" className={css.cancelBtn} onClick={doCancel}>{t('cancelOp')}</button>\n </div>\n )}\n </div>\n <span className={css.grow} />\n {repoUrl !== null && <a className={css.src} href={repoUrl + '#readme'} target=\"_blank\" rel=\"noreferrer\">{t('readme')}</a>}\n {updatedNames.includes(name)\n ? <span className={css.okState}>{t('updated')}</span>\n : updatingName === name\n ? <Button variant=\"primary\" size=\"sm\" className={css.warnBtn} disabled>{t('updating')}</Button>\n : status && status.updateAvailable\n ? (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.warnBtn}\n disabled={updatingName !== null}\n onClick={() => doUpdate(name)}\n >{t('update')}</Button>\n )\n : status && status.kind === 'linked'\n ? <span className={css.owner}>{t('linkedDev')}</span>\n : <span className={css.owner}>{t('upToDate')}</span>}\n {name !== 'dsh-market' && name !== 'dshmarket' && (\n removingName === name\n ? <Button variant=\"outline\" size=\"sm\" className={css.dangerBtn} disabled>{t('uninstalling')}</Button>\n : removeArmed === name\n ? (\n <Button\n variant=\"primary\"\n size=\"sm\"\n className={css.dangerArmed}\n onClick={() => doUninstall(name)}\n onMouseLeave={() => setRemoveArmed(null)}\n >{t('confirmRemove')}</Button>\n )\n : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className={css.dangerBtn}\n disabled={removingName !== null || busyUrl !== null || updatingName !== null}\n onClick={() => setRemoveArmed(name)}\n >{t('uninstall')}</Button>\n )\n )}\n </div>\n )\n })}\n </div>\n {showTop && (\n <button\n className={css.top}\n title={t('backTop')}\n onClick={() => { const el = bodyRef.current; if (el) el.scrollTo({ top: 0, behavior: 'smooth' }) }}\n >↑</button>\n )}\n {confirming !== null && (\n <Modal\n open\n onClose={() => setConfirming(null)}\n title={t('confirmTitle') + ' ' + confirming.name + '?'}\n description={(confirming.description && (confirming.description[lang] || confirming.description.en)) || ''}\n footer={(\n <>\n <Button variant=\"ghost\" onClick={() => setConfirming(null)}>{t('cancel')}</Button>\n <Button variant=\"primary\" onClick={() => doInstall(confirming)}>{t('confirm')}</Button>\n </>\n )}\n >\n <details className={css.cmdDetails}>\n <summary className={css.cmdSummary}>{t('cmdDetails')}</summary>\n <div className={css.cmd}>{confirming.install}</div>\n </details>\n {looksTerminal(confirming, lang) && (\n <p className={css.warnLine}>\n {'🖥️ ' + t('terminalWarn') + ' '}\n <a className={css.src} href={confirming.url + '#readme'} target=\"_blank\" rel=\"noreferrer\">{t('readme')}</a>\n </p>\n )}\n <p className={css.modalNote}>{'⚠️ ' + t('confirmWarn')}</p>\n </Modal>\n )}\n </div>\n )\n}\n","/**\n * dsh-market client: registers a \"Market\" settings section rendering the\n * plugin market UI, plus the post-install toast in the shell overlay layer.\n * Built by tsdown into the __ModuleLoader__ factory bundle at\n * client/client.js; the only externals are the loader module table's react\n * entries.\n */\nimport { createElement as h } from 'react'\nimport { en, zh } from './locales.ts'\nimport { InstallToast } from './InstallToast.tsx'\nimport { MarketSection } from './MarketSection.tsx'\nimport type { ThemeSnapshot, Translate } from './market-data.ts'\n\nconst NS = 'dsh-market'\n\n/** The subset of the theme service this plugin touches. */\ninterface ThemeService {\n getTheme(): ThemeSnapshot | null\n setTheme(id: string): void\n}\n\n/** The subset of the locale service this plugin touches. */\ninterface LocaleService {\n register(namespace: string, dicts: { zh: Record<string, string>; en: Record<string, string> }): unknown\n bind(namespace: string): Translate\n subscribe(callback: () => void): () => void\n getSnapshot(): { active: string }\n}\n\n/** The subset of the slots service this plugin touches. */\ninterface SlotsService {\n inject(slot: string, register: () => unknown): void\n register(meta: Record<string, unknown>, component: () => unknown): unknown\n}\n\n/** The client cordis context shape this plugin relies on (structural: the\n * host provides the real Context; typing the touched surface keeps this\n * external package free of monorepo-internal type dependencies). */\ninterface MarketClientContext {\n effect(callback: () => unknown, label?: string): void\n on(event: string, callback: () => void): () => void\n locale: LocaleService\n slots: SlotsService\n theme: ThemeService\n}\n\nexport const name = 'dsh-market'\n// 'theme' is safe to require: ui-layout (mandatory in every web composition)\n// already hard-depends on it. This cordis's object-form inject means\n// intercept config, NOT {required,optional} — do not use it here.\nexport const inject = ['slots', 'locale', 'theme']\nexport function apply(ctx: MarketClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-market: dictionaries')\n const t = ctx.locale.bind(NS)\n\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'market',\n order: 40,\n label: () => t('nav'),\n locale: NS,\n inject: () => ({ t }),\n }, () => h(MarketSection, {\n t,\n locale: ctx.locale,\n theme: ctx.theme,\n themeStore: {\n subscribe: (cb: () => void) => ctx.on('theme/change', cb),\n getSnapshot: () => ctx.theme.getTheme(),\n },\n })))\n\n const Toast = () => h(InstallToast, { t })\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\n id: 'dsh-market-toast',\n label: () => 'dsh-market',\n }, Toast))\n}\n"],"mappings":"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"}
package/lib/dsh-cli.js CHANGED
@@ -7,12 +7,31 @@
7
7
  * the agent's sandboxed executor and denies writes to the profile directory.
8
8
  */
9
9
  import { spawn } from 'node:child_process';
10
- import { dirname, resolve } from 'node:path';
10
+ import { homedir } from 'node:os';
11
+ import { dirname, join, resolve } from 'node:path';
11
12
  import { logEvent } from './log.js';
12
13
  import { pluginArgsFor } from './pnpm-compat.js';
13
14
  import { profileDir } from './profile.js';
14
15
  // 15 min default (slow networks + git installs), overridable for CI/tests.
15
16
  // (#6 by @qichuang321.)
17
+ /**
18
+ * macOS apps launched from Finder/Dock inherit a minimal PATH without the
19
+ * shell profile — Homebrew/npm/corepack all vanish and every install dies
20
+ * with ENOENT/127 (#32, #38). Append the well-known bin directories so the
21
+ * market's children find their tools regardless of how dsh was started.
22
+ */
23
+ function spawnEnv() {
24
+ // pnpm v10+ blocks forever on a silent interactive prompt without a TTY;
25
+ // CI mode forces it to act or fail instead of asking.
26
+ if (process.platform === 'win32')
27
+ return { ...process.env, CI: 'true' };
28
+ const parts = (process.env.PATH ?? '').split(':').filter(part => part !== '');
29
+ for (const bin of ['/opt/homebrew/bin', '/usr/local/bin', join(homedir(), '.local', 'bin')]) {
30
+ if (!parts.includes(bin))
31
+ parts.push(bin);
32
+ }
33
+ return { ...process.env, CI: 'true', PATH: parts.join(':') };
34
+ }
16
35
  const INSTALL_TIMEOUT_MS = Number(process.env.DSH_MARKET_INSTALL_TIMEOUT_MS) || 15 * 60 * 1000;
17
36
  /**
18
37
  * Windows npm/corepack/pnpm are `.cmd` shims. Node's `spawn` without a shell
@@ -108,7 +127,7 @@ export function probePnpm() {
108
127
  if (pnpmReady)
109
128
  return Promise.resolve(true);
110
129
  return new Promise((resolvePromise) => {
111
- const child = spawn('pnpm', ['--version'], { stdio: 'ignore', shell: winCmdShim });
130
+ const child = spawn('pnpm', ['--version'], { stdio: 'ignore', shell: winCmdShim, env: spawnEnv() });
112
131
  child.on('error', () => resolvePromise(false));
113
132
  child.on('close', (code) => {
114
133
  pnpmReady = code === 0;
@@ -119,7 +138,7 @@ export function probePnpm() {
119
138
  function runQuiet(file, args, timeoutMs) {
120
139
  return new Promise((resolvePromise) => {
121
140
  const child = spawn(file, args, {
122
- env: { ...process.env, CI: 'true' },
141
+ env: spawnEnv(),
123
142
  stdio: ['ignore', 'pipe', 'pipe'],
124
143
  shell: winCmdShim,
125
144
  });
@@ -141,10 +160,22 @@ export async function provisionPnpm() {
141
160
  const corepack = await runQuiet('corepack', ['enable', 'pnpm'], 60 * 1000);
142
161
  logEvent(corepack.code === 0 ? 'info' : 'warn', 'setup-pnpm', `corepack enable: exit=${String(corepack.code)} ${corepack.output.slice(-200)}`);
143
162
  if (await probePnpm())
144
- return true;
163
+ return { ok: true };
145
164
  const npm = await runQuiet('npm', ['install', '-g', 'pnpm'], 3 * 60 * 1000);
146
165
  logEvent(npm.code === 0 ? 'info' : 'error', 'setup-pnpm', `npm -g: exit=${String(npm.code)} ${npm.output.slice(-200)}`);
147
- return probePnpm();
166
+ if (await probePnpm())
167
+ return { ok: true };
168
+ // Both provisioning tools missing = Node itself is not on this process's
169
+ // PATH (typical for Finder/Dock launches with nvm/fnm). Pointing the user
170
+ // back at this same button would be a dead end (#32) — say what actually
171
+ // helps.
172
+ const pathIssue = /ENOENT/.test(corepack.output) && /ENOENT/.test(npm.output);
173
+ return {
174
+ ok: false,
175
+ hint: pathIssue
176
+ ? '这台机器的 dsh 进程找不到 Node(从图形界面启动不继承终端 PATH)。请改从终端启动 dsh,或安装 Homebrew 版 pnpm:brew install pnpm / This dsh process cannot find Node (GUI launches skip your shell PATH). Start dsh from a terminal, or install pnpm via Homebrew: brew install pnpm'
177
+ : undefined,
178
+ };
148
179
  }
149
180
  /** Singleton progress state; the status route reads it, runDshPlugin writes it. */
150
181
  export const progress = { active: false, target: '', startedAt: 0, lastLine: '' };
@@ -180,7 +211,7 @@ export function runDshPlugin(profile, pluginArgs) {
180
211
  // pnpm v10 blocks forever on a silent interactive prompt without a TTY
181
212
  // (observed on re-add over a pinned git spec); CI mode forces it to act
182
213
  // or fail instead of asking.
183
- env: { ...process.env, CI: 'true' },
214
+ env: spawnEnv(),
184
215
  stdio: ['ignore', 'pipe', 'pipe'],
185
216
  shell: viaShell,
186
217
  // Own process group on POSIX so cancel/timeout can kill the whole
package/lib/routes.js CHANGED
@@ -315,7 +315,8 @@ export function mountMarketRoutes(host, config) {
315
315
  return;
316
316
  }
317
317
  try {
318
- sendJson(response, 200, { ok: await provisionPnpm() });
318
+ const result = await provisionPnpm();
319
+ sendJson(response, 200, { ok: result.ok, error: result.hint });
319
320
  }
320
321
  catch (error) {
321
322
  sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) });
@@ -457,6 +458,14 @@ export function mountMarketRoutes(host, config) {
457
458
  if (ok) {
458
459
  invalidateUpdates();
459
460
  hot = await hotUnmount(name);
461
+ // Bundle-layer plugins never hot-mount, but their loader entry
462
+ // is still LIVE in this process — after the remove deleted the
463
+ // package, the next refresh would 404 on its client bundle and
464
+ // wedge the whole page until a dsh restart (#37 by
465
+ // @1123762794). Live-disable the entry so the refresh composes
466
+ // without it; after a real restart the entry is gone anyway.
467
+ if (!hot)
468
+ hot = await themes.setEntryDisabled(name, true);
460
469
  }
461
470
  logEvent(ok || cancelled ? 'info' : 'error', 'uninstall', `${name} exit=${String(result.exitCode)}${cancelled ? ' CANCELLED' : ''}${ok ? ` live-removed=${String(hot)}` : cancelled ? '' : ` stderr=${result.stderr.slice(-300)}`}`);
462
471
  sendJson(response, ok || cancelled ? 200 : 502, {
@@ -52,7 +52,10 @@ export declare function probePnpm(): Promise<boolean>;
52
52
  * a global npm install as fallback.
53
53
  * @returns true when `pnpm --version` succeeds afterwards.
54
54
  */
55
- export declare function provisionPnpm(): Promise<boolean>;
55
+ export declare function provisionPnpm(): Promise<{
56
+ ok: boolean;
57
+ hint?: string;
58
+ }>;
56
59
  /** Live progress of the running plugin command, for the status route. */
57
60
  export interface InstallProgress {
58
61
  active: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dshmarket",
3
3
  "description": "Visual plugin market inside DeepSeek Harness — browse, search, and one-click install community plugins. · DSH 可视化插件市场:逛一逛,点一下,装好。",
4
- "version": "1.3.0",
4
+ "version": "1.3.1",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
@@ -29,7 +29,9 @@
29
29
  "test:compat": "vitest run --config vitest.compat.config.ts",
30
30
  "prepack": "npm run build && node scripts/preflight.mjs",
31
31
  "prepare": "npm run build",
32
- "snapshot": "curl -sf https://awesome-dsh-plugin.com/plugins.json -o data/registry-snapshot.json"
32
+ "validate:registry": "node scripts/validate-registry.mjs",
33
+ "snapshot": "curl -sf https://awesome-dsh-plugin.com/plugins.json -o data/registry-snapshot.json",
34
+ "test:web": "vitest run --config vitest.web.config.ts"
33
35
  },
34
36
  "peerDependencies": {
35
37
  "@deepseek-ai/cordis": "^4.0.1"
@@ -63,14 +65,20 @@
63
65
  "src",
64
66
  "client",
65
67
  "data",
66
- "cordis.patch.yml"
68
+ "cordis.patch.yml",
69
+ "LICENSE"
67
70
  ],
68
71
  "devDependencies": {
69
72
  "@deepseek-ai/cordis": "^4.0.1",
73
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.0.1-rc.1",
74
+ "@testing-library/react": "^16.3.2",
70
75
  "@types/node": "^26.2.0",
71
76
  "@types/react": "~18.3.1",
77
+ "jsdom": "^29.1.1",
72
78
  "lightningcss": "^1.33.0",
79
+ "playwright": "^1.62.1",
73
80
  "react": "^18.3.1",
81
+ "react-dom": "~18.3.1",
74
82
  "tsdown": "^0.22.14",
75
83
  "typescript": "^7.0.2",
76
84
  "vitest": "^4.1.10"
@@ -3,11 +3,11 @@
3
3
  * /dsh-market/* host routes, with install/update/uninstall flows and the
4
4
  * pending-restart bookkeeping in sessionStorage.
5
5
  */
6
- import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
6
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, type CSSProperties } from 'react'
7
7
  import { Button, IconChevronDownOutline14, IconChevronUpOutline14, IconSearchOutline16, Input, Modal, Pill, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'
8
8
  import css from './Market.module.css'
9
9
  import {
10
- avatarColor, entryForDep, isInstalled, LOGO_URI, looksTerminal, matchInstalledName, orderedCategories,
10
+ avatarColor, entryForDep, isInstalled, looksTerminal, matchInstalledName, orderedCategories,
11
11
  readSession, repoOf, themePlugins as themePluginsOf, themeSwatch, visiblePlugins,
12
12
  } from './market-data.ts'
13
13
  import type {
@@ -38,6 +38,21 @@ function OwnerAvatar({ name, owner }: { name: string; owner: string }) {
38
38
  )
39
39
  }
40
40
 
41
+ /**
42
+ * Official-style market glyph: the shared block-grid brand mark converted to
43
+ * the official monochrome icon form (16×16, fill="currentColor") so it
44
+ * follows the active theme. Mirrors the settings-nav glyph used for the
45
+ * "market" section id.
46
+ */
47
+ function MarketLogo({ size = 16, style }: { size?: number; style?: CSSProperties }) {
48
+ return (
49
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" style={style}>
50
+ <path fill="currentColor" d="M2.35 1.75H4.95A0.6 0.6 0 0 1 5.55 2.35V4.95A0.6 0.6 0 0 1 4.95 5.55H2.35A0.6 0.6 0 0 1 1.75 4.95V2.35A0.6 0.6 0 0 1 2.35 1.75ZM6.7 1.75H9.3A0.6 0.6 0 0 1 9.9 2.35V4.95A0.6 0.6 0 0 1 9.3 5.55H6.7A0.6 0.6 0 0 1 6.1 4.95V2.35A0.6 0.6 0 0 1 6.7 1.75ZM2.35 6.1H4.95A0.6 0.6 0 0 1 5.55 6.7V9.3A0.6 0.6 0 0 1 4.95 9.9H2.35A0.6 0.6 0 0 1 1.75 9.3V6.7A0.6 0.6 0 0 1 2.35 6.1ZM6.7 6.1H9.3A0.6 0.6 0 0 1 9.9 6.7V9.3A0.6 0.6 0 0 1 9.3 9.9H6.7A0.6 0.6 0 0 1 6.1 9.3V6.7A0.6 0.6 0 0 1 6.7 6.1ZM11.05 6.1H13.65A0.6 0.6 0 0 1 14.25 6.7V9.3A0.6 0.6 0 0 1 13.65 9.9H11.05A0.6 0.6 0 0 1 10.45 9.3V6.7A0.6 0.6 0 0 1 11.05 6.1ZM2.35 10.45H4.95A0.6 0.6 0 0 1 5.55 11.05V13.65A0.6 0.6 0 0 1 4.95 14.25H2.35A0.6 0.6 0 0 1 1.75 13.65V11.05A0.6 0.6 0 0 1 2.35 10.45ZM6.7 10.45H9.3A0.6 0.6 0 0 1 9.9 11.05V13.65A0.6 0.6 0 0 1 9.3 14.25H6.7A0.6 0.6 0 0 1 6.1 13.65V11.05A0.6 0.6 0 0 1 6.7 10.45ZM11.05 10.45H13.65A0.6 0.6 0 0 1 14.25 11.05V13.65A0.6 0.6 0 0 1 13.65 14.25H11.05A0.6 0.6 0 0 1 10.45 13.65V11.05A0.6 0.6 0 0 1 11.05 10.45Z" />
51
+ <path fill="currentColor" d="M11.05 1.75H13.65A0.6 0.6 0 0 1 14.25 2.35V4.95A0.6 0.6 0 0 1 13.65 5.55H11.05A0.6 0.6 0 0 1 10.45 4.95V2.35A0.6 0.6 0 0 1 11.05 1.75Z" transform="rotate(9 12.35 3.65)" />
52
+ </svg>
53
+ )
54
+ }
55
+
41
56
  /**
42
57
  * Module-scope caches so re-entering the section renders instantly instead
43
58
  * of refetching and rebuilding from a spinner (#30 by @StarsTom). Module
@@ -85,6 +100,8 @@ export function MarketSection(props: MarketSectionProps) {
85
100
  const [cat, setCat] = useState('all')
86
101
  const [confirming, setConfirming] = useState<RegistryPlugin | null>(null)
87
102
  const [busyUrl, setBusyUrl] = useState<string | null>(null)
103
+ /** Consecutive idle polls with a pending install that never landed (#32). */
104
+ const idleStrikes = useRef(0)
88
105
  const [doneUrls, setDoneUrls] = useState<string[]>([])
89
106
  const [installError, setInstallError] = useState<string | null>(null)
90
107
  const [updates, setUpdates] = useState<Record<string, UpdateStatus>>({})
@@ -199,8 +216,12 @@ export function MarketSection(props: MarketSectionProps) {
199
216
  fetch('/dsh-market/setup-pnpm', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })
200
217
  .then(res => res.json())
201
218
  .then(body => {
202
- if (body.ok) setEnvReady(true)
203
- else setEnvFailed(true)
219
+ if (body.ok) {
220
+ setEnvReady(true)
221
+ } else {
222
+ setEnvFailed(true)
223
+ if (typeof body.error === 'string') setInstallError(body.error)
224
+ }
204
225
  })
205
226
  .catch(() => setEnvFailed(true))
206
227
  .finally(() => setEnvFixing(false))
@@ -239,9 +260,18 @@ export function MarketSection(props: MarketSectionProps) {
239
260
  const nowInstalled = data !== null && data.plugins.some(p =>
240
261
  p.url === busyUrl && isInstalled(p, status.installed || {}))
241
262
  if (nowInstalled) {
263
+ idleStrikes.current = 0
242
264
  sessionStorage.removeItem('dshm-pending')
243
265
  setDoneUrls(urls => urls.includes(busyUrl) ? urls : urls.concat(busyUrl))
244
266
  setBusyUrl(null)
267
+ } else if (++idleStrikes.current >= 2) {
268
+ // Host is idle and the plugin never landed: the install died
269
+ // (e.g. exit 127) with its response lost. Without this the
270
+ // button says "installing" forever — across reloads (#32).
271
+ idleStrikes.current = 0
272
+ sessionStorage.removeItem('dshm-pending')
273
+ setBusyUrl(null)
274
+ setInstallError(t('installFail') + ' — ' + t('exportLog'))
245
275
  }
246
276
  }
247
277
  }
@@ -619,7 +649,7 @@ export function MarketSection(props: MarketSectionProps) {
619
649
  <div className={css.root}>
620
650
  <div className={css.head}>
621
651
  <div className={css.titleRow}>
622
- <img src={LOGO_URI} width={22} height={22} alt="" style={{ borderRadius: '5px', flexShrink: 0 }} />
652
+ <MarketLogo size={22} style={{ flexShrink: 0 }} />
623
653
  <h2 className={css.title}>{t('nav')}</h2>
624
654
  {(() => {
625
655
  const self = installed['dshmarket'] !== undefined ? 'dshmarket' : 'dsh-market'
@@ -191,10 +191,10 @@ export function isInstalled(plugin: RegistryPlugin, installed: InstalledMap): bo
191
191
  }
192
192
 
193
193
  /**
194
- * The brand mark (assets/logo.svg shared block-grid mark with
195
- * awesome-dsh-plugin), inlined so the header needs no extra request.
194
+ * The header brand mark now lives in MarketSection.tsx as an inline SVG
195
+ * (official-style monochrome glyph, fill="currentColor") so it follows the
196
+ * active theme; the colored assets/logo.svg tile is no longer inlined here.
196
197
  */
197
- export const LOGO_URI = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><rect width="128" height="128" rx="28" fill="#f6f2ea"/><g transform="translate(15.7 16.7) scale(0.3) translate(-112 -78)"><g fill="#2b2620"><rect x="112" y="112" width="88" height="88" rx="14"/><rect x="212" y="112" width="88" height="88" rx="14"/><rect x="112" y="212" width="88" height="88" rx="14"/><rect x="212" y="212" width="88" height="88" rx="14"/><rect x="112" y="312" width="88" height="88" rx="14"/><rect x="212" y="312" width="88" height="88" rx="14"/><rect x="312" y="212" width="88" height="88" rx="14"/><rect x="312" y="312" width="88" height="88" rx="14"/></g><rect x="346" y="78" width="88" height="88" rx="14" fill="#c0392b" transform="rotate(9 390 122)"/></g></svg>')
198
198
 
199
199
  /** Four representative colors for a theme card's preview strip. */
200
200
  export function themeSwatch(def: ThemeDef): string[] {
package/src/dsh-cli.ts CHANGED
@@ -9,13 +9,31 @@
9
9
 
10
10
  import { spawn } from 'node:child_process'
11
11
  import type { ChildProcess } from 'node:child_process'
12
- import { dirname, resolve } from 'node:path'
12
+ import { homedir } from 'node:os'
13
+ import { dirname, join, resolve } from 'node:path'
13
14
  import { logEvent } from './log.ts'
14
15
  import { pluginArgsFor } from './pnpm-compat.ts'
15
16
  import { profileDir } from './profile.ts'
16
17
 
17
18
  // 15 min default (slow networks + git installs), overridable for CI/tests.
18
19
  // (#6 by @qichuang321.)
20
+ /**
21
+ * macOS apps launched from Finder/Dock inherit a minimal PATH without the
22
+ * shell profile — Homebrew/npm/corepack all vanish and every install dies
23
+ * with ENOENT/127 (#32, #38). Append the well-known bin directories so the
24
+ * market's children find their tools regardless of how dsh was started.
25
+ */
26
+ function spawnEnv(): NodeJS.ProcessEnv {
27
+ // pnpm v10+ blocks forever on a silent interactive prompt without a TTY;
28
+ // CI mode forces it to act or fail instead of asking.
29
+ if (process.platform === 'win32') return { ...process.env, CI: 'true' }
30
+ const parts = (process.env.PATH ?? '').split(':').filter(part => part !== '')
31
+ for (const bin of ['/opt/homebrew/bin', '/usr/local/bin', join(homedir(), '.local', 'bin')]) {
32
+ if (!parts.includes(bin)) parts.push(bin)
33
+ }
34
+ return { ...process.env, CI: 'true', PATH: parts.join(':') }
35
+ }
36
+
19
37
  const INSTALL_TIMEOUT_MS = Number(process.env.DSH_MARKET_INSTALL_TIMEOUT_MS) || 15 * 60 * 1000
20
38
 
21
39
  /**
@@ -121,7 +139,7 @@ let pnpmReady = false
121
139
  export function probePnpm(): Promise<boolean> {
122
140
  if (pnpmReady) return Promise.resolve(true)
123
141
  return new Promise((resolvePromise) => {
124
- const child = spawn('pnpm', ['--version'], { stdio: 'ignore', shell: winCmdShim })
142
+ const child = spawn('pnpm', ['--version'], { stdio: 'ignore', shell: winCmdShim, env: spawnEnv() })
125
143
  child.on('error', () => resolvePromise(false))
126
144
  child.on('close', (code) => {
127
145
  pnpmReady = code === 0
@@ -133,7 +151,7 @@ export function probePnpm(): Promise<boolean> {
133
151
  function runQuiet(file: string, args: string[], timeoutMs: number): Promise<{ code: number | null; output: string }> {
134
152
  return new Promise((resolvePromise) => {
135
153
  const child = spawn(file, args, {
136
- env: { ...process.env, CI: 'true' },
154
+ env: spawnEnv(),
137
155
  stdio: ['ignore', 'pipe', 'pipe'],
138
156
  shell: winCmdShim,
139
157
  })
@@ -152,13 +170,24 @@ function runQuiet(file: string, args: string[], timeoutMs: number): Promise<{ co
152
170
  * a global npm install as fallback.
153
171
  * @returns true when `pnpm --version` succeeds afterwards.
154
172
  */
155
- export async function provisionPnpm(): Promise<boolean> {
173
+ export async function provisionPnpm(): Promise<{ ok: boolean; hint?: string }> {
156
174
  const corepack = await runQuiet('corepack', ['enable', 'pnpm'], 60 * 1000)
157
175
  logEvent(corepack.code === 0 ? 'info' : 'warn', 'setup-pnpm', `corepack enable: exit=${String(corepack.code)} ${corepack.output.slice(-200)}`)
158
- if (await probePnpm()) return true
176
+ if (await probePnpm()) return { ok: true }
159
177
  const npm = await runQuiet('npm', ['install', '-g', 'pnpm'], 3 * 60 * 1000)
160
178
  logEvent(npm.code === 0 ? 'info' : 'error', 'setup-pnpm', `npm -g: exit=${String(npm.code)} ${npm.output.slice(-200)}`)
161
- return probePnpm()
179
+ if (await probePnpm()) return { ok: true }
180
+ // Both provisioning tools missing = Node itself is not on this process's
181
+ // PATH (typical for Finder/Dock launches with nvm/fnm). Pointing the user
182
+ // back at this same button would be a dead end (#32) — say what actually
183
+ // helps.
184
+ const pathIssue = /ENOENT/.test(corepack.output) && /ENOENT/.test(npm.output)
185
+ return {
186
+ ok: false,
187
+ hint: pathIssue
188
+ ? '这台机器的 dsh 进程找不到 Node(从图形界面启动不继承终端 PATH)。请改从终端启动 dsh,或安装 Homebrew 版 pnpm:brew install pnpm / This dsh process cannot find Node (GUI launches skip your shell PATH). Start dsh from a terminal, or install pnpm via Homebrew: brew install pnpm'
189
+ : undefined,
190
+ }
162
191
  }
163
192
 
164
193
  /** Live progress of the running plugin command, for the status route. */
@@ -206,7 +235,7 @@ export function runDshPlugin(profile: string, pluginArgs: string[]): Promise<Ins
206
235
  // pnpm v10 blocks forever on a silent interactive prompt without a TTY
207
236
  // (observed on re-add over a pinned git spec); CI mode forces it to act
208
237
  // or fail instead of asking.
209
- env: { ...process.env, CI: 'true' },
238
+ env: spawnEnv(),
210
239
  stdio: ['ignore', 'pipe', 'pipe'],
211
240
  shell: viaShell,
212
241
  // Own process group on POSIX so cancel/timeout can kill the whole
package/src/routes.ts CHANGED
@@ -349,7 +349,8 @@ export function mountMarketRoutes(host: MarketHost, config: MarketConfig): () =>
349
349
  return
350
350
  }
351
351
  try {
352
- sendJson(response, 200, { ok: await provisionPnpm() })
352
+ const result = await provisionPnpm()
353
+ sendJson(response, 200, { ok: result.ok, error: result.hint })
353
354
  } catch (error) {
354
355
  sendJson(response, 500, { error: error instanceof Error ? error.message : String(error) })
355
356
  }
@@ -492,6 +493,13 @@ export function mountMarketRoutes(host: MarketHost, config: MarketConfig): () =>
492
493
  if (ok) {
493
494
  invalidateUpdates()
494
495
  hot = await hotUnmount(name)
496
+ // Bundle-layer plugins never hot-mount, but their loader entry
497
+ // is still LIVE in this process — after the remove deleted the
498
+ // package, the next refresh would 404 on its client bundle and
499
+ // wedge the whole page until a dsh restart (#37 by
500
+ // @1123762794). Live-disable the entry so the refresh composes
501
+ // without it; after a real restart the entry is gone anyway.
502
+ if (!hot) hot = await themes.setEntryDisabled(name, true)
495
503
  }
496
504
  logEvent(ok || cancelled ? 'info' : 'error', 'uninstall',
497
505
  `${name} exit=${String(result.exitCode)}${cancelled ? ' CANCELLED' : ''}${ok ? ` live-removed=${String(hot)}` : cancelled ? '' : ` stderr=${result.stderr.slice(-300)}`}`)