@lanbaolu/dsh-wechat-bridge 0.4.1 → 0.6.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/README.md +45 -1
- package/docs/plan-multi-user.md +92 -0
- package/lib/approval.js +2 -2
- package/lib/approval.js.map +1 -1
- package/lib/bridge/commands/handlers.js +119 -0
- package/lib/bridge/commands/handlers.js.map +1 -1
- package/lib/bridge/commands/router.js +11 -1
- package/lib/bridge/commands/router.js.map +1 -1
- package/lib/bridge/config.js +6 -0
- package/lib/bridge/config.js.map +1 -1
- package/lib/bridge/dsh-client.js.map +1 -1
- package/lib/bridge/main.js +370 -71
- package/lib/bridge/main.js.map +1 -1
- package/lib/bridge/notify.js +9 -8
- package/lib/bridge/notify.js.map +1 -1
- package/lib/bridge/session-key.js +62 -0
- package/lib/bridge/session-key.js.map +1 -0
- package/lib/bridge/session.js +109 -16
- package/lib/bridge/session.js.map +1 -1
- package/lib/bridge/store.js +10 -2
- package/lib/bridge/store.js.map +1 -1
- package/lib/bridge/trust.js +160 -0
- package/lib/bridge/trust.js.map +1 -0
- package/lib/client/Panel.js +99 -2
- package/lib/client/Panel.js.map +1 -1
- package/lib/client.js +279 -0
- package/lib/client.js.map +1 -1
- package/lib/index.js +259 -26
- package/lib/index.js.map +1 -1
- package/lib/types/approval.d.ts +6 -2
- package/lib/types/bridge/commands/handlers.d.ts +12 -0
- package/lib/types/bridge/commands/router.d.ts +13 -0
- package/lib/types/bridge/config.d.ts +8 -0
- package/lib/types/bridge/dsh-client.d.ts +7 -0
- package/lib/types/bridge/notify.d.ts +3 -3
- package/lib/types/bridge/session-key.d.ts +14 -0
- package/lib/types/bridge/session.d.ts +15 -4
- package/lib/types/bridge/trust.d.ts +61 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -71,6 +71,19 @@ window.__ModuleLoader__.load({
|
|
|
71
71
|
fontSize: 12,
|
|
72
72
|
opacity: .7
|
|
73
73
|
};
|
|
74
|
+
const TRUST_MODE_LABELS = {
|
|
75
|
+
"owner-only": "仅本机主人(默认)",
|
|
76
|
+
bootstrap: "首位陌生人自动入集(一次性)",
|
|
77
|
+
manual: "仅手动添加的人"
|
|
78
|
+
};
|
|
79
|
+
function formatTime(ms) {
|
|
80
|
+
if (!ms) return "从未活跃";
|
|
81
|
+
try {
|
|
82
|
+
return new Date(ms).toLocaleString("zh-CN");
|
|
83
|
+
} catch {
|
|
84
|
+
return "未知";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
74
87
|
function WechatBridgePanel(_props) {
|
|
75
88
|
const [output, setOutput] = (0, react.useState)("加载中…");
|
|
76
89
|
const [error, setError] = (0, react.useState)(null);
|
|
@@ -89,6 +102,12 @@ window.__ModuleLoader__.load({
|
|
|
89
102
|
const [projectMessage, setProjectMessage] = (0, react.useState)("");
|
|
90
103
|
const [projectError, setProjectError] = (0, react.useState)("");
|
|
91
104
|
const [notifyStatus, setNotifyStatus] = (0, react.useState)(null);
|
|
105
|
+
const [trust, setTrust] = (0, react.useState)(null);
|
|
106
|
+
const [trustBusy, setTrustBusy] = (0, react.useState)(false);
|
|
107
|
+
const [trustMessage, setTrustMessage] = (0, react.useState)("");
|
|
108
|
+
const [trustError, setTrustError] = (0, react.useState)("");
|
|
109
|
+
const [newTrustId, setNewTrustId] = (0, react.useState)("");
|
|
110
|
+
const [newTrustNote, setNewTrustNote] = (0, react.useState)("");
|
|
92
111
|
const refresh = (0, react.useCallback)(async () => {
|
|
93
112
|
try {
|
|
94
113
|
const [statusRes, projectsRes, notifyRes] = await Promise.all([
|
|
@@ -111,6 +130,13 @@ window.__ModuleLoader__.load({
|
|
|
111
130
|
} catch (err) {
|
|
112
131
|
setError(err instanceof Error ? err.message : String(err));
|
|
113
132
|
}
|
|
133
|
+
try {
|
|
134
|
+
const trustRes = await fetch(`${API_BASE}/trust`, { cache: "no-store" });
|
|
135
|
+
if (trustRes.ok) {
|
|
136
|
+
const trustData = await trustRes.json();
|
|
137
|
+
if (trustData && typeof trustData === "object" && trustData.ok) setTrust(trustData);
|
|
138
|
+
}
|
|
139
|
+
} catch {}
|
|
114
140
|
}, []);
|
|
115
141
|
(0, react.useEffect)(() => {
|
|
116
142
|
refresh();
|
|
@@ -203,6 +229,56 @@ window.__ModuleLoader__.load({
|
|
|
203
229
|
setProjectBusy(false);
|
|
204
230
|
}
|
|
205
231
|
}
|
|
232
|
+
function applyTrustResponse(data) {
|
|
233
|
+
if (data.ok === false) throw new Error(data.error || "操作失败");
|
|
234
|
+
setTrust({
|
|
235
|
+
mode: data.mode,
|
|
236
|
+
bootstrapConsumed: data.bootstrapConsumed,
|
|
237
|
+
owner: data.owner,
|
|
238
|
+
notifyRejected: data.notifyRejected,
|
|
239
|
+
trusted: Array.isArray(data.trusted) ? data.trusted : []
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
async function trustRequest(path, body, okMessage) {
|
|
243
|
+
setTrustBusy(true);
|
|
244
|
+
setTrustError("");
|
|
245
|
+
setTrustMessage("");
|
|
246
|
+
try {
|
|
247
|
+
const res = await fetch(`${API_BASE}/${path}`, {
|
|
248
|
+
method: "POST",
|
|
249
|
+
headers: { "Content-Type": "application/json" },
|
|
250
|
+
body: JSON.stringify(body)
|
|
251
|
+
});
|
|
252
|
+
const data = await res.json().catch(() => null);
|
|
253
|
+
if (!res.ok || !data?.ok) throw new Error(data?.error || `HTTP ${res.status}`);
|
|
254
|
+
applyTrustResponse(data);
|
|
255
|
+
setTrustMessage(okMessage);
|
|
256
|
+
} catch (err) {
|
|
257
|
+
setTrustError(err instanceof Error ? err.message : String(err));
|
|
258
|
+
} finally {
|
|
259
|
+
setTrustBusy(false);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function addTrustedUser() {
|
|
263
|
+
const id = newTrustId.trim();
|
|
264
|
+
if (!id) return;
|
|
265
|
+
await trustRequest("trust/add", {
|
|
266
|
+
userId: id,
|
|
267
|
+
note: newTrustNote.trim() || void 0
|
|
268
|
+
}, `已添加:${id}`);
|
|
269
|
+
setNewTrustId("");
|
|
270
|
+
setNewTrustNote("");
|
|
271
|
+
}
|
|
272
|
+
function removeTrustedUser(userId) {
|
|
273
|
+
if (!window.confirm(`确认吊销 ${userId}?其后续消息将被拒绝,已有会话历史保留。`)) return;
|
|
274
|
+
trustRequest("trust/remove", { userId }, `已吊销:${userId}`);
|
|
275
|
+
}
|
|
276
|
+
function changeTrustMode(mode) {
|
|
277
|
+
trustRequest("trust/config", { mode }, `信任模式已切换为:${TRUST_MODE_LABELS[mode]}`);
|
|
278
|
+
}
|
|
279
|
+
function toggleNotifyRejected(enabled) {
|
|
280
|
+
trustRequest("trust/config", { notifyRejected: enabled }, enabled ? "已开启陌生人联系提醒" : "已关闭陌生人联系提醒");
|
|
281
|
+
}
|
|
206
282
|
(0, react.useEffect)(() => {
|
|
207
283
|
if (setupPhase !== "qr" || !qrcodeId) return;
|
|
208
284
|
let cancelled = false;
|
|
@@ -440,6 +516,209 @@ window.__ModuleLoader__.load({
|
|
|
440
516
|
children: "守护进程未运行,暂无数据。"
|
|
441
517
|
})]
|
|
442
518
|
}),
|
|
519
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
520
|
+
style: { marginBottom: 12 },
|
|
521
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
522
|
+
style: {
|
|
523
|
+
...titleStyle,
|
|
524
|
+
marginBottom: 4
|
|
525
|
+
},
|
|
526
|
+
children: "🔐 信任用户(多用户)"
|
|
527
|
+
}), !trust ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
528
|
+
style: {
|
|
529
|
+
fontSize: 12,
|
|
530
|
+
opacity: .7
|
|
531
|
+
},
|
|
532
|
+
children: "加载中…"
|
|
533
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
534
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
535
|
+
style: {
|
|
536
|
+
fontSize: 12,
|
|
537
|
+
opacity: .85,
|
|
538
|
+
marginBottom: 6
|
|
539
|
+
},
|
|
540
|
+
children: ["信任模式", /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
541
|
+
value: trust.mode,
|
|
542
|
+
onChange: (e) => changeTrustMode(e.target.value),
|
|
543
|
+
disabled: trustBusy,
|
|
544
|
+
style: {
|
|
545
|
+
...inputStyle,
|
|
546
|
+
marginLeft: 8,
|
|
547
|
+
minWidth: 240
|
|
548
|
+
},
|
|
549
|
+
"aria-label": "选择信任模式",
|
|
550
|
+
children: [
|
|
551
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
552
|
+
value: "owner-only",
|
|
553
|
+
children: TRUST_MODE_LABELS["owner-only"]
|
|
554
|
+
}),
|
|
555
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
556
|
+
value: "bootstrap",
|
|
557
|
+
children: TRUST_MODE_LABELS.bootstrap
|
|
558
|
+
}),
|
|
559
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
560
|
+
value: "manual",
|
|
561
|
+
children: TRUST_MODE_LABELS.manual
|
|
562
|
+
})
|
|
563
|
+
]
|
|
564
|
+
})]
|
|
565
|
+
}),
|
|
566
|
+
trust.mode === "bootstrap" && trust.bootstrapConsumed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
567
|
+
style: {
|
|
568
|
+
fontSize: 12,
|
|
569
|
+
color: "#b7791f",
|
|
570
|
+
marginBottom: 6
|
|
571
|
+
},
|
|
572
|
+
children: "⚠️ bootstrap 首次名额已用完,后续陌生人不会再自动入集,请用下方表单手动添加或切到 manual。"
|
|
573
|
+
}),
|
|
574
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
575
|
+
style: {
|
|
576
|
+
display: "flex",
|
|
577
|
+
alignItems: "center",
|
|
578
|
+
gap: 6,
|
|
579
|
+
fontSize: 12,
|
|
580
|
+
marginBottom: 8
|
|
581
|
+
},
|
|
582
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
583
|
+
type: "checkbox",
|
|
584
|
+
checked: trust.notifyRejected,
|
|
585
|
+
disabled: trustBusy,
|
|
586
|
+
onChange: (e) => toggleNotifyRejected(e.target.checked)
|
|
587
|
+
}), "陌生人尝试联系时向 owner 推送提醒"]
|
|
588
|
+
}),
|
|
589
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
590
|
+
style: {
|
|
591
|
+
fontSize: 12,
|
|
592
|
+
opacity: .7,
|
|
593
|
+
marginBottom: 8
|
|
594
|
+
},
|
|
595
|
+
children: [
|
|
596
|
+
"owner:",
|
|
597
|
+
trust.owner || "(未绑定)",
|
|
598
|
+
" · 信任用户:",
|
|
599
|
+
trust.trusted.length,
|
|
600
|
+
" 个"
|
|
601
|
+
]
|
|
602
|
+
}),
|
|
603
|
+
trust.trusted.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
604
|
+
style: {
|
|
605
|
+
marginBottom: 8,
|
|
606
|
+
display: "flex",
|
|
607
|
+
flexDirection: "column",
|
|
608
|
+
gap: 6
|
|
609
|
+
},
|
|
610
|
+
children: trust.trusted.map((u) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
611
|
+
style: {
|
|
612
|
+
display: "flex",
|
|
613
|
+
alignItems: "center",
|
|
614
|
+
gap: 8,
|
|
615
|
+
padding: "6px 8px",
|
|
616
|
+
background: "var(--surface-3, rgba(127,127,127,.05))",
|
|
617
|
+
border: "1px solid var(--border-color, rgba(127,127,127,.12))",
|
|
618
|
+
borderRadius: 6
|
|
619
|
+
},
|
|
620
|
+
children: [
|
|
621
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
622
|
+
style: { fontWeight: 600 },
|
|
623
|
+
children: u.userId
|
|
624
|
+
}),
|
|
625
|
+
u.note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
626
|
+
style: {
|
|
627
|
+
opacity: .7,
|
|
628
|
+
fontSize: 12
|
|
629
|
+
},
|
|
630
|
+
children: u.note
|
|
631
|
+
}),
|
|
632
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
633
|
+
style: {
|
|
634
|
+
marginLeft: "auto",
|
|
635
|
+
fontSize: 11,
|
|
636
|
+
opacity: .6
|
|
637
|
+
},
|
|
638
|
+
children: [
|
|
639
|
+
u.by === "bootstrap" ? "自动入集" : u.by === "restore" ? "迁移导入" : "手动添加",
|
|
640
|
+
" · ",
|
|
641
|
+
formatTime(u.lastSeenAt)
|
|
642
|
+
]
|
|
643
|
+
}),
|
|
644
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
645
|
+
type: "button",
|
|
646
|
+
style: {
|
|
647
|
+
...buttonStyle,
|
|
648
|
+
color: "#e5484d"
|
|
649
|
+
},
|
|
650
|
+
disabled: trustBusy,
|
|
651
|
+
onClick: () => removeTrustedUser(u.userId),
|
|
652
|
+
children: "吊销"
|
|
653
|
+
})
|
|
654
|
+
]
|
|
655
|
+
}, u.userId))
|
|
656
|
+
}),
|
|
657
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
658
|
+
style: {
|
|
659
|
+
display: "flex",
|
|
660
|
+
gap: 8,
|
|
661
|
+
flexWrap: "wrap",
|
|
662
|
+
alignItems: "center"
|
|
663
|
+
},
|
|
664
|
+
children: [
|
|
665
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
666
|
+
type: "text",
|
|
667
|
+
value: newTrustId,
|
|
668
|
+
onChange: (e) => setNewTrustId(e.target.value),
|
|
669
|
+
placeholder: "要添加的微信 userId",
|
|
670
|
+
style: {
|
|
671
|
+
...inputStyle,
|
|
672
|
+
minWidth: 180
|
|
673
|
+
}
|
|
674
|
+
}),
|
|
675
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
676
|
+
type: "text",
|
|
677
|
+
value: newTrustNote,
|
|
678
|
+
onChange: (e) => setNewTrustNote(e.target.value),
|
|
679
|
+
placeholder: "备注(可选)",
|
|
680
|
+
style: {
|
|
681
|
+
...inputStyle,
|
|
682
|
+
minWidth: 120
|
|
683
|
+
}
|
|
684
|
+
}),
|
|
685
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
686
|
+
type: "button",
|
|
687
|
+
style: buttonStyle,
|
|
688
|
+
disabled: trustBusy || !newTrustId.trim(),
|
|
689
|
+
onClick: () => void addTrustedUser(),
|
|
690
|
+
children: "添加信任"
|
|
691
|
+
})
|
|
692
|
+
]
|
|
693
|
+
}),
|
|
694
|
+
trustMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
695
|
+
role: "status",
|
|
696
|
+
style: {
|
|
697
|
+
color: "#2f9e44",
|
|
698
|
+
marginTop: 6,
|
|
699
|
+
fontSize: 12
|
|
700
|
+
},
|
|
701
|
+
children: trustMessage
|
|
702
|
+
}),
|
|
703
|
+
trustError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
704
|
+
role: "alert",
|
|
705
|
+
style: {
|
|
706
|
+
color: "#e5484d",
|
|
707
|
+
marginTop: 6,
|
|
708
|
+
fontSize: 12
|
|
709
|
+
},
|
|
710
|
+
children: trustError
|
|
711
|
+
}),
|
|
712
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
713
|
+
style: {
|
|
714
|
+
fontSize: 12,
|
|
715
|
+
opacity: .7,
|
|
716
|
+
marginTop: 8
|
|
717
|
+
},
|
|
718
|
+
children: "信任用户与 owner 各自拥有独立会话、独立上下文,互不可见。撤销信任后其新消息将被拒绝,但已有历史保留。 修改信任模式后,新入站消息立即生效,无需重启。"
|
|
719
|
+
})
|
|
720
|
+
] })]
|
|
721
|
+
}),
|
|
443
722
|
setupPhase === "starting" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
444
723
|
role: "status",
|
|
445
724
|
style: { marginBottom: 8 },
|
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\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\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\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 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 {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: 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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"}
|