permission-mode / relay-key / permission-grants / sse-client 的 实现与测试一并同步 —— 档位语义与决策判定若分叉,「同意」在 ZCode 上 会悄悄变成另一种意思。
116 lines
5.0 KiB
Bash
Executable File
116 lines
5.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 共用模块必须逐字节相同 —— 见 docs/PLUGIN-CONTRACT.md 第六节。
|
||
#
|
||
# 一侧改了另一侧没改,几个平台的行为就会悄悄分叉:同一封邮件在 opencode 那边
|
||
# 标了已读、在 DSH 那边没标,而两处代码看起来都"对"。
|
||
#
|
||
# 比对一律以 opencode 为基准逐个对比,而不是两两对比:后者在三方都不同时
|
||
# 会打出三条互相矛盾的差异,读的人无从判断谁是对的。
|
||
#
|
||
# # 为什么每个 peer 的清单不同
|
||
#
|
||
# 四个插件共用的是**协议无关**的那几个模块(地址解析、收件箱渲染、附件 id 归一…),
|
||
# 但各自用到的子集不同:
|
||
#
|
||
# - pi / dsh / opencode 是邮件驱动的**桥**,需要会话快照、中继去重、SSE 客户端等;
|
||
# - zcode-mail-bridge 目前是 **MCP 工具服务器**(模型侧的工具面),
|
||
# 不订阅 SSE、不管会话生命周期,所以只需要那 5 个协议无关模块。
|
||
#
|
||
# 用「对等清单」会逼它拷一份用不到的 relay/session 模块进来 —— 那些文件
|
||
# 永远不会被执行,却要跟着一起同步,反而让「哪些是真的共用」变得看不清。
|
||
# 于是改成显式列举:**声明共用就必须逐字节相同**,声明之外的模块不检查
|
||
# (因为根本没拷过来,结构上就不可能分叉)。
|
||
set -euo pipefail
|
||
BASE=plugins/opencode-mail-bridge
|
||
PEERS=(plugins/dsh-mail-bridge plugins/pi-mail-bridge plugins/zcode-mail-bridge)
|
||
|
||
ALL_LIBS="relay-dedup relay-policy relay-key permission-mode bounded inbox-format session-snapshot workspace model-scope catchup addressing discovery rename-proposal permission-grants adopt sse-client user-question attachment-ids"
|
||
ALL_TESTS="relay-policy relay-key permission-mode bounded inbox-format session-snapshot workspace model-scope catchup addressing discovery rename-proposal permission-grants adopt sse-client user-question attachment-ids"
|
||
|
||
# MCP 工具服务器 + 授权钩子用到的子集(实现与测试都同步)。
|
||
# 钩子这一层额外需要 permission-mode / relay-key / permission-grants / sse-client ——
|
||
# 档位语义、relay_key 截断、决策判定与 SSE 帧解析都必须与三桥同源,
|
||
# 否则「同意」的含义会在 ZCode 上悄悄变得不一样。
|
||
MCP_LIBS="addressing inbox-format bounded discovery attachment-ids permission-mode relay-key permission-grants sse-client"
|
||
MCP_TESTS="addressing inbox-format bounded discovery attachment-ids permission-mode relay-key permission-grants sse-client"
|
||
|
||
# ── 判据:用 cmp,不用 diff ─────────────────────────────────────────
|
||
#
|
||
# 本机 PATH 上的 `diff` **不是 GNU diff**,而是鸿蒙 SDK 工具链里的
|
||
# /opt/huawei/harmonyos/ohos-sdk/linux/toolchains/diff。它不认 `-q`,
|
||
# 却对**内容不同的文件照样返回 0** —— 于是 `if ! diff -q ... >/dev/null`
|
||
# 恒为假,整支脚本变成永真输出(本检查器曾长期如此,实测才发现)。
|
||
# cmp 的语义明确:相同 0、不同 1。
|
||
same() { cmp -s "$1" "$2"; }
|
||
|
||
# 判据本身必须先被验证。否则「比较永远说相同」与「真的都相同」
|
||
# 在结果上完全一样,而这正是上面那个坑的形状。
|
||
selfcheck() {
|
||
local a b
|
||
a=$(mktemp) && b=$(mktemp)
|
||
printf 'x\n' >"$a"
|
||
printf 'y\n' >"$b"
|
||
if same "$a" "$b"; then
|
||
echo "检查器自检失败:比较函数无法发现差异(别用 PATH 上的 diff)" >&2
|
||
exit 1
|
||
fi
|
||
printf 'y\n' >"$a"
|
||
if ! same "$a" "$b"; then
|
||
echo "检查器自检失败:相同内容的两个文件被判为不同" >&2
|
||
exit 1
|
||
fi
|
||
rm -f "$a" "$b"
|
||
}
|
||
selfcheck
|
||
|
||
libs_for() {
|
||
case "$1" in
|
||
*zcode-mail-bridge) echo "$MCP_LIBS" ;;
|
||
*) echo "$ALL_LIBS" ;;
|
||
esac
|
||
}
|
||
|
||
tests_for() {
|
||
case "$1" in
|
||
*zcode-mail-bridge) echo "$MCP_TESTS" ;;
|
||
*) echo "$ALL_TESTS" ;;
|
||
esac
|
||
}
|
||
|
||
# 差异明细也走 cmp,不借 diff。
|
||
show_diff() {
|
||
cmp "$1" "$2" 2>&1 | head -3
|
||
}
|
||
|
||
fail=0
|
||
|
||
for peer in "${PEERS[@]}"; do
|
||
for f in $(libs_for "$peer"); do
|
||
if [[ ! -f "$peer/lib/$f.js" ]]; then
|
||
echo "共用模块缺失:$peer/lib/$f.js" >&2
|
||
fail=1
|
||
continue
|
||
fi
|
||
if ! same "$BASE/lib/$f.js" "$peer/lib/$f.js"; then
|
||
echo "共用模块已分叉:lib/$f.js($BASE vs $peer)" >&2
|
||
show_diff "$BASE/lib/$f.js" "$peer/lib/$f.js" >&2
|
||
fail=1
|
||
fi
|
||
done
|
||
# 测试同样要同源:共用模块的行为约定写在测试里,
|
||
# 只同步实现不同步测试,等于允许一侧偷偷放宽约定。
|
||
for f in $(tests_for "$peer"); do
|
||
if [[ ! -f "$peer/test/$f.test.mjs" ]]; then
|
||
echo "共用测试缺失:$peer/test/$f.test.mjs" >&2
|
||
fail=1
|
||
continue
|
||
fi
|
||
if ! same "$BASE/test/$f.test.mjs" "$peer/test/$f.test.mjs"; then
|
||
echo "共用测试已分叉:test/$f.test.mjs($BASE vs $peer)" >&2
|
||
fail=1
|
||
fi
|
||
done
|
||
done
|
||
|
||
[[ $fail -eq 0 ]] && echo " 共用模块四方同源(opencode 基准 vs dsh / pi / zcode)(判据已自检)" || exit 1
|