@lanbaolu/dsh-wechat-bridge 0.1.1 → 0.2.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
@@ -61,6 +61,11 @@ window.__ModuleLoader__.load({
61
61
  fontSize: 12,
62
62
  minWidth: 220
63
63
  };
64
+ const selectStyle = {
65
+ ...inputStyle,
66
+ minWidth: 320,
67
+ maxWidth: "100%"
68
+ };
64
69
  const hintStyle = {
65
70
  marginTop: 8,
66
71
  fontSize: 12,
@@ -77,13 +82,23 @@ window.__ModuleLoader__.load({
77
82
  const [setupError, setSetupError] = (0, react.useState)("");
78
83
  const [boundAccountId, setBoundAccountId] = (0, react.useState)("");
79
84
  const [daemonMessage, setDaemonMessage] = (0, react.useState)("");
85
+ const [projects, setProjects] = (0, react.useState)([]);
86
+ const [projectChoice, setProjectChoice] = (0, react.useState)("");
87
+ const [boundProject, setBoundProject] = (0, react.useState)(null);
88
+ const [projectBusy, setProjectBusy] = (0, react.useState)(false);
89
+ const [projectMessage, setProjectMessage] = (0, react.useState)("");
90
+ const [projectError, setProjectError] = (0, react.useState)("");
80
91
  const refresh = (0, react.useCallback)(async () => {
81
92
  try {
82
- const res = await fetch(`${API_BASE}/status`, { cache: "no-store" });
83
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
84
- const data = await res.json();
93
+ const [statusRes, projectsRes] = await Promise.all([fetch(`${API_BASE}/status`, { cache: "no-store" }), fetch(`${API_BASE}/projects`, { cache: "no-store" })]);
94
+ if (!statusRes.ok) throw new Error(`status HTTP ${statusRes.status}`);
95
+ if (!projectsRes.ok) throw new Error(`projects HTTP ${projectsRes.status}`);
96
+ const data = await statusRes.json();
97
+ const projectsData = await projectsRes.json();
85
98
  setOutput(JSON.stringify(data, null, 2));
86
99
  if (typeof data.workingDirectory === "string") setWorkingDir((prev) => prev || data.workingDirectory);
100
+ setBoundProject(data.selectedProject ?? null);
101
+ if (Array.isArray(projectsData.items)) setProjects(projectsData.items);
87
102
  setError(null);
88
103
  } catch (err) {
89
104
  setError(err instanceof Error ? err.message : String(err));
@@ -141,6 +156,45 @@ window.__ModuleLoader__.load({
141
156
  setSetupError(err instanceof Error ? err.message : String(err));
142
157
  }
143
158
  }
159
+ async function bindProject() {
160
+ if (!projectChoice) return;
161
+ setProjectBusy(true);
162
+ setProjectError("");
163
+ setProjectMessage("");
164
+ try {
165
+ const res = await fetch(`${API_BASE}/projects/select`, {
166
+ method: "POST",
167
+ headers: { "Content-Type": "application/json" },
168
+ body: JSON.stringify({ sessionId: projectChoice })
169
+ });
170
+ const data = await res.json().catch(() => null);
171
+ if (!res.ok || !data?.ok) throw new Error(data?.error || data?.message || `HTTP ${res.status}`);
172
+ const project = data.project;
173
+ setProjectMessage(`已绑定项目会话${project?.workspaceTitle ? `:${project.workspaceTitle}` : ""}${data.daemon ? `(${data.daemon})` : ""}`);
174
+ await refresh();
175
+ } catch (err) {
176
+ setProjectError(err instanceof Error ? err.message : String(err));
177
+ } finally {
178
+ setProjectBusy(false);
179
+ }
180
+ }
181
+ async function detachProject() {
182
+ setProjectBusy(true);
183
+ setProjectError("");
184
+ setProjectMessage("");
185
+ try {
186
+ const res = await fetch(`${API_BASE}/projects/detach`, { method: "POST" });
187
+ const data = await res.json().catch(() => null);
188
+ if (!res.ok || !data?.ok) throw new Error(data?.error || data?.message || `HTTP ${res.status}`);
189
+ setProjectMessage(`已解除项目会话绑定${data.daemon ? `(${data.daemon})` : ""}`);
190
+ setProjectChoice("");
191
+ await refresh();
192
+ } catch (err) {
193
+ setProjectError(err instanceof Error ? err.message : String(err));
194
+ } finally {
195
+ setProjectBusy(false);
196
+ }
197
+ }
144
198
  (0, react.useEffect)(() => {
145
199
  if (setupPhase !== "qr" || !qrcodeId) return;
146
200
  let cancelled = false;
@@ -253,6 +307,87 @@ window.__ModuleLoader__.load({
253
307
  }
254
308
  })]
255
309
  }),
310
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
311
+ style: { marginBottom: 12 },
312
+ children: [
313
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
314
+ style: {
315
+ ...titleStyle,
316
+ marginBottom: 4
317
+ },
318
+ children: "项目对话绑定"
319
+ }),
320
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
321
+ style: {
322
+ fontSize: 12,
323
+ opacity: .8
324
+ },
325
+ children: boundProject ? `当前绑定:${boundProject.workspaceTitle} · ${boundProject.path} · ${boundProject.sessionId.slice(-8)}` : "当前未绑定:微信消息使用独立桥接会话(也可选择项目对话以共享记忆)。"
326
+ }),
327
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
328
+ style: {
329
+ display: "flex",
330
+ gap: 8,
331
+ flexWrap: "wrap",
332
+ alignItems: "center",
333
+ marginTop: 6
334
+ },
335
+ children: [
336
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
337
+ value: projectChoice,
338
+ onChange: (e) => setProjectChoice(e.target.value),
339
+ style: selectStyle,
340
+ "aria-label": "选择要绑定的项目会话",
341
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
342
+ value: "",
343
+ children: "— 选择要绑定的项目会话 —"
344
+ }), projects.map((project) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
345
+ value: project.sessionId,
346
+ children: [
347
+ project.workspaceTitle,
348
+ " · ",
349
+ project.path,
350
+ " · ",
351
+ project.sessionId.slice(-8)
352
+ ]
353
+ }, project.sessionId))]
354
+ }),
355
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
356
+ type: "button",
357
+ style: buttonStyle,
358
+ disabled: !projectChoice || projectBusy,
359
+ onClick: () => void bindProject(),
360
+ children: "绑定"
361
+ }),
362
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
363
+ type: "button",
364
+ style: buttonStyle,
365
+ disabled: projectBusy || !boundProject,
366
+ onClick: () => void detachProject(),
367
+ children: "解除绑定"
368
+ })
369
+ ]
370
+ }),
371
+ projectMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
372
+ role: "status",
373
+ style: {
374
+ color: "#2f9e44",
375
+ marginTop: 6,
376
+ fontSize: 12
377
+ },
378
+ children: projectMessage
379
+ }),
380
+ projectError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
381
+ role: "alert",
382
+ style: {
383
+ color: "#e5484d",
384
+ marginTop: 6,
385
+ fontSize: 12
386
+ },
387
+ children: projectError
388
+ })
389
+ ]
390
+ }),
256
391
  setupPhase === "starting" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
257
392
  role: "status",
258
393
  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 hintStyle: React.CSSProperties = {\n marginTop: 8,\n fontSize: 12,\n opacity: 0.7,\n}\n\ntype SetupPhase = 'idle' | 'starting' | 'qr' | 'confirmed' | 'error'\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\n const refresh = useCallback(async () => {\n try {\n const res = await fetch(`${API_BASE}/status`, { cache: 'no-store' })\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = await res.json()\n setOutput(JSON.stringify(data, null, 2))\n if (typeof data.workingDirectory === 'string') {\n setWorkingDir((prev) => prev || data.workingDirectory)\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 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 {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\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\n const refresh = useCallback(async () => {\n try {\n const [statusRes, projectsRes] = await Promise.all([\n fetch(`${API_BASE}/status`, { cache: 'no-store' }),\n fetch(`${API_BASE}/projects`, { 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 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 {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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"}