@lanbaolu/dsh-wechat-bridge 0.8.0 → 0.9.0

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
@@ -76,6 +76,30 @@ window.__ModuleLoader__.load({
76
76
  fontSize: 12,
77
77
  opacity: .7
78
78
  };
79
+ /** 折叠分组:把面板拆成可收起的区块,降低设置页复杂度。 */
80
+ function Section({ title, defaultOpen = false, children }) {
81
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
82
+ open: defaultOpen,
83
+ style: {
84
+ marginBottom: 10,
85
+ border: "1px solid var(--border-color, rgba(127,127,127,.18))",
86
+ borderRadius: 8,
87
+ padding: "8px 10px"
88
+ },
89
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", {
90
+ style: {
91
+ fontWeight: 600,
92
+ fontSize: 13,
93
+ cursor: "pointer",
94
+ userSelect: "none"
95
+ },
96
+ children: title
97
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
98
+ style: { marginTop: 8 },
99
+ children
100
+ })]
101
+ });
102
+ }
79
103
  const TRUST_MODE_LABELS = {
80
104
  "owner-only": "仅本机主人(默认)",
81
105
  bootstrap: "首位陌生人自动入集(一次性)",
@@ -138,6 +162,7 @@ window.__ModuleLoader__.load({
138
162
  const [projectMessage, setProjectMessage] = (0, react.useState)("");
139
163
  const [projectError, setProjectError] = (0, react.useState)("");
140
164
  const [notifyStatus, setNotifyStatus] = (0, react.useState)(null);
165
+ const [pendingStatus, setPendingStatus] = (0, react.useState)(null);
141
166
  const [calm, setCalm] = (0, react.useState)(CALM_DEFAULTS);
142
167
  const [preventSleep, setPreventSleep] = (0, react.useState)(false);
143
168
  const [calmBusy, setCalmBusy] = (0, react.useState)(false);
@@ -171,6 +196,13 @@ window.__ModuleLoader__.load({
171
196
  } catch (err) {
172
197
  setError(err instanceof Error ? err.message : String(err));
173
198
  }
199
+ try {
200
+ const pendingRes = await fetch(`${API_BASE}/pending/status`, { cache: "no-store" });
201
+ if (pendingRes.ok) {
202
+ const pendingData = await pendingRes.json();
203
+ if (pendingData && typeof pendingData === "object" && pendingData.ok) setPendingStatus(pendingData.data ?? null);
204
+ }
205
+ } catch {}
174
206
  try {
175
207
  const trustRes = await fetch(`${API_BASE}/trust`, { cache: "no-store" });
176
208
  if (trustRes.ok) {
@@ -417,37 +449,6 @@ window.__ModuleLoader__.load({
417
449
  setSetupError("");
418
450
  setDaemonMessage("");
419
451
  }
420
- const actions = [
421
- {
422
- label: "刷新状态",
423
- run: () => void refresh()
424
- },
425
- {
426
- label: "扫码绑定",
427
- run: () => void startSetup(),
428
- disabled: setupPhase === "starting" || setupPhase === "qr"
429
- },
430
- {
431
- label: "启动",
432
- run: () => void run("start"),
433
- disabled: busy !== null
434
- },
435
- {
436
- label: "停止",
437
- run: () => void run("stop"),
438
- disabled: busy !== null
439
- },
440
- {
441
- label: "重启",
442
- run: () => void run("restart"),
443
- disabled: busy !== null
444
- },
445
- {
446
- label: "查看日志",
447
- run: () => void showLogs(),
448
- disabled: busy !== null
449
- }
450
- ];
451
452
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
452
453
  style: panelStyle,
453
454
  role: "region",
@@ -465,539 +466,642 @@ window.__ModuleLoader__.load({
465
466
  },
466
467
  children: error
467
468
  }),
468
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
469
- style: {
470
- display: "block",
471
- marginBottom: 8,
472
- fontSize: 12
473
- },
474
- children: ["DSH 工作目录", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
475
- type: "text",
476
- value: workingDir,
477
- onChange: (e) => setWorkingDir(e.target.value),
478
- placeholder: "例如 ~/Documents/DSH",
479
- style: {
480
- ...inputStyle,
481
- marginLeft: 8
482
- }
483
- })]
484
- }),
485
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
486
- style: { marginBottom: 12 },
487
- children: [
488
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
489
- style: {
490
- ...titleStyle,
491
- marginBottom: 4
469
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
470
+ title: "⚙️ 状态与操作",
471
+ defaultOpen: true,
472
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
473
+ style: buttonRowStyle,
474
+ children: [
475
+ {
476
+ label: "刷新状态",
477
+ run: () => void refresh()
492
478
  },
493
- children: "项目对话绑定"
494
- }),
495
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
496
- style: {
497
- fontSize: 12,
498
- opacity: .8
479
+ {
480
+ label: "扫码绑定",
481
+ run: () => void startSetup(),
482
+ disabled: setupPhase === "starting" || setupPhase === "qr"
499
483
  },
500
- children: boundProject ? `当前绑定:${boundProject.workspaceTitle} · ${boundProject.path} · ${boundProject.sessionId.slice(-8)}` : "当前未绑定:微信消息使用独立桥接会话(也可选择项目对话以共享记忆)。"
501
- }),
502
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
503
- style: {
504
- display: "flex",
505
- gap: 8,
506
- flexWrap: "wrap",
507
- alignItems: "center",
508
- marginTop: 6
484
+ {
485
+ label: "启动",
486
+ run: () => void run("start"),
487
+ disabled: busy !== null
509
488
  },
510
- children: [
511
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
512
- value: projectChoice,
513
- onChange: (e) => setProjectChoice(e.target.value),
514
- style: selectStyle,
515
- "aria-label": "选择要绑定的项目会话",
516
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
517
- value: "",
518
- children: "— 选择要绑定的项目会话 —"
519
- }), projects.map((project) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
520
- value: project.sessionId,
521
- children: [
522
- project.workspaceTitle,
523
- " · ",
524
- project.path,
525
- " · ",
526
- project.sessionId.slice(-8)
527
- ]
528
- }, project.sessionId))]
529
- }),
530
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
531
- type: "button",
532
- style: buttonStyle,
533
- disabled: !projectChoice || projectBusy,
534
- onClick: () => void bindProject(),
535
- children: "绑定"
536
- }),
537
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
538
- type: "button",
539
- style: buttonStyle,
540
- disabled: projectBusy || !boundProject,
541
- onClick: () => void detachProject(),
542
- children: "解除绑定"
543
- })
544
- ]
545
- }),
546
- projectMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
547
- role: "status",
489
+ {
490
+ label: "停止",
491
+ run: () => void run("stop"),
492
+ disabled: busy !== null
493
+ },
494
+ {
495
+ label: "重启",
496
+ run: () => void run("restart"),
497
+ disabled: busy !== null
498
+ },
499
+ {
500
+ label: "查看日志",
501
+ run: () => void showLogs(),
502
+ disabled: busy !== null
503
+ }
504
+ ].map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
505
+ type: "button",
506
+ style: buttonStyle,
507
+ disabled: action.disabled ?? false,
508
+ onClick: action.run,
509
+ children: action.label
510
+ }, action.label))
511
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
512
+ style: { marginTop: 8 },
513
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", {
548
514
  style: {
549
- color: "#2f9e44",
550
- marginTop: 6,
551
- fontSize: 12
515
+ fontSize: 12,
516
+ opacity: .7,
517
+ cursor: "pointer"
552
518
  },
553
- children: projectMessage
554
- }),
555
- projectError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
556
- role: "alert",
519
+ children: "状态 / 日志输出"
520
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
557
521
  style: {
558
- color: "#e5484d",
559
- marginTop: 6,
560
- fontSize: 12
522
+ ...outputStyle,
523
+ marginTop: 6
561
524
  },
562
- children: projectError
563
- })
564
- ]
525
+ "aria-live": "polite",
526
+ children: output
527
+ })]
528
+ })]
565
529
  }),
566
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
567
- style: { marginBottom: 12 },
568
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
530
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
531
+ title: "🔗 连接与账号",
532
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
569
533
  style: {
570
- ...titleStyle,
571
- marginBottom: 4
572
- },
573
- children: "主动通知节流"
574
- }), notifyStatus ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
575
- style: {
576
- fontSize: 12,
577
- opacity: .85
534
+ display: "block",
535
+ marginBottom: 8,
536
+ fontSize: 12
578
537
  },
538
+ children: ["DSH 工作目录", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
539
+ type: "text",
540
+ value: workingDir,
541
+ onChange: (e) => setWorkingDir(e.target.value),
542
+ placeholder: "例如 ~/Documents/DSH",
543
+ style: {
544
+ ...inputStyle,
545
+ marginLeft: 8
546
+ }
547
+ })]
548
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
549
+ style: { marginBottom: 12 },
579
550
  children: [
580
- "今日已发 ",
581
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: notifyStatus.dailySent }),
582
- " / ",
583
- notifyStatus.dailyLimit,
584
- " 条 · 近一小时",
585
- " ",
586
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: notifyStatus.hourlySent }),
587
- " / ",
588
- notifyStatus.hourlyLimit,
589
- " 条 · 排队中",
590
- " ",
591
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: notifyStatus.pendingCount }),
592
- " 条",
593
551
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
594
552
  style: {
595
- marginTop: 4,
553
+ ...titleStyle,
554
+ marginBottom: 4
555
+ },
556
+ children: "项目对话绑定"
557
+ }),
558
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
559
+ style: {
596
560
  fontSize: 12,
597
- opacity: .7
561
+ opacity: .8
562
+ },
563
+ children: boundProject ? `当前绑定:${boundProject.workspaceTitle} · ${boundProject.path} · ${boundProject.sessionId.slice(-8)}` : "当前未绑定:微信消息使用独立桥接会话(也可选择项目对话以共享记忆)。"
564
+ }),
565
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
566
+ style: {
567
+ display: "flex",
568
+ gap: 8,
569
+ flexWrap: "wrap",
570
+ alignItems: "center",
571
+ marginTop: 6
598
572
  },
599
- children: "agent 通过 wechat_notify 主动推送的通知,超限自动排队延迟发送,避免触发微信风控。"
573
+ children: [
574
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
575
+ value: projectChoice,
576
+ onChange: (e) => setProjectChoice(e.target.value),
577
+ style: selectStyle,
578
+ "aria-label": "选择要绑定的项目会话",
579
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
580
+ value: "",
581
+ children: "— 选择要绑定的项目会话 —"
582
+ }), projects.map((project) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
583
+ value: project.sessionId,
584
+ children: [
585
+ project.workspaceTitle,
586
+ " · ",
587
+ project.path,
588
+ " · ",
589
+ project.sessionId.slice(-8)
590
+ ]
591
+ }, project.sessionId))]
592
+ }),
593
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
594
+ type: "button",
595
+ style: buttonStyle,
596
+ disabled: !projectChoice || projectBusy,
597
+ onClick: () => void bindProject(),
598
+ children: "绑定"
599
+ }),
600
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
601
+ type: "button",
602
+ style: buttonStyle,
603
+ disabled: projectBusy || !boundProject,
604
+ onClick: () => void detachProject(),
605
+ children: "解除绑定"
606
+ })
607
+ ]
608
+ }),
609
+ projectMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
610
+ role: "status",
611
+ style: {
612
+ color: "#2f9e44",
613
+ marginTop: 6,
614
+ fontSize: 12
615
+ },
616
+ children: projectMessage
617
+ }),
618
+ projectError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
619
+ role: "alert",
620
+ style: {
621
+ color: "#e5484d",
622
+ marginTop: 6,
623
+ fontSize: 12
624
+ },
625
+ children: projectError
600
626
  })
601
627
  ]
602
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
603
- style: {
604
- fontSize: 12,
605
- opacity: .7
606
- },
607
- children: "守护进程未运行,暂无数据。"
608
628
  })]
609
629
  }),
610
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
611
- style: { marginBottom: 12 },
630
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
631
+ title: "💬 消息与通知",
612
632
  children: [
613
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
614
- style: {
615
- ...titleStyle,
616
- marginBottom: 4
617
- },
618
- children: "⏳ 超时安抚"
619
- }),
620
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
621
- style: {
622
- fontSize: 12,
623
- opacity: .7,
624
- marginBottom: 8
625
- },
626
- children: "DSH 长时间没有产出消息时,主动发一条\"还在处理\"的安抚消息。改配置后即时生效(最长延迟数秒)。"
633
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
634
+ style: { marginBottom: 12 },
635
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
636
+ style: {
637
+ ...titleStyle,
638
+ marginBottom: 4
639
+ },
640
+ children: "主动通知节流"
641
+ }), notifyStatus ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
642
+ style: {
643
+ fontSize: 12,
644
+ opacity: .85
645
+ },
646
+ children: [
647
+ "今日已发 ",
648
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: notifyStatus.dailySent }),
649
+ " / ",
650
+ notifyStatus.dailyLimit,
651
+ " 条 · 近一小时",
652
+ " ",
653
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: notifyStatus.hourlySent }),
654
+ " / ",
655
+ notifyStatus.hourlyLimit,
656
+ " 条 · 排队中",
657
+ " ",
658
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: notifyStatus.pendingCount }),
659
+ " 条",
660
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
661
+ style: {
662
+ marginTop: 4,
663
+ fontSize: 12,
664
+ opacity: .7
665
+ },
666
+ children: "agent 通过 wechat_notify 主动推送的通知,超限自动排队延迟发送,避免触发微信风控。"
667
+ })
668
+ ]
669
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
670
+ style: {
671
+ fontSize: 12,
672
+ opacity: .7
673
+ },
674
+ children: "守护进程未运行,暂无数据。"
675
+ })]
627
676
  }),
628
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
629
- style: {
630
- display: "flex",
631
- alignItems: "center",
632
- gap: 6,
633
- fontSize: 12,
634
- marginBottom: 8
635
- },
636
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
637
- type: "checkbox",
638
- checked: calm.enabled,
639
- onChange: (e) => setCalm((c) => ({
640
- ...c,
641
- enabled: e.target.checked
642
- }))
643
- }), "启用安抚消息"]
677
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
678
+ style: { marginBottom: 12 },
679
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
680
+ style: {
681
+ ...titleStyle,
682
+ marginBottom: 4
683
+ },
684
+ children: "📮 待补发队列"
685
+ }), pendingStatus && pendingStatus.count > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
686
+ style: { fontSize: 12 },
687
+ children: [
688
+ "有 ",
689
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
690
+ style: { color: "#b7791f" },
691
+ children: pendingStatus.count
692
+ }),
693
+ " 条消息发送失败待补发(共 ",
694
+ pendingStatus.chars,
695
+ " 字),daemon 会启动/定时自动重试。",
696
+ pendingStatus.oldestQueuedAt ? ` 最早入队 ${new Date(pendingStatus.oldestQueuedAt).toLocaleString("zh-CN")}` : ""
697
+ ]
698
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
699
+ style: {
700
+ fontSize: 12,
701
+ opacity: .7
702
+ },
703
+ children: pendingStatus ? "无待补发消息(发送失败会自动暂存并在 daemon 重启/定时时补发)。" : "守护进程未运行,暂无数据。"
704
+ })]
644
705
  }),
645
706
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
646
- style: {
647
- display: "flex",
648
- gap: 12,
649
- flexWrap: "wrap",
650
- alignItems: "center",
651
- marginBottom: 8
652
- },
707
+ style: { marginBottom: 12 },
653
708
  children: [
654
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
655
- style: { fontSize: 12 },
656
- children: ["首次静默(分钟)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
657
- type: "number",
658
- min: 1,
659
- value: calm.silenceMin,
660
- onChange: (e) => setCalm((c) => ({
661
- ...c,
662
- silenceMin: e.target.value
663
- })),
664
- style: {
665
- ...inputStyle,
666
- marginLeft: 6,
667
- minWidth: 70
668
- }
669
- })]
709
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
710
+ style: {
711
+ ...titleStyle,
712
+ marginBottom: 4
713
+ },
714
+ children: "⏳ 超时安抚"
715
+ }),
716
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
717
+ style: {
718
+ fontSize: 12,
719
+ opacity: .7,
720
+ marginBottom: 8
721
+ },
722
+ children: "DSH 长时间没有产出消息时,主动发一条\"还在处理\"的安抚消息。改配置后即时生效(最长延迟数秒)。"
670
723
  }),
671
724
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
672
- style: { fontSize: 12 },
673
- children: ["重复间隔(分钟)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
674
- type: "number",
675
- min: 1,
676
- value: calm.intervalMin,
725
+ style: {
726
+ display: "flex",
727
+ alignItems: "center",
728
+ gap: 6,
729
+ fontSize: 12,
730
+ marginBottom: 8
731
+ },
732
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
733
+ type: "checkbox",
734
+ checked: calm.enabled,
677
735
  onChange: (e) => setCalm((c) => ({
678
736
  ...c,
679
- intervalMin: e.target.value
680
- })),
681
- style: {
682
- ...inputStyle,
683
- marginLeft: 6,
684
- minWidth: 70
685
- }
686
- })]
737
+ enabled: e.target.checked
738
+ }))
739
+ }), "启用安抚消息"]
740
+ }),
741
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
742
+ style: {
743
+ display: "flex",
744
+ gap: 12,
745
+ flexWrap: "wrap",
746
+ alignItems: "center",
747
+ marginBottom: 8
748
+ },
749
+ children: [
750
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
751
+ style: { fontSize: 12 },
752
+ children: ["首次静默(分钟)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
753
+ type: "number",
754
+ min: 1,
755
+ value: calm.silenceMin,
756
+ onChange: (e) => setCalm((c) => ({
757
+ ...c,
758
+ silenceMin: e.target.value
759
+ })),
760
+ style: {
761
+ ...inputStyle,
762
+ marginLeft: 6,
763
+ minWidth: 70
764
+ }
765
+ })]
766
+ }),
767
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
768
+ style: { fontSize: 12 },
769
+ children: ["重复间隔(分钟)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
770
+ type: "number",
771
+ min: 1,
772
+ value: calm.intervalMin,
773
+ onChange: (e) => setCalm((c) => ({
774
+ ...c,
775
+ intervalMin: e.target.value
776
+ })),
777
+ style: {
778
+ ...inputStyle,
779
+ marginLeft: 6,
780
+ minWidth: 70
781
+ }
782
+ })]
783
+ }),
784
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
785
+ style: { fontSize: 12 },
786
+ children: ["每轮上限(次,0=不限)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
787
+ type: "number",
788
+ min: 0,
789
+ value: calm.maxCount,
790
+ onChange: (e) => setCalm((c) => ({
791
+ ...c,
792
+ maxCount: e.target.value
793
+ })),
794
+ style: {
795
+ ...inputStyle,
796
+ marginLeft: 6,
797
+ minWidth: 70
798
+ }
799
+ })]
800
+ })
801
+ ]
687
802
  }),
688
803
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
689
- style: { fontSize: 12 },
690
- children: ["每轮上限(次,0=不限)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
691
- type: "number",
692
- min: 0,
693
- value: calm.maxCount,
804
+ style: {
805
+ fontSize: 12,
806
+ display: "block",
807
+ marginBottom: 6
808
+ },
809
+ children: ["自定义文案(每行一条,留空用内置默认;每次随机取一条)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
810
+ value: calm.messages,
694
811
  onChange: (e) => setCalm((c) => ({
695
812
  ...c,
696
- maxCount: e.target.value
813
+ messages: e.target.value
697
814
  })),
815
+ rows: 3,
698
816
  style: {
699
817
  ...inputStyle,
700
- marginLeft: 6,
701
- minWidth: 70
818
+ display: "block",
819
+ marginTop: 4,
820
+ minWidth: "100%",
821
+ boxSizing: "border-box",
822
+ resize: "vertical",
823
+ fontFamily: "inherit"
702
824
  }
703
825
  })]
704
- })
705
- ]
706
- }),
707
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
708
- style: {
709
- fontSize: 12,
710
- display: "block",
711
- marginBottom: 6
712
- },
713
- children: ["自定义文案(每行一条,留空用内置默认;每次随机取一条)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
714
- value: calm.messages,
715
- onChange: (e) => setCalm((c) => ({
716
- ...c,
717
- messages: e.target.value
718
- })),
719
- rows: 3,
720
- style: {
721
- ...inputStyle,
722
- display: "block",
723
- marginTop: 4,
724
- minWidth: "100%",
725
- boxSizing: "border-box",
726
- resize: "vertical",
727
- fontFamily: "inherit"
728
- }
729
- })]
730
- }),
731
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
732
- style: {
733
- display: "flex",
734
- gap: 8,
735
- alignItems: "center"
736
- },
737
- children: [
738
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
739
- type: "button",
740
- style: buttonStyle,
741
- disabled: calmBusy,
742
- onClick: () => void saveCalm(),
743
- children: "保存安抚设置"
744
- }),
745
- calmMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
746
- role: "status",
747
- style: {
748
- color: "#2f9e44",
749
- fontSize: 12
750
- },
751
- children: calmMessage
752
826
  }),
753
- calmError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
754
- role: "alert",
827
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
755
828
  style: {
756
- color: "#e5484d",
757
- fontSize: 12
829
+ display: "flex",
830
+ gap: 8,
831
+ alignItems: "center"
758
832
  },
759
- children: calmError
833
+ children: [
834
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
835
+ type: "button",
836
+ style: buttonStyle,
837
+ disabled: calmBusy,
838
+ onClick: () => void saveCalm(),
839
+ children: "保存安抚设置"
840
+ }),
841
+ calmMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
842
+ role: "status",
843
+ style: {
844
+ color: "#2f9e44",
845
+ fontSize: 12
846
+ },
847
+ children: calmMessage
848
+ }),
849
+ calmError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
850
+ role: "alert",
851
+ style: {
852
+ color: "#e5484d",
853
+ fontSize: 12
854
+ },
855
+ children: calmError
856
+ })
857
+ ]
760
858
  })
761
859
  ]
762
860
  })
763
861
  ]
764
862
  }),
765
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
766
- style: { marginBottom: 12 },
767
- children: [
768
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
863
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Section, {
864
+ title: "⚡ 系统行为",
865
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
866
+ style: { marginBottom: 12 },
867
+ children: [
868
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
869
+ style: {
870
+ ...titleStyle,
871
+ marginBottom: 4
872
+ },
873
+ children: "💤 防休眠"
874
+ }),
875
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
876
+ style: {
877
+ fontSize: 12,
878
+ opacity: .7,
879
+ marginBottom: 8
880
+ },
881
+ children: "守护进程运行期间抑制系统休眠(锁屏/合盖不挂起,微信消息持续响应)。macOS 用 caffeinate、Linux 用 systemd-inhibit、Windows 尽力而为。"
882
+ }),
883
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
884
+ style: {
885
+ display: "flex",
886
+ alignItems: "center",
887
+ gap: 6,
888
+ fontSize: 12
889
+ },
890
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
891
+ type: "checkbox",
892
+ checked: preventSleep,
893
+ disabled: calmBusy,
894
+ onChange: (e) => void changePreventSleep(e.target.checked)
895
+ }), "启用防休眠(重启守护进程后生效)"]
896
+ })
897
+ ]
898
+ })
899
+ }),
900
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Section, {
901
+ title: "🔐 多用户与安全",
902
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
903
+ style: { marginBottom: 12 },
904
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
769
905
  style: {
770
906
  ...titleStyle,
771
907
  marginBottom: 4
772
908
  },
773
- children: "💤 防休眠"
774
- }),
775
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
909
+ children: "🔐 信任用户(多用户)"
910
+ }), !trust ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
776
911
  style: {
777
912
  fontSize: 12,
778
- opacity: .7,
779
- marginBottom: 8
780
- },
781
- children: "守护进程运行期间抑制系统休眠(锁屏/合盖不挂起,微信消息持续响应)。macOS 用 caffeinate、Linux 用 systemd-inhibit、Windows 尽力而为。"
782
- }),
783
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
784
- style: {
785
- display: "flex",
786
- alignItems: "center",
787
- gap: 6,
788
- fontSize: 12
913
+ opacity: .7
789
914
  },
790
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
791
- type: "checkbox",
792
- checked: preventSleep,
793
- disabled: calmBusy,
794
- onChange: (e) => void changePreventSleep(e.target.checked)
795
- }), "启用防休眠(重启守护进程后生效)"]
796
- })
797
- ]
798
- }),
799
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
800
- style: { marginBottom: 12 },
801
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
802
- style: {
803
- ...titleStyle,
804
- marginBottom: 4
805
- },
806
- children: "🔐 信任用户(多用户)"
807
- }), !trust ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
808
- style: {
809
- fontSize: 12,
810
- opacity: .7
811
- },
812
- children: "加载中…"
813
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
814
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
815
- style: {
816
- fontSize: 12,
817
- opacity: .85,
818
- marginBottom: 6
819
- },
820
- children: ["信任模式", /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
821
- value: trust.mode,
822
- onChange: (e) => changeTrustMode(e.target.value),
823
- disabled: trustBusy,
915
+ children: "加载中…"
916
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
917
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
824
918
  style: {
825
- ...inputStyle,
826
- marginLeft: 8,
827
- minWidth: 240
919
+ fontSize: 12,
920
+ opacity: .85,
921
+ marginBottom: 6
922
+ },
923
+ children: ["信任模式", /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
924
+ value: trust.mode,
925
+ onChange: (e) => changeTrustMode(e.target.value),
926
+ disabled: trustBusy,
927
+ style: {
928
+ ...inputStyle,
929
+ marginLeft: 8,
930
+ minWidth: 240
931
+ },
932
+ "aria-label": "选择信任模式",
933
+ children: [
934
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
935
+ value: "owner-only",
936
+ children: TRUST_MODE_LABELS["owner-only"]
937
+ }),
938
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
939
+ value: "bootstrap",
940
+ children: TRUST_MODE_LABELS.bootstrap
941
+ }),
942
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
943
+ value: "manual",
944
+ children: TRUST_MODE_LABELS.manual
945
+ })
946
+ ]
947
+ })]
948
+ }),
949
+ trust.mode === "bootstrap" && trust.bootstrapConsumed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
950
+ style: {
951
+ fontSize: 12,
952
+ color: "#b7791f",
953
+ marginBottom: 6
954
+ },
955
+ children: "⚠️ bootstrap 首次名额已用完,后续陌生人不会再自动入集,请用下方表单手动添加或切到 manual。"
956
+ }),
957
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
958
+ style: {
959
+ display: "flex",
960
+ alignItems: "center",
961
+ gap: 6,
962
+ fontSize: 12,
963
+ marginBottom: 8
964
+ },
965
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
966
+ type: "checkbox",
967
+ checked: trust.notifyRejected,
968
+ disabled: trustBusy,
969
+ onChange: (e) => toggleNotifyRejected(e.target.checked)
970
+ }), "陌生人尝试联系时向 owner 推送提醒"]
971
+ }),
972
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
973
+ style: {
974
+ fontSize: 12,
975
+ opacity: .7,
976
+ marginBottom: 8
828
977
  },
829
- "aria-label": "选择信任模式",
830
978
  children: [
831
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
832
- value: "owner-only",
833
- children: TRUST_MODE_LABELS["owner-only"]
834
- }),
835
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
836
- value: "bootstrap",
837
- children: TRUST_MODE_LABELS.bootstrap
838
- }),
839
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
840
- value: "manual",
841
- children: TRUST_MODE_LABELS.manual
842
- })
979
+ "owner:",
980
+ trust.owner || "(未绑定)",
981
+ " · 信任用户:",
982
+ trust.trusted.length,
983
+ " "
843
984
  ]
844
- })]
845
- }),
846
- trust.mode === "bootstrap" && trust.bootstrapConsumed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
847
- style: {
848
- fontSize: 12,
849
- color: "#b7791f",
850
- marginBottom: 6
851
- },
852
- children: "⚠️ bootstrap 首次名额已用完,后续陌生人不会再自动入集,请用下方表单手动添加或切到 manual。"
853
- }),
854
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
855
- style: {
856
- display: "flex",
857
- alignItems: "center",
858
- gap: 6,
859
- fontSize: 12,
860
- marginBottom: 8
861
- },
862
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
863
- type: "checkbox",
864
- checked: trust.notifyRejected,
865
- disabled: trustBusy,
866
- onChange: (e) => toggleNotifyRejected(e.target.checked)
867
- }), "陌生人尝试联系时向 owner 推送提醒"]
868
- }),
869
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
870
- style: {
871
- fontSize: 12,
872
- opacity: .7,
873
- marginBottom: 8
874
- },
875
- children: [
876
- "owner:",
877
- trust.owner || "(未绑定)",
878
- " · 信任用户:",
879
- trust.trusted.length,
880
- " 个"
881
- ]
882
- }),
883
- trust.trusted.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
884
- style: {
885
- marginBottom: 8,
886
- display: "flex",
887
- flexDirection: "column",
888
- gap: 6
889
- },
890
- children: trust.trusted.map((u) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
985
+ }),
986
+ trust.trusted.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
987
+ style: {
988
+ marginBottom: 8,
989
+ display: "flex",
990
+ flexDirection: "column",
991
+ gap: 6
992
+ },
993
+ children: trust.trusted.map((u) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
994
+ style: {
995
+ display: "flex",
996
+ alignItems: "center",
997
+ gap: 8,
998
+ padding: "6px 8px",
999
+ background: "var(--surface-3, rgba(127,127,127,.05))",
1000
+ border: "1px solid var(--border-color, rgba(127,127,127,.12))",
1001
+ borderRadius: 6
1002
+ },
1003
+ children: [
1004
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1005
+ style: { fontWeight: 600 },
1006
+ children: u.userId
1007
+ }),
1008
+ u.note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1009
+ style: {
1010
+ opacity: .7,
1011
+ fontSize: 12
1012
+ },
1013
+ children: u.note
1014
+ }),
1015
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1016
+ style: {
1017
+ marginLeft: "auto",
1018
+ fontSize: 11,
1019
+ opacity: .6
1020
+ },
1021
+ children: [
1022
+ u.by === "bootstrap" ? "自动入集" : u.by === "restore" ? "迁移导入" : "手动添加",
1023
+ " · ",
1024
+ formatTime(u.lastSeenAt)
1025
+ ]
1026
+ }),
1027
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1028
+ type: "button",
1029
+ style: {
1030
+ ...buttonStyle,
1031
+ color: "#e5484d"
1032
+ },
1033
+ disabled: trustBusy,
1034
+ onClick: () => removeTrustedUser(u.userId),
1035
+ children: "吊销"
1036
+ })
1037
+ ]
1038
+ }, u.userId))
1039
+ }),
1040
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
891
1041
  style: {
892
1042
  display: "flex",
893
- alignItems: "center",
894
1043
  gap: 8,
895
- padding: "6px 8px",
896
- background: "var(--surface-3, rgba(127,127,127,.05))",
897
- border: "1px solid var(--border-color, rgba(127,127,127,.12))",
898
- borderRadius: 6
1044
+ flexWrap: "wrap",
1045
+ alignItems: "center"
899
1046
  },
900
1047
  children: [
901
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
902
- style: { fontWeight: 600 },
903
- children: u.userId
904
- }),
905
- u.note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1048
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1049
+ type: "text",
1050
+ value: newTrustId,
1051
+ onChange: (e) => setNewTrustId(e.target.value),
1052
+ placeholder: "要添加的微信 userId",
906
1053
  style: {
907
- opacity: .7,
908
- fontSize: 12
909
- },
910
- children: u.note
1054
+ ...inputStyle,
1055
+ minWidth: 180
1056
+ }
911
1057
  }),
912
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1058
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1059
+ type: "text",
1060
+ value: newTrustNote,
1061
+ onChange: (e) => setNewTrustNote(e.target.value),
1062
+ placeholder: "备注(可选)",
913
1063
  style: {
914
- marginLeft: "auto",
915
- fontSize: 11,
916
- opacity: .6
917
- },
918
- children: [
919
- u.by === "bootstrap" ? "自动入集" : u.by === "restore" ? "迁移导入" : "手动添加",
920
- " · ",
921
- formatTime(u.lastSeenAt)
922
- ]
1064
+ ...inputStyle,
1065
+ minWidth: 120
1066
+ }
923
1067
  }),
924
1068
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
925
1069
  type: "button",
926
- style: {
927
- ...buttonStyle,
928
- color: "#e5484d"
929
- },
930
- disabled: trustBusy,
931
- onClick: () => removeTrustedUser(u.userId),
932
- children: "吊销"
1070
+ style: buttonStyle,
1071
+ disabled: trustBusy || !newTrustId.trim(),
1072
+ onClick: () => void addTrustedUser(),
1073
+ children: "添加信任"
933
1074
  })
934
1075
  ]
935
- }, u.userId))
936
- }),
937
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
938
- style: {
939
- display: "flex",
940
- gap: 8,
941
- flexWrap: "wrap",
942
- alignItems: "center"
943
- },
944
- children: [
945
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
946
- type: "text",
947
- value: newTrustId,
948
- onChange: (e) => setNewTrustId(e.target.value),
949
- placeholder: "要添加的微信 userId",
950
- style: {
951
- ...inputStyle,
952
- minWidth: 180
953
- }
954
- }),
955
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
956
- type: "text",
957
- value: newTrustNote,
958
- onChange: (e) => setNewTrustNote(e.target.value),
959
- placeholder: "备注(可选)",
960
- style: {
961
- ...inputStyle,
962
- minWidth: 120
963
- }
964
- }),
965
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
966
- type: "button",
967
- style: buttonStyle,
968
- disabled: trustBusy || !newTrustId.trim(),
969
- onClick: () => void addTrustedUser(),
970
- children: "添加信任"
971
- })
972
- ]
973
- }),
974
- trustMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
975
- role: "status",
976
- style: {
977
- color: "#2f9e44",
978
- marginTop: 6,
979
- fontSize: 12
980
- },
981
- children: trustMessage
982
- }),
983
- trustError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
984
- role: "alert",
985
- style: {
986
- color: "#e5484d",
987
- marginTop: 6,
988
- fontSize: 12
989
- },
990
- children: trustError
991
- }),
992
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
993
- style: {
994
- fontSize: 12,
995
- opacity: .7,
996
- marginTop: 8
997
- },
998
- children: "信任用户与 owner 各自拥有独立会话、独立上下文,互不可见。撤销信任后其新消息将被拒绝,但已有历史保留。 修改信任模式后,新入站消息立即生效,无需重启。"
999
- })
1000
- ] })]
1076
+ }),
1077
+ trustMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1078
+ role: "status",
1079
+ style: {
1080
+ color: "#2f9e44",
1081
+ marginTop: 6,
1082
+ fontSize: 12
1083
+ },
1084
+ children: trustMessage
1085
+ }),
1086
+ trustError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1087
+ role: "alert",
1088
+ style: {
1089
+ color: "#e5484d",
1090
+ marginTop: 6,
1091
+ fontSize: 12
1092
+ },
1093
+ children: trustError
1094
+ }),
1095
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1096
+ style: {
1097
+ fontSize: 12,
1098
+ opacity: .7,
1099
+ marginTop: 8
1100
+ },
1101
+ children: "信任用户与 owner 各自拥有独立会话、独立上下文,互不可见。撤销信任后其新消息将被拒绝,但已有历史保留。 修改信任模式后,新入站消息立即生效,无需重启。"
1102
+ })
1103
+ ] })]
1104
+ })
1001
1105
  }),
1002
1106
  setupPhase === "starting" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1003
1107
  role: "status",
@@ -1083,21 +1187,6 @@ window.__ModuleLoader__.load({
1083
1187
  })
1084
1188
  ]
1085
1189
  }),
1086
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
1087
- style: outputStyle,
1088
- "aria-live": "polite",
1089
- children: output
1090
- }),
1091
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1092
- style: buttonRowStyle,
1093
- children: actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1094
- type: "button",
1095
- style: buttonStyle,
1096
- disabled: action.disabled ?? false,
1097
- onClick: action.run,
1098
- children: action.label
1099
- }, action.label))
1100
- }),
1101
1190
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1102
1191
  style: hintStyle,
1103
1192
  children: "也可在 DSH 对话中直接使用 wechat_bridge_setup / wechat_bridge_status / wechat_bridge_start / wechat_bridge_stop / wechat_bridge_logs 等工具。"