@rezti/dsh-rez-suite 0.1.45 → 0.1.47

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +9 -10
  3. package/README.zh.md +7 -3
  4. package/cordis.patch.yml +3 -1
  5. package/lib/client.d.ts +8 -2
  6. package/lib/client.js +191 -22
  7. package/lib/index.d.ts +4 -0
  8. package/lib/index.js +269 -16
  9. package/lib/style.css +43 -0
  10. package/package.json +7 -5
  11. package/src/boss/mount.ts +44 -4
  12. package/src/boss/register.ts +2 -0
  13. package/src/boss/seed.ts +29 -1
  14. package/src/changelog.ts +104 -0
  15. package/src/client/locales.ts +16 -4
  16. package/src/client/panel/ChangelogTab.tsx +57 -0
  17. package/src/client/panel/ConfigTab.tsx +16 -9
  18. package/src/client/panel/panel.module.css +43 -0
  19. package/src/client/settings-card.tsx +4 -1
  20. package/src/esphome-lab.ts +181 -0
  21. package/src/index.ts +17 -4
  22. package/src/observe-mcp.ts +12 -6
  23. package/src/presets.ts +11 -5
  24. package/src/protocol.ts +2 -0
  25. package/src/rooms.ts +29 -5
  26. package/src/store.ts +6 -0
  27. package/src/tools.ts +41 -0
  28. package/templates/boss/ops/AGENTS.md +1 -0
  29. package/templates/boss/product/AGENTS.md +5 -2
  30. package/templates/staff/design/.agents/skills/ops-design/SKILL.md +6 -0
  31. package/templates/staff/design/AGENTS.md +71 -0
  32. package/templates/staff/design/BOOTSTRAP.md +23 -0
  33. package/templates/staff/design/IDENTITY.md +8 -0
  34. package/templates/staff/design/MEMORY.md +9 -0
  35. package/templates/staff/design/PRIORITIES.md +3 -0
  36. package/templates/staff/design/SOUL.md +6 -0
  37. package/templates/staff/design/USER.md +8 -0
  38. package/templates/staff/hr/.agents/skills/staff-hr/SKILL.md +1 -1
  39. package/templates/staff/hr/.agents/skills/staff-onboard-keys/SKILL.md +99 -0
  40. package/templates/staff/hr/AGENTS.md +10 -0
  41. package/templates/staff/lab/.agents/skills/engineer-lab/SKILL.md +6 -0
  42. package/templates/staff/lab/AGENTS.md +34 -0
  43. package/templates/staff/lab/BOOTSTRAP.md +23 -0
  44. package/templates/staff/lab/IDENTITY.md +8 -0
  45. package/templates/staff/lab/MEMORY.md +9 -0
  46. package/templates/staff/lab/PRIORITIES.md +3 -0
  47. package/templates/staff/lab/SOUL.md +5 -0
  48. package/templates/staff/lab/USER.md +7 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,49 @@
1
+ # 更新日志
2
+
3
+ 员工只装 `@rezti/dsh-rez-suite`。设置 → 插件 → **ReZ-TI** → **更新日志** 也能看到同一份说明。发版时把这一节发给同事即可。
4
+
5
+ 升级:
6
+
7
+ ```bash
8
+ dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.47
9
+ ```
10
+
11
+ 不要用裸 `plugin update`,不要写 `latest`(新 profile 有 24 小时发布冷却,当天可能装不上)。不要装 **0.1.46**(GitHub 子依赖会被 DSH 拦住)。
12
+
13
+ 发版顺序:`sso@0.1.14` → `nextcloud@0.1.11` → `@rezti/dsh-web-file-uploader@0.2.2` → `suite@0.1.47`。
14
+
15
+ ## 0.1.47 — 2026-08-19
16
+
17
+ - **安装修复**:0.1.46 报 `ERR_PNPM_EXOTIC_SUBDEP`,因为回形针钉在 GitHub,而 DSH profile 禁止子依赖走 git。回形针改为 npm:`@rezti/dsh-web-file-uploader@0.2.2`(同源 Mooling0602 钉死 commit)。
18
+ - 设置页「更新日志」页签。
19
+
20
+ ## 0.1.46 — 2026-08-19
21
+
22
+ 相对上次已发 npm 的 **0.1.45**。**此版本无法在 DSH 员工 profile 安装**,请用 0.1.47。
23
+
24
+ ### 员工会碰到的
25
+
26
+ - **回形针上传 PDF**:说明书 / 规格书走输入栏回形针,先入 `Marketing/Inbox`,对应 TAPD 改成测试中并转凯文;凯文说审批了哪份,再进 `Marketing/Publish`。不要用微信发 PDF。
27
+ - **运营多了「设计」房间**:拍摄原片 Comfy **只修一次**,shot / clean 先入 Inbox;凯文终审后同时写入 `Marketing/RAW/…`。
28
+ - **品牌 / VI**:走 `Marketing/Inbox/Brand/`,终审后写入 `Marketing/RAW/Brand/`,不要写进某个 SKU。
29
+ - **工程师多了「实验室」**:对话里给 YAML,立刻拿到下载链接。还在编是说明文件;成功是 `firmware.bin`;失败是带日志的 README。不要在对话里等 bin,不要默认 OTA。
30
+ - **人事助理**:可引导新人领本机安装包、自己申请 API Key。
31
+ - **设置页**:暂时不显示企业微信配置栏(已填过的 webhook 不会被擦掉)。
32
+ - **运营权限**:仍可改 TAPD 状态、写评论、往 Inbox 传文件;**不能**删 TAPD / Nextcloud。
33
+
34
+ ### 安装与审批机
35
+
36
+ - 员工 Mac zip / Windows exe、审批人 Docker:每次启动拉 **钉死的 0.1.46**,不跟 `latest`。
37
+ - 安装包只是启动壳,第一次会从外网拉 Node 和 dsh。
38
+ - 回形针依赖还在 GitHub。装 suite **要能访问 GitHub**;公司机禁外网会失败。
39
+
40
+ ### 一起发的子包
41
+
42
+ | 包 | 版本 | 原因 |
43
+ | --- | --- | --- |
44
+ | `@rezti/dsh-rez-sso` | 0.1.14 | 实验室连接字段;空 Nextcloud 用户名不拉 MCP |
45
+ | `@rezti/dsh-rez-nextcloud` | 0.1.11 | Inbox → 凯文终审 → Publish / RAW 的入库说明 |
46
+
47
+ ## 0.1.45
48
+
49
+ 上次已发 npm。本文件从 0.1.46 起记用户可见变更。
package/README.md CHANGED
@@ -2,24 +2,23 @@
2
2
 
3
3
  雷泽插件的**唯一安装入口**。Odoo / 企微 / HA / TAPD / GSC / 企查查(仅法务助理房间) / 天眼查(仅老板) / 工作区(老板三室 + 全员助理)都由这一包拉齐,不要再逐个 `plugin add`,**不要**再装 `@rezti/dsh-rez-boss-desk`。
4
4
 
5
- 发版顺序:先发 `@rezti/dsh-rez-sso@0.1.13` `@rezti/dsh-rez-nextcloud@0.1.10`,再发 `@rezti/dsh-rez-suite@0.1.45`。suite 读取 SSO 的 `REZ_DEFAULT_CONNECTIONS.qcc`;缺字段时用官方 URL 兜底,避免插件加载失败把微信面板一起拖垮。
5
+ 发版顺序(必做):先发 `@rezti/dsh-rez-sso@0.1.14` `@rezti/dsh-rez-nextcloud@0.1.11` `@rezti/dsh-web-file-uploader@0.2.2` → `@rezti/dsh-rez-suite@0.1.47`。只发 suite 没有 SSO 0.1.14,实验室连接字段不会上 npm。suite 读取 SSO 的 `REZ_DEFAULT_CONNECTIONS.qcc`;缺字段时用官方 URL 兜底,避免插件加载失败把微信面板一起拖垮。
6
6
 
7
- 设置里选身份后,左侧自己出现对应房间(全员三助理;老板另加搞钱/产品/运营),不必手动添加工作区。
7
+ 设置里选身份后,左侧自己出现对应房间(全员三助理;工程师另加实验室;运营另加设计;老板另加搞钱/产品/运营),不必手动添加工作区。实验室:大模型写 YAML、调 MCP、给下载链接。
8
8
 
9
- ```bash
10
- # 第一次、以后升级都是这一条
11
- dsh plugin --profile web add @rezti/dsh-rez-suite@latest
12
- ```
9
+ 回形针走 npm 包 `@rezti/dsh-web-file-uploader@0.2.2`(不要 GitHub:DSH 会拦子依赖 git,0.1.46 因此装不上)。
13
10
 
14
- DSH profile 默认 `minimumReleaseAge: 1440`(新包要满 24 小时才让装)。当天发的 suite 会被当成「太新」而退回更旧的版(例如卡在 `0.1.19`)。发版当天先改:
11
+ 员工机不要 `SUITE_VERSION=latest`:新 profile 默认 `minimumReleaseAge: 1440`,当天发的包可能装不到。钉死 `0.1.47`,或把 profile `minimumReleaseAge` 改成 `0`。
15
12
 
16
13
  ```bash
17
- # ~/.dsh/profiles/web/pnpm-workspace.yaml
18
- minimumReleaseAge: 0
14
+ # 第一次 / 升级(钉死版本,避开 24h 发布冷却)
15
+ dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.47
19
16
  ```
20
17
 
21
- 然后再跑上面的 `add @latest`。不要用裸 `dsh plugin update`(不会拉 latest)。
18
+ 本版改了什么:见 [CHANGELOG.md](./CHANGELOG.md)。
22
19
 
23
20
  包名是 `@rezti/dsh-rez-suite`,不是 `dsh-rezti-suite`。不要对同一 profile 再单独 add 子包,会重复注册。
24
21
 
22
+ 说明书 / 规格书:输入栏回形针上传原 PDF(官方对话只收图)。不要用微信发 PDF。先入 TAPD **测试中** 转凯文终审,批准后再进 `Marketing/Publish`。
23
+
25
24
  拆分包(`dsh-rez-odoo` 等)给开发改代码用。Web 面板(含微信扫码)暂时仍在本包。
package/README.zh.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # dsh-rez-suite
2
2
 
3
- **用户只装这一包。** 升级只记:`dsh plugin --profile web add @rezti/dsh-rez-suite@latest`(不要用裸 `update`,那不会拉 npm 最新版)。拆分包给开发改代码;不要对同一 profile 再单独 add 子包。
3
+ **用户只装这一包。** 升级只记:`dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.47`(不要用裸 `update`;不要 latest;不要 0.1.46,那一版 GitHub 子依赖会被 DSH 拦住)。本版改了什么见 [CHANGELOG.md](./CHANGELOG.md)。拆分包给开发改代码;不要对同一 profile 再单独 add 子包。
4
+
5
+ 说明书 / 规格书用输入栏**回形针**上传原 PDF(官方对话只收图,不要拖文件;不要用微信发 PDF)。先入 `Marketing/Inbox` + TAPD 测试中,凯文跟 Harness 说审批了哪份后,再写入 `Marketing/Publish/…`。
6
+
7
+ 拍摄原片:运营岗在「设计」房间交图,官方 Comfy MCP **只修一次**,声明类型后入 Inbox;凯文在老板产品室审批通过后**同时**写入 RAW。品牌规范 / 公司 VI 同一套逻辑,走公司级 `Marketing/Inbox/Brand/` → 终审后 `Marketing/RAW/Brand/`,不要写进某个 SKU。不要直接写 RAW,不要在这次做图生场景/白底。
4
8
 
5
9
  DSH Web GUI 的「Rez Suite」插件包:在插件内部启动一个 MCP Host,支持 **stdio** 与 **streamable-http** 两种 MCP 连接;提供 Web 配置面板(连通性一键验证)、按角色动态筛选 MCP 工具的 Preset 加载器,以及 SQLite 本地 Token/审计账本。
6
10
 
@@ -104,9 +108,9 @@ dsh plugin --profile web add link:$(pwd)
104
108
 
105
109
  MCP 工具按 \`mcp__<server>__<rawName>\` 注册,Preset 加载器用通配符匹配 \`server + 工具名\`。规则位于 \`src/presets.ts\`,可按团队实际工具名调整;\`role: all\` 注册全部工具。
106
110
 
107
- - \`engineer\`:odoo 检索/读取、homeassistant 状态读取、tapd/gsc 查询、fs/sqlite 读取
111
+ - \`engineer\`:odoo 检索/读取、homeassistant 状态读取、tapd/gsc 查询、fs/sqlite 读取;侧栏另有实验室(对话生成 YAML → MCP 编译 → 下载链接)
108
112
  - \`sales\`:odoo CRM/销售、nextcloud 上传、wecom 发送
109
- - \`operations\`:odoo 报表/库存/采购、homeassistant 控制、tapd 增删改、gsc 查询、nextcloud 管理、wecom 群发
113
+ - \`operations\`:odoo 报表/库存/采购、homeassistant 控制、tapd 读+建评论/改状态(无 delete)、gsc 查询、nextcloud Inbox 读写/移动(无 delete/manage)、wecom 群发;侧栏另有设计工作房间
110
114
 
111
115
  ## Token / 审计
112
116
 
package/cordis.patch.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  # 用户只装这一包:`dsh plugin --profile web add @rezti/dsh-rez-suite`
2
- # 升级只记这一条:`dsh plugin --profile web add @rezti/dsh-rez-suite@latest`
2
+ # 升级只记这一条:`dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.47`
3
3
  # 不要再单独 add 子包,会重复注册。
4
4
  #
5
5
  # MCP rows are started by the domain plugins after rezSso resolves secrets.
@@ -24,5 +24,7 @@
24
24
  name: '@rezti/dsh-rez-tapd'
25
25
  - id: rez-gsc
26
26
  name: '@rezti/dsh-rez-gsc'
27
+ - id: dsh-web-file-uploader
28
+ name: '@rezti/dsh-web-file-uploader'
27
29
  - id: rez-suite
28
30
  name: '@rezti/dsh-rez-suite'
package/lib/client.d.ts CHANGED
@@ -7255,14 +7255,15 @@ declare const zh: {
7255
7255
  readonly 'entry.label': "Rez";
7256
7256
  readonly 'entry.tooltip': "Rez Suite 配置与审计面板";
7257
7257
  readonly 'settings.title': "ReZ-TI";
7258
- readonly 'settings.description': "公司 MCP(Odoo / Nextcloud / 企微 / HA / TAPD / GSC)与个人微信扫码通道。";
7258
+ readonly 'settings.description': "公司 MCP(Odoo / Nextcloud / HA / TAPD / GSC)。企业微信栏暂隐。个人微信在「微信」页签扫码。";
7259
7259
  readonly 'panel.title': "Rez Suite";
7260
7260
  readonly 'tab.config': "配置";
7261
7261
  readonly 'tab.weixin': "微信";
7262
7262
  readonly 'tab.status': "状态";
7263
7263
  readonly 'tab.audit': "用量";
7264
+ readonly 'tab.changelog': "更新日志";
7264
7265
  readonly 'config.role': "角色";
7265
- readonly 'config.roleHint': "选身份后左侧自动出现工作区。人事/财务/法务助理全员可见;搞钱/产品/运营仅「老板」。";
7266
+ readonly 'config.roleHint': "选身份后左侧自动出现工作区。人事/财务/法务助理全员可见;设计房间仅「运营」;实验室仅「工程师」;搞钱/产品/运营仅「老板」。";
7266
7267
  readonly 'role.all': "全部";
7267
7268
  readonly 'role.boss': "老板";
7268
7269
  readonly 'role.engineer': "工程师";
@@ -7306,6 +7307,9 @@ declare const zh: {
7306
7307
  readonly 'config.tianyancha': "天眼查(法务助理 · 仅老板)";
7307
7308
  readonly 'config.tianyancha.url': "天眼查 MCP URL";
7308
7309
  readonly 'config.tianyancha.token': "OpenAPI Token";
7310
+ readonly 'config.esphome': "ESPHome 实验室";
7311
+ readonly 'config.esphome.url': "MCP URL";
7312
+ readonly 'config.esphome.token': "实验室 Token";
7309
7313
  readonly 'config.fs': "本地文件 (fs-mcp-server)";
7310
7314
  readonly 'config.fs.root': "根目录";
7311
7315
  readonly 'config.sqlite': "SQLite (sqlite-mcp-server)";
@@ -7348,6 +7352,8 @@ declare const zh: {
7348
7352
  readonly 'audit.reset': "清空账本";
7349
7353
  readonly 'audit.resetConfirm': "确定清空全部用量记录吗?";
7350
7354
  readonly 'audit.empty': "暂无记录";
7355
+ readonly 'changelog.current': "当前 {version}";
7356
+ readonly 'changelog.upgrade': "升级:";
7351
7357
  readonly 'common.close': "关闭";
7352
7358
  readonly 'common.loading': "加载中…";
7353
7359
  readonly 'common.error': "出错:{error}";
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=".r9dlUa_wordmark {\n min-width: 0;\n color: inherit;\n align-items: center;\n gap: 8px;\n display: inline-flex;\n overflow: hidden;\n}\n\n.r9dlUa_mark {\n object-fit: contain;\n flex: none;\n width: 28px;\n height: 28px;\n display: block;\n}\n\n.r9dlUa_markOnly {\n object-fit: contain;\n width: 100%;\n max-width: 28px;\n height: 100%;\n max-height: 28px;\n display: block;\n}\n\n.r9dlUa_name {\n letter-spacing: .02em;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 15px;\n font-weight: 650;\n overflow: hidden;\n}\n\n.r9dlUa_badge {\n letter-spacing: .06em;\n opacity: .72;\n white-space: nowrap;\n border: 1px solid;\n border-radius: 4px;\n flex: none;\n padding: 2px 6px;\n font-size: 10px;\n font-weight: 700;\n line-height: 1.2;\n}\n.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);})();
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=".r9dlUa_wordmark {\n min-width: 0;\n color: inherit;\n align-items: center;\n gap: 8px;\n display: inline-flex;\n overflow: hidden;\n}\n\n.r9dlUa_mark {\n object-fit: contain;\n flex: none;\n width: 28px;\n height: 28px;\n display: block;\n}\n\n.r9dlUa_markOnly {\n object-fit: contain;\n width: 100%;\n max-width: 28px;\n height: 100%;\n max-height: 28px;\n display: block;\n}\n\n.r9dlUa_name {\n letter-spacing: .02em;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: 15px;\n font-weight: 650;\n overflow: hidden;\n}\n\n.r9dlUa_badge {\n letter-spacing: .06em;\n opacity: .72;\n white-space: nowrap;\n border: 1px solid;\n border-radius: 4px;\n flex: none;\n padding: 2px 6px;\n font-size: 10px;\n font-weight: 700;\n line-height: 1.2;\n}\n.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\n.LOjPTW_changelogDate {\n font-variant-numeric: tabular-nums;\n color: var(--dsw-alias-label-tertiary);\n margin-left: 8px;\n font-weight: 500;\n}\n\n.LOjPTW_changelogBlock {\n flex-direction: column;\n gap: 6px;\n display: flex;\n}\n\n.LOjPTW_changelogHeading {\n color: var(--dsw-alias-label-secondary);\n font-size: 12.5px;\n font-weight: 600;\n}\n\n.LOjPTW_changelogList {\n color: var(--dsw-alias-label-primary);\n flex-direction: column;\n gap: 6px;\n margin: 0;\n padding-left: 18px;\n font-size: 13px;\n line-height: 1.55;\n display: flex;\n}\n\n.LOjPTW_changelogList li + li {\n margin: 0;\n}\n\n.LOjPTW_changelogCode {\n background: var(--dsw-alias-bg-layer-3);\n border: 1px solid var(--dsw-alias-border-l2);\n word-break: break-all;\n border-radius: 6px;\n padding: 1px 6px;\n font-size: 12px;\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");
@@ -139,14 +139,15 @@ const zh = {
139
139
  "entry.label": "Rez",
140
140
  "entry.tooltip": "Rez Suite 配置与审计面板",
141
141
  "settings.title": "ReZ-TI",
142
- "settings.description": "公司 MCP(Odoo / Nextcloud / 企微 / HA / TAPD / GSC)与个人微信扫码通道。",
142
+ "settings.description": "公司 MCP(Odoo / Nextcloud / HA / TAPD / GSC)。企业微信栏暂隐。个人微信在「微信」页签扫码。",
143
143
  "panel.title": "Rez Suite",
144
144
  "tab.config": "配置",
145
145
  "tab.weixin": "微信",
146
146
  "tab.status": "状态",
147
147
  "tab.audit": "用量",
148
+ "tab.changelog": "更新日志",
148
149
  "config.role": "角色",
149
- "config.roleHint": "选身份后左侧自动出现工作区。人事/财务/法务助理全员可见;搞钱/产品/运营仅「老板」。",
150
+ "config.roleHint": "选身份后左侧自动出现工作区。人事/财务/法务助理全员可见;设计房间仅「运营」;实验室仅「工程师」;搞钱/产品/运营仅「老板」。",
150
151
  "role.all": "全部",
151
152
  "role.boss": "老板",
152
153
  "role.engineer": "工程师",
@@ -190,6 +191,9 @@ const zh = {
190
191
  "config.tianyancha": "天眼查(法务助理 · 仅老板)",
191
192
  "config.tianyancha.url": "天眼查 MCP URL",
192
193
  "config.tianyancha.token": "OpenAPI Token",
194
+ "config.esphome": "ESPHome 实验室",
195
+ "config.esphome.url": "MCP URL",
196
+ "config.esphome.token": "实验室 Token",
193
197
  "config.fs": "本地文件 (fs-mcp-server)",
194
198
  "config.fs.root": "根目录",
195
199
  "config.sqlite": "SQLite (sqlite-mcp-server)",
@@ -232,6 +236,8 @@ const zh = {
232
236
  "audit.reset": "清空账本",
233
237
  "audit.resetConfirm": "确定清空全部用量记录吗?",
234
238
  "audit.empty": "暂无记录",
239
+ "changelog.current": "当前 {version}",
240
+ "changelog.upgrade": "升级:",
235
241
  "common.close": "关闭",
236
242
  "common.loading": "加载中…",
237
243
  "common.error": "出错:{error}",
@@ -262,14 +268,15 @@ const en = {
262
268
  "entry.label": "Rez",
263
269
  "entry.tooltip": "Rez Suite configuration and audit panel",
264
270
  "settings.title": "ReZ-TI",
265
- "settings.description": "Company MCP (Odoo / Nextcloud / WeCom / HA / TAPD / GSC) and personal WeChat scan-and-chat.",
271
+ "settings.description": "Company MCP (Odoo / Nextcloud / HA / TAPD / GSC). WeCom settings are hidden for now. Personal WeChat is the WeChat tab.",
266
272
  "panel.title": "Rez Suite",
267
273
  "tab.config": "Config",
268
274
  "tab.weixin": "WeChat",
269
275
  "tab.status": "Status",
270
276
  "tab.audit": "Usage",
277
+ "tab.changelog": "Changelog",
271
278
  "config.role": "Role",
272
- "config.roleHint": "Identity registers workspaces in the sidebar. Staff assistants for every role; 搞钱 / 产品 / 运营 for Boss only.",
279
+ "config.roleHint": "Identity registers workspaces in the sidebar. Staff assistants for every role; 设计 for Operations only; 实验室 for Engineer only; 搞钱 / 产品 / 运营 for Boss only.",
273
280
  "role.all": "All",
274
281
  "role.boss": "Boss",
275
282
  "role.engineer": "Engineer",
@@ -313,6 +320,9 @@ const en = {
313
320
  "config.tianyancha": "Tianyancha (Legal assistant, boss only)",
314
321
  "config.tianyancha.url": "Tianyancha MCP URL",
315
322
  "config.tianyancha.token": "OpenAPI token",
323
+ "config.esphome": "ESPHome lab",
324
+ "config.esphome.url": "MCP URL",
325
+ "config.esphome.token": "Lab token",
316
326
  "config.fs": "Local files (fs-mcp-server)",
317
327
  "config.fs.root": "Root directory",
318
328
  "config.sqlite": "SQLite (sqlite-mcp-server)",
@@ -355,6 +365,8 @@ const en = {
355
365
  "audit.reset": "Clear ledger",
356
366
  "audit.resetConfirm": "Clear all usage records?",
357
367
  "audit.empty": "No records",
368
+ "changelog.current": "Now {version}",
369
+ "changelog.upgrade": "Upgrade:",
358
370
  "common.close": "Close",
359
371
  "common.loading": "Loading…",
360
372
  "common.error": "Error: {error}",
@@ -502,6 +514,11 @@ var panel_module_default = {
502
514
  "cardOpen": "LOjPTW_cardOpen",
503
515
  "cards": "LOjPTW_cards",
504
516
  "cardValue": "LOjPTW_cardValue",
517
+ "changelogBlock": "LOjPTW_changelogBlock",
518
+ "changelogCode": "LOjPTW_changelogCode",
519
+ "changelogDate": "LOjPTW_changelogDate",
520
+ "changelogHeading": "LOjPTW_changelogHeading",
521
+ "changelogList": "LOjPTW_changelogList",
505
522
  "checkbox": "LOjPTW_checkbox",
506
523
  "chevron": "LOjPTW_chevron",
507
524
  "chevronOpen": "LOjPTW_chevronOpen",
@@ -700,6 +717,144 @@ function AuditTab({ api }) {
700
717
  });
701
718
  }
702
719
  //#endregion
720
+ //#region src/changelog.ts
721
+ const SUITE_CHANGELOG = [{
722
+ version: "0.1.47",
723
+ date: "2026-08-19",
724
+ sections: [{
725
+ title: {
726
+ zh: "安装修复",
727
+ en: "Install fix"
728
+ },
729
+ items: [{
730
+ zh: "0.1.46 装不上:DSH 禁止插件子依赖走 GitHub。回形针已改成 npm 包 @rezti/dsh-web-file-uploader@0.2.2。请装 0.1.47,不要再装 0.1.46。",
731
+ en: "0.1.46 cannot install: DSH blocks GitHub git deps as plugin subdependencies. The paperclip plugin is now @rezti/dsh-web-file-uploader@0.2.2 on npm. Install 0.1.47, not 0.1.46."
732
+ }, {
733
+ zh: "设置 → 插件 → ReZ-TI → 更新日志:能看到本页说明。",
734
+ en: "Settings → Plugins → ReZ-TI → Changelog shows these notes."
735
+ }]
736
+ }]
737
+ }, {
738
+ version: "0.1.46",
739
+ date: "2026-08-19",
740
+ sections: [{
741
+ title: {
742
+ zh: "员工会碰到的",
743
+ en: "What you will see"
744
+ },
745
+ items: [
746
+ {
747
+ zh: "回形针上传 PDF:说明书 / 规格书走输入栏回形针,先入 Marketing/Inbox,对应 TAPD 改成测试中并转凯文;凯文说审批了哪份,再进 Marketing/Publish。不要用微信发 PDF。",
748
+ en: "Paperclip PDF uploads: manuals go to Marketing/Inbox first. TAPD moves to 测试中 and Kelvin; after he names the file, it lands in Marketing/Publish. Do not send PDFs over WeChat."
749
+ },
750
+ {
751
+ zh: "运营多了「设计」房间:拍摄原片 Comfy 只修一次,shot / clean 先入 Inbox;凯文终审后同时写入 Marketing/RAW。",
752
+ en: "Operations gets a Design room. Retouch shots once in Comfy; shot/clean stay in Inbox until Kelvin dual-saves them to Marketing/RAW."
753
+ },
754
+ {
755
+ zh: "品牌 / VI 走 Marketing/Inbox/Brand/,终审后写入 Marketing/RAW/Brand/,不要写进某个 SKU。",
756
+ en: "Brand / VI files go Marketing/Inbox/Brand/, then Marketing/RAW/Brand/ after approval — not into a SKU folder."
757
+ },
758
+ {
759
+ zh: "工程师多了「实验室」:对话里给 YAML,立刻拿到下载链接。还在编是说明文件;成功是 firmware.bin;失败是带日志的 README。不要在对话里等 bin,不要默认 OTA。",
760
+ en: "Engineers get a Lab room. Submit YAML and get a download link immediately. Compiling shows a README; success is firmware.bin; failure includes the log. Do not wait for the bin in chat. Do not OTA by default."
761
+ },
762
+ {
763
+ zh: "人事助理可引导新人领本机安装包、自己申请 API Key。",
764
+ en: "HR assistant can walk new staff through the desktop installer and API key request."
765
+ },
766
+ {
767
+ zh: "设置页暂时不显示企业微信配置栏(已填过的 webhook 不会被擦掉)。",
768
+ en: "WeCom settings are hidden for now. An existing webhook is left as-is."
769
+ },
770
+ {
771
+ zh: "运营仍可改 TAPD 状态、写评论、往 Inbox 传文件;不能删 TAPD / Nextcloud。",
772
+ en: "Operations can still update TAPD and write Inbox files, but cannot delete TAPD or Nextcloud items."
773
+ }
774
+ ]
775
+ }, {
776
+ title: {
777
+ zh: "安装与审批机",
778
+ en: "Installers and approver machines"
779
+ },
780
+ items: [
781
+ {
782
+ zh: "员工 Mac zip / Windows exe、审批人 Docker:每次启动拉钉死的 0.1.46,不要 latest。",
783
+ en: "Staff Mac zip / Windows exe and approver Docker pin suite 0.1.46. Do not use latest."
784
+ },
785
+ {
786
+ zh: "安装包只是启动壳,第一次会从外网拉 Node 和 dsh。",
787
+ en: "The zip/exe is a launcher. The first run downloads Node and dsh."
788
+ },
789
+ {
790
+ zh: "回形针依赖还在 GitHub。装 suite 要能访问 GitHub;公司机禁外网会失败。",
791
+ en: "The paperclip plugin still comes from GitHub. Installing suite needs GitHub access."
792
+ }
793
+ ]
794
+ }]
795
+ }];
796
+ function latestSuiteChangelog() {
797
+ const latest = SUITE_CHANGELOG[0];
798
+ if (latest === void 0) throw new Error("SUITE_CHANGELOG is empty");
799
+ return latest;
800
+ }
801
+ //#endregion
802
+ //#region src/client/panel/ChangelogTab.tsx
803
+ /**
804
+ * Settings tab: what this suite version changed. Copy lives in src/changelog.ts.
805
+ */
806
+ function ChangelogTab({ api }) {
807
+ const t = useT();
808
+ const lang = t("tab.config") === zh["tab.config"] ? "zh" : "en";
809
+ const latest = latestSuiteChangelog();
810
+ const [installed, setInstalled] = (0, react.useState)("");
811
+ (0, react.useEffect)(() => {
812
+ let cancelled = false;
813
+ api.updateStatus().then((status) => {
814
+ if (!cancelled) setInstalled(status.installed);
815
+ }).catch(() => {
816
+ if (!cancelled) setInstalled(latest.version);
817
+ });
818
+ return () => {
819
+ cancelled = true;
820
+ };
821
+ }, [api, latest.version]);
822
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
823
+ className: panel_module_default.tabBody,
824
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
825
+ className: panel_module_default.message,
826
+ children: [
827
+ t("changelog.current", { version: installed || latest.version }),
828
+ " · ",
829
+ t("changelog.upgrade"),
830
+ " ",
831
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("code", {
832
+ className: panel_module_default.changelogCode,
833
+ children: ["dsh plugin --profile web add @rezti/dsh-rez-suite@", latest.version]
834
+ })
835
+ ]
836
+ }), SUITE_CHANGELOG.map((release) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
837
+ className: panel_module_default.section,
838
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
839
+ className: panel_module_default.sectionTitle,
840
+ children: [release.version, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
841
+ className: panel_module_default.changelogDate,
842
+ children: release.date
843
+ })]
844
+ }), release.sections.map((section) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
845
+ className: panel_module_default.changelogBlock,
846
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
847
+ className: panel_module_default.changelogHeading,
848
+ children: section.title[lang]
849
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
850
+ className: panel_module_default.changelogList,
851
+ children: section.items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: item[lang] }, item[lang]))
852
+ })]
853
+ }, section.title[lang]))]
854
+ }, release.version))]
855
+ });
856
+ }
857
+ //#endregion
703
858
  //#region src/client/panel/ConfigTab.tsx
704
859
  /**
705
860
  * Config tab: company MCP connections (Odoo / Nextcloud / WeCom / HA / TAPD / GSC / QCC),
@@ -735,7 +890,8 @@ const EMPTY_SECRETS = {
735
890
  tapd: "",
736
891
  gsc: "",
737
892
  qcc: "",
738
- tianyancha: ""
893
+ tianyancha: "",
894
+ esphome: ""
739
895
  };
740
896
  function Field({ label, children }) {
741
897
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -909,6 +1065,10 @@ function ConfigTab({ api }) {
909
1065
  tianyancha: {
910
1066
  ...config.connections.tianyancha,
911
1067
  secret: secrets.tianyancha || void 0
1068
+ },
1069
+ esphome: {
1070
+ ...config.connections.esphome,
1071
+ secret: secrets.esphome || void 0
912
1072
  }
913
1073
  }
914
1074
  };
@@ -1028,21 +1188,6 @@ function ConfigTab({ api }) {
1028
1188
  usernameLabel: t("config.nextcloud.username"),
1029
1189
  secretLabel: t("config.nextcloud.appPassword")
1030
1190
  }),
1031
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpSection, {
1032
- title: t("config.wecom"),
1033
- row: config.connections.wechat,
1034
- secret: secrets.wechat,
1035
- onEnabled: (enabled) => {
1036
- patchConnection("wechat", { enabled });
1037
- },
1038
- onSecret: (value) => {
1039
- setSecrets((prev) => ({
1040
- ...prev,
1041
- wechat: value
1042
- }));
1043
- },
1044
- secretLabel: t("config.wecom.webhook")
1045
- }),
1046
1191
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpSection, {
1047
1192
  title: t("config.ha"),
1048
1193
  row: config.connections.homeassistant,
@@ -1159,6 +1304,25 @@ function ConfigTab({ api }) {
1159
1304
  urlLabel: t("config.tianyancha.url"),
1160
1305
  secretLabel: t("config.tianyancha.token")
1161
1306
  }),
1307
+ (config.role === "engineer" || config.role === "boss") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpSection, {
1308
+ title: t("config.esphome"),
1309
+ row: config.connections.esphome,
1310
+ secret: secrets.esphome,
1311
+ onEnabled: (enabled) => {
1312
+ patchConnection("esphome", { enabled });
1313
+ },
1314
+ onUrl: (url) => {
1315
+ patchConnection("esphome", { url });
1316
+ },
1317
+ onSecret: (value) => {
1318
+ setSecrets((prev) => ({
1319
+ ...prev,
1320
+ esphome: value
1321
+ }));
1322
+ },
1323
+ urlLabel: t("config.esphome.url"),
1324
+ secretLabel: t("config.esphome.token")
1325
+ }),
1162
1326
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
1163
1327
  title: t("config.billing"),
1164
1328
  children: [
@@ -1505,6 +1669,10 @@ function RezSettingsPage({ t }) {
1505
1669
  {
1506
1670
  id: "audit",
1507
1671
  label: t("tab.audit")
1672
+ },
1673
+ {
1674
+ id: "changelog",
1675
+ label: t("tab.changelog")
1508
1676
  }
1509
1677
  ];
1510
1678
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RezT.Provider, {
@@ -1530,7 +1698,8 @@ function RezSettingsPage({ t }) {
1530
1698
  activeTab === "config" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigTab, { api }),
1531
1699
  activeTab === "weixin" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WeixinTab, { api }),
1532
1700
  activeTab === "status" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatusTab, { api }),
1533
- activeTab === "audit" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AuditTab, { api })
1701
+ activeTab === "audit" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AuditTab, { api }),
1702
+ activeTab === "changelog" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChangelogTab, { api })
1534
1703
  ]
1535
1704
  })
1536
1705
  });
package/lib/index.d.ts CHANGED
@@ -1738,6 +1738,10 @@ interface RezConnections {
1738
1738
  enabled: boolean;
1739
1739
  url: string;
1740
1740
  };
1741
+ esphome: {
1742
+ enabled: boolean;
1743
+ url: string;
1744
+ };
1741
1745
  }
1742
1746
  /** Full plugin configuration persisted under ~/.dsh/dsh-rez-suite.json. */
1743
1747
  interface RezConfig {