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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,9 +6,11 @@
6
6
  * change made on another surface shows here without a manual refresh.
7
7
  */
8
8
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
9
- import type { BundleInfo, ManagementError, PluginEntryId, PluginInfo, PluginInspectProblem, PluginInstallFailureKind, PluginInstallLogChunk, PluginInstallProgress, PluginInstallRequestId, PluginSpecInspection, ReadOnlyReason } from '@deepseek-ai/dsh-api-remotes/client';
9
+ import type { BundleInfo, ManagementError, PluginEntryId, PluginInfo, PluginInspectProblem, PluginInstallFailureKind, PluginInstallLogChunk, PluginInstallProgress, PluginInstallRequestId, PluginRegistries, PluginSpecInspection, ReadOnlyReason, Registry } from '@deepseek-ai/dsh-api-remotes/client';
10
10
  import { type SnapshotStore } from '@deepseek-ai/dsh-client-store';
11
11
  import type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots';
12
+ import type { LocalizedText, PluginLocalizedMeta } from '@deepseek-ai/dsh-package-manifest';
13
+ import type { SettingsDescribeFace, ConfigForms } from '@deepseek-ai/dsh-client-ui-settings/client';
12
14
  import type { ConfigLedger } from './config-ledger.ts';
13
15
  /** The action a failed notice names. */
14
16
  export type FailedAction = 'enable' | 'disable' | 'uninstall' | 'rowEnable' | 'rowDisable';
@@ -24,6 +26,10 @@ export type ManagerNotice = {
24
26
  } | {
25
27
  readonly kind: 'cancelled';
26
28
  readonly seq: number;
29
+ } | {
30
+ readonly kind: 'install';
31
+ readonly outcome: 'done' | 'failed' | 'unconfirmed' | 'applying' | 'unknown';
32
+ readonly seq: number;
27
33
  } | {
28
34
  readonly kind: 'failed';
29
35
  /** What was being done when it failed. */
@@ -43,6 +49,8 @@ export interface PackageRow {
43
49
  readonly rowId: string;
44
50
  /** The module the row names. */
45
51
  readonly moduleName: string;
52
+ /** Local package display text and metadata diagnostics supplied by the Host. */
53
+ readonly meta?: PluginLocalizedMeta;
46
54
  /** Whether the entry runs; false for a row without a live entry. */
47
55
  readonly enabled: boolean;
48
56
  /** The entry's fiber phase, null without a live fiber. */
@@ -55,6 +63,8 @@ export interface PackageView {
55
63
  readonly name: string;
56
64
  readonly version?: string;
57
65
  readonly description?: string;
66
+ /** Local package display text and metadata diagnostics supplied by the Host. */
67
+ readonly meta?: PluginLocalizedMeta;
58
68
  /** Whether the profile's own dependencies hold the package; false for a bundle the installation supplies. */
59
69
  readonly installed: boolean;
60
70
  /** Whether the installation ships the bundle for the person to switch on: official, off until selected, never removable. */
@@ -73,10 +83,26 @@ export type InstallSubject = Extract<PluginSpecInspection, {
73
83
  }> & {
74
84
  readonly spec: string;
75
85
  };
86
+ /** The registry the person picked for an install: one the Host offers, or a typed URL. */
87
+ export type RegistryChoice = {
88
+ readonly kind: 'offered';
89
+ readonly registry: Registry;
90
+ } | {
91
+ readonly kind: 'custom';
92
+ readonly url: string;
93
+ };
94
+ /**
95
+ * The registries the dialog offers: the Host's first, its fallbacks, and pnpm's own, each once.
96
+ * @param registries - what the Host configured, or null while unread.
97
+ * @returns the registries in the order the dialog lists them.
98
+ */
99
+ export declare function offeredRegistries(registries: PluginRegistries | null): Registry[];
76
100
  /** Why the typed spec was refused before anything installed. */
77
101
  export interface InstallInputError {
78
102
  readonly problem: PluginInspectProblem;
79
103
  readonly reason: string;
104
+ /** The registries the check asked, in order, when the refusal came from asking them. */
105
+ readonly registries?: readonly Registry[];
80
106
  }
81
107
  /** One pnpm run of an install, as the dialog's terminal draws it. */
82
108
  export interface InstallRun {
@@ -91,18 +117,30 @@ export interface InstallRun {
91
117
  readonly exitCode?: number | null;
92
118
  }
93
119
  /**
94
- * The install dialog: the spec is typed while `idle`, read by the Host while
95
- * `checking`, then installed through the Host-owned phases — `starting` until
96
- * the Host acknowledges the run, `running`, `cancelling` while the Host stops
97
- * it, `applying` once the bundle is being loaded, which closed the cancellation
98
- * window and the outcome shown as `done` or `failed`. A refused check, a
99
- * confirmed cancellation, and the back control return to `idle` with the spec kept.
120
+ * Installation input, Host progress, and the final outcome. `unconfirmed` keeps
121
+ * an unresolved request pending; `unknown` releases it after the Host reports
122
+ * no active request and its original reply is lost. Neither means cancellation.
123
+ * Closing any pending phase preserves its request and output for reopening.
124
+ * Confirmed cancellation and returning from an outcome keep the spec for editing.
100
125
  */
101
126
  export interface InstallState {
102
127
  readonly open: boolean;
103
128
  /** The package spec as typed. */
104
129
  readonly spec: string;
105
- readonly phase: 'idle' | 'checking' | 'starting' | 'running' | 'cancelling' | 'applying' | 'done' | 'failed';
130
+ /** The registries the Host configured, read when the dialog opens; null until the Host answered. */
131
+ readonly registries: PluginRegistries | null;
132
+ /** The registry this install asks first: the one last used, else the Host's first. */
133
+ readonly registry: RegistryChoice;
134
+ /** Whether the registry options are unfolded under the spec. */
135
+ readonly registryOpen: boolean;
136
+ /** Whether the typed registry was refused for not being an http(s) URL. */
137
+ readonly registryError: boolean;
138
+ /** The registries the Host asked for this install, in order, and how many it may ask; null before the run. */
139
+ readonly attempts: {
140
+ readonly registries: readonly Registry[];
141
+ readonly total: number;
142
+ } | null;
143
+ readonly phase: 'idle' | 'checking' | 'starting' | 'running' | 'cancelling' | 'applying' | 'unconfirmed' | 'unknown' | 'done' | 'failed';
106
144
  /** Identifies this dialog's installation, including log and cancellation messages. */
107
145
  readonly requestId?: PluginInstallRequestId;
108
146
  /** Why the spec was refused before installing; shown under the field. */
@@ -111,7 +149,7 @@ export interface InstallState {
111
149
  readonly subject: InstallSubject | null;
112
150
  /** The pnpm runs of the open install, in the order they started. */
113
151
  readonly runs: readonly InstallRun[];
114
- /** Whether the run's command and output are unfolded. */
152
+ /** Whether the run's command and output are unfolded, including after reopening. */
115
153
  readonly detailsOpen: boolean;
116
154
  /** The bundle the finished run added, left off until enabled from the installed screen. */
117
155
  readonly installed: string | null;
@@ -122,15 +160,17 @@ export interface InstallState {
122
160
  * `code` with its diagnostic as `reason`, or the transport's words alone;
123
161
  * `kind` classifies a pnpm failure, and `pendingBuilds` names the packages
124
162
  * whose install scripts pnpm left undecided, offered for approval.
125
- * `cancelUnconfirmed` is a stop the Host did not confirm, shown over the
126
- * running screen while the run goes on.
163
+ * `uncertainty` distinguishes a lost installation reply, an unconfirmed
164
+ * cancellation, and a cancellation awaiting the Host's acceptance of the run.
127
165
  */
128
166
  readonly failure: {
129
167
  readonly reason: string;
130
168
  readonly code?: ManagementError['code'];
131
169
  readonly kind?: PluginInstallFailureKind;
170
+ /** What the last failed run could not reach, as the Host attributed it: the registry, or the spec's own host. */
171
+ readonly failedAt?: 'registry' | 'spec-host';
132
172
  readonly pendingBuilds?: readonly string[];
133
- readonly cancelUnconfirmed?: true;
173
+ readonly uncertainty?: 'result' | 'cancellation' | 'acceptance';
134
174
  } | null;
135
175
  /** The packages whose install scripts the finished run was allowed to execute, saved for this profile. */
136
176
  readonly approvedBuilds: readonly string[];
@@ -140,7 +180,7 @@ export interface InstallState {
140
180
  /**
141
181
  * Whether an installation is still owned by the Host.
142
182
  * @param phase - the dialog's current installation phase.
143
- * @returns true until an authoritative result settles the installation.
183
+ * @returns true while a Host result or a check for an active request is outstanding.
144
184
  */
145
185
  export declare function isInstallPending(phase: InstallState['phase']): boolean;
146
186
  /** A destructive action waiting for the user's confirmation: a package's uninstall. */
@@ -163,7 +203,13 @@ export interface PluginManagerState {
163
203
  }
164
204
  /** The registration-side face the tab's slot entry injects. */
165
205
  export interface PluginManagerFace {
206
+ /** Resolve local package text in the current Client locale at render time. */
207
+ resolveText: (text: LocalizedText) => string;
208
+ /** Resolve a configuration form by the Host entry id. */
209
+ configForm: ConfigForms['get'];
166
210
  hooks: {
211
+ /** Shared accepted configuration values. */
212
+ configurations: SettingsDescribeFace;
167
213
  /** Tab snapshot bound by the renderer as usePluginManager. */
168
214
  pluginManager: SnapshotStore<PluginManagerState>;
169
215
  /** The plugins carrying configuration, bound by the renderer as useConfigLedger. */
@@ -174,20 +220,23 @@ export interface PluginManagerFace {
174
220
  /** Read the Host again. */
175
221
  refresh: () => void;
176
222
  openInstall: () => void;
177
- /** Close the dialog; a check in flight is dropped, a Host-owned run has to be cancelled first. */
223
+ /** Hide immediately, abort a check, or request cancellation while retaining the Host-owned installation. */
178
224
  closeInstall: () => void;
179
225
  editInstallSpec: (text: string) => void;
180
226
  /** Check the spec with the Host, then install it; from the failed screen, run it again. */
181
227
  runInstall: () => void;
228
+ /** Fold or unfold the registry options under the spec. */
229
+ toggleRegistryOptions: () => void;
230
+ /** Pick the registry the install asks first, or type one. */
231
+ chooseRegistry: (choice: RegistryChoice) => void;
232
+ /** From the failed screen: back to the spec with the registry options unfolded. */
233
+ changeRegistry: () => void;
182
234
  /** Allow the install scripts the failed run left pending, saved for this profile, and run the same spec again. */
183
235
  approveBuildsAndRetry: () => void;
184
236
  /** Leave the check or the failed screen for the spec, or ask the Host to stop the run and wait for its cleanup. */
185
237
  cancelInstall: () => void;
186
- /**
187
- * While the Host runs the install, ask it to stop and close the dialog once
188
- * it confirms; the dialog stays when it cannot. Otherwise nothing.
189
- */
190
- cancelInstallAndClose: () => void;
238
+ /** Ask the Host for the result of an installation whose original reply was lost. */
239
+ reconcileInstall: () => void;
191
240
  toggleInstallDetails: () => void;
192
241
  /** Enable the bundle the finished install added, then close the dialog and mark it in the list. */
193
242
  enableInstalled: () => void;
@@ -234,7 +283,11 @@ export declare class PluginManagerController {
234
283
  private pendingConfirm;
235
284
  /** Cancels the check the dialog has in flight. */
236
285
  private inspectAbort;
286
+ private request;
237
287
  private noticeSeq;
288
+ private registryRead;
289
+ /** The registry last used from this browser, kept across dialogs and page loads; null until one was used. */
290
+ private readonly registryMemory;
238
291
  /**
239
292
  * @param ctx - the tab plugin's context, whose `remote.pluginManager` and `remote.pluginInventory` namespaces answer.
240
293
  */
@@ -249,14 +302,18 @@ export declare class PluginManagerController {
249
302
  /**
250
303
  * Build the face the tab's slot registration injects.
251
304
  * @param configLedger - the projection of the plugins carrying configuration, bound beside the tab's own state.
305
+ * @param resolveText - render-time package text resolution supplied by the locale service.
252
306
  * @returns the tab's snapshot sources and its actions.
253
307
  */
254
- inject(configLedger: HostObservable<ConfigLedger>): PluginManagerFace;
308
+ inject(configLedger: HostObservable<ConfigLedger>, resolveText: PluginManagerFace['resolveText']): PluginManagerFace;
255
309
  /**
256
310
  * Follow the Host's cancellation window for this dialog's installation.
257
311
  * @param progress - a request id and phase received from the Host.
258
312
  */
259
313
  installProgress(progress: PluginInstallProgress): void;
314
+ private currentRegistryRead;
315
+ /** Read the registries the Host offers, for the dialog just opened; a refused read leaves pnpm's own and a typed one. */
316
+ private readRegistries;
260
317
  /**
261
318
  * Fold a chunk belonging to this installation into its pnpm command.
262
319
  * A final chunk may arrive after the install answer and still updates an existing run.
@@ -288,6 +345,10 @@ export declare class PluginManagerController {
288
345
  * the Host saves that permission for this profile before pnpm runs.
289
346
  */
290
347
  private startInstall;
348
+ /** A recovery call shares the Host's active result; absent results are explicitly unknown. */
349
+ private reconcileInstall;
350
+ private settleInstall;
351
+ private installUncertain;
291
352
  /**
292
353
  * Allow the install scripts the failed run left pending and run the same
293
354
  * spec again. Only the failed screen with pending names offers this.
@@ -295,15 +356,16 @@ export declare class PluginManagerController {
295
356
  private approveBuildsAndRetry;
296
357
  /**
297
358
  * Leave the check or the failed screen for the spec at once; a Host-owned
298
- * run is asked to stop and the dialog waits for the Host's word, since
359
+ * run is asked to stop and its state waits for the Host's word, since
299
360
  * neither a dropped RPC nor a closed connection means pnpm has stopped.
300
- * @param closeAfter - stop only a running install, and close the dialog once the Host confirms the stop.
301
361
  */
302
362
  private cancelInstall;
363
+ /** A cancellation that overtakes installation is retried after the Host acknowledges that request. */
364
+ private sendCancellation;
365
+ private notifyHiddenInstall;
303
366
  /**
304
- * Back to the spec: the check, the run, and its request are forgotten and
305
- * the spec is kept, with a toast when there is something to say — the Host
306
- * stopped the run.
367
+ * Release the tracked request and return to editing with its spec retained.
368
+ * A cancellation notice is supplied only after the Host confirms it stopped.
307
369
  */
308
370
  private offerSpecAgain;
309
371
  /**
@@ -1,9 +1,21 @@
1
1
  /** Display labels and toast sentences for global plugin management. */
2
- import type { ManagementError } from '@deepseek-ai/dsh-api-remotes/client';
2
+ import type { ManagementError, Registry } from '@deepseek-ai/dsh-api-remotes/client';
3
3
  import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
4
- import type { ManagerNotice, PackageView } from './manager-store.ts';
4
+ import type { ManagerNotice, PackageRow, PackageView, PluginManagerFace } from './manager-store.ts';
5
5
  /** The translate seat of the manager's dictionary. */
6
6
  export type Translate = PropsLocale<'pluginManager'>['t'];
7
+ /**
8
+ * What a registry reads as: pnpm's own as the default registry, a known mirror by its name, any other registry by
9
+ * its host; and the host each names, for where the name alone would leave it unsaid.
10
+ * @param registry - the registry, null for the one pnpm's own configuration names.
11
+ * @param t - the manager's translate seat.
12
+ * @param resolved - the URL pnpm's own configuration names, null while unknown, when it reads as npm's own.
13
+ * @returns the name and the host.
14
+ */
15
+ export declare function registryText(registry: Registry, t: Translate, resolved: string | null): {
16
+ name: string;
17
+ host: string;
18
+ };
7
19
  /**
8
20
  * What a management error reads as: the code's sentence, or, for an
9
21
  * operation error, the Host's diagnostic as it is.
@@ -22,16 +34,26 @@ export declare function managementText(error: {
22
34
  */
23
35
  export declare function shortName(name: string): string;
24
36
  /**
25
- * Localize known official packages by exact npm name at render time.
26
- * @param pkg - original package identity and optional metadata description.
27
- * @param t - the manager's current translate function.
28
- * @returns localized copy and whether the package is a beta feature, or the package's short name and original description.
37
+ * Resolve installed package metadata without changing its technical identity.
38
+ * @param pkg - package identity and local metadata.
39
+ * @param resolveText - current-locale package text resolver.
40
+ * @returns localized copy with a technical-name fallback and the independent beta status.
29
41
  */
30
- export declare function packageText(pkg: Pick<PackageView, 'name' | 'description'>, t: Translate): {
42
+ export declare function packageText(pkg: Pick<PackageView, 'name' | 'meta'>, resolveText: PluginManagerFace['resolveText']): {
31
43
  title: string;
32
44
  description: string | undefined;
33
45
  beta: boolean;
34
46
  };
47
+ /**
48
+ * Resolve a bundle row's plugin metadata, using its full module specifier as the final title fallback.
49
+ * @param row - row identity and local metadata.
50
+ * @param resolveText - current-locale package text resolver.
51
+ * @returns the row's display title and optional description.
52
+ */
53
+ export declare function rowText(row: Pick<PackageRow, 'moduleName' | 'meta'>, resolveText: PluginManagerFace['resolveText']): {
54
+ title: string;
55
+ description: string | undefined;
56
+ };
35
57
  /**
36
58
  * The sentence one notice shows.
37
59
  * @param notice - the last action's outcome.
@@ -1,28 +1,90 @@
1
1
  /**
2
- * The slots the Plugins page declares for plugins that carry their own
3
- * configuration: the official plugins listed beside the official bundles, one
4
- * bundle's configuration on its page, and one row's configuration opened from
5
- * that row. A registrant merges this contract with `import type` and registers
6
- * through `ctx.slots`; it never imports this package at runtime.
2
+ * The slots the Plugins page declares for other plugins. Three carry a
3
+ * plugin's own configuration: the official plugins listed beside the official
4
+ * bundles, one bundle's configuration on its page, and one row's configuration
5
+ * opened from that row. Three more take contributions to any detail page
6
+ * its head actions, the badges beside its title, and the sections under its
7
+ * own content — from a plugin that has something to say about bundles, rows,
8
+ * or official plugins it does not own. A registrant merges this contract with
9
+ * `import type` and registers through `ctx.slots`; it never imports this
10
+ * package at runtime.
7
11
  *
8
- * Every entry is rendered in two views the owner asks for: `summary` for the
9
- * one-liner the page places under the title, `page` for the form with its own
10
- * save control. The page draws the title, the icon, and the crumb itself.
12
+ * Entries accept `page` for the form with its own save control and `summary`
13
+ * for an official card's one-liner or a row's missing-description fallback.
14
+ * Bundle configuration renders only `page`. A detail contribution is rendered
15
+ * with the subject of the open page and decides from it whether to render at
16
+ * all. The page draws the title, icon, and crumb itself.
11
17
  */
18
+ import type { ConfigForm, ConfigFormSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client';
12
19
  /** The view the page asks a configuration entry for. */
13
20
  export interface PluginConfigViewProps {
14
21
  /** `summary` renders the one-liner alone, as text or inline nodes; `page` renders the form with its save control. */
15
22
  readonly view: 'summary' | 'page';
23
+ /** Host-owned configuration values and write actions for this page's entry. */
24
+ readonly form?: ConfigPageForm | undefined;
25
+ }
26
+ /** One row of a bundle as a detail contribution sees it. */
27
+ export interface PluginRowRef {
28
+ /** The row id as the bundle's patch declares it. */
29
+ readonly rowId: string;
30
+ /** The module the row names. */
31
+ readonly moduleName: string;
32
+ /** Whether the row's entry runs. */
33
+ readonly enabled: boolean;
34
+ }
35
+ /** One bundle as a detail contribution sees it: the facts a contribution decides on, never the page's own state. */
36
+ export interface PluginPackageRef {
37
+ /** The package name. */
38
+ readonly name: string;
39
+ /** The installed version, when the Host reports one. */
40
+ readonly version?: string;
41
+ /** Whether the profile's own dependencies hold the package; false for a bundle the installation supplies. */
42
+ readonly installed: boolean;
43
+ /** Whether the bundle is switched on. */
44
+ readonly enabled: boolean;
45
+ /** The rows the bundle declares. */
46
+ readonly rows: readonly PluginRowRef[];
47
+ }
48
+ /** What a detail page is about: a bundle, one row of a bundle, or an official plugin listed by its `plugins.item` id. */
49
+ export type PluginsSubject = {
50
+ readonly kind: 'bundle';
51
+ readonly pkg: PluginPackageRef;
52
+ } | {
53
+ readonly kind: 'row';
54
+ readonly pkg: PluginPackageRef;
55
+ readonly row: PluginRowRef;
56
+ } | {
57
+ readonly kind: 'item';
58
+ readonly id: string;
59
+ };
60
+ /** The owner props every detail contribution is rendered with. */
61
+ export interface PluginDetailProps {
62
+ /** The subject of the open page; an entry renders null for a subject it has nothing for. */
63
+ readonly subject: PluginsSubject;
64
+ }
65
+ /** One user-requested bundle activation and navigation to its configuration page. */
66
+ export interface PluginActivationOwnerProps {
67
+ readonly packageName: string;
68
+ /** Dismiss guidance for this activation. */
69
+ readonly onDismiss: () => void;
70
+ /** Dismiss guidance and open this bundle's detail page. */
71
+ readonly onOpenDetails: () => void;
16
72
  }
17
73
  declare module '@deepseek-ai/dsh-client-ui-slots' {
18
74
  interface SlotMap {
75
+ /** Optional guidance after the user enables a bundle from the list, keyed by npm package name. */
76
+ 'plugins.bundle.activation': {
77
+ kind: 'keyed';
78
+ scope: 'root';
79
+ owner: PluginActivationOwnerProps;
80
+ };
19
81
  /**
20
82
  * One official plugin the Plugins page lists in its Official group after
21
83
  * the official bundles: `label` is the card's title and `order` its place.
22
84
  * The page renders the entry as the card's one-liner (`view: 'summary'`)
23
85
  * and, once the card is opened, as the body of the plugin's own page
24
- * (`view: 'page'`). OCCUPIED by the host-plane configuration pages
25
- * `ui-settings-plugins` ships; a bundle's configuration belongs in
86
+ * (`view: 'page'`). OCCUPIED by the official settings pages, one companion
87
+ * package per host-plane namespace; a bundle's configuration belongs in
26
88
  * `plugins.bundle.config` or `plugins.row.config` instead.
27
89
  */
28
90
  'plugins.item': {
@@ -44,13 +106,51 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
44
106
  * The configuration of one row a bundle declares, keyed by
45
107
  * `<package name>#<row id>` with the row id as the bundle's patch declares
46
108
  * it: the row on the bundle's page gains a configure control that opens
47
- * the entry's page, headed by the row id and the entry's summary.
109
+ * the entry's page, headed by the plugin's display title and description.
110
+ * An absent description falls back to the entry's `view: 'summary'`.
48
111
  */
49
112
  'plugins.row.config': {
50
113
  kind: 'keyed';
51
114
  scope: 'root';
52
115
  owner: PluginConfigViewProps;
53
116
  };
117
+ /**
118
+ * Controls at the head of a detail page, before the page's own switch and
119
+ * uninstall, rendered with the page's subject. An entry renders null for a
120
+ * subject it has no control for.
121
+ */
122
+ 'plugins.detail.actions': {
123
+ kind: 'list';
124
+ scope: 'root';
125
+ owner: PluginDetailProps;
126
+ };
127
+ /**
128
+ * Tags beside a detail page's title, after the version, beta, and problem
129
+ * tags the page draws itself, rendered with the page's subject.
130
+ */
131
+ 'plugins.detail.badge': {
132
+ kind: 'list';
133
+ scope: 'root';
134
+ owner: PluginDetailProps;
135
+ };
136
+ /**
137
+ * Sections under a detail page's own content: after the rows on a bundle's
138
+ * page, after the configuration on a row's or an official plugin's page.
139
+ * An entry draws its own section chrome and renders null for a subject it
140
+ * has nothing for.
141
+ */
142
+ 'plugins.detail.section': {
143
+ kind: 'list';
144
+ scope: 'root';
145
+ owner: PluginDetailProps;
146
+ };
54
147
  }
55
148
  }
149
+ /** Reactive page values and commands supplied by the configuration page owner. */
150
+ export interface ConfigPageForm {
151
+ /** Accepted Host values; refreshed by the page owner. */
152
+ readonly state: ConfigFormSnapshot<Record<string, unknown>>;
153
+ /** Submit all field edits together with the revision the editor read. */
154
+ readonly mutate: ConfigForm<Record<string, unknown>>['mutate'];
155
+ }
56
156
  //# sourceMappingURL=slot-contract.d.ts.map
@@ -1,4 +1,36 @@
1
- /** Host loader entry for the plugin-manager tab's browser implementation exported from `./client`. */
2
- /** Host plugin body no host-side behavior for the plugin manager tab. */
3
- export declare function apply(): void;
1
+ /** Host registry-response probing for the plugin installation dialog. */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ import z from '@deepseek-ai/schemastery';
4
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
5
+ declare module '@deepseek-ai/cordis' {
6
+ interface Context {
7
+ pluginRegistryProbe: PluginRegistryProbe;
8
+ }
9
+ }
10
+ /** Registry-probe deadline and process-local cache policy. */
11
+ export interface Config {
12
+ /** Whether the dialog can compare the public npm registries. */
13
+ registryProbeEnabled: boolean;
14
+ /** Deadline for the parallel HTTPS probes, including response cleanup. */
15
+ registryProbeTimeoutMs: number;
16
+ /** Lifetime of a winning registry or unavailable result. */
17
+ registryProbeCacheTtlMs: number;
18
+ }
19
+ /** Compares public registry responses on the Host; the Client owns the initial selection. */
20
+ export default class PluginRegistryProbe extends TypertRemoteService {
21
+ private readonly config;
22
+ static Config: z<Partial<Config>, Config>;
23
+ private readonly lifetime;
24
+ private pending;
25
+ private cached;
26
+ constructor(ctx: Context, config: Config);
27
+ /**
28
+ * Race npm and npmmirror HTTPS ping responses through the Host's fetch proxy.
29
+ * Concurrent readers share a probe; a winner cancels and awaits the other request.
30
+ * @returns the first registry with a successful response, or null when disabled or neither responds successfully; results are cached.
31
+ * @throws rejects when the service has been unloaded.
32
+ */
33
+ fastest(): Promise<string | null>;
34
+ private probe;
35
+ }
4
36
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-plugin-manager",
3
3
  "description": "Plugin management for the dsh web client: the sidebar Plugins panel installs, enables, disables, retries, and composes installed plugin packages",
4
- "version": "0.1.6-alpha.2",
4
+ "version": "0.1.7-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -23,7 +23,15 @@
23
23
  "default": "./lib/client.js"
24
24
  },
25
25
  "./src/*": "./src/*",
26
- "./package.json": "./package.json"
26
+ "./package.json": "./package.json",
27
+ "./typert": {
28
+ "types": "./lib/typert.host.d.ts",
29
+ "default": "./lib/typert.host.js"
30
+ },
31
+ "./remote": {
32
+ "types": "./lib/typert.remote-client.d.ts",
33
+ "default": "./lib/typert.remote-client.js"
34
+ }
27
35
  },
28
36
  "dsh": {
29
37
  "client": {
@@ -38,32 +46,45 @@
38
46
  },
39
47
  "license": "MIT",
40
48
  "peerDependencies": {
41
- "@deepseek-ai/cordis": "^4.0.2"
49
+ "@deepseek-ai/cordis": "~4.0.4"
42
50
  },
43
51
  "devDependencies": {
44
52
  "@testing-library/react": "^16.1.0",
45
53
  "@types/react": "~18.3.1",
54
+ "@types/react-dom": "~18.3.0",
46
55
  "clsx": "^2.1.1",
47
56
  "react": "^18.2.0",
48
57
  "react-dom": "^18.2.0",
49
- "@deepseek-ai/cordis": "^4.0.2",
50
- "@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.2",
51
- "@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.2",
52
- "@deepseek-ai/dsh-client-store": "^0.1.6-alpha.2",
53
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.6-alpha.2",
54
- "@deepseek-ai/dsh-client-ui-layout": "^0.1.6-alpha.2",
55
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.2",
56
- "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.6-alpha.2",
57
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.2",
58
- "@deepseek-ai/dsh-plugin-manager": "^0.1.6-alpha.2",
59
- "@deepseek-ai/dsh-util-crypto": "^0.1.6-alpha.2",
60
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.2"
58
+ "@deepseek-ai/cordis": "~4.0.4",
59
+ "@deepseek-ai/dsh-api-remotes": "0.1.7-alpha.2",
60
+ "@deepseek-ai/dsh-client-locale": "0.1.7-alpha.2",
61
+ "@deepseek-ai/dsh-client-store": "0.1.7-alpha.2",
62
+ "@deepseek-ai/dsh-client-test-runtime": "0.1.7-alpha.2",
63
+ "@deepseek-ai/dsh-client-ui-layout": "0.1.7-alpha.2",
64
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-alpha.2",
65
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-alpha.2",
66
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.1.7-alpha.2",
67
+ "@deepseek-ai/dsh-package-manifest": "0.1.7-alpha.2",
68
+ "@deepseek-ai/dsh-util-crypto": "0.1.7-alpha.2",
69
+ "@deepseek-ai/dsh-plugin-manager": "0.1.7-alpha.2",
70
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.2",
71
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.7-alpha.2"
61
72
  },
62
73
  "files": [
63
74
  "lib/index.js",
64
75
  "lib/client.js",
65
- "lib/types/**/*.d.ts"
76
+ "lib/types/**/*.d.ts",
77
+ "lib/typert.host.js",
78
+ "lib/typert.host.d.ts",
79
+ "lib/typert.remote-client.js",
80
+ "lib/typert.remote-client.d.ts"
66
81
  ],
82
+ "dependencies": {
83
+ "zod": "^4.4.3",
84
+ "@deepseek-ai/dsh-timeout": "0.1.7-alpha.2",
85
+ "@deepseek-ai/schemastery": "~3.18.4",
86
+ "@deepseek-ai/dsh-typert-protocol": "0.1.7-alpha.2"
87
+ },
67
88
  "scripts": {
68
89
  "bundle": "tsdown",
69
90
  "watch": "tsdown --watch"