@goodandready/dsh-image-gen 0.11.15 → 0.11.17

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/lib/client.js CHANGED
@@ -3235,18 +3235,22 @@ window.__ModuleLoader__.load({
3235
3235
  )
3236
3236
  )
3237
3237
 
3238
- // Settings card item — sole slot registration for settings card (#208, #300)
3239
- registerSlotWhenReady('settings.plugin.item', () =>
3240
- ctx.slots.register(
3241
- {
3242
- name: 'settings.plugin.item',
3243
- key: SETTINGS_NS,
3244
- locale: NS,
3245
- inject: () => cardOnce().inject(),
3246
- },
3247
- (props) => react.createElement(ErrorBoundary, null, react.createElement(FalSettingsCard, props))
3238
+ // Settings card — settings.plugin.item was retired before DSH 0.1.7-rc.2, so
3239
+ // the card was mounted on no seat at all and had no configuration UI. Both
3240
+ // seats below exist in 0.1.7-rc.2 and 0.2.0 (#208, #300).
3241
+ for (const seat of ['plugins.item', 'plugins.row.config']) {
3242
+ registerSlotWhenReady(seat, () =>
3243
+ ctx.slots.register(
3244
+ {
3245
+ name: seat,
3246
+ key: SETTINGS_NS,
3247
+ locale: NS,
3248
+ inject: () => cardOnce().inject(),
3249
+ },
3250
+ (props) => react.createElement(ErrorBoundary, null, react.createElement(FalSettingsCard, props))
3251
+ )
3248
3252
  )
3249
- )
3253
+ }
3250
3254
  }
3251
3255
  // -------------------------------------------------------------- Asset Vault View (#159, #304)
3252
3256
  function AssetVaultView(props) {
package/lib/index.js CHANGED
@@ -73,9 +73,6 @@ export const name = '@goodandready/dsh-image-gen'
73
73
  /** Settings namespace the Web card edits. */
74
74
  const NS = 'dsh-image-gen'
75
75
 
76
- // The plugin was previously named dsh-fal-image-gen. Any settings saved
77
- // under the legacy namespace are read as fallback and migrated once on startup.
78
- const LEGACY_NS = 'dsh-fal-image-gen'
79
76
  export const inject = ['tools', 'attachments', 'credentials', 'webServer', 'settings', 'llm', 'systemPrompt']
80
77
 
81
78
  export function slugify(input) {
@@ -105,24 +102,6 @@ export async function resolveApiKey(ctx, ref) {
105
102
  return ''
106
103
  }
107
104
 
108
- /**
109
- * If the user configured the plugin under its old name (dsh-fal-image-gen), copy
110
- * those settings forward into dsh-image-gen once so existing keys and choices
111
- * are preserved. Only touches values that the user actually modified.
112
- */
113
- function migrateLegacySettings(sctx, scope) {
114
- try {
115
- if (!scope || typeof scope.update !== 'function') return
116
- const legacyScope = sctx.settings.get?.(LEGACY_NS)
117
- if (!legacyScope) return
118
- const legacy = legacyScope.get?.()
119
- if (!legacy || typeof legacy !== 'object') return
120
- scope.update(structuredClone(legacy))
121
- } catch (_) {
122
- // Settings migration skipped — fallback to default schema configuration
123
- }
124
- }
125
-
126
105
  /** Collect text chunks from llm.stream iterator.
127
106
  * Canonical implementation lives in prompt-enhancer.js; re-exported for backwards compat. */
128
107
  export { collectText } from './prompt-enhancer.js'
@@ -167,7 +146,7 @@ export function apply(ctx, rawConfig) {
167
146
  return {
168
147
  get: () => live(),
169
148
  replace: async (next) => {
170
- const parsed = Config(structuredClone(plainConfig(next)))
149
+ const parsed = plainConfig(Config(structuredClone(plainConfig(next))))
171
150
  currentLiveConfig = parsed
172
151
  const payload = volatileConfig(parsed)
173
152
  if (typeof svc.replace === 'function') {
@@ -178,7 +157,7 @@ export function apply(ctx, rawConfig) {
178
157
  return parsed
179
158
  },
180
159
  update: async (patch) => {
181
- const merged = Config({ ...publicConfig(live()), ...plainConfig(patch) })
160
+ const merged = plainConfig(Config({ ...publicConfig(live()), ...plainConfig(patch) }))
182
161
  currentLiveConfig = merged
183
162
  const payload = volatileConfig(merged)
184
163
  if (typeof svc.update === 'function') {
@@ -197,29 +176,56 @@ export function apply(ctx, rawConfig) {
197
176
  return undefined
198
177
  }
199
178
 
179
+ let settingsSvc = null
180
+
181
+ const readServedConfig = () => {
182
+ if (typeof settingsSvc?.describe !== 'function') return null
183
+ try {
184
+ const row = settingsSvc.describe().find((r) => r?.ns === NS)
185
+ if (!row || row.status !== 'ready' || !row.value) return null
186
+ return Config(structuredClone(plainConfig(row.value)))
187
+ } catch (_) {
188
+ return null
189
+ }
190
+ }
191
+
192
+ const adoptServed = () => {
193
+ const next = readServedConfig()
194
+ if (!next) return false
195
+ currentLiveConfig = next
196
+ getConfig = () => currentLiveConfig || config
197
+ return true
198
+ }
199
+
200
200
  ctx.inject(['settings'], (sctx) => {
201
- if (typeof sctx.settings?.register === 'function') {
202
- const scope = sctx.settings.register(NS, Config, { base: config })
203
- settingsApi = scope
204
- migrateLegacySettings(sctx, scope)
205
- getConfig = () => (scope?.get?.() ?? config) ?? config
206
- sctx.effect(() => () => {
207
- getConfig = () => config
208
- settingsApi = undefined
209
- })
210
- } else {
211
- settingsApi = createSettingsAdapter(sctx.settings)
212
- if (typeof sctx.settings?.describe === 'function') {
201
+ settingsSvc = sctx.settings
202
+ settingsApi = createSettingsAdapter(sctx.settings)
203
+ adoptServed()
204
+ sctx.effect(() => () => {
205
+ getConfig = () => config
206
+ settingsApi = undefined
207
+ })
208
+ })
209
+
210
+ // DSH 0.1.7-rc.2 and 0.2.0 share this contract: the Loader re-merges volatile
211
+ // profile entries in place and announces it with loader/volatile-update.
212
+ // settings.register exists in neither release, so the branch that used it was
213
+ // dead code and the card's writes never reached the host.
214
+ if (typeof ctx.on === 'function') {
215
+ try {
216
+ ctx.on('loader/volatile-update', () => {
213
217
  try {
214
- sctx.settings.describe(NS, Config)
215
- } catch (_) { /* bestEffort */ }
216
- }
217
- sctx.effect(() => () => {
218
- getConfig = () => config
219
- settingsApi = undefined
218
+ adoptServed()
219
+ } catch (err) {
220
+ const msg = `[dsh-image-gen] settings refresh failed: ${err?.message || err}`
221
+ if (typeof ctx.logger?.warn === 'function') ctx.logger.warn(msg)
222
+ }
220
223
  })
224
+ } catch (err) {
225
+ const msg = `[dsh-image-gen] volatile-update subscription failed: ${err?.message || err}`
226
+ if (typeof ctx.logger?.warn === 'function') ctx.logger.warn(msg)
221
227
  }
222
- })
228
+ }
223
229
 
224
230
  // Serve the stored image so the tool card can show it inline.
225
231
  const imageHandler = async (req, res) => {
@@ -103,7 +103,7 @@ export function registerSettingsRoutes(ctx, { live, getSettingsApi, setLiveConfi
103
103
 
104
104
  try {
105
105
  const base = plainConfig(live()) || {}
106
- const merged = Config({ ...base, ...raw })
106
+ const merged = plainConfig(Config({ ...base, ...raw }))
107
107
  const settingsApi = getSettingsApi ? getSettingsApi() : null
108
108
  if (settingsApi && typeof settingsApi.replace === 'function') {
109
109
  await settingsApi.replace(merged)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-image-gen",
3
- "version": "0.11.15",
3
+ "version": "0.11.17",
4
4
  "description": "Image generation for DeepSeek Harness: a generate_image tool with pluggable providers — the FAL queue, any OpenAI-compatible images API, or a ChatGPT/Grok subscription with no API key at all. The picture is shown inline in the conversation; the model receives either a link (works with any chat model) or the image itself (needs dsh-vision-bridge or a vision-capable model).",
5
5
  "keywords": [
6
6
  "deepseek-harness",