@goodandready/dsh-dsml-artifact-guard 0.2.9 → 0.2.11

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
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.2.11] - 2026-10-15
11
+
12
+ ### Fixed
13
+ - **Settings Policy Owner Attribution**: passed `ctx.fiber` as the owner argument to `ctx.settings.configure({ auto: false }, ctx.fiber)`, ensuring settings policy correctly attributes to the plugin fiber and suppresses generic duplicate form generation (#62).
14
+ - **Live Configuration Updates via Volatile Event**: subscribed to `loader/volatile-update` in `apply()`, allowing live settings mutations saved in the Web UI card to take effect in place without requiring a server restart (#62).
15
+
16
+ ## [0.2.10] - 2026-10-07
17
+
18
+ ### Removed
19
+ - **Dead `settings.register` Fallback**: removed dead legacy registration path in `apply()` and eliminated potential un-unwrapped volatile box leak on host settings delivery (#54, #55, #59).
20
+ - **Dead `settings.plugin.item` Slot**: removed dead slot registration in client bundle, routing exclusively through active `plugins.row.config` and `plugins.item` seats (#59).
21
+
22
+ ### Optimized
23
+ - **Single-Pass Config Unwrapping**: optimized `unwrapConfig` error fallback to evaluate raw plain config in a single pass instead of three recursive walks (#56).
24
+
10
25
  ## [0.2.9] - 2026-10-07
11
26
 
12
27
  ### Fixed
package/README.md CHANGED
@@ -119,8 +119,8 @@ The guard retains a minimal 96-byte window until the next chunk or `finish` even
119
119
  * **`disabled`**: Bypasses processing entirely.
120
120
 
121
121
  ### 5. Native Web UI Settings Card
122
- Registered directly in the DeepSeek Harness `settings.plugin.item` slot (`lib/client.js`):
123
- * **Reactive Configuration**: Adjust `mode`, `providerId`, and `modelId` on the fly without restarting the harness, powered by reactive `scope.watch`.
122
+ Registered directly in DeepSeek Harness `plugins.row.config` and `plugins.item` slots (`lib/client.js`):
123
+ * **Reactive Configuration**: Adjust `mode`, `providers`, and `modelPattern` on the fly without restarting the harness.
124
124
  * **Snapshot State Awareness**: Gracefully handles snapshot loading, ready, and unavailable states.
125
125
  * **Protection Bypass Warning**: Displays a prominent `OFF` badge and warning banner when the guard is set to `disabled`.
126
126
 
package/lib/client.js CHANGED
@@ -707,9 +707,8 @@ window.__ModuleLoader__.load({
707
707
  }
708
708
  }
709
709
 
710
- // Newest seat first: the Plugins page renders a row's own configuration
711
- // page from 'plugins.row.config'. Keep 'settings.plugin.item' below as the
712
- // fallback for cores that still render the old card slot.
710
+ // Plugins page row configuration: the Plugins page renders a row's own configuration
711
+ // page from 'plugins.row.config'.
713
712
  registerSlotWhenReady('plugins.row.config', () =>
714
713
  ctx.slots.register(
715
714
  {
@@ -742,18 +741,6 @@ window.__ModuleLoader__.load({
742
741
  )
743
742
  );
744
743
 
745
- registerSlotWhenReady('settings.plugin.item', () =>
746
- ctx.slots.register(
747
- {
748
- name: 'settings.plugin.item',
749
- key: NS,
750
- order: 95,
751
- locale: NS,
752
- inject: () => ({ ctx }),
753
- },
754
- (props) => React.createElement(PluginCard, { ...props, ctx: (props && props.ctx) || ctx })
755
- )
756
- );
757
744
  };
758
745
 
759
746
  return module.exports;
package/lib/index.js CHANGED
@@ -147,58 +147,50 @@ export async function* sanitizeDsmlArtifacts(s, { mode = 'sanitize', onArtifact
147
147
  export function unwrapConfig(conf) {
148
148
  if (!conf) return {};
149
149
  // A Volatile reference (any field is now volatile) resolves through .get().
150
- const readRef = (val) => {
150
+ if (typeof conf.get === 'function') {
151
151
  try {
152
- const inner = typeof val?.get === 'function' ? val.get() : val;
153
- return inner && typeof inner === 'object' ? inner : {};
154
- } catch {
152
+ const inner = conf.get();
153
+ const plain = plainConfig(inner);
154
+ return plain && typeof plain === 'object' ? plain : {};
155
+ } catch (err) {
156
+ /* Getter threw; return safe empty object fallback */
155
157
  return {};
156
158
  }
157
- };
158
- if (typeof conf.get === 'function') return readRef(conf);
159
+ }
159
160
  try {
160
161
  // Config() returns volatile boxes now, so unwrap them; a plain input stays plain.
161
162
  return plainConfig(Config(conf));
162
- } catch {
163
- return plainConfig(conf) && typeof plainConfig(conf) === 'object' ? plainConfig(conf) : {};
163
+ } catch (err) {
164
+ /* Schema validation threw; fallback to single-pass unwrapped raw config */
165
+ const plain = plainConfig(conf);
166
+ return plain && typeof plain === 'object' ? plain : {};
164
167
  }
165
168
  }
166
169
 
167
170
  export function apply(ctx, initialConfig = {}) {
168
- const NS = '@goodandready/dsh-dsml-artifact-guard';
169
171
  let activeConfig = unwrapConfig(initialConfig);
170
172
 
171
173
  let getConfig = () => (typeof initialConfig?.get === 'function' ? unwrapConfig(initialConfig) : activeConfig);
172
174
 
173
- // Live config subscription from the plugin fiber
175
+ // Live config subscription from the plugin fiber (re-read volatile entries on loader/volatile-update)
174
176
  if (typeof ctx.on === 'function') {
175
- ctx.effect(() => ctx.on('config', (nextConfig) => {
176
- activeConfig = unwrapConfig(nextConfig);
177
- }), 'dsh-dsml-artifact-guard: live config');
177
+ const syncConfig = (nextConfig) => {
178
+ activeConfig = unwrapConfig(nextConfig || initialConfig);
179
+ };
180
+ ctx.effect(() => {
181
+ const unsubVolatile = ctx.on('loader/volatile-update', () => syncConfig());
182
+ const unsubConfig = ctx.on('config', (nextConfig) => syncConfig(nextConfig));
183
+ return () => {
184
+ if (typeof unsubVolatile === 'function') unsubVolatile();
185
+ if (typeof unsubConfig === 'function') unsubConfig();
186
+ };
187
+ }, 'dsh-dsml-artifact-guard: live config');
178
188
  }
179
189
 
180
190
  // DSH 0.1.7 SettingsForms: suppress generic duplicate form, custom card mounts in plugins seat
181
191
  if (ctx.settings && typeof ctx.settings.configure === 'function') {
182
- ctx.effect(() => ctx.settings.configure({ auto: false }), 'dsh-dsml-artifact-guard: settings policy');
183
- } else if (typeof ctx.inject === 'function') {
184
- // Legacy settings service fallback
185
- ctx.inject(['settings'], (sctx) => {
186
- if (typeof sctx.settings?.register === 'function') {
187
- try {
188
- const scope = sctx.settings.register(NS, Config, { base: initialConfig });
189
- getConfig = () => Config(scope?.get() ?? initialConfig) ?? {};
190
- if (typeof scope?.watch === 'function') {
191
- sctx.effect(() => scope.watch(() => {
192
- activeConfig = getConfig();
193
- }));
194
- }
195
- } catch (err) {
196
- /* Legacy settings service registration unavailable */
197
- }
198
- }
199
- });
192
+ ctx.effect(() => ctx.settings.configure({ auto: false }, ctx.fiber), 'dsh-dsml-artifact-guard: settings policy');
200
193
  }
201
-
202
194
  // Register one-click updater endpoint
203
195
  if (ctx.webServer && typeof ctx.webServer.register === 'function') {
204
196
  const mountUpdater = () => registerPluginUpdater(ctx, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-dsml-artifact-guard",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Sanitizes leaked DeepSeek DSML closing tags from model text streams",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",