@rezti/dsh-rez-suite 0.1.49 → 0.1.51

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 (142) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/README.md +3 -3
  3. package/README.zh.md +2 -2
  4. package/cordis.patch.yml +1 -1
  5. package/lib/client.d.ts +31 -3
  6. package/lib/client.js +343 -7
  7. package/lib/index.js +244 -15
  8. package/lib/style.css +7 -0
  9. package/package.json +12 -11
  10. package/src/boss/mount.ts +4 -3
  11. package/src/boss/register.ts +1 -1
  12. package/src/boss/seed.ts +34 -0
  13. package/src/changelog.ts +48 -0
  14. package/src/channel-board.ts +55 -0
  15. package/src/client/locales.ts +62 -6
  16. package/src/client/panel/BoardTab.tsx +136 -0
  17. package/src/client/panel/ConfigTab.tsx +2 -2
  18. package/src/client/panel/StatusTab.tsx +31 -0
  19. package/src/client/panel/panel.module.css +7 -0
  20. package/src/client/settings-card.tsx +4 -1
  21. package/src/index.ts +3 -2
  22. package/src/protocol.ts +14 -0
  23. package/src/routes.ts +7 -1
  24. package/src/tools.ts +49 -6
  25. package/src/wecom-cli.ts +125 -0
  26. package/templates/boss/ops/AGENTS.md +2 -0
  27. package/templates/shared/wecom-cli.SOURCE.md +9 -0
  28. package/templates/shared/wecom-office/SKILL.md +32 -0
  29. package/templates/shared/wecomcli-calendar/SKILL.md +303 -0
  30. package/templates/shared/wecomcli-calendar/references/calendar-agenda.md +224 -0
  31. package/templates/shared/wecomcli-calendar/references/calendar-cancel.md +108 -0
  32. package/templates/shared/wecomcli-calendar/references/calendar-create.md +238 -0
  33. package/templates/shared/wecomcli-calendar/references/calendar-freebusy.md +207 -0
  34. package/templates/shared/wecomcli-calendar/references/calendar-meeting-room.md +170 -0
  35. package/templates/shared/wecomcli-calendar/references/calendar-search.md +206 -0
  36. package/templates/shared/wecomcli-calendar/references/calendar-update.md +272 -0
  37. package/templates/shared/wecomcli-contact/SKILL.md +58 -0
  38. package/templates/shared/wecomcli-disk/SKILL.md +389 -0
  39. package/templates/shared/wecomcli-doc/SKILL.md +137 -0
  40. package/templates/shared/wecomcli-doc/references/doc-contents-append.md +20 -0
  41. package/templates/shared/wecomcli-doc/references/doc-contents-overwrite.md +27 -0
  42. package/templates/shared/wecomcli-doc/references/doc-create.md +161 -0
  43. package/templates/shared/wecomcli-doc/scripts/build_docx.py +1375 -0
  44. package/templates/shared/wecomcli-doc-manage/SKILL.md +132 -0
  45. package/templates/shared/wecomcli-doc-manage/references/doc-members-update.md +24 -0
  46. package/templates/shared/wecomcli-doc-manage/references/doc-names-update.md +20 -0
  47. package/templates/shared/wecomcli-doc-manage/references/doc-rules-update.md +22 -0
  48. package/templates/shared/wecomcli-email/SKILL.md +218 -0
  49. package/templates/shared/wecomcli-email/references/forward-mail.md +131 -0
  50. package/templates/shared/wecomcli-email/references/get-mail.md +166 -0
  51. package/templates/shared/wecomcli-email/references/reply-mail.md +138 -0
  52. package/templates/shared/wecomcli-email/references/search-mail.md +111 -0
  53. package/templates/shared/wecomcli-email/references/security.md +53 -0
  54. package/templates/shared/wecomcli-email/references/send-mail.md +186 -0
  55. package/templates/shared/wecomcli-email/references/send-schedule.md +83 -0
  56. package/templates/shared/wecomcli-media/SKILL.md +98 -0
  57. package/templates/shared/wecomcli-meeting/SKILL.md +373 -0
  58. package/templates/shared/wecomcli-meeting/references/meeting-cancel.md +113 -0
  59. package/templates/shared/wecomcli-meeting/references/meeting-create.md +167 -0
  60. package/templates/shared/wecomcli-meeting/references/meeting-list.md +226 -0
  61. package/templates/shared/wecomcli-meeting/references/meeting-original-get.md +98 -0
  62. package/templates/shared/wecomcli-meeting/references/meeting-search.md +173 -0
  63. package/templates/shared/wecomcli-meeting/references/meeting-update.md +217 -0
  64. package/templates/shared/wecomcli-message/SKILL.md +200 -0
  65. package/templates/shared/wecomcli-shared/SKILL.md +73 -0
  66. package/templates/shared/wecomcli-sheet/SKILL.md +172 -0
  67. package/templates/shared/wecomcli-sheet/references/sheet-contents-update.md +47 -0
  68. package/templates/shared/wecomcli-sheet/references/sheet-ranges-get.md +45 -0
  69. package/templates/shared/wecomcli-sheet/references/sheet-rows-append.md +45 -0
  70. package/templates/shared/wecomcli-sheet/references/sheet-subsheets-add.md +26 -0
  71. package/templates/shared/wecomcli-sheet/references/sheet-subsheets-delete.md +20 -0
  72. package/templates/shared/wecomcli-smartpage/SKILL.md +170 -0
  73. package/templates/shared/wecomcli-smartpage/references/data-driven-pages.md +50 -0
  74. package/templates/shared/wecomcli-smartpage/references/formula/arraylist.md +369 -0
  75. package/templates/shared/wecomcli-smartpage/references/formula/datetime.md +283 -0
  76. package/templates/shared/wecomcli-smartpage/references/formula/logic.md +247 -0
  77. package/templates/shared/wecomcli-smartpage/references/formula/math.md +362 -0
  78. package/templates/shared/wecomcli-smartpage/references/formula/operators.md +246 -0
  79. package/templates/shared/wecomcli-smartpage/references/formula/pageblock.md +76 -0
  80. package/templates/shared/wecomcli-smartpage/references/formula/templates.md +410 -0
  81. package/templates/shared/wecomcli-smartpage/references/formula/text.md +377 -0
  82. package/templates/shared/wecomcli-smartpage/references/formula/user.md +22 -0
  83. package/templates/shared/wecomcli-smartpage/references/formula-reference.md +192 -0
  84. package/templates/shared/wecomcli-smartpage/references/mdx-syntax.md +739 -0
  85. package/templates/shared/wecomcli-smartpage/references/smartpage-edit.md +506 -0
  86. package/templates/shared/wecomcli-smartsheet/SKILL.md +154 -0
  87. package/templates/shared/wecomcli-smartsheet/assets/templates/README.md +53 -0
  88. package/templates/shared/wecomcli-smartsheet/assets/templates/ai_efficiency.md +709 -0
  89. package/templates/shared/wecomcli-smartsheet/assets/templates/connect_to_app.md +380 -0
  90. package/templates/shared/wecomcli-smartsheet/assets/templates/financial_accounting.md +369 -0
  91. package/templates/shared/wecomcli-smartsheet/assets/templates/hr_and_administration.md +475 -0
  92. package/templates/shared/wecomcli-smartsheet/assets/templates/ledger_records.md +156 -0
  93. package/templates/shared/wecomcli-smartsheet/assets/templates/manufacturing.md +395 -0
  94. package/templates/shared/wecomcli-smartsheet/assets/templates/marketing.md +186 -0
  95. package/templates/shared/wecomcli-smartsheet/assets/templates/office_essentials.md +299 -0
  96. package/templates/shared/wecomcli-smartsheet/assets/templates/personal_efficiency.md +70 -0
  97. package/templates/shared/wecomcli-smartsheet/assets/templates/procurement_logistics.md +325 -0
  98. package/templates/shared/wecomcli-smartsheet/assets/templates/project_management.md +564 -0
  99. package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_customer.md +222 -0
  100. package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_ops.md +105 -0
  101. package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_project.md +109 -0
  102. package/templates/shared/wecomcli-smartsheet/assets/templates/rd_process_research.md +92 -0
  103. package/templates/shared/wecomcli-smartsheet/assets/templates/sales_and_operations.md +446 -0
  104. package/templates/shared/wecomcli-smartsheet/assets/templates/store_management.md +431 -0
  105. package/templates/shared/wecomcli-smartsheet/assets/templates/team_tasks.md +274 -0
  106. package/templates/shared/wecomcli-smartsheet/assets/templates/wechat_customer.md +384 -0
  107. package/templates/shared/wecomcli-smartsheet/assets/templates/work_report.md +100 -0
  108. package/templates/shared/wecomcli-smartsheet/references/common.md +143 -0
  109. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-chart-types.md +95 -0
  110. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-edit.md +589 -0
  111. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-field-types.md +438 -0
  112. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-formula.md +845 -0
  113. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-read.md +391 -0
  114. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-record-values.md +201 -0
  115. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-view-types.md +356 -0
  116. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-webhook-examples.md +176 -0
  117. package/templates/shared/wecomcli-smartsheet/references/smart-sheet-webhook.md +169 -0
  118. package/templates/shared/wecomcli-todo/SKILL.md +76 -0
  119. package/templates/shared/wecomcli-todo/references/todo-create.md +137 -0
  120. package/templates/shared/wecomcli-todo/references/todo-delete.md +63 -0
  121. package/templates/shared/wecomcli-todo/references/todo-finish.md +72 -0
  122. package/templates/shared/wecomcli-todo/references/todo-get.md +66 -0
  123. package/templates/shared/wecomcli-todo/references/todo-list.md +133 -0
  124. package/templates/shared/wecomcli-todo/references/todo-update.md +112 -0
  125. package/templates/staff/design/AGENTS.md +2 -1
  126. package/templates/staff/ecommerce/.agents/skills/ops-ecommerce/SKILL.md +6 -0
  127. package/templates/staff/ecommerce/AGENTS.md +49 -0
  128. package/templates/staff/ecommerce/BOOTSTRAP.md +23 -0
  129. package/templates/staff/ecommerce/IDENTITY.md +8 -0
  130. package/templates/staff/ecommerce/MEMORY.md +9 -0
  131. package/templates/staff/ecommerce/PRIORITIES.md +3 -0
  132. package/templates/staff/ecommerce/SOUL.md +5 -0
  133. package/templates/staff/ecommerce/USER.md +8 -0
  134. package/templates/staff/hr/.agents/skills/staff-onboard-keys/SKILL.md +3 -3
  135. package/templates/staff/publish/.agents/skills/ops-publish/SKILL.md +6 -0
  136. package/templates/staff/publish/AGENTS.md +59 -0
  137. package/templates/staff/publish/BOOTSTRAP.md +23 -0
  138. package/templates/staff/publish/IDENTITY.md +8 -0
  139. package/templates/staff/publish/MEMORY.md +9 -0
  140. package/templates/staff/publish/PRIORITIES.md +3 -0
  141. package/templates/staff/publish/SOUL.md +6 -0
  142. package/templates/staff/publish/USER.md +8 -0
package/lib/index.js CHANGED
@@ -3,9 +3,9 @@ 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, loadRezConnections, mergeConnections, readManagedCredential, secretConfigured, startMcpWhenSecret, writeManagedCredential } from "@rezti/dsh-rez-sso";
5
5
  import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
6
+ import { spawn, spawnSync } from "node:child_process";
6
7
  import { DatabaseSync } from "node:sqlite";
7
8
  import { fileURLToPath } from "node:url";
8
- import { spawn } from "node:child_process";
9
9
  //#region ../../node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/index.js
10
10
  /** Return true when a value is `null` or `undefined`. */
11
11
  function isNullable(value) {
@@ -3230,6 +3230,145 @@ function saveConfig(config) {
3230
3230
  renameSync(tmp, path);
3231
3231
  }
3232
3232
  //#endregion
3233
+ //#region src/wecom-cli.ts
3234
+ /**
3235
+ * Official WeCom office APIs are @wecom/cli, not mcp__wechat__*.
3236
+ * TAPD bug 1154488930001000054: missing MCP row was treated as “no WeCom”.
3237
+ * Official CLI v1.1+ opened 通讯录 / 在线文档 etc. for every company size
3238
+ * (https://github.com/WecomTeam/wecom-cli). Kelvin enabled those modules.
3239
+ */
3240
+ /** Official @wecom/cli >=1.1 catalog. Do not invent extra HTTP APIs. */
3241
+ const WECOM_CLI_CATALOG = [
3242
+ {
3243
+ id: "contact",
3244
+ label: "通讯录"
3245
+ },
3246
+ {
3247
+ id: "doc",
3248
+ label: "在线文档"
3249
+ },
3250
+ {
3251
+ id: "doc-manage",
3252
+ label: "文档管理"
3253
+ },
3254
+ {
3255
+ id: "sheet",
3256
+ label: "在线表格"
3257
+ },
3258
+ {
3259
+ id: "smartsheet",
3260
+ label: "智能表格"
3261
+ },
3262
+ {
3263
+ id: "smartpage",
3264
+ label: "智能文档"
3265
+ },
3266
+ {
3267
+ id: "todo",
3268
+ label: "待办"
3269
+ },
3270
+ {
3271
+ id: "calendar",
3272
+ label: "日程"
3273
+ },
3274
+ {
3275
+ id: "meeting",
3276
+ label: "会议"
3277
+ },
3278
+ {
3279
+ id: "mail",
3280
+ label: "邮件"
3281
+ },
3282
+ {
3283
+ id: "disk",
3284
+ label: "微盘"
3285
+ },
3286
+ {
3287
+ id: "message",
3288
+ label: "消息"
3289
+ },
3290
+ {
3291
+ id: "media",
3292
+ label: "媒体文件"
3293
+ }
3294
+ ];
3295
+ const MODULE_LABELS = WECOM_CLI_CATALOG.map((row) => row.label).join("/");
3296
+ const HINT_MISSING = [
3297
+ `未安装官方 wecom-cli(@wecom/cli >=1.1)。企微办公能力(${MODULE_LABELS})走 CLI,不是 MCP。`,
3298
+ "安装:npm i -g @wecom/cli ,然后 wecom-cli auth init。",
3299
+ "官方已面向各规模企业开放通讯录等能力,不要再说「超过 10 人只能用文档」。",
3300
+ "不要因为 rez_status 没有 wechat MCP 行就说没有企微能力。"
3301
+ ].join("");
3302
+ const HINT_UNAUTH = [
3303
+ "已安装 wecom-cli,尚未授权。跑 wecom-cli auth init。",
3304
+ `授权后可用:${MODULE_LABELS}。本企业已开通这些品类。`,
3305
+ "CLI 报某模块未授权才说该能力未开通;不要说「没有企微 MCP」,也不要说 10 人限制。"
3306
+ ].join("");
3307
+ const HINT_OK = [
3308
+ `企微办公能力走 wecom-cli >=1.1(${MODULE_LABELS})。本企业已开通。`,
3309
+ "按房间里官方 wecomcli-* 技能执行,命令以 wecom-cli <模块> --help 为准。",
3310
+ "不要用旧帮助中心「超过 10 人只能用文档」的说法。CLI 报未授权才说该模块未开通。",
3311
+ "设置页 BotID+Secret 只是房间消息通道。不要把没有 mcp__wechat__* 当成没有企微能力。"
3312
+ ].join("");
3313
+ function wecomCliCatalog() {
3314
+ return WECOM_CLI_CATALOG.map((row) => ({ ...row }));
3315
+ }
3316
+ function defaultWecomCliRunner(argv) {
3317
+ const result = spawnSync("wecom-cli", argv, {
3318
+ encoding: "utf8",
3319
+ timeout: 4e3,
3320
+ env: process.env
3321
+ });
3322
+ const error = result.error;
3323
+ return {
3324
+ status: result.status,
3325
+ stdout: typeof result.stdout === "string" ? result.stdout : "",
3326
+ stderr: typeof result.stderr === "string" ? result.stderr : "",
3327
+ errorCode: error?.code
3328
+ };
3329
+ }
3330
+ function looksUnauthorized(text, status) {
3331
+ if (status !== 0) return true;
3332
+ return /未授权|未登录|未初始化|not (logged|auth)|unauthorized|请先.*auth|auth init/i.test(text);
3333
+ }
3334
+ function withCatalog(partial) {
3335
+ return {
3336
+ ...partial,
3337
+ modules: wecomCliCatalog()
3338
+ };
3339
+ }
3340
+ function probeWecomCli(run = defaultWecomCliRunner) {
3341
+ const help = run(["--help"]);
3342
+ if (help.errorCode === "ENOENT") return withCatalog({
3343
+ installed: false,
3344
+ authorized: false,
3345
+ hint: HINT_MISSING
3346
+ });
3347
+ const helpText = help.stdout + help.stderr;
3348
+ if (help.status !== 0 && helpText.trim().length === 0) return withCatalog({
3349
+ installed: false,
3350
+ authorized: false,
3351
+ hint: HINT_MISSING
3352
+ });
3353
+ const auth = run(["auth", "show"]);
3354
+ const text = auth.stdout + auth.stderr;
3355
+ if (auth.errorCode === "ENOENT") return withCatalog({
3356
+ installed: false,
3357
+ authorized: false,
3358
+ hint: HINT_MISSING
3359
+ });
3360
+ if (looksUnauthorized(text, auth.status)) return withCatalog({
3361
+ installed: true,
3362
+ authorized: false,
3363
+ hint: HINT_UNAUTH
3364
+ });
3365
+ return withCatalog({
3366
+ installed: true,
3367
+ authorized: true,
3368
+ hint: HINT_OK
3369
+ });
3370
+ }
3371
+ //#endregion
3233
3372
  //#region src/routes.ts
3234
3373
  const MAX_JSON_BODY_BYTES = 256 * 1024;
3235
3374
  const SECRET_MASK = "********";
@@ -3396,7 +3535,8 @@ function makeRoutes(deps) {
3396
3535
  writeJson(res, 200, {
3397
3536
  role: getConfig().role,
3398
3537
  servers,
3399
- totalRegisteredTools
3538
+ totalRegisteredTools,
3539
+ wecomCli: probeWecomCli()
3400
3540
  });
3401
3541
  }
3402
3542
  },
@@ -7854,10 +7994,24 @@ function text(value) {
7854
7994
  text: value
7855
7995
  }];
7856
7996
  }
7857
- function rezStatusTool(host, config) {
7997
+ function renderWecomCli(cli) {
7998
+ const row = cli ?? {
7999
+ installed: false,
8000
+ authorized: false,
8001
+ modules: [],
8002
+ hint: ""
8003
+ };
8004
+ const modules = (row.modules ?? []).map((item) => `${item.label}(${item.id})`).join("、");
8005
+ return [
8006
+ "wecom-cli(企微办公能力,不是 MCP): installed=" + (row.installed ? "yes" : "no") + " authorized=" + (row.authorized ? "yes" : "no"),
8007
+ modules.length > 0 ? "modules: " + modules : "modules: (官方目录见 wecomcli-* 技能)",
8008
+ row.hint
8009
+ ].join("\n");
8010
+ }
8011
+ function rezStatusTool(host, config, wecomCli = probeWecomCli) {
7858
8012
  return defineTool({
7859
8013
  name: "rez_status",
7860
- description: "List the dsh-rez-suite MCP server statuses and how many tools each server registered for the current role. Triggers: rez, MCP, 连接状态.",
8014
+ description: "List MCP server statuses plus WeCom office APIs (official wecom-cli, not mcp__wechat__). Triggers: rez, MCP, 连接状态, 企业微信, 企微能力.",
7861
8015
  parameters: {},
7862
8016
  output: {
7863
8017
  schema: {
@@ -7898,6 +8052,43 @@ function rezStatusTool(host, config) {
7898
8052
  startedAt: { type: "integer" }
7899
8053
  }
7900
8054
  }
8055
+ },
8056
+ wecomCli: {
8057
+ type: "object",
8058
+ required: true,
8059
+ additionalProperties: false,
8060
+ properties: {
8061
+ installed: {
8062
+ type: "boolean",
8063
+ required: true
8064
+ },
8065
+ authorized: {
8066
+ type: "boolean",
8067
+ required: true
8068
+ },
8069
+ hint: {
8070
+ type: "string",
8071
+ required: true
8072
+ },
8073
+ modules: {
8074
+ type: "array",
8075
+ required: true,
8076
+ items: {
8077
+ type: "object",
8078
+ additionalProperties: false,
8079
+ properties: {
8080
+ id: {
8081
+ type: "string",
8082
+ required: true
8083
+ },
8084
+ label: {
8085
+ type: "string",
8086
+ required: true
8087
+ }
8088
+ }
8089
+ }
8090
+ }
8091
+ }
7901
8092
  }
7902
8093
  },
7903
8094
  additionalProperties: false
@@ -7914,7 +8105,7 @@ function rezStatusTool(host, config) {
7914
8105
  "server | state | discovered | registered | error",
7915
8106
  "--- | --- | --- | --- | ---",
7916
8107
  ...rows
7917
- ].join("\n"));
8108
+ ].join("\n") + "\n\n" + renderWecomCli(value.wecomCli));
7918
8109
  }
7919
8110
  },
7920
8111
  async execute(_args, exec) {
@@ -7926,7 +8117,8 @@ function rezStatusTool(host, config) {
7926
8117
  });
7927
8118
  return {
7928
8119
  role: config().role,
7929
- servers
8120
+ servers,
8121
+ wecomCli: wecomCli()
7930
8122
  };
7931
8123
  }
7932
8124
  });
@@ -8009,7 +8201,7 @@ function rezEsphomeCompileTool() {
8009
8201
  * `workspaceRegistry.create` is idempotent: same canonical path returns the
8010
8202
  * existing record. New records are prepended, so we register in reverse then
8011
8203
  * `insertBefore` to pin 搞钱 → 产品 → 运营 → 人事助理 → 财务助理 → 法务助理
8012
- * (运营身份:设计 → 人事助理 → 财务助理 → 法务助理;
8204
+ * (运营身份:设计 → 发布 → 电商 → 人事助理 → 财务助理 → 法务助理;
8013
8205
  * 工程师身份:实验室 → 人事助理 → 财务助理 → 法务助理)
8014
8206
  * (微信 stays after that block). `delete` only drops the registry row —
8015
8207
  * directories and session logs stay.
@@ -8087,10 +8279,20 @@ const STAFF_ROOMS = [
8087
8279
  }
8088
8280
  ];
8089
8281
  /** 运营身份专用。不是全员助理,也不是老板「运营」简报室。 */
8090
- const OPS_ROOMS = [{
8091
- id: "design",
8092
- folder: "设计"
8093
- }];
8282
+ const OPS_ROOMS = [
8283
+ {
8284
+ id: "design",
8285
+ folder: "设计"
8286
+ },
8287
+ {
8288
+ id: "publish",
8289
+ folder: "发布"
8290
+ },
8291
+ {
8292
+ id: "ecommerce",
8293
+ folder: "电商"
8294
+ }
8295
+ ];
8094
8296
  /** 工程师身份专用。ESPHome YAML → 实验室服务器编译 firmware.bin。 */
8095
8297
  const ENGINEER_ROOMS = [{
8096
8298
  id: "lab",
@@ -8168,6 +8370,7 @@ function seedRoom(templatesRoot, destRoot, room) {
8168
8370
  writeFileSync(target, readFileSync(abs));
8169
8371
  written.push(rel);
8170
8372
  }
8373
+ seedSharedSkills(dest, written);
8171
8374
  return {
8172
8375
  id: room.id,
8173
8376
  folder: room.folder,
@@ -8178,6 +8381,27 @@ function seedRoom(templatesRoot, destRoot, room) {
8178
8381
  skipped
8179
8382
  };
8180
8383
  }
8384
+ function defaultSharedTemplatesRoot() {
8385
+ const here = fileURLToPath(new URL(".", import.meta.url));
8386
+ const candidates = [join(here, "../templates/shared"), join(here, "../../templates/shared")];
8387
+ for (const dir of candidates) if (existsSync(join(dir, "wecom-office", "SKILL.md"))) return dir;
8388
+ throw new Error("missing shared workspace templates (expected templates/shared/wecom-office/SKILL.md)");
8389
+ }
8390
+ function seedSharedSkills(dest, written) {
8391
+ const root = defaultSharedTemplatesRoot();
8392
+ for (const name of readdirSync(root).sort()) {
8393
+ const skillDir = join(root, name);
8394
+ if (!statSync(skillDir).isDirectory()) continue;
8395
+ if (!existsSync(join(skillDir, "SKILL.md"))) continue;
8396
+ for (const abs of listFiles(skillDir)) {
8397
+ const rel = join(".agents", "skills", name, relative(skillDir, abs));
8398
+ const target = join(dest, rel);
8399
+ mkdirSync(dirname(target), { recursive: true });
8400
+ writeFileSync(target, readFileSync(abs));
8401
+ written.push(rel);
8402
+ }
8403
+ }
8404
+ }
8181
8405
  function listFiles(root) {
8182
8406
  const out = [];
8183
8407
  const walk = (dir) => {
@@ -8208,9 +8432,13 @@ const BOSS_GUIDANCE = [
8208
8432
  "微信文件夹仍是收件箱,不要在那边查账、报销或砍 SKU。",
8209
8433
  "用户用中文就中文、用英文就英文;不要因为工作区文件是中文就强制中文。"
8210
8434
  ].join("");
8211
- const BOSS_ROLE_HINT = "搞钱 / 产品 / 运营仅角色选「老板」时出现。人事 / 财务 / 法务助理所有角色都会登记。设计工作房间仅「运营」身份出现。实验室仅「工程师」身份出现。";
8435
+ const BOSS_ROLE_HINT = "搞钱 / 产品 / 运营仅角色选「老板」时出现。人事 / 财务 / 法务助理所有角色都会登记。设计 / 发布 / 电商工作房间仅「运营」身份出现。实验室仅「工程师」身份出现。";
8212
8436
  const ENGINEER_LAB_GUIDANCE = ["当前身份是工程师。侧栏第一间是实验室:对方说板型/功能就自己写 ESPHome YAML,或用回形针/粘贴。调 mcp__esphome__compile(或 rez_esphome_compile)。", "立刻把下载链接发给对方。编译要时间:先点开可能是 README.md,编完刷新就是 firmware.bin;失败也是 README(含日志)。不要把 bin 贴进对话。未开通就说未开通。不要自写编译器,不要自写 Device Builder WebSocket,不要默认 OTA 刷机。"].join("");
8213
- const OPS_DESIGN_GUIDANCE = ["当前身份是运营。侧栏第一间是设计工作房间:产品拍摄图、品牌规范、公司 VI 都在这里交。拍原片或 VI 图用官方 Comfy MCP 只修一次;规范 PDF / 源文件用回形针、不修。员工声明类型、Inbox 待审并转凯文。终审只在老板产品室。", "不要代批、不要直接写 RAW、不要写 Publish、不要做图生场景或白底。搞钱 / 产品 / 运营仅老板身份出现。"].join("");
8437
+ const OPS_DESIGN_GUIDANCE = [
8438
+ "当前身份是运营。侧栏先是设计工作房间:产品拍摄图、品牌规范、公司 VI 都在这里交。拍原片或 VI 图用官方 Comfy MCP 只修一次;规范 PDF / 源文件用回形针、不修。员工声明类型、Inbox 待审并转凯文。终审只在老板产品室。",
8439
+ "接着是发布工作间(媒体连接):内容/社媒 PCP 与 MediaJob,preview 后确认才 submit。不要另建图库,不要做日历 UI;排期写企微一个共享发布日历。",
8440
+ "再接着是电商工作间(ec operation):一期只做阿里巴巴国际站 ListingJob。Amazon 现在没有号,看板标后续,有号再开。设置页「看板」看两室连接与 Odoo/企微权限。不要代批、不要直接写 RAW、不要做图生场景或白底。搞钱 / 产品 / 运营仅老板身份出现。"
8441
+ ].join("");
8214
8442
  function workspaceGuidanceFor(role) {
8215
8443
  if (role === "boss") return BOSS_GUIDANCE;
8216
8444
  if (role === "operations") return STAFF_GUIDANCE + OPS_DESIGN_GUIDANCE;
@@ -8645,8 +8873,9 @@ const Config = Schema.object({
8645
8873
  });
8646
8874
  const SECTION_ORDER = 150;
8647
8875
  const REZ_GUIDANCE_CORE = [
8648
- "本机已安装 ReZ-TI 拆分包:工作身份由 dsh-rez-sso 提供,MCP 由官方 dsh-mcp-client 接入 Odoo / Nextcloud / 企业微信 / Home Assistant / TAPD / GSC。",
8649
- "工具名 mcp__odoo__*、mcp__nextcloud__*、mcp__wechat__*、mcp__homeassistant__*、mcp__tapd__*、mcp__gsc__*。",
8876
+ "本机已安装 ReZ-TI 拆分包:工作身份由 dsh-rez-sso 提供,MCP 由官方 dsh-mcp-client 接入 Odoo / Nextcloud / Home Assistant / TAPD / GSC。",
8877
+ "工具名 mcp__odoo__*、mcp__nextcloud__*、mcp__homeassistant__*、mcp__tapd__*、mcp__gsc__*。",
8878
+ "企业微信办公能力不是 MCP:走官方 wecom-cli >=1.1(通讯录/在线文档/在线表格/智能表格/智能文档/待办/日程/会议/邮件/微盘/消息)。本企业已开通这些品类。看 rez_status 的 wecomCli.modules,按房间 wecomcli-* 技能执行。不要因为没有 mcp__wechat__* 就说没有企微能力,也不要说「超过 10 人只能用文档」。CLI 报某模块未授权才说该能力未开通。设置页 BotID+Secret 只是房间消息通道。旧群 webhook 兼容才会出现 mcp__wechat__*。",
8650
8879
  "密钥:REZ_ODOO_TOKEN、REZ_NEXTCLOUD_PASSWORD、REZ_WECHAT_WEBHOOK、REZ_HA_TOKEN、REZ_TAPD_TOKEN、REZ_GSC_KEY。",
8651
8880
  "个人微信(QClaw/ClawBot):打开 设置 → 插件 → ReZ-TI → 微信 扫码,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认。网页归档了再从微信说话会自动恢复到侧栏。发「重启对话」会新开一条可见会话并把旧会话归档。网页端必须开着。不必再跑命令、也不要调用微信 MCP 工具。",
8652
8881
  "意图用 rez_set_intent(erp/files/chat/home/auto)。审计用 rez_audit。",
package/lib/style.css CHANGED
@@ -306,6 +306,13 @@
306
306
  padding: 8px 10px;
307
307
  }
308
308
 
309
+ .LOjPTW_boardTitle {
310
+ color: var(--dsw-alias-label-primary);
311
+ margin: 16px 0 4px;
312
+ font-size: 13px;
313
+ font-weight: 600;
314
+ }
315
+
309
316
  .LOjPTW_badge {
310
317
  border-radius: 999px;
311
318
  padding: 2px 8px;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rezti/dsh-rez-suite",
3
- "description": "ReZ-TI one-package install for DeepSeek Harness. Update with: dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.49",
4
- "version": "0.1.49",
3
+ "description": "ReZ-TI one-package install for DeepSeek Harness. Update with: dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.51",
4
+ "version": "0.1.51",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": "^22.19.0 || >=24.0.0"
@@ -40,12 +40,12 @@
40
40
  "@rezti/dsh-rez-gsc": "^0.1.1",
41
41
  "@rezti/dsh-rez-ha-bridge": "^0.1.9",
42
42
  "@rezti/dsh-rez-intent": "^0.1.5",
43
- "@rezti/dsh-rez-nextcloud": "^0.1.11",
43
+ "@rezti/dsh-rez-nextcloud": "workspace:^0.1.11",
44
44
  "@rezti/dsh-rez-odoo": "^0.1.9",
45
- "@rezti/dsh-rez-sso": "^0.1.14",
45
+ "@rezti/dsh-rez-sso": "workspace:^0.1.14",
46
46
  "@rezti/dsh-rez-tapd": "^0.1.1",
47
47
  "@rezti/dsh-rez-token-manager": "^0.1.4",
48
- "@rezti/dsh-rez-wechat": "^0.1.15",
48
+ "@rezti/dsh-rez-wechat": "workspace:^0.1.16",
49
49
  "@rezti/dsh-web-file-uploader": "0.2.3",
50
50
  "@modelcontextprotocol/sdk": "^1.30.0",
51
51
  "zod": "^4.4.3"
@@ -88,6 +88,7 @@
88
88
  "servers",
89
89
  "templates/boss/**/*",
90
90
  "templates/staff/**/*",
91
+ "templates/shared/**/*",
91
92
  "cordis.patch.yml",
92
93
  "README.md",
93
94
  "README.zh.md",
@@ -97,16 +98,16 @@
97
98
  "publishConfig": {
98
99
  "access": "public"
99
100
  },
100
- "repository": {
101
- "type": "git",
102
- "url": "git+https://github.com/ReZ-TI/deepseek-harness.git",
103
- "directory": "packages/dsh-rez-suite"
104
- },
105
101
  "scripts": {
106
102
  "build": "tsc -p tsconfig.build.json && tsdown --config-loader native && node scripts/wrap-client.mjs",
107
103
  "bundle": "tsdown --config-loader native",
108
104
  "watch": "tsdown --config-loader native --watch",
109
105
  "typecheck": "tsc --noEmit",
110
106
  "test": "vitest run"
107
+ },
108
+ "repository": {
109
+ "type": "git",
110
+ "url": "git+https://github.com/ReZ-TI/deepseek-harness.git",
111
+ "directory": "packages/dsh-rez-suite"
111
112
  }
112
- }
113
+ }
package/src/boss/mount.ts CHANGED
@@ -28,7 +28,7 @@ export const BOSS_GUIDANCE = [
28
28
  '用户用中文就中文、用英文就英文;不要因为工作区文件是中文就强制中文。',
29
29
  ].join('')
30
30
 
31
- export const BOSS_ROLE_HINT = '搞钱 / 产品 / 运营仅角色选「老板」时出现。人事 / 财务 / 法务助理所有角色都会登记。设计工作房间仅「运营」身份出现。实验室仅「工程师」身份出现。'
31
+ export const BOSS_ROLE_HINT = '搞钱 / 产品 / 运营仅角色选「老板」时出现。人事 / 财务 / 法务助理所有角色都会登记。设计 / 发布 / 电商工作房间仅「运营」身份出现。实验室仅「工程师」身份出现。'
32
32
 
33
33
  export const ENGINEER_LAB_GUIDANCE = [
34
34
  '当前身份是工程师。侧栏第一间是实验室:对方说板型/功能就自己写 ESPHome YAML,或用回形针/粘贴。调 mcp__esphome__compile(或 rez_esphome_compile)。',
@@ -36,8 +36,9 @@ export const ENGINEER_LAB_GUIDANCE = [
36
36
  ].join('')
37
37
 
38
38
  export const OPS_DESIGN_GUIDANCE = [
39
- '当前身份是运营。侧栏第一间是设计工作房间:产品拍摄图、品牌规范、公司 VI 都在这里交。拍原片或 VI 图用官方 Comfy MCP 只修一次;规范 PDF / 源文件用回形针、不修。员工声明类型、Inbox 待审并转凯文。终审只在老板产品室。',
40
- '不要代批、不要直接写 RAW、不要写 Publish、不要做图生场景或白底。搞钱 / 产品 / 运营仅老板身份出现。',
39
+ '当前身份是运营。侧栏先是设计工作房间:产品拍摄图、品牌规范、公司 VI 都在这里交。拍原片或 VI 图用官方 Comfy MCP 只修一次;规范 PDF / 源文件用回形针、不修。员工声明类型、Inbox 待审并转凯文。终审只在老板产品室。',
40
+ '接着是发布工作间(媒体连接):内容/社媒 PCP MediaJob,preview 后确认才 submit。不要另建图库,不要做日历 UI;排期写企微一个共享发布日历。',
41
+ '再接着是电商工作间(ec operation):一期只做阿里巴巴国际站 ListingJob。Amazon 现在没有号,看板标后续,有号再开。设置页「看板」看两室连接与 Odoo/企微权限。不要代批、不要直接写 RAW、不要做图生场景或白底。搞钱 / 产品 / 运营仅老板身份出现。',
41
42
  ].join('')
42
43
 
43
44
  export function workspaceGuidanceFor(role: RezRoleId): string {
@@ -3,7 +3,7 @@
3
3
  * `workspaceRegistry.create` is idempotent: same canonical path returns the
4
4
  * existing record. New records are prepended, so we register in reverse then
5
5
  * `insertBefore` to pin 搞钱 → 产品 → 运营 → 人事助理 → 财务助理 → 法务助理
6
- * (运营身份:设计 → 人事助理 → 财务助理 → 法务助理;
6
+ * (运营身份:设计 → 发布 → 电商 → 人事助理 → 财务助理 → 法务助理;
7
7
  * 工程师身份:实验室 → 人事助理 → 财务助理 → 法务助理)
8
8
  * (微信 stays after that block). `delete` only drops the registry row —
9
9
  * directories and session logs stay.
package/src/boss/seed.ts CHANGED
@@ -17,6 +17,8 @@ export const STAFF_ROOMS = [
17
17
  /** 运营身份专用。不是全员助理,也不是老板「运营」简报室。 */
18
18
  export const OPS_ROOMS = [
19
19
  { id: 'design', folder: '设计' },
20
+ { id: 'publish', folder: '发布' },
21
+ { id: 'ecommerce', folder: '电商' },
20
22
  ] as const
21
23
 
22
24
  /** 工程师身份专用。ESPHome YAML → 实验室服务器编译 firmware.bin。 */
@@ -162,6 +164,8 @@ function seedRoom(templatesRoot: string, destRoot: string, room: RoomSpec): Seed
162
164
  written.push(rel)
163
165
  }
164
166
 
167
+ seedSharedSkills(dest, written)
168
+
165
169
  return {
166
170
  id: room.id,
167
171
  folder: room.folder,
@@ -173,6 +177,36 @@ function seedRoom(templatesRoot: string, destRoot: string, room: RoomSpec): Seed
173
177
  }
174
178
  }
175
179
 
180
+ export function defaultSharedTemplatesRoot(): string {
181
+ const here = fileURLToPath(new URL('.', import.meta.url))
182
+ const candidates = [
183
+ join(here, '../templates/shared'),
184
+ join(here, '../../templates/shared'),
185
+ ]
186
+ for (const dir of candidates) {
187
+ if (existsSync(join(dir, 'wecom-office', 'SKILL.md'))) return dir
188
+ }
189
+ throw new Error('missing shared workspace templates (expected templates/shared/wecom-office/SKILL.md)')
190
+ }
191
+
192
+ function seedSharedSkills(dest: string, written: string[]): void {
193
+ const root = defaultSharedTemplatesRoot()
194
+ for (const name of readdirSync(root).sort()) {
195
+ const skillDir = join(root, name)
196
+ if (!statSync(skillDir).isDirectory()) continue
197
+ if (!existsSync(join(skillDir, 'SKILL.md'))) continue
198
+ // Official wecomcli-* skills ship references/assets/scripts next to SKILL.md.
199
+ for (const abs of listFiles(skillDir)) {
200
+ const relInside = relative(skillDir, abs)
201
+ const rel = join('.agents', 'skills', name, relInside)
202
+ const target = join(dest, rel)
203
+ mkdirSync(dirname(target), { recursive: true })
204
+ writeFileSync(target, readFileSync(abs))
205
+ written.push(rel)
206
+ }
207
+ }
208
+ }
209
+
176
210
  function listFiles(root: string): string[] {
177
211
  const out: string[] = []
178
212
  const walk = (dir: string): void => {
package/src/changelog.ts CHANGED
@@ -20,6 +20,54 @@ export interface ChangelogRelease {
20
20
  }
21
21
 
22
22
  export const SUITE_CHANGELOG: readonly ChangelogRelease[] = [
23
+ {
24
+ version: '0.1.51',
25
+ date: '2026-08-20',
26
+ sections: [
27
+ {
28
+ title: { zh: '企微办公技能补全', en: 'WeCom office skill pack' },
29
+ items: [
30
+ {
31
+ zh: '官方 wecomcli-* 整包种进房间(含 references)。办公用 wecom-cli auth init(可扫码);房间消息通道仍设置页 BotID+Secret,不改扫码。请装 @wecom/cli >=1.1.0。',
32
+ en: 'Vendor full upstream wecomcli-* skills including references. Office auth stays wecom-cli auth init (QR OK); room chat still uses settings BotID+Secret. Use @wecom/cli >=1.1.0.',
33
+ },
34
+ ],
35
+ },
36
+ ],
37
+ },
38
+ {
39
+ version: '0.1.50',
40
+ date: '2026-08-20',
41
+ sections: [
42
+ {
43
+ title: { zh: '运营发布工作间', en: 'Operations publish room' },
44
+ items: [
45
+ {
46
+ zh: '运营身份侧栏多了「发布」房间(合同 Post editor / 媒体连接)和「电商」房间(一期只阿里巴巴国际站;Amazon 等有号)。设置页「看板」看两室状态与 Odoo/企微权限。不建图库,排期写企微共享日历。员工机安装包仍钉已发布版本,不要改审批镜像。',
47
+ en: 'Operations now gets 发布 (media / Post editor) and 电商 (phase 1: Alibaba.com; Amazon waits for an account). The settings Board tab shows channel status plus Odoo/WeCom identity. No media library; schedule goes to one shared WeCom calendar. Do not bump the installer SUITE_VERSION.',
48
+ },
49
+ ],
50
+ },
51
+ {
52
+ title: { zh: '企微固定对话框', en: 'Sticky WeCom sessions' },
53
+ items: [
54
+ {
55
+ zh: '同一房间连续说话复用网页左侧同一条会话。只有「重启对话」才新开。',
56
+ en: 'WeCom turns in one room reuse the same sidebar session. Only “重启对话” opens a new one.',
57
+ },
58
+ ],
59
+ },
60
+ {
61
+ title: { zh: '企微办公能力', en: 'WeCom office APIs' },
62
+ items: [
63
+ {
64
+ zh: 'rez_status / 状态页报官方 wecom-cli >=1.1 品类(通讯录/在线文档/表格/待办/日程/会议/邮件/微盘等)。房间种入官方 wecomcli-* 技能。不要把「没有 wechat MCP」或旧的 10 人限制当成没有企微能力。BotID 只是房间消息通道。不改员工机安装包。',
65
+ en: 'rez_status lists official wecom-cli >=1.1 modules (contacts/docs/sheets/todos/calendar/meetings/mail/disk). Rooms get upstream wecomcli-* skills. A missing wechat MCP row is not “no WeCom”. BotID is only the room chat channel. Do not bump the installer.',
66
+ },
67
+ ],
68
+ },
69
+ ],
70
+ },
23
71
  {
24
72
  version: '0.1.49',
25
73
  date: '2026-08-19',
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Contract Account connections → two ops rooms + the settings 看板.
3
+ * Phase-1 ecommerce is Alibaba.com only (Amazon waits for an account). Media stays in 发布.
4
+ * Secrets never live here.
5
+ */
6
+
7
+ export type ChannelKind = 'media' | 'ecommerce'
8
+ export type ChannelPhase = '1' | 'later'
9
+
10
+ export interface ChannelSpec {
11
+ id: string
12
+ nameZh: string
13
+ nameEn: string
14
+ kind: ChannelKind
15
+ room: '发布' | '电商'
16
+ phase: ChannelPhase
17
+ }
18
+
19
+ export const MEDIA_ROOM = '发布'
20
+ export const ECOMMERCE_ROOM = '电商'
21
+
22
+ export const CHANNEL_BOARD: readonly ChannelSpec[] = [
23
+ {
24
+ id: 'media_via_publish',
25
+ nameZh: '内容 / 社媒分发',
26
+ nameEn: 'Content / social',
27
+ kind: 'media',
28
+ room: MEDIA_ROOM,
29
+ phase: '1',
30
+ },
31
+ {
32
+ id: 'alibaba_icbu',
33
+ nameZh: '阿里巴巴国际站',
34
+ nameEn: 'Alibaba.com',
35
+ kind: 'ecommerce',
36
+ room: ECOMMERCE_ROOM,
37
+ phase: '1',
38
+ },
39
+ {
40
+ id: 'amazon',
41
+ nameZh: 'Amazon',
42
+ nameEn: 'Amazon',
43
+ kind: 'ecommerce',
44
+ room: ECOMMERCE_ROOM,
45
+ phase: 'later',
46
+ },
47
+ ]
48
+
49
+ export function channelsFor(kind: ChannelKind): ChannelSpec[] {
50
+ return CHANNEL_BOARD.filter((row) => row.kind === kind)
51
+ }
52
+
53
+ export function wecomBound(room: string, bots: ReadonlyArray<{ room: string }>): boolean {
54
+ return bots.some((bot) => bot.room === room)
55
+ }