@lanbaolu/dsh-wechat-bridge 0.6.0 → 0.7.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
@@ -17,7 +17,12 @@ window.__ModuleLoader__.load({
17
17
  background: "var(--surface-2, rgba(127,127,127,.06))",
18
18
  border: "1px solid var(--border-color, rgba(127,127,127,.18))",
19
19
  borderRadius: 10,
20
- margin: "8px 0"
20
+ margin: "8px 0",
21
+ "--text-1": "var(--dsw-alias-label-primary, #1f2328)",
22
+ "--surface-2": "var(--dsw-alias-bg-module-platform, rgba(127,127,127,.06))",
23
+ "--surface-3": "var(--dsw-alias-bg-layer-2, rgba(0,0,0,.04))",
24
+ "--border-color": "var(--dsw-alias-border-l2, rgba(127,127,127,.18))",
25
+ "--button-bg": "var(--dsw-alias-bg-layer-1, #fff)"
21
26
  };
22
27
  const titleStyle = {
23
28
  fontWeight: 600,
@@ -76,6 +81,37 @@ window.__ModuleLoader__.load({
76
81
  bootstrap: "首位陌生人自动入集(一次性)",
77
82
  manual: "仅手动添加的人"
78
83
  };
84
+ const CALM_DEFAULTS = {
85
+ enabled: true,
86
+ silenceMin: "5",
87
+ intervalMin: "5",
88
+ maxCount: "0",
89
+ messages: ""
90
+ };
91
+ function calmFromConfig(calm) {
92
+ return {
93
+ enabled: calm?.enabled !== false,
94
+ silenceMin: calm?.silenceMs && calm.silenceMs > 0 ? String(Math.round(calm.silenceMs / 6e4)) : "5",
95
+ intervalMin: calm?.intervalMs && calm.intervalMs > 0 ? String(Math.round(calm.intervalMs / 6e4)) : "5",
96
+ maxCount: calm?.maxCount !== void 0 ? String(calm.maxCount) : "0",
97
+ messages: calm?.messages?.length ? calm.messages.join("\n") : ""
98
+ };
99
+ }
100
+ function calmToConfig(ui) {
101
+ const toMin = (v) => {
102
+ const n = Number(v);
103
+ return Number.isFinite(n) && n > 0 ? Math.round(n * 6e4) : void 0;
104
+ };
105
+ const maxCount = Number(ui.maxCount);
106
+ const messages = ui.messages.split("\n").map((s) => s.trim()).filter(Boolean);
107
+ return {
108
+ enabled: ui.enabled,
109
+ silenceMs: toMin(ui.silenceMin),
110
+ intervalMs: toMin(ui.intervalMin),
111
+ maxCount: Number.isFinite(maxCount) && maxCount >= 0 ? Math.round(maxCount) : void 0,
112
+ messages: messages.length > 0 ? messages : void 0
113
+ };
114
+ }
79
115
  function formatTime(ms) {
80
116
  if (!ms) return "从未活跃";
81
117
  try {
@@ -102,6 +138,10 @@ window.__ModuleLoader__.load({
102
138
  const [projectMessage, setProjectMessage] = (0, react.useState)("");
103
139
  const [projectError, setProjectError] = (0, react.useState)("");
104
140
  const [notifyStatus, setNotifyStatus] = (0, react.useState)(null);
141
+ const [calm, setCalm] = (0, react.useState)(CALM_DEFAULTS);
142
+ const [calmBusy, setCalmBusy] = (0, react.useState)(false);
143
+ const [calmMessage, setCalmMessage] = (0, react.useState)("");
144
+ const [calmError, setCalmError] = (0, react.useState)("");
105
145
  const [trust, setTrust] = (0, react.useState)(null);
106
146
  const [trustBusy, setTrustBusy] = (0, react.useState)(false);
107
147
  const [trustMessage, setTrustMessage] = (0, react.useState)("");
@@ -137,7 +177,33 @@ window.__ModuleLoader__.load({
137
177
  if (trustData && typeof trustData === "object" && trustData.ok) setTrust(trustData);
138
178
  }
139
179
  } catch {}
180
+ try {
181
+ const cfgRes = await fetch(`${API_BASE}/config`, { cache: "no-store" });
182
+ if (cfgRes.ok) {
183
+ const cfgData = await cfgRes.json();
184
+ if (cfgData && typeof cfgData === "object" && cfgData.ok) setCalm(calmFromConfig(cfgData.calm));
185
+ }
186
+ } catch {}
140
187
  }, []);
188
+ async function saveCalm() {
189
+ setCalmBusy(true);
190
+ setCalmError("");
191
+ setCalmMessage("");
192
+ try {
193
+ const res = await fetch(`${API_BASE}/config`, {
194
+ method: "POST",
195
+ headers: { "Content-Type": "application/json" },
196
+ body: JSON.stringify({ calm: calmToConfig(calm) })
197
+ });
198
+ const data = await res.json().catch(() => null);
199
+ if (!res.ok || !data?.ok) throw new Error(data?.error || `HTTP ${res.status}`);
200
+ setCalmMessage("已保存,下次安抚时生效(最长延迟数秒)。");
201
+ } catch (err) {
202
+ setCalmError(err instanceof Error ? err.message : String(err));
203
+ } finally {
204
+ setCalmBusy(false);
205
+ }
206
+ }
141
207
  (0, react.useEffect)(() => {
142
208
  refresh();
143
209
  }, [refresh]);
@@ -516,6 +582,161 @@ window.__ModuleLoader__.load({
516
582
  children: "守护进程未运行,暂无数据。"
517
583
  })]
518
584
  }),
585
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
586
+ style: { marginBottom: 12 },
587
+ children: [
588
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
589
+ style: {
590
+ ...titleStyle,
591
+ marginBottom: 4
592
+ },
593
+ children: "⏳ 超时安抚"
594
+ }),
595
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
596
+ style: {
597
+ fontSize: 12,
598
+ opacity: .7,
599
+ marginBottom: 8
600
+ },
601
+ children: "DSH 长时间没有产出消息时,主动发一条\"还在处理\"的安抚消息。改配置后即时生效(最长延迟数秒)。"
602
+ }),
603
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
604
+ style: {
605
+ display: "flex",
606
+ alignItems: "center",
607
+ gap: 6,
608
+ fontSize: 12,
609
+ marginBottom: 8
610
+ },
611
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
612
+ type: "checkbox",
613
+ checked: calm.enabled,
614
+ onChange: (e) => setCalm((c) => ({
615
+ ...c,
616
+ enabled: e.target.checked
617
+ }))
618
+ }), "启用安抚消息"]
619
+ }),
620
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
621
+ style: {
622
+ display: "flex",
623
+ gap: 12,
624
+ flexWrap: "wrap",
625
+ alignItems: "center",
626
+ marginBottom: 8
627
+ },
628
+ children: [
629
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
630
+ style: { fontSize: 12 },
631
+ children: ["首次静默(分钟)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
632
+ type: "number",
633
+ min: 1,
634
+ value: calm.silenceMin,
635
+ onChange: (e) => setCalm((c) => ({
636
+ ...c,
637
+ silenceMin: e.target.value
638
+ })),
639
+ style: {
640
+ ...inputStyle,
641
+ marginLeft: 6,
642
+ minWidth: 70
643
+ }
644
+ })]
645
+ }),
646
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
647
+ style: { fontSize: 12 },
648
+ children: ["重复间隔(分钟)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
649
+ type: "number",
650
+ min: 1,
651
+ value: calm.intervalMin,
652
+ onChange: (e) => setCalm((c) => ({
653
+ ...c,
654
+ intervalMin: e.target.value
655
+ })),
656
+ style: {
657
+ ...inputStyle,
658
+ marginLeft: 6,
659
+ minWidth: 70
660
+ }
661
+ })]
662
+ }),
663
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
664
+ style: { fontSize: 12 },
665
+ children: ["每轮上限(次,0=不限)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
666
+ type: "number",
667
+ min: 0,
668
+ value: calm.maxCount,
669
+ onChange: (e) => setCalm((c) => ({
670
+ ...c,
671
+ maxCount: e.target.value
672
+ })),
673
+ style: {
674
+ ...inputStyle,
675
+ marginLeft: 6,
676
+ minWidth: 70
677
+ }
678
+ })]
679
+ })
680
+ ]
681
+ }),
682
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
683
+ style: {
684
+ fontSize: 12,
685
+ display: "block",
686
+ marginBottom: 6
687
+ },
688
+ children: ["自定义文案(每行一条,留空用内置默认;每次随机取一条)", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
689
+ value: calm.messages,
690
+ onChange: (e) => setCalm((c) => ({
691
+ ...c,
692
+ messages: e.target.value
693
+ })),
694
+ rows: 3,
695
+ style: {
696
+ ...inputStyle,
697
+ display: "block",
698
+ marginTop: 4,
699
+ minWidth: "100%",
700
+ boxSizing: "border-box",
701
+ resize: "vertical",
702
+ fontFamily: "inherit"
703
+ }
704
+ })]
705
+ }),
706
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
707
+ style: {
708
+ display: "flex",
709
+ gap: 8,
710
+ alignItems: "center"
711
+ },
712
+ children: [
713
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
714
+ type: "button",
715
+ style: buttonStyle,
716
+ disabled: calmBusy,
717
+ onClick: () => void saveCalm(),
718
+ children: "保存安抚设置"
719
+ }),
720
+ calmMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
721
+ role: "status",
722
+ style: {
723
+ color: "#2f9e44",
724
+ fontSize: 12
725
+ },
726
+ children: calmMessage
727
+ }),
728
+ calmError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
729
+ role: "alert",
730
+ style: {
731
+ color: "#e5484d",
732
+ fontSize: 12
733
+ },
734
+ children: calmError
735
+ })
736
+ ]
737
+ })
738
+ ]
739
+ }),
519
740
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
520
741
  style: { marginBottom: 12 },
521
742
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","useCallback"],"sources":["../src/client/Panel.tsx","../src/client/index.ts"],"sourcesContent":["import type * as React from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport type { SettingsSectionOwnerProps } from '@deepseek-ai/dsh-client-ui-settings/client'\n\nconst API_BASE = '/@lanbaolu/dsh-wechat-bridge'\n\nconst panelStyle: React.CSSProperties = {\n padding: '14px 16px',\n fontFamily: 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n fontSize: 13,\n lineHeight: 1.6,\n color: 'var(--text-1, #1f2328)',\n background: 'var(--surface-2, rgba(127,127,127,.06))',\n border: '1px solid var(--border-color, rgba(127,127,127,.18))',\n borderRadius: 10,\n margin: '8px 0',\n}\n\nconst titleStyle: React.CSSProperties = {\n fontWeight: 600,\n fontSize: 14,\n marginBottom: 8,\n}\n\nconst outputStyle: React.CSSProperties = {\n margin: '4px 0 8px',\n padding: '8px 10px',\n background: 'var(--surface-3, rgba(0,0,0,.04))',\n border: '1px solid var(--border-color, rgba(127,127,127,.15))',\n borderRadius: 6,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',\n fontSize: 12,\n maxHeight: 360,\n overflow: 'auto',\n}\n\nconst buttonRowStyle: React.CSSProperties = {\n display: 'flex',\n gap: 8,\n flexWrap: 'wrap',\n alignItems: 'center',\n}\n\nconst buttonStyle: React.CSSProperties = {\n padding: '4px 10px',\n border: '1px solid var(--border-color, rgba(127,127,127,.4))',\n borderRadius: 6,\n background: 'var(--button-bg, #fff)',\n color: 'var(--text-1, inherit)',\n cursor: 'pointer',\n fontSize: 12,\n}\n\nconst inputStyle: React.CSSProperties = {\n padding: '4px 8px',\n border: '1px solid var(--border-color, rgba(127,127,127,.4))',\n borderRadius: 6,\n background: 'var(--surface-3, rgba(127,127,127,.06))',\n color: 'var(--text-1, inherit)',\n fontSize: 12,\n minWidth: 220,\n}\n\nconst selectStyle: React.CSSProperties = {\n ...inputStyle,\n minWidth: 320,\n maxWidth: '100%',\n}\n\nconst hintStyle: React.CSSProperties = {\n marginTop: 8,\n fontSize: 12,\n opacity: 0.7,\n}\n\ntype SetupPhase = 'idle' | 'starting' | 'qr' | 'confirmed' | 'error'\n\ninterface ProjectSessionItem {\n sessionId: string\n workspaceId: string\n workspaceTitle: string\n path: string\n cwd?: string\n createdAt: string\n live: boolean\n}\n\ninterface SelectedProjectInfo {\n sessionId: string\n workspaceId: string\n workspaceTitle: string\n path: string\n}\n\ninterface NotifyStatus {\n dailySent: number\n dailyLimit: number\n hourlySent: number\n hourlyLimit: number\n pendingCount: number\n queueCapacity: number\n}\n\ninterface TrustedUser {\n userId: string\n addedAt: string\n by: 'owner' | 'bootstrap' | 'restore'\n lastSeenAt?: number\n note?: string\n}\n\ninterface TrustInfo {\n mode: 'owner-only' | 'bootstrap' | 'manual'\n bootstrapConsumed: boolean\n owner: string\n notifyRejected: boolean\n trusted: TrustedUser[]\n}\n\nconst TRUST_MODE_LABELS: Record<TrustInfo['mode'], string> = {\n 'owner-only': '仅本机主人(默认)',\n bootstrap: '首位陌生人自动入集(一次性)',\n manual: '仅手动添加的人',\n}\n\nfunction formatTime(ms?: number): string {\n if (!ms) return '从未活跃'\n try {\n return new Date(ms).toLocaleString('zh-CN')\n } catch {\n return '未知'\n }\n}\n\nexport function WechatBridgePanel(_props: SettingsSectionOwnerProps): React.JSX.Element {\n const [output, setOutput] = useState('加载中…')\n const [error, setError] = useState<string | null>(null)\n const [busy, setBusy] = useState<string | null>(null)\n const [workingDir, setWorkingDir] = useState('')\n const [setupPhase, setSetupPhase] = useState<SetupPhase>('idle')\n const [qrcodeDataUrl, setQrcodeDataUrl] = useState('')\n const [qrcodeId, setQrcodeId] = useState('')\n const [setupError, setSetupError] = useState('')\n const [boundAccountId, setBoundAccountId] = useState('')\n const [daemonMessage, setDaemonMessage] = useState('')\n const [projects, setProjects] = useState<ProjectSessionItem[]>([])\n const [projectChoice, setProjectChoice] = useState('')\n const [boundProject, setBoundProject] = useState<SelectedProjectInfo | null>(null)\n const [projectBusy, setProjectBusy] = useState(false)\n const [projectMessage, setProjectMessage] = useState('')\n const [projectError, setProjectError] = useState('')\n const [notifyStatus, setNotifyStatus] = useState<NotifyStatus | null>(null)\n const [trust, setTrust] = useState<TrustInfo | null>(null)\n const [trustBusy, setTrustBusy] = useState(false)\n const [trustMessage, setTrustMessage] = useState('')\n const [trustError, setTrustError] = useState('')\n const [newTrustId, setNewTrustId] = useState('')\n const [newTrustNote, setNewTrustNote] = useState('')\n\n const refresh = useCallback(async () => {\n try {\n const [statusRes, projectsRes, notifyRes] = await Promise.all([\n fetch(`${API_BASE}/status`, { cache: 'no-store' }),\n fetch(`${API_BASE}/projects`, { cache: 'no-store' }),\n fetch(`${API_BASE}/notify/status`, { cache: 'no-store' }),\n ])\n if (!statusRes.ok) throw new Error(`status HTTP ${statusRes.status}`)\n if (!projectsRes.ok) throw new Error(`projects HTTP ${projectsRes.status}`)\n const data = await statusRes.json()\n const projectsData = await projectsRes.json()\n const notifyData = await notifyRes.json().catch(() => null)\n if (notifyData && typeof notifyData === 'object' && typeof (notifyData as { data?: NotifyStatus }).data?.dailyLimit === 'number') {\n setNotifyStatus((notifyData as { data: NotifyStatus }).data)\n } else if (notifyData && typeof (notifyData as NotifyStatus).dailyLimit === 'number') {\n setNotifyStatus(notifyData as NotifyStatus)\n }\n setOutput(JSON.stringify(data, null, 2))\n if (typeof data.workingDirectory === 'string') {\n setWorkingDir((prev) => prev || data.workingDirectory)\n }\n setBoundProject(data.selectedProject ?? null)\n if (Array.isArray(projectsData.items)) {\n setProjects(projectsData.items as ProjectSessionItem[])\n }\n setError(null)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n }\n // 信任集单独拉取(失败不影响主状态展示)\n try {\n const trustRes = await fetch(`${API_BASE}/trust`, { cache: 'no-store' })\n if (trustRes.ok) {\n const trustData = await trustRes.json()\n if (trustData && typeof trustData === 'object' && trustData.ok) {\n setTrust(trustData as TrustInfo)\n }\n }\n } catch {\n // ignore\n }\n }, [])\n\n useEffect(() => {\n void refresh()\n }, [refresh])\n\n async function run(path: string): Promise<void> {\n setBusy(path)\n setError(null)\n try {\n const res = await fetch(`${API_BASE}/${path}`, { method: 'POST' })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n setOutput(JSON.stringify(data, null, 2))\n await refresh()\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setBusy(null)\n }\n }\n\n async function showLogs(): Promise<void> {\n setBusy('logs')\n setError(null)\n try {\n const res = await fetch(`${API_BASE}/logs`, { cache: 'no-store' })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n setOutput(await res.text())\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setBusy(null)\n }\n }\n\n async function startSetup(): Promise<void> {\n setSetupPhase('starting')\n setSetupError('')\n try {\n const res = await fetch(`${API_BASE}/setup/start`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ workingDirectory: workingDir || undefined }),\n })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n if (!data.ok) throw new Error(data.message || data.error || '启动扫码绑定失败')\n setQrcodeDataUrl(data.qrcodeDataUrl)\n setQrcodeId(data.qrcodeId)\n setWorkingDir(data.workingDirectory || workingDir)\n setSetupPhase('qr')\n } catch (err) {\n setSetupPhase('error')\n setSetupError(err instanceof Error ? err.message : String(err))\n }\n }\n\n async function bindProject(): Promise<void> {\n if (!projectChoice) return\n setProjectBusy(true)\n setProjectError('')\n setProjectMessage('')\n try {\n const res = await fetch(`${API_BASE}/projects/select`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId: projectChoice }),\n })\n const data = await res.json().catch(() => null)\n if (!res.ok || !data?.ok) {\n throw new Error(data?.error || data?.message || `HTTP ${res.status}`)\n }\n const project = data.project as SelectedProjectInfo | undefined\n setProjectMessage(`已绑定项目会话${project?.workspaceTitle ? `:${project.workspaceTitle}` : ''}${data.daemon ? `(${data.daemon})` : ''}`)\n await refresh()\n } catch (err) {\n setProjectError(err instanceof Error ? err.message : String(err))\n } finally {\n setProjectBusy(false)\n }\n }\n\n async function detachProject(): Promise<void> {\n setProjectBusy(true)\n setProjectError('')\n setProjectMessage('')\n try {\n const res = await fetch(`${API_BASE}/projects/detach`, { method: 'POST' })\n const data = await res.json().catch(() => null)\n if (!res.ok || !data?.ok) {\n throw new Error(data?.error || data?.message || `HTTP ${res.status}`)\n }\n setProjectMessage(`已解除项目会话绑定${data.daemon ? `(${data.daemon})` : ''}`)\n setProjectChoice('')\n await refresh()\n } catch (err) {\n setProjectError(err instanceof Error ? err.message : String(err))\n } finally {\n setProjectBusy(false)\n }\n }\n\n // ---- 信任集管理(P1-2 / M4)----\n\n function applyTrustResponse(data: TrustInfo & { ok?: boolean; error?: string }): void {\n if (data.ok === false) throw new Error(data.error || '操作失败')\n setTrust({\n mode: data.mode,\n bootstrapConsumed: data.bootstrapConsumed,\n owner: data.owner,\n notifyRejected: data.notifyRejected,\n trusted: Array.isArray(data.trusted) ? data.trusted : [],\n })\n }\n\n async function trustRequest(path: string, body: Record<string, unknown>, okMessage: string): Promise<void> {\n setTrustBusy(true)\n setTrustError('')\n setTrustMessage('')\n try {\n const res = await fetch(`${API_BASE}/${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n const data = await res.json().catch(() => null)\n if (!res.ok || !data?.ok) {\n throw new Error(data?.error || `HTTP ${res.status}`)\n }\n applyTrustResponse(data as TrustInfo & { ok?: boolean; error?: string })\n setTrustMessage(okMessage)\n } catch (err) {\n setTrustError(err instanceof Error ? err.message : String(err))\n } finally {\n setTrustBusy(false)\n }\n }\n\n async function addTrustedUser(): Promise<void> {\n const id = newTrustId.trim()\n if (!id) return\n await trustRequest('trust/add', { userId: id, note: newTrustNote.trim() || undefined }, `已添加:${id}`)\n setNewTrustId('')\n setNewTrustNote('')\n }\n\n function removeTrustedUser(userId: string): void {\n if (!window.confirm(`确认吊销 ${userId}?其后续消息将被拒绝,已有会话历史保留。`)) return\n void trustRequest('trust/remove', { userId }, `已吊销:${userId}`)\n }\n\n function changeTrustMode(mode: TrustInfo['mode']): void {\n void trustRequest('trust/config', { mode }, `信任模式已切换为:${TRUST_MODE_LABELS[mode]}`)\n }\n\n function toggleNotifyRejected(enabled: boolean): void {\n void trustRequest('trust/config', { notifyRejected: enabled }, enabled ? '已开启陌生人联系提醒' : '已关闭陌生人联系提醒')\n }\n\n useEffect(() => {\n if (setupPhase !== 'qr' || !qrcodeId) return\n\n let cancelled = false\n let timer: number | undefined\n\n async function poll(): Promise<void> {\n try {\n const res = await fetch(`${API_BASE}/setup/status?qrcodeId=${encodeURIComponent(qrcodeId)}`, { cache: 'no-store' })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n if (cancelled) return\n\n if (data.status === 'confirmed') {\n setSetupPhase('confirmed')\n setBoundAccountId(data.accountId || '')\n setDaemonMessage(data.daemon || '')\n void refresh()\n return\n }\n\n if (data.status === 'expired' || (data.status === 'error' && !data.retryable)) {\n setSetupPhase('error')\n setSetupError(data.message || '绑定失败,请重试')\n return\n }\n\n timer = window.setTimeout(() => void poll(), 3000)\n } catch (err) {\n if (!cancelled) {\n setSetupPhase('error')\n setSetupError(err instanceof Error ? err.message : String(err))\n }\n }\n }\n\n void poll()\n return () => {\n cancelled = true\n if (timer) window.clearTimeout(timer)\n }\n }, [setupPhase, qrcodeId, refresh])\n\n function cancelSetup(): void {\n setSetupPhase('idle')\n setQrcodeDataUrl('')\n setQrcodeId('')\n setSetupError('')\n setDaemonMessage('')\n }\n\n const actions: Array<{ label: string; run: () => void; disabled?: boolean }> = [\n { label: '刷新状态', run: () => void refresh() },\n { label: '扫码绑定', run: () => void startSetup(), disabled: setupPhase === 'starting' || setupPhase === 'qr' },\n { label: '启动', run: () => void run('start'), disabled: busy !== null },\n { label: '停止', run: () => void run('stop'), disabled: busy !== null },\n { label: '重启', run: () => void run('restart'), disabled: busy !== null },\n { label: '查看日志', run: () => void showLogs(), disabled: busy !== null },\n ]\n\n return (\n <div style={panelStyle} role=\"region\" aria-label=\"DSH 微信桥接管理面板\">\n <div style={titleStyle}>📱 DSH 微信桥接</div>\n\n {error && <div role=\"alert\" style={{ color: '#e5484d', marginBottom: 8 }}>{error}</div>}\n\n <label style={{ display: 'block', marginBottom: 8, fontSize: 12 }}>\n DSH 工作目录\n <input\n type=\"text\"\n value={workingDir}\n onChange={(e) => setWorkingDir(e.target.value)}\n placeholder=\"例如 ~/Documents/DSH\"\n style={{ ...inputStyle, marginLeft: 8 }}\n />\n </label>\n\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...titleStyle, marginBottom: 4 }}>项目对话绑定</div>\n <div style={{ fontSize: 12, opacity: 0.8 }}>\n {boundProject\n ? `当前绑定:${boundProject.workspaceTitle} · ${boundProject.path} · ${boundProject.sessionId.slice(-8)}`\n : '当前未绑定:微信消息使用独立桥接会话(也可选择项目对话以共享记忆)。'}\n </div>\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center', marginTop: 6 }}>\n <select\n value={projectChoice}\n onChange={(e) => setProjectChoice(e.target.value)}\n style={selectStyle}\n aria-label=\"选择要绑定的项目会话\"\n >\n <option value=\"\">— 选择要绑定的项目会话 —</option>\n {projects.map((project) => (\n <option key={project.sessionId} value={project.sessionId}>\n {project.workspaceTitle} · {project.path} · {project.sessionId.slice(-8)}\n </option>\n ))}\n </select>\n <button type=\"button\" style={buttonStyle} disabled={!projectChoice || projectBusy} onClick={() => void bindProject()}>\n 绑定\n </button>\n <button type=\"button\" style={buttonStyle} disabled={projectBusy || !boundProject} onClick={() => void detachProject()}>\n 解除绑定\n </button>\n </div>\n {projectMessage && (\n <div role=\"status\" style={{ color: '#2f9e44', marginTop: 6, fontSize: 12 }}>{projectMessage}</div>\n )}\n {projectError && (\n <div role=\"alert\" style={{ color: '#e5484d', marginTop: 6, fontSize: 12 }}>{projectError}</div>\n )}\n </div>\n\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...titleStyle, marginBottom: 4 }}>主动通知节流</div>\n {notifyStatus ? (\n <div style={{ fontSize: 12, opacity: 0.85 }}>\n 今日已发 <strong>{notifyStatus.dailySent}</strong> / {notifyStatus.dailyLimit} 条 · 近一小时{' '}\n <strong>{notifyStatus.hourlySent}</strong> / {notifyStatus.hourlyLimit} 条 · 排队中{' '}\n <strong>{notifyStatus.pendingCount}</strong> 条\n <div style={{ marginTop: 4, fontSize: 12, opacity: 0.7 }}>\n agent 通过 wechat_notify 主动推送的通知,超限自动排队延迟发送,避免触发微信风控。\n </div>\n </div>\n ) : (\n <div style={{ fontSize: 12, opacity: 0.7 }}>守护进程未运行,暂无数据。</div>\n )}\n </div>\n\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...titleStyle, marginBottom: 4 }}>🔐 信任用户(多用户)</div>\n {!trust ? (\n <div style={{ fontSize: 12, opacity: 0.7 }}>加载中…</div>\n ) : (\n <>\n <div style={{ fontSize: 12, opacity: 0.85, marginBottom: 6 }}>\n 信任模式\n <select\n value={trust.mode}\n onChange={(e) => changeTrustMode(e.target.value as TrustInfo['mode'])}\n disabled={trustBusy}\n style={{ ...inputStyle, marginLeft: 8, minWidth: 240 }}\n aria-label=\"选择信任模式\"\n >\n <option value=\"owner-only\">{TRUST_MODE_LABELS['owner-only']}</option>\n <option value=\"bootstrap\">{TRUST_MODE_LABELS.bootstrap}</option>\n <option value=\"manual\">{TRUST_MODE_LABELS.manual}</option>\n </select>\n </div>\n {trust.mode === 'bootstrap' && trust.bootstrapConsumed && (\n <div style={{ fontSize: 12, color: '#b7791f', marginBottom: 6 }}>\n ⚠️ bootstrap 首次名额已用完,后续陌生人不会再自动入集,请用下方表单手动添加或切到 manual。\n </div>\n )}\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, marginBottom: 8 }}>\n <input\n type=\"checkbox\"\n checked={trust.notifyRejected}\n disabled={trustBusy}\n onChange={(e) => toggleNotifyRejected(e.target.checked)}\n />\n 陌生人尝试联系时向 owner 推送提醒\n </label>\n <div style={{ fontSize: 12, opacity: 0.7, marginBottom: 8 }}>\n owner:{trust.owner || '(未绑定)'} · 信任用户:{trust.trusted.length} 个\n </div>\n {trust.trusted.length > 0 && (\n <div style={{ marginBottom: 8, display: 'flex', flexDirection: 'column', gap: 6 }}>\n {trust.trusted.map((u) => (\n <div\n key={u.userId}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '6px 8px',\n background: 'var(--surface-3, rgba(127,127,127,.05))',\n border: '1px solid var(--border-color, rgba(127,127,127,.12))',\n borderRadius: 6,\n }}\n >\n <span style={{ fontWeight: 600 }}>{u.userId}</span>\n {u.note && <span style={{ opacity: 0.7, fontSize: 12 }}>{u.note}</span>}\n <span style={{ marginLeft: 'auto', fontSize: 11, opacity: 0.6 }}>\n {u.by === 'bootstrap' ? '自动入集' : u.by === 'restore' ? '迁移导入' : '手动添加'} · {formatTime(u.lastSeenAt)}\n </span>\n <button\n type=\"button\"\n style={{ ...buttonStyle, color: '#e5484d' }}\n disabled={trustBusy}\n onClick={() => removeTrustedUser(u.userId)}\n >\n 吊销\n </button>\n </div>\n ))}\n </div>\n )}\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>\n <input\n type=\"text\"\n value={newTrustId}\n onChange={(e) => setNewTrustId(e.target.value)}\n placeholder=\"要添加的微信 userId\"\n style={{ ...inputStyle, minWidth: 180 }}\n />\n <input\n type=\"text\"\n value={newTrustNote}\n onChange={(e) => setNewTrustNote(e.target.value)}\n placeholder=\"备注(可选)\"\n style={{ ...inputStyle, minWidth: 120 }}\n />\n <button type=\"button\" style={buttonStyle} disabled={trustBusy || !newTrustId.trim()} onClick={() => void addTrustedUser()}>\n 添加信任\n </button>\n </div>\n {trustMessage && <div role=\"status\" style={{ color: '#2f9e44', marginTop: 6, fontSize: 12 }}>{trustMessage}</div>}\n {trustError && <div role=\"alert\" style={{ color: '#e5484d', marginTop: 6, fontSize: 12 }}>{trustError}</div>}\n <div style={{ fontSize: 12, opacity: 0.7, marginTop: 8 }}>\n 信任用户与 owner 各自拥有独立会话、独立上下文,互不可见。撤销信任后其新消息将被拒绝,但已有历史保留。\n 修改信任模式后,新入站消息立即生效,无需重启。\n </div>\n </>\n )}\n </div>\n\n {setupPhase === 'starting' && (\n <div role=\"status\" style={{ marginBottom: 8 }}>正在生成二维码…</div>\n )}\n\n {setupPhase === 'qr' && qrcodeDataUrl && (\n <div style={{ marginBottom: 8 }}>\n <div style={{ fontWeight: 600, marginBottom: 4 }}>请用微信扫描下方二维码完成绑定</div>\n <img\n src={qrcodeDataUrl}\n alt=\"微信扫码绑定二维码\"\n width={240}\n height={240}\n style={{ display: 'block', maxWidth: '100%', height: 'auto', borderRadius: 8, background: '#fff' }}\n />\n <div style={{ fontSize: 12, opacity: 0.7, marginTop: 4 }}>\n 工作目录:{workingDir || '未设置'}。等待扫码确认中…\n </div>\n <button type=\"button\" style={{ ...buttonStyle, marginTop: 8 }} onClick={cancelSetup}>\n 取消绑定\n </button>\n </div>\n )}\n\n {setupPhase === 'confirmed' && (\n <div role=\"status\" style={{ marginBottom: 8, color: '#2f9e44' }}>\n ✅ 绑定成功{boundAccountId ? `:${boundAccountId}` : ''},{daemonMessage || '桥接已自动重启/启动。'}\n </div>\n )}\n\n {setupPhase === 'error' && (\n <div role=\"alert\" style={{ marginBottom: 8, color: '#e5484d' }}>\n ❌ {setupError}\n <button type=\"button\" style={{ ...buttonStyle, marginLeft: 8 }} onClick={() => setSetupPhase('idle')}>\n 重新扫码\n </button>\n </div>\n )}\n\n <pre style={outputStyle} aria-live=\"polite\">{output}</pre>\n\n <div style={buttonRowStyle}>\n {actions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n style={buttonStyle}\n disabled={action.disabled ?? false}\n onClick={action.run}\n >\n {action.label}\n </button>\n ))}\n </div>\n\n <div style={hintStyle}>\n 也可在 DSH 对话中直接使用 wechat_bridge_setup / wechat_bridge_status / wechat_bridge_start / wechat_bridge_stop / wechat_bridge_logs 等工具。\n </div>\n </div>\n )\n}\n","/**\n * @lanbaolu/dsh-wechat-bridge — Web 管理面板。\n *\n * 渲染在 settings.section 槽位(设置页),不绑定具体会话,打开任何任务前都可通过\n * 侧边栏 Settings 进入;通过 DSH Web 同源路由读取/控制桥接状态。\n */\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport { WechatBridgePanel } from './Panel.js'\n\nexport const inject = ['slots']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: '@lanbaolu/dsh-wechat-bridge-panel',\n order: 55,\n label: () => '📱 微信桥接',\n }, WechatBridgePanel),\n ), '@lanbaolu/dsh-wechat-bridge: panel')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useState","useCallback"],"sources":["../src/client/Panel.tsx","../src/client/index.ts"],"sourcesContent":["import type * as React from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport type { SettingsSectionOwnerProps } from '@deepseek-ai/dsh-client-ui-settings/client'\n\nconst API_BASE = '/@lanbaolu/dsh-wechat-bridge'\n\nconst panelStyle = {\n padding: '14px 16px',\n fontFamily: 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n fontSize: 13,\n lineHeight: 1.6,\n color: 'var(--text-1, #1f2328)',\n background: 'var(--surface-2, rgba(127,127,127,.06))',\n border: '1px solid var(--border-color, rgba(127,127,127,.18))',\n borderRadius: 10,\n margin: '8px 0',\n // DSH 宿主不使用 --text-1/--surface-2 等通用变量名(实际变量体系为 --dsw-alias-*),\n // 导致深色主题下文字永远 fallback 到黑色 #1f2328,几乎不可读。\n // 在面板根元素上把用到的变量映射到宿主真实变量,深浅主题自动跟随。\n // @types/react 18 的 CSSProperties 不含 CSS 自定义属性键,故用交叉类型断言。\n '--text-1': 'var(--dsw-alias-label-primary, #1f2328)',\n '--surface-2': 'var(--dsw-alias-bg-module-platform, rgba(127,127,127,.06))',\n '--surface-3': 'var(--dsw-alias-bg-layer-2, rgba(0,0,0,.04))',\n '--border-color': 'var(--dsw-alias-border-l2, rgba(127,127,127,.18))',\n '--button-bg': 'var(--dsw-alias-bg-layer-1, #fff)',\n} as React.CSSProperties &\n Record<'--text-1' | '--surface-2' | '--surface-3' | '--border-color' | '--button-bg', string>\n\nconst titleStyle: React.CSSProperties = {\n fontWeight: 600,\n fontSize: 14,\n marginBottom: 8,\n}\n\nconst outputStyle: React.CSSProperties = {\n margin: '4px 0 8px',\n padding: '8px 10px',\n background: 'var(--surface-3, rgba(0,0,0,.04))',\n border: '1px solid var(--border-color, rgba(127,127,127,.15))',\n borderRadius: 6,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',\n fontSize: 12,\n maxHeight: 360,\n overflow: 'auto',\n}\n\nconst buttonRowStyle: React.CSSProperties = {\n display: 'flex',\n gap: 8,\n flexWrap: 'wrap',\n alignItems: 'center',\n}\n\nconst buttonStyle: React.CSSProperties = {\n padding: '4px 10px',\n border: '1px solid var(--border-color, rgba(127,127,127,.4))',\n borderRadius: 6,\n background: 'var(--button-bg, #fff)',\n color: 'var(--text-1, inherit)',\n cursor: 'pointer',\n fontSize: 12,\n}\n\nconst inputStyle: React.CSSProperties = {\n padding: '4px 8px',\n border: '1px solid var(--border-color, rgba(127,127,127,.4))',\n borderRadius: 6,\n background: 'var(--surface-3, rgba(127,127,127,.06))',\n color: 'var(--text-1, inherit)',\n fontSize: 12,\n minWidth: 220,\n}\n\nconst selectStyle: React.CSSProperties = {\n ...inputStyle,\n minWidth: 320,\n maxWidth: '100%',\n}\n\nconst hintStyle: React.CSSProperties = {\n marginTop: 8,\n fontSize: 12,\n opacity: 0.7,\n}\n\ntype SetupPhase = 'idle' | 'starting' | 'qr' | 'confirmed' | 'error'\n\ninterface ProjectSessionItem {\n sessionId: string\n workspaceId: string\n workspaceTitle: string\n path: string\n cwd?: string\n createdAt: string\n live: boolean\n}\n\ninterface SelectedProjectInfo {\n sessionId: string\n workspaceId: string\n workspaceTitle: string\n path: string\n}\n\ninterface NotifyStatus {\n dailySent: number\n dailyLimit: number\n hourlySent: number\n hourlyLimit: number\n pendingCount: number\n queueCapacity: number\n}\n\ninterface TrustedUser {\n userId: string\n addedAt: string\n by: 'owner' | 'bootstrap' | 'restore'\n lastSeenAt?: number\n note?: string\n}\n\ninterface TrustInfo {\n mode: 'owner-only' | 'bootstrap' | 'manual'\n bootstrapConsumed: boolean\n owner: string\n notifyRejected: boolean\n trusted: TrustedUser[]\n}\n\nconst TRUST_MODE_LABELS: Record<TrustInfo['mode'], string> = {\n 'owner-only': '仅本机主人(默认)',\n bootstrap: '首位陌生人自动入集(一次性)',\n manual: '仅手动添加的人',\n}\n\n/** 超时安抚配置的面板编辑态(分钟用字符串便于输入,保存时转换)。 */\ninterface CalmUiState {\n enabled: boolean\n silenceMin: string\n intervalMin: string\n maxCount: string\n messages: string\n}\n\nconst CALM_DEFAULTS: CalmUiState = { enabled: true, silenceMin: '5', intervalMin: '5', maxCount: '0', messages: '' }\n\nfunction calmFromConfig(calm?: { enabled?: boolean; silenceMs?: number; intervalMs?: number; maxCount?: number; messages?: string[] }): CalmUiState {\n return {\n enabled: calm?.enabled !== false,\n silenceMin: calm?.silenceMs && calm.silenceMs > 0 ? String(Math.round(calm.silenceMs / 60000)) : '5',\n intervalMin: calm?.intervalMs && calm.intervalMs > 0 ? String(Math.round(calm.intervalMs / 60000)) : '5',\n maxCount: calm?.maxCount !== undefined ? String(calm.maxCount) : '0',\n messages: calm?.messages?.length ? calm.messages.join('\\n') : '',\n }\n}\n\nfunction calmToConfig(ui: CalmUiState): { enabled: boolean; silenceMs?: number; intervalMs?: number; maxCount?: number; messages?: string[] } {\n const toMin = (v: string): number | undefined => {\n const n = Number(v)\n return Number.isFinite(n) && n > 0 ? Math.round(n * 60000) : undefined\n }\n const maxCount = Number(ui.maxCount)\n const messages = ui.messages.split('\\n').map((s) => s.trim()).filter(Boolean)\n return {\n enabled: ui.enabled,\n silenceMs: toMin(ui.silenceMin),\n intervalMs: toMin(ui.intervalMin),\n maxCount: Number.isFinite(maxCount) && maxCount >= 0 ? Math.round(maxCount) : undefined,\n messages: messages.length > 0 ? messages : undefined,\n }\n}\n\nfunction formatTime(ms?: number): string {\n if (!ms) return '从未活跃'\n try {\n return new Date(ms).toLocaleString('zh-CN')\n } catch {\n return '未知'\n }\n}\n\nexport function WechatBridgePanel(_props: SettingsSectionOwnerProps): React.JSX.Element {\n const [output, setOutput] = useState('加载中…')\n const [error, setError] = useState<string | null>(null)\n const [busy, setBusy] = useState<string | null>(null)\n const [workingDir, setWorkingDir] = useState('')\n const [setupPhase, setSetupPhase] = useState<SetupPhase>('idle')\n const [qrcodeDataUrl, setQrcodeDataUrl] = useState('')\n const [qrcodeId, setQrcodeId] = useState('')\n const [setupError, setSetupError] = useState('')\n const [boundAccountId, setBoundAccountId] = useState('')\n const [daemonMessage, setDaemonMessage] = useState('')\n const [projects, setProjects] = useState<ProjectSessionItem[]>([])\n const [projectChoice, setProjectChoice] = useState('')\n const [boundProject, setBoundProject] = useState<SelectedProjectInfo | null>(null)\n const [projectBusy, setProjectBusy] = useState(false)\n const [projectMessage, setProjectMessage] = useState('')\n const [projectError, setProjectError] = useState('')\n const [notifyStatus, setNotifyStatus] = useState<NotifyStatus | null>(null)\n const [calm, setCalm] = useState<CalmUiState>(CALM_DEFAULTS)\n const [calmBusy, setCalmBusy] = useState(false)\n const [calmMessage, setCalmMessage] = useState('')\n const [calmError, setCalmError] = useState('')\n const [trust, setTrust] = useState<TrustInfo | null>(null)\n const [trustBusy, setTrustBusy] = useState(false)\n const [trustMessage, setTrustMessage] = useState('')\n const [trustError, setTrustError] = useState('')\n const [newTrustId, setNewTrustId] = useState('')\n const [newTrustNote, setNewTrustNote] = useState('')\n\n const refresh = useCallback(async () => {\n try {\n const [statusRes, projectsRes, notifyRes] = await Promise.all([\n fetch(`${API_BASE}/status`, { cache: 'no-store' }),\n fetch(`${API_BASE}/projects`, { cache: 'no-store' }),\n fetch(`${API_BASE}/notify/status`, { cache: 'no-store' }),\n ])\n if (!statusRes.ok) throw new Error(`status HTTP ${statusRes.status}`)\n if (!projectsRes.ok) throw new Error(`projects HTTP ${projectsRes.status}`)\n const data = await statusRes.json()\n const projectsData = await projectsRes.json()\n const notifyData = await notifyRes.json().catch(() => null)\n if (notifyData && typeof notifyData === 'object' && typeof (notifyData as { data?: NotifyStatus }).data?.dailyLimit === 'number') {\n setNotifyStatus((notifyData as { data: NotifyStatus }).data)\n } else if (notifyData && typeof (notifyData as NotifyStatus).dailyLimit === 'number') {\n setNotifyStatus(notifyData as NotifyStatus)\n }\n setOutput(JSON.stringify(data, null, 2))\n if (typeof data.workingDirectory === 'string') {\n setWorkingDir((prev) => prev || data.workingDirectory)\n }\n setBoundProject(data.selectedProject ?? null)\n if (Array.isArray(projectsData.items)) {\n setProjects(projectsData.items as ProjectSessionItem[])\n }\n setError(null)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n }\n // 信任集单独拉取(失败不影响主状态展示)\n try {\n const trustRes = await fetch(`${API_BASE}/trust`, { cache: 'no-store' })\n if (trustRes.ok) {\n const trustData = await trustRes.json()\n if (trustData && typeof trustData === 'object' && trustData.ok) {\n setTrust(trustData as TrustInfo)\n }\n }\n } catch {\n // ignore\n }\n // 桥接配置(超时安抚等)单独拉取,避免被初次渲染的默认值覆盖\n try {\n const cfgRes = await fetch(`${API_BASE}/config`, { cache: 'no-store' })\n if (cfgRes.ok) {\n const cfgData = await cfgRes.json()\n if (cfgData && typeof cfgData === 'object' && cfgData.ok) {\n setCalm(calmFromConfig(cfgData.calm))\n }\n }\n } catch {\n // ignore\n }\n }, [])\n\n async function saveCalm(): Promise<void> {\n setCalmBusy(true)\n setCalmError('')\n setCalmMessage('')\n try {\n const res = await fetch(`${API_BASE}/config`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ calm: calmToConfig(calm) }),\n })\n const data = await res.json().catch(() => null)\n if (!res.ok || !data?.ok) {\n throw new Error(data?.error || `HTTP ${res.status}`)\n }\n setCalmMessage('已保存,下次安抚时生效(最长延迟数秒)。')\n } catch (err) {\n setCalmError(err instanceof Error ? err.message : String(err))\n } finally {\n setCalmBusy(false)\n }\n }\n\n useEffect(() => {\n void refresh()\n }, [refresh])\n\n async function run(path: string): Promise<void> {\n setBusy(path)\n setError(null)\n try {\n const res = await fetch(`${API_BASE}/${path}`, { method: 'POST' })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n setOutput(JSON.stringify(data, null, 2))\n await refresh()\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setBusy(null)\n }\n }\n\n async function showLogs(): Promise<void> {\n setBusy('logs')\n setError(null)\n try {\n const res = await fetch(`${API_BASE}/logs`, { cache: 'no-store' })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n setOutput(await res.text())\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setBusy(null)\n }\n }\n\n async function startSetup(): Promise<void> {\n setSetupPhase('starting')\n setSetupError('')\n try {\n const res = await fetch(`${API_BASE}/setup/start`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ workingDirectory: workingDir || undefined }),\n })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n if (!data.ok) throw new Error(data.message || data.error || '启动扫码绑定失败')\n setQrcodeDataUrl(data.qrcodeDataUrl)\n setQrcodeId(data.qrcodeId)\n setWorkingDir(data.workingDirectory || workingDir)\n setSetupPhase('qr')\n } catch (err) {\n setSetupPhase('error')\n setSetupError(err instanceof Error ? err.message : String(err))\n }\n }\n\n async function bindProject(): Promise<void> {\n if (!projectChoice) return\n setProjectBusy(true)\n setProjectError('')\n setProjectMessage('')\n try {\n const res = await fetch(`${API_BASE}/projects/select`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sessionId: projectChoice }),\n })\n const data = await res.json().catch(() => null)\n if (!res.ok || !data?.ok) {\n throw new Error(data?.error || data?.message || `HTTP ${res.status}`)\n }\n const project = data.project as SelectedProjectInfo | undefined\n setProjectMessage(`已绑定项目会话${project?.workspaceTitle ? `:${project.workspaceTitle}` : ''}${data.daemon ? `(${data.daemon})` : ''}`)\n await refresh()\n } catch (err) {\n setProjectError(err instanceof Error ? err.message : String(err))\n } finally {\n setProjectBusy(false)\n }\n }\n\n async function detachProject(): Promise<void> {\n setProjectBusy(true)\n setProjectError('')\n setProjectMessage('')\n try {\n const res = await fetch(`${API_BASE}/projects/detach`, { method: 'POST' })\n const data = await res.json().catch(() => null)\n if (!res.ok || !data?.ok) {\n throw new Error(data?.error || data?.message || `HTTP ${res.status}`)\n }\n setProjectMessage(`已解除项目会话绑定${data.daemon ? `(${data.daemon})` : ''}`)\n setProjectChoice('')\n await refresh()\n } catch (err) {\n setProjectError(err instanceof Error ? err.message : String(err))\n } finally {\n setProjectBusy(false)\n }\n }\n\n // ---- 信任集管理(P1-2 / M4)----\n\n function applyTrustResponse(data: TrustInfo & { ok?: boolean; error?: string }): void {\n if (data.ok === false) throw new Error(data.error || '操作失败')\n setTrust({\n mode: data.mode,\n bootstrapConsumed: data.bootstrapConsumed,\n owner: data.owner,\n notifyRejected: data.notifyRejected,\n trusted: Array.isArray(data.trusted) ? data.trusted : [],\n })\n }\n\n async function trustRequest(path: string, body: Record<string, unknown>, okMessage: string): Promise<void> {\n setTrustBusy(true)\n setTrustError('')\n setTrustMessage('')\n try {\n const res = await fetch(`${API_BASE}/${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n const data = await res.json().catch(() => null)\n if (!res.ok || !data?.ok) {\n throw new Error(data?.error || `HTTP ${res.status}`)\n }\n applyTrustResponse(data as TrustInfo & { ok?: boolean; error?: string })\n setTrustMessage(okMessage)\n } catch (err) {\n setTrustError(err instanceof Error ? err.message : String(err))\n } finally {\n setTrustBusy(false)\n }\n }\n\n async function addTrustedUser(): Promise<void> {\n const id = newTrustId.trim()\n if (!id) return\n await trustRequest('trust/add', { userId: id, note: newTrustNote.trim() || undefined }, `已添加:${id}`)\n setNewTrustId('')\n setNewTrustNote('')\n }\n\n function removeTrustedUser(userId: string): void {\n if (!window.confirm(`确认吊销 ${userId}?其后续消息将被拒绝,已有会话历史保留。`)) return\n void trustRequest('trust/remove', { userId }, `已吊销:${userId}`)\n }\n\n function changeTrustMode(mode: TrustInfo['mode']): void {\n void trustRequest('trust/config', { mode }, `信任模式已切换为:${TRUST_MODE_LABELS[mode]}`)\n }\n\n function toggleNotifyRejected(enabled: boolean): void {\n void trustRequest('trust/config', { notifyRejected: enabled }, enabled ? '已开启陌生人联系提醒' : '已关闭陌生人联系提醒')\n }\n\n useEffect(() => {\n if (setupPhase !== 'qr' || !qrcodeId) return\n\n let cancelled = false\n let timer: number | undefined\n\n async function poll(): Promise<void> {\n try {\n const res = await fetch(`${API_BASE}/setup/status?qrcodeId=${encodeURIComponent(qrcodeId)}`, { cache: 'no-store' })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n if (cancelled) return\n\n if (data.status === 'confirmed') {\n setSetupPhase('confirmed')\n setBoundAccountId(data.accountId || '')\n setDaemonMessage(data.daemon || '')\n void refresh()\n return\n }\n\n if (data.status === 'expired' || (data.status === 'error' && !data.retryable)) {\n setSetupPhase('error')\n setSetupError(data.message || '绑定失败,请重试')\n return\n }\n\n timer = window.setTimeout(() => void poll(), 3000)\n } catch (err) {\n if (!cancelled) {\n setSetupPhase('error')\n setSetupError(err instanceof Error ? err.message : String(err))\n }\n }\n }\n\n void poll()\n return () => {\n cancelled = true\n if (timer) window.clearTimeout(timer)\n }\n }, [setupPhase, qrcodeId, refresh])\n\n function cancelSetup(): void {\n setSetupPhase('idle')\n setQrcodeDataUrl('')\n setQrcodeId('')\n setSetupError('')\n setDaemonMessage('')\n }\n\n const actions: Array<{ label: string; run: () => void; disabled?: boolean }> = [\n { label: '刷新状态', run: () => void refresh() },\n { label: '扫码绑定', run: () => void startSetup(), disabled: setupPhase === 'starting' || setupPhase === 'qr' },\n { label: '启动', run: () => void run('start'), disabled: busy !== null },\n { label: '停止', run: () => void run('stop'), disabled: busy !== null },\n { label: '重启', run: () => void run('restart'), disabled: busy !== null },\n { label: '查看日志', run: () => void showLogs(), disabled: busy !== null },\n ]\n\n return (\n <div style={panelStyle} role=\"region\" aria-label=\"DSH 微信桥接管理面板\">\n <div style={titleStyle}>📱 DSH 微信桥接</div>\n\n {error && <div role=\"alert\" style={{ color: '#e5484d', marginBottom: 8 }}>{error}</div>}\n\n <label style={{ display: 'block', marginBottom: 8, fontSize: 12 }}>\n DSH 工作目录\n <input\n type=\"text\"\n value={workingDir}\n onChange={(e) => setWorkingDir(e.target.value)}\n placeholder=\"例如 ~/Documents/DSH\"\n style={{ ...inputStyle, marginLeft: 8 }}\n />\n </label>\n\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...titleStyle, marginBottom: 4 }}>项目对话绑定</div>\n <div style={{ fontSize: 12, opacity: 0.8 }}>\n {boundProject\n ? `当前绑定:${boundProject.workspaceTitle} · ${boundProject.path} · ${boundProject.sessionId.slice(-8)}`\n : '当前未绑定:微信消息使用独立桥接会话(也可选择项目对话以共享记忆)。'}\n </div>\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center', marginTop: 6 }}>\n <select\n value={projectChoice}\n onChange={(e) => setProjectChoice(e.target.value)}\n style={selectStyle}\n aria-label=\"选择要绑定的项目会话\"\n >\n <option value=\"\">— 选择要绑定的项目会话 —</option>\n {projects.map((project) => (\n <option key={project.sessionId} value={project.sessionId}>\n {project.workspaceTitle} · {project.path} · {project.sessionId.slice(-8)}\n </option>\n ))}\n </select>\n <button type=\"button\" style={buttonStyle} disabled={!projectChoice || projectBusy} onClick={() => void bindProject()}>\n 绑定\n </button>\n <button type=\"button\" style={buttonStyle} disabled={projectBusy || !boundProject} onClick={() => void detachProject()}>\n 解除绑定\n </button>\n </div>\n {projectMessage && (\n <div role=\"status\" style={{ color: '#2f9e44', marginTop: 6, fontSize: 12 }}>{projectMessage}</div>\n )}\n {projectError && (\n <div role=\"alert\" style={{ color: '#e5484d', marginTop: 6, fontSize: 12 }}>{projectError}</div>\n )}\n </div>\n\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...titleStyle, marginBottom: 4 }}>主动通知节流</div>\n {notifyStatus ? (\n <div style={{ fontSize: 12, opacity: 0.85 }}>\n 今日已发 <strong>{notifyStatus.dailySent}</strong> / {notifyStatus.dailyLimit} 条 · 近一小时{' '}\n <strong>{notifyStatus.hourlySent}</strong> / {notifyStatus.hourlyLimit} 条 · 排队中{' '}\n <strong>{notifyStatus.pendingCount}</strong> 条\n <div style={{ marginTop: 4, fontSize: 12, opacity: 0.7 }}>\n agent 通过 wechat_notify 主动推送的通知,超限自动排队延迟发送,避免触发微信风控。\n </div>\n </div>\n ) : (\n <div style={{ fontSize: 12, opacity: 0.7 }}>守护进程未运行,暂无数据。</div>\n )}\n </div>\n\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...titleStyle, marginBottom: 4 }}>⏳ 超时安抚</div>\n <div style={{ fontSize: 12, opacity: 0.7, marginBottom: 8 }}>\n DSH 长时间没有产出消息时,主动发一条\"还在处理\"的安抚消息。改配置后即时生效(最长延迟数秒)。\n </div>\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, marginBottom: 8 }}>\n <input\n type=\"checkbox\"\n checked={calm.enabled}\n onChange={(e) => setCalm((c) => ({ ...c, enabled: e.target.checked }))}\n />\n 启用安抚消息\n </label>\n <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center', marginBottom: 8 }}>\n <label style={{ fontSize: 12 }}>\n 首次静默(分钟)\n <input\n type=\"number\"\n min={1}\n value={calm.silenceMin}\n onChange={(e) => setCalm((c) => ({ ...c, silenceMin: e.target.value }))}\n style={{ ...inputStyle, marginLeft: 6, minWidth: 70 }}\n />\n </label>\n <label style={{ fontSize: 12 }}>\n 重复间隔(分钟)\n <input\n type=\"number\"\n min={1}\n value={calm.intervalMin}\n onChange={(e) => setCalm((c) => ({ ...c, intervalMin: e.target.value }))}\n style={{ ...inputStyle, marginLeft: 6, minWidth: 70 }}\n />\n </label>\n <label style={{ fontSize: 12 }}>\n 每轮上限(次,0=不限)\n <input\n type=\"number\"\n min={0}\n value={calm.maxCount}\n onChange={(e) => setCalm((c) => ({ ...c, maxCount: e.target.value }))}\n style={{ ...inputStyle, marginLeft: 6, minWidth: 70 }}\n />\n </label>\n </div>\n <label style={{ fontSize: 12, display: 'block', marginBottom: 6 }}>\n 自定义文案(每行一条,留空用内置默认;每次随机取一条)\n <textarea\n value={calm.messages}\n onChange={(e) => setCalm((c) => ({ ...c, messages: e.target.value }))}\n rows={3}\n style={{\n ...inputStyle,\n display: 'block',\n marginTop: 4,\n minWidth: '100%',\n boxSizing: 'border-box',\n resize: 'vertical',\n fontFamily: 'inherit',\n }}\n />\n </label>\n <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>\n <button type=\"button\" style={buttonStyle} disabled={calmBusy} onClick={() => void saveCalm()}>\n 保存安抚设置\n </button>\n {calmMessage && <span role=\"status\" style={{ color: '#2f9e44', fontSize: 12 }}>{calmMessage}</span>}\n {calmError && <span role=\"alert\" style={{ color: '#e5484d', fontSize: 12 }}>{calmError}</span>}\n </div>\n </div>\n\n <div style={{ marginBottom: 12 }}>\n <div style={{ ...titleStyle, marginBottom: 4 }}>🔐 信任用户(多用户)</div>\n {!trust ? (\n <div style={{ fontSize: 12, opacity: 0.7 }}>加载中…</div>\n ) : (\n <>\n <div style={{ fontSize: 12, opacity: 0.85, marginBottom: 6 }}>\n 信任模式\n <select\n value={trust.mode}\n onChange={(e) => changeTrustMode(e.target.value as TrustInfo['mode'])}\n disabled={trustBusy}\n style={{ ...inputStyle, marginLeft: 8, minWidth: 240 }}\n aria-label=\"选择信任模式\"\n >\n <option value=\"owner-only\">{TRUST_MODE_LABELS['owner-only']}</option>\n <option value=\"bootstrap\">{TRUST_MODE_LABELS.bootstrap}</option>\n <option value=\"manual\">{TRUST_MODE_LABELS.manual}</option>\n </select>\n </div>\n {trust.mode === 'bootstrap' && trust.bootstrapConsumed && (\n <div style={{ fontSize: 12, color: '#b7791f', marginBottom: 6 }}>\n ⚠️ bootstrap 首次名额已用完,后续陌生人不会再自动入集,请用下方表单手动添加或切到 manual。\n </div>\n )}\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, marginBottom: 8 }}>\n <input\n type=\"checkbox\"\n checked={trust.notifyRejected}\n disabled={trustBusy}\n onChange={(e) => toggleNotifyRejected(e.target.checked)}\n />\n 陌生人尝试联系时向 owner 推送提醒\n </label>\n <div style={{ fontSize: 12, opacity: 0.7, marginBottom: 8 }}>\n owner:{trust.owner || '(未绑定)'} · 信任用户:{trust.trusted.length} 个\n </div>\n {trust.trusted.length > 0 && (\n <div style={{ marginBottom: 8, display: 'flex', flexDirection: 'column', gap: 6 }}>\n {trust.trusted.map((u) => (\n <div\n key={u.userId}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '6px 8px',\n background: 'var(--surface-3, rgba(127,127,127,.05))',\n border: '1px solid var(--border-color, rgba(127,127,127,.12))',\n borderRadius: 6,\n }}\n >\n <span style={{ fontWeight: 600 }}>{u.userId}</span>\n {u.note && <span style={{ opacity: 0.7, fontSize: 12 }}>{u.note}</span>}\n <span style={{ marginLeft: 'auto', fontSize: 11, opacity: 0.6 }}>\n {u.by === 'bootstrap' ? '自动入集' : u.by === 'restore' ? '迁移导入' : '手动添加'} · {formatTime(u.lastSeenAt)}\n </span>\n <button\n type=\"button\"\n style={{ ...buttonStyle, color: '#e5484d' }}\n disabled={trustBusy}\n onClick={() => removeTrustedUser(u.userId)}\n >\n 吊销\n </button>\n </div>\n ))}\n </div>\n )}\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>\n <input\n type=\"text\"\n value={newTrustId}\n onChange={(e) => setNewTrustId(e.target.value)}\n placeholder=\"要添加的微信 userId\"\n style={{ ...inputStyle, minWidth: 180 }}\n />\n <input\n type=\"text\"\n value={newTrustNote}\n onChange={(e) => setNewTrustNote(e.target.value)}\n placeholder=\"备注(可选)\"\n style={{ ...inputStyle, minWidth: 120 }}\n />\n <button type=\"button\" style={buttonStyle} disabled={trustBusy || !newTrustId.trim()} onClick={() => void addTrustedUser()}>\n 添加信任\n </button>\n </div>\n {trustMessage && <div role=\"status\" style={{ color: '#2f9e44', marginTop: 6, fontSize: 12 }}>{trustMessage}</div>}\n {trustError && <div role=\"alert\" style={{ color: '#e5484d', marginTop: 6, fontSize: 12 }}>{trustError}</div>}\n <div style={{ fontSize: 12, opacity: 0.7, marginTop: 8 }}>\n 信任用户与 owner 各自拥有独立会话、独立上下文,互不可见。撤销信任后其新消息将被拒绝,但已有历史保留。\n 修改信任模式后,新入站消息立即生效,无需重启。\n </div>\n </>\n )}\n </div>\n\n {setupPhase === 'starting' && (\n <div role=\"status\" style={{ marginBottom: 8 }}>正在生成二维码…</div>\n )}\n\n {setupPhase === 'qr' && qrcodeDataUrl && (\n <div style={{ marginBottom: 8 }}>\n <div style={{ fontWeight: 600, marginBottom: 4 }}>请用微信扫描下方二维码完成绑定</div>\n <img\n src={qrcodeDataUrl}\n alt=\"微信扫码绑定二维码\"\n width={240}\n height={240}\n style={{ display: 'block', maxWidth: '100%', height: 'auto', borderRadius: 8, background: '#fff' }}\n />\n <div style={{ fontSize: 12, opacity: 0.7, marginTop: 4 }}>\n 工作目录:{workingDir || '未设置'}。等待扫码确认中…\n </div>\n <button type=\"button\" style={{ ...buttonStyle, marginTop: 8 }} onClick={cancelSetup}>\n 取消绑定\n </button>\n </div>\n )}\n\n {setupPhase === 'confirmed' && (\n <div role=\"status\" style={{ marginBottom: 8, color: '#2f9e44' }}>\n ✅ 绑定成功{boundAccountId ? `:${boundAccountId}` : ''},{daemonMessage || '桥接已自动重启/启动。'}\n </div>\n )}\n\n {setupPhase === 'error' && (\n <div role=\"alert\" style={{ marginBottom: 8, color: '#e5484d' }}>\n ❌ {setupError}\n <button type=\"button\" style={{ ...buttonStyle, marginLeft: 8 }} onClick={() => setSetupPhase('idle')}>\n 重新扫码\n </button>\n </div>\n )}\n\n <pre style={outputStyle} aria-live=\"polite\">{output}</pre>\n\n <div style={buttonRowStyle}>\n {actions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n style={buttonStyle}\n disabled={action.disabled ?? false}\n onClick={action.run}\n >\n {action.label}\n </button>\n ))}\n </div>\n\n <div style={hintStyle}>\n 也可在 DSH 对话中直接使用 wechat_bridge_setup / wechat_bridge_status / wechat_bridge_start / wechat_bridge_stop / wechat_bridge_logs 等工具。\n </div>\n </div>\n )\n}\n","/**\n * @lanbaolu/dsh-wechat-bridge — Web 管理面板。\n *\n * 渲染在 settings.section 槽位(设置页),不绑定具体会话,打开任何任务前都可通过\n * 侧边栏 Settings 进入;通过 DSH Web 同源路由读取/控制桥接状态。\n */\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport { WechatBridgePanel } from './Panel.js'\n\nexport const inject = ['slots']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: '@lanbaolu/dsh-wechat-bridge-panel',\n order: 55,\n label: () => '📱 微信桥接',\n }, WechatBridgePanel),\n ), '@lanbaolu/dsh-wechat-bridge: panel')\n}\n"],"mappings":"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"}
package/lib/index.js CHANGED
@@ -26,6 +26,7 @@ import { startQrLogin, checkQrStatus } from './bridge/wechat/login.js';
26
26
  import { loadJson, saveJson, validateAccountId } from './bridge/store.js';
27
27
  import { loadTrust, saveTrust, addTrusted, removeTrusted, setTrustMode, listTrusted, isPlausibleUserId } from './bridge/trust.js';
28
28
  import { parseSessionKey } from './bridge/session-key.js';
29
+ import { parseCalmConfig } from './bridge/config.js';
29
30
  export const name = '@lanbaolu/dsh-wechat-bridge';
30
31
  /** Host services the plugin needs. `webServer` is optional (headless profiles). */
31
32
  export const inject = ['tools', 'agents', 'agentDefaultModel', 'agentPresets'];
@@ -862,6 +863,11 @@ export function apply(ctx, config) {
862
863
  cwd: dirname(script),
863
864
  env: {
864
865
  ...process.env,
866
+ // 宿主是 Electron(DSH Desktop)时 process.execPath 是 Electron 二进制:
867
+ // 必须用 ELECTRON_RUN_AS_NODE=1 让它以纯 Node 模式执行 daemon 脚本,
868
+ // 否则每次拉起都会启动一个 Electron 实例(窗口闪现后秒退,watchdog 无限循环)。
869
+ // 纯 node 宿主(npx dsh web)下该变量无害。
870
+ ELECTRON_RUN_AS_NODE: '1',
865
871
  DSH_HOME: dshHome,
866
872
  DSH_BRIDGE_DATA_DIR: dataDir,
867
873
  DSH_BRIDGE_API_BASE: `http://127.0.0.1:${internalPort}`,
@@ -935,6 +941,8 @@ export function apply(ctx, config) {
935
941
  model: raw.model,
936
942
  systemPrompt: raw.systemPrompt,
937
943
  notifyRejected: raw.notifyRejected === true || raw.notifyRejected === 'true',
944
+ usageFooter: raw.usageFooter === undefined ? undefined : (raw.usageFooter === true || raw.usageFooter === 'true'),
945
+ calm: raw.calm && typeof raw.calm === 'object' ? raw.calm : undefined,
938
946
  };
939
947
  }
940
948
  catch {
@@ -965,6 +973,8 @@ export function apply(ctx, config) {
965
973
  data.systemPrompt = config.systemPrompt;
966
974
  if (config.notifyRejected !== undefined)
967
975
  data.notifyRejected = config.notifyRejected;
976
+ if (config.calm !== undefined)
977
+ data.calm = config.calm;
968
978
  writeFileSync(bridgeConfigPath(), JSON.stringify(data, null, 2) + '\n', 'utf8');
969
979
  if (process.platform !== 'win32') {
970
980
  chmodSync(bridgeConfigPath(), 0o600);
@@ -1310,6 +1320,53 @@ export function apply(ctx, config) {
1310
1320
  }
1311
1321
  },
1312
1322
  }));
1323
+ // 桥接配置读写(面板「超时安抚」等设置):GET 读全部配置,POST 按字段合并写回。
1324
+ // config.json 由 host 与 daemon 共享,写盘后 daemon 侧最多延迟一个轮询周期生效。
1325
+ disposers.push(webServer.register({
1326
+ kind: 'exact',
1327
+ path: '/@lanbaolu/dsh-wechat-bridge/config',
1328
+ handler: async (req, res) => {
1329
+ try {
1330
+ if (req.method === 'GET' || req.method === undefined) {
1331
+ const config = readBridgeConfig();
1332
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1333
+ res.end(JSON.stringify({
1334
+ ok: true,
1335
+ workingDirectory: config.workingDirectory,
1336
+ model: config.model ?? null,
1337
+ usageFooter: config.usageFooter ?? undefined,
1338
+ notifyRejected: config.notifyRejected ?? false,
1339
+ calm: config.calm ?? {},
1340
+ }));
1341
+ return;
1342
+ }
1343
+ if (req.method === 'POST') {
1344
+ const body = await readBody(req);
1345
+ const config = readBridgeConfig();
1346
+ if (body.calm !== undefined) {
1347
+ if (!body.calm || typeof body.calm !== 'object') {
1348
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1349
+ res.end(JSON.stringify({ ok: false, error: 'calm 必须是对象' }));
1350
+ return;
1351
+ }
1352
+ // 写盘前清洗(非法字段丢弃),daemon 读取时还会再兜底一次。
1353
+ const parsed = parseCalmConfig(body.calm);
1354
+ config.calm = parsed ?? {};
1355
+ }
1356
+ saveBridgeConfig(config);
1357
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1358
+ res.end(JSON.stringify({ ok: true, calm: config.calm ?? {} }));
1359
+ return;
1360
+ }
1361
+ res.writeHead(405, { 'Content-Type': 'application/json' });
1362
+ res.end(JSON.stringify({ ok: false, error: 'method not allowed' }));
1363
+ }
1364
+ catch (err) {
1365
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1366
+ res.end(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }));
1367
+ }
1368
+ },
1369
+ }));
1313
1370
  return disposers;
1314
1371
  }
1315
1372
  // -------------------------------------------------------------------------