dsh-opencode-go 0.1.20 → 0.1.22

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 (56) hide show
  1. package/README.en.md +133 -127
  2. package/README.md +131 -127
  3. package/THIRD_PARTY_NOTICES.md +3 -1
  4. package/docs/development.md +60 -8
  5. package/docs/fork-review-2026-09-25.md +191 -0
  6. package/docs/independent-package.md +2 -2
  7. package/docs/verification.md +241 -0
  8. package/lib/build-info.json +8 -1
  9. package/lib/client.js +1576 -234
  10. package/lib/index.js +7001 -338
  11. package/lib/types/account-manager.d.ts +23 -0
  12. package/lib/types/account-operations.d.ts +31 -0
  13. package/lib/types/account-policy.d.ts +16 -0
  14. package/lib/types/account-recovery.d.ts +2 -0
  15. package/lib/types/account-selection.d.ts +30 -0
  16. package/lib/types/account-service.d.ts +12 -0
  17. package/lib/types/accounts-contract.d.ts +38 -0
  18. package/lib/types/accounts.d.ts +31 -0
  19. package/lib/types/adapter.d.ts +43 -9
  20. package/lib/types/call-trace.d.ts +54 -0
  21. package/lib/types/catalog-manager.d.ts +20 -0
  22. package/lib/types/catalog.d.ts +6 -3
  23. package/lib/types/client/AccountsCard.d.ts +19 -0
  24. package/lib/types/client/Section.d.ts +3 -6
  25. package/lib/types/client/UsagePill.d.ts +4 -2
  26. package/lib/types/client/accounts-controller.d.ts +69 -0
  27. package/lib/types/client/host-compat.d.ts +7 -0
  28. package/lib/types/client/locales.d.ts +55 -1
  29. package/lib/types/client/section-controller.d.ts +17 -41
  30. package/lib/types/client/staged-form.d.ts +1 -3
  31. package/lib/types/client/usage.d.ts +1 -1
  32. package/lib/types/config-contract.d.ts +69 -0
  33. package/lib/types/config.d.ts +12 -47
  34. package/lib/types/conversion/context.d.ts +5 -1
  35. package/lib/types/conversion/image-pool.d.ts +24 -0
  36. package/lib/types/conversion/replay.d.ts +1 -1
  37. package/lib/types/conversion/stream.d.ts +1 -1
  38. package/lib/types/gateway-diagnostics.d.ts +22 -0
  39. package/lib/types/gateway-error.d.ts +2 -0
  40. package/lib/types/host-settings.d.ts +11 -0
  41. package/lib/types/index.d.ts +2 -1
  42. package/lib/types/json-response.d.ts +1 -1
  43. package/lib/types/model-metadata.d.ts +3 -1
  44. package/lib/types/models-contract.d.ts +7 -0
  45. package/lib/types/protocol-contract.d.ts +5 -0
  46. package/lib/types/protocol-policy.d.ts +4 -0
  47. package/lib/types/proxy-url.d.ts +2 -0
  48. package/lib/types/proxy.d.ts +11 -0
  49. package/lib/types/reasoning.d.ts +36 -6
  50. package/lib/types/request-control.d.ts +2 -0
  51. package/lib/types/sdk-types.d.ts +1568 -0
  52. package/lib/types/settings-bridge.d.ts +22 -0
  53. package/lib/types/usage-contract.d.ts +5 -0
  54. package/lib/types/usage.d.ts +14 -2
  55. package/lib/vendor-licenses.txt +103 -0
  56. package/package.json +8 -2
package/README.md CHANGED
@@ -2,210 +2,214 @@
2
2
 
3
3
  [English](README.en.md)
4
4
 
5
- 功能:让你在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 中完美使用 OpenCode Go 订阅模型,支持流式回复、工具调用和图片输入。
5
+ 在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 中使用 OpenCode Go 订阅模型,支持流式回复、思考模式、工具调用和图片输入。插件自动同步模型列表与容量信息,并提供多账号管理、订阅用量显示和网络代理设置。
6
6
 
7
- 插件会自动添加 OpenCode Go 所需的会话请求头、读取网关模型目录,并显示订阅用量,无需给模型配置协议、模态、上下文长度、最大输出token
7
+ 适用于 DSH `0.1.5-rc.1` 及以上版本。
8
8
 
9
- ## 功能说明
9
+ 安装兼容性已覆盖十个宿主版本,从 `0.1.5-rc.1` 到 `0.2.1-alpha.1`,具体版本见[兼容矩阵](docs/development.md#installed-package-matrix)。后续宿主版本仍需验证;目前会明确拒绝 developer 消息、动态工具增删和延迟工具加载。
10
10
 
11
- - **会话请求头**:每次请求包含 Harness User-Agent 和 `x-opencode-session`。同一会话保持稳定 ID,支持网关路由和提示词缓存优化;实际命中率取决于上游服务。
12
- - **流式与历史**:支持流式输出、工具调用及历史回放,协议请求由 pi-ai 执行。
13
- - **图片输入**:支持目录中声明图片能力的模型。
14
- - **模型容量覆盖**:可按模型覆盖上下文窗口和最大输出,空值继承在线目录。
15
- - **逐模型开关**:每个模型独立控制会话中的显示状态,修改立即生效;普通模型默认开启,过时模型默认关闭,也可单独开启。
16
- - **提示与缓存**:插件不增加隐藏系统提示;会话 ID 用于网关路由。
11
+ ## 安装
17
12
 
18
- ## 安装与使用
13
+ ### 在 DSH 中安装
19
14
 
20
- 支持 DSH `0.1.5-rc.1` 及以上版本,包括 alpha、rc 和正式版,并持续跟随宿主版本更新维护兼容性。
21
-
22
- 已验证版本:`0.1.5-rc.1`、`0.1.5-rc.2`、`0.1.6-alpha.1`、`0.1.6-alpha.2`、`0.1.7-alpha.1`、`0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2` 和 `0.2.0-rc.2`。
23
-
24
- ### 在 DSH 中安装(推荐)
25
-
26
- 1. 打开 DSH 的 **插件** 页面,点击右上角 **添加插件**。
15
+ 1. 打开 **插件 → 添加插件**。
27
16
  2. 输入 `dsh-opencode-go`,点击 **安装**。
28
- 3. 安装成功后,如果出现 **立即启用**,点击即可。
29
-
30
- ![在 DSH 插件页添加、安装并启用 dsh-opencode-go](docs/assets/install-via-dsh.gif)
17
+ 3. 安装完成后点击 **立即启用**。
31
18
 
32
- 然后打开 **设置 → OpenCode Go**,填入 API Key 并保存,即可在会话中选择 OpenCode Go 模型。
19
+ ![在 DSH 中安装插件](docs/assets/install-via-dsh.gif)
33
20
 
34
- 也支持在添加插件时直接输入 Git 仓库地址:
21
+ 也可以在添加插件时输入 Git 仓库地址:
35
22
 
36
23
  ```text
37
24
  https://github.com/Duskriver/dsh-opencode-go
38
25
  ```
39
26
 
40
- 当前主分支附带编译好的插件,安装时无需本地构建,也无需为本插件修改 `allowBuilds`。固定到旧提交的 Git 地址仍沿用旧提交的安装方式,请更新到当前主分支。
41
-
42
- 若当前 DSH 没有「添加插件」入口,可使用下面的命令行方式。
43
-
44
- ### 命令行安装(备选)
27
+ ### 命令行安装
45
28
 
46
29
  ```sh
47
30
  dsh plugin --profile web add dsh-opencode-go
48
31
  ```
49
32
 
50
- 安装后启动或重启 `dsh web`,然后:
33
+ 安装后启动或重启 `dsh web`。Web 和 Headless 使用各自的 profile,分别安装和更新。
51
34
 
52
- 1. 打开 **设置 → OpenCode Go**。
53
- 2. 填入 OpenCode Go API Key 并保存。
54
- 3. 在会话的模型选择器中选择 OpenCode Go 模型。
35
+ ## 开始使用
55
36
 
56
- ### 无头模式
37
+ 1. 打开 **设置 → OpenCode Go**,填入 API Key 并保存,或在「账号」中添加账号。
38
+ 2. 在会话模型选择器中选择 **DSH OpenCode Go** 下的模型。
39
+ 3. 开始对话;支持思考的模型可选择其提供的思考档位,支持图片的模型可直接接收图片。
57
40
 
58
- 安装到 Headless profile:
41
+ 在设置页刷新模型列表即可同步最新目录。每个模型旁的开关控制它是否出现在选择器中,修改后立即生效。模型的上下文窗口和最大输出默认使用目录配置,也可逐个修改并保存。
59
42
 
60
- ```sh
61
- dsh plugin --profile headless add dsh-opencode-go
62
- ```
43
+ 思考选项中的 **默认** 使用服务商设置;**Off** 明确关闭思考。只有开关的模型显示 **On / Off**,支持强度的模型显示其可用档位,预算式模型显示具体的 token 数值。
63
44
 
64
- 将以下内容保存为 `headless.patch.yml`,选择默认模型:
45
+ 预算式模型提供 1,024 / 2,048 / 8,192 / 16,384 tokens 等常用选项。在设置页选择模型,展开“思考预算”,输入数值、点击“添加”并保存,即可在会话中选择自定义预算。可用范围随模型而定;SDK 会根据剩余输出空间缩小实际预算。
65
46
 
66
- ```yaml
67
- - id: agent-default-model
68
- config:
69
- provider: dsh-opencode-go
70
- model: deepseek-v4.1-flash
71
- ```
47
+ 插件跟随 DSH 的界面语言,支持中文和英文。
72
48
 
73
- 在 Bash 或 Zsh 中读取 API Key,然后运行任务:
49
+ ### 查看订阅用量
74
50
 
75
- ```sh
76
- read -s OPENCODE_API_KEY
77
- export OPENCODE_API_KEY
78
- dsh --profile headless --patch ./headless.patch.yml "你好"
79
- ```
51
+ 点击会话输入区旁的用量胶囊,查看当前账号的 5 小时、周和月用量及重置时间。用量每分钟刷新,也可手动刷新。
80
52
 
81
- 模型 ID 须在当前网关目录中可用。Web 和 Headless 使用各自的 profile,需要分别安装插件。
53
+ 在 **高级设置 → 额度显示** 中选择:
82
54
 
83
- 如需从源码构建并安装本地包:
55
+ - **自动**:使用本插件的模型时显示,默认选项。
56
+ - **常驻**:使用其他模型时也显示。
57
+ - **关闭**:隐藏用量显示并停止轮询。
84
58
 
85
- ```sh
86
- npm ci
87
- npm run compile
88
- npm pack
89
- dsh plugin --profile web add ./dsh-opencode-go-0.1.20.tgz
90
- ```
59
+ ![订阅用量](image.png)
91
60
 
92
- 源码开发时显式运行 `npm run compile`;普通用户直接安装预编译产物,无需 `--legacy-peer-deps`。多版本 DSH 兼容性测试使用独立环境,不参与普通安装或构建。Headless 用户将 `web` 换成 `headless`。
61
+ ### 管理多个账号
93
62
 
94
- ### 开发与验证
63
+ 在「账号」中添加、重命名或更换 Key,展开账号行可查看详细用量。拖动行首手柄调整顺序,第一行成为当前账号。
95
64
 
96
- ```sh
97
- npm run compile # 更新 lib/,与源码一起提交
98
- npm test # 基础功能测试(自动重新构建)
99
- npm run check:dist # 检查已提交产物是否与源码一致
100
- npm run test:compat # 同一安装包在 9 套独立 DSH 环境中测试
101
- npm run test:install # npm / pnpm 无额外构建授权的 Git 安装检查
102
- npm run verify # 执行以上全部检查
103
- ```
65
+ 开启 **自动切换** 后,当前账号额度耗尽或 Key 不可用时,插件会在开始输出前按列表顺序尝试其他账号。也可以在用量胶囊中点击 **切换**,直接选择后续请求使用的账号。
104
66
 
105
- 兼容性与安装检查会下载依赖,使用系统临时目录并在结束后清理。只检查一个宿主可运行 `npm run test:compat -- v017-rc2`。维护测试版本的方式见[开发与测试说明](docs/development.md)。
67
+ 新增或删除账号中途关闭页面、断开连接时,宿主会在后续启动或设置、凭据更新时继续恢复。未能写入 Key 的新增账号会保留在列表,可补填 Key 或删除;恢复不会覆盖期间手动选择的当前账号。
106
68
 
107
- ## 升级插件
69
+ ## 高级用法
108
70
 
109
- 更新 Web profile 中的插件到 npm 最新版本:
71
+ ### Headless 模式
72
+
73
+ 安装插件:
110
74
 
111
75
  ```sh
112
- dsh plugin --profile web update dsh-opencode-go --latest
76
+ dsh plugin --profile headless add dsh-opencode-go
113
77
  ```
114
78
 
115
- 完成后重启 `dsh web` 并刷新浏览器。Headless 用户将 `web` 换成 `headless`;如果两个 profile 都安装了插件,需要分别升级。
79
+ 将以下内容保存为 `headless.patch.yml`:
116
80
 
117
- 桌面版升级后,请完全退出并重新打开 DeepSeek Harness,以加载更新后的插件代码。
81
+ ```yaml
82
+ - id: agent-default-model
83
+ config:
84
+ provider: dsh-opencode-go
85
+ model: deepseek-v4.1-flash
86
+ ```
118
87
 
119
- ## 订阅用量显示
88
+ 在 Bash 或 Zsh 中输入 Key 后运行任务:
120
89
 
121
- 在「设置 → OpenCode Go → 高级设置 → 额度显示」中选择并保存:**自动(默认)**仅在选中本插件的 DSH OpenCode Go 模型时显示;**常驻**在使用其他模型(包括宿主自带的 `opencode-go`)时也显示;**关闭**隐藏胶囊并停止轮询。停用 OpenCode Go 后所有模式均隐藏。显示时点击胶囊展开用量面板。
90
+ ```sh
91
+ read -s OPENCODE_API_KEY
92
+ export OPENCODE_API_KEY
93
+ dsh --profile headless --patch ./headless.patch.yml "你好"
94
+ ```
122
95
 
123
- 用量每分钟刷新。临时网络或服务错误会保留同一账号的上次数据,并标明刷新失败、更新时间和错误原因;可在用量弹层中立即重试。首次获取失败或鉴权失败时不显示旧额度。模型目录、模型配置和用量的 JSON 请求遇到短暂连接重置时会在原有超时范围内额外重试一次;这不能保证故障中的网络恢复可用。
96
+ 将 `model` 换成设置页中可用的模型 ID。示例文件见 [examples/headless.patch.yml](examples/headless.patch.yml)。
124
97
 
125
- ![OpenCode Go usage display](image.png)
98
+ ### 网络代理
126
99
 
127
- ## 界面语言
100
+ 在 **设置 → OpenCode Go → 高级设置 → 代理地址** 中填写并保存,例如:
128
101
 
129
- 插件跟随 Harness 的界面语言,提供中文和英文文案,不另存一套语言设置。未手动指定语言时,Web 版按浏览器语言列表匹配中英文(浏览器通常跟随系统);支持系统语言桥接的桌面版由宿主提供系统语言。没有匹配的语言时使用英文。
102
+ ```text
103
+ http://127.0.0.1:7890
104
+ socks5://127.0.0.1:1080
105
+ ```
130
106
 
131
- 在 Harness 中手动选择的语言优先,切换后插件即时更新,保留未保存的表单内容。模型名称和 ID 保留原名;用量日期和容量数字按当前界面语言格式化。自动语言在启动时识别:Web 版更改浏览器语言后需刷新页面,桌面版更改系统语言后需重启 Harness。
107
+ 支持 HTTP、HTTPS、SOCKS5 和带用户名、密码的代理 URL。保存后,后续对话、模型目录更新和用量查询使用新代理。代理运行在 DSH 所在的机器上;远程部署中的 `127.0.0.1` 指服务器自身。
132
108
 
133
- ## 模型开关
109
+ ### 手动配置
134
110
 
135
- 在 **设置 → OpenCode Go** 中,每个模型右侧的开关决定它是否出现在会话模型选择器中。开关立即保存,无需再点“保存”;容量和 API Key 的修改仍需保存。普通模型默认开启,过时模型默认关闭。你可以单独开启任意过时模型,也可以关闭普通模型。新出现且未单独配置的模型同样按此规则处理。
111
+ 在 **高级设置 → DeepSeek V4.1 Flash 协议** 中可选择 **Responses(实验性)** 并保存,便于比较同一模型的不同协议。默认 **自动** 跟随模型目录;改回自动即可恢复。选择只影响新请求,不会切换已准备或正在执行的调用,也不会在协议错误后自动改用另一协议。
136
112
 
137
- 手动配置时,在插件的 `config` 下添加 `modelVisibility`,使用真实模型 ID 替换示例中的占位符:
113
+ 目前仅支持 `deepseek-v4.1-flash` 的 Responses 覆盖,沿用当前账号、代理、会话标识与用量处理。[issue #45](https://github.com/Duskriver/dsh-opencode-go/issues/45) 报告了更低延迟,但它不是网关的稳定性能承诺,也不能据此确认底层服务商;是否更快请以自己的测试为准。无需覆盖时省略以下配置:
138
114
 
139
115
  ```yaml
140
- modelVisibility:
141
- your-model-id: false
142
- your-deprecated-model-id: true
116
+ - id: opencode-go
117
+ config:
118
+ protocolOverrides:
119
+ deepseek-v4.1-flash: openai-responses
143
120
  ```
144
121
 
145
- 只有列出的 ID 被显式覆盖。开关只影响模型选择器;已有会话仍可调用网关提供的隐藏模型,设置页也保留完整模型列表。
146
-
147
- 旧配置中的 `showDeprecatedModels` 和 `visibleModelIds` 不再控制显示状态。请使用逐模型开关或 `modelVisibility`;旧字段可以保留,不会妨碍插件加载。
148
-
149
- ## 图片数量上限
150
-
151
- 在「设置 → OpenCode Go → 高级设置」中可以设置 `maxImages`,填写正整数后保存即可生效,无需重启。默认不设置,不限制图片张数;清空或重置会移除用户覆盖,重新继承基础配置(基础配置也未设置时没有张数上限)。
122
+ 将该模型的值设为 `null` 会明确选择自动,即使继承的配置启用了 Responses;设置页的「恢复默认」会移除当前层覆盖,恢复继承值。其他模型或协议组合会被拒绝。
152
123
 
153
- 数量按单次请求携带的完整历史统计,包括工具输出里的图片;同一附件出现多次也分别计数。例如设置为 `30` 时,30 张正常发送,31 张会先卸载最旧的 1 张,再继续请求。卸载将图片内容替换为文字占位,原始附件仍保留,但模型在该次请求中看不到被卸载图片的内容。
124
+ 在 patch 文件中添加 `opencode-go` 配置块,可与上面的默认模型配置一起使用:
154
125
 
155
- DSH 0.1.5 的卸载只影响本次请求;DSH 0.1.6 及以上版本通过宿主的图片卸载机制记录卸载状态并重试,调高或清空上限不会自动恢复已卸载的历史图片。现有图片载荷、像素和单图字节预算仍独立生效,可能需要卸载更多图片。`maxImages` 是可选的兼容设置,不会改变上游服务自身的限制。
156
-
157
- ## 常见问题
158
-
159
- ### 与宿主的 OpenCode Go 共存及升级迁移
160
-
161
- 从 0.1.17 起使用独立的 `dsh-opencode-go` provider,模型选择器中显示为 **DSH OpenCode Go**;宿主 pi-ai 的 `opencode-go` 可以同时使用。请在插件设置页配置 API Key,然后选择 **DSH OpenCode Go** 下的模型。0.1.16 及以前版本使用 `opencode-go`,这些版本的 headless 配置也应使用旧标识。
162
-
163
- 升级前保存为 `provider: opencode-go` 的会话、Agent 预设和 headless 默认模型,需要重新选择 **DSH OpenCode Go**,或将 provider 改为 `dsh-opencode-go`。API Key、模型设置和元数据缓存继续沿用。旧会话内容保留;跨 provider 切换时,DSH 会按其规则去除旧适配器的专用回放元数据。
126
+ ```yaml
127
+ - id: opencode-go
128
+ config:
129
+ apiKeyEnv: OPENCODE_API_KEY
130
+ accounts:
131
+ - id: primary
132
+ name: 主账号
133
+ apiKeyEnv: OPENCODE_API_KEY
134
+ - id: backup
135
+ name: 备用账号
136
+ apiKeyEnv: OPENCODE_GO_BACKUP_KEY
137
+ autoSwitch: true
138
+ proxyURL: http://127.0.0.1:7890
139
+ refreshMinutes: 60
140
+ modelVisibility:
141
+ deepseek-v4-pro: false
142
+ modelLimits:
143
+ deepseek-v4.1-flash:
144
+ maxTokens: 8192
145
+ qwen3.7-plus:
146
+ thinkingBudgets: [4096, 6000]
147
+ maxImages: 30
148
+ ```
164
149
 
165
- ### 没有出现预期的模型
150
+ 按需保留配置项,并通过 DSH 凭据服务或环境变量提供对应的 Key。`apiKeyEnv` 选择当前账号,`accounts` 的顺序决定自动切换顺序。
166
151
 
167
- 先在 **设置 → OpenCode Go** 检查该模型的开关是否开启。过时模型默认关闭,单独打开它的开关后即可出现在会话模型选择器中,无需开启其他全局选项。
152
+ | 配置项 | 用途 |
153
+ | --- | --- |
154
+ | `baseURL` | OpenCode Go 网关地址,默认 `https://opencode.ai/zen/go/v1` |
155
+ | `usageDisplay` | 额度显示模式:`auto`、`always` 或 `off` |
156
+ | `proxyURL` | 网络代理;空字符串使用默认网络设置 |
157
+ | `refreshMinutes` | 模型目录缓存时长,默认 60 分钟;设置页可随时手动刷新 |
158
+ | `modelVisibility` | 按模型 ID 控制选择器中的显示状态 |
159
+ | `protocolOverrides` | 实验性协议覆盖;目前仅支持 `deepseek-v4.1-flash: openai-responses`,省略或模型值为 `null` 时自动跟随目录 |
160
+ | `modelLimits` | 按模型覆盖 `contextWindow`、`maxTokens`,或用 `thinkingBudgets` 添加思考预算选项;空值使用默认设置 |
161
+ | `maxImages` | 单次请求历史中的图片数量上限,默认不设上限;超过时先卸载最旧图片 |
162
+ | `streamIdleTimeoutMs` | 等待下一个流事件的最长时间,默认 300000 毫秒 |
163
+ | `requestPreparationTimeoutMs` | 目录查询及每次尝试的凭据、图片准备时限,默认 60000 毫秒 |
164
+ | `requestTimeoutMs` | 一次发送的完整时限,包含目录查询、账号切换和流式输出,默认 1800000 毫秒;预先准备的调用从发送时计时 |
168
165
 
169
- 先确认插件已启用且 API Key 已配置,再刷新设置页中的模型列表。设置页读取或刷新列表时会请求网关 `/models`,并同步 [models.dev 的 OpenCode Go 配置](https://models.dev/api.json)。会话模型选择器遵守目录缓存时长,切换模型开关不会强制重新请求网关。模型的协议、上下文长度、输出上限和图片能力来自在线配置,新模型无需等待本插件或 pi-ai 发布新版本。
166
+ 图片卸载会保留原始附件,并将请求中的旧图片替换为文字占位;调高上限不会自动恢复已卸载的历史图片。
170
167
 
171
- 网关和在线配置已收录、且使用 Anthropic Messages、OpenAI Chat Completions 或 OpenAI Responses 协议的新模型,在下次设置页刷新或目录缓存到期后即可被发现。设置页刷新会绕过已有缓存,并通知已打开的会话模型选择器使用同一份新目录;直接请求尚未缓存的新模型也会立即重新同步。设置页显示完整模型列表。
168
+ 图片数量超限会在读取附件前返回卸载请求;图片准备在同一插件模块内共享四个执行名额和最多 32 个等待名额,精确字节超限时停止安排剩余图片。正在发送的图片请求共享 128 MiB 的已准备原始数据与 base64 预算;这不是进程总内存上限。排队或共享预算超限会返回 `IMAGE_RESOURCE_BUSY`,可在其他请求结束后重试。数量与字节限制可能需要宿主分次卸载后重试。
172
169
 
173
- 网关已公布 ID 但尚无有效协议/能力配置的模型会在设置页标注“配置缺失”,开关保持关闭且不可操作,不进入对话模型选择器,避免一个未配置的模型阻断整个列表;直接调用时会说明原因。配置补齐后,刷新列表即可使用。仅凭模型 ID 无法可靠推断调用方式。上游新增全新协议或协议特例时,仍可能需要适配。
170
+ 首次查询目录失败会报告 `DISCOVERY_FAILED`;已有目录时保留之前确认过的模型。网关明确返回空列表才会清空目录。列表中仅部分行格式错误时,仍可使用有效模型,设置页与日志会提示被忽略的行数。高级表单的普通配置项一次提交并检查版本;凭据由独立服务保存,凭据保存失败时保留其草稿,重试只提交未成功的部分。
174
171
 
175
- 如果在线配置获取失败,没有可用缓存或内置配置的模型会标注“配置暂不可用”,页面会显示配置源错误。请检查运行 DSH 的设备能否访问 `https://models.dev/api.json`,并查看具体错误后刷新重试。已有模型列表在重试期间保留上次的失败提示,成功后自动清除;已配置的模型继续可用。
172
+ ### 导出错误诊断
176
173
 
177
- 模型具有推理能力但没有可调节的推理档位时(如 `union-alpha`),仍可正常选择和使用,只是不显示推理强度选项。
174
+ 需要排查请求失败时,在启动 DSH 前设置诊断目录:
178
175
 
179
- MiMo V2.6 Flash 的网关目录尚未列出可调节档位,插件按 OpenCode Go 实测提供 **Off / Low / Medium / High**:默认不发送 `reasoning_effort`,保留网关默认思考;Off 发送 `none`,其余发送对应值。仅对这个已验证的型号和协议补充映射,不扩展到其他 MiMo 型号。Low / Medium / High 已验证可正常请求并返回思考内容,但不保证实际思考量随档位递增。
176
+ ```sh
177
+ export DSH_OPENCODE_GO_DEBUG_DIR=/tmp/dsh-opencode-go-debug
178
+ dsh web
179
+ ```
180
180
 
181
- 在线目录中的 effort 列表决定可选强度。仅有 toggle 或 budget 声明时,插件只对已有原生开关或预算协议提供相应控件,不为普通 OpenAI 兼容协议猜测 `off` 或 `high` 参数。明确的空控制列表不会因为模型具有推理能力就自动增加 Off。
181
+ Windows PowerShell:
182
182
 
183
- 提供可调节档位的模型,如果其传输协议在未选择档位时会显式关闭思考(`deepseek`、`zai`、`qwen`、`qwen-chat-template`),还会声明一个默认档位(模型支持 `high` 时用 `high`,否则用它提供的最高档位)。用户未选择档位时 DSH 使用该默认值,因此留空也会带上推理档位,而不是关闭思考。由服务商自行决定的协议不声明默认值,行为不变;显式选择的档位始终优先。
183
+ ```powershell
184
+ $env:DSH_OPENCODE_GO_DEBUG_DIR = "$env:TEMP\dsh-opencode-go-debug"
185
+ dsh web
186
+ ```
184
187
 
185
- 在线配置暂时不可达时,优先复用之前成功获取的配置(包括重启前的磁盘缓存),以 pi-ai 内置配置作为备用。网关目录刷新失败时,已有请求和设置页均保留本次运行中上次成功获取的列表。任一来源刷新失败,设置页都会显示警告、失败原因,以及模型名单和模型配置各自上次成功检查的时间。首次读取网关失败时,不会仅凭元数据缓存生成模型列表。
188
+ 复现后,错误信息会给出 JSON 文件路径。记录包含模型、请求参数摘要、HTTP 状态、上游日志与路由编号及错误响应,便于提交 [问题反馈](https://github.com/Duskriver/dsh-opencode-go/issues)。分享前检查服务返回的错误内容;清空环境变量并重启 DSH 即可关闭诊断。
186
189
 
187
- 模型配置自动保存到 `$DSH_HOME/cache/dsh-opencode-go/models.dev.api.json`,未设置 `DSH_HOME` 时位于 `~/.dsh/cache/dsh-opencode-go/models.dev.api.json`。缓存仅包含公共元数据、ETag 和上次成功检查时间,不包含 API Key 或网关模型名单。重启后的普通读取先确认网关名单,再使用磁盘中的配置,同时后台校验元数据;后台完成后同步模型选择器。缓存损坏时重新联网获取,无法写入时仍可使用在线结果。设置页刷新始终等待在线校验,失败会保留旧配置并显示原因,不会把缓存命中标记为在线刷新成功。需要清除磁盘缓存时,可退出 DSH 后删除该文件。
190
+ DSH debug 日志另有每次发送的调用编号,以及各次尝试的阶段耗时、HTTP 状态、上游请求编号、首次输出等待时间与错误码,包含 HTTP 200 后的流中断;图片请求还记录排队累计等待与资源占用峰值。错误文件带有相同调用编号与尝试序号,便于关联排查。这些摘要不记录提示词、Key、代理地址或原始会话编号。
188
191
 
189
- `refreshMinutes` 控制成功刷新后的目录缓存时长。刷新失败后,下一次读取会按 5、10、20、40、60 秒的退避间隔尝试恢复,最长等待间隔为 60 秒;没有读取时不会后台轮询。设置页主动刷新和未知模型的即时发现不受这个间隔限制。取消模型解析或生成时,会立即结束当前调用的目录等待,其他调用仍可继续使用同一次共享刷新。
192
+ ## 更新与卸载
190
193
 
191
- 已验证的模型配置在缓存到期后的 5 分钟内可直接用于生成,同时触发一次共享后台刷新。这个窗口按两种来源各自上次成功检查的时间计算,失败重试不会延长它;超过窗口后,请求等待下一次到期刷新,刷新仍失败时保留已有回退行为。没有磁盘缓存的首次加载、未知模型和手动刷新会等待在线结果。模型名单请求限时 10 秒,体积更大的模型配置下载单独限时 30 秒,并协商 gzip 压缩以减少慢速连接的传输量。若宿主因 HTTP/2 兼容问题返回未解压的 gzip 数据,插件会在同一超时预算内异步解压,原始数据和解压结果均受 16 MiB 限制。模型名单和用量接口继续使用非压缩传输。
194
+ 更新到 npm 最新版本:
192
195
 
193
- 同一会话继续、重试以及恢复后的请求沿用宿主保存的会话 ID。分叉和子会话使用各自的 ID,不复用父会话标识;没有会话 ID 的独立请求每次生成随机标识。
196
+ ```sh
197
+ dsh plugin --profile web update dsh-opencode-go --latest
198
+ ```
194
199
 
195
- ## 卸载
200
+ 更新后重启 `dsh web` 并刷新页面;桌面版完全退出后重新打开。Headless 用户将 `web` 换成 `headless`。
196
201
 
197
- 从对应 profile 移除插件,再重启应用:
202
+ 卸载:
198
203
 
199
204
  ```sh
200
205
  dsh plugin --profile web remove dsh-opencode-go
201
- # 或
202
- dsh plugin --profile headless remove dsh-opencode-go
203
206
  ```
204
207
 
205
- ## 反馈
206
-
207
- 遇到 bug 或有功能建议请提 issue。
208
+ 从 `0.1.16` 及更早版本升级时,在旧会话或 Agent 预设中重新选择 **DSH OpenCode Go**;手动配置使用 `provider: dsh-opencode-go`。
208
209
 
209
- ## 许可证
210
+ ## 更多
210
211
 
211
- [MIT](LICENSE)
212
+ - [开发与测试](docs/development.md)
213
+ - [验证记录](docs/verification.md)
214
+ - [问题与建议](https://github.com/Duskriver/dsh-opencode-go/issues)
215
+ - [MIT 许可证](LICENSE)
@@ -1,5 +1,7 @@
1
1
  # Third-party notices
2
2
 
3
- The adapter, settings UI, and `src/conversion/{context,stream,replay}.ts` derive from DeepSeek Harness, copyright (c) 2026 DeepSeek, under the MIT license included in LICENSE. The conversion modules are maintained in this package because the published DSH pi-ai package does not export its conversion helpers. Wire protocol implementations remain supplied by `@earendil-works/pi-ai`, installed under the plugin's `opencode-go-pi-ai` npm alias.
3
+ The adapter, settings UI, and `src/conversion/{context,stream,replay}.ts` derive from DeepSeek Harness, copyright (c) 2026 DeepSeek, under the MIT license included in LICENSE. The conversion modules are maintained in this package because the published DSH pi-ai package does not export its conversion helpers.
4
+
5
+ The host bundle includes the required portions of `@earendil-works/pi-ai@1.1.0` and `partial-json`; SDK declarations include pi-ai, pi-telemetry and TypeBox types. Their original MIT licenses are reproduced in `lib/vendor-licenses.txt`. The pi packages' license comes from the [upstream v1.1.0 license](https://github.com/earendil-works/pi/blob/v1.1.0/LICENSE), which their npm distributions omit. OpenAI and Anthropic transport SDKs remain separate runtime dependencies.
4
6
 
5
7
  The GitHub icon in the settings footer comes from Simple Icons, distributed under CC0 1.0 Universal.
@@ -12,10 +12,10 @@ The root package contains one coherent DSH 0.1.6-alpha.1 development environment
12
12
  | `npm run test:ci` | Verify shipped artifacts match source, then run the core suite |
13
13
  | `npm test` | Rebuild, then run the core Vitest suite |
14
14
  | `npm run test:compat` | Pack once and test the installed artifact across every supported host fixture |
15
- | `npm run test:compat -- v015-rc1 v017-rc2 v020-rc2` | Test only the named fixtures; unknown names fail |
16
- | `npm run test:install` | Test npm and pnpm 11.7.0 Git installs of prebuilt artifacts without plugin build approval |
15
+ | `npm run test:compat -- v015-rc1 v017-rc2 v021-alpha1` | Test only the named fixtures; unknown names fail |
16
+ | `npm run test:install` | Test npm Git installation and fresh pnpm 11.7.0 Git/tarball installs with no script approvals, plus consumer type resolution |
17
17
  | `npm run test:install -- npm` / `-- pnpm` | Run just one package manager; unknown names fail |
18
- | `npm run verify` | Run core, compatibility, and Git-installation checks |
18
+ | `npm run verify` | Run core, compatibility, and installation checks |
19
19
 
20
20
  The checks use loopback gateways and local fixtures, not paid inference or an installed user profile. Compatibility and installation checks need registry access; installation checks also require Git. Temporary consumers are created outside the repository and removed on success or failure. Tests never implicitly skip a missing host environment.
21
21
 
@@ -25,11 +25,11 @@ The default Git branch ships `lib/` so a GitHub URL, an npm release, and an npm
25
25
 
26
26
  After source or build-tool changes, run `npm run compile` and commit the regenerated `lib/` with those changes. `npm run check:dist` checks missing, changed, and extra artifacts against an independent rebuild. CI uses `npm run test:ci` so it checks the committed files before running tests, instead of silently replacing stale files first. CSS module filenames are repository-relative, CSS export keys are sorted, and declaration line endings are fixed to LF so artifacts are independent of the checkout path and operating system.
27
27
 
28
- The Git-installation regression creates a fresh repository containing the shipped artifacts but no `src/`, `scripts/`, `tests/`, or `node_modules/`, then installs it with both package managers. Each installed package must expose its host and client entrypoints, declarations, build metadata, and importable host module, and must not declare scripts that trigger Git preparation or dependency installation hooks. pnpm receives no approval for this plugin; only unrelated Google/protobuf scripts are explicitly skipped. The cold Git identity changes for each temporary repository, preventing a previously approved Git build from hiding a missing approval. Consumer profiles and their trust settings are never modified by these tests.
28
+ The installation regression creates a fresh repository containing the shipped artifacts but no `src/`, `scripts/`, `tests/`, or `node_modules/`, then installs it with both package managers. Each installed package must expose its host and client entrypoints, declarations, build metadata, and importable host module, and must not declare scripts that trigger Git preparation or dependency installation hooks. Fresh pnpm consumers install both the Git artifact and a packed npm artifact with `strictDepBuilds=true`, separate empty stores and isolated user configuration. They receive no `allowBuilds` entries, including Google/protobuf skips. The fixtures assert that the private SDK alias, Google SDK and protobufjs are absent, and type-check exported model types without access to development dependencies. The cold Git identity changes for each temporary repository. Consumer profiles and their trust settings are never modified by these tests.
29
29
 
30
30
  ## Installed-package matrix
31
31
 
32
- `scripts/compatibility-hosts.mjs` lists nine host generations, including DSH `0.2.0-rc.2`. Each `tests/hosts/<id>` has a private manifest and its own lockfile. DSH packages and their required DSH peer/dependency closure are pinned to that host generation, together with compatible Cordis packages. This prevents a broad upstream peer range from silently selecting a later host generation. The 0.2 fixture also installs its real `dsh-llm-pi-ai` adapter and public pi-ai dependency alongside this plugin.
32
+ `scripts/compatibility-hosts.mjs` lists ten host generations, including DSH `0.2.0-rc.2` and `0.2.1-alpha.1`. Each `tests/hosts/<id>` has a private manifest and its own lockfile. DSH packages and their required DSH peer/dependency closure are pinned to that host generation, together with compatible Cordis packages. This prevents a broad upstream peer range from silently selecting a later host generation. The 0.2 fixtures also install their real `dsh-llm-pi-ai` adapter and public pi-ai dependency alongside this plugin.
33
33
 
34
34
  The runner performs these steps for each host:
35
35
 
@@ -43,16 +43,66 @@ Local compatibility runs are serial by default. Set `DSH_COMPAT_CONCURRENCY` to
43
43
 
44
44
  All host JavaScript imports use ordinary Node resolution. The fixtures do not redirect DSH imports to alternate packages or load the plugin from the source checkout. The client fixture uses the consumer's React, store, and UI primitives, with a CSS loader for published host styles. It verifies the installed browser factory, settings registration, catalog injection, rendering, CSS, and cleanup. Host fixtures retain text streaming, real image processing, history/offload, limits, reasoning, live settings, and profile-bundle checks. Each host also runs all three wire protocols through prompt and tool declaration checks, a streamed tool call, JSON-restored assistant replay, tool-result continuation, and a one-shot request with no tools.
45
45
 
46
- ## Isolated pi-ai dependency
46
+ ## Architecture and ownership
47
47
 
48
- The runtime dependency `opencode-go-pi-ai` is an npm alias for `@earendil-works/pi-ai@0.87.1`. All plugin imports, including declaration types and lazy API factories, use the alias. It keeps this plugin's SDK requirement separate from the host's public `@earendil-works/pi-ai` name, so an older plugin that declares pi-ai only as a peer is not redirected by our dependency. The npm and pnpm Git-installation checks include a public pi-ai 0.85.1 and a peer-only probe, and verify that the probe retains 0.85.1 while this plugin resolves its own 0.87.1.
48
+ `src/index.ts` composes the host services. `src/config-contract.ts` is the browser-safe configuration vocabulary; both faces import it instead of maintaining separate interfaces. Version-dependent settings attachment lives in `src/host-settings.ts` and `src/client/host-compat.ts`. `src/settings-bridge.ts` owns section/profile selection and the applied/rejected/unknown write verdict: modern acknowledgments are authoritative, while older hosts require a committed-state check.
49
49
 
50
- DSH requests still convert through `toPiContext`, preserving the existing host input and durable replay contracts. Immediately before calling a provider directly, the adapter applies pi-ai's `normalizeContext`. In 0.87.1, direct providers require `TranscriptContext`; only `Models` streaming entry points normalize legacy Context automatically. Normalizing at this call site preserves the system prompt and tool declarations on both text and image paths without tying the SDK format to the DSH version.
50
+ `GoCatalogManager` owns one configuration-keyed catalog per mount. Inference, model discovery and the settings model service share that catalog directly. The inference adapter retains its standalone catalog fallback for public callers. A superseded catalog cannot send a late route-refresh notification.
51
+
52
+ The browser sends typed `opencodeGoAccounts.execute` commands for account additions, removals, selection, naming, ordering, automatic switching and key replacement, including staged key drafts. `GoAccountManager` serializes these commands with recovery; both use `accountOperationPatch` to finish the same durable intention. A client-generated addition ID makes RPC retries idempotent. The UI owns drafts, busy state and quota display; the host owns credentials and revision-guarded metadata writes. Add account operations to the shared command contract and host manager, rather than creating another browser write path.
53
+
54
+ `src/account-policy.ts` decides whether a failed request may try another account and whether a gateway key should be remembered as rejected. Error classification stays in `src/gateway-error.ts`; stream lifecycle and dispatch stay in `src/adapter.ts`. Both terminal stream errors and thrown errors use the same policy, which blocks fallback after any output, positive token usage or cancellation.
55
+
56
+ ## Failure boundaries and resource policy
57
+
58
+ The gateway uses HTTP 401 for model errors, subscription limits and authentication failures. `gateway-error.ts` classifies captured `error.type`/`error.code` first. Untyped quota text is admitted only on HTTP 401/402/403/429; untyped 5xx keeps `SERVER` (504 keeps `TIMEOUT`) even when diagnostics quote earlier quota failures. A generic 401/403 never proves a key is invalid. Only `INVALID_CREDENTIAL` is remembered as a gateway key rejection; quota failures can switch accounts before output but do not blacklist credentials. HTTP 200 stream errors continue through the stream mapper's fallback classification. Retry-After remains in bounded HTTP evidence for diagnosis; the host owns retry scheduling.
59
+
60
+ Discovery and credential/image preparation have a default 60-second deadline. Dispatch has a separate default 30-minute deadline spanning discovery, fallback and streaming. The existing idle watchdog still limits an outstanding stream read. Every external wait observes cancellation, including services that ignore their signal; canceling a catalog waiter does not abort the shared refresh. Prepared capability resolution has its own preparation deadline, and the dispatch timer starts when the prepared stream is consumed.
61
+
62
+ Image count preflight does not estimate encoded bytes on modern hosts. Four shared permits and a 32-task queue bound preparation across simultaneous calls; exact encoded sizes are checked incrementally with unknown sizes contributing zero. A shared 128 MiB lease budget charges each prepared raw image plus occurrence-weighted base64 bytes. Adapter leases last through streaming and release on completion, failure or consumer stop; standalone conversion only holds its lease during conversion. Queue/budget admission fails with `IMAGE_RESOURCE_BUSY`, without account switching. This logical budget excludes decoder RSS, JSON/SDK copies and retained history. A returned raw image exists before its charge is checked, so four active native operations can still produce transient overshoot. Failure aborts queued work. An in-flight service that ignores cancellation retains its permit until it really settles, so cancellation cannot accidentally admit unbounded native work. A permanently stuck service can therefore exhaust these slots and needs host/service recovery. DSH 0.1.5 retains its transient projection policy; later hosts retain durable `IMAGE_OFFLOAD_REQUIRED` retries.
63
+
64
+ `StagedForm` submits settings set/unset operations in one `scope.mutate` with the captured revision. A refused batch leaves drafts and does not write secrets. Successful settings drafts clear even if a separate secret write fails, allowing an idempotent retry. A newer draft typed during a save is retained. Settings and credentials remain separate stores, without a cross-store transaction.
65
+
66
+ Account additions and generated-account removals first confirm a durable `accountOperations` intention in the account's own section/profile. The hidden field stores operation ID, kind and account metadata, never a key. The Host reconciles it at startup, settings/credential connection and committed updates. Already stored addition keys gain their metadata; additions without keys remain visible and can be repaired or removed. Deletion intentions finish credential removal before atomically removing metadata and the intention. Revision guards preserve concurrent edits and later selections; a refused store retains the intention, with at most four passes per trigger and a 30-second deadline per operation. Closing or replacing the connection cancels its waits so a new service can resume. Credential deletion requires an exact generated ID/reference pairing; external or shared legacy references keep their values. Recovery acts only while its service connection is current. Cancelling a wait cannot roll back an already accepted storage write. It cannot recover a key that was never stored, provide isolation against arbitrary simultaneous writes in other profiles, or repair operations predating the journal. Manually sharing a generated reference across profiles also shares its deletion lifecycle.
67
+
68
+ A nonempty gateway listing with no valid model IDs is a discovery failure and preserves served membership. A confirmed empty list clears it. Missing models on a cold or failed listing report `DISCOVERY_FAILED`, while confirmed absence reports `UNKNOWN_MODEL` through the adapter. Mixed valid/invalid rows use valid IDs and expose a warning in `sources.listing.warning`, the settings page and Host logs. The warning includes counts and at most eight row positions, never malformed row contents, and clears after a clean listing. The choice favors usable partial data while making potential membership loss visible. Public disk metadata still does not establish gateway membership after a restart.
69
+
70
+ The public `onCallTrace` observer receives one content-free summary per dispatch: random call ID, model, elapsed and stage milliseconds, attempt count, outcome and final code. A bounded `attemptDetails` array includes each attempt's stages, outcome/code, HTTP status, selected redacted upstream request ID, first text/reasoning/tool-argument delta latency and image pool diagnostics. Queue wait is summed across image tasks and may exceed wall-clock image-stage time. HTTP evidence files carry the same call ID and attempt number. There is no stable account identity in this trace. The plugin forwards it to the host debug logger. Observer failures cannot alter inference. Compile-time `never` checking and runtime rejection guard the SDK event union; unknown host roles are explicitly rejected. The open peer range is an installation policy, while the installed matrix is the finite evidence of compatibility.
71
+
72
+ ## Reasoning intent
73
+
74
+ `src/protocol-contract.ts` restricts the experimental `protocolOverrides` surface to DeepSeek V4.1 Flash → Responses. `src/protocol-policy.ts` resolves the wire API, base URL and fresh protocol compatibility profile together on the captured request config, before capacity overrides. The cached catalog remains unmodified. Effort choices stay those advertised by metadata; an unexpected native toggle/budget or source protocol is rejected before inference. Protocol errors do not trigger a second-protocol retry. The installed-host transcript matrix exercises the override as a Chat Completions-declared model through the real Responses SDK, including tool-result continuation and restored replay; focused tests also switch existing histories in both directions and retain only valid native reasoning state.
75
+
76
+ For latency comparisons, fix the account, proxy/network, prompt, model, reasoning effort, output cap and stable `x-opencode-session` header. Interleave protocols and report cold and warm samples separately. Measure first body-text delta, total time, output/reasoning tokens and failures; the existing `GoCallTrace.firstOutputMs` includes reasoning and tool deltas and is not body-text TTFT. Local fixtures establish compatibility, not live gateway speed or its underlying provider. Run paid live benchmarks only when requested.
77
+
78
+ `scripts/benchmark-protocols.mjs` compares the plugin already installed in the macOS desktop profile using the app's actual peer packages. It requires explicit `--live`, performs 20 bounded synthetic calls with a 4,096-token output cap, and writes JSON results under `opencode-protocol-benchmark-<runId>` without changing settings or stored credentials. Automatic fallback is disabled in memory. The output includes first and repeated samples, reasoning/output tokens, route headers, and failures; first-session samples do not prove an upstream cache miss. Run its offline observer/statistics check with `node scripts/benchmark-protocols.mjs --self-test`.
79
+
80
+ ```sh
81
+ ELECTRON_RUN_AS_NODE=1 '/Applications/DeepSeek Harness.app/Contents/MacOS/DeepSeek Harness' scripts/benchmark-protocols.mjs --live
82
+ ```
83
+
84
+ Use `--profile`, `--resources`, or `--out` to change the desktop profile, application resources directory, or report directory. The selected account's credential is read from the environment or the user's DSH credential store and stays in memory.
85
+
86
+ The model catalog records whether controls are a switch, adjustable effort, or a token budget, independently of pi-ai's wire compatibility hints. `src/reasoning.ts` owns the picker choices and translates a validated selection into Default, Off, On, an explicit effort, or a token budget. Model resolution declares no `defaultEffort`: an omitted user choice remains omitted through the DSH runtime.
87
+
88
+ Before the SDK sends a payload, the shared `onPayload` hook removes automatic thinking controls for Default. For On it retains the SDK's native enable/budget but removes synthetic effort fields. Off and explicit effort keep the SDK's serialization. Other output configuration, rendering and history options are retained, and payload edits do not mutate shared catalog models. Switches keep their previous opaque `high` ID for durable selection compatibility and display it as On. The verified MiMo Flash control override stays in the same reasoning module.
89
+
90
+ Token budgets use pi-ai's `thinkingBudgets` override; the SDK still handles the wire field, context ceiling, and answer room. Only SDK-supported budget protocols expose the control; adaptive Anthropic models retain effort controls. Models declaring both effort and budget keep their efforts and can add numeric budget choices. Standard budget presets retain the historical `minimal`/`low`/`medium`/`high` IDs. Additional presets use durable `budget:N` IDs and are configured in `modelLimits[modelId].thinkingBudgets`. Catalog bounds reach the settings page through the models RPC; numeric choices and request settings are captured together before dispatch.
91
+
92
+ ## Bundled pi-ai implementation
93
+
94
+ The development dependency `opencode-go-pi-ai` is an npm alias for `@earendil-works/pi-ai@1.1.0`. esbuild retains the three supported protocol implementations and the OpenCode Go model table, and discards unrelated provider implementations. Public SDK types are flattened into `lib/types/sdk-types.d.ts`; consumers do not need the private alias to resolve them. OpenAI 7.19.0 and Anthropic 0.129.0 remain runtime dependencies at the same versions pi-ai uses. Bundled code and type licenses ship in `lib/vendor-licenses.txt`.
95
+
96
+ The published package does not depend on pi-ai, so it no longer introduces pi-ai's unrelated Google SDK and protobufjs install hooks. This avoids the pnpm 11 script-approval interruption that triggered issue #43 without changing the host's policy. An npm consumer separately includes public pi-ai 0.85.1 and a peer-only probe, plus OpenAI 6.40.0 and Anthropic 0.124.0. It verifies that the peer retains pi-ai 0.85.1, the consumer retains both older transport SDKs, and the plugin resolves its own OpenAI 7.19.0 and Anthropic 0.129.0. Other plugins' dependencies still follow the user's host trust settings.
97
+
98
+ DSH requests still convert through `toPiContext`, preserving the existing host input and durable replay contracts. Immediately before calling a provider directly, the adapter applies pi-ai's `normalizeContext`. In 1.1.0, direct providers require `TranscriptContext`; only `Models` streaming entry points normalize legacy Context automatically. Normalizing at this call site preserves the system prompt and tool declarations on both text and image paths without tying the SDK format to the DSH version.
51
99
 
52
100
  This upgrade does not enable developer messages, tool-change blocks, or deferred tool loading. Their existing `UNSUPPORTED_CONTENT` errors remain explicit. The minimum DSH version and peer ranges stay unchanged; new host fixtures verify runtime compatibility rather than expanding the supported content vocabulary.
53
101
 
54
102
  There is one explicit npm prerelease exception: DSH evaluates plugin ranges with prereleases included, whereas npm does not generally accept a future prerelease under `>=0.1.5-rc.1`. Only the tarball-install step uses `--legacy-peer-deps` after the host has passed strict installation. This is not a project `.npmrc` policy and does not affect root installs. The post-install version assertions ensure npm did not replace pinned host packages. Changing the plugin's published version policy is a separate decision.
55
103
 
104
+ DSH 0.2.1-alpha.1 uses Cordis 4.0.5-alpha.1 and Schemastery 3.18.5-alpha.1 and no longer publishes runtime invariant plugins. Its fixture pins that dependency generation without the removed package. The plugin does not import invariant entrypoints or replace the former composer statistics row; its quota pill uses the retained `conversation.input.right` list slot. The installed client check verifies that the published composer still declares that slot, and profile checks validate proxy writes, rejection, clearing and reset through each modern host's real settings service.
105
+
56
106
  ## Updating a fixture
57
107
 
58
108
  Add or update the entry in `scripts/compatibility-hosts.mjs`, its private manifest, and its lockfile together. Pin each DSH package reached through dependencies and required peers to the intended host generation; do not upgrade an old host merely to satisfy a newer package. Keep compatible Cordis versions and the client fixture's React, DOM, CSS, and UI dependencies explicit.
@@ -69,6 +119,8 @@ After changing the root lockfile, verify a clean `npm ci --strict-peer-deps` and
69
119
 
70
120
  The GitHub workflow runs core and Git-installation checks on Linux and Windows with Node 22.19.0 and 24. Core tests, npm installs, and pnpm installs run as independent jobs, so one slow installation does not consume another check's time allowance. Installation jobs need no root `npm ci`: their runner uses only Node built-ins, and the fresh Git fixture supplies committed artifacts and must not need build dependencies or plugin build approval. The complete installed-host matrix runs separately on Linux/Node 24.
71
121
 
122
+ Each isolated installation consumer installs the root's pinned TypeScript version solely to check the plugin's public declarations. That check resolves its compiler from the consumer, so it also runs when the checkout has no `node_modules`. Bundled license text uses LF regardless of the source checkout's line endings, keeping Windows artifact checks reproducible.
123
+
72
124
  Installation jobs reuse the npm download cache and a separate pnpm store, preferring cached packages while still fetching missing data. They never restore the checkout's `node_modules` or `lib/`. CI keeps the npm cache, isolated consumers, and the cached pnpm store under `RUNNER_TEMP`, on the runner's work volume. `DSH_PNPM_STORE_DIR` selects the pnpm store; local runs use the system temporary directory and the default package caches unless overridden.
73
125
 
74
126
  Every Git-installation run reports fixture preparation, installation, artifact verification, cleanup, and total elapsed time. GitHub job summaries include a phase table. CI also enables npm's internal timing records and uploads the `*-timing.json` files for seven days, for diagnosing dependency resolution and extraction; a timeout may prevent the still-running process from writing its final timing file. The 15-minute job limit remains unchanged.