pi 2026-09-14 两件: 1. **登记册真的没有**。我上封信说"已写进 test/CRITERIA.md 的已知限制一节"——**不成立**, 只有 `appearance-defaults.test.mjs` 里有那段注释。已在 CRITERIA.md 补 §9「已知限制」 (标识符只解析一层;静态判据的到期前提是"本工作区能装能点")。 过度声明自己做过什么是这轮反复出现的那一类错,这次是同一个形状的又一例。 2. **新建 §10「缺省语义登记处」**(pi 的更正:不是无条件 fail-closed,而是"缺了的后果必须 有人登记 + 写明谁批准了这个方向")。三条入库,各带依据: · 邮件 `permission_mode` 缺 → **不写、不改档**(窄),依据是本轮那个 `|| 'workspace'` 兜窄档的坑; · HomeAgent `plugin.json.sdk` 缺 → 内核**不读**(不是语义,是文档),依据内核 manifest.go 结构体 + registry.go; · HomeAgent `capabilities` 缺 → **不受限**(宽),依据内核注释明写的理由:17 个存量清单都没有它。 3. `build/BUILD_INFO.txt` 现在**原文贴入** `go version -m <内核>` 的输出,并附"这两行怎么读" (`dep … vX.Y.Z` 后面跟 `=> … (devel)` 时那串版本号只是 require 行残留;`=>` 必须按模块名联接)。 理由:这场争论的全部内容就是这两行该怎么读,原始证据必须和结论放在一起。
124 lines
7.6 KiB
Bash
Executable File
124 lines
7.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 构建 homeagent-mail-bridge —— 用**明确指定的** SDK 源码,并记录"这次到底用了哪份代码"。
|
||
#
|
||
# # 这份脚本被改过一轮,因为它的第一版判错了根因(pi 2026-09-14 晚逐条反驳)
|
||
#
|
||
# 第一版的错:把 `go version -m <内核>` 里的
|
||
# dep ... homeagent-sdk v0.9.2 / => ./third_party/homeagent-sdk (devel)
|
||
# 当成"内核链的是 0.9.x 血脉",然后按候选根目录**第一个命中就算**去解析 SDK 源码,
|
||
# 命中的是 `/root/ha-test/third_party/homeagent-sdk`(C-ABI 时代的老 checkout,无 plugin.bin 支持)。
|
||
# 而本机共有 6+ 份同名 checkout,内核自己用的是 1.3.0 那份。两个教训:
|
||
#
|
||
# ① **不要用"第一个存在的路径"当权威来源** —— 猜根目录会命中不相关的 checkout,
|
||
# "两条血脉"于是成了脚本的产物,而不是事实;
|
||
# ② **不要把模块版本字符串当身份** —— `replace => local (devel)` 时那个版本号
|
||
# 只是 require 行的文本残留,不代表实际编译的代码。
|
||
#
|
||
# 所以现在:SDK 源码**只认显式指定**(`HOMEAGENT_SDK_DIR`)。
|
||
# 不猜、不试探、不"第一个命中"。要指定内核的构建目录就显式传进来。
|
||
#
|
||
# # 不变量是什么
|
||
#
|
||
# 不是"版本号相等"(那正是第一版想抛弃的东西),而是 **wire 协议 + 一次真实握手**:
|
||
# 产物要能被内核 `protocol=2` 认下来。这个脚本能做的是"把身份记清楚 + 把明显不对的挡下来",
|
||
# 真握手由内核启动时完成(所以部署后要回看一次日志,见末尾提示)。
|
||
set -euo pipefail
|
||
|
||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
SDK_MODULE="gitcode.com/JianFeeeee/homeagent-sdk"
|
||
KERNEL_BIN="${HOMEAGENT_KERNEL_BIN:-/usr/local/bin/homed}"
|
||
|
||
die() { echo "构建失败:$*" >&2; exit 1; }
|
||
|
||
# cron/非登录 shell 里 HOME 可能没设,Go 会因此拒绝工作(曾经在这里栽过)
|
||
export HOME="${HOME:-/root}"
|
||
export GOPATH="${GOPATH:-$HOME/go}"
|
||
export GOCACHE="${GOCACHE:-${TMPDIR:-/tmp}/go-build-agentmail}"
|
||
mkdir -p "$GOCACHE"
|
||
|
||
# ── 1. SDK 源码:只认显式指定 ───────────────────────────────────────
|
||
[[ -n "${HOMEAGENT_SDK_DIR:-}" ]] || die "必须显式指定 SDK 源码树:HOMEAGENT_SDK_DIR=/path/to/homeagent-sdk
|
||
为什么不让脚本自己猜:本机有 6+ 份同名 checkout(有的是 C-ABI 时代的老代码),
|
||
第一版按候选根目录'第一个命中就算',命中了 /root/ha-test 那份老 checkout,
|
||
于是把'内核链老血脉'这个**错误结论**当成了事实写进注释。猜路径 = 制造事实。"
|
||
|
||
SDK_DIR="$(cd "$HOMEAGENT_SDK_DIR" && pwd)"
|
||
[[ -f "$SDK_DIR/go.mod" ]] || die "$SDK_DIR 不是 Go 模块(没有 go.mod)"
|
||
|
||
# 身份用 **realpath + 内容哈希**,不用版本字符串(版本号可能是 -ldflags 注入的默认值,
|
||
# 也可能是注释里的示例 —— 后者我在 electron 侧的判据里刚踩过一次)。
|
||
SDK_HASH="$(find "$SDK_DIR" -type f -name '*.go' -print0 2>/dev/null | sort -z | xargs -0 cat 2>/dev/null | sha256sum | cut -c1-16)"
|
||
SDK_VER="$(sed 's://.*::' "$SDK_DIR/meta/meta.go" 2>/dev/null | grep -m1 -oE 'Version = "[0-9]+\.[0-9]+\.[0-9]+"' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || true)"
|
||
echo "[build] SDK 源码:$SDK_DIR"
|
||
echo "[build] meta.Version(已剥注释)= ${SDK_VER:-未知} | 内容哈希 = ${SDK_HASH:-未知}"
|
||
|
||
# 内核签名的**提示**(不是判据):按模块名精确联接,不按"输出里第一个 =>"。
|
||
# "两张表各缺一半时必须按 id 联接"—— 读 go version -m 的输出同理。
|
||
if [[ -x "$KERNEL_BIN" ]]; then
|
||
KERNEL_INFO="$(go version -m "$KERNEL_BIN" 2>/dev/null || true)"
|
||
KERNEL_SDK_LINE="$(awk -v m="$SDK_MODULE" '$1=="dep" && $2==m {print NR": "$0}' <<<"$KERNEL_INFO" | head -1)"
|
||
if [[ -n "$KERNEL_SDK_LINE" ]]; then
|
||
KERNEL_SDK_DEP="$(cut -d' ' -f3 <<<"${KERNEL_SDK_LINE#*: }")"
|
||
# 只接受**紧跟在 SDK 那一行之后**的 => 行(按位置配对的唯一正确写法)
|
||
KERNEL_SDK_REPL="$(awk -v m="$SDK_MODULE" '
|
||
$1=="dep" && $2==m {want=NR+1}
|
||
want && NR==want && $1=="=>" {print $2; exit}' <<<"$KERNEL_INFO")"
|
||
echo "[build] 内核 $KERNEL_BIN 的 dep 行:$KERNEL_SDK_DEP${KERNEL_SDK_REPL:+(本地替换 $KERNEL_SDK_REPL)}"
|
||
echo "[build] 注意:这条只是**提示**,不是判据 —— replace 到本地目录时这个版本号只是 require 行的残留,"
|
||
echo "[build] 而且它指向的相对路径未必是本机这份源码。要对齐请显式传 HOMEAGENT_SDK_DIR。"
|
||
fi
|
||
fi
|
||
|
||
# ── 2. 用临时 modfile 替换,不改动受版本管理的 go.mod ───────────────
|
||
cd "$HERE"
|
||
TMP_MOD="$(mktemp -d)/go.local.mod"
|
||
cp go.mod "$TMP_MOD"
|
||
go mod edit -modfile="$TMP_MOD" -replace "$SDK_MODULE=$SDK_DIR"
|
||
export GOFLAGS="${GOFLAGS:-} -modfile=$TMP_MOD"
|
||
|
||
# 注意:这个插件**没有** `func main()`(入口由 hmapdev 生成/包装),
|
||
# 所以 `go build ./...` 会报 "function main is undeclared" —— 那是正常的,
|
||
# 不能用它来数 API 兼容性错误;真正的编译在 hmapdev 那一步。
|
||
# 这条工具会**重写 plugin.json/plg.json**(实测:只把文件末尾的换行吃掉了)。
|
||
# 构建不该把源码树弄脏 —— 在 electron 那边我们刚为同一形状定过规矩
|
||
# (脏树产物不得自称发布候选)。所以:先记哈希,构建后若被改就还原并出声。
|
||
MANIFESTS=(plugin.json plg.json)
|
||
SNAP_DIR="$(mktemp -d)"
|
||
for f in "${MANIFESTS[@]}"; do [[ -f "$f" ]] && cp "$f" "$SNAP_DIR/$f"; done
|
||
hmapdev build || die "hmapdev build 失败(编译错误见上;它才是真正的编译入口)"
|
||
for f in "${MANIFESTS[@]}"; do
|
||
[[ -f "$SNAP_DIR/$f" ]] || continue
|
||
if ! cmp -s "$SNAP_DIR/$f" "$f"; then
|
||
cp "$SNAP_DIR/$f" "$f"
|
||
echo "[build] 注意:hmapdev 改写了 $f(已还原)—— 构建工具不该动受版本管理的源码;"
|
||
echo "[build] 否则每次构建都把树弄脏,而'脏树'在别的端已经是'不是发布候选'的判据了。"
|
||
fi
|
||
done
|
||
rm -rf "$SNAP_DIR"
|
||
|
||
# ── 3. 产物自报身份 ─────────────────────────────────────────────────
|
||
BIN="build/plugin.bin"
|
||
[[ -f "$BIN" ]] || die "没找到产物 $BIN"
|
||
echo "[build] 产物:$BIN($(stat -c%s "$BIN") 字节)"
|
||
echo "[build] 本次身份:SDK=$SDK_DIR hash=$SDK_HASH version=${SDK_VER:-未知}"
|
||
# 原始证据与结论放在一起(pi 2026-09-14):这场争论的全部内容就是
|
||
# "`dep` 行与 `=>` 行该怎么读",把两行原文贴进来,下一个人不必重演。
|
||
cat > build/BUILD_INFO.txt <<EOF
|
||
sdkDir=$SDK_DIR
|
||
sdkHash=$SDK_HASH
|
||
sdkMetaVersion=${SDK_VER:-unknown}
|
||
builtAt=$(date -Iseconds)
|
||
|
||
# --- 以下是 \`go version -m $KERNEL_BIN\` 的原文(原样,不改写)---
|
||
${KERNEL_INFO:-(取不到:$KERNEL_BIN 不可读或 go 不在 PATH)}
|
||
|
||
# 怎么读这两行(这一轮踩过的坑):
|
||
# · \`dep <mod> vX.Y.Z\` 后面若跟着 \`=> <dir> (devel)\`,那个 vX.Y.Z 只是 require 行
|
||
# 的**文本残留**,不代表实际编译用的代码;本次的 SDK 源码以上面的 sdkDir/sdkHash 为准。
|
||
# · \`=>\` 必须按**模块名联接**读取(先定位 SDK 的 dep 行,只接受紧跟其后那条),
|
||
# 不能取"整份输出里第一个 =>"。
|
||
EOF
|
||
echo "[build] 已写 build/BUILD_INFO.txt —— 部署后请回看内核日志确认握手:"
|
||
echo " grep -a 'mail-bridge' /home/newqqagent/log/homed_*.log | tail -5"
|
||
echo " (判据不是版本号相等,而是 protocol=2 建链成功、且没有崩溃重启循环)"
|