@rezti/dsh-rez-suite 0.1.18 → 0.1.20

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/README.md CHANGED
@@ -6,10 +6,10 @@
6
6
  # 第一次
7
7
  dsh plugin --profile web add @rezti/dsh-rez-suite
8
8
 
9
- # 以后升级(只记这一条)
9
+ # 以后升级:侧栏底部「升级」按钮,或
10
10
  dsh plugin --profile web update @rezti/dsh-rez-suite
11
11
  ```
12
12
 
13
13
  包名是 `@rezti/dsh-rez-suite`,不是 `dsh-rezti-suite`。不要对同一 profile 再单独 add 子包,会重复注册。
14
14
 
15
- 拆分包(`dsh-rez-odoo` 等)给开发改代码用。Web 面板(含微信扫码)暂时仍在本包。老板三室(搞钱 / 产品 / 运营)也在本包内播种并登记侧栏,**不要**再装 `@rezti/dsh-rez-boss-desk`。
15
+ 拆分包(`dsh-rez-odoo` 等)给开发改代码用。Web 面板(含微信扫码)暂时仍在本包。设置里角色选「老板」后,才会在侧栏登记搞钱 / 产品 / 运营;切走老板会拿掉这三间(文件夹保留)。**不要**再装 `@rezti/dsh-rez-boss-desk`。
package/lib/client.d.ts CHANGED
@@ -7349,6 +7349,13 @@ declare const zh: {
7349
7349
  readonly 'weixin.listening': "通道在听:微信 → 网页「微信」会话(同一条,不另开窗口)→ 回微信。";
7350
7350
  readonly 'weixin.loggedIn': "已登录,通道未在听。点「重新连接」即可拉起,不必再扫码。";
7351
7351
  readonly 'weixin.loggedOut': "尚未登录。";
7352
+ readonly 'upgrade.label': "升级";
7353
+ readonly 'upgrade.current': "已最新";
7354
+ readonly 'upgrade.aria': "升级 ReZ-TI 插件";
7355
+ readonly 'upgrade.running': "升级中…";
7356
+ readonly 'upgrade.reloading': "正在重载";
7357
+ readonly 'upgrade.already': "已是 {version}";
7358
+ readonly 'upgrade.reloadTimeout': "升级完成,但网页还没重新连上。请刷新这一页。";
7352
7359
  };
7353
7360
  type RezKey = keyof typeof zh;
7354
7361
  //#endregion
@@ -7372,6 +7379,13 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
7372
7379
  children?: never;
7373
7380
  };
7374
7381
  };
7382
+ 'sidebar.footer.action': {
7383
+ kind: 'list';
7384
+ scope: 'root';
7385
+ owner: {
7386
+ wide: boolean;
7387
+ };
7388
+ };
7375
7389
  }
7376
7390
  }
7377
7391
  declare const inject: string[];
package/lib/client.js CHANGED
@@ -4,7 +4,7 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
- (function(){var id="dsh-rez-suite-css";if(typeof document==="undefined"||document.getElementById(id))return;var s=document.createElement("style");s.id=id;s.textContent=".LOjPTW_shell {\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n display: flex;\n}\n\n.LOjPTW_card {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n}\n\n.LOjPTW_card:hover {\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n.LOjPTW_cardOpen {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n.LOjPTW_header {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n\n.LOjPTW_header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n.LOjPTW_headText {\n flex-direction: column;\n flex: 1;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n.LOjPTW_name {\n color: var(--dsw-alias-label-primary);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n.LOjPTW_description {\n color: var(--dsw-alias-label-tertiary);\n font-size: 13px;\n line-height: 1.5;\n}\n\n.LOjPTW_chevron {\n color: var(--dsw-alias-label-tertiary);\n flex: none;\n transition: transform .16s;\n}\n\n.LOjPTW_chevronOpen {\n transform: rotate(180deg);\n}\n\n.LOjPTW_body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin: 0 16px 12px;\n padding-top: 8px;\n}\n\n.LOjPTW_tabBar {\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n flex: none;\n gap: 2px;\n display: flex;\n}\n\n.LOjPTW_tab {\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n border-radius: 6px 6px 0 0;\n padding: 7px 14px;\n font-size: 13px;\n}\n\n.LOjPTW_tab:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.LOjPTW_tab[data-active] {\n color: var(--dsw-alias-label-primary);\n border-bottom-color: var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.LOjPTW_tabBody {\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n padding: 12px 0 4px;\n display: flex;\n}\n\n.LOjPTW_section {\n border: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-layer-1, var(--dsw-alias-bg-base));\n border-radius: 10px;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n display: flex;\n}\n\n.LOjPTW_sectionTitle {\n color: var(--dsw-alias-label-primary);\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n.LOjPTW_field {\n flex-direction: column;\n align-items: stretch;\n gap: 4px;\n display: flex;\n}\n\n.LOjPTW_label {\n color: var(--dsw-alias-label-secondary);\n font-size: 12.5px;\n}\n\n.LOjPTW_input, .LOjPTW_select {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-3));\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n outline: none;\n padding: 6px 8px;\n font-size: 13px;\n}\n\n.LOjPTW_checkbox {\n justify-self: start;\n width: 15px;\n height: 15px;\n}\n\n.LOjPTW_toolbar {\n flex-wrap: wrap;\n flex: none;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.LOjPTW_button {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-3));\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n border-radius: 8px;\n padding: 7px 12px;\n font-size: 13px;\n}\n\n.LOjPTW_button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.LOjPTW_button:disabled {\n opacity: .4;\n cursor: default;\n}\n\n.LOjPTW_primaryButton {\n background: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n\n.LOjPTW_dangerButton {\n background: var(--dsw-alias-state-danger, #c62828);\n border-color: var(--dsw-alias-state-danger, #c62828);\n color: #fff;\n}\n\n.LOjPTW_qr {\n background: #fff;\n border-radius: 8px;\n width: 200px;\n height: 200px;\n margin: 8px 0;\n display: block;\n}\n\n.LOjPTW_message {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 12.5px;\n line-height: 1.5;\n}\n\n.LOjPTW_error {\n color: var(--dsw-alias-state-danger, #c62828);\n}\n\n.LOjPTW_tableWrap {\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n overflow: auto;\n}\n\n.LOjPTW_table {\n border-collapse: collapse;\n width: 100%;\n font-size: 12.5px;\n}\n\n.LOjPTW_table th {\n z-index: 1;\n text-align: left;\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));\n padding: 8px 10px;\n position: sticky;\n top: 0;\n}\n\n.LOjPTW_table td {\n border-top: 1px solid var(--dsw-alias-border-l1);\n vertical-align: top;\n padding: 8px 10px;\n}\n\n.LOjPTW_badge {\n border-radius: 999px;\n padding: 2px 8px;\n font-size: 11px;\n display: inline-block;\n}\n\n.LOjPTW_badgeOk {\n color: #229a55;\n background: #229a5524;\n}\n\n.LOjPTW_badgeFail {\n color: #c62828;\n background: #c6282824;\n}\n\n.LOjPTW_cards {\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\n gap: 8px;\n display: grid;\n}\n\n.LOjPTW_stat {\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n padding: 10px;\n}\n\n.LOjPTW_cardLabel {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.LOjPTW_cardValue {\n color: var(--dsw-alias-label-primary);\n font-size: 15px;\n font-weight: 600;\n}\n";document.head.appendChild(s);})();
7
+ (function(){var id="dsh-rez-suite-css";if(typeof document==="undefined"||document.getElementById(id))return;var s=document.createElement("style");s.id=id;s.textContent=".LOjPTW_shell {\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n display: flex;\n}\n\n.LOjPTW_card {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n}\n\n.LOjPTW_card:hover {\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n.LOjPTW_cardOpen {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n.LOjPTW_header {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n\n.LOjPTW_header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n.LOjPTW_headText {\n flex-direction: column;\n flex: 1;\n gap: 4px;\n min-width: 0;\n display: flex;\n}\n\n.LOjPTW_name {\n color: var(--dsw-alias-label-primary);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n\n.LOjPTW_description {\n color: var(--dsw-alias-label-tertiary);\n font-size: 13px;\n line-height: 1.5;\n}\n\n.LOjPTW_chevron {\n color: var(--dsw-alias-label-tertiary);\n flex: none;\n transition: transform .16s;\n}\n\n.LOjPTW_chevronOpen {\n transform: rotate(180deg);\n}\n\n.LOjPTW_body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin: 0 16px 12px;\n padding-top: 8px;\n}\n\n.LOjPTW_tabBar {\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n flex: none;\n gap: 2px;\n display: flex;\n}\n\n.LOjPTW_tab {\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n border-radius: 6px 6px 0 0;\n padding: 7px 14px;\n font-size: 13px;\n}\n\n.LOjPTW_tab:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.LOjPTW_tab[data-active] {\n color: var(--dsw-alias-label-primary);\n border-bottom-color: var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.LOjPTW_tabBody {\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n padding: 12px 0 4px;\n display: flex;\n}\n\n.LOjPTW_section {\n border: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-layer-1, var(--dsw-alias-bg-base));\n border-radius: 10px;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n display: flex;\n}\n\n.LOjPTW_sectionTitle {\n color: var(--dsw-alias-label-primary);\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n}\n\n.LOjPTW_field {\n flex-direction: column;\n align-items: stretch;\n gap: 4px;\n display: flex;\n}\n\n.LOjPTW_label {\n color: var(--dsw-alias-label-secondary);\n font-size: 12.5px;\n}\n\n.LOjPTW_input, .LOjPTW_select {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-3));\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n outline: none;\n padding: 6px 8px;\n font-size: 13px;\n}\n\n.LOjPTW_checkbox {\n justify-self: start;\n width: 15px;\n height: 15px;\n}\n\n.LOjPTW_toolbar {\n flex-wrap: wrap;\n flex: none;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.LOjPTW_button {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-3));\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n border-radius: 8px;\n padding: 7px 12px;\n font-size: 13px;\n}\n\n.LOjPTW_button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.LOjPTW_button:disabled {\n opacity: .4;\n cursor: default;\n}\n\n.LOjPTW_primaryButton {\n background: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n\n.LOjPTW_dangerButton {\n background: var(--dsw-alias-state-danger, #c62828);\n border-color: var(--dsw-alias-state-danger, #c62828);\n color: #fff;\n}\n\n.LOjPTW_qr {\n background: #fff;\n border-radius: 8px;\n width: 200px;\n height: 200px;\n margin: 8px 0;\n display: block;\n}\n\n.LOjPTW_message {\n color: var(--dsw-alias-label-secondary);\n margin: 0;\n font-size: 12.5px;\n line-height: 1.5;\n}\n\n.LOjPTW_error {\n color: var(--dsw-alias-state-danger, #c62828);\n}\n\n.LOjPTW_tableWrap {\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n overflow: auto;\n}\n\n.LOjPTW_table {\n border-collapse: collapse;\n width: 100%;\n font-size: 12.5px;\n}\n\n.LOjPTW_table th {\n z-index: 1;\n text-align: left;\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));\n padding: 8px 10px;\n position: sticky;\n top: 0;\n}\n\n.LOjPTW_table td {\n border-top: 1px solid var(--dsw-alias-border-l1);\n vertical-align: top;\n padding: 8px 10px;\n}\n\n.LOjPTW_badge {\n border-radius: 999px;\n padding: 2px 8px;\n font-size: 11px;\n display: inline-block;\n}\n\n.LOjPTW_badgeOk {\n color: #229a55;\n background: #229a5524;\n}\n\n.LOjPTW_badgeFail {\n color: #c62828;\n background: #c6282824;\n}\n\n.LOjPTW_cards {\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\n gap: 8px;\n display: grid;\n}\n\n.LOjPTW_stat {\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n padding: 10px;\n}\n\n.LOjPTW_cardLabel {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.LOjPTW_cardValue {\n color: var(--dsw-alias-label-primary);\n font-size: 15px;\n font-weight: 600;\n}\n\n.LOjPTW_upgradeLayer {\n flex: none;\n align-items: center;\n width: 100%;\n height: 42px;\n margin: 8px 0 0;\n display: flex;\n position: relative;\n}\n\n.LOjPTW_upgradeLayerRail {\n width: 36px;\n height: 36px;\n margin: 0;\n}\n\n.LOjPTW_upgradeButton {\n width: calc(100% + 4px);\n height: 42px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 12px;\n align-items: center;\n gap: 8px;\n margin: 0 -2px;\n padding: 0 10px 0 8px;\n font-family: inherit;\n font-size: 14px;\n display: inline-flex;\n overflow: hidden;\n}\n\n.LOjPTW_upgradeButton:hover, .LOjPTW_upgradeButton[data-outdated] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.LOjPTW_upgradeButton:disabled {\n cursor: progress;\n opacity: .72;\n}\n\n.LOjPTW_upgradeButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n.LOjPTW_upgradeLayerRail .LOjPTW_upgradeButton {\n border-radius: 50%;\n justify-content: center;\n gap: 0;\n width: 36px;\n height: 36px;\n padding: 0;\n}\n\n.LOjPTW_upgradeLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n.LOjPTW_upgradeMeta {\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n flex: none;\n margin-left: auto;\n font-size: 12px;\n line-height: 16px;\n}\n\n.LOjPTW_upgradeDot {\n background: var(--dsw-alias-brand-primary);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n";document.head.appendChild(s);})();
8
8
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
9
9
  let react = require("react");
10
10
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -109,7 +109,14 @@ const zh = {
109
109
  "weixin.qrAlt": "微信登录二维码",
110
110
  "weixin.listening": "通道在听:微信 → 网页「微信」会话(同一条,不另开窗口)→ 回微信。",
111
111
  "weixin.loggedIn": "已登录,通道未在听。点「重新连接」即可拉起,不必再扫码。",
112
- "weixin.loggedOut": "尚未登录。"
112
+ "weixin.loggedOut": "尚未登录。",
113
+ "upgrade.label": "升级",
114
+ "upgrade.current": "已最新",
115
+ "upgrade.aria": "升级 ReZ-TI 插件",
116
+ "upgrade.running": "升级中…",
117
+ "upgrade.reloading": "正在重载",
118
+ "upgrade.already": "已是 {version}",
119
+ "upgrade.reloadTimeout": "升级完成,但网页还没重新连上。请刷新这一页。"
113
120
  };
114
121
  const en = {
115
122
  "entry.label": "Rez",
@@ -208,7 +215,14 @@ const en = {
208
215
  "weixin.qrAlt": "WeChat login QR",
209
216
  "weixin.listening": "Channel is live: WeChat → the WeChat folder session on the left → WeChat.",
210
217
  "weixin.loggedIn": "Logged in, listener idle. Click Reconnect — no need to scan again.",
211
- "weixin.loggedOut": "Not logged in."
218
+ "weixin.loggedOut": "Not logged in.",
219
+ "upgrade.label": "Upgrade",
220
+ "upgrade.current": "Up to date",
221
+ "upgrade.aria": "Upgrade the ReZ-TI plugin",
222
+ "upgrade.running": "Updating…",
223
+ "upgrade.reloading": "Reloading",
224
+ "upgrade.already": "Already {version}",
225
+ "upgrade.reloadTimeout": "Update finished, but the page did not reconnect. Refresh this tab."
212
226
  };
213
227
  /** Minimal {name} interpolator shared by the panel helpers. */
214
228
  function t(dict, key, values) {
@@ -225,7 +239,8 @@ const REZ_API = {
225
239
  audit: "/api/dsh-rez-suite/audit",
226
240
  auditReset: "/api/dsh-rez-suite/audit/reset",
227
241
  weixin: "/api/dsh-rez-suite/weixin",
228
- weixinVerify: "/api/dsh-rez-suite/weixin/verify"
242
+ weixinVerify: "/api/dsh-rez-suite/weixin/verify",
243
+ update: "/api/dsh-rez-suite/update"
229
244
  };
230
245
  //#endregion
231
246
  //#region src/client/api.ts
@@ -287,6 +302,12 @@ var RezApi = class {
287
302
  async weixinLogout() {
288
303
  return readJson(await fetch(REZ_API.weixin, { method: "DELETE" }));
289
304
  }
305
+ async updateStatus() {
306
+ return readJson(await fetch(REZ_API.update));
307
+ }
308
+ async applyUpdate() {
309
+ return readJson(await fetch(REZ_API.update, { method: "POST" }));
310
+ }
290
311
  };
291
312
  //#endregion
292
313
  //#region src/client/panel/helpers.ts
@@ -341,7 +362,13 @@ var panel_module_default = {
341
362
  "tabBody": "LOjPTW_tabBody",
342
363
  "table": "LOjPTW_table",
343
364
  "tableWrap": "LOjPTW_tableWrap",
344
- "toolbar": "LOjPTW_toolbar"
365
+ "toolbar": "LOjPTW_toolbar",
366
+ "upgradeButton": "LOjPTW_upgradeButton",
367
+ "upgradeDot": "LOjPTW_upgradeDot",
368
+ "upgradeLabel": "LOjPTW_upgradeLabel",
369
+ "upgradeLayer": "LOjPTW_upgradeLayer",
370
+ "upgradeLayerRail": "LOjPTW_upgradeLayerRail",
371
+ "upgradeMeta": "LOjPTW_upgradeMeta"
345
372
  };
346
373
  //#endregion
347
374
  //#region src/client/panel/AuditTab.tsx
@@ -1249,6 +1276,109 @@ function RezPluginCard() {
1249
1276
  });
1250
1277
  }
1251
1278
  //#endregion
1279
+ //#region src/client/upgrade-button.tsx
1280
+ /**
1281
+ * Sidebar footer action: upgrade @rezti/dsh-rez-suite without a terminal.
1282
+ * Host code still needs a process respawn; the button does that after pnpm add.
1283
+ */
1284
+ function UpgradeIcon() {
1285
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1286
+ width: "16",
1287
+ height: "16",
1288
+ viewBox: "0 0 16 16",
1289
+ "aria-hidden": "true",
1290
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1291
+ d: "M8 12.5V4.8M8 4.8 4.8 8M8 4.8 11.2 8M3 13.2h10",
1292
+ fill: "none",
1293
+ stroke: "currentColor",
1294
+ strokeWidth: "1.4",
1295
+ strokeLinecap: "round",
1296
+ strokeLinejoin: "round"
1297
+ })
1298
+ });
1299
+ }
1300
+ async function waitUntilHostBack(api, timeoutMs = 6e4) {
1301
+ const deadline = Date.now() + timeoutMs;
1302
+ await new Promise((resolve) => setTimeout(resolve, 800));
1303
+ while (Date.now() < deadline) try {
1304
+ await api.updateStatus();
1305
+ return;
1306
+ } catch {
1307
+ await new Promise((resolve) => setTimeout(resolve, 700));
1308
+ }
1309
+ throw new Error(tt("upgrade.reloadTimeout"));
1310
+ }
1311
+ function UpgradeButton({ wide }) {
1312
+ const api = (0, react.useMemo)(() => new RezApi(), []);
1313
+ const [info, setInfo] = (0, react.useState)();
1314
+ const [busy, setBusy] = (0, react.useState)(false);
1315
+ const [note, setNote] = (0, react.useState)("");
1316
+ (0, react.useEffect)(() => {
1317
+ let cancelled = false;
1318
+ api.updateStatus().then((value) => {
1319
+ if (!cancelled) setInfo(value);
1320
+ }).catch((error) => {
1321
+ if (!cancelled) setNote(error instanceof Error ? error.message : String(error));
1322
+ });
1323
+ return () => {
1324
+ cancelled = true;
1325
+ };
1326
+ }, [api]);
1327
+ const label = busy ? tt("upgrade.running") : info?.outdated === true ? tt("upgrade.label") : tt("upgrade.current");
1328
+ const meta = note !== "" ? note : info === void 0 ? "" : info.outdated ? info.latest : info.installed;
1329
+ async function onClick() {
1330
+ if (busy) return;
1331
+ setBusy(true);
1332
+ setNote("");
1333
+ try {
1334
+ const snapshot = info ?? await api.updateStatus();
1335
+ setInfo(snapshot);
1336
+ if (!snapshot.outdated) {
1337
+ setNote(tt("upgrade.already", { version: snapshot.installed }));
1338
+ return;
1339
+ }
1340
+ const result = await api.applyUpdate();
1341
+ setInfo(result);
1342
+ if (result.restarting) {
1343
+ setNote(tt("upgrade.reloading"));
1344
+ await waitUntilHostBack(api);
1345
+ window.location.reload();
1346
+ return;
1347
+ }
1348
+ setNote(tt("upgrade.already", { version: result.installed }));
1349
+ } catch (error) {
1350
+ setNote(error instanceof Error ? error.message : String(error));
1351
+ } finally {
1352
+ setBusy(false);
1353
+ }
1354
+ }
1355
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1356
+ className: wide ? panel_module_default.upgradeLayer : `${panel_module_default.upgradeLayer} ${panel_module_default.upgradeLayerRail}`,
1357
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1358
+ type: "button",
1359
+ className: panel_module_default.upgradeButton,
1360
+ "data-outdated": info?.outdated === true ? "" : void 0,
1361
+ "aria-label": tt("upgrade.aria"),
1362
+ disabled: busy,
1363
+ onClick: () => {
1364
+ onClick();
1365
+ },
1366
+ children: [
1367
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UpgradeIcon, {}),
1368
+ wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1369
+ className: panel_module_default.upgradeLabel,
1370
+ children: label
1371
+ }),
1372
+ wide && meta !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1373
+ className: panel_module_default.upgradeMeta,
1374
+ children: meta
1375
+ }),
1376
+ !wide && info?.outdated === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_default.upgradeDot })
1377
+ ]
1378
+ })
1379
+ });
1380
+ }
1381
+ //#endregion
1252
1382
  //#region src/client/index.ts
1253
1383
  const NS = "dsh-rez-suite";
1254
1384
  const inject = ["slots", "locale"];
@@ -1270,6 +1400,13 @@ function apply(ctx) {
1270
1400
  label: () => t("settings.title"),
1271
1401
  locale: NS
1272
1402
  }, RezSettingsPage));
1403
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
1404
+ name: "sidebar.footer.action",
1405
+ id: "rez-upgrade",
1406
+ order: 10,
1407
+ label: () => t("upgrade.label"),
1408
+ locale: NS
1409
+ }, UpgradeButton));
1273
1410
  }
1274
1411
  //#endregion
1275
1412
  exports.apply = apply;
package/lib/index.d.ts CHANGED
@@ -1741,7 +1741,8 @@ declare const name = "rez-suite";
1741
1741
  declare const inject: string[];
1742
1742
  declare const REZ_SETTINGS_NAMESPACE: SettingsNamespace;
1743
1743
  declare const Config: Schema<RezConfig>;
1744
- declare const REZ_GUIDANCE: string;
1744
+ declare const REZ_GUIDANCE_CORE: string;
1745
+ declare function rezGuidanceFor(role: RezConfig['role']): string;
1745
1746
  declare function apply(ctx: Context, config?: RezConfig): void;
1746
1747
  //#endregion
1747
- export { Config, REZ_GUIDANCE, REZ_SETTINGS_NAMESPACE, apply, inject, name };
1748
+ export { Config, REZ_GUIDANCE_CORE, REZ_SETTINGS_NAMESPACE, apply, inject, name, rezGuidanceFor };
package/lib/index.js CHANGED
@@ -2,9 +2,10 @@ import { createRequire } from "node:module";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join, relative } from "node:path";
4
4
  import { REZ_CREDENTIAL_REFS, REZ_DEFAULT_CONNECTIONS, REZ_SYSTEMS, lastMcpStartError, mergeConnections, secretConfigured, writeManagedCredential } from "@rezti/dsh-rez-sso";
5
- import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
5
+ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
6
6
  import { DatabaseSync } from "node:sqlite";
7
7
  import { fileURLToPath } from "node:url";
8
+ import { spawn } from "node:child_process";
8
9
  //#region ../../node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/index.js
9
10
  /** Return true when a value is `null` or `undefined`. */
10
11
  function isNullable(value) {
@@ -2955,7 +2956,8 @@ const REZ_API = {
2955
2956
  audit: "/api/dsh-rez-suite/audit",
2956
2957
  auditReset: "/api/dsh-rez-suite/audit/reset",
2957
2958
  weixin: "/api/dsh-rez-suite/weixin",
2958
- weixinVerify: "/api/dsh-rez-suite/weixin/verify"
2959
+ weixinVerify: "/api/dsh-rez-suite/weixin/verify",
2960
+ update: "/api/dsh-rez-suite/update"
2959
2961
  };
2960
2962
  //#endregion
2961
2963
  //#region src/store.ts
@@ -3205,7 +3207,7 @@ function applyPublicPatch(current, patch) {
3205
3207
  }
3206
3208
  /** Build every /api/dsh-rez-suite route (exact paths). */
3207
3209
  function makeRoutes(deps) {
3208
- const { getConfig, updateConfig, host, tokens, onCredentialWritten } = deps;
3210
+ const { getConfig, updateConfig, host, tokens, onCredentialWritten, selfUpdate } = deps;
3209
3211
  const guard = (req, res, method) => {
3210
3212
  if (!isLoopbackRequest(req)) {
3211
3213
  writeJson(res, 403, { error: "forbidden: loopback-only" });
@@ -3277,6 +3279,31 @@ function makeRoutes(deps) {
3277
3279
  tokens.reset();
3278
3280
  writeJson(res, 200, { ok: true });
3279
3281
  }
3282
+ },
3283
+ {
3284
+ kind: "exact",
3285
+ path: REZ_API.update,
3286
+ handler: async (req, res) => {
3287
+ const method = req.method === "POST" ? "POST" : "GET";
3288
+ if (!guard(req, res, method)) return;
3289
+ if (selfUpdate === void 0) {
3290
+ writeJson(res, 501, { error: "self-update is not available" });
3291
+ return;
3292
+ }
3293
+ try {
3294
+ if (method === "GET") {
3295
+ writeJson(res, 200, await selfUpdate.status());
3296
+ return;
3297
+ }
3298
+ const result = await selfUpdate.apply();
3299
+ writeJson(res, 200, result);
3300
+ if (result.restarting) setTimeout(() => {
3301
+ selfUpdate.relaunch();
3302
+ }, 400);
3303
+ } catch (error) {
3304
+ writeJson(res, 502, { error: error instanceof Error ? error.message : String(error) });
3305
+ }
3306
+ }
3280
3307
  }
3281
3308
  ];
3282
3309
  }
@@ -7667,9 +7694,32 @@ function rezConfigTool(config) {
7667
7694
  }
7668
7695
  //#endregion
7669
7696
  //#region src/boss/register.ts
7697
+ /**
7698
+ * Register or drop the three boss rooms in the official workspace sidebar.
7699
+ * `workspaceRegistry.create` is idempotent: same canonical path returns the
7700
+ * existing record. New records are prepended, so we register in reverse to
7701
+ * keep 搞钱 → 产品 → 运营 at the top of the sidebar.
7702
+ * `delete` only drops the registry row — directories and session logs stay.
7703
+ */
7704
+ function canon(path) {
7705
+ try {
7706
+ return realpathSync(path);
7707
+ } catch {
7708
+ return path;
7709
+ }
7710
+ }
7711
+ function isRegisteredBossRoom(workspace, rooms) {
7712
+ return new Set(rooms.map((room) => canon(room.path))).has(canon(workspace.path));
7713
+ }
7670
7714
  async function registerBossWorkspaces(registry, rooms) {
7671
7715
  for (const room of [...rooms].reverse()) await registry.create(room.path, room.folder);
7672
7716
  }
7717
+ async function unregisterBossWorkspaces(registry, rooms) {
7718
+ for (const workspace of registry.list()) {
7719
+ if (!isRegisteredBossRoom(workspace, rooms)) continue;
7720
+ await registry.delete(workspace.id);
7721
+ }
7722
+ }
7673
7723
  //#endregion
7674
7724
  //#region src/boss/seed.ts
7675
7725
  const BOSS_ROOMS = [
@@ -7766,27 +7816,195 @@ function listFiles(root) {
7766
7816
  }
7767
7817
  //#endregion
7768
7818
  //#region src/boss/mount.ts
7819
+ const BOSS_ROLE_HINT = "设置 → 插件 → ReZ-TI → 角色选「老板」后,左侧会出现搞钱 / 产品 / 运营三室。不必手动「添加工作区」。";
7769
7820
  const BOSS_GUIDANCE = [
7770
- "老板三室已播种并登记为侧栏工作区:~/.dsh/workspaces/搞钱、产品、运营。不必手动「添加工作区」。",
7771
- "设置 → 插件 → ReZ-TI → 角色选「老板」。每个文件夹是独立作战室,官方 dsh 会注入该目录 AGENTS.md。",
7821
+ "当前角色是老板。侧栏已登记三室:~/.dsh/workspaces/搞钱、产品、运营。不必手动「添加工作区」。",
7822
+ "每个文件夹是独立作战室,官方 dsh 会注入该目录 AGENTS.md。",
7772
7823
  "若该室仍有 BOOTSTRAP.md:本会话先做短问三拍,沉淀到 PRIORITIES.md / MEMORY.md,然后删除 BOOTSTRAP.md。",
7773
7824
  "已初始化后:读 PRIORITIES.md + MEMORY.md + 今日/昨日 memory/;回答固定四行:结论 → 数字(哪家公司、哪段时间)→ 拍板 1~3 件事 → 未执行任何过账/付款/对外发送。",
7774
7825
  "微信文件夹仍是收件箱,不要在那边查账或砍 SKU。"
7775
7826
  ].join("");
7827
+ function bossGuidanceFor(role) {
7828
+ return role === "boss" ? BOSS_GUIDANCE : BOSS_ROLE_HINT;
7829
+ }
7776
7830
  function destRoot(env = process.env) {
7777
7831
  if (env.REZ_BOSS_WORKSPACES !== void 0 && env.REZ_BOSS_WORKSPACES !== "") return env.REZ_BOSS_WORKSPACES;
7778
7832
  return join(env.DSH_HOME !== void 0 && env.DSH_HOME !== "" ? env.DSH_HOME : join(homedir(), ".dsh"), "workspaces");
7779
7833
  }
7780
- /** Seed files, then register official workspaces once workspaceRegistry is ready. */
7781
- function mountBossDesk(ctx) {
7782
- const seeded = seedBossWorkspaces({ destRoot: destRoot() });
7783
- ctx.inject(["workspaceRegistry"], (inner) => {
7784
- registerBossWorkspaces(inner.get("workspaceRegistry"), seeded.rooms).catch((error) => {
7785
- const why = error instanceof Error ? error.message : String(error);
7786
- console.error("[dsh-rez-suite] workspaceRegistry.create failed:", why);
7834
+ function expectedBossRooms(env = process.env) {
7835
+ const root = destRoot(env);
7836
+ return BOSS_ROOMS.map((room) => ({
7837
+ path: join(root, room.folder),
7838
+ folder: room.folder
7839
+ }));
7840
+ }
7841
+ async function syncBossWorkspaces(registry, role, env = process.env) {
7842
+ if (role === "boss") {
7843
+ await registerBossWorkspaces(registry, seedBossWorkspaces({ destRoot: destRoot(env) }).rooms);
7844
+ return;
7845
+ }
7846
+ await unregisterBossWorkspaces(registry, expectedBossRooms(env));
7847
+ }
7848
+ /** Seed/register 三室 only for role=boss; drop sidebar rows otherwise. Returns a re-sync function. */
7849
+ function mountBossDesk(ctx, getRole) {
7850
+ const run = () => {
7851
+ ctx.inject(["workspaceRegistry"], (inner) => {
7852
+ syncBossWorkspaces(inner.get("workspaceRegistry"), getRole()).catch((error) => {
7853
+ const why = error instanceof Error ? error.message : String(error);
7854
+ console.error("[dsh-rez-suite] boss workspace sync failed:", why);
7855
+ });
7856
+ });
7857
+ };
7858
+ run();
7859
+ return run;
7860
+ }
7861
+ //#endregion
7862
+ //#region src/self-update.ts
7863
+ /**
7864
+ * In-place upgrade of @rezti/dsh-rez-suite inside the running dsh profile.
7865
+ * pnpm add writes the new bits; Node cannot replace an already-imported host
7866
+ * module, so we respawn the same argv after the HTTP response flushes.
7867
+ */
7868
+ const SUITE_PACKAGE = "@rezti/dsh-rez-suite";
7869
+ const NPM_LATEST = "https://registry.npmjs.org/@rezti/dsh-rez-suite/latest";
7870
+ const PNPM_TIMEOUT_MS = 18e4;
7871
+ function compareVersions(left, right) {
7872
+ const a = left.split(".").map((part) => Number.parseInt(part, 10) || 0);
7873
+ const b = right.split(".").map((part) => Number.parseInt(part, 10) || 0);
7874
+ const n = Math.max(a.length, b.length);
7875
+ for (let i = 0; i < n; i += 1) {
7876
+ const av = a[i] ?? 0;
7877
+ const bv = b[i] ?? 0;
7878
+ if (av > bv) return 1;
7879
+ if (av < bv) return -1;
7880
+ }
7881
+ return 0;
7882
+ }
7883
+ function readInstalledVersion(packageDir) {
7884
+ const raw = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8"));
7885
+ if (typeof raw.version !== "string" || raw.version === "") throw new Error("suite package.json missing version");
7886
+ return raw.version;
7887
+ }
7888
+ function findProfileDir(startDir) {
7889
+ let dir = startDir;
7890
+ for (let i = 0; i < 12; i += 1) {
7891
+ const manifest = join(dir, "package.json");
7892
+ if (existsSync(manifest)) try {
7893
+ const raw = JSON.parse(readFileSync(manifest, "utf8"));
7894
+ if (Array.isArray(raw.dsh?.profile?.bundles)) return dir;
7895
+ } catch {}
7896
+ const parent = dirname(dir);
7897
+ if (parent === dir) break;
7898
+ dir = parent;
7899
+ }
7900
+ throw new Error("cannot find dsh profile directory (no package.json with dsh.profile.bundles)");
7901
+ }
7902
+ function shellQuote(value) {
7903
+ return `'${value.replaceAll("'", `'\\''`)}'`;
7904
+ }
7905
+ function relaunchScript(argv, parentPid) {
7906
+ return `while kill -0 ${parentPid} 2>/dev/null; do sleep 0.15; done; sleep 0.25; exec ${argv.map(shellQuote).join(" ")}`;
7907
+ }
7908
+ async function fetchLatestVersion(fetchImpl = fetch) {
7909
+ const response = await fetchImpl(NPM_LATEST, { headers: { accept: "application/json" } });
7910
+ if (!response.ok) throw new Error(`npm registry HTTP ${response.status}`);
7911
+ const body = await response.json();
7912
+ if (typeof body.version !== "string" || body.version === "") throw new Error("npm registry missing version");
7913
+ return body.version;
7914
+ }
7915
+ function runPnpmAdd(cwd, spec, env = process.env) {
7916
+ return new Promise((resolve, reject) => {
7917
+ const child = spawn("pnpm", ["add", spec], {
7918
+ cwd,
7919
+ env,
7920
+ stdio: [
7921
+ "ignore",
7922
+ "pipe",
7923
+ "pipe"
7924
+ ]
7925
+ });
7926
+ let stderr = "";
7927
+ child.stderr.on("data", (chunk) => {
7928
+ stderr += chunk.toString();
7929
+ });
7930
+ const timer = setTimeout(() => {
7931
+ child.kill("SIGTERM");
7932
+ reject(/* @__PURE__ */ new Error("pnpm add timed out after 3 minutes"));
7933
+ }, PNPM_TIMEOUT_MS);
7934
+ child.on("error", (error) => {
7935
+ clearTimeout(timer);
7936
+ reject(error);
7937
+ });
7938
+ child.on("close", (code) => {
7939
+ clearTimeout(timer);
7940
+ if (code === 0) resolve();
7941
+ else reject(new Error(stderr.trim() || `pnpm add exited ${String(code)}`));
7787
7942
  });
7788
7943
  });
7789
7944
  }
7945
+ function spawnRelaunch(argv, parentPid, cwd, env = process.env) {
7946
+ spawn("/bin/bash", ["-c", relaunchScript(argv, parentPid)], {
7947
+ cwd,
7948
+ env,
7949
+ detached: true,
7950
+ stdio: "ignore"
7951
+ }).unref();
7952
+ }
7953
+ let inflight;
7954
+ function createSelfUpdate(io) {
7955
+ const status = async () => {
7956
+ const installed = readInstalledVersion(io.packageDir);
7957
+ const latest = await io.fetchLatest();
7958
+ return {
7959
+ package: SUITE_PACKAGE,
7960
+ installed,
7961
+ latest,
7962
+ outdated: compareVersions(latest, installed) > 0
7963
+ };
7964
+ };
7965
+ const apply = async () => {
7966
+ if (inflight !== void 0) throw new Error("upgrade already running");
7967
+ const work = (async () => {
7968
+ const snapshot = await status();
7969
+ if (!snapshot.outdated) return {
7970
+ ...snapshot,
7971
+ restarting: false
7972
+ };
7973
+ const profileDir = findProfileDir(io.packageDir);
7974
+ await io.install(profileDir, `${SUITE_PACKAGE}@${snapshot.latest}`);
7975
+ return {
7976
+ ...snapshot,
7977
+ installed: snapshot.latest,
7978
+ outdated: false,
7979
+ restarting: true
7980
+ };
7981
+ })();
7982
+ inflight = work;
7983
+ try {
7984
+ return await work;
7985
+ } finally {
7986
+ inflight = void 0;
7987
+ }
7988
+ };
7989
+ return {
7990
+ status,
7991
+ apply,
7992
+ relaunch: io.relaunch
7993
+ };
7994
+ }
7995
+ function liveSelfUpdate() {
7996
+ return createSelfUpdate({
7997
+ packageDir: dirname(fileURLToPath(new URL(".", import.meta.url))),
7998
+ fetchLatest: () => fetchLatestVersion(),
7999
+ install: (profileDir, spec) => runPnpmAdd(profileDir, spec),
8000
+ relaunch: () => {
8001
+ spawnRelaunch(process.argv, process.pid, process.cwd());
8002
+ setTimeout(() => {
8003
+ process.exit(0);
8004
+ }, 50);
8005
+ }
8006
+ });
8007
+ }
7790
8008
  //#endregion
7791
8009
  //#region src/index.ts
7792
8010
  const name = "rez-suite";
@@ -7845,15 +8063,17 @@ const Config = Schema.object({
7845
8063
  })
7846
8064
  });
7847
8065
  const SECTION_ORDER = 150;
7848
- const REZ_GUIDANCE = [
8066
+ const REZ_GUIDANCE_CORE = [
7849
8067
  "本机已安装 ReZ-TI 拆分包:工作身份由 dsh-rez-sso 提供,MCP 由官方 dsh-mcp-client 接入 Odoo / Nextcloud / 企业微信 / Home Assistant。",
7850
8068
  "工具名 mcp__odoo__*、mcp__nextcloud__*、mcp__wechat__*、mcp__homeassistant__*。",
7851
8069
  "密钥:REZ_ODOO_TOKEN、REZ_NEXTCLOUD_PASSWORD、REZ_WECHAT_WEBHOOK、REZ_HA_TOKEN。",
7852
8070
  "个人微信(QClaw/ClawBot):打开 设置 → 插件 → ReZ-TI → 微信 扫码,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认。网页归档了再从微信说话会自动恢复到侧栏。发「重启对话」会新开一条可见会话并把旧会话归档。网页端必须开着。不必再跑命令、也不要调用微信 MCP 工具。",
7853
8071
  "意图用 rez_set_intent(erp/files/chat/home/auto)。审计用 rez_audit。",
7854
- "涉及资金、对外发送、设备控制、生产写入时先征得用户批准。",
7855
- BOSS_GUIDANCE
8072
+ "涉及资金、对外发送、设备控制、生产写入时先征得用户批准。"
7856
8073
  ].join("");
8074
+ function rezGuidanceFor(role) {
8075
+ return REZ_GUIDANCE_CORE + bossGuidanceFor(role);
8076
+ }
7857
8077
  function normalize(input) {
7858
8078
  return mergeConfig(defaultConfig(), input ?? {});
7859
8079
  }
@@ -7873,8 +8093,8 @@ function delegatedHost(ctx, getConfig) {
7873
8093
  };
7874
8094
  }
7875
8095
  function apply(ctx, config) {
7876
- mountBossDesk(ctx);
7877
8096
  let current = () => normalize(config);
8097
+ const syncBossDesk = mountBossDesk(ctx, () => current().role);
7878
8098
  const tokens = new TokenManager(joinTokenDb());
7879
8099
  const host = delegatedHost(ctx, () => current());
7880
8100
  ctx.effect(() => () => {
@@ -7887,6 +8107,7 @@ function apply(ctx, config) {
7887
8107
  const value = normalize(next);
7888
8108
  saveConfig(value);
7889
8109
  current = () => value;
8110
+ syncBossDesk();
7890
8111
  try {
7891
8112
  const settings = ctx.get("settings");
7892
8113
  if (settings?.update !== void 0) await settings.update(REZ_SETTINGS_NAMESPACE, value);
@@ -7900,7 +8121,8 @@ function apply(ctx, config) {
7900
8121
  onCredentialWritten: (ref) => {
7901
8122
  const emit = ctx.emit;
7902
8123
  emit("credentials/updated", ref);
7903
- }
8124
+ },
8125
+ selfUpdate: liveSelfUpdate()
7904
8126
  });
7905
8127
  let disposeRoutes;
7906
8128
  let disposeTools;
@@ -7923,7 +8145,7 @@ function apply(ctx, config) {
7923
8145
  if (value.announceToAgent) disposeSection = ctx.systemPrompt.section({
7924
8146
  name: "plugin:dsh-rez-suite",
7925
8147
  order: SECTION_ORDER,
7926
- text: REZ_GUIDANCE
8148
+ text: rezGuidanceFor(value.role)
7927
8149
  });
7928
8150
  disposeRoutes = ctx.effect(() => {
7929
8151
  const disposers = routes.map((route) => ctx.webServer.register(route));
@@ -7942,8 +8164,12 @@ function apply(ctx, config) {
7942
8164
  setSource: (source) => {
7943
8165
  current = source;
7944
8166
  sync();
8167
+ syncBossDesk();
7945
8168
  },
7946
- onChange: sync
8169
+ onChange: () => {
8170
+ sync();
8171
+ syncBossDesk();
8172
+ }
7947
8173
  });
7948
8174
  sync();
7949
8175
  }
@@ -7951,4 +8177,4 @@ function joinTokenDb() {
7951
8177
  return join(homedir(), ".dsh", "dsh-rez-token-manager.sqlite");
7952
8178
  }
7953
8179
  //#endregion
7954
- export { Config, REZ_GUIDANCE, REZ_SETTINGS_NAMESPACE, apply, inject, name };
8180
+ export { Config, REZ_GUIDANCE_CORE, REZ_SETTINGS_NAMESPACE, apply, inject, name, rezGuidanceFor };