Skip to content

feat: 支持 CLI/TUI 程序启动时静默检测新版本与平滑升级#340

Merged
phantom5099 merged 4 commits into
1024XEngineer:mainfrom
pionxe:main
Apr 17, 2026
Merged

feat: 支持 CLI/TUI 程序启动时静默检测新版本与平滑升级#340
phantom5099 merged 4 commits into
1024XEngineer:mainfrom
pionxe:main

Conversation

@pionxe

@pionxe pionxe commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator

📝 动机与背景 (Motivation)

之前用户只能通过手动重新执行 install 脚本来升级版本,且没有任何新版本更新提醒,导致版本迭代和分发效率较低。
本次 PR 引入了原生的自动更新机制(Auto-Update),旨在不阻塞主 TUI 启动、不干扰 AltScreen 渲染的前提下,提供优雅的版本更新体验。
Closes #336

✨ 核心功能 (Key Features)

  1. 后台静默检测:在执行常规命令(排除高频内部调用的 url-dispatch)前,启动带有超时(3s)的异步 Goroutine 检测远端 Release。
  2. 退出后防吞提示:针对 Bubble Tea 的 AltScreen 清屏特性,将更新提示语挂载到 Execute 之后的安全生命周期,确保在 TUI 完全退出后才将提示打印到终端。
  3. 一键手动更新:新增 neocode update 命令。支持自动解析架构、下载 tar.gz/.zip、校验 checksums.txt 并原地替换可执行文件。
  4. 预发布支持:默认更新到 Stable 版本,极客用户可通过 neocode update --prerelease 选择升级到尝鲜版。

🛠️ 技术实现细节 (Technical Details)

  • 版本注入:新增 internal/version 包,修改 .goreleaser.yaml,通过 ldflags -X 在 CI 构建时将 GitHub Tag 动态注入程序。开发模式下默认回退至 dev 并禁用自动提醒。
  • 底层驱动:引入 github.com/creativeprojects/go-selfupdate,处理了复杂的跨平台(特别是 Windows)执行文件覆盖锁问题。
  • 资产正则匹配:精准配置 Config.FiltersConfig.OS/Arch,完美适配我们现有的构建产物命名规则。
  • 【修复】测试顽疾清理:修复了 internal/config 包中 TestLoadCustomProvidersReadDirAndStatErrors 用例在 Windows 环境下因 os.Chmod 无法剥夺目录权限而导致的偶发性/必然性失败,引入了针对性的 t.Skip 跨平台兼容策略。

✅ 测试情况 (Testing)

  • go test ./... 全量绿灯(历史失败用例已修复)。
  • Mac/Linux/Windows 环境下验证原地替换成功。
  • TUI 退出后提示语能够正常打印,且不发生屏幕重叠。
  • --prerelease 标志位路由正确。
  • 本地 dev 版本编译时,不触发网络更新提示。

⚠️ 注意事项 (Notes)

  • Windows Scoop 冲突说明:如果用户之前曾使用 Scoop 安装过旧版本,因为 Scoop shims 的 PATH 优先级极高,且旧版本未注入版本号,可能会导致环境变量覆盖问题。建议在相关文档中提示用户手动清理孤儿垫片 (scoop/shims/neocode.exe)。
  • 文档更新:已在 README.mddocs/guides/update.md 中补充新命令的使用说明。

- 引入 `go-selfupdate`,支持检测 Github Releases 并自动替换二进制文件
- 新增 `internal/version` 包,配合 `.goreleaser.yaml` 注入构建版本号
- 在根命令 `PersistentPreRunE` 挂载异步静默版本检测(屏蔽 `url-dispatch`)
- 优化 TUI 生命周期,利用提示缓冲实现 AltScreen 退出后的更新提醒
- 新增 `neocode update [--prerelease]` 手动升级命令
- fix(test): 修复 Windows 环境下 config 目录权限测试由于 `os.Chmod` 不兼容导致的误报
@codecov

codecov Bot commented Apr 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.61017% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/cli/root.go 91.17% 3 Missing and 3 partials ⚠️
cmd/neocode/main.go 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a few issues worth addressing before merge: one behavior/perf regression around when update checks run, and terminal-output safety concerns for untrusted release metadata.

Comment thread internal/cli/root.go Outdated
if err := runGlobalPreload(cmd.Context()); err != nil {
return err
}
runSilentUpdateCheck(cmd.Context())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runSilentUpdateCheck currently runs for every command except url-dispatch, so neocode update also triggers an extra background release check. That adds an unnecessary second network call and can produce a stale post-exit notice right after a manual update. Consider skipping silent checks for update (and potentially other short-lived utility commands).

Comment thread internal/cli/root.go Outdated
if strings.TrimSpace(result.LatestVersion) == "" {
return
}
setUpdateNotice(fmt.Sprintf("🚀 发现新版本: %s,运行 neocode update 即可升级", result.LatestVersion))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result.LatestVersion comes from remote release metadata and is interpolated directly into terminal output. Please sanitize/strip control characters (especially ANSI escape sequences) before rendering, to avoid terminal escape injection if upstream metadata is ever malformed or compromised.

if latest == "" {
latest = "unknown"
}
_, _ = fmt.Fprintf(out, "Already up-to-date (latest: %s).\n", latest)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

latest (remote metadata) is printed directly to stdout. For consistency with security hardening, sanitize control characters before output (same concern applies to the success line at Updated successfully: ... -> ...).

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused review completed (code quality, performance, security, docs). I found two behavior issues in the new update-check flow worth addressing.

Comment thread internal/cli/root.go
}
return runGlobalPreload(cmd.Context())
if err := runGlobalPreload(cmd.Context()); err != nil {
return err

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runSilentUpdateCheck is invoked for every command that passes preload, including neocode update. That means update can trigger a background check concurrently with the foreground upgrade flow, and may later print a stale "new version" notice even after a successful update. Consider skipping silent check for the update command (similar to url-dispatch).

Comment thread internal/cli/root.go
// defaultSilentUpdateCheck 在后台异步检查新版本并缓存退出后提示文案。
func defaultSilentUpdateCheck(ctx context.Context) {
currentVersion := version.Current()
if !version.IsSemverRelease(currentVersion) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The silent check runs in a detached goroutine and the process does not wait for it before printing/consuming notice at program end. For short-lived commands, this often drops the notice entirely because the process exits first. If the intent is to reliably show a post-exit notice, add a bounded synchronization point or persist the check result for next run.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

发现 1 处需要修正的问题,主要是 update 命令路径上的更新提示时序会产生误导。

Comment thread internal/cli/root.go Outdated
if err := runGlobalPreload(cmd.Context()); err != nil {
return err
}
runSilentUpdateCheck(cmd.Context())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runSilentUpdateCheck 会在所有非 url-dispatch 命令前执行,因此 neocode update 也会并发触发一次“新版本检测”。这会导致一个可见回归:用户刚执行完升级后,进程退出时仍可能打印“发现新版本”的过期提示(静默检查结果比升级动作更早缓存)。建议将 update 也加入跳过名单,或在 update 命令执行路径里禁用/清空该提示。

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

发现 2 个值得修正的问题,主要集中在更新流程的可靠性与阻塞风险。

Comment thread internal/cli/root.go Outdated
if err := runGlobalPreload(cmd.Context()); err != nil {
return err
}
runSilentUpdateCheck(cmd.Context())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PersistentPreRunE 会在执行 neocode update 时也触发 runSilentUpdateCheck,导致一次手动升级流程里并发发起两次 Release 检测请求。这个回归会放大 GitHub API 限流/抖动风险,并可能让前台 update 命令偶发失败。建议在 shouldSkipGlobalPreload(或独立判断)里把 update 命令也加入跳过列表。

}

// defaultUpdateCommandRunner 执行手动升级流程并返回升级结果。
func defaultUpdateCommandRunner(ctx context.Context, options updateCommandOptions) (updater.UpdateResult, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultUpdateCommandRunner 直接沿用 cmd.Context(),而 main 里传入的是 context.Background(),没有超时或取消边界。网络异常时 neocode update 可能长时间阻塞。建议为手动更新增加明确超时(如 context.WithTimeout)并返回可诊断的超时错误。

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体实现和测试覆盖不错,但有 3 处仍建议修正:

  1. update 子命令路径也会触发静默更新检查,可能造成重复请求并在升级后出现过期提示。
  2. 远端版本字符串直接写入终端输出,未清理控制字符,存在终端转义注入风险。
  3. neocode update 使用调用方上下文,未设置显式超时,网络异常时可能长时间阻塞。

Comment thread internal/cli/root.go Outdated
if err := runGlobalPreload(cmd.Context()); err != nil {
return err
}
runSilentUpdateCheck(cmd.Context())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PersistentPreRunEupdate 命令路径也会调用 runSilentUpdateCheck。这会与手动升级流程并发访问 release API,并可能在升级成功后仍输出“发现新版本”的过期提示。建议将 update 加入跳过名单,或在该命令路径禁用静默检查。

Comment thread internal/cli/root.go Outdated
if strings.TrimSpace(result.LatestVersion) == "" {
return
}
setUpdateNotice(fmt.Sprintf("🚀 发现新版本: %s,运行 neocode update 即可升级", result.LatestVersion))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里把远端 LatestVersion 直接拼接进终端输出。若上游字符串包含 ANSI 控制序列,可能导致终端转义注入。建议在展示前统一剥离控制字符(例如仅允许可打印字符,或过滤 ESC/CSI 序列)。

}

// defaultUpdateCommandRunner 执行手动升级流程并返回升级结果。
func defaultUpdateCommandRunner(ctx context.Context, options updateCommandOptions) (updater.UpdateResult, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update 命令直接使用 cmd.Context() 进入网络更新流程,没有显式超时边界。遇到网络劣化/长时间重试时可能阻塞命令。建议在 runner 内包一层 context.WithTimeout(可配置),并在超时时返回可读错误。

- 拦截 `update` 命令的静默检测逻辑,避免与手动升级流程产生并发冲突及输出过期提示
- 新增 `sanitizeVersionForTerminal`,剥离远端版本字符串中的 ANSI 控制序列,防止终端转义注入
- 为 `neocode update` 手动升级命令增加 5 分钟显式超时上下文,并优化网络超时错误提示
- 补全边界场景单元测试(涵盖跳过静默检测、字符串清洗及网络超时触发分支)
@pionxe

pionxe commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator Author

@xgopilot 将internal/security/workspace.go、internal/context/microcompact.go、internal/updater/updater.go、internal/session/store.go、internal/tui/core/app/update.go、internal/subagent/worker.go等文件的测试覆盖率提升至百分之九十五以上

@fennoai

fennoai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

执行结果

已完成并推送提交:fbc5f8a(已推送到 pionxe:main,PR #340 已包含本次改动)。

本次改动

  • 新增/补强 internal/updater/updater_test.go:覆盖 CheckLatestDoUpdate 的异常分支与 selfupdateClient 分支。
  • 新增/补强 internal/security/workspace_test.go:覆盖 capability 校验拒绝、validateWorkspacePlan 错误分支、ValidateForExecution 的额外边界分支、nearestExistingPath/ensureNoSymlinkEscape 的错误路径。

覆盖率结果(目标文件)

  • internal/updater/updater.go: 100.00%(已达成 >95%)
  • internal/security/workspace.go: 91.71%(较基线 86.74% 提升)
  • internal/context/microcompact.go: 95.83%(已满足)
  • internal/subagent/worker.go: 98.26%(已满足)
  • internal/session/store.go: 85.40%(未达 95%)
  • internal/tui/core/app/update.go: 77.37%(未达 95%)

未完成项说明

本次未能将 workspace.gostore.goupdate.go 全部提升到 95%+。其中:

  • update.go 语句体量较大(1454 statements),当前测试虽多但缺口仍大。
  • workspace.go / store.go 存在部分依赖平台或难以稳定触发的防御分支,继续提升需要更大规模的测试重构或对可测性做代码层改造。

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@phantom5099

Copy link
Copy Markdown
Collaborator

@xgopilot 针对本次PR,请给我一份给AIreview用的提示词,针对的是修改中所有可能存在的风险点

@fennoai

fennoai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

AIreview 提示词(可直接复制)

你是资深 Go 代码审查员。请仅基于 origin/main...HEAD 的 diff,对 PR #340(自动更新能力)做“风险导向”审查,不要表扬、不要总结优点,只输出问题与证据。

审查范围文件(重点):

  • internal/cli/root.go
  • internal/cli/update_command.go
  • internal/cli/update_notice.go
  • internal/updater/updater.go
  • internal/version/version.go
  • cmd/neocode/main.go
  • docs/guides/update.md
  • .goreleaser.yaml
  • 相关测试:internal/cli/*_test.go, internal/updater/updater_test.go, internal/version/version_test.go, internal/config/loader_test.go

请重点检查以下风险点(逐项给结论):

  1. 启动生命周期与并发:静默检查 goroutine 是否可能在短命令退出前丢提示;是否存在竞态或时序导致“升级后仍提示有新版本”。
  2. 命令路由正确性:PersistentPreRunE 下静默检查跳过条件是否覆盖所有不应触发的命令(如 updateurl-dispatch),是否引入重复网络请求。
  3. 取消与超时边界:context.WithoutCancelcontext.WithTimeout 使用是否可能造成后台任务悬挂或用户可感知阻塞;update 5 分钟超时是否可配置/可诊断。
  4. 终端输出安全:远端版本字符串是否在所有输出路径都做了控制字符/ANSI 注入防护(包含成功/失败提示、notice 输出)。
  5. 版本语义正确性:dev、空版本、非 semver、prerelease/stable 分支下的比较逻辑是否符合预期,是否会误报/漏报更新。
  6. 跨平台升级可靠性:GOOS/GOARCH 到资产名映射是否与 .goreleaser.yaml 完全一致(含 windows zip、x86_64 命名);是否存在平台遗漏。
  7. 供应链与完整性:checksum 校验是否被正确强制;release 资产筛选正则是否可能误匹配/漏匹配。
  8. 可执行替换风险:ExecutablePath 与原地替换在权限不足、文件被占用、路径异常时的错误处理是否足够可诊断。
  9. 文档与实现一致性:文档是否准确反映代码行为(例如静默检查跳过命令列表)。
  10. 测试有效性:新增测试是否真实覆盖异常分支与回归风险;是否存在仅为覆盖率而缺失行为断言;是否有平台相关 t.Skip 掩盖真实问题。

输出格式要求:

  • 仅输出“发现的问题”;按严重级别排序:Critical -> High -> Medium -> Low
  • 每条问题必须包含:
    • 标题
    • 位置(文件 + 行号)
    • 风险说明(会导致什么错误/安全问题)
    • 触发条件或复现思路
    • 最小修复建议(可执行)
  • 如果某一风险点未发现问题,写“未发现问题(已检查)”。
  • 不要输出与风险无关的风格建议。

说明

上面这份提示词已经按本 PR 的改动内容定制,直接粘贴到 AIreview 即可。

View job run

@phantom5099

Copy link
Copy Markdown
Collaborator

@xgopilot 你是资深 Go 代码审查员。请仅基于 origin/main...HEAD 的 diff,对 PR #340(自动更新能力)做“风险导向”审查,不要表扬、不要总结优点,只输出问题与证据。

审查范围文件(重点):

  • internal/cli/root.go
  • internal/cli/update_command.go
  • internal/cli/update_notice.go
  • internal/updater/updater.go
  • internal/version/version.go
  • cmd/neocode/main.go
  • docs/guides/update.md
  • .goreleaser.yaml
  • 相关测试:internal/cli/*_test.go, internal/updater/updater_test.go, internal/version/version_test.go, internal/config/loader_test.go

请重点检查以下风险点(逐项给结论):

  1. 启动生命周期与并发:静默检查 goroutine 是否可能在短命令退出前丢提示;是否存在竞态或时序导致“升级后仍提示有新版本”。
  2. 命令路由正确性:PersistentPreRunE 下静默检查跳过条件是否覆盖所有不应触发的命令(如 updateurl-dispatch),是否引入重复网络请求。
  3. 取消与超时边界:context.WithoutCancelcontext.WithTimeout 使用是否可能造成后台任务悬挂或用户可感知阻塞;update 5 分钟超时是否可配置/可诊断。
  4. 终端输出安全:远端版本字符串是否在所有输出路径都做了控制字符/ANSI 注入防护(包含成功/失败提示、notice 输出)。
  5. 版本语义正确性:dev、空版本、非 semver、prerelease/stable 分支下的比较逻辑是否符合预期,是否会误报/漏报更新。
  6. 跨平台升级可靠性:GOOS/GOARCH 到资产名映射是否与 .goreleaser.yaml 完全一致(含 windows zip、x86_64 命名);是否存在平台遗漏。
  7. 供应链与完整性:checksum 校验是否被正确强制;release 资产筛选正则是否可能误匹配/漏匹配。
  8. 可执行替换风险:ExecutablePath 与原地替换在权限不足、文件被占用、路径异常时的错误处理是否足够可诊断。
  9. 文档与实现一致性:文档是否准确反映代码行为(例如静默检查跳过命令列表)。
  10. 测试有效性:新增测试是否真实覆盖异常分支与回归风险;是否存在仅为覆盖率而缺失行为断言;是否有平台相关 t.Skip 掩盖真实问题。

输出格式要求:

  • 仅输出“发现的问题”;按严重级别排序:Critical -> High -> Medium -> Low

  • 每条问题必须包含:

    • 标题
    • 位置(文件 + 行号)
    • 风险说明(会导致什么错误/安全问题)
    • 触发条件或复现思路
    • 最小修复建议(可执行)
  • 如果某一风险点未发现问题,写“未发现问题(已检查)”。

  • 不要输出与风险无关的风格建议。

@fennoai

fennoai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

High

  1. 静默更新提示存在“短命令退出即丢失”时序缺陷(风险点 1)
  • 位置:internal/cli/root.go:123internal/cli/root.go:124cmd/neocode/main.go:16
  • 风险说明:静默检查在 goroutine 异步执行,主流程在 Execute 返回后立即 ConsumeUpdateNotice();若检查尚未完成,提示不会输出,导致更新提醒随机丢失。
  • 触发条件或复现思路:让 checkLatestRelease 人为延迟(如 500ms~2s),执行一个快速结束路径(如参数错误立即返回或很快退出的命令路径),可观察到 ConsumeUpdateNotice() 先于 setUpdateNotice() 执行。
  • 最小修复建议:让 runSilentUpdateCheck 返回一个可等待句柄(channel/wait func),在主流程退出前做“短等待+超时”收口;或将提示持久化到会话外存储,在下一次启动时消费,避免单次进程内时序丢失。
  1. update 命令输出路径未做版本字符串终端清洗(风险点 4)
  • 位置:internal/cli/update_command.go:44internal/cli/update_command.go:48internal/cli/update_command.go:52
  • 风险说明:LatestVersion 来自远端 release tag,当前直接写终端;若 tag 含 ANSI/控制字符,可造成终端污染或注入式显示。
  • 触发条件或复现思路:构造包含 \x1b[31m... 的 release tag,执行 neocode update,输出将携带控制序列。
  • 最小修复建议:在 update 成功与“已是最新”两条输出路径统一复用 sanitizeVersionForTerminal(至少对 LatestVersion,建议对 CurrentVersion 也清洗)。

Medium

  1. 更新超时策略不可配置且诊断信息不足(风险点 3)
  • 位置:internal/cli/update_command.go:23internal/cli/update_command.go:63internal/cli/update_command.go:71
  • 风险说明:5 分钟超时硬编码,且超时后返回固定文案,缺少上下文诊断信息(实际错误链/阶段);在慢网或企业网络环境下不利于排障。
  • 触发条件或复现思路:限速网络下触发 context deadline exceeded,用户只能看到泛化提示,无法区分下载慢、校验慢或替换阶段失败。
  • 最小修复建议:将超时暴露为配置项或命令参数(如 --timeout);超时错误用 %w 包装并附带阶段信息,保留可诊断性。
  1. 新增测试未覆盖关键回归场景:提示丢失时序与 update 输出清洗(风险点 10)
  • 位置:internal/cli/root_test.go:1328internal/cli/update_command_test.go:48
  • 风险说明:已有测试验证“能设置 notice”和“update 有输出”,但未验证“主流程消费时机晚于异步检查完成”以及“update 输出防注入”,回归风险未被测试网兜住。
  • 触发条件或复现思路:在测试中让 checkLatestRelease 延迟并模拟快速退出;或让 runUpdateCommand 返回含 ANSI 的 LatestVersion,当前用例不会失败。
  • 最小修复建议:补充两个回归用例:
    • 异步检查慢于 ConsumeUpdateNotice 时应有兜底策略断言;
    • update 输出中不应出现控制字符断言。

Low

  1. 文档与实现不一致:静默检测跳过命令列表缺项(风险点 9)
  • 位置:docs/guides/update.md:7internal/cli/root.go:157
  • 风险说明:文档仅写 url-dispatch 会跳过;实现同时跳过 update。用户会误判 update 前是否会做后台检测,影响行为预期。
  • 触发条件或复现思路:阅读文档后执行 neocode update,实际不会触发静默检测。
  • 最小修复建议:文档补充 update 也在跳过列表内(并说明避免重复网络请求)。

逐项结论(其余风险点)

  • 风险点 2(命令路由正确性):未发现问题(已检查)
  • 风险点 5(版本语义正确性):未发现问题(已检查)
  • 风险点 6(跨平台升级可靠性):未发现问题(已检查)
  • 风险点 7(供应链与完整性):未发现问题(已检查)
  • 风险点 8(可执行替换风险):未发现问题(已检查)

View job run

@pionxe

pionxe commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator Author

/simplify

@fennoai

fennoai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

已完成请求中的三件事:检查未解决 review comment、修复值得修复的问题、执行代码简化并推送。

处理结果

  • 已读取并评估历史 review comments,针对当前仍成立的问题完成修复:
    • internal/cli/update_command.go:对 CurrentVersion/LatestVersion 统一做终端安全清洗,避免 ANSI/控制字符注入输出。
    • internal/cli/root.go:在 Execute 返回前增加静默检查有界收口等待(300ms),降低短命令场景更新提示丢失概率。
    • docs/guides/update.md:文档补齐 update 也会跳过静默检测。
  • 已按“code-simplifier 等效流程”完成简化并落地:
    • 抽取 displayVersionForTerminal,消除重复清洗/回退逻辑。
    • 抽取 normalizedCommandName,消除命令名标准化重复代码。
    • 测试移除时间敏感断言,改为更稳健的事件驱动断言思路。

测试

  • go test ./internal/cli
  • go test ./...
  • 以上均通过。

提交与推送

  • Commit: 6c0338a
  • 已推送到当前 PR 分支:pionxe:main

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@phantom5099 phantom5099 merged commit 6a6e7eb into 1024XEngineer:main Apr 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 支持 CLI/TUI 程序启动时静默检测新版本与平滑升级

3 participants