dsh-plugin-shop 0.4.3 → 0.4.5

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
@@ -1,13 +1,23 @@
1
1
  import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
2
2
  import { loadOptionalPatches, readProfileManifest, resolveProfileDir } from "@deepseek-ai/dsh-app-boot";
3
- import { lt, minVersion } from "semver";
3
+ import { lt, minVersion, valid } from "semver";
4
4
  import { fileURLToPath } from "node:url";
5
- import { createHash, randomUUID } from "node:crypto";
6
- import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from "node:fs";
7
5
  import { basename, dirname, join } from "node:path";
6
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, writeFileSync } from "node:fs";
7
+ import { createHash, randomUUID } from "node:crypto";
8
8
  import { z } from "zod";
9
9
  import { spawn } from "node:child_process";
10
10
  import { dump } from "js-yaml";
11
+ //#region src/own-version.ts
12
+ /** The shop's own published version, read from the package.json that ships
13
+ * next to this package — the RUNNING version, not the manifest's range
14
+ * spec. This lives at the package root (not under src/host) on purpose:
15
+ * both the source tree (tests) and the bundled `lib/index.js` sit exactly
16
+ * one level below the package root, so the same relative URL resolves in
17
+ * both. */
18
+ function ownVersion() {
19
+ return JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8")).version;
20
+ }
11
21
  /** A cached catalog younger than this is served without touching the network. */
12
22
  const FRESH_MS = 3e5;
13
23
  /** Records when the loader itself wrote the cache; the pointer's `builtAt` is
@@ -419,82 +429,72 @@ function startUninstall(options) {
419
429
  }
420
430
  //#endregion
421
431
  //#region src/host/restart.ts
422
- /** Restart executor: re-spawn the Host's own command line and hand the
423
- * browser the new server's URL. The child is detached (its own process
424
- * group), so it survives both the parent's exit and the launching
425
- * terminal's. The parent exits only AFTER the child printed its
426
- * `dsh web: <url>` line — a restart that fails to come up leaves the old
427
- * process running untouched. */
428
- /** How long to wait for the child to print its URL before declaring the
429
- * restart failed and killing the child. dsh web prints the URL once the
430
- * Loader tree settles; 20s is generous on slow machines. */
431
- const RESTART_UP_TIMEOUT_MS = 2e4;
432
- /** Spawn the restarted server and wait for it to announce its URL.
432
+ /** Restart executor: hand the port to a new dsh instance, two-phase.
433
433
  *
434
- * The child runs the same `dsh` with the same argv the current process was
435
- * launched with (`process.argv.slice(2)` node and the CLI script path
436
- * stripped), so the profile, port and flags reproduce the user's launch
437
- * verbatim. `--port 0` therefore yields a NEW port, and the returned URL is
438
- * how the browser finds it.
434
+ * The old process cannot wait for the new one: the new one must bind the
435
+ * port the old one still holds, and two live processes cannot bind it at
436
+ * once the first implementation spawned the child and waited for its URL,
437
+ * and the child crashed in boot with EADDRINUSE every time. The handoff is
438
+ * therefore inverted: the parent commits and exits FIRST, and a detached
439
+ * helper waits for the parent's pid to disappear before exec'ing the same
440
+ * dsh command line. The browser monitors the origin and refreshes once the
441
+ * new server answers; a boot that fails is diagnosed from the log file,
442
+ * since nobody is attached to the child's pipes. */
443
+ /** Spawn the two-phase handoff. The helper is a POSIX shell wrapper that
444
+ * polls the parent pid until it is gone, then replaces itself with the dsh
445
+ * command — `exec "$@"` keeps the argv verbatim, so no argument quoting is
446
+ * involved. The child's stdout/stderr go to `logFile`, opened here in
447
+ * append mode; opening throws on failure, and the caller treats a throw as
448
+ * a refusal (the restart is never committed without its log).
439
449
  *
440
- * On success the caller exits the old process but only after delivering
441
- * the RPC response carrying `url`, which is the caller's sequencing duty,
442
- * not this module's. On failure (child exits before announcing, spawn
443
- * error, or the timeout) the child is killed if still running and the old
444
- * process is untouched. */
450
+ * The pid-poll has the usual tiny reuse raceif the parent's pid is
451
+ * recycled within the 0.2s polling gap the helper waits for the unrelated
452
+ * process too. Harmless: it only delays the boot. */
445
453
  function startRestart(options) {
446
- const { dshBin, argv, env, timeoutMs = RESTART_UP_TIMEOUT_MS } = options;
447
- const stderr = [];
448
- return new Promise((resolve) => {
449
- const child = spawn(dshBin, argv, {
454
+ const { dshBin, argv, parentPid, logFile, env } = options;
455
+ const logFd = openSync(logFile, "a");
456
+ try {
457
+ spawn("sh", [
458
+ "-c",
459
+ "while kill -0 \"$1\" 2>/dev/null; do sleep 0.2; done; shift; exec \"$@\"",
460
+ "sh",
461
+ String(parentPid),
462
+ dshBin,
463
+ ...argv
464
+ ], {
450
465
  stdio: [
451
466
  "ignore",
452
- "pipe",
453
- "pipe"
467
+ logFd,
468
+ logFd
454
469
  ],
455
470
  env: env ?? process.env,
456
471
  detached: true
457
- });
458
- child.unref();
459
- const timeout = setTimeout(() => {
460
- child.kill();
461
- resolve({
462
- ok: false,
463
- detail: "the restarted server did not announce its URL in time"
464
- });
465
- }, timeoutMs);
466
- child.stdout.on("data", (chunk) => {
467
- for (const line of chunk.toString().split("\n")) {
468
- if (line === "") continue;
469
- const match = /dsh web: (http:\/\/\S+)/.exec(line);
470
- if (match?.[1] !== void 0) {
471
- clearTimeout(timeout);
472
- resolve({
473
- ok: true,
474
- url: match[1]
475
- });
476
- }
477
- }
478
- });
479
- child.stderr.on("data", (chunk) => {
480
- for (const line of chunk.toString().split("\n")) if (line !== "") stderr.push(line);
481
- });
482
- child.on("error", (error) => {
483
- const code = error.code;
484
- clearTimeout(timeout);
485
- resolve({
486
- ok: false,
487
- detail: code === "ENOENT" ? "dsh not found on PATH — restart could not be launched" : `restart spawn failed: ${error.message}`
488
- });
489
- });
490
- child.on("close", () => {
491
- clearTimeout(timeout);
492
- resolve({
493
- ok: false,
494
- detail: `the restarted server exited during boot — ${stderr[stderr.length - 1] ?? "no output"}`
495
- });
496
- });
497
- });
472
+ }).unref();
473
+ } finally {
474
+ closeSync(logFd);
475
+ }
476
+ }
477
+ //#endregion
478
+ //#region src/host/self-update.ts
479
+ /** Self-update version check: the shop's latest published version, from the
480
+ * npm packument. Advisory by design — like the stars sidecar, a failed
481
+ * check degrades to `null` and never throws, never blocks a publish. The
482
+ * catalog cannot serve here: the shop is bootstrap-installed and is not
483
+ * harvested into its own catalog. */
484
+ /** The npm package the shop itself is published as. */
485
+ const SHOP_PACKAGE = "dsh-plugin-shop";
486
+ /** Fetch the shop's `latest` dist-tag, or `null` when the registry cannot
487
+ * answer (network failure, unexpected payload — anything). The caller
488
+ * renders `null` as "no update check", never as a failure. */
489
+ async function fetchLatestVersion(fetchFn = fetch) {
490
+ try {
491
+ const response = await fetchFn(`https://registry.npmjs.org/${SHOP_PACKAGE}`);
492
+ if (!response.ok) return null;
493
+ const latest = (await response.json())["dist-tags"]?.latest;
494
+ return typeof latest === "string" ? latest : null;
495
+ } catch {
496
+ return null;
497
+ }
498
498
  }
499
499
  //#endregion
500
500
  //#region src/host/profile.ts
@@ -623,6 +623,8 @@ let ShopGateway = (() => {
623
623
  let _installed_decorators;
624
624
  let _uninstall_decorators;
625
625
  let _restart_decorators;
626
+ let _version_decorators;
627
+ let _updateStart_decorators;
626
628
  return class ShopGateway extends _classSuper {
627
629
  static {
628
630
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -633,6 +635,8 @@ let ShopGateway = (() => {
633
635
  _installed_decorators = [Remote("installed")];
634
636
  _uninstall_decorators = [Remote("uninstallStart")];
635
637
  _restart_decorators = [Remote("restart")];
638
+ _version_decorators = [Remote("version")];
639
+ _updateStart_decorators = [Remote("updateStart")];
636
640
  __esDecorate(this, null, _setEnabled_decorators, {
637
641
  kind: "method",
638
642
  name: "setEnabled",
@@ -710,6 +714,28 @@ let ShopGateway = (() => {
710
714
  },
711
715
  metadata: _metadata
712
716
  }, null, _instanceExtraInitializers);
717
+ __esDecorate(this, null, _version_decorators, {
718
+ kind: "method",
719
+ name: "version",
720
+ static: false,
721
+ private: false,
722
+ access: {
723
+ has: (obj) => "version" in obj,
724
+ get: (obj) => obj.version
725
+ },
726
+ metadata: _metadata
727
+ }, null, _instanceExtraInitializers);
728
+ __esDecorate(this, null, _updateStart_decorators, {
729
+ kind: "method",
730
+ name: "updateStart",
731
+ static: false,
732
+ private: false,
733
+ access: {
734
+ has: (obj) => "updateStart" in obj,
735
+ get: (obj) => obj.updateStart
736
+ },
737
+ metadata: _metadata
738
+ }, null, _instanceExtraInitializers);
713
739
  if (_metadata) Object.defineProperty(this, Symbol.metadata, {
714
740
  enumerable: true,
715
741
  configurable: true,
@@ -731,6 +757,8 @@ let ShopGateway = (() => {
731
757
  * production, a spy in tests. */
732
758
  exit;
733
759
  restartExitDelayMs;
760
+ restartParentPid;
761
+ latestVersion;
734
762
  /** The install gate runs against the last loaded snapshot, never a fresh
735
763
  * fetch per request (§7.2: the Host's cached snapshot is the truth). */
736
764
  /** Finished install records retained, so a poll sees the true terminal
@@ -756,6 +784,8 @@ let ShopGateway = (() => {
756
784
  this.restartArgv = options.restartArgv ?? process.argv.slice(2);
757
785
  this.exit = options.exit ?? ((code) => process.exit(code));
758
786
  this.restartExitDelayMs = options.restartExitDelayMs ?? ShopGateway.RESTART_EXIT_DELAY_MS;
787
+ this.restartParentPid = options.restartParentPid ?? process.pid;
788
+ this.latestVersion = options.fetchLatestVersion ?? (() => fetchLatestVersion());
759
789
  }
760
790
  /** The boot's Loader root directory (the active profile's `cordis.yml`
761
791
  * directory, carried on `ctx.baseUrl`), when present. A `link:` install
@@ -971,19 +1001,69 @@ let ShopGateway = (() => {
971
1001
  };
972
1002
  }
973
1003
  /** Restart the dsh process the shop runs in (§8 amendment, 2026-08-27):
974
- * re-spawn this process's own command line, return the new server's URL
975
- * once it announces itself, and only then exit. A failed restart returns a
976
- * typed failure and the old process keeps serving the restart is
977
- * all-or-nothing. The response must reach the browser before the exit, so
978
- * the exit is delayed past the RPC round-trip. */
1004
+ * commit a two-phase handoff a detached helper waits for this pid to
1005
+ * exit, then re-runs this process's own command line and exit once the
1006
+ * response is out. The browser monitors the origin and refreshes when the
1007
+ * new server answers. Refusals are issued before anything is torn down. */
979
1008
  async restart() {
980
- const outcome = await startRestart({
1009
+ const portIndex = this.restartArgv.indexOf("--port");
1010
+ if (portIndex !== -1 && this.restartArgv[portIndex + 1] === "0") return {
1011
+ ok: false,
1012
+ detail: "dsh-plugin-shop: restart is not supported when dsh was launched with --port 0; restart dsh manually"
1013
+ };
1014
+ try {
1015
+ const { cacheDir } = this.rowConfig();
1016
+ startRestart({
1017
+ dshBin: this.dshBin,
1018
+ argv: this.restartArgv,
1019
+ parentPid: this.restartParentPid,
1020
+ logFile: join(cacheDir, "restart.log"),
1021
+ env: process.env
1022
+ });
1023
+ } catch (error) {
1024
+ return {
1025
+ ok: false,
1026
+ detail: `dsh-plugin-shop: restart could not be started: ${error.message}`
1027
+ };
1028
+ }
1029
+ setTimeout(() => this.exit(0), this.restartExitDelayMs);
1030
+ return { ok: true };
1031
+ }
1032
+ /** The shop's own version and whether npm has a newer one (§7.3). The
1033
+ * check is advisory: a registry that cannot answer leaves `latest` null
1034
+ * and the client shows the version alone. `installed` is the RUNNING
1035
+ * version (own-version.ts), not the manifest's range spec. */
1036
+ async version() {
1037
+ const installed = ownVersion();
1038
+ const latest = await this.latestVersion();
1039
+ return {
1040
+ installed,
1041
+ latest,
1042
+ outdated: latest !== null && lt(installed, latest)
1043
+ };
1044
+ }
1045
+ /** Update the shop itself to a published version (§7.3): the explicit pin
1046
+ * is the only install form that bypasses pnpm's release cooldown. The
1047
+ * version is re-validated as plain semver at the boundary — the spec
1048
+ * `dsh-plugin-shop@<version>` is built here, never from the wire. */
1049
+ async updateStart(args) {
1050
+ if (valid(args.version) === null) return {
1051
+ ok: false,
1052
+ detail: `dsh-plugin-shop: ${args.version} is not a valid version`
1053
+ };
1054
+ const running = startInstall({
1055
+ profile: this.profile,
1056
+ spec: `dsh-plugin-shop@${args.version}`,
981
1057
  dshBin: this.dshBin,
982
- argv: this.restartArgv,
983
- env: process.env
1058
+ expectedName: "dsh-plugin-shop"
984
1059
  });
985
- if (outcome.ok) setTimeout(() => this.exit(0), this.restartExitDelayMs);
986
- return outcome;
1060
+ this.installs.set(running.installId, running);
1061
+ this.installOrder.push(running.installId);
1062
+ this.evictFinishedInstalls();
1063
+ return {
1064
+ ok: true,
1065
+ installId: running.installId
1066
+ };
987
1067
  }
988
1068
  };
989
1069
  })();
@@ -69,7 +69,6 @@ const dsh_plugin_shop_shop_installStatus_result$schema = z.object({
69
69
  })
70
70
  const dsh_plugin_shop_shop_restart_result$schema = z.union([z.object({
71
71
  'ok': z.literal(true),
72
- 'url': z.string(),
73
72
  }), z.object({
74
73
  'ok': z.literal(false),
75
74
  'detail': z.string(),
@@ -92,6 +91,21 @@ const dsh_plugin_shop_shop_uninstallStart_result$schema = z.union([z.object({
92
91
  'ok': z.literal(false),
93
92
  'detail': z.string(),
94
93
  })])
94
+ const dsh_plugin_shop_shop_updateStart_parameter_0$schema = z.object({
95
+ 'version': z.string(),
96
+ })
97
+ const dsh_plugin_shop_shop_updateStart_result$schema = z.union([z.object({
98
+ 'ok': z.literal(true),
99
+ 'installId': z.string(),
100
+ }), z.object({
101
+ 'ok': z.literal(false),
102
+ 'detail': z.string(),
103
+ })])
104
+ const dsh_plugin_shop_shop_version_result$schema = z.object({
105
+ 'installed': z.string(),
106
+ 'latest': z.union([z.literal(null), z.string()]),
107
+ 'outdated': z.boolean(),
108
+ })
95
109
 
96
110
  export const TYPERT = {
97
111
  package: 'dsh-plugin-shop',
@@ -123,7 +137,7 @@ export const TYPERT = {
123
137
  typeSymbol: 'dsh-plugin-shop/types#ShopCatalogResult',
124
138
  schema: dsh_plugin_shop_shop_catalog_result$schema,
125
139
  },
126
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":218,"column":9},
140
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":9},
127
141
  },
128
142
  {
129
143
  id: 'dsh-plugin-shop#shop/installed',
@@ -138,7 +152,7 @@ export const TYPERT = {
138
152
  typeSymbol: 'dsh-plugin-shop#shop/installed:result',
139
153
  schema: dsh_plugin_shop_shop_installed_result$schema,
140
154
  },
141
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":293,"column":9},
155
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":319,"column":9},
142
156
  },
143
157
  {
144
158
  id: 'dsh-plugin-shop#shop/installStart',
@@ -164,7 +178,7 @@ export const TYPERT = {
164
178
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallResult',
165
179
  schema: dsh_plugin_shop_shop_installStart_result$schema,
166
180
  },
167
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":9},
181
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":270,"column":9},
168
182
  },
169
183
  {
170
184
  id: 'dsh-plugin-shop#shop/installStatus',
@@ -189,7 +203,7 @@ export const TYPERT = {
189
203
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallStatusResult',
190
204
  schema: dsh_plugin_shop_shop_installStatus_result$schema,
191
205
  },
192
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":282,"column":3},
206
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":308,"column":3},
193
207
  },
194
208
  {
195
209
  id: 'dsh-plugin-shop#shop/restart',
@@ -204,7 +218,7 @@ export const TYPERT = {
204
218
  typeSymbol: 'dsh-plugin-shop/types#ShopRestartResult',
205
219
  schema: dsh_plugin_shop_shop_restart_result$schema,
206
220
  },
207
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":367,"column":9},
221
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":392,"column":9},
208
222
  },
209
223
  {
210
224
  id: 'dsh-plugin-shop#shop/setEnabled',
@@ -229,7 +243,7 @@ export const TYPERT = {
229
243
  typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
230
244
  schema: dsh_plugin_shop_shop_setEnabled_result$schema,
231
245
  },
232
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":187,"column":3},
246
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":213,"column":3},
233
247
  },
234
248
  {
235
249
  id: 'dsh-plugin-shop#shop/uninstallStart',
@@ -255,7 +269,47 @@ export const TYPERT = {
255
269
  typeSymbol: 'dsh-plugin-shop/types#ShopUninstallResult',
256
270
  schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
257
271
  },
258
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":333,"column":9},
272
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":359,"column":9},
273
+ },
274
+ {
275
+ id: 'dsh-plugin-shop#shop/updateStart',
276
+ service: 'shop',
277
+ namespace: 'shop',
278
+ method: 'updateStart',
279
+ invocation: { kind: 'direct' },
280
+ parameters: [
281
+ {
282
+ name: 'args',
283
+ wire: 'args',
284
+ source: 'json',
285
+ codec: {
286
+ mode: 'strict',
287
+ typeSymbol: 'dsh-plugin-shop#shop/updateStart:args',
288
+ schema: dsh_plugin_shop_shop_updateStart_parameter_0$schema,
289
+ },
290
+ },
291
+ ],
292
+ result: {
293
+ mode: 'strict',
294
+ typeSymbol: 'dsh-plugin-shop/types#ShopUpdateResult',
295
+ schema: dsh_plugin_shop_shop_updateStart_result$schema,
296
+ },
297
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":441,"column":9},
298
+ },
299
+ {
300
+ id: 'dsh-plugin-shop#shop/version',
301
+ service: 'shop',
302
+ namespace: 'shop',
303
+ method: 'version',
304
+ invocation: { kind: 'direct' },
305
+ parameters: [
306
+ ],
307
+ result: {
308
+ mode: 'strict',
309
+ typeSymbol: 'dsh-plugin-shop/types#ShopVersionResult',
310
+ schema: dsh_plugin_shop_shop_version_result$schema,
311
+ },
312
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":426,"column":9},
259
313
  },
260
314
  ],
261
315
  model: {
@@ -320,8 +374,22 @@ export const TYPERT = {
320
374
  "kind": "method",
321
375
  "name": "restart",
322
376
  "signature": "@Remote('restart') async restart(): Promise<ShopRestartResult>",
323
- "summary": "Restart the dsh process the shop runs in (§8 amendment, 2026-08-27): re-spawn this process's own command line, return the new server's URL once it announces itself, and only then exit.",
324
- "jsDoc": "/** Restart the dsh process the shop runs in (§8 amendment, 2026-08-27):\n * re-spawn this process's own command line, return the new server's URL\n * once it announces itself, and only then exit. A failed restart returns a\n * typed failure and the old process keeps serving the restart is\n * all-or-nothing. The response must reach the browser before the exit, so\n * the exit is delayed past the RPC round-trip. */"
377
+ "summary": "Restart the dsh process the shop runs in (§8 amendment, 2026-08-27): commit a two-phase handoff — a detached helper waits for this pid to exit, then re-runs this process's own command line and exit once the response is out.",
378
+ "jsDoc": "/** Restart the dsh process the shop runs in (§8 amendment, 2026-08-27):\n * commit a two-phase handoff a detached helper waits for this pid to\n * exit, then re-runs this process's own command line and exit once the\n * response is out. The browser monitors the origin and refreshes when the\n * new server answers. Refusals are issued before anything is torn down. */"
379
+ },
380
+ {
381
+ "kind": "method",
382
+ "name": "version",
383
+ "signature": "@Remote('version') async version(): Promise<ShopVersionResult>",
384
+ "summary": "The shop's own version and whether npm has a newer one (§7.3).",
385
+ "jsDoc": "/** The shop's own version and whether npm has a newer one (§7.3). The\n * check is advisory: a registry that cannot answer leaves `latest` null\n * and the client shows the version alone. `installed` is the RUNNING\n * version (own-version.ts), not the manifest's range spec. */"
386
+ },
387
+ {
388
+ "kind": "method",
389
+ "name": "updateStart",
390
+ "signature": "@Remote('updateStart') async updateStart(args: { version: string }): Promise<ShopUpdateResult>",
391
+ "summary": "Update the shop itself to a published version (§7.3): the explicit pin is the only install form that bypasses pnpm's release cooldown.",
392
+ "jsDoc": "/** Update the shop itself to a published version (§7.3): the explicit pin\n * is the only install form that bypasses pnpm's release cooldown. The\n * version is re-validated as plain semver at the boundary — the spec\n * `dsh-plugin-shop@<version>` is built here, never from the wire. */"
325
393
  }
326
394
  ],
327
395
  "types": [
@@ -359,7 +427,7 @@ export const TYPERT = {
359
427
  },
360
428
  {
361
429
  "name": "RestartOutcome",
362
- "declaration": "export type RestartOutcome = { ok: true; url: string; } | { ok: false; detail: string; };"
430
+ "declaration": "export type RestartOutcome = { ok: true; } | { ok: false; detail: string; };"
363
431
  },
364
432
  {
365
433
  "name": "ShopCatalogResult",
@@ -388,6 +456,14 @@ export const TYPERT = {
388
456
  {
389
457
  "name": "ShopUninstallResult",
390
458
  "declaration": "export type ShopUninstallResult = { ok: true; installId: string; } | { ok: false; detail: string; };"
459
+ },
460
+ {
461
+ "name": "ShopUpdateResult",
462
+ "declaration": "export type ShopUpdateResult = { ok: true; installId: string; } | { ok: false; detail: string; };"
463
+ },
464
+ {
465
+ "name": "ShopVersionResult",
466
+ "declaration": "export interface ShopVersionResult {\n installed: string;\n latest: string | null;\n outdated: boolean;\n}"
391
467
  }
392
468
  ]
393
469
  }
@@ -3,7 +3,7 @@ import type {
3
3
  RemoteResult,
4
4
  TypertRemoteContribution,
5
5
  } from '@deepseek-ai/dsh-typert-protocol'
6
- import type { InstallArgs, ShopCatalogResult, ShopInstalledEntry, ShopInstallResult, ShopInstallStatusResult, ShopRestartResult, ShopSetEnabledResult, ShopUninstallResult } from 'dsh-plugin-shop/types'
6
+ import type { InstallArgs, ShopCatalogResult, ShopInstalledEntry, ShopInstallResult, ShopInstallStatusResult, ShopRestartResult, ShopSetEnabledResult, ShopUninstallResult, ShopUpdateResult, ShopVersionResult } from 'dsh-plugin-shop/types'
7
7
 
8
8
  declare module '@deepseek-ai/dsh-typert-protocol' {
9
9
  interface TypertRemoteNamespace$73686f70 {
@@ -14,6 +14,8 @@ declare module '@deepseek-ai/dsh-typert-protocol' {
14
14
  restart: () => Promise<RemoteResult<ShopRestartResult>>
15
15
  setEnabled: (args: { name: string; enabled: boolean; }) => Promise<RemoteResult<ShopSetEnabledResult>>
16
16
  uninstallStart: (args: { name: string; }) => Promise<RemoteResult<ShopUninstallResult>>
17
+ updateStart: (args: { version: string; }) => Promise<RemoteResult<ShopUpdateResult>>
18
+ version: () => Promise<RemoteResult<ShopVersionResult>>
17
19
  }
18
20
  interface TypertRemoteMap {
19
21
  'shop/catalog': (args?: { refresh?: boolean; }) => Promise<RemoteResult<ShopCatalogResult>>
@@ -23,6 +25,8 @@ declare module '@deepseek-ai/dsh-typert-protocol' {
23
25
  'shop/restart': () => Promise<RemoteResult<ShopRestartResult>>
24
26
  'shop/setEnabled': (args: { name: string; enabled: boolean; }) => Promise<RemoteResult<ShopSetEnabledResult>>
25
27
  'shop/uninstallStart': (args: { name: string; }) => Promise<RemoteResult<ShopUninstallResult>>
28
+ 'shop/updateStart': (args: { version: string; }) => Promise<RemoteResult<ShopUpdateResult>>
29
+ 'shop/version': () => Promise<RemoteResult<ShopVersionResult>>
26
30
  }
27
31
  interface TypertRemoteNamespaceMap {
28
32
  'shop': TypertRemoteNamespace$73686f70
@@ -69,7 +69,6 @@ const dsh_plugin_shop_shop_installStatus_result$schema = z.object({
69
69
  })
70
70
  const dsh_plugin_shop_shop_restart_result$schema = z.union([z.object({
71
71
  'ok': z.literal(true),
72
- 'url': z.string(),
73
72
  }), z.object({
74
73
  'ok': z.literal(false),
75
74
  'detail': z.string(),
@@ -92,6 +91,21 @@ const dsh_plugin_shop_shop_uninstallStart_result$schema = z.union([z.object({
92
91
  'ok': z.literal(false),
93
92
  'detail': z.string(),
94
93
  })])
94
+ const dsh_plugin_shop_shop_updateStart_parameter_0$schema = z.object({
95
+ 'version': z.string(),
96
+ })
97
+ const dsh_plugin_shop_shop_updateStart_result$schema = z.union([z.object({
98
+ 'ok': z.literal(true),
99
+ 'installId': z.string(),
100
+ }), z.object({
101
+ 'ok': z.literal(false),
102
+ 'detail': z.string(),
103
+ })])
104
+ const dsh_plugin_shop_shop_version_result$schema = z.object({
105
+ 'installed': z.string(),
106
+ 'latest': z.union([z.literal(null), z.string()]),
107
+ 'outdated': z.boolean(),
108
+ })
95
109
 
96
110
  export const TYPERT_REMOTE = {
97
111
  package: 'dsh-plugin-shop',
@@ -120,7 +134,7 @@ export const TYPERT_REMOTE = {
120
134
  typeSymbol: 'dsh-plugin-shop/types#ShopCatalogResult',
121
135
  schema: dsh_plugin_shop_shop_catalog_result$schema,
122
136
  },
123
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":218,"column":9},
137
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":9},
124
138
  },
125
139
  {
126
140
  id: 'dsh-plugin-shop#shop/installed',
@@ -135,7 +149,7 @@ export const TYPERT_REMOTE = {
135
149
  typeSymbol: 'dsh-plugin-shop#shop/installed:result',
136
150
  schema: dsh_plugin_shop_shop_installed_result$schema,
137
151
  },
138
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":293,"column":9},
152
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":319,"column":9},
139
153
  },
140
154
  {
141
155
  id: 'dsh-plugin-shop#shop/installStart',
@@ -161,7 +175,7 @@ export const TYPERT_REMOTE = {
161
175
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallResult',
162
176
  schema: dsh_plugin_shop_shop_installStart_result$schema,
163
177
  },
164
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":9},
178
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":270,"column":9},
165
179
  },
166
180
  {
167
181
  id: 'dsh-plugin-shop#shop/installStatus',
@@ -186,7 +200,7 @@ export const TYPERT_REMOTE = {
186
200
  typeSymbol: 'dsh-plugin-shop/types#ShopInstallStatusResult',
187
201
  schema: dsh_plugin_shop_shop_installStatus_result$schema,
188
202
  },
189
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":282,"column":3},
203
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":308,"column":3},
190
204
  },
191
205
  {
192
206
  id: 'dsh-plugin-shop#shop/restart',
@@ -201,7 +215,7 @@ export const TYPERT_REMOTE = {
201
215
  typeSymbol: 'dsh-plugin-shop/types#ShopRestartResult',
202
216
  schema: dsh_plugin_shop_shop_restart_result$schema,
203
217
  },
204
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":367,"column":9},
218
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":392,"column":9},
205
219
  },
206
220
  {
207
221
  id: 'dsh-plugin-shop#shop/setEnabled',
@@ -226,7 +240,7 @@ export const TYPERT_REMOTE = {
226
240
  typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
227
241
  schema: dsh_plugin_shop_shop_setEnabled_result$schema,
228
242
  },
229
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":187,"column":3},
243
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":213,"column":3},
230
244
  },
231
245
  {
232
246
  id: 'dsh-plugin-shop#shop/uninstallStart',
@@ -252,7 +266,47 @@ export const TYPERT_REMOTE = {
252
266
  typeSymbol: 'dsh-plugin-shop/types#ShopUninstallResult',
253
267
  schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
254
268
  },
255
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":333,"column":9},
269
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":359,"column":9},
270
+ },
271
+ {
272
+ id: 'dsh-plugin-shop#shop/updateStart',
273
+ service: 'shop',
274
+ namespace: 'shop',
275
+ method: 'updateStart',
276
+ invocation: { kind: 'direct' },
277
+ parameters: [
278
+ {
279
+ name: 'args',
280
+ wire: 'args',
281
+ source: 'json',
282
+ codec: {
283
+ mode: 'strict',
284
+ typeSymbol: 'dsh-plugin-shop#shop/updateStart:args',
285
+ schema: dsh_plugin_shop_shop_updateStart_parameter_0$schema,
286
+ },
287
+ },
288
+ ],
289
+ result: {
290
+ mode: 'strict',
291
+ typeSymbol: 'dsh-plugin-shop/types#ShopUpdateResult',
292
+ schema: dsh_plugin_shop_shop_updateStart_result$schema,
293
+ },
294
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":441,"column":9},
295
+ },
296
+ {
297
+ id: 'dsh-plugin-shop#shop/version',
298
+ service: 'shop',
299
+ namespace: 'shop',
300
+ method: 'version',
301
+ invocation: { kind: 'direct' },
302
+ parameters: [
303
+ ],
304
+ result: {
305
+ mode: 'strict',
306
+ typeSymbol: 'dsh-plugin-shop/types#ShopVersionResult',
307
+ schema: dsh_plugin_shop_shop_version_result$schema,
308
+ },
309
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":426,"column":9},
256
310
  },
257
311
  ],
258
312
  }