@tencent-weixin/openclaw-weixin-cli 2.0.1 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -30
- package/cli.mjs +75 -7
- package/lib/compat.mjs +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,10 +19,10 @@ npx -y @tencent-weixin/openclaw-weixin-cli install
|
|
|
19
19
|
|
|
20
20
|
## 兼容矩阵
|
|
21
21
|
|
|
22
|
-
| openclaw-weixin | 支持的 OpenClaw
|
|
23
|
-
|
|
24
|
-
| 1.0.x | >=2026.3.0 <2026.3.22 | `
|
|
25
|
-
| 2.0.x | >=2026.3.22
|
|
22
|
+
| openclaw-weixin | 支持的 OpenClaw | dist-tag | 说明 |
|
|
23
|
+
|-----------------|-----------------------|---------------------------------------|----------------------|
|
|
24
|
+
| 1.0.x | >=2026.3.0 <2026.3.22 | `compat-host-gte2026.3.0-lt2026.3.22` | 兼容轨道 |
|
|
25
|
+
| 2.0.x | >=2026.3.22 | `latest` | 当前推荐主线 |
|
|
26
26
|
|
|
27
27
|
> 从 2.0.0 开始,插件采用独立 semver 版本号,不再对齐宿主 OpenClaw 版本号。
|
|
28
28
|
|
|
@@ -34,11 +34,11 @@ npx -y @tencent-weixin/openclaw-weixin-cli install
|
|
|
34
34
|
# 查看当前 OpenClaw 版本
|
|
35
35
|
openclaw --version
|
|
36
36
|
|
|
37
|
-
#
|
|
37
|
+
# 当前推荐主线 (>=2026.3.22)
|
|
38
38
|
openclaw plugins install @tencent/openclaw-weixin@latest
|
|
39
39
|
|
|
40
|
-
#
|
|
41
|
-
openclaw plugins install @tencent/openclaw-weixin@
|
|
40
|
+
# 兼容轨道 (<2026.3.22)
|
|
41
|
+
openclaw plugins install @tencent/openclaw-weixin@compat-host-gte2026.3.0-lt2026.3.22
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
## 运行时版本校验
|
|
@@ -49,7 +49,7 @@ openclaw plugins install @tencent/openclaw-weixin@legacy
|
|
|
49
49
|
[openclaw-weixin] 宿主版本不兼容!
|
|
50
50
|
当前 OpenClaw 版本: 2026.3.10
|
|
51
51
|
当前插件支持范围: >=2026.3.22
|
|
52
|
-
请安装 openclaw-weixin@
|
|
52
|
+
请安装 openclaw-weixin@compat-host-gte2026.3.0-lt2026.3.22
|
|
53
53
|
或运行: npx @tencent-weixin/openclaw-weixin-cli install (自动选择兼容版本)
|
|
54
54
|
```
|
|
55
55
|
|
|
@@ -68,46 +68,122 @@ openclaw --version
|
|
|
68
68
|
npx -y @tencent-weixin/openclaw-weixin-cli install
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
###
|
|
71
|
+
### 如何查看当前 openclaw 版本
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
openclaw --version
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 发布策略
|
|
78
|
+
|
|
79
|
+
### 本仓库(CLI installer)与插件仓库的关系
|
|
80
|
+
|
|
81
|
+
本仓库发布的是 **CLI 安装器**(`openclaw-weixin-cli`),不是插件本身(`openclaw-weixin`)。
|
|
82
|
+
|
|
83
|
+
- **插件仓库**:openclaw-weixin,通过各分支发布到不同的 npm dist-tag
|
|
84
|
+
- **本仓库**:CLI 安装器,根据 `COMPAT_MATRIX` 自动选择正确的插件 dist-tag 来安装
|
|
85
|
+
|
|
86
|
+
### 分支管理规则
|
|
76
87
|
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
内网和外网通过不同分支管理,prerelease 分支从主分支拉出,合并回主分支:
|
|
89
|
+
|
|
90
|
+
| 分支 | 用途 | package.json 状态 |
|
|
91
|
+
|------|------|------------------|
|
|
92
|
+
| `master-prerelease` | 日常开发 + 内网发布 | 内网发布后保持内网包名和版本 |
|
|
93
|
+
| `master` | 外网发布 | 外网发布后保持外网包名和版本 |
|
|
94
|
+
|
|
95
|
+
**核心原则:**
|
|
96
|
+
- 日常开发和内网发布在 `-prerelease` 分支上进行
|
|
97
|
+
- 需要发外网时,将 prerelease 分支合入对应主分支,再在主分支上发布
|
|
98
|
+
- 发布后 package.json **不回退**,分支保持对应环境的最新发布状态
|
|
99
|
+
- prerelease 和主分支同构(共用 `publish.config.json`),合并时自然更新
|
|
100
|
+
|
|
101
|
+
### CLI 发布命令
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# 在 prerelease 分支上发布内网
|
|
105
|
+
node scripts/publish.mjs internal patch
|
|
106
|
+
|
|
107
|
+
# dry run 预检
|
|
108
|
+
node scripts/publish.mjs internal patch --dry-run
|
|
79
109
|
```
|
|
80
110
|
|
|
81
|
-
|
|
111
|
+
发布脚本会:
|
|
112
|
+
1. 检查工作区是否干净
|
|
113
|
+
2. 将 `package.json` 的 name/version 和 `cli.mjs` 的 PLUGIN_SPEC 替换为目标环境的值
|
|
114
|
+
3. 更新 `publish.config.json` 中对应目标的版本号
|
|
115
|
+
4. 提交 release commit 并打 git tag
|
|
116
|
+
5. npm publish
|
|
117
|
+
6. push commit + tag
|
|
118
|
+
|
|
119
|
+
发布后 package.json 保持发布态,不回退。如果 npm publish 失败,自动回滚 release commit 和 tag。
|
|
120
|
+
|
|
121
|
+
### 内网验证后发外网
|
|
82
122
|
|
|
83
123
|
```bash
|
|
84
|
-
|
|
124
|
+
# ① 在 prerelease 分支上完成内网发布和验证
|
|
125
|
+
|
|
126
|
+
# ② 合入主分支
|
|
127
|
+
git checkout master
|
|
128
|
+
git merge master-prerelease
|
|
129
|
+
|
|
130
|
+
# ③ 在主分支上发布外网
|
|
131
|
+
node scripts/publish.mjs external patch
|
|
85
132
|
```
|
|
86
133
|
|
|
87
|
-
|
|
134
|
+
### 兼容轨道发版流程
|
|
88
135
|
|
|
89
|
-
|
|
136
|
+
当 openclaw 发布破坏兼容性的新版本时:
|
|
90
137
|
|
|
91
|
-
|
|
92
|
-
|----------|-----------|------|
|
|
93
|
-
| `latest` | 2.x | 新宿主线,`npm install` / `openclaw plugins install` 默认安装 |
|
|
94
|
-
| `legacy` | 1.x | 旧宿主维护线,需显式指定 `@legacy` |
|
|
138
|
+
#### 1. 插件仓库操作(openclaw-weixin)
|
|
95
139
|
|
|
96
|
-
|
|
140
|
+
```bash
|
|
141
|
+
# 从当前分支拉出兼容轨道
|
|
142
|
+
git checkout -b compat-host-gteX.Y.Z-ltA.B.C-prerelease master-prerelease
|
|
143
|
+
git checkout -b compat-host-gteX.Y.Z-ltA.B.C master
|
|
144
|
+
# 修改 compat 分支上的 publish.config.json,将 npmTag 改为轨道名
|
|
145
|
+
|
|
146
|
+
# master-prerelease 上适配新宿主,major + 1
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### 2. CLI 仓库操作(本仓库)
|
|
97
150
|
|
|
98
151
|
```bash
|
|
99
|
-
#
|
|
100
|
-
npm run publish:external:latest -- patch
|
|
101
|
-
npm run publish:internal:latest -- patch
|
|
152
|
+
# ① 更新 lib/compat.mjs 的 COMPAT_MATRIX
|
|
102
153
|
|
|
103
|
-
#
|
|
104
|
-
|
|
105
|
-
npm run publish:internal:legacy -- patch
|
|
154
|
+
# ② 在 prerelease 分支上发布内网验证
|
|
155
|
+
node scripts/publish.mjs internal minor
|
|
106
156
|
|
|
107
|
-
#
|
|
108
|
-
|
|
157
|
+
# ③ 验证后合入主分支发外网
|
|
158
|
+
git checkout master && git merge master-prerelease
|
|
159
|
+
node scripts/publish.mjs external minor
|
|
109
160
|
```
|
|
110
161
|
|
|
162
|
+
#### 3. 验证清单
|
|
163
|
+
|
|
164
|
+
- [ ] `npx @tencent/openclaw-weixin-cli install` 在旧宿主上安装兼容轨道版本
|
|
165
|
+
- [ ] `npx @tencent/openclaw-weixin-cli install` 在新宿主上安装 latest 版本
|
|
166
|
+
- [ ] 已安装旧 tag 的用户重跑 CLI 后自动卸载旧版、安装新版
|
|
167
|
+
- [ ] 插件运行时 `version-check.mjs` 报错信息指引正确
|
|
168
|
+
|
|
169
|
+
### 兼容轨道 bug 修复
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# ① 在 compat prerelease 分支上修复
|
|
173
|
+
git checkout compat-host-gteX.Y.Z-ltA.B.C-prerelease
|
|
174
|
+
# cherry-pick 或直接修复
|
|
175
|
+
node scripts/publish.mjs internal patch
|
|
176
|
+
|
|
177
|
+
# ② 需要发外网时合入 compat 主分支
|
|
178
|
+
git checkout compat-host-gteX.Y.Z-ltA.B.C
|
|
179
|
+
git merge compat-host-gteX.Y.Z-ltA.B.C-prerelease
|
|
180
|
+
node scripts/publish.mjs external patch
|
|
181
|
+
|
|
182
|
+
# ③ 评估是否需要同步到 master 和其他 compat 分支
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
> CLI 不需要重新发布——同一 dist-tag 下的 patch 更新,用户通过 `openclaw plugins update` 即可获取。
|
|
186
|
+
|
|
111
187
|
## 开发
|
|
112
188
|
|
|
113
189
|
```bash
|
package/cli.mjs
CHANGED
|
@@ -6,12 +6,20 @@ import path from "node:path";
|
|
|
6
6
|
import os from "node:os";
|
|
7
7
|
import {
|
|
8
8
|
COMPAT_MATRIX,
|
|
9
|
+
compareVersions,
|
|
9
10
|
findCompatEntry,
|
|
10
11
|
formatRange,
|
|
11
12
|
} from "./lib/compat.mjs";
|
|
12
13
|
|
|
13
14
|
const PLUGIN_SPEC = "@tencent-weixin/openclaw-weixin";
|
|
14
15
|
const CHANNEL_ID = "openclaw-weixin";
|
|
16
|
+
/** Only OpenClaw 2026.3.22–2026.3.23 need node_modules/openclaw symlink for jiti. */
|
|
17
|
+
const SYMLINK_OPENCLAW_MIN = "2026.3.22";
|
|
18
|
+
const SYMLINK_OPENCLAW_MAX = "2026.3.23";
|
|
19
|
+
|
|
20
|
+
const LEGACY_TAG_ALIASES = {
|
|
21
|
+
legacy: "compat-host-gte2026.3.0-lt2026.3.22",
|
|
22
|
+
};
|
|
15
23
|
|
|
16
24
|
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
17
25
|
|
|
@@ -110,7 +118,23 @@ function resolvePluginExtDir() {
|
|
|
110
118
|
* openclaw package root. This lets jiti resolve openclaw/plugin-sdk/*
|
|
111
119
|
* without openclaw being a runtime dependency.
|
|
112
120
|
*/
|
|
113
|
-
function
|
|
121
|
+
function hostVersionNeedsOpenclawSymlink(hostVersion) {
|
|
122
|
+
if (!hostVersion) return false;
|
|
123
|
+
const geMin = compareVersions(hostVersion, SYMLINK_OPENCLAW_MIN);
|
|
124
|
+
const leMax = compareVersions(hostVersion, SYMLINK_OPENCLAW_MAX);
|
|
125
|
+
return (
|
|
126
|
+
!Number.isNaN(geMin) &&
|
|
127
|
+
!Number.isNaN(leMax) &&
|
|
128
|
+
geMin >= 0 &&
|
|
129
|
+
leMax <= 0
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function ensureOpenclawSymlink(hostVersion) {
|
|
134
|
+
if (!hostVersionNeedsOpenclawSymlink(hostVersion)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
114
138
|
const hostRoot = resolveHostOpenclawRoot();
|
|
115
139
|
if (!hostRoot) {
|
|
116
140
|
error("无法定位宿主 openclaw 包根目录,跳过 symlink 创建");
|
|
@@ -130,7 +154,6 @@ function ensureOpenclawSymlink() {
|
|
|
130
154
|
try {
|
|
131
155
|
const existing = fs.readlinkSync(linkPath);
|
|
132
156
|
if (fs.realpathSync(existing) === fs.realpathSync(hostRoot)) {
|
|
133
|
-
log("openclaw symlink 已存在且正确");
|
|
134
157
|
return;
|
|
135
158
|
}
|
|
136
159
|
// Wrong target — remove and recreate
|
|
@@ -144,6 +167,30 @@ function ensureOpenclawSymlink() {
|
|
|
144
167
|
log(`已创建 symlink: node_modules/openclaw → ${hostRoot}`);
|
|
145
168
|
}
|
|
146
169
|
|
|
170
|
+
// ── installed plugin detection ───────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Read the openclaw config and return the dist-tag that was used to install
|
|
174
|
+
* the plugin. OpenClaw stores `plugins.installs.<id>.spec` as the raw
|
|
175
|
+
* install spec (e.g. "@tencent/openclaw-weixin@latest"). We extract the
|
|
176
|
+
* trailing tag/version after the last "@".
|
|
177
|
+
* Returns the tag string, or null if not installed / unreadable.
|
|
178
|
+
*/
|
|
179
|
+
function getInstalledPluginTag() {
|
|
180
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), ".openclaw");
|
|
181
|
+
const configPath = path.join(stateDir, "openclaw.json");
|
|
182
|
+
try {
|
|
183
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
184
|
+
const spec = config?.plugins?.installs?.[CHANNEL_ID]?.spec;
|
|
185
|
+
if (!spec) return null;
|
|
186
|
+
const atIdx = spec.lastIndexOf("@");
|
|
187
|
+
const raw = atIdx > 0 ? spec.slice(atIdx + 1) : "latest";
|
|
188
|
+
return LEGACY_TAG_ALIASES[raw] || raw;
|
|
189
|
+
} catch {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
147
194
|
// ── commands ─────────────────────────────────────────────────────────────────
|
|
148
195
|
|
|
149
196
|
function install() {
|
|
@@ -172,7 +219,28 @@ function install() {
|
|
|
172
219
|
const pluginInstallSpec = `${PLUGIN_SPEC}@${compat.distTag}`;
|
|
173
220
|
log(`匹配兼容版本: ${compat.label} (dist-tag: ${compat.distTag})`);
|
|
174
221
|
|
|
175
|
-
// 3.
|
|
222
|
+
// 3. If already installed with a different dist-tag, uninstall first
|
|
223
|
+
// so the fresh install picks up the correct dist-tag.
|
|
224
|
+
// If the installed spec is a pinned version number, skip entirely.
|
|
225
|
+
const installedTag = getInstalledPluginTag();
|
|
226
|
+
if (installedTag !== null && /^\d+\.\d+\.\d+/.test(installedTag)) {
|
|
227
|
+
log(`本地已安装插件为固定版本 ${installedTag},跳过升级`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (installedTag !== null && installedTag !== compat.distTag) {
|
|
231
|
+
log(`本地已安装插件为 @${installedTag},与目标 @${compat.distTag} 不一致,先卸载旧版本...`);
|
|
232
|
+
try {
|
|
233
|
+
run(`echo y | openclaw plugins uninstall "${CHANNEL_ID}"`);
|
|
234
|
+
log("旧版本已卸载");
|
|
235
|
+
} catch (uninstallErr) {
|
|
236
|
+
error("旧版本卸载失败,请手动执行:");
|
|
237
|
+
if (uninstallErr.stderr) console.error(uninstallErr.stderr);
|
|
238
|
+
console.log(` openclaw plugins uninstall "${CHANNEL_ID}"`);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 4. Install plugin via openclaw
|
|
176
244
|
log(`正在安装插件 ${pluginInstallSpec}...`);
|
|
177
245
|
try {
|
|
178
246
|
const installOut = run(`openclaw plugins install "${pluginInstallSpec}"`);
|
|
@@ -197,11 +265,11 @@ function install() {
|
|
|
197
265
|
}
|
|
198
266
|
}
|
|
199
267
|
|
|
200
|
-
//
|
|
268
|
+
// 5. Symlink host openclaw into plugin's node_modules (2026.3.22–2026.3.23 only)
|
|
201
269
|
// so jiti can resolve openclaw/plugin-sdk/* without a runtime dependency.
|
|
202
|
-
ensureOpenclawSymlink();
|
|
270
|
+
ensureOpenclawSymlink(hostVersion);
|
|
203
271
|
|
|
204
|
-
//
|
|
272
|
+
// 6. Login (interactive QR scan)
|
|
205
273
|
log("插件就绪,开始首次连接...");
|
|
206
274
|
try {
|
|
207
275
|
run(`openclaw channels login --channel ${CHANNEL_ID}`, { silent: false });
|
|
@@ -211,7 +279,7 @@ function install() {
|
|
|
211
279
|
console.log(` openclaw channels login --channel ${CHANNEL_ID}`);
|
|
212
280
|
}
|
|
213
281
|
|
|
214
|
-
//
|
|
282
|
+
// 7. Restart gateway so it picks up the new account
|
|
215
283
|
log("正在重启 OpenClaw Gateway...");
|
|
216
284
|
try {
|
|
217
285
|
run(`openclaw gateway restart`, { silent: false });
|
package/lib/compat.mjs
CHANGED
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
export const COMPAT_MATRIX = [
|
|
9
9
|
{
|
|
10
10
|
pluginMajor: 1,
|
|
11
|
-
distTag: '
|
|
11
|
+
distTag: 'compat-host-gte2026.3.0-lt2026.3.22',
|
|
12
12
|
openclawRange: { gte: '2026.3.0', lt: '2026.3.22' },
|
|
13
|
-
label: '1.0.x (
|
|
13
|
+
label: '1.0.x (兼容轨道: OpenClaw >=2026.3.0 <2026.3.22)',
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
pluginMajor: 2,
|
|
17
17
|
distTag: 'latest',
|
|
18
18
|
openclawRange: { gte: '2026.3.22' },
|
|
19
|
-
label: '2.0.x (
|
|
19
|
+
label: '2.0.x (当前最新主线)',
|
|
20
20
|
},
|
|
21
21
|
];
|
|
22
22
|
|