dsh-notify-yimit 0.1.4 → 0.1.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/lib/client.js CHANGED
@@ -40,8 +40,6 @@ window.__ModuleLoader__.load({
40
40
  '.dn-seg{display:flex;gap:2px;padding:2px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:520px}',
41
41
  '.dn-seg-btn{flex:1;font:inherit;font-size:13px;color:var(--dsw-alias-label-secondary);border:0;border-radius:8px;padding:6px 10px;cursor:pointer;background:transparent;transition:background .15s ease,color .15s ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
42
42
  '.dn-seg-btn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}',
43
- // 选中态用主题主色 + 反色文字:浅色模式下与背景对比也足够清晰(此前浅色下
44
- // 白底+深灰与容器太接近,深色正常)。
45
43
  '.dn-seg-btn[data-on="true"]{background:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary-inverted);box-shadow:var(--dsw-shadow-lv1)}',
46
44
  '.dn-seg-btn[data-on="true"]:hover{background:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary-inverted)}',
47
45
  '.dn-seg-btn:disabled{opacity:.45;cursor:not-allowed}',
@@ -52,17 +50,13 @@ window.__ModuleLoader__.load({
52
50
  '.dn-collapse>.dn-collapse-body>.dn-block{min-width:0}',
53
51
  '.dn-kind-list{display:flex;flex-direction:column;gap:8px}',
54
52
  '.dn-kind-row{display:flex;align-items:center;gap:12px;padding:8px 12px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-1)}',
55
- // 每类型的背景/文字/开关项右对齐(预览块留在左侧)
56
53
  '.dn-kind-row>.dn-kind-field:first-of-type{margin-left:auto}',
57
- // 样式预览:纯色块内嵌类型文字,始终用配置的背景/文字色(内联样式,不受主题影响)
58
54
  '.dn-kind-preview{flex:none;min-width:72px;text-align:center;font-size:12px;font-weight:600;line-height:22px;padding:2px 10px;border-radius:6px;white-space:nowrap;box-shadow:inset 0 0 0 1px rgba(0,0,0,.08)}',
59
55
  '.dn-kind-field{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--dsw-alias-label-tertiary);flex:none}',
60
56
  '.dn-input{font:inherit;font-size:13px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:5px 10px;outline:none;max-width:120px}',
61
57
  '.dn-input:focus{border-color:var(--dsw-alias-state-business-primary)}',
62
58
  '.dn-input[type=color]{padding:2px 4px;width:48px;height:28px;cursor:pointer;max-width:none}',
63
59
  '.dn-input:disabled{opacity:.45;cursor:not-allowed}',
64
- // 浏览器选择器:原生 select 的展开列表为系统绘制、无法贴合主题,改为自绘下拉,
65
- // 触发器与弹层都走 --dsw-* 变量,深浅色模式下与设置页风格一致。
66
60
  '.dn-bselect{position:relative;width:280px;max-width:100%;flex:none}',
67
61
  '.dn-bselect-trigger{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;font:inherit;font-size:13px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:5px 10px;cursor:pointer;outline:none}',
68
62
  '.dn-bselect-trigger:hover:not(:disabled){border-color:var(--dsw-alias-border-l2)}',
@@ -577,11 +571,8 @@ window.__ModuleLoader__.load({
577
571
  }
578
572
 
579
573
  if (config.mode === 'custom') {
580
- if (typeof Notification === 'undefined' || Notification.permission !==
581
- 'granted') {
582
- ack();
583
- return
584
- }
574
+ ack();
575
+ return
585
576
  } else if (config.mode === 'system') {
586
577
  if (typeof Notification === 'undefined' || Notification.permission ===
587
578
  'denied') {
@@ -801,7 +792,8 @@ window.__ModuleLoader__.load({
801
792
  const controlsDisabled = !config.enabled
802
793
 
803
794
  const kindRows = KIND_ORDER.map((kind) => {
804
- const entry = config.colors?. [kind] ?? {}
795
+ // 修正:去掉 `?.` 和 `[kind]` 之间的空格
796
+ const entry = config.colors?.[kind] ?? {}
805
797
  const bg = entry.bg || config.bgColor || '#20272f'
806
798
  const fg = entry.fg || config.textColor || '#e6edf3'
807
799
  const enabled = entry.enabled !== false
@@ -1366,4 +1358,4 @@ window.__ModuleLoader__.load({
1366
1358
  exports.inject = inject
1367
1359
  return module.exports
1368
1360
  },
1369
- })
1361
+ })
package/lib/index.js CHANGED
@@ -1,7 +1,3 @@
1
- /**
2
- * dsh-notify-yimit-yimit 宿主插件。
3
- * 优化点:内存LRU控制、队列头指针优化、浏览器探测缓存、宿主崩溃退避、全面多语言支持。
4
- */
5
1
  import {
6
2
  z
7
3
  } from 'zod'
@@ -30,39 +26,42 @@ const DEFAULT_CONFIG = Object.freeze({
30
26
  bgColor: '#20272f',
31
27
  textColor: '#e6edf3',
32
28
  locale: 'en',
33
- // 通知窗口样式:width 窗口宽度(编辑模式拖拽边缘调整);gap 通知间距(px);
34
- // position = null 表示默认右下贴边,{left,top} 为任意屏幕位置(工作区相对坐标)。
35
29
  toast: {
36
30
  width: 340,
37
31
  gap: 12,
38
- position: null,
32
+ position: null
39
33
  },
40
34
  colors: {
41
35
  completed: {
42
36
  bg: '#1f5138',
43
37
  fg: '#e6f4ec',
38
+ accent: '#34d399',
44
39
  enabled: true
45
- },
40
+ }, // 翠绿
46
41
  error: {
47
42
  bg: '#5c1f24',
48
43
  fg: '#fbe9ea',
44
+ accent: '#f87171',
49
45
  enabled: true
50
- },
46
+ }, // 珊瑚红
51
47
  running: {
52
48
  bg: '#203a5c',
53
49
  fg: '#e8f0fb',
50
+ accent: '#60a5fa',
54
51
  enabled: true
55
- },
52
+ }, // 天蓝
56
53
  approval: {
57
54
  bg: '#4a3a12',
58
55
  fg: '#f7efd8',
56
+ accent: '#fbbf24',
59
57
  enabled: true
60
- },
58
+ }, // 琥珀
61
59
  question: {
62
60
  bg: '#3d2a55',
63
61
  fg: '#f0e8fa',
62
+ accent: '#a78bfa',
64
63
  enabled: true
65
- },
64
+ }, // 雾紫
66
65
  },
67
66
  })
68
67
 
@@ -137,7 +136,11 @@ function normalizeConfig(input) {
137
136
  if (src.locale === 'zh' || src.locale === 'en') out.locale = src.locale
138
137
 
139
138
  // 通知窗口样式:width 260–520;gap 0–60;position 缺省 null(默认右下贴边),合法 {left,top} 才采纳。
140
- out.toast = { width: 340, gap: 12, position: null }
139
+ out.toast = {
140
+ width: 340,
141
+ gap: 12,
142
+ position: null
143
+ }
141
144
  const srcToast = src.toast !== null && typeof src.toast === 'object' && !Array.isArray(src.toast) ? src.toast : {}
142
145
  if (typeof srcToast.width === 'number' && Number.isFinite(srcToast.width)) {
143
146
  out.toast.width = Math.max(260, Math.min(520, Math.round(srcToast.width)))
@@ -149,7 +152,10 @@ function normalizeConfig(input) {
149
152
  if (pos !== null && typeof pos === 'object' && !Array.isArray(pos) &&
150
153
  typeof pos.left === 'number' && Number.isFinite(pos.left) &&
151
154
  typeof pos.top === 'number' && Number.isFinite(pos.top)) {
152
- out.toast.position = { left: Math.round(pos.left), top: Math.round(pos.top) }
155
+ out.toast.position = {
156
+ left: Math.round(pos.left),
157
+ top: Math.round(pos.top)
158
+ }
153
159
  }
154
160
 
155
161
  const srcColors = src.colors !== null && typeof src.colors === 'object' && !Array.isArray(src.colors) ? src.colors :
@@ -161,6 +167,7 @@ function normalizeConfig(input) {
161
167
  out.colors[kind] = {
162
168
  bg: isHex(entry?.bg) ? entry.bg : def.bg,
163
169
  fg: isHex(entry?.fg) ? entry.fg : def.fg,
170
+ accent: isHex(entry?.accent) ? entry.accent : def.accent, // 新增
164
171
  enabled: entry?.enabled !== false,
165
172
  }
166
173
  }
@@ -201,7 +208,8 @@ function mergeConfigPatch(base, patch) {
201
208
  if (patch !== null && typeof patch === 'object' && patch.toast !== null && typeof patch.toast === 'object' && !
202
209
  Array.isArray(patch.toast)) {
203
210
  out.toast = {
204
- ...(base.toast !== null && typeof base.toast === 'object' && !Array.isArray(base.toast) ? base.toast : {}),
211
+ ...(base.toast !== null && typeof base.toast === 'object' && !Array.isArray(base.toast) ? base.toast :
212
+ {}),
205
213
  ...patch.toast
206
214
  }
207
215
  }
@@ -258,7 +266,8 @@ function openConfig() {
258
266
  fs.writeFileSync(tmp, JSON.stringify(config, null, 2), 'utf8')
259
267
  fs.renameSync(tmp, file)
260
268
  } catch {
261
- /* 静默 */ }
269
+ /* 静默 */
270
+ }
262
271
  },
263
272
  }
264
273
  }
@@ -276,7 +285,11 @@ function clip(text) {
276
285
  }
277
286
 
278
287
  function titleOf(session) {
279
- const events = session?.events
288
+ // 宿主兼容:0.1.2-alpha.4 起 `Session.events` 被 `snapshotEvents()` 取代(旧版仍有 .events)。
289
+ // 优先用 snapshotEvents()(无参返回全量冻结事件数组),旧宿主回退 .events。
290
+ const events = typeof session?.snapshotEvents === 'function'
291
+ ? session.snapshotEvents()
292
+ : session?.events
280
293
  if (Array.isArray(events)) {
281
294
  // 全量扫描:标题事件通常在会话早期(seq 小)生成,长会话/恢复会话里它可能在
282
295
  // 最后 50 条之外——只扫尾部会漏掉,导致回退到占位/目录名(恢复会话不会重放
@@ -489,7 +502,8 @@ export function apply(ctx) {
489
502
  if (idx !== -1) toastOrder.splice(idx, 1)
490
503
  reflowToasts()
491
504
  }
492
- } else if (msg.type === 'geometry' && typeof msg.left === 'number' && typeof msg.top === 'number') {
505
+ } else if (msg.type === 'geometry' && typeof msg.left === 'number' && typeof msg.top ===
506
+ 'number') {
493
507
  // 编辑模式:样板窗拖拽/缩放结束 → 写回配置,并应用到在屏浮窗。
494
508
  const width = Math.max(260, Math.min(520, Math.round(Number(msg.width) || 340)))
495
509
  const left = Math.round(Number(msg.left))
@@ -497,11 +511,18 @@ export function apply(ctx) {
497
511
  store.set({
498
512
  toast: {
499
513
  width,
500
- position: { left, top }
514
+ position: {
515
+ left,
516
+ top
517
+ }
501
518
  }
502
519
  })
503
520
  for (const rec of activeToasts.values()) {
504
- sendCmd({ cmd: 'size', key: rec.key, width })
521
+ sendCmd({
522
+ cmd: 'size',
523
+ key: rec.key,
524
+ width
525
+ })
505
526
  }
506
527
  reflowToasts()
507
528
  }
@@ -585,9 +606,16 @@ export function apply(ctx) {
585
606
  const needsTop = rec.meta !== null && newTop !== rec.meta.top
586
607
  const needsLeft = rec.meta !== null && rec.meta.left !== pos.left
587
608
  if (needsTop || needsLeft) {
588
- const move = { cmd: 'move', key: rec.key, top: newTop }
609
+ const move = {
610
+ cmd: 'move',
611
+ key: rec.key,
612
+ top: newTop
613
+ }
589
614
  if (needsTop) rec.meta.top = newTop
590
- if (needsLeft) { move.left = pos.left; rec.meta.left = pos.left }
615
+ if (needsLeft) {
616
+ move.left = pos.left;
617
+ rec.meta.left = pos.left
618
+ }
591
619
  sendCmd(move)
592
620
  }
593
621
  prevTop = newTop
@@ -626,6 +654,23 @@ export function apply(ctx) {
626
654
  return `http://127.0.0.1:${ws !== null && ws !== undefined && typeof ws.port === 'number' ? ws.port : 3080}`
627
655
  }
628
656
 
657
+ const KIND_BADGES = {
658
+ zh: {
659
+ completed: '完成',
660
+ error: '出错',
661
+ running: '运行中',
662
+ approval: '待审批',
663
+ question: '待回答'
664
+ },
665
+ en: {
666
+ completed: 'Done',
667
+ error: 'Failed',
668
+ running: 'Running',
669
+ approval: 'Approval',
670
+ question: 'Question'
671
+ },
672
+ }
673
+
629
674
  function showDesktopToast(cfg, ev) {
630
675
  const maxVisible = Math.max(1, Math.min(20, Math.floor(Number(cfg.maxVisible) || 3)))
631
676
  const stickyKind = ev.kind === 'running' || ev.kind === 'approval' || ev.kind === 'question'
@@ -691,6 +736,8 @@ export function apply(ctx) {
691
736
  bg: colors?.bg ?? cfg.bgColor ?? '#20272f',
692
737
  fg: colors?.fg ?? cfg.textColor ?? '#e6edf3',
693
738
  durationSec: Math.max(1, Math.round((Number(cfg.durationMs) || 8000) / 1000)),
739
+ accent: colors?.accent ?? '#60a5fa', // 强调色
740
+ durationSec: Math.max(1, Math.round((Number(cfg.durationMs) || 8000) / 1000)),
694
741
  sticky: stickyKind,
695
742
  offsetY,
696
743
  sessionId: String(ev.sessionId),
@@ -736,7 +783,11 @@ export function apply(ctx) {
736
783
  if (typeof title !== 'string' || title.length === 0) return
737
784
  for (const rec of activeToasts.values()) {
738
785
  if (rec.sessionId === sessionId) {
739
- sendCmd({ cmd: 'title', key: rec.key, title })
786
+ sendCmd({
787
+ cmd: 'title',
788
+ key: rec.key,
789
+ title
790
+ })
740
791
  }
741
792
  }
742
793
  }
@@ -748,11 +799,13 @@ export function apply(ctx) {
748
799
  cmd: 'shutdown'
749
800
  })
750
801
  } catch {
751
- /* 忽略 */ }
802
+ /* 忽略 */
803
+ }
752
804
  try {
753
805
  host.kill()
754
806
  } catch {
755
- /* 已退出 */ }
807
+ /* 已退出 */
808
+ }
756
809
  }
757
810
  activeToasts.clear()
758
811
  toastOrder.length = 0
@@ -768,7 +821,7 @@ export function apply(ctx) {
768
821
  const at = Date.now()
769
822
  const cfg = store.get()
770
823
  // 每类型开关:该类型被关闭时完全不产生通知(桌面浮窗与系统通知都不发)。
771
- if (cfg.colors?.[kind]?.enabled === false) return
824
+ if (cfg.colors?. [kind]?.enabled === false) return
772
825
  const desktop = cfg.enabled === true && cfg.mode === 'custom'
773
826
  const lang = cfg.locale === 'zh' ? 'zh' : 'en'
774
827
  const l = TOAST_LABELS[lang]
@@ -878,7 +931,8 @@ export function apply(ctx) {
878
931
  if (typeof event.data?.title === 'string' && event.data.title.length > 0) {
879
932
  st.title = event.data.title
880
933
  for (let i = queueHead; i < queue.length; i++) {
881
- if (queue[i].sessionId === id && (queue[i].title.length === 0 || UNTITLED_NAMES.has(queue[i].title)))
934
+ if (queue[i].sessionId === id && (queue[i].title.length === 0 || UNTITLED_NAMES.has(
935
+ queue[i].title)))
882
936
  queue[i].title = st.title
883
937
  }
884
938
  // 已弹浮窗(运行中/待审批/待回答等)标题原地更新,不再一直顶着占位/旧标题。
@@ -928,7 +982,8 @@ export function apply(ctx) {
928
982
  push(id, 'question', first.question)
929
983
  }
930
984
  } catch {
931
- /* arguments 非 JSON */ }
985
+ /* arguments 非 JSON */
986
+ }
932
987
  }
933
988
  return
934
989
  }
@@ -1015,7 +1070,8 @@ export function apply(ctx) {
1015
1070
  `${L.approvalPrefix} ${toolName}` : L.approvalFallback))
1016
1071
  }
1017
1072
  } catch {
1018
- /* 观察失败不影响审批链路 */ }
1073
+ /* 观察失败不影响审批链路 */
1074
+ }
1019
1075
  return next()
1020
1076
  })
1021
1077
 
@@ -1032,11 +1088,16 @@ export function apply(ctx) {
1032
1088
  const prev = store.get()
1033
1089
  const next = store.set(patch)
1034
1090
  // toast 几何(位置/宽度/间距)变更:立即应用到在屏浮窗,无需等待下一个浮窗。
1035
- const pToast = patch !== null && typeof patch === 'object' && !Array.isArray(patch) ? patch.toast : undefined
1091
+ const pToast = patch !== null && typeof patch === 'object' && !Array.isArray(patch) ? patch.toast :
1092
+ undefined
1036
1093
  if (pToast !== null && typeof pToast === 'object' && !Array.isArray(pToast)) {
1037
1094
  if (typeof pToast.width === 'number' && pToast.width !== prev.toast?.width) {
1038
1095
  for (const rec of activeToasts.values()) {
1039
- sendCmd({ cmd: 'size', key: rec.key, width: next.toast.width })
1096
+ sendCmd({
1097
+ cmd: 'size',
1098
+ key: rec.key,
1099
+ width: next.toast.width
1100
+ })
1040
1101
  }
1041
1102
  }
1042
1103
  reflowToasts()
@@ -1072,13 +1133,26 @@ export function apply(ctx) {
1072
1133
  title: EDIT_TITLES[lang],
1073
1134
  width: cfg.toast?.width ?? 340,
1074
1135
  position: cfg.toast?.position ?? null,
1136
+ // 新增:类型色卡数组,样板窗内做预览
1137
+ chips: KIND_KEYS.map((k) => ({
1138
+ label: (KIND_BADGES[lang] ?? KIND_BADGES.en)[k],
1139
+ accent: cfg.colors[k].accent,
1140
+ bg: cfg.colors[k].bg,
1141
+ fg: cfg.colors[k].fg,
1142
+ })),
1075
1143
  })
1076
- return { ok: true }
1144
+ return {
1145
+ ok: true
1146
+ }
1077
1147
  },
1078
1148
  /** 退出编辑模式:样板窗淡出消失。 */
1079
1149
  endEditMode() {
1080
- sendCmd({ cmd: 'edit-end' })
1081
- return { ok: true }
1150
+ sendCmd({
1151
+ cmd: 'edit-end'
1152
+ })
1153
+ return {
1154
+ ok: true
1155
+ }
1082
1156
  },
1083
1157
  }
1084
1158