dsh-update-status 0.1.4 → 0.1.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.d.ts CHANGED
@@ -4,6 +4,23 @@ import { Context } from "@deepseek-ai/cordis";
4
4
  declare const RELEASE_CHANNELS: readonly ['latest', 'next', 'alpha'];
5
5
  type ReleaseChannel = (typeof RELEASE_CHANNELS)[number];
6
6
  type ReleaseCompatibility = 'verified' | 'unverified' | 'incompatible';
7
+ /**
8
+ * Severity of `warning`, so a surface can tell "the plugin could not determine
9
+ * the update state" from "here is something worth knowing".
10
+ *
11
+ * - `failure`: no usable answer — a failed registry read, a channel the registry
12
+ * does not publish, or a version SemVer cannot compare. This is what justifies
13
+ * repainting the sidebar chip.
14
+ * - `notice`: the answer is complete and usable; the text is advisory, e.g. a
15
+ * preview channel whose release this bundle has not been verified against.
16
+ * The chip must NOT repaint for this — an operator upgrading DSH ahead of the
17
+ * plugin would otherwise see the chip turn red for a plugin-side bookkeeping
18
+ * fact.
19
+ *
20
+ * Optional on purpose: a Host older than this field leaves it `undefined`, and
21
+ * the client then falls back to treating any warning as a failure.
22
+ */
23
+ type UpdateWarningKind = 'failure' | 'notice';
7
24
  type InstallKind = 'npm-global' | 'pnpm-global' | 'source-checkout' | 'unknown';
8
25
  interface ChannelRelease {
9
26
  channel: ReleaseChannel;
@@ -23,6 +40,8 @@ interface UpdateStatus {
23
40
  cached: boolean;
24
41
  checkedAt: string | null;
25
42
  warning: string | null;
43
+ /** Severity of `warning`; absent from a Host older than the field. */
44
+ warningKind?: UpdateWarningKind | null;
26
45
  installKind: InstallKind;
27
46
  upgradeCommand: string;
28
47
  releaseUrl: string;
@@ -37,6 +56,32 @@ interface UpdateStatus {
37
56
  canApplyInPlace: false;
38
57
  }
39
58
  //#endregion
59
+ //#region src/host/settings.d.ts
60
+ /** Deployment config (ordinary) plus the volatile user preferences the form edits. */
61
+ interface UpdateStatusConfig {
62
+ /** Deployment: on-demand registry cache duration, in hours. */
63
+ cacheTtlHours?: number;
64
+ /** Deployment: registry request timeout, in milliseconds. */
65
+ timeoutMs?: number;
66
+ /** Deployment: run one metadata check when the process mounts the plugin. */
67
+ autoCheckOnMount?: boolean;
68
+ /** Preference: show the sidebar version chip and its update panel. */
69
+ sidebarEnabled?: boolean;
70
+ /** Preference: release channel followed for comparison and commands. */
71
+ channel?: ReleaseChannel;
72
+ /** Preference: on-demand registry cache duration, in minutes. */
73
+ cacheTtlMinutes?: number;
74
+ }
75
+ /**
76
+ * The plugin's Config schema; its volatile fields ARE the settings form.
77
+ *
78
+ * The explicit two-argument annotation is load-bearing: a `.volatile()` field's
79
+ * output is a stable reference (`Volatile<T>`) rather than the bare value the
80
+ * input side takes, so the inferred schema type cannot be named by the emitted
81
+ * `.d.ts` (TS2883) without stating the input side here.
82
+ */
83
+ declare const Config: z<UpdateStatusConfig, Record<string, unknown>>;
84
+ //#endregion
40
85
  //#region src/host/installation.d.ts
41
86
  interface InstallationInfo {
42
87
  currentVersion: string;
@@ -74,6 +119,7 @@ declare class UpdateStatusService {
74
119
  private refreshRelease;
75
120
  private statusAfterFailure;
76
121
  private statusFromCache;
122
+ /** No remote data at all: the registry read itself failed, never a notice. */
77
123
  private statusWithoutRemoteRelease;
78
124
  }
79
125
  //#endregion
@@ -81,13 +127,7 @@ declare class UpdateStatusService {
81
127
  declare const name = "dsh-update-status";
82
128
  /** Connection supplies the authenticated transport; settings remains optional. */
83
129
  declare const inject: string[];
84
- interface Config {
85
- cacheTtlHours?: number;
86
- timeoutMs?: number;
87
- autoCheckOnMount?: boolean;
88
- }
89
- /** Deployment config only controls metadata-check timing; it never authorizes upgrades. */
90
- declare const Config: z<Config>;
130
+ type Config = UpdateStatusConfig;
91
131
  declare function apply(ctx: Context, config?: Config): void;
92
132
  //#endregion
93
133
  export { Config, type InstallKind, type UpdateStatus, UpdateStatusService, apply, inject, name };
package/lib/index.js CHANGED
@@ -1,17 +1,8 @@
1
1
  import { createRequire } from "node:module";
2
- import z from "@deepseek-ai/schemastery";
3
2
  import { existsSync, readFileSync, realpathSync } from "node:fs";
4
3
  import { dirname, join, normalize, sep } from "node:path";
4
+ import z from "@deepseek-ai/schemastery";
5
5
  //#region src/shared/types.ts
6
- /**
7
- * JSON-only contract shared by the Host and Web halves.
8
- *
9
- * The static package uses the authenticated Connection RPC channel because
10
- * `harness.handle` / `host.call` are dynamic-Cordis-only closure APIs in DSH
11
- * 0.1.5-rc.1. The endpoint vocabulary remains deliberately small and private
12
- * to this plugin channel.
13
- */
14
- const PLUGIN_ID = "dsh-update-status";
15
6
  const PACKAGE_NAME = "@deepseek-ai/dsh";
16
7
  /** Shared Connection RPC channel. Custom prefixes 405 on the SPA fallback. */
17
8
  const UPDATE_STATUS_CHANNEL = "/api";
@@ -21,7 +12,7 @@ const UPDATE_STATUS_CHANNEL = "/api";
21
12
  * release the registry reports stays `unverified` — the plugin never claims a
22
13
  * compatibility nobody checked.
23
14
  */
24
- const VERIFIED_DSH_VERSIONS = ["0.1.5-rc.1", "0.1.6-alpha.1"];
15
+ const VERIFIED_DSH_VERSIONS = ["0.1.7-alpha.2", "0.1.7-rc.1"];
25
16
  const RELEASE_CHANNELS = [
26
17
  "latest",
27
18
  "next",
@@ -262,34 +253,6 @@ function installUpdateStatusRpc(ctx, service) {
262
253
  });
263
254
  }
264
255
  //#endregion
265
- //#region src/host/settings.ts
266
- const SettingsSchema = z.object({
267
- sidebarEnabled: z.boolean().default(true),
268
- channel: z.union([
269
- "latest",
270
- "next",
271
- "alpha"
272
- ]).default("latest").loose(),
273
- cacheTtlMinutes: z.number().min(30).max(1440).default(360)
274
- });
275
- /** Settings are optional composition; absent providers leave the Web default on. */
276
- function installSettings(ctx) {
277
- ctx.inject(["settings"], (settingsCtx) => {
278
- try {
279
- settingsCtx.settings.register(PLUGIN_ID, SettingsSchema, {
280
- base: {
281
- sidebarEnabled: true,
282
- channel: "latest",
283
- cacheTtlMinutes: 360
284
- },
285
- applies: "live"
286
- });
287
- } catch (error) {
288
- console.error("[dsh-update-status] settings namespace registration failed:", error);
289
- }
290
- });
291
- }
292
- //#endregion
293
256
  //#region src/shared/semver.ts
294
257
  const SEMVER = /^(?:v)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
295
258
  const NUMERIC_IDENTIFIER = /^(0|[1-9]\d*)$/;
@@ -477,13 +440,16 @@ var UpdateStatusService = class {
477
440
  const missingWarning = selected.version === null ? `npm registry 未发布 ${channel} 通道。` : null;
478
441
  const comparisonWarning = selected.version !== null && comparison === void 0 ? `无法按 SemVer 比较当前版本 ${this.installation.currentVersion} 与 ${channel} 通道版本 ${selected.version}。` : null;
479
442
  const previewWarning = channel !== "latest" && selected.version !== null && selected.compatibility !== "verified" ? `${channel} 是预览通道,版本 ${selected.version} 尚未验证与本插件兼容。` : null;
443
+ const failureWarning = warningWith(warningWith(initialWarning, missingWarning), comparisonWarning);
444
+ const warning = warningWith(failureWarning, previewWarning);
480
445
  return {
481
446
  currentVersion: this.installation.currentVersion,
482
447
  latestVersion: selected.version,
483
448
  hasUpdate: comparison !== void 0 && comparison < 0,
484
449
  cached,
485
450
  checkedAt: new Date(cache.checkedAtMs).toISOString(),
486
- warning: warningWith(warningWith(initialWarning, missingWarning), warningWith(comparisonWarning, previewWarning)),
451
+ warning,
452
+ warningKind: warning === null ? null : failureWarning === null ? "notice" : "failure",
487
453
  installKind: this.installation.installKind,
488
454
  upgradeCommand: upgradeCommandFor(this.installation.installKind, this.installation.packageName || "@deepseek-ai/dsh", channel),
489
455
  releaseUrl: this.releaseUrl,
@@ -495,6 +461,7 @@ var UpdateStatusService = class {
495
461
  canApplyInPlace: false
496
462
  };
497
463
  }
464
+ /** No remote data at all: the registry read itself failed, never a notice. */
498
465
  statusWithoutRemoteRelease(channel, warning) {
499
466
  return {
500
467
  currentVersion: this.installation.currentVersion,
@@ -503,6 +470,7 @@ var UpdateStatusService = class {
503
470
  cached: false,
504
471
  checkedAt: null,
505
472
  warning,
473
+ warningKind: "failure",
506
474
  installKind: this.installation.installKind,
507
475
  upgradeCommand: upgradeCommandFor(this.installation.installKind, this.installation.packageName || "@deepseek-ai/dsh", channel),
508
476
  releaseUrl: this.releaseUrl,
@@ -521,16 +489,57 @@ var UpdateStatusService = class {
521
489
  }
522
490
  };
523
491
  //#endregion
524
- //#region src/index.ts
525
- const name = "dsh-update-status";
526
- /** Connection supplies the authenticated transport; settings remains optional. */
527
- const inject = ["connection"];
528
- /** Deployment config only controls metadata-check timing; it never authorizes upgrades. */
492
+ //#region src/host/settings.ts
493
+ /**
494
+ * The plugin's Config schema; its volatile fields ARE the settings form.
495
+ *
496
+ * The explicit two-argument annotation is load-bearing: a `.volatile()` field's
497
+ * output is a stable reference (`Volatile<T>`) rather than the bare value the
498
+ * input side takes, so the inferred schema type cannot be named by the emitted
499
+ * `.d.ts` (TS2883) without stating the input side here.
500
+ */
529
501
  const Config = z.object({
530
502
  cacheTtlHours: z.number().step(1).min(1).max(24).default(6),
531
503
  timeoutMs: z.number().step(1).min(1e3).max(3e4).default(DEFAULT_TIMEOUT_MS),
532
- autoCheckOnMount: z.boolean().default(true)
504
+ autoCheckOnMount: z.boolean().default(true),
505
+ sidebarEnabled: z.boolean().default(true).volatile(),
506
+ channel: z.union([
507
+ "latest",
508
+ "next",
509
+ "alpha"
510
+ ]).default("latest").loose().volatile(),
511
+ cacheTtlMinutes: z.number().min(30).max(1440).default(360).volatile()
533
512
  });
513
+ /**
514
+ * Suppress the auto-generated settings page for this entry.
515
+ *
516
+ * `autoGenerate` defaults to true, which would put a second, generic form beside
517
+ * the plugin's own `settings.section` page. Registering the policy is the
518
+ * documented move for a plugin that owns its preference UI (`ui-theme`,
519
+ * `ui-chat`, `ui-conversation` all do exactly this), and the entry's row stays
520
+ * in `settings.describe()` either way — the browser half still reads and writes
521
+ * it through `ctx.configForms`.
522
+ *
523
+ * Guarded twice: a deployment without the settings service never runs the inject
524
+ * callback (the plugin keeps working from its defaults), and a refused policy
525
+ * registration is contained instead of taking the plugin down.
526
+ *
527
+ * @param ctx - Host plugin context owning the entry's page policy.
528
+ */
529
+ function installSettings(ctx) {
530
+ try {
531
+ ctx.inject(["settings"], (child) => {
532
+ child.effect(() => child.settings.configure({ auto: false }, ctx.fiber));
533
+ });
534
+ } catch (error) {
535
+ console.error("[dsh-update-status] settings page policy registration failed:", error);
536
+ }
537
+ }
538
+ //#endregion
539
+ //#region src/index.ts
540
+ const name = "dsh-update-status";
541
+ /** Connection supplies the authenticated transport; settings remains optional. */
542
+ const inject = ["connection"];
534
543
  function boundedNumber(value, fallback, min, max) {
535
544
  if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
536
545
  return Math.min(max, Math.max(min, Math.floor(value)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-update-status",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Read-only DeepSeek Harness Web plugin that shows the running DSH version, discovers latest/next/alpha releases, warns about compatibility, and generates copy-only upgrade commands.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -24,6 +24,7 @@
24
24
  "CHANGELOG.md",
25
25
  "LICENSE",
26
26
  "assets/update-panel.png",
27
+ "assets/sidebar-chip.png",
27
28
  "docs/RELEASING.md"
28
29
  ],
29
30
  "engines": {
@@ -41,12 +42,17 @@
41
42
  "access": "public"
42
43
  },
43
44
  "dsh": {
45
+ "manifestVersion": 1,
46
+ "engines": {
47
+ "dsh": ">=0.1.7-alpha.2 <0.2.0"
48
+ },
44
49
  "bundle": {
45
50
  "patch": "./cordis.patch.yml"
46
51
  },
47
52
  "client": {
48
53
  "platform": "web",
49
54
  "inject": [
55
+ "@deepseek-ai/dsh-api-remotes",
50
56
  "@deepseek-ai/dsh-client-connection",
51
57
  "@deepseek-ai/dsh-client-ui-layout",
52
58
  "@deepseek-ai/dsh-client-ui-sidebar",
@@ -56,8 +62,8 @@
56
62
  },
57
63
  "compatibility": {
58
64
  "dshReleases": {
59
- "0.1.5-rc.1": "compatible",
60
- "0.1.6-alpha.1": "compatible"
65
+ "0.1.7-alpha.2": "compatible",
66
+ "0.1.7-rc.1": "compatible"
61
67
  }
62
68
  }
63
69
  },
@@ -70,17 +76,15 @@
70
76
  "version"
71
77
  ],
72
78
  "license": "MIT",
73
- "dependencies": {
74
- "@deepseek-ai/schemastery": "^3.18.2"
75
- },
76
79
  "peerDependencies": {
77
- "@deepseek-ai/cordis": "^4.0.2",
78
- "@deepseek-ai/dsh-settings": ">=0.1.5-rc.1"
80
+ "@deepseek-ai/cordis": "^4.0.4",
81
+ "@deepseek-ai/dsh-settings": ">=0.1.7-alpha.2 <0.2.0",
82
+ "@deepseek-ai/schemastery": "^3.18.4"
79
83
  },
80
84
  "devDependencies": {
81
- "@deepseek-ai/cordis": "^4.0.2",
82
- "@deepseek-ai/dsh-settings": "0.1.5-rc.1",
83
- "@deepseek-ai/schemastery": "^3.18.2",
85
+ "@deepseek-ai/cordis": "^4.0.4",
86
+ "@deepseek-ai/dsh-settings": "0.1.7-alpha.2",
87
+ "@deepseek-ai/schemastery": "^3.18.4",
84
88
  "@types/node": "^26.2.0",
85
89
  "@types/react": "^18.3.31",
86
90
  "react": "^18.3.1",