Commit Graph
7 Commits
Author SHA1 Message Date
jkooe b7f44f7a64 feat(scripts): na-gui 陈旧计划任务白名单清理(ARCH B-P1-6)
历史版本在被控端上注册过 na-gui 等旧名计划任务,漏删会留下「端口被占、
新版本起不来」的幽灵任务。误删用户自己的任务则是比漏删严重得多的
生产事故 —— 故只按白名单删。

- scripts/lib/scheduled-tasks.mjs(新):TASK_WHITELIST(nodeagent /
  na-gui / nodeagent-console,只增不改)+ planTaskCleanup 纯函数
  (查询结果注入,白名单外一律不删、精确匹配大小写敏感、重复名去重)。
- scripts/uninstall.ps1:卸载末尾按白名单逐个注销(-ccontains 存在性
  检查 + 动作进日志)。
- scripts/control.ps1:新增 cleanup 子命令(ValidateSet + Clear-StaleTasks),
  Uninstall-Agent 复用同一白名单;control.cmd 菜单加第 8 项
  (CRLF 安全插入,纯 ASCII 不变)。
- tests/unit/na-gui-cleanup.test.mjs(新,10 例):白名单命中才删 /
  白名单外零动作 / 空列表 / 重复名 / 脏输入 + ps1 源码守卫与跨端
  一致性守卫(白名单 mjs 与 ps1 漂移即红 —— 注入故障实测 2 处变红,
  恢复后全绿)。
2026-10-26 01:01:05 +08:00
jkooe cb468df7da feat(agent): 看门狗自动恢复 LKG —— 启动连续失败 N 次从 LKG 恢复(决策 R-1)
scripts/startup-guard.mjs + scripts/lib/startup-guard-core.mjs(新增):
- 被控端启动连续失败 N 次(默认 3)自动从 LKG 指纹匹配的备份恢复入口脚本
- 30s 启动宽限期 + 端口探活,避免计划内重启与 supervisor 重启撞车被误计数
- 无 LKG / 无指纹匹配只记日志放行,绝不擦除 install-dir
- 恢复成功或服务已就绪均归零失败计数;被控端启动成功后 resetStartupGuardState 归零
  (apps/agent/src/index.ts 为本任务对 agent 的唯一改动点)

三端 supervisor 接入:
- Windows install.ps1:计划任务包一层 guard,RestartCount 3→10(保证阈值可达)
- Linux install-linux.sh:systemd unit 的 ExecStart 包一层 guard
- macOS launchd:无安装器,docs/DEVELOPMENT.md §7.4 给出完整接法

docs:DELIVERY-PIPELINE §6 由「不做自动回滚」收窄为
「手动 rollback + 看门狗自动恢复 + 边界明示」,附录 C 同步;
DEVELOPMENT.md 新增 §7.4 三端 supervisor 接入说明。
2026-10-26 00:09:56 +08:00
jkooe 6adf11c85a fix(test): 两条守卫在 Windows 上必红(CRLF 与路径分隔符)
CI run 38380306200(提交 73ed06f)Windows 单元测试 319/321,macOS 全绿。

① 仓库内全部版本号互一致 → 报 undefined apps/console/src-tauri/Cargo.lock
   根因:actions/checkout 在 Windows 默认 core.autocrlf=true → CRLF,
   而 Cargo.lock 的版本提取把 \n 写死。**同一隐患也在生产代码里**:
   version-write.mjs 另有一条 name…\nversion… 正则读旧值,CRLF 下返回
   undefined → 把 Cargo.lock 记入 skipped 并跳过 → 发版后滞留旧版本
   (正是本模块要消灭的分叉,且不报错)。
   修法:读旧值收敛到 readCargoTomlVersion / setCargoLockVersion().before
   单一真源,删掉重复正则;新增 splitLineEol() 拆「正文+行尾」后改写
   (不能写 ("".*)$ 兜行尾 —— JS 的 . 不匹配 \r)。

② W-01 根因守卫 → 把唯一真源自己判成违规(util\quote.ts)
   根因:file.slice(dir.length+1) 在 Windows 得到反斜杠路径,与白名单
   的 util/quote.ts 比不中 → 守卫自己错。
   修法:新增 relPosix() 归一成 /。

新增 4 条守卫:Cargo.lock / Cargo.toml 的 CRLF 纯函数用例、
CRLF 工作区上真跑 writeVersionEverywhere 再读回文件、
以及用 path.win32 形态字符串在 macOS 上直接测 Windows 分支。
注入故障实测 4 条如期变红;test:unit 325/325(321 + 4)。
2026-10-13 18:57:04 +08:00
jkooe bce11514a9 fix(release): 发版脚本漏改 Cargo 清单导致版本号分叉
release.mjs patch --dry-run 实测:只改 8 个 package.json + 1 个 tauri.conf.json,而
apps/console/src-tauri/{Cargo.toml,Cargo.lock} 里**同样存着 2.0.2** —— 发版后必然滞留,
与 tauri.conf.json 悄悄分叉,且**不报错**(Tauri 打包以 tauri.conf.json 为准)。

- 版本写入抽成 scripts/lib/version-write.mjs(纯函数、可测),release.mjs 调用它。
  抽出来的理由:埋在脚本里时单测只能断言「源码里出现过某个字符串」—— 那种守卫注入
  故障都不会变红(铁律:守卫要落在最终产物字节上)。
- Cargo.toml **只在 [package] 段**改(非 package 段里也可能有独占一行的 version = "…");
  Cargo.lock **按 [[package]] 块 + crate 名定位**(全文盲替换会改坏 thiserror 2.0.21
  这类依赖版本)。
- release.mjs 的「脏文件白名单」改为取自**实际改写结果**(changed),不再手写文件名列表 ——
  手写的那份一旦与写入逻辑漂移,要么拦下本该放行的(发版卡死),要么放过不该放行的
  (静默推走改动)。
- 新增 tests/unit/version-write.test.mjs(9 条):在临时目录铺**真实文件**并 git init/git add
  (versionTargets 走 git ls-files,不真进索引就会假绿),跑完读回文件断言;另含一条
  **仓库版本号一致性守卫**,发版漏项会直接变红。
- 注入 4 处故障实测:编排漏 Cargo / Cargo.toml 全文盲替换 / Cargo.lock 按位置盲改 /
  仓库版本分叉 —— 全部变红,还原后全绿。
2026-10-13 17:16:46 +08:00
jkooe a0be43d76c refactor(pack): 被控端 esbuild 配置抽为单一实现
`agent.mjs` 现在有两个消费方:
  1. scripts/pack.mjs            → Windows 便携包 / 自更新载荷(Release 资产)
  2. scripts/prepare-console.mjs → 桌面控制台的随包资源(控制台要能托起本机被控端)

若各写一份 esbuild 配置就是「两套真相」——改了一处漏另一处时构建过、单测过,
只在真机产物里暴露(本项目已多次吃过这类亏)。故配置只此一份。

bundle-agent.mjs 导出 repoRoot / repoVersion / gitShortCommit / bundleAgent,
沿用原有全部约束:JS API(pnpm 隔离布局下 .bin/esbuild 在 Windows 不存在)、
不注入构建时间(否则每次打包字节不同,指纹比对失真)、
define 用 JSON.stringify 得纯双引号。

本次对 pack.mjs 的输出无语义变化(同一份 options 原样迁移)。
2026-10-11 11:41:38 +08:00
jkooe 5e6231493e fix(pack): Windows 打包条目带目录前缀 —— 与 macOS 产物结构不一致
CI 在 f85acad 上红了:`✗ zip 内未找到条目 node.exe: release/nodeagent-win-x64.zip`
(而本地 macOS 全绿 —— 方向恰好相反)。根因是两平台用了不同打包器:

- macOS/Linux: `cd <dir> && zip -r <out> .`       → 条目是裸名 `node.exe`
- Windows    : `Compress-Archive -Path '<dir>\*'` → 条目带前缀 `<dir>/node.exe`

两处一起修:

1. `scripts/lib/zip-pe-arch.mjs`:条目名匹配改用 **basename**,兼容两种打包方式。
   已用构造的带前缀 zip 实测通过,并注入错架构验证守卫仍会红。
2. `scripts/pack.mjs`:Windows 分支改用 .NET `ZipFile::CreateFromDirectory`
   —— 它打包**目录内容**,条目同样是裸名,从根上消除两平台产物结构差异。
   否则 CI 校验的产物与发布产物**不同构**,校验本身的价值打折;
   且「解压后双击 install.cmd」的说明会因多一层目录而失配。

教训:**「本地全绿」≠「Windows 绿」** —— 平台差异只有真 runner 能暴露(第 N 次实证)。
2026-10-11 10:32:41 +08:00
jkooe f558e3e7df chore(release): 交付物架构断言 + CHANGELOG 归置 v2.0.2
已公开发布的 nodeagent-win-arm64.zip 内装的其实是 x64 的 node.exe
(两包内 node.exe 字节完全相同,PE Machine 均为 0x8664),该包在 ARM Windows 上
能启动、能 listen,却 TLS 握手不完成 —— 被控端实际不可用,而 macOS 侧 100% 复现不出。

- 新增 scripts/lib/zip-pe-arch.mjs:纯内置 zlib 手解 zip、读 PE 头判架构。
  不依赖 unzip / Expand-Archive(Windows runner 上没有 unzip)。
  含 CLI 自检入口,已注入故障实测会红(arm64 包去要 x64 期望 → 退出码 1)。
- release.mjs:生成资产前调用之,不符即中止发版 —— 拦在 tag/push 之前,
  是「交付物本身」的断言,与 pack.mjs 的「流程内部」断言分两层。
- windows-e2e.yml:把原先内联的 PowerShell 校验实现改为复用同一模块,
  消除两套实现各自漂移的可能。
- CHANGELOG:[未发布] 归入 v2.0.2。
2026-10-11 10:17:30 +08:00