@mars-sea/dsh-commandcode-provider 0.9.1 → 0.10.0-alpha.1

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
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.10.0-alpha.1] - 2026-09-01
10
+
11
+ > **Alpha channel for dsh 0.1.2-alpha.2.** This release requires **dsh 0.1.2-alpha.2 or later** and is published under the `alpha` npm tag, so `@latest` stays on 0.9.1 for older Harness releases. Install it explicitly with `@alpha`.
12
+
13
+ ### Changed
14
+
15
+ - **Raised the minimum supported DeepSeek Harness version to 0.1.2-alpha.2.** Every Harness peer and development package now starts at the alpha.2 line; earlier RC/alpha builds use incompatible Host and browser APIs and are no longer advertised as supported.
16
+ - **Adapted the provider to the 0.1.2-alpha.2 Host and browser contracts.** Tool-call IDs use `ToolCallId`, settings register through the optional `SettingsProvider` service, credential operations use Typert Remotes, and the browser client consumes the current settings/models surfaces without the removed `dsh-client-runtime` package.
17
+
18
+ ### Fixed
19
+
20
+ - **Restored fresh plugin-marketplace installs under pnpm 10.** The package declares `@deepseek-ai/dsh-invariants` as an explicit alpha.2 Host peer instead of bundling a second Harness core package; a pnpm 10.34.5 tarball-install smoke test pins the isolated-generation path.
21
+ - **Kept the Web client enabled on alpha.2.** The client no longer requests the removed `dsh-client-runtime/client` module, while its React, slot, store, and primitive dependencies match the official alpha.2 platform module table; settings and Models pages therefore remain available instead of disabling the entire client bundle.
22
+ - **Isolated snapshot subscriber failures.** The client-local `getSnapshot`/`subscribe`/`set` store now continues notifying remaining UI consumers when one subscriber throws.
23
+ - **Prevented the friendly image-session error wrapper from blocking alpha.2 client startup.** Alpha.2 no longer exposes `connection.api.sessions`, so the optional copy rewrite safely skips itself when that legacy façade is absent.
24
+
9
25
  ## [0.9.1] - 2026-08-28
10
26
 
11
27
  ### Added
package/README.md CHANGED
@@ -18,7 +18,7 @@ Unofficial [DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harnes
18
18
 
19
19
  - **Plugin bundle** — install into any dsh profile with `dsh plugin add`; registers a `commandcode` provider route with a live model catalog.
20
20
  - **Dedicated settings page** — API key, connection options, a live account-usage card, and a "Hide out-of-plan models" toggle.
21
- - **Models-page key card** — on dsh 0.1.2-alpha.1 and later, the **Settings → Models → Command Code** card carries the key status, a paste field, and the sign-in button inline; on older dsh builds it is simply absent and the dedicated page remains the surface.
21
+ - **Models-page key card** — the **Settings → Models → Command Code** card carries the key status, a paste field, and the sign-in button inline.
22
22
  - **In-browser sign-in for keys** — start the official authorization flow (the same one `cmd login` runs) from the settings page; the approved key lands in the local credential service automatically. Manual paste remains the fallback.
23
23
  - **Multi-account rotation** — when one account hits its usage limit, requests switch to the next account automatically. See [Account rotation](#account-rotation).
24
24
  - **Flexible API key setup** — via the settings page, an environment variable, or the official CLI login file.
@@ -31,14 +31,31 @@ See [Screenshots](#screenshots) below for what the UI looks like.
31
31
 
32
32
  ## Install
33
33
 
34
- ```sh
35
- dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@latest
36
- ```
34
+ Pick the release line that matches your DeepSeek Harness version:
35
+
36
+ - **dsh 0.1.2-alpha.2 or later** (the current alpha line) — use the matching alpha plugin release. Install explicitly with the `alpha` tag:
37
+
38
+ ```sh
39
+ dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@alpha
40
+ ```
41
+
42
+ - **Older dsh releases** (the 0.5.0 line and earlier, which use the rc-era Host/browser APIs) — the 0.9.1 plugin keeps working there and stays on the `latest` tag:
43
+
44
+ ```sh
45
+ dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@latest
46
+ ```
47
+
48
+ > The `alpha` tag never moves `latest`: a plain `@latest` install always gets the newest stable release for older Harness versions, and upgrading to the alpha line is always an explicit opt-in.
49
+
50
+ Fresh pnpm 10 marketplace generations are supported directly. Do not add a separate `@deepseek-ai/dsh-invariants` dependency; the plugin declares it as a Host peer so the active dsh profile remains the owner of Harness packages.
37
51
 
38
52
  ## Updating
39
53
 
54
+ Update with the same tag you installed with:
55
+
40
56
  ```sh
41
- dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest
57
+ dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@alpha # dsh 0.1.2-alpha.2+
58
+ dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest # older dsh (0.5.0 line)
42
59
  ```
43
60
 
44
61
  Then restart the web app.
package/README.zh-CN.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  - **插件包**:一条 `dsh plugin add` 命令安装到任意 dsh 配置,注册 `commandcode` provider 路由,带实时模型目录。
20
20
  - **专属设置页**:API key 输入、连接参数、实时「账户用量」卡片和「隐藏套餐外模型」开关。
21
- - **Models 页快捷卡片**:在 dsh 0.1.2-alpha.1 及以上版本,**设置 → Models → Command Code** 卡片内直接显示 key 状态、粘贴输入框和登录按钮;旧版 dsh 上该卡片不出现,一切照旧走专属设置页。
21
+ - **Models 页快捷卡片**:**设置 → Models → Command Code** 卡片内直接显示 key 状态、粘贴输入框和登录按钮。
22
22
  - **浏览器内登录获取 key**:设置页一键发起官方授权(与 `cmd login` 同一流程),完成后密钥自动写入本机凭据服务,无需手动创建或粘贴;不可用时随时退回手动粘贴。
23
23
  - **多账户轮换**:一个账户用量打满后,请求自动切换到下一个账户。详见[多账户轮换](#多账户轮换)。
24
24
  - **key 配置灵活**:设置页填写、环境变量或官方 CLI 登录文件均可。
@@ -29,14 +29,31 @@
29
29
 
30
30
  ## 安装
31
31
 
32
- ```sh
33
- dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@latest
34
- ```
32
+ 按你的 DeepSeek Harness 版本选择对应的发布线:
33
+
34
+ - **dsh 0.1.2-alpha.2 或更高版本**(当前 alpha 线)——使用配套的 alpha 插件版本,显式用 `alpha` tag 安装:
35
+
36
+ ```sh
37
+ dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@alpha
38
+ ```
39
+
40
+ - **更早的 dsh 版本**(0.5.0 线及更早,使用 rc 时代的 Host/浏览器 API)——0.9.1 插件在这些版本上继续可用,并保持在 `latest` tag:
41
+
42
+ ```sh
43
+ dsh plugin --profile web add @mars-sea/dsh-commandcode-provider@latest
44
+ ```
45
+
46
+ > `alpha` tag 永远不会移动 `latest`:普通的 `@latest` 安装始终为旧版 dsh 拿到最新的稳定版,升级到 alpha 线永远是显式选择。
47
+
48
+ 插件可直接在 pnpm 10 的全新插件市场 generation 中安装。不要另行添加 `@deepseek-ai/dsh-invariants` dependency;插件已将其声明为 Host peer,Harness 包仍由当前 dsh profile 统一管理。
35
49
 
36
50
  ## 更新
37
51
 
52
+ 用与安装时相同的 tag 更新:
53
+
38
54
  ```sh
39
- dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest
55
+ dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@alpha # dsh 0.1.2-alpha.2 及以上
56
+ dsh plugin --profile web update @mars-sea/dsh-commandcode-provider@latest # 更早的 dsh(0.5.0 线)
40
57
  ```
41
58
 
42
59
  然后重启 Web 应用。
package/lib/client.js CHANGED
@@ -4,10 +4,38 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
8
7
  let react = require("react");
9
8
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/client/snapshot-store.ts
11
+ /** Notify every subscriber without letting one faulty UI consumer suppress the rest. */
12
+ function notifyListeners(listeners) {
13
+ for (const listener of listeners) try {
14
+ listener();
15
+ } catch (error) {
16
+ console.error("[dsh-commandcode-provider] snapshot subscriber failed:", error);
17
+ }
18
+ }
19
+ /** Create one observable snapshot store. */
20
+ function createSnapshotStore(initial) {
21
+ let snapshot = initial;
22
+ const listeners = /* @__PURE__ */ new Set();
23
+ return {
24
+ getSnapshot: () => snapshot,
25
+ subscribe(listener) {
26
+ listeners.add(listener);
27
+ return () => {
28
+ listeners.delete(listener);
29
+ };
30
+ },
31
+ set(value) {
32
+ if (Object.is(value, snapshot)) return;
33
+ snapshot = value;
34
+ notifyListeners(listeners);
35
+ }
36
+ };
37
+ }
38
+ //#endregion
11
39
  //#region src/command-locales.ts
12
40
  const commandcodeCommand = {
13
41
  zh: {
@@ -137,12 +165,49 @@ window.__ModuleLoader__.load({
137
165
  }
138
166
  };
139
167
  }
140
- /** Install the wrapper on a connection's shared sessions face. */
168
+ /**
169
+ * Install the friendly-error wrapper when a legacy sessions face is present.
170
+ *
171
+ * @returns whether the wrapper was installed. The rewrite is only UX polish;
172
+ * a 0.1.2 connection has no `api.sessions`, and its absence must never block
173
+ * the plugin from mounting its settings, credential, or usage surfaces.
174
+ */
141
175
  function installFriendlyImageError(connection, getLocale) {
142
- connection.api.sessions = withFriendlyImageError(connection.api.sessions, getLocale);
176
+ const api = connection.api;
177
+ const sessions = api?.sessions;
178
+ if (api === void 0 || sessions === void 0 || typeof sessions.selectModel !== "function") return false;
179
+ api.sessions = withFriendlyImageError(sessions, getLocale);
180
+ return true;
143
181
  }
144
182
  //#endregion
145
183
  //#region src/client/settings.ts
184
+ /**
185
+ * Browser controller for the "Command Code" settings page.
186
+ *
187
+ * The page lives at the same settings-nav level as General / Models / Plugins
188
+ * (a `settings.section` entry, id `commandcode`). It exists because the
189
+ * Models page renders an unknown-adapter-family card for the `commandcode`
190
+ * provider and deliberately disables its submit — the API key cannot be
191
+ * configured there. This page owns the connection facts the plugin resolves
192
+ * per request:
193
+ *
194
+ * - API key -> written through the credentials domain under the reference
195
+ * the plugin resolves (`apiKeyEnv`, default
196
+ * `COMMANDCODE_API_KEY`). The literal never rides a response,
197
+ * so the control only reports whether one is configured.
198
+ * - API base -> the `llm-commandcode` settings namespace (`apiBase`), same
199
+ * namespace the Models page card addresses.
200
+ * - Working dir, request/stream timeouts -> the same namespace.
201
+ *
202
+ * The controller mirrors the plugin-card pattern from the harness's own
203
+ * settings UI: it binds the `llm-commandcode` namespace through the
204
+ * `settingsScope` service, keeps a staged draft of edits, and writes them on
205
+ * save through `scope.set` / the credentials domain. The Host stays the
206
+ * single fact source; the snapshot is republished after each accepted write.
207
+ *
208
+ * This module is deliberately free of JSX — it only produces the state face
209
+ * the React component renders.
210
+ */
146
211
  /** The settings namespace the plugin registers (host half, src/index.ts). */
147
212
  const COMMANDCODE_NS = "llm-commandcode";
148
213
  /** Default credential reference the plugin resolves when none is named. */
@@ -607,10 +672,7 @@ window.__ModuleLoader__.load({
607
672
  /** Write one account's key, then re-read the Host's credential states. */
608
673
  async writeKeyTo(ref, value) {
609
674
  try {
610
- if (!(await this.api.credentials.set({
611
- ref,
612
- value
613
- })).result.ok) return false;
675
+ if (!(await this.api.credentials.set(ref, value)).ok) return false;
614
676
  } catch {
615
677
  return false;
616
678
  }
@@ -626,14 +688,14 @@ window.__ModuleLoader__.load({
626
688
  ];
627
689
  let response;
628
690
  try {
629
- response = await this.api.credentials.describe({ refs });
691
+ response = await this.api.credentials.describe(refs);
630
692
  } catch {
631
693
  return;
632
694
  }
633
- if (!response.result.ok) return;
695
+ if (!response.ok) return;
634
696
  let changed = false;
635
697
  for (const ref of refs) {
636
- const view = response.result.value.credentials[ref];
698
+ const view = response.value?.[ref];
637
699
  const next = {
638
700
  configured: view?.configured ?? false,
639
701
  writable: view?.writable ?? true
@@ -711,7 +773,7 @@ window.__ModuleLoader__.load({
711
773
  /** Unset one stored credential, then re-read the Host's credential states. */
712
774
  async unsetKey(ref) {
713
775
  try {
714
- if (!(await this.api.credentials.unset({ ref })).result.ok) return false;
776
+ if (!(await this.api.credentials.unset(ref)).ok) return false;
715
777
  } catch {
716
778
  return false;
717
779
  }
@@ -751,6 +813,47 @@ window.__ModuleLoader__.load({
751
813
  }
752
814
  };
753
815
  //#endregion
816
+ //#region src/client/legacy-credentials.ts
817
+ /** Convert a legacy credentials ApiProxy into the current settings-page face. */
818
+ function adaptLegacyCredentials(legacy) {
819
+ if (legacy === void 0) return void 0;
820
+ return { credentials: {
821
+ describe: async (refs) => {
822
+ const response = await legacy.describe({ refs });
823
+ return response.result.ok ? {
824
+ ok: true,
825
+ value: response.result.value.credentials
826
+ } : {
827
+ ok: false,
828
+ error: response.result.error
829
+ };
830
+ },
831
+ set: async (ref, value) => {
832
+ const response = await legacy.set({
833
+ ref,
834
+ value
835
+ });
836
+ return response.result.ok ? {
837
+ ok: true,
838
+ value: void 0
839
+ } : {
840
+ ok: false,
841
+ error: response.result.error
842
+ };
843
+ },
844
+ unset: async (ref) => {
845
+ const response = await legacy.unset({ ref });
846
+ return response.result.ok ? {
847
+ ok: true,
848
+ value: void 0
849
+ } : {
850
+ ok: false,
851
+ error: response.result.error
852
+ };
853
+ }
854
+ } };
855
+ }
856
+ //#endregion
754
857
  //#region src/client/usage.ts
755
858
  const IDLE = {
756
859
  status: "idle",
@@ -1299,7 +1402,7 @@ window.__ModuleLoader__.load({
1299
1402
  };
1300
1403
  //#endregion
1301
1404
  //#region package.json
1302
- var version = "0.9.1";
1405
+ var version = "0.10.0-alpha.1";
1303
1406
  var repository = {
1304
1407
  "type": "git",
1305
1408
  "url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
@@ -2538,7 +2641,7 @@ window.__ModuleLoader__.load({
2538
2641
  /**
2539
2642
  * The Command Code provider card inside the harness Models settings page
2540
2643
  * (browser half). Rendered through the `settings.models.provider-card` keyed
2541
- * slot introduced in dsh 0.1.2-alpha.1, registered with
2644
+ * slot available in dsh 0.1.2-alpha.2, registered with
2542
2645
  * `entryKey = 'llm-commandcode'` (the plugin's settings namespace, the key the
2543
2646
  * Models page dispatches for every Command Code provider row).
2544
2647
  *
@@ -3128,25 +3231,38 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
3128
3231
  document.head.appendChild(tag);
3129
3232
  }
3130
3233
  /**
3131
- * Client plugin body. Gates on the services the settings page needs
3132
- * (`slots`, `locale`, `connection`, `remote`, `settingsScope`) plus the
3133
- * `connection` used by the friendly-error wrapper the same inject list the
3134
- * harness's own settings-surface plugins declare.
3234
+ * Client plugin body. Gates on the services shared by both client generations
3235
+ * (`slots`, `locale`, `connection`, `remote`, `settingsScope`). Current clients
3236
+ * mount the page after `remote.credentials` appears; legacy clients mount it
3237
+ * from the connection ApiProxy credential face.
3135
3238
  */
3136
3239
  function apply(ctx) {
3137
3240
  injectPageCss();
3138
3241
  const connection = ctx.get("connection");
3139
- if (connection !== void 0) installFriendlyImageError(connection, () => ctx.locale.getLocale().active);
3242
+ if (connection !== void 0) installFriendlyImageError(connection, () => ctx.locale.getLocale().active === "zh" ? "zh" : "en");
3140
3243
  ctx.effect(() => ctx.locale.register("settings.commandcode", {
3141
3244
  zh,
3142
3245
  en
3143
3246
  }), "dsh-commandcode-provider: page copy");
3144
- const api = ctx.get("connection").api;
3145
- const hostDescription = ctx.get("connection").hostDescription;
3146
- const controller = new CommandCodeSettingsController(ctx.settingsScope.bind({ namespace: COMMANDCODE_NS }), { credentials: api.credentials }, hostDescription);
3247
+ const legacyApi = adaptLegacyCredentials(connection?.api?.credentials);
3248
+ if (legacyApi !== void 0) {
3249
+ applyClientSurfaces(ctx, legacyApi, connection?.hostDescription);
3250
+ return;
3251
+ }
3252
+ ctx.inject(["remote.credentials"], (remoteCtx) => {
3253
+ const credentials = remoteCtx.remote.credentials;
3254
+ applyClientSurfaces(remoteCtx, { credentials });
3255
+ });
3256
+ }
3257
+ /** Mount the one shared UI implementation over either credential transport. */
3258
+ function applyClientSurfaces(ctx, api, hostDescription) {
3259
+ const controller = new CommandCodeSettingsController(ctx.settingsScope.bind({ namespace: COMMANDCODE_NS }), api, hostDescription);
3147
3260
  ctx.effect(() => () => controller.dispose(), "dsh-commandcode-provider: settings controller");
3148
- const store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(controller.state());
3261
+ const store = createSnapshotStore(controller.state());
3149
3262
  controller.subscribe(() => store.set(controller.state()));
3263
+ ctx.effect(() => ctx.remote.$on("credentials/reference-updated", () => {
3264
+ controller.refreshCredentials();
3265
+ }), "dsh-commandcode-provider: credential invalidations");
3150
3266
  let usageNamespace;
3151
3267
  let usageMountError;
3152
3268
  const contribution = {
@@ -3186,7 +3302,7 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
3186
3302
  return namespace.report();
3187
3303
  } });
3188
3304
  ctx.effect(() => () => usageController.dispose(), "dsh-commandcode-provider: usage controller");
3189
- const usageStore = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(usageController.state());
3305
+ const usageStore = createSnapshotStore(usageController.state());
3190
3306
  usageController.subscribe(() => usageStore.set(usageController.state()));
3191
3307
  const loginRemote = {
3192
3308
  loginBegin: async () => {
@@ -3213,7 +3329,7 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
3213
3329
  };
3214
3330
  const loginController = new CommandCodeLoginController(() => loginRemote);
3215
3331
  ctx.effect(() => () => loginController.dispose(), "dsh-commandcode-provider: login controller");
3216
- const loginStore = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(loginController.state());
3332
+ const loginStore = createSnapshotStore(loginController.state());
3217
3333
  let lastLoginPhase = loginController.state().phase;
3218
3334
  loginController.subscribe(() => {
3219
3335
  const phase = loginController.state().phase;