Conversation
- children 分两种形态:remote(按 operation 懒拉取,原行为)与 static(宿主 直接渲染的功能子节点,零请求展开)。`kind` 缺省即 remote,旧 manifest 无需改动; 旧宿主因 `deny_unknown_fields` 会拒绝 `kind`/`items`,所以新声明装进旧宿主是 解析期硬失败,而不是静默少渲染一层 - 注册期按 `kind` 分别校验且两形态字段互斥:remote 要求 operation/itemsPath/ labelPath,static 要求至少一个 item 且不得声明这些字段。静态项 id 同层唯一、 不得含控制字符(节点键是父键 + 分隔符 + 行键,控制字符会让键无法再拆回去)、 open 目标页必须存在;嵌套深度上限 8 - 新增 10 个注册期用例覆盖上述约束,并补 static 形态的解析用例、把旧断言改为 兼容新的 Option 化字段 验证:cargo test -p extension-runtime(215 passed)。另用真实 ES manifest 走 ExtensionRuntimeCatalog::from_manifests 全量注册校验通过,并把某个静态项的 pageId 改成不存在的页面复核过会被拒。
- 行模型归一:TreeChildRow 同时携带 open 与 children,remote 行与 static 项 在渲染层不再分叉;静态项在本地直接物化,不进 dispatcher(零请求展开) - 展开意图(tree_expanded)与子节点缓存(tree_children)分离:折叠只删展开集合, 缓存留着,来回展开不再重拉 - 迟到响应按请求代次(tree_load_seq + tree_load_generation)判归属,刷新时保留 展开态并分批恢复(tree_pending_expand),避免刷新把树打回收起 - 箭头与整行语义分离:箭头是独立点击目标并 stop_propagation,整行点击只导航; 键盘 right/left 展开折叠、enter/space 激活 - 补失败重试与刷新入口(刷新图标用 RotateCw —— gpui_component::IconName 是精选 子集,没有 RefreshCw) - 新增用例:静态项无 provider 行也能成行、同级静态项各带自己的 open、静态项 parent 绑定解析到索引行、remote 行仍带集合 open、静态子项先于 dispatcher 物化、 键盘动作与鼠标语义一一对应 验证:cargo test -p resource_view(45 passed)。
macOS arm64 二进制 177,369,216B → 112,557,680B(-36.5%)。 1. [profile.release] lto=thin→fat、codegen-units=16→1、panic=abort。 __eh_frame 16.0→0.07MiB、__gcc_except_tab 8.6→0.02MiB、 __unwind_info 2.8→0.29MiB,展开元数据共省约 27MB。 代价:release 下 catch_unwind 不再拦 panic(terminal 录制 observer、 windows_rdp_host event 回调);dev/test profile 不变,测试照样跑。 2. extension-wasm 只用 async/cache/component-model/cranelift/gc/runtime/std/ threads,wasmtime 与 wasmtime-wasi 都关 default-features; wat 解析器移入 dev-dependencies(只有 fixtures/*.wat 测试用)。 掉包:wiggle、wiggle-generate、wiggle-macro、witx、wast、leb128。 3. bundle-macos-dmg.sh:按 staging 目录实际大小显式 -size(首次 +512MB, 重试逐次放大),制完删 staging 拷贝。hdiutil 自动估算偏小时会报 "No space left on device",与磁盘剩余空间无关(已本地复现)。
- release profile 已是 fat LTO + panic=abort,输入项说明还写着 thin LTO。 - 构建后 ls -lh 打出二进制体积,方便在日志里发现体积回归。 - .gitignore 补本地 DMG/tar.gz 产物(bundle-macos-dmg.sh 写在仓库根)。
release profile 改成 panic=abort 后,`catch_unwind` 观察不到 panic, 这个断言会直接把测试进程 abort。加 #[cfg(panic = "unwind")]: dev/test profile(CI 的 `cargo test --all`)照常跑,release 下跳过。 验证:`cargo test --release -p universal-plugins --lib` 21 passed; dev 下 `--list` 仍包含该用例。
彩色图标走 gpui-component 的 img() 分支,按 SVG 固有尺寸栅格化并乘 SMOOTH_SVG_SCALE_FACTOR(2),再缓存进 App 的 asset cache。28 个 SSH 图标 固有尺寸为 1024x1024,单个解码后 2048x2048x4 = 16 MiB,一次渲染约 1.3 GiB (CPU BGRA + resvg pixmap + GPU 纹理),关闭窗口也不释放。 将 28 个 *_color.svg 根标签 width/height 改为 48,viewBox 保持 1024, 单个约 36 KiB。新增 icon_assets_are_not_oversized 测试,限制图标固有 尺寸不超过 256,防止回归。Refs #185
LLM HTTP 客户端对每个请求设置了 reqwest 总超时(timeout),而 reqwest 的总超时覆盖响应体读取,导致单轮流式响应(思考/CoT、工具循环)超过 120s 就被中途中断,表现为「模型流式输出失败」、任务跑不完。 改为按读超时(read_timeout)+ connect_timeout:只要字节持续到达就永不 中断,只在真正停滞超过阈值时失败。 - HttpClient::new / with_config 统一走 build_http_client,去掉 ClientBuilder::timeout - 新增回归测试:健康长流跨过 idle 阈值仍收完;真停滞仍超时报错
新增跨平台系统托盘,关闭主窗口时隐藏到托盘并保留标签页/连接/后台任务。 - 新增 main/src/system_tray.rs:基于 tray-icon 的托盘桥接。菜单事件通过 set_event_handler + channel 异步消费(MenuEvent::receiver() 与 set_event_handler 互斥),前台任务用 recv().await 而非阻塞 recv();TrayIcon 全平台 !Send, 以 thread_local! 保活,避免 drop 后图标消失。 - 新增 main/src/window_visibility.rs:hide/show_main_window 平台适配,macOS 走 objc2-app-kit orderOut:/makeKeyAndOrderFront:,Windows 走 ShowWindow + SetForegroundWindow,Linux X11 走 x11rb unmap/map(Wayland 退化 minimize_window)。 - 关闭策略抽成纯函数 main_window_close_action(tray_ready),托盘不可用时回退到既有 退出确认。 - 主窗口恢复拆成两段:main_window_target(GPUI 借用内只读原生句柄)+ show_main_window(借用外改原生状态)。在 cx.update_window 借用内同步调用 makeKeyAndOrderFront:/NSApplication::activate 会让 AppKit 同步回调 on_active_status_change 重入 App 借用,产生 gpui::window: RefCell already borrowed。 新增守卫测试 native_restore_runs_outside_the_gpui_window_borrow 钉住该纪律。 - main.rs: QuitMode::LastWindowClosed -> Explicit,窗口隐藏不再终止进程。 - onetcli_app.rs: request_active_window_quit 增加主窗口句柄回退,隐藏到托盘后 无 key window 时显式退出仍能落到主窗口走确认流程;托盘退出复用既有 request_window_quit,不直接 cx.quit()。 - raw-window-handle 0.6 无默认特性,显式开启 std(否则 HandleError 不实现 StdError)。 验证:cargo build -p main / cargo test -p main 624 passed; macOS 真机冒烟(NAVOP_TRAY_SMOKE=1 隐藏->恢复)0 条 RefCell 报错, CGWindowList 逐秒取样主窗口 onscreen true -> nil -> true。 Linux X11 分支经探针 crate 在本机编过;Windows 分支本机无法编译,交 CI matrix 覆盖。
设计稿与落地代码在四处已不一致,按实现真相修正: - 后端选择:macOS/Windows/Linux 统一用 tray-icon(Linux 走其 ksni feature), 不再是「Linux 用独立 ksni crate」两套后端。 - window_visibility 签名去掉 cx: &mut App;恢复路径改为两段式 (main_window_target 借用内 + show_main_window 借用外),并说明原因: 在 GPUI 借用内同步调用 makeKeyAndOrderFront/NSApplication::activate 会让 AppKit 同步回调 on_active_status_change 重入 App 借用。 - 图标处理:改为解码 PNG 并缩放到 32px RGBA,不再手写 ARGB32 变换。 - 测试策略:补充源码守卫清单(关闭策略、菜单/点击映射、图标解码、 thread_local 保活、命令通道分离、原生恢复在借用之外)。
fast 之前用 CARGO_PROFILE_RELEASE_LTO=false,发出的包体积回到旧档。 改为 thin + codegen-units=16(与 arm_linux 分支一致),构建仍远快于 fat。 验证:release.yml YAML 解析通过;未跑实际 fast 构建。
重复注册原来用 assert! panic,测试靠 catch_unwind 观察,并加了 #[cfg(panic = "unwind")] 跳过:release profile 是 panic = "abort",没有展开 可捕获,该用例会把测试进程 abort,release 下等于没有覆盖。 register_application_owner 改为返回 Option,init 用 expect 保留「这是 bug」 的强语义,测试直接断言 is_none(),去掉 cfg。同时给两处 catch_unwind 注明在 abort 下是死代码,并确认被包住的主体本身 panic-free:terminal 录制 observer 只 wake pane,RDP 原生事件回调只做前缀校验 + enqueue。 验证:cargo test -p universal-plugins --lib 21 passed; CARGO_PROFILE_RELEASE_LTO=false CARGO_PROFILE_RELEASE_CODEGEN_UNITS=16 cargo test --release -p universal-plugins --lib 21 passed(panic 仍取 profile 的 abort); cargo clippy -p universal-plugins --all-targets 干净; cargo test -p windows_rdp_host 140 + 39 passed。
component fork 的 Windows 原生菜单固定 resvg 0.45.1,gpui-pre 用 0.46.0, 每个下游二进制都链两份 usvg/tiny-skia。fork 侧 6df86ef8 把 resvg 提到 0.46.0, navop 侧 rev 跟到 6df86ef8(含 rquickjs)。 同时清掉脚本/文档里改名前的 gpui-ce 标识: - sync-gpui-component.sh 的 -p 包名(原值实跑报 did not match any packages) - update_gpui_component_revision.py 的包名映射 - gpui-component-external.md 的旧仓库地址与 rev - gpui-shell-extension-design.md / home-theme-sidebar-refinement.md 的旧包名与 rev 验证:Cargo.lock 里 resvg/usvg/tiny-skia/tiny-skia-path 各只剩 1 个版本; cargo check -p main 通过;resvg 调用序列探针对 0.46.0 编译通过。 未跑 Windows 构建:唯一调用点是 native_menu/windows.rs(Windows 专用)。 已知遗留:update_gpui_component_revision.py 仍不能跑(依赖行需含 gpui-component.git + version =,SHELL_VERSION_FILES 锚点已不存在)。
在内置 Agent 设置中新增「模型请求空闲超时(秒)」,默认 120,范围 10-3600, 用于兜底之前写死的 120s 空闲超时;超时按每次读空闲计算,不限制请求总时长。 - AiChatSettings.request_timeout_secs(serde 缺省 + 超界 clamp) - ProviderManager 持有该值并在变更时清 provider 缓存; GlobalProviderState::set_request_timeout_secs - LlmConnector::from_config_with_proxy_and_timeout 贯通超时(ClientOptions) - 设置项改动后同步 ProviderState 并通知界面重建 provider - 启动时从设置注入 ProviderState
v0.18.0 尚未发布,把 tag 之后的用户可见改动并入该版本: - 修正 Shell 页描述:32 位 Windows 产物不带 Shell 页(quickjs JIT 不支持 32 位) - 新增:关闭主窗口最小化到系统托盘;资源工作台树支持静态子项 - 修复与优化:AI 流式请求改用空闲读超时(可配置);SSH 彩色图标内存暴涨; 发布体积缩小(二进制约 -36%,DMG 68MB → 56MB) 同步 docs-site 中/英/繁三个「当前版本」摘要。 验证:python3 script/changelog.py validate --tag v0.18.0; python3 -m unittest script.tests.test_changelog(12 passed)。
实测 onetcli.log 在 48 天内涨到 1.2G(672 万行)且无任何轮转。日志文件本就 不该无界增长,而用户很可能在出问题时才发现磁盘被吃掉。 - 新增 LOG_FILE_MAX_BYTES = 64MB:log_file_appender 在打开文件之前先检查大小, 超限就把当前文件改名为 <文件名>.1(覆盖上一份),再新建同名文件继续写。 只保留一份历史,磁盘上限约 128MB。 - 轮转放在打开之前,因此本次写入始终落到干净文件;改名走 inode,即使另有实例 正持有旧文件也不会丢日志(对方继续写 .1)。轮转失败只记 warn,绝不挡住日志。 - 新增两个行为测试:超限必轮转且新文件为空、未达上限绝不轮转(后者防止 过于激进地丢日志)。 验证:cargo test -p main 627 passed(含两个新用例);cargo clippy -p main --all-targets exit 0 且本文件 0 诊断;rustfmt 本文件改动区域 clean。
日志文件里每行都裹着颜色转义序列——形如 <ESC>[2m<时间><ESC>[0m <ESC>[32m INFO<ESC>[0m <ESC>[2mtarget<ESC>[0m<ESC>[2m:<ESC>[0m 消息。 肉眼看是乱码,grep 也过滤不干净。原因是 init_tracing 里写文件的那一层用的是 fmt::layer() 默认配置,而它默认 with_ansi(true),会把终端样式码一并写进文件。 - 写文件的那一层显式 .with_ansi(false);终端那一层保留颜色,不受影响。 - 新增源码守卫测试,锁定「文件层关 ANSI,且只关这一层」。 验证(探针 crate 复刻同样的两层构造,写真实文件后按字节判据,含变异对照): - 文件层关 ANSI ⇒ 0 行含 0x1b,产出 `2026-09-17T08:14:50Z INFO ansiprobe: plain text probe count=7` - 对照:开着 ANSI ⇒ 2 行含 0x1b,形态与线上日志逐字节一致 ⇒ 探针具备检出能力 - cargo test -p main 628 passed(含新守卫);cargo clippy -p main --all-targets exit 0
实测 48 天可到 1.2G。打开日志前先检查大小,超过 LOG_FILE_MAX_BYTES(64MB) 就把旧文件改名为 `<文件名>.1`(覆盖上一份),本次写入落回干净文件;改名走 inode,因此另有实例持有旧文件时也不会丢日志。轮转失败只意味着体积不收敛, 不阻断日志写入。 验证:cargo check -p main 通过。
按迁移审计 docs/migration/onetcli-to-navop-audit.md「可稍后整理的内部命名」 完成这批内部重构: - crate `crates/onetcli_runtime` → `crates/navop_runtime` - 文件 `main/src/onetcli_app.rs` → `main/src/navop_app.rs`; `crates/core/src/llm/onet_cli_provider.rs` → `navop_provider.rs` - 类型 `OnetCliApp` / `GlobalOnetCliApp` / `OnetCliLLMProvider` → `NavopApp` / `GlobalNavopApp` / `NavopLLMProvider` - `refresh_onetcli_models`、`spawn_onetcli_model_refresh`、 `ONETCLI_MODEL_REFRESH_*` → navop 命名 - 日志文件 `onetcli.log` → `navop.log` - Windows 集成脚本里的 `__OnetCli*` 全局名 → `__Navop*` - 同步 CLAUDE.md / AGENTS.md 的入口路径与类型名 有意保留的历史命名(审计结论):`ProviderType::OnetCli` 及其序列化值 `"onet_cli"`(已写入本地配置与云端)、升级兼容入口(`OnetCli.app`、 `onetcli.exe`、Linux Provides/Replaces/Conflicts)、公开 `ONETCLI_*` 环境变量、bundle id `com.onetcli.app`、历史文档。 验证:cargo check --workspace --all-targets 通过; cargo test -p navop_runtime 69+7+7 passed; cargo test -p one-core --lib llm:: 24 passed; cargo test -p main 628+1+1 passed; cargo clippy -p navop_runtime -p main --all-targets 无错误。
这三条断言在之前的发布 profile 改造后就没跟上,CI(ci.yml 会跑 `node --test script/test-release-packaging.mjs`)一直是红的: - 超时:改为断言统一的 `timeout-minutes: 180`(原表达式已删除) - Cargo.toml:`lto = "thin"`/`codegen-units = 16` → `lto = "fat"`/ `codegen-units = 1`,并补 `panic = "abort"` - Windows 构建:feature 已收进 `$features` 数组,改断言 `"windows-native-rdp"`(原 `--features windows-native-rdp` 不再出现) 验证:node --test script/test-release-packaging.mjs 全绿。
日志文件改为 navop.log 并在超过 64MB 时轮转,属于本次发布的用户可见改动。 验证:python3 script/changelog.py validate --tag v0.18.0; python3 -m unittest script.tests.test_changelog 12 passed。
- 左键/右键都打开托盘菜单(原先左键只恢复窗口),移除左键→显示主窗口的 TrayIconEvent 派发 - 菜单新增「会话」段,最多 8 项、标题 40 字符截断;随 TabContainerEvent 重建 - 会话项按 id 激活:用主窗口 handle 切换,避免刚恢复时 active_window 为空 - 托盘点击相关 info 日志降为 debug
- rustfmt 重排:home_tab、persistent_connection_sidebar、connection_visuals、 setting_tab、settings/agent_settings、personal_sync_runtime 等,无逻辑改动 - main/locales/main.yml:设置页「日志目录或文件」说明里的 onetcli.log → navop.log,与 LOG_FILE_NAME 改名保持一致
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
内容
本次 PR 把
dev上的 v0.18.0 发布内容合入main(main/Cargo.toml已为0.18.0,tag 尚未重指),并包含 tag 之后的用户可见改动:navop.log超过 64MB 自动轮转(保留一份.1),避免长期使用撑到 GB 级。img路径内存暴涨(收缩固有尺寸);macOS DMG 制作显式给出镜像大小并清理 staging。crates/onetcli_runtime→crates/navop_runtime、main/src/onetcli_app.rs→navop_app.rs、OnetCliApp等类型改名;有意保留持久化/升级兼容/公开的OnetCli、onet_cli、ONETCLI_*、com.onetcli.app。验证(本地)
cargo check --workspace --all-targets通过cargo test -p main630 passed;cargo test -p navop_runtime69+7+7;cargo test -p terminal -p ai_chat_view448 + 496 passedcargo test -p universal-plugins --lib(dev 与 release profile)各 21 passedpython3 script/changelog.py validate --tag v0.18.0;python3 -m unittest script.tests.test_changelog12 passednode --test script/test-release-packaging.mjs全绿cargo clippy -p navop_runtime -p universal-plugins -p main --all-targets无错误发布步骤(合并后)
FORCE_RETAG=true script/release-tag.sh v0.18.0 # 删除远端旧 tag 并重指到 main HEADtag push 会触发
release-trigger.yml→release.yml(platform=all, build_mode=release)→ 8 平台构建并创建 GitHub Release。