Commit b889dc9
authored
* fix: 修复打开 WSL 文件时主进程因 EISDIR 崩溃 (#172)
打开 \\wsl.localhost\ 下的文件时,应用会自动把文件所在目录作为工作区并用
chokidar 递归监听。chokidar 遍历到目录中的 Linux 软链接(如 *.so.0)时会对其
lstat,而 Windows/Node 对经 9P 重定向器暴露的 WSL 软链接做 lstat 会返回 EISDIR
(底层是 9P 不支持读取该软链接的 reparse 数据,返回 Incorrect function,被 libuv
映射成了 EISDIR)。该错误没有任何地方处理,冒泡成主进程 uncaughtException,于是弹出
"A JavaScript error occurred in the main process" 并使文件区卡死。
修复采用双保险:
- workspacePath.ts:isRemoteWorkspacePath 不再依赖 isWindows 做前置短路。该模块运行在
渲染进程(nodeIntegration:false),那里 process.platform 不可用,isWindows 恒为
false,会让原有的 WSL/远程路径防护永远失效。去掉该短路后,防护真正生效,从源头避免对
WSL 目录自动加载工作区与递归监听。UNC 路径(\\wsl.localhost\、\\wsl$\、\\server\share)
本身是 Windows 专有写法,不会出现在其他平台的合法路径里,无需平台判断即可安全识别。
- ipcBridge.ts:给 file watcher 与 directoryWatcher 各补一个 "error" 监听。chokidar
出错时会 emit "error",没有监听器时会冒泡成主进程 uncaughtException。补上后任何 watcher
错误都只记录、不再使应用崩溃,对所有文件系统(不止 WSL)都更健壮。
注:本次修复保证不再崩溃,但 WSL 文件暂时不会自动加载左侧文件树(防护跳过了)。后续会做
第二层改进,让 WSL 文件也能正常显示文件树。
* docs: 新增 WSL/远程文件监听第二层实施规约 (草案 v2)
* docs(wsl-l2): 记录 §0 前置实测结果(A/B PASS) + 按实测修订 symlink 分支
§0 实测 2026-06-06 (Debian11 / Node v22 / Windows host):
A 完整建树无 EISDIR -- PASS:
- 生产 scanDirectory 在含 symlink/.so链/大目录/深目录 的 WSL 树上建 115 节点,
0 吞错 / 0 EISDIR / 0 uncaught
- 新发现: WSL symlink 从 Windows 侧完全读不透
lstat/readlink=EISDIR, stat(跟随)/readFile=ENOENT (含指向真实存在的目标)
-> symlink 仅能由 readdir d_type 识别, 拿不到 mtime, 无法解引用/打开
B fs.watchFile 在 9P 可靠性 -- PASS (全绿):
追加 / 原子替换(mv,新inode) / 同mtime仅改size(size触发) /
删除(mtime=0) / 删后重建(跟踪存活) / 同秒多写 全部 DETECTED
据 A 缩范围 (spec §4.3/§6.2/§8):
- WSL 分支默认丢弃 symlink (避免死节点/点开 ENOENT), 重指向不可知文档化为局限
- isSymbolicLink() 分支只对 local/SMB 有效
- WSL symlink inert 显示移入 §8 defer
* feat(wsl-l2): WSL/远程文件树轮询监听(撤销第一层跳过)
第二层:撤销第一层对 WSL/远程路径的"跳过自动加载工作区",让 WSL 文件也能
显示文件树并在外部变更时提示重载。事件式 fs.watch 在 9P 上启动即 EISDIR,
故 WSL 改走轮询;本地/SMB 保持 chokidar 实时。依据 §0 前置实测(已 PASS)。
新增 src/main/wslWatch.ts(不依赖 electron,回调注入,便于单测):
- 路径分流 classifyWatchTarget / normalizeWatchPath(还原 \\?\UNC\ 防误判重开 EISDIR)
- scanDirectory(WSL 丢弃读不透的 symlink;本地/SMB 加 isSymbolicLink 分支)
- WslDirectoryWatcher:per-dir interval + in-flight guard + epoch 丢弃迟到结果
+ 快照(path+mtime+size)diff + 不可达不清树 + 300ms debounce
- WslFileWatcher:per-window union 引用计数 + fs.watchFile + mtime=0 删除语义
+ size 兜底 + focus checkWindow 兜底 + before-quit dispose
接入 ipcBridge.ts:watchDirectory/file:watch 按 classify 分流;getDirectoryFiles
改用模块 scanDirectory;app browser-window-focus / before-quit / 窗口关闭清理。
renderer:workspacePath.shouldAutoLoadWorkspace 撤销远程跳过;useWorkSpace 远程
空树也置锁(避免 tabs 变化反复重扫慢 9P) + refreshWorkSpace 加 in-flight 互斥。
测试:node:test 22 个(纯函数 + 两个管理器,假依赖) 全过;另用真实 fs.watchFile +
snapshotDirectory 在真 \\wsl.localhost\ 集成验证 9/9(目录增删/文件追加替换/focus/
引用计数)。新增 pnpm test 脚本。
注:GUI 视觉确认(文件树渲染 / 重载弹框)需本机 pnpm run dev 验证。
1 parent 75c86a6 commit b889dc9
8 files changed
Lines changed: 990 additions & 122 deletions
File tree
- docs
- src
- main
- renderer
- hooks
- utils
- test
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
33 | 34 | | |
34 | 35 | | |
35 | 36 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | 8 | | |
10 | 9 | | |
11 | 10 | | |
| |||
35 | 34 | | |
36 | 35 | | |
37 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
38 | 44 | | |
39 | 45 | | |
40 | 46 | | |
| |||
52 | 58 | | |
53 | 59 | | |
54 | 60 | | |
| 61 | + | |
| 62 | + | |
55 | 63 | | |
56 | 64 | | |
57 | 65 | | |
| |||
63 | 71 | | |
64 | 72 | | |
65 | 73 | | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
66 | 90 | | |
67 | 91 | | |
68 | 92 | | |
| |||
1187 | 1211 | | |
1188 | 1212 | | |
1189 | 1213 | | |
| 1214 | + | |
| 1215 | + | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
1190 | 1224 | | |
1191 | 1225 | | |
1192 | 1226 | | |
| |||
1465 | 1499 | | |
1466 | 1500 | | |
1467 | 1501 | | |
1468 | | - | |
| 1502 | + | |
1469 | 1503 | | |
1470 | 1504 | | |
1471 | 1505 | | |
1472 | 1506 | | |
1473 | 1507 | | |
1474 | | - | |
1475 | | - | |
1476 | | - | |
1477 | | - | |
1478 | | - | |
1479 | | - | |
1480 | | - | |
1481 | | - | |
1482 | | - | |
1483 | | - | |
1484 | | - | |
1485 | | - | |
1486 | | - | |
1487 | | - | |
1488 | | - | |
1489 | | - | |
1490 | | - | |
1491 | | - | |
1492 | | - | |
1493 | | - | |
1494 | | - | |
1495 | | - | |
1496 | | - | |
1497 | | - | |
1498 | | - | |
1499 | | - | |
1500 | | - | |
1501 | | - | |
1502 | | - | |
1503 | | - | |
1504 | | - | |
1505 | | - | |
1506 | | - | |
1507 | | - | |
1508 | | - | |
1509 | | - | |
1510 | | - | |
1511 | | - | |
1512 | | - | |
1513 | | - | |
1514 | | - | |
1515 | | - | |
1516 | | - | |
1517 | | - | |
1518 | | - | |
1519 | | - | |
1520 | | - | |
1521 | | - | |
1522 | | - | |
1523 | | - | |
1524 | | - | |
1525 | | - | |
1526 | | - | |
1527 | | - | |
1528 | | - | |
1529 | | - | |
1530 | | - | |
1531 | | - | |
1532 | | - | |
1533 | | - | |
1534 | | - | |
1535 | | - | |
1536 | | - | |
1537 | | - | |
1538 | | - | |
1539 | | - | |
1540 | | - | |
1541 | | - | |
1542 | | - | |
1543 | | - | |
1544 | | - | |
1545 | | - | |
1546 | | - | |
1547 | | - | |
1548 | | - | |
1549 | | - | |
1550 | | - | |
1551 | | - | |
1552 | | - | |
1553 | | - | |
1554 | | - | |
1555 | | - | |
1556 | | - | |
1557 | | - | |
1558 | | - | |
1559 | | - | |
1560 | | - | |
1561 | | - | |
1562 | | - | |
1563 | | - | |
1564 | | - | |
1565 | | - | |
1566 | | - | |
1567 | | - | |
1568 | | - | |
1569 | | - | |
1570 | | - | |
1571 | | - | |
1572 | | - | |
1573 | | - | |
1574 | | - | |
1575 | | - | |
1576 | | - | |
| 1508 | + | |
| 1509 | + | |
1577 | 1510 | | |
1578 | 1511 | | |
1579 | 1512 | | |
| |||
1595 | 1528 | | |
1596 | 1529 | | |
1597 | 1530 | | |
1598 | | - | |
1599 | | - | |
| 1531 | + | |
| 1532 | + | |
| 1533 | + | |
| 1534 | + | |
| 1535 | + | |
| 1536 | + | |
1600 | 1537 | | |
1601 | | - | |
| 1538 | + | |
1602 | 1539 | | |
1603 | 1540 | | |
1604 | 1541 | | |
| |||
1644 | 1581 | | |
1645 | 1582 | | |
1646 | 1583 | | |
1647 | | - | |
| 1584 | + | |
1648 | 1585 | | |
1649 | 1586 | | |
1650 | 1587 | | |
1651 | 1588 | | |
1652 | 1589 | | |
1653 | | - | |
| 1590 | + | |
| 1591 | + | |
| 1592 | + | |
| 1593 | + | |
| 1594 | + | |
| 1595 | + | |
| 1596 | + | |
| 1597 | + | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
| 1601 | + | |
| 1602 | + | |
1654 | 1603 | | |
1655 | 1604 | | |
1656 | 1605 | | |
| |||
1688 | 1637 | | |
1689 | 1638 | | |
1690 | 1639 | | |
| 1640 | + | |
1691 | 1641 | | |
1692 | 1642 | | |
1693 | 1643 | | |
| |||
0 commit comments