dsh-opencode-go 0.1.19 → 0.1.20
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 +4 -2
- package/README.md +4 -2
- package/docs/verification.md +18 -0
- package/lib/client.js +17 -3
- package/lib/types/client/staged-form.d.ts +8 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -86,7 +86,7 @@ To build from source and install a local package:
|
|
|
86
86
|
npm ci
|
|
87
87
|
npm run compile
|
|
88
88
|
npm pack
|
|
89
|
-
dsh plugin --profile web add ./dsh-opencode-go-0.1.
|
|
89
|
+
dsh plugin --profile web add ./dsh-opencode-go-0.1.20.tgz
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
Source development builds the plugin explicitly with `npm run compile`; `--legacy-peer-deps` is not required. Multi-version DSH compatibility tests use independent environments and are not installed during ordinary installation or builds. For Headless, replace `web` with `headless`.
|
|
@@ -97,7 +97,7 @@ Source development builds the plugin explicitly with `npm run compile`; `--legac
|
|
|
97
97
|
npm run compile # Regenerate lib/ and commit it with source changes
|
|
98
98
|
npm test # Core tests, rebuilding the plugin first
|
|
99
99
|
npm run check:dist # Verify shipped artifacts match the source
|
|
100
|
-
npm run test:compat # One tarball tested in
|
|
100
|
+
npm run test:compat # One tarball tested in 9 independent DSH environments
|
|
101
101
|
npm run test:install # npm / pnpm Git installs without plugin build approval
|
|
102
102
|
npm run verify # All of the above
|
|
103
103
|
```
|
|
@@ -114,6 +114,8 @@ dsh plugin --profile web update dsh-opencode-go --latest
|
|
|
114
114
|
|
|
115
115
|
Restart `dsh web` and refresh the browser afterwards. For Headless, replace `web` with `headless`; if both profiles have the plugin installed, update each one separately.
|
|
116
116
|
|
|
117
|
+
After updating the desktop plugin, fully quit and reopen DeepSeek Harness to load the updated plugin code.
|
|
118
|
+
|
|
117
119
|
## Subscription usage display
|
|
118
120
|
|
|
119
121
|
Under **Settings → OpenCode Go → Advanced settings → Usage display**, choose a mode and save: **Auto (default)** shows the pill only for this plugin's DSH OpenCode Go models; **Always** keeps it visible with other models, including the built-in `opencode-go` provider; **Off** hides it and stops polling. Disabling OpenCode Go hides the pill in every mode. Click the pill to open the usage panel.
|
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ dsh --profile headless --patch ./headless.patch.yml "你好"
|
|
|
86
86
|
npm ci
|
|
87
87
|
npm run compile
|
|
88
88
|
npm pack
|
|
89
|
-
dsh plugin --profile web add ./dsh-opencode-go-0.1.
|
|
89
|
+
dsh plugin --profile web add ./dsh-opencode-go-0.1.20.tgz
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
源码开发时显式运行 `npm run compile`;普通用户直接安装预编译产物,无需 `--legacy-peer-deps`。多版本 DSH 兼容性测试使用独立环境,不参与普通安装或构建。Headless 用户将 `web` 换成 `headless`。
|
|
@@ -97,7 +97,7 @@ dsh plugin --profile web add ./dsh-opencode-go-0.1.19.tgz
|
|
|
97
97
|
npm run compile # 更新 lib/,与源码一起提交
|
|
98
98
|
npm test # 基础功能测试(自动重新构建)
|
|
99
99
|
npm run check:dist # 检查已提交产物是否与源码一致
|
|
100
|
-
npm run test:compat # 同一安装包在
|
|
100
|
+
npm run test:compat # 同一安装包在 9 套独立 DSH 环境中测试
|
|
101
101
|
npm run test:install # npm / pnpm 无额外构建授权的 Git 安装检查
|
|
102
102
|
npm run verify # 执行以上全部检查
|
|
103
103
|
```
|
|
@@ -114,6 +114,8 @@ dsh plugin --profile web update dsh-opencode-go --latest
|
|
|
114
114
|
|
|
115
115
|
完成后重启 `dsh web` 并刷新浏览器。Headless 用户将 `web` 换成 `headless`;如果两个 profile 都安装了插件,需要分别升级。
|
|
116
116
|
|
|
117
|
+
桌面版升级后,请完全退出并重新打开 DeepSeek Harness,以加载更新后的插件代码。
|
|
118
|
+
|
|
117
119
|
## 订阅用量显示
|
|
118
120
|
|
|
119
121
|
在「设置 → OpenCode Go → 高级设置 → 额度显示」中选择并保存:**自动(默认)**仅在选中本插件的 DSH OpenCode Go 模型时显示;**常驻**在使用其他模型(包括宿主自带的 `opencode-go`)时也显示;**关闭**隐藏胶囊并停止轮询。停用 OpenCode Go 后所有模式均隐藏。显示时点击胶囊展开用量面板。
|
package/docs/verification.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Verification
|
|
2
2
|
|
|
3
|
+
## Release 0.1.20: usage pill and settings draft fixes (2026-10-02)
|
|
4
|
+
|
|
5
|
+
The release includes the Host scope receiver fix and shared no-op draft predicate from PR #34. The installed-client compatibility fixture now reads instance state and exercises both SSR snapshot reads and client subscription cleanup. Desktop follow-up confirmed that saving Always works after restarting a Host process that predated the installed plugin update; the upgrade instructions now explicitly require quitting and reopening desktop Harness.
|
|
6
|
+
|
|
7
|
+
On macOS / Node 24.14.1, `DSH_COMPAT_CONCURRENCY=4 npm run verify` passed **401 tests in 28 files**, freshness checks for **34 shipped build files**, **all nine installed-host generations**, and both **npm and pnpm Git installation checks**. The compatibility run took **87.9 seconds** including cleanup; installation checks took **11.8 seconds**. Both installation paths loaded the shipped artifacts without source builds or plugin build approval and retained the private pi-ai 0.87.1 alongside the independent peer's 0.85.1. The test suite used local gateways and isolated consumers.
|
|
8
|
+
|
|
9
|
+
## Usage pill rendering on a real Host and the staged override badge (2026-10-02)
|
|
10
|
+
|
|
11
|
+
The browser half no longer hands the Host settings scope's methods over as plain values. `UsagePill` subscribed with `useSyncExternalStore(settings.subscribe, settings.getSnapshot, ...)`, and a Host scope is a class instance whose methods read their own state (`ConfigFormController` behind `ctx.configForms.get(entryId)`, `SettingsScopeController` behind `ctx.settingsScope.bind(spec)`); both providers return that instance as-is. The detached reference lost its receiver, so the pill threw `TypeError: Cannot read properties of undefined (reading 'store')` on its first render, the slot's per-entry error boundary removed it, and no usage mode could ever show a pill — including Always, which is why a saved `usageDisplay: always` had no visible effect. React now reaches the scope through `useCallback` wrappers, the same shape the Host's own slot outlet uses.
|
|
12
|
+
|
|
13
|
+
The staged form's override badge now answers for the same state its save plan does. `plan` skipped a draft equal to the field's effective value while `field` reported it as an override, so a value typed back to its original (`60 → 59 → 60`) disabled Save and Discard yet kept the "overridden" badge, its reset button, and the advanced card's badge. Both paths now share one `unchangedDraft` predicate: a no-op draft reports whatever the user layer already holds, a clear still previews as not overridden, and an invalid draft still blocks the save.
|
|
14
|
+
|
|
15
|
+
Before the fix, `npx vitest run tests/usage-pill.client.spec.tsx tests/stores.client.spec.ts` failed 25 of 54 cases: all **24** usage-pill cases (including the new receiver case) with the detached-call `TypeError`, and the new no-op-draft case on `overridden`. The test double now keeps its scope methods on the prototype (`tests/support/settings-scope.ts`) and the installed-host fixture builds the same class shape, so a method passed as a value fails in tests exactly as it failed in a browser; before this change every double used arrow-function literals, which is what hid the regression from the suite and from the `v020-rc2` compatibility row.
|
|
16
|
+
|
|
17
|
+
Host/Client type checks and production compilation passed; `npm run test:ci` passed **401 tests in 28 files** and freshness checks for all **34 shipped artifacts** on Windows / Node 24.15.0. `DSH_COMPAT_CONCURRENCY=1 npm run test:compat -- v020-rc2 v017-rc2` passed both installed generations — 0.2.0-rc.2 and 0.1.7-rc.2 (both use the `configForms` path) — including the client fixture's module table, settings binding, rendering, CSS and cleanup. On this machine the client fixture also exceeded the runner's 30-second per-fixture limit before this change, so the two local rows ran with that limit temporarily raised to 180 seconds; the committed limit is unchanged. The other seven host generations, macOS and Linux, and a live Desktop session were not exercised. Every check used loopback fixtures; no installed user profile, GitHub issue or npm publication was changed.
|
|
18
|
+
|
|
19
|
+
Follow-up on macOS / Node 24.14.1: the installed-host fixture now reads `this.snapshot` and `this.listeners`; prototype methods that only closed over local variables still allowed detached calls. Its SSR checks exercise the snapshot reader, and a client mount/unmount now checks the scope subscription and cleanup while Auto keeps the pill hidden. The receiver unit case also checks a live display change and subscription disposal. Two temporary negative-control bundles failed as expected: the original detached snapshot reader threw on `snapshot`, and a client with only the subscription detached threw on `listeners`; the fixed bundle passed. Both type checks, **401 tests in 28 files**, all **34 shipped artifacts**, and **all nine installed-host generations** passed. The compatibility run took **88.2 seconds** including cleanup, with the committed 30-second fixture limit unchanged. The matrix exercises legacy `settingsScope` on 0.1.5/0.1.6 and `configForms` on 0.1.7/0.2. No live Desktop UI or installed user profile was exercised.
|
|
20
|
+
|
|
3
21
|
## Release 0.1.19: consolidate pending features (2026-10-02)
|
|
4
22
|
|
|
5
23
|
The prepared-call configuration, Anthropic alias replay and usage-display changes are now integrated with 0.1.18's MiMo controls. Prepared calls retain the captured endpoint, credential reference and nested capacities; later calls use updated settings. Anthropic replay preserves signed thinking against the requested model ID. Settings now offer Auto / Always / Off usage visibility, with Off and a disabled plugin stopping the poller. The existing default remains Auto.
|
package/lib/client.js
CHANGED
|
@@ -932,7 +932,9 @@ var StagedForm = class {
|
|
|
932
932
|
const write = staged.clear ? { kind: "clear" } : spec.parse(staged.text);
|
|
933
933
|
return {
|
|
934
934
|
text: staged.text,
|
|
935
|
-
|
|
935
|
+
// A draft a save would skip leaves the user layer exactly as it stands, so
|
|
936
|
+
// the badge answers for that standing override instead of the edit.
|
|
937
|
+
overridden: this.unchangedDraft(field, staged) ? this.stored(field) : write?.kind === "set",
|
|
936
938
|
invalid: write === void 0
|
|
937
939
|
};
|
|
938
940
|
}
|
|
@@ -1003,7 +1005,7 @@ var StagedForm = class {
|
|
|
1003
1005
|
if (this.stored(field)) plan.push({ field, run: () => this.clear(field) });
|
|
1004
1006
|
continue;
|
|
1005
1007
|
}
|
|
1006
|
-
if (
|
|
1008
|
+
if (this.unchangedDraft(field, staged)) continue;
|
|
1007
1009
|
const write = spec.parse(staged.text);
|
|
1008
1010
|
if (write === void 0) plan.push({ field, run: void 0 });
|
|
1009
1011
|
else if (write.kind === "clear") plan.push({ field, run: () => this.clear(field) });
|
|
@@ -1045,6 +1047,16 @@ var StagedForm = class {
|
|
|
1045
1047
|
const user = this.userLayer();
|
|
1046
1048
|
return user !== void 0 && Object.hasOwn(user, field);
|
|
1047
1049
|
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Whether a draft already equals the field's effective value, so a save would
|
|
1052
|
+
* write nothing. The save plan and the override badge both answer for it.
|
|
1053
|
+
* @param field - field name inside the namespace section.
|
|
1054
|
+
* @param staged - the staged edit to test.
|
|
1055
|
+
* @returns true when the draft is a no-op; a clear is never one.
|
|
1056
|
+
*/
|
|
1057
|
+
unchangedDraft(field, staged) {
|
|
1058
|
+
return !staged.clear && staged.text === this.spec(field).format(this.sectionValue(field));
|
|
1059
|
+
}
|
|
1048
1060
|
publish() {
|
|
1049
1061
|
for (const listener of this.listeners) listener();
|
|
1050
1062
|
}
|
|
@@ -1690,7 +1702,9 @@ function usageLevel(window) {
|
|
|
1690
1702
|
}
|
|
1691
1703
|
function UsagePill({ directory, settings, ...props }) {
|
|
1692
1704
|
const state = (0, import_react3.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
|
|
1693
|
-
const
|
|
1705
|
+
const readSettings = (0, import_react3.useCallback)(() => settings.getSnapshot(), [settings]);
|
|
1706
|
+
const subscribeSettings = (0, import_react3.useCallback)((listener) => settings.subscribe(listener), [settings]);
|
|
1707
|
+
const config = (0, import_react3.useSyncExternalStore)(subscribeSettings, readSettings, readSettings);
|
|
1694
1708
|
const mode = config.value?.usageDisplay ?? DEFAULT_USAGE_DISPLAY;
|
|
1695
1709
|
const visible = config.status === "ready" && config.value?.enabled !== false && (mode === "always" || mode === "auto" && state.current?.provider === PROVIDER_ID);
|
|
1696
1710
|
return visible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActiveUsage, { ...props }) : null;
|
|
@@ -191,5 +191,13 @@ export declare class StagedForm {
|
|
|
191
191
|
private baseValue;
|
|
192
192
|
private userLayer;
|
|
193
193
|
private stored;
|
|
194
|
+
/**
|
|
195
|
+
* Whether a draft already equals the field's effective value, so a save would
|
|
196
|
+
* write nothing. The save plan and the override badge both answer for it.
|
|
197
|
+
* @param field - field name inside the namespace section.
|
|
198
|
+
* @param staged - the staged edit to test.
|
|
199
|
+
* @returns true when the draft is a no-op; a clear is never one.
|
|
200
|
+
*/
|
|
201
|
+
private unchangedDraft;
|
|
194
202
|
private publish;
|
|
195
203
|
}
|