[Feature] Rust Core 下沉清单:Git 等 104 处双端重复/单端私有逻辑搬入 core(含 7 个已核实 bug)

Open
#1,662 6 comments 0 reactions 2 assignees View on GitHub

Maintainers usually reply within 1 day

@puppyben1 is already working on this.

Since Nov 4, 2026.

  • #1769 by @1lck — open

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
8/100
Issue type
Refactor
Clarity
Needs clarification
Activity status
Active
Domain
tooling

Research direction

This is a tracking issue with 104 items, not a single task, so pick one checklist entry first. BUG-2 is the smallest: windows/tauri/src/features/keymaps/utils/context.ts tokenize loops forever on characters like @, so start there and check the import path in keybinding-import-export.ts. Done means the function advances or throws on those characters, with a fixture in shared/fixtures/.

Written by the indexing model from the issue text.

Description

area:ai area:debug area:extensions area:git area:language area:run area:search area:workspace enhancement P1 platform:cross-platform review: high Rust Core
Problem to solve / 要解决的问题

按 develop-lithe 的架构规则,两端都会用到的确定性逻辑(解析、校验、匹配、排序、选择、预算、状态归约、诊断码)应该只在 rust/lithe-core/ 写一份,macOS(Swift)和 Windows(Tauri + TS)只负责原生 I/O、本地化和界面呈现。实际上仍有大量规则留在平台层:有的两端各写一份,有的只有一端有,有的 core 已经实现了但其中一端没接。结果是同一个操作在两端表现不同,有些地方已经能从代码推出错误结果。

核心要求是将所有逻辑全部沉入到 Rust Core 中去,然后尽可能少的写双端适配逻辑——双端只负责 UI 跟少了专属平台 API 调用

这次按领域分 6 路静态读码,覆盖 macos/Sources/ 全部 16 个 Swift 模块、windows/tauri/{src,src-tauri,crates} 和 rust/lithe-core/src,共找到 104 处:

领域 P0 P1 P2 合计
Git:状态、提交、回滚、Shelf、Diff、Blame、历史、提交图、引用、Pull、Rebase、GitHub 17 10 7 34
运行、构建、调试、测试 8 4 5 17
LSP、编辑器、文档 10 3 4 17
工作区、文件、搜索、快捷键、设置 10 5 3 18
Agent、AI、MCP、插件 8 6 4 18
合计 53 28 23 104

条目优先级的含义(只用于本 issue 内部排序):

  • P0:代码已经能证明两端行为不同,或者会产生错误结果
  • P1:两端重复实现的大块业务逻辑,暂未发现分歧
  • P2:小块重复,或者边界有争议(条目里标【灰色】)

几个从代码能直接推出的后果:

  • Windows Problems 面板右键快速修复用不了:code action 请求里的 severity 是字符串,core 要整数,请求反序列化失败。
  • Windows 导入一条 when 为 "@" 的快捷键后,按键处理会把前端卡死。
  • 同样是“更新当前分支”,历史分叉时 macOS 让用户选策略,Windows 直接 merge。
  • 运行参数 ["--name","Alice Smith"] 在两端编辑保存一次后,都会变成三个参数。
  • macOS 生成 AI 提交消息时输出上限是 256 token;core 已有的实现是 4096,敏感文件过滤也更全,但只有 Windows 在用。

说明:

  • 全部是静态分析,没有构建、跑测试或启动应用。7 个 bug 已回到源码逐行核对。
  • 审计基线是 50b4ebe0f,文中行号已在 preview 的 1620f69d0 上复核。搬运时行号可能已经漂移,请以符号名为准。
  • 这是一个跟踪 issue,下面每条都可以单独认领、单独提 PR。
Proposed solution / 建议方案
0. 搬运规则(每个 PR 都适用)
  1. 先判断归属。 通用的确定性规则进 core。Maven、Java、Spring、JUnit 这类工具专属语义交给插件或上游,和 #1495 一起做。不得在 core 或宿主里按工具名、语言名加分支,也不要在 shared schema 里加工具品牌枚举。标【插件】的条目都属于这一类。
  2. 接口形态。 core 提供 plan / reduce / classify 类 JSON 命令:平台把采集到的事实(文件内容、git 输出、事件、当前时间)交进来,core 返回计划或新状态以及稳定错误码,平台执行并呈现。文中的 API 名都是建议,最终按 core 现有命名来定。
  3. 先写 fixture。 先在 shared/fixtures/<domain>/ 加能覆盖这条分歧的样例,core 测试通过后再接两端,两端用同一套 fixture。
  4. 一次切干净。 接入 core 的同时删除旧的平台实现,不留双写、fallback 或兼容分支。某一端暂时没有这个功能的,在功能矩阵里写明。
  5. 兼容面。 Windows 直接链接 lithe-core 的公开 Rust 类型,改了公开类型要跑 cargo check --bin lithe-windows。错误码一码一义。新增的用户可见文案走 shared/i18n/。改插件后端协议时,按 CLAUDE.md 在 lithe-plugin-docs 跑 SDK e2e。
  6. 验证。 按改动范围运行下面的脚本;行为有变化时同步更新 shared/platform-feature-matrix/features/<id>.json。
    ./scripts/rust-core/verify-rust-core-comments.sh
    ./scripts/rust-core/verify-rust-core.sh
    ./scripts/architecture/verify-shared-contracts.sh
    ./scripts/architecture/verify-core.sh
    ./scripts/architecture/verify-service-boundaries.sh
    ./scripts/git-graph/verify-git-graph.sh            # 动到提交图时
    ./scripts/macos/test/test-macos.sh
    ./scripts/windows/verify/verify-windows-boundaries.sh
    ./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh
    
  7. 认领和提交。 在本 issue 下评论编号(例如 GIT-05)认领。从最新的 preview 拉分支,一条一个 PR,先开 Draft PR;PR 标题带编号,描述里引用本 issue。合并后在这里勾掉。

标记说明

  • 【接线】core 已有能力,只是有一端没用。改动最小,一般不用新增 core API。
  • 【计划】core 只有底层原语,规则写在平台,需要新增计划或归约 API。
  • 【双写】两端各有一份完整算法,需要合并成一份。
  • 【拼命令】平台自己拼 git 参数,或自己解析原始输出。
  • 【插件】应归插件或上游,不搬进 core。
  • 【灰色】只有一部分应该下沉,条目里写了边界。

路径缩写:M: = macos/Sources/,W: = windows/tauri/src/,T: = windows/tauri/src-tauri/src/,WC: = windows/tauri/crates/,C: = rust/lithe-core/src/。证据按“macOS;Windows;core”的顺序列出。

1. 先修:7 个已核实的 bug

都是小改动,可以先单独提 PR,不用等对应的大条目。

  • BUG-1 macOS 上不指向提交的标签也会显示删除菜单。M:Lithe/Core/Rust/RustCoreBridge.swift:1240 解码了 peelsToCommit,但 :1327 的 makeReference 没有传下去;M:LitheGitModule/Models/GitModels.swift:217 默认它为 true,:234 的 supportsTagDeletion 因此判断错误,M:Lithe/Views/Git/GitLogView.swift:1105 的菜单被错误启用,执行时才被 core 拒绝。(对应 GIT-02)
  • BUG-2 Windows 快捷键 when 表达式会死循环。W:features/keymaps/utils/context.ts:28 的 tokenize 遇到 @、单个 & | =、- 等字符时,既不前进也不报错。导入入口 W:features/keymaps/utils/keybinding-import-export.ts:72 接受任意非空 when,W:features/keymaps/hooks/use-keymaps.ts:282 在按键事件里求值,前端卡死。(对应 WS-09)
  • BUG-3 Windows Problems 面板右键快速修复失败。W:features/diagnostics/stores/diagnostics.store.ts:39 把 severity 转成 "error" 等字符串,W:features/editor/lsp/lsp-client.ts:1965 和 W:platform/lsp-core-adapter.ts:1382 原样发出;C:lsp/interface/types.rs:212 要求 Option<i64>,请求在到达语言服务器之前就反序列化失败。入口在 W:features/diagnostics/components/diagnostics-pane.tsx:281。(对应 LSP-01)
  • BUG-4 Windows 无法对提交列表的第一行 cherry-pick。W:features/git/components/log/git-commit-table.tsx:654 写死了 commits[0]?.hash === row.commit.hash 时禁用;查看其他分支时,第一行是那个分支的尖端而不是 HEAD,合法操作被禁。(对应 GIT-03)
  • BUG-5 macOS AI 提交消息的输出上限只有 256 token。M:LitheAIAssistanceModule/Services/CommitMessageGenerationService.swift:33 用了 maximumOutputTokens: 256;core C:ai/generation.rs:7 的 COMMIT_OUTPUT_TOKEN_BUDGET 是 4096,敏感文件规则也更全,目前只有 T:ai_commit.rs:225 在用。修法就是 GIT-01。
  • BUG-6 Windows 整文件回滚会漏掉 rename 的源路径,新增文件会尝试从 HEAD 恢复。W:features/git/components/status/git-status-panel.tsx:780 只把当前路径传给 rollbackFilesChanges。(对应 GIT-04)
  • BUG-7 macOS saved changes 自己拼 stash show --include-untracked --patch --binary,再用 Swift parser 解析(M:LitheGitModule/Services/GitService.swift:1313);core C:git/mod.rs:1969 的 git.diff 已经支持 stashReference。(对应 GIT-20)
2. Git(34 条)

P0

  • GIT-01 AI 提交消息生成【接线】macOS 自己生成请求、prompt、预算和清洗,输出上限 256(core 是 4096),敏感路径只拦 .env* 和部分证书扩展名;core 能识别输出额度耗尽,禁用正文时只返回首行,Swift 没有这些规则。证据:M:LitheAIAssistanceModule/Services/CommitMessageGenerationService.swift:16、:188、:431;T:ai_commit.rs:225、:269;C:ai/generation.rs:90、:222、:239。→ 补 ai.planCommit / ai.decodeCommitMessage 的 JSON bridge,macOS 切过去;凭据和 HTTP 留平台。
  • GIT-02 标签的 peelsToCommit 在 bridge 丢失【接线】见 BUG-1。Windows 的 W:platform/core-result-adapter.ts:224 保留了这个字段;core 在 C:git/mod.rs:7297 推导、:5318 拒绝删除。→ 直接消费 git.references.peelsToCommit,去掉语义字段的宽松默认值。
  • GIT-03 历史动作资格【计划】Windows 把第一行当成 HEAD 禁止 cherry-pick(BUG-4),还从已加载的图里自行推导 squash 的 first-parent 连续性,和 core 在真实 HEAD 链上的判断形成两份真源。证据:M:Lithe/Views/Git/GitGraphView.swift:57、M:Lithe/Views/Git/GitHistoryRewriteMenu.swift:9;W:features/git/components/log/git-commit-table.tsx:654、W:features/git/utils/git-history-selection.ts:52;C:git/rewrite.rs:261、:299。→ git.historyActionCapabilities,最终授权仍走现有 rewrite preview。 完成: #1691。
  • GIT-04 整文件回滚的目标规则【计划】macOS 对新增文件先 unstage、默认保留磁盘文件,rename 带上两侧路径;Windows 把所有非 untracked 项交给 discardAll,并且只传当前路径(BUG-6)。证据:M:LitheGitModule/Models/GitRollbackSelection.swift:33、M:LitheGitModule/Application/GitFeatureModel.swift:1814、M:LitheGitModule/Models/GitModels.swift:893;W:features/git/components/status/git-status-panel.tsx:754、:212、W:features/git/api/git-status-api.ts:381;core 只有 C:git/mod.rs:5655 的 discard_all。→ git.rollbackPlan:输入完整的 change 身份和 deleteAddedFiles,由 core 推导路径和步骤。 完成: #1687、#1692。
  • GIT-05 右键“提交所选文件”的 index 准备【计划】macOS 先取消其他文件的暂存,只暂存尚未暂存的所选文件,再复核 index;Windows 直接 stage 所选路径。A 已暂存、B 部分暂存时右键提交 B,Windows 会把 A 和 B 的剩余修改一起带进提交。证据:M:LitheGitModule/Application/GitFeatureModel.swift:2008、:2067;W:features/git/components/status/git-status-panel.tsx:740、:661、W:features/git/components/git-view.tsx:921;C:git/workspace_commit.rs:293。→ git.prepareCommitSelection,保留部分暂存,检查 ChangeList 和实际结果。 完成: #1693。
  • GIT-06 删除已暂存的新文件后清理 index【计划】macOS 删除后重新读取状态,只对确认已消失的新增项 unstage;Windows 没有这一步,已经删掉的新文件内容仍可能进入下一次提交。证据:M:LitheGitModule/Application/GitFeatureModel.swift:2014、:2041;W:features/git/components/status/git-status-panel.tsx:792、W:features/git/utils/git-status-deletion.ts:11、W:features/file-system/stores/file-system.store.ts:2708。→ git.reconcileDeletedSelection:根据删除前的选择和删除后的状态,生成有限的 unstage 操作。 完成: #1694。
  • GIT-07 ChangeList 归属与提交范围【双写】删除 ChangeList 时,Swift 删掉 assignment,TS 改成显式 default。例如 dir/ 属于 L1、dir/a 属于被删除的 L2,之后 Swift 把 a 归入 L1,Windows 归入 Default,提交范围也就不同。rename、目录继承和校验也各有一份。证据:M:LitheGitModule/Application/GitFeatureModel+Changelists.swift:89、M:LitheGitModule/Models/GitLocalChangelists.swift:30、:73;W:features/git/stores/git-changelists.store.ts:86、W:features/git/utils/git-changelists.ts:35、:83;core 的 C:git/workspace_commit/path_scope.rs:11 只校验平台给的范围。→ git::changelists 纯 reducer:membership 和 commitScope;UI 和持久化留平台。 完成: #1697。
  • GIT-08 Shelf 保存后的清理与恢复【计划】macOS 保存后直接逐路径 discardAll,不验证当前内容是否仍等于保存的内容,保存期间的新编辑可能被清掉;Windows 会重新比较快照,并用 core 的状态令牌反向应用。恢复顺序和部分成功后的重试规则,两端各写一份。证据:M:LitheGitModule/Application/GitFeatureModel.swift:2186、:2230、:2256;W:features/git/services/git-shelf-workflow.ts:42、W:features/git/api/git-shelf-api.ts:65;C:git/patch_exchange.rs:375、:421。→ git::shelf 的 capture / clean / restore 计划,清理统一用 reviewed reverse patch。 完成: #1708。
  • GIT-09 AI 提交上下文与过期判断【计划】macOS 跳过读取失败或空的 diff,生成后只比较路径 ID,同一路径重新暂存了新内容时仍会接受旧说明;Windows 遇到缺失的 diff 会失败并做哈希比较,但读取走 30 秒的 diff 缓存。证据:M:LitheGitModule/Application/GitFeatureModel.swift:1644、M:Lithe/Application/Features/CommitWorkflowCoordinator.swift:85、M:Lithe/Application/Composition/CommitWorkflowComposition.swift:13;W:features/git/services/ai-commit-context.ts:34、:75、W:features/git/services/ai-commit-workflow.ts:17、W:features/git/api/git-diff-api.ts:165;C:git/commit_state.rs:121。→ git.commitMessageContext 返回完整输入、截断信息和 index token,应用结果前校验 token;预算统一由 ai 管。 完成: #1711。
  • GIT-10 Blame 的所属仓库解析【计划】macOS 用当前活动仓库根做前缀相对化,多仓库下编辑的文件属于另一个仓库时,blame 为空或查错仓库;Windows 按文件父目录发现仓库。证据:M:LitheGitModule/Application/GitFeatureModel.swift:2876、M:LitheGitModule/Services/GitService.swift:861;W:features/git/api/git-blame-api.ts:11、W:features/git/api/git-repo-api.ts:152;C:git/mod.rs:3425、:1004、C:vcs/roots.rs:138。→ git.resolveFileContext 输出真实 root、相对路径和归属,供 blame、diff、gutter 共用。 完成: #1717。
  • GIT-11 多仓库状态刷新失败时的合并【计划】Swift 只要有一个仓库成功,就用成功的集合重建变更列表,失败仓库的行会消失;Windows 遇到必需根失败就放弃整次发布。证据:M:LitheGitModule/Application/GitFeatureModel.swift:989、:902;W:features/git/api/git-status-api.ts:131、W:features/git/stores/git.store.ts:281;core 只有单仓库的 C:git/mod.rs:7962。→ git.workspaceStatus 或 mergeWorkspaceStatus(previous, outcomes),显式带上每个根的成败和可保留的快照。 完成: #1718。
  • GIT-12 提交日期的时区【接线】macOS bridge 的提交 DTO 不接收时区偏移,再按本机时区解析,跨时区的提交会落进错误的“今天”或日期区间;Windows 保留了偏移。证据:M:Lithe/Core/Rust/RustCoreBridge.swift:1247、M:LitheGitModule/Models/GitModels.swift:716、:814;W:platform/core-result-adapter.ts:251、W:features/git/utils/git-log-date.ts:8;C:git/mod.rs:7349、C:protocol/contracts.rs:690。→ 先接上偏移字段;再由 git.historyQuery 统一日期比较,当前时间和用户时区作为输入。
  • GIT-13 标签创建和删除【拼命令】Windows 走兼容命令,在 host 里自己拼 git tag 参数,能创建 core 契约拒绝的非 commit 标签,删除时也不产生 core 的恢复记录;macOS 用的是类型化的 createTag / deleteTag。证据:M:Lithe/Core/Rust/RustGitOperations.swift:466;W:features/git/api/git-tags-api.ts:36、:137、T:platform.rs:675、:716;C:git/mod.rs:1499、:5286。→ 统一 git.write(createTag/deleteTag),签名和 lightweight 模式纳入类型化请求。 完成: #1728。
  • GIT-14 Branch Update / Pull 策略【计划】同一个“更新当前分支”,历史分叉时 macOS 让用户选策略,Windows 直接 merge;默认策略一个是 ffOnly、一个是 merge;Windows 会拦住 dirty 状态并复查前检,macOS 前检失败后仍继续执行。证据:M:LitheGitModule/Application/GitFeatureModel.swift:4258、M:Lithe/Core/Rust/RustGitOperations.swift:322;W:features/git/services/git-log-branch-update.ts:21、W:features/git/utils/git-pull-selection.ts:25、W:features/git/hooks/git-pull-workflow.ts:86;C:git/mod.rs:3148、:1332。→ git.updatePlan:统一默认策略、blocker、需确认的状态,以及期望的 checkout 和 upstream。
  • GIT-15 历史刷新时的窗口与选择【计划】Windows 收到 metadata 事件后固定重拉第一页 50 条,翻到深处的历史会缩回去,选中的提交和范围锚点也会丢;macOS 按已加载的数量刷新,并计算头部新增造成的位移。证据:M:LitheGitModule/Application/GitFeatureModel.swift:2399、:2494、:3063;W:features/git/hooks/use-git-log-controller.ts:321、:141、:209、W:features/git/components/log/git-log-tool-window.tsx:804;C:git/history.rs:256。→ git::history_window:refreshPlan、mergePage、reconcileSelection;像素级滚动锚点留在视图。
  • GIT-16 新分支名的清理与冲突预检【计划】Windows 删掉非法字符、把空格换成 - 后再创建,并自己检查 HEAD、本地、远程和前缀冲突;macOS 只做 trim,交给 Git 拒绝。证据:M:Lithe/Views/Git/GitLogView.swift:2147;W:features/git/utils/git-branch-name.ts:29、:86、W:features/git/components/log/git-create-branch-dialog.tsx:95;C:git/mod.rs:5194。→ git.branchNamePreview 返回规范化后的候选和结构化冲突,ref 是否合法仍交给 Git 判断。 完成: #1728。
  • GIT-17 从 Blame 定位到 Log 中的提交【计划】macOS 找不到时单独查询这个提交并插到列表最前面,打乱了拓扑顺序;Windows 最多追 20 页,找不到就放弃。证据:M:LitheGitModule/Application/GitFeatureModel.swift:2884;W:features/git/components/log/git-log-tool-window.tsx:94、:284;core 已有 git.commit 和 git.historyPage(C:protocol/command.rs:817)。→ git.historyLocate:统一引用范围、预算、定位结果,以及窗口外提交的处理方式。 完成: #1728。

P1

  • GIT-18 提交图的布局、lane、引用优先级和颜色【双写】Swift 和 TS 各有一套完整的拓扑布局(DFS、permanent layout、head 排序、按名称哈希定色)。core 的 C:git/graph.rs:125 有一份固定槽位投影,但既没有 JSON 命令也没有调用方,颜色规则和两端都不一样。证据:M:LitheGitModule/Services/GitGraphProjection.swift:88、:182、M:LitheGitModule/Services/GitGraphHeadOrdering.swift:8;W:features/git/utils/git-graph-layout.ts:258、:283、:543、W:features/git/utils/git-graph-colors.ts:52。→ 扩展 git::graph,新增 git.graphProjection,返回整数 lane、稳定的 color ID、路由和标签;平台只负责像素和主题。不能直接把现有的 project_graph 接上去,要先把现有行为连同 fixture 搬进 core。
  • GIT-19 过滤后的提交图:虚线拓扑、隐藏祖先、missing parents【双写】TS 注释里写明了照搬 macOS;core 的 graph.rs 只接受 commits,没有可见集合的上下文。证据:M:LitheGitModule/Services/GitGraphProjection.swift:75、:122、M:LitheGitModule/Services/GitGraphMissingParents.swift:14;W:features/git/utils/git-graph-filter-projection.ts:14、W:features/git/utils/git-graph-layout.ts:493。→ 并入 GIT-18,给 git.graphProjection 增加 visibleHashes 和仓库上下文输入。
  • GIT-20 core 已经解析过的 diff,平台又解析一遍;stash 专用 API 没用上【接线】macOS saved changes 用 Swift parser(BUG-7);Windows adapter 重新解析 patch 的文件边界、状态和行号,扔掉现有的 hunks,再交给写入链路重建。证据:M:LitheGitModule/Services/GitService.swift:1303、M:LitheGitModule/Models/GitSavedChangesSnapshot.swift:16、M:LitheGitModule/Models/GitModels.swift:1480;W:platform/core-result-adapter.ts:106、W:features/git/utils/git-diff-parser.ts:41;C:git/mod.rs:1969、:2271。→ saved stash 统一用 stashReference;git.diff 返回按文件组织的结构;需要时新增 git.parsePatch,复用现有 parser。 完成: #1688 接入 macOS Stash;#1690 接入 Shelf 与 Windows 逐文件差异和保真 hunk。
  • GIT-21 可写 diff block、部分暂存状态与 hunk 构造【计划】TS 计算 checked / indeterminate、暂存导致的坐标偏移,以及 stage / unstage / revert 的 patch,host 再拼一次 patch。这些结果决定了实际写入的范围。证据:macOS 直接消费 core hunk(M:LitheGitModule/Application/GitFeatureModel.swift:1695);W:features/git/utils/commit-diff-blocks.ts:63、W:features/git/utils/monaco-diff-rows.ts:25、W:features/git/utils/git-gutter-changes.ts:259、T:platform.rs:857;C:git/mod.rs:7667、:2289。→ git.planDiffBlocks / git.planGutterChange 返回稳定的 block ID、资格,以及由 core 持有的 patch。
  • GIT-22 字节保真回滚与 .gitattributes 安全判断【拼命令】TS 自己拼 check-attr、解析输出、判断 filter 和 encoding 是否安全、切出 U0 patch、写之前比较快照,这些都不在 core 的写锁内。证据:W:features/git/utils/lossy-rollback-attrs.ts:17、:39、W:features/git/utils/lossy-rollback-patch.ts:22、W:features/git/api/git-diff-api.ts:357;C:git/mod.rs:2271、:2304。→ git.hunkRollbackPreview / git.hunkRollbackApply,core 返回资格、raw patch 身份和状态令牌,并在写锁内复核。
  • GIT-23 Git 元数据变更的分类与刷新范围【双写】Swift 和 Windows Rust 各自理解 linked worktree 的私有状态、公共 refs、objects / lfs / lithe-commit-* 过滤以及 index-only;Windows 只刷新 working tree,Swift 会广泛触发 metadata 和 history 刷新。证据:M:LitheCoreContracts/Workspace/DirectoryChangeContracts.swift:34、M:Lithe/Platform/MacOS/FileWatching/MacDirectoryWatcher.swift:152、M:LitheWorkspaceModule/Application/WorkspaceFeatureModel.swift:1393;WC:project/src/git_watcher.rs:248、:262、T:file_events.rs:20、W:features/git/runtime/git-metadata-watch-host.tsx:22、W:features/git/runtime/git-read-coordinator.ts:14;core 的 C:git/mod.rs:7788 只负责发现路径。→ git.classifyMetadataChanges(context, events) 返回受影响的仓库和刷新范围;watcher 注册和计时留平台。(WS-15 是同一件事,在这里一起做。) 已完成:#1748。
  • GIT-24 交互式 rebase 的计划校验与消息推导【双写】Swift、TS、core 三处都推导 squash / fixup 的消息;Swift 默认的 squash 不裁掉前一条消息末尾的换行,预览和实际结果可能不一致。证据:M:LitheGitModule/Models/GitRebasePlanDraft.swift:29、:80;W:features/git/utils/git-rebase-plan.ts:5、W:features/git/components/git-rebase-dialog.tsx:199;C:git/rebase_session.rs:264(目前只在 :751 启动时用到)。→ git.rebasePlanPreview 复用 planned_messages,返回校验码、每一步的消息和输出的提交数。
  • GIT-25 Git 执行日志的归约与保留【双写】【灰色】两端各写一份 started / output / finished → running / completed / unconfirmed 的状态规则,单条保留预算一个 32768、一个 65536,还各自再脱敏一次(core 已经脱敏过)。证据:M:LitheGitModule/Models/GitExecutionModels.swift:133、:62、M:LitheGitModule/Models/GitConsoleModels.swift:202;W:features/git/services/git-execution-journal.ts:51、:29、:133;C:git/execution_events.rs:492。→ git::execution_journal::reduce 加统一的保留策略;存储、锁和通知节流留平台。
  • GIT-26 GitHub PR checkout【拼命令】macOS adapter 自己拼 PR 的 fetch refspec 和 checkout -B(会覆盖同名分支),分支名清理也在这里做。Windows 的 GitHub 后端能力目前关闭。证据:M:Lithe/Platform/MacOS/GitHub/MacGitHubGitOperations.swift:51、:70;W:config/backend-capabilities.ts:13。→ git.checkoutPullRequest 或 github.checkoutPlan,显式返回分支冲突和需要确认的动作。 完成: #1737。
  • GIT-27 Remote 和 Tag 列表【拼命令】Windows host 构造 remote -v 和 for-each-ref,前端用正则解析 URL、按 NUL 切分标签字段;标签名用的是 %(refname:short),branch 和 tag 同名时没有 core 的规范化。证据:T:platform.rs:645、:663、W:platform/core-result-adapter.ts:322;C:git/history.rs:136、C:git/mod.rs:7309。→ git.remotes / git.tags 返回 URL、tag object、peeled target、日期和注释。 完成: #1736。

P2

  • GIT-28 未跟踪目录摘要的操作目标去重【双写】两端各自去掉“目录摘要 + 已列出的子文件”这类重复目标,影响 Shelf、删除和回滚的范围。证据:M:LitheGitModule/Application/GitFeatureModel.swift:1094、M:LitheGitModule/Models/GitModels.swift:866、:975;W:features/git/utils/git-untracked-directories.ts:24、:38、W:features/git/utils/git-status-selection.ts:99;C:git/untracked_directories.rs:81。→ 在共享的选择规划里加 normalizeChangeTargets。
  • GIT-29 引用树的分组与排序【双写】【灰色】同一组引用在两端的树结构和顺序不同。证据:M:Lithe/Views/Git/GitReferenceRows.swift:263、:300;W:features/git/utils/git-reference-tree.ts:70、:99;core 的 C:git/history.rs:140 只给平铺列表。→ git.referenceTree;展开、缩进和虚拟化留在视图。
  • GIT-30 与工作区比较时合并 untracked 文件【接线】macOS 服务层自己读 comparison 和 status,再合并、去重;Windows 交给 core 处理。证据:M:LitheGitModule/Services/GitService.swift:875;T:platform.rs:503;C:git/mod.rs:2103、:2460。→ 给 git.comparison 增加 includeUntracked。 完成: #1735。
  • GIT-31 Fetch 标签行为的实际生效值【计划】macOS 设置页自己解析 remote 和 global 的 pruneTags、tagOpt、skipFetchAll,来解释实际会怎么 fetch。证据:M:LitheGitModule/Models/GitConfigurationFallback.swift:47、M:Lithe/Views/App/GitExecutionSettingsView.swift:239;C:git/configuration.rs:361、C:git/fetch_execution.rs:80。→ git.executionInspect 增加 resolvedFetchBehavior。 完成: #1738。
  • GIT-32 最近项目的 HEAD 与 gitdir 解析【灰色】macOS 为了不启动 Git,直接读 HEAD 和 gitdir 指针。有界读文件留平台,文本解释可以共享。证据:M:Lithe/Platform/MacOS/RecentProjectBranchReader.swift:18、:41。→ 纯函数 git.parseCheckoutMetadata / git.parseGitdirPointer。 完成: #1736。
  • GIT-33 仓库颜色分配【灰色】两端各自做路径匹配、按位置取模和未知路径回退。证据:M:Lithe/Views/Git/GitRepositoryColor.swift:26;W:features/git/utils/git-repository-colors.ts:24、:41。→ git.repositoryColorAssignments 返回“仓库 ID → 稳定槽位”,色板留平台。 完成: #1741。
  • GIT-34 GitHub Device Flow 的状态与退避【计划】macOS 自己裁剪过期时间和轮询间隔,自己处理 pending、slowDown、expired、denied。证据:M:Lithe/Services/GitHub/GitHubService.swift:88;core 的 C:github/mod.rs:605 只归一化协议状态。→ github.deviceAuthorizationTransition 返回下一个状态、等待时间和终止原因。 完成: #1737。
3. 运行、构建、调试、测试(17 条)

P0

  • RUN-01 运行参数编辑后丢失参数边界【计划】两端都把参数数组用空格连起来,再交给 core 拆分:["--name","Alice Smith"] 保存后变成三个参数,只改其他配置也会重写参数。证据:M:Lithe/Platform/MacOS/RunConfiguration/MacRunConfigurationStore.swift:130、:284;W:features/run/stores/run.store.ts:352、W:features/run/api/run-core-api.ts:179;C:execution/configuration.rs:1625、:3037。→ 编辑契约里保留参数数组,或者用 execution.argumentText 提供可逆的编码。 完成: #1732。
  • RUN-02 启动时 PATH 的优先级与候选顺序【计划】macOS 保留已有 PATH 的优先级,再往后追加;Windows 把运行时和启动器目录插到显式 PATH 前面,运行时目录来自 HashMap.values(),顺序不稳定。证据:M:Lithe/Services/Java/RunLaunchEnvironment.swift:38、M:Lithe/Services/Java/RunExecutableResolver.swift:61;T:run.rs:681、:2056、:2072;C:execution/environment.rs:35。→ execution.resolveSearchPath 统一候选顺序和显式覆盖的优先级;路径分隔符和环境 I/O 留平台。 完成: #1732。
  • RUN-03 测试零匹配时的最终判定【计划】选中的测试一个都没跑时,macOS 只看退出码判为通过,Windows 判为失败。证据:M:LitheExecutionModule/Services/LanguageTestService.swift:452、:479;W:features/maven/stores/maven.store.ts:1424;C:project/maven.rs:1495。→ build.resolveTestRunOutcome:输入退出码、超时或取消、解析状态、选择范围和结果,返回统一的结论。
  • RUN-04 Maven Portable 配置的 Profile 保留【插件】macOS 原样保留 selectedProfiles,Windows 回读时删掉不在 POM 和 customProfiles 里的 Profile。证据:M:LitheExecutionModule/Services/MavenService.swift:935、:95、M:Lithe/Platform/MacOS/Persistence/MacMavenConfigurationStore.swift:17;W:features/maven/stores/maven.store.ts:874、:245、T:maven.rs:30。→ 在 #1495 的 Maven 插件里统一,不在 core 新增 Maven 专用 API。
  • RUN-05 Windows 编辑源码后断点不跟着移动【接线】Windows 的编辑回调不更新断点 store,store 里和发给适配器的行号还是旧的,重新投影或启动调试时会回到错误的位置;macOS 已经接了 core。证据:M:Lithe/Platform/MacOS/MonacoWorkbenchEditor.swift:1555、M:Lithe/Core/Rust/RustDebugProtocolCore.swift:16;W:features/editor/components/monaco-editor.tsx:1846、W:features/debugger/stores/debugger.store.ts:185、W:features/debugger/services/monaco-debug-decorations.ts:43;C:debug/breakpoint_relocation.rs:41。→ Windows 接入 debug.relocateBreakpoints。
  • RUN-06 Windows 一次请求所有 Scope 和变量,并丢掉数量信息【接线】macOS 优先请求非 expensive 的 Scope 并分页;Windows 同时请求所有 Scope,丢掉 named / indexed 数量,展开时也不传 start / count。证据:M:LitheDebugModule/Application/GenericDebugFeatureModel.swift:1508、:2728;W:features/debugger/services/debug-adapter-events.ts:202、:320、W:features/debugger/components/debugger-variables-panel.tsx:59;C:debug/engine.rs:1959、:2574。→ 先用上 debug.inspect 已有的字段,core 之后可以统一默认请求上限;页大小和展开状态留平台。
  • RUN-07 Windows 把 sourceReference 源码当磁盘文件打开【接线】反编译或适配器提供的源码会被当成本地文件打开,同时丢掉了 isFiltered 和指令地址。证据:M:LitheDebugModule/Runtime/CoreDebugAdapterProtocolSession.swift:369、:694;W:features/debugger/services/debug-adapter-events.ts:302、W:features/debugger/components/debugger-view.tsx:338;C:debug/engine.rs:2332、C:debug/projection_v2.rs:73。→ 完整消费 debug.projectionV2 的源码身份。
  • RUN-08 服务端口推导与调试前的拒绝规则【插件】macOS 私下实现了参数、环境变量、配置文件之间的端口优先级,读取第一个带端口的 application-* 文件,不看活动 Profile;如果那个未生效 Profile 的端口恰好被占用,调试会被错误拒绝。证据:M:LitheExecutionModule/Services/RunService.swift:2240、:764、M:Lithe/Application/Features/DebugLaunchPreparationCoordinator.swift:71。→ 由 provider 返回有效的 endpoint 或“未知”;core 只做通用的 endpoint 校验,平台检查端口占用。不要把这套算法复制进 core。

P1

  • RUN-09 测试选择、框架判断与命令构造【插件】macOS 按项目标记选工具,自己拼 -Dtest=、--tests;Windows 按目录约定推导模块和类名,再拼 Surefire 参数。core 已有的类型化 Test 计划没被用上。证据:M:LitheExecutionModule/Services/StandardLanguageTestProvider.swift:82、:141、:200、M:LitheExecutionModule/Services/LanguageTestService.swift:174;W:features/maven/utils/maven-test-selection.ts:105、W:features/maven/stores/maven.store.ts:1238、:404;C:build/plans.rs:628、C:build/test_discovery.rs:34。→ 复用 build.testDiscoveryPlan / build.testPlan,选择器由 provider 或 JDT 提供。
  • RUN-10 测试历史的覆盖合并【双写】两端都实现了“按方法运行只替换这个方法,按类运行替换这个类和 $ 嵌套类”。证据:M:LitheExecutionModule/Services/LanguageTestService.swift:547、:471;W:features/maven/stores/maven.store.ts:385、:1416。→ build.mergeTestOutcomes,覆盖范围由 provider 明确给出,core 不去猜 Java 嵌套类的语义。
  • RUN-11 Java 主入口复用哪份运行配置【双写】两端各自过滤、匹配 source 和 mainClass、打分,决定 Run 和 Debug 用哪份配置。证据:M:Lithe/Models/AppModel/AppModel+JavaRunMarkers.swift:116、:77;W:features/run/services/java-main-launch.ts:21、:80;C:execution/configuration.rs:1047。→ runConfig.selectContextConfiguration:输入入口身份(由插件提供)、配置列表和 preferredID,输出配置 ID;core 只做通用匹配。 完成: #1733。
  • RUN-12 自动调试表达式【插件】Swift 维护了一张 Java 关键字表,扫描当前行,失败时再试 this.<name>,没有处理字符串和注释。证据:M:Lithe/Application/Features/DebugAutomaticExpressionProjection.swift:7、M:Lithe/Models/AppModel/AppModel+ExecutionModules.swift:120、M:LitheDebugModule/Application/GenericDebugFeatureModel.swift:1629。→ 候选表达式由 Java provider 生成;core 只做和语言无关的去重、预算和取消。

P2

  • RUN-13 Spring 配置补全【插件】【灰色】macOS 扫描 token、推导 YAML 父键、做包含匹配;Windows 只支持 properties,做前缀匹配。证据:M:Lithe/Application/Features/SpringFeatureModel.swift:127、:259;W:features/spring/utils/spring-property-completion.ts:16、W:features/editor/engines/monaco/lsp-providers.ts:151。→ 由 Spring provider 返回补全项和编辑范围。
  • RUN-14 反汇编的分页恢复【灰色】二分缩小窗口、耗尽判定和负偏移回退只在 macOS 有;Windows host 还没有开放 disassemble 和 readMemory。证据:M:LitheDebugModule/Application/GenericDebugDisassemblyModel.swift:338、:365、:546;T:debug.rs:761、:798;C:debug/engine.rs:792。→ debug.planDisassemblyWindow / debug.reduceDisassemblyPage;视口和滚动锚点留平台。
  • RUN-15 JDK release 文件的版本解析【接线】Windows 读完文件后调 core,Swift 手写了同样的 JAVA_VERSION 解析。证据:M:Lithe/Platform/MacOS/RunConfiguration/MacJavaLaunchArgumentPreparer.swift:117;T:run/launch_arguments.rs:148;C:execution/launch_command.rs:118。→ macOS 改用 core 现有的函数;如果 #1495 把 JDK 解析迁到插件,这里一起迁。 完成: #1733。
  • RUN-16 Windows Run Actions 里休眠的解析器【双写】TS 自己解析 manifest、选择包管理器、拼 Cargo、Make、Python 命令。现在 runActions:false,不在活动路径上,但重新打开就会恢复第二套规则。证据:W:features/run-actions/utils/run-action-discovery.ts:131、:166、W:config/backend-capabilities.ts:16;C:execution/detectors/npm.rs:92、C:execution/detectors/cargo.rs:8、C:execution/detectors/make.rs:15。→ 重新开启前改成消费 runConfig.generate / runConfig.resolve,或者直接删掉。 完成: #1738。
  • RUN-17 测试 JVM worker 识别与 JFR【插件】【灰色】macOS 按 Surefire、JUnit、TestNG、Gradle 的主类名猜测试 worker,并自己拼 JFR 参数。证据:M:Lithe/Platform/MacOS/Debug/MacTestJVMPerformance.swift:19、:69、:94。→ provider 返回 worker 身份和性能采集计划;采样和清理留平台。
4. LSP、编辑器、文档(17 条)

P0

  • LSP-01 code action 请求的 severity 类型错误【接线】见 BUG-3。另外 Windows 的展示模型丢掉了 tags 和 relatedInformation。→ 用 lsp::LspClientDiagnostic 作为完整诊断的唯一来源,展示字段另行派生;code action 按诊断身份或原始对象调用。
  • LSP-02 TextEdit 的范围计算与批量应用【接线】Windows 自己算行偏移、排序和拼接,把不存在的行夹到文件末尾,不拒绝反向范围、重叠编辑和落在代理对中间的位置;macOS 用的是 core。证据:M:Lithe/Services/Language/LanguageServerTextEditApplicator.swift:17;W:features/editor/lsp/workspace-edit.ts:97、:135、W:features/editor/lsp/lsp-client.ts:1824;C:lsp/lightweight/edits.rs:34(lsp.applyTextEdits)。→ Windows 改用 lsp.applyTextEdits。
  • LSP-03 Workspace edit 的目标限制与提交保护【计划】macOS 先确认所有目标都在工作区内,再检查只读、工作区身份和文档版本,失败时可以回滚;Windows 读完就并行提交,不限制工作区,不检查版本,部分失败也不回滚,未打开的文件按 UTF-8 重写。证据:M:Lithe/Platform/MacOS/MonacoWorkbenchEditor.swift:638、M:Lithe/Application/Features/LanguageWorkspaceEditService.swift:39;W:features/editor/lsp/workspace-edit.ts:168、:207、W:features/file-system/controllers/platform.ts:38;C:lsp/interface/client.rs:1605。→ lsp.planWorkspaceEdit 返回校验结果、稳定的提交顺序和效果计划;带保护的写入和撤销留平台。
  • LSP-04 跳转到外部源码时的许可与只读【计划】macOS 区分工作区内、同语言的外部源码(只读)和拒绝三种情况;Windows 遇到物理路径直接作为可编辑 buffer 打开,也不读 isReadOnly。证据:M:Lithe/Application/Features/LanguageNavigationCoordinator.swift:222、M:Lithe/Models/AppModel/AppModel+CodeNavigation.swift:282;W:features/editor/lsp/navigation-target.ts:81;C:lsp/interface/client.rs:1531。→ lsp.classifyNavigationTarget 返回 workspace、externalReadOnly 或 rejected。
  • LSP-05 引用结果按“同文件同一行”过滤【计划】Windows 会把和当前位置在同一行的引用全部删掉,可能误报“没有其他引用”;macOS 会保留。证据:M:Lithe/Application/Features/LanguageNavigationCoordinator.swift:201;W:features/keymaps/commands/navigation-command-actions.ts:135、:753。→ 如果确实要排除当前位置,就在 core 里按 URI 加完整范围来判断。 完成: #1731。
  • LSP-06 文件路径转 LSP URI【计划】TS 拼出 file:// 后调 encodeURI,# 和 ? 不会被编码,A#B.java 这样的文件 URI 身份就错了。证据:M:Lithe/Core/Rust/RustCoreBridge.swift:3906;W:platform/lsp-core-adapter.ts:364、:864、:1666;C:lsp/interface/client.rs:1671、C:lsp/interface/engine.rs:5911。→ lsp.documentUri / lsp.normalizeDocumentIdentity,统一盘符、UNC、百分号编码和保留字符的规则。 已完成:#1744。
  • LSP-07 Windows Markdown 预览绕过 core【接线】Windows 用自写的正则和列表状态机,并且会展示 front matter;core 用 Comrak 加 Ammonia,隐藏 front matter,支持 alerts、上下标、数学公式和 shortcode。证据:M:Lithe/Core/Rust/RustMarkdownRendering.swift:6;W:features/editor/markdown/use-highlighted-markdown.ts:13、W:features/editor/markdown/parser.ts:23、:171;C:project/markdown.rs:28。→ Windows 改用 markdown.render;需要展示 front matter 的话由 core 返回结构化的 metadata。
  • LSP-08 LSP 启动失败后的重试策略【计划】macOS 连续失败 3 次后不再自动启动,需要用户显式恢复;Windows 5 秒后清掉失败记录,继续尝试。证据:M:LitheLanguageIntelligenceModule/Services/LanguageToolingSessionManager.swift:77、:1647;W:features/editor/lsp/language-server-failure-cooldown.ts:1、W:features/editor/lsp/lsp-client.ts:1104;C:lsp/interface/engine.rs:1107。→ lsp.activationPolicy:输入事件、尝试状态和单调时间,返回允许、等待或需要显式重试。
  • LSP-09 补全合并按 label 去重,以及 Swift 私有的关键词补全【计划】服务器返回同一个 label、不同签名的多个候选时,Swift 只留第一个,Windows 全部保留;Swift 还有一套不依赖 LSP 的关键词表和排序。证据:M:LitheLanguageIntelligenceModule/Services/LanguageToolingSessionManager.swift:1930、:1960、M:LitheLanguageIntelligenceModule/Providers/LanguageFeatureProvider.swift:289、:368;W:features/editor/lsp/lsp-client.ts:1484;C:lsp/lightweight/symbols.rs:91。→ lsp.mergeCompletions 用完整的候选身份去重;关键词由语言插件声明或复用上游的词法资源,不在 core 里写各语言的关键词表。
  • LSP-10 Go to Line 的输入解析【计划】输入 120:35 时,macOS 定位到第 35 列,Windows 把列丢掉;输入 12abc 时,Windows 接受,macOS 拒绝。证据:M:Lithe/Models/Editor/GoToLineInput.swift:24、M:Lithe/Models/AppModel/AppModel+GoToLine.swift:29;W:features/keymaps/commands/navigation-command-actions.ts:587。→ editor.parseNavigationInput 返回规范化的行列号,以及是否整行选中。 完成: #1741。

P1

  • LSP-11 文档版本号有两套【接线】Windows 拿到了 core 的版本号但没有往上返回,上层另外从 1 开始计数,并用这个计数丢弃诊断。证据:M:LitheLanguageIntelligenceModule/Runtime/LanguageServerSession.swift:474;W:platform/lsp-core-adapter.ts:1465、W:features/editor/lsp/lsp-client.ts:2042、:2130、:640;C:lsp/interface/engine.rs:2273、C:lsp/interface/client.rs:231。→ 透传 lsp.syncDocument 的 documentVersion,上层只保留编辑器自己的 revision。 完成: #1731。
  • LSP-12 文件属于哪个语言、由哪个插件负责【双写】Swift、TS 和 host Rust 各有一份匹配和 owner 选择逻辑;Windows 取第一个匹配的包,macOS 按语言 ID 排序。证据:M:LitheModuleAPI/Plugins/PluginTypes.swift:483、M:LitheApplicationKernel/Plugins/PluginManifestValidator.swift:199、M:LitheCoreContracts/Language/LanguageToolingContracts.swift:189;T:plugin_host/launch.rs:150、:170、W:extensions/types/extension-contributions.ts:147;C:lsp/languages/catalog.rs:65、C:plugins/declarative.rs:1943。→ languages.resolveFile / plugins.resolveLanguageOwner。(和 AGT-02 一起做。)
  • LSP-13 插件文档的编辑计划只在 Swift 里【计划】Swift 建行索引,严格校验范围、代理对和重叠,稳定排序并规范化换行;Windows 没有等价实现。证据:M:Lithe/Application/Features/EditorTextEditPlanner.swift:15、:90、M:Lithe/Application/Features/EditorDocumentService.swift:120;C:plugins/editor_actions.rs:142。→ editor.planTextEdits 返回 UTF-16 的 offset 和 length、规范化后的文本和稳定顺序;和 LSP-02 统一规则。

P2

  • LSP-14 批量保存的成员快照与结果归约【灰色】macOS 逐个保存,遇到第一个失败就停,最后重新检查 dirty;Windows 先快照 dirty 的文件,再并行保存,按结果计数。证据:M:Lithe/Application/Features/DocumentFeatureModel.swift:1010、M:Lithe/Application/Features/DocumentSaveBatch.swift:4;W:features/editor/stores/editor-app.store.ts:840;C:project/document_lifecycle.rs:148。→ documents.planSaveBatch / documents.reduceSaveBatch;并发 I/O 留平台。
  • LSP-15 导航历史【双写】【灰色】后退 / 前进栈、去重、分支截断和容量上限各写一份。证据:M:Lithe/Application/Features/NavigationHistoryFeatureModel.swift:49;W:features/editor/stores/jump-list.store.ts:49、:70。→ editor.navigationHistory.reduce;哪些手势要记进历史由平台决定。
  • LSP-16 编辑器标签和分组的状态规则【双写】【灰色】成员去重、移除空组、选中项收敛,以及移动和关闭之后的状态。证据:M:Lithe/Application/Features/EditorTabOrderFeatureModel.swift:130、:188、M:Lithe/Application/Features/EditorGroupLayout.swift:24;W:features/panes/utils/pane-tree.ts:106、:327、:422。→ editor.workbenchState.reduce;比例、像素和拖动留平台,按可调整面板的 Agent Note 执行。
  • LSP-17 Problems 列表的排序与分组【灰色】两端默认顺序不同,路径比较一个用系统的自然排序,一个用 localeCompare。证据:M:Lithe/Views/Language/JavaProblemsView.swift:216、:239;W:features/diagnostics/components/diagnostics-pane.tsx:81、:318、:373。→ lsp.problems.query 返回稳定的分组和顺序。
5. 工作区、文件、搜索、快捷键、设置(18 条)

P0

  • WS-01 全局搜索的分页、截断与过滤【计划】Windows 不用 file_offset,按文件组的数量推导 has_more(单个根最多 140 条命中,可能误报已经搜完);include / exclude 在截断之后才执行,后面符合条件的结果永远拿不到。证据:M:Lithe/Core/Rust/RustCoreBridge.swift:2702;W:features/file-search/lib/file-search-api.ts:87、W:features/global-search/hooks/use-content-search.ts:257、W:features/global-search/utils/path-filters.ts:3;C:project/files.rs:453、C:project/search_paging.rs:119。→ workspace.searchPage:在 core 里先过滤再截断,返回真实的 cursor 和计数。 完成: #1734。
  • WS-02 全局替换用的是 JS 正则【接线】Windows 搜索走 core,替换却对整篇文本跑 JS RegExp:整词搜 foo 时 core 不会命中 $foo,但 Windows 的 \bfoo\b 会把它也改掉;^foo 逐行搜索和整篇替换的结果也不一致。证据:M:LitheSearchModule/Application/SearchFeatureModel.swift:347;W:features/global-search/utils/source-replace.ts:92、:127、W:features/editor/utils/search.ts:26、W:features/global-search/components/global-search-buffer.tsx:355;C:project/files.rs:892、:1734、:1952。→ 两端都用 workspace.replacePreview,再补一个单次替换的范围 API。 完成: #1734。
  • WS-03 Quick Open 的名称匹配与评分【接线】Windows 对完整快照用 TS 模糊评分,fffSearchFiles 又只做子串匹配:输入 DH 时 core 能命中 DeviceHandler.java,TS 的两套算法都找不到。macOS 还留着一份旧的兼容打分。证据:M:Lithe/Models/Search/SearchRelevance.swift:18;W:features/quick-open/hooks/use-file-search.ts:226、W:features/quick-open/utils/fuzzy-search.ts:1、W:features/file-search/lib/file-search-api.ts:186;C:project/name_matching.rs:13。→ 统一用 workspace.searchEverywhere 的分数和高亮区间,最近访问等上下文作为显式输入。
  • WS-04 隐藏路径规则有三份【双写】Swift、TS、core 各有一份默认列表:Windows 默认的目录隐藏表里没有 node_modules 和 target,core 有;Windows 的搜索和历史调用也不带隐藏规则。证据:M:LitheCoreContracts/Workspace/FileVisibilityRules.swift:6、:75;W:features/settings/config/default-settings.ts:24、W:features/file-explorer/components/file-explorer-tree.tsx:360、W:features/file-search/lib/file-search-api.ts:104、W:features/local-history/api/local-history-api.ts:63;C:project/files.rs:19、:112、:1093。→ project::visibility 统一默认规则和批量分类,区分“只在文件树里隐藏”和“搜索、历史也排除”。
  • WS-05 文件树的自然排序【接线】Windows 先转小写再 localeCompare,v0.1.12 会排在 v0.1.4 前面,而且结果受 locale 影响;Windows 的文件树还自己枚举、自己排序,没用 workspace.listDirectories。证据:M:LitheCoreContracts/Workspace/NaturalNameOrder.swift:15;W:features/file-system/controllers/file-tree-utils.ts:4、W:features/file-explorer/lib/visible-file-tree-rows.ts:124、W:features/file-system/stores/file-system.store.ts:732;C:project/file_name_order.rs:1、C:project/files.rs:1395。→ 改用 workspace.listDirectories;确实需要平台枚举时加 workspace.orderEntries,同时删掉 Swift 的那份比较器。
  • WS-06 Local History 的记录时机与重命名迁移【计划】Windows 重命名文件后不迁移历史,旧历史留在旧路径下;保存后也不会立刻生成快照。证据:M:LitheLocalHistoryModule/Application/ProjectHistoryFeatureModel.swift:147、M:LitheWorkspaceModule/Application/WorkspaceFeatureModel.swift:845;W:features/editor/stores/editor-app.store.ts:398、W:features/local-history/api/local-history-api.ts:53、W:features/file-system/stores/file-system.store.ts:2903;C:project/history.rs:443(relocate)、:1106。→ 先让 Windows 接上 history.relocate,再做 project::history::planEvent。
  • WS-07 复制和粘贴时的重名命名【双写】有三套实现:macOS 和 Windows host 用 copy,Windows TS 的 Duplicate 用 _copy,会把 foo.txt 变成 foo._copy.txt,并且只查内存里的树,不查磁盘。证据:M:LitheWorkspaceModule/Application/WorkspaceFeatureModel.swift:1074、:2058;W:features/file-system/stores/file-system.store.ts:2864、T:host.rs:284。→ project::file_operations::{planDuplicate, planPaste},平台提供文件是否存在的事实,并以不覆盖的方式原子执行。
  • WS-08 快捷键冲突检测【计划】macOS 按最终生效的绑定检测冲突,并拒绝保存;Windows 只看用户 store,按原始字符串比较,漏掉了默认绑定、预设绑定和修饰键顺序不同的等价绑定,保存时也不拒绝。证据:M:Lithe/Application/Features/KeyboardShortcutFeatureModel.swift:112、:159;W:features/keymaps/hooks/use-keybinding-conflicts.ts:16、W:features/keymaps/components/keybinding-row.tsx:34、W:features/keymaps/utils/parser.ts:42、W:features/keymaps/hooks/use-keymaps.ts:248。→ keymap::{parseBinding, resolveBindings, analyzeConflicts};原生按键事件的转换留平台。
  • WS-09 when 表达式解析器死循环【计划】见 BUG-2。只有 Windows 有表达式解析器。→ keymap::parseContext / keymap::evaluateContext:限制输入长度,检查是否完整消费,给出稳定的语法错误码;导入和保存时校验,按键路径上只求值已经解析好的表达式。
  • WS-10 Maven settings 的读取与插值【插件】Swift 在视图里解析 XML,不检查元素层级,会展开 ${env.NAME};Windows 只认 <settings> 的直接子项,只展开 ${user.home}。同一份配置得到不同的有效路径。证据:M:Lithe/Views/App/ProjectRuntimeSettingsView.swift:380、:436、:720;T:maven/settings_xml.rs:19、T:maven.rs:360、:405;C:project/maven.rs:298、:464。→ core 统一 toolSettings.inspect 的来源、未知和失败契约;XML 解析和有效值由 Maven 插件提供(#1495)。

P1

  • WS-11 目录角色、取消排除和移动之后的规则迁移【双写】排除时记住原来的角色、取消排除时恢复、移动或删除后迁移子树的键,两端各写一份。证据:M:LitheWorkspaceModule/Application/WorkspaceFeatureModel.swift:639、:1283;W:features/file-explorer/stores/directory-marks.ts:138、:31;C:project/indexing.rs:14、:578。→ project::directory_actions::{reduce, relocate}。
  • WS-12 macOS 远程文件树绕开了 workspace listing【接线】macOS 直接调 remote.readDir,然后在 Swift 里过滤和排序,绕过了 nested worktree 等判定;而 bridge 已经支持远程 envelope。证据:M:Lithe/Services/Remote/RemoteWorkspaceRouting.swift:180、:248、M:Lithe/Core/Rust/RustCoreBridge+RemoteWorkspace.swift:12;C:remote/workspace.rs:34、C:project/files.rs:337。→ 复用 workspace.listDirectories 加 remote envelope。 完成: #1735。
  • WS-13 Local History 的文本 diff 与行配对【双写】Swift 用 collection difference 加 bigram 相似度 DP,TS 用 patience 加 LIS,core 的 git 模块里还有一份和 Swift 很像的私有配对;换行的规范化方式也不一样。证据:M:LitheLocalHistoryModule/Models/LocalHistoryModels.swift:35、M:LitheLocalHistoryModule/Models/LocalHistoryDiffModels.swift:30;W:features/local-history/utils/local-history-diff.ts:44、:136;C:git/mod.rs:7548。→ diff::compareTexts,复用成熟的 diff 实现和现有的配对逻辑,返回中立的行或区块模型。
  • WS-14 JDK 和 Maven 版本输出的解析【接线】【插件】macOS 和 Windows 各自用正则解析 java -version、mvn -v 的输出,规则不一样;core 已有按插件工具定义提取版本的 toolchains.checkVersion。证据:M:Lithe/Platform/MacOS/Runtime/MacRuntimeDiscovery.swift:222、:232、:262;T:run.rs:1839、:2410;C:toolchain/resolution.rs:82、:107。→ 把原始输出交给 toolchains.checkVersion,版本格式由插件的工具定义提供,core 里不出现工具名。
  • WS-15 Git 元数据事件的相关性判断:和 GIT-23 是同一件事,在那条里一起做。 已完成:#1748。

P2

  • WS-16 终端里的文件链接解析【灰色】path:line:column、file URI 解码和相对路径映射两端各写一份,Windows 还有一张扩展名白名单。证据:M:LitheTerminalModule/Services/TerminalLinkResolver.swift:13、:35;W:features/terminal/utils/terminal-file-links.ts:64、:120。→ terminal::parseLinkTarget;命中区域、文件是否存在和打开动作留平台。
  • WS-17 Double Shift 手势状态机【双写】两份实现逐段相同。证据:M:Lithe/Platform/MacOS/UI/MacShortcutDetector.swift:307;W:features/keymaps/utils/double-shift-recognizer.ts:3。→ keymap::modifierGestureStep(state, event, timestamp);注意不要让每个原生按键事件都走一次重 IPC。
  • WS-18 最近项目列表【灰色】macOS 最多保留 20 项,按时间排序;Windows 固定项优先,再加 12 个非固定项,两端保留下来的集合不同。证据:M:Lithe/Services/Workspace/RecentProjectsStore.swift:15;W:features/file-system/utils/recent-folders.ts:3、:26、:64。→ workspace::recent_projects::reduce,容量和固定策略作为参数。
6. Agent、AI、MCP、插件(18 条)

P0

  • AGT-01 插件签名与包的完整性【计划】Windows 明确没有实现验签,确认安装时只比较 manifest 的摘要,资源和后端文件变了也不会被发现;macOS 比较完整的文件集合和逐个文件的摘要,并验证签名。证据:M:LithePluginPackageSigning/PluginPackageSignature.swift:171、M:Lithe/Platform/MacOS/Plugins/MacPluginPackageStore.swift:704;T:plugin_host/install.rs:4、:427、T:plugin_host/scan.rs:55;core 的 C:plugins/declarative.rs:853 只校验签名策略的声明。→ plugins::package_integrity:规范化文件清单、计算内容摘要、生成签名载荷并做 Ed25519 验证;平台负责提交读到的文件。
  • AGT-02 插件冲突准入与语言所有权【计划】macOS 按插件 ID 顺序接受,并拒绝模块、动作、renderer 和语言的冲突;Windows 全部保留,启动时按 read_dir 的顺序取第一个匹配的包,结果不稳定。证据:M:Lithe/Platform/MacOS/Plugins/MacPluginStartupLoader.swift:114、M:LitheApplicationKernel/Plugins/PluginManifestValidator.swift:132、:174;T:plugin_host/scan.rs:21、T:plugin_host/launch.rs:150、T:plugin_host/store.rs:100;C:plugins/mod.rs:220、C:plugins/declarative.rs:4118。→ plugins.catalog.resolve 返回准入列表、所有权和每个包的拒绝原因。(和 LSP-12 一起做。)
  • AGT-03 Codex 和 Claude 配置的解析【接线】macOS 手写了逐行的 TOML 解析,wire_api 缺省时落到 chatCompletions(core 缺省是 responses),也不支持 profile;Claude 字段的优先级散落在 Swift、TS 和 core 三处。证据:M:Lithe/Platform/MacOS/AI/MacCodexConfigurationSource.swift:53、M:Lithe/Platform/MacOS/AI/MacClaudeConfigurationSource.swift:27、M:Lithe/Application/Features/AgentLaunchConfigurationResolver.swift:32;W:features/agent/services/agent-provider-import.ts:87、W:features/agent/services/agent-provider-credentials.ts:7;C:ai/configuration.rs:35、:130、C:ai/agent_configuration.rs:35。→ 统一用 ai.configuration.parse,凭据只在 host 里解析,对外返回不含秘密的元数据;平台只负责发现来源和读文件。
  • AGT-04 Agent 改动回退时的换行、删除与冲突【计划】Windows 把 LF 和 CRLF 规范化后再匹配,macOS 直接匹配原文,同一份 LF 证据作用在 CRLF 文件上结果就不同;macOS 还认工具级的删除标记。证据:M:Lithe/Platform/MacOS/Agent/MacAgentEditRestorer.swift:35;W:features/agent/services/agent-edit-review.ts:46、W:platform/agent-edit-restorer.ts:10。→ agent.edits.reversePlan 返回新文本、恢复删除或移入废纸篓的计划,或者一个稳定的冲突码;原子写入和编码留平台。
  • AGT-05 插件回滚的目标版本【计划】macOS 记录真正的上一个激活版本,连同来源、批准记录和摘要;Windows 选择“版本号最高、但不是当前版本”的那个:按 1.0 → 3.0 → 2.0 的顺序安装后,回滚会回到 3.0。证据:M:Lithe/Platform/MacOS/Plugins/MacPluginPackageStore.swift:499、:549;T:plugin_host/install.rs:277、:405;C:plugins/marketplace.rs:379。→ plugins.installation.transition / plugins.installation.rollbackPlan。
  • AGT-06 粘贴图片的保留策略【计划】macOS 每次粘贴都会清理 7 天前的图片,历史会话里引用的图片可能被删;Windows 只清理被放弃或失败的批次。证据:M:Lithe/Models/AppModel/AppModel+AgentConversation.swift:203;W:platform/agent-pasted-images.ts:12、:30。→ agent.attachments.retentionPlan,根据已接受的引用决定能删什么。
  • AGT-07 模型调用的统计口径【双写】同一个非流式请求返回 HTTP 500,Swift 不计入 nonStreamingCount,TS 计入;Windows 的“当前上下文”直接取最后一次调用,辅助请求也会把它覆盖掉。证据:M:LitheAgentConversationModule/Application/AgentModelCall.swift:128、M:LitheAgentConversationModule/Application/AgentSessionStatistics.swift:44;W:features/agent/types/agent-observations.ts:136、W:features/agent/components/agent-observed-statistics.tsx:28;rust/lithe-agent-host/src/model_calls.rs:88。→ agent.statistics.reduce。
  • AGT-08 Agent diff 证据的规范化与可回退资格【双写】截断阈值两端都是 32768,但 Swift 按 String.count 计数,TS 按 UTF-16 的 .length 计数,同一段含 Unicode 的 diff 在两端的可回退资格不同。证据:M:LitheAgentConversationModule/Application/AgentSessionConfiguration.swift:93、:153、M:LitheAgentConversationModule/Application/AgentActivity.swift:40;W:features/agent/types/agent.types.ts:426、:447、W:features/agent/services/agent-edit-review.ts:12。→ agent.evidence.merge / agent.edits.snapshot。

P1

  • AGT-09 下一轮的配置队列与确认顺序【双写】模型优先、一次只确认一个配置、用新目录重新校验、出错后如何处理待续的输入,两端各写一份。证据:M:LitheAgentConversationModule/Application/AgentConnectionModel.swift:1149、:1423;W:features/agent/stores/agent-connection.model.ts:1356、:1619;rust/lithe-agent-host/src/lib.rs:1850。→ agent.conversation.reduce,输出新状态和要执行的 effects。
  • AGT-10 插件设置值的校验与分层【接线】macOS 已经有 bridge 却没用,另外写了一套 accepts、正则和路径校验,以及 project → global → default 的分层;值等于默认值时是否删除,两端各自决定。证据:M:LitheCoreContracts/Plugins/DeclarativePluginContracts.swift:255、M:Lithe/Application/Features/PluginManagement.swift:35、M:Lithe/Platform/MacOS/Plugins/MacPluginManager.swift:552、M:Lithe/Core/Rust/RustDeclarativePluginOperations.swift:319;W:features/plugins/declarative-plugin-settings-editor.tsx:76;C:plugins/settings.rs:399、:677。→ 统一用 plugins.declarative.resolveSettings,再加一个 settingsMutationPlan。
  • AGT-11 AI 生成 PR 描述【双写】Swift 有完整的证据预算、敏感文件策略和严格的响应格式;TS 只取前 12 个文件、每个 30 行,接受只有部分字段的响应。Windows 的 GitHub 后端目前关闭。证据:M:LitheAIAssistanceModule/Services/CommitMessageGenerationService.swift:42、:237;W:features/github/components/github-create-view.tsx:54、:306;C:ai/mod.rs:9。→ ai.pullRequest.plan / ai.pullRequest.decode,和 GIT-01 共用证据收集和请求规划。
  • AGT-12 Windows 的 AI inline edit【计划】只有 Windows 有:它自己决定 provider 和模型的回退、4096 的上限、提示词上下文和输出清洗,还在 TS 里构造协议 payload。证据:W:features/editor/services/editor-inline-edit-service.ts:45、:137、W:features/ai/services/providers/openai-compatible-provider.ts:49。→ ai.inlineEdit.plan / ai.inlineEdit.decode,抽出通用的 provider 请求模型;HTTP 和凭据留平台。
  • AGT-13 MCP 服务器库的合并与批量编辑【计划】只有 Swift 有:按 name 和 hash 合并多个来源、计算同名冲突、判断 ledger 归属、生成批量计划。证据:M:Lithe/Application/Features/McpServerLibraryFeatureModel.swift:287、:375、:826;C:mcp/model.rs:62、C:mcp/plan.rs:86。→ mcp.librarySnapshot / mcp.validateDraft / mcp.batchPlan。
  • AGT-14 Java 调试插件的特判【插件】Swift 在建立“按文件启动”的 adapter 索引时,直接排除了 languageID == "java"。证据:M:Lithe/Platform/MacOS/Plugins/MacLivePluginRegistry.swift:47、M:Lithe/Platform/MacOS/MacServiceContainer.swift:218;C:plugins/declarative.rs:3404。→ 由插件声明按文件启动的能力和默认选择关系,core 做通用的 plugins.debugProviderSelection,删掉这个按语言名的分支。

P2

  • AGT-15 Windows 按工具名拼版本探测参数【插件】java 用 -version,其他工具用 --version。证据:T:plugin_host/launch.rs:343;C:build/invocation.rs:69、C:plugins/declarative.rs:3594。→ 所有 runtimeRequirements 都输出规范化的探测计划,Windows 只负责执行。
  • AGT-16 插件热激活的资格、代际与撤销【灰色】macOS 按模块种类决定能不能免重启、什么时候递增 generation;Windows 另外维护 blocked 和 revisions。证据:M:LitheCoreContracts/Plugins/DeclarativePluginContracts.swift:886、M:Lithe/Platform/MacOS/Plugins/MacLivePluginRegistry.swift:250;W:features/plugins/declarative-plugin-lifecycle.ts:1、T:plugin_host/lifecycle.rs:25;C:plugins/declarative.rs:1602。→ plugins.activation.transition,宿主支持哪些动态变更作为显式输入。
  • AGT-17 插件后端宿主 API 的方法目录与授权映射【灰色】Swift 又定义了一遍 implicit services、legacy 方法集合和 grant 判定。证据:M:Lithe/Application/Features/PluginHostServiceDispatch.swift:204、:255、:335;C:lsp/interface/plugin_function.rs:723。→ core 导出 plugins.hostApi.describe / plugins.hostApi.authorize;当前会话和资源的复核留平台。
  • AGT-18 Hook 编辑时的校验【灰色】名字的字符集、描述长度、命令字节数、超时、matcher 和 event 的兼容规则写了三遍;Swift 的 canSave 少了一部分条件(Host 最终会拒绝)。证据:M:Lithe/Application/Features/AgentHooksFeatureModel.swift:21;W:features/agent/services/agent-hooks.ts:34;rust/lithe-agent-host/src/hooks.rs:380。→ agent.hooks.validateDraft 返回字段级的错误。
7. 建议顺序
  1. BUG-1 到 BUG-7,大多是一到几行的改动。
  2. 【接线】类:GIT-01、GIT-02、GIT-12、GIT-20、GIT-30、RUN-05、RUN-06、RUN-07、RUN-15、LSP-01、LSP-02、LSP-07、LSP-11、WS-02、WS-03、WS-05、WS-12、WS-14、AGT-03、AGT-10。基本不用改契约,最多补一个 JSON 入口。
  3. Git P0 的【计划】类(GIT-03 到 GIT-11、GIT-13 到 GIT-17),一条一个 PR,按“core 计划 API + 共享 fixture + 两端接入”的方式推进。
  4. 其他领域的 P0。
  5. 提交图(GIT-18、GIT-19)放在最后,这是最大的一块:先把 Swift 和 TS 的现有算法连同 fixture 搬进 graph.rs,用 ./scripts/git-graph/verify-git-graph.sh 锁住行为,再让两端切过去。
  6. 【插件】类和 #1495 一起排期。
8. 已经下沉、不用动的部分
  • Git:porcelain v2 status 解析和未跟踪目录摘要、仓库扫描和 VCS 根映射、workspace_commit 提交状态机、基础的 diff / blame / 行历史、冲突检查、patch exchange、历史分页 cursor 和引用事实、fetch 参数和进度解析、push 预览和执行、rebase 和改写的执行安全、worktree 创建、console 呈现、Git 认证应答。两端都没有自己启动 git 进程。
  • 运行:运行配置的发现、生成和三层合并,Java 启动就绪判断,JDK 自动选择,Maven 通用的启动计划、诊断、依赖树和测试报告解析,DAP 协议引擎,退出策略,长命令缩短。
  • LSP:进程和协议的生命周期、文档同步和增量回放、补全 / 悬停 / Location / code action 的基础解析、单文档保存状态机、JDT 工作区指纹、插件 grammar 校验。
  • 工作区:目录索引排除、搜索索引和基本匹配、Local History 的存储格式和保留预算、声明式 toolchain 发现、SSH 连接、文本和二进制的判定。Shell 发现和 PTY 按契约本来就归平台。
  • Agent:ACP 执行和认证;hooks、skills、instructions 的管理;MCP 配置的解析和编辑计划;插件单包声明的解码;插件市场索引的校验;IDE MCP 的工具目录。
Target platform / 目标平台

Cross-platform / 跨平台

Area / 模块

Git

Priority / 优先级

P1 / 尽快处理:使用体验大幅下降,但通常仍可继续使用

Alternatives considered / 已考虑的替代方案
  • 只修 7 个 bug:成本最低,但两端各写一份的规则还会继续分歧,下次只改一端又会出新的 bug。
  • 直接把 core 里现成的 graph.rs 接给两端:它和两端现有的布局、颜色规则都不等价,直接接会改变用户看到的提交图。
  • 把 Maven、Java、Spring 相关的逻辑也搬进 core:这违反插件所有权规则,和 #1495 的方向冲突。
  • 一个大 PR 全部搬完:没法评审,也没法按条回滚;而且每 push 一次都会重跑完整 CI。
Additional context / 补充信息
  • 方法:按领域拆成 6 路静态读码(Git 两路,运行、LSP、工作区、Agent 各一路),没有构建、跑测试或启动应用。条目的 P0 / P1 / P2 只是本 issue 内部的排序;issue 标签选 P1,指的是整体。
  • 这次没有覆盖的部分:
    • 没有做运行时复现。
    • 没有重新审查 core 里已有的工具知识(例如 Maven POM 模型、Spring 索引)是否符合最新的上游所有权规则。
    • Java 测试调试准备(M:LitheLanguageIntelligenceModule/Services/LanguageToolingSessionManager.swift:731)里的 JUnit / TestNG 类型映射和上游命令组装,归属还要对照 Java Test 扩展的公开能力再定。
    • Windows 侧通用 Build Provider 的接入是否完整,要结合实际安装的插件和功能矩阵确认。
    • Windows 目前没有活动的 Docker 实现,没有审计。
  • 相关 issue:#1495(把 Maven、Java 迁到插件后端)、#1186(已关闭的迁移 epic)。
Checklist / 提交前检查
  • I searched existing issues for duplicates. / 我已搜索现有 Issue,确认没有重复建议。
Dominant language
TypeScript
Stars
1.8k
Forks
151
Avg merge
11h 47m
Merged PRs (30d)
409

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from 1lck/Lithe-IDEA

All issues in 1lck/Lithe-IDEA

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.