🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

iMessage 桥接 vINyLogY/dsh-bluebubbles

DeepSeek Harness
vINyLogY34 天前有提交已提供中文文档扫描:含敏感能力

把本地 iMessage 接入智能体,收发消息与附件

29.5/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/2 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add vINyLogY/dsh-bluebubbles
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · security
装得上吗
实装验证未通过(dependency_conflict),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 34 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(dependency_conflict · 2026/10/2) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 32 处,展示前 25 条)
  • 读取密钥环境变量
    src/index.ts:53
    password: (process.env.BLUEBUBBLES_PASSWORD || '') as string,
  • 读取本地文件
    bin/bb-channel.mjs:30
    const text = readFileSync(path, 'utf8')
  • 发起网络请求
    bin/bb-channel.mjs:76
    const res = await fetch(url(path), {
  • 读取本地文件
    bin/bb-channel.mjs:94
    try { return JSON.parse(readFileSync(path, 'utf8')) } catch { return fallback }
  • 写入本地文件
    bin/bb-channel.mjs:98
    mkdirSync(join(path, '..'), { recursive: true })
  • 写入本地文件
    bin/bb-channel.mjs:99
    writeFileSync(path, JSON.stringify(value, null, 2) + '\n')
  • 写入本地文件
    bin/bb-channel.mjs:104
    mkdirSync(join(BINDINGS_PATH, '..'), { recursive: true, mode: 0o700 })
  • 读取本地文件
    bin/bb-channel.mjs:110
    if (existsSync(BINDINGS_PATH)) bytes = readFileSync(BINDINGS_PATH, 'utf8')
  • 读取本地文件
    bin/bb-channel.mjs:110
    if (existsSync(BINDINGS_PATH)) bytes = readFileSync(BINDINGS_PATH, 'utf8')
  • 写入本地文件
    bin/bb-channel.mjs:115
    try { writeFileSync(file, JSON.stringify(table, null, 2)); fsyncSync(file) } finally { closeSync(file) }
  • 读取本地文件
    bin/bb-channel.mjs:116
    if ((existsSync(BINDINGS_PATH) ? readFileSync(BINDINGS_PATH, 'utf8') : '{}') !== bytes) throw new Error('binding store changed concurrently')
  • 读取本地文件
    bin/bb-channel.mjs:116
    if ((existsSync(BINDINGS_PATH) ? readFileSync(BINDINGS_PATH, 'utf8') : '{}') !== bytes) throw new Error('binding store changed concurrently')
  • 写入本地文件
    bin/bb-channel.mjs:117
    renameSync(temporary, BINDINGS_PATH)
  • 删除本地文件
    bin/bb-channel.mjs:119
    try { if (existsSync(temporary)) unlinkSync(temporary) }
  • 发起网络请求
    bin/bb-channel.mjs:276
    const res = await fetch(url('message/attachment'), { method: 'POST', body: form, signal: AbortSignal.timeout(60000) })
  • 写入本地文件
    bin/bb-channel.mjs:289
    mkdirSync(dir, { recursive: true })
  • 发起网络请求
    bin/bb-channel.mjs:291
    const res = await fetch(url('attachment/' + encodeURIComponent(guid) + '/download'), { signal: AbortSignal.timeout(60000) })
  • 读取本地文件
    src/bindings-store.ts:24
    try { bytes = await readFile(path, 'utf8') }
  • 写入本地文件
    src/bindings-store.ts:65
    await mkdir(dirname(path), { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/bindings-store.ts:82
    await rename(temporary, path)
  • 删除本地文件
    src/bindings-store.ts:89
    try { await unlink(temporary).catch(error => { if (error.code !== 'ENOENT') throw error }) }
  • 写入本地文件
    src/bindings-lock.mjs:15
    await mkdir(dirname(path), { recursive: true, mode: 0o700 })
  • 读取本地文件
    src/bindings-lock.mjs:21
    const current = await stat(path + '.lock', { bigint: true }).catch(error => {
  • 写入本地文件
    client/bindings-ui/build.mjs:4
    await mkdir('lib',{recursive:true});
  • 写入本地文件
    client/bindings-ui/build.mjs:8
    await writeFile('lib/client.js',`window.__ModuleLoader__.load({id:"@vinylogy/dsh-client-imessage-bindings",factory:(require)=>{var module={exports:{}}
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/node-addon-system@deepseek-ai/cordis@deepseek-ai/cordis-plugin-group@deepseek-ai/dsh@deepseek-ai/dsh-agent@deepseek-ai/dsh-fs@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-shell@deepseek-ai/dsh-tools@deepseek-ai/dsh-user-approval
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 接入本地iMessage
  • 收发消息与附件

README

由 DeepSeek 最新模型翻译生成
dsh-bluebubbles 把本地 BlueBubbles 服务器(macOS 上的 iMessage 桥)接入 DeepSeek Harness。 DSH 版本支持: 支持的主机版本为 0.1.1-rc.1、0.1.1-rc.2 和 0.1.7-rc.2。CI 用真实的会话持久化、智能体、shell 执行,以及两条冷启动会话绑定的 webhook 路由,测试了锁定的旧版与新版运行时组合。0.1.5 及其他未测试的预发布版不受支持。可选且精确的主机 peer 声明,让 DSH 无需向插件再装一个命令行就能检查兼容性。 桥接层会对旧版/新版 shell 与持久化 API 做特性探测。冷恢复会保留绑定 ID 与预设,恢复有效的持久化模型/token 上限或配置的默认模型,并在支持时保留 reasoning effort。之后在 web/UI 里选的模型仍然优先。较新的持久化后端能把旧版会话头迁移到独立的一代,而不改动原文件;旧版后端则继续往已有的日志里追加。 升级主机是单独的部署步骤:先备份 DSH home 和锁定的运行时,再安装一套完整的锁定运行时组合,切换前验证新的配置档与预设注册表配置。这些测试使用合成会话和回环的假 BlueBubbles 服务器;它们不迁移线上数据,也不发送真实 iMessage。见 runtime test setup。
展开完整文档(README 剩余 1 节)
dsh-bluebubbles

把本地 BlueBubbles 服务器(macOS 上的 iMessage 桥)接入 DeepSeek Harness。

DSH 版本支持: 支持的主机版本为 0.1.1-rc.1、0.1.1-rc.2 和 0.1.7-rc.2。CI 用真实的会话持久化、智能体、shell 执行,以及两条冷启动会话绑定的 webhook 路由,测试了锁定的旧版与新版运行时组合。0.1.5 及其他未测试的预发布版不受支持。可选且精确的主机 peer 声明,让 DSH 无需向插件再装一个命令行就能检查兼容性。

桥接层会对旧版/新版 shell 与持久化 API 做特性探测。冷恢复会保留绑定 ID 与预设,恢复有效的持久化模型/token 上限或配置的默认模型,并在支持时保留 reasoning effort。之后在 web/UI 里选的模型仍然优先。较新的持久化后端能把旧版会话头迁移到独立的一代,而不改动原文件;旧版后端则继续往已有的日志里追加。

升级主机是单独的部署步骤:先备份 DSH home 和锁定的运行时,再安装一套完整的锁定运行时组合,切换前验证新的配置档与预设注册表配置。这些测试使用合成会话和回环的假 BlueBubbles 服务器;它们不迁移线上数据,也不发送真实 iMessage。见 runtime test setup。

设计原则(Unix 哲学):主机插件只保留被动能力(webhook 接收 + 绑定解析 + 消息注入)和两个高频模型工具(发文本 / 发附件);其余全部收敛进 bb-channel 命令行——智能体通过 bash 调用它,人和自动化脚本直接用它。

组件

| 组件 | 位置 | 职责 |
| bluebubbles-bridge | src/index.ts | webhook 路由 + 消息注入 + 2 个发送工具 + bluebubbles 服务 |
| dsh-heartbeat | src/heartbeat.ts | 通用定时唤醒(读取 heartbeat-targets.json) |
| dsh-cron | src/cron.ts | cron 定时任务(读取 cron-jobs.json) |
| bb-channel | bin/bb-channel.mjs | 命令行:chats/messages/send/bind/contacts/webhook/configure… |

模型工具(刻意只留两个)

| 工具 | 职责 |
| bluebubbles_send_text | 发送文本消息 |
| bluebubbles_send_attachment | 发送附件(图片/文件) |

其余全部走命令行(智能体通过 bash 调用——能力等价):

~/.local/bin/bb-channel chats [--limit N] [--all] # list chats (placeholder/pairing-code noise hidden by default)
~/.local/bin/bb-channel messages <chatGuid> [--limit N] # read history (with sender display names)
~/.local/bin/bb-channel send <chatGuid> <text...> # send text
~/.local/bin/bb-channel send-attachment <chatGuid> <file>
~/.local/bin/bb-channel attachment <guid> [--dir D] # download an attachment
~/.local/bin/bb-channel bind <chatGuid> (--workspace PATH | --session ID)
~/.local/bin/bb-channel unbind <chatGuid>
~/.local/bin/bb-channel bindings # show the binding table
~/.local/bin/bb-channel contacts / set-contact <name>
~/.local/bin/bb-channel webhook [--url URL] # check/self-register the webhook
~/.local/bin/bb-channel ping / configure # connectivity / write ~/.dsh/.env

- 输出始终是格式化好的 JSON(对 jq 友好);错误写到 stderr,退出码 1。
- 凭据链与插件一致:process.env → ~/.dsh/.env → ~/.zshenv;不用手动填任何东西。
- 命令行直接改 ~/.dsh/bluebubbles-bindings.json / bluebubbles-contacts.json;插件在每条入站消息到达前都会热重读这两个文件 —— 改完立即生效,不用重载。

推送路径(webhook)

BlueBubbles server (new message)
│ POST {type:"new-message", data:{...}}
▼
DSH webServer route /bluebubbles/webhook (loopback only)
│ hot re-read bindings/contacts → look up chatGuid → workspacePath/sessionId
▼
workspace.sessionIds[0] → agents.get(sessionId).send(userMessage, 'next-step', true)
▼
The workspace's model wakes up and sees a message annotated
"📱 iMessage · <MM-DD HH:mm UTC±N> · <chat name> · 来自 <name> (<number>)"

头部时间戳取自消息的 dateCreated(BlueBubbles 返回的可能是 Apple epoch 毫秒,也可能是 Unix 毫秒 —— 按数值大小区分),按宿主机时区渲染,末尾始终带上 UTC 偏移量。BLUEBUBBLES_TZ 可以覆盖时区(例如 BLUEBUBBLES_TZ=Asia/Shanghai);只有消息不属于当前年份时,才会在前面加上年份。BLUEBUBBLES_TZ 未知或不支持时,回退到宿主机时区;如果格式化时 Intl 拒绝该时区,时间戳就退化成宿主机本地时间戳 —— 头部只是装饰,绝不会影响入站投递。没有 dateCreated 的消息保持原来的头部不变。

防回环(两层,v22+):

1. pendingSent 队列:每次发送前,插件记录 (chatGuid, normalized text);webhook 回显中 isFromMe=true 且能匹配上某条记录的消息会被丢弃(TTL 60 秒,比较时做 unicode NFC 归一化);
2. seenGuids:发送成功后,API 返回的真实 guid 会加入去重集合(BlueBubbles 偶尔会把同一个事件推两次 —— 这是第二层兜底)。

不能一刀切地丢弃所有 isFromMe 消息:同一个 Apple ID 下的手机,在自聊私信里也会产生 isFromMe=true,全丢掉就会误杀真实用户消息。
发送者显示名:payload.handle.displayName → ~/.dsh/bluebubbles-contacts.json(地址→姓名,通过 bb-channel set-contact 维护)→ 裸号码。

引用回复(swipe-reply):iMessage 几乎给每条消息都打上 replyToGuid,而它默认的父消息就是聊天里的上一条——所以光看这个指针,分不清是真引用还是这种链式关系(实测:40 条连续消息里有 35 条带 replyToGuid,且这 35 条全都指向前一条)。桥接会记住每个聊天的上一条消息 guid,只有当父消息是别的消息时才渲染引用,做法是从 BlueBubbles 把那条消息读回来:

↪ 引用(<author>):「<parent text, whitespace collapsed, 40 chars + …>」

如果这条消息是中继账号自己发的,作者就是 我;否则走和头部同一条解析链(payload.handle.displayName → 联系人 → 裸地址),最后兜底为 对方。在另一台共用同一 Apple ID 的 Mac 上打的自我聊天私信,同样会以 isFromMe 到达,这个标签区分不了两者。点按回应(tapback)排除在外——BlueBubbles 已经把它们渲染成 很疑惑:<quoted text>,再引用一次就重复了。查父消息时会显式请求附件:父消息没有文本但有附件时,渲染为 (附件)。查询失败(包括 shell 基础设施异常)只丢掉引用那一行,收到的消息本身照常投递。

每个聊天的记忆存在进程内,所以插件重载后的第一条入站消息永远不会带引用。桥接发送回声的第一次 webhook 观测,会在防循环丢弃之前推进记忆,即使 REST 发送已经登记过它的 guid 用于投递去重。重复观测不会推进记忆;这个独立的观测缓存保留最近 500 个唯一 guid。创建时间戳早于记忆中最晚时间戳的消息,投递时不带引用,也不会回退记忆,因为它的实际前驱未知。时间戳缺失或相等时,新观测按到达顺序处理。这终究是启发式:漏掉的 webhook 或顺序不明都可能导致引用检测不准。

中继自动投递(入站与 cron 用同一模式)

绑定上开启 relay: true 后,桥接会为被唤醒的会话注册回复触发器(持久化到 bluebubbles-relay-state.json)。空闲触发器在下一个 turn/start 时超过十分钟即过期,启动时也会忽略过期的持久化触发器。一旦回合开始,即使任务耗时超过十分钟,回复依然可投递。每次 turn/end(包括出错)都会清除触发器;要重试就得有新的入站消息,或显式调用 armRelay。回复恰好是 NO_REPLY 也会清除它。在该回合期间,每条含文本部分的助手消息都会立即发回聊天——思考和工具结果永不投递。
DSH 重启后,已绑定的会话会用最近一条有效 request/header 里的服务商/模型恢复,如果其中带有有效的输出 token 上限也一并沿用。只有 header 的会话使用部署默认模型。两者都没能给出完整模型选择时,桥接层记录失败并跳过投递,而不是创建一个无法使用的智能体。

dsh-cron 触发任务时,如果目标任务会话绑定了 relay: true,它会通过 bluebubbles 服务的 armRelay 启动同一套机制。cron 任务的提示词不能告诉模型自己去调用发送工具——那会重复发送。

无头防护(未挂载 Web UI)

纯靠 iMessage 驱动的会话,没有人去点 Web UI 上的交互卡片,而这两类卡片都会让这一轮永远停住。对于 bindings 表中列出的任何会话(包括其子代理子会话),桥接层会注册前置监听器,它们先于 Web 应答器运行:

- ask_user_question 被拒绝,并附带一条纠正消息,告诉模型改用纯文本提问——回复会自动转发到 iMessage,随后这一轮结束,用户的下一条 iMessage 就是回答;
- 审批请求自动裁决——默认 reject(失败即关闭:沙箱提权被拒绝,并告知模型在没有提权的情况下继续)。设置 BLUEBUBBLES_GUARD_APPROVAL=allow 可改为自动批准,仅限可信环境。

不在 bindings 表中的会话不受影响,走普通 Web 流程。设置 BLUEBUBBLES_GUARD=0 可完全关闭防护。

配置

凭据

| 方式 | 生效时机 |
| bb-channel configure --password <pw>(写入 ~/.dsh/.env) | DSH 重启或桥接层重载后 |
| 环境变量 BLUEBUBBLES_PASSWORD(可选 BLUEBUBBLES_BASE_URL) | DSH 重启后 |

绝不要把带 DSH_ 前缀的变量放进 .env——DSH 引导会拒绝启动。所以 heartbeat/cron 的配置键是 HEARTBEAT_INTERVAL / HEARTBEAT_TARGETS / CRON_JOBS。

状态文件($DSH_HOME,默认 ~/.dsh)

| 路径 | 内容 | 写入方 |
| bluebubbles-bindings.json | { "chat:<guid>": { workspacePath \| sessionId } } | bb-channel bind/unbind |
| bluebubbles-contacts.json | { "address": "display name" } | bb-channel set-contact |
| bluebubbles-media/ | 入站附件(<guid>-<filename>) | 桥接层自动下载 |
| heartbeat-targets.json | heartbeat 目标 | 手工编辑 |
| cron-jobs.json | cron 任务 | 手工编辑 |

会话解析链:直接给 sessionId → 否则用 workspacePath → 该工作区的 sessionIds[0](最近的会话)→ 活跃智能体。没有活跃智能体时,桥接层按需恢复已持久化的会话(折叠其存储的预设,与 Web UI 的挂载路径相同)——已绑定的聊天在 DSH 重启后依然可用,无需任何人重新打开。只有恢复本身失败时(会话未知、会话归子代理所有、预设缺失),消息才会被丢弃并记录日志。
可选的 WebUI 绑定设置(仅限 DSH 0.1.7-rc.2)

这个可选页面在官方 WebUI 上新增 Settings → iMessage,不改动官方 WebUI。页面会列出已有的聊天摘要、会话和绑定;你可以选择某个聊天和某个精确会话,保存或解绑,也可以切换自动回复投递(relay)。它不会创建聊天、发送测试消息、激活模型,也不会更改预设。会话可用性只是列表提示;保存时会校验会话当前生效的预设(包括之后持久化的选择),但不会恢复该会话。

在 0.1.7-rc.2 的 Web 配置档中安装并启用桥接之后,还要从同一版本的检出目录显式安装这个可选本地包: sh
dsh plugin --profile web add ./client/bindings-ui

它的可选 bundle 会加入 dsh-bluebubbles/bindings-management 和浏览器设置入口。配置档必须已经提供官方带认证的 Connection/API Gateway 以及 settings/client-module 服务。按你平时的部署流程重新加载配置档;只安装旧版桥接不会启用它。仓库中已提交的 lib/client.js 产物可直接用于 Git 发布版,无需本地构建前端。开发构建使用客户端包锁定的 npm ci && npm run build;CI 会检查已提交的 bundle 可复现。

管理操作沿用现有的浏览器认证和 Host/Origin 防护,而不是匿名的 webhook CRUD。绑定 API 不会返回密码、端点配置和消息正文。仍然共用一份规范的 bluebubbles-bindings.json,与 bb-channel 共享;未知字段以及旧的工作区/遗留记录都会保留。已有的悬空或冲突绑定会显示出来,不会悄悄修复。新绑定都是精确会话绑定,会拒绝其他聊天解析出的会话,包括工作区别名。更改工作区绑定上的 relay 不会把它变成精确会话绑定。

保存使用字节哈希版本号、协作式文件锁,以及经 fsync 的临时文件,再通过原子重命名发布。本版本的命令行使用同一套锁协议;发生冲突时需要刷新,而不是自动重试。旧版命令行二进制和忽略锁的任意编辑器不保证是 compare-and-swap 写入者:检测到的外部编辑会被拒绝,但最后的比较/重命名窗口无法防范忽略协议的编辑器。在 macOS/Linux 上,所有权是原生非阻塞 POSIX 文件租约:描述符关闭或其进程死亡时,内核会释放它,不会按时间抢占仍存活的所有者锁。永久性的 .lock 载体文件永不删除;删除或替换存活的载体文件会破坏协作式互斥。缺少原生支持或平台不受支持时,会以 lock-unavailable 失败关闭;没有目录锁回退方案。不承诺断电情况下的发布持久性。

当入站准入、回复触发/发送,或受影响的智能体处于活动状态时,管理操作会以 busy 为由拒绝更改。该检查与发布共用一次准入边界;活跃的空闲智能体在保存期间保留公共维护所有权。
在发送入站回复之前,桥接会在文件租约下重新检查规范的 chat/session/ relay 关联,因此 CLI 解绑/重新绑定无法使用过期绑定投递迟到的回复。只有等待开始发送的 relay 才可以在租约争用时最多等待一秒;随后它会重新验证规范关联和触发代次。超时会记录为未发送,不会抢占活跃锁,也不会重试已经启动的网络请求。UI/CLI 变更保持立即忙碌,绝不自动重试。显式工具发送和调度器 armRelay 保留各自独立的授权语义。如果发生浏览器超时,写入结果是未知:先刷新;不要假定它失败,也不要自动重试该变更。保存失败绝不报告成功,也不会预先更新桥接的活动映射。CLI 更新仍会在下一条入站消息时热应用。

更新代码

1. 编辑 src/.ts → npm run typecheck → git commit
2. 在 ~/.dsh/profiles/web/cordis.patch.yml 中,将对应行的 ?v=N 加 1 并保存
3. 进程内 HMR 无法可靠地热替换桥接模块(过期的 fiber 路由会存活),因此重启 DSH 是可靠的加载路径;用 curl -X POST -d '{}' http://127.0.0.1:3080/bluebubbles/webhook(ok-vN)验证版本标记。

诊断

设置 BLUEBUBBLES_DEBUG=1(环境变量或 .env)后,入站事件和丢弃原因会写入 ~/.dsh/bluebubbles-debug.log(串行追加,不丢行)。

安全

- webhook 路由只接受回环来源;BlueBubbles webhook 没有签名机制。
- 注入内容是纯文本消息,不触发任何工具;出站发送始终通过显式的模型工具调用发生。
- 仓库和补丁文件都不包含凭据。

安装

作为配置档捆绑包(消费者): bash
dsh plugin --profile web add github:vINyLogY/dsh-bluebubbles

dsh plugin add 转发到 pnpm,并且由于此包声明了
dsh.bundle.patch,会自动加入配置档的捆绑栈——随附的 cordis.patch.yml 为所有三个插件插入行(bluebubbles-bridge、dsh-heartbeat、dsh-cron,通过包导出映射解析)。重启 DSH 会加载它们。bb-channel 命令行通过包的 bin 条目落到配置档的 node_modules/.bin。

本地开发时,改为在配置档自己的 cordis.patch.yml 中插入带 ?v=N 缓存破坏参数的绝对路径行(见下文)。

技术栈可选的 legacy ChatCompletions 兼容插件 是独立的服务商,需要显式配置,且仅支持 DSH 0.1.7-rc.2;安装这个桥接插件并不会激活它。入站生产者归属使用真实的会话头:format 0 保留 legacy wrapper,format 4 使用其官方生产者自有的拼写。缺失或其他格式一律拒绝投递,而不是去猜测未来的 schema。

- TypeScript(仅可擦除语法),类型来自 @deepseek-ai/dsh- devDeps(^0.1.1-rc.2 / cordis ^4.0.1 —— 准确的 CI 验证命令行版本见上方徽章)。0.1.5-rc.x 系列未经测试,目前不支持。
- 零构建:Node ≥ 23.6 原生类型剥离;composition 行直接指向 src/index.ts。
- 命令行是纯 Node ESM(bin/bb-channel.mjs),使用全局 fetch/FormData。
请从完整安装的包里运行它,不要用复制出来的独立脚本:它共享的绑定租约依赖固定版本的 @deepseek-ai/node-addon-system 预编译原生依赖。绑定写入和受保护的 relay 支持 macOS 和 Linux;不可用或不支持的原生锁会直接失败关闭。.mjs 让命令行无需 TypeScript 剥离。
- 引导:npm install --cache ./.npm-cache && npm run typecheck。
预览分享卡片长什么样 ↓vINyLogY/dsh-bluebubbles
分享 · DeepSeek Harness Hub
vINyLogY/dsh-bluebubbles

把本地 iMessage 接入智能体,收发消息与附件

回到顶部