Skip to content

Commit ba636d1

Browse files
hxy91819steipete
authored andcommitted
plugin-sdk: keep command status compatibility path light
1 parent aa15de8 commit ba636d1

7 files changed

Lines changed: 575 additions & 233 deletions

File tree

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
5+
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)"
6+
DEFAULT_ROOT="/tmp/openclaw-weixin-cli-repro"
7+
if [[ -d /data/tmp || -w /data ]]; then
8+
DEFAULT_ROOT="/data/tmp/openclaw-weixin-cli-repro"
9+
fi
10+
11+
STATE_ROOT="${OPENCLAW_WEIXIN_REPRO_ROOT:-$DEFAULT_ROOT}"
12+
PLUGIN_SPEC="${OPENCLAW_WEIXIN_PLUGIN_SPEC:-@tencent-weixin/openclaw-weixin@2.1.7}"
13+
PLUGIN_TGZ=""
14+
PAIRING_CHANNEL="feishu"
15+
PAIRING_CODE="BAH8YVB3"
16+
CHANNEL_ID="openclaw-weixin"
17+
TIMEOUT_ONBOARD=30
18+
TIMEOUT_PAIRING=30
19+
TIMEOUT_LOGIN=30
20+
SKIP_BUILD=0
21+
22+
usage() {
23+
cat <<'USAGE'
24+
Usage:
25+
bash scripts/repro/verify-weixin-plugin-cli.sh [options]
26+
27+
Options:
28+
--repo <path> Repo/worktree to validate. Default: current repo root.
29+
--state-root <path> Temp run root. Default: /data/tmp/openclaw-weixin-cli-repro when available, else /tmp/openclaw-weixin-cli-repro.
30+
--plugin-spec <spec> npm spec for the plugin. Default: @tencent-weixin/[email protected]
31+
--plugin-tgz <path> Use a local plugin tarball instead of npm pack.
32+
--pairing-channel <id> Pairing channel for the approve smoke. Default: feishu
33+
--pairing-code <code> Pairing code for the approve smoke. Default: BAH8YVB3
34+
--channel-id <id> Channel id for login smoke. Default: openclaw-weixin
35+
--timeout-onboard <sec> Timeout for onboard smoke. Default: 30
36+
--timeout-pairing <sec> Timeout for pairing smoke. Default: 30
37+
--timeout-login <sec> Timeout for channel login smoke. Default: 30
38+
--skip-build Skip `pnpm build` before running probes.
39+
-h, --help Show this help.
40+
41+
Examples:
42+
bash scripts/repro/verify-weixin-plugin-cli.sh
43+
bash scripts/repro/verify-weixin-plugin-cli.sh --repo /data/worktrees/openclaw-main-weixin-repro --skip-build
44+
bash scripts/repro/verify-weixin-plugin-cli.sh --plugin-spec @tencent-weixin/[email protected]
45+
bash scripts/repro/verify-weixin-plugin-cli.sh --plugin-tgz /tmp/openclaw-weixin-bad.tgz
46+
USAGE
47+
}
48+
49+
log() {
50+
local level="$1"
51+
shift
52+
printf '[weixin-repro][%s] %s\n' "$level" "$*"
53+
}
54+
55+
fail() {
56+
log ERROR "$*"
57+
exit 1
58+
}
59+
60+
require_cmd() {
61+
command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
62+
}
63+
64+
while [[ $# -gt 0 ]]; do
65+
case "$1" in
66+
--repo)
67+
REPO_ROOT="$2"
68+
shift 2
69+
;;
70+
--state-root)
71+
STATE_ROOT="$2"
72+
shift 2
73+
;;
74+
--plugin-spec)
75+
PLUGIN_SPEC="$2"
76+
shift 2
77+
;;
78+
--plugin-tgz)
79+
PLUGIN_TGZ="$2"
80+
shift 2
81+
;;
82+
--pairing-channel)
83+
PAIRING_CHANNEL="$2"
84+
shift 2
85+
;;
86+
--pairing-code)
87+
PAIRING_CODE="$2"
88+
shift 2
89+
;;
90+
--channel-id)
91+
CHANNEL_ID="$2"
92+
shift 2
93+
;;
94+
--timeout-onboard)
95+
TIMEOUT_ONBOARD="$2"
96+
shift 2
97+
;;
98+
--timeout-pairing)
99+
TIMEOUT_PAIRING="$2"
100+
shift 2
101+
;;
102+
--timeout-login)
103+
TIMEOUT_LOGIN="$2"
104+
shift 2
105+
;;
106+
--skip-build)
107+
SKIP_BUILD=1
108+
shift
109+
;;
110+
-h|--help)
111+
usage
112+
exit 0
113+
;;
114+
*)
115+
fail "unknown option: $1"
116+
;;
117+
esac
118+
done
119+
120+
require_cmd npm
121+
require_cmd pnpm
122+
require_cmd rg
123+
require_cmd script
124+
require_cmd tar
125+
require_cmd timeout
126+
127+
[[ -d "$REPO_ROOT" ]] || fail "repo not found: $REPO_ROOT"
128+
[[ -f "$REPO_ROOT/package.json" ]] || fail "repo package.json not found: $REPO_ROOT/package.json"
129+
if [[ -n "$PLUGIN_TGZ" && ! -f "$PLUGIN_TGZ" ]]; then
130+
fail "plugin tarball not found: $PLUGIN_TGZ"
131+
fi
132+
133+
RUN_ID="$(basename "$REPO_ROOT")-$(date +%Y%m%d-%H%M%S)"
134+
RUN_ROOT="$STATE_ROOT/$RUN_ID"
135+
STATE_DIR="$RUN_ROOT/state"
136+
PKG_DIR="$RUN_ROOT/pkg"
137+
PLUGIN_DIR="$STATE_DIR/extensions/openclaw-weixin"
138+
CONFIG_PATH="$STATE_DIR/openclaw.json"
139+
140+
mkdir -p "$RUN_ROOT" "$STATE_DIR" "$PKG_DIR" "$PLUGIN_DIR"
141+
142+
log INFO "repo=$REPO_ROOT"
143+
log INFO "run_root=$RUN_ROOT"
144+
if [[ -n "$PLUGIN_TGZ" ]]; then
145+
log INFO "plugin_source=tarball:$PLUGIN_TGZ"
146+
else
147+
log INFO "plugin_spec=$PLUGIN_SPEC"
148+
fi
149+
150+
if [[ ! -d "$REPO_ROOT/node_modules" ]]; then
151+
log INFO "node_modules missing; running pnpm install"
152+
(cd "$REPO_ROOT" && pnpm install)
153+
fi
154+
155+
if [[ "$SKIP_BUILD" -eq 0 ]]; then
156+
log INFO "running pnpm build"
157+
(cd "$REPO_ROOT" && pnpm build)
158+
else
159+
log INFO "skipping pnpm build"
160+
fi
161+
162+
if [[ -n "$PLUGIN_TGZ" ]]; then
163+
log INFO "using plugin tarball: $PLUGIN_TGZ"
164+
tar -xzf "$PLUGIN_TGZ" -C "$PLUGIN_DIR" --strip-components=1
165+
else
166+
log INFO "packing plugin via npm: $PLUGIN_SPEC"
167+
(cd "$PKG_DIR" && npm pack "$PLUGIN_SPEC" >/dev/null)
168+
PACKED_TGZ="$(find "$PKG_DIR" -maxdepth 1 -type f -name '*.tgz' | sort | tail -n 1)"
169+
[[ -n "$PACKED_TGZ" ]] || fail "npm pack did not produce a tarball"
170+
tar -xzf "$PACKED_TGZ" -C "$PLUGIN_DIR" --strip-components=1
171+
fi
172+
173+
log INFO "installing plugin runtime dependencies"
174+
(cd "$PLUGIN_DIR" && npm install --omit=dev)
175+
176+
if ! rg -n 'openclaw/plugin-sdk/command-auth' "$PLUGIN_DIR" >/dev/null; then
177+
fail "plugin does not import openclaw/plugin-sdk/command-auth; check the plugin version"
178+
fi
179+
180+
cat > "$CONFIG_PATH" <<CONFIG
181+
{
182+
"plugins": {
183+
"load": {
184+
"paths": ["$PLUGIN_DIR"]
185+
}
186+
}
187+
}
188+
CONFIG
189+
190+
COMMON_BAD_PATTERN='Maximum call stack size exceeded|Failed to read config.*RangeError|failed to load .*Maximum call stack size exceeded'
191+
192+
run_probe() {
193+
local name="$1"
194+
local timeout_secs="$2"
195+
local expected_status="$3"
196+
local required_pattern="$4"
197+
local fallback_pattern="$5"
198+
shift 5
199+
local logfile="$RUN_ROOT/${name}.log"
200+
local rendered_cmd
201+
rendered_cmd="$(printf '%q ' "$@")"
202+
203+
log INFO "probe=$name timeout=${timeout_secs}s"
204+
set +e
205+
(
206+
cd "$REPO_ROOT"
207+
env \
208+
OPENCLAW_STATE_DIR="$STATE_DIR" \
209+
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1 \
210+
OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1 \
211+
script -q -e -c "$rendered_cmd" /dev/null
212+
) >"$logfile" 2>&1
213+
local status=$?
214+
set -e
215+
216+
log INFO "probe=$name exit=$status log=$logfile"
217+
218+
if rg -n "$COMMON_BAD_PATTERN" "$logfile" >/dev/null; then
219+
sed -n '1,220p' "$logfile"
220+
fail "probe '$name' hit the recursion/stack-overflow signature"
221+
fi
222+
223+
if ! rg -n "$required_pattern" "$logfile" >/dev/null; then
224+
if [[ -n "$fallback_pattern" ]] && rg -n "$fallback_pattern" "$logfile" >/dev/null; then
225+
:
226+
else
227+
sed -n '1,220p' "$logfile"
228+
fail "probe '$name' did not emit the expected success/fallback markers"
229+
fi
230+
fi
231+
232+
case "$expected_status" in
233+
zero-or-timeout)
234+
if [[ "$status" -ne 0 && "$status" -ne 124 && "$status" -ne 143 ]]; then
235+
sed -n '1,220p' "$logfile"
236+
fail "probe '$name' expected exit 0, 124, or 143, got $status"
237+
fi
238+
;;
239+
one)
240+
if [[ "$status" -ne 1 ]]; then
241+
sed -n '1,220p' "$logfile"
242+
fail "probe '$name' expected exit 1, got $status"
243+
fi
244+
;;
245+
one-or-timeout)
246+
if [[ "$status" -ne 1 && "$status" -ne 124 && "$status" -ne 143 ]]; then
247+
sed -n '1,220p' "$logfile"
248+
fail "probe '$name' expected exit 1, 124, or 143, got $status"
249+
fi
250+
;;
251+
*)
252+
fail "internal error: unknown expected status policy '$expected_status'"
253+
;;
254+
esac
255+
}
256+
257+
run_probe \
258+
onboard \
259+
"$TIMEOUT_ONBOARD" \
260+
zero-or-timeout \
261+
'OpenClaw setup|Security warning|I understand this is personal-by-default' \
262+
'node scripts/run-node\.mjs onboard|OpenClaw' \
263+
timeout "${TIMEOUT_ONBOARD}s" pnpm openclaw onboard
264+
265+
run_probe \
266+
pairing_approve \
267+
"$TIMEOUT_PAIRING" \
268+
one-or-timeout \
269+
"No pending pairing request found for code: ${PAIRING_CODE}" \
270+
'node scripts/run-node\.mjs pairing approve|OpenClaw' \
271+
timeout "${TIMEOUT_PAIRING}s" pnpm openclaw pairing approve "$PAIRING_CHANNEL" "$PAIRING_CODE"
272+
273+
run_probe \
274+
channels_login \
275+
"$TIMEOUT_LOGIN" \
276+
zero-or-timeout \
277+
'正在启动微信扫码登录|使用微信扫描以下二维码|如果二维码未能成功展示|等待连接结果|Gateway online' \
278+
'node scripts/run-node\.mjs channels login --channel|OpenClaw' \
279+
timeout "${TIMEOUT_LOGIN}s" pnpm openclaw channels login --channel "$CHANNEL_ID"
280+
281+
log INFO "all probes passed"
282+
log INFO "artifacts kept under: $RUN_ROOT"

0 commit comments

Comments
 (0)