@goodandready/dsh-clinebot 0.3.21 → 0.3.22
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 +6 -0
- package/lib/client.js +50 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ 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.22] - 2026-09-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **SettingsPage Crash on Cordis Strict Context (#67 / GitHub #4)**: Fixed unhandled `TypeError: cannot get property "settingsScope" without inject` thrown when accessing `ctx?.settingsScope` under DSH 0.17+ / Cordis v3+ strict proxy contexts. Replaced bare property access with defensive `ctx.get('lanSettings') || ctx.get('settingsScope')` inside `try/catch` across both `settings-page.js` and `entry.js`.
|
|
12
|
+
- **Standalone Unblocked UI Rendering**: When `settingsScope` / `lanSettings` service is absent or not injected in the client fiber, `SettingsPage` snapshot now defaults to `{ status: 'ready', view: null }` instead of permanently hanging on `status: 'loading'`. The settings page is entirely functional via its own HTTP REST endpoints (`/dsh-clinebot/status`, `/save-key`, `/models/toggle`, etc.).
|
|
13
|
+
|
|
8
14
|
## [0.3.21] - 2026-09-23
|
|
9
15
|
|
|
10
16
|
### Fixed
|
package/lib/client.js
CHANGED
|
@@ -839,13 +839,31 @@ function SettingsPage(props) {
|
|
|
839
839
|
const t = props?.t || makeT(en, en)
|
|
840
840
|
|
|
841
841
|
const scope = React.useMemo(() => {
|
|
842
|
-
|
|
843
|
-
if (!s?.bind) return undefined
|
|
842
|
+
let s = null
|
|
844
843
|
try {
|
|
845
|
-
|
|
844
|
+
if (typeof ctx?.get === 'function') {
|
|
845
|
+
s = ctx.get('lanSettings') || ctx.get('settingsScope')
|
|
846
|
+
}
|
|
847
|
+
} catch (_) {
|
|
848
|
+
s = null
|
|
849
|
+
}
|
|
850
|
+
if (!s) {
|
|
851
|
+
try {
|
|
852
|
+
if (ctx && typeof ctx === 'object') {
|
|
853
|
+
s = ctx.lanSettings || ctx.settingsScope || null
|
|
854
|
+
}
|
|
855
|
+
} catch (_) {
|
|
856
|
+
s = null
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (!s) return undefined
|
|
860
|
+
try {
|
|
861
|
+
if (typeof s.bind === 'function') return s.bind({ namespace: NS })
|
|
862
|
+
if (typeof s.get === 'function') return s.get(NS)
|
|
846
863
|
} catch (_) {
|
|
847
864
|
return undefined
|
|
848
865
|
}
|
|
866
|
+
return undefined
|
|
849
867
|
}, [ctx])
|
|
850
868
|
|
|
851
869
|
const subscribe = React.useMemo(() => {
|
|
@@ -860,11 +878,11 @@ function SettingsPage(props) {
|
|
|
860
878
|
}, [scope])
|
|
861
879
|
|
|
862
880
|
const getSnapshot = React.useCallback(() => {
|
|
863
|
-
if (!scope?.getSnapshot) return
|
|
881
|
+
if (!scope?.getSnapshot) return { status: 'ready', view: null }
|
|
864
882
|
try {
|
|
865
|
-
return scope.getSnapshot() ||
|
|
883
|
+
return scope.getSnapshot() || { status: 'ready', view: null }
|
|
866
884
|
} catch (_) {
|
|
867
|
-
return
|
|
885
|
+
return { status: 'ready', view: null }
|
|
868
886
|
}
|
|
869
887
|
}, [scope])
|
|
870
888
|
|
|
@@ -1369,28 +1387,48 @@ function PluginCard(props) {
|
|
|
1369
1387
|
|
|
1370
1388
|
// --- src/client/entry.js ---
|
|
1371
1389
|
function refreshMirrorUntilVisible(ctx) {
|
|
1390
|
+
const getSettingsService = () => {
|
|
1391
|
+
try {
|
|
1392
|
+
if (typeof ctx?.get === 'function') {
|
|
1393
|
+
const s = ctx.get('lanSettings') || ctx.get('settingsScope')
|
|
1394
|
+
if (s) return s
|
|
1395
|
+
}
|
|
1396
|
+
} catch (_) {}
|
|
1397
|
+
try {
|
|
1398
|
+
if (ctx && typeof ctx === 'object') {
|
|
1399
|
+
return ctx.lanSettings || ctx.settingsScope || null
|
|
1400
|
+
}
|
|
1401
|
+
} catch (_) {}
|
|
1402
|
+
return null
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
const s = getSettingsService()
|
|
1406
|
+
if (!s) return
|
|
1407
|
+
|
|
1372
1408
|
const visible = () => {
|
|
1373
1409
|
try {
|
|
1374
|
-
const
|
|
1375
|
-
const view =
|
|
1410
|
+
const current = getSettingsService()
|
|
1411
|
+
const view = current?.describe?.()?.getSnapshot?.()?.view
|
|
1376
1412
|
return !!view && Array.isArray(view.namespaces) && view.namespaces.some((row) => row.ns === NS)
|
|
1377
1413
|
} catch (_) {
|
|
1378
1414
|
return false
|
|
1379
1415
|
}
|
|
1380
1416
|
}
|
|
1381
|
-
if (visible()) return
|
|
1417
|
+
if (visible()) return
|
|
1418
|
+
|
|
1419
|
+
if (typeof setInterval !== 'function') return
|
|
1420
|
+
|
|
1382
1421
|
let tries = 0
|
|
1383
1422
|
const timer = setInterval(() => {
|
|
1384
1423
|
if (visible() || tries >= 15) { clearInterval(timer); return }
|
|
1385
1424
|
tries += 1
|
|
1386
1425
|
try {
|
|
1387
|
-
const
|
|
1388
|
-
|
|
1426
|
+
const current = getSettingsService()
|
|
1427
|
+
current?.describe?.()?.load?.()
|
|
1389
1428
|
} catch (e) {
|
|
1390
1429
|
console.debug?.('[dsh-clinebot] Polling settings mirror:', e)
|
|
1391
1430
|
}
|
|
1392
1431
|
}, 1000)
|
|
1393
|
-
return () => clearInterval(timer)
|
|
1394
1432
|
}
|
|
1395
1433
|
|
|
1396
1434
|
function apply(ctx) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-clinebot",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.22",
|
|
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",
|