@goodandready/dsh-plugin-notify 0.3.6 → 0.3.8

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
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.7
4
+
5
+ ### Fixed
6
+ - **Peer gate on DSH 0.2.0-rc.1** (#58): DSH skips a profile bundle whose `peerDependencies` exclude the running version, so this plugin was absent from the profile with no error in the UI. Every `@deepseek-ai/dsh-*` peer now names both the 0.1.7-rc.2 and 0.2.0-rc.1 lines, because semver does not admit a prerelease of the next minor into a range that does not name it.
7
+
3
8
  All notable changes to this project will be documented in this file.
4
9
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
10
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
package/lib/index.js CHANGED
@@ -13,6 +13,15 @@ const webhookRef = (label) => Schema.string()
13
13
  .role('credential-ref')
14
14
  .description(`${label}: DSH credential name whose value is the full webhook URL (not the URL itself). Empty disables the channel.`);
15
15
 
16
+ // Unwrap Volatile boxes before any caller reads a value. A volatile field holds a box
17
+ // rather than its value, and the Loader mutates those boxes in place.
18
+ export function plainConfig(value) {
19
+ if (value === null || typeof value !== 'object') return value
20
+ if (Array.isArray(value)) return value.map(plainConfig)
21
+ if (typeof value.get === 'function') return plainConfig(value.get())
22
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, plainConfig(v)]))
23
+ }
24
+
16
25
  export const Config = Schema.object({
17
26
  webhooks: Schema.object({
18
27
  feishu: webhookRef('Feishu custom bot'),
@@ -22,21 +31,21 @@ export const Config = Schema.object({
22
31
  discord: webhookRef('Discord webhook'),
23
32
  custom: webhookRef('Custom generic webhook (POST JSON)'),
24
33
  }).description('Per-channel credential refs for webhook URLs; leave empty to disable'),
25
- events: Schema.array(Schema.string())
34
+ events: Schema.array(Schema.string()).volatile()
26
35
  .description('Events that trigger notifications: task_done / error / approval_requested'),
27
- local: Schema.boolean().default(true).description('Also emit a local system notification (macOS osascript)'),
28
- enableSound: Schema.boolean().default(false).description('Play synthesized audio chime on completion, error, or approval'),
29
- enableToasts: Schema.boolean().default(false).description('Show in-app on-screen toast notifications across sessions'),
30
- enableDesktopNotifications: Schema.boolean().default(false).description('Show native desktop/OS push notifications (Windows, macOS, Linux)'),
31
- notifyBackgroundOnly: Schema.boolean().default(false).description('Notify only if the event occurred in a background/inactive session'),
32
- timeoutMs: Schema.number().default(5000).description('Per-webhook request timeout (ms)'),
36
+ local: Schema.boolean().volatile().default(true).description('Also emit a local system notification (macOS osascript)'),
37
+ enableSound: Schema.boolean().volatile().default(false).description('Play synthesized audio chime on completion, error, or approval'),
38
+ enableToasts: Schema.boolean().volatile().default(false).description('Show in-app on-screen toast notifications across sessions'),
39
+ enableDesktopNotifications: Schema.boolean().volatile().default(false).description('Show native desktop/OS push notifications (Windows, macOS, Linux)'),
40
+ notifyBackgroundOnly: Schema.boolean().volatile().default(false).description('Notify only if the event occurred in a background/inactive session'),
41
+ timeoutMs: Schema.number().volatile().default(5000).description('Per-webhook request timeout (ms)'),
33
42
  dnd: Schema.object({
34
43
  start: Schema.string().default('').description('Do-not-disturb start (HH:MM, empty disables)'),
35
44
  end: Schema.string().default('').description('Do-not-disturb end (HH:MM, cross-midnight ok)'),
36
45
  }).description('DND window: events are logged but no local/webhook emission'),
37
- includeSession: Schema.boolean().default(true).description('Include the session line in notification text'),
38
- includeDuration: Schema.boolean().default(true).description('Include the duration line in notification text'),
39
- excludeSessionPrefixes: Schema.array(Schema.string())
46
+ includeSession: Schema.boolean().volatile().default(true).description('Include the session line in notification text'),
47
+ includeDuration: Schema.boolean().volatile().default(true).description('Include the duration line in notification text'),
48
+ excludeSessionPrefixes: Schema.array(Schema.string()).volatile()
40
49
  .default([])
41
50
  .description('Skip notifications when session id starts with any prefix (e.g. msgw- for messenger-gateway)'),
42
51
  });
@@ -329,7 +338,11 @@ export function apply(ctx, config = {}) {
329
338
 
330
339
  if (typeof ctx.inject === 'function') {
331
340
  ctx.inject(['settings'], (sctx) => {
332
- const scope = sctx.settings.register(NS, Config, { base: config ?? {} });
341
+ const row = (() => { try { return sctx.settings?.describe?.().find((r) => r && r.ns === NS); } catch { return null; } })();
342
+ const scope = {
343
+ get: () => row?.value ?? config ?? {},
344
+ replace: async (next) => { try { return await sctx.settings?.replace?.(NS, next, row?.revision); } catch {} },
345
+ };
333
346
  getConfig = () => scope.get() ?? config ?? {};
334
347
  });
335
348
  ctx.inject(['webServer'], (wctx) => tryMountWebServer(wctx));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-plugin-notify",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "DSH plugin: audio chimes, cross-session toasts, desktop push, and IM webhooks for turn completion, errors, and approvals.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,15 +37,15 @@
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@deepseek-ai/cordis": "^4.0.1",
40
- "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
41
- "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8",
42
- "@deepseek-ai/schemastery": "^3.18.1"
40
+ "@deepseek-ai/dsh-session": "^0.1.7-rc.2 || ^0.2.0-rc.1",
41
+ "@deepseek-ai/dsh-credentials": "^0.1.7-rc.2 || ^0.2.0-rc.1",
42
+ "@deepseek-ai/schemastery": "^3.18.4"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@deepseek-ai/cordis": "^4.0.1",
46
46
  "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
47
47
  "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8",
48
- "@deepseek-ai/schemastery": "^3.18.1"
48
+ "@deepseek-ai/schemastery": "^3.18.4"
49
49
  },
50
50
  "repository": {
51
51
  "type": "git",