Skip to content

v0.3.0

Choose a tag to compare

@33moren33 33moren33 released this 23 Aug 05:36
· 5 commits to main since this release

这一版最要紧的一件事,跟 dsh-box 无关,但每个 Windows 用户都该知道。

Windows 上有几段 Node 删不掉、拷不动带中文的路径

不是本工具的缺陷,是 Node 自己的(#61067#61878)。递归删除和递归拷贝,只要路径里有中文、日文、重音字母或 emoji,就回报成功、什么都没做,有时直接让进程崩掉。

上一版 0.2.0 的产物上能原样复现:建一台叫「中文测试」的沙箱,rm 它,得到 {"ok":true}、退出码 0、沙箱还在磁盘上

这一版已经绕开,在下面每一段版本上都正常。

正常 有缺陷
20.x、21.x 22.17 – 22.21(现行 LTS,至今未修)
22.0 – 22.16 23.x 全线
24.15 或更新 24.0 – 24.14
25.9 或更新、26.x 25.0 – 25.8

每一格都是下载那一版真跑出来的。只在 Windows 上,Linux 与 macOS 不受影响。

两个调用是两个不同的 bug、不同版本修的——删除修在 24.13.1,拷贝修在 24.15.0。只看删除那一行会以为「退回 22 LTS 就安全」,那是错的:22 线从 22.17 起拷贝就坏,至今没修。没有一个在维护的 LTS 是干净的。

用户名是「张三」或 José 的人,路径里到处都是这类字符。要一个干净的,装 24.15 或更新。

批准改成「窗口起的才算」

--approved 从一句恳求变成一条判据:这次运行的父进程是不是那个配置窗。窗口执行任何动作都是它起一个命令行子进程,所以「父进程是窗口」就是「有人点过头」的证据。你自己带上旗标过不去,agent 带上也过不去。

config ask-on-daily off 的含义同时收窄成「窗口别问我第二遍」——它不再给命令行那一侧开门。一个人为自己少点一次而勾的框,不该变成机器上任何东西的通行证。

一个数据目录,一个配置窗

双击两次桌面版,不再开出两个壳、两个服务、两个指着同一个数据目录的窗口。第二次会说清楚第一个开在哪儿。

规则只写了一份:壳带 --json 起命令行,认 UI_ALREADY_SERVING 这个 code,Rust 那边不抄第二份判断。

其余

同名沙箱并发:两条 start --sandbox <同一个名字> 同时发,只有一条真的起 dsh,另一条明说被拦下的原因。启动前先独占占位,不再等起完了才记账。

登录凭证三态:跟插件那套一致——绿钩是已有、蓝是这次导入、取消勾是这次拿掉。新增 signin / signout。日常档案柜那份是硬闸门,不备份。

回看也画框:可以点到某一步,那一步动过的控件重新亮起来;当时删掉的东西给虚线占位。

--json 里的 places 改成给身份plugins rm 被拦下时,它原来给的是翻译过的档案柜名字,于是同一个拒绝在中文机器和英文机器上返回不同的值。现在给 {sandbox, main}sandboxnull 就是日常档案柜。

验收

npm test 现在 242 项,自己造一次性数据目录、跑完删掉,用几十行的 dsh 替身,不下包、不联网、不碰你真实的 ~/.dsh

新加一道 check-no-recursive-fs全仓禁止直接调用递归的 rmSync / cpSync,新代码白白继承这条规则,不必有人记得。删除与拷贝各带一个对照组,跑的就是内建那两个调用——它们哪天开始通过,就是 Node 修好了、这套绕法可以整个删掉的信号。

本版在 Linux(aarch64 + musl) 上跑过 240 项,零不通过(差的两条正是只在 Windows 上成立的对照组)。

下载

桌面版、便携包、.dmg.deb.AppImage 都在下方资产里,或者不装直接跑:

npx dsh-box@0.3.0 ui

macOS 的 .dmg 仅 Apple Silicon。macOS 与 Linux 的安装包仍未有人实跑过,遇到问题请开 issue。


English

The most important thing in this release has nothing to do with dsh-box, and every Windows user should know it.

Some Node versions cannot delete or copy non-ASCII paths on Windows

A defect in Node itself, not in this tool (#61067, #61878). Recursive delete and recursive copy, given a path holding an accented letter, Chinese, Japanese or an emoji, report success and do nothing — and on some shapes they take the process down. It reproduces on the 0.2.0 artifacts as shipped: create a sandbox named 中文测试, rm it, and get {"ok":true}, exit code 0, and the sandbox still on disk.

This release works around both, so it behaves the same on every version below.

Fine Defective
20.x, 21.x 22.17 – 22.21 (the current LTS, still unfixed)
22.0 – 22.16 the whole 23 line
24.15 or newer 24.0 – 24.14
25.9 or newer, 26.x 25.0 – 25.8

Every cell was measured by downloading that version and running it. Windows only.

They are two bugs fixed in two different versions — the delete in 24.13.1, the copy in 24.15.0. Reading only the delete row suggests falling back to the 22 LTS is safe. It is not: the copy has been broken there since 22.17 and still is. No maintained LTS line is clean. For a clean one, install 24.15 or newer.

Approval means "started by the window"

--approved stopped being a request and became a test: is the parent process of this run the config window? Every action the window performs spawns a command-line child, so "the parent is the window" is the evidence that a person was present. Passing the flag yourself does not get through, and neither does an agent passing it. config ask-on-daily off now means only "the window need not ask me twice" — it no longer opens the command-line door.

One data directory, one config window

Double-clicking the desktop build twice no longer produces two shells, two services and two windows pointing at the same data directory; the second one says where the first is. The rule exists once: the shell runs the command line with --json and recognises the UI_ALREADY_SERVING code, rather than keeping a second copy of the rule in Rust.

Also

Concurrent same-name sandboxes: two start --sandbox <same name> at once now start exactly one dsh, and the other says why it was held back — the claim is taken before launching, not recorded after.

Sign-in credentials are tri-state, matching plugins: green means present, blue means importing now, unticking means removing now. New signin / signout. The daily cabinet's copy is a hard gate and is never backed up.

The recall is framed too: click any step and the controls it touched light up again; whatever it deleted gets a dashed placeholder.

places in --json now carries identity, not prose. When plugins rm is refused it used to return the translated name of the daily cabinet, so the same refusal answered differently on a Chinese and an English machine. It is now {sandbox, main}, with sandbox: null meaning the daily cabinet.

Verification

npm test is now 242 checks against a throwaway data directory and a small dsh stub — no downloads, no network, and it never touches your real ~/.dsh. A new check-no-recursive-fs forbids calling recursive rmSync / cpSync anywhere in the repository, so new code inherits the rule for free. Delete and copy each keep a control group running the built-in call: when those start passing everywhere, Node has been fixed and the whole workaround can go. This release also passes 240 checks on Linux (aarch64 + musl), the two missing ones being the controls that only hold on Windows.

Installers for all three platforms are in the assets below, or run it without installing: npx dsh-box@0.3.0 ui. The .dmg is Apple Silicon only.