Repository navigation
Conversation
…alled files authoritative The macOS file clipboard writer published file URLs via writeObjects plus a plain-text path fallback. GPUI's pasteboard reader only restores ExternalPaths from the legacy NSFilenamesPboardType, so the reader saw a plain string: the 500ms local sync echo-pushed the clipboard back to the remote (rdpclip churn: Lock/Unlock PDUs right after every transfer), and Finder had no reliable classic representation to paste from, showing the 'already pasted <date>' text file instead of the real file. Write the legacy filenames property list alongside the modern file URLs (after writeObjects so it is not cleared), and stop honouring remote text announcements while installed files remain the authoritative clipboard content - rdpclip re-announces a copied file's text long after the transfer (observed ~15s), beyond the previous 3s window.
…ssic declareTypes sequence writeObjects(NSURL) publishes no public.file-url in practice here: the pasteboard only ends up with plain-text types, so Finder pastes an 'already pasted <date>' text file and GPUI's reader (which only restores ExternalPaths from NSFilenamesPboardType) falls back to the path string, making the 500ms local-clipboard sync echo the freshly installed files back to the remote as text. Reproduced with a standalone probe: after writeObjects the only types are public.utf8-plain-text/NSStringPboardType, and a following setPropertyList:forType: returns false; with declareTypes + setPropertyList(NSFilenamesPboardType) the pasteboard carries the full file representation (NSFilenamesPboardType, public.file-url, Apple URL pasteboard type). Use that sequence, and log the install at info level so the host side can be verified from navop.log.
冲突表的主键是 (profile, data_type, 云端 record_id),但解决冲突一直硬解
local_snapshot 里存的那条本地行 id。本地行一旦消失(用户在界面里删掉它,
或它被远端墓碑处理顺手删掉),两个按钮就都废了:
使用远程版本 -> personal sync io error: Connection 22 not found or
credential revision exhausted
使用本地版本 -> personal sync parse error: connection not found: 22
而且冲突会永远躺在表里(planner 按 paused_record_keys 跳过它),用户只能
手改 sqlite 才出得来。
三处改动:
1. 解析冲突前按 (data_type, cloud_id) 现场重解析本地条目,与 planner / worker
判定本地条目的口径一致;本地条目已不存在时,「使用远程版本」走插入(远端
胜出),「使用本地版本」把本地删除意图推到云端(tombstone)。
2. 处理远端墓碑时跳过已挂起冲突的记录 —— 之前会把冲突指向的那条本地行照样
删掉,冲突瞬间变悬挂;同时补上「本地自上次同步后改过」的
LocalModifiedRemoteDeleted 分支,连接不再被无条件静默删除(这个枚举以前
从来没被产生过)。本轮新挂起的记录也一并排除出 planner,避免同一次 pass
一边记冲突一边把记录推回云端。
3. 本地删除事件清掉该记录遗留的冲突(sink 新增 forget_record)。
新增用例全部做了变异验证:把对应修复改回旧行为,用例即红。
Refs #361
本地条目被删掉之后,它遗留的冲突就再也解不开了(解析要按云端 id 反查本地 条目);更糟的是这时点「使用远程版本」会把刚删掉的条目重新拉回来。 三处删除入口(连接列表 / 分组侧栏 / 凭据保险库)在删成功、发删除事件之前, 按 (data_type, cloud_id) 清掉冲突。用 sqlite 端到端用例锁住: 只清目标记录,同云端 id 的另一种 data_type 和别的云端 id 都不受影响。 Refs #361
dev HEAD(`ed070f033`)在 CI 的警告门禁下编不过,两处都在这个文件的导入语句上,
与本次要发的改动无关,但会让任何 `dev -> main` 的 PR 直接红:
- `NSFilenamesPboardType` 已 deprecated,而 `#[allow(deprecated)]` 加在函数上
覆盖不到顶层的 `use`,必须单独给这条导入放行(Finder 与 gpui_macos 的
pasteboard 读回都只认这个旧类型来还原 ExternalPaths,不能改成新 API)。
- `NSURL` 只有测试用例在用,非测试构建会报 unused import;改成 `#[cfg(test)]`
导入。
验证:`RUSTFLAGS="-D warnings" cargo check -p remote_desktop_view --all-targets`
通过,全仓 `cargo test --all --no-run` 亦通过。
`LocalDeletedRemoteModified` 这个冲突类型(UI 文案与默认策略早就写好)从来没被 产生过。原因是本地删除事件(`PersonalSyncEvent::LocalDeleted`)只带 data_type + cloud_id,判不出「远端在我们删除之后是不是又被别的设备改过」, 于是 worker 只能无条件把远端记录推成墓碑 —— 对方刚做的改动就被静默抹掉了。 改动: 1. 删除事件带上 `last_synced_at`:删除前那条本地行记录的同步基线(远端 `updated_at` 的秒值,与 planner 判定 remote_changed 的口径一致)。三处删除 入口(连接列表 / 分组侧栏 / 凭据保险库)都在真正删行**之前**把基线读出来, 同时随 `ConnectionDeleted` / `WorkspaceDeleted` / `CredentialDeleted` 事件上抛。 2. `apply_local_delete_events` 分三种情况:远端已是墓碑 ⇒ 无事可做;远端在基线 之后被改过 ⇒ 挂 `LocalDeletedRemoteModified` 并计入本轮冲突数;否则照旧推墓碑。 3. 这种冲突没有本地行,所以 `PersonalSyncRecordConflict.local_id` 改成 `Option<String>`:挂起时只存远端快照,解决时按 (data_type, cloud_id) 现场反查 本地条目(上一提交已经做到「本地条目不存在也能解」)。 验证(本提交单独成立):`RUSTFLAGS="-D warnings"` 下 one-core 个人同步 106 passed、main personal_sync 25 passed;变异验证两个方向都试过 —— 把判决函数改成恒 false(少挂冲突)只有「远端改过要挂冲突」那条转红,改成恒 true (多挂冲突)则 5 条「远端没变要照旧推墓碑」的用例全红。 Refs #361
`acquire_lock` 原来是永远成功、且持有者从不释放的空实现(目录后端只是把 `SyncStoreLock` 造出来,WebDAV 后端的 `_lock` 直接丢掉)。但这两类后端都可能被 同一台机器上的两个 navop 实例,甚至被两台机器通过 Dropbox / iCloud 共享同一个 目标目录指向,那时两边会并发做「读记录 → 改 → 写回」,单文件原子写保不住版本。 改动: 1. `SyncStoreLock` 从「只有 owner 字段的公开结构体」改成不透明的锁句柄,两条释放 路径:本地后端挂 `Drop` 回调(pass 结束、包括提前 `?` 返回都会释放),远端后端 把凭据放在 `token` 里由 worker 显式调 `PersonalSyncStore::release_lock`(`Drop` 里 await 不了)。新增 `store.release_lock` 默认实现,worker 的 `run_pass` 拆出 `run_locked_pass` 以便在 pass 结束后统一释放。 2. 目录后端(Git 后端复用):`create_new` 原子创建锁文件 + nonce + 300s TTL; 已被占且未过期 ⇒ `LockTimeout` 让路;确认过期才抢占,抢占用「临时文件 + rename」 再回读 nonce 确认,两个实例同时判断出「已过期」时只有回读到自己的 nonce 的算抢到。 释放前也比对 nonce,避免 TTL 过期后把别人新拿到的锁删掉。锁文件放在同步包 **之外**(`.onetcli-sync.lock`),否则 Git 后端会把它 `git add` 提交上去。 3. WebDAV 后端:读现有锁 → 阻塞则让路;PUT 自己的锁后**回读确认 nonce**(服务端 普遍没有原子创建,只能靠回读裁决);释放用 PUT `released: true` 而不是 DELETE (有些服务端对 DELETE 直接 405),且只释放 nonce 还是自己的那一次。 4. 锁基础设施本身失败(读不到 / 写不进)一律降级成「本轮不加锁继续」,不把本来 能跑的同步变成失败;`LockTimeout` 也不再被状态栏当成存储故障(它只是这一轮 让路,下一轮自动重试)。 验证:`RUSTFLAGS="-D warnings"` 下 one-core 个人同步 116 passed、main personal_sync 27 passed;变异验证覆盖三处关键判定(目录后端未过期不得抢占、释放 时必须比对 nonce、WebDAV 回读 nonce 不匹配必须让路、释放不得清掉别人的锁、 `LockTimeout` 不得算存储故障),每个变异体都确认**能编译**、且只有对应用例转红。 顺带(仅排版):`PersonalSyncEvent` 的 `LocalDeleted` 因新增第 3 个字段触发了 rustfmt 的枚举变体展开规则,同枚举里的 `LocalChanged` 一并展开。 Refs #361
流水线下载按固定偏移、固定长度(61440 字节)并发读分片,并要求服务端一次 读满。但 SFTP 协议只保证「不超过请求长度」,短读是合法应答:经堡垒机/隧道 (issue #363 是 JumpServer)时服务端会真的只回一部分(请求 61440、拿到 32768),于是整条下载以 `SFTP short read at offset 368640: received 32768 bytes, expected 61440` 失败——报障者看到的正是这个。 改成在同一个分片内按已读到的偏移续读,直到凑满 expected_len:短读被补齐 而不是被当成错误,下游「长度恰好、连续写入」的约定完全不变(连续写、进度 累计、validate_chunk_len 都不用动)。空读(远端提前结束)与「返回超过请求 长度」仍按错误处理,不会静默错位。 验证: - cargo test -p sftp --lib:98 passed(含新增 5 个用例) - RUSTFLAGS="-D warnings" 下无新增告警 - 变异验证 4 个变异体全部被捕获,且都先确认变异体本身能编译: M1 砍掉续读循环 -> a_short_read_is_read_again_until_the_chunk_is_complete 转红 M2 超长响应放行 -> a_read_longer_than_requested_is_rejected 转红 M3 空读当作读完了 -> an_empty_read_is_reported_as_eof_instead_of_looping 转红 M4 EOF 状态码不映射 -> an_eof_status_is_reported_as_eof 转红 - 未验证:真实堡垒机链路(需要 JumpServer 环境);本机无法复现短读。
refresh_tree 会先 clear_node_descendants + reset_node_children 把整棵子树从
db_nodes 里删掉,再异步重新拉取。这期间界面上这个节点是空的:被过滤/搜索命中
的表会连带整条命中分支一起「消失」一下,等懒加载回来才重新长出来(报障者的
截图就是过滤 TOP 之后右键刷新,命中的表瞬时不见)。
改成刷新只清掉「已加载」标记(让懒加载重新拉一次),已有子树继续显示;新数据
到达时才由新的 install_loaded_children 整体替换——先递归回收旧后代、再挂上新的,
所以既不闪烁,也不会在 db_nodes 里留下从根走不到的孤儿节点。clear_node_descendants
的其余调用点(切换库/断连/删节点)行为完全不变。
顺带修好同一根因的另一面:刷新一个**收起**的库/模式节点后,旧实现把 children
清空且 children_loaded=false,而 node_has_children 对 Connection/Database/Schema
直接返回 false ⇒ 该节点再也长不出展开箭头;现在旧子节点还在,箭头与展开都正常,
点开时照样重新拉取。
验证:
- cargo test -p db_view --lib:888 passed / 0 failed;RUSTFLAGS="-D warnings" 无新增告警
- 新增 3 个用例:
refreshing_a_filtered_node_keeps_the_matching_table_visible
(gpui 测试,直接复现报障场景:过滤后刷新,命中的表与列目录必须还在)
installing_new_children_recycles_the_replaced_subtree
(替换要回收旧子树,且不碰其它分支)
removing_descendants_reaches_grandchildren_and_keeps_the_node_itself
(递归回收要挖到孙辈,并保留节点自己)
- 变异验证 4 个变异体全部被捕获,且都先确认变异体本身能编译:
M1 刷新时清空子树 / M2 替换时不回收 / M3 回收不递归 / M4 忘标记已加载
- 未验证:真实 GUI 观感(本机没有可复现的数据库实例,行为由 gpui 测试钉住)
受限设备(华为 S5720 交换机等防火墙/交换机)掐断传输层后不会立刻回收自己
那边的会话记录。原来的降级重连是「失效 transport 后零延迟重连一次」,第二次
往往被同一原因再掐一次,于是错误直接抛到界面上——用户看到的就是
"Connection Lost: ... while a session channel was being opened: Disconnected",
过几秒手动按 Enter 重连又正常(那时设备已经回收了旧会话)。
改动(crates/terminal/src/ssh_backend.rs):
- 退化重连改成有界退避重试:失败后等 1s、3s 再以单个裸交互 channel 重连
(DEGRADED_RECONNECT_BACKOFFS),预算用尽才如实返回错误,不会无限重连;
- 每次重试打一条 warn(attempt / backoff / probe_killed_transport / invalidated /
error),下次同类问题从日志即可确认重试是否发生、是否用尽;
- 重试日志统一到一处,探测掐断传输层与 channel open 被拒不再各自打不同文案;
- 修正 add_connect_error_context 的提示:不再只把用户往「VTY 并发上限」上引
(案发设备自报 10 上限 / 1 在线),改为说明设备会短暂保留已断开的旧会话,
建议几秒后重试,或对该连接勾选「禁用 Shell 集成」。
验证:
- cargo test -p terminal --lib ssh_backend::tests:39 passed / 0 failed
- 新增 2 个用例:
establish_channel_retries_degraded_channel_until_device_releases_session
(探测与紧随其后的重连都被掐断,退避后的重试才拿到交互 channel;
被掐断的 transport generation 每次都要失效)
establish_channel_reports_disconnect_after_degraded_retries_are_exhausted
(重试预算有界:耗尽后如实报错,并仍带可诊断上下文与原始 Disconnected)
- 4 个既有重连用例改在 start_paused 时钟下跑,退避不真实等待(本模块 0.02s 跑完)
- crates/terminal 新增 dev-dependency:tokio test-util(仅为暂停时钟)
- 未验证:真实华为交换机上的首连复现(没有设备,也没有现场日志)
本机 rustfmt 与仓库基线版本不同,`cargo fmt` 在整仓重排了 52 个文件:主要是 `pub mod` / `use` 的排序与少量换行,与本次 SSH 修复无逻辑关联。 已核对:在 HEAD 的临时 worktree 里重跑一遍 rustfmt,它单独改动出来的文件集合 与这 52 个完全一致(两个方向都无差异)⇒ 这些文件相对 HEAD 只差格式化,不含 其它未提交改动。
#363 的修复此前只有「分片续读」这一层的单元测试:`read_chunk_fully` 的入参是 一个闭包,短读是被喂进去的假数据,真实协议往返(open → read → close、并发 分片、按偏移落盘)从未被跑过。这道 e2e 把它补上。 做法:用 `russh_sftp::server` 起一个真的 SFTP 服务端,只把 `read` 覆写成 「一次最多回 32 KiB」(JumpServer 的形态),接在 `tokio::io::duplex` 的另一端, 让 `pipelined_read_into_writer` 走完整协议往返写进临时文件。不开端口、不依赖 网络或外部服务。 - a_short_reading_server_still_yields_a_byte_exact_download 10 个分片(9 满 + 1 残,>512 KB 的流水线阈值)下载后逐字节相等。 用例自带三道「场景真的成立」的断言,避免变成空转:必须真的出现过 「请求 61440 / 只回 32768」、服务端不得回超过请求长度、每个满片只补读一次 (9*2+1 = 19 次读请求)。 - a_well_behaved_server_still_downloads_without_extra_requests 对照组:老实服务端不触发续读(10 个分片恰好 10 次请求),既证明修复没有给 正常链路增加往返,也兜住「假服务端自身是坏的」这种情况。 RED 反证:把 `read_chunk_fully` 的续读退回修复前语义(短读即整条失败)后, 主用例转红并复现报障者那条错 `SFTP short read at offset 0: received 32768 bytes, expected 61440`, 对照组仍绿;已还原。 验证:cargo test -p sftp --lib = 100 passed / 0 failed(新增 2 个); RUSTFLAGS="-D warnings" 无新增告警;两个文件 rustfmt 零偏差。
工具栏上「自动跟随终端目录」和「隐藏文件」两个开关此前只用 bg(hover) 标出开启状态,而 hover 本身就是鼠标悬停色、图标又恒为次要前景色,开与关 几乎长得一样。新增 toggle_icon_color():开启用强调色,关闭退回次要前景色。 另外补一个「定位到终端目录」按钮,方向与既有的「同步终端目录」相反 (面板当前目录 → 终端 cd),复用已有的 FileManagerPanelEvent::CdToTerminal。 不可用时(未连接 / 跨主机目标)置灰并禁用点击。 验证:cargo test -p terminal_view --lib 579 passed / 0 failed; 6/6 变异体被杀(含 payload 漂移、丢掉两个守卫条件、开关恒同色)。
内部工具 id 用 `.` 分层(`ssh.command.poll`),此前原样暴露在 tools/list 里。Grok 注册函数时只接受 [A-Za-z0-9_-],带点的名字被整批丢弃,于是「连上 了却一个工具都查不到」。 ACP 侧早已由 agent_runtime 的 ToolName/ToolNameAllocator 做过净化,只有公开 MCP 服务端漏了。这里复用同一套规则、同一个「先按内部 id 排序」的分配顺序, 所以同一工具在 ACP 与 MCP 两端名字一致,冲突消解(sample.echo 与 sample_echo → sample_echo / sample_echo_2)也可复现。 内部 id 一律不动,只在 PublicMcpToolRegistry 增加对外视图: - client_tools():tools/list 用的清单(名字已净化) - client_tool(name):单个查询 - resolve_client_tool_name(name):回翻成内部 id,同时接受净化名与原始 id, 让仍允许 `.` 的客户端(Claude 等)照旧调用 验证:public_mcp 全部 24 个 target 绿;6/6 变异体被杀(清单退回带点 id、 调用不回翻、丢掉内部 id 回退、对照表不排序、清单不排序、解析优先级反转); 下游 terminal_view / main 的 --all-targets check 通过(-D warnings)。
命令提示 / cd 补全 / 历史搜索共用同一个下拉弹层,其背景此前按 0.72 透明度绘制,下层终端文字以 28% 的权重透进弹层 —— 与弹层自身文字的对比度 同量级,亮色主题下整层内容几乎不可读(issue #73 截图反解:弹层内透出的 目录蓝 = 0.72×背景 + 0.28×文字,与常数完全吻合)。 0.72 是 issue #5 时代为「不遮挡终端内容」从 0.88 特意调低的,属于同一个 弹层的两个相反诉求。现在取 0.96:透出权重 28% → 4%(降为 1/7),弹层文字 恢复可读,同时保留少量下层内容痕迹,不回到 #5 抱怨的完全遮挡观感。 补源码断言锁住渲染层必须走治理 helper,不允许裸用背景色。 验证:cargo test -p terminal_view --lib 579 passed / 0 failed; 3/3 变异体被杀(退回 0.72、改成 1.0、渲染层绕过 helper)。
命令提示 / cd 补全 / 历史搜索共用同一个下拉弹层,其背景此前是一个写死的 0.72 常量:issue #5 嫌它遮挡终端内容,把它从 0.88 调低到 0.72;而 0.72 会 透出 28% 的下层文字,与弹层自身文字的对比度同量级,亮色主题下整层几乎不 可读(issue #73,截图像素反解与常数完全吻合)。两个诉求相反,任何一个常数 都无法同时满足,因此改成用户在终端侧边栏设置里自己定,默认 0.96(透出 4%)。 链路共 6 段,每段都有源码锚点测试锁住,避免任何一环漏接导致静默失效: AppSettings::terminal_suggestion_popup_opacity(新字段,默认 0.96、范围 0.5–1.0,normalize 兜住手改 settings.json 的越界与 NaN) → TerminalSettings::from_parts → 终端侧边栏设置面板「弹层背景不透明度」滑块(拖动中只重绘百分比读数, 松手才写回设置,避免一路拖动把 settings.json 写十几遍;候选词开关关掉时 滑块置灰) → SettingsPanelEvent/TerminalSidebarEvent → TerminalView::set_suggestion_popup_opacity → 回灌视图(apply_settings_snapshot 同步侧边栏与 self) → history_prompt_dropdown_background(background, opacity) 验证:cargo test -p terminal_view --lib 583 passed / 0 failed; cargo test -p one-core --lib 788 passed / 0 failed; 6/6 变异体被杀(helper 退回写死 0.96、渲染层改用写死 0.72、老配置缺字段 回落到 0.0、normalize 不再夹紧、from_parts 写死、不回写 settings.json); 改动文件 rustfmt 零偏差。
面板原先把最多 1000 条记录(每条一个 Popover + Button)全量铺进 element 树,约两万个元素。打开「执行记录」后 SQL 编辑器每敲一个字都要重建它们, 表现为「每打一个字卡一下」,清空记录后立刻消失。 - 列表换成 uniform_list,只渲染可见的十来行;行高抽成固定常量 EXECUTION_RECORD_ROW_HEIGHT(按钮 88 + 行间距 8)—— uniform_list 要求 所有行等高,又不支持 item 间距,行间距只能并进行高里。 - 「过滤 + 倒序」的下标映射抽成纯函数 visible_record_indices,渲染回调只按 原始下标回查记录,不再为整份列表克隆记录(sql/details 都是字符串)。 - render_record 改回 AnyElement:impl IntoElement 会捕获入参生命周期,让 uniform_list 回调的返回类型收敛不到单一的 R,编译不过。 - 补 4 条契约测试:3 条源码锚点(虚拟化 + 固定行高 + 按下标回查)+ 1 条 「过滤后仍保留原始下标」的行为测试。变异 6/6 被杀。
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.
Closes #73
Closes #194
Closes #359
Closes #362
Closes #363
Description
dev → main集成分支汇总,共 16 个提交(另含一次 main 回合并fdfe845a7)。91 files changed, 3700 insertions(+), 634 deletions(-)。1. 终端(terminal_view)
66cd7a88c+10237c5d0)命令提示 /
cd路径补全 /Ctrl+R历史搜索共用的下拉弹层,背景以0.72的不透明度绘制,下层终端文字以 28% 权重透进弹层,亮色主题下弹层自身文字几乎不可读([Feature]: 命令提示的配色是否可以优化一下,透明的都看不到了 #73)。
先把写死值压到
0.96(透出 28% → 4%),再做成终端侧边栏设置面板里的「弹层背景不透明度」滑块(范围
0.5–1.0,默认0.96)。终端命令提示框,及vim光标 背景色太深遮挡终端内容 #5(嫌弹层太遮挡)与 [Feature]: 命令提示的配色是否可以优化一下,透明的都看不到了 #73(嫌弹层太透)是同一个弹层的相反诉求,可配置是唯一能同时满足的做法。
f69526596):开关状态可辨,并补上「定位到终端目录」。7cd6de826):目标设备尚未回收旧会话时不再直接报错。2. public_mcp —— 线上工具名净化(#194,
508e98c0b)MCP 客户端把工具名里出现
[A-Za-z0-9_-]之外字符(例如ssh.command.poll中的点)的名字判定为非法并整批丢弃,表现为「Grok build 连上了 MCP 却拿不到任何工具」。
PublicMcpToolRegistry增加一层对外视图(client_tools/client_tool/resolve_client_tool_name):tools/list只暴露净化后的名字,tools/call同时接受净化名与内部原始 id,registry 内部 id 一律不变。
3. sftp —— 短读不再让整条下载失败(#363,
7a4fa5cad+9bc237cdb)跳板机场景下 SFTP 一次读只回 32 KiB(请求 61440),原实现按整块长度校验,
短读即判定失败并终止整条下载。改为按实际返回长度推进,并补一条协议层回归测试:
用
tokio::io::duplex()把真服务端与客户端在同一进程里对接,假服务端一次只回32 KiB,复现 #363 的短读路径(含对照组,防止用例空转通过)。
4. db_view —— 刷新节点不再先清空子树(#362,
bcede3b2c)过滤状态下点刷新会先清空子树再拉取,导致被过滤掉的表短暂「消失」。
5. personal-sync(4 个提交)
4c8fe22ce)30b25a6d0)034fb8230)663a6571e)6. remote_desktop_view —— macOS 文件剪贴板(3 个提交)
72782fcb4+ed070f033:改用经典declareTypes序列写入 macOS 文件剪贴板,并发布
NSFilenamesPboardType,让「已安装的文件列表」保持权威,避免远端迟到的文本通告把它覆写成纯文本;
a4007dfe7消掉-D warnings拦下的两处告警。7. 其他
76cb55f6f:rustfmt重排 52 个文件,无逻辑改动。fdfe845a7:回合并main,带入 feat: 增添字段的注释显示开关设置, 而非鼠标悬浮在列名上才显示 #365(字段注释显示开关,作者 @ekovovo)。该开关默认关闭,列头保持单行;开启后在列头下方常驻一行字段注释并把列头加高一行。
Screenshot
本次改动以终端 / 表格 UI 行为为主,未附截图,以下为文本对照(非视觉 diff):
How to Test
本地实测结果(合并
main之后重跑):cargo check --workspace --all-targets(-D warnings)通过,无 error / warningone-core789 passed /one-ui892 passed(1 ignored)/db_view123 /terminal_view583 /main661 + 1 + 1 —— 全部0 failedmain回合并无冲突弹层不透明度一项另做了变异验证(6/6 变异体被测试杀死):helper 退回写死 0.96 /
渲染层绕过 helper / 旧配置缺字段回落
0.0/ normalize 不再夹紧 /from_parts写死 /不回写
settings.json。Checklist
cargo runfor story tests related to the changes.—— navop 本体无 story 测试机制(story 在 gpui-component 仓),本 PR 未涉及;改用
cargo check --workspace --all-targets+ 上述 crate 单测覆盖。—— macOS 剪贴板改动只在本机 macOS 上编译与单测验证,Windows / Linux 未实机验证。
AI Assistance
本 PR 是
dev集成分支的汇总,其中相当一部分修复与测试由 AI(WorkBuddy)辅助产出,均已逐行人 review 并跑本地测试:
#73的不透明度可配置链路(设置字段 →TerminalSettings映射 →侧边栏滑块 → 事件 → 视图回灌 → 渲染 helper,共 6 段接线)及其源码锚点测试;
#194的client_tools/client_tool/resolve_client_tool_name与协议级测试;#363的tokio::io::duplex()复现测试;#359、#362的改动与断言。(MCP 工具名净化)确认内部 id 未被改动、
tools/call向后兼容。反向确认测试确实能抓住坏代码(
#736/6、#1946/6)。76cb55f6f(rustfmt 重排)为机械格式化,无生成式逻辑。