dsh-widget-center
DSH plugin: native macOS desktop widget center — shares quote tickers & notes memos, multi-instance, with a market_quote model tool
- Stars
- 0
- Language
- JavaScript
- Created
- Sep 6, 2026
- Updated
- Sep 6, 2026
Introduction
dsh-widget-center
English | 中文
NSPanel + WKWebView 独立进程 ——
settings.section slot · /widget-center/* API · Type Studio 会话管道
dsh-widget-center 是一个 DSH 插件:在桌面上管理任意多个原生 macOS 小窗 (widget 实例)——**行情(shares)与便签(notes)**两种类型,每实例独立窗口、 独立配置、独立生命周期;在 DSH 设置 UI 的「Widget Center」页以两层卡片配置 (卡片列表 → 点进详情编辑)。行情数据由 host 常驻进程直抓免费公开接口: 零 token、秒级轮询、多源 fallback,附
market_quote模型工具供任意会话调用。 设置页与桌面窗文案双语(zh 默认 / en,分别跟随 DSH 语言与浏览器 Accept-Language)。
界面

功能
🧩 Widget 实例(多实例)
- 每个实例 = 一个独立桌面小窗,
type+ 名称 + 窗口几何 + 类型专属配置; 可同时开多个行情、多个便签,互不干扰。 - shares 行情:watchlist(规范符号、可分组)、红涨绿跌/美式配色、stale ⚠、 sparkline、美股盘前盘后、交易时段感知节流。
- notes 便签:多行文本(≤50 行 × 500 字符/行),桌面窗 30s 轮询跟随设置, 改文案无需重开窗口。
🖥 原生 macOS 桌面窗(主交互面)
- Swift 单文件编译(
swiftc懒编译,二进制缓存):NSPanel borderless + nonactivating + WKWebView——无 dock 图标、悬浮于普通窗口之上、跟随所有桌面空间。 - 任意位置拖动;类型感知右键菜单(刷新/重新加载 · 置顶开关 · 重置尺寸 · 退出), 窗口标题随类型。
detached独立进程:DSH 重启不影响已开的 widget;每个实例独立 pidfile (widget-<id>.pid),二进制全实例共享。- 备用入口:chrome
--app命令(浏览器窗,功能等价,如实标注为 fallback)。
⚙️ Widget Center 设置页(三视图)
- DSH 设置 UI 侧栏「Widget Center」页(
settings.sectionslot,additive)。 - 列表:每实例一张紧凑卡——类型徽标 / 名称 / 运行状态 / 一行摘要 + 「在桌面显示 / 隐藏」快捷操作;唯一「+ 新增 Widget 实例」按钮, 无保存栏(列表恒等于已落盘状态)。
- 创建:点新增进入类型选择页(已注册 widget type),点选即以默认配置创建 并跳入详情。
- 新建类型(Type Studio):列表页与「新增 Widget 实例」并排的「+ 新建
Widget 类型」→ 纯 client 管道(
sessions.create挂当前工作区 + 创造模式cordis预设,缺失回退 standard)创建不启动的会话并钉标题,composer 预填 issue-template 创作模板,补全{{占位}}后发送开始。 - 详情:点卡片进入——「‹ 返回列表」独立导航行 + 全部配置编辑(名称 / 窗口 / autostart / 启停 / 类型专属配置 / market_quote 开关)+ 删除实例(两步确认)。
- 修改保存即
PUT /api/instances全量提交;创建/删除即时持久化;host 校验热应用、 重启保留、非法输入 400 显原因。页内不渲染行情数据。
📡 数据层与模型工具
- 5 个 provider(tencent / eastmoney / sina / yahoo / binance)按优先级 fallback; GBK 转码、新浪 Referer、代理重试(socks5,仅 needsProxy 源)、交易时段 TTL 节流、 磁盘缓存(stale 兜底)。
market_quote(symbols[])模型工具:任意会话拉标准化 Quote(强制引用时间戳); 开关在 shares 实例 config(conversationTool),execute 内检查,注册常驻。
快速开始
# 安装(DSH ≥ 0.1.1-rc.6)
dsh plugin --profile web add github:NattoCB/dsh-widget-center
# 插件集变更需重启 dsh web;client 内容变更刷新页面即热更
- 原生 widget 前置:
swiftc(Xcode Command Line Tools)。首次「显示 Widget」 自动编译(数秒),二进制缓存在~/.dsh/storages/widget-center/SharesWidget。 - 使用:DSH 设置 UI → 侧栏「Widget Center」→ 点卡片「在桌面显示」→ 桌面出现小窗;
拖动定位;会话内对 agent 说「现在 159845 多少」→
market_quote工具应答。
符号规范
| 形式 | 市场 | 主源 |
|---|---|---|
sh000852 sz399006 | A股指数 | tencent → eastmoney → sina |
sz159845 sh560010 | A股 ETF | 同上 |
sh600519 等 | A股个股 | 同上 |
hk00700 | 港股 | tencent(yahoo 兜底) |
usAAPL | 美股 | tencent(yahoo 兜底) |
fx_susdcny | 外汇 | sina(yahoo 兜底) |
binance:USDCUSDT | 加密 | binance |
nf_CU0 | 期货 | 未实现(无 provider 支持时进 failed 列表) |
设置($DSH_HOME/storages/widget-center/settings.json,v2 instances 模型)
{
"version": 2,
"instances": [
{
"id": "shares-1", "type": "shares", "name": "行情",
"enabled": true, "autoStart": true,
"window": { "x": 120, "y": 240, "w": 380, "h": 460 },
"config": { "conversationTool": true, "watchlist": [ /* … */ ] }
},
{
"id": "notes-1", "type": "notes", "name": "便签",
"enabled": true, "autoStart": true,
"window": { "x": 160, "y": 160, "w": 260, "h": 320 },
"config": { "lines": ["第一行", "第二行"] }
}
]
}
shares config 要点(完整表见 PRD §6):conversationTool(market_quote
开关,实例级)、watchlist、refreshIntervalSec(5–600)、openTtlSec/closedTtlSec
(交易相位 TTL)、providerPriority、proxy、theme/upsideGreen/showSparkline/
extendedHours。notes config:lines: string[]。v1 单 widget 设置与 v0.10 顶层
conversationTool 均自动迁移。
HTTP API(挂 /widget-center/ 前缀,JSON envelope {ok,data}/{ok:false,error})
GET /api/instances # {instances[+widget{running,pid}]}
PUT /api/instances # 全量替换,非法 400;热应用
POST /api/instances/:id/show # 懒编译 + detached 启动实例窗
POST /api/instances/:id/hide # SIGTERM + 清 pidfile
GET /api/quotes?symbols=sh000852,usAAPL # 省略 symbols = 首个 enabled shares 实例 watchlist
GET /api/health # {providers, cacheSize, instances[]摘要}
GET /dashboard/:id # 实例桌面窗 HTML(shares/notes 按 type 分派)
开发
node --test # 63 项单测(parser/相位/设置/服务/路由/widget-host/dashboard)
node scripts/verify-live.mjs # 真机六品种 + 断源 fallback 演示(只读)
swiftc -O -swift-version 5 -o /tmp/SharesWidget src/widget/WidgetApp.swift # 手动编译验证
本地开发安装:克隆本仓库后 dsh plugin --profile web add file:<repo>(file: 依赖
指向本目录,源码即真相源);改源码后同步安装副本
cp -R src client cordis.patch.yml package.json ~/.dsh/profiles/web/node_modules/dsh-widget-center/。
与 PRD 的偏差(实现裁决留痕)
- 代理传输:FR-1.6 写 undici ProxyAgent + socks-proxy-agent;实际 undici 不可从插件 bundle 导入,代理仅支持 socks5/socks5h。所有 provider 失败后自动经代理重试并记住 上次成功通道——覆盖了实测「eastmoney 直连被本机网络丢弃、经代理可通」的现实。
- 期货
nf_*:FR-1.1 列入符号规范,无 provider 实现;请求即入failed。 - 节假日:仅周末判定(PRD R6);cn/hk 节假日开盘日误判 closed 仅影响刷新频率,
休市日误判 open 时抓到最近交易日快照——以返回
ts为准。 - 原生 widget 无系统级「桌面层」吸附:NSPanel .floating 悬浮于普通窗口之上; 真正钉在桌面图标层(WidgetKit)需要 app bundle + 沙盒签名,后续评估。
已知坑位
- 新浪必须带
Referer: https://finance.sina.com.cn,否则 403(provider 已固化)。 - eastmoney push2 长字段列表/高频访问 502;当前走「短字段集 + 代理重试 + 限频自然恢复」。
- widget 内容页(
src/dashboard.js)与设置页是两处独立实现(client bundle 不能 import host 模块);改行情行视觉两处同步。
- 设计与实现裁决:PRD.md(真相源)
- License: MIT