dsh-xrxs-lingting 0.4.0-dev.49 → 0.4.0-dev.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -98,7 +98,7 @@ LINGTING_XIN_PROBE=1 nohup "/path/to/DSH Desktop Dev.app/Contents/MacOS/DSH Desk
98
98
 
99
99
  ## 客户端兼容性验证
100
100
 
101
- `0.4.0-dev.48` 起不再要求宿主提供旧版补丁的 `layout.business`。标准薪灵客户端通过公开的 `shell.overlay` 插槽显示灵听页面,页面中的「返回聊天」关闭页面;提供业务页扩展的旧宿主仍沿用原入口。
101
+ `0.4.0-dev.48` 起不再要求宿主提供旧版补丁的 `layout.business`。`0.4.0-dev.50` 起,标准薪灵客户端通过渲染器公开的 `[data-slot="conversation"]` 标记,将原有灵听页面挂载到主内容区:保留侧栏,暂时隐藏而不卸载聊天,返回时恢复原聊天和草稿。弹窗、列表、实时转写仍复用原组件;转写面板继续使用 `shell.overlay`。提供业务页扩展的旧宿主仍沿用原入口。
102
102
 
103
103
  发布前除单元测试外,应在构建后对目标薪灵源码运行客户端产物冒烟,验证真实布局对象、公开插槽、页面打开及返回聊天:
104
104
 
@@ -108,3 +108,7 @@ npm run smoke:client -- /path/to/cinlyn-desktop
108
108
  ```
109
109
 
110
110
  该检查不代替安装后对授权、录音、转写和回放的人工验证。
111
+
112
+ 布局回归验证:`node scripts/smoke-layout-browser.mjs <playwright/index.mjs 路径>`,使用 Chrome 无头浏览器运行真实插件产物,验证页面边界、弹窗居中、转写面板层级、窗口缩放与卸载后聊天恢复。使用合成录音状态,不访问业务数据、不采集声音。
113
+
114
+ 设备切换:支持的桌面原生模块会在默认输出变化时重新连接系统采集,插件重新采样并替换默认麦克风输入,保留同一录音与转写连接。操作系统切换设备期间可能存在短暂音频缺口;持续无法恢复才报错暂停。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-xrxs-lingting",
3
- "version": "0.4.0-dev.49",
3
+ "version": "0.4.0-dev.51",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite --host 127.0.0.1",
@@ -30,7 +30,7 @@ module.exports = __toCommonJS(client_exports);
30
30
  var define_import_meta_env_default = { VITE_XIN_PACKAGED: "1" };
31
31
 
32
32
  // src/plugin/client.tsx
33
- var import_react22 = require("react");
33
+ var import_react23 = require("react");
34
34
 
35
35
  // node_modules/lucide-react/dist/esm/createLucideIcon.js
36
36
  var import_react2 = require("react");
@@ -1606,6 +1606,117 @@ function toSegment(segment) {
1606
1606
  return { id: segment.id, speaker: speakerLabel(segment.speakerId), text: segment.text, final: segment.final };
1607
1607
  }
1608
1608
 
1609
+ // src/audio/microphone-switch.ts
1610
+ function followDefaultMicrophone(options) {
1611
+ let current = options.initial;
1612
+ let stopped = false;
1613
+ let running = false;
1614
+ let queued = false;
1615
+ let cancelAcquire;
1616
+ let cancelDelay;
1617
+ const delay = () => new Promise((resolve) => {
1618
+ const timer = setTimeout(() => {
1619
+ cancelDelay = void 0;
1620
+ resolve();
1621
+ }, 250);
1622
+ cancelDelay = () => {
1623
+ clearTimeout(timer);
1624
+ cancelDelay = void 0;
1625
+ resolve();
1626
+ };
1627
+ });
1628
+ const watch = (stream) => {
1629
+ stream.getAudioTracks().forEach((track) => {
1630
+ track.onended = () => {
1631
+ void reconnect();
1632
+ };
1633
+ });
1634
+ };
1635
+ const reconnect = async () => {
1636
+ if (stopped) return;
1637
+ if (running) {
1638
+ queued = true;
1639
+ return;
1640
+ }
1641
+ running = true;
1642
+ const began = Date.now();
1643
+ try {
1644
+ do {
1645
+ queued = false;
1646
+ try {
1647
+ const next = await new Promise((resolve, reject) => {
1648
+ let settled = false;
1649
+ const finishError = (error) => {
1650
+ if (settled) return;
1651
+ settled = true;
1652
+ clearTimeout(timer);
1653
+ cancelAcquire = void 0;
1654
+ reject(error);
1655
+ };
1656
+ const timer = setTimeout(() => finishError(new Error("Microphone recovery timed out")), Math.max(0, 8e3 - (Date.now() - began)));
1657
+ cancelAcquire = () => finishError(new Error("Recording stopped"));
1658
+ Promise.resolve().then(options.acquire).then((stream) => {
1659
+ if (settled || stopped) {
1660
+ stream.getTracks().forEach((track) => track.stop());
1661
+ return;
1662
+ }
1663
+ settled = true;
1664
+ clearTimeout(timer);
1665
+ cancelAcquire = void 0;
1666
+ resolve(stream);
1667
+ }, finishError);
1668
+ });
1669
+ if (stopped) {
1670
+ next.getTracks().forEach((track) => track.stop());
1671
+ return;
1672
+ }
1673
+ if (!next.getAudioTracks().some((track) => track.readyState === "live")) {
1674
+ next.getTracks().forEach((track) => track.stop());
1675
+ throw new Error("Microphone is not live");
1676
+ }
1677
+ const previous = current;
1678
+ try {
1679
+ options.replace(next, previous);
1680
+ } catch (error) {
1681
+ next.getTracks().forEach((track) => track.stop());
1682
+ throw error;
1683
+ }
1684
+ current = next;
1685
+ previous.getTracks().forEach((track) => {
1686
+ track.onended = null;
1687
+ track.stop();
1688
+ });
1689
+ watch(current);
1690
+ } catch {
1691
+ if (stopped) return;
1692
+ if (Date.now() - began >= 8e3) {
1693
+ if (!current.getAudioTracks().some((track) => track.readyState === "live")) options.failed();
1694
+ return;
1695
+ }
1696
+ await delay();
1697
+ queued = true;
1698
+ }
1699
+ } while (queued && !stopped);
1700
+ } finally {
1701
+ running = false;
1702
+ }
1703
+ };
1704
+ const changed = () => {
1705
+ void reconnect();
1706
+ };
1707
+ watch(current);
1708
+ options.devices.addEventListener?.("devicechange", changed);
1709
+ return () => {
1710
+ stopped = true;
1711
+ cancelDelay?.();
1712
+ cancelAcquire?.();
1713
+ options.devices.removeEventListener?.("devicechange", changed);
1714
+ current.getTracks().forEach((track) => {
1715
+ track.onended = null;
1716
+ });
1717
+ };
1718
+ }
1719
+
1609
1720
  // src/audio/worklet-source.ts
1610
1721
  var captureWorkletSource = `
1611
1722
  class LingtingCaptureProcessor extends AudioWorkletProcessor {
@@ -1691,7 +1802,7 @@ class NativeSystemSource extends AudioWorkletProcessor {
1691
1802
  accept(data) {
1692
1803
  if (this.failed) return;
1693
1804
  if (!data || !(data.samples instanceof Float32Array) || !Number.isFinite(data.sampleRate) || data.sampleRate < 8000 || data.sampleRate > 192000) return;
1694
- if (this.rate && this.rate !== data.sampleRate) { this.fail('\u7CFB\u7EDF\u58F0\u97F3\u91C7\u6837\u7387\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u5F00\u59CB\u5F55\u97F3\u3002'); return; }
1805
+ if (this.rate && this.rate !== data.sampleRate) { this.read = 0; this.write = 0; this.started = false; this.buffer.fill(0); }
1695
1806
  this.rate = data.sampleRate;
1696
1807
  // Bound latency, not just memory. After a render stall, retain the newest
1697
1808
  // 100 ms instead of spending minutes playing stale audio or killing capture.
@@ -1784,6 +1895,7 @@ var MeetingCapture = class {
1784
1895
  emitting = false;
1785
1896
  stopSystem = null;
1786
1897
  systemNode = null;
1898
+ stopMicrophoneSwitch = null;
1787
1899
  async start(onChunk, onError) {
1788
1900
  if (this.context || this.starting) throw new Error("\u91C7\u96C6\u5DF2\u5728\u8FDB\u884C\u4E2D\u3002");
1789
1901
  this.starting = true;
@@ -1822,7 +1934,6 @@ var MeetingCapture = class {
1822
1934
  for (const stream of this.streams) {
1823
1935
  for (const track of stream.getAudioTracks()) {
1824
1936
  if (track.readyState !== "live") throw new Error("\u97F3\u9891\u8BBE\u5907\u5DF2\u65AD\u5F00\uFF0C\u8BF7\u91CD\u65B0\u5F00\u59CB\u5F55\u97F3\u3002");
1825
- track.onended = () => fail(stream === microphone ? "\u9EA6\u514B\u98CE\u5DF2\u65AD\u5F00\uFF0C\u5F55\u97F3\u5DF2\u6682\u505C\uFF0C\u8BF7\u68C0\u67E5\u8BBE\u5907\u540E\u7EE7\u7EED\u3002" : "\u7CFB\u7EDF\u58F0\u97F3\u91C7\u96C6\u5DF2\u505C\u6B62\uFF0C\u5F55\u97F3\u5DF2\u6682\u505C\uFF0C\u8BF7\u91CD\u65B0\u6388\u6743\u540E\u7EE7\u7EED\u3002");
1826
1937
  }
1827
1938
  }
1828
1939
  const context = new AudioContext();
@@ -1836,7 +1947,7 @@ var MeetingCapture = class {
1836
1947
  return;
1837
1948
  }
1838
1949
  stalledSince ??= Date.now();
1839
- if (Date.now() - stalledSince >= 5e3) {
1950
+ if (Date.now() - stalledSince >= 8e3) {
1840
1951
  fail("\u97F3\u9891\u5904\u7406\u6062\u590D\u8D85\u65F6\uFF0C\u8BF7\u91CD\u65B0\u5F00\u59CB\u5F55\u97F3\u3002");
1841
1952
  return;
1842
1953
  }
@@ -1846,7 +1957,8 @@ var MeetingCapture = class {
1846
1957
  return;
1847
1958
  }
1848
1959
  recovering = true;
1849
- void context.resume().catch(() => fail("\u97F3\u9891\u5904\u7406\u65E0\u6CD5\u6062\u590D\uFF0C\u8BF7\u91CD\u65B0\u5F00\u59CB\u5F55\u97F3\u3002")).finally(() => {
1960
+ void context.resume().catch(() => {
1961
+ }).finally(() => {
1850
1962
  recovering = false;
1851
1963
  });
1852
1964
  };
@@ -1924,6 +2036,24 @@ var MeetingCapture = class {
1924
2036
  this.nodes.push(source, analyser, gain);
1925
2037
  analysers.push(analyser);
1926
2038
  }
2039
+ this.stopMicrophoneSwitch = followDefaultMicrophone({
2040
+ devices,
2041
+ initial: microphone,
2042
+ acquire: () => devices.getUserMedia({ audio: { channelCount: 1, echoCancellation: true, noiseSuppression: true, autoGainControl: true } }),
2043
+ replace: (next, previous) => {
2044
+ if (generation !== this.generation) throw new Error("\u5F55\u97F3\u5DF2\u53D6\u6D88\u3002");
2045
+ const replacement = context.createMediaStreamSource(next);
2046
+ replacement.connect(analysers[0]);
2047
+ const oldSource = sources[0];
2048
+ oldSource.disconnect();
2049
+ sources[0] = replacement;
2050
+ this.nodes = this.nodes.filter((item) => item !== oldSource);
2051
+ this.nodes.push(replacement);
2052
+ this.streams = this.streams.filter((item) => item !== previous);
2053
+ this.streams.push(next);
2054
+ },
2055
+ failed: () => fail("\u9EA6\u514B\u98CE\u5207\u6362\u540E\u672A\u80FD\u6062\u590D\uFF0C\u5F55\u97F3\u5DF2\u6682\u505C\uFF0C\u8BF7\u68C0\u67E5\u8BBE\u5907\u8FDE\u63A5\u3002")
2056
+ });
1927
2057
  const mute = context.createGain();
1928
2058
  mute.gain.value = 0;
1929
2059
  node.connect(mute);
@@ -1970,6 +2100,8 @@ var MeetingCapture = class {
1970
2100
  }
1971
2101
  async stop() {
1972
2102
  ++this.generation;
2103
+ this.stopMicrophoneSwitch?.();
2104
+ this.stopMicrophoneSwitch = null;
1973
2105
  this.emitting = false;
1974
2106
  if (this.timer) clearInterval(this.timer);
1975
2107
  this.timer = null;
@@ -5419,11 +5551,72 @@ function createBusinessNavigation() {
5419
5551
  };
5420
5552
  }
5421
5553
 
5554
+ // src/plugin/business-surface.tsx
5555
+ var import_react22 = require("react");
5556
+ var import_react_dom = require("react-dom");
5557
+ function mountBusinessSurface(doc) {
5558
+ const conversation = doc.querySelector('[data-slot="conversation"]');
5559
+ const center = conversation?.parentElement;
5560
+ if (!conversation || !center) return null;
5561
+ const target = doc.createElement("section");
5562
+ target.className = "lt-business-surface";
5563
+ target.setAttribute("aria-label", "\u7075\u542C");
5564
+ const display = conversation.style.getPropertyValue("display");
5565
+ const displayPriority = conversation.style.getPropertyPriority("display");
5566
+ const position = center.style.getPropertyValue("position");
5567
+ const positionPriority = center.style.getPropertyPriority("position");
5568
+ const inert = conversation.inert;
5569
+ conversation.style.setProperty("display", "none", "important");
5570
+ conversation.inert = true;
5571
+ center.style.setProperty("position", "relative");
5572
+ center.appendChild(target);
5573
+ let disposed = false;
5574
+ return { target, dispose() {
5575
+ if (disposed) return;
5576
+ disposed = true;
5577
+ target.remove();
5578
+ if (display) conversation.style.setProperty("display", display, displayPriority);
5579
+ else conversation.style.removeProperty("display");
5580
+ conversation.inert = inert;
5581
+ if (position) center.style.setProperty("position", position, positionPriority);
5582
+ else center.style.removeProperty("position");
5583
+ } };
5584
+ }
5585
+ function BusinessSurface({ children, onClose }) {
5586
+ const [target, setTarget] = (0, import_react22.useState)(null);
5587
+ (0, import_react22.useLayoutEffect)(() => {
5588
+ let mounted = null;
5589
+ const attach = () => {
5590
+ if (mounted?.target.isConnected) return;
5591
+ mounted?.dispose();
5592
+ mounted = mountBusinessSurface(document);
5593
+ setTarget(mounted?.target ?? null);
5594
+ };
5595
+ attach();
5596
+ const onSidebarClick = (event) => {
5597
+ const element = event.target instanceof Element ? event.target : null;
5598
+ const button = element?.closest("button");
5599
+ if (!button?.closest('[data-slot="sidebar"]')) return;
5600
+ const label = button.getAttribute("aria-label")?.trim();
5601
+ if (label && /^(新会话|新建会话|New session)$/i.test(label)) onClose();
5602
+ };
5603
+ document.addEventListener("click", onSidebarClick, true);
5604
+ const observer = new MutationObserver(attach);
5605
+ observer.observe(document.body, { childList: true, subtree: true });
5606
+ return () => {
5607
+ document.removeEventListener("click", onSidebarClick, true);
5608
+ observer.disconnect();
5609
+ mounted?.dispose();
5610
+ };
5611
+ }, []);
5612
+ return target ? (0, import_react_dom.createPortal)(children, target) : null;
5613
+ }
5614
+
5422
5615
  // src/plugin/embedded.css
5423
5616
  var tag3 = document.createElement("style");
5424
5617
  tag3.dataset.plugin = "dsh-xrxs-lingting";
5425
5618
  tag3.dataset.pluginCss = "dsh-xrxs-lingting/embedded.css";
5426
- tag3.textContent = ".lingting-root { color-scheme: light; }\n/* Host \u9002\u914D\u5C42\u72B6\u6001\u63D0\u793A\uFF08\u6388\u6743/\u8EAB\u4EFD/\u76EE\u7684\u5730\u672A\u5C31\u7EEA\uFF09\uFF1A\u56FA\u5B9A\u9876\u90E8\uFF0C\u53EF\u5173\u95ED\uFF0C\u4E0D\u53C2\u4E0E\u9875\u9762\u5E03\u5C40 */\n.lt-host-notice { position: fixed; top: 12px; left: 50%; transform: translateX(-50%); z-index: 60; display: flex; align-items: center; gap: 12px; max-width: min(680px, calc(100vw - 32px)); padding: 10px 14px; border: 1px solid #e7e0fa; border-radius: 10px; background: #fff; box-shadow: 0 6px 24px rgb(40 28 74 / 16%); color: #605972; font-size: 13px; line-height: 1.5; }\n.lt-host-notice-text { flex: 1; }\n.lt-host-notice-close { flex-shrink: 0; border: 0; background: transparent; color: inherit; font-size: 16px; line-height: 1; padding: 2px 4px; border-radius: 6px; cursor: pointer; }\n.lt-host-notice-close:hover { background: #6650d814; }\n.lt-host-notice-close:focus-visible { outline: 2px solid #6650d8; outline-offset: 2px; }\n/* \u5D4C\u5165\u6A21\u5F0F\u4E0B\u6839\u5143\u7D20\u5373 .app\uFF08lingting-root app \u540C\u5143\u7D20\uFF09\uFF0C\u89C4\u5219\u9700\u7528\u7EC4\u5408\u9009\u62E9\u5668\uFF1B\u4FDD\u7559\u540E\u4EE3\u5F62\u5F0F\u517C\u5BB9\u53CC\u5C42\u5305\u88F9\u7ED3\u6784 */\n.lingting-root[data-embedded] { height: 100%; min-height: 0; container-type: inline-size; }\n.lingting-root[data-embedded].app, .lingting-root[data-embedded] .app { height: 100%; min-height: 0; display: flex; flex-direction: column; overflow: hidden; position: relative; padding-bottom: 0; }\n.lingting-root[data-embedded].app .app-header, .lingting-root[data-embedded] .app-header { height: 66px; flex-shrink: 0; }\n.lingting-root[data-embedded].app .header-inner, .lingting-root[data-embedded] .header-inner { padding: 0 28px; max-width: none; }\n.lingting-root[data-embedded].app .brand-caption, .lingting-root[data-embedded] .brand-caption { display: none; }\n.lingting-root[data-embedded].app .main-content, .lingting-root[data-embedded] .main-content { width: 100%; max-width: none; min-height: 0; flex: 1; overflow: auto; padding: 30px 28px 0; scrollbar-width: thin; }\n\n.lingting-root[data-embedded].app .toast, .lingting-root[data-embedded] .toast { position: absolute; top: 77px; }\n.lingting-root[data-global-status] { flex-shrink: 0; border-top: 1px solid #e7e0fa; background: white; padding: 0 24px; }\n.lingting-root[data-global-status] .recording-controls.compact { min-height: 76px; padding: 12px 0; }\n.lingting-root[data-global-status] .error-notice { margin: 8px 0 0; }\n.lingting-sidebar-entry { display: flex; align-items: center; gap: 10px; border: 0; background: transparent; color: var(--dsw-alias-text-primary, #605972); padding: 10px 12px; width: 100%; border-radius: 9px; cursor: pointer; font: inherit; font-size: 14px; }\n.lingting-sidebar-entry:hover, .lingting-sidebar-entry[data-active] { background: #6650d814; color: #6650d8; }\n.lingting-sidebar-entry:focus-visible { outline: 2px solid #6650d8; outline-offset: 2px; }\n@container (max-width: 900px) {\n .lingting-root[data-embedded] .overview-note { display: none; }\n .lingting-root[data-embedded] .overview { grid-template-columns: 1fr 1fr; }\n .lingting-root[data-embedded] .list-heading { flex-wrap: wrap; }\n .lingting-root[data-embedded] .source-label { display: none; }\n}\n\n/* Standard DSH has no layout.business extension; keep the page in its public overlay slot. */\n.lt-business-surface { position: fixed; inset: 48px 12px 12px; z-index: 40; min-width: 0; overflow: hidden; border: 1px solid #e7e0fa; border-radius: 12px; background: #fff; box-shadow: 0 8px 32px #2c245221; pointer-events: auto; -webkit-app-region: no-drag; }\n";
5619
+ tag3.textContent = ".lingting-root { color-scheme: light; }\n/* Host \u9002\u914D\u5C42\u72B6\u6001\u63D0\u793A\uFF08\u6388\u6743/\u8EAB\u4EFD/\u76EE\u7684\u5730\u672A\u5C31\u7EEA\uFF09\uFF1A\u56FA\u5B9A\u9876\u90E8\uFF0C\u53EF\u5173\u95ED\uFF0C\u4E0D\u53C2\u4E0E\u9875\u9762\u5E03\u5C40 */\n.lt-host-notice { position: fixed; top: 12px; left: 50%; transform: translateX(-50%); z-index: 60; display: flex; align-items: center; gap: 12px; max-width: min(680px, calc(100vw - 32px)); padding: 10px 14px; border: 1px solid #e7e0fa; border-radius: 10px; background: #fff; box-shadow: 0 6px 24px rgb(40 28 74 / 16%); color: #605972; font-size: 13px; line-height: 1.5; }\n.lt-host-notice-text { flex: 1; }\n.lt-host-notice-close { flex-shrink: 0; border: 0; background: transparent; color: inherit; font-size: 16px; line-height: 1; padding: 2px 4px; border-radius: 6px; cursor: pointer; }\n.lt-host-notice-close:hover { background: #6650d814; }\n.lt-host-notice-close:focus-visible { outline: 2px solid #6650d8; outline-offset: 2px; }\n/* \u5D4C\u5165\u6A21\u5F0F\u4E0B\u6839\u5143\u7D20\u5373 .app\uFF08lingting-root app \u540C\u5143\u7D20\uFF09\uFF0C\u89C4\u5219\u9700\u7528\u7EC4\u5408\u9009\u62E9\u5668\uFF1B\u4FDD\u7559\u540E\u4EE3\u5F62\u5F0F\u517C\u5BB9\u53CC\u5C42\u5305\u88F9\u7ED3\u6784 */\n.lingting-root[data-embedded] { height: 100%; min-height: 0; container-type: inline-size; }\n.lingting-root[data-embedded].app, .lingting-root[data-embedded] .app { height: 100%; min-height: 0; display: flex; flex-direction: column; overflow: hidden; position: relative; padding-bottom: 0; }\n.lingting-root[data-embedded].app .app-header, .lingting-root[data-embedded] .app-header { height: 66px; flex-shrink: 0; }\n.lingting-root[data-embedded].app .header-inner, .lingting-root[data-embedded] .header-inner { padding: 0 28px; max-width: none; }\n.lingting-root[data-embedded].app .brand-caption, .lingting-root[data-embedded] .brand-caption { display: none; }\n.lingting-root[data-embedded].app .main-content, .lingting-root[data-embedded] .main-content { width: 100%; max-width: none; min-height: 0; flex: 1; overflow: auto; padding: 30px 28px 0; scrollbar-width: thin; }\n\n.lingting-root[data-embedded].app .toast, .lingting-root[data-embedded] .toast { position: absolute; top: 77px; }\n.lingting-root[data-global-status] { flex-shrink: 0; border-top: 1px solid #e7e0fa; background: white; padding: 0 24px; }\n.lingting-root[data-global-status] .recording-controls.compact { min-height: 76px; padding: 12px 0; }\n.lingting-root[data-global-status] .error-notice { margin: 8px 0 0; }\n.lingting-sidebar-entry { display: flex; align-items: center; gap: 10px; border: 0; background: transparent; color: var(--dsw-alias-text-primary, #605972); padding: 10px 12px; width: 100%; border-radius: 9px; cursor: pointer; font: inherit; font-size: 14px; }\n.lingting-sidebar-entry:hover, .lingting-sidebar-entry[data-active] { background: #6650d814; color: #6650d8; }\n.lingting-sidebar-entry:focus-visible { outline: 2px solid #6650d8; outline-offset: 2px; }\n@container (max-width: 900px) {\n .lingting-root[data-embedded] .overview-note { display: none; }\n .lingting-root[data-embedded] .overview { grid-template-columns: 1fr 1fr; }\n .lingting-root[data-embedded] .list-heading { flex-wrap: wrap; }\n .lingting-root[data-embedded] .source-label { display: none; }\n}\n\n/* Use the real center column, preserving the host sidebar and conversation state. */\n.lt-business-surface { position: absolute; inset: 0; z-index: 1; min-width: 0; overflow: hidden; background: #f8f9fc; pointer-events: auto; -webkit-app-region: no-drag; }\n/* Host reset styles must not remove the native dialog's centered placement. */\n.lingting-root .modal { margin: auto; background: #fff; }\n";
5427
5620
  document.querySelectorAll("style[data-plugin-css=" + JSON.stringify("dsh-xrxs-lingting/embedded.css") + "]").forEach((old) => old.remove());
5428
5621
  document.head.appendChild(tag3);
5429
5622
 
@@ -5431,7 +5624,7 @@ document.head.appendChild(tag3);
5431
5624
  var import_jsx_runtime21 = require("react/jsx-runtime");
5432
5625
  var ID = "dsh-xrxs-lingting";
5433
5626
  var inject = ["slots", "layout"];
5434
- var PanelBoundary = class extends import_react22.Component {
5627
+ var PanelBoundary = class extends import_react23.Component {
5435
5628
  state = { failed: false };
5436
5629
  static getDerivedStateFromError() {
5437
5630
  return { failed: true };
@@ -5472,8 +5665,8 @@ async function apply(ctx) {
5472
5665
  }));
5473
5666
  const unregisterPage = business.register(ID);
5474
5667
  function Entry({ wide }) {
5475
- const panel = (0, import_react22.useSyncExternalStore)(controller.subscribe, controller.getSnapshot);
5476
- const layout = (0, import_react22.useSyncExternalStore)(business.subscribe, business.getSnapshot);
5668
+ const panel = (0, import_react23.useSyncExternalStore)(controller.subscribe, controller.getSnapshot);
5669
+ const layout = (0, import_react23.useSyncExternalStore)(business.subscribe, business.getSnapshot);
5477
5670
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { type: "button", className: "lingting-sidebar-entry", "data-active": layout.activeId === ID || panel.open || void 0, title: "\u7075\u542C", "aria-label": "\u7075\u542C", onClick: () => business.open(ID), children: [
5478
5671
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Headphones, { size: 19 }),
5479
5672
  wide && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "\u7075\u542C" })
@@ -5483,9 +5676,9 @@ async function apply(ctx) {
5483
5676
  return activeId === ID ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PanelBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LingtingApp, { service, navigation, visible: true, embedded: true, hostState, onBackToHost: () => business.close(), onOpenLive: () => controller.open(), onOpenRecord: (id) => controller.openRecord(id) }) }) : null;
5484
5677
  }
5485
5678
  function Overlay() {
5486
- const page = (0, import_react22.useSyncExternalStore)(business.subscribe, business.getSnapshot, business.getSnapshot);
5679
+ const page = (0, import_react23.useSyncExternalStore)(business.subscribe, business.getSnapshot, business.getSnapshot);
5487
5680
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
5488
- !hostBusiness && page.activeId === ID && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("section", { className: "lt-business-surface", "aria-label": "\u7075\u542C", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Page, { activeId: page.activeId }) }),
5681
+ !hostBusiness && page.activeId === ID && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(BusinessSurface, { onClose: () => business.close(), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Page, { activeId: page.activeId }) }),
5489
5682
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PanelBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(XinHostNotice, { store: hostState }) }),
5490
5683
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PanelBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LingtingSidebar, { service, controller, onOpenPage: () => business.open(ID) }) }),
5491
5684
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PanelBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MeetingPrompt, { service }) })