@goodandready/dsh-clinebot 0.3.19 → 0.3.21

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
@@ -5,6 +5,17 @@ All notable changes to `@goodandready/dsh-clinebot` will be documented in this f
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.21] - 2026-09-23
9
+
10
+ ### Fixed
11
+ - **Account Failover Persistence & Cache Invalidation (#61)**: Fixed `rotateToNextAccount` returning `rotated: true` when settings persistence (`settingsApi.replace` or `settings.mutate`) fails. It now returns `{ rotated: false, activeAccount: active, reason: 'failed_to_persist' }` on failure, and defers `clearUsageCache()` and `clearProbeCache()` until settings are confirmed written. This prevents the provider from staying on the previous account while its quota and health telemetry caches are wiped.
12
+
13
+ ## [0.3.20] - 2026-09-23
14
+
15
+ ### Fixed
16
+ - **Web Boot Freeze Hotfix (#64 / GitHub #3)**: Removed non-existent `configForms` service from client `inject: ['slots', 'locale']` and cleared `dsh.client.inject: []` in `package.json`. In version 0.3.19, Cordis in the browser hung indefinitely waiting for `configForms`, causing DSH startup to fail with `Failed to load plugins / web boot: 1 entry did not activate / @goodandready/dsh-clinebot: pending (waiting for service: configForms)`.
17
+ - **Safe Fallback**: Retained safe optional chaining for settings mirror refresh (`(ctx?.get && ctx.get('lanSettings')) || ctx?.settingsScope`) without introducing hard service dependencies.
18
+
8
19
  ## 0.3.19
9
20
 
10
21
  ### Fixed
@@ -117,6 +117,17 @@ export async function rotateToNextAccount(ctx, cfg, reason = 'rate_limit', setti
117
117
  }
118
118
  }
119
119
 
120
+ if (!updated) {
121
+ return {
122
+ rotated: false,
123
+ previousAccount: active,
124
+ activeAccount: active,
125
+ reason: 'failed_to_persist',
126
+ message: 'Failed to persist rotated activeAccount to settings',
127
+ updatedSettings: false,
128
+ }
129
+ }
130
+
120
131
  // Reset cached quota and host probes so new account immediately revalidates
121
132
  clearUsageCache()
122
133
  clearProbeCache()
@@ -126,6 +137,6 @@ export async function rotateToNextAccount(ctx, cfg, reason = 'rate_limit', setti
126
137
  previousAccount: active,
127
138
  activeAccount: nextAcc.apiKeyEnv,
128
139
  reason,
129
- updatedSettings: updated,
140
+ updatedSettings: true,
130
141
  }
131
142
  }
package/lib/client.js CHANGED
@@ -839,10 +839,10 @@ function SettingsPage(props) {
839
839
  const t = props?.t || makeT(en, en)
840
840
 
841
841
  const scope = React.useMemo(() => {
842
- const s = (ctx?.get && ctx.get('lanSettings')) || ctx?.configForms
843
- if (!s?.get) return undefined
842
+ const s = (ctx?.get && ctx.get('lanSettings')) || ctx?.settingsScope
843
+ if (!s?.bind) return undefined
844
844
  try {
845
- return s.get(NS)
845
+ return s.bind({ namespace: NS })
846
846
  } catch (_) {
847
847
  return undefined
848
848
  }
@@ -1371,7 +1371,7 @@ function PluginCard(props) {
1371
1371
  function refreshMirrorUntilVisible(ctx) {
1372
1372
  const visible = () => {
1373
1373
  try {
1374
- const s = (ctx?.get && ctx.get('lanSettings')) || ctx?.configForms
1374
+ const s = (ctx?.get && ctx.get('lanSettings')) || ctx?.settingsScope
1375
1375
  const view = s?.describe?.()?.getSnapshot?.()?.view
1376
1376
  return !!view && Array.isArray(view.namespaces) && view.namespaces.some((row) => row.ns === NS)
1377
1377
  } catch (_) {
@@ -1384,7 +1384,7 @@ function refreshMirrorUntilVisible(ctx) {
1384
1384
  if (visible() || tries >= 15) { clearInterval(timer); return }
1385
1385
  tries += 1
1386
1386
  try {
1387
- const s = (ctx?.get && ctx.get('lanSettings')) || ctx?.configForms
1387
+ const s = (ctx?.get && ctx.get('lanSettings')) || ctx?.settingsScope
1388
1388
  s?.describe?.()?.load?.()
1389
1389
  } catch (e) {
1390
1390
  console.debug?.('[dsh-clinebot] Polling settings mirror:', e)
@@ -1494,7 +1494,7 @@ function apply(ctx) {
1494
1494
  )
1495
1495
  }
1496
1496
 
1497
- module.exports = { apply, inject: ['slots', 'locale', 'configForms'] }
1497
+ module.exports = { apply, inject: ['slots', 'locale'] }
1498
1498
 
1499
1499
  return module.exports
1500
1500
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-clinebot",
3
- "version": "0.3.19",
3
+ "version": "0.3.21",
4
4
  "description": "DeepSeek Harness companion for ClineBot / ClinePass: dynamic subscription models sync, quota exhaustion warnings, session metrics, dedicated settings page, live usage limits, and /cline slash-command.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -49,11 +49,7 @@
49
49
  },
50
50
  "client": {
51
51
  "platform": "web",
52
- "inject": [
53
- "@deepseek-ai/dsh-client-ui-slots",
54
- "@deepseek-ai/dsh-client-locale",
55
- "@deepseek-ai/dsh-client-ui-settings"
56
- ]
52
+ "inject": []
57
53
  }
58
54
  },
59
55
  "peerDependencies": {