dsh-plugin-shop 0.8.5 → 0.8.6

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
@@ -3,7 +3,7 @@ import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
3
3
  import { loadOptionalPatches, readProfileManifest, resolveProfileDir } from "@deepseek-ai/dsh-app-boot";
4
4
  import { lt, minVersion, parse, satisfies, valid, validRange } from "semver";
5
5
  import { createHash, randomUUID } from "node:crypto";
6
- import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
6
+ import { appendFileSync, chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
7
7
  import { fileURLToPath, pathToFileURL } from "node:url";
8
8
  import { basename, delimiter, dirname, isAbsolute, join, posix, relative, resolve, sep, win32 } from "node:path";
9
9
  import { homedir } from "node:os";
@@ -16,7 +16,8 @@ import { isMap, isSeq, parseDocument } from "yaml";
16
16
  //#region src/own-version.ts
17
17
  /** The shop's own published version, read from the package.json that ships
18
18
  * next to this package — the RUNNING version, not the manifest's range
19
- * spec. This lives at the package root (not under src/host) on purpose:
19
+ * spec — and the identity of the process running it (`bootId`). This lives
20
+ * at the package root (not under src/host) on purpose:
20
21
  * both the source tree (tests) and the bundled `lib/index.js` sit exactly
21
22
  * one level below the package root, so the same relative URL resolves in
22
23
  * both. */
@@ -49,6 +50,17 @@ function versionAtLoad(read) {
49
50
  * evaluated — at boot, before any self-update could rewrite the file. */
50
51
  const runningVersion = versionAtLoad(() => ownManifest().version);
51
52
  /**
53
+ * Which run of the code this is: drawn when the module is first evaluated,
54
+ * fixed for the life of the process, and different in the next one.
55
+ *
56
+ * The version cannot answer that. A restart that installed no new shop keeps
57
+ * it, and so does one that never happened — which is what a page reloaded
58
+ * into the process it asked to restart could not tell apart from success,
59
+ * and showed as a self-update that silently did not land (design §8,
60
+ * 2026-10-06 amendment).
61
+ */
62
+ const bootId = randomUUID();
63
+ /**
52
64
  * The peer ranges this build declares — the input to the load-time harness
53
65
  * self-check. Read from the same shipped manifest as `runningVersion`, so the
54
66
  * ranges checked are the ones this build was actually published with, never
@@ -638,7 +650,8 @@ const entrySchema = z.object({
638
650
  }).optional(),
639
651
  dshPeers: z.record(z.string(), z.string()).optional(),
640
652
  unpackedSize: z.number().int().nonnegative().optional(),
641
- installSize: z.number().int().nonnegative().optional()
653
+ installSize: z.number().int().nonnegative().optional(),
654
+ archived: z.boolean().optional()
642
655
  }).superRefine((entry, ctx) => {
643
656
  if (entry.source === "npm") {
644
657
  if (!NPM_NAME.test(entry.name)) ctx.addIssue({
@@ -2661,29 +2674,43 @@ function restartCommand(options) {
2661
2674
  args: [...argv]
2662
2675
  };
2663
2676
  }
2677
+ /** One line of the handoff's own in the log, stamped in UTC ISO 8601 so a
2678
+ * reader can line it up against the new process's output and the browser's
2679
+ * clock. The helper stamps its line with `date -u` to the same shape, to the
2680
+ * second. */
2681
+ function stamped(text) {
2682
+ return `${(/* @__PURE__ */ new Date()).toISOString()} dsh-plugin-shop: ${text}\n`;
2683
+ }
2664
2684
  function startRestart(options) {
2665
2685
  const { command, args, parentPid, logFile, env } = options;
2666
2686
  const logFd = openSync(logFile, "a");
2667
2687
  try {
2668
- const helper = spawn("sh", [
2669
- "-c",
2670
- "while kill -0 \"$1\" 2>/dev/null; do sleep 0.2; done; shift; exec \"$@\"",
2671
- "sh",
2672
- String(parentPid),
2673
- command,
2674
- ...args
2675
- ], {
2676
- stdio: [
2677
- "ignore",
2678
- logFd,
2679
- logFd
2680
- ],
2681
- env: env ?? process.env,
2682
- detached: true
2683
- });
2688
+ writeSync(logFd, stamped(`restart committed; the new dsh starts once pid ${parentPid} exits: ${[command, ...args].join(" ")}`));
2689
+ let helper;
2690
+ try {
2691
+ helper = spawn("sh", [
2692
+ "-c",
2693
+ "while kill -0 \"$1\" 2>/dev/null; do sleep 0.2; done; echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) dsh-plugin-shop: pid $1 exited; starting the new dsh\"; shift; exec \"$@\"",
2694
+ "sh",
2695
+ String(parentPid),
2696
+ command,
2697
+ ...args
2698
+ ], {
2699
+ stdio: [
2700
+ "ignore",
2701
+ logFd,
2702
+ logFd
2703
+ ],
2704
+ env: env ?? process.env,
2705
+ detached: true
2706
+ });
2707
+ } catch (error) {
2708
+ writeSync(logFd, stamped(`the restart helper could not start: ${error.message}`));
2709
+ throw error;
2710
+ }
2684
2711
  helper.on("error", (error) => {
2685
2712
  try {
2686
- appendFileSync(logFile, `dsh-plugin-shop: the restart helper could not start: ${error.message}\n`);
2713
+ appendFileSync(logFile, stamped(`the restart helper could not start: ${error.message}`));
2687
2714
  } catch {}
2688
2715
  });
2689
2716
  helper.unref();
@@ -5851,10 +5878,12 @@ let ShopGateway = (() => {
5851
5878
  return present.length === 0 || present.every(([, enabled]) => enabled);
5852
5879
  };
5853
5880
  const installed = [];
5881
+ const claimed = /* @__PURE__ */ new Set();
5854
5882
  for (const entry of snapshot.entries) {
5855
5883
  const spec = ownDependencySpec(dependencies, entry.name);
5856
5884
  if (spec === void 0) continue;
5857
5885
  if (!installedSpecMatches(entry, spec)) continue;
5886
+ claimed.add(entry.name);
5858
5887
  const identity = {
5859
5888
  source: entry.source,
5860
5889
  repo: entry.repo,
@@ -5879,6 +5908,25 @@ let ShopGateway = (() => {
5879
5908
  enabled: enabledOf(entry.name)
5880
5909
  });
5881
5910
  }
5911
+ for (const name of Object.keys(dependencies)) {
5912
+ if (claimed.has(name)) continue;
5913
+ const spec = ownDependencySpec(dependencies, name);
5914
+ if (spec === void 0) continue;
5915
+ const origin = parseSpec(spec);
5916
+ if (origin?.kind !== "github") continue;
5917
+ const pinPrefix = `github:${origin.repo}#`;
5918
+ const pinKey = pins[pinPrefix] !== void 0 ? pinPrefix : Object.keys(pins).find((key) => key.startsWith(pinPrefix));
5919
+ installed.push({
5920
+ name,
5921
+ source: "github",
5922
+ repo: origin.repo,
5923
+ installed: (pinKey === void 0 ? void 0 : pins[pinKey]) ?? pins[name] ?? spec,
5924
+ latest: null,
5925
+ outdated: false,
5926
+ enabled: enabledOf(name),
5927
+ shadowed: true
5928
+ });
5929
+ }
5882
5930
  return installed;
5883
5931
  }
5884
5932
  /** Whether an installed dependency spec sits behind the catalog's version.
@@ -5908,11 +5956,17 @@ let ShopGateway = (() => {
5908
5956
  detail: DESKTOP_PROFILE_DETAIL
5909
5957
  };
5910
5958
  const named = (await this.snapshotNow()).entries.filter((entry) => entry.name === args.name);
5911
- if (named.length === 0) return {
5912
- ok: false,
5913
- detail: `dsh-plugin-shop: ${args.name} is not in the catalog`
5914
- };
5915
5959
  const spec = ownDependencySpec(readProfileManifest("dsh-plugin-shop", this.profileDirResolved()).dependencies ?? {}, args.name);
5960
+ if (named.length === 0) {
5961
+ if (spec === void 0) return {
5962
+ ok: false,
5963
+ detail: `dsh-plugin-shop: ${args.name} is not in the catalog`
5964
+ };
5965
+ if (parseSpec(spec)?.kind !== "github") return {
5966
+ ok: false,
5967
+ detail: `dsh-plugin-shop: ${args.name} is not in the catalog`
5968
+ };
5969
+ }
5916
5970
  if (spec === void 0) return {
5917
5971
  ok: false,
5918
5972
  detail: `dsh-plugin-shop: ${args.name} is not installed`
@@ -5966,10 +6020,7 @@ let ShopGateway = (() => {
5966
6020
  * response is out. The browser monitors the origin and refreshes when the
5967
6021
  * new server answers. Refusals are issued before anything is torn down. */
5968
6022
  async restart() {
5969
- if (this.committedRestart !== null) return {
5970
- ok: true,
5971
- logFile: this.committedRestart.logFile
5972
- };
6023
+ if (this.committedRestart !== null) return this.committedRestart;
5973
6024
  if (this.hasRunningCommand()) return {
5974
6025
  ok: false,
5975
6026
  detail: "dsh-plugin-shop: an install is still running in this profile; a restart now would boot the new dsh against a half-written profile. Wait for it to finish and try again."
@@ -6003,12 +6054,14 @@ let ShopGateway = (() => {
6003
6054
  detail: `dsh-plugin-shop: restart could not be started: ${error.message}`
6004
6055
  };
6005
6056
  }
6006
- this.committedRestart = { logFile };
6007
- setTimeout(() => this.exit(0), this.restartExitDelayMs);
6008
- return {
6057
+ this.committedRestart = {
6009
6058
  ok: true,
6010
- logFile
6059
+ logFile,
6060
+ bootId,
6061
+ pid: this.restartParentPid
6011
6062
  };
6063
+ setTimeout(() => this.exit(0), this.restartExitDelayMs);
6064
+ return this.committedRestart;
6012
6065
  }
6013
6066
  /** The shop's own version and whether npm has a newer one (§7.3). The
6014
6067
  * check is advisory: a registry that cannot answer leaves `latest` null
@@ -6022,7 +6075,8 @@ let ShopGateway = (() => {
6022
6075
  latest,
6023
6076
  outdated: latest !== null && lt(installed, latest),
6024
6077
  restartBlocked: this.staticRestartBlock(),
6025
- pendingVersion: this.pendingVersion(installed)
6078
+ pendingVersion: this.pendingVersion(installed),
6079
+ bootId
6026
6080
  };
6027
6081
  }
6028
6082
  /**
@@ -52,6 +52,7 @@ const dsh_plugin_shop_shop_catalog_result$schema = z.object({
52
52
  'dshPeers': z.union([z.undefined(), z.record(z.string(), z.string())]).optional(),
53
53
  'unpackedSize': z.union([z.undefined(), z.number()]).optional(),
54
54
  'installSize': z.union([z.undefined(), z.number()]).optional(),
55
+ 'archived': z.union([z.undefined(), z.literal(false), z.literal(true)]).optional(),
55
56
  })),
56
57
  'denied': z.array(z.object({
57
58
  'name': z.string(),
@@ -83,9 +84,10 @@ const dsh_plugin_shop_shop_installed_result$schema = z.array(z.object({
83
84
  'repo': z.union([z.undefined(), z.string()]).optional(),
84
85
  'subdir': z.union([z.undefined(), z.string()]).optional(),
85
86
  'installed': z.string(),
86
- 'latest': z.string(),
87
+ 'latest': z.union([z.literal(null), z.string()]),
87
88
  'outdated': z.boolean(),
88
89
  'enabled': z.boolean(),
90
+ 'shadowed': z.union([z.undefined(), z.literal(true)]).optional(),
89
91
  }))
90
92
  const dsh_plugin_shop_shop_installedSpecs_result$schema = z.union([z.literal(null), z.record(z.string(), z.string())])
91
93
  const dsh_plugin_shop_shop_installStart_parameter_0$schema = z.object({
@@ -119,6 +121,8 @@ const dsh_plugin_shop_shop_installStatus_result$schema = z.object({
119
121
  const dsh_plugin_shop_shop_restart_result$schema = z.union([z.object({
120
122
  'ok': z.literal(true),
121
123
  'logFile': z.union([z.undefined(), z.string()]).optional(),
124
+ 'bootId': z.union([z.undefined(), z.string()]).optional(),
125
+ 'pid': z.union([z.undefined(), z.number()]).optional(),
122
126
  }), z.object({
123
127
  'ok': z.literal(false),
124
128
  'detail': z.string(),
@@ -161,6 +165,7 @@ const dsh_plugin_shop_shop_version_result$schema = z.object({
161
165
  'outdated': z.boolean(),
162
166
  'restartBlocked': z.union([z.literal(null), z.literal("desktop"), z.literal("windows"), z.literal("systemd"), z.literal("port-zero")]),
163
167
  'pendingVersion': z.union([z.undefined(), z.literal(null), z.string()]).optional(),
168
+ 'bootId': z.union([z.undefined(), z.string()]).optional(),
164
169
  })
165
170
 
166
171
  export const TYPERT = {
@@ -195,7 +200,7 @@ export const TYPERT = {
195
200
  schema: dsh_plugin_shop_shop_catalog_result$schema,
196
201
  create: () => dsh_plugin_shop_shop_catalog_result$schema,
197
202
  },
198
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1253,"column":9},
203
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1272,"column":9},
199
204
  },
200
205
  {
201
206
  id: 'dsh-plugin-shop#shop/installed',
@@ -211,7 +216,7 @@ export const TYPERT = {
211
216
  schema: dsh_plugin_shop_shop_installed_result$schema,
212
217
  create: () => dsh_plugin_shop_shop_installed_result$schema,
213
218
  },
214
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1720,"column":9},
219
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1739,"column":9},
215
220
  },
216
221
  {
217
222
  id: 'dsh-plugin-shop#shop/installedSpecs',
@@ -227,7 +232,7 @@ export const TYPERT = {
227
232
  schema: dsh_plugin_shop_shop_installedSpecs_result$schema,
228
233
  create: () => dsh_plugin_shop_shop_installedSpecs_result$schema,
229
234
  },
230
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1711,"column":9},
235
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1730,"column":9},
231
236
  },
232
237
  {
233
238
  id: 'dsh-plugin-shop#shop/installStart',
@@ -255,7 +260,7 @@ export const TYPERT = {
255
260
  schema: dsh_plugin_shop_shop_installStart_result$schema,
256
261
  create: () => dsh_plugin_shop_shop_installStart_result$schema,
257
262
  },
258
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1379,"column":9},
263
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1398,"column":9},
259
264
  },
260
265
  {
261
266
  id: 'dsh-plugin-shop#shop/installStatus',
@@ -282,7 +287,7 @@ export const TYPERT = {
282
287
  schema: dsh_plugin_shop_shop_installStatus_result$schema,
283
288
  create: () => dsh_plugin_shop_shop_installStatus_result$schema,
284
289
  },
285
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1687,"column":3},
290
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1706,"column":3},
286
291
  },
287
292
  {
288
293
  id: 'dsh-plugin-shop#shop/restart',
@@ -298,7 +303,7 @@ export const TYPERT = {
298
303
  schema: dsh_plugin_shop_shop_restart_result$schema,
299
304
  create: () => dsh_plugin_shop_shop_restart_result$schema,
300
305
  },
301
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1916,"column":9},
306
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1990,"column":9},
302
307
  },
303
308
  {
304
309
  id: 'dsh-plugin-shop#shop/setEnabled',
@@ -325,7 +330,7 @@ export const TYPERT = {
325
330
  schema: dsh_plugin_shop_shop_setEnabled_result$schema,
326
331
  create: () => dsh_plugin_shop_shop_setEnabled_result$schema,
327
332
  },
328
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":924,"column":9},
333
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":943,"column":9},
329
334
  },
330
335
  {
331
336
  id: 'dsh-plugin-shop#shop/uninstallStart',
@@ -353,7 +358,7 @@ export const TYPERT = {
353
358
  schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
354
359
  create: () => dsh_plugin_shop_shop_uninstallStart_result$schema,
355
360
  },
356
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1827,"column":9},
361
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1884,"column":9},
357
362
  },
358
363
  {
359
364
  id: 'dsh-plugin-shop#shop/updateStart',
@@ -380,7 +385,7 @@ export const TYPERT = {
380
385
  schema: dsh_plugin_shop_shop_updateStart_result$schema,
381
386
  create: () => dsh_plugin_shop_shop_updateStart_result$schema,
382
387
  },
383
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2020,"column":9},
388
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2097,"column":9},
384
389
  },
385
390
  {
386
391
  id: 'dsh-plugin-shop#shop/version',
@@ -396,7 +401,7 @@ export const TYPERT = {
396
401
  schema: dsh_plugin_shop_shop_version_result$schema,
397
402
  create: () => dsh_plugin_shop_shop_version_result$schema,
398
403
  },
399
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1978,"column":9},
404
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2054,"column":9},
400
405
  },
401
406
  ],
402
407
  model: {
@@ -493,7 +498,7 @@ export const TYPERT = {
493
498
  },
494
499
  {
495
500
  "name": "CatalogEntry",
496
- "declaration": "export interface CatalogEntry {\n name: string;\n version: string;\n integrity: string | null;\n publishedAt: string | null;\n repository: string | null;\n license: string | null;\n tier: 'verified' | 'verified-stale' | 'community';\n metadata: 'declared' | 'derived';\n review?: { reviewedVersion?: string; reviewedCommit?: string; reviewedSha256?: string; repo?: string; reviewer: string; reviewCommit: string; notes: string; };\n catalog?: CatalogSection;\n source: 'npm' | 'github';\n publisher?: string;\n repo?: string;\n subdir?: string;\n tarball?: { url: string; sha256: string; };\n added?: string;\n peers?: string[];\n compatibility?: { dsh?: string; profiles?: string[]; };\n dshPeers?: Record<string, string>;\n unpackedSize?: number;\n installSize?: number;\n}"
501
+ "declaration": "export interface CatalogEntry {\n name: string;\n version: string;\n integrity: string | null;\n publishedAt: string | null;\n repository: string | null;\n license: string | null;\n tier: 'verified' | 'verified-stale' | 'community';\n metadata: 'declared' | 'derived';\n review?: { reviewedVersion?: string; reviewedCommit?: string; reviewedSha256?: string; repo?: string; reviewer: string; reviewCommit: string; notes: string; };\n catalog?: CatalogSection;\n source: 'npm' | 'github';\n publisher?: string;\n repo?: string;\n subdir?: string;\n tarball?: { url: string; sha256: string; };\n added?: string;\n peers?: string[];\n compatibility?: { dsh?: string; profiles?: string[]; };\n dshPeers?: Record<string, string>;\n unpackedSize?: number;\n installSize?: number;\n archived?: boolean;\n}"
497
502
  },
498
503
  {
499
504
  "name": "CatalogSection",
@@ -541,7 +546,7 @@ export const TYPERT = {
541
546
  },
542
547
  {
543
548
  "name": "RestartOutcome",
544
- "declaration": "export type RestartOutcome = { ok: true; logFile?: string; } | { ok: false; detail: string; };"
549
+ "declaration": "export type RestartOutcome = { ok: true; logFile?: string; bootId?: string; pid?: number; } | { ok: false; detail: string; };"
545
550
  },
546
551
  {
547
552
  "name": "ShopCatalogResult",
@@ -549,7 +554,7 @@ export const TYPERT = {
549
554
  },
550
555
  {
551
556
  "name": "ShopInstalledEntry",
552
- "declaration": "export interface ShopInstalledEntry {\n name: string;\n source: 'npm' | 'github';\n repo?: string;\n subdir?: string;\n installed: string;\n latest: string;\n outdated: boolean;\n enabled: boolean;\n}"
557
+ "declaration": "export interface ShopInstalledEntry {\n name: string;\n source: 'npm' | 'github';\n repo?: string;\n subdir?: string;\n installed: string;\n latest: string | null;\n outdated: boolean;\n enabled: boolean;\n shadowed?: true;\n}"
553
558
  },
554
559
  {
555
560
  "name": "ShopInstallResult",
@@ -577,7 +582,7 @@ export const TYPERT = {
577
582
  },
578
583
  {
579
584
  "name": "ShopVersionResult",
580
- "declaration": "export interface ShopVersionResult {\n installed: string;\n latest: string | null;\n outdated: boolean;\n restartBlocked: RestartBlockedReason | null;\n pendingVersion?: string | null;\n}"
585
+ "declaration": "export interface ShopVersionResult {\n installed: string;\n latest: string | null;\n outdated: boolean;\n restartBlocked: RestartBlockedReason | null;\n pendingVersion?: string | null;\n bootId?: string;\n}"
581
586
  }
582
587
  ]
583
588
  }
@@ -52,6 +52,7 @@ const dsh_plugin_shop_shop_catalog_result$schema = z.object({
52
52
  'dshPeers': z.union([z.undefined(), z.record(z.string(), z.string())]).optional(),
53
53
  'unpackedSize': z.union([z.undefined(), z.number()]).optional(),
54
54
  'installSize': z.union([z.undefined(), z.number()]).optional(),
55
+ 'archived': z.union([z.undefined(), z.literal(false), z.literal(true)]).optional(),
55
56
  })),
56
57
  'denied': z.array(z.object({
57
58
  'name': z.string(),
@@ -83,9 +84,10 @@ const dsh_plugin_shop_shop_installed_result$schema = z.array(z.object({
83
84
  'repo': z.union([z.undefined(), z.string()]).optional(),
84
85
  'subdir': z.union([z.undefined(), z.string()]).optional(),
85
86
  'installed': z.string(),
86
- 'latest': z.string(),
87
+ 'latest': z.union([z.literal(null), z.string()]),
87
88
  'outdated': z.boolean(),
88
89
  'enabled': z.boolean(),
90
+ 'shadowed': z.union([z.undefined(), z.literal(true)]).optional(),
89
91
  }))
90
92
  const dsh_plugin_shop_shop_installedSpecs_result$schema = z.union([z.literal(null), z.record(z.string(), z.string())])
91
93
  const dsh_plugin_shop_shop_installStart_parameter_0$schema = z.object({
@@ -119,6 +121,8 @@ const dsh_plugin_shop_shop_installStatus_result$schema = z.object({
119
121
  const dsh_plugin_shop_shop_restart_result$schema = z.union([z.object({
120
122
  'ok': z.literal(true),
121
123
  'logFile': z.union([z.undefined(), z.string()]).optional(),
124
+ 'bootId': z.union([z.undefined(), z.string()]).optional(),
125
+ 'pid': z.union([z.undefined(), z.number()]).optional(),
122
126
  }), z.object({
123
127
  'ok': z.literal(false),
124
128
  'detail': z.string(),
@@ -161,6 +165,7 @@ const dsh_plugin_shop_shop_version_result$schema = z.object({
161
165
  'outdated': z.boolean(),
162
166
  'restartBlocked': z.union([z.literal(null), z.literal("desktop"), z.literal("windows"), z.literal("systemd"), z.literal("port-zero")]),
163
167
  'pendingVersion': z.union([z.undefined(), z.literal(null), z.string()]).optional(),
168
+ 'bootId': z.union([z.undefined(), z.string()]).optional(),
164
169
  })
165
170
 
166
171
  export const TYPERT_REMOTE = {
@@ -192,7 +197,7 @@ export const TYPERT_REMOTE = {
192
197
  schema: dsh_plugin_shop_shop_catalog_result$schema,
193
198
  create: () => dsh_plugin_shop_shop_catalog_result$schema,
194
199
  },
195
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1253,"column":9},
200
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1272,"column":9},
196
201
  },
197
202
  {
198
203
  id: 'dsh-plugin-shop#shop/installed',
@@ -208,7 +213,7 @@ export const TYPERT_REMOTE = {
208
213
  schema: dsh_plugin_shop_shop_installed_result$schema,
209
214
  create: () => dsh_plugin_shop_shop_installed_result$schema,
210
215
  },
211
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1720,"column":9},
216
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1739,"column":9},
212
217
  },
213
218
  {
214
219
  id: 'dsh-plugin-shop#shop/installedSpecs',
@@ -224,7 +229,7 @@ export const TYPERT_REMOTE = {
224
229
  schema: dsh_plugin_shop_shop_installedSpecs_result$schema,
225
230
  create: () => dsh_plugin_shop_shop_installedSpecs_result$schema,
226
231
  },
227
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1711,"column":9},
232
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1730,"column":9},
228
233
  },
229
234
  {
230
235
  id: 'dsh-plugin-shop#shop/installStart',
@@ -252,7 +257,7 @@ export const TYPERT_REMOTE = {
252
257
  schema: dsh_plugin_shop_shop_installStart_result$schema,
253
258
  create: () => dsh_plugin_shop_shop_installStart_result$schema,
254
259
  },
255
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1379,"column":9},
260
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1398,"column":9},
256
261
  },
257
262
  {
258
263
  id: 'dsh-plugin-shop#shop/installStatus',
@@ -279,7 +284,7 @@ export const TYPERT_REMOTE = {
279
284
  schema: dsh_plugin_shop_shop_installStatus_result$schema,
280
285
  create: () => dsh_plugin_shop_shop_installStatus_result$schema,
281
286
  },
282
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1687,"column":3},
287
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1706,"column":3},
283
288
  },
284
289
  {
285
290
  id: 'dsh-plugin-shop#shop/restart',
@@ -295,7 +300,7 @@ export const TYPERT_REMOTE = {
295
300
  schema: dsh_plugin_shop_shop_restart_result$schema,
296
301
  create: () => dsh_plugin_shop_shop_restart_result$schema,
297
302
  },
298
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1916,"column":9},
303
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1990,"column":9},
299
304
  },
300
305
  {
301
306
  id: 'dsh-plugin-shop#shop/setEnabled',
@@ -322,7 +327,7 @@ export const TYPERT_REMOTE = {
322
327
  schema: dsh_plugin_shop_shop_setEnabled_result$schema,
323
328
  create: () => dsh_plugin_shop_shop_setEnabled_result$schema,
324
329
  },
325
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":924,"column":9},
330
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":943,"column":9},
326
331
  },
327
332
  {
328
333
  id: 'dsh-plugin-shop#shop/uninstallStart',
@@ -350,7 +355,7 @@ export const TYPERT_REMOTE = {
350
355
  schema: dsh_plugin_shop_shop_uninstallStart_result$schema,
351
356
  create: () => dsh_plugin_shop_shop_uninstallStart_result$schema,
352
357
  },
353
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1827,"column":9},
358
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1884,"column":9},
354
359
  },
355
360
  {
356
361
  id: 'dsh-plugin-shop#shop/updateStart',
@@ -377,7 +382,7 @@ export const TYPERT_REMOTE = {
377
382
  schema: dsh_plugin_shop_shop_updateStart_result$schema,
378
383
  create: () => dsh_plugin_shop_shop_updateStart_result$schema,
379
384
  },
380
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2020,"column":9},
385
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2097,"column":9},
381
386
  },
382
387
  {
383
388
  id: 'dsh-plugin-shop#shop/version',
@@ -393,7 +398,7 @@ export const TYPERT_REMOTE = {
393
398
  schema: dsh_plugin_shop_shop_version_result$schema,
394
399
  create: () => dsh_plugin_shop_shop_version_result$schema,
395
400
  },
396
- sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":1978,"column":9},
401
+ sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":2054,"column":9},
397
402
  },
398
403
  ],
399
404
  }
@@ -47,6 +47,12 @@ export interface ShopTabInjected {
47
47
  noteUninstalled?: (name: string) => void;
48
48
  restart: () => Promise<ShopRestartResult>;
49
49
  version: () => Promise<ShopVersionResult>;
50
+ /** Be told when the version answers start coming from another dsh process
51
+ * — dsh restarted under the page, which nothing reloads — with the first
52
+ * answer from it; returns the unsubscribe. The receipts a restart settles
53
+ * are the tab's to clear (design §8, 2026-10-06 amendment). Optional: a
54
+ * stub may not offer it. */
55
+ onRestarted?: (listener: (fresh: ShopVersionResult) => void) => () => void;
50
56
  updateStart: (args: {
51
57
  version: string;
52
58
  }) => Promise<ShopUpdateResult>;
@@ -13,6 +13,17 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
13
13
  'settings.shop': ShopLocaleKey;
14
14
  }
15
15
  }
16
+ declare module '@deepseek-ai/cordis' {
17
+ interface Events {
18
+ /** A connection generation was established: the first connect after
19
+ * plugin boot, and every reconnect. `@deepseek-ai/dsh-client-connection`
20
+ * declares it, in these words, from 0.1.5-rc.3 on, and dsh-api-gateway's
21
+ * client emits it there through 0.2.0-rc.2; the 0.1.1-rc.2 this package
22
+ * builds against predates the declaration. A harness that never emits
23
+ * it leaves the shop as it was before it listened. */
24
+ 'connection/reset'(): void;
25
+ }
26
+ }
16
27
  /** Dictionary namespace owned by this plugin. */
17
28
  export declare const NS = "settings.shop";
18
29
  /** How long a stashed catalog may satisfy a plain open. The host applies the
@@ -11,6 +11,11 @@ export declare const zh: {
11
11
  * 2026-09-26-market-borrowings §4). */
12
12
  tabCrashed: string;
13
13
  search: string;
14
+ /** One subdued line under the search box when a Chinese query fired a
15
+ * dictionary intent (design 2026-10-08-search-query-expansion §4).
16
+ * `{terms}` is the comma-joined recall terms, without the `#` marker
17
+ * (boundary-only surface detail, not a reader's fact). */
18
+ zhExpansionNote: string;
14
19
  all: string;
15
20
  catalog: string;
16
21
  catalogStats: string;
@@ -27,6 +32,10 @@ export declare const zh: {
27
32
  tierVerified: string;
28
33
  tierVerifiedStale: string;
29
34
  tierCommunity: string;
35
+ /** The github repository GitHub reports as archived (design 2026-10-08 §1.3).
36
+ * Subdued register, like `tierCommunity`: nothing is wrong with the install
37
+ * itself; the owner has simply frozen the project. */
38
+ archivedBadge: string;
30
39
  capabilitiesNote: string;
31
40
  install: string;
32
41
  confirm: string;
@@ -108,6 +117,14 @@ export declare const zh: {
108
117
  nameTakenDetail: string;
109
118
  npmSource: string;
110
119
  githubSource: string;
120
+ /** The badge and the explanation for an installed github entry no catalog
121
+ * row claims (C10 MVP). The mechanism synthesizes a row for ANY github spec
122
+ * with no catalog row — shadowed by a same-named npm package, an unlisted
123
+ * fork, a removed listing, or a same-named conflict with a different repo —
124
+ * so the copy names the catalog fact and lists the causes, rather than
125
+ * claiming the npm-twin one. */
126
+ shadowedBadge: string;
127
+ shadowedDetail: string;
111
128
  updatableSection: string;
112
129
  installedVersion: string;
113
130
  latestVersion: string;
@@ -133,6 +150,9 @@ export declare const zh: {
133
150
  * that answered and then died. */
134
151
  restartFailedLogNotice: string;
135
152
  restartTransportFailed: string;
153
+ notRestartedNotice: string;
154
+ notRestartedPidNotice: string;
155
+ notRestartedLogNotice: string;
136
156
  restartBlockedDesktopNotice: string;
137
157
  restartBlockedWindowsNotice: string;
138
158
  restartBlockedSystemdNotice: string;
@@ -159,6 +179,9 @@ export declare const en: {
159
179
  retry: string;
160
180
  tabCrashed: string;
161
181
  search: string;
182
+ /** One subdued line under the search box when a Chinese query fired a
183
+ * dictionary intent (design 2026-10-08-search-query-expansion §4). */
184
+ zhExpansionNote: string;
162
185
  all: string;
163
186
  catalog: string;
164
187
  catalogStats: string;
@@ -173,6 +196,10 @@ export declare const en: {
173
196
  empty: string;
174
197
  emptySearch: string;
175
198
  tierVerified: string;
199
+ /** The github repository GitHub reports as archived (design 2026-10-08 §1.3).
200
+ * Subdued register: nothing is wrong with the install; the owner has simply
201
+ * frozen the project. */
202
+ archivedBadge: string;
176
203
  tierVerifiedStale: string;
177
204
  tierCommunity: string;
178
205
  capabilitiesNote: string;
@@ -232,6 +259,8 @@ export declare const en: {
232
259
  nameTakenDetail: string;
233
260
  npmSource: string;
234
261
  githubSource: string;
262
+ shadowedBadge: string;
263
+ shadowedDetail: string;
235
264
  updatableSection: string;
236
265
  installedVersion: string;
237
266
  latestVersion: string;
@@ -252,6 +281,9 @@ export declare const en: {
252
281
  restartFailedNotice: string;
253
282
  restartFailedLogNotice: string;
254
283
  restartTransportFailed: string;
284
+ notRestartedNotice: string;
285
+ notRestartedPidNotice: string;
286
+ notRestartedLogNotice: string;
255
287
  restartBlockedDesktopNotice: string;
256
288
  restartBlockedWindowsNotice: string;
257
289
  restartBlockedSystemdNotice: string;
@@ -5,7 +5,7 @@ export { isShopLike } from '../shared/shop-like.ts';
5
5
  export { identityKey, type EntryIdentity } from '../shared/identity.ts';
6
6
  import { type EntryIdentity } from '../shared/identity.ts';
7
7
  import type { ShopLocaleKey } from './locales.ts';
8
- import type { CatalogEntry, HarnessVerdict, HotRestartReason, InstallRejectionCode, RestartBlockedReason } from '../host/index.ts';
8
+ import type { CatalogEntry, HarnessVerdict, HotRestartReason, InstallRejectionCode, RestartBlockedReason, ShopVersionResult } from '../host/index.ts';
9
9
  import type { Activation } from '../host/activation.ts';
10
10
  import { type InstallState } from '../shared/install-state.ts';
11
11
  export type { Activation };
@@ -287,6 +287,26 @@ export declare function restartMonitorVerdict(input: {
287
287
  elapsedMs: number;
288
288
  stableSinceMs: number | null;
289
289
  }): 'wait' | 'reload' | 'failed';
290
+ /**
291
+ * Whether two `version()` answers came from different dsh processes — dsh
292
+ * restarted under the page between them (design §8, 2026-10-06 amendment).
293
+ *
294
+ * A process names itself by `bootId` for as long as it lives, so where either
295
+ * answer carries one, a difference decides: a host older than the field never
296
+ * starts naming itself, and a newer one never stops. Where neither does, only
297
+ * the code they run can differ — one process runs one version, read once at
298
+ * its boot — which still catches the first restart after a self-update from
299
+ * a host older than the field, the one that matters most.
300
+ */
301
+ export declare function answeredByAnotherProcess(previous: ShopVersionResult, next: ShopVersionResult): boolean;
302
+ /**
303
+ * Whether dsh restarting under the page settles this receipt: a change that
304
+ * landed and was waiting for exactly that. The tab clears these once the
305
+ * answers come from another process, and nothing else — a reload is still
306
+ * owed by a page nobody reloaded, a failure still happened, and a flow still
307
+ * running settles by its own poll.
308
+ */
309
+ export declare function settledByRestart(view: InstallView): boolean;
290
310
  /** How long the check-update button reports "up to date" after a re-check
291
311
  * finds no newer release, before reverting to its idle label. */
292
312
  export declare const CHECK_UP_TO_DATE_MS = 3000;