pi 2026-09-14(两封)提的六条,能做的都做了。
1. **`[Empty]` 不是"没有设备",是第三态**(pi §1)。改了,而且不是改成"一律红",
是**去证服务端健康**:探针现在读 `/proc/<pid>/cmdline` 找 `hdc -m`(server 模式),
服务端在 → 空集才是可判的"确实没有目标"(false);服务端找不到 → `unknown`(红)。
本机实测:`hdc -m -s ::ffff:127.0.0.1:8710` 在跑 → 空集可信。
这条用机制而不是用嘴回答"我检查过了"。
2. **硬编码候选清单**(pi §2):候选来源写清(`/opt/huawei/command-line-tools` 是文档安装根),
`hdc` 也走 PATH;**工具链根在、里面却没有 hdc → `unknown`**("装了但长得不一样"不是"没装")。
这与 build.sh 那次"第一个命中就算"是同一形状 —— 今天各咬一次。
3. **前提改成"本工作区能装能点"**(pi §2):原前提"设备存在"会让 5 条判据在**我修不了**的时候同时红
(模拟器要写 /run、/var/log)。现在前提是工作区能力,`need` 逐条写清,
并且**到期报文会把这些门槛打出来** —— 第一次真红不能被当成噪音消掉。
4. **broken ≠ red**(pi §3):跑不起来(语言级崩痕:SyntaxError/ReferenceError/…)单列
"跑不起来的判据(N)—— 不是红,也不算过",红是"判据说不成立",broken 是"判据没说话"。
变异验证:注入未定义标识符 → 报 broken ✓;绿基线 → exit 0 ✓。
第一版我用"输出里有没有 `not ok`"判,当场误判(node:test 把导入期 ReferenceError 也报成 `not ok`),
已改成语言级崩痕 —— 判据自己的第一版就得被现实修一次。
5. **标签要有消费点**(pi §4):`release-linux.sh --release` 遇脏树**拒绝**(`--allow-dirty` 才放行),
不加参数是自用打包(只出声)。"出声≠拒绝"这条说得对。
6. **`deploy/install.sh --check` 干跑**(pi §6):跑全部门禁、不写系统目录,末尾列出正式安装会写什么、
需要哪里的权限。干跑立刻抓到两个真缺陷:
· `set -u` 下 `$HOME` 未设 → `HOME: unbound variable`(cron/env -i/某些 sudo 下就是没有),
而它发生在**所有门禁跑完之后**——最贵的位置(这轮第三次同形状,前两次在 homeagent build.sh)。
· **packaging 这条门在部署路径上永远过不去**:install.sh 先 `npm test`(含 packaging),
而 packaging 要求"安装包里的 dist == 当前 dist",部署路径却不重新打包 →
前端一改,install.sh 就卡在这条门上(第二条"挂在部署路径上却恒红"的门,第一条是 check-shared-libs)。
这条需要决定:部署路径要么重新打包、要么把 packaging 排除在部署门禁外。**我没有擅自改口径。**
63 lines
3.5 KiB
Bash
Executable File
63 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
#
|
||
# 发布 Linux 包:**构建成功才打包**。
|
||
#
|
||
# 为什么要有这个脚本(而不是在命令行里手打两步):
|
||
# `npm run build 2>&1 | tail -4 && electron-builder …` 这种写法里,
|
||
# pipeline 的退出码取的是**最后一个命令**(`tail`)的 —— 构建失败、`&&` 照走、
|
||
# 打包器拿**旧的 dist** 打了个新包,而所有判据都是绿的
|
||
# (vitest 绿、packaging 绿:它比的是 dist 与包,两边都是旧的,自然一致)。
|
||
# 那是真实发生过的一次(见 test/build-stamp.test.mjs 与计划文档 §7.20)。
|
||
#
|
||
# 两道门,互不替代:
|
||
# - `set -euo pipefail` + 顺序调用:**构建失败就不打包**(喂退出码,真正的门);
|
||
# - `dist` 比 `src` 新那条判据:**探测器**,抓"src 改了而产物没跟上"。
|
||
# 注意它抓不到"构建失败但已经碰过 dist"—— 实测过,那种情况它是绿的。
|
||
#
|
||
# 构建只有一条路:走 `npm run build`(= `gen:bg` + `vite build`)。
|
||
# 这里原来写的是裸 `vite build`,那会**跳过 gen:bg**(背景接管用的 CSS 生成步骤),
|
||
# 于是生成物缺失/过期时打包器照打不误。
|
||
#
|
||
# 两个环境变量是给判据用的接缝(test/packaging.test.mjs 会注入一个失败的构建,
|
||
# 断言它**真的会停下**且不进入打包):
|
||
# AGENTMAIL_BUILD_CMD / AGENTMAIL_PACK_CMD
|
||
set -euo pipefail
|
||
|
||
BUILD_CMD="${AGENTMAIL_BUILD_CMD:-npm run build}"
|
||
PACK_CMD="${AGENTMAIL_PACK_CMD:-npx electron-builder --linux -c.electronDownload.isVerifyChecksum=false}"
|
||
|
||
mkdir -p .tmp
|
||
export TMPDIR="${TMPDIR:-$PWD/.tmp/${DSH_SESSION_ID:-$(id -un)-$$}}"
|
||
mkdir -p "$TMPDIR"
|
||
|
||
echo "[release] 构建:$BUILD_CMD"
|
||
bash -c "$BUILD_CMD"
|
||
|
||
echo "[release] 打包:$PACK_CMD"
|
||
bash -c "$PACK_CMD"
|
||
|
||
# 产物自报来源:把 BUILD_INFO 打进日志(pi 提的"一个包要自带它对应哪个源码状态")。
|
||
# 出问题时先看这几行:包是在哪个提交、哪份源码指纹上构建的,以及当时树干不干净。
|
||
# `--release` = "这个包是给别人装的":脏树**拒绝**(pi §4 的消费点)。
|
||
# 不加这个参数是**自用打包**:只出声、不拒绝(共享树上脏是常态,天天拒会让人绕过它)。
|
||
if [[ "${1:-}" == "--release" && -f dist/BUILD_INFO.json ]]; then
|
||
if grep -q '"releaseCandidate": *false' dist/BUILD_INFO.json 2>/dev/null; then
|
||
echo "[release] 拒绝:工作树是脏的,这个包**不是发布候选** —— 它可能含着别人未提交的半成品。" >&2
|
||
echo "[release] 给人装请先提交/清理;确实要发就说清楚:$0 --release --allow-dirty" >&2
|
||
[[ "${2:-}" == "--allow-dirty" ]] || exit 1
|
||
echo "[release] (--allow-dirty:你显式接受了这个风险)" >&2
|
||
fi
|
||
fi
|
||
if [[ -f dist/BUILD_INFO.json ]]; then
|
||
# "脏树打的包"必须**看得见**(pi §1):共享树上脏是常态,所以不做成红,
|
||
# 但要在日志里明说这个包不是发布候选(含别人未提交的半成品时不能给人装)。
|
||
if grep -q '"releaseCandidate": *false' dist/BUILD_INFO.json 2>/dev/null; then
|
||
echo "[release] ⚠ 这个包不是发布候选(releaseCandidate=false):构建时工作树是脏的。"
|
||
fi
|
||
echo "[release] 产物来源:$(cat dist/BUILD_INFO.json | tr -d '\n' | sed 's/ */ /g')"
|
||
else
|
||
echo "[release] 警告:dist/BUILD_INFO.json 不存在 —— 构建没走 npm run build?(判据会红)" >&2
|
||
fi
|
||
|
||
echo "[release] 完成:dist 与安装包同批(这一句只在两步都成功后才出现)"
|