Files
HomeAgent/internal/update/doc.go
JianFeeeee 475aac867b refactor(update): 内核与插件更新合并为 update 子系统(三端共享一个底层)
## 为什么合并(用户口径:更新部分应独立为子系统)

之前 kernelupgrade / pluginupdate 两个包,但它们共享三样东西,
分开写就要各复制一份,然后慢慢不一致:

① **版本比较** —— 合并前共 6 个函数做同一件事:
   kernel 侧 ParseSemver / CmpSemver / versionNewer / trimTagV
   plugin 侧 trimV / isNewer / semverNums(还自带一份正则)
   且**行为不一致**:kernel 侧只挡 len<2,"1.4" 漏过去被填成 1.4.0;
   plugin 侧的正则要求两段所以也漏。两份都把 "1.4" 当合法版本。

② **两阶段交互**(检查 → 确认 → 执行)—— 同一套用户口径。

③ **失败要响亮** —— 都不静默降级。

## 收敛结果

internal/update/
  doc.go     子系统头:职责边界、三端共享契约、为何不分家
  semver.go  ParseSemver / CmpSemver / Newer / TrimTag(**唯一一份**)
  kernel.go  内核升级闭环(解包→校验→备份→替换→重启→复核→回滚)
  release.go GitHub Release 查询
  plugin.go  插件升级(查仓库→拉源码→hmapdev 编译→产物)

三端共享:
  agent 工具(plugin_update / kernel_update)  ┐
  WebAPI(/plugins/update、/kernel/update)    ├─ internal/update
  CLI(homed-upgrade)                         ┘

入口层只做参数解析与结果呈现,不含业务逻辑 —— 否则会出现
"agent 说没有新版、WebUI 却升了级"的分裂状态。

## 合并时抓到的两个真实 bug

① **ParseSemver 只挡 len<2** ⇒ "1.4" 被零值填成 1.4.0,
   「1.4 → 1.4.0」被判完全相同(说"无需升级"),而两者内容未必相同。
   现在要求恰好三段。

② **不认 v 前缀** ⇒ GitHub release tag 全是 v1.4.0 形态,
   CLI 对"当前 v1.4.0 vs 包内 v1.4.0"判不可比、只能退回字符串比较。
   现在 TrimTag 去 v 前缀后再比。

## 新增入口

· plugin_update(agent 工具)+ GET/POST /plugins/update
  —— 两阶段:apply=false 只检查(列出 updatable / no_repo 两类,
     后者是"未声明仓库、无法自动更新"的内置/私有插件);
     apply=true 需显式 plugins=all 或名单(不默认全升)
· kernel_update(agent 工具)+ GET/POST /kernel/update
  —— 两阶段同构;apply 只收本机包路径(URL 下载是 CLI 职责,
     agent 不该在推理中发起长下载)

判据:
· internal/update: Newer / TrimTag / ParseSemver 的边界(含上述两个 bug 的回归)
· pluginmgr 入口层 5 条:检查形状、apply 必须显式给范围、
  kernel apply 必须给 pkg 且指向 homed-upgrade、拒绝目录当包
2026-10-26 01:05:09 +08:00

41 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package update 是 HologramAgent 的**更新子系统**。
//
// ## 职责边界
//
// 只负责"发现新版 + 拿到产物",不负责"装上之后怎么跑":
//
// kernel.go 内核升级:解包 → 校验 → 备份 → 原子替换 → 重启 → 版本复核 → 回滚
// release.go GitHub Release 查询(内核新版发现)
// plugin.go 插件升级:查仓库 → 拉源码 → hmapdev 现场编译 → 产物 .hmap
// semver.go 版本号解析与比较(子系统内唯一一份)
//
// ## 三端共享(架构约束,用户明确要求)
//
// agent 工具(plugin_update / kernel_update) ┐
// WebAPI(/plugins/update、/kernel/update) ├─ 本包
// CLI(homed-upgrade) ┘
//
// 三份实现必然漂移,症状是"agent 说没有新版、WebUI 却升了级"这类自相矛盾的
// 状态。所以入口层只做参数解析与结果呈现,全部逻辑收敛在此。
//
// ## 为什么内核与插件在同一个包里
//
// 它们共享三样东西,分开写就要各自复制一份:
//
// 1. **版本比较** —— 合并前 kernel 侧有 ParseSemver/CmpSemver/versionNewer/
// trimTagV,plugin 侧有 trimV/isNewer/semverNums,共 6 个函数做同一件事,
// 且行为不一致(kernel 侧会把 "1.4" 判不可比,plugin 侧的正则却漏过去)。
// 2. **两阶段交互**(检查 → 确认 → 执行)—— 同一套用户口径。
// 3. **失败要响亮** —— 都不静默降级:查不到就说查不到,编译失败给日志尾部,
// 替换失败自动回滚。
//
// 分家的代价是这三样各复制一遍,然后慢慢不一致。
//
// ## 与既有升级通道的关系
//
// 不新造安装逻辑:
// · 插件产物交给 pluginmgr.installFromPath(保留配置、原地覆盖)
// · 内核重启走 sdk.KernelControlAPI(guard 重拉,不经 systemd)
// 本包只管到"产物就绪"为止。
package update