@goodandready/dsh-clinebot 0.4.5 → 0.4.6

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,14 @@ 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.4.6] - 2026-09-25
9
+
10
+ ### Fixed
11
+ - **Obsolete Settings Service Dependency Removal (#119)**: Removed ` settings` from `inject` and eradicated legacy `ctx.inject([settings], ...)` and `sctx.settings.register(...)` calls, adapting to DSH 0.1.7 kernel architecture where the Cordis `settings` service was removed.
12
+ - **Config Reader Export (#119)**: Exported `configReader(config)` returning `() => config` to provide standard DSH configuration introspection.
13
+ - **Defensive SettingsForms Adapter (#119)**: Implemented lightweight `settingsApi` adapter providing `get()`, `replace()`, `update()`, and `watch()` without declaring `settings` in `inject`, accessing `ctx?.get?.(settings)` defensively.
14
+ - **Failover & Settings Regression Tests (#119)**: Added 5 strict DoD regression tests verifying `inject`, absence of `settings.register`, proxy property safety, config reader, and strict proxy boot.
15
+
8
16
  ## [0.4.5] - 2026-09-25
9
17
 
10
18
  ### Fixed
package/lib/index.js CHANGED
@@ -26,7 +26,11 @@ import { registerAuthRoutes } from './routes/auth.js'
26
26
  import { registerSlashCommand } from './slash-command.js'
27
27
 
28
28
  export const name = '@goodandready/dsh-clinebot'
29
- export const inject = ['settings', 'webServer', 'credentials']
29
+ export const inject = ['webServer', 'credentials']
30
+
31
+ export function configReader(config) {
32
+ return () => config
33
+ }
30
34
 
31
35
  export { NS, LLM_PI_AI_NS, Config, sessionStats, recordSessionRequest, resetSessionStats, rotateToNextAccount }
32
36
 
@@ -56,66 +60,51 @@ export function apply(ctx, config) {
56
60
  autoDiscoverPlanModels(ctx, { live, getSettingsApi: () => settingsApi, syncProviderState })
57
61
  }
58
62
 
59
- const createSettingsAdapter = (svc) => {
60
- if (!svc) return undefined
61
- if (typeof svc.replace === 'function' || typeof svc.update === 'function' || typeof svc.write === 'function') {
62
- const getRevision = () => {
63
- try {
64
- return svc.describe?.().find((row) => row.ns === NS)?.revision
65
- } catch {
66
- return undefined
67
- }
68
- }
69
- return {
70
- get: () => live(),
71
- replace: async (next) => {
72
- const parsed = Config(structuredClone(plainConfig(next)))
73
- currentConfig = parsed
74
- const payload = volatileConfig(parsed)
75
- if (typeof svc.replace === 'function') {
76
- await svc.replace(NS, payload, getRevision())
77
- } else if (typeof svc.update === 'function') {
78
- await svc.update(NS, payload, getRevision())
79
- }
80
- return parsed
81
- },
82
- update: async (patch) => {
83
- const merged = Config({ ...publicConfig(live()), ...plainConfig(patch) })
84
- currentConfig = merged
85
- const payload = volatileConfig(merged)
86
- if (typeof svc.update === 'function') {
87
- await svc.update(NS, payload, getRevision())
88
- } else if (typeof svc.replace === 'function') {
89
- await svc.replace(NS, payload, getRevision())
90
- }
91
- return merged
92
- },
93
- watch: (cb) => {
94
- if (typeof svc.watch === 'function') return svc.watch(cb)
95
- return () => {}
96
- },
97
- }
63
+ const getRevision = (svc) => {
64
+ try {
65
+ return svc?.describe?.().find((row) => row.ns === NS)?.revision
66
+ } catch {
67
+ return undefined
98
68
  }
99
- return undefined
100
69
  }
101
70
 
102
- if (typeof ctx.inject === 'function') {
103
- ctx.inject(['settings'], (sctx) => {
104
- if (typeof sctx.settings?.register === 'function') {
105
- const scope = sctx.settings.register(NS, Config, { base: config })
106
- settingsApi = scope
107
- getConfig = () => (scope?.get?.() ?? config) ?? config
108
- sctx.effect(() => scope.watch((next) => {
109
- syncProviderState(live())
110
- }), 'dsh-clinebot: settings')
111
- } else {
112
- settingsApi = createSettingsAdapter(sctx.settings)
71
+ settingsApi = {
72
+ get: () => live(),
73
+ replace: async (next) => {
74
+ const parsed = Config(structuredClone(plainConfig(next)))
75
+ currentConfig = parsed
76
+ const svc = ctx?.get?.('settings')
77
+ if (svc) {
78
+ const payload = volatileConfig(parsed)
79
+ if (typeof svc.replace === 'function') {
80
+ await svc.replace(NS, payload, getRevision(svc))
81
+ } else if (typeof svc.update === 'function') {
82
+ await svc.update(NS, payload, getRevision(svc))
83
+ }
113
84
  }
114
- sctx.effect(() => () => {
115
- getConfig = () => config
116
- settingsApi = undefined
117
- })
118
- })
85
+ await syncProviderState(live())
86
+ return parsed
87
+ },
88
+ update: async (patch) => {
89
+ const merged = Config({ ...publicConfig(live()), ...plainConfig(patch) })
90
+ currentConfig = merged
91
+ const svc = ctx?.get?.('settings')
92
+ if (svc) {
93
+ const payload = volatileConfig(merged)
94
+ if (typeof svc.update === 'function') {
95
+ await svc.update(NS, payload, getRevision(svc))
96
+ } else if (typeof svc.replace === 'function') {
97
+ await svc.replace(NS, payload, getRevision(svc))
98
+ }
99
+ }
100
+ await syncProviderState(live())
101
+ return merged
102
+ },
103
+ watch: (cb) => {
104
+ const svc = ctx?.get?.('settings')
105
+ if (typeof svc?.watch === 'function') return svc.watch(cb)
106
+ return () => {}
107
+ },
119
108
  }
120
109
 
121
110
  syncProviderState(live())
@@ -22,6 +22,7 @@ import {
22
22
  } from './cline-client.js'
23
23
 
24
24
  export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderState }) {
25
+ if (typeof ctx.inject !== 'function') return
25
26
  ctx.inject(['commands'], (cmdCtx) => {
26
27
  const commands = cmdCtx.commands
27
28
  if (typeof commands?.register !== 'function') return
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-clinebot",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
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",