Replies: 4 comments
|
Shipped your exact fix (leading space, not
Your four-form table was the right call — the naive "just drop |
|
Three additions from the plugin side, all of which make this harder to dismiss. Reproduced on a second ash implementation, so it is not a busybox quirk. Same six forms on
Identical to the busybox column. This is POSIX rather than an implementation gap. There is no workaround below this line, which is worth knowing before deciding priority. The obvious escape is to shadow Injecting it through Confirming @zoahdev's branch is the right shape from the consumer side. Ours is a textual rewrite anchored on the full wrapper shape, which is the wrong place for it to live permanently. It goes away the moment the core fix ships. One note for whoever reviews the branch. The severity is easy to understate from the diff, since one token looks cosmetic. The effect is that every command on a non-bash persistent shell fails before it runs, including a bare |
|
Strong additions — the Keeping the cherry-pick-ready branch in sync with this (it already emits |
|
Taking you up on that, because there is one, and it is not a stray form. It is the quoting itself. dash has no ANSI-C quoting at alldash reads So the leading-space fix moves the error, it does not clear itReplaying what the core actually sends, before and after your patch. The failing token goes from Where that leaves the fixYour patch is still correct and I would still ship it. busybox ash does implement But it does not make Full POSIX portability means not emitting ANSI-C quoting at all, so I am not asking you to fold that into the branch. I am flagging that the branch's scope is "busybox ash and friends that implement Disclosure, our own plugin is in exactly the same position. 中文有一个,而且不是零散的形式,是引用方式本身。 dash 根本不支持 ANSI-C 引用。 所以你的补丁把报错从 补丁本身仍然是对的,我照样会合。 busybox ash 确实实现了 但它没让 不是要你把这个塞进分支。只是想说清楚分支的适用范围是「实现了 利益披露,我们自己的插件处境完全一样, |
Uh oh!
There was an error while loading. Please reload this page.
摘要 / Summary
@deepseek-ai/dsh-tool-bash-persistent的wrapCommand()用eval --包裹每一条命令。--是 bash 的写法,busybox ash 的eval内建不认它,会把--当成命令名。结果是:只要持久 shell 不是 bash,每一条命令都在真正执行前就死于not found/ exit 127。wrapCommand()in@deepseek-ai/dsh-tool-bash-persistentwraps every command ineval --. The--end-of-options separator is a bashism; busybox ash'sevalbuiltin does not implement it and takes--as the command name. So whenever the persistent shell is not bash, every command dies withnot found/ exit 127 before it ever runs.位置 / Where
@deepseek-ai/dsh-tool-bash-persistent/lib/index.js:91(v0.1.0-rc.6)$'...'ANSI-C 引用本身没问题,busybox ash 支持。唯一的不兼容就是--这一个 token。The
$'...'quoting is fine — busybox ash supports it. The--token is the only incompatibility.最小复现 / Minimal repro
不需要 DSH,一行就能看到 / No DSH needed:
把
wrapCommand()的真实产物原样跑一遍 / The actualwrapCommand()output, run verbatim:环境 / Environment: BusyBox v1.38.0-FRP-6075-g169694ebd (2026-05-06, busybox-w32), Windows 11 26100, node 24.19.0,
@deepseek-ai/dsh0.1.0-rc.6.修复建议 / Suggested fix
请不要只是删掉
--—— 那样 bash 会回归。实测四种写法 / Do not simply drop--, that regresses bash. All four forms measured:eval -- $'-n hi'(现状 / today)-n: command not found(127) ✅--: not found(127) ❌eval $'-n hi'(直接删 / naive drop)eval: -n: invalid option(2) ❌-n: not found(127) ✅eval $' -n hi'(前导空格 / leading space)-n: command not found(127) ✅-n: not found(127) ✅eval $' echo ok'ok(0) ✅ok(0) ✅--的作用是防止以-开头的命令被eval当成选项。在被引用的字符串前加一个空格能达到同样效果,而且是可移植的:参数本身以空格开头,就不会进入选项解析;前导空白对 shell 解析没有影响。--exists to stop a command starting with-from being parsed as an option toeval. A single leading space inside the quoted word achieves the same thing portably: the argument no longer begins with-, so it is never considered an option, and leading whitespace is insignificant to shell parsing.function wrapCommand(command, marker) { - return `printf '%s\n' ${quoteForBash(marker.start)}; eval -- ${quoteForBash(command)}; ...` + // A leading space, not `--`: it blocks option parsing in every POSIX shell, + // while `eval --` is a bashism that busybox ash takes as the command name. + return `printf '%s\n' ${quoteForBash(marker.start)}; eval ${quoteForBash(' ' + command)}; ...` }已验证 / Verified end to end
在本机把这一行改掉、重启
dsh web、用 busybox ash 作为持久 shell 跑了两个独立回合 / Patched that one line locally, restarteddsh web, ran two separate turns with busybox ash as the persistent shell:bash {"command": "MARK=box7"}bash {"command": "echo sandbox:$MARK:$(pwd)"}sandbox:box7:C:/work/demo改之前两个回合都是
sh: eval: --: not found/ exit 127。改之后不仅能跑,跨工具调用的 shell 状态也正常保持。Before the change both turns returned
sh: eval: --: not found/ exit 127. After it, commands run and shell state persists across separate tool calls as intended.为什么值得修 / Why it matters
持久 shell 的 shell 路径是可配置的,但
wrapCommand里的 bashism 实际上把它锁死成「只能是 bash」。这在 Windows 上尤其要命:MSYS/Git Bash 在workspace-write受限令牌下启动即死,busybox-w32 ash 是目前已知唯一能在沙箱里活下来的持久 shell,而它恰好就是被这个 token 挡住的那一类 shell。The persistent shell's path is configurable, but the bashism in
wrapCommandeffectively hard-codes it to bash. That bites hardest on Windows: MSYS/Git Bash dies at cygheap init under theworkspace-writerestricted token, and busybox-w32 ash is the one persistent shell known to survive the sandbox — and it is exactly the kind of shell this token shuts out.发现于测试 dsh-win32 的沙箱预设时,完整记录在 sjh9714/dsh-win32#12。
Found while testing the sandboxed preset of dsh-win32; full trace in sjh9714/dsh-win32#12.
(依 CONTRIBUTING,这里不提 PR,只把问题和实测放在 Discussions。/ Per CONTRIBUTING, reporting here rather than opening a PR.)
All reactions