dsh-monkeyai-sessions 0.1.8 → 0.1.9

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.
@@ -538,12 +538,19 @@ var t = {
538
538
  radiusLg: 10
539
539
  };
540
540
  var style = {
541
- page: { display: "grid", gap: 12, maxWidth: 1080, margin: "0 auto", padding: "16px 18px 24px", color: t.text, height: "100%", minHeight: 0, overflowY: "auto", boxSizing: "border-box", alignContent: "start", fontSize: 13, lineHeight: 1.5 },
541
+ page: { display: "grid", gap: 14, maxWidth: 1320, margin: "0 auto", padding: "18px 20px 24px", color: t.text, background: "#f7f8fb", height: "100%", minHeight: 0, overflowY: "auto", boxSizing: "border-box", alignContent: "start", fontSize: 13, lineHeight: 1.5 },
542
542
  header: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, paddingBottom: 2 },
543
- title: { margin: 0, fontSize: 15, fontWeight: 650, letterSpacing: "-0.01em", color: t.text },
543
+ title: { margin: 0, fontSize: 18, fontWeight: 700, letterSpacing: "-0.025em", color: "#182230" },
544
+ eyebrow: { margin: 0, fontSize: 10.5, fontWeight: 700, letterSpacing: "0.1em", color: t.text3, textTransform: "uppercase" },
544
545
  subtitle: { margin: 0, fontSize: 12, color: t.text3 },
545
546
  sectionTitle: { margin: 0, fontSize: 12, fontWeight: 650, color: t.text2, textTransform: "uppercase", letterSpacing: "0.04em" },
546
- card: { display: "grid", gap: 10, padding: 14, border: `1px solid ${t.border}`, borderRadius: t.radiusLg, background: t.surface },
547
+ card: { display: "grid", gap: 10, padding: 14, border: `1px solid ${t.border}`, borderRadius: 12, background: t.surface, boxShadow: "0 2px 8px rgba(16,24,40,0.035)" },
548
+ toolbarCard: { display: "grid", gap: 10, padding: "13px 15px", border: `1px solid ${t.border}`, borderRadius: 12, background: t.surface, boxShadow: "0 2px 8px rgba(16,24,40,0.035)" },
549
+ workspace: { display: "grid", gridTemplateColumns: "minmax(248px, 292px) minmax(0, 1fr)", gap: 12, minWidth: 0, alignItems: "stretch" },
550
+ sessionSidebar: { display: "grid", gridTemplateRows: "auto minmax(0, 1fr) auto", gap: 10, minWidth: 0, padding: 12, border: `1px solid ${t.border}`, borderRadius: 12, background: t.surface, boxShadow: "0 2px 8px rgba(16,24,40,0.035)" },
551
+ sessionList: { display: "grid", gridTemplateColumns: "1fr", alignContent: "start", gap: 6, minHeight: 0, overflowY: "auto", padding: "1px 3px 2px 1px" },
552
+ thread: { display: "grid", gridTemplateRows: "auto minmax(0, 1fr) auto", gap: 10, minWidth: 0, height: "min(70vh, 720px)", minHeight: 440, overflow: "hidden", padding: 12 },
553
+ emptyThread: { display: "grid", placeContent: "center", justifyItems: "center", gap: 9, minWidth: 0, minHeight: "min(70vh, 720px)", padding: 28, border: `1px dashed ${t.border2}`, borderRadius: 12, background: "linear-gradient(145deg, #ffffff 0%, #f8faff 100%)", textAlign: "center" },
547
554
  row: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
548
555
  label: { display: "grid", gap: 4, flex: 1, minWidth: 180, fontSize: 12, fontWeight: 600, color: t.text2 },
549
556
  input: { width: "100%", boxSizing: "border-box", padding: "7px 10px", borderRadius: t.radius, border: `1px solid ${t.border2}`, background: t.surface, color: t.text, outline: "none", fontSize: 13, transition: "border-color .15s, box-shadow .15s" },
@@ -562,13 +569,13 @@ var style = {
562
569
  sessionTitle: { fontSize: 13, fontWeight: 650, lineHeight: 1.35, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
563
570
  sessionMeta: { fontSize: 11.5, color: t.text3, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
564
571
  chip: { display: "inline-flex", alignItems: "center", gap: 5, padding: "2px 8px", borderRadius: 999, border: `1px solid ${t.border}`, background: t.surfaceAlt, fontSize: 11.5 },
565
- events: { display: "flex", flexDirection: "column", gap: 8, height: "56vh", minHeight: 200, overflowY: "auto", padding: "4px 6px 4px 2px" },
572
+ events: { display: "flex", flexDirection: "column", gap: 10, height: "auto", minHeight: 0, overflowY: "auto", padding: "6px 8px 8px 4px", overscrollBehavior: "contain" },
566
573
  event: { padding: "8px 11px", borderRadius: t.radius, background: t.surfaceAlt, border: `1px solid ${t.border}`, overflowWrap: "anywhere", color: t.text },
567
574
  bubbleWrap: { display: "flex", gap: 8, alignItems: "flex-start", width: "100%" },
568
575
  bubbleWrapUser: { display: "flex", gap: 8, alignItems: "flex-start", justifyContent: "flex-end", width: "100%" },
569
576
  avatar: { width: 24, height: 24, borderRadius: "50%", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 10, fontWeight: 700, color: "#ffffff", flexShrink: 0, marginTop: 2 },
570
- bubble: { maxWidth: "88%", minWidth: 0, flex: "0 1 auto", width: "fit-content", borderRadius: t.radiusLg, padding: "8px 13px", background: t.surfaceAlt, border: `1px solid ${t.border}`, lineHeight: 1.55, fontSize: 13 },
571
- bubbleUser: { maxWidth: "88%", minWidth: 0, flex: "0 1 auto", width: "fit-content", borderRadius: t.radiusLg, padding: "8px 13px", background: t.accent, color: "#ffffff", lineHeight: 1.55, fontSize: 13 },
577
+ bubble: { maxWidth: "88%", minWidth: 0, flex: "0 1 auto", width: "fit-content", borderRadius: 12, padding: "9px 13px", background: t.surface, border: `1px solid ${t.border}`, boxShadow: "0 1px 2px rgba(16,24,40,0.04)", lineHeight: 1.6, fontSize: 13 },
578
+ bubbleUser: { maxWidth: "88%", minWidth: 0, flex: "0 1 auto", width: "fit-content", borderRadius: 12, padding: "9px 13px", background: "#315fe8", color: "#ffffff", boxShadow: "0 2px 5px rgba(49,95,232,0.18)", lineHeight: 1.6, fontSize: 13 },
572
579
  thought: { maxWidth: "88%", borderRadius: t.radiusLg, padding: "7px 11px", background: "#faf7fd", border: `1px solid #e8ddf5`, lineHeight: 1.5, fontSize: 12.5, color: "#5b4a72" },
573
580
  thoughtSummary: { cursor: "pointer", color: "#6b4fa0", fontWeight: 650, fontSize: 10.5, letterSpacing: "0.05em", textTransform: "uppercase", userSelect: "none" },
574
581
  approval: { padding: "11px 13px", borderRadius: t.radiusLg, border: `1px solid #f0d98c`, background: "#fffbeb", display: "grid", gap: 8 },
@@ -591,6 +598,36 @@ var PANEL_CSS = `
591
598
  .mai-panel [data-events]::-webkit-scrollbar-thumb:hover { background: #b8c2cf; }
592
599
  .mai-panel .mai-card-hover { transition: border-color .15s, background .15s; }
593
600
  .mai-panel .mai-card-hover:not(:disabled):hover { border-color: #b9cdf3 !important; background: #f7faff !important; }
601
+ .mai-panel .mai-toolbar { position: relative; overflow: hidden; }
602
+ .mai-panel .mai-toolbar::before { content: ''; position: absolute; inset: 0 0 auto; height: 3px; background: linear-gradient(90deg, #3568e8 0%, #8baaf4 46%, #e7edfc 100%); }
603
+ .mai-panel .mai-workspace { display: grid; grid-template-columns: minmax(248px, 292px) minmax(0, 1fr); gap: 12px; min-width: 0; align-items: stretch; }
604
+ .mai-panel .mai-session-sidebar { min-height: min(70vh, 720px); }
605
+ .mai-panel .mai-session-list { scrollbar-gutter: stable; }
606
+ .mai-panel .mai-session-card { position: relative; }
607
+ .mai-panel .mai-session-card[aria-current='true']::before { content: ''; position: absolute; left: 0; top: 9px; bottom: 9px; width: 3px; border-radius: 0 3px 3px 0; background: #3568e8; }
608
+ .mai-panel .mai-thread { height: min(70vh, 720px); min-height: 440px; }
609
+ .mai-panel .mai-thread-events { height: auto !important; min-height: 0 !important; }
610
+ .mai-panel .mai-empty-thread { min-height: min(70vh, 720px); }
611
+ .mai-panel .mai-empty-mark { display: grid; place-items: center; width: 54px; height: 54px; border-radius: 17px; background: #edf2ff; color: #315fe8; box-shadow: inset 0 0 0 1px #dce6ff; }
612
+ .mai-panel .mai-session-meta { overflow-wrap: anywhere; }
613
+ @media (max-width: 900px) {
614
+ .mai-panel .mai-workspace { grid-template-columns: minmax(0, 1fr); }
615
+ .mai-panel .mai-session-sidebar { min-height: 0; grid-template-rows: auto minmax(0, auto) auto; }
616
+ .mai-panel .mai-session-list { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); max-height: 235px; }
617
+ .mai-panel .mai-thread { height: 68vh; min-height: 390px; }
618
+ .mai-panel .mai-empty-thread { min-height: 330px; }
619
+ }
620
+ @media (max-width: 560px) {
621
+ .mai-panel .mai-page-title { font-size: 16px !important; }
622
+ .mai-panel .mai-toolbar-controls { align-items: stretch; }
623
+ .mai-panel .mai-toolbar-controls select { flex-basis: 100% !important; }
624
+ .mai-panel .mai-session-list { grid-template-columns: 1fr !important; max-height: 210px; }
625
+ .mai-panel .mai-thread { height: 68vh; min-height: 360px; padding: 10px; }
626
+ .mai-panel .mai-thread-header { gap: 6px !important; }
627
+ .mai-panel .mai-thread-header strong { min-width: 100px; }
628
+ .mai-panel .mai-thread-header select { flex-basis: 100% !important; }
629
+ .mai-panel .mai-events { gap: 7px; }
630
+ }
594
631
  @keyframes mai-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
595
632
  .mai-panel .mai-pulse { animation: mai-pulse 1.2s ease-in-out infinite; }
596
633
  .mai-panel .mai-md > div:first-child > :first-child { margin-top: 0; }
@@ -1409,9 +1446,14 @@ function RemoteSessionPage({ api }) {
1409
1446
  { style: style.header },
1410
1447
  h(
1411
1448
  "div",
1412
- { style: { display: "flex", alignItems: "center", gap: 8 } },
1413
- h(MonkeyIcon, { size: 22 }),
1414
- h("h1", { style: style.title }, "MonkeyAI \u4F1A\u8BDD")
1449
+ { style: { display: "grid", gap: 1 } },
1450
+ h("p", { style: style.eyebrow }, "\u8FDC\u7A0B\u5DE5\u4F5C\u533A"),
1451
+ h(
1452
+ "div",
1453
+ { style: { display: "flex", alignItems: "center", gap: 8 } },
1454
+ h(MonkeyIcon, { size: 22 }),
1455
+ h("h1", { style: style.title, className: "mai-page-title" }, "MonkeyAI \u4F1A\u8BDD")
1456
+ )
1415
1457
  ),
1416
1458
  h(StatusBadge, { status, live: isLive })
1417
1459
  ),
@@ -1565,16 +1607,21 @@ function RemoteSessionPage({ api }) {
1565
1607
  ) : null,
1566
1608
  currentAccount ? h(
1567
1609
  "section",
1568
- { style: style.card },
1610
+ { style: style.toolbarCard, className: "mai-toolbar" },
1569
1611
  h(
1570
1612
  "div",
1571
- { style: style.row },
1572
- h("h2", { style: { ...style.sectionTitle, flex: 1 } }, "\u8FDC\u7A0B\u4F1A\u8BDD"),
1573
- h("span", { style: { fontSize: 11, color: t.text3 } }, currentAccount.scopes.filter((s) => s !== "device:connect").join(" \xB7 "))
1613
+ { style: style.row, className: "mai-toolbar-heading" },
1614
+ h(
1615
+ "div",
1616
+ { style: { display: "grid", gap: 1, flex: 1, minWidth: 0 } },
1617
+ h("h2", { style: style.sectionTitle }, "\u8FDC\u7A0B\u4F1A\u8BDD"),
1618
+ h("p", { style: style.subtitle }, "\u9009\u62E9\u8BBE\u5907\uFF0C\u7EE7\u7EED\u5904\u7406 MonkeyAI \u4F1A\u8BDD")
1619
+ ),
1620
+ h("span", { style: style.chip }, currentAccount.scopes.filter((s) => s !== "device:connect").join(" \xB7 "))
1574
1621
  ),
1575
1622
  h(
1576
1623
  "div",
1577
- { style: style.row },
1624
+ { style: style.row, className: "mai-toolbar-controls" },
1578
1625
  h(
1579
1626
  "select",
1580
1627
  { style: { ...style.input, flex: "1 1 200px" }, value: accountId, onChange: (event) => setAccountId(event.target.value), "aria-label": "\u5DF2\u6388\u6743\u8D26\u53F7" },
@@ -1676,248 +1723,282 @@ function RemoteSessionPage({ api }) {
1676
1723
  }, newSessionBusy ? "\u521B\u5EFA\u4E2D\u2026" : "\u521B\u5EFA")
1677
1724
  )
1678
1725
  )
1679
- ),
1680
- sessionOptions.length > 0 ? h("div", { style: style.sessions }, sessionOptions.map((session) => {
1681
- const flag = session.stale ? "\u5DF2\u8FC7\u671F" : session.deviceStatus && session.deviceStatus !== "online" ? session.deviceStatus === "offline" ? "\u79BB\u7EBF" : session.deviceStatus : "";
1682
- return h(
1683
- "button",
1684
- {
1685
- style: { ...style.session, ...session.id === sessionId ? style.selected : {} },
1686
- className: "mai-card-hover",
1687
- key: session.id,
1688
- type: "button",
1689
- disabled: !session.cwd,
1690
- onClick: () => openSession(session),
1691
- title: session.cwd ? `\u6253\u5F00 ${session.cwd}` : "ACP \u4F1A\u8BDD\u5217\u8868\u672A\u63D0\u4F9B\u5DE5\u4F5C\u76EE\u5F55"
1692
- },
1693
- h("span", { style: style.sessionTitle }, session.title || session.id),
1694
- h("span", { style: style.sessionMeta }, session.cwd || "\u52A0\u8F7D\u5386\u53F2\u9700\u8981 runtime \u63D0\u4F9B\u5DE5\u4F5C\u76EE\u5F55"),
1695
- flag !== "" ? h("span", { style: { fontSize: 10.5, fontWeight: 650, color: session.stale ? t.text3 : "#8a6d1d", textTransform: "uppercase", letterSpacing: "0.04em" } }, flag) : null
1696
- );
1697
- })) : h("p", { style: style.subtitle }, machineId ? "\u8BE5\u8BBE\u5907\u6682\u65E0\u4F1A\u8BDD\u3002\u53EF\u5728\u4E0A\u65B9\u65B0\u5EFA\uFF0C\u6216\u70B9\u51FB\u5237\u65B0\u3002" : "\u8BF7\u9009\u62E9\u8BBE\u5907\u4EE5\u5217\u51FA\u5176\u4F1A\u8BDD\u3002")
1726
+ )
1698
1727
  ) : null,
1699
- sessionId ? h(
1700
- "section",
1701
- { style: style.card },
1728
+ currentAccount ? h(
1729
+ "div",
1730
+ { className: "mai-workspace" },
1702
1731
  h(
1703
- "div",
1704
- { style: style.row },
1705
- h("button", {
1706
- type: "button",
1707
- style: { ...style.button, flexShrink: 0 },
1708
- title: "\u5173\u95ED\u4F1A\u8BDD\u5E76\u8FD4\u56DE\u5217\u8868",
1709
- onClick: () => {
1710
- streamGenerationRef.current += 1;
1711
- streamRef.current?.dispose();
1712
- streamRef.current = null;
1713
- setSessionId("");
1714
- setTurnActive(false);
1715
- setStopping(false);
1716
- setSessionStatus("");
1717
- setStatus("\u8FDC\u7A0B\u4F1A\u8BDD\u5DF2\u5173\u95ED");
1718
- }
1719
- }, "\u2190"),
1720
- h("strong", { style: { flex: 1, fontSize: 13.5, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, title }, title),
1721
- sessionStatus ? h(
1722
- "span",
1723
- {
1724
- style: {
1725
- ...style.statusBadge,
1726
- background: sessionStatus === "running" ? t.accentSoft : sessionStatus === "error" ? t.dangerBg : t.surfaceAlt,
1727
- borderColor: sessionStatus === "running" ? t.accent : sessionStatus === "error" ? t.dangerBorder : t.border,
1728
- color: sessionStatus === "running" ? t.accent : sessionStatus === "error" ? t.danger : t.text2
1732
+ "aside",
1733
+ { style: style.sessionSidebar, className: "mai-session-sidebar" },
1734
+ h(
1735
+ "div",
1736
+ { style: { ...style.row, justifyContent: "space-between" } },
1737
+ h("h2", { style: style.sectionTitle }, "\u4F1A\u8BDD\u5217\u8868"),
1738
+ h("span", { style: style.chip }, String(sessionOptions.length))
1739
+ ),
1740
+ sessionOptions.length > 0 ? h("div", { style: style.sessions, className: "mai-session-list" }, sessionOptions.map((session) => {
1741
+ const flag = session.stale ? "\u5DF2\u8FC7\u671F" : session.deviceStatus && session.deviceStatus !== "online" ? session.deviceStatus === "offline" ? "\u79BB\u7EBF" : session.deviceStatus : "";
1742
+ return h(
1743
+ "button",
1744
+ {
1745
+ style: { ...style.session, ...session.id === sessionId ? style.selected : {} },
1746
+ className: "mai-card-hover mai-session-card",
1747
+ "aria-current": session.id === sessionId ? "true" : void 0,
1748
+ key: session.id,
1749
+ type: "button",
1750
+ disabled: !session.cwd,
1751
+ onClick: () => openSession(session),
1752
+ title: session.cwd ? `\u6253\u5F00 ${session.cwd}` : "ACP \u4F1A\u8BDD\u5217\u8868\u672A\u63D0\u4F9B\u5DE5\u4F5C\u76EE\u5F55"
1729
1753
  },
1730
- title: "\u4F1A\u8BDD\u72B6\u6001",
1731
- "aria-label": `\u4F1A\u8BDD\u72B6\u6001\uFF1A${SESSION_STATUS_LABEL[sessionStatus]}`
1732
- },
1733
- sessionStatus === "running" ? h("span", { className: "mai-pulse", style: { ...style.dot, background: t.accent } }) : null,
1734
- SESSION_STATUS_LABEL[sessionStatus]
1735
- ) : null,
1754
+ h("span", { style: style.sessionTitle }, session.title || session.id),
1755
+ h("span", { style: style.sessionMeta, className: "mai-session-meta" }, session.cwd || "\u52A0\u8F7D\u5386\u53F2\u9700\u8981 runtime \u63D0\u4F9B\u5DE5\u4F5C\u76EE\u5F55"),
1756
+ flag !== "" ? h("span", { style: { fontSize: 10.5, fontWeight: 650, color: session.stale ? t.text3 : "#8a6d1d", textTransform: "uppercase", letterSpacing: "0.04em" } }, flag) : null
1757
+ );
1758
+ })) : h(
1759
+ "div",
1760
+ { style: { display: "grid", justifyItems: "center", gap: 7, padding: "22px 12px", textAlign: "center" } },
1761
+ h("span", { style: { ...style.avatar, width: 34, height: 34, background: t.surfaceAlt, color: t.text3, fontSize: 17 } }, "\xB7"),
1762
+ h("span", { style: { fontSize: 12, fontWeight: 600, color: t.text2 } }, machineId ? "\u8FD9\u91CC\u8FD8\u6CA1\u6709\u4F1A\u8BDD" : "\u8BF7\u9009\u62E9\u8FDC\u7A0B\u8BBE\u5907"),
1763
+ h("span", { style: { fontSize: 11, color: t.text3 } }, machineId ? "\u5237\u65B0\u4F1A\u8BDD\u6216\u521B\u5EFA\u4E00\u4E2A\u65B0\u4F1A\u8BDD" : "\u4F1A\u8BDD\u5217\u8868\u4F1A\u663E\u793A\u5728\u8FD9\u91CC")
1764
+ ),
1736
1765
  h(
1737
- "select",
1738
- {
1739
- style: { ...style.input, flex: "0 1 190px", minWidth: 130 },
1740
- value: currentModel,
1741
- disabled: !hasControl || switchingModel || models.length === 0,
1742
- title: "\u5207\u6362\u8BE5\u4F1A\u8BDD\u7684\u6A21\u578B",
1743
- onChange: (event) => {
1744
- const next = event.target.value;
1745
- if (next && next !== currentModel) switchSessionModel(next);
1746
- }
1747
- },
1748
- currentModel && !models.some((m) => m.id === currentModel) ? h("option", { value: currentModel }, currentModel.slice(0, 24)) : null,
1749
- models.map((m) => h("option", { key: m.id, value: m.id }, `${m.displayName} (${Math.round(m.contextWindowTokens / 1e3)}k)`))
1766
+ "div",
1767
+ { style: { borderTop: `1px solid ${t.border}`, paddingTop: 8 } },
1768
+ h("p", { style: { margin: 0, fontSize: 10.5, color: t.text3 } }, machineId ? "\u4F1A\u8BDD\u6765\u81EA\u6240\u9009\u8BBE\u5907\u7684 runtime" : "\u8FDE\u63A5\u8BBE\u5907\u540E\u67E5\u770B\u4F1A\u8BDD")
1750
1769
  )
1751
1770
  ),
1752
- h(
1753
- "div",
1754
- {
1755
- style: style.events,
1756
- "aria-live": "polite",
1757
- "data-events": "",
1758
- ref: eventsRef,
1759
- onScroll: (event) => {
1760
- const el = event.currentTarget;
1761
- if (el.scrollTop < 60 && visibleCount < displayEntries.length) {
1762
- prevScrollHeightRef.current = el.scrollHeight;
1763
- setVisibleCount((count) => Math.min(count + 100, displayEntries.length));
1771
+ sessionId ? h(
1772
+ "section",
1773
+ { style: { ...style.card, ...style.thread }, className: "mai-thread" },
1774
+ h(
1775
+ "div",
1776
+ { style: style.row, className: "mai-thread-header" },
1777
+ h("button", {
1778
+ type: "button",
1779
+ style: { ...style.button, flexShrink: 0 },
1780
+ title: "\u5173\u95ED\u4F1A\u8BDD\u5E76\u8FD4\u56DE\u5217\u8868",
1781
+ onClick: () => {
1782
+ streamGenerationRef.current += 1;
1783
+ streamRef.current?.dispose();
1784
+ streamRef.current = null;
1785
+ setSessionId("");
1786
+ setTurnActive(false);
1787
+ setStopping(false);
1788
+ setSessionStatus("");
1789
+ setStatus("\u8FDC\u7A0B\u4F1A\u8BDD\u5DF2\u5173\u95ED");
1764
1790
  }
1765
- }
1766
- },
1767
- historyLoading ? h(
1791
+ }, "\u2190"),
1792
+ h("strong", { style: { flex: 1, fontSize: 13.5, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, title }, title),
1793
+ sessionStatus ? h(
1794
+ "span",
1795
+ {
1796
+ style: {
1797
+ ...style.statusBadge,
1798
+ background: sessionStatus === "running" ? t.accentSoft : sessionStatus === "error" ? t.dangerBg : t.surfaceAlt,
1799
+ borderColor: sessionStatus === "running" ? t.accent : sessionStatus === "error" ? t.dangerBorder : t.border,
1800
+ color: sessionStatus === "running" ? t.accent : sessionStatus === "error" ? t.danger : t.text2
1801
+ },
1802
+ title: "\u4F1A\u8BDD\u72B6\u6001",
1803
+ "aria-label": `\u4F1A\u8BDD\u72B6\u6001\uFF1A${SESSION_STATUS_LABEL[sessionStatus]}`
1804
+ },
1805
+ sessionStatus === "running" ? h("span", { className: "mai-pulse", style: { ...style.dot, background: t.accent } }) : null,
1806
+ SESSION_STATUS_LABEL[sessionStatus]
1807
+ ) : null,
1808
+ h(
1809
+ "select",
1810
+ {
1811
+ style: { ...style.input, flex: "0 1 190px", minWidth: 130 },
1812
+ value: currentModel,
1813
+ disabled: !hasControl || switchingModel || models.length === 0,
1814
+ title: "\u5207\u6362\u8BE5\u4F1A\u8BDD\u7684\u6A21\u578B",
1815
+ onChange: (event) => {
1816
+ const next = event.target.value;
1817
+ if (next && next !== currentModel) switchSessionModel(next);
1818
+ }
1819
+ },
1820
+ currentModel && !models.some((m) => m.id === currentModel) ? h("option", { value: currentModel }, currentModel.slice(0, 24)) : null,
1821
+ models.map((m) => h("option", { key: m.id, value: m.id }, `${m.displayName} (${Math.round(m.contextWindowTokens / 1e3)}k)`))
1822
+ )
1823
+ ),
1824
+ h(
1768
1825
  "div",
1769
- { style: { fontSize: 12.5, color: t.text3, textAlign: "center", padding: "32px 12px" } },
1770
- displayEntries.length > 0 ? `\u6B63\u5728\u52A0\u8F7D\u4F1A\u8BDD\u5386\u53F2\u2026\uFF08\u5DF2\u52A0\u8F7D ${displayEntries.length} \u6761\uFF09` : "\u6B63\u5728\u52A0\u8F7D\u4F1A\u8BDD\u5386\u53F2\u2026"
1771
- ) : h(
1772
- import_react.default.Fragment,
1773
- null,
1774
- displayEntries.length > visibleCount ? h("div", { style: { fontSize: 11, color: t.text3, textAlign: "center", padding: "6px 0" } }, `\u8FD8\u6709 ${displayEntries.length - visibleCount} \u6761\u66F4\u65E9\u7684\u6D88\u606F \u2014 \u5411\u4E0A\u6EDA\u52A8\u52A0\u8F7D`) : null,
1775
- displayEntries.slice(-visibleCount).map((entry) => {
1776
- if (entry.kind === "thought") {
1777
- return h(
1778
- "div",
1779
- { style: { display: "flex", gap: 8, alignItems: "flex-start", justifyContent: "flex-start" }, key: entry.key },
1780
- h("div", { style: { ...style.avatar, background: "#8a5fd0" } }, "\xB7\xB7\xB7"),
1781
- h(
1782
- "details",
1783
- { style: style.thought },
1784
- h("summary", { style: style.thoughtSummary }, "\u601D\u8003\u8FC7\u7A0B"),
1785
- h("p", { style: { margin: "6px 0 0", whiteSpace: "pre-wrap", overflowWrap: "anywhere", color: "#5b4a72", fontStyle: "italic" } }, entry.text || "")
1786
- )
1787
- );
1826
+ {
1827
+ style: style.events,
1828
+ className: "mai-thread-events mai-events",
1829
+ "aria-live": "polite",
1830
+ "data-events": "",
1831
+ ref: eventsRef,
1832
+ onScroll: (event) => {
1833
+ const el = event.currentTarget;
1834
+ if (el.scrollTop < 60 && visibleCount < displayEntries.length) {
1835
+ prevScrollHeightRef.current = el.scrollHeight;
1836
+ setVisibleCount((count) => Math.min(count + 100, displayEntries.length));
1837
+ }
1788
1838
  }
1789
- if (entry.kind === "message") {
1790
- const isUser = entry.role === "user";
1791
- const isThought = entry.role === "thought";
1792
- const avatarColor = isUser ? "#5a6472" : isThought ? "#8a5fd0" : t.accent;
1793
- const bubbleStyle = isUser ? style.bubbleUser : isThought ? style.thought : style.bubble;
1794
- return h(
1795
- "div",
1796
- { style: isUser ? style.bubbleWrapUser : style.bubbleWrap, key: entry.key },
1797
- !isUser ? h("div", { style: { ...style.avatar, background: avatarColor, padding: isUser ? 0 : 3 } }, isThought ? "\xB7\xB7\xB7" : h(MonkeyIcon, { size: 18 })) : null,
1798
- h(
1839
+ },
1840
+ historyLoading ? h(
1841
+ "div",
1842
+ { style: { fontSize: 12.5, color: t.text3, textAlign: "center", padding: "32px 12px" } },
1843
+ displayEntries.length > 0 ? `\u6B63\u5728\u52A0\u8F7D\u4F1A\u8BDD\u5386\u53F2\u2026\uFF08\u5DF2\u52A0\u8F7D ${displayEntries.length} \u6761\uFF09` : "\u6B63\u5728\u52A0\u8F7D\u4F1A\u8BDD\u5386\u53F2\u2026"
1844
+ ) : h(
1845
+ import_react.default.Fragment,
1846
+ null,
1847
+ displayEntries.length > visibleCount ? h("div", { style: { fontSize: 11, color: t.text3, textAlign: "center", padding: "6px 0" } }, `\u8FD8\u6709 ${displayEntries.length - visibleCount} \u6761\u66F4\u65E9\u7684\u6D88\u606F \u2014 \u5411\u4E0A\u6EDA\u52A8\u52A0\u8F7D`) : null,
1848
+ displayEntries.slice(-visibleCount).map((entry) => {
1849
+ if (entry.kind === "thought") {
1850
+ return h(
1799
1851
  "div",
1800
- { style: bubbleStyle },
1801
- h("div", { style: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.04em", marginBottom: 3, opacity: 0.7, textTransform: "uppercase", color: isUser ? "rgba(255,255,255,0.85)" : t.text3 } }, entry.label),
1802
- isUser ? h("p", { style: { margin: 0, whiteSpace: "pre-wrap", overflowWrap: "anywhere" } }, entry.text || "") : h("div", { className: "mai-md" }, renderMarkdown(entry.text || ""))
1803
- ),
1804
- isUser ? h("div", { style: { ...style.avatar, background: avatarColor } }, "\u6211") : null
1805
- );
1806
- }
1807
- if (entry.kind === "tool") {
1808
- const statusLabel = entry.status ? TOOL_STATUS_LABEL[entry.status] ?? entry.status : "running";
1809
- const running = entry.status !== "completed" && entry.status !== "failed" && entry.status !== "cancelled";
1810
- const statusColor = entry.status === "completed" ? "#2f7d54" : entry.status === "failed" ? t.danger : "#8a6d1d";
1811
- const statusBg = entry.status === "completed" ? "#e9f5ee" : entry.status === "failed" ? t.dangerBg : "#fdf6e3";
1812
- return h(
1813
- "details",
1814
- { style: { ...style.event, padding: "6px 11px", background: t.surface }, key: entry.key },
1815
- h(
1816
- "summary",
1817
- { style: { ...style.row, cursor: "pointer", userSelect: "none", listStyle: "none" } },
1818
- h("span", { style: { fontSize: 10, fontWeight: 700, color: t.text3, textTransform: "uppercase", letterSpacing: "0.05em", flexShrink: 0 } }, "\u5DE5\u5177"),
1819
- h("span", { style: { fontSize: 12.5, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1, minWidth: 0 } }, entry.title || "\u6267\u884C\u4E2D"),
1820
- running ? h("span", { className: "mai-pulse", style: { ...style.dot, width: 6, height: 6, background: "#d4a72c" } }) : null,
1821
- h("span", { style: { fontSize: 10.5, padding: "1px 8px", borderRadius: 999, background: statusBg, color: statusColor, fontWeight: 650, flexShrink: 0 } }, statusLabel)
1822
- ),
1823
- entry.detail ? h("pre", { style: { margin: "6px 0 0", whiteSpace: "pre-wrap", overflowWrap: "anywhere", fontSize: 11.5, maxHeight: 320, overflowY: "auto", background: t.surfaceAlt, borderRadius: 6, padding: "8px 10px" } }, entry.detail) : null
1824
- );
1825
- }
1826
- if (entry.kind === "plan") {
1852
+ { style: { display: "flex", gap: 8, alignItems: "flex-start", justifyContent: "flex-start" }, key: entry.key },
1853
+ h("div", { style: { ...style.avatar, background: "#8a5fd0" } }, "\xB7\xB7\xB7"),
1854
+ h(
1855
+ "details",
1856
+ { style: style.thought },
1857
+ h("summary", { style: style.thoughtSummary }, "\u601D\u8003\u8FC7\u7A0B"),
1858
+ h("p", { style: { margin: "6px 0 0", whiteSpace: "pre-wrap", overflowWrap: "anywhere", color: "#5b4a72", fontStyle: "italic" } }, entry.text || "")
1859
+ )
1860
+ );
1861
+ }
1862
+ if (entry.kind === "message") {
1863
+ const isUser = entry.role === "user";
1864
+ const isThought = entry.role === "thought";
1865
+ const avatarColor = isUser ? "#5a6472" : isThought ? "#8a5fd0" : t.accent;
1866
+ const bubbleStyle = isUser ? style.bubbleUser : isThought ? style.thought : style.bubble;
1867
+ return h(
1868
+ "div",
1869
+ { style: isUser ? style.bubbleWrapUser : style.bubbleWrap, key: entry.key },
1870
+ !isUser ? h("div", { style: { ...style.avatar, background: avatarColor, padding: isUser ? 0 : 3 } }, isThought ? "\xB7\xB7\xB7" : h(MonkeyIcon, { size: 18 })) : null,
1871
+ h(
1872
+ "div",
1873
+ { style: bubbleStyle },
1874
+ h("div", { style: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.04em", marginBottom: 3, opacity: 0.7, textTransform: "uppercase", color: isUser ? "rgba(255,255,255,0.85)" : t.text3 } }, entry.label),
1875
+ isUser ? h("p", { style: { margin: 0, whiteSpace: "pre-wrap", overflowWrap: "anywhere" } }, entry.text || "") : h("div", { className: "mai-md" }, renderMarkdown(entry.text || ""))
1876
+ ),
1877
+ isUser ? h("div", { style: { ...style.avatar, background: avatarColor } }, "\u6211") : null
1878
+ );
1879
+ }
1880
+ if (entry.kind === "tool") {
1881
+ const statusLabel = entry.status ? TOOL_STATUS_LABEL[entry.status] ?? entry.status : "running";
1882
+ const running = entry.status !== "completed" && entry.status !== "failed" && entry.status !== "cancelled";
1883
+ const statusColor = entry.status === "completed" ? "#2f7d54" : entry.status === "failed" ? t.danger : "#8a6d1d";
1884
+ const statusBg = entry.status === "completed" ? "#e9f5ee" : entry.status === "failed" ? t.dangerBg : "#fdf6e3";
1885
+ return h(
1886
+ "details",
1887
+ { style: { ...style.event, padding: "6px 11px", background: t.surface }, key: entry.key },
1888
+ h(
1889
+ "summary",
1890
+ { style: { ...style.row, cursor: "pointer", userSelect: "none", listStyle: "none" } },
1891
+ h("span", { style: { fontSize: 10, fontWeight: 700, color: t.text3, textTransform: "uppercase", letterSpacing: "0.05em", flexShrink: 0 } }, "\u5DE5\u5177"),
1892
+ h("span", { style: { fontSize: 12.5, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1, minWidth: 0 } }, entry.title || "\u6267\u884C\u4E2D"),
1893
+ running ? h("span", { className: "mai-pulse", style: { ...style.dot, width: 6, height: 6, background: "#d4a72c" } }) : null,
1894
+ h("span", { style: { fontSize: 10.5, padding: "1px 8px", borderRadius: 999, background: statusBg, color: statusColor, fontWeight: 650, flexShrink: 0 } }, statusLabel)
1895
+ ),
1896
+ entry.detail ? h("pre", { style: { margin: "6px 0 0", whiteSpace: "pre-wrap", overflowWrap: "anywhere", fontSize: 11.5, maxHeight: 320, overflowY: "auto", background: t.surfaceAlt, borderRadius: 6, padding: "8px 10px" } }, entry.detail) : null
1897
+ );
1898
+ }
1899
+ if (entry.kind === "plan") {
1900
+ return h(
1901
+ "article",
1902
+ { style: style.event, key: entry.key },
1903
+ h("div", { style: { fontSize: 10.5, fontWeight: 700, color: t.text3, marginBottom: 3, textTransform: "uppercase", letterSpacing: "0.04em" } }, "\u8BA1\u5212"),
1904
+ ...entry.entries.map((item, index) => h(
1905
+ "div",
1906
+ { style: { display: "flex", gap: 6, fontSize: 12.5, margin: "2px 0" }, key: index },
1907
+ h("span", { style: { opacity: 0.55 } }, index + 1 + "."),
1908
+ h(
1909
+ "span",
1910
+ { style: { textDecoration: item.status === "completed" ? "line-through" : "none", opacity: item.status === "completed" ? 0.55 : 1 } },
1911
+ typeof item.content === "string" ? item.content : JSON.stringify(item.content ?? item)
1912
+ )
1913
+ ))
1914
+ );
1915
+ }
1916
+ if (entry.kind === "system") {
1917
+ return h("div", { style: { fontSize: 11.5, color: t.text3, textAlign: "center", padding: "2px 0" }, key: entry.key }, entry.label);
1918
+ }
1827
1919
  return h(
1828
1920
  "article",
1829
1921
  { style: style.event, key: entry.key },
1830
- h("div", { style: { fontSize: 10.5, fontWeight: 700, color: t.text3, marginBottom: 3, textTransform: "uppercase", letterSpacing: "0.04em" } }, "\u8BA1\u5212"),
1831
- ...entry.entries.map((item, index) => h(
1832
- "div",
1833
- { style: { display: "flex", gap: 6, fontSize: 12.5, margin: "2px 0" }, key: index },
1834
- h("span", { style: { opacity: 0.55 } }, index + 1 + "."),
1835
- h(
1836
- "span",
1837
- { style: { textDecoration: item.status === "completed" ? "line-through" : "none", opacity: item.status === "completed" ? 0.55 : 1 } },
1838
- typeof item.content === "string" ? item.content : JSON.stringify(item.content ?? item)
1839
- )
1840
- ))
1922
+ h("div", { style: { opacity: 0.6, fontSize: 11, marginBottom: 4 } }, entry.label),
1923
+ h(
1924
+ "details",
1925
+ null,
1926
+ h("summary", { style: style.summary }, "\u67E5\u770B\u8BE6\u60C5"),
1927
+ h("pre", { style: { margin: "5px 0 0", whiteSpace: "pre-wrap", overflowWrap: "anywhere", fontSize: 11.5 } }, JSON.stringify(entry.data ?? {}, null, 2))
1928
+ )
1841
1929
  );
1842
- }
1843
- if (entry.kind === "system") {
1844
- return h("div", { style: { fontSize: 11.5, color: t.text3, textAlign: "center", padding: "2px 0" }, key: entry.key }, entry.label);
1845
- }
1846
- return h(
1847
- "article",
1848
- { style: style.event, key: entry.key },
1849
- h("div", { style: { opacity: 0.6, fontSize: 11, marginBottom: 4 } }, entry.label),
1850
- h(
1851
- "details",
1852
- null,
1853
- h("summary", { style: style.summary }, "\u67E5\u770B\u8BE6\u60C5"),
1854
- h("pre", { style: { margin: "5px 0 0", whiteSpace: "pre-wrap", overflowWrap: "anywhere", fontSize: 11.5 } }, JSON.stringify(entry.data ?? {}, null, 2))
1855
- )
1856
- );
1857
- })
1858
- )
1859
- ),
1860
- ...pendingRequests.map((request) => h(ApprovalCard, {
1861
- key: `${typeof request.requestId}:${request.requestId}`,
1862
- request,
1863
- hasControl,
1864
- onRespond: respond,
1865
- answerText,
1866
- setAnswerText,
1867
- onAnswer: answerQuestion
1868
- })),
1869
- h(
1870
- "form",
1871
- { style: style.composer, onSubmit: (event) => {
1872
- event.preventDefault();
1873
- sendPrompt();
1874
- } },
1875
- h("textarea", {
1876
- style: style.textarea,
1877
- value: prompt,
1878
- onChange: (event) => setPrompt(event.target.value),
1879
- onKeyDown: (event) => {
1880
- if (event.key === "Enter" && !event.shiftKey) {
1881
- event.preventDefault();
1882
- sendPrompt();
1883
- }
1884
- },
1885
- placeholder: hasControl ? "\u5411\u8FDC\u7A0B\u4F1A\u8BDD\u4E0B\u53D1\u6307\u4EE4\uFF08\u56DE\u8F66\u53D1\u9001\uFF0CShift+\u56DE\u8F66\u6362\u884C\uFF09" : "\u53EA\u8BFB\u6A21\u5F0F\uFF1A\u4E0B\u53D1\u6307\u4EE4\u9700\u8981 session:control \u6743\u9650",
1886
- disabled: !hasControl
1887
- }),
1888
- turnActive ? h(
1889
- "button",
1890
- {
1891
- type: "button",
1892
- style: style.stopButton,
1893
- disabled: !hasControl || stopping,
1894
- onClick: stopTurn,
1895
- title: stopping ? "\u505C\u6B62\u4E2D\u2026" : "\u505C\u6B62\u5F53\u524D\u56DE\u5408",
1896
- "aria-label": "\u505C\u6B62\u5F53\u524D\u56DE\u5408"
1897
- },
1898
- h("span", { style: style.stopIcon })
1899
- ) : h(
1900
- "button",
1901
- {
1902
- type: "submit",
1903
- style: style.sendButton,
1904
- disabled: !streamRef.current || !hasControl || prompt.trim() === "",
1905
- title: "\u53D1\u9001\uFF08\u56DE\u8F66\uFF09",
1906
- "aria-label": "\u53D1\u9001\u6307\u4EE4"
1907
- },
1908
- h(
1909
- "svg",
1910
- { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", style: { display: "block" } },
1911
- h("path", { d: "M8 12.5V3.5M8 3.5L4 7.5M8 3.5L12 7.5", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round" })
1930
+ })
1912
1931
  )
1913
- )
1914
- ),
1915
- lastDelivery || turnActive ? h(
1916
- "div",
1917
- { style: { fontSize: 11.5, color: turnActive ? t.accent : lastDelivery?.accepted ? t.success : lastDelivery?.frame === "pending" ? t.text3 : t.danger, textAlign: "right", display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 6 } },
1918
- turnActive ? h("span", { className: "mai-pulse", style: { ...style.dot, background: t.accent } }) : null,
1919
- turnActive ? stopping ? "\u6B63\u5728\u505C\u6B62\u5F53\u524D\u56DE\u5408\u2026" : "MonkeyAI \u6B63\u5728\u5904\u7406\u2026" : lastDelivery?.accepted ? "\u56DE\u5408\u5DF2\u7ED3\u675F" : lastDelivery?.frame === "pending" ? "\u7B49\u5F85\u6295\u9012" : "\u6295\u9012\u88AB\u62D2\u7EDD"
1920
- ) : null
1932
+ ),
1933
+ ...pendingRequests.map((request) => h(ApprovalCard, {
1934
+ key: `${typeof request.requestId}:${request.requestId}`,
1935
+ request,
1936
+ hasControl,
1937
+ onRespond: respond,
1938
+ answerText,
1939
+ setAnswerText,
1940
+ onAnswer: answerQuestion
1941
+ })),
1942
+ h(
1943
+ "form",
1944
+ { style: style.composer, onSubmit: (event) => {
1945
+ event.preventDefault();
1946
+ sendPrompt();
1947
+ } },
1948
+ h("textarea", {
1949
+ style: style.textarea,
1950
+ value: prompt,
1951
+ onChange: (event) => setPrompt(event.target.value),
1952
+ onKeyDown: (event) => {
1953
+ if (event.key === "Enter" && !event.shiftKey) {
1954
+ event.preventDefault();
1955
+ sendPrompt();
1956
+ }
1957
+ },
1958
+ placeholder: hasControl ? "\u5411\u8FDC\u7A0B\u4F1A\u8BDD\u4E0B\u53D1\u6307\u4EE4\uFF08\u56DE\u8F66\u53D1\u9001\uFF0CShift+\u56DE\u8F66\u6362\u884C\uFF09" : "\u53EA\u8BFB\u6A21\u5F0F\uFF1A\u4E0B\u53D1\u6307\u4EE4\u9700\u8981 session:control \u6743\u9650",
1959
+ disabled: !hasControl
1960
+ }),
1961
+ turnActive ? h(
1962
+ "button",
1963
+ {
1964
+ type: "button",
1965
+ style: style.stopButton,
1966
+ disabled: !hasControl || stopping,
1967
+ onClick: stopTurn,
1968
+ title: stopping ? "\u505C\u6B62\u4E2D\u2026" : "\u505C\u6B62\u5F53\u524D\u56DE\u5408",
1969
+ "aria-label": "\u505C\u6B62\u5F53\u524D\u56DE\u5408"
1970
+ },
1971
+ h("span", { style: style.stopIcon })
1972
+ ) : h(
1973
+ "button",
1974
+ {
1975
+ type: "submit",
1976
+ style: style.sendButton,
1977
+ disabled: !streamRef.current || !hasControl || prompt.trim() === "",
1978
+ title: "\u53D1\u9001\uFF08\u56DE\u8F66\uFF09",
1979
+ "aria-label": "\u53D1\u9001\u6307\u4EE4"
1980
+ },
1981
+ h(
1982
+ "svg",
1983
+ { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", style: { display: "block" } },
1984
+ h("path", { d: "M8 12.5V3.5M8 3.5L4 7.5M8 3.5L12 7.5", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round" })
1985
+ )
1986
+ )
1987
+ ),
1988
+ lastDelivery || turnActive ? h(
1989
+ "div",
1990
+ { style: { fontSize: 11.5, color: turnActive ? t.accent : lastDelivery?.accepted ? t.success : lastDelivery?.frame === "pending" ? t.text3 : t.danger, textAlign: "right", display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 6 } },
1991
+ turnActive ? h("span", { className: "mai-pulse", style: { ...style.dot, background: t.accent } }) : null,
1992
+ turnActive ? stopping ? "\u6B63\u5728\u505C\u6B62\u5F53\u524D\u56DE\u5408\u2026" : "MonkeyAI \u6B63\u5728\u5904\u7406\u2026" : lastDelivery?.accepted ? "\u56DE\u5408\u5DF2\u7ED3\u675F" : lastDelivery?.frame === "pending" ? "\u7B49\u5F85\u6295\u9012" : "\u6295\u9012\u88AB\u62D2\u7EDD"
1993
+ ) : null
1994
+ ) : h(
1995
+ "section",
1996
+ { style: style.emptyThread, className: "mai-empty-thread" },
1997
+ h("div", { className: "mai-empty-mark" }, h(MonkeyIcon, { size: 26 })),
1998
+ h("p", { style: style.eyebrow }, "\u8FDC\u7A0B\u4F1A\u8BDD"),
1999
+ h("h2", { style: { margin: 0, fontSize: 18, fontWeight: 650, color: "#182230" } }, "\u9009\u62E9\u4E00\u4E2A\u4F1A\u8BDD"),
2000
+ h("p", { style: { ...style.subtitle, maxWidth: 300 } }, sessionOptions.length > 0 ? "\u4ECE\u5DE6\u4FA7\u9009\u62E9\u4F1A\u8BDD\uFF0C\u5728\u6B64\u7EE7\u7EED\u5BF9\u8BDD\u3002" : machineId ? "\u5F53\u524D\u8BBE\u5907\u8FD8\u6CA1\u6709\u4F1A\u8BDD\u3002\u53EF\u5728\u4E0A\u65B9\u65B0\u5EFA\u6216\u5237\u65B0\u3002" : "\u5148\u9009\u62E9\u4E00\u4E2A\u8FDC\u7A0B\u8BBE\u5907\u3002")
2001
+ )
1921
2002
  ) : null
1922
2003
  );
1923
2004
  }