dsh-xrxs-lingting
v0.4.3
Published
灵听 DSH 插件:数据列表在主页面(业务插槽),实时转写在右侧面板,在聊天旁边使用。已对接真实后端(aim 表单接口 + cinlyn JSON/SSE + 转写 WebSocket),麦克风与系统声音混合采集 16kHz PCM,记录保存在服务端。
Readme
dsh-xrxs-lingting
灵听 DSH 插件:数据列表在主页面(业务插槽),实时转写在右侧面板,在聊天旁边使用。已对接真实后端(aim 表单接口 + cinlyn JSON/SSE + 转写 WebSocket),麦克风与系统声音混合采集 16kHz PCM,记录保存在服务端。
运行与打包
需要 Node.js 22.12+。
npm ci
npm test
npm run build
npm run build:plugin # Host bundle + 前端 + 原生 helper,产物与环境无关
npm pack # 出 DSH 插件包(prepack 先跑 build:plugin).tgz 为 DSH 插件包,dist/ 为独立网页预览。环境与凭据由「薪人薪事授权」插件决定
(面板里改地址即换环境),灵听产物本身与环境无关;详见 连接与环境说明。
npm 包名固定为 dsh-xrxs-lingting,版本使用正式的 x.y.z 格式,不添加 -dev 后缀;
打包文件使用 npm 默认名称 dsh-xrxs-lingting-<版本>.tgz(当前为 dsh-xrxs-lingting-0.4.1.tgz)。
Dev 仅表示本地开发环境,不加入包名、版本号或打包文件名。插件的 cordis.patch.yml 也使用包名加载。
npm run dev 打开组合预览(主页面 + 侧栏,含模拟宿主布局),仅用于 UI 样式与交互开发——
业务数据需在 DSH 宿主内使用。
DSH 中的实际体验和安装见 Desktop Dev 说明;环境名表、两种运行形态与排错见 环境切换指南。
会议声音采集
线上会议默认使用「麦克风 + 系统声音」,也可在开始面板选择「仅麦克风」用于线下交流。 采集程序随灵听插件分发,宿主需支持同源流式接口。macOS 与 Windows 均由插件独立采集,不依赖宿主原生音频模块。 录音侧栏分别显示两路音量;系统音轨缺失时不会悄悄退化为仅录麦克风,原生采集中断会暂停录音。 平台条件、权限、测试边界和验收步骤见 跨平台会议录音说明。
传输与授权
业务请求统一经同源 Host 路由发送。Host 从 ctx.xrxsAuth 现取凭据,按部署绑定访问业务网关;浏览器不持有 Cookie、CSRF 或 access token。独立预览用于 UI 开发,真实业务需在 DSH 中验收。
授权适配以 [email protected] 消费契约为基线,按能力判断,不根据版本号猜测接口。
本机核对的 0.2.3 包也已有 authorize(),可以使用显式入口;只有缺少该方法的 provider 才需要去授权插件面板操作。
未授权时,灵听显示「开始授权」;点击后 Host 在后台发起设备码流程,授权插件打开浏览器。 等待期间按钮禁用,状态每次读取完成后约 3 秒再刷新;确认并建立业务上下文后自动进入列表。 取消、验证码过期或网络失败会显示原因并恢复重试入口,正常状态恢复为约 20 秒轮询。
部署前提:支持按需授权的授权插件应设置 grant.authorizeOnDemand: false。
预检能拦住已知未授权状态,但无法消除预检之后凭据失效、续期被拒所触发的隐式交互;关闭该配置才能保证后台不弹窗、不等待人确认。
显式 authorize() 不受此开关限制,配置位置见 环境说明。
业务未就绪时仍显示具体原因(插件缺失、未配置、未授权、授权中、身份未知或目的地未确认)。 实现、差异与验收项见 按需授权优化实施文档; 早期凭据联调记录见 对接说明。
P0 探针(只读诊断)
设 LINGTING_XIN_PROBE=1 启动时,插件在 Host 内跑一次只读矩阵(11 种凭据形态 × 3 个头档位 × 2 个业务前缀),把报告写进 harness 日志,
同时注册 POST /api/lingting/xin.probe;未设置该变量时这条路由不存在。报告只含形状(长度/有无/命中),不含 sessionId / csrf / token 的值。
LINGTING_XIN_PROBE=1 nohup "/path/to/DSH Desktop Dev.app/Contents/MacOS/DSH Desktop Dev" >/dev/null 2>&1 &能力
- 主页面数据列表:搜索、状态筛选、分页、详情、AI 纪要重新生成、重命名、删除。
- 480px 右侧实时转写面板:折叠控制栏、展开阅读、收起后浮动状态入口(录音继续)。
- 真实录音链路:插件原生麦克风(macOS AVAudioEngine / Windows WASAPI)+ 系统音频(macOS 14.2+ Core Audio Tap、13–14.1 ScreenCaptureKit / Windows WASAPI Loopback) → 双路混音 → AudioWorklet 降采样 → 1600 采样 PCM 分块 → WS 上传;在线增量/离线定稿合并、发言人、时间戳。
- 暂停/继续复用同一 recordId 重连;结束失败保留 finish-error 可重试;异常掉线标记断连。
- 逐段追问建议与 SSE 流式速答;复制转写、TXT 导出。
- 开始录音自动弹出侧栏;主页面与侧栏共享同一服务实例。
- AI 纪要分享:企业内可见(按部门/员工授权,服务端登录后校验范围)或互联网公开,复制服务端生成的分享链接;回显上次设置。
- 会议自动提醒(默认开启,可关闭):macOS 14.4+ 与 Windows 10/11 x64、ARM64 使用插件自带组件读取音频会话活动,由 Host 仲裁后显示确认提醒。Windows 为待实机验收的实验实现,适配钉钉、飞书、腾讯会议、Zoom;关联钉钉/飞书通话结束后可提醒结束灵听。检测不读取声音内容,不可用时不影响手动录音,Windows 暂无录音浮动球。详见 Windows 会议检测。
尚未实现:Linux 插件独立采集、拖拽和跨窗口录音协调。Windows 采集已提供 x64/arm64 实现与构建,真实设备验收范围见 跨平台会议录音说明。
工程入口
| 路径 | 内容 |
| --- | --- |
| src/plugin/client.tsx | DSH 插件入口,main / shell.overlay / sidebar.footer.action 三插槽 |
| src/plugin/host.ts | Host 半边入口(Harness Node 进程):helper 监督、提醒策略与 connection.fetch 路由 |
| src/plugin/native/ | helper 产物定位、私有协议(NDJSON)与 supervisor(握手、水位、心跳、重启) |
| src/plugin/meeting/ | 提醒策略、配置持久化、前端在场聚合与路由 |
| native/windows/meeting-helper.cpp | Windows WASAPI 会话状态枚举和原生提醒窗口;独立 Node helper 负责状态机和协议 |
| native/macos/lingting-helper.swift | 原生 helper:音频活动采样、应用适配、每应用会话状态机、--probe 标定模式 |
| src/services/xin-service.ts | XinLingtingService:真实后端编排(生命周期、转写、问答、目录) |
| src/integrations/xin-ui/ | 后端契约层:protocol(请求/wire/转写/SSE)、http、ws、config、units |
| src/audio/ | 麦克风与系统声音:双路音量、混音、AudioWorklet 降采样、PCM 分块 |
| src/sidebar/LingtingSidebar.tsx | 右侧实时转写面板 |
| src/App.tsx / src/pages | 主页面数据列表与记录详情 |
| src/sidebar/controller.ts | 面板显示状态,与录音服务独立 |
| src/domain/types.ts | 服务接口与数据模型 |
| scripts/install-desktop-dev.mjs | 使用本机 Dev 的版本注册表更新插件 |
原 Web 代码位置、接口字段、生命周期、宿主契约及剩余待办见 侧栏与后端接入说明;原文见 源码摘录;测试见 验证记录。
数据说明
记录保存在公司服务端(aim/cinlyn),插件不落本地数据文件。业务 origin、平台身份与 moduleId 等上下文由宿主或 VITE_* 环境变量注入,见 src/integrations/xin-ui/config.ts。
凭据由 Host 经 ctx.xrxsAuth 现取,浏览器不持有,也不在授权失败时回退到直连或本机 Cookie 注入。
客户端兼容性验证
当前开发版面向团队分支 feature/merge-20260922 的新版 DSH:通过公开 main keyed 插槽注册灵听页面,通过 ctx.layout.selectPanel(id) 打开、selectPanel(null) 返回聊天,并用 usePanelInfo 同步入口状态。已删除宿主 DOM 查找、聊天隐藏、MutationObserver 和插件私有页面导航,不再提供旧版 DOM 挂载回退;旧版仅有 conversation 插槽的 DSH 不属于本版支持范围。录音服务由插件持有,不随主页面卸载而销毁;实时转写继续使用 shell.overlay。
升级前执行 npm test -- src/plugin/client.test.tsx、类型检查及构建后的 node --experimental-transform-types scripts/smoke-client.mjs /path/to/cinlyn-desktop。还需在实际 APP 验证打开灵听、返回聊天,以及有录音时切换页面的连续性。2026-09-24 已验证本机新版 APP 打开记录列表和返回聊天;服务生命周期由测试覆盖,未新增实际录音。
发布前除单元测试外,应在构建后对目标薪灵源码运行客户端产物冒烟,验证真实布局对象、公开插槽、页面打开及返回聊天:
npm run build:plugin
npm run smoke:client -- /path/to/cinlyn-desktop该检查不代替安装后对授权、录音、转写和回放的人工验证。
布局回归验证:node scripts/smoke-layout-browser.mjs <playwright/index.mjs 路径>,使用 Chrome 无头浏览器运行真实插件产物,验证页面边界、弹窗居中、转写面板层级、窗口缩放与卸载后聊天恢复。使用合成录音状态,不访问业务数据、不采集声音。
设备切换:插件原生麦克风跟随默认输入设备,接到音频引擎配置变化后在同一进程内重建采集;短时间反复变化或无法恢复时报错停止,不静默录制缺失一路的音频。系统声音优先由 Core Audio Tap 采集,设备断开时报错;设备切换与语音处理效果仍需实机验收。
独立系统采集(实验)
macOS 麦克风由插件原生 helper 的 AVAudioEngine 提供;系统声音在 macOS 14.2+ 使用 Core Audio Tap,仅在 macOS 13–14.1 使用 ScreenCaptureKit。旧系统首次录音由独立的「灵听采集」请求屏幕录制权限,不能用「薪灵」的开关代替;授权后重新开始录音。现代系统采集失败不会回退到屏幕采集或自动重试授权。Windows 使用插件内的 WASAPI 采集程序,同时支持麦克风与系统回环。两路声音经同源 Host 音频流接入混音。页面不调用 getUserMedia(),不依赖 APP 原生采集模块或 preload 桥接。统一插件包包含 macOS/Windows 的 arm64/x64 采集程序。首次授权、Intel/macOS 13、Windows 实机和跨 APP 升级仍需验收。
已验证本机 arm64 原生麦克风、双路 Host 流、重复启动拒绝和退出回收。9 月 22 日旧采集启动方式曾完成 APP 内录音、转写、保存、详情和回放验收;9 月 23 日改为独立采集应用后的验收另见记录,不能沿用旧结论。源码默认使用插件采集。首次授权、其他系统和升级矩阵仍需验证,详细范围见 独立采集验证记录。
独立安装与麦克风迁移
薪灵源码不再把灵听列为内置插件。新 profile 使用标准插件安装机制;现有 profile 若已在 dsh.profile.bundles 持久登记,则继续作为普通插件加载。插件更新也改用标准插件机制,不再由薪灵内置更新器管理。业务授权仍依赖原有授权插件。
本次开发源码尚未发布到 npm。构建并打包本地版本后,通过目标 APP 的 dsh CLI 安装实际生成的 tgz,例如:
npm run build:plugin
npm pack --ignore-scripts
DSH_HOME="$HOME/.xsh" dsh plugin --profile desktop add file:/absolute/path/to/plugin.tgz插件采集应用内嵌麦克风和系统声音用途声明,构建时签名;默认 ad-hoc 仅供开发验证。正式构建应固定 LINGTING_AUDIO_SIGN_IDENTITY,临时钥匙串可通过 LINGTING_AUDIO_SIGN_KEYCHAIN 指定;公证仍需单独完成。旧版直接启动可执行文件时,TCC 曾归属于宿主:实机验收中,薪灵的麦克风开关已开启,但缺少 com.apple.security.device.audio-input 签名权限时原生麦克风仍被拒绝,补充该通用权限后恢复。2026-09-23 已从薪灵打包配置删除麦克风用途声明及灵听专用音频输入签名配置。声明和 audio-input entitlement 由插件自己的 LingtingCapture.app 提供,经 LaunchServices 启动,通过权限 0700 的私有 Unix socket 传回音频。无上述声明和权限的 hardened 测试宿主已成功完成麦克风、系统声音有限采集;连续两轮 Host 双路采集与停止也通过。本次 arm64/x64 采集应用均已完成公司签名、公证和票据验证。已替换本机薪灵并完成 21 秒录音、保存和进程回收;未来跨升级授权复用另行验收。
权限体验:打开页面和 GET 能力检查不请求权限;只有显式开始录音时才调用采集 API。macOS 14.2+ 不枚举屏幕、不查询完整录屏授权,也不调用屏幕捕获接口。首次使用仍需 macOS 的麦克风与系统声音授权,已有授权由系统复用;Host 和原生采集等待 60 秒,页面等待 65 秒,避免用户处理弹窗时 12 秒超时。拒绝或失败后停止,由用户决定是否重试,不循环唤起授权。不能保证系统撤销授权、更换签名身份或所有 macOS 升级后永不提示。
本地验收(会短时采集,不保存音频、不调用业务接口):
node scripts/smoke-independent-audio.mjs --plugin --microphone --probe
node scripts/smoke-independent-audio.mjs --plugin --microphone --capture
node scripts/smoke-plugin-audio.mjs --capture耳机播放音量与回声处理(当前开发版)
独立采集程序读取 CoreAudio 默认输出设备的 stream terminal type。明确为扬声器时启用语音处理,macOS 14+ 将其他音频 ducking 设置为最低(并非完全关闭);耳机或未知类型默认关闭语音处理,避免压低正常播放音量。USB 仅表示连接方式,不能直接作为耳机依据。macOS 13 的公开 API 不提供相同 ducking 配置,外放仍使用系统默认程度。
录音期间每秒检查输出策略,策略变化时重配;常态不重建音频引擎。设备切换可能有短暂采集间隙,需用真实耳机插拔验证。运行 node scripts/test-output-audio-policy.mjs 检查实际 Swift 策略,运行 node scripts/test-audio-writer.mjs 验证音频帧传输;二者均不启动麦克风录音。
