better-dsh 0.2.5-a → 0.2.5-c

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.
Files changed (54) hide show
  1. package/THIRD_PARTY_NOTICES.md +49 -0
  2. package/docs/50_test-reports/2026-10-02-better-dsh-schemastery/344/276/235/350/265/226/345/243/260/346/230/216/344/277/256/345/244/215/345/256/236/346/265/213/346/212/245/345/221/212.md +62 -0
  3. package/docs/50_test-reports/2026-10-03-better-dsh-tool-surface-repl-dvc-browser-ast-lsp-4999/345/256/236/346/265/213/346/212/245/345/221/212.md +185 -0
  4. package/docs/50_test-reports/2026-10-03-physical-import/344/270/216llm-completion-ast/347/233/270/345/257/271/350/267/257/345/276/204/344/277/256/345/244/215/345/256/236/346/265/213/346/212/245/345/221/212.md +101 -0
  5. package/docs/50_test-reports/2026-10-03-pnpm11/345/271/264/351/276/204/351/227/250/351/224/201/346/226/207/344/273/266/347/233/270/344/275/215/345/256/236/350/257/201.md +54 -0
  6. package/docs/50_test-reports/2026-10-03-remote-BYO-PTY-label/351/207/215/346/236/204/347/254/254/344/270/200/344/272/272/347/247/260/345/256/236/346/265/213/346/212/245/345/221/212.md +447 -0
  7. package/docs/50_test-reports/2026-10-03-schemastery-cosmokit/346/272/220/347/240/201/345/206/205/350/201/224/345/256/236/346/265/213/346/212/245/345/221/212.md +63 -0
  8. package/docs/50_test-reports/2026-10-03-zero-npm-runtime-deps/345/256/236/346/265/213/346/212/245/345/221/212.md +82 -0
  9. package/docs/specs/remote-pty-label/spec.md +126 -0
  10. package/docs/specs/zero-npm-runtime-deps/spec.md +85 -0
  11. package/lib/BrowserWebSocketTransport-FbPg_VFT.js +39 -0
  12. package/lib/BrowserWebSocketTransport-Q5SUMk7_.js +4 -0
  13. package/lib/LaunchOptions-DlBKKKLC.js +4 -0
  14. package/lib/LaunchOptions-RNO1YIoJ.js +17 -0
  15. package/lib/NodeWebSocketTransport-BdrEPUFe.js +3629 -0
  16. package/lib/NodeWebSocketTransport-DyU2tm5L.js +4 -0
  17. package/lib/bidi-D0POLRy7.js +16106 -0
  18. package/lib/chunk-DQxbwPpZ.js +30 -0
  19. package/lib/compaction/index.d.ts +3 -3
  20. package/lib/compaction/index.js +4 -4
  21. package/lib/failover/index.d.ts +3 -3
  22. package/lib/failover/index.js +4 -4
  23. package/lib/fs-aware/sandbox-plugin.js +20 -20
  24. package/lib/index-DZQNwO7f.d.ts +208 -0
  25. package/lib/index-browser-rqlXyoed.js +21061 -0
  26. package/lib/index.d.ts +4 -4
  27. package/lib/index.js +397 -149
  28. package/lib/kernel-bridge.py +172 -0
  29. package/lib/kernel-env.js +1 -1
  30. package/lib/lib-C8_jXvwA.js +894 -0
  31. package/lib/{lsp-server-registry-946ysdqg.js → lsp-server-registry-C05QLdw0.js} +13 -13
  32. package/lib/{lsp-server-registry-XU6aHSqZ.js → lsp-server-registry-LUjrrLxk.js} +1 -1
  33. package/lib/main-7c69ae95.js +1432 -0
  34. package/lib/main-Dlv0Jm8U.js +3 -0
  35. package/lib/mobile/plugin.d.ts +4 -4
  36. package/lib/mobile/plugin.js +10 -10
  37. package/lib/puppeteer-core-BIIJGWPE.js +1136 -0
  38. package/lib/py-sdk.js +1 -1
  39. package/lib/remote/plugin.d.ts +3 -3
  40. package/lib/remote/plugin.js +148 -53
  41. package/lib/url-schemes/index.d.ts +11 -11
  42. package/lib/url-schemes/index.js +4274 -308
  43. package/lib/util-DgR7HQUl.js +2953 -0
  44. package/lib/web-password.d.ts +7 -7
  45. package/lib/web-password.js +2 -2
  46. package/lib/{web-trust-BO66y72w.js → web-trust-B27wcZEw.js} +2 -2
  47. package/lib/{web-trust-BihHCelF.d.ts → web-trust-CL9P6jVe.d.ts} +7 -7
  48. package/lib/web-trust.d.ts +1 -1
  49. package/lib/web-trust.js +2 -1
  50. package/lib/{wrap-Bzdimp4p.js → wrap-0VA0uFx8.js} +54 -51
  51. package/package.json +9 -21
  52. /package/lib/{kernel-env-hxaihi9C.js → kernel-env-BLPZE-I3.js} +0 -0
  53. /package/lib/{native-capture-x_Hos2e8.js → native-capture-BEByDXYM.js} +0 -0
  54. /package/lib/{py-sdk-Chvy92MB.js → py-sdk-D7klhpWb.js} +0 -0
@@ -0,0 +1,49 @@
1
+ # Third-party notices
2
+
3
+ `better-dsh` ships source copies of three MIT-licensed packages under
4
+ [`third_party/`](third_party/). They are **vendored, not dependencies**: the
5
+ plugin must not depend on how a host installation scope resolves them, so the
6
+ sources live here, are imported by relative path, and are inlined into the
7
+ published `lib/` bundle. Provenance, version pins, and the update procedure are
8
+ documented in [`third_party/README.md`](third_party/README.md).
9
+
10
+ | Package | Version | License | Upstream |
11
+ |---|---|---|---|
12
+ | `@deepseek-ai/schemastery` | 3.18.4 | MIT | <https://github.com/deepseek-ai/deepseek-harness> |
13
+ | `@deepseek-ai/cosmokit` | 1.8.5 | MIT | <https://github.com/deepseek-ai/deepseek-harness> |
14
+ | `@standard-schema/spec` | 1.1.0 | MIT | <https://github.com/standard-schema/standard-schema> |
15
+
16
+ `@standard-schema/spec` is a type-only import of `schemastery`'s declarations;
17
+ `cosmokit` is `schemastery`'s sole runtime dependency and is resolved from
18
+ `third_party/schemastery/node_modules/`.
19
+
20
+ ## MIT License
21
+
22
+ Applies to all three packages above, each with its own copyright holder:
23
+
24
+ ```
25
+ MIT License
26
+
27
+ Copyright (c) 2021-present Shigma (schemastery, cosmokit)
28
+ Copyright (c) 2024 Colin McDonnell (@standard-schema/spec)
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining a copy
31
+ of this software and associated documentation files (the "Software"), to deal
32
+ in the Software without restriction, including without limitation the rights
33
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
+ copies of the Software, and to permit persons to whom the Software is
35
+ furnished to do so, subject to the following conditions:
36
+
37
+ The above copyright notice and this permission notice shall be included in all
38
+ copies or substantial portions of the Software.
39
+
40
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
46
+ SOFTWARE.
47
+ ```
48
+
49
+ Each copy also retains its upstream `LICENSE` file in place.
@@ -0,0 +1,62 @@
1
+ # better-dsh schemastery 依赖声明修复实测报告(2026-10-02)
2
+
3
+ - **对象**:better-dsh **0.2.5 → 0.2.5-a** —— `@deepseek-ai/schemastery` 从 `dependencies` 改为 optional **peer**(commit `c4018aa`)
4
+ - **症状(用户报告)**:prod 实例每次启动都出现
5
+ `dashr-failover (better-dsh/failover): failed to import` +
6
+ `dashr-compaction-tuning (better-dsh/compaction-tuning): failed to import`
7
+ (本机 PC 3080 journal 自 **Sep 29** 起、共 **10 次 boot** 均复现,另附 `corti-memory`;dev3 prod 3080 同样两行)
8
+ - **载体**:本机 PC 3080 / dev3 prod 3080(dsh **0.2.0-rc.2**)+ 干净 profile 单变量复现 + dev3 全新重装验收
9
+
10
+ ## 一、根因
11
+
12
+ **链条**:better-dsh 把 `@deepseek-ai/schemastery` 写在自己的 **`dependencies`** → pnpm 在 `profiles/<p>/node_modules/@deepseek-ai/schemastery` **实体化出第二份** → Node 就近 walk-up 先命中这一份,**永远走不到 harness 的 installation-scope 拦截** → 该份被 profile 的 lockfile 冻在 **3.18.2**,而宿主已随 dsh 升到 **3.18.4**。
13
+
14
+ **为什么致命**:`.volatile()`(dsh 0.1.7+ settings 模型所需)**3.18.3 才引入**。better-dsh 的 `failover` / `compaction` 在**模块作用域**用 `.volatile()` 建 Config schema,导入即抛 → loader 记为 `failed to import`(fiber 根本没建)。
15
+
16
+ | 构建产物 | `volatile` 命中 | 实测 |
17
+ |---|---|---|
18
+ | `lib/failover/index.js` | 4 | **FAILS** |
19
+ | `lib/compaction/index.js` | 4 | **FAILS** |
20
+ | `lib/url-schemes/index.js` | 0 | OK |
21
+ | `lib/index.js`(main) | 0 | OK |
22
+
23
+ **harness 本来就已经供给它**(app-boot `collectInstallationScopePackages`):从已安装的 `@deepseek-ai/dsh` manifest 出发,BFS 走 **`dependencies ∪ peerDependencies` 传递闭包**,闭包内每个名字对**所有 profile** 生效。而 **dsh 自己 declare 了 `@deepseek-ai/schemastery: ~3.18.4`**,宿主树内即有(`…/dsh/node_modules/@deepseek-ai/schemastery`,**3.18.4**,带 `.volatile()`)。所以指针本应指向宿主,被我们自己搬到了 profile 层。
24
+
25
+ ## 二、修复
26
+
27
+ `c4018aa`:把 `@deepseek-ai/schemastery` 从 `dependencies` **删除**,只保留 optional peer 声明(与 `@deepseek-ai/dsh-*` 等其他 harness 包同款)。这样 pnpm 不再在 profile 里物化副本,解析回落到 installation scope(宿主的 3.18.4)。
28
+
29
+ (前一轮 `f11dda8` 的 floor bump `^3.18.1 → ^3.18.3` 保留为 0.2.5 存量用户的桥;peer 修正落地后不再有实际作用。**已按 §〇.5 撤回自包含/vendoring 方案** —— DSH 已 bundle 过一次,ride-on-DSH 的插件不应再抄一份。)
30
+
31
+ ## 三、验证
32
+
33
+ **1) 单变量复现/对照(决定性)**:一个 boot 完全干净的 profile,把 schemastery 从 3.18.4 换成 **3.18.2** → 重启后**恰好这两行**失败;换回即干净。单一变量、单一结果。
34
+
35
+ **2) 新 profile 装修正版**:profile 内 **`@deepseek-ai/` 整个目录都不存在**;boot **零 `did not activate`**。
36
+
37
+ **3) dev3 全新重装验收(第一人称,按 user 指令做的实验)**:
38
+ - 保留全部 user 数据(`sessions`/`storages`/`credentials`/`superd`/`task-board`),`cordis.patch.yml`(111 行用户层)原样恢复;
39
+ - 清空 `~/.dsh/profiles`(2.4G)与全局 DSH → DSH **从 registry** 重装 `0.2.0-rc.2`;
40
+ - profile 重建:DSH/SuperD **从 registry**,**better-dsh 用本次修正 tarball**;
41
+ - 结果对照:
42
+
43
+ | | 修复前 | 修复后 |
44
+ |---|---|---|
45
+ | `dashr-failover`/`dashr-compaction-tuning` `failed to import` | **2** | **0** |
46
+ | `dsh: warning: N entries did not activate` | 有 | **整行消失** |
47
+ | profile 层 `node_modules/@deepseek-ai/` | schemastery 3.18.2 + cosmokit | **不存在** |
48
+ | 正向验证 `curl :3080/` | — | **200 + `Enter the session password`**(web-password 行活着,独占 exact `/`) |
49
+
50
+ - 剩余 warning 属 **super-dsh**(`superd-hermes`/`superd-codex` 各 1 条 `session-controller: pending (waiting for service: fileUploads)`)——**pending 非 failed,且修复前的 boot 同样存在**,与本修复无关。
51
+
52
+ **4) 单元/类型**:`tsc --noEmit` **0 错**;`vitest run` **649 passed / 1 skipped**(57 文件)。
53
+
54
+ ## 四、附:一个独立的运维坑(非本 bug)
55
+
56
+ 本机曾出现 `dsh plugin add/remove` 报 `node_modules was installed with a different major version of pnpm`。根因 = **两个 pnpm 版本打架**:`/home/u1/.local/bin/pnpm` = 11.7.0(profile 的 node_modules 由它建,store **v11**)、`/usr/local/bin/pnpm` = **10.29.2**;某些调用上下文 PATH 不含 `~/.local/bin` → harness 调到 pnpm 10 去动 v11 建的树 → 硬错。
57
+
58
+ **已修**:`sudo npm i -g pnpm@11.7.0` → 两个路径均 **11.7.0**;模拟"`~/.local/bin` 掉出 PATH"的最坏情况仍得 11.7.0。dev3 全程用其本地 pnpm 10.33.2 干净完成安装,证明**该 bug 与 pnpm 无关**。
59
+
60
+ ## 五、判定
61
+
62
+ **通过**。根因单一且已用单变量复现 + 全新重装双重证明;修复面只有一个声明位的移动;dev3 第一人称验收 0 失败。发布 `0.2.5-a`。
@@ -0,0 +1,185 @@
1
+ # better-dsh 0.2.5-a 工具面实测报告:REPL / dvc://browser / dvc://ast_grep / dvc://ast_edit / dvc://lsp(4999 rig)
2
+
3
+ > **状态**:第一人称实测完成(agent 在真实 4999 会话内自测并留证)。
4
+ > **性质**:工具面**冒烟 + 回归**,**不是**发布验收——本轮未走 AGENTS.md §〇 的 a–d 发布闸,
5
+ > 不涉及也不授权 `npm publish`。
6
+ > **被测版本**:better-dsh `0.2.5-a`(package.json 与 profile 实装双侧一致);core `@deepseek-ai/dsh` `0.2.0-rc.2`。
7
+ > **仓库 commit**:`fb49834`(根仓与 `better-dsh/` 同 SHA)。
8
+ > **rig**:`.test/home/compat`,端口 4999,unit `dsh-4999-test123`;本轮**未重启、未改产物、未动 prod**。
9
+ > **时间**:2026-10-03 01:40–01:56 HKT(2026-10-02 17:40–17:56 UTC)。
10
+ > **相关前序**:[2026-09-27-lsp-ast-reminder-4999实测报告.md](2026-09-27-lsp-ast-reminder-4999实测报告.md)(lsp/ast 提醒的发布轮)。
11
+
12
+ ---
13
+
14
+ ## 0. 方法
15
+
16
+ - 全部证据取自**本会话内的真实工具调用**(第一人称),非单测、非静态检查、非进程活性。
17
+ - `dvc://` 设备经 `write dvc://<device>` 执行,`read dvc://<device>` 仅取用法;REPL 证据取自 `eval` 单元。
18
+ - 临时产物集中在 `.scratch/ast-probe/`;browser 设备测毕已 `close`(无孤儿 Chrome)。
19
+
20
+ ## 1. 结论摘要
21
+
22
+ | # | 面 | 结论 | 关键证据 |
23
+ |---|---|---|---|
24
+ | 1 | REPL(`eval`) | ✅ 全绿 | 跨 cell 状态、完成值、工具桥、错误信封、异常存活 7/7 |
25
+ | 2 | `dvc://browser` | ✅ 功能全绿;⚠️ 进不去带密码闸的 GUI | open/run/type+click/close + 字段白名单全通 |
26
+ | 3 | `dvc://ast_grep` | ✅ 可用;⚠️ 相对路径基准非 workspace | 15 命中、`metaVariables`、`offset/limit` |
27
+ | 4 | `dvc://ast_edit` | ✅ dryRun 与实写均正确 | `dryRun:true` 不落盘;`false` → `applied:true` 且盘面核实 |
28
+ | 5 | `dvc://lsp` | ✅ gate + diagnostics + hover 全绿 | TS2322 error + TS6133 hint,坐标精确 |
29
+ | 6 | AST 可用性提醒 | ✅ 实测出现 | `write` 结果尾行一行提醒 |
30
+
31
+ 净结论:**四个 dvc 设备与 REPL 主体功能无回归**;发现 2 个可用性摩擦(F1/F2)与 1 个 API 面不一致(F3),
32
+ 均非阻断,建议并入下一次批量发布(AGENTS.md §〇.5)。
33
+
34
+ ## 2. REPL(`eval` / dashr-repl 桥)— 全绿
35
+
36
+ | 探针 | 结果 |
37
+ |---|---|
38
+ | 跨 cell 状态 | cell 1 设 `REPL_MARKER = "cell-1-alive"`,cell 2/4/6 读回一致 |
39
+ | 导入持久 | cell 3 `import asyncio, json, collections`,cell 4 仍绑定 |
40
+ | 完成值协议 | 末行裸表达式 `x`(=42)作为 completion value 返回,与 `print` 并存 |
41
+ | 工具桥 | `await tool.bash({"command": "echo bridge-ok"})` → `bridge-ok`,exit 0 |
42
+ | 错误信封 | 失败子调用抛 `ToolCallError`,`.toolName == "read"` |
43
+ | 入参校验 | `tool.read({})` → `[E_BAD_SHAPE] Read request requires a non-empty "path" string.` |
44
+ | 异常存活 | 内核在 SyntaxError、AttributeError 两次异常后仍持有全部状态 |
45
+ | 内核 | CPython `3.11.15`(profile 内 `.venv-kernel`) |
46
+
47
+ 桥接口径与 wire description 一致(`await tool.<name>(args)` 单位置参数对象,`true/false/null` → `True/False/None`)。
48
+
49
+ ## 3. `dvc://browser`
50
+
51
+ | 动作 | 结果 |
52
+ |---|---|
53
+ | `{"action":"open","url":"https://example.com"}` | `{ok:true, url, title:"Example Domain"}` |
54
+ | `{"action":"run","code":"…"}`(DOM eval) | 取回 `title/links/readyState`,JSON 字符串回传 |
55
+ | `{"action":"run","type":…,"click":…}` | 复合动作生效:`data:` 页 title 由 `t0` → `hello-dvc` |
56
+ | `{"action":"close"}` | `{ok:true}` |
57
+ | 未知字段 | `{"action":"open",…,"bogusField":1}` → `unknown field(s) "bogusField" for action "open" — allowed: "action", "url", "executablePath"` |
58
+
59
+ **⚠️ 限制(F2)**:指向本 GUI(`http://127.0.0.1:4999`)时,`?token=` 启动 URL **不能**为新浏览器铸出会话——
60
+ 页面停在 `Enter the session password to continue. PASSWORD Unlock`,`window.__DSH_BOOT__` 不存在、
61
+ 无任何 `better-dsh` 资源请求。因此 `dvc://browser` 目前**无法**用于对本 GUI 做端到端第一人称验收,
62
+ 除非补一条 cookie 注入/免密通道。(本 rig 是密码闸实例;token 只负责首铸 cookie,而全新 Chrome 无 cookie。)
63
+
64
+ **方法学附注(假阳性预防)**:首轮 DOM 探针返回 `h1count: 0`,一度疑似设备缺陷;
65
+ 核对线上原文后确认 **example.com 今日已无 `<h1>`**(仅 `<p>` + `<script>`),**设备是对的,探针是我的错**。
66
+ 记录此条以防后续把同类现象误判为插件 bug。
67
+
68
+ ## 4. `dvc://ast_grep`
69
+
70
+ | 项 | 结果 |
71
+ |---|---|
72
+ | 模式 | `defineTool($$$ARGS)`,`includeMeta:true` → 命中 15 / 13 文件 / 扫 189 文件,`limitReached:true` |
73
+ | 结构信息 | 每条含 `byteStart/byteEnd/startLine/startColumn/endLine/endColumn` + AST 级 `metaVariables` |
74
+ | 分页 | `offset:10, limit:2` → 精确返回 2 条(分页生效) |
75
+ | 语法错误容忍 | `defineTool({$$$})` 在 `defaults.json` 上语法不合法 → 该文件进 `parseErrors[]`,**整次搜索不失败**,其余 15 命中照常返回 |
76
+
77
+ **⚠️ 相对路径基准(F1)**:`path:"better-dsh/src"` → `Path not found: No such file or directory (os error 2)`;
78
+ 改为绝对路径即通。决定性实验:**`path:"../../better-dsh/src"` 命中 15 条,与绝对路径结果一致**。
79
+ 即 ast 设备的相对路径基准 = **harness 进程 cwd(`upstream/deepseek-harness`)**,而非会话 workspace
80
+ (`/home/u1/workspaces/dashr`)——与 `read/glob/grep` 的 workspace 基准**不一致**。
81
+ 返回值里的 `path` 也用同一基准显示(`../../better-dsh/src/bridges/index.ts`)。
82
+ **规避**:始终传绝对路径。
83
+
84
+ ## 5. `dvc://ast_edit`
85
+
86
+ 输入(作用于 scratch 文件):
87
+
88
+ ```json
89
+ {"ops":[{"pat":"const $NAME = function ($ARG) { $$$B }","out":"function $NAME($ARG) { $$$B }"}],
90
+ "paths":["/home/u1/workspaces/dashr/.scratch/ast-probe/sample.ts"],"dryRun":true}
91
+ ```
92
+
93
+ | 项 | 结果 |
94
+ |---|---|
95
+ | `dryRun:true`(默认) | 返回 `before`/`after` 与字节区间 `byteStart:74, byteEnd:128, deletedLength:54`;**`applied:false`,盘面未变** |
96
+ | `dryRun:false` | 同区间,**`applied:true`**;盘面核实:`const legacy = function (x: number) {…}` → `function legacy(x: number) { return x * 2 }` |
97
+ | `fileChanges`/`totalReplacements`/`filesTouched` | 1 / 1 / 1,与 `limitReached:false` 自洽 |
98
+
99
+ `paths` 同样受 F1 影响(本轮用绝对路径,未复现相对路径问题)。
100
+
101
+ ## 6. `dvc://lsp`
102
+
103
+ | 步骤 | 结果 |
104
+ |---|---|
105
+ | 初始 `status` | `{ok:true, gate:"unasked"}` —— per-session 闸,未询问态 |
106
+ | `{"action":"on"}` | `{ok:true, gate:"on", message:"lsp on for this session: servers warm-start per language on first file contact; no repo artifacts are written."}` |
107
+ | `diagnostics`(植入 2 处错) | `server:"typescript-language-server"`,自动推断 `root`;返回 **TS2322 error**(`Type 'number' is not assignable to type 'string'`,4:3)+ **TS6133 hint**(`'unusedVar' is declared but its value is never read.`,1:7);`summary:"1 error(s), 1 hint(s)"` |
108
+ | `hover`(3:17) | ```typescript\nfunction bad(x: number): string\n``` |
109
+
110
+ 坐标与 `severityName`(error/hint)均正确;服务器来源为 `typescript-language-server`。
111
+
112
+ ## 7. AST 可用性提醒 — 实测出现
113
+
114
+ 对新建 `.ts` 文件执行 `write`,结果尾部实测出现:
115
+
116
+ ```
117
+ ast_edit / ast_grep available — write dvc://ast_edit (structured rewrite) or dvc://ast_grep (pattern search)
118
+ ```
119
+
120
+ 与前序报告的制度一致(提醒挂 `write/edit/grep` 结果尾部、per-session cap)。
121
+ **注**:本轮未观测到 **LSP nag**(在接触代码文件前已把 gate 置 `on`,`unasked` 条件不再成立),故 nag 路径未覆盖;
122
+ 提醒的 **cap 计数**本轮亦未触及边界(未做 >5 次触发)。
123
+
124
+ ## 8. 发现清单
125
+
126
+ | ID | 严重度 | 面 | 现象 | 建议 |
127
+ |---|---|---|---|---|
128
+ | **F1** | 中(摩擦) | `dvc://ast_grep`/`ast_edit` | 相对 `path` 基准 = harness 进程 cwd(`upstream/deepseek-harness`),非会话 workspace;`"better-dsh/src"` 直接 `Path not found` | 二选一:①基准改为 workspace / `exec.cwd`;②保持现状但在 device help 明写"仅收绝对路径" |
129
+ | **F2** | 中(能力缺口) | `dvc://browser` | 无 cookie 注入通道,进不去密码闸 GUI;`?token=` 不足以对新浏览器铸会话 | 若要支撑 GUI 端到端第一人称验收,需补 cookie/免密通道 |
130
+ | **F3** | 中(API 一致性) | `llm_completion` | **返回类型不稳定**:成功回 **裸 `str`**(`'alpha beta gamma'`),失败回 **`dict`**(`{"error":"llm_completion() output reached its maxTokens ceiling"}`);调用方 `r["text"]` / `r.keys()` 会炸 | 统一为判别式对象(`{ok:true,text}` / `{ok:false,error}`) |
131
+ | **F4** | 低(调优) | REPL 子调用池 | 变更类子调用实际**串行**:4×`sleep 1` = 4.78s;6×`glob` = 14.71s。源码有 `maxParallelSubCalls`(默认 10)与 `parallel\|exclusive` 分类,但观测未见并行收益 | 复核 classify 是否把常用工具过度判为 `exclusive` |
132
+ | **F5** | 低(体验) | `llm_completion` | `maxTokens` 偏小(16)时因推理吃掉预算而**整次失败**而非截断 | 考虑截断或给出可操作的错误提示 |
133
+ | — | 观察(正面) | harness | 连续 5 次同参调用触发**重复调用护栏**并阻止了潜在死循环 | 保留 |
134
+
135
+ ## 9. 未覆盖 / 遗留
136
+
137
+ - `dvc://lsp` 的 `references` / `definition` / `format` / `rename` / `code_actions` / `reload` 未在本轮复测
138
+ (2026-09-27 报告已全绿;本轮只补 `status`/`on`/`diagnostics`/`hover`)。
139
+ - LSP **nag 路径**与 AST 提醒 **cap 边界**未覆盖(见 §7)。
140
+ - `dvc://ast_edit` 相对路径未复测(F1 已在 `ast_grep` 上定位)。
141
+ - `agent` / `agent_message` / `agent_workflow` / `remote` / 各 URL scheme(`ctx://` `skill://` `dsh://`)
142
+ 本轮未测(不属本次指定的工具面;`ctx://` 另有 2026-10-02 专项报告)。
143
+ - 生产 3080 **未部署验证**(本轮纯 4999,未触碰 prod)。
144
+
145
+ ## 10. 复现命令
146
+
147
+ ```bash
148
+ # REPL:在任意 4999 会话内
149
+ # eval: REPL_MARKER = "cell-1-alive" → 下一 cell: print(REPL_MARKER)
150
+
151
+ # ast_grep(务必绝对路径,或按 F1 用 ../../ 相对 harness 根)
152
+ # write dvc://ast_grep {"patterns":["defineTool($$$ARGS)"],
153
+ # "path":"/home/u1/workspaces/dashr/better-dsh/src","limit":5,"includeMeta":true}
154
+
155
+ # ast_edit dryRun → 实写
156
+ # write dvc://ast_edit {"ops":[{"pat":"const $NAME = function ($ARG) { $$$B }",
157
+ # "out":"function $NAME($ARG) { $$$B }"}],
158
+ # "paths":["<abs>/sample.ts"],"dryRun":true} # 再 dryRun:false 并 cat 盘面
159
+
160
+ # lsp
161
+ # write dvc://lsp {"action":"status"} # → gate:"unasked"
162
+ # write dvc://lsp {"action":"on"} # → gate:"on"
163
+ # write dvc://lsp {"action":"diagnostics","file":"<abs>/diag.ts"}
164
+ # write dvc://lsp {"action":"hover","file":"<abs>/diag.ts","line":3,"character":17}
165
+
166
+ # browser
167
+ # write dvc://browser {"action":"open","url":"https://example.com"}
168
+ # write dvc://browser {"action":"run","code":"document.title"}
169
+ # write dvc://browser {"action":"close"}
170
+ ```
171
+
172
+ ## 11. 附:本轮环境事实
173
+
174
+ | 项 | 值 |
175
+ |---|---|
176
+ | better-dsh | `0.2.5-a`(package.json ≡ profile 实装) |
177
+ | core | `@deepseek-ai/dsh` `0.2.0-rc.2` |
178
+ | commit | `fb49834` |
179
+ | rig home | `.test/home/compat` |
180
+ | 内核 | CPython `3.11.15`(`.venv-kernel`) |
181
+ | LSP 服务器 | `typescript-language-server` |
182
+ | browser 引擎 | Chromium(`puppeteer-core`,UA 含 `HeadlessChrome`) |
183
+
184
+ > 注:`readlink /proc/<pid>/cwd` 在本沙箱内取不到 4999 进程的 cwd(进程在另一命名空间),
185
+ > F1 的基准结论由**路径算术实验**(`better-dsh/src` 失败 vs `../../better-dsh/src` 全量命中)独立钉死,不依赖该读法。
@@ -0,0 +1,101 @@
1
+ # better-dsh:vendored 包改物理 import + `llm_completion` 返回形态 + ast 相对路径(2026-10-03)
2
+
3
+ - **对象**:better-dsh `0.2.5-a`(本地过程版本,未发布)
4
+ - **载体**:dev 树 + 4999 rig(`.test/home/compat`,unit `dsh-4999-test123`,core `0.2.0-rc.2`)
5
+ - **前序**:[2026-10-03-schemastery-cosmokit源码内联实测报告](2026-10-03-schemastery-cosmokit源码内联实测报告.md)、[2026-10-03-better-dsh-tool-surface-repl-dvc-browser-ast-lsp-4999实测报告](2026-10-03-better-dsh-tool-surface-repl-dvc-browser-ast-lsp-4999实测报告.md)(后者的 F1/F3 在本轮修复)
6
+
7
+ ## 一、vendored 包改为"物理 import"(去掉我上一轮加的 shim)
8
+
9
+ user 裁决:不要额外逻辑,**物理 import** 即可 —— 文件名就叫 `@deepseek-ai/<pkg>`,目标只是避开构建期/运行期的解析 logistics。
10
+
11
+ **终态**(41 个文件 / **348 KB**):
12
+
13
+ ```
14
+ third_party/
15
+ schemastery/ @deepseek-ai/schemastery 3.18.4 (MIT)
16
+ lib/index.mjs lib/index.cjs lib/types/…
17
+ lib/index.d.mts ← 唯一自加文件(见下)
18
+ src/index.ts LICENSE README.md package.json
19
+ node_modules/@deepseek-ai/cosmokit/ @deepseek-ai/cosmokit 1.8.5 (MIT)
20
+ node_modules/@standard-schema/spec/ 1.1.0 (MIT, 仅类型)
21
+ ```
22
+
23
+ `package.json` 里一个子路径映射(**删除了 `src/schemastery.ts`**):
24
+
25
+ ```json
26
+ "imports": {
27
+ "#schemastery": {
28
+ "types": "./third_party/schemastery/lib/index.d.mts",
29
+ "default": "./third_party/schemastery/lib/index.mjs"
30
+ }
31
+ }
32
+ ```
33
+
34
+ 9 个源文件统一 `import z from '#schemastery'`。
35
+
36
+ **两个必须知道的机制点**(都是实测撞出来的,不是猜的):
37
+
38
+ 1. **TS 拒绝把 `imports` target 指进 `node_modules` 段**。最初的镜像布局是
39
+ `third_party/node_modules/@deepseek-ai/schemastery/…`,`tsc` 报
40
+ `package.json scope … has invalid type for target of specifier '#schemastery'`;
41
+ 读 TS 源码定位到该诊断位于 `loadModuleFromTargetImportOrExport` 的
42
+ `!startsWith(target, "./")` 分支后,把 target 换成不含 `node_modules` 的路径即通。
43
+ 于是 schemastery **平铺**在 `third_party/schemastery/`,而它的依赖仍按真实安装形态
44
+ **嵌在它自己的 `node_modules/` 里**——这样 schemastery 内部的
45
+ `import '@deepseek-ai/cosmokit'` 就地解析,**vendored 代码一行都不用改**(`diff -rq`
46
+ 与上游逐字节一致,除我们新增的 `lib/index.d.mts`)。
47
+ 2. **`lib/index.d.mts` 这一个两行文件是必需的**:本包 `"type": "module"`,TS 会把
48
+ `lib/types/index.d.ts` 当 CJS 声明,直接 import `lib/index.mjs` 时取不到类型;
49
+ `.d.mts` 是 TS 的标准 ESM 声明位。
50
+
51
+ **副产品(比预期更好)**:类型面也不再引用外部 —— `lib/*.d.ts` 现在从**本地 chunk**
52
+ (`import { t as Schema } from "./index-DZQNwO7f.js"`)取 `Schema`,`lib/` 里既无
53
+ `#schemastery` 也无裸 `@deepseek-ai/schemastery`。即发布物**运行期 + 类型面双双自包含**。
54
+
55
+ ## 二、F3:`llm_completion` 返回形态统一(这是**我们自己**的工具)
56
+
57
+ 它是本插件自研的 one-shot / 无工具 / 无上下文的工具(`src/llm-completion.ts`),桥接上游
58
+ `ctx.llm` 服务;不是上游工具。原实现**成功回裸 `str`、失败回 `{ error }`**,程序化调用方
59
+ `r["text"]` / `r.keys()` 会炸。
60
+
61
+ 修法(三层一起改,缺一不可):
62
+
63
+ - 返回值:`{ ok: true, text }` / `{ ok: false, error }`(9 个错误点 + 1 个成功点);
64
+ - 工具 `output.schema`:`oneOf: [textVariant, errorVariant]`(原为 `oneOf: [string, errorVariant]`
65
+ —— **不改这里会直接报** `value must match exactly one oneOf branch (matched 0)`);
66
+ - `render`:成功时仍渲染纯文本(模型面可读),失败渲染 JSON;
67
+ - 描述补一句"直接调用成功时只渲染文本",消除"契约说对象、surface 是文本"的歧义(本轮第一人称
68
+ agent 如实报了这一点)。
69
+ - 测试同步:`test/surface-devices/llm-completion.spec.ts` 4/4 绿。
70
+
71
+ ## 三、F1:ast 设备的相对路径基准改为**会话 workspace**
72
+
73
+ 根因:eval 工具用的是 `exec.agent.session.header.cwd`(`src/index.ts:896`),而 dvc 写入这条路
74
+ 只把 `session` 传进设备(`dispatchDvcWrite(path, content, meta.session)`),没传 cwd,
75
+ `ast-device` 的 `ctxCwd()` 只能回落到**守护进程 cwd**(= `upstream/deepseek-harness`)。
76
+
77
+ 修法:把同一个 cwd 作为 transport 槽位补齐(不是 payload,避免触发设备的严格字段校验):
78
+
79
+ - `tools/write.ts`:`writeScheme(..., { session, ...exec.agent ? { cwd: exec.agent.session.header.cwd } : {} })`;
80
+ - `handlers/dvc.ts`:`dispatchDvcWrite(path, content, session?, cwd?)` → `device.execute(args, { session, ...(cwd ? { cwd } : {}) })`。
81
+
82
+ ## 四、验证
83
+
84
+ | 项 | 结果 |
85
+ |---|---|
86
+ | `tsc --noEmit`(host + client) | **0 错** |
87
+ | `npm run build` | 通过;产物 JS 无任何裸 `@deepseek-ai/schemastery\|cosmokit`;`lib/` 无 `#schemastery` |
88
+ | 全量单测 | **57 文件 / 649 passed, 1 skipped** |
89
+ | rig 安装 | 两个 profile 均 **`Packages: +1`** |
90
+ | rig 启动 | 零 `failed to import` / `did not activate` / `EPIPE`(上一轮修的 EPIPE:新 boot 段实测干净) |
91
+ | **F1 第一人称** | `write dvc://ast_grep {"patterns":["loadPiNatives"],"path":"better-dsh/src"}` → 命中 2 文件 / 3 处,且返回 `path` 为 **workspace 相对**(`better-dsh/src/devices/ast/ast-device.ts`) |
92
+ | **F3 第一人称** | `llm_completion({prompt:'只回答一个词:OK'})` → 程序化值为 `{ok:true,text:"OK"}`;agent 观测到的 surface 为纯文本 `OK`(render 层行为,描述已写明) |
93
+
94
+ ## 五、未做 / 限制
95
+
96
+ - **发布**:按 AGENTS.md §〇,`npm publish` 需 user 单次明确放行,本轮未发。
97
+ - `third_party/` **不随 tarball 发布**(`files` 不含它):`lib/` 已经内联了运行期与类型面,
98
+ 发布物自包含;vendored 源码只服务本仓构建。`package.json#imports` 因此在发布物里是
99
+ "指向未发布文件"的悬空映射 —— 发布物内没有任何代码 import 它(已实测 `lib/` 零引用)。
100
+ - `llm_completion` 的 F5(`maxTokens` 过小时整次失败而非截断)**未动**,见汇报;改动它会变更语义。
101
+ - F2(browser 无 cookie 注入通道)、F4(REPL 子调用未并行)未动。
@@ -0,0 +1,54 @@
1
+ # pnpm 11 年龄门:`minimumReleaseAgeExclude` 对"锁文件校验相位"完全无效(2026-10-03 实证)
2
+
3
+ - **触发**:user 在 homepc(prod)执行 `dsh plugin --profile web add better-dsh@0.2.5-b`,被拦:
4
+ ```
5
+ ✗ Lockfile failed supply-chain policy check (431 entries in 2.6s)
6
+ [ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION] 1 lockfile entries failed verification:
7
+ super-dsh@0.1.9 was published at 2026-10-02T07:45:36.963Z, within the minimumReleaseAge cutoff
8
+ ```
9
+ 即:**装 better-dsh 被 _另一个插件_ super-dsh@0.1.9 的年龄拦下**(该条目在 profile 锁文件里,发布未满 24h)。
10
+ - **环境**:pnpm 11.7.0,profile `~/.dsh/profiles/web`,core dsh 0.2.0-rc.2。
11
+
12
+ ## 一、决定性 A/B(同一份 prod 锁文件,只改变量)
13
+
14
+ 把 prod profile 的 `package.json` + `pnpm-lock.yaml` + `pnpm-workspace.yaml` 复制到 `.scratch/age-probe/`,
15
+ 每个变体只往 `pnpm-workspace.yaml` 追加一行,跑 `pnpm install --lockfile-only`,只看策略结论行:
16
+
17
+ | 变体 | `minimumReleaseAgeExclude` 内容 | 结果 |
18
+ |---|---|---|
19
+ | **V1** 现状 | `better-dsh` + `super-dsh@0.1.5-a` + `super-dsh@0.1.9` | ✗ failed(复现现场报错) |
20
+ | **V2** | V1 + 裸名 `super-dsh` | ✗ failed |
21
+ | **V3** | V2 + 裸名 `better-dsh` | ✗ failed |
22
+ | **V4** | V1 + `minimumReleaseAge: 0` | **✓ passes** |
23
+
24
+ **结论**:在 pnpm 11.7.0 上,`minimumReleaseAgeExclude` —— 无论 `pkg@x.y.z` 形式还是裸包名 ——
25
+ **都不能豁免锁文件校验相位**;唯一有效旋钮是 `minimumReleaseAge` 本身(设 0,或设成小于该条目年龄的值)。
26
+ 本仓 AGENTS.md 此前"持久形式 = 裸包名,全相位生效(scratch A5–A7 实证)"的结论**是错的,已订正**。
27
+
28
+ ## 二、修复(prod 现场)
29
+
30
+ ```yaml
31
+ # ~/.dsh/profiles/web/pnpm-workspace.yaml (追加)
32
+ minimumReleaseAge: 0
33
+ ```
34
+
35
+ - 备份:`pnpm-workspace.yaml.bak-minimumReleaseAge-20261003`。
36
+ - 重跑 user 原命令:`Packages: +8 -95`,`Done in 4.8s`,pin 落到 `0.2.5-b`。
37
+ - 装机核查:`version 0.2.5-b` / `deps: None, optional: None` / `lib/kernel-bridge.py` 在位 /
38
+ 树里无 `zeromq` / lockfile integrity `sha512-M93FoCq…BYYrHQ==`(与 registry 发布物、与 dev3 拉到的**同一份**)。
39
+
40
+ ## 三、影响面与建议
41
+
42
+ - **任何"发布后立刻装"的 profile 都会撞这道门**,而且拦的往往是**别的**插件条目(本例是 super-dsh)。
43
+ 当前 prod profile 的 `minimumReleaseAgeExclude` 三条全是无效配置(留着无害,但别再依赖它)。
44
+ - 两条可行路线:① profile 级 `minimumReleaseAge: 0`(本次采用,最省事,代价是该 profile 放弃 24h 冷却);
45
+ ② 等服务窗口(super-dsh@0.1.9 → 2026-10-03T07:45Z / 15:45 HKT 自然解锁)——但装完 better-dsh@0.2.5-b 后,
46
+ 它自己又变成"未满 24h 条目",后续任何 pnpm 操作会**再撞一次**,所以路线 ② 只是把窗口推后。
47
+ - `dsh plugin add` 输出里的 `dshmarket@1.40.0 is incompatible with dsh 0.2.0-rc.2`(peer 不符)是**既有**状态
48
+ (untouched 分支:保留安装、启动时 deny,需 `dsh plugin allow-version` 豁免),与本次改动无关。
49
+
50
+ ## 四、未做
51
+
52
+ - 未重启 `dsh.service`:prod 运行中的 daemon 仍持有 0.2.5-a 的代码,激活需重启(重启会中断当前 GUI 会话;
53
+ session 数据在盘上,刷新即回)。
54
+ - 未提交 AGENTS.md 订正与本报(git 侧待 user 指示)。