@rezti/dsh-rez-suite 0.1.56 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -2
- package/README.md +4 -4
- package/README.zh.md +2 -2
- package/lib/client.d.ts +1 -1
- package/lib/client.js +25 -2
- package/lib/index.js +110 -20
- package/package.json +3 -3
- package/src/boss/seed.ts +2 -0
- package/src/changelog.ts +24 -0
- package/src/client/locales.ts +2 -2
- package/src/index.ts +2 -2
- package/src/protocol.ts +2 -0
- package/src/self-update.ts +28 -6
- package/src/tools.ts +2 -0
- package/src/wecom-cli.ts +91 -21
- package/templates/shared/wecom-office/SKILL.md +3 -3
- package/templates/shared/wecomcli-shared/SKILL.md +15 -7
- package/templates/staff/hr/.agents/skills/staff-onboard-keys/SKILL.md +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,19 @@
|
|
|
5
5
|
升级:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.
|
|
8
|
+
dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.57
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
不要用裸 `plugin update`,不要写 `latest`(新 profile 有 24 小时发布冷却,当天可能装不上)。不要装 **0.1.46**(GitHub 子依赖会被 DSH 拦住)。不要装 **0.1.51**(误用 `npm publish` 把 `workspace:` 打进包了)。
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Windows 员工机日常点网页左下角「升级」,不必重装 EXE。
|
|
14
|
+
|
|
15
|
+
发版顺序:`sso@0.1.15` → `vision@0.1.1` → `nextcloud@0.1.13` → **`suite@0.1.57`**。**必须用 `pnpm publish`**(会把 `workspace:` 写成真实版本),不要用 `npm publish`。
|
|
16
|
+
|
|
17
|
+
## 0.1.57 — 2026-08-21
|
|
18
|
+
|
|
19
|
+
- **Windows 升级 + 企微办公 CLI**:启动脚本每次装 npm 上已满 24 小时的最新 suite,不再钉 0.1.48。左下角「升级」仍可当天装。Windows「升级」用 PowerShell 重启。`wecom-cli` 用 `node wecom.js` + 房间垫片,禁止 `npm install -g`。
|
|
20
|
+
- **对话贴图不再整轮失败**:DeepSeek 适配器会拒 `{type:image}`。贴图/回形针图片先走 Kimi/Qwen 转成文字,再交给当前网页模型(不用换 DeepSeek-V4-Flash Low)。无 key 时插入失败占位并继续对话,不再 `UNSUPPORTED_CONTENT`。本机路径仍可用 `mcp__vision__view_image`。不要装 GitHub 看图插件。
|
|
14
21
|
|
|
15
22
|
## 0.1.56 — 2026-08-21
|
|
16
23
|
|
package/README.md
CHANGED
|
@@ -2,23 +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.15` → `@rezti/dsh-rez-vision@0.1.
|
|
5
|
+
发版顺序(必做):先发 `@rezti/dsh-rez-sso@0.1.15` → `@rezti/dsh-rez-vision@0.1.1` → `@rezti/dsh-rez-nextcloud@0.1.13` → `@rezti/dsh-rez-suite@0.1.57`。**发 suite 必须用 `pnpm publish`**(会把 `workspace:` 写成真实版本),不要用 `npm publish`。员工机启动脚本跟 npm 满 24h 的 latest,不必改安装包里的钉死号。
|
|
6
6
|
|
|
7
7
|
设置里选身份后,左侧自己出现对应房间(全员三助理;工程师另加实验室;运营另加设计、发布、电商;老板另加搞钱/产品/运营),不必手动添加工作区。实验室:大模型写 YAML、调 MCP、给下载链接。
|
|
8
8
|
|
|
9
9
|
回形针走 npm 包 `@rezti/dsh-web-file-uploader@0.2.3`(不要 GitHub:DSH 会拦子依赖 git,0.1.46 因此装不上)。suite 自带 `@wecom/cli@1.1.0`(企微办公;不要依赖 Homebrew 全局 0.1.x)。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
员工机启动脚本装 npm 上已满 24 小时的最新 suite(不必钉死版本)。左下角「升级」仍可当天装(profile `minimumReleaseAge: 0`)。不要用裸 `plugin update`。
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
# 第一次 / 升级(钉死版本,避开 24h 发布冷却)
|
|
15
|
-
dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.
|
|
15
|
+
dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.57
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
本版改了什么:见 [CHANGELOG.md](./CHANGELOG.md)。
|
|
19
19
|
|
|
20
20
|
包名是 `@rezti/dsh-rez-suite`,不是 `dsh-rezti-suite`。不要对同一 profile 再单独 add 子包,会重复注册。
|
|
21
21
|
|
|
22
|
-
说明书 / 规格书:输入栏回形针上传原 PDF(官方对话只收图)。入库后立刻用 Nextcloud MCP `parse_document`
|
|
22
|
+
说明书 / 规格书:输入栏回形针上传原 PDF(官方对话只收图)。入库后立刻用 Nextcloud MCP `parse_document` 抽字交回对话。看图:对话框直接贴图即可(先转文字再交给 DeepSeek),网页对话模型不要改。不要用微信发 PDF。先入 TAPD **测试中** 转凯文终审,批准后再进 `Marketing/Publish`。
|
|
23
23
|
|
|
24
24
|
拆分包(`dsh-rez-odoo` 等)给开发改代码用。Web 面板(含微信扫码)暂时仍在本包。
|
package/README.zh.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# dsh-rez-suite
|
|
2
2
|
|
|
3
|
-
**用户只装这一包。** 升级只记:`dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.
|
|
3
|
+
**用户只装这一包。** 升级只记:`dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.57`(不要用裸 `update`;不要 latest;不要 0.1.46 / 0.1.47 / 0.1.51)。本版改了什么见 [CHANGELOG.md](./CHANGELOG.md)。拆分包给开发改代码;不要对同一 profile 再单独 add 子包。
|
|
4
4
|
|
|
5
|
-
说明书 / 规格书用输入栏**回形针**上传原 PDF(官方对话只收图,不要拖文件;不要用微信发 PDF)。先入 `Marketing/Inbox`,立刻用 Nextcloud MCP 抽字交回对话,TAPD 测试中,凯文跟 Harness 说审批了哪份后,再写入 `Marketing/Publish
|
|
5
|
+
说明书 / 规格书用输入栏**回形针**上传原 PDF(官方对话只收图,不要拖文件;不要用微信发 PDF)。先入 `Marketing/Inbox`,立刻用 Nextcloud MCP 抽字交回对话,TAPD 测试中,凯文跟 Harness 说审批了哪份后,再写入 `Marketing/Publish/…`。看产品图直接贴进对话即可(旁路先转文字),网页对话模型不要改。
|
|
6
6
|
|
|
7
7
|
拍摄原片:运营岗在「设计」房间交图,官方 Comfy MCP **只修一次**,声明类型后入 Inbox;凯文在老板产品室审批通过后**同时**写入 RAW。品牌规范 / 公司 VI 同一套逻辑,走公司级 `Marketing/Inbox/Brand/` → 终审后 `Marketing/RAW/Brand/`,不要写进某个 SKU。不要直接写 RAW,不要在这次做图生场景/白底。
|
|
8
8
|
|
package/lib/client.d.ts
CHANGED
|
@@ -7324,7 +7324,7 @@ declare const zh: {
|
|
|
7324
7324
|
readonly 'config.vision.model': "模型(可空)";
|
|
7325
7325
|
readonly 'config.vision.modelHint': "空则默认 kimi-k2.7-code;更快可填 kimi-k2.7-code-highspeed";
|
|
7326
7326
|
readonly 'config.vision.token': "API Key";
|
|
7327
|
-
readonly 'config.vision.hint': "网页对话模型保持 DeepSeek
|
|
7327
|
+
readonly 'config.vision.hint': "网页对话模型保持 DeepSeek。对话框直接贴图或回形针图片会自动转成文字再交给 DeepSeek;本机路径也可调 mcp__vision__view_image。图会发到所选厂家。Kimi 填 Moonshot Key;Qwen 填 DashScope Key。改厂家后需重启 dsh web。";
|
|
7328
7328
|
readonly 'config.fs': "本地文件 (fs-mcp-server)";
|
|
7329
7329
|
readonly 'config.fs.root': "根目录";
|
|
7330
7330
|
readonly 'config.sqlite': "SQLite (sqlite-mcp-server)";
|
package/lib/client.js
CHANGED
|
@@ -208,7 +208,7 @@ const zh = {
|
|
|
208
208
|
"config.vision.model": "模型(可空)",
|
|
209
209
|
"config.vision.modelHint": "空则默认 kimi-k2.7-code;更快可填 kimi-k2.7-code-highspeed",
|
|
210
210
|
"config.vision.token": "API Key",
|
|
211
|
-
"config.vision.hint": "网页对话模型保持 DeepSeek
|
|
211
|
+
"config.vision.hint": "网页对话模型保持 DeepSeek。对话框直接贴图或回形针图片会自动转成文字再交给 DeepSeek;本机路径也可调 mcp__vision__view_image。图会发到所选厂家。Kimi 填 Moonshot Key;Qwen 填 DashScope Key。改厂家后需重启 dsh web。",
|
|
212
212
|
"config.fs": "本地文件 (fs-mcp-server)",
|
|
213
213
|
"config.fs.root": "根目录",
|
|
214
214
|
"config.sqlite": "SQLite (sqlite-mcp-server)",
|
|
@@ -379,7 +379,7 @@ const en = {
|
|
|
379
379
|
"config.vision.model": "Model (optional)",
|
|
380
380
|
"config.vision.modelHint": "Blank defaults to kimi-k2.7-code; faster option is kimi-k2.7-code-highspeed",
|
|
381
381
|
"config.vision.token": "API key",
|
|
382
|
-
"config.vision.hint": "Keep DeepSeek as the chat model.
|
|
382
|
+
"config.vision.hint": "Keep DeepSeek as the chat model. Pasted or paperclip images are transcribed automatically before DeepSeek; mcp__vision__view_image still works for local paths. Images leave the machine to that vendor. Kimi uses a Moonshot key; Qwen uses a DashScope key. Restart dsh web after switching vendor.",
|
|
383
383
|
"config.fs": "Local files (fs-mcp-server)",
|
|
384
384
|
"config.fs.root": "Root directory",
|
|
385
385
|
"config.sqlite": "SQLite (sqlite-mcp-server)",
|
|
@@ -1010,6 +1010,29 @@ function ChannelTable({ kind, lang }) {
|
|
|
1010
1010
|
//#endregion
|
|
1011
1011
|
//#region src/changelog.ts
|
|
1012
1012
|
const SUITE_CHANGELOG = [
|
|
1013
|
+
{
|
|
1014
|
+
version: "0.1.57",
|
|
1015
|
+
date: "2026-08-21",
|
|
1016
|
+
sections: [{
|
|
1017
|
+
title: {
|
|
1018
|
+
zh: "Windows 升级与企微 CLI",
|
|
1019
|
+
en: "Windows upgrade + WeCom CLI"
|
|
1020
|
+
},
|
|
1021
|
+
items: [{
|
|
1022
|
+
zh: "启动脚本每次装 npm 上已满 24 小时的最新 suite,不再钉 0.1.48。左下角「升级」仍可当天装。Windows 升级用 PowerShell 重启。办公 wecom-cli 用 node wecom.js + 房间垫片;禁止 npm install -g。",
|
|
1023
|
+
en: "Launchers install the newest suite published on npm for >=24h; no 0.1.48 pin. Sidebar Upgrade can still install a same-day build. Windows Upgrade respawns via PowerShell. Office wecom-cli runs as node wecom.js; never npm install -g."
|
|
1024
|
+
}]
|
|
1025
|
+
}, {
|
|
1026
|
+
title: {
|
|
1027
|
+
zh: "对话贴图不再整轮失败",
|
|
1028
|
+
en: "GUI paste vision"
|
|
1029
|
+
},
|
|
1030
|
+
items: [{
|
|
1031
|
+
zh: "对话里直接贴图不再被 DeepSeek 适配器 UNSUPPORTED_CONTENT 整轮打断:先走 Kimi/Qwen 转成文字再交给当前网页模型。本机路径仍可用 mcp__vision__view_image。不要换网页模型,不要 plugin add github。",
|
|
1032
|
+
en: "Pasted GUI images are transcribed before the DeepSeek adapter, so UNSUPPORTED_CONTENT no longer aborts the turn. Local paths can still use mcp__vision__view_image. Do not switch the chat model or add GitHub vision plugins."
|
|
1033
|
+
}]
|
|
1034
|
+
}]
|
|
1035
|
+
},
|
|
1013
1036
|
{
|
|
1014
1037
|
version: "0.1.56",
|
|
1015
1038
|
date: "2026-08-21",
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,7 @@ 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, loadRezConnections, mergeConnections, readManagedCredential, secretConfigured, startMcpWhenSecret, writeManagedCredential } from "@rezti/dsh-rez-sso";
|
|
5
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { spawn, spawnSync } from "node:child_process";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { DatabaseSync } from "node:sqlite";
|
|
@@ -3247,6 +3247,11 @@ function saveConfig(config) {
|
|
|
3247
3247
|
*
|
|
3248
3248
|
* Suite depends on @wecom/cli@1.1.0 so the profile gets a modern binary.
|
|
3249
3249
|
* Prefer that over a global Homebrew 0.1.x that lacks `mail` / `auth`.
|
|
3250
|
+
*
|
|
3251
|
+
* Windows: the package entry is wecom.js (not wecom-cli.exe). spawnSync of a
|
|
3252
|
+
* .js path is ENOENT; agent shells looking for wecom-cli also miss it. Always
|
|
3253
|
+
* invoke `node wecom.js`, put node_modules/.bin on PATH, and seed a workspace
|
|
3254
|
+
* shim. Never npm install -g: workspace-write sandbox cannot write npm-cache.
|
|
3250
3255
|
*/
|
|
3251
3256
|
/** Official @wecom/cli >=1.1 catalog. Do not invent extra HTTP APIs. */
|
|
3252
3257
|
const WECOM_CLI_CATALOG = [
|
|
@@ -3306,29 +3311,30 @@ const WECOM_CLI_CATALOG = [
|
|
|
3306
3311
|
const MODULE_LABELS = WECOM_CLI_CATALOG.map((row) => row.label).join("/");
|
|
3307
3312
|
const HINT_MISSING = [
|
|
3308
3313
|
`未找到可用的 wecom-cli >=1.1(企微办公:${MODULE_LABELS})。`,
|
|
3309
|
-
"suite 已依赖 @wecom/cli@1.1.0
|
|
3314
|
+
"suite 已依赖 @wecom/cli@1.1.0:请点网页左下角「升级」,或确认 profile 的 node_modules 里有 @wecom/cli。",
|
|
3315
|
+
"Windows 用 node %REZ_WECOM_CLI% 或房间 .agents/bin/wecom-cli.cmd。禁止 npm install -g(沙箱 workspace-write 会 EPERM 写 npm-cache)。",
|
|
3310
3316
|
"不要用 Homebrew 全局 0.1.x(没有 mail/auth)。不要因为没有 wechat MCP 就说没有企微能力。"
|
|
3311
3317
|
].join("");
|
|
3312
3318
|
const HINT_OUTDATED = [
|
|
3313
3319
|
"PATH 上的 wecom-cli 过旧(<1.1,没有 mail 等子命令)。",
|
|
3314
|
-
"请用 suite 自带的 @wecom/cli@1.1.0
|
|
3315
|
-
"
|
|
3320
|
+
"请用 suite 自带的 @wecom/cli@1.1.0:点左下角升级,或把 profile node_modules/.bin 放在 PATH 最前。",
|
|
3321
|
+
"禁止 npm i -g(Windows 沙箱会挡 npm-cache;也容易仍被旧 Homebrew 盖住)。"
|
|
3316
3322
|
].join("");
|
|
3317
3323
|
const HINT_UNAUTH = [
|
|
3318
|
-
"已安装 wecom-cli >=1.1,尚未授权。跑 wecom-cli auth init(可扫码)。",
|
|
3324
|
+
"已安装 wecom-cli >=1.1,尚未授权。跑 wecom-cli auth init(可扫码)。Windows:node %REZ_WECOM_CLI% auth init。",
|
|
3319
3325
|
`授权后可用:${MODULE_LABELS}。本企业已开通这些品类。`,
|
|
3320
3326
|
"CLI 报某模块未授权才说该能力未开通;不要说「没有企微 MCP」,也不要说 10 人限制。"
|
|
3321
3327
|
].join("");
|
|
3322
3328
|
const HINT_OK = [
|
|
3323
3329
|
`企微办公能力走 wecom-cli >=1.1(${MODULE_LABELS})。本企业已开通。suite 已带 @wecom/cli。`,
|
|
3324
|
-
"
|
|
3325
|
-
"
|
|
3326
|
-
"设置页 BotID+Secret
|
|
3330
|
+
"调用:node $REZ_WECOM_CLI … 或房间 .agents/bin/wecom-cli(Windows 用 .cmd)。禁止 npm install -g。",
|
|
3331
|
+
"按房间里官方 wecomcli-* 技能执行。不要用旧帮助中心「超过 10 人只能用文档」的说法。CLI 报未授权才说该模块未开通。",
|
|
3332
|
+
"设置页 BotID+Secret 只是房间消息通道,不是查邮件。不要把没有 mcp__wechat__* 当成没有企微能力。"
|
|
3327
3333
|
].join("");
|
|
3328
3334
|
function wecomCliCatalog() {
|
|
3329
3335
|
return WECOM_CLI_CATALOG.map((row) => ({ ...row }));
|
|
3330
3336
|
}
|
|
3331
|
-
/** Resolve suite-bundled @wecom/cli
|
|
3337
|
+
/** Resolve suite-bundled @wecom/cli wecom.js; undefined if not installed next to suite. */
|
|
3332
3338
|
function resolveWecomCliBin() {
|
|
3333
3339
|
const require = createRequire(import.meta.url);
|
|
3334
3340
|
try {
|
|
@@ -3342,21 +3348,78 @@ function resolveWecomCliBin() {
|
|
|
3342
3348
|
join(here, "..", "..", "..", "node_modules", "@wecom", "cli", "bin", "wecom.js")
|
|
3343
3349
|
]) if (existsSync(candidate)) return candidate;
|
|
3344
3350
|
}
|
|
3351
|
+
/** node_modules/.bin (wecom-cli.cmd) plus the package bin dir (wecom.js). */
|
|
3352
|
+
function wecomCliPathDirs(jsPath) {
|
|
3353
|
+
const pkgBin = dirname(jsPath);
|
|
3354
|
+
return [join(pkgBin, "..", "..", "..", ".bin"), pkgBin];
|
|
3355
|
+
}
|
|
3356
|
+
function workspaceWecomShimDirs(home = process.env.DSH_HOME ?? join(homedir(), ".dsh")) {
|
|
3357
|
+
const root = join(home, "workspaces");
|
|
3358
|
+
if (!existsSync(root)) return [];
|
|
3359
|
+
return readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join(root, entry.name, ".agents", "bin")).filter((dir) => existsSync(dir));
|
|
3360
|
+
}
|
|
3361
|
+
function prependPathDirs(dirs, env = process.env) {
|
|
3362
|
+
const sep = process.platform === "win32" ? ";" : ":";
|
|
3363
|
+
const parts = (env.PATH ?? env.Path ?? "").split(sep).filter(Boolean);
|
|
3364
|
+
const joined = [...dirs.filter((dir) => dir.length > 0 && !parts.includes(dir)), ...parts].join(sep);
|
|
3365
|
+
env.PATH = joined;
|
|
3366
|
+
if (process.platform === "win32") env.Path = joined;
|
|
3367
|
+
return joined;
|
|
3368
|
+
}
|
|
3369
|
+
/** Windows cannot spawn wecom.js as argv0; always use the running Node. */
|
|
3370
|
+
function wecomCliSpawn(bundled, nodePath = process.execPath) {
|
|
3371
|
+
if (bundled !== void 0) return {
|
|
3372
|
+
command: nodePath,
|
|
3373
|
+
prefixArgs: [bundled]
|
|
3374
|
+
};
|
|
3375
|
+
return {
|
|
3376
|
+
command: "wecom-cli",
|
|
3377
|
+
prefixArgs: []
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
function wecomCliShimScripts(opts) {
|
|
3381
|
+
if (opts.jsPath === void 0 || opts.jsPath === "") {
|
|
3382
|
+
const msg = "wecom-cli is bundled in ReZ-TI suite. Click Upgrade. Do not npm install -g.";
|
|
3383
|
+
return {
|
|
3384
|
+
unix: `#!/bin/sh\necho "${msg}" >&2\nexit 1\n`,
|
|
3385
|
+
cmd: `@echo off\r\necho ${msg}\r\nexit /b 1\r\n`
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
return {
|
|
3389
|
+
unix: `#!/bin/sh\nexec "${opts.nodePath.replaceAll("\"", "\\\"")}" "${opts.jsPath.replaceAll("\"", "\\\"")}" "$@"\n`,
|
|
3390
|
+
cmd: `@echo off\r\n"${opts.nodePath}" "${opts.jsPath}" %*\r\n`
|
|
3391
|
+
};
|
|
3392
|
+
}
|
|
3393
|
+
function writeWecomCliShims(dest, written, jsPath = resolveWecomCliBin()) {
|
|
3394
|
+
const scripts = wecomCliShimScripts({
|
|
3395
|
+
nodePath: process.execPath,
|
|
3396
|
+
jsPath
|
|
3397
|
+
});
|
|
3398
|
+
const dirRel = join(".agents", "bin");
|
|
3399
|
+
mkdirSync(join(dest, dirRel), { recursive: true });
|
|
3400
|
+
const unixRel = join(dirRel, "wecom-cli");
|
|
3401
|
+
const cmdRel = join(dirRel, "wecom-cli.cmd");
|
|
3402
|
+
writeFileSync(join(dest, unixRel), scripts.unix);
|
|
3403
|
+
writeFileSync(join(dest, cmdRel), scripts.cmd);
|
|
3404
|
+
try {
|
|
3405
|
+
chmodSync(join(dest, unixRel), 493);
|
|
3406
|
+
} catch {}
|
|
3407
|
+
written.push(unixRel, cmdRel);
|
|
3408
|
+
}
|
|
3345
3409
|
/** Put suite-bundled wecom-cli ahead of global Homebrew 0.1.x on PATH. */
|
|
3346
3410
|
function ensureWecomCliOnPath() {
|
|
3347
3411
|
const bin = resolveWecomCliBin();
|
|
3348
|
-
if (bin
|
|
3349
|
-
|
|
3350
|
-
const pathKey = process.platform === "win32" ? "Path" : "PATH";
|
|
3351
|
-
const parts = (process.env[pathKey] ?? "").split(process.platform === "win32" ? ";" : ":").filter(Boolean);
|
|
3352
|
-
if (parts[0] !== dir) process.env[pathKey] = [dir, ...parts.filter((p) => p !== dir)].join(process.platform === "win32" ? ";" : ":");
|
|
3412
|
+
if (bin !== void 0) process.env.REZ_WECOM_CLI = bin;
|
|
3413
|
+
prependPathDirs([...bin === void 0 ? [] : wecomCliPathDirs(bin), ...workspaceWecomShimDirs()]);
|
|
3353
3414
|
return bin;
|
|
3354
3415
|
}
|
|
3355
3416
|
function defaultWecomCliRunner(argv) {
|
|
3356
|
-
const
|
|
3417
|
+
const spawn = wecomCliSpawn(resolveWecomCliBin());
|
|
3418
|
+
const result = spawnSync(spawn.command, [...spawn.prefixArgs, ...argv], {
|
|
3357
3419
|
encoding: "utf8",
|
|
3358
3420
|
timeout: 4e3,
|
|
3359
|
-
env: process.env
|
|
3421
|
+
env: process.env,
|
|
3422
|
+
windowsHide: true
|
|
3360
3423
|
});
|
|
3361
3424
|
const error = result.error;
|
|
3362
3425
|
return {
|
|
@@ -8064,8 +8127,10 @@ function renderWecomCli(cli) {
|
|
|
8064
8127
|
hint: ""
|
|
8065
8128
|
};
|
|
8066
8129
|
const modules = (row.modules ?? []).map((item) => `${item.label}(${item.id})`).join("、");
|
|
8130
|
+
const bin = row.bin ? `bin: node "${row.bin}"` : "bin: (missing — click Upgrade, do not npm install -g)";
|
|
8067
8131
|
return [
|
|
8068
8132
|
"wecom-cli(企微办公能力,不是 MCP): installed=" + (row.installed ? "yes" : "no") + " authorized=" + (row.authorized ? "yes" : "no"),
|
|
8133
|
+
bin,
|
|
8069
8134
|
modules.length > 0 ? "modules: " + modules : "modules: (官方目录见 wecomcli-* 技能)",
|
|
8070
8135
|
row.hint
|
|
8071
8136
|
].join("\n");
|
|
@@ -8433,6 +8498,7 @@ function seedRoom(templatesRoot, destRoot, room) {
|
|
|
8433
8498
|
written.push(rel);
|
|
8434
8499
|
}
|
|
8435
8500
|
seedSharedSkills(dest, written);
|
|
8501
|
+
writeWecomCliShims(dest, written);
|
|
8436
8502
|
return {
|
|
8437
8503
|
id: room.id,
|
|
8438
8504
|
folder: room.folder,
|
|
@@ -8597,9 +8663,21 @@ function findProfileDir(startDir) {
|
|
|
8597
8663
|
function shellQuote(value) {
|
|
8598
8664
|
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
8599
8665
|
}
|
|
8666
|
+
function powershellQuote(value) {
|
|
8667
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
8668
|
+
}
|
|
8600
8669
|
function relaunchScript(argv, parentPid) {
|
|
8601
8670
|
return `while kill -0 ${parentPid} 2>/dev/null; do sleep 0.15; done; sleep 0.25; exec ${argv.map(shellQuote).join(" ")}`;
|
|
8602
8671
|
}
|
|
8672
|
+
/** Windows staff EXE has no /bin/bash. Wait for the old node, then respawn argv. */
|
|
8673
|
+
function windowsRelaunchScript(argv, parentPid) {
|
|
8674
|
+
const cmd = argv.map(powershellQuote).join(" ");
|
|
8675
|
+
return [
|
|
8676
|
+
`while (Get-Process -Id ${parentPid} -ErrorAction SilentlyContinue) { Start-Sleep -Milliseconds 200 }`,
|
|
8677
|
+
"Start-Sleep -Milliseconds 300",
|
|
8678
|
+
`& ${cmd}`
|
|
8679
|
+
].join("; ");
|
|
8680
|
+
}
|
|
8603
8681
|
async function fetchLatestVersion(fetchImpl = fetch) {
|
|
8604
8682
|
const response = await fetchImpl(NPM_LATEST, { headers: { accept: "application/json" } });
|
|
8605
8683
|
if (!response.ok) throw new Error(`npm registry HTTP ${response.status}`);
|
|
@@ -8638,12 +8716,24 @@ function runPnpmAdd(cwd, spec, env = process.env) {
|
|
|
8638
8716
|
});
|
|
8639
8717
|
}
|
|
8640
8718
|
function spawnRelaunch(argv, parentPid, cwd, env = process.env) {
|
|
8641
|
-
|
|
8719
|
+
(process.platform === "win32" ? spawn("powershell.exe", [
|
|
8720
|
+
"-NoProfile",
|
|
8721
|
+
"-WindowStyle",
|
|
8722
|
+
"Hidden",
|
|
8723
|
+
"-Command",
|
|
8724
|
+
windowsRelaunchScript(argv, parentPid)
|
|
8725
|
+
], {
|
|
8726
|
+
cwd,
|
|
8727
|
+
env,
|
|
8728
|
+
detached: true,
|
|
8729
|
+
stdio: "ignore",
|
|
8730
|
+
windowsHide: true
|
|
8731
|
+
}) : spawn("/bin/bash", ["-c", relaunchScript(argv, parentPid)], {
|
|
8642
8732
|
cwd,
|
|
8643
8733
|
env,
|
|
8644
8734
|
detached: true,
|
|
8645
8735
|
stdio: "ignore"
|
|
8646
|
-
}).unref();
|
|
8736
|
+
})).unref();
|
|
8647
8737
|
}
|
|
8648
8738
|
let inflight;
|
|
8649
8739
|
function createSelfUpdate(io) {
|
|
@@ -8946,7 +9036,7 @@ const SECTION_ORDER = 150;
|
|
|
8946
9036
|
const REZ_GUIDANCE_CORE = [
|
|
8947
9037
|
"本机已安装 ReZ-TI 拆分包:工作身份由 dsh-rez-sso 提供,MCP 由官方 dsh-mcp-client 接入 Odoo / Nextcloud / Home Assistant / TAPD / GSC / 看图旁路。",
|
|
8948
9038
|
"工具名 mcp__odoo__*、mcp__nextcloud__*、mcp__homeassistant__*、mcp__tapd__*、mcp__gsc__*、mcp__vision__*。",
|
|
8949
|
-
"
|
|
9039
|
+
"企业微信有两层,不要混。① 房间消息通道 = 设置页 BotID+Secret(同事在企微跟那个智能机器人说话,进网页左侧对应房间)。② 办公能力不是 MCP:走官方 wecom-cli >=1.1(通讯录/在线文档/在线表格/智能表格/智能文档/待办/日程/会议/邮件/微盘/消息)。本企业已开通这些品类。看 rez_status 的 wecomCli.bin / modules,优先 node $REZ_WECOM_CLI 或房间 .agents/bin/wecom-cli(Windows 用 .cmd)。禁止 npm install -g(Windows 沙箱会 EPERM 写 npm-cache)。不要因为没有 mcp__wechat__* 就说没有企微能力,也不要说「超过 10 人只能用文档」。CLI 报某模块未授权才说该能力未开通。旧群 webhook 兼容才会出现 mcp__wechat__*。",
|
|
8950
9040
|
"密钥:REZ_ODOO_TOKEN、REZ_NEXTCLOUD_PASSWORD、REZ_WECHAT_WEBHOOK、REZ_HA_TOKEN、REZ_TAPD_TOKEN、REZ_GSC_KEY、REZ_VISION_KEY。",
|
|
8951
9041
|
"个人微信(QClaw/ClawBot):打开 设置 → 插件 → ReZ-TI → 微信 扫码,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认。网页归档了再从微信说话会自动恢复到侧栏。发「重启对话」会新开一条可见会话并把旧会话归档。网页端必须开着。不必再跑命令、也不要调用微信 MCP 工具。",
|
|
8952
9042
|
"意图用 rez_set_intent(erp/files/chat/home/auto)。审计用 rez_audit。",
|
|
@@ -8954,7 +9044,7 @@ const REZ_GUIDANCE_CORE = [
|
|
|
8954
9044
|
"Match the user language: Chinese or English. Do not force 中文 when they write English.",
|
|
8955
9045
|
"制度、手册、出差/报销标准、素材路径:打开 Nextcloud Documents/Standards/INDEX.yaml,按 code 取当前 effective_from 最新且未被 replace 的条目,再按相对 uri 打开。引用带路径+生效日。找不到就说「标准文件未归档」,不要用 MEMORY 旧数字。素材文件夹用首次创建标题,不用会变的 Odoo/销售名。",
|
|
8956
9046
|
"读 PDF(Kimi/Cursor 同款:先抽字再问):mcp__nextcloud__nc_webdav_read_file,parse_document 用 auto;表格/标题再试 markdown。不要把 PDF 当图或 base64 塞进对话,内置 read 会当二进制拒掉。parse_status 不是 parsed 或正文空,就说没有文字层(扫描件本期不开 OCR),不要假装读过。不要 plugin add github 看图/PDF 插件。跨很多本说明书检索走 Dify 发布知识库(1154488930001001237),不要另建向量库。",
|
|
8957
|
-
"看产品图/标签/截图:网页对话模型不要改。DeepSeek
|
|
9047
|
+
"看产品图/标签/截图:网页对话模型不要改。DeepSeek 官方聊天是纯文本,看不见像素;对话里直接贴图或回形针图片会先走看图旁路转成文字,再交给 DeepSeek,不要因为 UNSUPPORTED_CONTENT 就换网页模型。本机文件路径也可调 mcp__vision__view_image。旁路默认 Kimi Code(kimi-k2.7-code),设置里可切通义 Qwen-VL。没有看图旁路就说本机未配 REZ_VISION_KEY(设置 → 插件 → ReZ-TI),不要切网页模型假装能看见。官方对话只收图。Comfy MCP 只修图,不拿来认字。",
|
|
8958
9048
|
"同事交说明书/规格书:用输入栏回形针上传原 PDF(不要拖进对话——官方只收图,PDF 不要当图塞;也不要用微信发文件)。不要直接写 Marketing/Publish。先找到该产品对应 TAPD 需求(Wiki 写死的说明书/规格书 TAPD ID;没有则按首次创建标题搜「产品使用说明书」或「技术手册」),把 PDF 放到 Marketing/Inbox/{分类}/{首次创建标题}/manual/ 或 datasheet/(zh.pdf 或 en.pdf),立刻用 mcp__nextcloud__nc_webdav_read_file(parse_document=auto)抽出文字交回本轮,不要只说已入库。评论该需求、状态改测试中(status_3)、处理人改凯文智能家居。规划中先转到开发中再测试中;已实现要先退回开发中。凯文说审批了哪份(产品、说明书或规格书、中英)之后,再把 Inbox 文件写入 Marketing/Publish 对应路径,TAPD 改已实现。拒绝则改已拒绝、不写 Publish。Wiki 缺 NC RAW、NC Publish、Git products/{slug}/models 与 motion 就说「Wiki 未归档」。这不是一件发布;不要拷下游、不要上渠道。",
|
|
8959
9049
|
"同事交拍摄原片:对话里交图即可。先调官方 Comfy MCP 只修一次,得到高精度干净原片;Harness 不做推理,不要自写 WebSocket。这不是图生场景图也不是图生白底图。修完后员工必须声明是什么图(white_bg/scene/label/gallery/packaging,写进 TAPD 评论);未声明不准进审批。不要直接写 Marketing/RAW。两种都先放到 Marketing/Inbox/{分类}/{首次创建标题}/photo/shot/ 与 photo/clean/。对应 TAPD(Wiki 写死的拍摄图 TAPD ID;没有则按首次创建标题搜「产品拍摄」;还没有则评论 1154488930001001218)改测试中、处理人改凯文智能家居。凯文说审批了哪份之后,shot 与 clean 同时写入 Marketing/RAW 对应路径,TAPD 改已实现。拒绝不写 RAW。不要写 Publish、不要上渠道。现有 photo/ 根目录或产品根目录样板不强制搬家。",
|
|
8960
9050
|
"同事交品牌规范或公司 VI:这是公司级,写 Marketing/Brand/,不要写进某个产品 SKU 目录。规范 PDF 和 psd/ai 源文件用回形针;VI 图在对话里交,才调官方 Comfy MCP 只修一次。声明类型(guideline 或 logo/wordmark/icon/color/font/template)后,两种先入 Marketing/Inbox/Brand/guideline/ 或 vi/ 的 shot 与 clean。评论 1154488930001001220,改测试中、处理人凯文智能家居。凯文说审批了哪份之后,shot 与 clean 同时写入 Marketing/RAW/Brand 对应路径。拒绝不写 RAW。不要写 Publish。根上 VI/ 与 MKT/VI 是历史盘,不搬家、不再当正式路径。不要把规范抄进 Standards 正文。"
|
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.
|
|
4
|
-
"version": "0.1.
|
|
3
|
+
"description": "ReZ-TI one-package install for DeepSeek Harness. Update with: dsh plugin --profile web add @rezti/dsh-rez-suite@0.1.57",
|
|
4
|
+
"version": "0.1.57",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@rezti/dsh-rez-sso": "^0.1.15",
|
|
46
46
|
"@rezti/dsh-rez-tapd": "^0.1.1",
|
|
47
47
|
"@rezti/dsh-rez-token-manager": "^0.1.4",
|
|
48
|
-
"@rezti/dsh-rez-vision": "^0.1.
|
|
48
|
+
"@rezti/dsh-rez-vision": "^0.1.1",
|
|
49
49
|
"@rezti/dsh-rez-wechat": "^0.1.17",
|
|
50
50
|
"@rezti/dsh-web-file-uploader": "0.2.3",
|
|
51
51
|
"@wecom/cli": "1.1.0",
|
package/src/boss/seed.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
|
2
2
|
import { dirname, join, relative } from 'node:path'
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { writeWecomCliShims } from '../wecom-cli.ts'
|
|
4
5
|
|
|
5
6
|
export const BOSS_ROOMS = [
|
|
6
7
|
{ id: 'money', folder: '搞钱' },
|
|
@@ -165,6 +166,7 @@ function seedRoom(templatesRoot: string, destRoot: string, room: RoomSpec): Seed
|
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
seedSharedSkills(dest, written)
|
|
169
|
+
writeWecomCliShims(dest, written)
|
|
168
170
|
|
|
169
171
|
return {
|
|
170
172
|
id: room.id,
|
package/src/changelog.ts
CHANGED
|
@@ -20,6 +20,30 @@ export interface ChangelogRelease {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export const SUITE_CHANGELOG: readonly ChangelogRelease[] = [
|
|
23
|
+
{
|
|
24
|
+
version: '0.1.57',
|
|
25
|
+
date: '2026-08-21',
|
|
26
|
+
sections: [
|
|
27
|
+
{
|
|
28
|
+
title: { zh: 'Windows 升级与企微 CLI', en: 'Windows upgrade + WeCom CLI' },
|
|
29
|
+
items: [
|
|
30
|
+
{
|
|
31
|
+
zh: '启动脚本每次装 npm 上已满 24 小时的最新 suite,不再钉 0.1.48。左下角「升级」仍可当天装。Windows 升级用 PowerShell 重启。办公 wecom-cli 用 node wecom.js + 房间垫片;禁止 npm install -g。',
|
|
32
|
+
en: 'Launchers install the newest suite published on npm for >=24h; no 0.1.48 pin. Sidebar Upgrade can still install a same-day build. Windows Upgrade respawns via PowerShell. Office wecom-cli runs as node wecom.js; never npm install -g.',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
title: { zh: '对话贴图不再整轮失败', en: 'GUI paste vision' },
|
|
38
|
+
items: [
|
|
39
|
+
{
|
|
40
|
+
zh: '对话里直接贴图不再被 DeepSeek 适配器 UNSUPPORTED_CONTENT 整轮打断:先走 Kimi/Qwen 转成文字再交给当前网页模型。本机路径仍可用 mcp__vision__view_image。不要换网页模型,不要 plugin add github。',
|
|
41
|
+
en: 'Pasted GUI images are transcribed before the DeepSeek adapter, so UNSUPPORTED_CONTENT no longer aborts the turn. Local paths can still use mcp__vision__view_image. Do not switch the chat model or add GitHub vision plugins.',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
23
47
|
{
|
|
24
48
|
version: '0.1.56',
|
|
25
49
|
date: '2026-08-21',
|
package/src/client/locales.ts
CHANGED
|
@@ -76,7 +76,7 @@ export const zh = {
|
|
|
76
76
|
'config.vision.model': '模型(可空)',
|
|
77
77
|
'config.vision.modelHint': '空则默认 kimi-k2.7-code;更快可填 kimi-k2.7-code-highspeed',
|
|
78
78
|
'config.vision.token': 'API Key',
|
|
79
|
-
'config.vision.hint': '网页对话模型保持 DeepSeek
|
|
79
|
+
'config.vision.hint': '网页对话模型保持 DeepSeek。对话框直接贴图或回形针图片会自动转成文字再交给 DeepSeek;本机路径也可调 mcp__vision__view_image。图会发到所选厂家。Kimi 填 Moonshot Key;Qwen 填 DashScope Key。改厂家后需重启 dsh web。',
|
|
80
80
|
'config.fs': '本地文件 (fs-mcp-server)',
|
|
81
81
|
'config.fs.root': '根目录',
|
|
82
82
|
'config.sqlite': 'SQLite (sqlite-mcp-server)',
|
|
@@ -253,7 +253,7 @@ export const en: Record<RezKey, string> = {
|
|
|
253
253
|
'config.vision.model': 'Model (optional)',
|
|
254
254
|
'config.vision.modelHint': 'Blank defaults to kimi-k2.7-code; faster option is kimi-k2.7-code-highspeed',
|
|
255
255
|
'config.vision.token': 'API key',
|
|
256
|
-
'config.vision.hint': 'Keep DeepSeek as the chat model.
|
|
256
|
+
'config.vision.hint': 'Keep DeepSeek as the chat model. Pasted or paperclip images are transcribed automatically before DeepSeek; mcp__vision__view_image still works for local paths. Images leave the machine to that vendor. Kimi uses a Moonshot key; Qwen uses a DashScope key. Restart dsh web after switching vendor.',
|
|
257
257
|
'config.fs': 'Local files (fs-mcp-server)',
|
|
258
258
|
'config.fs.root': 'Root directory',
|
|
259
259
|
'config.sqlite': 'SQLite (sqlite-mcp-server)',
|
package/src/index.ts
CHANGED
|
@@ -114,7 +114,7 @@ const SECTION_ORDER = 150
|
|
|
114
114
|
export const REZ_GUIDANCE_CORE = [
|
|
115
115
|
'本机已安装 ReZ-TI 拆分包:工作身份由 dsh-rez-sso 提供,MCP 由官方 dsh-mcp-client 接入 Odoo / Nextcloud / Home Assistant / TAPD / GSC / 看图旁路。',
|
|
116
116
|
'工具名 mcp__odoo__*、mcp__nextcloud__*、mcp__homeassistant__*、mcp__tapd__*、mcp__gsc__*、mcp__vision__*。',
|
|
117
|
-
'
|
|
117
|
+
'企业微信有两层,不要混。① 房间消息通道 = 设置页 BotID+Secret(同事在企微跟那个智能机器人说话,进网页左侧对应房间)。② 办公能力不是 MCP:走官方 wecom-cli >=1.1(通讯录/在线文档/在线表格/智能表格/智能文档/待办/日程/会议/邮件/微盘/消息)。本企业已开通这些品类。看 rez_status 的 wecomCli.bin / modules,优先 node $REZ_WECOM_CLI 或房间 .agents/bin/wecom-cli(Windows 用 .cmd)。禁止 npm install -g(Windows 沙箱会 EPERM 写 npm-cache)。不要因为没有 mcp__wechat__* 就说没有企微能力,也不要说「超过 10 人只能用文档」。CLI 报某模块未授权才说该能力未开通。旧群 webhook 兼容才会出现 mcp__wechat__*。',
|
|
118
118
|
'密钥:REZ_ODOO_TOKEN、REZ_NEXTCLOUD_PASSWORD、REZ_WECHAT_WEBHOOK、REZ_HA_TOKEN、REZ_TAPD_TOKEN、REZ_GSC_KEY、REZ_VISION_KEY。',
|
|
119
119
|
'个人微信(QClaw/ClawBot):打开 设置 → 插件 → ReZ-TI → 微信 扫码,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认。网页归档了再从微信说话会自动恢复到侧栏。发「重启对话」会新开一条可见会话并把旧会话归档。网页端必须开着。不必再跑命令、也不要调用微信 MCP 工具。',
|
|
120
120
|
'意图用 rez_set_intent(erp/files/chat/home/auto)。审计用 rez_audit。',
|
|
@@ -122,7 +122,7 @@ export const REZ_GUIDANCE_CORE = [
|
|
|
122
122
|
'Match the user language: Chinese or English. Do not force 中文 when they write English.',
|
|
123
123
|
'制度、手册、出差/报销标准、素材路径:打开 Nextcloud Documents/Standards/INDEX.yaml,按 code 取当前 effective_from 最新且未被 replace 的条目,再按相对 uri 打开。引用带路径+生效日。找不到就说「标准文件未归档」,不要用 MEMORY 旧数字。素材文件夹用首次创建标题,不用会变的 Odoo/销售名。',
|
|
124
124
|
'读 PDF(Kimi/Cursor 同款:先抽字再问):mcp__nextcloud__nc_webdav_read_file,parse_document 用 auto;表格/标题再试 markdown。不要把 PDF 当图或 base64 塞进对话,内置 read 会当二进制拒掉。parse_status 不是 parsed 或正文空,就说没有文字层(扫描件本期不开 OCR),不要假装读过。不要 plugin add github 看图/PDF 插件。跨很多本说明书检索走 Dify 发布知识库(1154488930001001237),不要另建向量库。',
|
|
125
|
-
'看产品图/标签/截图:网页对话模型不要改。DeepSeek
|
|
125
|
+
'看产品图/标签/截图:网页对话模型不要改。DeepSeek 官方聊天是纯文本,看不见像素;对话里直接贴图或回形针图片会先走看图旁路转成文字,再交给 DeepSeek,不要因为 UNSUPPORTED_CONTENT 就换网页模型。本机文件路径也可调 mcp__vision__view_image。旁路默认 Kimi Code(kimi-k2.7-code),设置里可切通义 Qwen-VL。没有看图旁路就说本机未配 REZ_VISION_KEY(设置 → 插件 → ReZ-TI),不要切网页模型假装能看见。官方对话只收图。Comfy MCP 只修图,不拿来认字。',
|
|
126
126
|
'同事交说明书/规格书:用输入栏回形针上传原 PDF(不要拖进对话——官方只收图,PDF 不要当图塞;也不要用微信发文件)。不要直接写 Marketing/Publish。先找到该产品对应 TAPD 需求(Wiki 写死的说明书/规格书 TAPD ID;没有则按首次创建标题搜「产品使用说明书」或「技术手册」),把 PDF 放到 Marketing/Inbox/{分类}/{首次创建标题}/manual/ 或 datasheet/(zh.pdf 或 en.pdf),立刻用 mcp__nextcloud__nc_webdav_read_file(parse_document=auto)抽出文字交回本轮,不要只说已入库。评论该需求、状态改测试中(status_3)、处理人改凯文智能家居。规划中先转到开发中再测试中;已实现要先退回开发中。凯文说审批了哪份(产品、说明书或规格书、中英)之后,再把 Inbox 文件写入 Marketing/Publish 对应路径,TAPD 改已实现。拒绝则改已拒绝、不写 Publish。Wiki 缺 NC RAW、NC Publish、Git products/{slug}/models 与 motion 就说「Wiki 未归档」。这不是一件发布;不要拷下游、不要上渠道。',
|
|
127
127
|
'同事交拍摄原片:对话里交图即可。先调官方 Comfy MCP 只修一次,得到高精度干净原片;Harness 不做推理,不要自写 WebSocket。这不是图生场景图也不是图生白底图。修完后员工必须声明是什么图(white_bg/scene/label/gallery/packaging,写进 TAPD 评论);未声明不准进审批。不要直接写 Marketing/RAW。两种都先放到 Marketing/Inbox/{分类}/{首次创建标题}/photo/shot/ 与 photo/clean/。对应 TAPD(Wiki 写死的拍摄图 TAPD ID;没有则按首次创建标题搜「产品拍摄」;还没有则评论 1154488930001001218)改测试中、处理人改凯文智能家居。凯文说审批了哪份之后,shot 与 clean 同时写入 Marketing/RAW 对应路径,TAPD 改已实现。拒绝不写 RAW。不要写 Publish、不要上渠道。现有 photo/ 根目录或产品根目录样板不强制搬家。',
|
|
128
128
|
'同事交品牌规范或公司 VI:这是公司级,写 Marketing/Brand/,不要写进某个产品 SKU 目录。规范 PDF 和 psd/ai 源文件用回形针;VI 图在对话里交,才调官方 Comfy MCP 只修一次。声明类型(guideline 或 logo/wordmark/icon/color/font/template)后,两种先入 Marketing/Inbox/Brand/guideline/ 或 vi/ 的 shot 与 clean。评论 1154488930001001220,改测试中、处理人凯文智能家居。凯文说审批了哪份之后,shot 与 clean 同时写入 Marketing/RAW/Brand 对应路径。拒绝不写 RAW。不要写 Publish。根上 VI/ 与 MKT/VI 是历史盘,不搬家、不再当正式路径。不要把规范抄进 Standards 正文。',
|
package/src/protocol.ts
CHANGED
|
@@ -138,6 +138,8 @@ export interface RezWecomCliStatus {
|
|
|
138
138
|
authorized: boolean
|
|
139
139
|
modules: RezWecomCliModule[]
|
|
140
140
|
hint: string
|
|
141
|
+
/** Absolute wecom.js path. Agent should run: node "<bin>" … */
|
|
142
|
+
bin?: string
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
/** Complete /api/dsh-rez-suite/status response. */
|
package/src/self-update.ts
CHANGED
|
@@ -55,10 +55,24 @@ export function shellQuote(value: string): string {
|
|
|
55
55
|
return `'${value.replaceAll("'", `'\\''`)}'`
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
export function powershellQuote(value: string): string {
|
|
59
|
+
return `'${value.replaceAll("'", "''")}'`
|
|
60
|
+
}
|
|
61
|
+
|
|
58
62
|
export function relaunchScript(argv: string[], parentPid: number): string {
|
|
59
63
|
return `while kill -0 ${parentPid} 2>/dev/null; do sleep 0.15; done; sleep 0.25; exec ${argv.map(shellQuote).join(' ')}`
|
|
60
64
|
}
|
|
61
65
|
|
|
66
|
+
/** Windows staff EXE has no /bin/bash. Wait for the old node, then respawn argv. */
|
|
67
|
+
export function windowsRelaunchScript(argv: string[], parentPid: number): string {
|
|
68
|
+
const cmd = argv.map(powershellQuote).join(' ')
|
|
69
|
+
return [
|
|
70
|
+
`while (Get-Process -Id ${parentPid} -ErrorAction SilentlyContinue) { Start-Sleep -Milliseconds 200 }`,
|
|
71
|
+
'Start-Sleep -Milliseconds 300',
|
|
72
|
+
`& ${cmd}`,
|
|
73
|
+
].join('; ')
|
|
74
|
+
}
|
|
75
|
+
|
|
62
76
|
export async function fetchLatestVersion(fetchImpl: typeof fetch = fetch): Promise<string> {
|
|
63
77
|
const response = await fetchImpl(NPM_LATEST, { headers: { accept: 'application/json' } })
|
|
64
78
|
if (!response.ok) throw new Error(`npm registry HTTP ${response.status}`)
|
|
@@ -89,12 +103,20 @@ export function runPnpmAdd(cwd: string, spec: string, env: NodeJS.ProcessEnv = p
|
|
|
89
103
|
}
|
|
90
104
|
|
|
91
105
|
export function spawnRelaunch(argv: string[], parentPid: number, cwd: string, env: NodeJS.ProcessEnv = process.env): void {
|
|
92
|
-
const child =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
106
|
+
const child = process.platform === 'win32'
|
|
107
|
+
? spawn('powershell.exe', ['-NoProfile', '-WindowStyle', 'Hidden', '-Command', windowsRelaunchScript(argv, parentPid)], {
|
|
108
|
+
cwd,
|
|
109
|
+
env,
|
|
110
|
+
detached: true,
|
|
111
|
+
stdio: 'ignore',
|
|
112
|
+
windowsHide: true,
|
|
113
|
+
})
|
|
114
|
+
: spawn('/bin/bash', ['-c', relaunchScript(argv, parentPid)], {
|
|
115
|
+
cwd,
|
|
116
|
+
env,
|
|
117
|
+
detached: true,
|
|
118
|
+
stdio: 'ignore',
|
|
119
|
+
})
|
|
98
120
|
child.unref()
|
|
99
121
|
}
|
|
100
122
|
|
package/src/tools.ts
CHANGED
|
@@ -34,9 +34,11 @@ function renderTest(results: RezTestResult[]): string {
|
|
|
34
34
|
function renderWecomCli(cli: RezWecomCliStatus | undefined): string {
|
|
35
35
|
const row = cli ?? { installed: false, authorized: false, modules: [], hint: '' }
|
|
36
36
|
const modules = (row.modules ?? []).map((item) => `${item.label}(${item.id})`).join('、')
|
|
37
|
+
const bin = row.bin ? `bin: node "${row.bin}"` : 'bin: (missing — click Upgrade, do not npm install -g)'
|
|
37
38
|
return [
|
|
38
39
|
'wecom-cli(企微办公能力,不是 MCP): installed=' + (row.installed ? 'yes' : 'no')
|
|
39
40
|
+ ' authorized=' + (row.authorized ? 'yes' : 'no'),
|
|
41
|
+
bin,
|
|
40
42
|
modules.length > 0 ? 'modules: ' + modules : 'modules: (官方目录见 wecomcli-* 技能)',
|
|
41
43
|
row.hint,
|
|
42
44
|
].join('\n')
|
package/src/wecom-cli.ts
CHANGED
|
@@ -6,10 +6,16 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Suite depends on @wecom/cli@1.1.0 so the profile gets a modern binary.
|
|
8
8
|
* Prefer that over a global Homebrew 0.1.x that lacks `mail` / `auth`.
|
|
9
|
+
*
|
|
10
|
+
* Windows: the package entry is wecom.js (not wecom-cli.exe). spawnSync of a
|
|
11
|
+
* .js path is ENOENT; agent shells looking for wecom-cli also miss it. Always
|
|
12
|
+
* invoke `node wecom.js`, put node_modules/.bin on PATH, and seed a workspace
|
|
13
|
+
* shim. Never npm install -g: workspace-write sandbox cannot write npm-cache.
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
import { spawnSync } from 'node:child_process'
|
|
12
|
-
import { existsSync } from 'node:fs'
|
|
17
|
+
import { chmodSync, existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs'
|
|
18
|
+
import { homedir } from 'node:os'
|
|
13
19
|
import { dirname, join } from 'node:path'
|
|
14
20
|
import { createRequire } from 'node:module'
|
|
15
21
|
import { fileURLToPath } from 'node:url'
|
|
@@ -24,7 +30,7 @@ export interface WecomCliStatus {
|
|
|
24
30
|
authorized: boolean
|
|
25
31
|
modules: WecomCliModule[]
|
|
26
32
|
hint: string
|
|
27
|
-
/** Absolute path
|
|
33
|
+
/** Absolute path of bundled wecom.js; agent should run: node "<bin>" … */
|
|
28
34
|
bin?: string
|
|
29
35
|
}
|
|
30
36
|
|
|
@@ -37,6 +43,11 @@ export interface WecomCliRunResult {
|
|
|
37
43
|
|
|
38
44
|
export type WecomCliRunner = (argv: string[]) => WecomCliRunResult
|
|
39
45
|
|
|
46
|
+
export interface WecomCliSpawn {
|
|
47
|
+
command: string
|
|
48
|
+
prefixArgs: string[]
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
/** Official @wecom/cli >=1.1 catalog. Do not invent extra HTTP APIs. */
|
|
41
52
|
export const WECOM_CLI_CATALOG: readonly WecomCliModule[] = [
|
|
42
53
|
{ id: 'contact', label: '通讯录' },
|
|
@@ -58,27 +69,28 @@ const MODULE_LABELS = WECOM_CLI_CATALOG.map((row) => row.label).join('/')
|
|
|
58
69
|
|
|
59
70
|
const HINT_MISSING = [
|
|
60
71
|
`未找到可用的 wecom-cli >=1.1(企微办公:${MODULE_LABELS})。`,
|
|
61
|
-
'suite 已依赖 @wecom/cli@1.1.0
|
|
72
|
+
'suite 已依赖 @wecom/cli@1.1.0:请点网页左下角「升级」,或确认 profile 的 node_modules 里有 @wecom/cli。',
|
|
73
|
+
'Windows 用 node %REZ_WECOM_CLI% 或房间 .agents/bin/wecom-cli.cmd。禁止 npm install -g(沙箱 workspace-write 会 EPERM 写 npm-cache)。',
|
|
62
74
|
'不要用 Homebrew 全局 0.1.x(没有 mail/auth)。不要因为没有 wechat MCP 就说没有企微能力。',
|
|
63
75
|
].join('')
|
|
64
76
|
|
|
65
77
|
const HINT_OUTDATED = [
|
|
66
78
|
'PATH 上的 wecom-cli 过旧(<1.1,没有 mail 等子命令)。',
|
|
67
|
-
'请用 suite 自带的 @wecom/cli@1.1.0
|
|
68
|
-
'
|
|
79
|
+
'请用 suite 自带的 @wecom/cli@1.1.0:点左下角升级,或把 profile node_modules/.bin 放在 PATH 最前。',
|
|
80
|
+
'禁止 npm i -g(Windows 沙箱会挡 npm-cache;也容易仍被旧 Homebrew 盖住)。',
|
|
69
81
|
].join('')
|
|
70
82
|
|
|
71
83
|
const HINT_UNAUTH = [
|
|
72
|
-
'已安装 wecom-cli >=1.1,尚未授权。跑 wecom-cli auth init(可扫码)。',
|
|
84
|
+
'已安装 wecom-cli >=1.1,尚未授权。跑 wecom-cli auth init(可扫码)。Windows:node %REZ_WECOM_CLI% auth init。',
|
|
73
85
|
`授权后可用:${MODULE_LABELS}。本企业已开通这些品类。`,
|
|
74
86
|
'CLI 报某模块未授权才说该能力未开通;不要说「没有企微 MCP」,也不要说 10 人限制。',
|
|
75
87
|
].join('')
|
|
76
88
|
|
|
77
89
|
const HINT_OK = [
|
|
78
90
|
`企微办公能力走 wecom-cli >=1.1(${MODULE_LABELS})。本企业已开通。suite 已带 @wecom/cli。`,
|
|
79
|
-
'
|
|
80
|
-
'
|
|
81
|
-
'设置页 BotID+Secret
|
|
91
|
+
'调用:node $REZ_WECOM_CLI … 或房间 .agents/bin/wecom-cli(Windows 用 .cmd)。禁止 npm install -g。',
|
|
92
|
+
'按房间里官方 wecomcli-* 技能执行。不要用旧帮助中心「超过 10 人只能用文档」的说法。CLI 报未授权才说该模块未开通。',
|
|
93
|
+
'设置页 BotID+Secret 只是房间消息通道,不是查邮件。不要把没有 mcp__wechat__* 当成没有企微能力。',
|
|
82
94
|
].join('')
|
|
83
95
|
|
|
84
96
|
export function wecomCliCatalog(): WecomCliModule[] {
|
|
@@ -93,7 +105,7 @@ export function parseWecomCliHelpModules(helpText: string): WecomCliModule[] {
|
|
|
93
105
|
})
|
|
94
106
|
}
|
|
95
107
|
|
|
96
|
-
/** Resolve suite-bundled @wecom/cli
|
|
108
|
+
/** Resolve suite-bundled @wecom/cli wecom.js; undefined if not installed next to suite. */
|
|
97
109
|
export function resolveWecomCliBin(): string | undefined {
|
|
98
110
|
const require = createRequire(import.meta.url)
|
|
99
111
|
try {
|
|
@@ -103,7 +115,6 @@ export function resolveWecomCliBin(): string | undefined {
|
|
|
103
115
|
} catch {
|
|
104
116
|
// not hoisted next to this module
|
|
105
117
|
}
|
|
106
|
-
// Fallbacks when published layout differs
|
|
107
118
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
108
119
|
for (const candidate of [
|
|
109
120
|
join(here, '..', 'node_modules', '@wecom', 'cli', 'bin', 'wecom.js'),
|
|
@@ -115,27 +126,86 @@ export function resolveWecomCliBin(): string | undefined {
|
|
|
115
126
|
return undefined
|
|
116
127
|
}
|
|
117
128
|
|
|
129
|
+
/** node_modules/.bin (wecom-cli.cmd) plus the package bin dir (wecom.js). */
|
|
130
|
+
export function wecomCliPathDirs(jsPath: string): string[] {
|
|
131
|
+
const pkgBin = dirname(jsPath)
|
|
132
|
+
const nmBin = join(pkgBin, '..', '..', '..', '.bin')
|
|
133
|
+
return [nmBin, pkgBin]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function workspaceWecomShimDirs(home = process.env.DSH_HOME ?? join(homedir(), '.dsh')): string[] {
|
|
137
|
+
const root = join(home, 'workspaces')
|
|
138
|
+
if (!existsSync(root)) return []
|
|
139
|
+
return readdirSync(root, { withFileTypes: true })
|
|
140
|
+
.filter((entry) => entry.isDirectory())
|
|
141
|
+
.map((entry) => join(root, entry.name, '.agents', 'bin'))
|
|
142
|
+
.filter((dir) => existsSync(dir))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function prependPathDirs(dirs: string[], env: NodeJS.ProcessEnv = process.env): string {
|
|
146
|
+
const sep = process.platform === 'win32' ? ';' : ':'
|
|
147
|
+
const current = env.PATH ?? env.Path ?? ''
|
|
148
|
+
const parts = current.split(sep).filter(Boolean)
|
|
149
|
+
const head = dirs.filter((dir) => dir.length > 0 && !parts.includes(dir))
|
|
150
|
+
const joined = [...head, ...parts].join(sep)
|
|
151
|
+
env.PATH = joined
|
|
152
|
+
if (process.platform === 'win32') env.Path = joined
|
|
153
|
+
return joined
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Windows cannot spawn wecom.js as argv0; always use the running Node. */
|
|
157
|
+
export function wecomCliSpawn(bundled: string | undefined, nodePath = process.execPath): WecomCliSpawn {
|
|
158
|
+
if (bundled !== undefined) return { command: nodePath, prefixArgs: [bundled] }
|
|
159
|
+
return { command: 'wecom-cli', prefixArgs: [] }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function wecomCliShimScripts(opts: { nodePath: string; jsPath?: string }): { unix: string; cmd: string } {
|
|
163
|
+
if (opts.jsPath === undefined || opts.jsPath === '') {
|
|
164
|
+
const msg = 'wecom-cli is bundled in ReZ-TI suite. Click Upgrade. Do not npm install -g.'
|
|
165
|
+
return {
|
|
166
|
+
unix: `#!/bin/sh\necho "${msg}" >&2\nexit 1\n`,
|
|
167
|
+
cmd: `@echo off\r\necho ${msg}\r\nexit /b 1\r\n`,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const node = opts.nodePath.replaceAll('"', '\\"')
|
|
171
|
+
const js = opts.jsPath.replaceAll('"', '\\"')
|
|
172
|
+
return {
|
|
173
|
+
unix: `#!/bin/sh\nexec "${node}" "${js}" "$@"\n`,
|
|
174
|
+
cmd: `@echo off\r\n"${opts.nodePath}" "${opts.jsPath}" %*\r\n`,
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function writeWecomCliShims(dest: string, written: string[], jsPath = resolveWecomCliBin()): void {
|
|
179
|
+
const scripts = wecomCliShimScripts({ nodePath: process.execPath, jsPath })
|
|
180
|
+
const dirRel = join('.agents', 'bin')
|
|
181
|
+
mkdirSync(join(dest, dirRel), { recursive: true })
|
|
182
|
+
const unixRel = join(dirRel, 'wecom-cli')
|
|
183
|
+
const cmdRel = join(dirRel, 'wecom-cli.cmd')
|
|
184
|
+
writeFileSync(join(dest, unixRel), scripts.unix)
|
|
185
|
+
writeFileSync(join(dest, cmdRel), scripts.cmd)
|
|
186
|
+
try { chmodSync(join(dest, unixRel), 0o755) } catch { /* win */ }
|
|
187
|
+
written.push(unixRel, cmdRel)
|
|
188
|
+
}
|
|
189
|
+
|
|
118
190
|
/** Put suite-bundled wecom-cli ahead of global Homebrew 0.1.x on PATH. */
|
|
119
191
|
export function ensureWecomCliOnPath(): string | undefined {
|
|
120
192
|
const bin = resolveWecomCliBin()
|
|
121
|
-
if (bin
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (parts[0] !== dir) {
|
|
127
|
-
process.env[pathKey] = [dir, ...parts.filter((p) => p !== dir)].join(process.platform === 'win32' ? ';' : ':')
|
|
128
|
-
}
|
|
193
|
+
if (bin !== undefined) process.env.REZ_WECOM_CLI = bin
|
|
194
|
+
prependPathDirs([
|
|
195
|
+
...(bin === undefined ? [] : wecomCliPathDirs(bin)),
|
|
196
|
+
...workspaceWecomShimDirs(),
|
|
197
|
+
])
|
|
129
198
|
return bin
|
|
130
199
|
}
|
|
131
200
|
|
|
132
201
|
export function defaultWecomCliRunner(argv: string[]): WecomCliRunResult {
|
|
133
202
|
const bundled = resolveWecomCliBin()
|
|
134
|
-
const
|
|
135
|
-
const result = spawnSync(
|
|
203
|
+
const spawn = wecomCliSpawn(bundled)
|
|
204
|
+
const result = spawnSync(spawn.command, [...spawn.prefixArgs, ...argv], {
|
|
136
205
|
encoding: 'utf8',
|
|
137
206
|
timeout: 4000,
|
|
138
207
|
env: process.env,
|
|
208
|
+
windowsHide: true,
|
|
139
209
|
})
|
|
140
210
|
const error = result.error as NodeJS.ErrnoException | undefined
|
|
141
211
|
return {
|
|
@@ -24,9 +24,9 @@ description: 企业微信办公能力索引。官方 wecom-cli v1.1+ 已面向
|
|
|
24
24
|
| `wecomcli-message` | 消息 |
|
|
25
25
|
| `wecomcli-media` | 媒体文件 |
|
|
26
26
|
|
|
27
|
-
1. 先看 `rez_status` 的 `wecomCli.modules
|
|
27
|
+
1. 先看 `rez_status` 的 `wecomCli.bin` / `modules`,用 `node <bin> auth show`(Windows 同样)。不要 `npm install -g`。
|
|
28
28
|
2. 先读 `wecomcli-shared`,再读对应 `wecomcli-*`。子命令以 `wecom-cli <模块> --help` 为准。
|
|
29
29
|
3. CLI 返回未授权 / 无权限,才说**该模块未开通**。不要总结成「当前系统没有企业微信 MCP」,也不要说「超过 10 人没有通讯录」。
|
|
30
|
-
4. 设置页 **BotID + Secret** 是房间**消息通道**(同事在企微跟哪个 bot 说话进哪个 Harness 房间)。**继续用手填绑定,不要改成扫码。**
|
|
31
|
-
5. 办公 API:suite 已带 `@wecom/cli@1.1.0`。授权跑 `
|
|
30
|
+
4. 设置页 **BotID + Secret** 是房间**消息通道**(同事在企微跟哪个 bot 说话进哪个 Harness 房间)。**继续用手填绑定,不要改成扫码。** 查邮件/文档走 wecom-cli,不是这条通道。
|
|
31
|
+
5. 办公 API:suite 已带 `@wecom/cli@1.1.0`。授权跑 `node $REZ_WECOM_CLI auth init`(可扫码)。找不到命令就让用户点左下角升级,禁止 npm。两套凭证不要混。
|
|
32
32
|
6. 未另批前不要群发、不要改通讯录结构、不要对外发邮件。
|
|
@@ -11,19 +11,27 @@ description: wecom-cli 业务技能的公共前置检查、获取机器人及授
|
|
|
11
11
|
|
|
12
12
|
## Step 1:检查 CLI 安装与版本
|
|
13
13
|
|
|
14
|
-
ReZ-TI suite 已依赖 `@wecom/cli@1.1.0`(随
|
|
14
|
+
ReZ-TI suite 已依赖 `@wecom/cli@1.1.0`(随 suite 装进 profile)。**优先用 profile 里的二进制**,不要用 Homebrew 全局 `0.1.x`(没有 `mail` / 完整 `auth`)。
|
|
15
|
+
|
|
16
|
+
**禁止** `npm install -g @wecom/cli`、禁止 `npm i @wecom/cli`。Windows 员工机沙箱 `workspace-write` 不能写 `AppData\Local\npm-cache`,会 EPERM,而且装到全局也找不到 suite 自带的 1.1。找不到命令时让用户点网页**左下角「升级」**,不要自己装 npm 包。
|
|
17
|
+
|
|
18
|
+
调用顺序(Windows 用 PowerShell / cmd 均可):
|
|
15
19
|
|
|
16
20
|
```bash
|
|
21
|
+
# 1) suite 写入的环境变量(推荐)
|
|
22
|
+
node "$REZ_WECOM_CLI" --version
|
|
23
|
+
# Windows: node $env:REZ_WECOM_CLI --version
|
|
24
|
+
|
|
25
|
+
# 2) 房间内垫片(Glob 能搜到)
|
|
26
|
+
.agents/bin/wecom-cli --version
|
|
27
|
+
# Windows: .agents\bin\wecom-cli.cmd --version
|
|
28
|
+
|
|
29
|
+
# 3) 仅当上面都没有时
|
|
17
30
|
wecom-cli --version
|
|
18
|
-
# 若输出是 0.1.x,或 which wecom-cli 指向 /opt/homebrew,改用:
|
|
19
|
-
# npx --no-install wecom-cli --version
|
|
20
|
-
# 或:node "$(node -p \"require('path').join(require('path').dirname(require.resolve('@wecom/cli/package.json')),'bin/wecom.js')\")" --version
|
|
21
31
|
```
|
|
22
32
|
|
|
23
33
|
- 命令成功,且版本号不低于 `1.1.0` → 继续 Step 2。
|
|
24
|
-
- 命令不存在、执行报错或版本仍低于 `1.1.0` →
|
|
25
|
-
|
|
26
|
-
安装/重装后重新执行 `wecom-cli --version`;仍失败或版本仍低于 `1.1.0` 时停止业务操作,并把错误告知用户。
|
|
34
|
+
- 命令不存在、执行报错或版本仍低于 `1.1.0` → **停止**,告诉用户点左下角升级 ReZ-TI 插件。不要 npm、不要 npx、不要改沙箱去装全局包。
|
|
27
35
|
|
|
28
36
|
## Step 2:检查授权状态
|
|
29
37
|
|
|
@@ -22,7 +22,7 @@ description: 人事助理。引导员工自己领取本机安装包、申请各
|
|
|
22
22
|
|
|
23
23
|
没有 GitHub 权限:找人事要包,不要下未知来源的安装程序。
|
|
24
24
|
|
|
25
|
-
**发包装时说清楚:** zip/exe 只是启动壳,第一次会从外网下 Node、**pnpm**、dsh
|
|
25
|
+
**发包装时说清楚:** zip/exe 只是启动壳,第一次会从外网下 Node、**pnpm**、dsh,再装 npm 上已满 24 小时的最新 suite。刚发的包要等一天;当天要用就点网页左下角「升级」。不是装完就能离线用。长期分发走 CI artifact,不要把仓里 `deploy/dist/` 当主渠道。
|
|
26
26
|
|
|
27
27
|
回形针上传走 npm `@rezti/dsh-web-file-uploader`,装进 suite 即可。不要再单独从 GitHub add。
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@ description: 人事助理。引导员工自己领取本机安装包、申请各
|
|
|
30
30
|
|
|
31
31
|
1. 解压 zip,把 **ReZ-TI Harness** 拖进「应用程序」。
|
|
32
32
|
2. 若提示无法打开 / 已损坏:让对方双击包里的 **首次打开.command**,或在终端执行 `xattr -cr "/Applications/ReZ-TI Harness.app"`,再**右键 → 打开**。
|
|
33
|
-
3. 第一次会弹出终端:下载 Node、安装 pnpm 和稳定 dsh、拉
|
|
33
|
+
3. 第一次会弹出终端:下载 Node、安装 pnpm 和稳定 dsh、拉 npm 上已满 24 小时的最新 suite。不是装完就能离线用。当天要用新功能:点左下角「升级」。
|
|
34
34
|
4. 浏览器打开 `http://127.0.0.1:3080/`。失败看 `~/Library/Application Support/ReZ-TI/harness/logs/harness.log`。
|
|
35
35
|
|
|
36
36
|
### Windows
|
|
@@ -42,6 +42,14 @@ description: 人事助理。引导员工自己领取本机安装包、申请各
|
|
|
42
42
|
|
|
43
43
|
密钥写在本机 `~/.dsh`(Windows `%USERPROFILE%\.dsh`)。不要删这份目录。
|
|
44
44
|
|
|
45
|
+
### 日常升级(已装完,不要重装 EXE)
|
|
46
|
+
|
|
47
|
+
exe / App **只是启动壳**。插件升级点网页**左下角「升级」**,等它重载。不要 `latest`,不要让员工自己 `npm install`。
|
|
48
|
+
|
|
49
|
+
- 不必为升 suite 重装 Setup.exe。密钥还在 `%USERPROFILE%\.dsh`。
|
|
50
|
+
- 只有启动脚本坏了、黑窗口一闪、或人事发了新安装包时,才覆盖装 EXE。先关黑窗口,任务管理器结束 `powershell` / `node`。
|
|
51
|
+
- 同事在企微跟机器人说话要进 Harness:设置 → 插件 → ReZ-TI → **企业微信**,给该房间填 BotID + Secret;网页必须开着;聊的是那个智能机器人,不是普通客服。查邮件是另一条(官方 wecom-cli,先 `auth init`),不要 `npm i -g`。
|
|
52
|
+
|
|
45
53
|
## 填到哪
|
|
46
54
|
|
|
47
55
|
| 用途 | 填哪里 | 面板字段(中文) |
|