Repository navigation
feat(windows): 对齐项目与提交面板交互并完善 Shelf 恢复 - #1341
Conversation
…t-tree-drag-session
Lithe Review结论: 未发现需要阻塞合并的问题。 Findings
Scope Check
Suggestions
Summary整体延续了既有 owner 和平台存储边界,会话隔离与部分失败保护较充分。上述两处有限正确性问题建议修正;现有测试未覆盖对应输入。 Verification
|
|
@lithe review |
Lithe Review结论: 未发现需要阻塞合并的问题。 Scope Check
Suggestions
Summary本次 head 已针对前一轮 Shelf 补丁基线和 Maven 嵌套路径问题补充实现与回归覆盖,项目树会话保护、Git 操作互斥和应用数据存储边界也有相应契约与测试说明。静态审查未发现需要阻塞合并的正确性或安全问题;视觉验收、跨平台实机行为和完整 CI 结果仍需补齐。 Verification
|
|
@lithe review |
Lithe Review⏳ 正在以大型变更模式审查代码,完成或失败后会更新本评论。 |
|
@lithe review |
Lithe Review结论: 未发现需要阻塞合并的问题。 Findings
Scope Check
Suggestions
Summary恢复数据持久化、不可变 Stash 身份和操作生命周期保护有相应实现与回归覆盖,两处 Swift 修改也仅调整夹具。项目树新增选择模型仍与既有活动路径同步产生冲突,建议修正;未发现明确 P0/P1 问题。 Verification
|
|
@lithe review Head: 已修复评论 6253345907 的 P2:单选跟随真实编辑器目标,共享 sidebar 路径往返不再覆盖目录选择。回归挂载真实 FileExplorerPane 并连接 sidebar/buffer store,核对目录高亮、复制/剪切、键盘焦点、范围锚点及后续真实文件切换。 本地 Release 构建通过,Project 树 40 项及 Windows 原生 350 项通过、1 项原有跳过;Notes、矩阵和静态门禁通过。前一 head 594df56 的 Swift/插件 CI 已实际通过,新 head 的 CI 等待运行;真实 WebView2/macOS 视觉及截图仍 pending。PR 描述已更新详细验证边界。 |
|
@lithe review |
Lithe Review结论: 未发现需要阻塞合并的问题。 Scope Check
Suggestions
Summary静态审查未发现需要阻塞合并的正确性、安全性、资源清理或架构边界问题。当前实现延续了既有 Core、Git 和 Maven owner,会话隔离、操作互斥及部分失败恢复也有相应契约和测试说明。剩余主要是视觉、真实平台行为和当前 head 完整 CI 的验收缺口。 Verification
|
|
已核对当前
本轮没有代码改动、push 或重跑 CI;bot 对当前 head 已完成审查且没有 P0/P1/P2 finding,因此不重复请求同一 head 的评审。继续每 30 分钟监控新的意见及必需正式评审, |
rebase 到 preview(含 1lck#1341 多选拖拽重写)后的适配: - 终端分支改用 dragState.draggedItems,多选时插入全部路径; - dispatchTerminalPathInsert 现在接收原始路径数组(由终端按自身 shell 引用),不再在此处预先格式化; - 移除未使用的 formatPathsForTerminal 导入。 tsc --noEmit、70 项聚焦测试、lint 通过。
* feat(windows): 项目树复制或拖拽文件后可在终端插入路径
Windows 项目树的「复制」只写入应用内文件剪贴板(Rust 侧 state),
外部程序无法读取,因此复制一个文件后在集成终端按 Ctrl+V 不会得到
任何内容;把项目树条目拖到终端时,落点会命中编辑器 pane 分支,
结果是在编辑器里打开文件(拖目录则没有任何反应)。
本次改动把文件条目转换成终端可直接使用的路径,且不改变原有复制语义:
- 复制行为不变:copy/cut 仍只写应用内剪贴板,系统剪贴板不被覆写。
store 额外只读一次剪贴板文本快照,用于判断「文件复制」是否仍是
用户最近一次操作。
- 终端粘贴:Ctrl+V / Ctrl+Shift+V / 右键「粘贴」优先插入复制条目的
路径;若此后用户又复制了文本,则照旧粘贴该文本,避免插入过期路径。
- 终端拖拽:项目树条目拖到终端时插入路径并追加一个空格,且不再
打开编辑器标签;拖到非终端 pane 仍按原逻辑打开文件。
- 路径规则:工作区内用相对路径并把分隔符统一为 `/`(Windows shell
从工作区根目录启动且不发送 OSC 7),工作区外条目保持完整路径;
含空格的路径沿用终端拖放的引号规则,保证保持为一个 shell 参数。
复用终端既有的引号函数 quoteTerminalPaths,避免两套转义规则漂移。
资源管理器的外部拖拽路径解析(要求绝对路径)不受影响。
验证:
- 新增 23 个单元测试(路径格式化、引号、落点判定)全部通过。
- 完整前端套件按基线/含改动两轮对比,失败集合完全一致(各 221),
未引入新的失败。
- tsc --noEmit、lint、verify-test-stability、verify-windows-boundaries、
verify-platform-feature-matrix 均通过。
- 真实 Windows 交互验收尚未执行,矩阵中 verificationStatus 标为 pending。
不在本次范围:系统剪贴板写入文件格式(CF_HDROP),因此桌面/资源管理器
粘贴文件仍不支持;该能力需要 Rust 侧原生剪贴板实现。
* fix(windows): 修正终端路径插入的注入风险、相对基准与 CI 覆盖
回应 review 的三项 findings。
[P1] 相对路径缺少 shell 元字符转义
quoteTerminalPath 原先只在路径含空白、引号或反斜杠时才加引号。绝对
Windows 路径必含反斜杠,因此一直命中引用分支;本次新增入口把路径变成
不含反斜杠的工作区相对路径后,`README&whoami` 这类文件名会原样送到
cmd,`&` 被当作命令分隔符执行。
改为安全字符白名单:只有字母、数字和 `._/\:-` 不引用,其余一律加引号,
覆盖 cmd 的 & | < > ^ ( ) 和 PowerShell 的 ; $ ` { } 等。
顺带修正引号内的转义策略:反斜杠在 cmd / PowerShell 的引号内不是转义符,
不再改成 `\`(旧写法会破坏路径);只把内嵌的 `"` 双写。未加引号的安全
路径现在原样返回,不再被无条件加反斜杠。
[P2] 路径应按目标终端目录相对化,而非工作区根
terminal 已有 currentDirectory(含 OSC 7 更新)。改为由终端在插入时按
自身目录相对化:抓取和拖放都只在事件里传绝对路径,终端用
getSession(sessionId).currentDirectory 决定基准;目录未知时保留完整路径,
因为此时相对路径可能指向错误文件。这修掉了在子目录中打开终端后
`src/Main.java` 被解析成 `.../src/src/Main.java` 的问题。
[P2] 新增测试接入 CI
在 ci-windows.yml 增加 "Test explorer file paths inserted into the
terminal" 步骤,用既有有界计时入口运行三个新测试文件,产出 JUnit/HTML
报告。本地已按 CI 写法实跑,36 项通过。
未采纳的 finding:
- [P2] 用文本相等判断剪贴板先后。准确修复需要 Windows
GetClipboardSequenceNumber,Tauri clipboard-manager 只暴露
read/writeText|Html|Image,没有变更序号或事件 API,必须新增原生 FFI。
这与本 PR 明确排除的 CF_HDROP 属同一前置依赖,留作后续独立改动。
当前启发式已在代码注释说明其局限。
验证:
- 新增/更新 36 个单元测试全部通过,含 10 个 shell 元字符注入回归用例
和子目录相对化用例。
- 完整前端套件按基线/修复后两轮对比,失败集合完全一致(各 221),
未引入新的失败。
- tsc --noEmit、lint、verify-test-stability、verify-windows-boundaries、
verify-platform-feature-matrix 均通过。
- 外部拖放(OS 拖入绝对路径)行为经手工探测确认无回归。
* fix(windows): 按目标 shell 引用终端路径并改用绝对路径
回应第二轮 review。两个 P1/P2 经实测确认成立:
[P1] 双引号在 PowerShell / Git Bash 中仍会求值
PowerShell 实测:文件名 report$(hostname).txt 用双引号包裹后,解释器
把它展开成 reportchenbk7995.txt 而报找不到文件。Git Bash 同理。
上一版还把旧代码对 $ 和反引号的反斜杠转义删掉了,使既有外部拖放
在 Git Bash 下也发生回归。
改为按 shell 家族选择引用方式:terminalShellFamily 从 session.shell
识别 cmd / powershell / pwsh / nu / bash,然后
- PowerShell、Nushell:单引号,内嵌单引号双写;
- Git Bash 等 POSIX:单引号,内嵌单引号用 '\'' 闭合;
- cmd.exe:只能双引号(无字面量语法),但保留 %NAME% 可展开的已知局限。
单引号同时保住反斜杠,修掉了 Git Bash 把 C:\work\proj\a.txt 解析成
C:workproja.txt 的回归。实测单引号可正确读到字面文件。
[P2] 启动目录不能当作可靠的当前目录
cmd 与 PowerShell 都不发送 OSC 7,session.currentDirectory 只是启动
目录,用户 cd 后即过期,?? null 识别不出「非空但过期」。
改为不再相对化:路径一律使用完整绝对路径。绝对路径在任何 cd 之后的
当前位置都成立,也不再需要可靠性判断。顺带修掉 [P2] 目录自身被过滤成
空串的问题——绝对路径不会退化为空。
[P2] 内容相等无法证明先后
Tauri clipboard-manager 没有变更序号 API,正确修复需 GetClipboardSequence
Number 原生 FFI,与本 PR 排除的 CF_HDROP 同一前置依赖。按建议补充
不依赖启发式的显式入口:终端右键菜单新增「粘贴已复制的文件路径」,
直接插入应用内文件剪贴板的路径,不受系统剪贴板内容影响。
验证:
- 32 个单元测试通过,含 PowerShell/Git Bash 的 $() 不求值、反斜杠保留、
单引号转义、cmd 双引号、OS 拖放按 shell 引用等回归用例。
- 手工实测 PowerShell 双引号确实展开 $()、单引号不展开;Git Bash
裸路径丢反斜杠、单引号保留。
- 完整前端套件按基线/修复后两轮对比,失败集合完全一致(各 221),
未引入新的失败。
- CI 步骤按实际写法本地实跑,32 项通过并生成报告。
- tsc --noEmit、lint、verify-test-stability、verify-windows-boundaries、
verify-platform-feature-matrix 均通过。
* fix(windows): 记录实际启动的 shell 并统一路径引用入口
[P1] shell 分类没有接通实际调用链
初始化时 updateSession 只写入 connectionId、currentDirectory 和
remoteConnectionId,没有保存 shell。而 TerminalSlot 的 shell prop 本身
就来自 terminal.shell,因此 getSession(sessionId)?.shell 恒为 undefined,
上一版按 shell 家族引用路径的修复全部回退到 cmd 双引号——PowerShell 与
Git Bash 下 report$(whoami).txt 这类文件名仍会被求值。
修复两处:
- updateSession 一并保存实际启动的 shell(沿用创建时同一来源
shell || existingSession?.shell || wslShellId),使 remount、
重新打开以及其它读取 session 的入口都能拿到;
- 组件内新增 resolveShell(),优先使用 shell prop(初始化完成后权威),
回退到 session 记录,普通粘贴、显式粘贴、外部拖放和应用内拖放四个
入口统一走它,不再各自读取。
新增 terminal-session-shell.test.ts,直接覆盖这条断点:shell 能经
updateSession 落到 session、与 connectionId/currentDirectory 共存、
后续省略 shell 的更新不会清除它、初始化前为空。该文件已加入 CI 步骤。
[P2] 普通粘贴的内容误判
未修复,属已知局限:正确做法需要 GetClipboardSequenceNumber 原生 FFI,
Tauri clipboard-manager 不提供变更序号。按上一轮评审建议,显式入口
「粘贴已复制的文件路径」已提供不依赖启发式的选择;普通 Ctrl+V 仍保留
内容比较并在代码注释中写明其局限。
验证:
- 36 个单元测试通过(4 个文件),含新增的 4 个 session shell 用例。
- CI 步骤按实际写法本地实跑,36 项通过并生成报告。
- 完整前端套件按基线/修复后两轮对比,失败集合完全一致(各 221),
未引入新的失败。
- tsc --noEmit、lint、verify-test-stability、verify-windows-boundaries、
verify-platform-feature-matrix 均通过。
* docs(windows): 记录终端粘贴优先级的取舍决策
[P2] 内容相等无法区分「重新复制了相同文本」。在没有 OS 变更序号的前提下
无法正确修复,因此把它作为明确决策固定下来,而不是留作开放问题:
保留普通 Ctrl+V 自动插入文件路径。理由是这条判断两侧代价不对称——
插入路径正是复制文件的目的,误判需要「相同内容复制两次且中间夹一次文件
复制」才发生,代价只是一次可见、可撤销的插入;而移除自动分支会给每次
「复制文件→终端粘贴」都增加一步手动操作,且并非本 PR 能正确实现(需要
GetClipboardSequenceNumber 原生 FFI)。
- 函数注释改为记录决策依据与两侧代价,不再只描述局限;
- 新增一个测试固定该取舍,使未来改动必须同步修改注释中的决策。
仅注释与测试变更,无生产逻辑改动。37 个单元测试与 CI 聚焦步骤通过,
tsc 与 lint 通过。
* fix(windows): 覆盖 WSL、MSYS2 与 Cygwin 的 shell 家族
[P1] 原生 shell 目录还提供 msys2、cygwin 和 wsl:<发行版>,三者都运行
bash,但 terminalShellFamily 未覆盖,会回退为 cmd 并生成双引号——
这些 shell 下 report$(whoami).txt 仍会被求值。base 的外部拖放原本会
转义 $ 和反引号,本次替换使该入口同样回归。
补齐家族映射:wsl:* 前缀、msys2、cygwin 归为 posix。并在注释中写明
映射必须与 windows_shells.rs 保持对齐,以及「落到 cmd 就意味着双引号」
这一失效路径。
新增覆盖:4 个真实 shell id 的分类用例,以及从 shell id 到最终插入文本
的端到端用例(wsl:Ubuntu / msys2 / cygwin / bash / powershell / pwsh
六种均产出单引号字面路径)。
验证:44 个单元测试通过(4 文件);CI 聚焦命令本地实跑 44 项通过并
生成报告;完整前端套件基线/修复后两轮对比,失败集合完全一致(各 221),
新增 0;tsc --noEmit 与 lint 通过。
* fix(windows): WSL 会话转换路径命名空间并补充弯引号覆盖
[P2] WSL 会话路径未转换命名空间 — 成立,已修复
分类为 posix 只解决了引用问题,原样保留的 Windows 盘符路径在 WSL 内仍
不可访问:Linux 把 `C:\work\proj\a.txt` 当作含反斜杠的相对文件名。
新增 windowsPathToWslPath,把 `C:\work\proj\a.txt` 转成
`/mnt/c/work/proj/a.txt`(WSL 默认按盘符挂载);已是 Linux 形式的路径
原样保留;UNC 共享没有可预测挂载点,返回 null 并保留原值,避免插入
指向不到的位置。quoteTerminalPaths 在 wsl: 会话下先转换再引用。
[P1] 弯单引号可逃逸 — 复核后不成立,未改代码
按 finding 逐字节验证 PowerShell 5.1:把 U+2018、U+2019、U+201A、
U+201B、U+FF07、U+2032 分别置于单引号字符串内并尝试注入
`$(Write-Host PWNED)`,六种全部未执行,脚本正常解析。说明这些字符
不是 PowerShell 的字符串分隔符,只有 ASCII `'` 需要双写(已实现)。
为免该假设日后静默失效,新增 6 个用例固定「弯引号保持字面值」。
[P2] 相同文本误判 — 维持决策,修正注释
保留自动插入的取舍不变。原注释称「再次粘贴即可撤销」,经复核不成立
(剪贴板文本与应用内文件剪贴板都仍然有效),已改为准确描述恢复方式。
验证:
- 57 个单元测试通过(5 个文件),含 WSL 路径转换 6 例、弯引号 6 例、
wsl: 端到端 2 例;CI 聚焦命令本地实跑 57 项通过并生成报告。
- 完整前端套件基线/修复后两轮对比,失败集合完全一致(各 221),新增 0。
- tsc --noEmit、lint 0/0 通过。
* fix(windows): WSL 工作区的协议路径转换为发行版内路径
[P2] wsl:// 协议路径未转换 — 成立,已修复
上一轮只把 wsl:* 归为 POSIX,并处理了 Windows 盘符路径;但 explorer 的
WSL 工作区根是用 buildWslPath 生成的 `wsl://Ubuntu/home/me/proj`,该
形态既不是盘符路径也不是 Linux 路径,windowsPathToWslPath 返回 null 后
回退原值,Linux 下无法访问。
新增 pathToWslPath(path, distro):命中 wsl:// 时用 parseWslPath 取出
linuxPath,并校验发行版与目标终端一致(跨发行版不可达,返回 null 让
调用方保留原值而不是插入猜测);否则交给 windowsPathToWslPath 处理
盘符路径与已是 Linux 的路径。quoteTerminalPaths 在 wsl: 会话下改用它。
[P1] 弯单引号 — 仍不成立,但改用更强证据并修正了判定方法
上一轮我用 grep 匹配输出中的 PWNED,这个判定有缺陷:字符串内容本身也会
被打印出来,造成假阳性/假阴性。改用 PowerShell 自身的词法分析器
(System.Management.Automation.Language.Parser)直接查看切分结果:
含 U+2019 的路径被解析为**单个 StringLiteral**,errors=0;同样形状换成
ASCII `'` 则切分为 StringLiteral + 独立语句 + 注释。结论不变:弯引号不是
PowerShell 的字符串分隔符,只有 ASCII `'` 需双写。测试注释已改为记录该
词法证据及其判定方法。
验证:64 个单元测试通过(5 个文件),含 pathToWslPath 6 例;CI 聚焦命令
本地实跑 64 项通过;完整前端套件基线/修复后两轮对比,失败集合完全一致
(各 221),新增 0;tsc 与 lint 通过。
* fix(windows): 双写 PowerShell 认可的四种弯单引号
[P1] 弯单引号可逃逸字符串 — **成立**。此前两轮我判定它不成立,结论是错的。
用无歧义的副作用检测(注入语句创建文件,只检查文件是否出现)在
PowerShell 5.1 上复验:把注入串放在单引号字符串内执行,
'report<Q>; New-Item ... 'pwned_XXXX.txt' ...; #.txt'
U+2018、U+2019、U+201A、U+201B 四种全部**创建了文件**,与 ASCII `'`
一致;U+FF07、U+2032 未创建。即 PowerShell 收四种弯引号为字符串分隔符,
只双写 ASCII `'` 确实留有命令注入入口。
我此前两次误判的原因,如实记录:第一次用 `grep PWNED` 匹配程序输出,
而字符串内容本身也会被打印,判定不可靠;第二次构造注入串时多插了一个
ASCII 引号,导致引号配对被破坏、结果全部显示为「未执行」。
修复:PowerShell 分支对 `'` 与 U+2018/U+2019/U+201A/U+201B 一并双写。
已用应用真实输出做端到端复验——生成的
`'C:\work\report’’; New-Item ...; #.txt'` 在 PowerShell 中执行后没有
产生文件,且良性文件名往返值保持不变。POSIX 分支不受影响(这些字符在
bash 中不是分隔符,双写反而会破坏路径)。
测试改为按「分隔符 / 非分隔符」两组断言,并注明判据来自真实执行而非
仅比较输出字符串。
验证:65 个单元测试通过(5 文件);CI 聚焦命令本地实跑 65 项通过;
完整前端套件基线/修复后两轮对比,失败集合完全一致(各 221),新增 0;
tsc 与 lint 通过。
* fix(windows): 按 Nushell 语法引用路径并记录 WSL 挂载限制
阻塞已解除(上轮结论为「有建议」)。本轮处理剩余 P2:
[P2] Nushell 不应沿用 PowerShell 的单引号双写 — 成立,已修复
Nushell 的单引号字符串没有 `'` 转义,双写不会还原为一个引号,
`C:\work\it's.txt` 插入后无法访问。改用 Nushell 的 raw string
(反引号),它保留引号、`$` 与 Windows 反斜杠:
- 常规路径与含 `$()`、单引号的路径统一用 raw string;
- 文件名含反引号时 raw string 无法表达,退化到单引号(仅当不含单引号);
- 两者同时出现时没有能保持字面的 Nushell 形式,按原样输出而不是
生成 Nushell 会读成别的值的转义。
已补 4 个用例覆盖上述分支。
[P2] WSL 自定义 automount root — 不修复,记录限制
`/etc/wsl.conf` 的 `[automount] root` 可改变盘符挂载前缀,正确解析需要
目标发行版的 `wslpath`,前端没有该能力。已在 windowsPathToWslPath 的
注释和功能矩阵验证说明中明确记录这一前提,避免被当作通用事实。
[P2] 相同文本误判 — 非阻塞,决策不变。
验证:69 个单元测试通过(5 文件);CI 聚焦命令本地实跑 69 项通过;
完整前端套件基线/修复后两轮对比,失败集合完全一致(各 221),新增 0;
tsc --noEmit、lint 0/0、verify-platform-feature-matrix 通过。
* fix(windows): Nushell 无法字面表示时丢弃路径而非输出裸文本
[P1] Nushell 回退分支重新引入注入入口 — 成立,是我上一轮引入的。
上一轮为处理「文件名同时含反引号与单引号」,让 quotePathForShell 直接
返回原路径。该分支取消了整条路径的引用:文件名中的 `;` 会被 Nushell
当作命令分隔符,`print C:\work\a; ^whoami; #'`.txt` 会执行 `^whoami`。
修复:quotePathForShell 改为返回 string | null,无法字面表示时返回
null;quoteTerminalPaths 过滤掉 null。即**拒绝插入**而不是输出裸路径。
本次改动前该场景输出裸文本(不安全),改动后不插入任何内容——宁可
不插入,也不能执行文件名里的命令。
同时把上一轮固定「原样输出」的测试改为断言输出为空,并注明原因。
验证:
- 实测 无法表示 -> ""(不再输出裸路径);仅含反引号 -> 单引号形式。
- 37 个终端引用用例通过;CI 聚焦命令 69 项通过。
- 完整前端套件基线/修复后两轮对比,失败集合完全一致(各 221),新增 0。
- tsc --noEmit、lint 0/0 通过。
* fix(windows): 拖放路径被全部丢弃时不再插入孤立空格;显式粘贴项补 disabled
自查发现两处不一致:
1. formatDroppedPathsForTerminal 在引用阶段丢弃全部路径时仍会追加
尾部空格,向提示符插入一个孤立空格。formatPathsForTerminal 已有
该保护,两者行为不一致。补同样的空值判断,并加回归用例
(Nushell 下文件名同时含反引号与单引号时,quote 返回 null)。
2. 终端右键「粘贴已复制的文件路径」缺少 disabled={!connectionId},
与上方「粘贴」不一致,未连接时仍可点击。补齐。
验证:70 个单元测试通过(5 文件);完整前端套件基线/修复后两轮对比,
失败集合完全一致(各 229),新增 0。注意基线从 221 升至 229 是上游
41 个提交自带的失败,与本改动无关,已用同一轮基线验证。
tsc --noEmit、lint 0/0、verify-test-stability、verify-windows-boundaries 通过。
* fix(windows): 用剪贴板变更序号替代文本比较判断粘贴优先级
[P2] 相同文本会让旧文件路径覆盖最近复制的文本 — 已从「记录取舍」改为
真正修复。
原实现比较系统剪贴板的**文本内容**来判断「文件复制是否仍是最近一次
操作」。该判据在「复制文本 → 复制文件 → 再复制同一段文本」时失效:
内容相同,函数仍选文件路径,且重复复制该文本也不会恢复。
Windows 提供 GetClipboardSequenceNumber(),每次任何进程写剪贴板都会
递增,是内容比较无法替代的变更身份。新增 tauri 命令
clipboard_sequence_number(cfg(windows) 下调用该 API,其它平台返回 0):
- copy/cut 时读取序号存为 sourceClipboardSequence;
- 粘贴时再读一次,序号相同才插入文件路径,不同则说明用户此后复制过
其它内容,照旧粘贴剪贴板文本;
- 任一侧读不到序号时回退为粘贴文本,不猜测。
新增 windows-sys 的 Win32_System_DataExchange feature。该 feature
不需要更新 Cargo.lock:src-tauri 的 lock 目前与上游 #1267 引入的
lithe-agent-host 依赖不同步(缺 tungstenite 等),cargo check 会自动
补写;那属于上游 lock 维护问题,不在本 PR 范围内,故未提交 lock 变更。
顺带更新功能矩阵:补充 Rust 侧证据路径,并把验证说明改为覆盖「复制相同
文本」这一纯文本比较无法区分的场景。
验证:
- 70 个单元测试通过(5 文件),新增 4 个序号语义用例(含回归:
相同文本二次复制现在正确让位)。
- 实测 GetClipboardSequenceNumber 连续读取稳定(16738/16738),只读、
未扰动剪贴板。
- cargo check --target x86_64-pc-windows-msvc 通过。
- 完整前端套件基线/修复后两轮对比,失败集合完全一致(各 229),新增 0。
- tsc --noEmit、lint 0/0、verify-platform-feature-matrix(172 项)通过。
* fix(windows): 适配上游多选拖拽接口并复用终端路径通道
rebase 到 preview(含 #1341 多选拖拽重写)后的适配:
- 终端分支改用 dragState.draggedItems,多选时插入全部路径;
- dispatchTerminalPathInsert 现在接收原始路径数组(由终端按自身 shell
引用),不再在此处预先格式化;
- 移除未使用的 formatPathsForTerminal 导入。
tsc --noEmit、70 项聚焦测试、lint 通过。
* fix(windows): 剪贴板变更序号随文件条目一同广播
[P2] 跨窗口时条目与序号不同步 — 成立,是我上一轮引入的。
上一轮把序号存在前端 store 的独立字段里,而跨窗口同步只广播条目
(`file-clipboard-changed` 事件与 `clipboard_get` 都只含条目),
于是 `setClipboard` 保留了**接收窗口自己的旧序号**。后果:
- 窗口 B 从未复制过文件时序号为 null,粘贴永远回退到系统剪贴板文本;
- B 复制过文件时,新条目会与旧操作的序号配对,判断依据错位。
修复:把序号移入 `FileClipboardState` 本身。
- 后端 `clipboard_set` 用 `clipboard_change_counter()` 取得序号并写入
state,随 `file-clipboard-changed` 一起广播;`clipboard_set` 改为返回
该 state,前端直接使用,不再单独读取;
- 前端删除独立的 `sourceClipboardSequence` 字段,`setClipboard` 整体
替换 state,条目与序号始终成对;
- 粘贴时从 `clipboard.source_sequence` 读取基准序号。
新增回归用例:同一组条目分别用「随条目而来的序号」与「本窗口旧序号」
判定,前者插入路径、后者让位,固定住这个 bug 的形态。
验证:71 个单元测试通过(5 文件);tsc --noEmit、cargo check
(x86_64-pc-windows-msvc)、lint、verify-test-stability、
verify-windows-boundaries 通过;完整前端套件基线/修复后两轮对比,
失败集合完全一致(各 317),新增 0。
* fix(windows): clipboard_set 返回记录状态;修正 Nushell 引用并让复制容错
两个 P1 均为我方缺陷。
[P1] clipboard_set 仍返回 Result<(), String>,前端按 FileClipboardState 接收
成功时序列化为 null,`set({ clipboard: state })` 会清空当前窗口条目,
导致复制后立即粘贴看不到文件。CI 的 "Test Project tree selection" 门禁
正是这样红的(5 个用例失败,报 clipboard.entries 为 undefined)。
- host.rs: clipboard_set 改为返回记录下来的 FileClipboardState,并在
emit 时用引用,避免返回值与广播内容分叉;
- store: 先本地记录条目,再尽力采纳后端返回的 state。后端调用失败或返回
意外值都不会清空用户刚复制的条目——终端是从这个 store 读条目的。
[P1] Nushell 分支把反引号当作 raw string 定界符
Nushell 的反引号是 quoted identifier,不是字符串字面量,用它包裹路径
会改变含义而非保护路径。改为只用单引号;单引号内无法转义,故文件名含
`'` 时返回 null(丢弃),既不改写路径也不输出裸文本。
验证(均为本地实跑):
- CI 门禁 "Test Project tree selection, reveal, and move lifecycle":
修复前 5 失败 → 修复后 40 项全通过;
- CI 门禁 "Test explorer file paths inserted into the terminal":70 项通过;
- 71 个单元测试、tsc --noEmit、cargo check(x86_64-pc-windows-msvc)、
lint 0/0 通过。
已知无关失败:完整套件中 file-explorer-selection 的 5 个用例仍失败,
根因是 editor 目录的 svg-editor.test.tsx 用 mock.module 把 buffer.store
替换成无 setState 的裸对象,跨文件污染了后续测试。该测试文件与上游
preview 完全一致,属上游既有缺陷,不在本 PR 范围内。
* fix(windows): 远程工作区条目转换为连接内路径
[P2] remote:// 协议路径被原样交给远程 shell — 成立。
远程工作区在项目树里用前端 URI `remote://<connection>/<path>` 表示路径,
原样插入后远程 shell 得到一个打不开的字符串。
改为在插入前按目标终端解析:
- 命中 `remote://` 时用已有的 parseRemotePath 取出 remotePath;
- **只有当终端连接的就是该 connection 时才转换**,否则返回 null 丢弃——
把 URI 交给别的 shell 等于插入一个看起来像路径、实际打不开的值,
丢弃比这更安全;
- 转换逻辑收敛到 shellPath(),与 WSL 转换并列,避免两条路径各写一份。
terminal.tsx 新增 resolveRemoteConnectionId()(prop 优先,回退 session),
粘贴、显式粘贴、应用内拖放、外部拖放四个入口统一使用。
验证:73 个单元测试通过(新增 3 个远程路径用例:同连接去协议、
跨连接丢弃、本地不受影响);两套 CI 门禁本地实跑 40 项与 73 项全通过;
tsc --noEmit、lint 0/0 通过。
* fix(windows): 复制失败时前后端剪贴板保持一致
[P2] 复制失败时前后端分叉 — 成立,是我上一轮修 P1 时引入的新问题。
上一轮为了不让「后端返回意外值」清空条目,改成**先本地写入、再吞掉错误**。
代价是:后端拒绝 `clipboard_set`(源文件消失等)时,前端仍持有新条目,
而后端保留旧条目。于是终端显式粘贴得到 B、项目树粘贴却操作后端保留的 A;
若旧操作是剪切,项目树还会去移动旧文件。
改回以后端为准:`invoke` 成功才写入,失败时抛出、前端保持原状,前后端
一致。唯一的兜底是「返回体不含条目」——那只能来自未实现该命令的宿主或
测试替身(早期 `clipboard_set` 返回空),此时保留本次复制条目,避免把
剪贴板清空。
验证:两套 CI 门禁本地实跑 40 项与 73 项全通过;tsc --noEmit、lint 通过。
* fix(windows): 把剪贴板序号 0 当作未知而不是有效身份
[P2] 序号 0 被当作有效值 — 成立。
host.rs 在平台没有变更计数器时返回 0(`cfg(not(windows))` 分支与
GetClipboardSequenceNumber 的失败语义都用 0 表示未知),而判断函数只拒绝
null。于是两侧都是 0 时被判为「未变化」,粘贴仍插入旧文件路径,没有按设计
回退到文本——正是序号机制要解决的失效。
改为 `!sourceSequence || !currentSequence` 一律回退,并补回归用例
(0/0 与 0/42 均让位)。doc comment 同步说明 0 表示未知。
顺带按 review 建议更新 PR 描述中两处过时内容:剪贴板判断已从「文本快照」
改为变更序号;Nushell 已改为单引号并过滤含单引号路径(不再使用反引号
raw string)。并补充远程协议路径的转换规则。
验证:CI 门禁「explorer file paths…」74 项、门禁「Project tree selection…」
40 项本地实跑全通过;tsc --noEmit、lint 0/0 通过。
Windows 项目树在长文件名、定位当前文件和多选操作时使用不便,提交面板的结构与交互也与当前 macOS Swift 实现存在差异。本次按 Swift 源码补齐主要工作流,并为文件移动及 Shelf/Stash 恢复加入会话和数据保护。
Refs #1257
改动
项目树支持长文件名横向滚动、虚拟列表离屏定位及重复定位;定位时清除搜索并从 Dependencies 返回 Project,等待祖先目录展开后再滚动,忽略过期请求。
补齐 Ctrl/Shift 多选、同级全选、复制/剪切/删除及集合拖动;行选择、键盘焦点、范围锚点跟随真实编辑器目标的变化,明确多选不被编辑器切换覆盖;目录点击引发的共享侧栏路径往返不会把选择和复制/剪切目标改回已打开文件。移动整批预检重名和父子重复,原生移动不覆盖目标;工作区切换或 A→B→A 后停止旧批次,已成功项仍同步原工作区。
项目右键补齐查找/替换、目录标记和项目本地历史入口。查找/替换复用既有全局搜索流程及工作区状态;目录标记跟随移动/删除,并按 Windows、WSL 和远程路径身份隔离。
新增 Project/Dependencies 切换,展示现有 Maven owner 的模块与依赖快照;只有用户明确点击解析才启动既有 Maven 操作。POM 导航与 Maven 面板共用路径解析,支持根项目、嵌套 reactor 目录和 WSL UNC。
按当前 Swift 组件对齐 Commit/Shelf 页签、紧凑操作栏、ChangeList 分组及复选框顺序、Amend、提交说明和按钮布局。保留用户字号缩放和已有尺寸偏好;说明框最小高度为 50px,窄面板布局调整,拖动结束时才保存尺寸。常驻范围说明移入提示,刷新、AI 和丢弃按钮使用对应 IDEA 图标。
提交列表区分行选择与实际暂存状态,默认和命名列表一致呈现;工具栏暂存限定活动列表,Diff 预览打开完整首项,父仓库引用选项由共享 owner 控制并保留到重试计划。
新增 Shelf 原生持久化与两层原始补丁恢复:先可靠保存暂存/工作区版本,再验证快照并清理;恢复先暂存后工作区,全部完成后删除记录。冲突和部分失败保留完整恢复材料,重试检查已应用层,支持未跟踪和二进制文件。工作区层通过兼容选项
git.patchExport(source: "unstaged", includeUntracked: true)从临时索引导出,覆盖暂存删除后保留原路径、暂存重命名后重建源路径;真实索引及旧调用语义不变。Stash 列表、Diff 缓存及写操作使用不可变 OID,Core 在仓库写锁内重新解析当前位置,兼容既有位置引用。Shelf/Stash 的列表、选择、确认和恢复绑定仓库会话;操作锁跨面板卸载保留,仅由原操作释放,并与提交、暂存和 ChangeList 修改互斥。
本地历史按工作区隔离同名相对路径并统一时间单位,保留旧数据;WSL/remote 等尚无 Core 支持的项目历史入口保持关闭。Shelf 数据写入 app data,WSL 大小写独立,保留无法证明归属的旧桶,不写发行目录。
同步共享契约与 fixtures、功能矩阵、Agent Notes、IDEA 图标资源和 Windows Cargo lock;Windows CI 注册项目树与四组 Shelf/Stash 安全回归,各组使用计时报告和本地超时,Shelf/Stash 分进程隔离 mock。
为五个真实 Git Patch 集成用例同步本地 SharedRust 与 real-JDT CI 的单项预算:四项 30 秒、一次完整双层恢复 60 秒。用例实测约 17~50 秒;保留每次 Patch 请求 15 秒及原套件总期限,不改变断言或其他用例上限。
修正两个上游 Swift 测试夹具:插件构建使用既有只读 fixture 目录作为必填包 URL,Web Bridge 的工作区 URL 明确标记为目录;保留所有产品逻辑、断言、等待、清理与超时。
验证
PR base:
upstream/preview的7121aee6。当前 head:84008cee。FileExplorerPane并连接侧栏、缓冲区 store,覆盖目录选择、复制/剪切、键盘焦点、范围锚点、真实编辑器切换、明确多选、滚动定位和拖动生命周期。修改的选择测试最慢 94ms,目录选择回归 78ms。.artifacts/test-stability/issue-1257-editor-selection/final/;旧实现的目录选择失败报告保留在before/。全目录单进程试跑遇到了仓库 CI 已要求隔离的 debugger mock 冲突,已停止;相同 adapter 分进程运行 5 项通过。该混跑不计为全量测试通过。git diff --check通过。71659004通过,报告保留在.artifacts/test-stability/issue-1257-review/final/。Shelf 暂存删除/保留原路径和暂存重命名/重建源路径分别为 51.8s、54.9s,使用已有 60s 单项预算;原始计时异常与最终结果均保留,没有放宽每次请求的 15s 期限。CI 状态
594df568的 Swift tests、插件测试与包校验、macOS/Plugin/Windows/Database gates、Notes 和矩阵均已通过,确认上述两处 Swift 夹具修复;该 head 的 Windows/Core/Release 测试 lane 按范围跳过,不计作重跑通过。71659004的 Windows 前端、Windows Rust、真实 JDT、Rust Core、macOS arm64 打包此前已通过。打包日志证实原版verify-runtime-bundle-immutability.sh实际执行通过;不等同于完整实机工作流哈希验收。当前 head
84008cee93847d2a6d1e5d94b27d8c816b580962的所有 checks 已结束,没有排队、运行中或失败的 check;成功 gate 不代表被跳过的测试重新执行。2026-10-19 已重新读取 GitHub job 状态,结果如下。84008cee71659004实跑成功71659004实跑成功71659004实跑成功594df568实跑成功594df568实跑成功71659004arm64 实跑成功原版
scripts/verify-runtime-bundle-immutability.sh的实际成功证据来自前序71659004的 macOS arm64 打包 job,Build complete macOS test package步骤日志:该原始 job 日志已保存到
.artifacts/issue-1257/suggestions-20261019/71659004-macos-arm64-package.log。本轮确认71659004..84008cee之间该脚本及其扫描的macos/Sources、windows/tauri/src-tauri/src没有改动。当前 head 的打包 lane 跳过,因此没有把这条历史成功记录表述为当前 head 重新执行,也不把静态脚本视为完整安装包工作流的运行时哈希验收。bot 已完成当前 head 的审查:没有 P0/P1/P2 finding,两条非阻塞 Suggestions 分别要求视觉证据和 CI 证据。CI 证据已补齐;当前正式 review 仍为 0,
REVIEW_REQUIRED尚未满足。验收边界
真实 WebView2 明暗主题、窄面板、拖动和完整恢复交互,以及真实 WSL/macOS 对照尚待实机验收,相关矩阵保持
pending。2026-10-19 本轮准备了独立 Git fixture 以补原生截图,但 Windows 桌面处于锁屏,已立即停止 UI 操作;没有取得可用界面截图,不将此次尝试计入 WebView2 验收。本轮新启动的 Lithe 实例及遗留 Java 子进程已关闭,未保留验证应用。解锁后可继续,macOS 前后对照和完整视觉证据仍待提供。
Dependencies 当前覆盖 Maven 快照;通用插件依赖、归档及虚拟文档浏览尚未达到 macOS 全部能力。
macOS 的完整契约脚本依赖 zsh/Ruby;本机完成共享 JSON、定向 Core 测试和发行目录写入等价静态扫描,不将这些结果视为 macOS 实机或安装包哈希验收。
新上游
ci-workflow-gates.test.mjs依赖 Linux 的 LF 文本、Bash/jq 及进程组语义;原生 Windows CRLF checkout 的直接执行在提取 gate 时失败,留待 Linux CI 验证。工作流 YAML 已单独解析检查。本轮同步引入的 macOS Swift 功能与测试、关闭 PR 后取消历史 CI 的 Bash 集成测试由完整 CI 验证,本机 Windows 未运行这些 macOS/Linux 专用检查。