@dan-ai-studio/dshopencodego 0.1.64 → 0.1.66
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/README.en.md +13 -6
- package/README.md +13 -6
- package/lib/client.js +765 -560
- package/lib/index.js +22 -11
- package/lib/types/config.d.ts +3 -3
- package/lib/types/request-log/store.d.ts +18 -6
- package/package.json +18 -1
package/README.en.md
CHANGED
|
@@ -116,7 +116,7 @@ Configuration lives in the profile's `cordis.patch.yml`:
|
|
|
116
116
|
pinnedAddresses: # fixed IP: host -> address (only the gateway host counts)
|
|
117
117
|
opencode.ai: 104.18.32.47 # IPv4 or IPv6; an invalid or absent address uses the system DNS
|
|
118
118
|
requestLogEnabled: false # request-log master switch, default off: off reads byte-for-byte as without the log
|
|
119
|
-
requestLogDebug: false # debug detail: pool events and
|
|
119
|
+
requestLogDebug: false # debug detail: pool events and the request user agent; session ids are always whole
|
|
120
120
|
requestLogMaxEntries: 200 # most entries to keep, 50 to 500; oldest are dropped first
|
|
121
121
|
retryPolicy: # optional: this route's retry policy, executed by dsh-llm-retry
|
|
122
122
|
mode: normal # or always (retry every failure; maxRetries is ignored)
|
|
@@ -141,9 +141,16 @@ The API key comes from the Harness credential store (reference name `OPENCODE_GO
|
|
|
141
141
|
- The settings page shows and accepts the value in **seconds** (a number of milliseconds is not readable at a glance) and stores it in milliseconds. Range: 1 to 1800000 milliseconds.
|
|
142
142
|
- Once a connection has been idle that long, the pool **reclaims it** on its own — no separate mechanism is needed. The actual release comes a couple of seconds later than the setting, which is the client's own small margin beyond the deadline the server states. When the plugin is unloaded, the pool is **closed with it**: the pool belongs to the plugin and should not be left behind on the machine.
|
|
143
143
|
|
|
144
|
-
**Request log**: per-request records, off by default; enabling them changes nothing about what requests do. The settings page's "Request log" group holds the master switch, the debug switch (pool events and
|
|
144
|
+
**Request log**: per-request records, off by default; enabling them changes nothing about what requests do. The settings page's "Request log" group holds the master switch, the debug switch (pool events and the request user agent), and the retention count (default 200).
|
|
145
145
|
|
|
146
|
-
-
|
|
146
|
+
- **Two entries, one page**:
|
|
147
|
+
- **A sidebar icon → a full page in the main column**: every request across sessions. The log is a process-wide thing, so the sidebar is where it belongs — a fixed, always-visible spot, and the same pattern the Harness's own plugin manager uses.
|
|
148
|
+
- **A "Request log" View inside the conversation**: this session's requests, in place — answering "why was that turn slow" without leaving the chat.
|
|
149
|
+
- It is a page, not a floating card: the head, the summary (requests / failures / mean latency / mean first token / mean tok/s / mean cache hit / connection reuse) and the filters stay put while the table scrolls. Each row carries time, model, session, input/output/cache, **cache hit**, **tok/s**, first token, latency and status; clicking one expands its HTTP detail (method, URL, redacted headers, request shape, result and usage). Filters: model, result, slow requests, session; groups: session, model, result; **click a column head to sort by it**, click again to flip.
|
|
150
|
+
- **tok/s** is the output rate over the decode window (first token to the end), on the same scale as the Harness's own per-turn reading (reasoning tokens included). A request that produced no token has no rate — none is invented.
|
|
151
|
+
- **Cache hit** is the share of input tokens served from cache (cache reads over uncached input plus cache reads). No reported input means no share — none is invented either.
|
|
152
|
+
- Session ids are **always stored whole**: an id is a conversation identity, not a credential, and a truncated one reads two conversations as one.
|
|
153
|
+
- The log is a ring buffer (oldest dropped first) that dies with the process; snapshots are read on demand, never polled, so a page nobody opens costs no traffic.
|
|
147
154
|
- The credential never enters a record: the recorder takes no headers argument at all, only the allowlisted session id and user agent. Failed requests are recorded with their error code; a request cut off before any terminal event is not recorded — no total reported, none invented.
|
|
148
155
|
|
|
149
156
|
**Images**: three fields, one layer each. An image outside a bound is refused explicitly rather than silently downscaled or dropped:
|
|
@@ -240,7 +247,7 @@ The verdict:
|
|
|
240
247
|
| Binding layer | Declared | Enforced by |
|
|
241
248
|
| --- | --- | --- |
|
|
242
249
|
| `engines.dsh` | `>=0.2.0-rc.1 <0.3.0-0` | **DSH's gate at plugin load time; declaring it skips the peer verdict entirely** |
|
|
243
|
-
| `peerDependencies` (
|
|
250
|
+
| `peerDependencies` (20 `@deepseek-ai/dsh-*` packages) | all `>=0.2.0-rc.1 <0.3.0-0` | takes over only when `engines.dsh` is absent; this plugin declares it, so the peers take no part today |
|
|
244
251
|
| `@deepseek-ai/cordis` | `4.0.4 \|\| 4.0.5-alpha.1 \|\| 4.0.5-alpha.2 \|\| 4.0.5` | the same peer channel |
|
|
245
252
|
| `engines.node` | `^22.19.0 \|\| >=24.0.0` | the package manager |
|
|
246
253
|
| bundled `@earendil-works/pi-ai` | `~1.3.0` (within 1.3.x), **compiled into `lib/`** (devDependency) | an independent coupling: a change in pi-ai's request construction changes this plugin's wire behaviour, and its opencode-go builtin catalog is this plugin's fallback data. Bundling leaves the plugin with **no runtime dependencies** for an installer to resolve |
|
|
@@ -248,7 +255,7 @@ The verdict:
|
|
|
248
255
|
|
|
249
256
|
Things to keep in mind when maintaining this:
|
|
250
257
|
|
|
251
|
-
- **Required versus optional peers**:
|
|
258
|
+
- **Required versus optional peers**: nine of the twenty-one are marked `optional` (`dsh-api-remotes`, `dsh-client-locale`, `dsh-client-store`, `dsh-client-ui-layout`, `dsh-client-ui-model-selection`, `dsh-client-ui-primitives`, `dsh-client-ui-settings`, `dsh-client-ui-sidebar`, `dsh-client-ui-slots`). The other twelve are required at runtime: `cordis`, `dsh-attachment`, `dsh-brand`, `dsh-client-ui-conversation`, `dsh-client-ui-renderer`, `dsh-credentials`, `dsh-fs`, `dsh-launch-environment`, `dsh-llm`, `dsh-timeout`, `dsh-typert-protocol`, and `dsh-typert-registry`. None of the twenty-one takes part in the load verdict today (see above: `engines.dsh` decides alone); their value is declaring the dependency for the package manager and for readers. `dsh-llm` is the heaviest coupling — more than twenty imports across the source.
|
|
252
259
|
- **Declared range ≠ verified range**: the declaration is `>=0.2.0-rc.1 <0.3.0-0`. What was actually verified here, in order, is `0.2.0-rc.1` (the dev-dependency baseline: gate verdict + typecheck + full suite), `0.2.0-rc.2` (the same plus a `prepareCall` generation freeze), `0.2.1-alpha.3` (the first target release), `0.2.1-alpha.4` (T-24), `0.2.1-alpha.5` (T-26), and `0.2.1-rc.2` (T-31, where the runtime moved to cordis `4.0.5`; the upstream contract layer had zero source changes). Other versions inside the range were not verified one by one.
|
|
253
260
|
- **The upper bound is a tracking line**: `<0.3.0-0` means that the moment DSH ships `0.3.0-0` (the first prerelease on the `0.3.0` line), this plugin must ship a new release in the same window or every user loses the plugin. `tests/peer-coverage.spec.ts` asserts both ends — the lower bound accepts the installed version, the upper bound rejects `0.3.0-0` — so a drift here fails locally instead of failing on a user's machine. After changing a range, `npm test` is the verification (local mock gateway, no network, no tokens) — ranges follow what the interfaces declare, and are never "measured" with live probes.
|
|
254
261
|
- **Peer coverage is now guarded both ways**: `dsh-typert-registry`, `dsh-client-ui-conversation`, and `dsh-client-ui-renderer` were imported by the source but absent from `peerDependencies`, invisible to the gate; they are declared now, and `tests/peer-coverage.spec.ts` asserts both directions — anything the source imports must be declared, and anything declared but unreached must be removed (`dsh-settings` went that way: the settings form is actually provided by `dsh-client-ui-settings`).
|
|
@@ -281,7 +288,7 @@ npm test # contract tests against a real local HTTP mock gateway
|
|
|
281
288
|
|
|
282
289
|
**Order matters**: `npm run build` must come before `npm test` — `tests/pack-contents.spec.ts` walks every `exports` target, and whether `lib/` exists decides whether that check runs or is silently skipped (it does not fail, it just stops protecting you). `package.json` no longer carries `prepare`, so `npm ci` will not build for you; all three CI workflows run `npm run build` explicitly.
|
|
283
290
|
|
|
284
|
-
The suite covers configuration validation, the protocol ladder, gateway and online metadata, the catalog projection, the adapter on the wire (all three protocols), Remote contracts and services, session-header invariants, usage windows and the meter, the client controller and usage pill, both halves' mounting and registration, the error mapping for stream idle timeouts and aborts, the exit-code contract of the verification scripts, and several **structural invariants** (inject declarations match the source's reads, peer coverage holds both ways, the READMEs match the manifest, and the READMEs' claims about the upstream match the upstream actually installed). That is **
|
|
291
|
+
The suite covers configuration validation, the protocol ladder, gateway and online metadata, the catalog projection, the adapter on the wire (all three protocols), Remote contracts and services, session-header invariants, usage windows and the meter, the client controller and usage pill, both halves' mounting and registration, the error mapping for stream idle timeouts and aborts, the exit-code contract of the verification scripts, and several **structural invariants** (inject declarations match the source's reads, peer coverage holds both ways, the READMEs match the manifest, and the READMEs' claims about the upstream match the upstream actually installed). That is **59 test files** — a number `tests/readme-consistency.spec.ts` checks against the `tests/` directory, so it cannot drift.
|
|
285
292
|
|
|
286
293
|
## Releasing (maintainers)
|
|
287
294
|
|
package/README.md
CHANGED
|
@@ -115,7 +115,7 @@ DSH 桌面端是 Electron 壳 + 完整的 dsh Web 应用,本插件对它同样
|
|
|
115
115
|
pinnedAddresses: # 固定 IP:域名 → 地址(只对网关域名生效)
|
|
116
116
|
opencode.ai: 104.18.32.47 # 可写 IPv4 或 IPv6;不合法或未设置时走系统 DNS
|
|
117
117
|
requestLogEnabled: false # 请求日志总开关,默认关闭:关闭时请求路径与没有该日志逐字节一致
|
|
118
|
-
requestLogDebug: false #
|
|
118
|
+
requestLogDebug: false # 排错详情:连接池事件与请求 UA;会话 id 始终完整记录
|
|
119
119
|
requestLogMaxEntries: 200 # 最多保留条数,50 ~ 500,超限丢弃最旧的
|
|
120
120
|
retryPolicy: # 可选:本路由的重试策略(由 dsh-llm-retry 执行)
|
|
121
121
|
mode: normal # 也可用 always(对所有失败重试,maxRetries 被忽略)
|
|
@@ -140,9 +140,16 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
|
|
|
140
140
|
- 设置页里以**秒**显示与填写(毫秒的数字人读不出量级),存储时换算成毫秒。取值 1 ~ 1800000 毫秒。
|
|
141
141
|
- 空闲满这个时间之后,连接由连接池**自己回收**,不需要额外的清理机制(实际释放时间比设置值多约 2 秒,那是客户端在服务端给的期限之外自留的一点缓冲)。插件被卸载时,连接池也会**一并关掉**——它是插件的,不该留在机器上。
|
|
142
142
|
|
|
143
|
-
**请求日志**:默认关闭的逐请求记录,打开它不改变请求的任何行为。设置页"请求日志"
|
|
143
|
+
**请求日志**:默认关闭的逐请求记录,打开它不改变请求的任何行为。设置页"请求日志"分组里有总开关、排错详情开关(连接池事件与请求 UA)、保留条数(默认 200)。
|
|
144
144
|
|
|
145
|
-
-
|
|
145
|
+
- **两个入口,同一个页面**:
|
|
146
|
+
- **侧边栏图标 → 主区域整页**:跨会话看全部请求。日志是进程级的数据,放在侧边栏最合理——位置固定、常驻可见,和 DSH 自己的插件管理器同一个范式。
|
|
147
|
+
- **会话里的「请求日志」标签页**:就地看**本会话**的请求,回答"刚才那轮为什么慢"不用离开对话。
|
|
148
|
+
- 页面是一整页而不是浮层:标题、统计(请求数/失败数/平均耗时/平均首字/平均 tok/s/平均缓存命中/连接复用率)、筛选栏固定在上方,只有表格自己滚动。每行含时间、模型、会话、输入/输出/缓存、**缓存命中**、**tok/s**、首字、耗时与状态;点一行展开 HTTP 明细(方法、地址、脱敏后的请求头、请求构成、结果与用量)。筛选有模型/结果/慢请求/会话,分组有会话/模型/结果;**点列头按该列排序**,再点一次反向。
|
|
149
|
+
- **tok/s** 是**首字到结束**这段解码窗口上的输出速率,口径与 Harness 自己的每轮读数一致(含推理 token)。没有 token 的请求没有速率——不编数。
|
|
150
|
+
- **缓存命中**是输入 token 里走缓存的占比(缓存读取/(未缓存输入+缓存读取))。网关没报输入就没有占比——同样不编数。
|
|
151
|
+
- 会话 id **始终完整记录**(它是会话身份,不是凭据;截断后两个会话会读成一个)。
|
|
152
|
+
- 记录的是环形缓冲(超限丢最旧),进程重启即清;只读快照,不轮询,没人打开的页面零流量。
|
|
146
153
|
- 凭据永远不进记录:记录器根本不接收请求头参数,只收白名单里的会话 id 与 UA;失败的请求同样记一条(含错误码),中断到没有终端事件的不记(网关没报总数就不编数)。
|
|
147
154
|
|
|
148
155
|
**图片**:三个字段各管一层,超限的图片会被明确拒绝,而不是静默降质或丢弃:
|
|
@@ -239,7 +246,7 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
|
|
|
239
246
|
| 绑定层 | 声明 | 谁在把关 |
|
|
240
247
|
| --- | --- | --- |
|
|
241
248
|
| `engines.dsh` | `>=0.2.0-rc.1 <0.3.0-0` | **DSH 加载时的真门禁;声明了它,peer 判定被整体跳过** |
|
|
242
|
-
| `peerDependencies`(
|
|
249
|
+
| `peerDependencies`(20 个 `@deepseek-ai/dsh-*`) | 均为 `>=0.2.0-rc.1 <0.3.0-0` | 仅当 `engines.dsh` 缺席时才接管;本插件声明了它,故当前不参与判定 |
|
|
243
250
|
| `@deepseek-ai/cordis` | `4.0.4 \|\| 4.0.5-alpha.1 \|\| 4.0.5-alpha.2 \|\| 4.0.5` | 同上(peer 通道) |
|
|
244
251
|
| `engines.node` | `^22.19.0 \|\| >=24.0.0` | 包管理器 |
|
|
245
252
|
| 已打包依赖 `@earendil-works/pi-ai` | `~1.3.0`(1.3.x 内),**打进产物**(devDependency) | 独立耦合:pi-ai 改请求构造即影响本插件的线上行为;其 opencode-go 内置目录同时是本插件的打底数据。打包后本插件**没有任何运行时依赖**,安装者不必再解析它 |
|
|
@@ -247,7 +254,7 @@ API Key 通过 Harness 凭证库提供(引用名 `OPENCODE_GO_API_KEY`),
|
|
|
247
254
|
|
|
248
255
|
维护时需要注意:
|
|
249
256
|
|
|
250
|
-
- **必选与可选之分**:
|
|
257
|
+
- **必选与可选之分**:21 个 peer(20 个 `dsh-*` 加框架 `cordis`)中 9 个标了 `optional`(`dsh-api-remotes`、`dsh-client-locale`、`dsh-client-store`、`dsh-client-ui-layout`、`dsh-client-ui-model-selection`、`dsh-client-ui-primitives`、`dsh-client-ui-settings`、`dsh-client-ui-sidebar`、`dsh-client-ui-slots`);其余 12 个是运行时必需的——`cordis`、`dsh-attachment`、`dsh-brand`、`dsh-client-ui-conversation`、`dsh-client-ui-renderer`、`dsh-credentials`、`dsh-fs`、`dsh-launch-environment`、`dsh-llm`、`dsh-timeout`、`dsh-typert-protocol`、`dsh-typert-registry`。这 21 个当前都**不参与加载判定**(见上:`engines.dsh` 单独决定),它们的价值在于声明依赖并供包管理器与读者使用。其中 `dsh-llm` 是最重的一处耦合(源码 import 二十余处)。
|
|
251
258
|
- **名义范围 ≠ 实测范围**:声明范围是 `>=0.2.0-rc.1 <0.3.0-0`,本项目实际验证过的基线依次是 `0.2.0-rc.1`(开发依赖基线:门禁判定 + typecheck + 全量用例)、`0.2.0-rc.2`(同上 + `prepareCall` 代次冻结)、`0.2.1-alpha.3`(首个目标版本)、`0.2.1-alpha.4`(T-24)、`0.2.1-alpha.5`(T-26)与 `0.2.1-rc.2`(T-31,运行时升到 cordis `4.0.5`;上游契约层源码零变更)。范围内的其他版本没有逐个验证过。
|
|
252
259
|
- **上界就是跟版线**:`<0.3.0-0` 意味着 DSH 一旦发布 `0.3.0-0`(`0.3.0` 线的第一个预发布版),本插件必须同批发新版,否则所有用户加载失败。`tests/peer-coverage.spec.ts` 会同时断言下界接受已安装版本、上界拒绝 `0.3.0-0`,所以这条线漂移会在本地测试里先失败,而不是等用户加载失败。调整范围后用 `npm test` 验证即可(本地 mock 网关,零网络零 token)——范围以接口声明为准,不要用线上探测来"测"出一个范围。
|
|
253
260
|
- **peer 覆盖已双向守住**:`dsh-typert-registry`、`dsh-client-ui-conversation`、`dsh-client-ui-renderer` 曾被源码 import 却未声明、门禁管不到,现已补进 `peerDependencies`;`tests/peer-coverage.spec.ts` 双向断言——源码用到的必须声明,声明了却没人用的必须删(`dsh-settings` 就这样被移除:设置表单实际由 `dsh-client-ui-settings` 提供)。
|
|
@@ -280,7 +287,7 @@ npm test # 契约测试:真实 HTTP mock 网关,断言请求头/
|
|
|
280
287
|
|
|
281
288
|
**顺序有讲究**:`npm run build` 要排在 `npm test` 之前——`tests/pack-contents.spec.ts` 会遍历 `exports` 的每个目标,`lib/` 存在与否决定这条检查是执行还是被跳过(不报错,但会少一层保护)。`package.json` 已移除 `prepare`,因此 `npm ci` 不会再替你隐式构建;三个 CI workflow 都显式跑了 `npm run build`。
|
|
282
289
|
|
|
283
|
-
测试覆盖配置校验、协议阶梯、网关与在线元数据、目录投影、适配器(三种协议的线上请求)、Remote 契约与服务、会话头不变量、用量窗口与计量、客户端控制器与用量组件、两半的挂载与登记、流空闲超时与中止的错误映射、验证脚本的退出码契约、以及几条**结构性不变量**(inject 声明与源码读取一致、peer 覆盖双向、README 与 manifest 一致、README 对上游的断言与实装的上游一致)。共 **
|
|
290
|
+
测试覆盖配置校验、协议阶梯、网关与在线元数据、目录投影、适配器(三种协议的线上请求)、Remote 契约与服务、会话头不变量、用量窗口与计量、客户端控制器与用量组件、两半的挂载与登记、流空闲超时与中止的错误映射、验证脚本的退出码契约、以及几条**结构性不变量**(inject 声明与源码读取一致、peer 覆盖双向、README 与 manifest 一致、README 对上游的断言与实装的上游一致)。共 **59 个测试文件**——这个数字由 `tests/readme-consistency.spec.ts` 对着 `tests/` 目录校验,不会漂移。
|
|
284
291
|
|
|
285
292
|
## 发布(维护者)
|
|
286
293
|
|