dsh-update-plugin 0.1.0 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -6,15 +6,68 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.1] - 2026-09-17
10
+
11
+ Published to npm as `dsh-update-plugin@0.3.1`. No plugin behaviour changed; this
12
+ release refreshes the package metadata after the project rename.
13
+
14
+ ### Changed
15
+
16
+ - `repository`, `homepage` and `bugs` now point at
17
+ `haotian-lu-prog/dsh-update-plugin` — the project was renamed from
18
+ `dsh-update-all`.
19
+ - The READMEs name the CLI by its new command, `dsh-update-plugin`, and explain
20
+ that the standalone CLI is optional because the update logic is built in.
21
+ - Refreshed the English and Chinese screenshots for the 0.3.0 settings page,
22
+ the Check for Updates page and the right sidebar tab.
23
+
24
+ ### Fixed
25
+
26
+ - Backups whose `manifest.json` has no `source` field are now attributed to
27
+ `dsh-update-plugin` instead of the retired `dsh-update-all` name.
28
+
29
+ ## [0.3.0] - 2026-09-16
30
+
31
+ Published to npm as `dsh-update-plugin@0.3.0`. This is the first release that
32
+ actually ships the automatic-check and browser-notification work listed under
33
+ `0.2.0` below — `0.2.0` itself was never published.
34
+
9
35
  ### Added
10
36
 
11
- - **Send test reminder / 测试更新提醒** button in the settings page: opens the
12
- sidebar tab, sends a browser notification (permission required) and shows the
13
- update badge for 10 seconds, so the reminder can be verified without a real
14
- release.
37
+ - Automatic update checks: on startup, hourly, daily or off, persisted in the
38
+ plugin config and restarted when the setting is saved.
39
+ - Browser notification when a real update is available: sent once per target
40
+ version, with a notification-permission row and an enable button in the
41
+ settings page.
42
+ - The **Send test reminder / 测试更新提醒** button now requests notification
43
+ permission and uses its own test copy, so it can be told apart from real
44
+ notifications.
45
+
46
+ ### Fixed
47
+
48
+ - Screenshot references in `README.md` and `README.zh-CN.md`: three links pointed
49
+ at files that do not exist. They now use the current captures, and the
50
+ duplicate `plugin-zh.png` (byte-identical to `plugin-cn.png`) is gone.
51
+
52
+ ## [0.2.0] - 2026-09-13
53
+
54
+ Not published to npm; its changes shipped in `0.3.0`.
55
+
56
+ ### Added
57
+
58
+ - Automatic update checks: on startup, hourly, daily or off, persisted in the
59
+ plugin config and restarted when the setting is saved.
60
+ - Browser notification when a real update is available: sent once per target
61
+ version, with a notification-permission row and an enable button in the
62
+ settings page.
63
+ - The **Send test reminder / 测试更新提醒** button now requests notification
64
+ permission and uses its own test copy, so it can be told apart from real
65
+ notifications.
15
66
 
16
67
  ## [0.1.0] - 2026-09-12
17
68
 
69
+ Published to npm as `dsh-update-plugin@0.1.0`.
70
+
18
71
  ### Added
19
72
 
20
73
  - **Settings → General** row titled **Check for Updates... / 检查更新**, registered
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 dsh-update-all contributors
3
+ Copyright (c) 2026 dsh-update-plugin contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  English | [中文](README.zh-CN.md)
4
4
 
5
+ [![npm](https://img.shields.io/npm/v/dsh-update-plugin.svg)](https://www.npmjs.com/package/dsh-update-plugin)
6
+ [![Topic: dsh-plugin](https://img.shields.io/badge/topic-dsh--plugin-0f766e)](https://github.com/topics/dsh-plugin)
7
+
5
8
  A DSH Web plugin that adds **Check for Updates...** (「检查更新」in Chinese) to
6
9
  **Settings → General**, right next to Permission, Language, Appearance and Font
7
10
  Size.
@@ -11,28 +14,30 @@ From one row you can check for a newer DeepSeek Harness release and update:
11
14
  - the global `@deepseek-ai/dsh` CLI and every bundled `@deepseek-ai/dsh-*` package;
12
15
  - every profile's plugins under `~/.dsh/profiles/*`.
13
16
 
14
- The update logic is built into the plugin. It does **not** require Homebrew or a
15
- separately installed `dsh-update-all` script.
17
+ The update logic is built into the plugin: it does **not** require Homebrew, and
18
+ it does not need the standalone `dsh-update-plugin` CLI to be installed either.
16
19
 
17
20
  ![Check for Updates... in Settings → General](assets/screenshots/general-en.webp)
21
+ ![Update reminder in the right sidebar](assets/screenshots/sidebar-en.png)
22
+ ![Check for Updates... page in Settings](assets/screenshots/plugin-en.png)
18
23
 
19
24
  ## Install
20
25
 
21
26
  ```bash
22
- # from npm (once published)
27
+ # from npm
23
28
  dsh plugin --profile web add dsh-update-plugin
24
29
 
25
- # from a local checkout / this repository
26
- dsh plugin --profile web add /path/to/dsh-update-all/plugin
30
+ # from a local checkout (development)
31
+ dsh plugin --profile web add /path/to/dsh-update-plugin/plugin
27
32
  ```
28
33
 
29
34
  If pnpm refuses the install because its `minimumReleaseAge` policy rejects an
30
- already-updated lockfile entry (for example right after you used
31
- `dsh-update-all --min-age 0`), rerun the command with the policy relaxed for
32
- that single install:
35
+ already-updated lockfile entry (for example right after you ran the
36
+ `dsh-update-plugin` CLI with `--min-age 0`), rerun the command with the policy
37
+ relaxed for that single install:
33
38
 
34
39
  ```bash
35
- dsh plugin --profile web add /path/to/dsh-update-all/plugin --config.minimum-release-age=0
40
+ dsh plugin --profile web add /path/to/dsh-update-plugin/plugin --config.minimum-release-age=0
36
41
  ```
37
42
 
38
43
  > **Always mount with `dsh plugin add`, not plain `pnpm add`.** The official
@@ -55,6 +60,10 @@ Then restart DSH Web, open **Settings → General**, and look for the
55
60
  sends a browser notification (permission required), and shows the update badge
56
61
  for 10 seconds so you can verify the reminder without a real release.
57
62
  - The row shows the current and newest versions plus the number of profiles.
63
+ - **Automatic update checks** can run on startup, hourly or daily, or be turned
64
+ off; pick the interval in the settings page.
65
+ - When a real update is available and browser notifications are allowed, the
66
+ plugin sends a notification once per new version.
58
67
  - **Check for updates** refreshes the status (it also refreshes after
59
68
  reconnecting).
60
69
  - **Update now** updates the CLI and then every profile with dependencies.
package/README.zh-CN.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  [English](README.md) | 中文
4
4
 
5
+ [![npm](https://img.shields.io/npm/v/dsh-update-plugin.svg)](https://www.npmjs.com/package/dsh-update-plugin)
6
+ [![Topic: dsh-plugin](https://img.shields.io/badge/topic-dsh--plugin-0f766e)](https://github.com/topics/dsh-plugin)
7
+
5
8
  一个 DSH Web 插件,在 **设置 → 通用设置** 里加入一行「检查更新」,和权限、语言、
6
9
  外观、字号大小同级。
7
10
 
@@ -10,26 +13,28 @@
10
13
  - 全局 `@deepseek-ai/dsh` CLI 以及随包的 `@deepseek-ai/dsh-*`;
11
14
  - `~/.dsh/profiles/*` 下每个 profile 的插件。
12
15
 
13
- 更新逻辑完整内置在插件里,**不依赖 Homebrew,也不依赖单独安装的
14
- `dsh-update-all` 脚本**。
16
+ 更新逻辑完整内置在插件里:**不依赖 Homebrew,也不需要额外安装同名的
17
+ `dsh-update-plugin` 命令行工具**。
15
18
 
16
19
  ![设置 → 通用设置里的「检查更新」](assets/screenshots/general-zh.webp)
20
+ ![右侧栏更新提醒](assets/screenshots/sidebar-cn.png)
21
+ ![设置 → 检查更新完整页面](assets/screenshots/plugin-cn.png)
17
22
 
18
23
  ## 安装
19
24
 
20
25
  ```bash
21
- # 从 npm 安装(发布之后)
26
+ # 从 npm 安装
22
27
  dsh plugin --profile web add dsh-update-plugin
23
28
 
24
- # 从本仓库 / 本地目录安装
25
- dsh plugin --profile web add /path/to/dsh-update-all/plugin
29
+ # 本地开发 / 从本仓库安装
30
+ dsh plugin --profile web add /path/to/dsh-update-plugin/plugin
26
31
  ```
27
32
 
28
33
  如果 pnpm 的 `minimumReleaseAge` 策略因为 lockfile 里已有较新的条目而拒绝安装
29
- (例如刚用过 `dsh-update-all --min-age 0`),给这一次安装临时放开策略即可:
34
+ (例如刚用 `dsh-update-plugin` 命令行工具跑过 `--min-age 0`),给这一次安装临时放开策略即可:
30
35
 
31
36
  ```bash
32
- dsh plugin --profile web add /path/to/dsh-update-all/plugin --config.minimum-release-age=0
37
+ dsh plugin --profile web add /path/to/dsh-update-plugin/plugin --config.minimum-release-age=0
33
38
  ```
34
39
 
35
40
  > **一定要用 `dsh plugin add` 挂载,不要只用 `pnpm add`。** 官方命令还会把包
@@ -49,6 +54,8 @@ dsh plugin --profile web add /path/to/dsh-update-all/plugin --config.minimum-rel
49
54
  - 状态卡片里有 **测试更新提醒** 按钮:会打开侧边栏 tab、发送浏览器通知
50
55
  (需要授权),并显示 10 秒的更新角标,方便验证提醒效果,不用等真实新版本。
51
56
  - 行内显示当前版本、最新版本和 profile 数量。
57
+ - **自动检查**支持启动时 / 每小时 / 每天,也可以关闭;在设置页选择即可。
58
+ - 发现真实新版本且浏览器通知已授权时,每个新版本只通知一次。
52
59
  - **检查更新**:刷新状态。
53
60
  - **立即更新**:先更新 CLI,再更新每个有依赖的 profile;更新前会自动把
54
61
  `package.json` / `pnpm-lock.yaml` 备份到 `~/.dsh/update-backups/`。
Binary file
Binary file
Binary file
Binary file
package/lib/client.js CHANGED
@@ -112,8 +112,23 @@ window.__ModuleLoader__.load({
112
112
  testStop: "停止测试",
113
113
  testReminder: "测试提醒:发现可用更新(仅测试,不会真的更新)",
114
114
  testReminderMeta: "仅用于验证角标和提醒效果",
115
- notificationTitle: "DSH 有可用更新",
116
- notificationBody: "测试提醒:仅用于验证浏览器通知和角标(不会真的更新)",
115
+ testNotificationTitle: "DSH 有可用更新",
116
+ testNotificationBody: "测试提醒:仅用于验证浏览器通知和角标(不会真的更新)",
117
+ updateNotificationTitle: "DSH 有可用更新",
118
+ updateNotificationBody: "最新版本 {version}。打开 设置 → 通用设置 查看。",
119
+ notifications: "浏览器通知",
120
+ notificationHint: "有新版本时发送浏览器通知",
121
+ notificationGranted: "已允许",
122
+ notificationDefault: "未授权",
123
+ notificationDenied: "已拒绝",
124
+ notificationUnsupported: "当前环境不支持",
125
+ enableNotifications: "启用通知",
126
+ checkInterval: "自动检查",
127
+ checkIntervalHint: "启动时 / 每小时 / 每天,或关闭",
128
+ intervalStartup: "启动时",
129
+ intervalHourly: "每小时",
130
+ intervalDaily: "每天",
131
+ intervalOff: "关闭",
117
132
  };
118
133
 
119
134
  var EN = {
@@ -171,8 +186,23 @@ window.__ModuleLoader__.load({
171
186
  testStop: "Stop test",
172
187
  testReminder: "Test reminder: update available (test only, nothing is updated)",
173
188
  testReminderMeta: "Only used to verify the badge and reminder UI",
174
- notificationTitle: "DSH update available",
175
- notificationBody: "Test reminder: only verifying the browser notification and badge (nothing is updated)",
189
+ testNotificationTitle: "DSH update available",
190
+ testNotificationBody: "Test reminder: only verifying the browser notification and badge (nothing is updated)",
191
+ updateNotificationTitle: "DSH update available",
192
+ updateNotificationBody: "Version {version} is available. Open Settings → General to review.",
193
+ notifications: "Browser notifications",
194
+ notificationHint: "Notify me when a new version is available",
195
+ notificationGranted: "Allowed",
196
+ notificationDefault: "Not allowed yet",
197
+ notificationDenied: "Denied",
198
+ notificationUnsupported: "Not supported in this environment",
199
+ enableNotifications: "Enable notifications",
200
+ checkInterval: "Automatic check",
201
+ checkIntervalHint: "On startup / hourly / daily, or off",
202
+ intervalStartup: "On startup",
203
+ intervalHourly: "Hourly",
204
+ intervalDaily: "Daily",
205
+ intervalOff: "Off",
176
206
  };
177
207
 
178
208
  function injectStyle() {
@@ -233,24 +263,59 @@ window.__ModuleLoader__.load({
233
263
  }).then(parseJson);
234
264
  }
235
265
 
236
- function sendBrowserNotification(t) {
237
- try {
238
- if (typeof Notification === "undefined") return;
239
- var show = function () {
240
- try {
241
- new Notification(t("notificationTitle"), { body: t("notificationBody") });
242
- } catch (error) {}
243
- };
244
- if (Notification.permission === "granted") {
245
- show();
246
- } else if (Notification.permission !== "denied") {
247
- Notification.requestPermission()
248
- .then(function (permission) {
249
- if (permission === "granted") show();
250
- })
251
- .catch(function () {});
252
- }
253
- } catch (error) {}
266
+ function notificationsSupported() {
267
+ return typeof Notification !== "undefined";
268
+ }
269
+
270
+ function notificationPermission() {
271
+ if (notificationsSupported()) return Notification.permission;
272
+ return "unsupported";
273
+ }
274
+
275
+ function requestNotificationPermission() {
276
+ if (notificationsSupported()) {
277
+ return Notification.requestPermission().catch(function () {
278
+ return notificationPermission();
279
+ });
280
+ }
281
+ return Promise.resolve("unsupported");
282
+ }
283
+
284
+ function sendBrowserNotification(title, body) {
285
+ if (notificationsSupported()) {
286
+ try {
287
+ if (Notification.permission === "granted") {
288
+ var notice = new Notification(title, { body: body, tag: "dsh-update-plugin" });
289
+ notice.onclick = function () {
290
+ try {
291
+ window.focus();
292
+ } catch (error) {}
293
+ };
294
+ return true;
295
+ }
296
+ } catch (error) {}
297
+ }
298
+ return false;
299
+ }
300
+
301
+ function useNotificationPermission() {
302
+ var pair = React.useState(notificationPermission());
303
+ var permission = pair[0];
304
+ var setPermission = pair[1];
305
+ var request = React.useCallback(function () {
306
+ return requestNotificationPermission().then(function (next) {
307
+ setPermission(next);
308
+ return next;
309
+ });
310
+ }, [setPermission]);
311
+ return { permission: permission, request: request };
312
+ }
313
+
314
+ function notificationStatusText(t, permission) {
315
+ if (permission === "granted") return t("notificationGranted");
316
+ if (permission === "denied") return t("notificationDenied");
317
+ if (permission === "unsupported") return t("notificationUnsupported");
318
+ return t("notificationDefault");
254
319
  }
255
320
 
256
321
  function manualCommands(profileName) {
@@ -343,6 +408,69 @@ window.__ModuleLoader__.load({
343
408
  return Object.assign({}, data || {}, { updateAvailable: true, testReminder: true });
344
409
  }
345
410
 
411
+ var NOTIFIED_KEY = "dsh-update-plugin:notified-version";
412
+ var autoCheckTimer = null;
413
+
414
+ function readNotifiedVersion() {
415
+ if (typeof window === "undefined" || typeof window.localStorage === "undefined") return null;
416
+ try {
417
+ return window.localStorage.getItem(NOTIFIED_KEY);
418
+ } catch (error) {
419
+ return null;
420
+ }
421
+ }
422
+
423
+ function writeNotifiedVersion(version) {
424
+ if (typeof window === "undefined" || typeof window.localStorage === "undefined") return;
425
+ try {
426
+ window.localStorage.setItem(NOTIFIED_KEY, version);
427
+ } catch (error) {}
428
+ }
429
+
430
+ function stopAutoCheck() {
431
+ if (autoCheckTimer) {
432
+ clearInterval(autoCheckTimer);
433
+ autoCheckTimer = null;
434
+ }
435
+ }
436
+
437
+ function autoCheckDelay(config) {
438
+ if (config && config.checkInterval === "hourly") return 60 * 60 * 1000;
439
+ if (config && config.checkInterval === "daily") return 24 * 60 * 60 * 1000;
440
+ return 0;
441
+ }
442
+
443
+ function checkUpdatesAndNotify(t) {
444
+ if (testReminder.active) return;
445
+ getStatus(true)
446
+ .then(function (data) {
447
+ if (data && data.updateAvailable && data.targetVersion) {
448
+ if (testReminder.active) return;
449
+ var last = readNotifiedVersion();
450
+ if (last === data.targetVersion) return;
451
+ var sent = sendBrowserNotification(
452
+ t("updateNotificationTitle"),
453
+ t("updateNotificationBody", { version: data.targetVersion }),
454
+ );
455
+ if (sent) writeNotifiedVersion(data.targetVersion);
456
+ }
457
+ })
458
+ .catch(function () {});
459
+ }
460
+
461
+ function startAutoCheck(config, t) {
462
+ stopAutoCheck();
463
+ var current = config || {};
464
+ if (current.checkInterval === "off") return;
465
+ checkUpdatesAndNotify(t);
466
+ var delay = autoCheckDelay(current);
467
+ if (delay > 0) {
468
+ autoCheckTimer = setInterval(function () {
469
+ checkUpdatesAndNotify(t);
470
+ }, delay);
471
+ }
472
+ }
473
+
346
474
  function useUpdater(t) {
347
475
  var pair = React.useState({ loading: true, data: null, error: null });
348
476
  var state = pair[0];
@@ -578,7 +706,8 @@ window.__ModuleLoader__.load({
578
706
  var test = useTestReminder();
579
707
  var configState = useConfig(t);
580
708
  var backupsState = useBackups(t);
581
- var draftPair = React.useState({ channel: "auto", minAge: 0 });
709
+ var notification = useNotificationPermission();
710
+ var draftPair = React.useState({ channel: "auto", minAge: 0, checkInterval: "startup" });
582
711
  var draft = draftPair[0];
583
712
  var setDraft = draftPair[1];
584
713
 
@@ -588,6 +717,7 @@ window.__ModuleLoader__.load({
588
717
  setDraft({
589
718
  channel: configState.state.config.channel || "auto",
590
719
  minAge: Number.isInteger(configState.state.config.minAge) ? configState.state.config.minAge : 0,
720
+ checkInterval: configState.state.config.checkInterval || "startup",
591
721
  });
592
722
  }
593
723
  },
@@ -612,6 +742,9 @@ window.__ModuleLoader__.load({
612
742
  configState.save({
613
743
  channel: draft.channel,
614
744
  minAge: Number(draft.minAge) || 0,
745
+ checkInterval: draft.checkInterval || "startup",
746
+ }).then(function (next) {
747
+ if (next) startAutoCheck(next, t);
615
748
  });
616
749
  }
617
750
 
@@ -681,7 +814,11 @@ window.__ModuleLoader__.load({
681
814
  return;
682
815
  }
683
816
  if (typeof props.openSidebar === "function") props.openSidebar();
684
- sendBrowserNotification(t);
817
+ requestNotificationPermission().then(function (permission) {
818
+ if (permission === "granted") {
819
+ sendBrowserNotification(t("testNotificationTitle"), t("testNotificationBody"));
820
+ }
821
+ });
685
822
  setTestReminder(true, 10000);
686
823
  },
687
824
  },
@@ -727,7 +864,7 @@ window.__ModuleLoader__.load({
727
864
  className: "dsu-select",
728
865
  value: draft.channel,
729
866
  onChange: function (event) {
730
- setDraft({ channel: event.target.value, minAge: draft.minAge });
867
+ setDraft({ channel: event.target.value, minAge: draft.minAge, checkInterval: draft.checkInterval });
731
868
  },
732
869
  },
733
870
  [
@@ -756,13 +893,67 @@ window.__ModuleLoader__.load({
756
893
  step: 60,
757
894
  value: draft.minAge,
758
895
  onChange: function (event) {
759
- setDraft({ channel: draft.channel, minAge: Math.max(0, Number(event.target.value) || 0) });
896
+ setDraft({ channel: draft.channel, minAge: Math.max(0, Number(event.target.value) || 0), checkInterval: draft.checkInterval });
760
897
  },
761
898
  }),
762
899
  h("span", { className: "dsu-desc", key: "unit" }, t("minAgeUnit")),
763
900
  ]),
764
901
  ],
765
902
  ),
903
+ h(
904
+ "div",
905
+ { className: "dsu-field", key: "check-interval" },
906
+ [
907
+ h("div", { className: "dsu-field-label", key: "label" }, [
908
+ h("div", { className: "dsu-title", key: "t" }, t("checkInterval")),
909
+ h("div", { className: "dsu-desc", key: "d" }, t("checkIntervalHint")),
910
+ ]),
911
+ h(
912
+ "select",
913
+ {
914
+ key: "select",
915
+ className: "dsu-select",
916
+ value: draft.checkInterval,
917
+ onChange: function (event) {
918
+ setDraft({ channel: draft.channel, minAge: draft.minAge, checkInterval: event.target.value });
919
+ },
920
+ },
921
+ [
922
+ h("option", { key: "startup", value: "startup" }, t("intervalStartup")),
923
+ h("option", { key: "hourly", value: "hourly" }, t("intervalHourly")),
924
+ h("option", { key: "daily", value: "daily" }, t("intervalDaily")),
925
+ h("option", { key: "off", value: "off" }, t("intervalOff")),
926
+ ],
927
+ ),
928
+ ],
929
+ ),
930
+ h(
931
+ "div",
932
+ { className: "dsu-field", key: "notifications" },
933
+ [
934
+ h("div", { className: "dsu-field-label", key: "label" }, [
935
+ h("div", { className: "dsu-title", key: "t" }, t("notifications")),
936
+ h("div", { className: "dsu-desc", key: "d" }, t("notificationHint")),
937
+ ]),
938
+ h("div", { className: "dsu-control", key: "control" }, [
939
+ h("span", { className: "dsu-desc", key: "status" }, notificationStatusText(t, notification.permission)),
940
+ notification.permission === "granted" || notification.permission === "unsupported"
941
+ ? null
942
+ : h(
943
+ "button",
944
+ {
945
+ key: "enable",
946
+ type: "button",
947
+ className: "dsu-btn",
948
+ onClick: function () {
949
+ notification.request();
950
+ },
951
+ },
952
+ t("enableNotifications"),
953
+ ),
954
+ ]),
955
+ ],
956
+ ),
766
957
  h(
767
958
  "div",
768
959
  { className: "dsu-control", key: "actions" },
@@ -963,6 +1154,33 @@ window.__ModuleLoader__.load({
963
1154
  "dsh-update-plugin: dictionaries",
964
1155
  );
965
1156
 
1157
+ var autoCheckDisposed = false;
1158
+ ctx.effect(
1159
+ function () {
1160
+ var translate = function (key, params) {
1161
+ return ctx.locale.bind(NS)(key, params);
1162
+ };
1163
+ getConfig()
1164
+ .then(function (config) {
1165
+ if (autoCheckDisposed) return;
1166
+ if (config && config.checkInterval) {
1167
+ startAutoCheck(config, translate);
1168
+ } else {
1169
+ startAutoCheck({ checkInterval: "startup" }, translate);
1170
+ }
1171
+ })
1172
+ .catch(function () {
1173
+ if (autoCheckDisposed) return;
1174
+ startAutoCheck({ checkInterval: "startup" }, translate);
1175
+ });
1176
+ return function () {
1177
+ autoCheckDisposed = true;
1178
+ stopAutoCheck();
1179
+ };
1180
+ },
1181
+ "dsh-update-plugin: automatic update check",
1182
+ );
1183
+
966
1184
  var sidebarRight = null;
967
1185
  ctx.inject(["sidebarRightTabs", "sidebarRight"], function (sideCtx) {
968
1186
  sidebarRight = sideCtx.sidebarRight;
@@ -1,7 +1,7 @@
1
1
  // dsh-update-plugin host-side update core.
2
2
  //
3
3
  // This module intentionally depends on Node built-ins only. It mirrors the
4
- // logic of the dsh-update-all shell script (resolve the newest CLI across all
4
+ // logic of the dsh-update-plugin shell script (resolve the newest CLI across all
5
5
  // npm dist-tags, discover profiles, back up, update the CLI and every profile)
6
6
  // so the plugin can work without Homebrew or a separately installed script.
7
7
 
@@ -20,8 +20,9 @@ export const CLI_TIMEOUT_MS = 10 * 60 * 1000;
20
20
  export const PROFILE_TIMEOUT_MS = 5 * 60 * 1000;
21
21
 
22
22
  export const CONFIG_FILENAME = "dsh-update-plugin.json";
23
- export const DEFAULT_CONFIG = { channel: "auto", minAge: 0 };
23
+ export const DEFAULT_CONFIG = { channel: "auto", minAge: 0, checkInterval: "startup" };
24
24
  const CHANNELS = new Set(["auto", "stable", "next", "alpha"]);
25
+ const CHECK_INTERVALS = new Set(["startup", "hourly", "daily", "off"]);
25
26
 
26
27
  export function normalizeConfig(raw) {
27
28
  const source = raw && typeof raw === "object" ? raw : {};
@@ -29,6 +30,11 @@ export function normalizeConfig(raw) {
29
30
  if (!CHANNELS.has(config.channel)) config.channel = DEFAULT_CONFIG.channel;
30
31
  const minAge = Number(config.minAge);
31
32
  config.minAge = Number.isInteger(minAge) && minAge >= 0 ? minAge : DEFAULT_CONFIG.minAge;
33
+ if (CHECK_INTERVALS.has(config.checkInterval)) {
34
+ // keep
35
+ } else {
36
+ config.checkInterval = DEFAULT_CONFIG.checkInterval;
37
+ }
32
38
  return config;
33
39
  }
34
40
 
@@ -386,7 +392,7 @@ export async function listBackups(dshHome) {
386
392
  backups.push({
387
393
  id: entry.name,
388
394
  dir,
389
- source: manifest.source || "dsh-update-all",
395
+ source: manifest.source || "dsh-update-plugin",
390
396
  createdAt: manifest.createdAt || manifest.timestamp || null,
391
397
  cliVersion: manifest.cliVersion || manifest.cli_version || null,
392
398
  targetVersion: manifest.targetVersion || manifest.target_version || null,
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "dsh-update-plugin",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "DSH Web plugin: check and update DeepSeek Harness CLI and all profile plugins from Settings → General.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/haotian-lu-prog/dsh-update-all.git",
8
+ "url": "git+https://github.com/haotian-lu-prog/dsh-update-plugin.git",
9
9
  "directory": "plugin"
10
10
  },
11
- "homepage": "https://github.com/haotian-lu-prog/dsh-update-all/tree/main/plugin",
11
+ "homepage": "https://github.com/haotian-lu-prog/dsh-update-plugin/tree/main/plugin",
12
12
  "bugs": {
13
- "url": "https://github.com/haotian-lu-prog/dsh-update-all/issues"
13
+ "url": "https://github.com/haotian-lu-prog/dsh-update-plugin/issues"
14
14
  },
15
15
  "type": "module",
16
16
  "main": "lib/index.js",