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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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");
@@ -86,26 +87,44 @@ window.__ModuleLoader__.load({
86
87
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
87
88
  }
88
89
  //#endregion
90
+ //#region ../../boot/plugin-manager/src/registry.ts
91
+ /** An http(s) URL, as pnpm's `--registry` takes it. */
92
+ const REGISTRY_URL = /^https?:\/\/\S+$/;
93
+ //#endregion
89
94
  //#region lib/types/client/presentation.js
90
95
  /** 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
- ]);
96
+ /** The registries with a name of their own, by host. */
97
+ const REGISTRY_COPY = new Map([["registry.npmmirror.com", "registryNpmmirror"]]);
98
+ /** npm's own registry, which pnpm names without any configuration. */
99
+ const OFFICIAL_NPM_HOST = "registry.npmjs.org";
100
+ /**
101
+ * What a registry reads as: pnpm's own as the default registry, a known mirror by its name, any other registry by
102
+ * its host; and the host each names, for where the name alone would leave it unsaid.
103
+ * @param registry - the registry, null for the one pnpm's own configuration names.
104
+ * @param t - the manager's translate seat.
105
+ * @param resolved - the URL pnpm's own configuration names, null while unknown, when it reads as npm's own.
106
+ * @returns the name and the host.
107
+ */
108
+ function registryText(registry, t, resolved) {
109
+ if (registry === null) return {
110
+ name: t("registryDefault"),
111
+ host: resolved === null ? OFFICIAL_NPM_HOST : registryHost(resolved)
112
+ };
113
+ const host = registryHost(registry);
114
+ const key = REGISTRY_COPY.get(host);
115
+ return {
116
+ name: key === void 0 ? host : t(key),
117
+ host
118
+ };
119
+ }
120
+ /** The host of a registry URL; the URL as written when it does not parse. */
121
+ function registryHost(registry) {
122
+ try {
123
+ return new URL(registry).host;
124
+ } catch {
125
+ return registry;
126
+ }
127
+ }
109
128
  /** The sentence each of the Host's refusal codes reads as. */
110
129
  const CODE_KEYS = {
111
130
  "management-required": "reasonManagementRequired",
@@ -148,21 +167,28 @@ window.__ModuleLoader__.load({
148
167
  return (name.startsWith("@") ? name.slice(name.indexOf("/") + 1) : name).replace(/^dsh-(?:host-|client-)?/, "");
149
168
  }
150
169
  /**
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.
170
+ * Resolve installed package metadata without changing its technical identity.
171
+ * @param pkg - package identity and local metadata.
172
+ * @param resolveText - current-locale package text resolver.
173
+ * @returns localized copy with a technical-name fallback and the independent beta status.
155
174
  */
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
175
+ function packageText(pkg, resolveText) {
176
+ return {
177
+ title: pkg.meta?.title === void 0 ? pkg.name : resolveText(pkg.meta.title),
178
+ description: pkg.meta?.description === void 0 ? void 0 : resolveText(pkg.meta.description) || void 0,
179
+ beta: pkg.name.startsWith("@deepseek-ai/dsh-experimental-")
180
+ };
181
+ }
182
+ /**
183
+ * Resolve a bundle row's plugin metadata, using its full module specifier as the final title fallback.
184
+ * @param row - row identity and local metadata.
185
+ * @param resolveText - current-locale package text resolver.
186
+ * @returns the row's display title and optional description.
187
+ */
188
+ function rowText(row, resolveText) {
189
+ return {
190
+ title: row.meta?.title === void 0 ? row.moduleName : resolveText(row.meta.title),
191
+ description: row.meta?.description === void 0 ? void 0 : resolveText(row.meta.description) || void 0
166
192
  };
167
193
  }
168
194
  /**
@@ -176,6 +202,13 @@ window.__ModuleLoader__.load({
176
202
  case "restart": return t("restartNotice");
177
203
  case "overridden": return t("overriddenNotice", { name: notice.packageName });
178
204
  case "cancelled": return t("installCancelled");
205
+ case "install": return t({
206
+ done: "installBackgroundDone",
207
+ failed: "installBackgroundFailed",
208
+ unconfirmed: "installBackgroundUnconfirmed",
209
+ applying: "installBackgroundApplying",
210
+ unknown: "installBackgroundUnknown"
211
+ }[notice.outcome]);
179
212
  case "failed": {
180
213
  const reason = notice.code === void 0 ? notice.reason : managementText({
181
214
  code: notice.code,
@@ -194,13 +227,28 @@ window.__ModuleLoader__.load({
194
227
  * after each action and after every `plugin-manager/changed` event, so a
195
228
  * change made on another surface shows here without a manual refresh.
196
229
  */
230
+ /** The choice shown until the Host has said which registry it asks first: the one pnpm's own configuration names. */
231
+ const OFFICIAL_REGISTRY = {
232
+ kind: "offered",
233
+ registry: null
234
+ };
235
+ /**
236
+ * The registries the dialog offers: the Host's first, its fallbacks, and pnpm's own, each once.
237
+ * @param registries - what the Host configured, or null while unread.
238
+ * @returns the registries in the order the dialog lists them.
239
+ */
240
+ function offeredRegistries(registries) {
241
+ const offered = [];
242
+ for (const registry of [...registries === null ? [] : [registries.registry, ...registries.fallbackRegistries], null]) if (!offered.includes(registry)) offered.push(registry);
243
+ return offered;
244
+ }
197
245
  /**
198
246
  * Whether an installation is still owned by the Host.
199
247
  * @param phase - the dialog's current installation phase.
200
- * @returns true until an authoritative result settles the installation.
248
+ * @returns true while a Host result or a check for an active request is outstanding.
201
249
  */
202
250
  function isInstallPending(phase) {
203
- return phase === "starting" || phase === "running" || phase === "cancelling" || phase === "applying";
251
+ return phase === "starting" || phase === "running" || phase === "cancelling" || phase === "applying" || phase === "unconfirmed";
204
252
  }
205
253
  /** A refused answer or a change the Host could not apply, carrying what it said and, for a refusal, its code. */
206
254
  var RemoteAnswerError = class extends Error {
@@ -214,11 +262,12 @@ window.__ModuleLoader__.load({
214
262
  }
215
263
  };
216
264
  /** 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) {
265
+ function failureOf(error, kind, pendingBuilds, failedAt) {
218
266
  return {
219
267
  reason: error?.diagnostic ?? "",
220
268
  ...error === void 0 ? {} : { code: error.code },
221
269
  ...kind === void 0 ? {} : { kind },
270
+ ...failedAt === void 0 ? {} : { failedAt },
222
271
  ...pendingBuilds === void 0 || pendingBuilds.length === 0 ? {} : { pendingBuilds }
223
272
  };
224
273
  }
@@ -262,6 +311,7 @@ window.__ModuleLoader__.load({
262
311
  moduleName: row.moduleName,
263
312
  enabled: live?.enabled ?? false,
264
313
  phase: live?.fiberPhase ?? null,
314
+ ...row.meta === void 0 ? {} : { meta: row.meta },
265
315
  ...row.entryId === void 0 ? {} : { entryId: row.entryId },
266
316
  ...live?.readOnlyReason === void 0 ? {} : { readOnlyReason: live.readOnlyReason }
267
317
  };
@@ -274,6 +324,7 @@ window.__ModuleLoader__.load({
274
324
  rows,
275
325
  ...bundle.version === void 0 ? {} : { version: bundle.version },
276
326
  ...bundle.description === void 0 ? {} : { description: bundle.description },
327
+ ...bundle.meta === void 0 ? {} : { meta: bundle.meta },
277
328
  ...bundle.readOnlyReason === void 0 ? {} : { readOnlyReason: bundle.readOnlyReason },
278
329
  ...bundle.error === void 0 ? {} : { error: bundle.error }
279
330
  };
@@ -290,6 +341,11 @@ window.__ModuleLoader__.load({
290
341
  const IDLE_INSTALL = {
291
342
  open: false,
292
343
  spec: "",
344
+ registries: null,
345
+ registry: OFFICIAL_REGISTRY,
346
+ registryOpen: false,
347
+ registryError: false,
348
+ attempts: null,
293
349
  phase: "idle",
294
350
  inputError: null,
295
351
  subject: null,
@@ -301,6 +357,31 @@ window.__ModuleLoader__.load({
301
357
  approvedBuilds: [],
302
358
  enabling: false
303
359
  };
360
+ /** The dialog back at its spec: the run and its outcome forgotten, the spec and the registries kept. */
361
+ function specAgain(install) {
362
+ const { open, spec, registries, registry } = install;
363
+ return {
364
+ ...IDLE_INSTALL,
365
+ open,
366
+ spec,
367
+ registries,
368
+ registry
369
+ };
370
+ }
371
+ /**
372
+ * The choice as the dialog can show it once the Host has answered: nothing remembered starts from the registry the
373
+ * Host asks first; a remembered registry the Host no longer offers is kept as a typed one.
374
+ */
375
+ function reconciled(remembered, registries) {
376
+ if (remembered === null) return {
377
+ kind: "offered",
378
+ registry: registries.registry
379
+ };
380
+ return remembered.kind === "offered" && remembered.registry !== null && !offeredRegistries(registries).includes(remembered.registry) ? {
381
+ kind: "custom",
382
+ url: remembered.registry
383
+ } : remembered;
384
+ }
304
385
  /** Reads and mutates the profile's plugins through the `pluginManager` Remote. */
305
386
  var PluginManagerController = class {
306
387
  ctx;
@@ -312,7 +393,10 @@ window.__ModuleLoader__.load({
312
393
  pendingConfirm;
313
394
  /** Cancels the check the dialog has in flight. */
314
395
  inspectAbort;
396
+ request;
315
397
  noticeSeq = 0;
398
+ /** The registry last used from this browser, kept across dialogs and page loads; null until one was used. */
399
+ registryMemory = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(null, { persist: { name: "dsh.plugin-manager.install-registry" } });
316
400
  /**
317
401
  * @param ctx - the tab plugin's context, whose `remote.pluginManager` and `remote.pluginInventory` namespaces answer.
318
402
  */
@@ -338,19 +422,24 @@ window.__ModuleLoader__.load({
338
422
  /** Stop publishing and drop every late settlement. */
339
423
  dispose() {
340
424
  this.disposed = true;
425
+ this.request = void 0;
341
426
  this.generation += 1;
342
427
  }
343
428
  /**
344
429
  * Build the face the tab's slot registration injects.
345
430
  * @param configLedger - the projection of the plugins carrying configuration, bound beside the tab's own state.
431
+ * @param resolveText - render-time package text resolution supplied by the locale service.
346
432
  * @returns the tab's snapshot sources and its actions.
347
433
  */
348
- inject(configLedger) {
434
+ inject(configLedger, resolveText) {
349
435
  return {
436
+ resolveText,
350
437
  hooks: {
351
438
  pluginManager: this.store,
352
- configLedger
439
+ configLedger,
440
+ configurations: this.ctx.configForms.describe()
353
441
  },
442
+ configForm: (id) => this.ctx.configForms.get(id),
354
443
  ensure: () => {
355
444
  if (this.getSnapshot().status === "idle") this.load();
356
445
  },
@@ -358,13 +447,22 @@ window.__ModuleLoader__.load({
358
447
  this.load();
359
448
  },
360
449
  openInstall: () => {
361
- if (!isInstallPending(this.getSnapshot().install.phase)) this.patch({ install: {
362
- ...IDLE_INSTALL,
363
- open: true
364
- } });
450
+ if (this.getSnapshot().install.requestId === void 0) {
451
+ this.patch({ install: {
452
+ ...IDLE_INSTALL,
453
+ open: true,
454
+ registry: this.registryMemory.getSnapshot() ?? OFFICIAL_REGISTRY
455
+ } });
456
+ this.readRegistries();
457
+ } else this.patchInstall({ open: true });
458
+ this.reconcileInstall();
365
459
  },
366
460
  closeInstall: () => {
367
- if (isInstallPending(this.getSnapshot().install.phase)) return;
461
+ if (isInstallPending(this.getSnapshot().install.phase)) {
462
+ this.patchInstall({ open: false });
463
+ this.cancelInstall();
464
+ return;
465
+ }
368
466
  this.abortInspect();
369
467
  this.patch({ install: IDLE_INSTALL });
370
468
  },
@@ -375,22 +473,37 @@ window.__ModuleLoader__.load({
375
473
  spec: text,
376
474
  inputError: null
377
475
  } : {
378
- ...IDLE_INSTALL,
379
- open: true,
476
+ ...specAgain(install),
380
477
  spec: text
381
478
  });
382
479
  },
383
480
  runInstall: () => {
384
481
  this.runInstall();
385
482
  },
483
+ toggleRegistryOptions: () => {
484
+ this.patchInstall({ registryOpen: !this.getSnapshot().install.registryOpen });
485
+ },
486
+ chooseRegistry: (choice) => {
487
+ if (this.getSnapshot().install.phase === "idle") this.patchInstall({
488
+ registry: choice,
489
+ registryError: false
490
+ });
491
+ },
492
+ changeRegistry: () => {
493
+ const install = this.getSnapshot().install;
494
+ if (install.phase === "failed") this.patch({ install: {
495
+ ...specAgain(install),
496
+ registryOpen: true
497
+ } });
498
+ },
386
499
  approveBuildsAndRetry: () => {
387
500
  this.approveBuildsAndRetry();
388
501
  },
389
502
  cancelInstall: () => {
390
503
  this.cancelInstall();
391
504
  },
392
- cancelInstallAndClose: () => {
393
- this.cancelInstall(true);
505
+ reconcileInstall: () => {
506
+ this.reconcileInstall();
394
507
  },
395
508
  toggleInstallDetails: () => {
396
509
  this.patchInstall({ detailsOpen: !this.getSnapshot().install.detailsOpen });
@@ -448,8 +561,32 @@ window.__ModuleLoader__.load({
448
561
  installProgress(progress) {
449
562
  const install = this.getSnapshot().install;
450
563
  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 });
564
+ const request = this.request;
565
+ if (request === void 0) return;
566
+ request.acknowledged = true;
567
+ if (install.phase === "applying") return;
568
+ if (progress.phase === "installing" && request.cancellation !== void 0) {
569
+ if (request.cancellation.waitingForStart) this.sendCancellation(request, request.cancellation);
570
+ return;
571
+ }
572
+ const attempt = progress.attempt;
573
+ this.patchInstall({
574
+ phase: progress.phase === "installing" ? "running" : progress.phase,
575
+ ...attempt === void 0 ? {} : { attempts: {
576
+ registries: [...install.attempts?.registries ?? [], attempt.registry],
577
+ total: attempt.total
578
+ } }
579
+ });
580
+ }
581
+ /** Read the registries the Host offers, for the dialog just opened; a refused read leaves pnpm's own and a typed one. */
582
+ async readRegistries() {
583
+ const answer = await this.ctx.remote.pluginManager.registries();
584
+ const install = this.getSnapshot().install;
585
+ if (this.disposed || !install.open || !answer.ok) return;
586
+ this.patchInstall({
587
+ registries: answer.value,
588
+ registry: reconciled(this.registryMemory.getSnapshot(), answer.value)
589
+ });
453
590
  }
454
591
  /**
455
592
  * Fold a chunk belonging to this installation into its pnpm command.
@@ -459,6 +596,10 @@ window.__ModuleLoader__.load({
459
596
  appendLog(chunk) {
460
597
  const install = this.getSnapshot().install;
461
598
  if (chunk.requestId !== install.requestId) return;
599
+ if (install.requestId !== void 0 && (install.phase === "starting" || install.phase === "cancelling" || install.phase === "unconfirmed")) this.installProgress({
600
+ requestId: install.requestId,
601
+ phase: "installing"
602
+ });
462
603
  const index = install.runs.findIndex((run) => run.jobId === chunk.jobId);
463
604
  if (index === -1 && !isInstallPending(install.phase)) return;
464
605
  const settled = chunk.exitCode === void 0 ? {} : { exitCode: chunk.exitCode };
@@ -482,6 +623,7 @@ window.__ModuleLoader__.load({
482
623
  */
483
624
  load() {
484
625
  if (this.disposed) return Promise.resolve();
626
+ this.reconcileInstall();
485
627
  if (this.inFlight !== void 0) {
486
628
  this.rerun = true;
487
629
  return this.inFlight;
@@ -562,6 +704,20 @@ window.__ModuleLoader__.load({
562
704
  });
563
705
  return;
564
706
  }
707
+ const choice = install.registry;
708
+ const typed = choice.kind === "custom" ? choice.url.trim() : void 0;
709
+ if (typed !== void 0 && !REGISTRY_URL.test(typed)) {
710
+ this.patchInstall({
711
+ phase: "idle",
712
+ registryError: true
713
+ });
714
+ return;
715
+ }
716
+ const registry = typed ?? choice.registry;
717
+ this.registryMemory.set(typed === void 0 ? choice : {
718
+ kind: "custom",
719
+ url: typed
720
+ });
565
721
  this.abortInspect();
566
722
  const controller = new AbortController();
567
723
  this.inspectAbort = controller;
@@ -571,12 +727,14 @@ window.__ModuleLoader__.load({
571
727
  subject: null,
572
728
  runs: [],
573
729
  detailsOpen: false,
730
+ attempts: null,
731
+ registryOpen: false,
574
732
  installed: null,
575
733
  restartRequired: false,
576
734
  failure: null,
577
735
  approvedBuilds: []
578
736
  });
579
- const inspected = await this.ctx.remote.pluginManager.inspect(spec, controller.signal);
737
+ const inspected = await this.ctx.remote.pluginManager.inspect(spec, { registry }, controller.signal);
580
738
  if (this.gone(controller.signal)) return;
581
739
  this.inspectAbort = void 0;
582
740
  if (!inspected.ok) {
@@ -590,11 +748,13 @@ window.__ModuleLoader__.load({
590
748
  return;
591
749
  }
592
750
  if (inspected.value.status === "refused") {
751
+ const { problem, reason, registries } = inspected.value;
593
752
  this.patchInstall({
594
753
  phase: "idle",
595
754
  inputError: {
596
- problem: inspected.value.problem,
597
- reason: inspected.value.reason
755
+ problem,
756
+ reason,
757
+ ...registries === void 0 ? {} : { registries }
598
758
  }
599
759
  });
600
760
  return;
@@ -610,13 +770,21 @@ window.__ModuleLoader__.load({
610
770
  * the Host saves that permission for this profile before pnpm runs.
611
771
  */
612
772
  async startInstall(subject, approvedBuilds) {
613
- const { spec } = subject;
773
+ const { spec, registry } = subject;
614
774
  const requestId = randomUUID();
775
+ const request = {
776
+ requestId,
777
+ acknowledged: false,
778
+ replyLost: false,
779
+ recovering: false
780
+ };
781
+ this.request = request;
615
782
  this.patchInstall({
616
783
  phase: "starting",
617
784
  requestId,
618
785
  subject,
619
786
  runs: [],
787
+ attempts: null,
620
788
  failure: null,
621
789
  installed: null,
622
790
  approvedBuilds: []
@@ -624,35 +792,85 @@ window.__ModuleLoader__.load({
624
792
  const result = await this.ctx.remote.pluginManager.installBundle(spec, {
625
793
  enabled: false,
626
794
  requestId,
795
+ registry,
627
796
  ...approvedBuilds === void 0 ? {} : { approvedBuilds: [...approvedBuilds] }
628
797
  });
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 }
798
+ if (this.disposed || this.request !== request) return;
799
+ if (!result.ok) {
800
+ request.replyLost = true;
801
+ this.installUncertain("result", result.error.message);
802
+ this.reconcileInstall();
803
+ return;
804
+ }
805
+ this.settleInstall(result.value);
806
+ }
807
+ /** A recovery call shares the Host's active result; absent results are explicitly unknown. */
808
+ async reconcileInstall() {
809
+ const request = this.request;
810
+ if (request === void 0 || !request.replyLost || request.recovering) return;
811
+ request.recovering = true;
812
+ const result = await this.ctx.remote.pluginManager.waitForInstall(request.requestId);
813
+ if (this.disposed || this.request !== request) return;
814
+ request.recovering = false;
815
+ if (!result.ok) {
816
+ this.installUncertain("result", result.error.message);
817
+ return;
818
+ }
819
+ if (result.value !== null) {
820
+ this.settleInstall(result.value);
821
+ return;
822
+ }
823
+ this.request = void 0;
824
+ this.patchInstall({
825
+ phase: "unknown",
826
+ failure: null,
827
+ runs: settledRuns(this.getSnapshot().install.runs, null)
635
828
  });
636
- else if (result.value.application === "cancelled") this.offerSpecAgain({
829
+ this.notifyHiddenInstall("unknown");
830
+ this.load();
831
+ }
832
+ settleInstall(result) {
833
+ const { runs, attempts } = this.getSnapshot().install;
834
+ this.request = void 0;
835
+ const asked = result.registries === void 0 ? {} : { attempts: {
836
+ registries: result.registries,
837
+ total: Math.max(attempts?.total ?? 0, result.registries.length)
838
+ } };
839
+ if (result.application === "cancelled") this.offerSpecAgain({
637
840
  kind: "cancelled",
638
841
  seq: ++this.noticeSeq
639
842
  });
640
- else if (result.value.application === "failed") {
641
- const packages = result.value.packageResult;
843
+ else if (result.application === "failed") {
844
+ const packages = result.packageResult;
642
845
  this.patchInstall({
643
846
  phase: "failed",
644
847
  runs: settledRuns(runs, packages?.exitCode ?? null),
645
- failure: failureOf(result.value.error, packages?.kind, result.value.pendingBuilds)
848
+ failure: failureOf(result.error, packages?.kind, result.pendingBuilds, result.failedAt),
849
+ ...asked
646
850
  });
647
851
  } else this.patchInstall({
648
852
  phase: "done",
649
853
  runs: settledRuns(runs, 0),
650
- installed: result.value.bundle ?? null,
651
- restartRequired: result.value.application === "restart-required",
652
- approvedBuilds: result.value.approvedBuilds ?? []
854
+ failure: null,
855
+ installed: result.bundle ?? null,
856
+ restartRequired: result.application === "restart-required",
857
+ approvedBuilds: result.approvedBuilds ?? [],
858
+ ...asked
653
859
  });
860
+ const phase = this.getSnapshot().install.phase;
861
+ if (phase === "done" || phase === "failed") this.notifyHiddenInstall(phase);
654
862
  this.load();
655
863
  }
864
+ installUncertain(uncertainty, reason) {
865
+ this.patchInstall({
866
+ phase: this.getSnapshot().install.phase === "applying" ? "applying" : "unconfirmed",
867
+ failure: {
868
+ reason,
869
+ uncertainty
870
+ }
871
+ });
872
+ this.notifyHiddenInstall("unconfirmed");
873
+ }
656
874
  /**
657
875
  * Allow the install scripts the failed run left pending and run the same
658
876
  * spec again. Only the failed screen with pending names offers this.
@@ -665,69 +883,80 @@ window.__ModuleLoader__.load({
665
883
  }
666
884
  /**
667
885
  * 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
886
+ * run is asked to stop and its state waits for the Host's word, since
669
887
  * 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
888
  */
672
- async cancelInstall(closeAfter = false) {
889
+ async cancelInstall() {
673
890
  const install = this.getSnapshot().install;
674
- if (!closeAfter && (install.phase === "checking" || install.phase === "failed")) {
891
+ if (install.phase === "checking" || install.phase === "failed" || install.phase === "unknown") {
675
892
  this.abortInspect();
676
893
  this.offerSpecAgain();
677
894
  return;
678
895
  }
679
- if (install.phase !== "running" || install.requestId === void 0) return;
680
- const requestId = install.requestId;
896
+ const request = this.request;
897
+ if (install.phase !== "starting" && install.phase !== "running" && install.phase !== "unconfirmed" || request === void 0) return;
898
+ if (request.cancellation !== void 0 && !request.cancellation.waitingForStart) return;
899
+ const cancellation = { waitingForStart: false };
900
+ request.cancellation = cancellation;
901
+ await this.sendCancellation(request, cancellation);
902
+ }
903
+ /** A cancellation that overtakes installation is retried after the Host acknowledges that request. */
904
+ async sendCancellation(request, cancellation) {
905
+ const acknowledged = request.acknowledged;
906
+ cancellation.waitingForStart = false;
681
907
  this.patchInstall({
682
908
  phase: "cancelling",
683
909
  failure: null
684
910
  });
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;
911
+ const result = await this.ctx.remote.pluginManager.cancelInstall(request.requestId);
912
+ if (this.disposed || this.request !== request || request.cancellation !== cancellation) return;
688
913
  if (!result.ok) {
689
- this.patchInstall({
690
- phase: "running",
691
- failure: {
692
- reason: result.error.message,
693
- cancelUnconfirmed: true
694
- }
695
- });
914
+ cancellation.waitingForStart = !request.acknowledged;
915
+ if (request.acknowledged) request.cancellation = void 0;
916
+ this.installUncertain(request.replyLost ? "result" : "cancellation", result.error.message);
696
917
  return;
697
918
  }
698
919
  if (result.value.status === "cancelled") {
699
- const notice = {
920
+ this.offerSpecAgain({
700
921
  kind: "cancelled",
701
922
  seq: ++this.noticeSeq
702
- };
703
- if (closeAfter) this.patch({
704
- install: IDLE_INSTALL,
705
- notice
706
923
  });
707
- else this.offerSpecAgain(notice);
708
924
  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
- });
925
+ } else if (result.value.status === "too-late") {
926
+ request.acknowledged = true;
927
+ request.cancellation = void 0;
928
+ this.patchInstall({ phase: "applying" });
929
+ this.notifyHiddenInstall("applying");
930
+ this.reconcileInstall();
931
+ } else if (request.replyLost) {
932
+ request.cancellation = void 0;
933
+ this.installUncertain("result", "");
934
+ this.reconcileInstall();
935
+ } else if (!acknowledged && this.getSnapshot().install.phase !== "applying") if (request.acknowledged) await this.sendCancellation(request, cancellation);
936
+ else {
937
+ cancellation.waitingForStart = true;
938
+ this.installUncertain("acceptance", "");
939
+ }
940
+ else {
941
+ request.cancellation = void 0;
942
+ this.installUncertain("cancellation", "");
943
+ }
944
+ }
945
+ notifyHiddenInstall(outcome) {
946
+ if (!this.getSnapshot().install.open) this.patch({ notice: {
947
+ kind: "install",
948
+ outcome,
949
+ seq: ++this.noticeSeq
950
+ } });
717
951
  }
718
952
  /**
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.
953
+ * Release the tracked request and return to editing with its spec retained.
954
+ * A cancellation notice is supplied only after the Host confirms it stopped.
722
955
  */
723
956
  offerSpecAgain(notice = null) {
724
- const { open, spec } = this.getSnapshot().install;
957
+ this.request = void 0;
725
958
  this.patch({
726
- install: {
727
- ...IDLE_INSTALL,
728
- open,
729
- spec
730
- },
959
+ install: specAgain(this.getSnapshot().install),
731
960
  ...notice === null ? {} : { notice }
732
961
  });
733
962
  }
@@ -832,7 +1061,7 @@ window.__ModuleLoader__.load({
832
1061
  }
833
1062
  //#endregion
834
1063
  //#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}";
1064
+ 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
1065
  const tagId = "@deepseek-ai/dsh-client-ui-plugin-manager/PluginManagerPage.module.css";
837
1066
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
838
1067
  const tag = document.createElement("style");
@@ -843,11 +1072,13 @@ window.__ModuleLoader__.load({
843
1072
  }
844
1073
  var PluginManagerPage_module_css_default = {
845
1074
  "actions": "X_2TxG_actions",
1075
+ "addButton": "X_2TxG_addButton",
846
1076
  "approval": "X_2TxG_approval",
847
1077
  "approvalCaution": "X_2TxG_approvalCaution",
848
1078
  "approvalList": "X_2TxG_approvalList",
849
1079
  "approvalText": "X_2TxG_approvalText",
850
1080
  "approvalTitle": "X_2TxG_approvalTitle",
1081
+ "attemptBadge": "X_2TxG_attemptBadge",
851
1082
  "banner": "X_2TxG_banner",
852
1083
  "card": "X_2TxG_card",
853
1084
  "cardArrow": "X_2TxG_cardArrow",
@@ -882,6 +1113,7 @@ window.__ModuleLoader__.load({
882
1113
  "dsh-plugin-highlight": "X_2TxG_dsh-plugin-highlight",
883
1114
  "empty": "X_2TxG_empty",
884
1115
  "failure": "X_2TxG_failure",
1116
+ "footAction": "X_2TxG_footAction",
885
1117
  "group": "X_2TxG_group",
886
1118
  "groupHead": "X_2TxG_groupHead",
887
1119
  "groupInfo": "X_2TxG_groupInfo",
@@ -892,11 +1124,9 @@ window.__ModuleLoader__.load({
892
1124
  "guideExampleLabel": "X_2TxG_guideExampleLabel",
893
1125
  "guideHint": "X_2TxG_guideHint",
894
1126
  "guideIndex": "X_2TxG_guideIndex",
895
- "guideIntro": "X_2TxG_guideIntro",
896
1127
  "guideItem": "X_2TxG_guideItem",
897
1128
  "guideList": "X_2TxG_guideList",
898
1129
  "guideMain": "X_2TxG_guideMain",
899
- "guideNote": "X_2TxG_guideNote",
900
1130
  "guideSafety": "X_2TxG_guideSafety",
901
1131
  "guideTitle": "X_2TxG_guideTitle",
902
1132
  "guideToggle": "X_2TxG_guideToggle",
@@ -904,9 +1134,12 @@ window.__ModuleLoader__.load({
904
1134
  "iconWrap": "X_2TxG_iconWrap",
905
1135
  "inputError": "X_2TxG_inputError",
906
1136
  "installBody": "X_2TxG_installBody",
1137
+ "installContent": "X_2TxG_installContent",
907
1138
  "installDialog": "X_2TxG_installDialog",
908
1139
  "installField": "X_2TxG_installField",
909
1140
  "installLocation": "X_2TxG_installLocation",
1141
+ "optionsRow": "X_2TxG_optionsRow",
1142
+ "packageImage": "X_2TxG_packageImage",
910
1143
  "page": "X_2TxG_page",
911
1144
  "pageHead": "X_2TxG_pageHead",
912
1145
  "pageIntro": "X_2TxG_pageIntro",
@@ -914,6 +1147,14 @@ window.__ModuleLoader__.load({
914
1147
  "partsFilter": "X_2TxG_partsFilter",
915
1148
  "partsHead": "X_2TxG_partsHead",
916
1149
  "reason": "X_2TxG_reason",
1150
+ "registry": "X_2TxG_registry",
1151
+ "registryChosen": "X_2TxG_registryChosen",
1152
+ "registryCustomField": "X_2TxG_registryCustomField",
1153
+ "registryCustomPick": "X_2TxG_registryCustomPick",
1154
+ "registryHint": "X_2TxG_registryHint",
1155
+ "registryOption": "X_2TxG_registryOption",
1156
+ "registryTitle": "X_2TxG_registryTitle",
1157
+ "registryToggle": "X_2TxG_registryToggle",
917
1158
  "result": "X_2TxG_result",
918
1159
  "resultWarn": "X_2TxG_resultWarn",
919
1160
  "row": "X_2TxG_row",
@@ -927,14 +1168,13 @@ window.__ModuleLoader__.load({
927
1168
  "rowOpenIcon": "X_2TxG_rowOpenIcon",
928
1169
  "rowState": "X_2TxG_rowState",
929
1170
  "rows": "X_2TxG_rows",
1171
+ "run": "X_2TxG_run",
930
1172
  "sectionCount": "X_2TxG_sectionCount",
931
1173
  "sectionHead": "X_2TxG_sectionHead",
932
1174
  "sectionTitle": "X_2TxG_sectionTitle",
933
- "spin": "X_2TxG_spin",
934
- "spinner": "X_2TxG_spinner",
935
- "spinnerLarge": "X_2TxG_spinnerLarge",
936
1175
  "status": "X_2TxG_status",
937
1176
  "statusTag": "X_2TxG_statusTag",
1177
+ "statusWithDot": "X_2TxG_statusWithDot",
938
1178
  "subLabel": "X_2TxG_subLabel",
939
1179
  "subject": "X_2TxG_subject",
940
1180
  "subjectDesc": "X_2TxG_subjectDesc",
@@ -946,6 +1186,7 @@ window.__ModuleLoader__.load({
946
1186
  "versionTag": "X_2TxG_versionTag",
947
1187
  "wide": "X_2TxG_wide",
948
1188
  "wizard": "X_2TxG_wizard",
1189
+ "wizardActions": "X_2TxG_wizardActions",
949
1190
  "wizardBack": "X_2TxG_wizardBack",
950
1191
  "wizardClose": "X_2TxG_wizardClose",
951
1192
  "wizardFoot": "X_2TxG_wizardFoot",
@@ -990,13 +1231,13 @@ window.__ModuleLoader__.load({
990
1231
  failed: "rowPhaseFailed",
991
1232
  unloading: "rowPhaseUnloading"
992
1233
  };
993
- /** Status dot naming a live root-fiber phase: pending and unloading fibers do nothing; only loading is in progress. */
1234
+ /** Status dot naming a root-fiber phase; loading and unloading are live transitions. */
994
1235
  const PHASE_STATES = {
995
1236
  pending: "idle",
996
1237
  loading: "ongoing",
997
1238
  active: "done",
998
1239
  failed: "error",
999
- unloading: "idle"
1240
+ unloading: "ongoing"
1000
1241
  };
1001
1242
  /** The count line over a pack's components: the total, then only the states that occur. */
1002
1243
  function partsSummary(rows, t) {
@@ -1012,12 +1253,41 @@ window.__ModuleLoader__.load({
1012
1253
  }
1013
1254
  /** Rows beyond this count get a filter box above the list. */
1014
1255
  const ROW_FILTER_THRESHOLD = 10;
1256
+ /** The size the 36-viewBox plugin artwork renders at inside a card's 48px frame. */
1257
+ const CARD_ARTWORK_SIZE = 36;
1258
+ /** The size the artwork renders at inside a row's 40px frame. */
1259
+ const ROW_ARTWORK_SIZE = 30;
1260
+ /** The artwork of the official plugins that registered their configuration, by registration id. */
1261
+ const ITEM_ARTWORK = new Map([
1262
+ ["shell", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkTerminal],
1263
+ ["agent-loop", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkLoop],
1264
+ ["subagent", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkSubagent],
1265
+ ["web-search", _deepseek_ai_dsh_client_ui_primitives.PluginArtworkSearch]
1266
+ ]);
1267
+ /** An official plugin's card and page artwork; plugins without their own get the default. */
1268
+ function itemArtwork(id) {
1269
+ return (0, react_jsx_runtime.jsx)(ITEM_ARTWORK.get(id) ?? _deepseek_ai_dsh_client_ui_primitives.PluginArtworkDefault, { size: CARD_ARTWORK_SIZE });
1270
+ }
1271
+ /** Manifest images remain isolated from the page DOM; a failed decode keeps the position's default artwork. */
1272
+ function PackageArtwork({ src, row = false, size = row ? ROW_ARTWORK_SIZE : CARD_ARTWORK_SIZE }) {
1273
+ const [failedSource, setFailedSource] = (0, react.useState)();
1274
+ 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", {
1275
+ className: PluginManagerPage_module_css_default.packageImage,
1276
+ src,
1277
+ width: size,
1278
+ height: size,
1279
+ alt: "",
1280
+ onError: () => {
1281
+ setFailedSource(src);
1282
+ }
1283
+ });
1284
+ }
1015
1285
  /** 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 }) {
1286
+ function RowSwitch({ row, title, t, busy, onChange }) {
1017
1287
  const locked = row.readOnlyReason !== void 0 || row.entryId === void 0;
1018
1288
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
1019
1289
  checked: row.enabled,
1020
- label: t("partToggle", { name: row.rowId }),
1290
+ label: t("partToggle", { name: title }),
1021
1291
  disabled: busy || locked,
1022
1292
  ...row.readOnlyReason === void 0 ? {} : { title: managementText({ code: row.readOnlyReason }, t) },
1023
1293
  onChange
@@ -1033,16 +1303,34 @@ window.__ModuleLoader__.load({
1033
1303
  if (!row.enabled || row.phase === null) return "idle";
1034
1304
  return PHASE_STATES[row.phase];
1035
1305
  }
1306
+ /** A Host metadata diagnostic does not change the package's management permissions. */
1307
+ function MetadataError({ error, t }) {
1308
+ return error === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
1309
+ className: PluginManagerPage_module_css_default.reason,
1310
+ role: "status",
1311
+ "data-package-meta-error": true,
1312
+ children: t("metadataError", { error })
1313
+ });
1314
+ }
1036
1315
  /**
1037
1316
  * A pack's rows as a list in the order the pack declares them: a state dot,
1038
1317
  * the row id, one line saying its state, a configure control for a row that
1039
1318
  * registered a page, and, when the pack is on, a switch. A pack like base
1040
1319
  * carries close to a hundred rows, so a long list gets a filter.
1041
1320
  */
1042
- function RowsSection({ rows, t, toggle, configure }) {
1321
+ function RowsSection({ rows, t, resolveText, toggle, configure }) {
1043
1322
  const [filter, setFilter] = (0, react.useState)("");
1044
1323
  const query = filter.trim().toLowerCase();
1045
- const shown = query === "" ? rows : rows.filter((row) => row.rowId.toLowerCase().includes(query));
1324
+ const localized = rows.map((row) => ({
1325
+ row,
1326
+ ...rowText(row, resolveText)
1327
+ }));
1328
+ const shown = query === "" ? localized : localized.filter(({ row, title, description }) => [
1329
+ title,
1330
+ description,
1331
+ row.rowId,
1332
+ row.moduleName
1333
+ ].some((value) => value?.toLowerCase().includes(query)));
1046
1334
  return (0, react_jsx_runtime.jsxs)("section", {
1047
1335
  className: PluginManagerPage_module_css_default.detailSection,
1048
1336
  "data-plugin-rows": true,
@@ -1077,51 +1365,63 @@ window.__ModuleLoader__.load({
1077
1365
  }) : null,
1078
1366
  shown.length === 0 ? null : (0, react_jsx_runtime.jsx)("ul", {
1079
1367
  className: PluginManagerPage_module_css_default.rows,
1080
- children: shown.map((row) => (0, react_jsx_runtime.jsx)("li", {
1368
+ children: shown.map(({ row, title, description }) => (0, react_jsx_runtime.jsxs)("li", {
1081
1369
  className: PluginManagerPage_module_css_default.row,
1082
1370
  "data-plugin-row": row.entryId ?? row.rowId,
1083
1371
  ...row.phase === "failed" ? { "data-state": "failed" } : row.enabled ? {} : { "data-state": "off" },
1084
- children: (0, react_jsx_runtime.jsxs)("div", {
1372
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1085
1373
  className: PluginManagerPage_module_css_default.rowLine,
1086
1374
  children: [
1087
1375
  (0, react_jsx_runtime.jsx)("span", {
1088
1376
  className: PluginManagerPage_module_css_default.rowIcon,
1089
1377
  "aria-hidden": "true",
1090
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCordisPluginOutline14, {})
1378
+ children: (0, react_jsx_runtime.jsx)(PackageArtwork, {
1379
+ src: row.meta?.icon,
1380
+ row: true
1381
+ }, row.meta?.icon)
1091
1382
  }),
1092
1383
  (0, react_jsx_runtime.jsxs)("div", {
1093
1384
  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", {
1385
+ children: [
1386
+ configure?.has(row) === true ? (0, react_jsx_runtime.jsxs)("button", {
1387
+ type: "button",
1388
+ className: PluginManagerPage_module_css_default.rowOpen,
1389
+ "aria-label": t("configureRow", { name: title }),
1390
+ onClick: () => {
1391
+ configure.open(row);
1392
+ },
1393
+ children: [(0, react_jsx_runtime.jsx)("span", {
1394
+ className: PluginManagerPage_module_css_default.rowId,
1395
+ children: title
1396
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, {
1397
+ className: PluginManagerPage_module_css_default.rowOpenIcon,
1398
+ "aria-hidden": "true"
1399
+ })]
1400
+ }) : (0, react_jsx_runtime.jsx)("span", {
1102
1401
  className: PluginManagerPage_module_css_default.rowId,
1402
+ children: title
1403
+ }),
1404
+ description === void 0 ? null : (0, react_jsx_runtime.jsx)("span", {
1405
+ className: PluginManagerPage_module_css_default.rowModule,
1406
+ children: description
1407
+ }),
1408
+ title === row.rowId ? null : (0, react_jsx_runtime.jsx)("code", {
1409
+ className: PluginManagerPage_module_css_default.rowModule,
1103
1410
  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
- })]
1411
+ }),
1412
+ title === row.moduleName ? null : (0, react_jsx_runtime.jsx)("code", {
1413
+ className: PluginManagerPage_module_css_default.rowModule,
1414
+ children: row.moduleName
1415
+ })
1416
+ ]
1115
1417
  }),
1116
1418
  (0, react_jsx_runtime.jsxs)("span", {
1117
1419
  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)]
1420
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: rowDotState(row) }), rowStateText(row, t)]
1122
1421
  }),
1123
1422
  toggle === void 0 ? null : (0, react_jsx_runtime.jsx)(RowSwitch, {
1124
1423
  row,
1424
+ title,
1125
1425
  t,
1126
1426
  busy: toggle.busy(row),
1127
1427
  onChange: (enabled) => {
@@ -1129,7 +1429,10 @@ window.__ModuleLoader__.load({
1129
1429
  }
1130
1430
  })
1131
1431
  ]
1132
- })
1432
+ }), (0, react_jsx_runtime.jsx)(MetadataError, {
1433
+ error: row.meta?.error,
1434
+ t
1435
+ })]
1133
1436
  }, row.rowId))
1134
1437
  })
1135
1438
  ]
@@ -1153,15 +1456,16 @@ window.__ModuleLoader__.load({
1153
1456
  if (pkg.error !== void 0) return "problem";
1154
1457
  return pkg.enabled ? "running" : "disabled";
1155
1458
  }
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 }) {
1459
+ /** 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. */
1460
+ function CardHead({ title, t, onOpen, icon, tags, description, end }) {
1461
+ const descriptionId = (0, react.useId)();
1158
1462
  return (0, react_jsx_runtime.jsxs)("div", {
1159
1463
  className: PluginManagerPage_module_css_default.cardHead,
1160
1464
  children: [
1161
1465
  (0, react_jsx_runtime.jsx)("span", {
1162
1466
  className: PluginManagerPage_module_css_default.cardIcon,
1163
1467
  "aria-hidden": "true",
1164
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutline16, { size: 20 })
1468
+ children: icon
1165
1469
  }),
1166
1470
  (0, react_jsx_runtime.jsxs)("div", {
1167
1471
  className: PluginManagerPage_module_css_default.cardMain,
@@ -1171,11 +1475,13 @@ window.__ModuleLoader__.load({
1171
1475
  type: "button",
1172
1476
  className: `${PluginManagerPage_module_css_default.cardTitle} ${PluginManagerPage_module_css_default.cardOpen}`,
1173
1477
  "aria-label": t("openDetail", { name: title }),
1478
+ "aria-describedby": description === void 0 ? void 0 : descriptionId,
1174
1479
  onClick: onOpen,
1175
1480
  children: title
1176
1481
  }), tags]
1177
1482
  }), description === void 0 ? null : (0, react_jsx_runtime.jsx)("span", {
1178
1483
  className: PluginManagerPage_module_css_default.cardDesc,
1484
+ id: descriptionId,
1179
1485
  children: description
1180
1486
  })]
1181
1487
  }),
@@ -1193,7 +1499,7 @@ window.__ModuleLoader__.load({
1193
1499
  className: PluginManagerPage_module_css_default.crumb,
1194
1500
  "aria-label": crumbLabel,
1195
1501
  onClick: onBack,
1196
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {
1502
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
1197
1503
  className: PluginManagerPage_module_css_default.crumbIcon,
1198
1504
  "aria-hidden": "true"
1199
1505
  }), (0, react_jsx_runtime.jsx)("span", { children: crumbText })]
@@ -1202,23 +1508,24 @@ window.__ModuleLoader__.load({
1202
1508
  children: [(0, react_jsx_runtime.jsx)("span", {
1203
1509
  className: PluginManagerPage_module_css_default.cardIcon,
1204
1510
  "aria-hidden": "true",
1205
- children: icon ?? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutline16, { size: 20 })
1511
+ children: icon
1206
1512
  }), actions]
1207
1513
  })] });
1208
1514
  }
1209
1515
  /** 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);
1516
+ function PackageCard({ pkg, t, resolveText, busy, highlighted, onOpen, onSetEnabled }) {
1517
+ const { title, description, beta } = packageText(pkg, resolveText);
1212
1518
  const status = packageStatus(pkg);
1213
- return (0, react_jsx_runtime.jsx)("li", {
1519
+ return (0, react_jsx_runtime.jsxs)("li", {
1214
1520
  className: `${PluginManagerPage_module_css_default.card} ${PluginManagerPage_module_css_default.cardLink}`,
1215
1521
  "data-plugin-package": pkg.name,
1216
1522
  "data-plugin-status": status,
1217
1523
  ...highlighted ? { "data-plugin-highlight": "" } : {},
1218
- children: (0, react_jsx_runtime.jsx)(CardHead, {
1524
+ children: [(0, react_jsx_runtime.jsx)(CardHead, {
1219
1525
  title,
1220
1526
  t,
1221
1527
  onOpen,
1528
+ icon: (0, react_jsx_runtime.jsx)(PackageArtwork, { src: pkg.meta?.icon }, pkg.meta?.icon),
1222
1529
  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
1530
  className: PluginManagerPage_module_css_default.statusTag,
1224
1531
  tone: "info",
@@ -1236,7 +1543,10 @@ window.__ModuleLoader__.load({
1236
1543
  busy,
1237
1544
  onSetEnabled
1238
1545
  })
1239
- })
1546
+ }), (0, react_jsx_runtime.jsx)(MetadataError, {
1547
+ error: pkg.meta?.error,
1548
+ t
1549
+ })]
1240
1550
  });
1241
1551
  }
1242
1552
  /**
@@ -1251,12 +1561,39 @@ window.__ModuleLoader__.load({
1251
1561
  title: item.label,
1252
1562
  t,
1253
1563
  onOpen,
1564
+ icon: itemArtwork(item.id),
1254
1565
  description: renderSlot("plugins.item", { view: "summary" }, { only: item.id })
1255
1566
  })
1256
1567
  });
1257
1568
  }
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 }) {
1569
+ /** One row as the detail slots see it. */
1570
+ function rowRef(row) {
1571
+ return {
1572
+ rowId: row.rowId,
1573
+ moduleName: row.moduleName,
1574
+ enabled: row.enabled
1575
+ };
1576
+ }
1577
+ /** One bundle as the detail slots see it. */
1578
+ function packageRef(pkg) {
1579
+ return {
1580
+ name: pkg.name,
1581
+ ...pkg.version === void 0 ? {} : { version: pkg.version },
1582
+ installed: pkg.installed,
1583
+ enabled: pkg.enabled,
1584
+ rows: pkg.rows.map(rowRef)
1585
+ };
1586
+ }
1587
+ /**
1588
+ * An official plugin's page: the crumb back to the cards, its icon with the
1589
+ * contributed actions, its title with the contributed badges over its
1590
+ * one-liner, the form the entry renders, and the contributed sections.
1591
+ */
1592
+ function ItemDetail({ item, t, onBack, renderSlot, form }) {
1593
+ const subject = {
1594
+ kind: "item",
1595
+ id: item.id
1596
+ };
1260
1597
  return (0, react_jsx_runtime.jsxs)("div", {
1261
1598
  className: PluginManagerPage_module_css_default.detail,
1262
1599
  "data-plugin-item-detail": item.id,
@@ -1264,36 +1601,53 @@ window.__ModuleLoader__.load({
1264
1601
  (0, react_jsx_runtime.jsx)(DetailTop, {
1265
1602
  crumbLabel: t("backToList"),
1266
1603
  crumbText: t("crumbRoot"),
1267
- onBack
1604
+ onBack,
1605
+ icon: itemArtwork(item.id),
1606
+ actions: (0, react_jsx_runtime.jsx)("div", {
1607
+ className: PluginManagerPage_module_css_default.detailActions,
1608
+ children: renderSlot("plugins.detail.actions", { subject })
1609
+ })
1268
1610
  }),
1269
1611
  (0, react_jsx_runtime.jsxs)("div", {
1270
1612
  className: PluginManagerPage_module_css_default.detailMain,
1271
- children: [(0, react_jsx_runtime.jsx)("div", {
1613
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1272
1614
  className: PluginManagerPage_module_css_default.titleRow,
1273
- children: (0, react_jsx_runtime.jsx)("h3", {
1615
+ children: [(0, react_jsx_runtime.jsx)("h3", {
1274
1616
  className: PluginManagerPage_module_css_default.detailTitle,
1275
1617
  children: item.label
1276
- })
1618
+ }), renderSlot("plugins.detail.badge", { subject })]
1277
1619
  }), (0, react_jsx_runtime.jsx)("p", {
1278
1620
  className: PluginManagerPage_module_css_default.detailDesc,
1279
1621
  children: renderSlot("plugins.item", { view: "summary" }, { only: item.id })
1280
1622
  })]
1281
1623
  }),
1282
- (0, react_jsx_runtime.jsx)("div", {
1624
+ (0, react_jsx_runtime.jsxs)("div", {
1283
1625
  className: PluginManagerPage_module_css_default.detailSections,
1284
- "data-plugin-config": true,
1285
- children: renderSlot("plugins.item", { view: "page" }, { only: item.id })
1626
+ children: [(0, react_jsx_runtime.jsx)("section", {
1627
+ className: PluginManagerPage_module_css_default.detailSection,
1628
+ "data-plugin-config": true,
1629
+ children: renderSlot("plugins.item", {
1630
+ view: "page",
1631
+ form
1632
+ }, { only: item.id })
1633
+ }), renderSlot("plugins.detail.section", { subject })]
1286
1634
  })
1287
1635
  ]
1288
1636
  });
1289
1637
  }
1290
1638
  /**
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.
1639
+ * A row's configuration page keeps its technical identity beside local package
1640
+ * text and the form supplied by its configuration entry.
1293
1641
  */
1294
- function RowDetail({ pkg, row, t, onBack, renderSlot }) {
1295
- const { title } = packageText(pkg, t);
1642
+ function RowDetail({ pkg, row, t, resolveText, onBack, renderSlot, form }) {
1643
+ const { title } = packageText(pkg, resolveText);
1644
+ const { title: rowTitle, description } = rowText(row, resolveText);
1296
1645
  const key = rowConfigKey(pkg.name, row.rowId);
1646
+ const subject = {
1647
+ kind: "row",
1648
+ pkg: packageRef(pkg),
1649
+ row: rowRef(row)
1650
+ };
1297
1651
  return (0, react_jsx_runtime.jsxs)("div", {
1298
1652
  className: PluginManagerPage_module_css_default.detail,
1299
1653
  "data-plugin-row-detail": key,
@@ -1302,17 +1656,29 @@ window.__ModuleLoader__.load({
1302
1656
  crumbLabel: t("backToPackage", { name: title }),
1303
1657
  crumbText: title,
1304
1658
  onBack,
1305
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCordisPluginOutline14, { size: 20 })
1659
+ icon: (0, react_jsx_runtime.jsx)(PackageArtwork, {
1660
+ src: row.meta?.icon,
1661
+ row: true,
1662
+ size: CARD_ARTWORK_SIZE
1663
+ }, row.meta?.icon),
1664
+ actions: (0, react_jsx_runtime.jsx)("div", {
1665
+ className: PluginManagerPage_module_css_default.detailActions,
1666
+ children: renderSlot("plugins.detail.actions", { subject })
1667
+ })
1306
1668
  }),
1307
1669
  (0, react_jsx_runtime.jsxs)("div", {
1308
1670
  className: PluginManagerPage_module_css_default.detailMain,
1309
1671
  children: [
1310
- (0, react_jsx_runtime.jsx)("div", {
1672
+ (0, react_jsx_runtime.jsxs)("div", {
1311
1673
  className: PluginManagerPage_module_css_default.titleRow,
1312
- children: (0, react_jsx_runtime.jsx)("h3", {
1674
+ children: [(0, react_jsx_runtime.jsx)("h3", {
1313
1675
  className: PluginManagerPage_module_css_default.detailTitle,
1314
- children: row.rowId
1315
- })
1676
+ children: rowTitle
1677
+ }), renderSlot("plugins.detail.badge", { subject })]
1678
+ }),
1679
+ rowTitle === row.rowId ? null : (0, react_jsx_runtime.jsx)("p", {
1680
+ className: PluginManagerPage_module_css_default.detailName,
1681
+ children: (0, react_jsx_runtime.jsx)("code", { children: row.rowId })
1316
1682
  }),
1317
1683
  (0, react_jsx_runtime.jsx)("p", {
1318
1684
  className: PluginManagerPage_module_css_default.detailName,
@@ -1320,14 +1686,21 @@ window.__ModuleLoader__.load({
1320
1686
  }),
1321
1687
  (0, react_jsx_runtime.jsx)("p", {
1322
1688
  className: PluginManagerPage_module_css_default.detailDesc,
1323
- children: renderSlot("plugins.row.config", { view: "summary" }, { entryKey: key })
1689
+ children: description ?? renderSlot("plugins.row.config", { view: "summary" }, { entryKey: key })
1324
1690
  })
1325
1691
  ]
1326
1692
  }),
1327
- (0, react_jsx_runtime.jsx)("div", {
1693
+ (0, react_jsx_runtime.jsx)(MetadataError, {
1694
+ error: row.meta?.error,
1695
+ t
1696
+ }),
1697
+ (0, react_jsx_runtime.jsxs)("div", {
1328
1698
  className: PluginManagerPage_module_css_default.detailSections,
1329
1699
  "data-plugin-config": true,
1330
- children: renderSlot("plugins.row.config", { view: "page" }, { entryKey: key })
1700
+ children: [renderSlot("plugins.row.config", {
1701
+ view: "page",
1702
+ form
1703
+ }, { entryKey: key }), renderSlot("plugins.detail.section", { subject })]
1331
1704
  })
1332
1705
  ]
1333
1706
  });
@@ -1340,9 +1713,13 @@ window.__ModuleLoader__.load({
1340
1713
  * problem when it reports one; the configuration the bundle registered for
1341
1714
  * itself; and its rows with their switches and configure controls.
1342
1715
  */
1343
- function PackageDetail({ pkg, t, busy, rowBusy, configured, configure, renderSlot, onBack, onSetEnabled, onUninstall, onSetRowEnabled }) {
1344
- const { title, description, beta } = packageText(pkg, t);
1716
+ function PackageDetail({ pkg, t, resolveText, busy, rowBusy, configured, configure, renderSlot, onBack, onSetEnabled, onUninstall, onSetRowEnabled }) {
1717
+ const { title, description, beta } = packageText(pkg, resolveText);
1345
1718
  const status = packageStatus(pkg);
1719
+ const subject = {
1720
+ kind: "bundle",
1721
+ pkg: packageRef(pkg)
1722
+ };
1346
1723
  return (0, react_jsx_runtime.jsxs)("div", {
1347
1724
  className: PluginManagerPage_module_css_default.detail,
1348
1725
  "data-plugin-detail": pkg.name,
@@ -1351,24 +1728,29 @@ window.__ModuleLoader__.load({
1351
1728
  crumbLabel: t("backToList"),
1352
1729
  crumbText: t("crumbRoot"),
1353
1730
  onBack,
1731
+ icon: (0, react_jsx_runtime.jsx)(PackageArtwork, { src: pkg.meta?.icon }, pkg.meta?.icon),
1354
1732
  actions: (0, react_jsx_runtime.jsxs)("div", {
1355
1733
  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
- })]
1734
+ children: [
1735
+ renderSlot("plugins.detail.actions", { subject }),
1736
+ pkg.installed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1737
+ variant: "outline",
1738
+ size: "sm",
1739
+ className: PluginManagerPage_module_css_default.danger,
1740
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 13 }),
1741
+ "aria-label": t("uninstallLabel", { name: title }),
1742
+ disabled: busy || pkg.readOnlyReason !== void 0,
1743
+ onClick: onUninstall,
1744
+ children: t("uninstall")
1745
+ }) : null,
1746
+ (0, react_jsx_runtime.jsx)(EnableSwitch, {
1747
+ pkg,
1748
+ title,
1749
+ t,
1750
+ busy,
1751
+ onSetEnabled
1752
+ })
1753
+ ]
1372
1754
  })
1373
1755
  }),
1374
1756
  (0, react_jsx_runtime.jsxs)("div", {
@@ -1395,7 +1777,8 @@ window.__ModuleLoader__.load({
1395
1777
  className: PluginManagerPage_module_css_default.statusTag,
1396
1778
  tone: "danger",
1397
1779
  children: t("statusProblem")
1398
- }) : null
1780
+ }) : null,
1781
+ renderSlot("plugins.detail.badge", { subject })
1399
1782
  ]
1400
1783
  }),
1401
1784
  (0, react_jsx_runtime.jsx)("p", {
@@ -1405,12 +1788,16 @@ window.__ModuleLoader__.load({
1405
1788
  children: pkg.name
1406
1789
  })
1407
1790
  }),
1408
- (0, react_jsx_runtime.jsx)("p", {
1791
+ description === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
1409
1792
  className: PluginManagerPage_module_css_default.detailDesc,
1410
- children: description ?? t("noDescription")
1793
+ children: description
1411
1794
  })
1412
1795
  ]
1413
1796
  }),
1797
+ (0, react_jsx_runtime.jsx)(MetadataError, {
1798
+ error: pkg.meta?.error,
1799
+ t
1800
+ }),
1414
1801
  pkg.error === void 0 ? null : (0, react_jsx_runtime.jsxs)("p", {
1415
1802
  className: PluginManagerPage_module_css_default.reason,
1416
1803
  role: "status",
@@ -1427,19 +1814,24 @@ window.__ModuleLoader__.load({
1427
1814
  }),
1428
1815
  (0, react_jsx_runtime.jsxs)("div", {
1429
1816
  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
- })]
1817
+ children: [
1818
+ configured ? (0, react_jsx_runtime.jsx)("section", {
1819
+ className: PluginManagerPage_module_css_default.detailSection,
1820
+ "data-plugin-config": true,
1821
+ children: renderSlot("plugins.bundle.config", { view: "page" }, { entryKey: pkg.name })
1822
+ }) : null,
1823
+ (0, react_jsx_runtime.jsx)(RowsSection, {
1824
+ rows: pkg.rows,
1825
+ t,
1826
+ resolveText,
1827
+ toggle: pkg.enabled ? {
1828
+ busy: (row) => busy || rowBusy(row),
1829
+ onSetEnabled: onSetRowEnabled
1830
+ } : void 0,
1831
+ configure
1832
+ }),
1833
+ renderSlot("plugins.detail.section", { subject })
1834
+ ]
1443
1835
  })
1444
1836
  ]
1445
1837
  });
@@ -1515,6 +1907,8 @@ window.__ModuleLoader__.load({
1515
1907
  running: "installingTitle",
1516
1908
  cancelling: "installCancelling",
1517
1909
  applying: "installApplying",
1910
+ unconfirmed: "installUnconfirmedTitle",
1911
+ unknown: "installUnknownTitle",
1518
1912
  done: "installedTitle",
1519
1913
  failed: "installFailedTitle"
1520
1914
  };
@@ -1525,13 +1919,31 @@ window.__ModuleLoader__.load({
1525
1919
  git: "installSubjectGit",
1526
1920
  tarball: "installSubjectTarball"
1527
1921
  };
1922
+ /** The registries asked, by name, in the dictionary's list form. */
1923
+ function registryList(registries, t, resolved) {
1924
+ return registries.map((registry) => registryText(registry, t, resolved).name).join(t("registryListSeparator"));
1925
+ }
1926
+ /** An option's label: the registry's name with the host it names, unless the host is the name. */
1927
+ function registryOption(registry, t, resolved) {
1928
+ const { name, host } = registryText(registry, t, resolved);
1929
+ return name === host ? name : t("registryWithHost", {
1930
+ name,
1931
+ host
1932
+ });
1933
+ }
1528
1934
  /**
1529
1935
  * The failed screen's one line: a pnpm failure by its kind, a refusal by its
1530
1936
  * code, any other failure in the Host's words; the run's output stays behind the details.
1937
+ * A run the Host laid at the spec's own host says so; one it laid at a registry
1938
+ * names every registry asked when there were several.
1531
1939
  */
1532
- function failureText(failure, t) {
1940
+ function failureText(failure, t, install) {
1533
1941
  if (failure === null) return t("installFailureGeneric");
1534
1942
  if (failure.kind === "build-blocked" && !failure.pendingBuilds?.length) return t("installFailureBuildBlockedManual");
1943
+ const host = install?.subject?.host;
1944
+ if (failure.failedAt === "spec-host" && host !== void 0) return t("installFailureNetworkHost", { host });
1945
+ const asked = install?.attempts?.registries ?? [];
1946
+ 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
1947
  if (failure.kind !== void 0) return t(FAILURE_KIND_KEYS[failure.kind]);
1536
1948
  if (failure.code !== void 0) return managementText({
1537
1949
  code: failure.code,
@@ -1568,15 +1980,47 @@ window.__ModuleLoader__.load({
1568
1980
  * and failed screens over the same subject card. A failed run that left
1569
1981
  * install scripts undecided shows them for approval in place of plain retry.
1570
1982
  */
1571
- function InstallDialog({ install, t, onClose, onEditSpec, onRun, onCancel, onCancelAndClose, onToggleDetails, onEnableNow, onApproveBuilds }) {
1983
+ function InstallDialog({ install, t, onClose, onEditSpec, onRun, onCancel, onReconcile, onToggleDetails, onEnableNow, onApproveBuilds, onToggleRegistry, onChooseRegistry, onChangeRegistry }) {
1572
1984
  const errorId = (0, react.useId)();
1573
1985
  const guideId = (0, react.useId)();
1574
1986
  const approvalId = (0, react.useId)();
1987
+ const registryId = (0, react.useId)();
1988
+ const registryErrorId = (0, react.useId)();
1575
1989
  const [guideOpen, setGuideOpen] = (0, react.useState)(false);
1576
1990
  const { phase } = install;
1991
+ const registryToggleRef = (0, react.useRef)(null);
1992
+ const registryPanelRef = (0, react.useRef)(null);
1993
+ const registryShown = install.registryOpen && phase === "idle";
1994
+ const registryPosition = (0, _deepseek_ai_dsh_client_ui_primitives.useAnchoredPosition)({
1995
+ open: registryShown,
1996
+ anchorRef: registryToggleRef,
1997
+ panelRef: registryPanelRef,
1998
+ align: "end",
1999
+ gap: 6,
2000
+ margin: 12
2001
+ });
2002
+ (0, _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer)(registryToggleRef, registryShown, onToggleRegistry, registryPanelRef);
2003
+ (0, react.useEffect)(() => {
2004
+ if (!registryShown) return;
2005
+ const onKeyDown = (event) => {
2006
+ if (event.key !== "Escape") return;
2007
+ event.stopPropagation();
2008
+ onToggleRegistry();
2009
+ };
2010
+ document.addEventListener("keydown", onKeyDown, true);
2011
+ return () => {
2012
+ document.removeEventListener("keydown", onKeyDown, true);
2013
+ };
2014
+ }, [registryShown, onToggleRegistry]);
1577
2015
  if (phase === "idle" || phase === "checking") {
1578
2016
  const checking = phase === "checking";
1579
2017
  const empty = install.spec.trim() === "";
2018
+ const choice = install.registry;
2019
+ const resolved = install.registries?.resolved ?? null;
2020
+ const chosenTitle = choice.kind === "custom" ? t("registryCustom") : registryText(choice.registry, t, resolved).name;
2021
+ const inputProblem = install.inputError;
2022
+ const askedByCheck = inputProblem?.registries ?? [];
2023
+ 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
2024
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1581
2025
  open: install.open,
1582
2026
  onClose,
@@ -1584,27 +2028,26 @@ window.__ModuleLoader__.load({
1584
2028
  closeLabel: t("close"),
1585
2029
  description: t("installDescription"),
1586
2030
  className: PluginManagerPage_module_css_default.installDialog,
2031
+ contentClassName: PluginManagerPage_module_css_default.installContent,
1587
2032
  footer: (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1588
2033
  variant: "primary",
1589
2034
  className: PluginManagerPage_module_css_default.wide,
1590
2035
  disabled: checking || empty,
1591
2036
  "aria-busy": checking,
1592
2037
  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")]
2038
+ children: [checking ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" }) : null, t(checking ? "installChecking" : "installRun")]
1597
2039
  }),
1598
2040
  children: (0, react_jsx_runtime.jsxs)("div", {
1599
2041
  className: PluginManagerPage_module_css_default.installBody,
1600
2042
  children: [
1601
- (0, react_jsx_runtime.jsxs)("label", {
2043
+ (0, react_jsx_runtime.jsx)("div", {
1602
2044
  className: PluginManagerPage_module_css_default.installField,
1603
- children: [(0, react_jsx_runtime.jsx)("span", { children: t("installSpecLabel") }), (0, react_jsx_runtime.jsx)("input", {
2045
+ children: (0, react_jsx_runtime.jsx)("input", {
1604
2046
  type: "text",
1605
2047
  value: install.spec,
1606
2048
  placeholder: t("installSpecPlaceholder"),
1607
2049
  disabled: checking,
2050
+ "aria-label": t("installSpecLabel"),
1608
2051
  "aria-invalid": install.inputError !== null,
1609
2052
  "aria-describedby": install.inputError === null ? void 0 : errorId,
1610
2053
  onChange: (event) => {
@@ -1613,104 +2056,219 @@ window.__ModuleLoader__.load({
1613
2056
  onKeyDown: (event) => {
1614
2057
  if (event.key === "Enter" && !empty && !checking) onRun();
1615
2058
  }
1616
- })]
2059
+ })
1617
2060
  }),
1618
- install.inputError === null ? null : (0, react_jsx_runtime.jsx)("p", {
2061
+ inputSentence === null ? null : (0, react_jsx_runtime.jsx)("p", {
1619
2062
  id: errorId,
1620
2063
  className: PluginManagerPage_module_css_default.inputError,
1621
2064
  role: "alert",
1622
- children: t(INPUT_PROBLEM_KEYS[install.inputError.problem], { reason: install.inputError.reason })
2065
+ children: inputSentence
1623
2066
  }),
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") })]
2067
+ (0, react_jsx_runtime.jsxs)("div", {
2068
+ className: PluginManagerPage_module_css_default.optionsRow,
2069
+ children: [(0, react_jsx_runtime.jsxs)("button", {
2070
+ type: "button",
2071
+ className: PluginManagerPage_module_css_default.guideToggle,
2072
+ "aria-expanded": guideOpen,
2073
+ "aria-controls": guideId,
2074
+ onClick: () => {
2075
+ setGuideOpen((open) => !open);
2076
+ },
2077
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
2078
+ className: PluginManagerPage_module_css_default.guideChevron,
2079
+ "aria-hidden": "true"
2080
+ }), (0, react_jsx_runtime.jsx)("span", { children: t(guideOpen ? "installGuideHide" : "installGuideToggle") })]
2081
+ }), (0, react_jsx_runtime.jsxs)("button", {
2082
+ ref: registryToggleRef,
2083
+ type: "button",
2084
+ className: PluginManagerPage_module_css_default.registryToggle,
2085
+ "aria-expanded": install.registryOpen,
2086
+ "aria-controls": registryId,
2087
+ "aria-haspopup": "dialog",
2088
+ disabled: checking,
2089
+ onClick: onToggleRegistry,
2090
+ children: [
2091
+ (0, react_jsx_runtime.jsx)("span", { children: t("registryToggle") }),
2092
+ " ",
2093
+ (0, react_jsx_runtime.jsx)("span", {
2094
+ className: PluginManagerPage_module_css_default.registryChosen,
2095
+ children: chosenTitle
2096
+ }),
2097
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
2098
+ className: PluginManagerPage_module_css_default.guideChevron,
2099
+ "aria-hidden": "true"
2100
+ })
2101
+ ]
2102
+ })]
1636
2103
  }),
1637
2104
  guideOpen ? (0, react_jsx_runtime.jsxs)("div", {
1638
2105
  id: guideId,
1639
2106
  className: PluginManagerPage_module_css_default.guide,
1640
2107
  "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
2108
+ children: [(0, react_jsx_runtime.jsx)("ol", {
2109
+ className: PluginManagerPage_module_css_default.guideList,
2110
+ children: GUIDE_EXAMPLES.map(({ key, titleKey, exampleKey, hintKey }, index) => (0, react_jsx_runtime.jsxs)("li", {
2111
+ className: PluginManagerPage_module_css_default.guideItem,
2112
+ children: [
2113
+ (0, react_jsx_runtime.jsx)("span", {
2114
+ className: PluginManagerPage_module_css_default.guideIndex,
2115
+ "aria-hidden": "true",
2116
+ children: index + 1
2117
+ }),
2118
+ (0, react_jsx_runtime.jsxs)("div", {
2119
+ className: PluginManagerPage_module_css_default.guideMain,
2120
+ children: [
2121
+ (0, react_jsx_runtime.jsx)("span", {
2122
+ className: PluginManagerPage_module_css_default.guideTitle,
2123
+ children: t(titleKey)
2124
+ }),
2125
+ (0, react_jsx_runtime.jsx)("span", {
2126
+ className: PluginManagerPage_module_css_default.guideHint,
2127
+ children: t(hintKey)
2128
+ }),
2129
+ (0, react_jsx_runtime.jsxs)("span", {
2130
+ className: PluginManagerPage_module_css_default.guideExample,
2131
+ children: [(0, react_jsx_runtime.jsx)("span", {
2132
+ className: PluginManagerPage_module_css_default.guideExampleLabel,
2133
+ children: t("installGuideExampleLabel")
2134
+ }), (0, react_jsx_runtime.jsx)("code", { children: t(exampleKey) })]
2135
+ })
2136
+ ]
2137
+ }),
2138
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2139
+ variant: "outline",
2140
+ size: "sm",
2141
+ "aria-label": t("installGuideFillAria", { example: t(exampleKey) }),
2142
+ disabled: checking,
2143
+ onClick: () => {
2144
+ onEditSpec(t(exampleKey));
2145
+ },
2146
+ children: t("installGuideFill")
2147
+ })
2148
+ ]
2149
+ }, key))
2150
+ }), (0, react_jsx_runtime.jsxs)("p", {
2151
+ className: PluginManagerPage_module_css_default.guideSafety,
2152
+ role: "note",
2153
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {
2154
+ size: 14,
2155
+ "aria-hidden": "true"
2156
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("installGuideSafety") })]
2157
+ })]
2158
+ }) : null,
2159
+ registryShown ? (0, react_dom.createPortal)((0, react_jsx_runtime.jsxs)("fieldset", {
2160
+ ref: registryPanelRef,
2161
+ id: registryId,
2162
+ className: PluginManagerPage_module_css_default.registry,
2163
+ style: registryPosition ?? {
2164
+ visibility: "hidden",
2165
+ left: 0,
2166
+ top: 0
2167
+ },
2168
+ "data-install-registry": true,
2169
+ "aria-label": t("registryLegend"),
2170
+ children: [offeredRegistries(install.registries).map((registry) => {
2171
+ const checked = choice.kind === "offered" && choice.registry === registry;
2172
+ return (0, react_jsx_runtime.jsxs)("label", {
2173
+ className: PluginManagerPage_module_css_default.registryOption,
2174
+ "data-checked": checked,
2175
+ children: [(0, react_jsx_runtime.jsx)("input", {
2176
+ type: "radio",
2177
+ name: registryId,
2178
+ checked,
2179
+ onChange: () => {
2180
+ onChooseRegistry({
2181
+ kind: "offered",
2182
+ registry
2183
+ });
2184
+ }
2185
+ }), (0, react_jsx_runtime.jsx)("span", {
2186
+ className: PluginManagerPage_module_css_default.registryTitle,
2187
+ children: (0, react_jsx_runtime.jsx)("span", { children: registryOption(registry, t, resolved) })
2188
+ })]
2189
+ }, registry ?? "");
2190
+ }), (0, react_jsx_runtime.jsxs)("div", {
2191
+ className: PluginManagerPage_module_css_default.registryOption,
2192
+ "data-checked": choice.kind === "custom",
2193
+ children: [
2194
+ (0, react_jsx_runtime.jsxs)("label", {
2195
+ className: PluginManagerPage_module_css_default.registryCustomPick,
2196
+ children: [(0, react_jsx_runtime.jsx)("input", {
2197
+ type: "radio",
2198
+ name: registryId,
2199
+ checked: choice.kind === "custom",
2200
+ onChange: () => {
2201
+ onChooseRegistry({
2202
+ kind: "custom",
2203
+ url: ""
2204
+ });
2205
+ }
2206
+ }), (0, react_jsx_runtime.jsx)("span", {
2207
+ className: PluginManagerPage_module_css_default.registryTitle,
2208
+ children: (0, react_jsx_runtime.jsx)("span", { children: t("registryCustom") })
2209
+ })]
2210
+ }),
2211
+ (0, react_jsx_runtime.jsx)("input", {
2212
+ type: "text",
2213
+ className: PluginManagerPage_module_css_default.registryCustomField,
2214
+ "aria-label": t("registryCustom"),
2215
+ placeholder: t("registryCustomPlaceholder"),
2216
+ value: choice.kind === "custom" ? choice.url : "",
2217
+ disabled: choice.kind !== "custom",
2218
+ "aria-invalid": install.registryError,
2219
+ "aria-describedby": install.registryError ? registryErrorId : void 0,
2220
+ onChange: (event) => {
2221
+ onChooseRegistry({
2222
+ kind: "custom",
2223
+ url: event.currentTarget.value
2224
+ });
2225
+ },
2226
+ onKeyDown: (event) => {
2227
+ if (event.key === "Enter" && !empty) onRun();
2228
+ }
2229
+ }),
2230
+ install.registryError ? (0, react_jsx_runtime.jsx)("p", {
2231
+ id: registryErrorId,
2232
+ className: PluginManagerPage_module_css_default.inputError,
2233
+ role: "alert",
2234
+ children: t("registryCustomInvalid")
2235
+ }) : null,
2236
+ (0, react_jsx_runtime.jsx)("span", {
2237
+ className: PluginManagerPage_module_css_default.registryHint,
2238
+ children: t("registryCustomHint")
2239
+ })
2240
+ ]
2241
+ })]
2242
+ }), document.body) : null
1703
2243
  ]
1704
2244
  })
1705
2245
  });
1706
2246
  }
1707
2247
  const heading = t(SCREEN_TITLE_KEYS[phase]);
1708
2248
  const pending = isInstallPending(phase);
1709
- const stoppable = phase === "running" || phase === "failed";
1710
- const unconfirmed = install.failure?.cancelUnconfirmed === true ? install.failure.reason : void 0;
2249
+ const cancellable = phase === "starting" || phase === "running" || phase === "unconfirmed";
2250
+ const stoppable = cancellable || phase === "failed" || phase === "unknown";
2251
+ const failure = install.failure;
2252
+ const uncertainty = failure?.uncertainty;
2253
+ const uncertaintyText = failure?.uncertainty === void 0 ? null : t({
2254
+ result: "installResultUnconfirmed",
2255
+ cancellation: phase === "applying" ? "installApplyingCancellationError" : "installCancelUnconfirmed",
2256
+ acceptance: "installAwaitingAcceptance"
2257
+ }[failure.uncertainty], { reason: failure.reason });
1711
2258
  const pendingBuilds = phase === "failed" ? install.failure?.pendingBuilds ?? [] : [];
1712
2259
  const approvable = pendingBuilds.length > 0;
1713
2260
  const firstRun = install.runs[0];
2261
+ const asked = install.attempts !== null && install.attempts.registries.length > 1 ? install.attempts : null;
2262
+ const current = asked === null ? void 0 : asked.registries.at(-1);
2263
+ const previous = asked === null ? void 0 : asked.registries.at(-2);
2264
+ const resolved = install.registries?.resolved ?? null;
2265
+ const attemptLine = pending && asked !== null && current !== void 0 && previous !== void 0 ? t("installAttempt", {
2266
+ previous: registryText(previous, t, resolved).name,
2267
+ registry: registryText(current, t, resolved).name,
2268
+ index: String(asked.registries.length),
2269
+ total: String(asked.total)
2270
+ }) : null;
2271
+ const changeable = phase === "failed" && !approvable && install.failure?.failedAt === "registry";
1714
2272
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1715
2273
  open: install.open,
1716
2274
  onClose,
@@ -1725,17 +2283,16 @@ window.__ModuleLoader__.load({
1725
2283
  children: [phase === "done" ? (0, react_jsx_runtime.jsx)("span", {}) : (0, react_jsx_runtime.jsxs)("button", {
1726
2284
  type: "button",
1727
2285
  className: PluginManagerPage_module_css_default.wizardBack,
1728
- "aria-label": t("installEditAria"),
2286
+ "aria-label": t(pending ? "installCancelAndEdit" : "installEditAria"),
1729
2287
  disabled: !stoppable,
1730
2288
  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") })]
2289
+ 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
2290
  }), (0, react_jsx_runtime.jsx)("button", {
1733
2291
  type: "button",
1734
2292
  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 })
2293
+ "aria-label": t(cancellable ? "installCloseCancels" : "close"),
2294
+ onClick: onClose,
2295
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineMedium, { size: 14 })
1739
2296
  })]
1740
2297
  }), (0, react_jsx_runtime.jsxs)("div", {
1741
2298
  className: PluginManagerPage_module_css_default.wizardScroll,
@@ -1745,9 +2302,12 @@ window.__ModuleLoader__.load({
1745
2302
  children: [
1746
2303
  (0, react_jsx_runtime.jsx)("span", {
1747
2304
  className: PluginManagerPage_module_css_default.wizardIcon,
1748
- "data-tone": pending ? "pending" : phase,
2305
+ "data-state": pending ? "ongoing" : phase === "done" ? "done" : "error",
1749
2306
  "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 })
2307
+ children: pending ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
2308
+ state: "ongoing",
2309
+ size: 28
2310
+ }) : 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
2311
  }),
1752
2312
  (0, react_jsx_runtime.jsx)("h2", {
1753
2313
  className: PluginManagerPage_module_css_default.wizardTitle,
@@ -1756,13 +2316,21 @@ window.__ModuleLoader__.load({
1756
2316
  }),
1757
2317
  phase === "failed" ? (0, react_jsx_runtime.jsx)("p", {
1758
2318
  className: PluginManagerPage_module_css_default.wizardSub,
1759
- children: failureText(install.failure, t)
2319
+ children: failureText(install.failure, t, install)
1760
2320
  }) : null,
1761
- unconfirmed === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
2321
+ attemptLine === null ? null : (0, react_jsx_runtime.jsx)("p", {
2322
+ className: PluginManagerPage_module_css_default.wizardSub,
2323
+ children: attemptLine
2324
+ }),
2325
+ uncertaintyText === null ? null : (0, react_jsx_runtime.jsx)("p", {
1762
2326
  className: PluginManagerPage_module_css_default.wizardSub,
1763
2327
  role: "alert",
1764
- children: t("installCancelUnconfirmed", { reason: unconfirmed })
1765
- })
2328
+ children: uncertaintyText
2329
+ }),
2330
+ phase === "unknown" ? (0, react_jsx_runtime.jsx)("p", {
2331
+ className: PluginManagerPage_module_css_default.wizardSub,
2332
+ children: t("installUnknownDescription")
2333
+ }) : null
1766
2334
  ]
1767
2335
  }),
1768
2336
  install.subject === null ? null : (0, react_jsx_runtime.jsx)(SubjectCard, {
@@ -1827,23 +2395,41 @@ window.__ModuleLoader__.load({
1827
2395
  className: PluginManagerPage_module_css_default.detailsToggle,
1828
2396
  "aria-expanded": install.detailsOpen,
1829
2397
  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, {
2398
+ 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
2399
  className: PluginManagerPage_module_css_default.detailsChevron,
1832
2400
  "aria-hidden": "true"
1833
2401
  })]
1834
2402
  }),
2403
+ uncertainty === "result" ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2404
+ variant: "outline",
2405
+ size: "sm",
2406
+ className: PluginManagerPage_module_css_default.footAction,
2407
+ onClick: onReconcile,
2408
+ children: t("installReconcile")
2409
+ }) : null,
1835
2410
  pending ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1836
2411
  variant: "outline",
1837
2412
  size: "sm",
1838
- disabled: phase !== "running",
2413
+ className: PluginManagerPage_module_css_default.footAction,
2414
+ disabled: !cancellable,
1839
2415
  onClick: onCancel,
1840
2416
  children: t(phase === "cancelling" ? "installCancelling" : "installCancel")
1841
2417
  }) : 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")
2418
+ phase === "failed" && !approvable ? (0, react_jsx_runtime.jsxs)("span", {
2419
+ className: PluginManagerPage_module_css_default.wizardActions,
2420
+ children: [changeable ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2421
+ variant: "outline",
2422
+ size: "sm",
2423
+ className: PluginManagerPage_module_css_default.footAction,
2424
+ onClick: onChangeRegistry,
2425
+ children: t("installChangeRegistry")
2426
+ }) : null, (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2427
+ variant: "primary",
2428
+ size: "sm",
2429
+ className: PluginManagerPage_module_css_default.footAction,
2430
+ onClick: onRun,
2431
+ children: t("installRetry")
2432
+ })]
1847
2433
  }) : null
1848
2434
  ]
1849
2435
  }),
@@ -1852,18 +2438,30 @@ window.__ModuleLoader__.load({
1852
2438
  children: [(0, react_jsx_runtime.jsx)("p", {
1853
2439
  className: PluginManagerPage_module_css_default.installLocation,
1854
2440
  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))]
2441
+ }), install.runs.map((run, index) => {
2442
+ const registry = asked?.registries[index];
2443
+ return (0, react_jsx_runtime.jsxs)("div", {
2444
+ className: PluginManagerPage_module_css_default.run,
2445
+ children: [registry === void 0 ? null : (0, react_jsx_runtime.jsx)("p", {
2446
+ className: PluginManagerPage_module_css_default.attemptBadge,
2447
+ children: t("installAttemptBadge", {
2448
+ index: String(index + 1),
2449
+ registry: registryText(registry, t, resolved).name
2450
+ })
2451
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
2452
+ command: run.command,
2453
+ output: run.output,
2454
+ running: run.exitCode === void 0,
2455
+ exitCode: run.exitCode,
2456
+ maxLines: INSTALL_TERMINAL_LINES,
2457
+ labels: {
2458
+ ...terminalLabels(t),
2459
+ ...phase === "cancelling" ? { failed: t("installCancelledShort") } : {}
2460
+ },
2461
+ className: PluginManagerPage_module_css_default.terminal
2462
+ })]
2463
+ }, run.jobId);
2464
+ })]
1867
2465
  }) : null,
1868
2466
  phase !== "done" ? null : install.installed !== null ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1869
2467
  variant: "primary",
@@ -1884,8 +2482,7 @@ window.__ModuleLoader__.load({
1884
2482
  });
1885
2483
  }
1886
2484
  /** The confirmation an uninstall waits on. */
1887
- function ConfirmDialog({ confirm, t, onConfirm, onCancel }) {
1888
- const { title: name } = packageText({ name: confirm.packageName }, t);
2485
+ function ConfirmDialog({ name, t, onConfirm, onCancel }) {
1889
2486
  return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1890
2487
  open: true,
1891
2488
  onClose: onCancel,
@@ -1906,10 +2503,20 @@ window.__ModuleLoader__.load({
1906
2503
  }
1907
2504
  /** Render the plugin manager: the official plugins and installed bundles, their pages, the install dialog, and the confirmation. */
1908
2505
  function PluginManagerPage(props) {
1909
- const { t, ensure, renderSlot } = props;
2506
+ const { t, ensure, renderSlot, resolveText } = props;
2507
+ const configurations = props.useConfigurations((snapshot) => snapshot.view?.namespaces);
2508
+ const formFor = (id) => {
2509
+ if (!configurations?.some((view) => view.ns === id)) return void 0;
2510
+ const form = props.configForm(id);
2511
+ return {
2512
+ state: form.getSnapshot(),
2513
+ mutate: (ops, revision) => form.mutate(ops, revision)
2514
+ };
2515
+ };
1910
2516
  const state = props.usePluginManager((snapshot) => snapshot);
1911
2517
  const ledger = props.useConfigLedger((snapshot) => snapshot);
1912
2518
  const [view, setView] = (0, react.useState)({ kind: "list" });
2519
+ const [activation, setActivation] = (0, react.useState)(null);
1913
2520
  (0, react.useEffect)(() => {
1914
2521
  ensure();
1915
2522
  }, [ensure]);
@@ -1938,6 +2545,7 @@ window.__ModuleLoader__.load({
1938
2545
  const openItem = view.kind === "item" ? ledger.items.find((item) => item.id === view.id) : void 0;
1939
2546
  const openRow = view.kind === "row" && openPkg !== void 0 ? openPkg.rows.find((row) => row.rowId === view.rowId) : void 0;
1940
2547
  const showsCards = openPkg === void 0 && openItem === void 0;
2548
+ const activated = listed.find((pkg) => pkg.name === activation && pkg.enabled && !state.busy.includes(pkg.name));
1941
2549
  const setRowEnabled = (row, enabled) => {
1942
2550
  /* v8 ignore next -- a row without a live entry has its switch disabled */
1943
2551
  if (row.entryId !== void 0) props.setRowEnabled(row.entryId, enabled);
@@ -1955,15 +2563,18 @@ window.__ModuleLoader__.load({
1955
2563
  const packageCard = (pkg) => (0, react_jsx_runtime.jsx)(PackageCard, {
1956
2564
  pkg,
1957
2565
  t,
2566
+ resolveText,
1958
2567
  busy: state.busy.includes(pkg.name),
1959
2568
  highlighted: state.highlight === pkg.name,
1960
2569
  onOpen: () => {
2570
+ setActivation(null);
1961
2571
  setView({
1962
2572
  kind: "package",
1963
2573
  name: pkg.name
1964
2574
  });
1965
2575
  },
1966
2576
  onSetEnabled: (enabled) => {
2577
+ setActivation(enabled ? pkg.name : null);
1967
2578
  props.setEnabled(pkg.name, enabled);
1968
2579
  }
1969
2580
  }, pkg.name);
@@ -2022,32 +2633,41 @@ window.__ModuleLoader__.load({
2022
2633
  children: (0, react_jsx_runtime.jsx)("span", {
2023
2634
  className: PluginManagerPage_module_css_default.iconWrap,
2024
2635
  "aria-hidden": "true",
2025
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {})
2636
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, {})
2026
2637
  })
2027
2638
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2028
2639
  variant: "primary",
2029
2640
  size: "sm",
2030
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 13 }),
2641
+ className: PluginManagerPage_module_css_default.addButton,
2642
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 13 }),
2031
2643
  disabled: !loaded,
2032
2644
  onClick: props.openInstall,
2033
- children: t("addPlugin")
2645
+ children: t(state.install.requestId === void 0 ? "addPlugin" : "installViewTask")
2034
2646
  })]
2035
2647
  })]
2036
2648
  }) : null,
2037
- state.status === "loading" ? (0, react_jsx_runtime.jsx)("p", {
2038
- className: PluginManagerPage_module_css_default.status,
2039
- children: t("loading")
2649
+ showsCards && state.status === "loading" ? (0, react_jsx_runtime.jsxs)("p", {
2650
+ className: `${PluginManagerPage_module_css_default.status} ${PluginManagerPage_module_css_default.statusWithDot}`,
2651
+ role: "status",
2652
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" }), t("loading")]
2040
2653
  }) : null,
2041
- state.status === "unavailable" ? (0, react_jsx_runtime.jsx)("p", {
2042
- className: PluginManagerPage_module_css_default.status,
2654
+ showsCards && state.status === "unavailable" ? (0, react_jsx_runtime.jsxs)("p", {
2655
+ className: `${PluginManagerPage_module_css_default.status} ${PluginManagerPage_module_css_default.statusWithDot}`,
2043
2656
  role: "status",
2044
- children: t("unavailable")
2657
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "idle" }), t("unavailable")]
2045
2658
  }) : null,
2046
- state.status === "error" ? (0, react_jsx_runtime.jsxs)("div", {
2659
+ state.notice === null || noticeLine === null ? null : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
2660
+ text: noticeLine,
2661
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
2662
+ holdMs: toastHoldMs(noticeLine),
2663
+ onDone: props.dismissNotice
2664
+ }, state.notice.seq),
2665
+ !showsCards && state.status === "error" ? (0, react_jsx_runtime.jsxs)("div", {
2047
2666
  className: PluginManagerPage_module_css_default.failure,
2048
- children: [(0, react_jsx_runtime.jsx)("p", {
2667
+ children: [(0, react_jsx_runtime.jsxs)("p", {
2668
+ className: PluginManagerPage_module_css_default.statusWithDot,
2049
2669
  role: "alert",
2050
- children: t("error")
2670
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }), t("error")]
2051
2671
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2052
2672
  variant: "outline",
2053
2673
  size: "sm",
@@ -2055,16 +2675,12 @@ window.__ModuleLoader__.load({
2055
2675
  children: t("retry")
2056
2676
  })]
2057
2677
  }) : 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
2678
  loaded && openPkg !== void 0 && openRow !== void 0 ? (0, react_jsx_runtime.jsx)(RowDetail, {
2065
2679
  pkg: openPkg,
2066
2680
  row: openRow,
2681
+ form: formFor(openRow.rowId),
2067
2682
  t,
2683
+ resolveText,
2068
2684
  renderSlot,
2069
2685
  onBack: () => {
2070
2686
  setView({
@@ -2076,6 +2692,7 @@ window.__ModuleLoader__.load({
2076
2692
  loaded && openPkg !== void 0 && openRow === void 0 ? (0, react_jsx_runtime.jsx)(PackageDetail, {
2077
2693
  pkg: openPkg,
2078
2694
  t,
2695
+ resolveText,
2079
2696
  busy: state.busy.includes(openPkg.name),
2080
2697
  rowBusy: (row) => row.entryId !== void 0 && state.busy.includes(rowKey(row.entryId)),
2081
2698
  configured: ledger.bundles.has(openPkg.name),
@@ -2093,6 +2710,7 @@ window.__ModuleLoader__.load({
2093
2710
  onSetRowEnabled: setRowEnabled
2094
2711
  }) : null,
2095
2712
  loaded && openItem !== void 0 ? (0, react_jsx_runtime.jsx)(ItemDetail, {
2713
+ form: formFor(openItem.id),
2096
2714
  item: openItem,
2097
2715
  t,
2098
2716
  renderSlot,
@@ -2100,10 +2718,39 @@ window.__ModuleLoader__.load({
2100
2718
  setView({ kind: "list" });
2101
2719
  }
2102
2720
  }) : null,
2103
- loaded && showsCards ? officialCards.length === 0 && mine.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
2721
+ loaded && showsCards ? officialCards.length === 0 && mine.length === 0 && state.status !== "error" ? (0, react_jsx_runtime.jsx)("p", {
2104
2722
  className: PluginManagerPage_module_css_default.empty,
2105
2723
  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,
2724
+ }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2725
+ renderGroup("official", t("officialTitle"), officialCards),
2726
+ renderGroup("bundles", t("bundlesTitle"), mine.map(packageCard)),
2727
+ state.status === "error" ? (0, react_jsx_runtime.jsxs)("div", {
2728
+ className: PluginManagerPage_module_css_default.failure,
2729
+ children: [(0, react_jsx_runtime.jsxs)("p", {
2730
+ className: PluginManagerPage_module_css_default.statusWithDot,
2731
+ role: "alert",
2732
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }), t("error")]
2733
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2734
+ variant: "outline",
2735
+ size: "sm",
2736
+ onClick: props.refresh,
2737
+ children: t("retry")
2738
+ })]
2739
+ }) : null
2740
+ ] }) : null,
2741
+ showsCards && activated !== void 0 && !state.install.open ? renderSlot("plugins.bundle.activation", {
2742
+ packageName: activated.name,
2743
+ onDismiss: () => {
2744
+ setActivation(null);
2745
+ },
2746
+ onOpenDetails: () => {
2747
+ setActivation(null);
2748
+ setView({
2749
+ kind: "package",
2750
+ name: activated.name
2751
+ });
2752
+ }
2753
+ }, { entryKey: activated.name }) : null,
2107
2754
  (0, react_jsx_runtime.jsx)(InstallDialog, {
2108
2755
  install: state.install,
2109
2756
  t,
@@ -2111,13 +2758,19 @@ window.__ModuleLoader__.load({
2111
2758
  onEditSpec: props.editInstallSpec,
2112
2759
  onRun: props.runInstall,
2113
2760
  onCancel: props.cancelInstall,
2114
- onCancelAndClose: props.cancelInstallAndClose,
2761
+ onReconcile: props.reconcileInstall,
2115
2762
  onToggleDetails: props.toggleInstallDetails,
2116
- onEnableNow: props.enableInstalled,
2117
- onApproveBuilds: props.approveBuildsAndRetry
2763
+ onEnableNow: () => {
2764
+ setActivation(state.install.installed);
2765
+ props.enableInstalled();
2766
+ },
2767
+ onApproveBuilds: props.approveBuildsAndRetry,
2768
+ onToggleRegistry: props.toggleRegistryOptions,
2769
+ onChooseRegistry: props.chooseRegistry,
2770
+ onChangeRegistry: props.changeRegistry
2118
2771
  }),
2119
2772
  state.confirm === null ? null : (0, react_jsx_runtime.jsx)(ConfirmDialog, {
2120
- confirm: state.confirm,
2773
+ name: packageText(state.packages.find((pkg) => pkg.name === state.confirm?.packageName) ?? { name: state.confirm.packageName }, resolveText).title,
2121
2774
  t,
2122
2775
  onConfirm: props.confirm,
2123
2776
  onCancel: props.cancelConfirm
@@ -2133,18 +2786,18 @@ window.__ModuleLoader__.load({
2133
2786
  * @returns the icon element.
2134
2787
  */
2135
2788
  function PluginsPanelIcon({ size }) {
2136
- return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutline16, { size });
2789
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPluginPinwheelOutlineRegular, { size });
2137
2790
  }
2138
2791
  //#endregion
2139
2792
  //#region lib/types/client/locales.js
2140
- /** Plugin management copy and display names of shipped global rows. */
2793
+ /** Plugin management interface copy. */
2141
2794
  /** Simplified Chinese dictionary and key source of truth. */
2142
2795
  const zh = {
2143
2796
  panel: "插件",
2144
2797
  title: "插件",
2145
2798
  intro: "添加和管理插件",
2146
2799
  loading: "正在读取插件…",
2147
- error: "暂时无法读取插件。",
2800
+ error: "可能由于网络问题,无法读取全部插件",
2148
2801
  unavailable: "本部署没有可管理的 profile,无法安装或启停插件。",
2149
2802
  retry: "重试",
2150
2803
  refresh: "刷新",
@@ -2154,17 +2807,11 @@ window.__ModuleLoader__.load({
2154
2807
  overriddenNotice: "{name} 已保存,但被更高优先级的配置覆盖,当前未生效",
2155
2808
  bundlesTitle: "已安装",
2156
2809
  officialTitle: "官方",
2157
- builtinAgentTeamTitle: "智能体团队",
2158
- builtinAgentTeamDescription: "启用智能体团队协作与团队工具。",
2159
- builtinAgentTeamWebTitle: "智能体团队 Web 界面",
2160
- builtinAgentTeamWebDescription: "在浏览器中查看团队成员、任务看板和成员会话。",
2161
- builtinAutoReviewTitle: "自动授权审查",
2162
- builtinAutoReviewDescription: "提供自动审查权限模式,由模型在每次工具调用前判断是否授权。",
2163
2810
  statusProblem: "异常",
2164
2811
  statusBeta: "Beta",
2165
2812
  reasonLabel: "原因",
2813
+ metadataError: "包元信息错误:{error}",
2166
2814
  versionTag: "v{version}",
2167
- noDescription: "暂无描述。",
2168
2815
  partsLabel: "包含的组件",
2169
2816
  partsEmpty: "这个插件包不包含任何组件。",
2170
2817
  partsCountTotal: "共 {count} 个",
@@ -2193,13 +2840,11 @@ window.__ModuleLoader__.load({
2193
2840
  installDescription: "输入插件的包名、GitHub 仓库地址或本地目录路径。",
2194
2841
  installSpecLabel: "包名或地址",
2195
2842
  installSpecPlaceholder: "例如 @deepseek-ai/dsh-experimental-auto-review",
2196
- installGuideToggle: "不知道该填什么?",
2843
+ installGuideToggle: "插件安装引导和示例",
2197
2844
  installGuideHide: "收起引导",
2198
- installGuideIntro: "从插件的 README 或发布页面复制以下任意一项。",
2199
- installGuideIdNote: "包名即 npm 包名,常见形式为 dsh-xxx 或 @作者/插件名;插件的显示名称不是包名。",
2200
2845
  installGuideIdTitle: "包名",
2201
2846
  installGuideIdExample: "@deepseek-ai/dsh-experimental-auto-review",
2202
- installGuideIdHint: "README 安装命令中 dsh plugin add 或 pnpm add 之后的部分。",
2847
+ installGuideIdHint: "插件包名即 npm 包名(如 dsh-xxx 或 @作者/插件名),社区插件的 README 安装命令中 dsh plugin add 或 pnpm add 之后的部分。",
2203
2848
  installGuideGitTitle: "GitHub 仓库地址",
2204
2849
  installGuideGitExample: "https://github.com/author/dsh-plugin",
2205
2850
  installGuideGitHint: "插件在 GitHub 上的开源仓库地址,也支持其他 Git 仓库。",
@@ -2210,6 +2855,16 @@ window.__ModuleLoader__.load({
2210
2855
  installGuideFill: "填入示例",
2211
2856
  installGuideFillAria: "填入示例 {example}",
2212
2857
  installGuideSafety: "请确认插件来源可信。插件在本机以你的权限运行,来源不明的插件可能损坏 DeepSeek Harness,或读取和泄露你的数据。",
2858
+ registryToggle: "安装源",
2859
+ registryLegend: "从哪个 npm 源下载插件",
2860
+ registryDefault: "默认安装源",
2861
+ registryNpmmirror: "中国大陆镜像源",
2862
+ registryWithHost: "{name}({host})",
2863
+ registryCustom: "自定义地址",
2864
+ registryCustomPlaceholder: "https://npm.example.com/",
2865
+ registryCustomHint: "公司内网或私有 npm 源;需要登录的源,把凭据放在本机的 ~/.npmrc 里",
2866
+ registryCustomInvalid: "请输入以 http:// 或 https:// 开头的地址",
2867
+ registryListSeparator: "、",
2213
2868
  installRun: "安装",
2214
2869
  installChecking: "正在检查…",
2215
2870
  installProblemInvalid: "无法识别这个包名或地址:{reason}",
@@ -2218,14 +2873,29 @@ window.__ModuleLoader__.load({
2218
2873
  installProblemNotPackage: "该路径不存在或不是有效的插件包",
2219
2874
  installProblemNotBundle: "这个包没有声明组合包,无法作为插件安装:{reason}",
2220
2875
  installProblemNetwork: "无法连接插件源,请检查网络后重试",
2876
+ installProblemNetworkAll: "所有安装源都无法连接(已尝试:{registries}),请检查网络或代理设置,或更换安装源",
2221
2877
  installProblemUnknown: "无法获取插件信息:{reason}",
2222
2878
  installingTitle: "插件安装中…",
2223
2879
  installedTitle: "已安装",
2224
2880
  installFailedTitle: "插件安装失败",
2225
2881
  installEdit: "编辑",
2226
2882
  installEditAria: "返回编辑",
2883
+ installCancelAndEdit: "取消安装并返回编辑",
2884
+ installApplyingCancellationError: "取消请求未得到确认;安装已进入收尾阶段,请等待结果。{reason}",
2885
+ installReconcile: "核对安装状态",
2886
+ installUnknownTitle: "未能获取安装结果",
2887
+ installUnknownDescription: "后端当前没有此安装任务。请检查插件列表后再尝试安装。",
2888
+ installResultUnconfirmed: "未收到安装结果,请核对安装状态。{reason}",
2889
+ installAwaitingAcceptance: "正在等待后端接收安装任务,收到确认后会自动重试取消。",
2890
+ installBackgroundUnknown: "未能获取安装结果,请检查插件列表。",
2227
2891
  installCancel: "取消安装",
2228
2892
  installCloseCancels: "取消安装并关闭",
2893
+ installViewTask: "查看安装任务",
2894
+ installUnconfirmedTitle: "安装状态尚未确认",
2895
+ installBackgroundDone: "插件安装已完成,可查看安装结果。",
2896
+ installBackgroundFailed: "插件安装失败,可查看安装详情。",
2897
+ installBackgroundUnconfirmed: "安装状态暂未确认,请查看安装任务了解详情。",
2898
+ installBackgroundApplying: "安装已进入收尾阶段,无法取消,可查看安装进度。",
2229
2899
  installStarting: "正在准备安装…",
2230
2900
  installCancelling: "正在停止安装…",
2231
2901
  installApplying: "正在应用配置,请稍候…",
@@ -2241,7 +2911,12 @@ window.__ModuleLoader__.load({
2241
2911
  installSubjectTarball: "压缩包",
2242
2912
  installLocation: "安装位置:{dir}",
2243
2913
  installRetry: "重试",
2914
+ installChangeRegistry: "更换安装源",
2915
+ installAttempt: "{previous} 不可用,正在改用 {registry} 重试(第 {index} 个源,共 {total} 个)",
2916
+ installAttemptBadge: "第 {index} 次 · {registry}",
2244
2917
  installFailureNetwork: "网络连接失败",
2918
+ installFailureNetworkAll: "所有安装源都无法连接(已尝试:{registries})。请检查网络或代理设置,或更换安装源后重试。",
2919
+ installFailureNetworkHost: "无法连接 {host}。GitHub 地址和 .tgz 直链不经过安装源,需要本机能直接访问它或配置代理;如果这个插件也发布到了 npm,请改填包名。",
2245
2920
  installFailureNotFound: "未找到相关插件",
2246
2921
  installFailureNoMatchingVersion: "没有匹配的版本",
2247
2922
  installFailureDiskFull: "磁盘空间不足,安装已停止",
@@ -2302,7 +2977,7 @@ window.__ModuleLoader__.load({
2302
2977
  title: "Plugins",
2303
2978
  intro: "Add and manage plugins",
2304
2979
  loading: "Reading plugins…",
2305
- error: "Plugins are temporarily unavailable.",
2980
+ error: "Could not read all plugins, possibly due to a network problem",
2306
2981
  unavailable: "This deployment runs without a manageable profile, so plugins cannot be installed or switched here.",
2307
2982
  retry: "Retry",
2308
2983
  refresh: "Refresh",
@@ -2312,17 +2987,11 @@ window.__ModuleLoader__.load({
2312
2987
  overriddenNotice: "{name} was saved, but a higher-priority configuration overrides it, so it is not in effect",
2313
2988
  bundlesTitle: "Installed",
2314
2989
  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
2990
  statusProblem: "Problem",
2322
2991
  statusBeta: "Beta",
2323
2992
  reasonLabel: "Reason",
2993
+ metadataError: "Package metadata error: {error}",
2324
2994
  versionTag: "v{version}",
2325
- noDescription: "No description.",
2326
2995
  partsLabel: "Components",
2327
2996
  partsEmpty: "This plugin pack contains no components.",
2328
2997
  partsCountTotal: "{count} total",
@@ -2351,13 +3020,11 @@ window.__ModuleLoader__.load({
2351
3020
  installDescription: "Enter the plugin's package name, GitHub repository address, or local directory path.",
2352
3021
  installSpecLabel: "Package name or address",
2353
3022
  installSpecPlaceholder: "for example @deepseek-ai/dsh-experimental-auto-review",
2354
- installGuideToggle: "Not sure what to enter?",
3023
+ installGuideToggle: "Install guide and examples",
2355
3024
  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
3025
  installGuideIdTitle: "Package name",
2359
3026
  installGuideIdExample: "@deepseek-ai/dsh-experimental-auto-review",
2360
- installGuideIdHint: "The part after dsh plugin add or pnpm add in the README's install command.",
3027
+ 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
3028
  installGuideGitTitle: "GitHub repository address",
2362
3029
  installGuideGitExample: "https://github.com/author/dsh-plugin",
2363
3030
  installGuideGitHint: "The address of the plugin's open-source repository on GitHub; other Git hosts work too.",
@@ -2368,6 +3035,16 @@ window.__ModuleLoader__.load({
2368
3035
  installGuideFill: "Use example",
2369
3036
  installGuideFillAria: "Use the example {example}",
2370
3037
  installGuideSafety: "Install only plugins you trust: they run with your permissions and can damage DeepSeek Harness or leak your data.",
3038
+ registryToggle: "Registry",
3039
+ registryLegend: "The npm registry the plugin is downloaded from",
3040
+ registryDefault: "Default registry",
3041
+ registryNpmmirror: "Mainland China mirror",
3042
+ registryWithHost: "{name} ({host})",
3043
+ registryCustom: "Custom address",
3044
+ registryCustomPlaceholder: "https://npm.example.com/",
3045
+ registryCustomHint: "A company or private npm registry; for one that needs a login, keep the credentials in ~/.npmrc on this machine",
3046
+ registryCustomInvalid: "Enter an address starting with http:// or https://",
3047
+ registryListSeparator: ", ",
2371
3048
  installRun: "Install",
2372
3049
  installChecking: "Checking…",
2373
3050
  installProblemInvalid: "This is not a package name or address that can be installed: {reason}",
@@ -2376,14 +3053,29 @@ window.__ModuleLoader__.load({
2376
3053
  installProblemNotPackage: "The path does not exist or is not a valid plugin package",
2377
3054
  installProblemNotBundle: "This package declares no bundle, so it cannot be installed as a plugin: {reason}",
2378
3055
  installProblemNetwork: "The plugin registry could not be reached; check the network and try again",
3056
+ installProblemNetworkAll: "No registry could be reached (tried: {registries}); check the network or proxy settings, or change the registry",
2379
3057
  installProblemUnknown: "The plugin could not be looked up: {reason}",
2380
3058
  installingTitle: "Installing the plugin…",
2381
3059
  installedTitle: "Installed",
2382
3060
  installFailedTitle: "The plugin could not be installed",
2383
3061
  installEdit: "Edit",
2384
3062
  installEditAria: "Back to editing",
3063
+ installCancelAndEdit: "Cancel installation and return to editing",
3064
+ installApplyingCancellationError: "Cancellation was not confirmed. Installation is being applied; wait for its result. {reason}",
3065
+ installReconcile: "Check installation status",
3066
+ installUnknownTitle: "Installation result unavailable",
3067
+ installUnknownDescription: "The Host has no active installation with this request id. Check the plugin list before trying again.",
3068
+ installResultUnconfirmed: "The installation result was not received. Check installation status. {reason}",
3069
+ installAwaitingAcceptance: "Waiting for the Host to accept installation. Cancellation will retry automatically after confirmation.",
3070
+ installBackgroundUnknown: "Installation result unavailable. Check the plugin list.",
2385
3071
  installCancel: "Cancel install",
2386
3072
  installCloseCancels: "Cancel install and close",
3073
+ installViewTask: "View installation",
3074
+ installUnconfirmedTitle: "Installation status unconfirmed",
3075
+ installBackgroundDone: "Installation finished. View installation details.",
3076
+ installBackgroundFailed: "Installation failed. View installation details.",
3077
+ installBackgroundUnconfirmed: "Installation status is unconfirmed. View the installation for details.",
3078
+ installBackgroundApplying: "Installation is being applied and cannot be cancelled. View installation progress.",
2387
3079
  installStarting: "Preparing installation…",
2388
3080
  installCancelling: "Stopping installation…",
2389
3081
  installApplying: "Applying configuration, please wait…",
@@ -2399,7 +3091,12 @@ window.__ModuleLoader__.load({
2399
3091
  installSubjectTarball: "Tarball",
2400
3092
  installLocation: "Installs into {dir}",
2401
3093
  installRetry: "Retry",
3094
+ installChangeRegistry: "Change registry",
3095
+ installAttempt: "{previous} could not serve the package; retrying through {registry} (registry {index} of {total})",
3096
+ installAttemptBadge: "Attempt {index} · {registry}",
2402
3097
  installFailureNetwork: "The network connection failed",
3098
+ installFailureNetworkAll: "No registry could be reached (tried: {registries}). Check the network or proxy settings, or change the registry and retry.",
3099
+ 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
3100
  installFailureNotFound: "No such plugin was found",
2404
3101
  installFailureNoMatchingVersion: "No version matches the request",
2405
3102
  installFailureDiskFull: "The disk is full; the install stopped",
@@ -2474,7 +3171,8 @@ window.__ModuleLoader__.load({
2474
3171
  "locale",
2475
3172
  "remote",
2476
3173
  "remote.pluginManager",
2477
- "remote.pluginInventory"
3174
+ "remote.pluginInventory",
3175
+ "configForms"
2478
3176
  ];
2479
3177
  /**
2480
3178
  * Contribute the Plugins entry to the sidebar with the management page it
@@ -2514,12 +3212,16 @@ window.__ModuleLoader__.load({
2514
3212
  name: "main",
2515
3213
  key: PANEL_ID,
2516
3214
  locale: NS,
2517
- inject: () => controller.inject(configLedger),
3215
+ inject: () => controller.inject(configLedger, (text) => ctx.locale.resolveText(text)),
2518
3216
  children: {
2519
3217
  "plugins.item": {
2520
3218
  kind: "list",
2521
3219
  scope: "root"
2522
3220
  },
3221
+ "plugins.bundle.activation": {
3222
+ kind: "keyed",
3223
+ scope: "root"
3224
+ },
2523
3225
  "plugins.bundle.config": {
2524
3226
  kind: "keyed",
2525
3227
  scope: "root"
@@ -2527,6 +3229,18 @@ window.__ModuleLoader__.load({
2527
3229
  "plugins.row.config": {
2528
3230
  kind: "keyed",
2529
3231
  scope: "root"
3232
+ },
3233
+ "plugins.detail.actions": {
3234
+ kind: "list",
3235
+ scope: "root"
3236
+ },
3237
+ "plugins.detail.badge": {
3238
+ kind: "list",
3239
+ scope: "root"
3240
+ },
3241
+ "plugins.detail.section": {
3242
+ kind: "list",
3243
+ scope: "root"
2530
3244
  }
2531
3245
  }
2532
3246
  }, PluginManagerPage));