dsh-magpie-connector 0.3.0 → 0.4.0

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
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ - **Line panel polish.** Settings now collapses every configured line by default (it no longer force-expands the active one); clicking a line header toggles it, and the add/remove/reorder actions are always-visible DSH product-icon buttons with accessible names and tooltips. A newly added line still opens for editing and stays open through its first save (including when it was moved before saving) and when a save fails.
6
+ - **Line latency.** Opening Settings measures each saved line with a parseable address once (parallel TCP connect time, ≤600ms per line, DNS included, no HTTP and no credentials) and shows a 4-bar signal reading plus the millisecond value; timeouts show 「超时」, failed or older-host responses degrade silently to 「—」. Readings are display-only: they are not persisted, never touch automatic line selection, and are re-measured only on the next panel open or after a successful line save (no polling). New GET-only host resource `GET /api/dsh-magpie-connector/latency`.
7
+ - Usage bar fill now has rounded ends matching the track.
8
+ - **Check a line before saving it.** Every line card has 「检查线路 / Check line」: it runs one real `GET /models` against the card's current draft (address, access mode, key; empty credentials fall back to that line's saved values) and renders a read-only snapshot — result kind, latency, model count and, when the host has a cached catalog with a sync time, the model ids extra to or missing from that cache. It never writes credentials or settings, never rotates the generation, never selects a line, never registers a route and never touches the probe cache, so it cannot change which line is in use; the snapshot is explicitly compared against the *cached* catalog, never called "same as the current line" (a switch keeps an inherited catalog).
9
+ - **Bounded, classified, redacted.** The `line-check` settings API resource admits no write: with a save in progress or a credential write pending it answers `pending`/`busy` without reading saved credentials, a host-memory connection-write version proves no write landed during the credential read, the whole check shares a 5 s budget, only one check runs at a time, and draft credentials are redacted from results, reasons and logs. Failure classification has a fixed precedence (response state before body, transport-blocked redirects included).
10
+ - **Quieter saves, honest labels.** Usage cards are cleared only when a save touches the active line's identity (line removed, address/access mode changed, credentials supplied) or the host auto-switches lines; editing or reordering spare lines keeps the cards and their read time. The save result states the resulting line (`已保存 · 当前线路 N` / no active line) with no live region, and a saved-but-incomplete line is labelled `未配置`.
11
+ - **Wire contract.** `POST /api/dsh-magpie-connector/line-check` accepts `{id?, baseUrl, accessMode?, key?, accessClientId?, accessClientSecret?}`; shape violations are 400, every other outcome is a 200 result with `kind`. See `openspec/changes/archive/2026-10-30-magpie-line-probe-and-save-clarity/` for the specification.
12
+
13
+ ## 0.3.1
14
+
15
+ - Replace both README demo GIFs with representative PNG screenshots (the model picker grouped by provider; per-provider visibility, default effort and usage cards in Settings), because the DSH plugin store does not show GIFs by default. No runtime behavior changes.
16
+
3
17
  ## 0.3.0
4
18
 
5
19
  **BREAKING:** the single provider route `dsh-magpie-connector` is retired and not aliased. Sessions, the default model and any external configuration saved with that route id no longer resolve; reselect the model after upgrading, and update anything that lists the exact route id (subagent routing, egress allowlists).
package/README.md CHANGED
@@ -3,23 +3,26 @@
3
3
  English · [简体中文](README.zh.md)
4
4
 
5
5
  <p align="center">
6
- <img src="docs/model-picker.gif" alt="Model picker grouped by upstream provider, with the GPT-only standard/fast control" width="49%">
6
+ <img src="docs/model-picker.png" alt="Model picker grouped by upstream provider: Magpie (Claude), Magpie (GPT), Magpie (deepseek)" width="49%">
7
+ <img src="docs/settings.png" alt="Settings: the connection line on top, then models grouped by provider with visibility, default effort and usage cards" width="49%">
7
8
  </p>
8
9
 
9
- *Model picker recorded from an isolated DSH host with a local mock Magpie gateway; models and accounts are synthetic. A fresh settings screenshot is pending re-recording.*
10
+ *Left: model picker grouped by upstream provider. Right: Settings → Magpie — the connection line, then per-provider model visibility, default effort and usage cards. Captured from an isolated DSH host with a local mock Magpie gateway; models and accounts are synthetic.*
10
11
 
11
- [Repository](https://github.com/prgrmrwy/dsh-magpie-connector) · [Releases](https://github.com/prgrmrwy/dsh-magpie-connector/releases) · [npm](https://www.npmjs.com/package/dsh-magpie-connector)
12
+ ![Magpie connector architecture: Web GUI and Host plugin, credentials and settings, Magpie gateway and upstream providers, optionally through Cloudflare Access](docs/architecture.en.svg)
12
13
 
13
14
  <!-- problem -->
14
- **Connect a self-hosted Magpie gateway to DeepSeek Harness as one provider route: models grouped by their upstream provider, read-only usage cards, and a per-session fast mode.** Magpie keeps managing logins, accounts, routing and provider egress; this plugin adds the DSH side.
15
+ **Connect a self-hosted Magpie gateway to DeepSeek Harness with one provider route per upstream owner: models grouped by upstream provider on stock DSH, read-only usage cards, and a per-session fast mode.** Magpie keeps managing logins, accounts, routing and provider egress; this plugin adds the DSH side.
15
16
 
16
17
  ### What you get
17
18
 
18
19
  | Capability | What it does |
19
20
  |---|---|
20
21
  | **Gateway lines** (basic) | Each line has its own URL and gateway key. The model catalog comes from the gateway's `GET /models`; Responses-capable models use Responses, everything else uses Chat Completions. Text, tool round trips, images, usage, cancellation and DSH-managed retries go through. |
22
+ | **Check a line before saving** (0.4.0) | Every line card has “Check line”: one real `GET /models` with that card's address, access mode and key (empty credentials fall back to the line's saved values), rendered as a read-only snapshot — result kind, latency, model count and, when the host has a cached catalog with a sync time, the model ids extra to or missing from that cache. It never changes the active line, writes credentials/settings, syncs the catalog or registers a route; the diff is against the *cached* catalog, so it never claims to match the current line. |
21
23
  | **Automatic multi-line failover** (signature) | Empty on first install; normally one line; add backup lines and let the order decide priority. Before every gateway operation the plugin picks the first reachable complete line with a ≤600ms TCP probe (10s positive / 15s negative in-memory cache, no background polling), so home uses the LAN while outside falls back to the public endpoint. Switching lines carries the catalog over (no flash), clears usage cards and re-syncs the new line; single-line users keep 0.1.x behavior. |
22
24
  | **Grouped by upstream provider** (signature) | Works on stock DSH, no Host extension needed: the plugin registers one real provider route per gateway `owned_by` (`dsh-magpie-connector-claude`, `-codex`, `-opencode-go`, …; missing or invalid ownership goes to `-other`), so the official model picker shows `Magpie (Claude)`, `Magpie (Codex)`, `Magpie (Opencode-go)`, `Magpie (Other)` groups. Settings and usage cards use the same grouping, and a provider that only appears in usage is never dropped. |
25
+ | **Line panel and latency** | Configured lines start collapsed; click a row header to edit it, and reorder/delete are always-visible DSH product-icon buttons with tooltips. Opening Settings measures every saved line with a parseable address once (parallel TCP connect time, ≤600ms per line, no HTTP, no credentials) and shows a 4-bar signal plus milliseconds; timeouts show a timeout reading and failures or older hosts degrade to a dash. Display-only: it never affects automatic line selection, is not persisted, and never polls. |
23
26
  | **Per-line Cloudflare Access** | Each line independently chooses Direct or Cloudflare Access. Access-enabled line requests carry the service token pair plus the bearer key; the token is never sent to a plain-HTTP line. |
24
27
  | **Read-only usage cards** | Each upstream account shows plan, expiry, window readings and Codex reset credits when the gateway provides them. Cards are read once when settings open and only re-read when you press **Refresh** on that card; bars turn orange above 70% and red at 90%. |
25
28
  | **Model visibility and default effort** | Per provider, leave visibility untouched to follow the gateway catalog, or save an explicit allowlist so new models stay hidden. Per model, save a default reasoning effort; DSH applies it on the next request. |
@@ -55,7 +58,7 @@ Need another method — custom headers, mTLS, another zero-trust gateway? **Issu
55
58
  | **Model picker** | Search across group headings, model names and full ids. Each group is a real route `dsh-magpie-connector-<owner>`; model ids stay the gateway's full ids, and visibility keys and default effort are unchanged. |
56
59
  | **Model menu groups** | `owned_by` (lower-cased; 1–48 chars of `a-z0-9._-`) picks the route and the label `Magpie (<Owner>)` with the first letter capitalised. Missing or invalid ownership goes to `Magpie (Other)` instead of guessing from the model name. Owners seen once are remembered in `settings.json` `knownOwners` (max 32) so their routes exist right after a restart; the models appear once the first catalog sync finishes. An owner that disappears keeps its (empty, hidden) route. Clearing `knownOwners` by hand invalidates selections saved on the removed routes. If route registration fails at start-up (another plugin owns the id), Settings shows the error and DSH must be restarted after resolving it. |
57
60
  | **Composer speed control** | Shows only for the current model when the gateway advertises the `priority` tier (on current Magpie: the Codex/GPT models), and updates as soon as the selection changes. Hover the model menu to see effort; the official picker shows one effort value. |
58
- | **Settings → Magpie** | Connection, advanced connection mode, per-provider model sections with visibility checkboxes and default effort selects, plus the usage cards for that provider. |
61
+ | **Settings → Magpie** | Connection, advanced connection mode, per-provider model sections with visibility checkboxes and default effort selects, plus the usage cards for that provider; each line card also carries the read-only “Check line” snapshot and an “unconfigured” label, and the save result states the resulting active line. |
59
62
  | **Usage card refresh** | Each card has its own **Refresh**, which asks Magpie to re-read that one account. A cold gateway may return no cards at all; the connection panel then offers **Fetch models and usage**, which first re-synchronizes the catalog and then asks Magpie to read every account once. A restricted held key cannot initialize an empty cache — ask the Magpie administrator to read usage first. |
60
63
 
61
64
  ### Behavior worth knowing
@@ -68,22 +71,22 @@ Need another method — custom headers, mTLS, another zero-trust gateway? **Issu
68
71
  - **Not supported:** `stop` sequences fail before any network access (`MAGPIE_STOP_UNSUPPORTED`) because Magpie cannot preserve them across every upstream translation. Usage cards and Codex reset credits are display-only; the plugin never calls account-management or reset endpoints.
69
72
  - **Secrets stay out of responses and logs.** Gateway-reflected text is redacted with the current key before it can reach the settings API or logs. Files are written `0600`; the settings API reports only `configured` / `writable`.
70
73
 
71
- ### Architecture
72
-
73
- ![Magpie connector architecture: Web GUI and Host plugin, credentials and settings, Magpie gateway and upstream providers, optionally through Cloudflare Access](docs/architecture.en.svg)
74
+ ### Code map
74
75
 
75
76
  Entry: [index.ts](src/index.ts). Adapter and request/stream mapping: [adapter.ts](src/host/adapter.ts). Routes: [routes.ts](src/host/routes.ts). Transport allowlist: [transport.ts](src/host/transport.ts). Settings page: [SettingsPage.ts](src/client/SettingsPage.ts). The diagram source, with credential-free repository evidence: [architecture.en.json](docs/architecture.en.json).
76
77
 
77
78
  ### Development
78
79
 
80
+ In a standalone checkout of this repository:
81
+
79
82
  ```sh
80
83
  npm install
81
- npm test --workspace=dsh-magpie-connector
82
- npm run typecheck --workspace=dsh-magpie-connector
83
- npm run build --workspace=dsh-magpie-connector
84
+ npm run typecheck
85
+ npm test
86
+ npm run build
84
87
  ```
85
88
 
86
- Tests use local mock gateways and the real wire library; no real key is required. Build output is not committed. Both `prepare` and `prepack` build the package.
89
+ Inside the ohmydsh monorepo, install once at the root and add `--workspace=dsh-magpie-connector` to the last three commands. Tests use local mock gateways and the real wire library; no real key is required. Build output is not committed. Both `prepare` and `prepack` build the package.
87
90
 
88
91
  ## Removal
89
92
  <!-- section: removal -->
@@ -96,6 +99,8 @@ Restart DSH and refresh the page. Disposal releases registrations, timers and co
96
99
 
97
100
  Inside [ohmydsh](https://github.com/prgrmrwy/ohmydsh), set the manifest entry to `enabled: false` and rebuild instead.
98
101
 
99
- ## License
102
+ ## Source, license and contributing
103
+
104
+ This plugin is developed in [ohmydsh](https://github.com/prgrmrwy/ohmydsh) (`packages/dsh-magpie-connector`); [this repository](https://github.com/prgrmrwy/dsh-magpie-connector) is its release mirror, published automatically to [npm](https://www.npmjs.com/package/dsh-magpie-connector) and [GitHub Releases](https://github.com/prgrmrwy/dsh-magpie-connector/releases). Current behavior is specified in [`openspec/specs/dsh-magpie-connector`](https://github.com/prgrmrwy/ohmydsh/blob/main/openspec/specs/dsh-magpie-connector/spec.md).
100
105
 
101
- MIT. `@earendil-works/pi-ai` and `undici` are separate MIT-licensed dependencies; the bird artwork follows the notice in [THIRD-PARTY-NOTICES](THIRD-PARTY-NOTICES).
106
+ [MIT](LICENSE). `@earendil-works/pi-ai` and `undici` are separate MIT-licensed dependencies; the bird artwork follows the notice in [THIRD-PARTY-NOTICES](THIRD-PARTY-NOTICES). Issues and pull requests are welcome at [prgrmrwy/dsh-magpie-connector](https://github.com/prgrmrwy/dsh-magpie-connector/issues).
package/README.zh.md CHANGED
@@ -3,23 +3,26 @@
3
3
  [English](README.md) · 简体中文
4
4
 
5
5
  <p align="center">
6
- <img src="docs/model-picker.gif" alt="模型选择器:按上游 provider 分组,仅 GPT 显示标准/快速" width="49%">
6
+ <img src="docs/model-picker.png" alt="模型选择器:按上游 provider 分组为 Magpie (Claude)、Magpie (GPT)、Magpie (deepseek)" width="49%">
7
+ <img src="docs/settings.png" alt="设置页:顶部连接线路,下方按 provider 分组的模型可见性、默认 effort 与用量卡片" width="49%">
7
8
  </p>
8
9
 
9
- *模型选择器录屏来自隔离 DSH 宿主与本地 mock Magpie 网关,模型和账号均为演示数据;设置页的线路列表截图待重录。*
10
+ *左:按上游 provider 分组的模型选择器;右:设置 → Magpie,顶部连接线路,下方按 provider 分组的模型可见性、默认 effort 与用量卡片。截图来自隔离 DSH 宿主与本地 mock Magpie 网关,模型和账号均为演示数据。*
10
11
 
11
- [插件仓库](https://github.com/prgrmrwy/dsh-magpie-connector) · [版本发布](https://github.com/prgrmrwy/dsh-magpie-connector/releases) · [npm](https://www.npmjs.com/package/dsh-magpie-connector)
12
+ ![Magpie connector 架构:Web GUI 与 Host 插件、凭据与设置、Magpie 网关与上游 provider,可选经 Cloudflare Access](docs/architecture.zh.svg)
12
13
 
13
14
  <!-- problem -->
14
- **把自托管的 Magpie 网关作为一个 provider route 接入 DeepSeek Harness:模型按上游 provider 分组展示,附带只读用量卡片和会话级快速档。** Magpie 继续负责登录、账号、路由和厂商出站代理,本插件补齐 DSH 侧。
15
+ **把自托管的 Magpie 网关接入 DeepSeek Harness,每个上游归属对应一个 provider route:原版 DSH 即按上游 provider 分组展示模型,附带只读用量卡片和会话级快速档。** Magpie 继续负责登录、账号、路由和厂商出站代理,本插件补齐 DSH 侧。
15
16
 
16
17
  ### 你会得到什么
17
18
 
18
19
  | 能力 | 具体行为 |
19
20
  |---|---|
20
21
  | **Magpie 网关接入**(基础) | 每条线路只需地址和该线路的 key。模型目录来自网关 `GET /models`;支持 Responses 的模型走 Responses,其余走 Chat Completions。文本、工具往返、图片、usage、取消以及 DSH 统一重试都能正常工作。 |
22
+ | **保存前检查线路**(0.4.0) | 每条线路卡片有「检查线路」:用当前填写的地址、接入方式与 key 发一次真实 `GET /models`(凭据留空则用该线路已保存的值),显示结果分类、耗时、模型数量,以及在宿主有缓存目录时与缓存相比多出/缺少的模型。它不改当前线路、不写凭据或设置、不触发目录同步,只是只读快照;差异基准是**缓存目录**,所以不会宣称「与当前线路一致」。 |
21
23
  | **多线路自动切换**(特色) | 通常一条线路(首次安装为空,最多 5 条),可添加备用线路并按序号自动选择:每次操作前对候选地址做 ≤600ms 的 TCP 可达探测(正缓存 10s / 负缓存 15s,不后台轮询),在家走局域网、在外自动落到公网。切换线路时模型目录继承不闪断、用量卡片清空并按新线路重读;单线路(通常一条)行为与旧版一致。 |
22
24
  | **按上游 provider 分组**(特色) | 原版 DSH 即可使用,无需 Host 扩展:插件按网关 `owned_by` 为每个归属注册一个真实 provider route(`dsh-magpie-connector-claude`、`-codex`、`-opencode-go` 等;缺失或不合法归入 `-other`),官方模型选择器因此显示 `Magpie (Claude)`、`Magpie (Codex)`、`Magpie (Opencode-go)`、`Magpie (Other)` 分组。设置页和用量卡片使用同一套分组,只出现在用量里的 provider 也不会被丢弃。 |
25
+ | **线路面板与延迟** | 已配置的线路默认全部收起,点行头部展开编辑;上移 / 下移 / 删除是常驻的 DSH 产品图标按钮(带 tooltip)。打开设置页对每条已保存且地址可解析的线路做一次 TCP 建连测速(并行、单条 ≤600ms、不发 HTTP、不带凭据),用 4 格信号条 + 毫秒显示;超时显示「超时」,旧版宿主或失败显示「—」。只展示当时的网络质量,不参与自动选线、不持久化、不轮询。 |
23
26
  | **按线路的 Cloudflare Access** | 每条线路可单独选择「直连」或「Cloudflare Access」。启用后该线路的请求带上服务令牌两项并保留 bearer key;服务令牌永远不会发往明文 HTTP 线路。 |
24
27
  | **只读用量卡片** | 每个上游账号展示计划、到期时间、各窗口读数和 Codex 重置次数(网关提供时)。打开设置页只读一次,之后只有点单张卡片的「刷新」才会重新读取;用量条超过 70% 变橙、达到 90% 变红。 |
25
28
  | **模型可见性与默认 effort** | 每个 provider 不设置可见性时跟随网关目录;保存过选择后只显示勾选项,新上架模型默认隐藏。每个模型可保存一个默认推理 effort,DSH 在下一次请求应用。 |
@@ -55,7 +58,7 @@ dsh plugin --profile web add dsh-magpie-connector
55
58
  | **模型选择器** | 统一搜索覆盖分组标题、型号名和完整 id。每个分组是一个真实 route `dsh-magpie-connector-<owner>`;model id 保持网关完整 id,可见性键和默认 effort 不变。 |
56
59
  | **模型菜单分组** | `owned_by`(转小写,1–48 个 `a-z0-9._-` 字符)决定 route 和标题 `Magpie (<Owner>)`(首字母大写)。缺失或不合法时归入 `Magpie (Other)`,不按模型名猜测。见过的归属记在 `settings.json` 的 `knownOwners`(最多 32 个),重启后 route 立即存在,首次目录同步完成后模型才出现。归属下架后其 route 保留(空组自动隐藏)。手动清空 `knownOwners` 会让保存在被移除 route 上的选择失效。启动时若 route 注册失败(例如被别的插件占用),设置页会显示错误,排除后需重启 DSH。 |
57
60
  | **输入框速度控件** | 仅当前模型被网关声明为 `priority` 档时显示(当前 Magpie 上即 Codex/GPT 模型),切换模型后立即更新。悬停模型菜单可看 effort;官方选择器只显示一个 effort 值。 |
58
- | **设置 → Magpie** | 连接、接入方式、按 provider 分组的模型区(可见性复选框与默认 effort 选择器),以及该 provider 的用量卡片。 |
61
+ | **设置 → Magpie** | 连接、接入方式、按 provider 分组的模型区(可见性复选框与默认 effort 选择器),以及该 provider 的用量卡片;每条线路卡片还有「检查线路」只读快照与「未配置」标记,保存结果只陈述当时的生效线路。 |
59
62
  | **用量卡片刷新** | 每张卡片有独立的「刷新」,请求 Magpie 重新读取这一个账号。网关冷启动可能没有任何卡片;此时连接面板提供「获取模型与用量」,先同步模型目录,再请 Magpie 读取全部账号一次。受限 held key 无法初始化空缓存,需要管理员先在 Magpie 中读取一次。 |
60
63
 
61
64
  ### 需要知道的行为
@@ -70,22 +73,22 @@ dsh plugin --profile web add dsh-magpie-connector
70
73
  - **不支持:** 非空 `stop` 序列会在发请求前失败(`MAGPIE_STOP_UNSUPPORTED`),因为 Magpie 无法在所有上游协议转换中保留 stop。用量卡片与 Codex 重置次数只读展示,插件不会调用账号管理或重置端点。
71
74
  - **密钥不会进入响应或日志。** 网关反射的文本在进入设置接口或日志之前会用当前 key 脱敏。写盘文件权限 `0600`;设置接口只报告 `configured` / `writable`。
72
75
 
73
- ### 架构
74
-
75
- ![Magpie connector 架构:Web GUI 与 Host 插件、凭据与设置、Magpie 网关与上游 provider,可选经 Cloudflare Access](docs/architecture.zh.svg)
76
+ ### 代码导览
76
77
 
77
78
  入口:[index.ts](src/index.ts)。适配器与请求/流映射:[adapter.ts](src/host/adapter.ts)。路由:[routes.ts](src/host/routes.ts)。传输白名单:[transport.ts](src/host/transport.ts)。设置页:[SettingsPage.ts](src/client/SettingsPage.ts)。不含凭据的图源与仓库证据:[architecture.zh.json](docs/architecture.zh.json)。
78
79
 
79
80
  ### 开发
80
81
 
82
+ 在本仓库的独立检出中:
83
+
81
84
  ```sh
82
85
  npm install
83
- npm test --workspace=dsh-magpie-connector
84
- npm run typecheck --workspace=dsh-magpie-connector
85
- npm run build --workspace=dsh-magpie-connector
86
+ npm run typecheck
87
+ npm test
88
+ npm run build
86
89
  ```
87
90
 
88
- 测试使用本机 mock 网关和真实线协议库,不需要真实 key。构建产物不入库;`prepare` 与 `prepack` 都会执行 build。
91
+ 在 ohmydsh monorepo 里,在仓库根目录安装一次,后三条命令加上 `--workspace=dsh-magpie-connector`。测试使用本机 mock 网关和真实线协议库,不需要真实 key。构建产物不入库;`prepare` 与 `prepack` 都会执行 build。
89
92
 
90
93
  ## 移除
91
94
  <!-- section: removal -->
@@ -98,6 +101,8 @@ dsh plugin --profile web remove dsh-magpie-connector
98
101
 
99
102
  在 [ohmydsh](https://github.com/prgrmrwy/ohmydsh) 中则把 manifest 条目设为 `enabled: false` 后重新构建。
100
103
 
101
- ## 许可
104
+ ## 来源、许可与参与
105
+
106
+ 本插件在 [ohmydsh](https://github.com/prgrmrwy/ohmydsh)(`packages/dsh-magpie-connector`)中持续开发,[本仓库](https://github.com/prgrmrwy/dsh-magpie-connector)是发布镜像,自动发布到 [npm](https://www.npmjs.com/package/dsh-magpie-connector) 与 [GitHub Releases](https://github.com/prgrmrwy/dsh-magpie-connector/releases)。当前行为见规范 [`openspec/specs/dsh-magpie-connector`](https://github.com/prgrmrwy/ohmydsh/blob/main/openspec/specs/dsh-magpie-connector/spec.md)。
102
107
 
103
- MIT。`@earendil-works/pi-ai` 与 `undici` 是分别以 MIT 许可分发的依赖;鸟形图标来源与许可见 [THIRD-PARTY-NOTICES](THIRD-PARTY-NOTICES)。
108
+ 采用 [MIT](LICENSE) 许可。`@earendil-works/pi-ai` 与 `undici` 是分别以 MIT 许可分发的依赖;鸟形图标来源与许可见 [THIRD-PARTY-NOTICES](THIRD-PARTY-NOTICES)。欢迎到 [prgrmrwy/dsh-magpie-connector](https://github.com/prgrmrwy/dsh-magpie-connector/issues) 提 issue 和 PR。
@@ -2,6 +2,5 @@
2
2
 
3
3
  | file | kind | source | date | reviewer | verdict | note |
4
4
  |---|---|---|---|---|---|---|
5
- | model-picker.gif | screenshot | isolated DSH_HOME instance (temp HOME/XDG/DSH_HOME under /tmp, port 3199), synthetic data: local mock Magpie gateway on loopback with demo models (only Codex models advertise the priority tier, as on Magpie); lossless deviceScaleFactor-2 screenshots of the real Web UI, 1500x880 at 1:1 | 2026-10-28 | lead | pass (viewed frames: demo workspace, mock models and mock account only; no hostname, user, path, token or real session) | Model picker grouped by upstream provider, search, switch to GPT shows the standard/fast control, switch back to Claude hides it immediately |
6
-
7
- > Settings screenshot removed pending re-recording after the 0.2.0 line-list settings rewrite; the old recording showed the pre-multi-line connection form.
5
+ | model-picker.png | screenshot | frame 11 of the 2026-10-28 recording (isolated DSH_HOME instance, temp HOME/XDG/DSH_HOME under /tmp, port 3199; local mock Magpie gateway on loopback with demo models; lossless deviceScaleFactor-2 screenshots of the real Web UI, 1500x880 at 1:1), exported losslessly from the global-palette GIF | 2026-10-29 | lead | pass (reviewed frame: demo workspace and mock models only; no hostname, user, path, token or real session) | 106789 bytes; picker open with Magpie (Claude), Magpie (GPT) and Magpie (deepseek) groups; replaces model-picker.gif because the plugin store does not show GIFs by default |
6
+ | settings.png | screenshot | isolated preview home (`git-common-dir/ws/dsh-home/<op>`, port 3202) running the 0.4.0 worktree build against a local loopback mock Magpie gateway (demo models and usage cards); headless Chrome 156 via agent-browser at 1600x1600 CSS pixels | 2026-10-30 | agent (privacy-reviewed; pending lead acceptance) | pass (reviewed: loopback/mock-only addresses 127.0.0.1 and 10.255.255.1, demo@example.com account, demo models and readings; no real hostname, user, key, path, token or session) | 137797 bytes; 0.4.0 connection section with two lines collapsed by default (fast line with 4-bar latency reading, backup line showing timeout), then the claude group with per-model default effort and its usage card with rounded bars; replaces the 0.3.1 screenshot |
@@ -28,6 +28,20 @@ BREAKING: the host settings surface keeps only the `lines[]` schema. Legacy top-
28
28
  - Credential writes are not transactional. Attempted `(lineId, field)` pairs are persisted as `pending` before any secret write; on successful whole-table commit, pending entries for lines absent from the commit are cleaned automatically (unset writable refs, keep env-owned ones in `retainedCredentials`). Deletes/access-mode changes commit only after every writable credential was cleared.
29
29
  - `Operation` captures `lineId`, `accessMode`, `baseUrl` and the credentials; use `op` (not `gen.baseUrl`) for requests. `Generation` still owns catalog/cards; a line switch replaces the generation but carries the catalog, so `isCurrent(gen)` remains the commit guard.
30
30
 
31
+ ## 0.4.0 line latency resource (current)
32
+
33
+ ```ts
34
+ // GET-only; the route is registered with methods:['GET'].
35
+ GET /api/dsh-magpie-connector/latency → { lines: [{ id, ms: number | null }] }
36
+ ```
37
+
38
+ - One entry per **saved line with a parseable address** (empty addresses are omitted, not reported as failures). Unconfigured lines still get a reading: measurement is a network property, not a completeness one.
39
+ - `ms` is a non-negative integer TCP connect time in milliseconds, DNS lookup included, capped by the same 600ms deadline the selector uses; `null` means no connect completed in time.
40
+ - Measurements run in parallel, single-flight (concurrent GETs share one pass), are never cached or persisted, and send no HTTP request and no credentials. They do not write settings, do not change `activeLineId`, and do not read or populate the selector's probe cache.
41
+ - Non-GET methods are not handled by the plugin: they fall through the connection layer to `404` and never open a socket.
42
+ - `dispose` aborts in-flight probes; a later read returns `{lines: []}` without connecting.
43
+ - The web half renders the reading per line (`data-latency-state/level/ms`); any non-2xx (including `404` from an older host) degrades silently to 「—」 with no alert/status/aria-live content.
44
+
31
45
  ## Runtime and connection identity
32
46
 
33
47
  ```ts
@@ -98,7 +112,7 @@ Every request validates same origin and exact API-root-relative path, forces aut
98
112
 
99
113
  ## Host wiring
100
114
 
101
- `apply(ctx,{home?})` registers one adapter on the owner routes derived from `knownOwners` (via `createRouteRegistrar`, see `src/host/registrar.ts`), credentials event, `/api/dsh-magpie-connector/settings` through injected `connection.fetch`, starts initial sync, and installs an async effect disposer. It returns `{runtime,adapter,routes}` for focused harness tests. The feature assembly adds cards/speed resources and their controller lifecycle here; do not add another adapter registration or another settings route.
115
+ `apply(ctx,{home?})` registers one adapter on the owner routes derived from `knownOwners` (via `createRouteRegistrar`, see `src/host/registrar.ts`), credentials event, `/api/dsh-magpie-connector/settings` through injected `connection.fetch`, starts initial sync, and installs an async effect disposer. It returns `{runtime,adapter,routes}` for focused harness tests. The feature assembly adds cards/speed/latency resources and their controller lifecycle here; do not add another adapter registration or another settings route.
102
116
 
103
117
  ## Evidence and remaining assembly
104
118
 
@@ -149,10 +163,10 @@ GREEN checkpoints:
149
163
  - Generation: all seven exact names exist. The two real dispatch cases `已准备的调用按捕获值跑完` and `进行中的生成不被换代中止` live in `generate.test.ts`, not the planned `generation.test.ts`; the names match verbatim, but the test-plan file location needs lead correction/acceptance. Executor did not modify OpenSpec.
150
164
  - Catalog sync: all five names match; mapping: both names match; generation: all fifteen names match; transport: all three names match.
151
165
  - `未配置时不提供模型且不发请求` was already negative-only green against the initial empty seam. A later real adapter test asserts `MAGPIE_NOT_CONFIGURED` plus empty advertised catalog and zero network, but there is **no legitimate first-red record for that full scenario**. Do not misreport the vacuous initial pass as RED. All generation negative tests initially vacuous were strengthened and confirmed RED before bridge implementation.
152
- - Transport `完整流程只触达白名单` directly exercises all allowed operations through the one transport and rejects forbidden paths, but the final assembled cards/speed feature workflow still requires its own end-to-end run. This test alone is not evidence that all feature endpoints were wired.
166
+ - Transport `完整流程只触达白名单` directly exercises all allowed operations through the one transport and rejects forbidden paths, but the final assembled cards/speed/latency feature workflow still requires its own end-to-end run. This test alone is not evidence that all feature endpoints were wired.
153
167
 
154
168
  ## Interfaces and assembly boundary
155
169
 
156
170
  See `internal-api.md`. Exported core classes: `MagpieRuntime`, `MagpieAdapter`, `GatewayTransport`, `SettingsStore`; operation/capability interfaces come from their host modules. Real DSH `LlmAdapter`/registration/credentials/attachment types are used, not an alternative adapter framework.
157
171
 
158
- The lead/host-features owner takes final composition of preferences, adapter projection and cards/speed routes. Do not mark tasks1–7 or shared task1 complete merely from this evidence: interface assembly and final whole-suite snapshot must be accepted by lead. No dependency installation was needed or performed in this takeover; pre-existing root lockfile changes were preserved.
172
+ The lead/host-features owner takes final composition of preferences, adapter projection and cards/speed/latency routes. Do not mark tasks1–7 or shared task1 complete merely from this evidence: interface assembly and final whole-suite snapshot must be accepted by lead. No dependency installation was needed or performed in this takeover; pre-existing root lockfile changes were preserved.
Binary file
Binary file
@@ -1,4 +1,5 @@
1
1
  import { type Api } from './api.js';
2
+ import { type CheckSnapshot, type SettingsView } from './view-model.js';
2
3
  /**
3
4
  * Magpie settings section: connection (with an advanced access mode), then
4
5
  * per-provider groups (model visibility, DSH-side default effort, read-only
@@ -9,6 +10,17 @@ import { type Api } from './api.js';
9
10
  export declare const EMPTY_TEXT = "Magpie \u672A\u8FD4\u56DE\u53EF\u89C1\u7528\u91CF";
10
11
  export declare const RESTRICTED_HINT = "\u53D7\u9650\u7684 gateway key \u65E0\u6CD5\u8BA9 Magpie \u9996\u6B21\u8BFB\u53D6\u7528\u91CF\uFF1A\u9700\u8981 Magpie \u7BA1\u7406\u5458\u5148\u5728 Magpie \u4E2D\u8BFB\u53D6\u4E00\u6B21\uFF0C\u6216\u8005\u6539\u7528\u4E0D\u53D7\u9650\u7684 key\u3002";
11
12
  export declare const NOT_REREAD = "Magpie \u672A\u91CD\u65B0\u8BFB\u53D6\uFF08\u53EF\u80FD\u5904\u4E8E\u8282\u6D41\u95F4\u9694\u5185\uFF09";
13
+ /**
14
+ * Does this submitted list touch the active line's identity? Only then the old usage cards must
15
+ * disappear before the request is even sent (the host writes credentials before awaiting its
16
+ * catalog sync, which can take up to 15s).
17
+ */
18
+ export declare function touchesActiveIdentity(lines: unknown[], view: SettingsView): boolean;
19
+ /** One line of the read-only snapshot: kind, model count, diff against the cache and latency. */
20
+ export declare function describeCheck(snapshot: CheckSnapshot, diff: {
21
+ added: string[];
22
+ removed: string[];
23
+ } | undefined, lastSyncAt: string | undefined): string;
12
24
  export declare function MagpieSettings({ api }: {
13
25
  api: Api;
14
26
  }): import("react").DetailedReactHTMLElement<{