dsh-github-router 0.3.1 → 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 +79 -56
- package/CONTRIBUTING.md +17 -6
- package/README.md +26 -18
- package/README.zh.md +22 -17
- package/docs/design.md +51 -43
- package/lib/client.js +165 -116
- package/lib/config.js +167 -116
- package/lib/core/issue.js +212 -202
- package/lib/core/pr.js +454 -429
- package/lib/index.js +11 -6
- package/lib/routes/gh.js +120 -109
- package/lib/routes/html.js +266 -250
- package/lib/settings.js +23 -21
- package/lib/tunnel.js +363 -247
- package/package.json +11 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,56 +1,79 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project are documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [0.
|
|
9
|
-
|
|
10
|
-
###
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.4.0] - 2026-09-28
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Migrated the plugin to the DSH `0.1.7-rc.2` plugin API
|
|
13
|
+
- Configuration is the exported `Config` schema.
|
|
14
|
+
- The configuration page moved to the plugin's row on the Plugins page.
|
|
15
|
+
- A blank token draft no longer clears the stored token.
|
|
16
|
+
|
|
17
|
+
## [0.3.2] - 2026-09-08
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- The `gh` route now builds valid arguments for its viewers.
|
|
22
|
+
- The `gh` route now returns the metadata URL field.
|
|
23
|
+
- The proxy transport now decodes chunked responses.
|
|
24
|
+
- The html route now handles the current GitHub pull request page payload.
|
|
25
|
+
- Fallback routes are now entered only when a part could not be fetched.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Offline regression tests for the `gh` route, chunked decoding, and failover gating.
|
|
30
|
+
|
|
31
|
+
## [0.3.1] - 2026-08-28
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- Boot with DSH 0.1.2-alpha.4
|
|
36
|
+
|
|
37
|
+
## [0.3.0] - 2026-08-28
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Adapted to DeepSeek Harness 0.1.2-alpha.1
|
|
42
|
+
|
|
43
|
+
## [0.2.1] - 2026-08-28
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- Declare compatibility for dsh 0.1.1-rc.2
|
|
48
|
+
|
|
49
|
+
## [0.2.0] - 2026-08-21
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
53
|
+
- **Migrated plugin configuration to the framework's plugin-settings mechanism** (requires DSH ≥ 0.1.0-rc.7, which serves every registered settings namespace and dispatches plugin-owned configuration cards). The browser half now registers a `settings.plugin.item` card keyed by the `dsh-github-router` namespace inside Settings → Plugins, bound through `ctx.settingsScope` (shared describe mirror, revision fencing, recovery reads, reconnect invalidation); the plugin-owned `/dsh-github-router/config` web routes and the standalone `settings.section` page are removed. The Host keeps the same `settings.register` seam and adds `applies: 'live'`.
|
|
54
|
+
- The token control is now a true write-only field: the configured state comes from the describe mirror's secret slot list (badge: "已配置/configured"), a typed value writes the token, and a blank save clears a configured one.
|
|
55
|
+
- Runtime requirements: the settings card needs DSH ≥ 0.1.0-rc.7; the Host-side settings seam alone still works on older compositions (tools resolve the composition config as before).
|
|
56
|
+
|
|
57
|
+
## [0.1.0] - 2026-08-19
|
|
58
|
+
|
|
59
|
+
First release.
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- Five read-only model tools: `github_probe`, `github_pr`, `github_issue`, `github_file`, `github_api`
|
|
64
|
+
- In-tool route ladder: api.github.com (direct → CONNECT-tunnel proxy) → gh CLI (read-only subcommands) → git protocol (plugin fetch cache + read-only local repo reads) → PR/issue page HTML (strict `react-app.embeddedData` JSON extraction) → user-configured raw mirrors (off by default), with per-part route attribution on every result
|
|
65
|
+
- `github_probe` connectivity matrix with per-route timings and a recommended route chain
|
|
66
|
+
- TTL response cache with atomic writes and corruption-tolerant reads
|
|
67
|
+
- Settings: the `dsh-github-router` namespace on the official settings seam (secret token / `tokenEnv` credential ref, proxy, route switches, cache TTLs, byte caps, granted local repos), an independent Settings page (the dsh-notification `settings.section` mechanism; common fields up top, the long tail in a collapsed "Advanced settings" disclosure), and plugin-owned `/dsh-github-router/config` web routes (the dsh-market pattern) with same-origin enforcement and revision fencing
|
|
68
|
+
- `github-router` skill and a system-prompt guidance section (order 118)
|
|
69
|
+
- Zero runtime dependencies: zero-dependency CONNECT tunnel for proxied requests; peers resolve from the DSH profile
|
|
70
|
+
- 72 offline tests (`node --test`) covering extraction, guards, cache, tunnel, tool wiring, client bundle, config routes, and localization compliance
|
|
71
|
+
- Documentation: bilingual README, SECURITY, design notes, and a development guide
|
|
72
|
+
|
|
73
|
+
### Security
|
|
74
|
+
|
|
75
|
+
- Read-only by construction: no write/push/comment/mutation verb exists anywhere
|
|
76
|
+
- Tokens attach only to api.github.com and are redacted on every wire boundary
|
|
77
|
+
- Page HTML is parsed with `JSON.parse` only (never evaluated); a bounded BFS copies a whitelist of fields
|
|
78
|
+
- Subprocess calls are argv arrays with fixed flag lists — no shell interpolation
|
|
79
|
+
- Configuration writes require same-origin POSTs and are body-capped
|
package/CONTRIBUTING.md
CHANGED
|
@@ -28,16 +28,27 @@ loads at process start).
|
|
|
28
28
|
|
|
29
29
|
## Offline peer resolution
|
|
30
30
|
|
|
31
|
-
The plugin's imports (`@deepseek-ai/dsh-tools`, `dsh-
|
|
32
|
-
`
|
|
33
|
-
|
|
34
|
-
registry round-trip, create a local
|
|
31
|
+
The plugin's imports (`@deepseek-ai/dsh-tools`, `dsh-credentials`,
|
|
32
|
+
`schemastery`, `cordis`) are peer dependencies and resolve from the DSH install
|
|
33
|
+
in production — the profile's `node_modules/@deepseek-ai` mirrors the checkout
|
|
34
|
+
that ran last. To run the tests without a registry round-trip, create a local
|
|
35
|
+
`node_modules/@deepseek-ai` inside this checkout and junction the packages the
|
|
36
|
+
tests import to the framework copies of the DSH you run:
|
|
35
37
|
|
|
36
38
|
```powershell
|
|
37
|
-
|
|
39
|
+
$dsh = '<path to the DSH checkout you run>'
|
|
40
|
+
New-Item -ItemType Directory -Force node_modules\@deepseek-ai | Out-Null
|
|
41
|
+
foreach ($p in 'schemastery', 'cordis', 'dsh-tools', 'dsh-settings') {
|
|
42
|
+
New-Item -ItemType Junction -Path "node_modules\@deepseek-ai\$p" -Target "$dsh\apps\cli\node_modules\@deepseek-ai\$p"
|
|
43
|
+
}
|
|
44
|
+
New-Item -ItemType Junction -Path node_modules\@deepseek-ai\dsh-credentials -Target "$dsh\packages\credentials\credentials"
|
|
38
45
|
```
|
|
39
46
|
|
|
40
|
-
|
|
47
|
+
For an npm-installed DSH the framework packages live under
|
|
48
|
+
`<DSH_HOME>\node_modules\@deepseek-ai\dsh\node_modules\@deepseek-ai` instead.
|
|
49
|
+
`schemastery` must be ≥ 3.18.3: `.volatile()`, which every settings field uses,
|
|
50
|
+
does not exist in 3.18.2. (`node_modules/` is git-ignored; the junction is a
|
|
51
|
+
local convenience only.)
|
|
41
52
|
|
|
42
53
|
## Conventions
|
|
43
54
|
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> Read-only GitHub access for a DeepSeek Harness project — load PRs, issues, files, and API data through tools that route internally (API, gh CLI, git protocol, page HTML, mirrors), so an agent never burns turns fighting shell-side TLS or proxy failures.
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
|
-
[](https://nodejs.org/)
|
|
9
9
|
[](https://www.npmjs.com/package/dsh-github-router)
|
|
10
10
|
|
|
11
11
|
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin bundle that gives agents GitHub reads without shell retries:
|
|
@@ -15,13 +15,13 @@ A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin bun
|
|
|
15
15
|
- **One call, structured outcome** — PRs come back with metadata, discussion, reviews, commits, changed files, and the diff, each part annotated with the route that served it; failures return a route matrix instead of a dozen retried shell commands.
|
|
16
16
|
- **Connectivity probe** — `github_probe` reports which routes are live from the host in one call, with timings and a recommended route chain.
|
|
17
17
|
- **Zero runtime dependencies** — peers resolve from the DSH profile; proxied requests travel through the plugin's own CONNECT tunnel (no third-party HTTP stack), so the package installs fully offline.
|
|
18
|
-
- **
|
|
18
|
+
- **Framework-declared settings page** — the plugin exports its `Config` schema, so DSH serves the `dsh-github-router` namespace to the browser and the plugin's row on Settings → **Plugins** opens the page (secret token, proxy, route switches, cache TTLs, byte caps) with staged edits, override badges, and a write-only token control.
|
|
19
19
|
- **Context efficiency** — response caching with per-kind TTLs, byte caps everywhere, list caps with truncation notes, and rate-limit surfacing.
|
|
20
20
|
|
|
21
21
|
## Requirements
|
|
22
22
|
|
|
23
|
-
- Node.js >=
|
|
24
|
-
-
|
|
23
|
+
- Node.js >= 22.19
|
|
24
|
+
- DeepSeek Harness **0.1.7-rc.2**, with a profile composed from `@deepseek-ai/dsh-base` (it provides the `tools`, `subprocess`, `skills`, `settings`, and `credentials` services the plugin uses)
|
|
25
25
|
- Optional: the `gh` CLI (authenticated) for the gh route; `git` for the git route
|
|
26
26
|
|
|
27
27
|
## Install
|
|
@@ -48,12 +48,17 @@ Then **restart the DSH backend** — the host composition loads at process start
|
|
|
48
48
|
|
|
49
49
|
## Compatibility
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
This plugin tracks the DSH plugin API, which does not keep backward
|
|
52
|
+
compatibility between releases. Pick the plugin version that matches your
|
|
53
|
+
DeepSeek Harness release:
|
|
52
54
|
|
|
53
55
|
| DeepSeek Harness | Install |
|
|
54
|
-
|
|
56
|
+
|------------------| --- |
|
|
57
|
+
| 0.1.7-rc.2 | `dsh-github-router@0.4.0` or later |
|
|
58
|
+
| 0.1.2 ~ 0.1.6 | `dsh-github-router@0.3.2` |
|
|
55
59
|
| 0.1.1 or earlier | `dsh-github-router@0.2.1` |
|
|
56
|
-
|
|
60
|
+
|
|
61
|
+
The mapping is recorded in `package.json` under `dsh.compatibility.dshReleases`.
|
|
57
62
|
|
|
58
63
|
## Usage
|
|
59
64
|
|
|
@@ -85,14 +90,16 @@ Behavior notes:
|
|
|
85
90
|
|
|
86
91
|
## Configuration
|
|
87
92
|
|
|
88
|
-
Settings → **Plugins**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
Settings → **Plugins** → the **dsh-github-router** bundle → its row's
|
|
94
|
+
**Configure** control opens the plugin's page. The framework owns the frame:
|
|
95
|
+
it reads the schema this plugin exports, serves the `dsh-github-router`
|
|
96
|
+
namespace to the browser, and renders the save control. Fields the user
|
|
97
|
+
overrode are badged with a reset control, and clearing a field falls back to
|
|
98
|
+
the defaults below. The token is a write-only field: a blank draft keeps the
|
|
99
|
+
stored token, and the **Clear stored token** control stages the removal. The
|
|
100
|
+
same values can be set in the composition (profile `cordis.patch.yml`) as the
|
|
101
|
+
plugin's base config; the page overrides per user, and a saved value applies to
|
|
102
|
+
the next tool call.
|
|
96
103
|
|
|
97
104
|
| Field | Default | Meaning |
|
|
98
105
|
| --- | --- | --- |
|
|
@@ -122,9 +129,10 @@ Settings UI overrides per user.
|
|
|
122
129
|
| Path | Purpose |
|
|
123
130
|
| ---- | ------- |
|
|
124
131
|
| `cordis.patch.yml` | Profile patch layer inserting the `dsh-github-router` row |
|
|
125
|
-
| `lib/index.js` | Host plugin:
|
|
126
|
-
| `lib/client.js` | Browser half: the
|
|
127
|
-
| `lib/config.js` | Settings schema, defaults, runtime option resolution |
|
|
132
|
+
| `lib/index.js` | Host plugin: the `Config` schema export, five tools, skill, guidance |
|
|
133
|
+
| `lib/client.js` | Browser half: the row configuration page (hand-written factory bundle, no build step) |
|
|
134
|
+
| `lib/config.js` | Settings schema, defaults, live section reads, runtime option resolution |
|
|
135
|
+
| `lib/settings.js` | Host settings wiring: the plugin-owned page policy and the options thunk |
|
|
128
136
|
| `lib/net.js`, `lib/tunnel.js` | Route-aware HTTP layer; zero-dependency CONNECT proxy tunnel |
|
|
129
137
|
| `lib/routes/` | One module per route: `api` (GET-only REST), `gh` (CLI), `git` (protocol), `html` (page parse), `mirror` (raw mirrors) |
|
|
130
138
|
| `lib/core/` | Per-call runtime assembly and the `pr`/`issue`/`file`/`probe` aggregators |
|
package/README.zh.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> 为 DeepSeek Harness 项目提供只读的 GitHub 访问——通过内部多路由(API、gh CLI、git 协议、页面 HTML、镜像)的工具加载 PR、issue、文件与 API 数据,agent 不再需要在终端里反复对抗 TLS 或代理故障。
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
|
-
[](https://nodejs.org/)
|
|
9
9
|
[](https://www.npmjs.com/package/dsh-github-router)
|
|
10
10
|
|
|
11
11
|
一个 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件捆绑包,为 agent 提供无需终端重试的 GitHub 读取能力:
|
|
@@ -15,13 +15,12 @@
|
|
|
15
15
|
- **一次调用、结构化结果** —— PR 一次返回元数据、讨论、评审、提交、变更文件与 diff,每个部件标注来源路由;失败时返回路由矩阵,而不是十几条重试过的终端命令。
|
|
16
16
|
- **连通性探针** —— `github_probe` 一次调用报告宿主侧哪些路由存活,附耗时与推荐路由链。
|
|
17
17
|
- **零运行时依赖** —— peer 依赖由 DSH profile 解析;代理请求走插件自带的 CONNECT 隧道(不依赖第三方 HTTP 栈),因此可以完全离线安装。
|
|
18
|
-
-
|
|
18
|
+
- **框架级插件设置页** —— 设置 → **Plugins(插件)** → 本插件 bundle 的**行**上的「配置」控件打开插件页面(框架声明式配置:插件导出 `Config` schema,框架以 Loader entry id `dsh-github-router` 作为设置命名空间服务到浏览器、派生表单、校验并落盘写入,需要 DSH 0.1.7-rc.2;`dsh-github-router` 设置命名空间含 secret token、代理、路由开关、缓存 TTL、字节上限)。编辑本地暂存、保存才写入;被用户覆盖的字段带徽标与「恢复默认」控件;token 为只写字段,留空表示保持已存 token,页面提供「清除已保存的 token」控件。
|
|
19
19
|
- **上下文效率** —— 按类别 TTL 的响应缓存、全局字节上限、带截断注记的列表上限,以及限流余量提示。
|
|
20
20
|
|
|
21
21
|
## 环境要求
|
|
22
22
|
|
|
23
|
-
- Node.js >=
|
|
24
|
-
- 由 `@deepseek-ai/dsh-base` 组合的 DSH profile(提供插件使用的 `tools`、`subprocess`、`skills`、`settings`、`credentials` 服务)
|
|
23
|
+
- Node.js >= 22.19
|
|
25
24
|
- 可选:gh 路由需要已安装且认证的 `gh` CLI;git 路由需要 `git`
|
|
26
25
|
|
|
27
26
|
## 安装
|
|
@@ -50,12 +49,16 @@ dsh plugin --profile web add github:<owner>/dsh-github-router
|
|
|
50
49
|
|
|
51
50
|
## 兼容性
|
|
52
51
|
|
|
52
|
+
本插件跟随 DSH 的插件 API 走,而 DSH 在快速迭代,不保证跨版本兼容。
|
|
53
53
|
请选择与你的 DeepSeek Harness 版本匹配的插件版本:
|
|
54
54
|
|
|
55
|
-
| DeepSeek Harness | 安装
|
|
56
|
-
|
|
57
|
-
| 0.1.
|
|
58
|
-
| 0.1.2
|
|
55
|
+
| DeepSeek Harness | 安装 |
|
|
56
|
+
|------------------|-------------------------------|
|
|
57
|
+
| 0.1.7-rc.2 | `dsh-github-router@0.4.0` 或最新 |
|
|
58
|
+
| 0.1.2 ~ 0.1.6 | `dsh-github-router@0.3.2` |
|
|
59
|
+
| 0.1.1 及更早 | `dsh-github-router@0.2.1` |
|
|
60
|
+
|
|
61
|
+
该映射同时记录在 `package.json` 的 `dsh.compatibility.dshReleases` 中。
|
|
59
62
|
|
|
60
63
|
## 使用
|
|
61
64
|
|
|
@@ -87,12 +90,13 @@ github_api { path: "/repos/o/r/commits", query: { per_page: 5 } }
|
|
|
87
90
|
|
|
88
91
|
## 配置
|
|
89
92
|
|
|
90
|
-
设置 → **Plugins(插件)** →
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
`cordis.patch.yml
|
|
93
|
+
设置 → **Plugins(插件)** → `dsh-github-router` bundle → 该**行**上的
|
|
94
|
+
**配置**控件打开插件页面。页面外框由框架负责:它读取本插件导出的 schema、
|
|
95
|
+
把 `dsh-github-router` 命名空间服务到浏览器,并渲染保存控件。被用户覆盖的字段带徽标和「恢复默认」控件,清空字段即回退到下方
|
|
96
|
+
默认值。token 为只写字段:留空表示保持已存 token,「清除已保存的 token」
|
|
97
|
+
控件才会暂存删除并在保存时写入。同样的值也可以在组合(profile 的
|
|
98
|
+
`cordis.patch.yml`)中作为插件基础配置写入;页面按用户覆盖,且保存的值在
|
|
99
|
+
下一次工具调用即生效。
|
|
96
100
|
|
|
97
101
|
| 字段 | 默认 | 含义 |
|
|
98
102
|
| --- | --- | --- |
|
|
@@ -122,9 +126,10 @@ DSH ≥ 0.1.0-rc.7):编辑内容先本地暂存、点保存才落盘,被
|
|
|
122
126
|
| 路径 | 用途 |
|
|
123
127
|
| ---- | ---- |
|
|
124
128
|
| `cordis.patch.yml` | 插入 `dsh-github-router` 行的 profile patch 层 |
|
|
125
|
-
| `lib/index.js` |
|
|
126
|
-
| `lib/client.js` |
|
|
127
|
-
| `lib/config.js` | 设置 schema
|
|
129
|
+
| `lib/index.js` | 宿主插件:导出 `Config` schema、五个工具、技能、引导 |
|
|
130
|
+
| `lib/client.js` | 浏览器半边:行配置页(手写工厂包,无构建步骤) |
|
|
131
|
+
| `lib/config.js` | 设置 schema、默认值、实时读取、运行时选项解析 |
|
|
132
|
+
| `lib/settings.js` | 宿主设置接线:插件自有页面策略与 options thunk |
|
|
128
133
|
| `lib/net.js`、`lib/tunnel.js` | 路由感知 HTTP 层;零依赖 CONNECT 代理隧道 |
|
|
129
134
|
| `lib/routes/` | 每条路由一个模块:`api`(GET-only REST)、`gh`(CLI)、`git`(协议)、`html`(页面解析)、`mirror`(raw 镜像) |
|
|
130
135
|
| `lib/core/` | 每次调用的运行时装配与 `pr`/`issue`/`file`/`probe` 聚合器 |
|
package/docs/design.md
CHANGED
|
@@ -107,52 +107,58 @@ substitute bytes. When enabled, each configured base yields two candidates
|
|
|
107
107
|
per file (raw passthrough and the `github.com` `/raw/` route), tried in
|
|
108
108
|
order.
|
|
109
109
|
|
|
110
|
-
## Settings
|
|
111
|
-
|
|
112
|
-
The
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
110
|
+
## Settings page
|
|
111
|
+
|
|
112
|
+
The plugin exports its `Config` schema from the Loader entry (`lib/index.js`
|
|
113
|
+
re-exports `lib/config.js`). DSH reads that schema, serves the entry id
|
|
114
|
+
(`dsh-github-router`, the row `cordis.patch.yml` inserts) as the settings
|
|
115
|
+
namespace, derives the page and its form from the schema, validates and
|
|
116
|
+
persists every write with revision fencing, redacts `role('secret')` fields on
|
|
117
|
+
each wire boundary, and hands the Host half Volatile references for the live
|
|
118
|
+
values. There is no registration call. `lib/settings.js` keeps the two
|
|
119
|
+
plugin-owned pieces: `settings.configure({ auto: false }, ctx.fiber)` (the
|
|
120
|
+
plugin ships its own page, so the framework generates none) and the
|
|
121
|
+
`options()` thunk, which reads the live section per call so a saved value
|
|
122
|
+
applies to the next tool call.
|
|
122
123
|
|
|
123
124
|
### Framework transport
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
`
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
126
|
+
The browser half (`lib/client.js`, a hand-written ModuleLoader factory bundle
|
|
127
|
+
with no build step) registers one page into the Plugins page's
|
|
128
|
+
`plugins.row.config` slot, keyed `<package name>#<row id>`
|
|
129
|
+
(`dsh-github-router#dsh-github-router`): the bundle's row gains a **Configure**
|
|
130
|
+
control that opens the page, and the entry's `view: 'summary'` answers the
|
|
131
|
+
row's one-liner. The slot is declared and dispatched by the Plugins page, so
|
|
132
|
+
the page exists while the Host serves the namespace and disappears with it
|
|
133
|
+
(`ctx.configForms.whileServed`). Reads and writes ride the shared configuration
|
|
134
|
+
form for the entry, `ctx.configForms.get('dsh-github-router')`, whose snapshot
|
|
135
|
+
carries the redacted resolved section
|
|
136
|
+
(`status`/`value`/`base`/`user`/`revision`/`writable`/`mode`) and whose
|
|
137
|
+
`set`/`unset`/`mutate` queue revision-fenced writes with recovery re-reads. All
|
|
138
|
+
of it derives from one shared describe mirror that refreshes on
|
|
139
|
+
`settings/document-updated` and `connection/reset`, so a Host restart no longer
|
|
140
|
+
strands the form in a failed state. No plugin-owned HTTP route exists.
|
|
141
|
+
|
|
142
|
+
### Page form
|
|
139
143
|
|
|
140
144
|
Edits are staged locally and written only on save, one field per
|
|
141
|
-
`scope.set`/`scope.unset`; after each write the card verifies the user
|
|
142
|
-
|
|
143
|
-
Secret fields never ride a response, so the token
|
|
144
|
-
its configured state comes from the describe mirror's
|
|
145
|
-
(the snapshot itself redacts
|
|
146
|
-
|
|
147
|
-
and a blank draft
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
`scope.set`/`scope.unset`; after each write the card verifies the user layer
|
|
146
|
+
(JSON-shaped deep equality) and keeps drafts that did not land. Leaving the
|
|
147
|
+
page drops every staged edit. Secret fields never ride a response, so the token
|
|
148
|
+
control is write-only: its configured state comes from the describe mirror's
|
|
149
|
+
secret-slot list (`ctx.configForms.describe()`, the snapshot itself redacts the
|
|
150
|
+
value from every layer), a typed value writes the token through the shared form
|
|
151
|
+
(the one direction secrets cross the wire), and a blank draft deliberately
|
|
152
|
+
writes nothing — the explicit **Clear stored token** control stages the `unset`
|
|
153
|
+
that removes a configured token.
|
|
154
|
+
|
|
155
|
+
Because the shared form writes **scalar fields by name**, the settings schema
|
|
156
|
+
is deliberately flat (`routesApi`, `cacheTtlMeta`, …); the Host projects it
|
|
151
157
|
into the nested runtime shape (`routes.api`, `cacheTtlSeconds.meta`) in
|
|
152
|
-
`resolveOptions`. The composition layer can still carry the same flat
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
`resolveOptions`. The composition layer can still carry the same flat keys. The
|
|
159
|
+
page shows the common fields up top (token, proxy, main route switches) and the
|
|
160
|
+
long tail (timeouts, retries, cache TTLs, mirrors, repos, git cache dir) in a
|
|
161
|
+
collapsed "Advanced settings" disclosure.
|
|
156
162
|
|
|
157
163
|
## Cache
|
|
158
164
|
|
|
@@ -189,9 +195,11 @@ within one host process.
|
|
|
189
195
|
|
|
190
196
|
## Known limitations
|
|
191
197
|
|
|
192
|
-
- **Fallback routes are
|
|
193
|
-
|
|
194
|
-
(
|
|
198
|
+
- **Fallback routes are failover, not fan-out.** A ladder is entered only
|
|
199
|
+
when a part could not be fetched by the route above it: a successfully
|
|
200
|
+
fetched empty list (an issue with no comments, a PR with no reviews) is
|
|
201
|
+
authoritative and does not trigger gh/html/git, saving quota. Forcing a
|
|
202
|
+
specific route per call is not yet supported.
|
|
195
203
|
- **Anonymous quota is shared per IP** (60 req/h). A PR aggregation costs
|
|
196
204
|
up to six calls. Token configuration is the intended mitigation; the
|
|
197
205
|
cache is the second line.
|