dsh-m 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -112,6 +112,304 @@ var init_market_state = __esm({
112
112
  }
113
113
  });
114
114
 
115
+ // src/client/markdown.js
116
+ var markdown_exports = {};
117
+ __export(markdown_exports, {
118
+ createMarkdown: () => createMarkdown,
119
+ safeUrl: () => safeUrl
120
+ });
121
+ function safeUrl(u) {
122
+ const t = String(u || "").trim();
123
+ if (/^(https?:\/\/|mailto:)/i.test(t)) return t;
124
+ if (/^[/#]/.test(t)) return t;
125
+ return "#";
126
+ }
127
+ function createMarkdown(h2) {
128
+ function ExtLink2({ href, className, children }) {
129
+ return h2(
130
+ "a",
131
+ {
132
+ className: className || "dshm-md-a",
133
+ href: safeUrl(href),
134
+ target: "_blank",
135
+ rel: "noopener noreferrer",
136
+ onClick: (e) => e.stopPropagation()
137
+ },
138
+ children
139
+ );
140
+ }
141
+ function MdImg2({ src, alt }) {
142
+ return h2("img", {
143
+ className: "dshm-md-img",
144
+ src: safeUrl(src),
145
+ alt: alt || "",
146
+ referrerPolicy: "no-referrer",
147
+ onError: (e) => {
148
+ e.currentTarget.style.display = "none";
149
+ }
150
+ });
151
+ }
152
+ function mdInline(text, kb) {
153
+ const re = /(\[!\[[^\]]*\]\([^)]*\)\]\([^)]*\))|(!\[[^\]]*\]\([^)]*\))|(\[[^\]]*\]\([^)]*\))|(`[^`]+`)|(\*\*[^*]+\*\*)|(~~[^~]+~~)|(\*[^*\s][^*]*\*)|(<https?:\/\/[^>\s]+>)|(https?:\/\/[^\s<>()\[\]{}"'「」【】]+[^\s<>()\[\]{}"'「」【】.,;:!?…,。;:!?)】」"')])/g;
154
+ const src = String(text);
155
+ const nodes = [];
156
+ let last = 0;
157
+ let m;
158
+ let i = 0;
159
+ while (m = re.exec(src)) {
160
+ if (m.index > last) nodes.push(src.slice(last, m.index));
161
+ const tok = m[0];
162
+ const k = `${kb}-${i++}`;
163
+ if (tok.startsWith("[![")) {
164
+ const im = /^!\[([^\]]*)\]\(([^)]*)\)/.exec(tok.slice(1));
165
+ const lm = /\]\(([^)]*)\)\s*$/.exec(tok);
166
+ const img = h2(MdImg2, { src: im && im[2], alt: im && im[1] });
167
+ const href = lm && lm[1];
168
+ nodes.push(href && safeUrl(href) !== "#" ? h2(ExtLink2, { key: k, href }, img) : h2("span", { key: k }, img));
169
+ } else if (tok.startsWith("![") || tok.startsWith("<![")) {
170
+ const im = /^!\[([^\]]*)\]\(([^)]*)\)$/.exec(tok);
171
+ nodes.push(h2(MdImg2, { key: k, src: im && im[2], alt: im && im[1] }));
172
+ } else if (tok.startsWith("[")) {
173
+ const lm = /^\[([^\]]*)\]\(([^)]*)\)$/.exec(tok);
174
+ nodes.push(h2(ExtLink2, { key: k, href: lm && lm[2] }, mdInline(lm ? lm[1] : tok, k)));
175
+ } else if (tok.startsWith("`")) {
176
+ nodes.push(h2("code", { key: k }, tok.slice(1, -1)));
177
+ } else if (tok.startsWith("**")) {
178
+ nodes.push(h2("strong", { key: k }, mdInline(tok.slice(2, -2), k)));
179
+ } else if (tok.startsWith("~~")) {
180
+ nodes.push(h2("del", { key: k }, mdInline(tok.slice(2, -2), k)));
181
+ } else if (tok.startsWith("*")) {
182
+ nodes.push(h2("em", { key: k }, mdInline(tok.slice(1, -1), k)));
183
+ } else if (tok.startsWith("<")) {
184
+ const u = tok.slice(1, -1);
185
+ nodes.push(h2(ExtLink2, { key: k, href: u }, u));
186
+ } else {
187
+ nodes.push(h2(ExtLink2, { key: k, href: tok }, tok.length > 72 ? `${tok.slice(0, 69)}\u2026` : tok));
188
+ }
189
+ last = m.index + tok.length;
190
+ }
191
+ if (last < src.length) nodes.push(src.slice(last));
192
+ return nodes;
193
+ }
194
+ function mdBlocks(lines, kb) {
195
+ const out = [];
196
+ let i = 0;
197
+ let n = 0;
198
+ const isFence = (s) => /^\s*```/.test(s);
199
+ const isHeading = (s) => /^#{1,6}\s+/.test(s);
200
+ const isHr = (s) => /^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(s);
201
+ const isQuote = (s) => /^\s*>/.test(s);
202
+ const isUl = (s) => /^\s*[-*+]\s+/.test(s);
203
+ const isOl = (s) => /^\s*\d+[.)]\s+/.test(s);
204
+ const isTableRow = (s) => s.includes("|") && /^\s*\|/.test(s);
205
+ while (i < lines.length) {
206
+ const line = lines[i];
207
+ if (!line.trim()) {
208
+ i++;
209
+ continue;
210
+ }
211
+ const k = `${kb}-b${n++}`;
212
+ if (isFence(line)) {
213
+ const buf2 = [];
214
+ i++;
215
+ while (i < lines.length && !/^\s*```\s*$/.test(lines[i])) buf2.push(lines[i++]);
216
+ i++;
217
+ out.push(h2("pre", { key: k }, h2("code", null, buf2.join("\n"))));
218
+ continue;
219
+ }
220
+ if (isHeading(line)) {
221
+ const hm = /^(#{1,6})\s+(.*)$/.exec(line);
222
+ out.push(h2(`h${hm[1].length}`, { key: k }, mdInline(hm[2], k)));
223
+ i++;
224
+ continue;
225
+ }
226
+ if (isHr(line)) {
227
+ out.push(h2("hr", { key: k }));
228
+ i++;
229
+ continue;
230
+ }
231
+ if (isQuote(line)) {
232
+ const buf2 = [];
233
+ while (i < lines.length && isQuote(lines[i])) buf2.push(lines[i++].replace(/^\s*>\s?/, ""));
234
+ out.push(h2("blockquote", { key: k }, mdBlocks(buf2, k)));
235
+ continue;
236
+ }
237
+ if (isUl(line) || isOl(line)) {
238
+ const ordered = isOl(line);
239
+ const re = ordered ? /^\s*\d+[.)]\s+(.*)$/ : /^\s*[-*+]\s+(.*)$/;
240
+ const items = [];
241
+ while (i < lines.length && (ordered ? isOl(lines[i]) : isUl(lines[i]))) {
242
+ items.push(h2("li", { key: `li${items.length}` }, mdInline(re.exec(lines[i])[1], `${k}-${items.length}`)));
243
+ i++;
244
+ }
245
+ out.push(h2(ordered ? "ol" : "ul", { key: k }, items));
246
+ continue;
247
+ }
248
+ if (isTableRow(line) && i + 1 < lines.length && lines[i + 1].includes("-") && /^\s*\|?[\s:|-]+\|?\s*$/.test(lines[i + 1])) {
249
+ const cells = (s) => s.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
250
+ const head = cells(lines[i]);
251
+ i += 2;
252
+ const rows = [];
253
+ while (i < lines.length && isTableRow(lines[i])) {
254
+ rows.push(cells(lines[i]));
255
+ i++;
256
+ }
257
+ out.push(
258
+ h2(
259
+ "table",
260
+ { key: k },
261
+ h2("thead", null, h2("tr", null, head.map((c, x) => h2("th", { key: x }, mdInline(c, `${k}h${x}`))))),
262
+ h2("tbody", null, rows.map((r, y) => h2("tr", { key: y }, r.map((c, x) => h2("td", { key: x }, mdInline(c, `${k}${y}x${x}`))))))
263
+ )
264
+ );
265
+ continue;
266
+ }
267
+ const buf = [line];
268
+ i++;
269
+ while (i < lines.length && lines[i].trim() && !isFence(lines[i]) && !isHeading(lines[i]) && !isHr(lines[i]) && !isQuote(lines[i]) && !isUl(lines[i]) && !isOl(lines[i])) {
270
+ buf.push(lines[i]);
271
+ i++;
272
+ }
273
+ out.push(h2("p", { key: k }, mdInline(buf.join(" "), k)));
274
+ }
275
+ return out;
276
+ }
277
+ function renderMarkdown2(src) {
278
+ return mdBlocks(String(src || "").replace(/\r\n?/g, "\n").split("\n"), "md");
279
+ }
280
+ return { ExtLink: ExtLink2, MdImg: MdImg2, renderMarkdown: renderMarkdown2 };
281
+ }
282
+ var init_markdown = __esm({
283
+ "src/client/markdown.js"() {
284
+ "use strict";
285
+ }
286
+ });
287
+
288
+ // src/client/installed-view.js
289
+ var installed_view_exports = {};
290
+ __export(installed_view_exports, {
291
+ installedViewModel: () => installedViewModel,
292
+ registrySourceKey: () => registrySourceKey
293
+ });
294
+ function uninstallGuardKeys(it) {
295
+ if (it.source === "link") {
296
+ return { confirmKey: "confirm.unlink", warnKey: "warn.unlink", warnParams: { path: it.path } };
297
+ }
298
+ if (it.source === "file") {
299
+ return { confirmKey: "confirm.core", warnKey: "warn.core", warnParams: {} };
300
+ }
301
+ return { confirmKey: "confirm.uninstall", warnKey: null, warnParams: {} };
302
+ }
303
+ function installedViewModel(it) {
304
+ return {
305
+ githubRepo: it.registryGithub || it.githubRepo || (it.spec.startsWith("github:") ? it.spec.slice(7).split("#")[0] : null),
306
+ sourceLabelKey: { npm: "src.npm", github: "src.github", link: "src.link", file: "src.file", unknown: "src.unknown" }[it.source] || null,
307
+ guard: uninstallGuardKeys(it),
308
+ latestLabel: it.latestTag || (it.latestVersion ? `v${it.latestVersion}` : ""),
309
+ latestLabelDetail: it.latestTag || (it.latestVersion ? `v${it.latestVersion}` : "\u2014")
310
+ };
311
+ }
312
+ function registrySourceKey(data) {
313
+ if (!data) return null;
314
+ const map = {
315
+ "default-raw": "src.default.raw",
316
+ "default-jsdelivr": "src.default.jsdelivr",
317
+ "default-cache": "src.default.cache",
318
+ bundled: "src.bundled",
319
+ "custom-url": "src.custom.url",
320
+ "custom-file": "src.custom.file",
321
+ "custom-cache": "src.custom.cache",
322
+ "custom-unavailable": "src.custom.unavailable",
323
+ // 旧字段兼容
324
+ override: "src.override",
325
+ jsdelivr: "src.jsdelivr",
326
+ raw: "src.raw",
327
+ cache: "src.cache"
328
+ };
329
+ return map[data.source] || data.source;
330
+ }
331
+ var init_installed_view = __esm({
332
+ "src/client/installed-view.js"() {
333
+ "use strict";
334
+ }
335
+ });
336
+
337
+ // src/client/tool-view.js
338
+ var tool_view_exports = {};
339
+ __export(tool_view_exports, {
340
+ parseToolArgs: () => parseToolArgs,
341
+ pickPayload: () => pickPayload
342
+ });
343
+ function pickPayload(props) {
344
+ const found = [];
345
+ const visit = (node, depth) => {
346
+ if (!node || depth > 6) return;
347
+ if (typeof node === "string") {
348
+ const t = node.trim();
349
+ if ((t.startsWith("{") || t.startsWith("[")) && t.length > 8) {
350
+ try {
351
+ visit(JSON.parse(t), depth + 1);
352
+ } catch {
353
+ }
354
+ }
355
+ return;
356
+ }
357
+ if (typeof node !== "object") return;
358
+ if (Array.isArray(node)) {
359
+ for (const x of node) visit(x, depth + 1);
360
+ return;
361
+ }
362
+ if (Array.isArray(node.items)) found.push(node);
363
+ for (const key of ["block", "meta", "result", "resultView", "view", "data", "value", "payload", "content", "message"]) {
364
+ if (node[key] != null) visit(node[key], depth + 1);
365
+ }
366
+ };
367
+ visit(props, 0);
368
+ return found.find((x) => x && Array.isArray(x.items)) || null;
369
+ }
370
+ function parseToolArgs(props) {
371
+ const block = props?.block;
372
+ const raw = (block && "kind" in block ? block.call?.argsRaw : block?.argsRaw) || "";
373
+ if (!raw || typeof raw !== "string") return {};
374
+ try {
375
+ return JSON.parse(raw);
376
+ } catch {
377
+ return {};
378
+ }
379
+ }
380
+ var init_tool_view = __esm({
381
+ "src/client/tool-view.js"() {
382
+ "use strict";
383
+ }
384
+ });
385
+
386
+ // src/client/restart-wait.js
387
+ var restart_wait_exports = {};
388
+ __export(restart_wait_exports, {
389
+ RESTART_DEADLINE_MS: () => RESTART_DEADLINE_MS,
390
+ RESTART_POLL_MS: () => RESTART_POLL_MS,
391
+ isAmbiguousRestartRequestError: () => isAmbiguousRestartRequestError,
392
+ nextRestartWait: () => nextRestartWait
393
+ });
394
+ function nextRestartWait({ phase, now = 0, deadlineAt = Infinity, bootChanged = false }) {
395
+ if (phase === "before-ping") {
396
+ return now > deadlineAt ? "timeout" : "continue";
397
+ }
398
+ return bootChanged ? "done" : "continue";
399
+ }
400
+ function isAmbiguousRestartRequestError(error) {
401
+ const name = error && typeof error === "object" ? error.name : "";
402
+ return name === "TypeError" || name === "AbortError" || name === "NetworkError";
403
+ }
404
+ var RESTART_POLL_MS, RESTART_DEADLINE_MS;
405
+ var init_restart_wait = __esm({
406
+ "src/client/restart-wait.js"() {
407
+ "use strict";
408
+ RESTART_POLL_MS = 2e3;
409
+ RESTART_DEADLINE_MS = 9e4;
410
+ }
411
+ });
412
+
115
413
  // src/client/main.jsx
116
414
  var React = require("react");
117
415
  var rd = require("react-dom");
@@ -120,6 +418,11 @@ var { useState, useEffect, useCallback, useMemo, useRef } = React;
120
418
  var PLUGIN_ID = "dsh-m";
121
419
  var API = "/dshm";
122
420
  var { MARKET_PAGE_SIZE: MARKET_PAGE_SIZE2, normalizeMarketQuery: normalizeMarketQuery2, resetPageOnFilterChange: resetPageOnFilterChange2, normalizeMarketResponse: normalizeMarketResponse2, registryNotice: registryNotice2 } = (init_market_state(), __toCommonJS(market_state_exports));
421
+ var { createMarkdown: createMarkdown2 } = (init_markdown(), __toCommonJS(markdown_exports));
422
+ var { ExtLink, MdImg, renderMarkdown } = createMarkdown2(h);
423
+ var { installedViewModel: installedViewModel2, registrySourceKey: registrySourceKey2 } = (init_installed_view(), __toCommonJS(installed_view_exports));
424
+ var { pickPayload: pickPayload2, parseToolArgs: parseToolArgs2 } = (init_tool_view(), __toCommonJS(tool_view_exports));
425
+ var { RESTART_POLL_MS: RESTART_POLL_MS2, RESTART_DEADLINE_MS: RESTART_DEADLINE_MS2, nextRestartWait: nextRestartWait2, isAmbiguousRestartRequestError: isAmbiguousRestartRequestError2 } = (init_restart_wait(), __toCommonJS(restart_wait_exports));
123
426
  var ZH = {
124
427
  "market.title": "\u63D2\u4EF6\u5E02\u573A",
125
428
  "tab.market": "\u5E02\u573A",
@@ -269,7 +572,7 @@ var ZH = {
269
572
  "restart.now": "\u26A1 \u4E00\u952E\u91CD\u542F",
270
573
  "restart.failed": "\u91CD\u542F\u5931\u8D25\uFF1A{err}",
271
574
  "restart.timeout": "\u91CD\u542F\u8D85\u65F6\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5 dsh web \u670D\u52A1\u72B6\u6001",
272
- "restart.hint.done": "\u5DF2\u8BF7\u6C42\u91CD\u542F DSH web\uFF08via {via}\uFF09\u3002\u670D\u52A1\u51E0\u79D2\u5185\u6062\u590D\uFF0C\u4E4B\u540E\u8BA9\u7528\u6237\u5237\u65B0\u9875\u9762\u5373\u53EF\u3002",
575
+ "restart.hint.done": "\u5DF2\u8BF7\u6C42\u91CD\u542F DSH web\uFF08via {via}\uFF09\u3002\u670D\u52A1\u6062\u590D\u540E DSH Web \u4F1A\u5728\u540E\u53F0\u81EA\u52A8\u91CD\u8FDE\u3002",
273
576
  "phase.resolving": "\u89E3\u6790\u4F9D\u8D56",
274
577
  "phase.downloading": "\u4E0B\u8F7D",
275
578
  "phase.linking": "\u94FE\u63A5\u5B89\u88C5",
@@ -288,8 +591,6 @@ var ZH = {
288
591
  };
289
592
  var EN = {
290
593
  "market.title": "Plugin Marketplace",
291
- "title.panel": "Plugin Marketplace",
292
- "title.full": "DeepSeek Harness Plugin Marketplace",
293
594
  "tab.market": "Market",
294
595
  "tab.installed": "Installed",
295
596
  "tab.settings": "Settings",
@@ -437,7 +738,7 @@ var EN = {
437
738
  "restart.now": "\u26A1 Restart",
438
739
  "restart.failed": "Restart failed: {err}",
439
740
  "restart.timeout": "Restart timed out \u2014 check the dsh web service manually",
440
- "restart.hint.done": "Restart requested (via {via}). The service will be back in seconds; ask the user to refresh afterwards.",
741
+ "restart.hint.done": "Restart requested (via {via}). DSH Web will reconnect in the background after the service returns.",
441
742
  "phase.resolving": "Resolving",
442
743
  "phase.downloading": "Downloading",
443
744
  "phase.linking": "Linking",
@@ -664,164 +965,6 @@ function Icon({ entry }) {
664
965
  function Spin() {
665
966
  return h("span", { className: "dshm-spin" });
666
967
  }
667
- function safeUrl(u) {
668
- const t = String(u || "").trim();
669
- if (/^(https?:\/\/|mailto:)/i.test(t)) return t;
670
- if (/^[/#]/.test(t)) return t;
671
- return "#";
672
- }
673
- function ExtLink({ href, className, children }) {
674
- return h(
675
- "a",
676
- {
677
- className: className || "dshm-md-a",
678
- href: safeUrl(href),
679
- target: "_blank",
680
- rel: "noopener noreferrer",
681
- onClick: (e) => e.stopPropagation()
682
- },
683
- children
684
- );
685
- }
686
- function MdImg({ src, alt }) {
687
- return h("img", {
688
- className: "dshm-md-img",
689
- src: safeUrl(src),
690
- alt: alt || "",
691
- referrerPolicy: "no-referrer",
692
- onError: (e) => {
693
- e.currentTarget.style.display = "none";
694
- }
695
- });
696
- }
697
- function mdInline(text, kb) {
698
- const re = /(\[!\[[^\]]*\]\([^)]*\)\]\([^)]*\))|(!\[[^\]]*\]\([^)]*\))|(\[[^\]]*\]\([^)]*\))|(`[^`]+`)|(\*\*[^*]+\*\*)|(~~[^~]+~~)|(\*[^*\s][^*]*\*)|(<https?:\/\/[^>\s]+>)|(https?:\/\/[^\s<>()\[\]{}"'「」【】]+[^\s<>()\[\]{}"'「」【】.,;:!?…,。;:!?)】」"')])/g;
699
- const src = String(text);
700
- const nodes = [];
701
- let last = 0;
702
- let m;
703
- let i = 0;
704
- while (m = re.exec(src)) {
705
- if (m.index > last) nodes.push(src.slice(last, m.index));
706
- const tok = m[0];
707
- const k = `${kb}-${i++}`;
708
- if (tok.startsWith("[![")) {
709
- const im = /^!\[([^\]]*)\]\(([^)]*)\)/.exec(tok.slice(1));
710
- const lm = /\]\(([^)]*)\)\s*$/.exec(tok);
711
- const img = h(MdImg, { src: im && im[2], alt: im && im[1] });
712
- const href = lm && lm[1];
713
- nodes.push(href && safeUrl(href) !== "#" ? h(ExtLink, { key: k, href }, img) : h("span", { key: k }, img));
714
- } else if (tok.startsWith("![") || tok.startsWith("<![")) {
715
- const im = /^!\[([^\]]*)\]\(([^)]*)\)$/.exec(tok);
716
- nodes.push(h(MdImg, { key: k, src: im && im[2], alt: im && im[1] }));
717
- } else if (tok.startsWith("[")) {
718
- const lm = /^\[([^\]]*)\]\(([^)]*)\)$/.exec(tok);
719
- nodes.push(h(ExtLink, { key: k, href: lm && lm[2] }, mdInline(lm ? lm[1] : tok, k)));
720
- } else if (tok.startsWith("`")) {
721
- nodes.push(h("code", { key: k }, tok.slice(1, -1)));
722
- } else if (tok.startsWith("**")) {
723
- nodes.push(h("strong", { key: k }, mdInline(tok.slice(2, -2), k)));
724
- } else if (tok.startsWith("~~")) {
725
- nodes.push(h("del", { key: k }, mdInline(tok.slice(2, -2), k)));
726
- } else if (tok.startsWith("*")) {
727
- nodes.push(h("em", { key: k }, mdInline(tok.slice(1, -1), k)));
728
- } else if (tok.startsWith("<")) {
729
- const u = tok.slice(1, -1);
730
- nodes.push(h(ExtLink, { key: k, href: u }, u));
731
- } else {
732
- nodes.push(h(ExtLink, { key: k, href: tok }, tok.length > 72 ? `${tok.slice(0, 69)}\u2026` : tok));
733
- }
734
- last = m.index + tok.length;
735
- }
736
- if (last < src.length) nodes.push(src.slice(last));
737
- return nodes;
738
- }
739
- function mdBlocks(lines, kb) {
740
- const out = [];
741
- let i = 0;
742
- let n = 0;
743
- const isFence = (s) => /^\s*```/.test(s);
744
- const isHeading = (s) => /^#{1,6}\s+/.test(s);
745
- const isHr = (s) => /^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(s);
746
- const isQuote = (s) => /^\s*>/.test(s);
747
- const isUl = (s) => /^\s*[-*+]\s+/.test(s);
748
- const isOl = (s) => /^\s*\d+[.)]\s+/.test(s);
749
- const isTableRow = (s) => s.includes("|") && /^\s*\|/.test(s);
750
- while (i < lines.length) {
751
- const line = lines[i];
752
- if (!line.trim()) {
753
- i++;
754
- continue;
755
- }
756
- const k = `${kb}-b${n++}`;
757
- if (isFence(line)) {
758
- const buf2 = [];
759
- i++;
760
- while (i < lines.length && !/^\s*```\s*$/.test(lines[i])) buf2.push(lines[i++]);
761
- i++;
762
- out.push(h("pre", { key: k }, h("code", null, buf2.join("\n"))));
763
- continue;
764
- }
765
- if (isHeading(line)) {
766
- const hm = /^(#{1,6})\s+(.*)$/.exec(line);
767
- out.push(h(`h${hm[1].length}`, { key: k }, mdInline(hm[2], k)));
768
- i++;
769
- continue;
770
- }
771
- if (isHr(line)) {
772
- out.push(h("hr", { key: k }));
773
- i++;
774
- continue;
775
- }
776
- if (isQuote(line)) {
777
- const buf2 = [];
778
- while (i < lines.length && isQuote(lines[i])) buf2.push(lines[i++].replace(/^\s*>\s?/, ""));
779
- out.push(h("blockquote", { key: k }, mdBlocks(buf2, k)));
780
- continue;
781
- }
782
- if (isUl(line) || isOl(line)) {
783
- const ordered = isOl(line);
784
- const re = ordered ? /^\s*\d+[.)]\s+(.*)$/ : /^\s*[-*+]\s+(.*)$/;
785
- const items = [];
786
- while (i < lines.length && (ordered ? isOl(lines[i]) : isUl(lines[i]))) {
787
- items.push(h("li", { key: `li${items.length}` }, mdInline(re.exec(lines[i])[1], `${k}-${items.length}`)));
788
- i++;
789
- }
790
- out.push(h(ordered ? "ol" : "ul", { key: k }, items));
791
- continue;
792
- }
793
- if (isTableRow(line) && i + 1 < lines.length && lines[i + 1].includes("-") && /^\s*\|?[\s:|-]+\|?\s*$/.test(lines[i + 1])) {
794
- const cells = (s) => s.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
795
- const head = cells(lines[i]);
796
- i += 2;
797
- const rows = [];
798
- while (i < lines.length && isTableRow(lines[i])) {
799
- rows.push(cells(lines[i]));
800
- i++;
801
- }
802
- out.push(
803
- h(
804
- "table",
805
- { key: k },
806
- h("thead", null, h("tr", null, head.map((c, x) => h("th", { key: x }, mdInline(c, `${k}h${x}`))))),
807
- h("tbody", null, rows.map((r, y) => h("tr", { key: y }, r.map((c, x) => h("td", { key: x }, mdInline(c, `${k}${y}x${x}`))))))
808
- )
809
- );
810
- continue;
811
- }
812
- const buf = [line];
813
- i++;
814
- while (i < lines.length && lines[i].trim() && !isFence(lines[i]) && !isHeading(lines[i]) && !isHr(lines[i]) && !isQuote(lines[i]) && !isUl(lines[i]) && !isOl(lines[i])) {
815
- buf.push(lines[i]);
816
- i++;
817
- }
818
- out.push(h("p", { key: k }, mdInline(buf.join(" "), k)));
819
- }
820
- return out;
821
- }
822
- function renderMarkdown(src) {
823
- return mdBlocks(String(src || "").replace(/\r\n?/g, "\n").split("\n"), "md");
824
- }
825
968
  function officialLinks({ npm, github, homepage }) {
826
969
  const links = [];
827
970
  if (github) links.push(["GitHub", `https://github.com/${github}`]);
@@ -872,17 +1015,25 @@ function RestartBanner({ note, onDone }) {
872
1015
  setPhase("restarting");
873
1016
  try {
874
1017
  const ping0 = await api("ping");
875
- await api("restart");
1018
+ try {
1019
+ await api("restart");
1020
+ } catch (requestError) {
1021
+ if (!isAmbiguousRestartRequestError2(requestError)) throw requestError;
1022
+ }
876
1023
  setPhase("waiting");
877
- const deadline = Date.now() + 9e4;
1024
+ const deadlineAt = Date.now() + RESTART_DEADLINE_MS2;
878
1025
  for (; ; ) {
879
- await new Promise((r) => setTimeout(r, 2e3));
880
- if (Date.now() > deadline) throw new Error(lookup("restart.timeout"));
1026
+ await new Promise((r) => setTimeout(r, RESTART_POLL_MS2));
1027
+ if (nextRestartWait2({ phase: "before-ping", now: Date.now(), deadlineAt }) === "timeout") {
1028
+ throw new Error(lookup("restart.timeout"));
1029
+ }
1030
+ let bootChanged = false;
881
1031
  try {
882
1032
  const ping = await api("ping");
883
- if (ping.boot !== ping0.boot) break;
1033
+ bootChanged = ping.boot !== ping0.boot;
884
1034
  } catch {
885
1035
  }
1036
+ if (nextRestartWait2({ phase: "after-ping", bootChanged }) === "done") break;
886
1037
  }
887
1038
  setPhase("idle");
888
1039
  onDone(true);
@@ -1091,18 +1242,6 @@ function ReadmeBlock({ pkg }) {
1091
1242
  state.truncated ? h("div", { className: "dshm-md-note" }, lookup("readme.truncated")) : null
1092
1243
  );
1093
1244
  }
1094
- function uninstallGuard(it) {
1095
- if (it.source === "link") {
1096
- return {
1097
- confirm: lookup("confirm.unlink"),
1098
- warn: lookup("warn.unlink", { path: it.path })
1099
- };
1100
- }
1101
- if (it.source === "file") {
1102
- return { confirm: lookup("confirm.core"), warn: lookup("warn.core") };
1103
- }
1104
- return { confirm: lookup("confirm.uninstall"), warn: null };
1105
- }
1106
1245
  function InstalledTab({ notify, installed }) {
1107
1246
  const { loading, data, error, reload } = installed;
1108
1247
  const [openPkg, setOpenPkg] = useState(null);
@@ -1158,33 +1297,33 @@ function InstalledTab({ notify, installed }) {
1158
1297
  "div",
1159
1298
  { className: "dshm-cards" },
1160
1299
  items.map((it) => {
1161
- const guard = uninstallGuard(it);
1300
+ const vm = installedViewModel2(it);
1162
1301
  return Card({
1163
1302
  key: it.pkg,
1164
- icon: h(Icon, { entry: { name: it.name, github: it.registryGithub || it.githubRepo || (it.spec.startsWith("github:") ? it.spec.slice(7).split("#")[0] : null), icon: null } }),
1303
+ icon: h(Icon, { entry: { name: it.name, github: vm.githubRepo, icon: null } }),
1165
1304
  name: it.name,
1166
1305
  badges: [
1167
- it.outdated ? h("span", { className: "dshm-badge warn", key: "u" }, `\u2B06 ${it.latestTag || (it.latestVersion ? `v${it.latestVersion}` : "")}`.trim()) : null,
1306
+ it.outdated ? h("span", { className: "dshm-badge warn", key: "u" }, `\u2B06 ${vm.latestLabel}`.trim()) : null,
1168
1307
  it.registryId ? h("span", { className: "dshm-badge", key: "r" }, lookup("badge.market")) : h("span", { className: "dshm-badge info", key: "r" }, lookup("badge.nonmarket"))
1169
1308
  ],
1170
1309
  desc: it.description || "\uFF08\u65E0\u63CF\u8FF0\uFF09",
1171
1310
  sub: [
1172
1311
  `v${it.version || "?"}`,
1173
- { npm: lookup("src.npm"), github: lookup("src.github"), link: lookup("src.link"), file: lookup("src.file"), unknown: lookup("src.unknown") }[it.source] || it.source
1312
+ vm.sourceLabelKey ? lookup(vm.sourceLabelKey) : it.source
1174
1313
  ].join(" \xB7 "),
1175
1314
  links: h(LinksRow, {
1176
1315
  npm: it.source === "npm" ? it.pkg : null,
1177
- github: it.registryGithub || it.githubRepo || (it.spec.startsWith("github:") ? it.spec.slice(7).split("#")[0] : null)
1316
+ github: vm.githubRepo
1178
1317
  }),
1179
1318
  open: openPkg === it.pkg,
1180
1319
  onToggle: () => setOpenPkg(openPkg === it.pkg ? null : it.pkg),
1181
1320
  detail: readmePkg === it.pkg ? h(ReadmeBlock, { pkg: it.pkg }) : DetailRows([
1182
1321
  [lookup("detail.pkg"), it.pkg],
1183
1322
  [lookup("detail.spec"), it.spec],
1184
- [lookup("detail.latest"), it.latestTag || (it.latestVersion ? `v${it.latestVersion}` : "\u2014")],
1323
+ [lookup("detail.latest"), vm.latestLabelDetail],
1185
1324
  [lookup("detail.listed"), it.registryId || lookup("detail.listed.no")],
1186
1325
  [lookup("detail.path"), it.path],
1187
- guard.warn ? [lookup("detail.note"), guard.warn] : null
1326
+ vm.guard.warnKey ? [lookup("detail.note"), lookup(vm.guard.warnKey, vm.guard.warnParams)] : null
1188
1327
  ]),
1189
1328
  actions: [
1190
1329
  h("button", {
@@ -1211,7 +1350,7 @@ function InstalledTab({ notify, installed }) {
1211
1350
  h(TwoStepButton, {
1212
1351
  key: "un",
1213
1352
  label: lookup("action.uninstall"),
1214
- confirmLabel: guard.confirm,
1353
+ confirmLabel: lookup(vm.guard.confirmKey),
1215
1354
  className: "dshm-btn sm",
1216
1355
  disabled: busyPkg === it.pkg,
1217
1356
  onConfirm: () => doUninstall(it)
@@ -1223,23 +1362,8 @@ function InstalledTab({ notify, installed }) {
1223
1362
  );
1224
1363
  }
1225
1364
  function regSourceLabel(data) {
1226
- if (!data) return "\u2014";
1227
- const map = {
1228
- "default-raw": "src.default.raw",
1229
- "default-jsdelivr": "src.default.jsdelivr",
1230
- "default-cache": "src.default.cache",
1231
- bundled: "src.bundled",
1232
- "custom-url": "src.custom.url",
1233
- "custom-file": "src.custom.file",
1234
- "custom-cache": "src.custom.cache",
1235
- "custom-unavailable": "src.custom.unavailable",
1236
- // 旧字段兼容
1237
- override: "src.override",
1238
- jsdelivr: "src.jsdelivr",
1239
- raw: "src.raw",
1240
- cache: "src.cache"
1241
- };
1242
- return lookup(map[data.source] || data.source);
1365
+ const key = registrySourceKey2(data);
1366
+ return key === null ? "\u2014" : lookup(key);
1243
1367
  }
1244
1368
  function configStatusLabel(status) {
1245
1369
  return lookup(`settings.status.${status || "loading"}` || "settings.status.loading");
@@ -1646,43 +1770,6 @@ function registerSlot(slots, options, component) {
1646
1770
  if (next.key == null && next.id != null) next.key = next.id;
1647
1771
  return slots.register(next, component);
1648
1772
  }
1649
- function pickPayload(props) {
1650
- const found = [];
1651
- const visit = (node, depth) => {
1652
- if (!node || depth > 6) return;
1653
- if (typeof node === "string") {
1654
- const t = node.trim();
1655
- if ((t.startsWith("{") || t.startsWith("[")) && t.length > 8) {
1656
- try {
1657
- visit(JSON.parse(t), depth + 1);
1658
- } catch {
1659
- }
1660
- }
1661
- return;
1662
- }
1663
- if (typeof node !== "object") return;
1664
- if (Array.isArray(node)) {
1665
- for (const x of node) visit(x, depth + 1);
1666
- return;
1667
- }
1668
- if (Array.isArray(node.items)) found.push(node);
1669
- for (const key of ["block", "meta", "result", "resultView", "view", "data", "value", "payload", "content", "message"]) {
1670
- if (node[key] != null) visit(node[key], depth + 1);
1671
- }
1672
- };
1673
- visit(props, 0);
1674
- return found.find((x) => x && Array.isArray(x.items)) || null;
1675
- }
1676
- function parseToolArgs(props) {
1677
- const block = props?.block;
1678
- const raw = (block && "kind" in block ? block.call?.argsRaw : block?.argsRaw) || "";
1679
- if (!raw || typeof raw !== "string") return {};
1680
- try {
1681
- return JSON.parse(raw);
1682
- } catch {
1683
- return {};
1684
- }
1685
- }
1686
1773
  function ToolCardRow({ it, onInstalled }) {
1687
1774
  const [busy, setBusy] = useState(false);
1688
1775
  const install = async (e) => {
@@ -1723,8 +1810,8 @@ function ToolCardRow({ it, onInstalled }) {
1723
1810
  }
1724
1811
  function SearchToolView(props) {
1725
1812
  useEffect(() => ensureCss(), []);
1726
- const payload = pickPayload(props);
1727
- const args = parseToolArgs(props);
1813
+ const payload = pickPayload2(props);
1814
+ const args = parseToolArgs2(props);
1728
1815
  const query = String(payload?.query || args.query || "").trim();
1729
1816
  const fromTool = Array.isArray(payload?.items) && payload.items.length ? payload.items : null;
1730
1817
  const running = !!(props?.block && !("kind" in props.block));
@@ -1764,7 +1851,7 @@ function SearchToolView(props) {
1764
1851
  }
1765
1852
  function ListToolView(props) {
1766
1853
  useEffect(() => ensureCss(), []);
1767
- const payload = pickPayload(props);
1854
+ const payload = pickPayload2(props);
1768
1855
  const items = Array.isArray(payload?.items) ? payload.items : [];
1769
1856
  if (!items.length) return null;
1770
1857
  return h(