@deepseek-ai/dsh-client-ui-plugin-manager 0.1.6-alpha.2 → 0.1.7-alpha.2

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
@@ -6,6 +6,7 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
8
  let react = require("react");
9
+ let react_dom = require("react-dom");
9
10
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
11
  let _deepseek_ai_dsh_client_ui_slots = require("@deepseek-ai/dsh-client-ui-slots");
11
12
  let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
@@ -73,7 +74,7 @@ window.__ModuleLoader__.load({
73
74
  };
74
75
  }
75
76
  //#endregion
76
- //#region ../../util/crypto/src/index.ts
77
+ //#region ../../util/crypto/lib/index.js
77
78
  /**
78
79
  * Random v4 UUID, minted from `crypto.getRandomValues`.
79
80
  * @returns the UUID string.
@@ -85,27 +86,60 @@ window.__ModuleLoader__.load({
85
86
  }).join("");
86
87
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
87
88
  }
89
+ /** Public npmmirror URL shared by the fallback configuration and public-registry comparison. */
90
+ const NPMMIRROR_REGISTRY = "https://registry.npmmirror.com/";
91
+ /** An http(s) URL, as pnpm's `--registry` takes it. */
92
+ const REGISTRY_URL = /^https?:\/\/\S+$/;
93
+ /**
94
+ * Parse a registry URL into the form pnpm compares registries in: lower-case host, trailing slash.
95
+ * @param url - the registry as configured or requested.
96
+ * @returns the normalized URL.
97
+ * @throws {Error} for anything but an http(s) URL.
98
+ */
99
+ function normalizeRegistry(url) {
100
+ let parsed;
101
+ try {
102
+ parsed = new URL(url);
103
+ } catch {}
104
+ if (parsed === void 0 || parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error(`a registry must be an http(s) URL: ${url}`);
105
+ if (!parsed.pathname.endsWith("/")) parsed.pathname += "/";
106
+ return parsed.href;
107
+ }
88
108
  //#endregion
89
109
  //#region lib/types/client/presentation.js
90
110
  /** Display labels and toast sentences for global plugin management. */
91
- /** The official packages with copy of their own, and whether each is a beta feature the page tags as such. */
92
- const BUILTIN_COPY = new Map([
93
- ["@deepseek-ai/dsh-experimental-agent-team-profile", {
94
- title: "builtinAgentTeamTitle",
95
- description: "builtinAgentTeamDescription",
96
- beta: true
97
- }],
98
- ["@deepseek-ai/dsh-experimental-agent-team-web-profile", {
99
- title: "builtinAgentTeamWebTitle",
100
- description: "builtinAgentTeamWebDescription",
101
- beta: true
102
- }],
103
- ["@deepseek-ai/dsh-experimental-auto-review", {
104
- title: "builtinAutoReviewTitle",
105
- description: "builtinAutoReviewDescription",
106
- beta: true
107
- }]
108
- ]);
111
+ /** The registries with a name of their own, by host. */
112
+ const REGISTRY_COPY = new Map([["registry.npmmirror.com", "registryNpmmirror"]]);
113
+ /** npm's own registry, which pnpm names without any configuration. */
114
+ const OFFICIAL_NPM_HOST = "registry.npmjs.org";
115
+ /**
116
+ * What a registry reads as: pnpm's own as the default registry, a known mirror by its name, any other registry by
117
+ * its host; and the host each names, for where the name alone would leave it unsaid.
118
+ * @param registry - the registry, null for the one pnpm's own configuration names.
119
+ * @param t - the manager's translate seat.
120
+ * @param resolved - the URL pnpm's own configuration names, null while unknown, when it reads as npm's own.
121
+ * @returns the name and the host.
122
+ */
123
+ function registryText(registry, t, resolved) {
124
+ if (registry === null) return {
125
+ name: t("registryDefault"),
126
+ host: resolved === null ? OFFICIAL_NPM_HOST : registryHost(resolved)
127
+ };
128
+ const host = registryHost(registry);
129
+ const key = REGISTRY_COPY.get(host);
130
+ return {
131
+ name: key === void 0 ? host : t(key),
132
+ host
133
+ };
134
+ }
135
+ /** The host of a registry URL; the URL as written when it does not parse. */
136
+ function registryHost(registry) {
137
+ try {
138
+ return new URL(registry).host;
139
+ } catch {
140
+ return registry;
141
+ }
142
+ }
109
143
  /** The sentence each of the Host's refusal codes reads as. */
110
144
  const CODE_KEYS = {
111
145
  "management-required": "reasonManagementRequired",
@@ -148,21 +182,28 @@ window.__ModuleLoader__.load({
148
182
  return (name.startsWith("@") ? name.slice(name.indexOf("/") + 1) : name).replace(/^dsh-(?:host-|client-)?/, "");
149
183
  }
150
184
  /**
151
- * Localize known official packages by exact npm name at render time.
152
- * @param pkg - original package identity and optional metadata description.
153
- * @param t - the manager's current translate function.
154
- * @returns localized copy and whether the package is a beta feature, or the package's short name and original description.
185
+ * Resolve installed package metadata without changing its technical identity.
186
+ * @param pkg - package identity and local metadata.
187
+ * @param resolveText - current-locale package text resolver.
188
+ * @returns localized copy with a technical-name fallback and the independent beta status.
189
+ */
190
+ function packageText(pkg, resolveText) {
191
+ return {
192
+ title: pkg.meta?.title === void 0 ? pkg.name : resolveText(pkg.meta.title),
193
+ description: pkg.meta?.description === void 0 ? void 0 : resolveText(pkg.meta.description) || void 0,
194
+ beta: pkg.name.startsWith("@deepseek-ai/dsh-experimental-")
195
+ };
196
+ }
197
+ /**
198
+ * Resolve a bundle row's plugin metadata, using its full module specifier as the final title fallback.
199
+ * @param row - row identity and local metadata.
200
+ * @param resolveText - current-locale package text resolver.
201
+ * @returns the row's display title and optional description.
155
202
  */
156
- function packageText(pkg, t) {
157
- const keys = BUILTIN_COPY.get(pkg.name);
158
- return keys === void 0 ? {
159
- title: shortName(pkg.name),
160
- description: pkg.description,
161
- beta: false
162
- } : {
163
- title: t(keys.title),
164
- description: t(keys.description),
165
- beta: keys.beta
203
+ function rowText(row, resolveText) {
204
+ return {
205
+ title: row.meta?.title === void 0 ? row.moduleName : resolveText(row.meta.title),
206
+ description: row.meta?.description === void 0 ? void 0 : resolveText(row.meta.description) || void 0
166
207
  };
167
208
  }
168
209
  /**
@@ -176,6 +217,13 @@ window.__ModuleLoader__.load({
176
217
  case "restart": return t("restartNotice");
177
218
  case "overridden": return t("overriddenNotice", { name: notice.packageName });
178
219
  case "cancelled": return t("installCancelled");
220
+ case "install": return t({
221
+ done: "installBackgroundDone",
222
+ failed: "installBackgroundFailed",
223
+ unconfirmed: "installBackgroundUnconfirmed",
224
+ applying: "installBackgroundApplying",
225
+ unknown: "installBackgroundUnknown"
226
+ }[notice.outcome]);
179
227
  case "failed": {
180
228
  const reason = notice.code === void 0 ? notice.reason : managementText({
181
229
  code: notice.code,
@@ -194,13 +242,28 @@ window.__ModuleLoader__.load({
194
242
  * after each action and after every `plugin-manager/changed` event, so a
195
243
  * change made on another surface shows here without a manual refresh.
196
244
  */
245
+ /** The choice shown until the Host has said which registry it asks first: the one pnpm's own configuration names. */
246
+ const OFFICIAL_REGISTRY = {
247
+ kind: "offered",
248
+ registry: null
249
+ };
250
+ /**
251
+ * The registries the dialog offers: the Host's first, its fallbacks, and pnpm's own, each once.
252
+ * @param registries - what the Host configured, or null while unread.
253
+ * @returns the registries in the order the dialog lists them.
254
+ */
255
+ function offeredRegistries(registries) {
256
+ const offered = [];
257
+ for (const registry of [...registries === null ? [] : [registries.registry, ...registries.fallbackRegistries], null]) if (!offered.includes(registry)) offered.push(registry);
258
+ return offered;
259
+ }
197
260
  /**
198
261
  * Whether an installation is still owned by the Host.
199
262
  * @param phase - the dialog's current installation phase.
200
- * @returns true until an authoritative result settles the installation.
263
+ * @returns true while a Host result or a check for an active request is outstanding.
201
264
  */
202
265
  function isInstallPending(phase) {
203
- return phase === "starting" || phase === "running" || phase === "cancelling" || phase === "applying";
266
+ return phase === "starting" || phase === "running" || phase === "cancelling" || phase === "applying" || phase === "unconfirmed";
204
267
  }
205
268
  /** A refused answer or a change the Host could not apply, carrying what it said and, for a refusal, its code. */
206
269
  var RemoteAnswerError = class extends Error {
@@ -214,11 +277,12 @@ window.__ModuleLoader__.load({
214
277
  }
215
278
  };
216
279
  /** The dialog's reading of a failed change: the Host's code and diagnostic, and the run's classified failure. */
217
- function failureOf(error, kind, pendingBuilds) {
280
+ function failureOf(error, kind, pendingBuilds, failedAt) {
218
281
  return {
219
282
  reason: error?.diagnostic ?? "",
220
283
  ...error === void 0 ? {} : { code: error.code },
221
284
  ...kind === void 0 ? {} : { kind },
285
+ ...failedAt === void 0 ? {} : { failedAt },
222
286
  ...pendingBuilds === void 0 || pendingBuilds.length === 0 ? {} : { pendingBuilds }
223
287
  };
224
288
  }
@@ -262,6 +326,7 @@ window.__ModuleLoader__.load({
262
326
  moduleName: row.moduleName,
263
327
  enabled: live?.enabled ?? false,
264
328
  phase: live?.fiberPhase ?? null,
329
+ ...row.meta === void 0 ? {} : { meta: row.meta },
265
330
  ...row.entryId === void 0 ? {} : { entryId: row.entryId },
266
331
  ...live?.readOnlyReason === void 0 ? {} : { readOnlyReason: live.readOnlyReason }
267
332
  };
@@ -274,6 +339,7 @@ window.__ModuleLoader__.load({
274
339
  rows,
275
340
  ...bundle.version === void 0 ? {} : { version: bundle.version },
276
341
  ...bundle.description === void 0 ? {} : { description: bundle.description },
342
+ ...bundle.meta === void 0 ? {} : { meta: bundle.meta },
277
343
  ...bundle.readOnlyReason === void 0 ? {} : { readOnlyReason: bundle.readOnlyReason },
278
344
  ...bundle.error === void 0 ? {} : { error: bundle.error }
279
345
  };
@@ -290,6 +356,11 @@ window.__ModuleLoader__.load({
290
356
  const IDLE_INSTALL = {
291
357
  open: false,
292
358
  spec: "",
359
+ registries: null,
360
+ registry: OFFICIAL_REGISTRY,
361
+ registryOpen: false,
362
+ registryError: false,
363
+ attempts: null,
293
364
  phase: "idle",
294
365
  inputError: null,
295
366
  subject: null,
@@ -301,6 +372,43 @@ window.__ModuleLoader__.load({
301
372
  approvedBuilds: [],
302
373
  enabling: false
303
374
  };
375
+ /** The dialog back at its spec: the run and its outcome forgotten, the spec and the registries kept. */
376
+ function specAgain(install) {
377
+ const { open, spec, registries, registry } = install;
378
+ return {
379
+ ...IDLE_INSTALL,
380
+ open,
381
+ spec,
382
+ registries,
383
+ registry
384
+ };
385
+ }
386
+ /**
387
+ * The choice as the dialog can show it once the Host has answered: nothing remembered starts from the registry the
388
+ * Host asks first; a remembered registry the Host no longer offers is kept as a typed one.
389
+ */
390
+ function reconciled(remembered, registries) {
391
+ if (remembered === null) return {
392
+ kind: "offered",
393
+ registry: registries.registry
394
+ };
395
+ return remembered.kind === "offered" && remembered.registry !== null && !offeredRegistries(registries).includes(remembered.registry) ? {
396
+ kind: "custom",
397
+ url: remembered.registry
398
+ } : remembered;
399
+ }
400
+ /** Only the shipped public mirror can replace an unconfigured official npm default. */
401
+ function eligibleMirror(registries) {
402
+ if (registries.registry !== null || registries.resolved === null) return void 0;
403
+ let resolved;
404
+ try {
405
+ resolved = normalizeRegistry(registries.resolved);
406
+ } catch (_error) {
407
+ return;
408
+ }
409
+ if (resolved !== "https://registry.npmjs.org/") return void 0;
410
+ return registries.fallbackRegistries.find((registry) => registry === NPMMIRROR_REGISTRY);
411
+ }
304
412
  /** Reads and mutates the profile's plugins through the `pluginManager` Remote. */
305
413
  var PluginManagerController = class {
306
414
  ctx;
@@ -312,7 +420,11 @@ window.__ModuleLoader__.load({
312
420
  pendingConfirm;
313
421
  /** Cancels the check the dialog has in flight. */
314
422
  inspectAbort;
423
+ request;
315
424
  noticeSeq = 0;
425
+ registryRead;
426
+ /** The registry last used from this browser, kept across dialogs and page loads; null until one was used. */
427
+ registryMemory = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(null, { persist: { name: "dsh.plugin-manager.install-registry" } });
316
428
  /**
317
429
  * @param ctx - the tab plugin's context, whose `remote.pluginManager` and `remote.pluginInventory` namespaces answer.
318
430
  */
@@ -338,19 +450,25 @@ window.__ModuleLoader__.load({
338
450
  /** Stop publishing and drop every late settlement. */
339
451
  dispose() {
340
452
  this.disposed = true;
453
+ this.registryRead = void 0;
454
+ this.request = void 0;
341
455
  this.generation += 1;
342
456
  }
343
457
  /**
344
458
  * Build the face the tab's slot registration injects.
345
459
  * @param configLedger - the projection of the plugins carrying configuration, bound beside the tab's own state.
460
+ * @param resolveText - render-time package text resolution supplied by the locale service.
346
461
  * @returns the tab's snapshot sources and its actions.
347
462
  */
348
- inject(configLedger) {
463
+ inject(configLedger, resolveText) {
349
464
  return {
465
+ resolveText,
350
466
  hooks: {
351
467
  pluginManager: this.store,
352
- configLedger
468
+ configLedger,
469
+ configurations: this.ctx.configForms.describe()
353
470
  },
471
+ configForm: (id) => this.ctx.configForms.get(id),
354
472
  ensure: () => {
355
473
  if (this.getSnapshot().status === "idle") this.load();
356
474
  },
@@ -358,14 +476,28 @@ window.__ModuleLoader__.load({
358
476
  this.load();
359
477
  },
360
478
  openInstall: () => {
361
- if (!isInstallPending(this.getSnapshot().install.phase)) this.patch({ install: {
362
- ...IDLE_INSTALL,
363
- open: true
364
- } });
479
+ if (this.getSnapshot().install.requestId === void 0) {
480
+ this.patch({ install: {
481
+ ...IDLE_INSTALL,
482
+ open: true,
483
+ registry: this.registryMemory.getSnapshot() ?? OFFICIAL_REGISTRY
484
+ } });
485
+ const read = { choice: this.getSnapshot().install.registry };
486
+ this.registryRead = read;
487
+ read.done = this.readRegistries(read).finally(() => {
488
+ delete read.done;
489
+ });
490
+ } else this.patchInstall({ open: true });
491
+ this.reconcileInstall();
365
492
  },
366
493
  closeInstall: () => {
367
- if (isInstallPending(this.getSnapshot().install.phase)) return;
494
+ if (isInstallPending(this.getSnapshot().install.phase)) {
495
+ this.patchInstall({ open: false });
496
+ this.cancelInstall();
497
+ return;
498
+ }
368
499
  this.abortInspect();
500
+ this.registryRead = void 0;
369
501
  this.patch({ install: IDLE_INSTALL });
370
502
  },
371
503
  editInstallSpec: (text) => {
@@ -375,22 +507,37 @@ window.__ModuleLoader__.load({
375
507
  spec: text,
376
508
  inputError: null
377
509
  } : {
378
- ...IDLE_INSTALL,
379
- open: true,
510
+ ...specAgain(install),
380
511
  spec: text
381
512
  });
382
513
  },
383
514
  runInstall: () => {
384
515
  this.runInstall();
385
516
  },
517
+ toggleRegistryOptions: () => {
518
+ this.patchInstall({ registryOpen: !this.getSnapshot().install.registryOpen });
519
+ },
520
+ chooseRegistry: (choice) => {
521
+ if (this.getSnapshot().install.phase === "idle") this.patchInstall({
522
+ registry: choice,
523
+ registryError: false
524
+ });
525
+ },
526
+ changeRegistry: () => {
527
+ const install = this.getSnapshot().install;
528
+ if (install.phase === "failed") this.patch({ install: {
529
+ ...specAgain(install),
530
+ registryOpen: true
531
+ } });
532
+ },
386
533
  approveBuildsAndRetry: () => {
387
534
  this.approveBuildsAndRetry();
388
535
  },
389
536
  cancelInstall: () => {
390
537
  this.cancelInstall();
391
538
  },
392
- cancelInstallAndClose: () => {
393
- this.cancelInstall(true);
539
+ reconcileInstall: () => {
540
+ this.reconcileInstall();
394
541
  },
395
542
  toggleInstallDetails: () => {
396
543
  this.patchInstall({ detailsOpen: !this.getSnapshot().install.detailsOpen });
@@ -448,8 +595,48 @@ window.__ModuleLoader__.load({
448
595
  installProgress(progress) {
449
596
  const install = this.getSnapshot().install;
450
597
  if (install.requestId !== progress.requestId || !isInstallPending(install.phase)) return;
451
- if (install.phase === "cancelling" && progress.phase === "installing") return;
452
- this.patchInstall({ phase: progress.phase === "installing" ? "running" : progress.phase });
598
+ const request = this.request;
599
+ if (request === void 0) return;
600
+ request.acknowledged = true;
601
+ if (install.phase === "applying") return;
602
+ if (progress.phase === "installing" && request.cancellation !== void 0) {
603
+ if (request.cancellation.waitingForStart) this.sendCancellation(request, request.cancellation);
604
+ return;
605
+ }
606
+ const attempt = progress.attempt;
607
+ this.patchInstall({
608
+ phase: progress.phase === "installing" ? "running" : progress.phase,
609
+ ...attempt === void 0 ? {} : { attempts: {
610
+ registries: [...install.attempts?.registries ?? [], attempt.registry],
611
+ total: attempt.total
612
+ } }
613
+ });
614
+ }
615
+ currentRegistryRead(read) {
616
+ return !this.disposed && this.registryRead === read;
617
+ }
618
+ /** Read the registries the Host offers, for the dialog just opened; a refused read leaves pnpm's own and a typed one. */
619
+ async readRegistries(read) {
620
+ const answer = await this.ctx.remote.pluginManager.registries();
621
+ const install = this.getSnapshot().install;
622
+ if (!this.currentRegistryRead(read) || !install.open || !answer.ok) return;
623
+ const remembered = this.registryMemory.getSnapshot();
624
+ const untouched = install.registry === read.choice && (install.phase === "idle" || install.phase === "checking");
625
+ if (untouched) read.choice = reconciled(remembered, answer.value);
626
+ this.patchInstall({
627
+ registries: answer.value,
628
+ ...untouched ? { registry: read.choice } : {}
629
+ });
630
+ const mirror = eligibleMirror(answer.value);
631
+ if (!untouched || remembered !== null || mirror === void 0) return;
632
+ const fastest = await this.ctx.remote.pluginRegistryProbe.fastest();
633
+ const current = this.getSnapshot().install;
634
+ if (!this.currentRegistryRead(read) || !current.open || current.phase !== "idle" && current.phase !== "checking" || current.registry !== read.choice || !fastest.ok || fastest.value !== mirror) return;
635
+ read.choice = {
636
+ kind: "offered",
637
+ registry: mirror
638
+ };
639
+ this.patchInstall({ registry: read.choice });
453
640
  }
454
641
  /**
455
642
  * Fold a chunk belonging to this installation into its pnpm command.
@@ -459,6 +646,10 @@ window.__ModuleLoader__.load({
459
646
  appendLog(chunk) {
460
647
  const install = this.getSnapshot().install;
461
648
  if (chunk.requestId !== install.requestId) return;
649
+ if (install.requestId !== void 0 && (install.phase === "starting" || install.phase === "cancelling" || install.phase === "unconfirmed")) this.installProgress({
650
+ requestId: install.requestId,
651
+ phase: "installing"
652
+ });
462
653
  const index = install.runs.findIndex((run) => run.jobId === chunk.jobId);
463
654
  if (index === -1 && !isInstallPending(install.phase)) return;
464
655
  const settled = chunk.exitCode === void 0 ? {} : { exitCode: chunk.exitCode };
@@ -482,6 +673,7 @@ window.__ModuleLoader__.load({
482
673
  */
483
674
  load() {
484
675
  if (this.disposed) return Promise.resolve();
676
+ this.reconcileInstall();
485
677
  if (this.inFlight !== void 0) {
486
678
  this.rerun = true;
487
679
  return this.inFlight;
@@ -562,6 +754,15 @@ window.__ModuleLoader__.load({
562
754
  });
563
755
  return;
564
756
  }
757
+ const choice = install.registry;
758
+ const typed = choice.kind === "custom" ? choice.url.trim() : void 0;
759
+ if (typed !== void 0 && !REGISTRY_URL.test(typed)) {
760
+ this.patchInstall({
761
+ phase: "idle",
762
+ registryError: true
763
+ });
764
+ return;
765
+ }
565
766
  this.abortInspect();
566
767
  const controller = new AbortController();
567
768
  this.inspectAbort = controller;
@@ -571,12 +772,26 @@ window.__ModuleLoader__.load({
571
772
  subject: null,
572
773
  runs: [],
573
774
  detailsOpen: false,
775
+ attempts: null,
776
+ registryOpen: false,
574
777
  installed: null,
575
778
  restartRequired: false,
576
779
  failure: null,
577
780
  approvedBuilds: []
578
781
  });
579
- const inspected = await this.ctx.remote.pluginManager.inspect(spec, controller.signal);
782
+ const read = this.registryRead;
783
+ if (read !== void 0 && choice === read.choice && read.done !== void 0) {
784
+ await read.done;
785
+ if (this.gone(controller.signal) || this.registryRead !== read) return;
786
+ }
787
+ const currentChoice = this.getSnapshot().install.registry;
788
+ const selected = currentChoice.kind === "custom" ? {
789
+ ...currentChoice,
790
+ url: currentChoice.url.trim()
791
+ } : currentChoice;
792
+ const registry = selected.kind === "custom" ? selected.url : selected.registry;
793
+ this.registryMemory.set(selected);
794
+ const inspected = await this.ctx.remote.pluginManager.inspect(spec, { registry }, controller.signal);
580
795
  if (this.gone(controller.signal)) return;
581
796
  this.inspectAbort = void 0;
582
797
  if (!inspected.ok) {
@@ -590,11 +805,13 @@ window.__ModuleLoader__.load({
590
805
  return;
591
806
  }
592
807
  if (inspected.value.status === "refused") {
808
+ const { problem, reason, registries } = inspected.value;
593
809
  this.patchInstall({
594
810
  phase: "idle",
595
811
  inputError: {
596
- problem: inspected.value.problem,
597
- reason: inspected.value.reason
812
+ problem,
813
+ reason,
814
+ ...registries === void 0 ? {} : { registries }
598
815
  }
599
816
  });
600
817
  return;
@@ -610,13 +827,21 @@ window.__ModuleLoader__.load({
610
827
  * the Host saves that permission for this profile before pnpm runs.
611
828
  */
612
829
  async startInstall(subject, approvedBuilds) {
613
- const { spec } = subject;
830
+ const { spec, registry } = subject;
614
831
  const requestId = randomUUID();
832
+ const request = {
833
+ requestId,
834
+ acknowledged: false,
835
+ replyLost: false,
836
+ recovering: false
837
+ };
838
+ this.request = request;
615
839
  this.patchInstall({
616
840
  phase: "starting",
617
841
  requestId,
618
842
  subject,
619
843
  runs: [],
844
+ attempts: null,
620
845
  failure: null,
621
846
  installed: null,
622
847
  approvedBuilds: []
@@ -624,35 +849,85 @@ window.__ModuleLoader__.load({
624
849
  const result = await this.ctx.remote.pluginManager.installBundle(spec, {
625
850
  enabled: false,
626
851
  requestId,
852
+ registry,
627
853
  ...approvedBuilds === void 0 ? {} : { approvedBuilds: [...approvedBuilds] }
628
854
  });
629
- if (this.disposed || this.getSnapshot().install.requestId !== requestId) return;
630
- const runs = this.getSnapshot().install.runs;
631
- if (!result.ok) this.patchInstall({
632
- phase: "failed",
633
- runs: settledRuns(runs, null),
634
- failure: { reason: result.error.message }
855
+ if (this.disposed || this.request !== request) return;
856
+ if (!result.ok) {
857
+ request.replyLost = true;
858
+ this.installUncertain("result", result.error.message);
859
+ this.reconcileInstall();
860
+ return;
861
+ }
862
+ this.settleInstall(result.value);
863
+ }
864
+ /** A recovery call shares the Host's active result; absent results are explicitly unknown. */
865
+ async reconcileInstall() {
866
+ const request = this.request;
867
+ if (request === void 0 || !request.replyLost || request.recovering) return;
868
+ request.recovering = true;
869
+ const result = await this.ctx.remote.pluginManager.waitForInstall(request.requestId);
870
+ if (this.disposed || this.request !== request) return;
871
+ request.recovering = false;
872
+ if (!result.ok) {
873
+ this.installUncertain("result", result.error.message);
874
+ return;
875
+ }
876
+ if (result.value !== null) {
877
+ this.settleInstall(result.value);
878
+ return;
879
+ }
880
+ this.request = void 0;
881
+ this.patchInstall({
882
+ phase: "unknown",
883
+ failure: null,
884
+ runs: settledRuns(this.getSnapshot().install.runs, null)
635
885
  });
636
- else if (result.value.application === "cancelled") this.offerSpecAgain({
886
+ this.notifyHiddenInstall("unknown");
887
+ this.load();
888
+ }
889
+ settleInstall(result) {
890
+ const { runs, attempts } = this.getSnapshot().install;
891
+ this.request = void 0;
892
+ const asked = result.registries === void 0 ? {} : { attempts: {
893
+ registries: result.registries,
894
+ total: Math.max(attempts?.total ?? 0, result.registries.length)
895
+ } };
896
+ if (result.application === "cancelled") this.offerSpecAgain({
637
897
  kind: "cancelled",
638
898
  seq: ++this.noticeSeq
639
899
  });
640
- else if (result.value.application === "failed") {
641
- const packages = result.value.packageResult;
900
+ else if (result.application === "failed") {
901
+ const packages = result.packageResult;
642
902
  this.patchInstall({
643
903
  phase: "failed",
644
904
  runs: settledRuns(runs, packages?.exitCode ?? null),
645
- failure: failureOf(result.value.error, packages?.kind, result.value.pendingBuilds)
905
+ failure: failureOf(result.error, packages?.kind, result.pendingBuilds, result.failedAt),
906
+ ...asked
646
907
  });
647
908
  } else this.patchInstall({
648
909
  phase: "done",
649
910
  runs: settledRuns(runs, 0),
650
- installed: result.value.bundle ?? null,
651
- restartRequired: result.value.application === "restart-required",
652
- approvedBuilds: result.value.approvedBuilds ?? []
911
+ failure: null,
912
+ installed: result.bundle ?? null,
913
+ restartRequired: result.application === "restart-required",
914
+ approvedBuilds: result.approvedBuilds ?? [],
915
+ ...asked
653
916
  });
917
+ const phase = this.getSnapshot().install.phase;
918
+ if (phase === "done" || phase === "failed") this.notifyHiddenInstall(phase);
654
919
  this.load();
655
920
  }
921
+ installUncertain(uncertainty, reason) {
922
+ this.patchInstall({
923
+ phase: this.getSnapshot().install.phase === "applying" ? "applying" : "unconfirmed",
924
+ failure: {
925
+ reason,
926
+ uncertainty
927
+ }
928
+ });
929
+ this.notifyHiddenInstall("unconfirmed");
930
+ }
656
931
  /**
657
932
  * Allow the install scripts the failed run left pending and run the same
658
933
  * spec again. Only the failed screen with pending names offers this.
@@ -665,69 +940,80 @@ window.__ModuleLoader__.load({
665
940
  }
666
941
  /**
667
942
  * Leave the check or the failed screen for the spec at once; a Host-owned
668
- * run is asked to stop and the dialog waits for the Host's word, since
943
+ * run is asked to stop and its state waits for the Host's word, since
669
944
  * neither a dropped RPC nor a closed connection means pnpm has stopped.
670
- * @param closeAfter - stop only a running install, and close the dialog once the Host confirms the stop.
671
945
  */
672
- async cancelInstall(closeAfter = false) {
946
+ async cancelInstall() {
673
947
  const install = this.getSnapshot().install;
674
- if (!closeAfter && (install.phase === "checking" || install.phase === "failed")) {
948
+ if (install.phase === "checking" || install.phase === "failed" || install.phase === "unknown") {
675
949
  this.abortInspect();
676
950
  this.offerSpecAgain();
677
951
  return;
678
952
  }
679
- if (install.phase !== "running" || install.requestId === void 0) return;
680
- const requestId = install.requestId;
953
+ const request = this.request;
954
+ if (install.phase !== "starting" && install.phase !== "running" && install.phase !== "unconfirmed" || request === void 0) return;
955
+ if (request.cancellation !== void 0 && !request.cancellation.waitingForStart) return;
956
+ const cancellation = { waitingForStart: false };
957
+ request.cancellation = cancellation;
958
+ await this.sendCancellation(request, cancellation);
959
+ }
960
+ /** A cancellation that overtakes installation is retried after the Host acknowledges that request. */
961
+ async sendCancellation(request, cancellation) {
962
+ const acknowledged = request.acknowledged;
963
+ cancellation.waitingForStart = false;
681
964
  this.patchInstall({
682
965
  phase: "cancelling",
683
966
  failure: null
684
967
  });
685
- const result = await this.ctx.remote.pluginManager.cancelInstall(requestId);
686
- const current = this.getSnapshot().install;
687
- if (this.disposed || current.requestId !== requestId || !isInstallPending(current.phase)) return;
968
+ const result = await this.ctx.remote.pluginManager.cancelInstall(request.requestId);
969
+ if (this.disposed || this.request !== request || request.cancellation !== cancellation) return;
688
970
  if (!result.ok) {
689
- this.patchInstall({
690
- phase: "running",
691
- failure: {
692
- reason: result.error.message,
693
- cancelUnconfirmed: true
694
- }
695
- });
971
+ cancellation.waitingForStart = !request.acknowledged;
972
+ if (request.acknowledged) request.cancellation = void 0;
973
+ this.installUncertain(request.replyLost ? "result" : "cancellation", result.error.message);
696
974
  return;
697
975
  }
698
976
  if (result.value.status === "cancelled") {
699
- const notice = {
977
+ this.offerSpecAgain({
700
978
  kind: "cancelled",
701
979
  seq: ++this.noticeSeq
702
- };
703
- if (closeAfter) this.patch({
704
- install: IDLE_INSTALL,
705
- notice
706
980
  });
707
- else this.offerSpecAgain(notice);
708
981
  this.load();
709
- } else if (result.value.status === "too-late") this.patchInstall({ phase: "applying" });
710
- else this.patchInstall({
711
- phase: "running",
712
- failure: {
713
- reason: "",
714
- cancelUnconfirmed: true
715
- }
716
- });
982
+ } else if (result.value.status === "too-late") {
983
+ request.acknowledged = true;
984
+ request.cancellation = void 0;
985
+ this.patchInstall({ phase: "applying" });
986
+ this.notifyHiddenInstall("applying");
987
+ this.reconcileInstall();
988
+ } else if (request.replyLost) {
989
+ request.cancellation = void 0;
990
+ this.installUncertain("result", "");
991
+ this.reconcileInstall();
992
+ } else if (!acknowledged && this.getSnapshot().install.phase !== "applying") if (request.acknowledged) await this.sendCancellation(request, cancellation);
993
+ else {
994
+ cancellation.waitingForStart = true;
995
+ this.installUncertain("acceptance", "");
996
+ }
997
+ else {
998
+ request.cancellation = void 0;
999
+ this.installUncertain("cancellation", "");
1000
+ }
1001
+ }
1002
+ notifyHiddenInstall(outcome) {
1003
+ if (!this.getSnapshot().install.open) this.patch({ notice: {
1004
+ kind: "install",
1005
+ outcome,
1006
+ seq: ++this.noticeSeq
1007
+ } });
717
1008
  }
718
1009
  /**
719
- * Back to the spec: the check, the run, and its request are forgotten and
720
- * the spec is kept, with a toast when there is something to say — the Host
721
- * stopped the run.
1010
+ * Release the tracked request and return to editing with its spec retained.
1011
+ * A cancellation notice is supplied only after the Host confirms it stopped.
722
1012
  */
723
1013
  offerSpecAgain(notice = null) {
724
- const { open, spec } = this.getSnapshot().install;
1014
+ this.request = void 0;
725
1015
  this.patch({
726
- install: {
727
- ...IDLE_INSTALL,
728
- open,
729
- spec
730
- },
1016
+ install: specAgain(this.getSnapshot().install),
731
1017
  ...notice === null ? {} : { notice }
732
1018
  });
733
1019
  }
@@ -832,7 +1118,7 @@ window.__ModuleLoader__.load({
832
1118
  }
833
1119
  //#endregion
834
1120
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-plugin-manager/src/client/PluginManagerPage.module.css.mjs
835
- const css = ".X_2TxG_page{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);flex-direction:column;align-items:center;gap:32px;padding:28px clamp(24px,4vw,48px) 48px;display:flex;overflow:auto}.X_2TxG_page>*{width:100%;max-width:960px}.X_2TxG_pageHead{justify-content:space-between;align-items:flex-start;gap:16px;display:flex}.X_2TxG_pageTitle{margin:0;font-size:20px;font-weight:500;line-height:28px}.X_2TxG_pageIntro{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px;line-height:20px}.X_2TxG_toolbar{justify-content:flex-end;align-items:center;gap:16px;display:flex}.X_2TxG_status,.X_2TxG_failure p,.X_2TxG_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:20px}.X_2TxG_failure{color:var(--dsw-alias-state-error-primary);align-items:center;gap:10px;display:flex}.X_2TxG_banner{background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 12%, transparent);color:var(--dsw-alias-label-primary);border-radius:10px;margin:0;padding:8px 12px;font-size:12px;line-height:18px}.X_2TxG_group{flex-direction:column;gap:8px;display:flex}.X_2TxG_groupHead{align-items:baseline;gap:8px;display:flex}.X_2TxG_groupTitle{margin:0;font-size:14px;font-weight:500;line-height:22px}.X_2TxG_count{color:var(--dsw-alias-label-caption);font-variant-numeric:tabular-nums;font-size:14px}.X_2TxG_groupInfo{color:var(--dsw-alias-label-caption);align-self:center;align-items:center;display:inline-flex}.X_2TxG_groupInfo:hover,.X_2TxG_groupInfo:focus-visible{color:var(--dsw-alias-label-secondary)}.X_2TxG_statusTag{height:20px;padding:0 8px;line-height:1}.X_2TxG_card[data-plugin-highlight]{animation:2.4s ease-out X_2TxG_dsh-plugin-highlight}@keyframes X_2TxG_dsh-plugin-highlight{0%,55%{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary)}to{box-shadow:0 0 #0000}}@media (prefers-reduced-motion:reduce){.X_2TxG_card[data-plugin-highlight]{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);animation:none}}.X_2TxG_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.X_2TxG_cards{flex-direction:column;gap:2px;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_card{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;min-width:0;margin:0 -8px}.X_2TxG_cardHead{align-items:center;gap:14px;padding:8px;display:flex}.X_2TxG_cardIcon{border:.5px solid var(--dsw-alias-border-l3);width:48px;height:48px;color:var(--dsw-alias-label-secondary);border-radius:10px;flex:none;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_cardMain{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.X_2TxG_titleRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.X_2TxG_cardTitle{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}.X_2TxG_cardLink{position:relative}.X_2TxG_cardLink:hover{background:var(--dsw-alias-interactive-bg-hover)}.X_2TxG_cardOpen{max-width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;padding:0;font-weight:500}.X_2TxG_cardOpen:after{content:\"\";border-radius:12px;position:absolute;inset:0}.X_2TxG_cardOpen:focus-visible{outline:none}.X_2TxG_cardOpen:focus-visible:after{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.X_2TxG_cardDesc{color:var(--dsw-alias-label-tertiary);-webkit-line-clamp:1;-webkit-box-orient:vertical;font-size:13px;line-height:18px;display:-webkit-box;overflow:hidden}.X_2TxG_cardEnd{z-index:1;flex:none;align-items:center;gap:8px;display:inline-flex;position:relative}.X_2TxG_iconButton{width:28px;height:28px;color:var(--dsw-alias-label-caption);cursor:pointer;background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.X_2TxG_iconButton:disabled{opacity:.5;cursor:default}.X_2TxG_iconWrap{display:inline-flex}.X_2TxG_danger{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);--dsw-alias-interactive-bg-hover:color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent)}.X_2TxG_detailActions{flex:none;align-items:center;gap:16px;display:flex}.X_2TxG_actions{align-items:center;gap:16px;display:flex}.X_2TxG_deleteButton{width:28px;height:28px;color:var(--dsw-alias-state-error-primary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_deleteButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger,var(--dsw-alias-interactive-bg-hover))}.X_2TxG_deleteButton:disabled{opacity:.5;cursor:default}.X_2TxG_deleteButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.X_2TxG_reason{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;white-space:pre-wrap;margin:0;font-size:12px;line-height:18px}.X_2TxG_partsHead .X_2TxG_subLabel{margin:0}.X_2TxG_partsFilter{width:200px}.X_2TxG_partsFilter:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.X_2TxG_installDialog{width:min(600px,100%);max-height:calc(100vh - 48px)}.X_2TxG_installBody{flex-direction:column;gap:12px;min-width:0;display:flex}.X_2TxG_installLocation{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.X_2TxG_installField{flex-direction:column;gap:6px;font-size:13px;display:flex}.X_2TxG_installField input[type=text]{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:36px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:10px;padding:0 12px;font-size:13px}.X_2TxG_installField input[aria-invalid=true]{border-color:var(--dsw-alias-state-error-primary)}.X_2TxG_guideToggle{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;align-self:flex-start;align-items:center;gap:4px;padding:0;font-size:12.5px;display:inline-flex}.X_2TxG_guideToggle:hover{color:var(--dsw-alias-label-primary)}.X_2TxG_guideChevron{transition:transform .16s}.X_2TxG_guideToggle[aria-expanded=true] .X_2TxG_guideChevron{transform:rotate(180deg)}.X_2TxG_guide{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;gap:10px;padding:12px 14px;display:flex}.X_2TxG_guideIntro,.X_2TxG_guideHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.X_2TxG_guideSafety{background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 12%, transparent);color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary));border-radius:8px;align-items:flex-start;gap:6px;margin:0;padding:8px 10px;font-size:12px;line-height:18px;display:flex}.X_2TxG_guideSafety>svg{flex:none;margin-top:2px}.X_2TxG_guideNote{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);border-radius:8px;margin:0;padding:8px 10px;font-size:12px;line-height:18px}.X_2TxG_guideList{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_guideItem{border-top:.5px solid var(--dsw-alias-border-l4);align-items:flex-start;gap:10px;padding:8px 0;display:flex}.X_2TxG_guideIndex{corner-shape:round;background:var(--dsw-alias-bg-layer-3);text-align:center;width:20px;height:20px;color:var(--dsw-alias-label-tertiary);border-radius:999px;flex:none;font-size:11px;line-height:20px}.X_2TxG_guideMain{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.X_2TxG_guideTitle{color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:600}.X_2TxG_guideExample{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;font-size:12px}.X_2TxG_guideExample code{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace)}.X_2TxG_guideExampleLabel{color:var(--dsw-alias-label-tertiary)}.X_2TxG_inputError{color:var(--dsw-alias-state-error-primary);margin:-4px 0 0;font-size:12px;line-height:18px}.X_2TxG_wide{justify-content:center;width:100%}.X_2TxG_wizard{flex-direction:column;flex:auto;gap:16px;min-width:0;min-height:0;padding:16px 20px 20px;display:flex}.X_2TxG_wizardScroll{flex-direction:column;flex:auto;gap:16px;min-height:0;display:flex;overflow-y:auto}.X_2TxG_wizardHead{justify-content:space-between;align-items:center;min-height:24px;display:flex}.X_2TxG_wizardBack{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;padding:0;font-size:15px;font-weight:600;display:inline-flex}.X_2TxG_wizardClose{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex}.X_2TxG_wizardClose:hover{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary)}.X_2TxG_wizardHero{text-align:center;flex-direction:column;align-items:center;gap:10px;padding:8px 0 4px;display:flex}.X_2TxG_wizardIcon{width:44px;height:44px;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;display:inline-flex}.X_2TxG_wizardIcon[data-tone=done]{color:var(--dsw-alias-state-success-primary)}.X_2TxG_wizardIcon[data-tone=failed]{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary))}.X_2TxG_wizardTitle{margin:0;font-size:18px;font-weight:600;line-height:26px}.X_2TxG_wizardSub{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.X_2TxG_subject{border:.5px solid var(--dsw-alias-border-l3);text-align:center;border-radius:12px;flex-direction:column;align-items:center;gap:6px;padding:16px;display:flex}.X_2TxG_subjectName{overflow-wrap:anywhere;margin:0;font-size:15px;font-weight:600;line-height:22px}.X_2TxG_subjectDesc,.X_2TxG_subjectMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.X_2TxG_wizardFoot{justify-content:space-between;align-items:center;gap:12px;display:flex}.X_2TxG_detailsToggle{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;padding:0;font-size:13px;display:inline-flex}.X_2TxG_detailsChevron{transition:transform .16s}.X_2TxG_detailsToggle[aria-expanded=true] .X_2TxG_detailsChevron{transform:rotate(180deg)}.X_2TxG_detailsBody{flex-direction:column;gap:8px;min-width:0;display:flex}.X_2TxG_spinnerLarge{border:3px solid color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent);border-top-color:var(--dsw-alias-label-primary);corner-shape:round;border-radius:50%;width:28px;height:28px;animation:.9s linear infinite X_2TxG_spin}.X_2TxG_spinner{border:2px solid color-mix(in srgb, var(--dsw-alias-label-primary) 18%, transparent);border-top-color:var(--dsw-alias-label-primary);corner-shape:round;border-radius:50%;flex:none;width:14px;height:14px;animation:.9s linear infinite X_2TxG_spin}@keyframes X_2TxG_spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.X_2TxG_spinner,.X_2TxG_spinnerLarge{animation:none}.X_2TxG_detailsChevron{transition:none}}.X_2TxG_result,.X_2TxG_resultWarn{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);color:var(--dsw-alias-label-primary);border-radius:10px;margin:0;padding:8px 12px;font-size:13px;line-height:20px}.X_2TxG_resultWarn{background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 12%, transparent)}.X_2TxG_approval{border:.5px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 40%, transparent);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 8%, transparent);border-radius:12px;flex-direction:column;gap:8px;padding:12px 14px;display:flex}.X_2TxG_approvalTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600}.X_2TxG_approvalText{color:var(--dsw-alias-label-secondary);margin:0;font-size:12.5px;line-height:18px}.X_2TxG_approvalCaution{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary));margin:0;font-size:12.5px;font-weight:600;line-height:18px}.X_2TxG_approvalList{flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_approvalList code{background:var(--dsw-alias-bg-layer-3);font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-primary);border-radius:6px;padding:2px 8px;font-size:12px;display:inline-block}.X_2TxG_terminal{--dsl-terminal-font:var(--dsw-font-markdown-code-block-small);--dsl-terminal-line-height:18px;--dsl-terminal-output-max-height:240px;border:.5px solid var(--dsw-alias-border-l1);margin:4px 0 0}.X_2TxG_dependents{color:var(--dsw-alias-label-secondary);margin:8px 0 0;padding-left:18px;font-size:13px;line-height:20px}.X_2TxG_dangerButton{--dsw-alias-button-primary-fill:var(--dsw-alias-state-error-primary);--dsw-alias-button-primary-hover:var(--dsw-alias-state-error-primary)}.X_2TxG_detail{flex-direction:column;display:flex}.X_2TxG_crumb{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:0;font-size:12.5px;display:inline-flex}.X_2TxG_crumb:hover{color:var(--dsw-alias-label-primary)}.X_2TxG_crumb:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.X_2TxG_crumbIcon{transform:rotate(90deg)}.X_2TxG_detailHead{justify-content:space-between;align-items:center;gap:12px;margin:32px 0 0;display:flex}.X_2TxG_detailMain{flex-direction:column;gap:8px;min-width:0;margin-top:20px;display:flex}.X_2TxG_detailTitle{margin:0;font-size:20px;font-weight:500;line-height:28px}.X_2TxG_versionTag{font-variant-numeric:tabular-nums;flex:none}.X_2TxG_detailDesc{color:var(--dsw-alias-label-secondary);margin:0;font-size:14px;line-height:22px}.X_2TxG_detailName{color:var(--dsw-alias-label-caption);overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.X_2TxG_detailName code{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace)}.X_2TxG_detail>.X_2TxG_detailDesc{margin-top:12px}.X_2TxG_detailSections{flex-direction:column;gap:32px;margin-top:32px;display:flex}.X_2TxG_detailSection{flex-direction:column;gap:12px;display:flex}.X_2TxG_sectionHead{align-items:baseline;gap:10px;display:flex}.X_2TxG_sectionTitle{margin:0;font-size:14px;font-weight:500;line-height:20px}.X_2TxG_sectionCount{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.X_2TxG_cardArrow{color:var(--dsw-alias-label-tertiary);flex:none}.X_2TxG_rows{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_row{border-bottom:.5px solid var(--dsw-alias-border-l2);padding:12px 2px}.X_2TxG_row:last-child{border-bottom:0}.X_2TxG_rowLine{align-items:center;gap:16px;min-width:0;display:flex}.X_2TxG_rowIcon{border:.5px solid var(--dsw-alias-border-l3);width:40px;height:40px;color:var(--dsw-alias-label-secondary);border-radius:10px;flex:none;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_rowMain{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.X_2TxG_rowId{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;font-size:13.5px;font-weight:500;line-height:20px}.X_2TxG_row[data-state=off] .X_2TxG_rowId{color:var(--dsw-alias-label-secondary)}.X_2TxG_rowModule{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:11.5px;line-height:16px}.X_2TxG_rowOpen{color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:2px;padding:0;display:inline-flex}.X_2TxG_rowOpen:hover .X_2TxG_rowId{text-underline-offset:3px;text-decoration:underline}.X_2TxG_rowOpenIcon{color:var(--dsw-alias-label-tertiary);flex:none}.X_2TxG_rowOpen:hover .X_2TxG_rowOpenIcon{color:var(--dsw-alias-label-primary)}.X_2TxG_rowState{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none;align-items:center;gap:6px;font-size:12.5px;line-height:18px;display:inline-flex}.X_2TxG_row[data-state=failed] .X_2TxG_rowState{color:var(--dsw-alias-state-error-primary)}.X_2TxG_rowFailure{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:4px 0 0 56px;font-size:12px;line-height:18px}";
1121
+ const css = ".X_2TxG_page{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);flex-direction:column;align-items:center;gap:32px;padding:28px clamp(24px,4vw,48px) 48px;display:flex;overflow:auto}.X_2TxG_page>*{width:100%;max-width:960px}.X_2TxG_pageHead{box-sizing:border-box;justify-content:space-between;align-items:flex-start;gap:16px;display:flex}[data-platform=darwin] .X_2TxG_pageHead{padding-top:var(--dsh-frame-top-clearance,0px)}.X_2TxG_pageTitle{margin:0;font-size:20px;font-weight:500;line-height:28px}.X_2TxG_pageIntro{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px;line-height:20px}.X_2TxG_toolbar{justify-content:flex-end;align-items:center;gap:16px;display:flex}.X_2TxG_status,.X_2TxG_failure p,.X_2TxG_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:20px}.X_2TxG_failure{color:var(--dsw-alias-state-error-primary);align-items:center;gap:10px;display:flex}.X_2TxG_statusWithDot{align-items:center;gap:6px;display:inline-flex}.X_2TxG_banner{background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 12%, transparent);color:var(--dsw-alias-label-primary);border-radius:10px;margin:0;padding:8px 12px;font-size:12px;line-height:18px}.X_2TxG_group{flex-direction:column;gap:8px;display:flex}.X_2TxG_groupHead{align-items:baseline;gap:8px;display:flex}.X_2TxG_groupTitle{margin:0;font-size:14px;font-weight:500;line-height:22px}.X_2TxG_count{color:var(--dsw-alias-label-caption);font-variant-numeric:tabular-nums;font-size:14px}.X_2TxG_groupInfo{color:var(--dsw-alias-label-caption);align-self:center;align-items:center;display:inline-flex}.X_2TxG_groupInfo:hover,.X_2TxG_groupInfo:focus-visible{color:var(--dsw-alias-label-secondary)}.X_2TxG_statusTag{height:18px;padding:0 7px;font-size:10px;line-height:1}.X_2TxG_card[data-plugin-highlight]{animation:2.4s ease-out X_2TxG_dsh-plugin-highlight}@keyframes X_2TxG_dsh-plugin-highlight{0%,55%{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary)}to{box-shadow:0 0 #0000}}@media (prefers-reduced-motion:reduce){.X_2TxG_card[data-plugin-highlight]{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);animation:none}}.X_2TxG_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.X_2TxG_cards{flex-direction:column;gap:2px;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_card{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;min-width:0;margin:0 -8px}.X_2TxG_cardHead{align-items:center;gap:14px;padding:8px;display:flex}.X_2TxG_cardIcon{border:.5px solid var(--dsw-alias-border-l3);width:48px;height:48px;color:var(--dsw-alias-label-secondary);border-radius:10px;flex:none;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_packageImage{object-fit:contain}.X_2TxG_cardMain{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.X_2TxG_titleRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.X_2TxG_cardTitle{text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}.X_2TxG_cardLink{position:relative}.X_2TxG_cardLink:hover{background:var(--dsw-alias-interactive-bg-hover)}.X_2TxG_cardOpen{max-width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;padding:0;font-size:14px;font-weight:500;line-height:20px}.X_2TxG_cardOpen:after{content:\"\";border-radius:12px;position:absolute;inset:0}.X_2TxG_cardOpen:focus-visible{outline:none}.X_2TxG_cardOpen:focus-visible:after{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.X_2TxG_cardDesc{color:var(--dsw-alias-label-tertiary);-webkit-line-clamp:1;-webkit-box-orient:vertical;font-size:13px;line-height:18px;display:-webkit-box;overflow:hidden}.X_2TxG_cardEnd{z-index:1;flex:none;align-items:center;gap:8px;display:inline-flex;position:relative}.X_2TxG_iconButton{width:28px;height:28px;color:var(--dsw-alias-label-caption);cursor:pointer;background:0 0;border:0;border-radius:28px;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.X_2TxG_iconButton:disabled{opacity:.5;cursor:default}.X_2TxG_addButton{border-radius:16px;height:32px;padding:0 12px;font-size:13px;line-height:20px}.X_2TxG_iconWrap{display:inline-flex}.X_2TxG_danger{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);--dsw-alias-interactive-bg-hover:color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent)}.X_2TxG_detailActions{flex:none;align-items:center;gap:16px;display:flex}.X_2TxG_actions{align-items:center;gap:16px;display:flex}.X_2TxG_deleteButton{width:28px;height:28px;color:var(--dsw-alias-state-error-primary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_deleteButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger,var(--dsw-alias-interactive-bg-hover))}.X_2TxG_deleteButton:disabled{opacity:.5;cursor:default}.X_2TxG_deleteButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.X_2TxG_reason{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;white-space:pre-wrap;margin:0;font-size:12px;line-height:18px}.X_2TxG_partsHead .X_2TxG_subLabel{margin:0}.X_2TxG_partsFilter{width:200px}.X_2TxG_partsFilter:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.X_2TxG_installDialog{width:min(560px,100%);max-height:min(800px,100%)}.X_2TxG_installContent{min-height:0;overflow-y:auto}.X_2TxG_installBody{flex-direction:column;gap:12px;min-width:0;display:flex}.X_2TxG_installLocation{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.X_2TxG_installField{flex-direction:column;gap:6px;font-size:13px;display:flex}.X_2TxG_installField input[type=text]{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:40px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:14px;outline:none;padding:0 14px;font-size:13px}.X_2TxG_installField input[type=text]:focus{border-color:var(--dsw-alias-brand-primary);box-shadow:inset 0 0 0 .5px var(--dsw-alias-brand-primary)}.X_2TxG_installField input[aria-invalid=true]{border-color:var(--dsw-alias-state-error-primary)}.X_2TxG_guideToggle{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;align-self:flex-start;align-items:center;gap:4px;margin-top:4px;padding:0;font-size:12.5px;display:inline-flex}.X_2TxG_guideToggle:hover{color:var(--dsw-alias-label-primary)}.X_2TxG_guideChevron{transition:transform .16s}.X_2TxG_guideToggle[aria-expanded=true] .X_2TxG_guideChevron{transform:rotate(180deg)}.X_2TxG_guide{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);border-radius:14px;flex-direction:column;gap:10px;padding:8px 14px 14px;display:flex}.X_2TxG_guideHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.X_2TxG_guideSafety{background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 12%, transparent);color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary));border-radius:10px;align-items:flex-start;gap:8px;margin:0;padding:10px 12px;font-size:12px;line-height:18px;display:flex}.X_2TxG_guideSafety>svg{flex:none;margin-top:2px}.X_2TxG_guideList{flex-direction:column;gap:2px;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_guideItem{align-items:flex-start;gap:10px;padding:8px 0;display:flex}.X_2TxG_guideIndex{corner-shape:round;background:var(--dsw-alias-bg-module-platform);width:20px;height:20px;color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;justify-content:center;align-items:center;font-size:11px;font-weight:500;display:inline-flex}.X_2TxG_guideMain{flex-direction:column;flex:1;gap:0;min-width:0;display:flex}.X_2TxG_guideTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.X_2TxG_guideExample{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;font-size:12px;line-height:20px}.X_2TxG_guideExample code{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace)}.X_2TxG_guideExampleLabel{color:var(--dsw-alias-label-tertiary)}.X_2TxG_optionsRow{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 12px;display:flex}.X_2TxG_registryToggle{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-2);height:26px;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;border-radius:8px;align-items:center;gap:6px;padding:0 8px 0 10px;font-size:12.5px;display:inline-flex}.X_2TxG_registryToggle:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.X_2TxG_registryToggle:disabled{cursor:default;opacity:.6}.X_2TxG_registryToggle[aria-expanded=true]{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-3)}.X_2TxG_registryToggle[aria-expanded=true] .X_2TxG_guideChevron{transform:rotate(180deg)}.X_2TxG_registryChosen{color:var(--dsw-alias-label-primary);font-weight:500}.X_2TxG_registry{z-index:1100;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l3);width:min(440px,100vw - 24px);box-shadow:var(--dsw-elevation-prominent);border:0;border-radius:12px;flex-direction:column;gap:4px;min-width:0;margin:0;padding:8px 10px 12px;display:flex;position:fixed}.X_2TxG_registryOption{cursor:pointer;border:.5px solid #0000;border-radius:10px;flex-direction:column;gap:4px;padding:8px 10px;display:flex}.X_2TxG_registryOption[data-checked=true]{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 40%, transparent);background:var(--dsw-alias-bg-layer-2)}label.X_2TxG_registryOption{flex-direction:row;align-items:flex-start;gap:10px}.X_2TxG_registryOption input[type=radio]{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);flex:none;margin:2px 0 0}.X_2TxG_registryTitle{color:var(--dsw-alias-label-primary);flex-wrap:wrap;align-items:center;gap:8px;font-size:13px;line-height:20px;display:flex}.X_2TxG_registryHint{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:12px;line-height:18px}.X_2TxG_registryCustomPick{cursor:pointer;align-items:flex-start;gap:10px;display:flex}.X_2TxG_registryCustomField{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:32px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;margin-left:26px;padding:0 10px;font-size:13px}.X_2TxG_registryCustomField[aria-invalid=true]{border-color:var(--dsw-alias-state-error-primary)}.X_2TxG_registryOption>.X_2TxG_inputError,.X_2TxG_registryOption>.X_2TxG_registryHint{margin-left:26px}.X_2TxG_inputError{color:var(--dsw-alias-state-error-primary);margin:-4px 0 0;font-size:12px;line-height:18px}.X_2TxG_wide{border-radius:14px;justify-content:center;width:100%;height:40px}.X_2TxG_wizard{flex-direction:column;flex:auto;gap:16px;min-width:0;min-height:0;padding:16px 20px 0;display:flex}.X_2TxG_wizardScroll{flex-direction:column;flex:auto;gap:16px;min-height:0;display:flex;overflow-y:auto}.X_2TxG_wizardHead{justify-content:space-between;align-items:center;min-height:24px;display:flex}.X_2TxG_wizardBack{font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;padding:0;font-size:15px;font-weight:600;display:inline-flex}.X_2TxG_wizardClose{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex}.X_2TxG_wizardClose:hover{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary)}.X_2TxG_wizardHero{text-align:center;flex-direction:column;align-items:center;gap:10px;padding:8px 0 4px;display:flex}.X_2TxG_wizardIcon{width:44px;height:44px;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;display:inline-flex}.X_2TxG_wizardIcon[data-state=done]{color:var(--dsw-alias-state-success-secondary)}.X_2TxG_wizardIcon[data-state=error]{color:var(--dsw-alias-state-warn-label)}.X_2TxG_wizardTitle{margin:0;font-size:18px;font-weight:600;line-height:26px}.X_2TxG_wizardSub{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.X_2TxG_subject{border:.5px solid var(--dsw-alias-border-l3);text-align:center;border-radius:12px;flex-direction:column;align-items:center;gap:6px;padding:16px;display:flex}.X_2TxG_subjectName{overflow-wrap:anywhere;margin:0;font-size:15px;font-weight:600;line-height:22px}.X_2TxG_subjectDesc,.X_2TxG_subjectMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.X_2TxG_wizardFoot{justify-content:space-between;align-items:center;gap:12px;display:flex}.X_2TxG_footAction{border-radius:16px;height:32px}.X_2TxG_detailsToggle{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;padding:0;font-size:13px;display:inline-flex}.X_2TxG_detailsChevron{transition:transform .16s}.X_2TxG_detailsToggle[aria-expanded=true] .X_2TxG_detailsChevron{transform:rotate(180deg)}.X_2TxG_detailsBody{flex-direction:column;gap:8px;min-width:0;display:flex}.X_2TxG_wizardActions{align-items:center;gap:8px;display:flex}.X_2TxG_run{flex-direction:column;gap:4px;min-width:0;display:flex}.X_2TxG_attemptBadge{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);border-radius:6px;align-self:flex-start;margin:0;padding:0 6px;font-size:11px;line-height:18px}@media (prefers-reduced-motion:reduce){.X_2TxG_detailsChevron{transition:none}}.X_2TxG_result,.X_2TxG_resultWarn{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);color:var(--dsw-alias-label-primary);border-radius:10px;margin:0;padding:8px 12px;font-size:13px;line-height:20px}.X_2TxG_resultWarn{background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 12%, transparent)}.X_2TxG_approval{border:.5px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 40%, transparent);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary)) 8%, transparent);border-radius:12px;flex-direction:column;gap:8px;padding:12px 14px;display:flex}.X_2TxG_approvalTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600}.X_2TxG_approvalText{color:var(--dsw-alias-label-secondary);margin:0;font-size:12.5px;line-height:18px}.X_2TxG_approvalCaution{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-state-business-primary));margin:0;font-size:12.5px;font-weight:600;line-height:18px}.X_2TxG_approvalList{flex-wrap:wrap;gap:6px;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_approvalList code{background:var(--dsw-alias-bg-layer-3);font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-primary);border-radius:6px;padding:2px 8px;font-size:12px;display:inline-block}.X_2TxG_terminal{--dsl-terminal-font:var(--dsw-font-markdown-code-block-small);--dsl-terminal-line-height:18px;--dsl-terminal-output-max-height:240px;border:.5px solid var(--dsw-alias-border-l1);margin:4px 0 0}.X_2TxG_dependents{color:var(--dsw-alias-label-secondary);margin:8px 0 0;padding-left:18px;font-size:13px;line-height:20px}.X_2TxG_dangerButton{--dsw-alias-button-primary-fill:var(--dsw-alias-state-error-primary);--dsw-alias-button-primary-hover:var(--dsw-alias-state-error-primary)}.X_2TxG_detail{flex-direction:column;display:flex}[data-platform=darwin] .X_2TxG_detail{padding-top:var(--dsh-frame-top-clearance,0px)}.X_2TxG_crumb{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:0;font-size:12.5px;display:inline-flex}.X_2TxG_crumb:hover{color:var(--dsw-alias-label-primary)}.X_2TxG_crumb:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.X_2TxG_crumbIcon{transform:rotate(90deg)}.X_2TxG_detailHead{justify-content:space-between;align-items:center;gap:12px;margin:32px 0 0;display:flex}.X_2TxG_detailMain{flex-direction:column;gap:8px;min-width:0;margin-top:20px;display:flex}.X_2TxG_detailTitle{margin:0;font-size:20px;font-weight:500;line-height:28px}.X_2TxG_versionTag{font-variant-numeric:tabular-nums;flex:none}.X_2TxG_detailDesc{color:var(--dsw-alias-label-secondary);margin:0;font-size:14px;line-height:22px}.X_2TxG_detailName{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.X_2TxG_detailName code{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace)}.X_2TxG_detail>.X_2TxG_detailDesc{margin-top:12px}.X_2TxG_detailSections{flex-direction:column;gap:32px;margin-top:32px;display:flex}.X_2TxG_detailSection{flex-direction:column;gap:12px;display:flex}.X_2TxG_sectionHead{align-items:baseline;gap:10px;display:flex}.X_2TxG_sectionTitle{margin:0;font-size:14px;font-weight:500;line-height:20px}.X_2TxG_sectionCount{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.X_2TxG_cardArrow{color:var(--dsw-alias-label-tertiary);flex:none}.X_2TxG_rows{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.X_2TxG_row{border-bottom:.5px solid var(--dsw-alias-border-l2);padding:12px 2px}.X_2TxG_row:last-child{border-bottom:0}.X_2TxG_rowLine{align-items:center;gap:16px;min-width:0;display:flex}.X_2TxG_rowIcon{border:.5px solid var(--dsw-alias-border-l3);width:40px;height:40px;color:var(--dsw-alias-label-secondary);border-radius:10px;flex:none;justify-content:center;align-items:center;display:inline-flex}.X_2TxG_rowMain{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.X_2TxG_rowId{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;font-size:13.5px;font-weight:500;line-height:20px}.X_2TxG_row[data-state=off] .X_2TxG_rowId{color:var(--dsw-alias-label-secondary)}.X_2TxG_rowModule{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:11.5px;line-height:16px}.X_2TxG_rowOpen{color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:2px;padding:0;display:inline-flex}.X_2TxG_rowOpen:hover .X_2TxG_rowId{text-underline-offset:3px;text-decoration:underline}.X_2TxG_rowOpenIcon{color:var(--dsw-alias-label-tertiary);flex:none}.X_2TxG_rowOpen:hover .X_2TxG_rowOpenIcon{color:var(--dsw-alias-label-primary)}.X_2TxG_rowState{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none;align-items:center;gap:6px;font-size:12.5px;line-height:18px;display:inline-flex}.X_2TxG_row[data-state=failed] .X_2TxG_rowState{color:var(--dsw-alias-state-error-primary)}.X_2TxG_rowFailure{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:4px 0 0 56px;font-size:12px;line-height:18px}";
836
1122
  const tagId = "@deepseek-ai/dsh-client-ui-plugin-manager/PluginManagerPage.module.css";
837
1123
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
838
1124
  const tag = document.createElement("style");
@@ -843,11 +1129,13 @@ window.__ModuleLoader__.load({
843
1129
  }
844
1130
  var PluginManagerPage_module_css_default = {
845
1131
  "actions": "X_2TxG_actions",
1132
+ "addButton": "X_2TxG_addButton",
846
1133
  "approval": "X_2TxG_approval",
847
1134
  "approvalCaution": "X_2TxG_approvalCaution",
848
1135
  "approvalList": "X_2TxG_approvalList",
849
1136
  "approvalText": "X_2TxG_approvalText",
850
1137
  "approvalTitle": "X_2TxG_approvalTitle",
1138
+ "attemptBadge": "X_2TxG_attemptBadge",
851
1139
  "banner": "X_2TxG_banner",
852
1140
  "card": "X_2TxG_card",
853
1141
  "cardArrow": "X_2TxG_cardArrow",
@@ -882,6 +1170,7 @@ window.__ModuleLoader__.load({
882
1170
  "dsh-plugin-highlight": "X_2TxG_dsh-plugin-highlight",
883
1171
  "empty": "X_2TxG_empty",
884
1172
  "failure": "X_2TxG_failure",
1173
+ "footAction": "X_2TxG_footAction",
885
1174
  "group": "X_2TxG_group",
886
1175
  "groupHead": "X_2TxG_groupHead",
887
1176
  "groupInfo": "X_2TxG_groupInfo",
@@ -892,11 +1181,9 @@ window.__ModuleLoader__.load({
892
1181
  "guideExampleLabel": "X_2TxG_guideExampleLabel",
893
1182
  "guideHint": "X_2TxG_guideHint",
894
1183
  "guideIndex": "X_2TxG_guideIndex",
895
- "guideIntro": "X_2TxG_guideIntro",
896
1184
  "guideItem": "X_2TxG_guideItem",
897
1185
  "guideList": "X_2TxG_guideList",
898
1186
  "guideMain": "X_2TxG_guideMain",
899
- "guideNote": "X_2TxG_guideNote",
900
1187
  "guideSafety": "X_2TxG_guideSafety",
901
1188
  "guideTitle": "X_2TxG_guideTitle",
902
1189
  "guideToggle": "X_2TxG_guideToggle",
@@ -904,9 +1191,12 @@ window.__ModuleLoader__.load({
904
1191
  "iconWrap": "X_2TxG_iconWrap",
905
1192
  "inputError": "X_2TxG_inputError",
906
1193
  "installBody": "X_2TxG_installBody",
1194
+ "installContent": "X_2TxG_installContent",
907
1195
  "installDialog": "X_2TxG_installDialog",
908
1196
  "installField": "X_2TxG_installField",
909
1197
  "installLocation": "X_2TxG_installLocation",
1198
+ "optionsRow": "X_2TxG_optionsRow",
1199
+ "packageImage": "X_2TxG_packageImage",
910
1200
  "page": "X_2TxG_page",
911
1201
  "pageHead": "X_2TxG_pageHead",
912
1202
  "pageIntro": "X_2TxG_pageIntro",
@@ -914,6 +1204,14 @@ window.__ModuleLoader__.load({
914
1204
  "partsFilter": "X_2TxG_partsFilter",
915
1205
  "partsHead": "X_2TxG_partsHead",
916
1206
  "reason": "X_2TxG_reason",
1207
+ "registry": "X_2TxG_registry",
1208
+ "registryChosen": "X_2TxG_registryChosen",
1209
+ "registryCustomField": "X_2TxG_registryCustomField",
1210
+ "registryCustomPick": "X_2TxG_registryCustomPick",
1211
+ "registryHint": "X_2TxG_registryHint",
1212
+ "registryOption": "X_2TxG_registryOption",
1213
+ "registryTitle": "X_2TxG_registryTitle",
1214
+ "registryToggle": "X_2TxG_registryToggle",
917
1215
  "result": "X_2TxG_result",
918
1216
  "resultWarn": "X_2TxG_resultWarn",
919
1217
  "row": "X_2TxG_row",
@@ -927,14 +1225,13 @@ window.__ModuleLoader__.load({
927
1225
  "rowOpenIcon": "X_2TxG_rowOpenIcon",
928
1226
  "rowState": "X_2TxG_rowState",
929
1227
  "rows": "X_2TxG_rows",
1228
+ "run": "X_2TxG_run",
930
1229
  "sectionCount": "X_2TxG_sectionCount",
931
1230
  "sectionHead": "X_2TxG_sectionHead",
932
1231
  "sectionTitle": "X_2TxG_sectionTitle",
933
- "spin": "X_2TxG_spin",
934
- "spinner": "X_2TxG_spinner",
935
- "spinnerLarge": "X_2TxG_spinnerLarge",
936
1232
  "status": "X_2TxG_status",
937
1233
  "statusTag": "X_2TxG_statusTag",
1234
+ "statusWithDot": "X_2TxG_statusWithDot",
938
1235
  "subLabel": "X_2TxG_subLabel",
939
1236
  "subject": "X_2TxG_subject",
940
1237
  "subjectDesc": "X_2TxG_subjectDesc",
@@ -946,6 +1243,7 @@ window.__ModuleLoader__.load({
946
1243
  "versionTag": "X_2TxG_versionTag",
947
1244
  "wide": "X_2TxG_wide",
948
1245
  "wizard": "X_2TxG_wizard",
1246
+ "wizardActions": "X_2TxG_wizardActions",
949
1247
  "wizardBack": "X_2TxG_wizardBack",
950
1248
  "wizardClose": "X_2TxG_wizardClose",
951
1249
  "wizardFoot": "X_2TxG_wizardFoot",
@@ -990,13 +1288,13 @@ window.__ModuleLoader__.load({
990
1288
  failed: "rowPhaseFailed",
991
1289
  unloading: "rowPhaseUnloading"
992
1290
  };
993
- /** Status dot naming a live root-fiber phase: pending and unloading fibers do nothing; only loading is in progress. */
1291
+ /** Status dot naming a root-fiber phase; loading and unloading are live transitions. */
994
1292
  const PHASE_STATES = {
995
1293
  pending: "idle",
996
1294
  loading: "ongoing",
997
1295
  active: "done",
998
1296
  failed: "error",
999
- unloading: "idle"
1297
+ unloading: "ongoing"
1000
1298
  };
1001
1299
  /** The count line over a pack's components: the total, then only the states that occur. */
1002
1300
  function partsSummary(rows, t) {
@@ -1012,12 +1310,41 @@ window.__ModuleLoader__.load({
1012
1310
  }
1013
1311
  /** Rows beyond this count get a filter box above the list. */
1014
1312
  const ROW_FILTER_THRESHOLD = 10;
1313
+ /** The size the 36-viewBox plugin artwork renders at inside a card's 48px frame. */
1314
+ const CARD_ARTWORK_SIZE = 36;
1315
+ /** The size the artwork renders at inside a row's 40px frame. */
1316
+ const ROW_ARTWORK_SIZE = 30;
1317
+ /** The artwork of the official plugins that registered their configuration, by registration id. */
1318
+ const ITEM_ARTWORK = new Map([
1319
+ ["shell", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkTerminal],
1320
+ ["agent-loop", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkLoop],
1321
+ ["subagent", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkSubagent],
1322
+ ["web-search", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkSearch]
1323
+ ]);
1324
+ /** An official plugin's card and page artwork; plugins without their own get the default. */
1325
+ function itemArtwork(id) {
1326
+ return (0, react_jsx_runtime.jsx)(ITEM_ARTWORK.get(id) ?? _deepseek_ai_dsh_client_ui_primitives.PluginArtworkDefault, { size: CARD_ARTWORK_SIZE });
1327
+ }
1328
+ /** Manifest images remain isolated from the page DOM; a failed decode keeps the position's default artwork. */
1329
+ function PackageArtwork({ src, row = false, size = row ? ROW_ARTWORK_SIZE : CARD_ARTWORK_SIZE }) {
1330
+ const [failedSource, setFailedSource] = (0, react.useState)();
1331
+ return src === void 0 || src === failedSource ? (0, react_jsx_runtime.jsx)(row ? _deepseek_ai_dsh_client_ui_primitives.PluginArtworkSubagent : _deepseek_ai_dsh_client_ui_primitives.PluginArtworkDefault, { size }) : (0, react_jsx_runtime.jsx)("img", {
1332
+ className: PluginManagerPage_module_css_default.packageImage,
1333
+ src,
1334
+ width: size,
1335
+ height: size,
1336
+ alt: "",
1337
+ onError: () => {
1338
+ setFailedSource(src);
1339
+ }
1340
+ });
1341
+ }
1015
1342
  /** A row's switch: locked, saying why, when the Host refuses to address the row through the profile patch. */
1016
- function RowSwitch({ row, t, busy, onChange }) {
1343
+ function RowSwitch({ row, title, t, busy, onChange }) {
1017
1344
  const locked = row.readOnlyReason !== void 0 || row.entryId === void 0;
1018
1345
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
1019
1346
  checked: row.enabled,
1020
- label: t("partToggle", { name: row.rowId }),
1347
+ label: t("partToggle", { name: title }),
1021
1348
  disabled: busy || locked,
1022
1349
  ...row.readOnlyReason === void 0 ? {} : { title: managementText({ code: row.readOnlyReason }, t) },
1023
1350
  onChange
@@ -1033,16 +1360,34 @@ window.__ModuleLoader__.load({
1033
1360
  if (!row.enabled || row.phase === null) return "idle";
1034
1361
  return PHASE_STATES[row.phase];
1035
1362
  }
1363
+ /** A Host metadata diagnostic does not change the package's management permissions. */
1364
+ function MetadataError({ error, t }) {
1365
+ return error === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
1366
+ className: PluginManagerPage_module_css_default.reason,
1367
+ role: "status",
1368
+ "data-package-meta-error": true,
1369
+ children: t("metadataError", { error })
1370
+ });
1371
+ }
1036
1372
  /**
1037
1373
  * A pack's rows as a list in the order the pack declares them: a state dot,
1038
1374
  * the row id, one line saying its state, a configure control for a row that
1039
1375
  * registered a page, and, when the pack is on, a switch. A pack like base
1040
1376
  * carries close to a hundred rows, so a long list gets a filter.
1041
1377
  */
1042
- function RowsSection({ rows, t, toggle, configure }) {
1378
+ function RowsSection({ rows, t, resolveText, toggle, configure }) {
1043
1379
  const [filter, setFilter] = (0, react.useState)("");
1044
1380
  const query = filter.trim().toLowerCase();
1045
- const shown = query === "" ? rows : rows.filter((row) => row.rowId.toLowerCase().includes(query));
1381
+ const localized = rows.map((row) => ({
1382
+ row,
1383
+ ...rowText(row, resolveText)
1384
+ }));
1385
+ const shown = query === "" ? localized : localized.filter(({ row, title, description }) => [
1386
+ title,
1387
+ description,
1388
+ row.rowId,
1389
+ row.moduleName
1390
+ ].some((value) => value?.toLowerCase().includes(query)));
1046
1391
  return (0, react_jsx_runtime.jsxs)("section", {
1047
1392
  className: PluginManagerPage_module_css_default.detailSection,
1048
1393
  "data-plugin-rows": true,
@@ -1077,51 +1422,63 @@ window.__ModuleLoader__.load({
1077
1422
  }) : null,
1078
1423
  shown.length === 0 ? null : (0, react_jsx_runtime.jsx)("ul", {
1079
1424
  className: PluginManagerPage_module_css_default.rows,
1080
- children: shown.map((row) => (0, react_jsx_runtime.jsx)("li", {
1425
+ children: shown.map(({ row, title, description }) => (0, react_jsx_runtime.jsxs)("li", {
1081
1426
  className: PluginManagerPage_module_css_default.row,
1082
1427
  "data-plugin-row": row.entryId ?? row.rowId,
1083
1428
  ...row.phase === "failed" ? { "data-state": "failed" } : row.enabled ? {} : { "data-state": "off" },
1084
- children: (0, react_jsx_runtime.jsxs)("div", {
1429
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1085
1430
  className: PluginManagerPage_module_css_default.rowLine,
1086
1431
  children: [
1087
1432
  (0, react_jsx_runtime.jsx)("span", {
1088
1433
  className: PluginManagerPage_module_css_default.rowIcon,
1089
1434
  "aria-hidden": "true",
1090
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCordisPluginOutline14, {})
1435
+ children: (0, react_jsx_runtime.jsx)(PackageArtwork, {
1436
+ src: row.meta?.icon,
1437
+ row: true
1438
+ }, row.meta?.icon)
1091
1439
  }),
1092
1440
  (0, react_jsx_runtime.jsxs)("div", {
1093
1441
  className: PluginManagerPage_module_css_default.rowMain,
1094
- children: [configure?.has(row) === true ? (0, react_jsx_runtime.jsxs)("button", {
1095
- type: "button",
1096
- className: PluginManagerPage_module_css_default.rowOpen,
1097
- "aria-label": t("configureRow", { name: row.rowId }),
1098
- onClick: () => {
1099
- configure.open(row);
1100
- },
1101
- children: [(0, react_jsx_runtime.jsx)("span", {
1442
+ children: [
1443
+ configure?.has(row) === true ? (0, react_jsx_runtime.jsxs)("button", {
1444
+ type: "button",
1445
+ className: PluginManagerPage_module_css_default.rowOpen,
1446
+ "aria-label": t("configureRow", { name: title }),
1447
+ onClick: () => {
1448
+ configure.open(row);
1449
+ },
1450
+ children: [(0, react_jsx_runtime.jsx)("span", {
1451
+ className: PluginManagerPage_module_css_default.rowId,
1452
+ children: title
1453
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, {
1454
+ className: PluginManagerPage_module_css_default.rowOpenIcon,
1455
+ "aria-hidden": "true"
1456
+ })]
1457
+ }) : (0, react_jsx_runtime.jsx)("span", {
1102
1458
  className: PluginManagerPage_module_css_default.rowId,
1459
+ children: title
1460
+ }),
1461
+ description === void 0 ? null : (0, react_jsx_runtime.jsx)("span", {
1462
+ className: PluginManagerPage_module_css_default.rowModule,
1463
+ children: description
1464
+ }),
1465
+ title === row.rowId ? null : (0, react_jsx_runtime.jsx)("code", {
1466
+ className: PluginManagerPage_module_css_default.rowModule,
1103
1467
  children: row.rowId
1104
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {
1105
- className: PluginManagerPage_module_css_default.rowOpenIcon,
1106
- "aria-hidden": "true"
1107
- })]
1108
- }) : (0, react_jsx_runtime.jsx)("span", {
1109
- className: PluginManagerPage_module_css_default.rowId,
1110
- children: row.rowId
1111
- }), (0, react_jsx_runtime.jsx)("span", {
1112
- className: PluginManagerPage_module_css_default.rowModule,
1113
- children: row.moduleName
1114
- })]
1468
+ }),
1469
+ title === row.moduleName ? null : (0, react_jsx_runtime.jsx)("code", {
1470
+ className: PluginManagerPage_module_css_default.rowModule,
1471
+ children: row.moduleName
1472
+ })
1473
+ ]
1115
1474
  }),
1116
1475
  (0, react_jsx_runtime.jsxs)("span", {
1117
1476
  className: PluginManagerPage_module_css_default.rowState,
1118
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
1119
- state: rowDotState(row),
1120
- size: 8
1121
- }), rowStateText(row, t)]
1477
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: rowDotState(row) }), rowStateText(row, t)]
1122
1478
  }),
1123
1479
  toggle === void 0 ? null : (0, react_jsx_runtime.jsx)(RowSwitch, {
1124
1480
  row,
1481
+ title,
1125
1482
  t,
1126
1483
  busy: toggle.busy(row),
1127
1484
  onChange: (enabled) => {
@@ -1129,7 +1486,10 @@ window.__ModuleLoader__.load({
1129
1486
  }
1130
1487
  })
1131
1488
  ]
1132
- })
1489
+ }), (0, react_jsx_runtime.jsx)(MetadataError, {
1490
+ error: row.meta?.error,
1491
+ t
1492
+ })]
1133
1493
  }, row.rowId))
1134
1494
  })
1135
1495
  ]
@@ -1153,15 +1513,16 @@ window.__ModuleLoader__.load({
1153
1513
  if (pkg.error !== void 0) return "problem";
1154
1514
  return pkg.enabled ? "running" : "disabled";
1155
1515
  }
1156
- /** The head every card shares: the pinwheel icon, the name that opens the page beside its tags, its one-liner, and what sits at the end. */
1157
- function CardHead({ title, t, onOpen, tags, description, end }) {
1516
+ /** The head every card shares: the artwork, the name that opens the page beside its tags, its one-liner, and what sits at the end. */
1517
+ function CardHead({ title, t, onOpen, icon, tags, description, end }) {
1518
+ const descriptionId = (0, react.useId)();
1158
1519
  return (0, react_jsx_runtime.jsxs)("div", {
1159
1520
  className: PluginManagerPage_module_css_default.cardHead,
1160
1521
  children: [
1161
1522
  (0, react_jsx_runtime.jsx)("span", {
1162
1523
  className: PluginManagerPage_module_css_default.cardIcon,
1163
1524
  "aria-hidden": "true",
1164
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutline16, { size: 20 })
1525
+ children: icon
1165
1526
  }),
1166
1527
  (0, react_jsx_runtime.jsxs)("div", {
1167
1528
  className: PluginManagerPage_module_css_default.cardMain,
@@ -1171,11 +1532,13 @@ window.__ModuleLoader__.load({
1171
1532
  type: "button",
1172
1533
  className: `${PluginManagerPage_module_css_default.cardTitle} ${PluginManagerPage_module_css_default.cardOpen}`,
1173
1534
  "aria-label": t("openDetail", { name: title }),
1535
+ "aria-describedby": description === void 0 ? void 0 : descriptionId,
1174
1536
  onClick: onOpen,
1175
1537
  children: title
1176
1538
  }), tags]
1177
1539
  }), description === void 0 ? null : (0, react_jsx_runtime.jsx)("span", {
1178
1540
  className: PluginManagerPage_module_css_default.cardDesc,
1541
+ id: descriptionId,
1179
1542
  children: description
1180
1543
  })]
1181
1544
  }),
@@ -1193,7 +1556,7 @@ window.__ModuleLoader__.load({
1193
1556
  className: PluginManagerPage_module_css_default.crumb,
1194
1557
  "aria-label": crumbLabel,
1195
1558
  onClick: onBack,
1196
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {
1559
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
1197
1560
  className: PluginManagerPage_module_css_default.crumbIcon,
1198
1561
  "aria-hidden": "true"
1199
1562
  }), (0, react_jsx_runtime.jsx)("span", { children: crumbText })]
@@ -1202,23 +1565,24 @@ window.__ModuleLoader__.load({
1202
1565
  children: [(0, react_jsx_runtime.jsx)("span", {
1203
1566
  className: PluginManagerPage_module_css_default.cardIcon,
1204
1567
  "aria-hidden": "true",
1205
- children: icon ?? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutline16, { size: 20 })
1568
+ children: icon
1206
1569
  }), actions]
1207
1570
  })] });
1208
1571
  }
1209
1572
  /** One package as a card that opens its page: its name, its one-liner, its tags, and its bundle switch. */
1210
- function PackageCard({ pkg, t, busy, highlighted, onOpen, onSetEnabled }) {
1211
- const { title, description, beta } = packageText(pkg, t);
1573
+ function PackageCard({ pkg, t, resolveText, busy, highlighted, onOpen, onSetEnabled }) {
1574
+ const { title, description, beta } = packageText(pkg, resolveText);
1212
1575
  const status = packageStatus(pkg);
1213
- return (0, react_jsx_runtime.jsx)("li", {
1576
+ return (0, react_jsx_runtime.jsxs)("li", {
1214
1577
  className: `${PluginManagerPage_module_css_default.card} ${PluginManagerPage_module_css_default.cardLink}`,
1215
1578
  "data-plugin-package": pkg.name,
1216
1579
  "data-plugin-status": status,
1217
1580
  ...highlighted ? { "data-plugin-highlight": "" } : {},
1218
- children: (0, react_jsx_runtime.jsx)(CardHead, {
1581
+ children: [(0, react_jsx_runtime.jsx)(CardHead, {
1219
1582
  title,
1220
1583
  t,
1221
1584
  onOpen,
1585
+ icon: (0, react_jsx_runtime.jsx)(PackageArtwork, { src: pkg.meta?.icon }, pkg.meta?.icon),
1222
1586
  tags: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [beta ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
1223
1587
  className: PluginManagerPage_module_css_default.statusTag,
1224
1588
  tone: "info",
@@ -1236,7 +1600,10 @@ window.__ModuleLoader__.load({
1236
1600
  busy,
1237
1601
  onSetEnabled
1238
1602
  })
1239
- })
1603
+ }), (0, react_jsx_runtime.jsx)(MetadataError, {
1604
+ error: pkg.meta?.error,
1605
+ t
1606
+ })]
1240
1607
  });
1241
1608
  }
1242
1609
  /**
@@ -1251,12 +1618,39 @@ window.__ModuleLoader__.load({
1251
1618
  title: item.label,
1252
1619
  t,
1253
1620
  onOpen,
1621
+ icon: itemArtwork(item.id),
1254
1622
  description: renderSlot("plugins.item", { view: "summary" }, { only: item.id })
1255
1623
  })
1256
1624
  });
1257
1625
  }
1258
- /** An official plugin's page: the crumb back to the cards, its icon, its title over its one-liner, and the form the entry renders. */
1259
- function ItemDetail({ item, t, onBack, renderSlot }) {
1626
+ /** One row as the detail slots see it. */
1627
+ function rowRef(row) {
1628
+ return {
1629
+ rowId: row.rowId,
1630
+ moduleName: row.moduleName,
1631
+ enabled: row.enabled
1632
+ };
1633
+ }
1634
+ /** One bundle as the detail slots see it. */
1635
+ function packageRef(pkg) {
1636
+ return {
1637
+ name: pkg.name,
1638
+ ...pkg.version === void 0 ? {} : { version: pkg.version },
1639
+ installed: pkg.installed,
1640
+ enabled: pkg.enabled,
1641
+ rows: pkg.rows.map(rowRef)
1642
+ };
1643
+ }
1644
+ /**
1645
+ * An official plugin's page: the crumb back to the cards, its icon with the
1646
+ * contributed actions, its title with the contributed badges over its
1647
+ * one-liner, the form the entry renders, and the contributed sections.
1648
+ */
1649
+ function ItemDetail({ item, t, onBack, renderSlot, form }) {
1650
+ const subject = {
1651
+ kind: "item",
1652
+ id: item.id
1653
+ };
1260
1654
  return (0, react_jsx_runtime.jsxs)("div", {
1261
1655
  className: PluginManagerPage_module_css_default.detail,
1262
1656
  "data-plugin-item-detail": item.id,
@@ -1264,36 +1658,53 @@ window.__ModuleLoader__.load({
1264
1658
  (0, react_jsx_runtime.jsx)(DetailTop, {
1265
1659
  crumbLabel: t("backToList"),
1266
1660
  crumbText: t("crumbRoot"),
1267
- onBack
1661
+ onBack,
1662
+ icon: itemArtwork(item.id),
1663
+ actions: (0, react_jsx_runtime.jsx)("div", {
1664
+ className: PluginManagerPage_module_css_default.detailActions,
1665
+ children: renderSlot("plugins.detail.actions", { subject })
1666
+ })
1268
1667
  }),
1269
1668
  (0, react_jsx_runtime.jsxs)("div", {
1270
1669
  className: PluginManagerPage_module_css_default.detailMain,
1271
- children: [(0, react_jsx_runtime.jsx)("div", {
1670
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1272
1671
  className: PluginManagerPage_module_css_default.titleRow,
1273
- children: (0, react_jsx_runtime.jsx)("h3", {
1672
+ children: [(0, react_jsx_runtime.jsx)("h3", {
1274
1673
  className: PluginManagerPage_module_css_default.detailTitle,
1275
1674
  children: item.label
1276
- })
1675
+ }), renderSlot("plugins.detail.badge", { subject })]
1277
1676
  }), (0, react_jsx_runtime.jsx)("p", {
1278
1677
  className: PluginManagerPage_module_css_default.detailDesc,
1279
1678
  children: renderSlot("plugins.item", { view: "summary" }, { only: item.id })
1280
1679
  })]
1281
1680
  }),
1282
- (0, react_jsx_runtime.jsx)("div", {
1681
+ (0, react_jsx_runtime.jsxs)("div", {
1283
1682
  className: PluginManagerPage_module_css_default.detailSections,
1284
- "data-plugin-config": true,
1285
- children: renderSlot("plugins.item", { view: "page" }, { only: item.id })
1683
+ children: [(0, react_jsx_runtime.jsx)("section", {
1684
+ className: PluginManagerPage_module_css_default.detailSection,
1685
+ "data-plugin-config": true,
1686
+ children: renderSlot("plugins.item", {
1687
+ view: "page",
1688
+ form
1689
+ }, { only: item.id })
1690
+ }), renderSlot("plugins.detail.section", { subject })]
1286
1691
  })
1287
1692
  ]
1288
1693
  });
1289
1694
  }
1290
1695
  /**
1291
- * A row's configuration page: the crumb back to its bundle's page, the row id
1292
- * over the module it names and the entry's one-liner, and the form the entry renders.
1696
+ * A row's configuration page keeps its technical identity beside local package
1697
+ * text and the form supplied by its configuration entry.
1293
1698
  */
1294
- function RowDetail({ pkg, row, t, onBack, renderSlot }) {
1295
- const { title } = packageText(pkg, t);
1699
+ function RowDetail({ pkg, row, t, resolveText, onBack, renderSlot, form }) {
1700
+ const { title } = packageText(pkg, resolveText);
1701
+ const { title: rowTitle, description } = rowText(row, resolveText);
1296
1702
  const key = rowConfigKey(pkg.name, row.rowId);
1703
+ const subject = {
1704
+ kind: "row",
1705
+ pkg: packageRef(pkg),
1706
+ row: rowRef(row)
1707
+ };
1297
1708
  return (0, react_jsx_runtime.jsxs)("div", {
1298
1709
  className: PluginManagerPage_module_css_default.detail,
1299
1710
  "data-plugin-row-detail": key,
@@ -1302,17 +1713,29 @@ window.__ModuleLoader__.load({
1302
1713
  crumbLabel: t("backToPackage", { name: title }),
1303
1714
  crumbText: title,
1304
1715
  onBack,
1305
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCordisPluginOutline14, { size: 20 })
1716
+ icon: (0, react_jsx_runtime.jsx)(PackageArtwork, {
1717
+ src: row.meta?.icon,
1718
+ row: true,
1719
+ size: CARD_ARTWORK_SIZE
1720
+ }, row.meta?.icon),
1721
+ actions: (0, react_jsx_runtime.jsx)("div", {
1722
+ className: PluginManagerPage_module_css_default.detailActions,
1723
+ children: renderSlot("plugins.detail.actions", { subject })
1724
+ })
1306
1725
  }),
1307
1726
  (0, react_jsx_runtime.jsxs)("div", {
1308
1727
  className: PluginManagerPage_module_css_default.detailMain,
1309
1728
  children: [
1310
- (0, react_jsx_runtime.jsx)("div", {
1729
+ (0, react_jsx_runtime.jsxs)("div", {
1311
1730
  className: PluginManagerPage_module_css_default.titleRow,
1312
- children: (0, react_jsx_runtime.jsx)("h3", {
1731
+ children: [(0, react_jsx_runtime.jsx)("h3", {
1313
1732
  className: PluginManagerPage_module_css_default.detailTitle,
1314
- children: row.rowId
1315
- })
1733
+ children: rowTitle
1734
+ }), renderSlot("plugins.detail.badge", { subject })]
1735
+ }),
1736
+ rowTitle === row.rowId ? null : (0, react_jsx_runtime.jsx)("p", {
1737
+ className: PluginManagerPage_module_css_default.detailName,
1738
+ children: (0, react_jsx_runtime.jsx)("code", { children: row.rowId })
1316
1739
  }),
1317
1740
  (0, react_jsx_runtime.jsx)("p", {
1318
1741
  className: PluginManagerPage_module_css_default.detailName,
@@ -1320,14 +1743,21 @@ window.__ModuleLoader__.load({
1320
1743
  }),
1321
1744
  (0, react_jsx_runtime.jsx)("p", {
1322
1745
  className: PluginManagerPage_module_css_default.detailDesc,
1323
- children: renderSlot("plugins.row.config", { view: "summary" }, { entryKey: key })
1746
+ children: description ?? renderSlot("plugins.row.config", { view: "summary" }, { entryKey: key })
1324
1747
  })
1325
1748
  ]
1326
1749
  }),
1327
- (0, react_jsx_runtime.jsx)("div", {
1750
+ (0, react_jsx_runtime.jsx)(MetadataError, {
1751
+ error: row.meta?.error,
1752
+ t
1753
+ }),
1754
+ (0, react_jsx_runtime.jsxs)("div", {
1328
1755
  className: PluginManagerPage_module_css_default.detailSections,
1329
1756
  "data-plugin-config": true,
1330
- children: renderSlot("plugins.row.config", { view: "page" }, { entryKey: key })
1757
+ children: [renderSlot("plugins.row.config", {
1758
+ view: "page",
1759
+ form
1760
+ }, { entryKey: key }), renderSlot("plugins.detail.section", { subject })]
1331
1761
  })
1332
1762
  ]
1333
1763
  });
@@ -1340,9 +1770,13 @@ window.__ModuleLoader__.load({
1340
1770
  * problem when it reports one; the configuration the bundle registered for
1341
1771
  * itself; and its rows with their switches and configure controls.
1342
1772
  */
1343
- function PackageDetail({ pkg, t, busy, rowBusy, configured, configure, renderSlot, onBack, onSetEnabled, onUninstall, onSetRowEnabled }) {
1344
- const { title, description, beta } = packageText(pkg, t);
1773
+ function PackageDetail({ pkg, t, resolveText, busy, rowBusy, configured, configure, renderSlot, onBack, onSetEnabled, onUninstall, onSetRowEnabled }) {
1774
+ const { title, description, beta } = packageText(pkg, resolveText);
1345
1775
  const status = packageStatus(pkg);
1776
+ const subject = {
1777
+ kind: "bundle",
1778
+ pkg: packageRef(pkg)
1779
+ };
1346
1780
  return (0, react_jsx_runtime.jsxs)("div", {
1347
1781
  className: PluginManagerPage_module_css_default.detail,
1348
1782
  "data-plugin-detail": pkg.name,
@@ -1351,24 +1785,29 @@ window.__ModuleLoader__.load({
1351
1785
  crumbLabel: t("backToList"),
1352
1786
  crumbText: t("crumbRoot"),
1353
1787
  onBack,
1788
+ icon: (0, react_jsx_runtime.jsx)(PackageArtwork, { src: pkg.meta?.icon }, pkg.meta?.icon),
1354
1789
  actions: (0, react_jsx_runtime.jsxs)("div", {
1355
1790
  className: PluginManagerPage_module_css_default.detailActions,
1356
- children: [pkg.installed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1357
- variant: "outline",
1358
- size: "sm",
1359
- className: PluginManagerPage_module_css_default.danger,
1360
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 13 }),
1361
- "aria-label": t("uninstallLabel", { name: title }),
1362
- disabled: busy || pkg.readOnlyReason !== void 0,
1363
- onClick: onUninstall,
1364
- children: t("uninstall")
1365
- }) : null, (0, react_jsx_runtime.jsx)(EnableSwitch, {
1366
- pkg,
1367
- title,
1368
- t,
1369
- busy,
1370
- onSetEnabled
1371
- })]
1791
+ children: [
1792
+ renderSlot("plugins.detail.actions", { subject }),
1793
+ pkg.installed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1794
+ variant: "outline",
1795
+ size: "sm",
1796
+ className: PluginManagerPage_module_css_default.danger,
1797
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 13 }),
1798
+ "aria-label": t("uninstallLabel", { name: title }),
1799
+ disabled: busy || pkg.readOnlyReason !== void 0,
1800
+ onClick: onUninstall,
1801
+ children: t("uninstall")
1802
+ }) : null,
1803
+ (0, react_jsx_runtime.jsx)(EnableSwitch, {
1804
+ pkg,
1805
+ title,
1806
+ t,
1807
+ busy,
1808
+ onSetEnabled
1809
+ })
1810
+ ]
1372
1811
  })
1373
1812
  }),
1374
1813
  (0, react_jsx_runtime.jsxs)("div", {
@@ -1395,7 +1834,8 @@ window.__ModuleLoader__.load({
1395
1834
  className: PluginManagerPage_module_css_default.statusTag,
1396
1835
  tone: "danger",
1397
1836
  children: t("statusProblem")
1398
- }) : null
1837
+ }) : null,
1838
+ renderSlot("plugins.detail.badge", { subject })
1399
1839
  ]
1400
1840
  }),
1401
1841
  (0, react_jsx_runtime.jsx)("p", {
@@ -1405,12 +1845,16 @@ window.__ModuleLoader__.load({
1405
1845
  children: pkg.name
1406
1846
  })
1407
1847
  }),
1408
- (0, react_jsx_runtime.jsx)("p", {
1848
+ description === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
1409
1849
  className: PluginManagerPage_module_css_default.detailDesc,
1410
- children: description ?? t("noDescription")
1850
+ children: description
1411
1851
  })
1412
1852
  ]
1413
1853
  }),
1854
+ (0, react_jsx_runtime.jsx)(MetadataError, {
1855
+ error: pkg.meta?.error,
1856
+ t
1857
+ }),
1414
1858
  pkg.error === void 0 ? null : (0, react_jsx_runtime.jsxs)("p", {
1415
1859
  className: PluginManagerPage_module_css_default.reason,
1416
1860
  role: "status",
@@ -1427,19 +1871,24 @@ window.__ModuleLoader__.load({
1427
1871
  }),
1428
1872
  (0, react_jsx_runtime.jsxs)("div", {
1429
1873
  className: PluginManagerPage_module_css_default.detailSections,
1430
- children: [configured ? (0, react_jsx_runtime.jsx)("section", {
1431
- className: PluginManagerPage_module_css_default.detailSection,
1432
- "data-plugin-config": true,
1433
- children: renderSlot("plugins.bundle.config", { view: "page" }, { entryKey: pkg.name })
1434
- }) : null, (0, react_jsx_runtime.jsx)(RowsSection, {
1435
- rows: pkg.rows,
1436
- t,
1437
- toggle: pkg.enabled ? {
1438
- busy: (row) => busy || rowBusy(row),
1439
- onSetEnabled: onSetRowEnabled
1440
- } : void 0,
1441
- configure
1442
- })]
1874
+ children: [
1875
+ configured ? (0, react_jsx_runtime.jsx)("section", {
1876
+ className: PluginManagerPage_module_css_default.detailSection,
1877
+ "data-plugin-config": true,
1878
+ children: renderSlot("plugins.bundle.config", { view: "page" }, { entryKey: pkg.name })
1879
+ }) : null,
1880
+ (0, react_jsx_runtime.jsx)(RowsSection, {
1881
+ rows: pkg.rows,
1882
+ t,
1883
+ resolveText,
1884
+ toggle: pkg.enabled ? {
1885
+ busy: (row) => busy || rowBusy(row),
1886
+ onSetEnabled: onSetRowEnabled
1887
+ } : void 0,
1888
+ configure
1889
+ }),
1890
+ renderSlot("plugins.detail.section", { subject })
1891
+ ]
1443
1892
  })
1444
1893
  ]
1445
1894
  });
@@ -1515,6 +1964,8 @@ window.__ModuleLoader__.load({
1515
1964
  running: "installingTitle",
1516
1965
  cancelling: "installCancelling",
1517
1966
  applying: "installApplying",
1967
+ unconfirmed: "installUnconfirmedTitle",
1968
+ unknown: "installUnknownTitle",
1518
1969
  done: "installedTitle",
1519
1970
  failed: "installFailedTitle"
1520
1971
  };
@@ -1525,13 +1976,31 @@ window.__ModuleLoader__.load({
1525
1976
  git: "installSubjectGit",
1526
1977
  tarball: "installSubjectTarball"
1527
1978
  };
1979
+ /** The registries asked, by name, in the dictionary's list form. */
1980
+ function registryList(registries, t, resolved) {
1981
+ return registries.map((registry) => registryText(registry, t, resolved).name).join(t("registryListSeparator"));
1982
+ }
1983
+ /** An option's label: the registry's name with the host it names, unless the host is the name. */
1984
+ function registryOption(registry, t, resolved) {
1985
+ const { name, host } = registryText(registry, t, resolved);
1986
+ return name === host ? name : t("registryWithHost", {
1987
+ name,
1988
+ host
1989
+ });
1990
+ }
1528
1991
  /**
1529
1992
  * The failed screen's one line: a pnpm failure by its kind, a refusal by its
1530
1993
  * code, any other failure in the Host's words; the run's output stays behind the details.
1994
+ * A run the Host laid at the spec's own host says so; one it laid at a registry
1995
+ * names every registry asked when there were several.
1531
1996
  */
1532
- function failureText(failure, t) {
1997
+ function failureText(failure, t, install) {
1533
1998
  if (failure === null) return t("installFailureGeneric");
1534
1999
  if (failure.kind === "build-blocked" && !failure.pendingBuilds?.length) return t("installFailureBuildBlockedManual");
2000
+ const host = install?.subject?.host;
2001
+ if (failure.failedAt === "spec-host" && host !== void 0) return t("installFailureNetworkHost", { host });
2002
+ const asked = install?.attempts?.registries ?? [];
2003
+ if (failure.failedAt === "registry" && (failure.kind === "network" || failure.kind === "timeout") && asked.length > 1) return t("installFailureNetworkAll", { registries: registryList(asked, t, install?.registries?.resolved ?? null) });
1535
2004
  if (failure.kind !== void 0) return t(FAILURE_KIND_KEYS[failure.kind]);
1536
2005
  if (failure.code !== void 0) return managementText({
1537
2006
  code: failure.code,
@@ -1568,15 +2037,47 @@ window.__ModuleLoader__.load({
1568
2037
  * and failed screens over the same subject card. A failed run that left
1569
2038
  * install scripts undecided shows them for approval in place of plain retry.
1570
2039
  */
1571
- function InstallDialog({ install, t, onClose, onEditSpec, onRun, onCancel, onCancelAndClose, onToggleDetails, onEnableNow, onApproveBuilds }) {
2040
+ function InstallDialog({ install, t, onClose, onEditSpec, onRun, onCancel, onReconcile, onToggleDetails, onEnableNow, onApproveBuilds, onToggleRegistry, onChooseRegistry, onChangeRegistry }) {
1572
2041
  const errorId = (0, react.useId)();
1573
2042
  const guideId = (0, react.useId)();
1574
2043
  const approvalId = (0, react.useId)();
2044
+ const registryId = (0, react.useId)();
2045
+ const registryErrorId = (0, react.useId)();
1575
2046
  const [guideOpen, setGuideOpen] = (0, react.useState)(false);
1576
2047
  const { phase } = install;
2048
+ const registryToggleRef = (0, react.useRef)(null);
2049
+ const registryPanelRef = (0, react.useRef)(null);
2050
+ const registryShown = install.registryOpen && phase === "idle";
2051
+ const registryPosition = (0, _deepseek_ai_dsh_client_ui_primitives.useAnchoredPosition)({
2052
+ open: registryShown,
2053
+ anchorRef: registryToggleRef,
2054
+ panelRef: registryPanelRef,
2055
+ align: "end",
2056
+ gap: 6,
2057
+ margin: 12
2058
+ });
2059
+ (0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(registryToggleRef, registryShown, onToggleRegistry, registryPanelRef);
2060
+ (0, react.useEffect)(() => {
2061
+ if (!registryShown) return;
2062
+ const onKeyDown = (event) => {
2063
+ if (event.key !== "Escape") return;
2064
+ event.stopPropagation();
2065
+ onToggleRegistry();
2066
+ };
2067
+ document.addEventListener("keydown", onKeyDown, true);
2068
+ return () => {
2069
+ document.removeEventListener("keydown", onKeyDown, true);
2070
+ };
2071
+ }, [registryShown, onToggleRegistry]);
1577
2072
  if (phase === "idle" || phase === "checking") {
1578
2073
  const checking = phase === "checking";
1579
2074
  const empty = install.spec.trim() === "";
2075
+ const choice = install.registry;
2076
+ const resolved = install.registries?.resolved ?? null;
2077
+ const chosenTitle = choice.kind === "custom" ? t("registryCustom") : registryText(choice.registry, t, resolved).name;
2078
+ const inputProblem = install.inputError;
2079
+ const askedByCheck = inputProblem?.registries ?? [];
2080
+ const inputSentence = inputProblem === null ? null : inputProblem.problem === "network" && askedByCheck.length > 1 ? t("installProblemNetworkAll", { registries: registryList(askedByCheck, t, resolved) }) : t(INPUT_PROBLEM_KEYS[inputProblem.problem], { reason: inputProblem.reason });
1580
2081
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1581
2082
  open: install.open,
1582
2083
  onClose,
@@ -1584,27 +2085,26 @@ window.__ModuleLoader__.load({
1584
2085
  closeLabel: t("close"),
1585
2086
  description: t("installDescription"),
1586
2087
  className: PluginManagerPage_module_css_default.installDialog,
2088
+ contentClassName: PluginManagerPage_module_css_default.installContent,
1587
2089
  footer: (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1588
2090
  variant: "primary",
1589
2091
  className: PluginManagerPage_module_css_default.wide,
1590
2092
  disabled: checking || empty,
1591
2093
  "aria-busy": checking,
1592
2094
  onClick: onRun,
1593
- children: [checking ? (0, react_jsx_runtime.jsx)("span", {
1594
- className: PluginManagerPage_module_css_default.spinner,
1595
- "aria-hidden": "true"
1596
- }) : null, t(checking ? "installChecking" : "installRun")]
2095
+ children: [checking ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" }) : null, t(checking ? "installChecking" : "installRun")]
1597
2096
  }),
1598
2097
  children: (0, react_jsx_runtime.jsxs)("div", {
1599
2098
  className: PluginManagerPage_module_css_default.installBody,
1600
2099
  children: [
1601
- (0, react_jsx_runtime.jsxs)("label", {
2100
+ (0, react_jsx_runtime.jsx)("div", {
1602
2101
  className: PluginManagerPage_module_css_default.installField,
1603
- children: [(0, react_jsx_runtime.jsx)("span", { children: t("installSpecLabel") }), (0, react_jsx_runtime.jsx)("input", {
2102
+ children: (0, react_jsx_runtime.jsx)("input", {
1604
2103
  type: "text",
1605
2104
  value: install.spec,
1606
2105
  placeholder: t("installSpecPlaceholder"),
1607
2106
  disabled: checking,
2107
+ "aria-label": t("installSpecLabel"),
1608
2108
  "aria-invalid": install.inputError !== null,
1609
2109
  "aria-describedby": install.inputError === null ? void 0 : errorId,
1610
2110
  onChange: (event) => {
@@ -1613,104 +2113,219 @@ window.__ModuleLoader__.load({
1613
2113
  onKeyDown: (event) => {
1614
2114
  if (event.key === "Enter" && !empty && !checking) onRun();
1615
2115
  }
1616
- })]
2116
+ })
1617
2117
  }),
1618
- install.inputError === null ? null : (0, react_jsx_runtime.jsx)("p", {
2118
+ inputSentence === null ? null : (0, react_jsx_runtime.jsx)("p", {
1619
2119
  id: errorId,
1620
2120
  className: PluginManagerPage_module_css_default.inputError,
1621
2121
  role: "alert",
1622
- children: t(INPUT_PROBLEM_KEYS[install.inputError.problem], { reason: install.inputError.reason })
2122
+ children: inputSentence
1623
2123
  }),
1624
- (0, react_jsx_runtime.jsxs)("button", {
1625
- type: "button",
1626
- className: PluginManagerPage_module_css_default.guideToggle,
1627
- "aria-expanded": guideOpen,
1628
- "aria-controls": guideId,
1629
- onClick: () => {
1630
- setGuideOpen((open) => !open);
1631
- },
1632
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {
1633
- className: PluginManagerPage_module_css_default.guideChevron,
1634
- "aria-hidden": "true"
1635
- }), (0, react_jsx_runtime.jsx)("span", { children: t(guideOpen ? "installGuideHide" : "installGuideToggle") })]
2124
+ (0, react_jsx_runtime.jsxs)("div", {
2125
+ className: PluginManagerPage_module_css_default.optionsRow,
2126
+ children: [(0, react_jsx_runtime.jsxs)("button", {
2127
+ type: "button",
2128
+ className: PluginManagerPage_module_css_default.guideToggle,
2129
+ "aria-expanded": guideOpen,
2130
+ "aria-controls": guideId,
2131
+ onClick: () => {
2132
+ setGuideOpen((open) => !open);
2133
+ },
2134
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
2135
+ className: PluginManagerPage_module_css_default.guideChevron,
2136
+ "aria-hidden": "true"
2137
+ }), (0, react_jsx_runtime.jsx)("span", { children: t(guideOpen ? "installGuideHide" : "installGuideToggle") })]
2138
+ }), (0, react_jsx_runtime.jsxs)("button", {
2139
+ ref: registryToggleRef,
2140
+ type: "button",
2141
+ className: PluginManagerPage_module_css_default.registryToggle,
2142
+ "aria-expanded": install.registryOpen,
2143
+ "aria-controls": registryId,
2144
+ "aria-haspopup": "dialog",
2145
+ disabled: checking,
2146
+ onClick: onToggleRegistry,
2147
+ children: [
2148
+ (0, react_jsx_runtime.jsx)("span", { children: t("registryToggle") }),
2149
+ " ",
2150
+ (0, react_jsx_runtime.jsx)("span", {
2151
+ className: PluginManagerPage_module_css_default.registryChosen,
2152
+ children: chosenTitle
2153
+ }),
2154
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
2155
+ className: PluginManagerPage_module_css_default.guideChevron,
2156
+ "aria-hidden": "true"
2157
+ })
2158
+ ]
2159
+ })]
1636
2160
  }),
1637
2161
  guideOpen ? (0, react_jsx_runtime.jsxs)("div", {
1638
2162
  id: guideId,
1639
2163
  className: PluginManagerPage_module_css_default.guide,
1640
2164
  "data-install-guide": true,
1641
- children: [
1642
- (0, react_jsx_runtime.jsx)("p", {
1643
- className: PluginManagerPage_module_css_default.guideIntro,
1644
- children: t("installGuideIntro")
1645
- }),
1646
- (0, react_jsx_runtime.jsx)("p", {
1647
- className: PluginManagerPage_module_css_default.guideNote,
1648
- children: t("installGuideIdNote")
1649
- }),
1650
- (0, react_jsx_runtime.jsx)("ol", {
1651
- className: PluginManagerPage_module_css_default.guideList,
1652
- children: GUIDE_EXAMPLES.map(({ key, titleKey, exampleKey, hintKey }, index) => (0, react_jsx_runtime.jsxs)("li", {
1653
- className: PluginManagerPage_module_css_default.guideItem,
1654
- children: [
1655
- (0, react_jsx_runtime.jsx)("span", {
1656
- className: PluginManagerPage_module_css_default.guideIndex,
1657
- "aria-hidden": "true",
1658
- children: index + 1
1659
- }),
1660
- (0, react_jsx_runtime.jsxs)("div", {
1661
- className: PluginManagerPage_module_css_default.guideMain,
1662
- children: [
1663
- (0, react_jsx_runtime.jsx)("span", {
1664
- className: PluginManagerPage_module_css_default.guideTitle,
1665
- children: t(titleKey)
1666
- }),
1667
- (0, react_jsx_runtime.jsxs)("span", {
1668
- className: PluginManagerPage_module_css_default.guideExample,
1669
- children: [(0, react_jsx_runtime.jsx)("span", {
1670
- className: PluginManagerPage_module_css_default.guideExampleLabel,
1671
- children: t("installGuideExampleLabel")
1672
- }), (0, react_jsx_runtime.jsx)("code", { children: t(exampleKey) })]
1673
- }),
1674
- (0, react_jsx_runtime.jsx)("span", {
1675
- className: PluginManagerPage_module_css_default.guideHint,
1676
- children: t(hintKey)
1677
- })
1678
- ]
1679
- }),
1680
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1681
- variant: "outline",
1682
- size: "sm",
1683
- "aria-label": t("installGuideFillAria", { example: t(exampleKey) }),
1684
- disabled: checking,
1685
- onClick: () => {
1686
- onEditSpec(t(exampleKey));
1687
- },
1688
- children: t("installGuideFill")
1689
- })
1690
- ]
1691
- }, key))
1692
- }),
1693
- (0, react_jsx_runtime.jsxs)("p", {
1694
- className: PluginManagerPage_module_css_default.guideSafety,
1695
- role: "note",
1696
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, {
1697
- size: 14,
1698
- "aria-hidden": "true"
1699
- }), (0, react_jsx_runtime.jsx)("span", { children: t("installGuideSafety") })]
1700
- })
1701
- ]
1702
- }) : null
2165
+ children: [(0, react_jsx_runtime.jsx)("ol", {
2166
+ className: PluginManagerPage_module_css_default.guideList,
2167
+ children: GUIDE_EXAMPLES.map(({ key, titleKey, exampleKey, hintKey }, index) => (0, react_jsx_runtime.jsxs)("li", {
2168
+ className: PluginManagerPage_module_css_default.guideItem,
2169
+ children: [
2170
+ (0, react_jsx_runtime.jsx)("span", {
2171
+ className: PluginManagerPage_module_css_default.guideIndex,
2172
+ "aria-hidden": "true",
2173
+ children: index + 1
2174
+ }),
2175
+ (0, react_jsx_runtime.jsxs)("div", {
2176
+ className: PluginManagerPage_module_css_default.guideMain,
2177
+ children: [
2178
+ (0, react_jsx_runtime.jsx)("span", {
2179
+ className: PluginManagerPage_module_css_default.guideTitle,
2180
+ children: t(titleKey)
2181
+ }),
2182
+ (0, react_jsx_runtime.jsx)("span", {
2183
+ className: PluginManagerPage_module_css_default.guideHint,
2184
+ children: t(hintKey)
2185
+ }),
2186
+ (0, react_jsx_runtime.jsxs)("span", {
2187
+ className: PluginManagerPage_module_css_default.guideExample,
2188
+ children: [(0, react_jsx_runtime.jsx)("span", {
2189
+ className: PluginManagerPage_module_css_default.guideExampleLabel,
2190
+ children: t("installGuideExampleLabel")
2191
+ }), (0, react_jsx_runtime.jsx)("code", { children: t(exampleKey) })]
2192
+ })
2193
+ ]
2194
+ }),
2195
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2196
+ variant: "outline",
2197
+ size: "sm",
2198
+ "aria-label": t("installGuideFillAria", { example: t(exampleKey) }),
2199
+ disabled: checking,
2200
+ onClick: () => {
2201
+ onEditSpec(t(exampleKey));
2202
+ },
2203
+ children: t("installGuideFill")
2204
+ })
2205
+ ]
2206
+ }, key))
2207
+ }), (0, react_jsx_runtime.jsxs)("p", {
2208
+ className: PluginManagerPage_module_css_default.guideSafety,
2209
+ role: "note",
2210
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {
2211
+ size: 14,
2212
+ "aria-hidden": "true"
2213
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("installGuideSafety") })]
2214
+ })]
2215
+ }) : null,
2216
+ registryShown ? (0, react_dom.createPortal)((0, react_jsx_runtime.jsxs)("fieldset", {
2217
+ ref: registryPanelRef,
2218
+ id: registryId,
2219
+ className: PluginManagerPage_module_css_default.registry,
2220
+ style: registryPosition ?? {
2221
+ visibility: "hidden",
2222
+ left: 0,
2223
+ top: 0
2224
+ },
2225
+ "data-install-registry": true,
2226
+ "aria-label": t("registryLegend"),
2227
+ children: [offeredRegistries(install.registries).map((registry) => {
2228
+ const checked = choice.kind === "offered" && choice.registry === registry;
2229
+ return (0, react_jsx_runtime.jsxs)("label", {
2230
+ className: PluginManagerPage_module_css_default.registryOption,
2231
+ "data-checked": checked,
2232
+ children: [(0, react_jsx_runtime.jsx)("input", {
2233
+ type: "radio",
2234
+ name: registryId,
2235
+ checked,
2236
+ onChange: () => {
2237
+ onChooseRegistry({
2238
+ kind: "offered",
2239
+ registry
2240
+ });
2241
+ }
2242
+ }), (0, react_jsx_runtime.jsx)("span", {
2243
+ className: PluginManagerPage_module_css_default.registryTitle,
2244
+ children: (0, react_jsx_runtime.jsx)("span", { children: registryOption(registry, t, resolved) })
2245
+ })]
2246
+ }, registry ?? "");
2247
+ }), (0, react_jsx_runtime.jsxs)("div", {
2248
+ className: PluginManagerPage_module_css_default.registryOption,
2249
+ "data-checked": choice.kind === "custom",
2250
+ children: [
2251
+ (0, react_jsx_runtime.jsxs)("label", {
2252
+ className: PluginManagerPage_module_css_default.registryCustomPick,
2253
+ children: [(0, react_jsx_runtime.jsx)("input", {
2254
+ type: "radio",
2255
+ name: registryId,
2256
+ checked: choice.kind === "custom",
2257
+ onChange: () => {
2258
+ onChooseRegistry({
2259
+ kind: "custom",
2260
+ url: ""
2261
+ });
2262
+ }
2263
+ }), (0, react_jsx_runtime.jsx)("span", {
2264
+ className: PluginManagerPage_module_css_default.registryTitle,
2265
+ children: (0, react_jsx_runtime.jsx)("span", { children: t("registryCustom") })
2266
+ })]
2267
+ }),
2268
+ (0, react_jsx_runtime.jsx)("input", {
2269
+ type: "text",
2270
+ className: PluginManagerPage_module_css_default.registryCustomField,
2271
+ "aria-label": t("registryCustom"),
2272
+ placeholder: t("registryCustomPlaceholder"),
2273
+ value: choice.kind === "custom" ? choice.url : "",
2274
+ disabled: choice.kind !== "custom",
2275
+ "aria-invalid": install.registryError,
2276
+ "aria-describedby": install.registryError ? registryErrorId : void 0,
2277
+ onChange: (event) => {
2278
+ onChooseRegistry({
2279
+ kind: "custom",
2280
+ url: event.currentTarget.value
2281
+ });
2282
+ },
2283
+ onKeyDown: (event) => {
2284
+ if (event.key === "Enter" && !empty) onRun();
2285
+ }
2286
+ }),
2287
+ install.registryError ? (0, react_jsx_runtime.jsx)("p", {
2288
+ id: registryErrorId,
2289
+ className: PluginManagerPage_module_css_default.inputError,
2290
+ role: "alert",
2291
+ children: t("registryCustomInvalid")
2292
+ }) : null,
2293
+ (0, react_jsx_runtime.jsx)("span", {
2294
+ className: PluginManagerPage_module_css_default.registryHint,
2295
+ children: t("registryCustomHint")
2296
+ })
2297
+ ]
2298
+ })]
2299
+ }), document.body) : null
1703
2300
  ]
1704
2301
  })
1705
2302
  });
1706
2303
  }
1707
2304
  const heading = t(SCREEN_TITLE_KEYS[phase]);
1708
2305
  const pending = isInstallPending(phase);
1709
- const stoppable = phase === "running" || phase === "failed";
1710
- const unconfirmed = install.failure?.cancelUnconfirmed === true ? install.failure.reason : void 0;
2306
+ const cancellable = phase === "starting" || phase === "running" || phase === "unconfirmed";
2307
+ const stoppable = cancellable || phase === "failed" || phase === "unknown";
2308
+ const failure = install.failure;
2309
+ const uncertainty = failure?.uncertainty;
2310
+ const uncertaintyText = failure?.uncertainty === void 0 ? null : t({
2311
+ result: "installResultUnconfirmed",
2312
+ cancellation: phase === "applying" ? "installApplyingCancellationError" : "installCancelUnconfirmed",
2313
+ acceptance: "installAwaitingAcceptance"
2314
+ }[failure.uncertainty], { reason: failure.reason });
1711
2315
  const pendingBuilds = phase === "failed" ? install.failure?.pendingBuilds ?? [] : [];
1712
2316
  const approvable = pendingBuilds.length > 0;
1713
2317
  const firstRun = install.runs[0];
2318
+ const asked = install.attempts !== null && install.attempts.registries.length > 1 ? install.attempts : null;
2319
+ const current = asked === null ? void 0 : asked.registries.at(-1);
2320
+ const previous = asked === null ? void 0 : asked.registries.at(-2);
2321
+ const resolved = install.registries?.resolved ?? null;
2322
+ const attemptLine = pending && asked !== null && current !== void 0 && previous !== void 0 ? t("installAttempt", {
2323
+ previous: registryText(previous, t, resolved).name,
2324
+ registry: registryText(current, t, resolved).name,
2325
+ index: String(asked.registries.length),
2326
+ total: String(asked.total)
2327
+ }) : null;
2328
+ const changeable = phase === "failed" && !approvable && install.failure?.failedAt === "registry";
1714
2329
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1715
2330
  open: install.open,
1716
2331
  onClose,
@@ -1725,17 +2340,16 @@ window.__ModuleLoader__.load({
1725
2340
  children: [phase === "done" ? (0, react_jsx_runtime.jsx)("span", {}) : (0, react_jsx_runtime.jsxs)("button", {
1726
2341
  type: "button",
1727
2342
  className: PluginManagerPage_module_css_default.wizardBack,
1728
- "aria-label": t("installEditAria"),
2343
+ "aria-label": t(pending ? "installCancelAndEdit" : "installEditAria"),
1729
2344
  disabled: !stoppable,
1730
2345
  onClick: onCancel,
1731
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutline14, { "aria-hidden": "true" }), (0, react_jsx_runtime.jsx)("span", { children: t("installEdit") })]
2346
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutlineMedium, { "aria-hidden": "true" }), (0, react_jsx_runtime.jsx)("span", { children: t(pending ? "installCancelAndEdit" : "installEdit") })]
1732
2347
  }), (0, react_jsx_runtime.jsx)("button", {
1733
2348
  type: "button",
1734
2349
  className: PluginManagerPage_module_css_default.wizardClose,
1735
- "aria-label": t(phase === "running" ? "installCloseCancels" : "close"),
1736
- disabled: pending && phase !== "running",
1737
- onClick: phase === "running" ? onCancelAndClose : onClose,
1738
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
2350
+ "aria-label": t(cancellable ? "installCloseCancels" : "close"),
2351
+ onClick: onClose,
2352
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineMedium, { size: 14 })
1739
2353
  })]
1740
2354
  }), (0, react_jsx_runtime.jsxs)("div", {
1741
2355
  className: PluginManagerPage_module_css_default.wizardScroll,
@@ -1745,9 +2359,12 @@ window.__ModuleLoader__.load({
1745
2359
  children: [
1746
2360
  (0, react_jsx_runtime.jsx)("span", {
1747
2361
  className: PluginManagerPage_module_css_default.wizardIcon,
1748
- "data-tone": pending ? "pending" : phase,
2362
+ "data-state": pending ? "ongoing" : phase === "done" ? "done" : "error",
1749
2363
  "aria-hidden": "true",
1750
- children: pending ? (0, react_jsx_runtime.jsx)("span", { className: PluginManagerPage_module_css_default.spinnerLarge }) : phase === "done" ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, { size: 28 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, { size: 28 })
2364
+ children: pending ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
2365
+ state: "ongoing",
2366
+ size: 28
2367
+ }) : phase === "done" ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckCircleFillRegular, { size: 28 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, { size: 28 })
1751
2368
  }),
1752
2369
  (0, react_jsx_runtime.jsx)("h2", {
1753
2370
  className: PluginManagerPage_module_css_default.wizardTitle,
@@ -1756,13 +2373,21 @@ window.__ModuleLoader__.load({
1756
2373
  }),
1757
2374
  phase === "failed" ? (0, react_jsx_runtime.jsx)("p", {
1758
2375
  className: PluginManagerPage_module_css_default.wizardSub,
1759
- children: failureText(install.failure, t)
2376
+ children: failureText(install.failure, t, install)
1760
2377
  }) : null,
1761
- unconfirmed === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
2378
+ attemptLine === null ? null : (0, react_jsx_runtime.jsx)("p", {
2379
+ className: PluginManagerPage_module_css_default.wizardSub,
2380
+ children: attemptLine
2381
+ }),
2382
+ uncertaintyText === null ? null : (0, react_jsx_runtime.jsx)("p", {
1762
2383
  className: PluginManagerPage_module_css_default.wizardSub,
1763
2384
  role: "alert",
1764
- children: t("installCancelUnconfirmed", { reason: unconfirmed })
1765
- })
2385
+ children: uncertaintyText
2386
+ }),
2387
+ phase === "unknown" ? (0, react_jsx_runtime.jsx)("p", {
2388
+ className: PluginManagerPage_module_css_default.wizardSub,
2389
+ children: t("installUnknownDescription")
2390
+ }) : null
1766
2391
  ]
1767
2392
  }),
1768
2393
  install.subject === null ? null : (0, react_jsx_runtime.jsx)(SubjectCard, {
@@ -1827,23 +2452,41 @@ window.__ModuleLoader__.load({
1827
2452
  className: PluginManagerPage_module_css_default.detailsToggle,
1828
2453
  "aria-expanded": install.detailsOpen,
1829
2454
  onClick: onToggleDetails,
1830
- children: [(0, react_jsx_runtime.jsx)("span", { children: t(install.detailsOpen ? "installDetailsHide" : "installDetailsShow") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {
2455
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t(install.detailsOpen ? "installDetailsHide" : "installDetailsShow") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
1831
2456
  className: PluginManagerPage_module_css_default.detailsChevron,
1832
2457
  "aria-hidden": "true"
1833
2458
  })]
1834
2459
  }),
2460
+ uncertainty === "result" ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2461
+ variant: "outline",
2462
+ size: "sm",
2463
+ className: PluginManagerPage_module_css_default.footAction,
2464
+ onClick: onReconcile,
2465
+ children: t("installReconcile")
2466
+ }) : null,
1835
2467
  pending ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1836
2468
  variant: "outline",
1837
2469
  size: "sm",
1838
- disabled: phase !== "running",
2470
+ className: PluginManagerPage_module_css_default.footAction,
2471
+ disabled: !cancellable,
1839
2472
  onClick: onCancel,
1840
2473
  children: t(phase === "cancelling" ? "installCancelling" : "installCancel")
1841
2474
  }) : null,
1842
- phase === "failed" && !approvable ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1843
- variant: "primary",
1844
- size: "sm",
1845
- onClick: onRun,
1846
- children: t("installRetry")
2475
+ phase === "failed" && !approvable ? (0, react_jsx_runtime.jsxs)("span", {
2476
+ className: PluginManagerPage_module_css_default.wizardActions,
2477
+ children: [changeable ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2478
+ variant: "outline",
2479
+ size: "sm",
2480
+ className: PluginManagerPage_module_css_default.footAction,
2481
+ onClick: onChangeRegistry,
2482
+ children: t("installChangeRegistry")
2483
+ }) : null, (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2484
+ variant: "primary",
2485
+ size: "sm",
2486
+ className: PluginManagerPage_module_css_default.footAction,
2487
+ onClick: onRun,
2488
+ children: t("installRetry")
2489
+ })]
1847
2490
  }) : null
1848
2491
  ]
1849
2492
  }),
@@ -1852,18 +2495,30 @@ window.__ModuleLoader__.load({
1852
2495
  children: [(0, react_jsx_runtime.jsx)("p", {
1853
2496
  className: PluginManagerPage_module_css_default.installLocation,
1854
2497
  children: firstRun === void 0 ? t("terminalNoOutput") : t("installLocation", { dir: firstRun.cwd })
1855
- }), install.runs.map((run) => (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
1856
- command: run.command,
1857
- output: run.output,
1858
- running: run.exitCode === void 0,
1859
- exitCode: run.exitCode,
1860
- maxLines: INSTALL_TERMINAL_LINES,
1861
- labels: {
1862
- ...terminalLabels(t),
1863
- ...phase === "cancelling" ? { failed: t("installCancelledShort") } : {}
1864
- },
1865
- className: PluginManagerPage_module_css_default.terminal
1866
- }, run.jobId))]
2498
+ }), install.runs.map((run, index) => {
2499
+ const registry = asked?.registries[index];
2500
+ return (0, react_jsx_runtime.jsxs)("div", {
2501
+ className: PluginManagerPage_module_css_default.run,
2502
+ children: [registry === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
2503
+ className: PluginManagerPage_module_css_default.attemptBadge,
2504
+ children: t("installAttemptBadge", {
2505
+ index: String(index + 1),
2506
+ registry: registryText(registry, t, resolved).name
2507
+ })
2508
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
2509
+ command: run.command,
2510
+ output: run.output,
2511
+ running: run.exitCode === void 0,
2512
+ exitCode: run.exitCode,
2513
+ maxLines: INSTALL_TERMINAL_LINES,
2514
+ labels: {
2515
+ ...terminalLabels(t),
2516
+ ...phase === "cancelling" ? { failed: t("installCancelledShort") } : {}
2517
+ },
2518
+ className: PluginManagerPage_module_css_default.terminal
2519
+ })]
2520
+ }, run.jobId);
2521
+ })]
1867
2522
  }) : null,
1868
2523
  phase !== "done" ? null : install.installed !== null ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1869
2524
  variant: "primary",
@@ -1884,8 +2539,7 @@ window.__ModuleLoader__.load({
1884
2539
  });
1885
2540
  }
1886
2541
  /** The confirmation an uninstall waits on. */
1887
- function ConfirmDialog({ confirm, t, onConfirm, onCancel }) {
1888
- const { title: name } = packageText({ name: confirm.packageName }, t);
2542
+ function ConfirmDialog({ name, t, onConfirm, onCancel }) {
1889
2543
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1890
2544
  open: true,
1891
2545
  onClose: onCancel,
@@ -1906,10 +2560,20 @@ window.__ModuleLoader__.load({
1906
2560
  }
1907
2561
  /** Render the plugin manager: the official plugins and installed bundles, their pages, the install dialog, and the confirmation. */
1908
2562
  function PluginManagerPage(props) {
1909
- const { t, ensure, renderSlot } = props;
2563
+ const { t, ensure, renderSlot, resolveText } = props;
2564
+ const configurations = props.useConfigurations((snapshot) => snapshot.view?.namespaces);
2565
+ const formFor = (id) => {
2566
+ if (!configurations?.some((view) => view.ns === id)) return void 0;
2567
+ const form = props.configForm(id);
2568
+ return {
2569
+ state: form.getSnapshot(),
2570
+ mutate: (ops, revision) => form.mutate(ops, revision)
2571
+ };
2572
+ };
1910
2573
  const state = props.usePluginManager((snapshot) => snapshot);
1911
2574
  const ledger = props.useConfigLedger((snapshot) => snapshot);
1912
2575
  const [view, setView] = (0, react.useState)({ kind: "list" });
2576
+ const [activation, setActivation] = (0, react.useState)(null);
1913
2577
  (0, react.useEffect)(() => {
1914
2578
  ensure();
1915
2579
  }, [ensure]);
@@ -1938,6 +2602,7 @@ window.__ModuleLoader__.load({
1938
2602
  const openItem = view.kind === "item" ? ledger.items.find((item) => item.id === view.id) : void 0;
1939
2603
  const openRow = view.kind === "row" && openPkg !== void 0 ? openPkg.rows.find((row) => row.rowId === view.rowId) : void 0;
1940
2604
  const showsCards = openPkg === void 0 && openItem === void 0;
2605
+ const activated = listed.find((pkg) => pkg.name === activation && pkg.enabled && !state.busy.includes(pkg.name));
1941
2606
  const setRowEnabled = (row, enabled) => {
1942
2607
  /* v8 ignore next -- a row without a live entry has its switch disabled */
1943
2608
  if (row.entryId !== void 0) props.setRowEnabled(row.entryId, enabled);
@@ -1955,15 +2620,18 @@ window.__ModuleLoader__.load({
1955
2620
  const packageCard = (pkg) => (0, react_jsx_runtime.jsx)(PackageCard, {
1956
2621
  pkg,
1957
2622
  t,
2623
+ resolveText,
1958
2624
  busy: state.busy.includes(pkg.name),
1959
2625
  highlighted: state.highlight === pkg.name,
1960
2626
  onOpen: () => {
2627
+ setActivation(null);
1961
2628
  setView({
1962
2629
  kind: "package",
1963
2630
  name: pkg.name
1964
2631
  });
1965
2632
  },
1966
2633
  onSetEnabled: (enabled) => {
2634
+ setActivation(enabled ? pkg.name : null);
1967
2635
  props.setEnabled(pkg.name, enabled);
1968
2636
  }
1969
2637
  }, pkg.name);
@@ -2022,32 +2690,41 @@ window.__ModuleLoader__.load({
2022
2690
  children: (0, react_jsx_runtime.jsx)("span", {
2023
2691
  className: PluginManagerPage_module_css_default.iconWrap,
2024
2692
  "aria-hidden": "true",
2025
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {})
2693
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, {})
2026
2694
  })
2027
2695
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2028
2696
  variant: "primary",
2029
2697
  size: "sm",
2030
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 13 }),
2698
+ className: PluginManagerPage_module_css_default.addButton,
2699
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 13 }),
2031
2700
  disabled: !loaded,
2032
2701
  onClick: props.openInstall,
2033
- children: t("addPlugin")
2702
+ children: t(state.install.requestId === void 0 ? "addPlugin" : "installViewTask")
2034
2703
  })]
2035
2704
  })]
2036
2705
  }) : null,
2037
- state.status === "loading" ? (0, react_jsx_runtime.jsx)("p", {
2038
- className: PluginManagerPage_module_css_default.status,
2039
- children: t("loading")
2706
+ showsCards && state.status === "loading" ? (0, react_jsx_runtime.jsxs)("p", {
2707
+ className: `${PluginManagerPage_module_css_default.status} ${PluginManagerPage_module_css_default.statusWithDot}`,
2708
+ role: "status",
2709
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" }), t("loading")]
2040
2710
  }) : null,
2041
- state.status === "unavailable" ? (0, react_jsx_runtime.jsx)("p", {
2042
- className: PluginManagerPage_module_css_default.status,
2711
+ showsCards && state.status === "unavailable" ? (0, react_jsx_runtime.jsxs)("p", {
2712
+ className: `${PluginManagerPage_module_css_default.status} ${PluginManagerPage_module_css_default.statusWithDot}`,
2043
2713
  role: "status",
2044
- children: t("unavailable")
2714
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "idle" }), t("unavailable")]
2045
2715
  }) : null,
2046
- state.status === "error" ? (0, react_jsx_runtime.jsxs)("div", {
2716
+ state.notice === null || noticeLine === null ? null : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
2717
+ text: noticeLine,
2718
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
2719
+ holdMs: toastHoldMs(noticeLine),
2720
+ onDone: props.dismissNotice
2721
+ }, state.notice.seq),
2722
+ !showsCards && state.status === "error" ? (0, react_jsx_runtime.jsxs)("div", {
2047
2723
  className: PluginManagerPage_module_css_default.failure,
2048
- children: [(0, react_jsx_runtime.jsx)("p", {
2724
+ children: [(0, react_jsx_runtime.jsxs)("p", {
2725
+ className: PluginManagerPage_module_css_default.statusWithDot,
2049
2726
  role: "alert",
2050
- children: t("error")
2727
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }), t("error")]
2051
2728
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2052
2729
  variant: "outline",
2053
2730
  size: "sm",
@@ -2055,16 +2732,12 @@ window.__ModuleLoader__.load({
2055
2732
  children: t("retry")
2056
2733
  })]
2057
2734
  }) : null,
2058
- state.notice === null || noticeLine === null ? null : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
2059
- text: noticeLine,
2060
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, {}),
2061
- holdMs: toastHoldMs(noticeLine),
2062
- onDone: props.dismissNotice
2063
- }, state.notice.seq),
2064
2735
  loaded && openPkg !== void 0 && openRow !== void 0 ? (0, react_jsx_runtime.jsx)(RowDetail, {
2065
2736
  pkg: openPkg,
2066
2737
  row: openRow,
2738
+ form: formFor(openRow.rowId),
2067
2739
  t,
2740
+ resolveText,
2068
2741
  renderSlot,
2069
2742
  onBack: () => {
2070
2743
  setView({
@@ -2076,6 +2749,7 @@ window.__ModuleLoader__.load({
2076
2749
  loaded && openPkg !== void 0 && openRow === void 0 ? (0, react_jsx_runtime.jsx)(PackageDetail, {
2077
2750
  pkg: openPkg,
2078
2751
  t,
2752
+ resolveText,
2079
2753
  busy: state.busy.includes(openPkg.name),
2080
2754
  rowBusy: (row) => row.entryId !== void 0 && state.busy.includes(rowKey(row.entryId)),
2081
2755
  configured: ledger.bundles.has(openPkg.name),
@@ -2093,6 +2767,7 @@ window.__ModuleLoader__.load({
2093
2767
  onSetRowEnabled: setRowEnabled
2094
2768
  }) : null,
2095
2769
  loaded && openItem !== void 0 ? (0, react_jsx_runtime.jsx)(ItemDetail, {
2770
+ form: formFor(openItem.id),
2096
2771
  item: openItem,
2097
2772
  t,
2098
2773
  renderSlot,
@@ -2100,10 +2775,39 @@ window.__ModuleLoader__.load({
2100
2775
  setView({ kind: "list" });
2101
2776
  }
2102
2777
  }) : null,
2103
- loaded && showsCards ? officialCards.length === 0 && mine.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
2778
+ loaded && showsCards ? officialCards.length === 0 && mine.length === 0 && state.status !== "error" ? (0, react_jsx_runtime.jsx)("p", {
2104
2779
  className: PluginManagerPage_module_css_default.empty,
2105
2780
  children: t("empty")
2106
- }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [renderGroup("official", t("officialTitle"), officialCards), renderGroup("bundles", t("bundlesTitle"), mine.map(packageCard))] }) : null,
2781
+ }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2782
+ renderGroup("official", t("officialTitle"), officialCards),
2783
+ renderGroup("bundles", t("bundlesTitle"), mine.map(packageCard)),
2784
+ state.status === "error" ? (0, react_jsx_runtime.jsxs)("div", {
2785
+ className: PluginManagerPage_module_css_default.failure,
2786
+ children: [(0, react_jsx_runtime.jsxs)("p", {
2787
+ className: PluginManagerPage_module_css_default.statusWithDot,
2788
+ role: "alert",
2789
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }), t("error")]
2790
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2791
+ variant: "outline",
2792
+ size: "sm",
2793
+ onClick: props.refresh,
2794
+ children: t("retry")
2795
+ })]
2796
+ }) : null
2797
+ ] }) : null,
2798
+ showsCards && activated !== void 0 && !state.install.open ? renderSlot("plugins.bundle.activation", {
2799
+ packageName: activated.name,
2800
+ onDismiss: () => {
2801
+ setActivation(null);
2802
+ },
2803
+ onOpenDetails: () => {
2804
+ setActivation(null);
2805
+ setView({
2806
+ kind: "package",
2807
+ name: activated.name
2808
+ });
2809
+ }
2810
+ }, { entryKey: activated.name }) : null,
2107
2811
  (0, react_jsx_runtime.jsx)(InstallDialog, {
2108
2812
  install: state.install,
2109
2813
  t,
@@ -2111,13 +2815,19 @@ window.__ModuleLoader__.load({
2111
2815
  onEditSpec: props.editInstallSpec,
2112
2816
  onRun: props.runInstall,
2113
2817
  onCancel: props.cancelInstall,
2114
- onCancelAndClose: props.cancelInstallAndClose,
2818
+ onReconcile: props.reconcileInstall,
2115
2819
  onToggleDetails: props.toggleInstallDetails,
2116
- onEnableNow: props.enableInstalled,
2117
- onApproveBuilds: props.approveBuildsAndRetry
2820
+ onEnableNow: () => {
2821
+ setActivation(state.install.installed);
2822
+ props.enableInstalled();
2823
+ },
2824
+ onApproveBuilds: props.approveBuildsAndRetry,
2825
+ onToggleRegistry: props.toggleRegistryOptions,
2826
+ onChooseRegistry: props.chooseRegistry,
2827
+ onChangeRegistry: props.changeRegistry
2118
2828
  }),
2119
2829
  state.confirm === null ? null : (0, react_jsx_runtime.jsx)(ConfirmDialog, {
2120
- confirm: state.confirm,
2830
+ name: packageText(state.packages.find((pkg) => pkg.name === state.confirm?.packageName) ?? { name: state.confirm.packageName }, resolveText).title,
2121
2831
  t,
2122
2832
  onConfirm: props.confirm,
2123
2833
  onCancel: props.cancelConfirm
@@ -2133,18 +2843,18 @@ window.__ModuleLoader__.load({
2133
2843
  * @returns the icon element.
2134
2844
  */
2135
2845
  function PluginsPanelIcon({ size }) {
2136
- return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutline16, { size });
2846
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutlineRegular, { size });
2137
2847
  }
2138
2848
  //#endregion
2139
2849
  //#region lib/types/client/locales.js
2140
- /** Plugin management copy and display names of shipped global rows. */
2850
+ /** Plugin management interface copy. */
2141
2851
  /** Simplified Chinese dictionary and key source of truth. */
2142
2852
  const zh = {
2143
2853
  panel: "插件",
2144
2854
  title: "插件",
2145
2855
  intro: "添加和管理插件",
2146
2856
  loading: "正在读取插件…",
2147
- error: "暂时无法读取插件。",
2857
+ error: "可能由于网络问题,无法读取全部插件",
2148
2858
  unavailable: "本部署没有可管理的 profile,无法安装或启停插件。",
2149
2859
  retry: "重试",
2150
2860
  refresh: "刷新",
@@ -2154,17 +2864,11 @@ window.__ModuleLoader__.load({
2154
2864
  overriddenNotice: "{name} 已保存,但被更高优先级的配置覆盖,当前未生效",
2155
2865
  bundlesTitle: "已安装",
2156
2866
  officialTitle: "官方",
2157
- builtinAgentTeamTitle: "智能体团队",
2158
- builtinAgentTeamDescription: "启用智能体团队协作与团队工具。",
2159
- builtinAgentTeamWebTitle: "智能体团队 Web 界面",
2160
- builtinAgentTeamWebDescription: "在浏览器中查看团队成员、任务看板和成员会话。",
2161
- builtinAutoReviewTitle: "自动授权审查",
2162
- builtinAutoReviewDescription: "提供自动审查权限模式,由模型在每次工具调用前判断是否授权。",
2163
2867
  statusProblem: "异常",
2164
2868
  statusBeta: "Beta",
2165
2869
  reasonLabel: "原因",
2870
+ metadataError: "包元信息错误:{error}",
2166
2871
  versionTag: "v{version}",
2167
- noDescription: "暂无描述。",
2168
2872
  partsLabel: "包含的组件",
2169
2873
  partsEmpty: "这个插件包不包含任何组件。",
2170
2874
  partsCountTotal: "共 {count} 个",
@@ -2193,13 +2897,11 @@ window.__ModuleLoader__.load({
2193
2897
  installDescription: "输入插件的包名、GitHub 仓库地址或本地目录路径。",
2194
2898
  installSpecLabel: "包名或地址",
2195
2899
  installSpecPlaceholder: "例如 @deepseek-ai/dsh-experimental-auto-review",
2196
- installGuideToggle: "不知道该填什么?",
2900
+ installGuideToggle: "插件安装引导和示例",
2197
2901
  installGuideHide: "收起引导",
2198
- installGuideIntro: "从插件的 README 或发布页面复制以下任意一项。",
2199
- installGuideIdNote: "包名即 npm 包名,常见形式为 dsh-xxx 或 @作者/插件名;插件的显示名称不是包名。",
2200
2902
  installGuideIdTitle: "包名",
2201
2903
  installGuideIdExample: "@deepseek-ai/dsh-experimental-auto-review",
2202
- installGuideIdHint: "README 安装命令中 dsh plugin add 或 pnpm add 之后的部分。",
2904
+ installGuideIdHint: "插件包名即 npm 包名(如 dsh-xxx 或 @作者/插件名),社区插件的 README 安装命令中 dsh plugin add 或 pnpm add 之后的部分。",
2203
2905
  installGuideGitTitle: "GitHub 仓库地址",
2204
2906
  installGuideGitExample: "https://github.com/author/dsh-plugin",
2205
2907
  installGuideGitHint: "插件在 GitHub 上的开源仓库地址,也支持其他 Git 仓库。",
@@ -2210,6 +2912,16 @@ window.__ModuleLoader__.load({
2210
2912
  installGuideFill: "填入示例",
2211
2913
  installGuideFillAria: "填入示例 {example}",
2212
2914
  installGuideSafety: "请确认插件来源可信。插件在本机以你的权限运行,来源不明的插件可能损坏 DeepSeek Harness,或读取和泄露你的数据。",
2915
+ registryToggle: "安装源",
2916
+ registryLegend: "从哪个 npm 源下载插件",
2917
+ registryDefault: "默认安装源",
2918
+ registryNpmmirror: "中国大陆镜像源",
2919
+ registryWithHost: "{name}({host})",
2920
+ registryCustom: "自定义地址",
2921
+ registryCustomPlaceholder: "https://npm.example.com/",
2922
+ registryCustomHint: "公司内网或私有 npm 源;需要登录的源,把凭据放在本机的 ~/.npmrc 里",
2923
+ registryCustomInvalid: "请输入以 http:// 或 https:// 开头的地址",
2924
+ registryListSeparator: "、",
2213
2925
  installRun: "安装",
2214
2926
  installChecking: "正在检查…",
2215
2927
  installProblemInvalid: "无法识别这个包名或地址:{reason}",
@@ -2218,14 +2930,29 @@ window.__ModuleLoader__.load({
2218
2930
  installProblemNotPackage: "该路径不存在或不是有效的插件包",
2219
2931
  installProblemNotBundle: "这个包没有声明组合包,无法作为插件安装:{reason}",
2220
2932
  installProblemNetwork: "无法连接插件源,请检查网络后重试",
2933
+ installProblemNetworkAll: "所有安装源都无法连接(已尝试:{registries}),请检查网络或代理设置,或更换安装源",
2221
2934
  installProblemUnknown: "无法获取插件信息:{reason}",
2222
2935
  installingTitle: "插件安装中…",
2223
2936
  installedTitle: "已安装",
2224
2937
  installFailedTitle: "插件安装失败",
2225
2938
  installEdit: "编辑",
2226
2939
  installEditAria: "返回编辑",
2940
+ installCancelAndEdit: "取消安装并返回编辑",
2941
+ installApplyingCancellationError: "取消请求未得到确认;安装已进入收尾阶段,请等待结果。{reason}",
2942
+ installReconcile: "核对安装状态",
2943
+ installUnknownTitle: "未能获取安装结果",
2944
+ installUnknownDescription: "后端当前没有此安装任务。请检查插件列表后再尝试安装。",
2945
+ installResultUnconfirmed: "未收到安装结果,请核对安装状态。{reason}",
2946
+ installAwaitingAcceptance: "正在等待后端接收安装任务,收到确认后会自动重试取消。",
2947
+ installBackgroundUnknown: "未能获取安装结果,请检查插件列表。",
2227
2948
  installCancel: "取消安装",
2228
2949
  installCloseCancels: "取消安装并关闭",
2950
+ installViewTask: "查看安装任务",
2951
+ installUnconfirmedTitle: "安装状态尚未确认",
2952
+ installBackgroundDone: "插件安装已完成,可查看安装结果。",
2953
+ installBackgroundFailed: "插件安装失败,可查看安装详情。",
2954
+ installBackgroundUnconfirmed: "安装状态暂未确认,请查看安装任务了解详情。",
2955
+ installBackgroundApplying: "安装已进入收尾阶段,无法取消,可查看安装进度。",
2229
2956
  installStarting: "正在准备安装…",
2230
2957
  installCancelling: "正在停止安装…",
2231
2958
  installApplying: "正在应用配置,请稍候…",
@@ -2241,7 +2968,12 @@ window.__ModuleLoader__.load({
2241
2968
  installSubjectTarball: "压缩包",
2242
2969
  installLocation: "安装位置:{dir}",
2243
2970
  installRetry: "重试",
2971
+ installChangeRegistry: "更换安装源",
2972
+ installAttempt: "{previous} 不可用,正在改用 {registry} 重试(第 {index} 个源,共 {total} 个)",
2973
+ installAttemptBadge: "第 {index} 次 · {registry}",
2244
2974
  installFailureNetwork: "网络连接失败",
2975
+ installFailureNetworkAll: "所有安装源都无法连接(已尝试:{registries})。请检查网络或代理设置,或更换安装源后重试。",
2976
+ installFailureNetworkHost: "无法连接 {host}。GitHub 地址和 .tgz 直链不经过安装源,需要本机能直接访问它或配置代理;如果这个插件也发布到了 npm,请改填包名。",
2245
2977
  installFailureNotFound: "未找到相关插件",
2246
2978
  installFailureNoMatchingVersion: "没有匹配的版本",
2247
2979
  installFailureDiskFull: "磁盘空间不足,安装已停止",
@@ -2302,7 +3034,7 @@ window.__ModuleLoader__.load({
2302
3034
  title: "Plugins",
2303
3035
  intro: "Add and manage plugins",
2304
3036
  loading: "Reading plugins…",
2305
- error: "Plugins are temporarily unavailable.",
3037
+ error: "Could not read all plugins, possibly due to a network problem",
2306
3038
  unavailable: "This deployment runs without a manageable profile, so plugins cannot be installed or switched here.",
2307
3039
  retry: "Retry",
2308
3040
  refresh: "Refresh",
@@ -2312,17 +3044,11 @@ window.__ModuleLoader__.load({
2312
3044
  overriddenNotice: "{name} was saved, but a higher-priority configuration overrides it, so it is not in effect",
2313
3045
  bundlesTitle: "Installed",
2314
3046
  officialTitle: "Official",
2315
- builtinAgentTeamTitle: "Agent Teams",
2316
- builtinAgentTeamDescription: "Enable agent team collaboration and team tools.",
2317
- builtinAgentTeamWebTitle: "Agent Teams Web UI",
2318
- builtinAgentTeamWebDescription: "View team members, the task board, and teammate sessions in the browser.",
2319
- builtinAutoReviewTitle: "Auto Authorization Review",
2320
- builtinAutoReviewDescription: "Add an Auto review permission mode that uses the model to assess authorization before each tool call.",
2321
3047
  statusProblem: "Problem",
2322
3048
  statusBeta: "Beta",
2323
3049
  reasonLabel: "Reason",
3050
+ metadataError: "Package metadata error: {error}",
2324
3051
  versionTag: "v{version}",
2325
- noDescription: "No description.",
2326
3052
  partsLabel: "Components",
2327
3053
  partsEmpty: "This plugin pack contains no components.",
2328
3054
  partsCountTotal: "{count} total",
@@ -2351,13 +3077,11 @@ window.__ModuleLoader__.load({
2351
3077
  installDescription: "Enter the plugin's package name, GitHub repository address, or local directory path.",
2352
3078
  installSpecLabel: "Package name or address",
2353
3079
  installSpecPlaceholder: "for example @deepseek-ai/dsh-experimental-auto-review",
2354
- installGuideToggle: "Not sure what to enter?",
3080
+ installGuideToggle: "Install guide and examples",
2355
3081
  installGuideHide: "Hide the guide",
2356
- installGuideIntro: "Copy any one of these from the plugin's README or release page.",
2357
- installGuideIdNote: "The package name is the npm package name, usually dsh-xxx or @author/plugin; the display name is not one.",
2358
3082
  installGuideIdTitle: "Package name",
2359
3083
  installGuideIdExample: "@deepseek-ai/dsh-experimental-auto-review",
2360
- installGuideIdHint: "The part after dsh plugin add or pnpm add in the README's install command.",
3084
+ installGuideIdHint: "The plugin package name is the npm package name (like dsh-xxx or @author/plugin): the part after dsh plugin add or pnpm add in a community plugin's README install command.",
2361
3085
  installGuideGitTitle: "GitHub repository address",
2362
3086
  installGuideGitExample: "https://github.com/author/dsh-plugin",
2363
3087
  installGuideGitHint: "The address of the plugin's open-source repository on GitHub; other Git hosts work too.",
@@ -2368,6 +3092,16 @@ window.__ModuleLoader__.load({
2368
3092
  installGuideFill: "Use example",
2369
3093
  installGuideFillAria: "Use the example {example}",
2370
3094
  installGuideSafety: "Install only plugins you trust: they run with your permissions and can damage DeepSeek Harness or leak your data.",
3095
+ registryToggle: "Registry",
3096
+ registryLegend: "The npm registry the plugin is downloaded from",
3097
+ registryDefault: "Default registry",
3098
+ registryNpmmirror: "Mainland China mirror",
3099
+ registryWithHost: "{name} ({host})",
3100
+ registryCustom: "Custom address",
3101
+ registryCustomPlaceholder: "https://npm.example.com/",
3102
+ registryCustomHint: "A company or private npm registry; for one that needs a login, keep the credentials in ~/.npmrc on this machine",
3103
+ registryCustomInvalid: "Enter an address starting with http:// or https://",
3104
+ registryListSeparator: ", ",
2371
3105
  installRun: "Install",
2372
3106
  installChecking: "Checking…",
2373
3107
  installProblemInvalid: "This is not a package name or address that can be installed: {reason}",
@@ -2376,14 +3110,29 @@ window.__ModuleLoader__.load({
2376
3110
  installProblemNotPackage: "The path does not exist or is not a valid plugin package",
2377
3111
  installProblemNotBundle: "This package declares no bundle, so it cannot be installed as a plugin: {reason}",
2378
3112
  installProblemNetwork: "The plugin registry could not be reached; check the network and try again",
3113
+ installProblemNetworkAll: "No registry could be reached (tried: {registries}); check the network or proxy settings, or change the registry",
2379
3114
  installProblemUnknown: "The plugin could not be looked up: {reason}",
2380
3115
  installingTitle: "Installing the plugin…",
2381
3116
  installedTitle: "Installed",
2382
3117
  installFailedTitle: "The plugin could not be installed",
2383
3118
  installEdit: "Edit",
2384
3119
  installEditAria: "Back to editing",
3120
+ installCancelAndEdit: "Cancel installation and return to editing",
3121
+ installApplyingCancellationError: "Cancellation was not confirmed. Installation is being applied; wait for its result. {reason}",
3122
+ installReconcile: "Check installation status",
3123
+ installUnknownTitle: "Installation result unavailable",
3124
+ installUnknownDescription: "The Host has no active installation with this request id. Check the plugin list before trying again.",
3125
+ installResultUnconfirmed: "The installation result was not received. Check installation status. {reason}",
3126
+ installAwaitingAcceptance: "Waiting for the Host to accept installation. Cancellation will retry automatically after confirmation.",
3127
+ installBackgroundUnknown: "Installation result unavailable. Check the plugin list.",
2385
3128
  installCancel: "Cancel install",
2386
3129
  installCloseCancels: "Cancel install and close",
3130
+ installViewTask: "View installation",
3131
+ installUnconfirmedTitle: "Installation status unconfirmed",
3132
+ installBackgroundDone: "Installation finished. View installation details.",
3133
+ installBackgroundFailed: "Installation failed. View installation details.",
3134
+ installBackgroundUnconfirmed: "Installation status is unconfirmed. View the installation for details.",
3135
+ installBackgroundApplying: "Installation is being applied and cannot be cancelled. View installation progress.",
2387
3136
  installStarting: "Preparing installation…",
2388
3137
  installCancelling: "Stopping installation…",
2389
3138
  installApplying: "Applying configuration, please wait…",
@@ -2399,7 +3148,12 @@ window.__ModuleLoader__.load({
2399
3148
  installSubjectTarball: "Tarball",
2400
3149
  installLocation: "Installs into {dir}",
2401
3150
  installRetry: "Retry",
3151
+ installChangeRegistry: "Change registry",
3152
+ installAttempt: "{previous} could not serve the package; retrying through {registry} (registry {index} of {total})",
3153
+ installAttemptBadge: "Attempt {index} · {registry}",
2402
3154
  installFailureNetwork: "The network connection failed",
3155
+ installFailureNetworkAll: "No registry could be reached (tried: {registries}). Check the network or proxy settings, or change the registry and retry.",
3156
+ installFailureNetworkHost: "{host} could not be reached. A GitHub address or a .tgz link is not fetched through the registry: this machine must reach it directly or through a proxy. If the plugin is also published to npm, enter its package name instead.",
2403
3157
  installFailureNotFound: "No such plugin was found",
2404
3158
  installFailureNoMatchingVersion: "No version matches the request",
2405
3159
  installFailureDiskFull: "The disk is full; the install stopped",
@@ -2474,7 +3228,9 @@ window.__ModuleLoader__.load({
2474
3228
  "locale",
2475
3229
  "remote",
2476
3230
  "remote.pluginManager",
2477
- "remote.pluginInventory"
3231
+ "remote.pluginInventory",
3232
+ "remote.pluginRegistryProbe",
3233
+ "configForms"
2478
3234
  ];
2479
3235
  /**
2480
3236
  * Contribute the Plugins entry to the sidebar with the management page it
@@ -2514,12 +3270,16 @@ window.__ModuleLoader__.load({
2514
3270
  name: "main",
2515
3271
  key: PANEL_ID,
2516
3272
  locale: NS,
2517
- inject: () => controller.inject(configLedger),
3273
+ inject: () => controller.inject(configLedger, (text) => ctx.locale.resolveText(text)),
2518
3274
  children: {
2519
3275
  "plugins.item": {
2520
3276
  kind: "list",
2521
3277
  scope: "root"
2522
3278
  },
3279
+ "plugins.bundle.activation": {
3280
+ kind: "keyed",
3281
+ scope: "root"
3282
+ },
2523
3283
  "plugins.bundle.config": {
2524
3284
  kind: "keyed",
2525
3285
  scope: "root"
@@ -2527,6 +3287,18 @@ window.__ModuleLoader__.load({
2527
3287
  "plugins.row.config": {
2528
3288
  kind: "keyed",
2529
3289
  scope: "root"
3290
+ },
3291
+ "plugins.detail.actions": {
3292
+ kind: "list",
3293
+ scope: "root"
3294
+ },
3295
+ "plugins.detail.badge": {
3296
+ kind: "list",
3297
+ scope: "root"
3298
+ },
3299
+ "plugins.detail.section": {
3300
+ kind: "list",
3301
+ scope: "root"
2530
3302
  }
2531
3303
  }
2532
3304
  }, PluginManagerPage));