dsh-composer-ux 0.15.4 → 0.15.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,43 @@
2
2
 
3
3
  本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [0.15.5] — 2026-09-30(**真凶**:重启时重放的启动命令是坏的 —— 桌面版一直没成功过)
6
+
7
+ 前一轮查壳的判定时顺手翻了自己的助手日志,发现一个比弹框严重得多的问题。
8
+
9
+ **证据**(`%TEMP%\composer-ux-restart-*.err.log`,就是用户那两次重启的产物):
10
+
11
+ ```
12
+ Error: dsh: invalid profile name "D:\\deepseekharness\\resources\\app.asar\\dsh"
13
+ at resolveProfileDir (…/@deepseek-ai/dsh-app-boot/lib/index.js:525)
14
+ [dsh-composer-ux] the replacement did not bind port 19387 within 20000ms
15
+ ```
16
+
17
+ 另一份(端口 3080 那次)是 `error: --profile <name> is required`。
18
+
19
+ **原因**:`launchCommand()` 只在 argv1 长得像 `bin.js`/`bin.ts`/`dsh` 时才忠实重放,**否则退回裸
20
+ `dsh` 并把 argv1 整个丢掉**。桌面壳起宿主用的是 `@deepseek-ai/dsh-desktop-host/lib/cli.js`
21
+ (不匹配那个正则)⇒ 重放成 `dsh "<asar>/dsh"` ⇒ 替换进程当场报 "invalid profile name" 退出。
22
+ **也就是说:桌面版的重启从来没成功过,一直是壳那个「应用无法启动」恢复框在兜底** —— 而那个框里的
23
+ 「退出」会把应用真的关掉。
24
+
25
+ **改法**:改成**逐字重放原命令** —— `node <execArgv> <argv1> <rest...>`,cwd 用原 cwd
26
+ (相对入口靠它解析)。只给 Windows 的 `.cmd`/`.bat` shim 保留「过一层 shell」那条分支。
27
+ 这也正是两个参考插件(Noah0509 / HHHEEEWWW 两版 dsh-quick-restart)的做法。
28
+
29
+ ## 验证
30
+
31
+ - `npm test`:**2359 passed / 0 failed**(23 个套件;新增 7 条,含一条**真机回归**:
32
+ 「入口不像 dsh(桌面壳那条路)也逐字重放,绝不退化成裸 dsh」)。
33
+ - 变异:**162/162 全部咬住**(新增 FM:又可以把 argv1 丢掉 ⇒ 那条回归报警)。
34
+
35
+ ## 仍未解决
36
+
37
+ 桌面壳那个恢复框**仍然会弹**:读它的 `lib/main.js` 证实,宿主的子进程一 close 它就 `fail()`,
38
+ 不管退出码是 0 还是别的;唯一的「恢复式重启」是它自己弹框里那个按钮(`app.relaunch()`)。
39
+ 所以只要还是「我们自己退出」,那一步就去不掉 —— 待用户决定:机制不动只把话说明白,还是换成
40
+ 「杀掉壳自己拉起 exe」(会先杀掉整个窗口,且有它自带的两个致命坑)。
41
+
5
42
  ## [0.15.4] — 2026-09-30(移除侧边栏那枚重启按钮)
6
43
 
7
44
  起因(用户原话):**「移除这里的重启按钮」**(配图是侧边栏底部,「移动访问」下面那枚)。
package/README.md CHANGED
@@ -506,7 +506,7 @@ Windows 上 DSH 给模型的终端工具是 **PowerShell**(工具名 `pwsh`)
506
506
  | 工具循环的消息形状 / 轮次封顶 / 异常必须降级 | 同上第 6 节(假 llm 驱动整条循环,逐条检查 `role:'tool'` 与 `toolCallId`) |
507
507
  | 工具路径:默认关、开了才派、**查完吐散文必须回落**、拿不到工作目录就不派 | `test/quick-commands.mjs` 5g 节(13 条,真路由 + 假 llm) |
508
508
  | 工具读到的内容不进台账 | 同 5g 节:断言台账里只有工具名与次数、没有读到的文件内容 |
509
- | 变异守卫真的会咬人,且**必须是指定的那条测试变红** | `npm run test:mutations`:**161 条全部咬住**(判据是 `red.some(line => line.includes(item.expect))`,不是"有红就行") |
509
+ | 变异守卫真的会咬人,且**必须是指定的那条测试变红** | `npm run test:mutations`:**162 条全部咬住**(判据是 `red.some(line => line.includes(item.expect))`,不是"有红就行") |
510
510
  | 发布门禁三条判据 | `npm run gates` 全过;`check:tag` 实测 `v0.12.0` 的 tag 名与所指提交里的版本一致 |
511
511
  | 三平台 CI | GitHub Actions:ubuntu / windows / macos × Node 20(`npm ci → typecheck → build → test → check:pack → check:docs`) |
512
512
 
@@ -640,9 +640,9 @@ node build.mjs # 产出 lib/index.js + lib/client.js
640
640
  # ⚠️ 宿主半会**内联** schemastery / cosmokit:
641
641
  # 优先用 DSH 检出里的 vendor 副本,检出不在时退到 node_modules
642
642
  # 里同版本的 npm 包(两者逐字节相同)——CI 上走的就是退路
643
- npm test # 23 个套件;当前 2357 passed, 0 failed(2026-09-29 实测;CI 三平台同样全绿)
643
+ npm test # 23 个套件;当前 2359 passed, 0 failed(2026-09-29 实测;CI 三平台同样全绿)
644
644
  # 走 scripts/run-tests.mjs:顺带把"多少套件/多少条"记进 test/.last-run.json
645
- npm run test:mutations # 手动跑:变异测试,证明那套护栏真的在咬人(161 条,须单独跑)
645
+ npm run test:mutations # 手动跑:变异测试,证明那套护栏真的在咬人(162 条,须单独跑)
646
646
  # 同样记录结果,供下面的文档门禁核对
647
647
  npm run gates # 发版门禁三条一起跑:tag 指向 / 包内容 / 文档数字
648
648
  npm run check:tag # ① tag 名里的版本 == 该 tag 所指提交里的 package.json 版本
package/lib/index.js CHANGED
@@ -3879,10 +3879,12 @@ function isAbsolutePath(value) {
3879
3879
  return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
3880
3880
  }
3881
3881
  function launchCommand(facts) {
3882
- const { argv1, execArgv, rest, cwd, platform, resolve: resolve4, dirname: dirname8 } = facts;
3883
- if (argv1 !== void 0 && /[\\/](?:bin\.(?:js|ts)|dsh)$/.test(argv1)) {
3884
- const absolute = resolve4(argv1);
3885
- return { file: facts.node, args: [...execArgv, absolute, ...rest], cwd: dirname8(absolute), viaShell: false };
3882
+ const { node, argv1, execArgv, rest, cwd, platform } = facts;
3883
+ if (argv1 !== void 0 && argv1 !== "") {
3884
+ if (/\.(?:cmd|bat)$/iu.test(argv1)) {
3885
+ return { file: argv1, args: [...rest], cwd, viaShell: true };
3886
+ }
3887
+ return { file: node, args: [...execArgv, argv1, ...rest], cwd, viaShell: false };
3886
3888
  }
3887
3889
  return { file: "dsh", args: [...rest], cwd, viaShell: platform === "win32" };
3888
3890
  }