dsh-plugin-shop 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -256,7 +256,10 @@ function validateInstall(snapshot, args) {
256
256
  }
257
257
  //#endregion
258
258
  //#region src/host/executor.ts
259
- /** Install executor: spawn the dsh CLI, stream its output, serialize per profile. */
259
+ /** Plugin-command executor: spawn the dsh CLI, stream its output, serialize
260
+ * per profile. One implementation drives both `dsh plugin add` (install) and
261
+ * `dsh plugin remove` (uninstall); the only differences are the verb and the
262
+ * post-exit manifest confirmation. */
260
263
  const MAX_LOG_LINES = 200;
261
264
  const MAX_LOG_BYTES = 65536;
262
265
  const profileQueues = /* @__PURE__ */ new Map();
@@ -265,8 +268,7 @@ function chain(profile, task) {
265
268
  profileQueues.set(profile, next.catch(() => {}));
266
269
  return next;
267
270
  }
268
- /**
269
- * The §7.2 step-6 confirm: after a zero exit, re-read the profile manifest and
271
+ /** The §7.2 step-6 confirm: after a zero exit, re-read the profile manifest and
270
272
  * verify the bundle actually landed in `dsh.profile.bundles`. Exit 0 alone is
271
273
  * not success — a library-that-looked-like-a-plugin, or a stale catalog,
272
274
  * exits 0 while changing nothing (§10). The shop cannot force a client
@@ -285,18 +287,31 @@ function confirmBundleActivation(profile, home, expectedName) {
285
287
  return `installed but the profile manifest could not be read (${join(profileDir, "package.json")}) — the catalog may be stale; refresh it`;
286
288
  }
287
289
  }
288
- /**
289
- * Run one `dsh plugin --profile <profile> add <spec>` and track it.
290
+ /** The uninstall mirror of §7.2 step 6: after a zero exit, re-read the profile
291
+ * manifest and verify the bundle actually left `dsh.profile.bundles`. A zero
292
+ * exit that changed nothing must not read as success. */
293
+ function confirmBundleRemoval(profile, home, expectedName) {
294
+ const profileDir = resolveProfileDir(profile, home);
295
+ try {
296
+ if (!readProfileManifest("dsh-plugin-shop", profileDir).dsh?.profile?.bundles?.includes(expectedName)) return null;
297
+ return "removed but dsh.profile.bundles did not change — re-run the uninstall";
298
+ } catch {
299
+ return `removed but the profile manifest could not be read (${join(profileDir, "package.json")}) — re-run the uninstall`;
300
+ }
301
+ }
302
+ /** Run one `dsh plugin --profile <profile> <verb> <target>` and track it.
290
303
  * Never rolls back; a failure surfaces stderr verbatim plus the recovery hint
291
304
  * (§10). The shop never passes build-script flags: `allowBuilds` stays the
292
305
  * user's explicit decision in the CLI (§7.2).
293
306
  * The child inherits the current environment unless `env` is given — the
294
307
  * real-install test pins DSH_HOME to a temporary directory this way.
295
- * When `expectedName` is given, a zero exit is confirmed against the profile
296
- * manifest (§7.2 step 6) before the install reports `done`.
297
- */
298
- function startInstall(options) {
299
- const { profile, spec, dshBin = "dsh", env, expectedName, onStatus } = options;
308
+ * When `confirm` is given, a zero exit is checked against the profile
309
+ * manifest before the command reports `done` (§7.2 step 6 and its uninstall
310
+ * mirror). */
311
+ function spawnPluginCli(options) {
312
+ const { profile, argv, dshBin, env, confirm, onStatus } = options;
313
+ const target = argv[1];
314
+ if (target === void 0 || target.startsWith("-")) throw new Error(`dsh-plugin-shop: refusing to spawn with a flag-like operand: ${target ?? "(none)"}`);
300
315
  const installId = randomUUID();
301
316
  const log = [];
302
317
  let logBytes = 0;
@@ -325,8 +340,7 @@ function startInstall(options) {
325
340
  "plugin",
326
341
  "--profile",
327
342
  profile,
328
- "add",
329
- spec
343
+ ...argv
330
344
  ], {
331
345
  stdio: [
332
346
  "ignore",
@@ -352,8 +366,8 @@ function startInstall(options) {
352
366
  if (state !== "running") return;
353
367
  if (exitCode === 0) {
354
368
  state = "done";
355
- if (expectedName !== void 0) {
356
- const confirmDetail = confirmBundleActivation(profile, env?.DSH_HOME, expectedName);
369
+ if (confirm !== void 0) {
370
+ const confirmDetail = confirm(env?.DSH_HOME);
357
371
  if (confirmDetail !== null) {
358
372
  state = "failed";
359
373
  detail = confirmDetail;
@@ -370,6 +384,39 @@ function startInstall(options) {
370
384
  }))
371
385
  };
372
386
  }
387
+ /**
388
+ * Run one `dsh plugin --profile <profile> add <spec>` and track it.
389
+ * When `expectedName` is given, a zero exit is confirmed against the profile
390
+ * manifest (§7.2 step 6) before the install reports `done`.
391
+ */
392
+ function startInstall(options) {
393
+ const { profile, spec, dshBin = "dsh", env, expectedName, onStatus } = options;
394
+ return spawnPluginCli({
395
+ profile,
396
+ argv: ["add", spec],
397
+ dshBin,
398
+ env,
399
+ confirm: expectedName !== void 0 ? (home) => confirmBundleActivation(profile, home, expectedName) : void 0,
400
+ onStatus
401
+ });
402
+ }
403
+ /**
404
+ * Run one `dsh plugin --profile <profile> remove <name>` and track it.
405
+ * When `expectedName` is given, a zero exit is confirmed against the profile
406
+ * manifest — the bundle must actually have LEFT `dsh.profile.bundles` — before
407
+ * the uninstall reports `done`.
408
+ */
409
+ function startUninstall(options) {
410
+ const { profile, name, dshBin = "dsh", env, expectedName, onStatus } = options;
411
+ return spawnPluginCli({
412
+ profile,
413
+ argv: ["remove", name],
414
+ dshBin,
415
+ env,
416
+ confirm: expectedName !== void 0 ? (home) => confirmBundleRemoval(profile, home, expectedName) : void 0,
417
+ onStatus
418
+ });
419
+ }
373
420
  //#endregion
374
421
  //#region src/host/profile.ts
375
422
  /** Profile directory discovery and user-layer writes (§8: hot enable/disable). */
@@ -494,7 +541,8 @@ let ShopGateway = (() => {
494
541
  let _catalog_decorators;
495
542
  let _install_decorators;
496
543
  let _installStatus_decorators;
497
- let _outdated_decorators;
544
+ let _installed_decorators;
545
+ let _uninstall_decorators;
498
546
  return class ShopGateway extends _classSuper {
499
547
  static {
500
548
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -502,7 +550,8 @@ let ShopGateway = (() => {
502
550
  _catalog_decorators = [Remote("catalog")];
503
551
  _install_decorators = [Remote("installStart")];
504
552
  _installStatus_decorators = [Remote("installStatus")];
505
- _outdated_decorators = [Remote("outdated")];
553
+ _installed_decorators = [Remote("installed")];
554
+ _uninstall_decorators = [Remote("uninstallStart")];
506
555
  __esDecorate(this, null, _setEnabled_decorators, {
507
556
  kind: "method",
508
557
  name: "setEnabled",
@@ -547,14 +596,25 @@ let ShopGateway = (() => {
547
596
  },
548
597
  metadata: _metadata
549
598
  }, null, _instanceExtraInitializers);
550
- __esDecorate(this, null, _outdated_decorators, {
599
+ __esDecorate(this, null, _installed_decorators, {
551
600
  kind: "method",
552
- name: "outdated",
601
+ name: "installed",
553
602
  static: false,
554
603
  private: false,
555
604
  access: {
556
- has: (obj) => "outdated" in obj,
557
- get: (obj) => obj.outdated
605
+ has: (obj) => "installed" in obj,
606
+ get: (obj) => obj.installed
607
+ },
608
+ metadata: _metadata
609
+ }, null, _instanceExtraInitializers);
610
+ __esDecorate(this, null, _uninstall_decorators, {
611
+ kind: "method",
612
+ name: "uninstall",
613
+ static: false,
614
+ private: false,
615
+ access: {
616
+ has: (obj) => "uninstall" in obj,
617
+ get: (obj) => obj.uninstall
558
618
  },
559
619
  metadata: _metadata
560
620
  }, null, _instanceExtraInitializers);
@@ -727,8 +787,11 @@ let ShopGateway = (() => {
727
787
  ...running.status()
728
788
  };
729
789
  }
730
- /** Installed plugins whose installed version is older than the catalog's (§7.3). */
731
- async outdated() {
790
+ /** Installed catalog plugins (§7.3): every entry of the snapshot the profile
791
+ * manifest declares as a dependency, with the Host's `outdated` verdict
792
+ * attached. The tab's shelf cards and its installed section both derive
793
+ * from this one list. */
794
+ async installed() {
732
795
  if (this.lastSnapshot === null) {
733
796
  const { catalogUrl, cacheDir } = this.rowConfig();
734
797
  const { snapshot } = await (this.options.loadCatalog ?? loadCatalog)({
@@ -738,24 +801,69 @@ let ShopGateway = (() => {
738
801
  this.lastSnapshot = snapshot;
739
802
  }
740
803
  const dependencies = readProfileManifest("dsh-plugin-shop", this.profileDirResolved()).dependencies ?? {};
741
- const outdated = [];
804
+ const installed = [];
742
805
  for (const entry of this.lastSnapshot.entries) {
743
- const installed = dependencies[entry.name];
744
- if (installed === void 0) continue;
745
- let floor;
746
- if (installed === entry.version) floor = installed;
747
- else try {
748
- floor = minVersion(installed)?.version ?? null;
749
- } catch {
750
- floor = null;
751
- }
752
- if (floor !== null && lt(floor, entry.version)) outdated.push({
806
+ const spec = dependencies[entry.name];
807
+ if (spec === void 0) continue;
808
+ installed.push({
753
809
  name: entry.name,
754
- installed,
755
- latest: entry.version
810
+ installed: spec,
811
+ latest: entry.version,
812
+ outdated: this.isBehind(spec, entry.version)
813
+ });
814
+ }
815
+ return installed;
816
+ }
817
+ /** Whether an installed dependency spec sits behind the catalog's version.
818
+ * A spec identical to the catalog version is current by definition; a
819
+ * pnpm-written non-semver spec like `workspace:*` is not reportable and
820
+ * reads as current rather than killing the RPC. */
821
+ isBehind(spec, latest) {
822
+ if (spec === latest) return false;
823
+ let floor;
824
+ try {
825
+ floor = minVersion(spec)?.version ?? null;
826
+ } catch {
827
+ floor = null;
828
+ }
829
+ return floor !== null && lt(floor, latest);
830
+ }
831
+ /** Uninstall one installed catalog plugin from the profile (§7.3 follow-up
832
+ * amendment). Removing revokes privilege rather than granting it, so there
833
+ * is no acknowledgement gate. The name must be a catalog entry the profile
834
+ * manifest declares as a dependency — the RPC cannot remove profile
835
+ * dependencies the shop does not manage (the base bundle, the shop
836
+ * itself). The same install records/polling serve the client. */
837
+ async uninstall(args) {
838
+ if (this.lastSnapshot === null) {
839
+ const { catalogUrl, cacheDir } = this.rowConfig();
840
+ const { snapshot } = await (this.options.loadCatalog ?? loadCatalog)({
841
+ baseUrl: catalogUrl,
842
+ cacheDir
756
843
  });
844
+ this.lastSnapshot = snapshot;
757
845
  }
758
- return outdated;
846
+ if (!this.lastSnapshot.entries.some((entry) => entry.name === args.name)) return {
847
+ ok: false,
848
+ detail: `dsh-plugin-shop: ${args.name} is not in the catalog`
849
+ };
850
+ if ((readProfileManifest("dsh-plugin-shop", this.profileDirResolved()).dependencies ?? {})[args.name] === void 0) return {
851
+ ok: false,
852
+ detail: `dsh-plugin-shop: ${args.name} is not installed`
853
+ };
854
+ const running = startUninstall({
855
+ profile: this.profile,
856
+ name: args.name,
857
+ dshBin: this.dshBin,
858
+ expectedName: args.name
859
+ });
860
+ this.installs.set(running.installId, running);
861
+ this.installOrder.push(running.installId);
862
+ this.evictFinishedInstalls();
863
+ return {
864
+ ok: true,
865
+ installId: running.installId
866
+ };
759
867
  }
760
868
  };
761
869
  })();
@@ -38,6 +38,12 @@ const dsh_plugin_shop_shop_catalog_result$schema = z.object({
38
38
  })),
39
39
  'stars': z.record(z.string(), z.number()),
40
40
  })
41
+ const dsh_plugin_shop_shop_installed_result$schema = z.array(z.object({
42
+ 'name': z.string(),
43
+ 'installed': z.string(),
44
+ 'latest': z.string(),
45
+ 'outdated': z.boolean(),
46
+ }))
41
47
  const dsh_plugin_shop_shop_installStart_parameter_0$schema = z.object({
42
48
  'name': z.string(),
43
49
  'version': z.string(),
@@ -61,11 +67,6 @@ const dsh_plugin_shop_shop_installStatus_result$schema = z.object({
61
67
  'needsRestart': z.union([z.undefined(), z.literal(false), z.literal(true)]).optional(),
62
68
  'detail': z.union([z.undefined(), z.string()]).optional(),
63
69
  })
64
- const dsh_plugin_shop_shop_outdated_result$schema = z.array(z.object({
65
- 'name': z.string(),
66
- 'installed': z.string(),
67
- 'latest': z.string(),
68
- }))
69
70
  const dsh_plugin_shop_shop_setEnabled_parameter_0$schema = z.object({
70
71
  'name': z.string(),
71
72
  'enabled': z.boolean(),
@@ -74,6 +75,16 @@ const dsh_plugin_shop_shop_setEnabled_result$schema = z.object({
74
75
  'ok': z.boolean(),
75
76
  'detail': z.union([z.undefined(), z.string()]).optional(),
76
77
  })
78
+ const dsh_plugin_shop_shop_uninstallStart_parameter_0$schema = z.object({
79
+ 'name': z.string(),
80
+ })
81
+ const dsh_plugin_shop_shop_uninstallStart_result$schema = z.union([z.object({
82
+ 'ok': z.literal(true),
83
+ 'installId': z.string(),
84
+ }), z.object({
85
+ 'ok': z.literal(false),
86
+ 'detail': z.string(),
87
+ })])
77
88
 
78
89
  export const TYPERT = {
79
90
  package: 'dsh-plugin-shop',
@@ -105,7 +116,22 @@ export const TYPERT = {
105
116
  typeSymbol: 'dsh-plugin-shop/types#ShopCatalogResult',
106
117
  schema: dsh_plugin_shop_shop_catalog_result$schema,
107
118
  },
108
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":180,"column":9},
119
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":190,"column":9},
120
+ },
121
+ {
122
+ id: 'dsh-plugin-shop#shop/installed',
123
+ service: 'shop',
124
+ namespace: 'shop',
125
+ method: 'installed',
126
+ invocation: { kind: 'direct' },
127
+ parameters: [
128
+ ],
129
+ result: {
130
+ mode: 'strict',
131
+ typeSymbol: 'dsh-plugin-shop#shop/installed:result',
132
+ schema: dsh_plugin_shop_shop_installed_result$schema,
133
+ },
134
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":265,"column":9},
109
135
  },
110
136
  {
111
137
  id: 'dsh-plugin-shop#shop/installStart',
@@ -131,7 +157,7 @@ export const TYPERT = {
131
157
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallResult',
132
158
  schema: dsh_plugin_shop_shop_installStart_result$schema,
133
159
  },
134
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":206,"column":9},
160
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":216,"column":9},
135
161
  },
136
162
  {
137
163
  id: 'dsh-plugin-shop#shop/installStatus',
@@ -156,28 +182,39 @@ export const TYPERT = {
156
182
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallStatusResult',
157
183
  schema: dsh_plugin_shop_shop_installStatus_result$schema,
158
184
  },
159
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":3},
185
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":254,"column":3},
160
186
  },
161
187
  {
162
- id: 'dsh-plugin-shop#shop/outdated',
188
+ id: 'dsh-plugin-shop#shop/setEnabled',
163
189
  service: 'shop',
164
190
  namespace: 'shop',
165
- method: 'outdated',
191
+ method: 'setEnabled',
166
192
  invocation: { kind: 'direct' },
167
193
  parameters: [
194
+ {
195
+ name: 'args',
196
+ wire: 'args',
197
+ source: 'json',
198
+ codec: {
199
+ mode: 'strict',
200
+ typeSymbol: 'dsh-plugin-shop#shop/setEnabled:args',
201
+ schema: dsh_plugin_shop_shop_setEnabled_parameter_0$schema,
202
+ },
203
+ },
168
204
  ],
169
205
  result: {
170
206
  mode: 'strict',
171
- typeSymbol: 'dsh-plugin-shop#shop/outdated:result',
172
- schema: dsh_plugin_shop_shop_outdated_result$schema,
207
+ typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
208
+ schema: dsh_plugin_shop_shop_setEnabled_result$schema,
173
209
  },
174
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":252,"column":9},
210
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":159,"column":3},
175
211
  },
176
212
  {
177
- id: 'dsh-plugin-shop#shop/setEnabled',
213
+ id: 'dsh-plugin-shop#shop/uninstallStart',
178
214
  service: 'shop',
179
215
  namespace: 'shop',
180
- method: 'setEnabled',
216
+ method: 'uninstallStart',
217
+ implementation: 'uninstall',
181
218
  invocation: { kind: 'direct' },
182
219
  parameters: [
183
220
  {
@@ -186,17 +223,17 @@ export const TYPERT = {
186
223
  source: 'json',
187
224
  codec: {
188
225
  mode: 'strict',
189
- typeSymbol: 'dsh-plugin-shop#shop/setEnabled:args',
190
- schema: dsh_plugin_shop_shop_setEnabled_parameter_0$schema,
226
+ typeSymbol: 'dsh-plugin-shop#shop/uninstallStart:args',
227
+ schema: dsh_plugin_shop_shop_uninstallStart_parameter_0$schema,
191
228
  },
192
229
  },
193
230
  ],
194
231
  result: {
195
232
  mode: 'strict',
196
- typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
197
- schema: dsh_plugin_shop_shop_setEnabled_result$schema,
233
+ typeSymbol: 'dsh-plugin-shop/types#ShopUninstallResult',
234
+ schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
198
235
  },
199
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":149,"column":3},
236
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":305,"column":9},
200
237
  },
201
238
  ],
202
239
  model: {
@@ -245,10 +282,17 @@ export const TYPERT = {
245
282
  },
246
283
  {
247
284
  "kind": "method",
248
- "name": "outdated",
249
- "signature": "@Remote('outdated') async outdated(): Promise<ShopOutdatedEntry[]>",
250
- "summary": "Installed plugins whose installed version is older than the catalog's (§7.3).",
251
- "jsDoc": "/** Installed plugins whose installed version is older than the catalog's (§7.3). */"
285
+ "name": "installed",
286
+ "signature": "@Remote('installed') async installed(): Promise<ShopInstalledEntry[]>",
287
+ "summary": "Installed catalog plugins (§7.3): every entry of the snapshot the profile manifest declares as a dependency, with the Host's `outdated` verdict attached.",
288
+ "jsDoc": "/** Installed catalog plugins (§7.3): every entry of the snapshot the profile\n * manifest declares as a dependency, with the Host's `outdated` verdict\n * attached. The tab's shelf cards and its installed section both derive\n * from this one list. */"
289
+ },
290
+ {
291
+ "kind": "method",
292
+ "name": "uninstall",
293
+ "signature": "@Remote('uninstallStart') async uninstall(args: { name: string }): Promise<ShopUninstallResult>",
294
+ "summary": "Uninstall one installed catalog plugin from the profile (§7.3 follow-up amendment).",
295
+ "jsDoc": "/** Uninstall one installed catalog plugin from the profile (§7.3 follow-up\n * amendment). Removing revokes privilege rather than granting it, so there\n * is no acknowledgement gate. The name must be a catalog entry the profile\n * manifest declares as a dependency — the RPC cannot remove profile\n * dependencies the shop does not manage (the base bundle, the shop\n * itself). The same install records/polling serve the client. */"
252
296
  }
253
297
  ],
254
298
  "types": [
@@ -288,6 +332,10 @@ export const TYPERT = {
288
332
  "name": "ShopCatalogResult",
289
333
  "declaration": "export interface ShopCatalogResult {\n schemaVersion: number;\n builtAt: string;\n stale: boolean;\n plugins: CatalogEntry[];\n denied: DeniedEntry[];\n stars: Record<string, number>;\n}"
290
334
  },
335
+ {
336
+ "name": "ShopInstalledEntry",
337
+ "declaration": "export interface ShopInstalledEntry {\n name: string;\n installed: string;\n latest: string;\n outdated: boolean;\n}"
338
+ },
291
339
  {
292
340
  "name": "ShopInstallResult",
293
341
  "declaration": "export type ShopInstallResult = { ok: true; installId: string; } | { ok: false; code: InstallRejectionCode; detail: string; };"
@@ -296,13 +344,13 @@ export const TYPERT = {
296
344
  "name": "ShopInstallStatusResult",
297
345
  "declaration": "export interface ShopInstallStatusResult extends InstallStatus {\n found: boolean;\n}"
298
346
  },
299
- {
300
- "name": "ShopOutdatedEntry",
301
- "declaration": "export interface ShopOutdatedEntry {\n name: string;\n installed: string;\n latest: string;\n}"
302
- },
303
347
  {
304
348
  "name": "ShopSetEnabledResult",
305
349
  "declaration": "export interface ShopSetEnabledResult {\n ok: boolean;\n detail?: string;\n}"
350
+ },
351
+ {
352
+ "name": "ShopUninstallResult",
353
+ "declaration": "export type ShopUninstallResult = { ok: true; installId: string; } | { ok: false; detail: string; };"
306
354
  }
307
355
  ]
308
356
  }
@@ -3,22 +3,24 @@ import type {
3
3
  RemoteResult,
4
4
  TypertRemoteContribution,
5
5
  } from '@deepseek-ai/dsh-typert-protocol'
6
- import type { InstallArgs, ShopCatalogResult, ShopInstallResult, ShopInstallStatusResult, ShopOutdatedEntry, ShopSetEnabledResult } from 'dsh-plugin-shop/types'
6
+ import type { InstallArgs, ShopCatalogResult, ShopInstalledEntry, ShopInstallResult, ShopInstallStatusResult, ShopSetEnabledResult, ShopUninstallResult } from 'dsh-plugin-shop/types'
7
7
 
8
8
  declare module '@deepseek-ai/dsh-typert-protocol' {
9
9
  interface TypertRemoteNamespace$73686f70 {
10
10
  catalog: (args?: { refresh?: boolean; }) => Promise<RemoteResult<ShopCatalogResult>>
11
+ installed: () => Promise<RemoteResult<ShopInstalledEntry[]>>
11
12
  installStart: (args: InstallArgs) => Promise<RemoteResult<ShopInstallResult>>
12
13
  installStatus: (args: { installId: string; }) => Promise<RemoteResult<ShopInstallStatusResult>>
13
- outdated: () => Promise<RemoteResult<ShopOutdatedEntry[]>>
14
14
  setEnabled: (args: { name: string; enabled: boolean; }) => Promise<RemoteResult<ShopSetEnabledResult>>
15
+ uninstallStart: (args: { name: string; }) => Promise<RemoteResult<ShopUninstallResult>>
15
16
  }
16
17
  interface TypertRemoteMap {
17
18
  'shop/catalog': (args?: { refresh?: boolean; }) => Promise<RemoteResult<ShopCatalogResult>>
19
+ 'shop/installed': () => Promise<RemoteResult<ShopInstalledEntry[]>>
18
20
  'shop/installStart': (args: InstallArgs) => Promise<RemoteResult<ShopInstallResult>>
19
21
  'shop/installStatus': (args: { installId: string; }) => Promise<RemoteResult<ShopInstallStatusResult>>
20
- 'shop/outdated': () => Promise<RemoteResult<ShopOutdatedEntry[]>>
21
22
  'shop/setEnabled': (args: { name: string; enabled: boolean; }) => Promise<RemoteResult<ShopSetEnabledResult>>
23
+ 'shop/uninstallStart': (args: { name: string; }) => Promise<RemoteResult<ShopUninstallResult>>
22
24
  }
23
25
  interface TypertRemoteNamespaceMap {
24
26
  'shop': TypertRemoteNamespace$73686f70
@@ -38,6 +38,12 @@ const dsh_plugin_shop_shop_catalog_result$schema = z.object({
38
38
  })),
39
39
  'stars': z.record(z.string(), z.number()),
40
40
  })
41
+ const dsh_plugin_shop_shop_installed_result$schema = z.array(z.object({
42
+ 'name': z.string(),
43
+ 'installed': z.string(),
44
+ 'latest': z.string(),
45
+ 'outdated': z.boolean(),
46
+ }))
41
47
  const dsh_plugin_shop_shop_installStart_parameter_0$schema = z.object({
42
48
  'name': z.string(),
43
49
  'version': z.string(),
@@ -61,11 +67,6 @@ const dsh_plugin_shop_shop_installStatus_result$schema = z.object({
61
67
  'needsRestart': z.union([z.undefined(), z.literal(false), z.literal(true)]).optional(),
62
68
  'detail': z.union([z.undefined(), z.string()]).optional(),
63
69
  })
64
- const dsh_plugin_shop_shop_outdated_result$schema = z.array(z.object({
65
- 'name': z.string(),
66
- 'installed': z.string(),
67
- 'latest': z.string(),
68
- }))
69
70
  const dsh_plugin_shop_shop_setEnabled_parameter_0$schema = z.object({
70
71
  'name': z.string(),
71
72
  'enabled': z.boolean(),
@@ -74,6 +75,16 @@ const dsh_plugin_shop_shop_setEnabled_result$schema = z.object({
74
75
  'ok': z.boolean(),
75
76
  'detail': z.union([z.undefined(), z.string()]).optional(),
76
77
  })
78
+ const dsh_plugin_shop_shop_uninstallStart_parameter_0$schema = z.object({
79
+ 'name': z.string(),
80
+ })
81
+ const dsh_plugin_shop_shop_uninstallStart_result$schema = z.union([z.object({
82
+ 'ok': z.literal(true),
83
+ 'installId': z.string(),
84
+ }), z.object({
85
+ 'ok': z.literal(false),
86
+ 'detail': z.string(),
87
+ })])
77
88
 
78
89
  export const TYPERT_REMOTE = {
79
90
  package: 'dsh-plugin-shop',
@@ -102,7 +113,22 @@ export const TYPERT_REMOTE = {
102
113
  typeSymbol: 'dsh-plugin-shop/types#ShopCatalogResult',
103
114
  schema: dsh_plugin_shop_shop_catalog_result$schema,
104
115
  },
105
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":180,"column":9},
116
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":190,"column":9},
117
+ },
118
+ {
119
+ id: 'dsh-plugin-shop#shop/installed',
120
+ service: 'shop',
121
+ namespace: 'shop',
122
+ method: 'installed',
123
+ invocation: { kind: 'direct' },
124
+ parameters: [
125
+ ],
126
+ result: {
127
+ mode: 'strict',
128
+ typeSymbol: 'dsh-plugin-shop#shop/installed:result',
129
+ schema: dsh_plugin_shop_shop_installed_result$schema,
130
+ },
131
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":265,"column":9},
106
132
  },
107
133
  {
108
134
  id: 'dsh-plugin-shop#shop/installStart',
@@ -128,7 +154,7 @@ export const TYPERT_REMOTE = {
128
154
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallResult',
129
155
  schema: dsh_plugin_shop_shop_installStart_result$schema,
130
156
  },
131
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":206,"column":9},
157
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":216,"column":9},
132
158
  },
133
159
  {
134
160
  id: 'dsh-plugin-shop#shop/installStatus',
@@ -153,28 +179,39 @@ export const TYPERT_REMOTE = {
153
179
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallStatusResult',
154
180
  schema: dsh_plugin_shop_shop_installStatus_result$schema,
155
181
  },
156
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":3},
182
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":254,"column":3},
157
183
  },
158
184
  {
159
- id: 'dsh-plugin-shop#shop/outdated',
185
+ id: 'dsh-plugin-shop#shop/setEnabled',
160
186
  service: 'shop',
161
187
  namespace: 'shop',
162
- method: 'outdated',
188
+ method: 'setEnabled',
163
189
  invocation: { kind: 'direct' },
164
190
  parameters: [
191
+ {
192
+ name: 'args',
193
+ wire: 'args',
194
+ source: 'json',
195
+ codec: {
196
+ mode: 'strict',
197
+ typeSymbol: 'dsh-plugin-shop#shop/setEnabled:args',
198
+ schema: dsh_plugin_shop_shop_setEnabled_parameter_0$schema,
199
+ },
200
+ },
165
201
  ],
166
202
  result: {
167
203
  mode: 'strict',
168
- typeSymbol: 'dsh-plugin-shop#shop/outdated:result',
169
- schema: dsh_plugin_shop_shop_outdated_result$schema,
204
+ typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
205
+ schema: dsh_plugin_shop_shop_setEnabled_result$schema,
170
206
  },
171
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":252,"column":9},
207
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":159,"column":3},
172
208
  },
173
209
  {
174
- id: 'dsh-plugin-shop#shop/setEnabled',
210
+ id: 'dsh-plugin-shop#shop/uninstallStart',
175
211
  service: 'shop',
176
212
  namespace: 'shop',
177
- method: 'setEnabled',
213
+ method: 'uninstallStart',
214
+ implementation: 'uninstall',
178
215
  invocation: { kind: 'direct' },
179
216
  parameters: [
180
217
  {
@@ -183,17 +220,17 @@ export const TYPERT_REMOTE = {
183
220
  source: 'json',
184
221
  codec: {
185
222
  mode: 'strict',
186
- typeSymbol: 'dsh-plugin-shop#shop/setEnabled:args',
187
- schema: dsh_plugin_shop_shop_setEnabled_parameter_0$schema,
223
+ typeSymbol: 'dsh-plugin-shop#shop/uninstallStart:args',
224
+ schema: dsh_plugin_shop_shop_uninstallStart_parameter_0$schema,
188
225
  },
189
226
  },
190
227
  ],
191
228
  result: {
192
229
  mode: 'strict',
193
- typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
194
- schema: dsh_plugin_shop_shop_setEnabled_result$schema,
230
+ typeSymbol: 'dsh-plugin-shop/types#ShopUninstallResult',
231
+ schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
195
232
  },
196
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":149,"column":3},
233
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":305,"column":9},
197
234
  },
198
235
  ],
199
236
  }
@@ -5,7 +5,7 @@
5
5
  * §11.3.4): no render path here may ever use dangerouslySetInnerHTML. */
6
6
  import { type ReactNode } from 'react';
7
7
  import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
8
- import type { InstallArgs, ShopCatalogResult, ShopInstallResult, ShopInstallStatusResult, ShopOutdatedEntry, ShopSetEnabledResult } from '../host/index.ts';
8
+ import type { InstallArgs, ShopCatalogResult, ShopInstalledEntry, ShopInstallResult, ShopInstallStatusResult, ShopSetEnabledResult, ShopUninstallResult } from '../host/index.ts';
9
9
  /** The tab's Remote face: the Host result types, already unwrapped from the
10
10
  * wire envelope by `index.ts`; `catalog` throws on a wire error so the tab's
11
11
  * error state renders. */
@@ -21,7 +21,10 @@ export interface ShopTabInjected {
21
21
  name: string;
22
22
  enabled: boolean;
23
23
  }) => Promise<ShopSetEnabledResult>;
24
- outdated: () => Promise<ShopOutdatedEntry[]>;
24
+ installed: () => Promise<ShopInstalledEntry[]>;
25
+ uninstall: (args: {
26
+ name: string;
27
+ }) => Promise<ShopUninstallResult>;
25
28
  }
26
29
  /** Full component props assembled by the Settings slot renderer. */
27
30
  export type ShopTabProps = PropsRuntime<'settings.plugins.tab'> & PropsLocale<'settings.shop'> & InjectFace<ShopTabInjected>;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shop settings surface, browser half — one tab in `settings.plugins.tab`
3
3
  * that browses the catalog, installs with acknowledgement, toggles
4
- * enablement, and lists outdated installs. Mounts the shop Remote itself
4
+ * enablement, and lists installed plugins. Mounts the shop Remote itself
5
5
  * (the assembly does not know this package) and holds no privilege beyond
6
6
  * the five `shop/*` methods (§5.3).
7
7
  */