@wenbin_wb/dsh-bridge 2.2.3 → 2.2.5

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/client/client.js CHANGED
@@ -89,17 +89,17 @@ function semverGt(a, b) {
89
89
  return av.pre > bv.pre;
90
90
  }
91
91
  var s = {
92
- card: { background: "var(--dsw-alias-bg-layer-1,transparent)", border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", borderRadius: 12, padding: "16px 20px", marginBottom: 16 },
92
+ card: { background: "var(--dsw-alias-bg-layer-2,#f9fafb)", border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", borderRadius: 12, padding: "16px 20px", marginBottom: 16 },
93
93
  block: { borderTop: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", marginTop: 12, paddingTop: 12 },
94
94
  muted: { color: "var(--dsw-alias-label-tertiary,#8b93a1)", fontSize: 12, lineHeight: 1.5 },
95
95
  label: { color: "var(--dsw-alias-label-primary,currentColor)", fontSize: 13, fontWeight: 500 },
96
96
  code: { fontFamily: "ui-monospace,Menlo,monospace", fontSize: 12, wordBreak: "break-all", color: "var(--dsw-alias-label-primary,currentColor)" },
97
97
  btnPri: { font: "inherit", cursor: "pointer", border: "none", background: "var(--dsw-alias-brand-primary,#4f6ef7)", color: "var(--dsw-alias-label-primary-foreground,#fff)", height: 32, padding: "0 14px", borderRadius: 999, fontSize: 13, fontWeight: 500, display: "inline-flex", alignItems: "center", gap: 4 },
98
- btnGhost: { font: "inherit", cursor: "pointer", border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", background: "var(--dsw-alias-bg-layer-1,transparent)", color: "var(--dsw-alias-label-primary,currentColor)", height: 32, padding: "0 14px", borderRadius: 999, fontSize: 13, display: "inline-flex", alignItems: "center", gap: 4, textDecoration: "none" },
98
+ btnGhost: { font: "inherit", cursor: "pointer", border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", background: "var(--dsw-alias-bg-layer-2,#f9fafb)", color: "var(--dsw-alias-label-primary,currentColor)", height: 32, padding: "0 14px", borderRadius: 999, fontSize: 13, display: "inline-flex", alignItems: "center", gap: 4, textDecoration: "none" },
99
99
  btnLink: { font: "inherit", cursor: "pointer", border: "none", background: "none", color: "var(--dsw-alias-brand-primary,#4f6ef7)", fontSize: 12, padding: 0, display: "inline-flex", alignItems: "center", gap: 3, textDecoration: "none" },
100
- qr: { width: 200, height: 200, borderRadius: 10, border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", margin: "8px 0", display: "block" },
100
+ qr: { width: 200, height: 200, borderRadius: 10, border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", margin: "8px 0", display: "block", background: "#ffffff", padding: 6, boxSizing: "border-box" },
101
101
  tag: { display: "inline-flex", alignItems: "center", padding: "2px 8px", borderRadius: 999, fontSize: 12, fontWeight: 500 },
102
- input: { width: "100%", font: "inherit", fontSize: 13, padding: "7px 10px", borderRadius: 8, border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", background: "var(--dsw-alias-bg-layer-1,transparent)", color: "var(--dsw-alias-label-primary,currentColor)", outline: "none", boxSizing: "border-box" },
102
+ input: { width: "100%", font: "inherit", fontSize: 13, padding: "7px 10px", borderRadius: 8, border: "1px solid var(--dsw-alias-border-l2,#d1d5db)", background: "var(--dsw-alias-bg-layer-2,#f9fafb)", color: "var(--dsw-alias-label-primary,currentColor)", outline: "none", boxSizing: "border-box" },
103
103
  warn: { background: "var(--dsw-alias-state-warn-bg,#fffbeb)", border: "1px solid var(--dsw-alias-state-warn-border,#fde68a)", borderRadius: 8, padding: "10px 14px", fontSize: 12, color: "var(--dsw-alias-state-warn-primary,#92400e)", lineHeight: 1.6 },
104
104
  tip: { background: "var(--dsw-alias-bg-layer-2,#f9fafb)", borderRadius: 8, padding: "10px 14px", fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", lineHeight: 1.6 }
105
105
  };
@@ -129,14 +129,38 @@ function useCopy() {
129
129
  }, []);
130
130
  return [copied, copy];
131
131
  }
132
- function StatusTag({ running }) {
132
+ function StatusTag({ running, status }) {
133
+ let bg = "var(--dsw-alias-bg-layer-2,#f3f4f6)";
134
+ let color = "var(--dsw-alias-label-secondary,#6b7280)";
135
+ let text = running ? "\u8FD0\u884C\u4E2D" : "\u672A\u542F\u52A8";
136
+ if (status === "connected") {
137
+ bg = "var(--dsw-alias-state-success-bg,#ecfdf5)";
138
+ color = "var(--dsw-alias-state-success-primary,#059669)";
139
+ text = "\u5DF2\u8FDE\u63A5";
140
+ } else if (status === "starting") {
141
+ bg = "var(--dsw-alias-state-info-bg,#eff6ff)";
142
+ color = "var(--dsw-alias-state-info-primary,#3b82f6)";
143
+ text = "\u8FDE\u63A5\u4E2D\u2026";
144
+ } else if (status === "reconnecting") {
145
+ bg = "var(--dsw-alias-state-warn-bg,#fffbeb)";
146
+ color = "var(--dsw-alias-state-warn-primary,#d97706)";
147
+ text = "\u91CD\u8FDE\u4E2D\u2026";
148
+ } else if (status === "paused") {
149
+ bg = "var(--dsw-alias-state-warn-bg,#fffbeb)";
150
+ color = "var(--dsw-alias-state-warn-primary,#d97706)";
151
+ text = "\u6682\u505C\u4E2D";
152
+ } else if (status === "error") {
153
+ bg = "var(--dsw-alias-state-error-bg,#fef2f2)";
154
+ color = "var(--dsw-alias-state-error-primary,#dc2626)";
155
+ text = "\u5F02\u5E38";
156
+ } else if (running) {
157
+ bg = "var(--dsw-alias-state-success-bg,#ecfdf5)";
158
+ color = "var(--dsw-alias-state-success-primary,#059669)";
159
+ text = "\u8FD0\u884C\u4E2D";
160
+ }
133
161
  return React.createElement("span", {
134
- style: {
135
- ...s.tag,
136
- background: running ? "var(--dsw-alias-state-success-bg,#ecfdf5)" : "var(--dsw-alias-bg-layer-2,#f3f4f6)",
137
- color: running ? "var(--dsw-alias-state-success-primary,#059669)" : "var(--dsw-alias-label-secondary,#6b7280)"
138
- }
139
- }, running ? "\u8FD0\u884C\u4E2D" : "\u672A\u542F\u52A8");
162
+ style: { ...s.tag, background: bg, color }
163
+ }, text);
140
164
  }
141
165
  function QrBlock({ url, qr, onReset }) {
142
166
  const [copied, setCopied] = React.useState(false);
@@ -220,6 +244,7 @@ var CustomTunnelConfigForm = React.memo(function CustomTunnelConfigForm2({ serve
220
244
  const [serverUrl, setServerUrl] = React.useState(initUrl ?? "");
221
245
  const [accessToken, setAccessToken] = React.useState(initToken ?? "");
222
246
  const [saving, setSaving] = React.useState(false);
247
+ const [saveSuccess, setSaveSuccess] = React.useState(false);
223
248
  const syncedRef = React.useRef(false);
224
249
  React.useEffect(() => {
225
250
  if (!syncedRef.current && (initUrl || initToken)) {
@@ -231,14 +256,23 @@ var CustomTunnelConfigForm = React.memo(function CustomTunnelConfigForm2({ serve
231
256
  const dirty = serverUrl !== (initUrl ?? "") || accessToken !== (initToken ?? "");
232
257
  const handleSave = React.useCallback(async () => {
233
258
  setSaving(true);
259
+ setSaveSuccess(false);
234
260
  try {
235
261
  await onSave(serverUrl, accessToken);
262
+ setSaveSuccess(true);
263
+ setTimeout(() => setSaveSuccess(false), 2500);
236
264
  } finally {
237
265
  setSaving(false);
238
266
  }
239
267
  }, [onSave, serverUrl, accessToken]);
240
- const handleUrlChange = React.useCallback((e) => setServerUrl(e.target.value), []);
241
- const handleTokenChange = React.useCallback((e) => setAccessToken(e.target.value), []);
268
+ const handleUrlChange = React.useCallback((e) => {
269
+ setServerUrl(e.target.value);
270
+ setSaveSuccess(false);
271
+ }, []);
272
+ const handleTokenChange = React.useCallback((e) => {
273
+ setAccessToken(e.target.value);
274
+ setSaveSuccess(false);
275
+ }, []);
242
276
  return React.createElement(
243
277
  "div",
244
278
  { style: s.block },
@@ -251,6 +285,9 @@ var CustomTunnelConfigForm = React.memo(function CustomTunnelConfigForm2({ serve
251
285
  placeholder: "WebSocket \u5730\u5740\uFF0C\u4F8B\u5982 wss://tunnel.example.com/connect",
252
286
  value: serverUrl,
253
287
  onChange: handleUrlChange,
288
+ onKeyDown: (e) => {
289
+ if (e.key === "Enter" && dirty && !saving) handleSave();
290
+ },
254
291
  disabled: saving
255
292
  }),
256
293
  React.createElement("input", {
@@ -259,13 +296,21 @@ var CustomTunnelConfigForm = React.memo(function CustomTunnelConfigForm2({ serve
259
296
  placeholder: "\u8BBF\u95EE\u4EE4\u724C\uFF08Access Token\uFF09",
260
297
  value: accessToken,
261
298
  onChange: handleTokenChange,
299
+ onKeyDown: (e) => {
300
+ if (e.key === "Enter" && dirty && !saving) handleSave();
301
+ },
262
302
  disabled: saving
263
303
  }),
264
304
  React.createElement("button", {
265
- style: { ...s.btnPri, alignSelf: "flex-start", opacity: !dirty || saving ? 0.5 : 1 },
266
- disabled: !dirty || saving,
305
+ style: {
306
+ ...s.btnPri,
307
+ alignSelf: "flex-start",
308
+ opacity: !dirty || saving ? saveSuccess ? 1 : 0.5 : 1,
309
+ background: saveSuccess ? "var(--dsw-alias-state-success-primary,#059669)" : void 0
310
+ },
311
+ disabled: !dirty && !saveSuccess || saving,
267
312
  onClick: handleSave
268
- }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u914D\u7F6E")
313
+ }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : saveSuccess ? "\u2713 \u5DF2\u4FDD\u5B58" : "\u4FDD\u5B58\u914D\u7F6E")
269
314
  )
270
315
  );
271
316
  });
@@ -381,6 +426,16 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
381
426
  await act(BRIDGE_ENDPOINTS.platformSetAllowFrom, { allowFrom: list });
382
427
  }, [act, platform?.allowFrom]);
383
428
  const handleNewId = React.useCallback((e) => setNewId(e.target.value), []);
429
+ const [showSecret, setShowSecret] = React.useState(false);
430
+ const resetDefaults = React.useCallback(() => {
431
+ setCfgDraft((d) => ({
432
+ ...d,
433
+ digestIntervalSec: "300",
434
+ approvalTimeoutSec: "600",
435
+ maxMessageChars: "2000",
436
+ sendChunkDelayMs: "1500"
437
+ }));
438
+ }, []);
384
439
  const saveConfig = React.useCallback(async () => {
385
440
  if (!cfgDraft) return;
386
441
  const payload = {
@@ -420,9 +475,9 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
420
475
  React.createElement("div", { style: s.label }, platformName),
421
476
  React.createElement("div", { style: { ...s.muted, marginTop: 2 } }, platformDesc)
422
477
  ),
423
- React.createElement(StatusTag, { running: connected })
478
+ React.createElement(StatusTag, { status: platform?.status, running: connected })
424
479
  ),
425
- // 快捷入口:使用说明 / 命令
480
+ // 快捷入口:使用说明 / 开放平台 / 命令速查
426
481
  React.createElement(
427
482
  "div",
428
483
  { style: { display: "flex", gap: 8, marginTop: 10, flexWrap: "wrap", alignItems: "center" } },
@@ -431,7 +486,19 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
431
486
  target: "_blank",
432
487
  rel: "noopener noreferrer",
433
488
  style: s.btnGhost
434
- }, "\u{1F4D6} \u4F7F\u7528\u8BF4\u660E"),
489
+ }, "\u{1F4D6} \u5FAE\u4FE1\u4F7F\u7528\u8BF4\u660E"),
490
+ platformId === "qq" && React.createElement("a", {
491
+ href: "https://github.com/wenbin-wb/dsh-bridge/blob/main/docs/qq-usage.md",
492
+ target: "_blank",
493
+ rel: "noopener noreferrer",
494
+ style: s.btnGhost
495
+ }, "\u{1F4D6} QQ \u4F7F\u7528\u8BF4\u660E"),
496
+ platformId === "qq" && React.createElement("a", {
497
+ href: "https://bot.q.qq.com/wiki/develop/api-v2/",
498
+ target: "_blank",
499
+ rel: "noopener noreferrer",
500
+ style: s.btnGhost
501
+ }, "\u{1F310} QQ \u5F00\u653E\u5E73\u53F0"),
435
502
  React.createElement("button", {
436
503
  style: s.btnGhost,
437
504
  onClick: () => setShowHelp((v) => !v)
@@ -441,32 +508,89 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
441
508
  showHelp && React.createElement(
442
509
  "div",
443
510
  { style: { ...s.block, fontSize: 12, lineHeight: 1.8, fontFamily: "monospace" } },
444
- React.createElement("div", null, "/new <\u63D0\u793A\u8BCD> \u2014 \u65B0\u5EFA\u4F1A\u8BDD\uFF08\u5F53\u524D\u5DE5\u4F5C\u533A\uFF09"),
445
- React.createElement("div", null, "/new <\u63D0\u793A\u8BCD> @N \u2014 \u5728\u6307\u5B9A\u5DE5\u4F5C\u533A\u65B0\u5EFA"),
446
- React.createElement("div", null, "/sessions \u2014 \u6309\u5DE5\u4F5C\u533A\u5206\u7EC4\u5217\u4F1A\u8BDD"),
447
- React.createElement("div", null, "/use N \u2014 \u5207\u6362\u5230\u4F1A\u8BDD N"),
448
- React.createElement("div", null, "/workspaces \u2014 \u5217\u51FA\u5DE5\u4F5C\u533A"),
449
- React.createElement("div", null, "/stop \u2014 \u505C\u6B62\u4EFB\u52A1"),
450
- React.createElement("div", null, "/status \u2014 \u67E5\u770B\u72B6\u6001"),
451
- React.createElement("div", null, "/yes \u6216 /no \u2014 \u56DE\u5E94\u5BA1\u6279"),
452
- React.createElement("div", null, "/help \u2014 \u5168\u90E8\u547D\u4EE4")
511
+ React.createElement("div", null, "/new <\u63D0\u793A\u8BCD> \u2014 \u65B0\u5EFA\u4F1A\u8BDD\u5E76\u5F00\u59CB\uFF08\u5F53\u524D\u5DE5\u4F5C\u533A\uFF09"),
512
+ React.createElement("div", null, "/new <\u63D0\u793A\u8BCD> @N \u2014 \u5728\u6307\u5B9A\u5DE5\u4F5C\u533A\u65B0\u5EFA\u4F1A\u8BDD"),
513
+ React.createElement("div", null, "/sessions\uFF08\u6216 /list\uFF09\u2014 \u5217\u51FA\u4F1A\u8BDD\uFF08\u6309\u5DE5\u4F5C\u533A\u5206\u7EC4\uFF0C\u5E26\u6807\u9898\uFF09"),
514
+ React.createElement("div", null, "/use N\uFF08\u6216 /resume N\uFF09\u2014 \u5207\u6362\u5230\u4F1A\u8BDD N"),
515
+ React.createElement("div", null, "/workspaces \u2014 \u5217\u51FA\u6240\u6709\u53EF\u7528\u5DE5\u4F5C\u533A"),
516
+ React.createElement("div", null, "/end \u2014 \u7ED3\u675F\u5F53\u524D\u4F1A\u8BDD\uFF08\u56DE\u5230\u65E0\u6D3B\u52A8\u4F1A\u8BDD\u72B6\u6001\uFF09"),
517
+ React.createElement("div", null, "/stop \u2014 \u505C\u6B62\u5F53\u524D\u4EFB\u52A1"),
518
+ React.createElement("div", null, "/status \u2014 \u67E5\u770B Agent \u72B6\u6001\u4E0E\u4F1A\u8BDD\u6458\u8981"),
519
+ React.createElement("div", null, "/yes \u6216 /no\uFF08\u6216 1/2\uFF09\u2014 \u56DE\u5E94\u6743\u9650\u5BA1\u6279\u8BF7\u6C42"),
520
+ React.createElement("div", null, "/help \u2014 \u663E\u793A\u5B8C\u6574\u547D\u4EE4\u5E2E\u52A9")
453
521
  ),
454
522
  err && React.createElement("div", { style: { ...s.warn, marginTop: 10 } }, err),
455
- // 已配置:状态详情 + 白名单
523
+ // 已配置:结构化状态看板 + 白名单
456
524
  platform?.configured && React.createElement(
457
525
  "div",
458
526
  { style: s.block },
527
+ // 结构化状态卡片看板
459
528
  React.createElement(
460
529
  "div",
461
- { style: { fontSize: 12, lineHeight: 1.7 } },
462
- React.createElement("div", null, `\u72B6\u6001: ${statusLabel}`),
463
- platform.accountId && React.createElement("div", null, `\u8D26\u53F7: ${platform.accountId}`),
464
- platform.sessionId && React.createElement("div", null, `\u5F53\u524D\u4F1A\u8BDD: ${platform.sessionId}`)
530
+ {
531
+ style: {
532
+ display: "grid",
533
+ gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))",
534
+ gap: 8,
535
+ marginBottom: 12
536
+ }
537
+ },
538
+ React.createElement(
539
+ "div",
540
+ {
541
+ style: {
542
+ background: "var(--dsw-alias-bg-layer-1,#fff)",
543
+ border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)",
544
+ borderRadius: 8,
545
+ padding: "8px 12px"
546
+ }
547
+ },
548
+ React.createElement("div", { style: { ...s.muted, fontSize: 11 } }, "\u8FDE\u63A5\u72B6\u6001"),
549
+ React.createElement(
550
+ "div",
551
+ { style: { ...s.label, fontSize: 13, marginTop: 2, display: "flex", alignItems: "center", gap: 6 } },
552
+ React.createElement("span", {
553
+ style: {
554
+ width: 6,
555
+ height: 6,
556
+ borderRadius: "50%",
557
+ background: connected ? "var(--dsw-alias-state-success-primary,#10b981)" : "var(--dsw-alias-label-tertiary,#9ca3af)"
558
+ }
559
+ }),
560
+ statusLabel
561
+ )
562
+ ),
563
+ platform.accountId && React.createElement(
564
+ "div",
565
+ {
566
+ style: {
567
+ background: "var(--dsw-alias-bg-layer-1,#fff)",
568
+ border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)",
569
+ borderRadius: 8,
570
+ padding: "8px 12px"
571
+ }
572
+ },
573
+ React.createElement("div", { style: { ...s.muted, fontSize: 11 } }, "\u767B\u5F55\u8D26\u53F7"),
574
+ React.createElement("div", { style: { ...s.code, fontSize: 12, marginTop: 2, fontWeight: 500 } }, platform.accountId)
575
+ ),
576
+ platform.sessionId && React.createElement(
577
+ "div",
578
+ {
579
+ style: {
580
+ background: "var(--dsw-alias-bg-layer-1,#fff)",
581
+ border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)",
582
+ borderRadius: 8,
583
+ padding: "8px 12px"
584
+ }
585
+ },
586
+ React.createElement("div", { style: { ...s.muted, fontSize: 11 } }, "\u6D3B\u52A8\u4F1A\u8BDD"),
587
+ React.createElement("div", { style: { ...s.code, fontSize: 12, marginTop: 2 } }, platform.sessionId)
588
+ )
465
589
  ),
466
590
  React.createElement(
467
591
  "div",
468
592
  { style: { ...s.muted, fontSize: 12, marginTop: 8, lineHeight: 1.6 } },
469
- "\u767D\u540D\u5355\uFF08\u4EC5\u8FD9\u4E9B\u7528\u6237\u53EF\u9A71\u52A8 agent\uFF09:"
593
+ `\u767D\u540D\u5355 (\u5DF2\u6388\u6743 ${platform.allowFrom?.length || 0} \u4E2A\u8D26\u53F7/\u7FA4):`
470
594
  ),
471
595
  React.createElement(
472
596
  "div",
@@ -493,9 +617,12 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
493
617
  { style: { display: "flex", gap: 8, marginTop: 8, alignItems: "center" } },
494
618
  React.createElement("input", {
495
619
  style: { ...s.input, flex: 1 },
496
- placeholder: platformId === "wechat" ? "\u6DFB\u52A0\u5141\u8BB8\u7684\u5FAE\u4FE1 ID\uFF08\u5982 xxx@im.wechat\uFF09" : "\u6DFB\u52A0\u5141\u8BB8\u7684\u7528\u6237 ID",
620
+ placeholder: platformId === "wechat" ? "\u6DFB\u52A0\u5141\u8BB8\u7684\u5FAE\u4FE1 ID\uFF08\u5982 xxx@im.wechat\uFF09\uFF0C\u6309 Enter \u6DFB\u52A0" : "\u6DFB\u52A0\u5141\u8BB8\u7684\u7528\u6237/\u7FA4 ID\uFF0C\u6309 Enter \u6DFB\u52A0",
497
621
  value: newId,
498
- onChange: handleNewId
622
+ onChange: handleNewId,
623
+ onKeyDown: (e) => {
624
+ if (e.key === "Enter" && newId.trim() && !busy) addAllow();
625
+ }
499
626
  }),
500
627
  React.createElement("button", {
501
628
  style: { ...s.btnGhost, whiteSpace: "nowrap", opacity: newId.trim() && !busy ? 1 : 0.5 },
@@ -543,19 +670,36 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
543
670
  style: { ...s.input, width: "100%" },
544
671
  placeholder: "\u8BF7\u8F93\u5165 AppID",
545
672
  value: cfgDraft?.appId ?? "",
546
- onChange: (e) => setCfgDraft((d) => ({ ...d, appId: e.target.value }))
673
+ onChange: (e) => setCfgDraft((d) => ({ ...d, appId: e.target.value })),
674
+ onKeyDown: (e) => {
675
+ if (e.key === "Enter" && cfgDraft?.appId?.trim() && cfgDraft?.clientSecret?.trim() && !busy) saveConfig();
676
+ }
547
677
  })
548
678
  ),
549
679
  React.createElement(
550
680
  "div",
551
681
  null,
552
682
  React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "ClientSecret \u2014 QQ \u5F00\u653E\u5E73\u53F0\u673A\u5668\u4EBA\u5BC6\u94A5"),
553
- React.createElement("input", {
554
- style: { ...s.input, width: "100%" },
555
- placeholder: "\u8BF7\u8F93\u5165 ClientSecret",
556
- value: cfgDraft?.clientSecret ?? "",
557
- onChange: (e) => setCfgDraft((d) => ({ ...d, clientSecret: e.target.value }))
558
- })
683
+ React.createElement(
684
+ "div",
685
+ { style: { display: "flex", gap: 6, alignItems: "center" } },
686
+ React.createElement("input", {
687
+ style: { ...s.input, flex: 1 },
688
+ type: showSecret ? "text" : "password",
689
+ placeholder: "\u8BF7\u8F93\u5165 ClientSecret",
690
+ value: cfgDraft?.clientSecret ?? "",
691
+ onChange: (e) => setCfgDraft((d) => ({ ...d, clientSecret: e.target.value })),
692
+ onKeyDown: (e) => {
693
+ if (e.key === "Enter" && cfgDraft?.appId?.trim() && cfgDraft?.clientSecret?.trim() && !busy) saveConfig();
694
+ }
695
+ }),
696
+ React.createElement("button", {
697
+ style: { ...s.btnGhost, height: 32, padding: "0 10px", fontSize: 13, flexShrink: 0 },
698
+ onClick: () => setShowSecret((v) => !v),
699
+ type: "button",
700
+ title: showSecret ? "\u9690\u85CF\u5BC6\u94A5" : "\u663E\u793A\u660E\u6587"
701
+ }, showSecret ? "\u{1F648} \u9690\u85CF" : "\u{1F441}\uFE0F \u663E\u793A")
702
+ )
559
703
  ),
560
704
  React.createElement(
561
705
  "div",
@@ -588,7 +732,7 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
588
732
  login.phase === "error" && React.createElement("div", { style: { ...s.muted, fontSize: 12 } }, login.error ?? "\u767B\u5F55\u5931\u8D25")
589
733
  )
590
734
  ),
591
- // 高级设置(可折叠)
735
+ // 高级设置(紧凑 2x2 网格 + 恢复默认值)
592
736
  cfgDraft && React.createElement(
593
737
  "div",
594
738
  { style: s.block },
@@ -599,72 +743,83 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
599
743
  showAdvanced && React.createElement(
600
744
  "div",
601
745
  { style: { display: "flex", flexDirection: "column", gap: 10 } },
602
- // 心跳间隔
746
+ // 2x2 参数网格
603
747
  React.createElement(
604
748
  "div",
605
- null,
606
- React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u5FC3\u8DF3\u95F4\u9694\uFF08\u79D2\uFF09\u2014 \u957F\u4EFB\u52A1\u5904\u7406\u4E2D\u6BCF\u9694\u591A\u4E45\u53D1\u4E00\u6B21\u8FDB\u5EA6\u63D0\u793A"),
607
- React.createElement("input", {
608
- style: { ...s.input, width: 120 },
609
- type: "number",
610
- min: 30,
611
- max: 3600,
612
- value: cfgDraft.digestIntervalSec,
613
- onChange: (e) => setCfgDraft((d) => ({ ...d, digestIntervalSec: e.target.value }))
614
- })
615
- ),
616
- // 审批超时
617
- React.createElement(
618
- "div",
619
- null,
620
- React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u5BA1\u6279\u8D85\u65F6\uFF08\u79D2\uFF09\u2014 \u5DE5\u5177\u8C03\u7528\u5BA1\u6279\u65E0\u54CD\u5E94\u540E\u81EA\u52A8\u62D2\u7EDD"),
621
- React.createElement("input", {
622
- style: { ...s.input, width: 120 },
623
- type: "number",
624
- min: 30,
625
- max: 86400,
626
- value: cfgDraft.approvalTimeoutSec,
627
- onChange: (e) => setCfgDraft((d) => ({ ...d, approvalTimeoutSec: e.target.value }))
628
- })
629
- ),
630
- // 每气泡字数
631
- React.createElement(
632
- "div",
633
- null,
634
- React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u6BCF\u6761\u6D88\u606F\u6700\u5927\u5B57\u6570 \u2014 \u8D85\u51FA\u65F6\u81EA\u52A8\u5206\u591A\u6761\u53D1\u9001"),
635
- React.createElement("input", {
636
- style: { ...s.input, width: 120 },
637
- type: "number",
638
- min: 100,
639
- max: 1e4,
640
- value: cfgDraft.maxMessageChars,
641
- onChange: (e) => setCfgDraft((d) => ({ ...d, maxMessageChars: e.target.value }))
642
- })
643
- ),
644
- // 分块延迟
645
- React.createElement(
646
- "div",
647
- null,
648
- React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u5206\u5757\u53D1\u9001\u5EF6\u8FDF\uFF08\u6BEB\u79D2\uFF09\u2014 \u591A\u6761\u6D88\u606F\u4E4B\u95F4\u7684\u95F4\u9694"),
649
- React.createElement("input", {
650
- style: { ...s.input, width: 120 },
651
- type: "number",
652
- min: 0,
653
- max: 1e4,
654
- value: cfgDraft.sendChunkDelayMs,
655
- onChange: (e) => setCfgDraft((d) => ({ ...d, sendChunkDelayMs: e.target.value }))
656
- })
749
+ {
750
+ style: {
751
+ display: "grid",
752
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
753
+ gap: 10
754
+ }
755
+ },
756
+ // 心跳间隔
757
+ React.createElement(
758
+ "div",
759
+ null,
760
+ React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u5FC3\u8DF3\u8FDB\u5EA6\u95F4\u9694 (\u79D2)"),
761
+ React.createElement("input", {
762
+ style: { ...s.input, width: "100%" },
763
+ type: "number",
764
+ min: 30,
765
+ max: 3600,
766
+ value: cfgDraft.digestIntervalSec,
767
+ onChange: (e) => setCfgDraft((d) => ({ ...d, digestIntervalSec: e.target.value }))
768
+ })
769
+ ),
770
+ // 审批超时
771
+ React.createElement(
772
+ "div",
773
+ null,
774
+ React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u5BA1\u6279\u8D85\u65F6\u81EA\u52A8\u62D2\u7EDD (\u79D2)"),
775
+ React.createElement("input", {
776
+ style: { ...s.input, width: "100%" },
777
+ type: "number",
778
+ min: 30,
779
+ max: 86400,
780
+ value: cfgDraft.approvalTimeoutSec,
781
+ onChange: (e) => setCfgDraft((d) => ({ ...d, approvalTimeoutSec: e.target.value }))
782
+ })
783
+ ),
784
+ // 每气泡字数
785
+ React.createElement(
786
+ "div",
787
+ null,
788
+ React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u5355\u6761\u6700\u5927\u5B57\u6570\u9650\u5236 (\u5B57)"),
789
+ React.createElement("input", {
790
+ style: { ...s.input, width: "100%" },
791
+ type: "number",
792
+ min: 100,
793
+ max: 1e4,
794
+ value: cfgDraft.maxMessageChars,
795
+ onChange: (e) => setCfgDraft((d) => ({ ...d, maxMessageChars: e.target.value }))
796
+ })
797
+ ),
798
+ // 分块延迟
799
+ React.createElement(
800
+ "div",
801
+ null,
802
+ React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "\u5206\u5757\u53D1\u9001\u5EF6\u8FDF (\u6BEB\u79D2)"),
803
+ React.createElement("input", {
804
+ style: { ...s.input, width: "100%" },
805
+ type: "number",
806
+ min: 0,
807
+ max: 1e4,
808
+ value: cfgDraft.sendChunkDelayMs,
809
+ onChange: (e) => setCfgDraft((d) => ({ ...d, sendChunkDelayMs: e.target.value }))
810
+ })
811
+ )
657
812
  ),
658
813
  // QQ 平台凭证
659
814
  platformId === "qq" && React.createElement(
660
815
  "div",
661
- { style: { display: "flex", flexDirection: "column", gap: 10 } },
816
+ { style: { display: "flex", flexDirection: "column", gap: 10, marginTop: 4 } },
662
817
  React.createElement(
663
818
  "div",
664
819
  null,
665
820
  React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "AppID \u2014 QQ \u5F00\u653E\u5E73\u53F0\u673A\u5668\u4EBA\u5E94\u7528 ID"),
666
821
  React.createElement("input", {
667
- style: { ...s.input, width: 220 },
822
+ style: { ...s.input, width: "100%" },
668
823
  placeholder: "\u8BF7\u8F93\u5165 AppID",
669
824
  value: cfgDraft.appId,
670
825
  onChange: (e) => setCfgDraft((d) => ({ ...d, appId: e.target.value }))
@@ -673,20 +828,40 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
673
828
  React.createElement(
674
829
  "div",
675
830
  null,
676
- React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "ClientSecret \u2014 QQ \u5F00\u653E\u5E73\u53F0\u673A\u5668\u4EBA\u5BC6\u94A5"),
677
- React.createElement("input", {
678
- style: { ...s.input, width: 220 },
679
- placeholder: "\u8BF7\u8F93\u5165 ClientSecret",
680
- value: cfgDraft.clientSecret,
681
- onChange: (e) => setCfgDraft((d) => ({ ...d, clientSecret: e.target.value }))
682
- })
831
+ React.createElement("div", { style: { ...s.muted, marginBottom: 4 } }, "ClientSecret \u2014 QQ \u5F00\u653E\u5E73\u53F0\u673A\u5668\u4EBA\u5BC6\u94A5\uFF08\u7559\u7A7A\u5219\u4FDD\u6301\u5DF2\u4FDD\u5B58\u5BC6\u94A5\uFF09"),
832
+ React.createElement(
833
+ "div",
834
+ { style: { display: "flex", gap: 6, alignItems: "center" } },
835
+ React.createElement("input", {
836
+ style: { ...s.input, flex: 1 },
837
+ type: showSecret ? "text" : "password",
838
+ placeholder: "\u7559\u7A7A\u4FDD\u6301\u5DF2\u4FDD\u5B58\u5BC6\u94A5",
839
+ value: cfgDraft.clientSecret,
840
+ onChange: (e) => setCfgDraft((d) => ({ ...d, clientSecret: e.target.value }))
841
+ }),
842
+ React.createElement("button", {
843
+ style: { ...s.btnGhost, height: 32, padding: "0 10px", fontSize: 13, flexShrink: 0 },
844
+ onClick: () => setShowSecret((v) => !v),
845
+ type: "button",
846
+ title: showSecret ? "\u9690\u85CF\u5BC6\u94A5" : "\u663E\u793A\u660E\u6587"
847
+ }, showSecret ? "\u{1F648} \u9690\u85CF" : "\u{1F441}\uFE0F \u663E\u793A")
848
+ )
683
849
  )
684
850
  ),
685
- React.createElement("button", {
686
- style: { ...s.btnPri, alignSelf: "flex-start", opacity: cfgDirty && !busy ? 1 : 0.5 },
687
- disabled: !cfgDirty || busy,
688
- onClick: saveConfig
689
- }, busy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u8BBE\u7F6E")
851
+ React.createElement(
852
+ "div",
853
+ { style: { display: "flex", gap: 8, alignItems: "center", marginTop: 4 } },
854
+ React.createElement("button", {
855
+ style: { ...s.btnPri, opacity: cfgDirty && !busy ? 1 : 0.5 },
856
+ disabled: !cfgDirty || busy,
857
+ onClick: saveConfig
858
+ }, busy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u8BBE\u7F6E"),
859
+ React.createElement("button", {
860
+ style: { ...s.btnGhost, height: 32, fontSize: 12 },
861
+ onClick: resetDefaults,
862
+ title: "\u6062\u590D\u63A8\u8350\u9ED8\u8BA4\u914D\u7F6E"
863
+ }, "\u21BA \u6062\u590D\u63A8\u8350\u9ED8\u8BA4")
864
+ )
690
865
  )
691
866
  ),
692
867
  React.createElement(
@@ -832,9 +1007,9 @@ function VersionBanner({ rpcCall }) {
832
1007
  );
833
1008
  }
834
1009
  var TABS = [
835
- { id: "lan", label: "\u5C40\u57DF\u7F51" },
836
- { id: "tunnel", label: "\u516C\u7F51\u96A7\u9053" },
837
- { id: "im", label: "IM \u673A\u5668\u4EBA" }
1010
+ { id: "lan", label: "\u5C40\u57DF\u7F51", icon: "\u{1F4F6}" },
1011
+ { id: "tunnel", label: "\u516C\u7F51\u96A7\u9053", icon: "\u{1F310}" },
1012
+ { id: "im", label: "IM \u673A\u5668\u4EBA", icon: "\u{1F916}" }
838
1013
  ];
839
1014
  function TabBar({ active, onChange, dots }) {
840
1015
  return React.createElement(
@@ -842,12 +1017,12 @@ function TabBar({ active, onChange, dots }) {
842
1017
  {
843
1018
  style: {
844
1019
  display: "flex",
845
- gap: 0,
1020
+ gap: 4,
846
1021
  marginBottom: 20,
847
1022
  borderBottom: "1px solid var(--dsw-alias-border-l2,#e5e7eb)"
848
1023
  }
849
1024
  },
850
- TABS.map(({ id, label }) => {
1025
+ TABS.map(({ id, label, icon }) => {
851
1026
  const isActive = active === id;
852
1027
  const hasDot = dots?.[id];
853
1028
  return React.createElement(
@@ -873,6 +1048,7 @@ function TabBar({ active, onChange, dots }) {
873
1048
  whiteSpace: "nowrap"
874
1049
  }
875
1050
  },
1051
+ React.createElement("span", { style: { fontSize: 14 } }, icon),
876
1052
  label,
877
1053
  hasDot && React.createElement("span", {
878
1054
  style: {
@@ -1011,9 +1187,9 @@ function BridgePanel({ rpcCall }) {
1011
1187
  );
1012
1188
  } else if (activeTab === "im") {
1013
1189
  const IM_PLATFORMS = [
1014
- { id: "wechat", label: "\u5FAE\u4FE1", desc: "iLink Bot API\uFF08ClawBot\uFF09" },
1015
- { id: "qq", label: "QQ", desc: "QQ Bot OpenAPI v2\uFF08\u79C1\u804A/\u7FA4\u804A/\u6309\u94AE\uFF09" },
1016
- { id: "feishu", label: "\u98DE\u4E66", desc: "\u5B98\u65B9\u4E8B\u4EF6\u56DE\u8C03 API" }
1190
+ { id: "wechat", label: "\u5FAE\u4FE1", icon: "\u{1F4AC}", desc: "ClawBot \u626B\u7801\u76F4\u8FDE \xB7 \u65E0\u9700\u516C\u7F51" },
1191
+ { id: "qq", label: "QQ", icon: "\u{1F427}", desc: "\u5B98\u65B9\u673A\u5668\u4EBA \xB7 \u79C1\u804A/\u7FA4\u804A/\u6309\u94AE" },
1192
+ { id: "feishu", label: "\u98DE\u4E66", icon: "\u{1F54A}\uFE0F", desc: "\u5B98\u65B9\u4E8B\u4EF6\u56DE\u8C03 API" }
1017
1193
  ];
1018
1194
  tabContent = React.createElement(
1019
1195
  "div",
@@ -1024,7 +1200,7 @@ function BridgePanel({ rpcCall }) {
1024
1200
  {
1025
1201
  style: { display: "flex", gap: 10, marginBottom: 16, flexWrap: "wrap" }
1026
1202
  },
1027
- IM_PLATFORMS.map(({ id, label, desc }) => {
1203
+ IM_PLATFORMS.map(({ id, label, icon, desc }) => {
1028
1204
  const platformData = platforms?.[id];
1029
1205
  const available = !!platformData;
1030
1206
  const active = platformData?.status === "connected" || platformData?.status === "starting" || platformData?.status === "reconnecting";
@@ -1033,21 +1209,27 @@ function BridgePanel({ rpcCall }) {
1033
1209
  {
1034
1210
  key: id,
1035
1211
  style: {
1036
- flex: "1 1 140px",
1037
- border: `1px solid ${selectedPlatform === id ? "var(--dsw-alias-state-info-primary,#3b82f6)" : active ? "var(--dsw-alias-state-success-primary,#10b981)" : "var(--dsw-alias-border-l2,#e5e7eb)"}`,
1212
+ flex: "1 1 150px",
1213
+ border: `1px solid ${selectedPlatform === id ? "var(--dsw-alias-brand-primary,#4f6ef7)" : active ? "var(--dsw-alias-state-success-primary,#10b981)" : "var(--dsw-alias-border-l2,#e5e7eb)"}`,
1038
1214
  borderRadius: 10,
1039
1215
  padding: "12px 14px",
1040
- opacity: available ? 1 : 0.45,
1216
+ opacity: available ? 1 : 0.5,
1041
1217
  cursor: available ? "pointer" : "not-allowed",
1042
- background: selectedPlatform === id ? "var(--dsw-alias-state-info-bg,#eff6ff)" : active ? "var(--dsw-alias-state-success-bg,#ecfdf5)" : available ? "var(--dsw-alias-bg-layer-1,transparent)" : "var(--dsw-alias-bg-layer-2,#f9fafb)",
1218
+ background: selectedPlatform === id ? "var(--dsw-alias-state-info-bg,#eff6ff)" : active ? "var(--dsw-alias-state-success-bg,#ecfdf5)" : "var(--dsw-alias-bg-layer-2,#f9fafb)",
1219
+ boxShadow: selectedPlatform === id ? "0 0 0 1px var(--dsw-alias-brand-primary,#4f6ef7)" : "none",
1043
1220
  transition: "all 0.15s ease"
1044
1221
  },
1045
1222
  onClick: available ? () => setSelectedPlatform(id) : void 0
1046
1223
  },
1047
1224
  React.createElement(
1048
1225
  "div",
1049
- { style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", gap: 6 } },
1050
- label,
1226
+ { style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", justifyContent: "space-between" } },
1227
+ React.createElement(
1228
+ "span",
1229
+ { style: { display: "flex", alignItems: "center", gap: 6 } },
1230
+ React.createElement("span", { style: { fontSize: 14 } }, icon),
1231
+ label
1232
+ ),
1051
1233
  active && React.createElement("span", {
1052
1234
  style: { width: 6, height: 6, borderRadius: "50%", background: "var(--dsw-alias-state-success-primary,#10b981)", flexShrink: 0 }
1053
1235
  }),
@@ -1058,7 +1240,7 @@ function BridgePanel({ rpcCall }) {
1058
1240
  style: { fontSize: 11, color: "var(--dsw-alias-label-tertiary,#9ca3af)", fontWeight: 400 }
1059
1241
  }, "\u5373\u5C06\u652F\u6301")
1060
1242
  ),
1061
- React.createElement("div", { style: { ...s.muted, marginTop: 3, fontSize: 11 } }, desc)
1243
+ React.createElement("div", { style: { ...s.muted, marginTop: 4, fontSize: 11 } }, desc)
1062
1244
  );
1063
1245
  })
1064
1246
  ),
@@ -1076,7 +1258,7 @@ function BridgePanel({ rpcCall }) {
1076
1258
  }
1077
1259
  return React.createElement(
1078
1260
  "div",
1079
- { style: { maxWidth: 560 } },
1261
+ { style: { maxWidth: 620 } },
1080
1262
  err && React.createElement("div", {
1081
1263
  style: { ...s.card, background: "var(--dsw-alias-state-error-bg,#fef2f2)", color: "var(--dsw-alias-state-error-primary,#dc2626)", fontSize: 13, marginBottom: 16 }
1082
1264
  }, err),