npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lijixu/bark-notify

v1.0.0

Published

DSH bundle: push Bark notifications to iPhone and Apple Watch when an agent finishes a run, needs approval, or errors out.

Readme

@lijixu/bark-notify

English npm CI DSH Plugin

当前语言:简体中文 | English

DSH 插件:Agent 运行结束、需要人工授权、或运行出错时,通过 Bark 推送到 iPhone / Apple Watch。

Bark 的通知会由 iPhone 自动镜像到配对的 Apple Watch,所以只需在 iPhone 上装好 Bark App。

通知时机

| 事件 | 触发点 | 通知标题 | |---|---|---| | Agent 运行结束 | agent/status 从 running 落到 idle,且本轮 turn/end 原因为 completed,settleMs 后仍空闲 | ✅ 任务完成 | | 需要授权 | approval/request(工具调用等待人工批准) | 🔔 需要授权 | | 运行出错 | agent/error(某一轮 / 某一步出错) | ⚠️ 运行出错 | | 运行被中止 | 本轮 turn/end 原因为 aborted,且 notifyOnAbort: true | ⏹️ 已中止 |

被中止的运行不会被当成「任务完成」。 点「停止」时 dsh-agent-loop 只会记下 turn/end { reason: { kind: 'aborted', reason: { kind: 'user' } } },不会发出 agent/error,而 agent/status 同样只是从 running 落到 idle —— 光看状态是分不出「跑完了」和「被停了」的。因此插件额外监听 session/event,读出本轮 turn/end 的原因再决定推不推:

| 本轮 turn/end 原因 | 插件行为 | |---|---| | aborted(手动停止 / 上级 Agent 取消 / hook 取消 / 会话关闭) | 默认不推送;notifyOnAbort: true 时改推 ⏹️ 已中止(正文写明是谁中止的) | | error(本轮以失败收尾) | 只推 ⚠️ 运行出错,不再补一条 ✅ 任务完成 | | 其他(completed、max-tokens 等正常收尾) | 推 ✅ 任务完成 | | 没有 turn/end(被唤醒但无活可干) | 不推送 |

插件只做「旁观者」:授权事件始终调用 next() 交回给原有的审批 UI,不会抢占或改变授权结果。

安装

已发布到 npm,一条命令即可(也可以从源码目录或 GitHub 装,见「打包与发布」):

plugin_manager: { action: "install_bundle", target: "@lijixu/bark-notify" }

安装会在当前 profile 的 dsh.profile.bundles 末尾加入本 bundle,并写入 bark-notify 行;改动对所有会话生效,重启后依然存在。

⚠️ 改了插件代码后必须重启 DSH。 DSH 按「模块代」缓存已加载的插件:重新安装同一个 bundle 只会重新应用行与配置,不会替换已加载的 JavaScript 模块(plugin_manager 会明确返回 restart-required)。

打包与发布

一个 DSH bundle 就是一个普通 npm 包,只要求 package.json 里有 dsh.bundle.patch 指向它的 patch 文件(见 package.json)。cordis.patch.yml 里的 id / name / config 就是安装后写进 profile 的那一行,plugin.js 是真正被加载的入口(main / exports)。本仓库零依赖、零转译、无构建步骤,所以「打包」= 把文件放进包里 —— npm pack 出来的 tarball 就是可分发的成品(9 个文件、约 17 kB)。

当前状态

| 项 | 值 | |---|---| | npm 包名 | @lijixu/bark-notify | | GitHub 仓库 | https://github.com/xuliji/bark-notify | | 发布可见性 | 公开(publishConfig.access = "public";scoped 包默认是私有的,免费账号发不了) | | 三处名字 | package.json 的 name、cordis.patch.yml 的 name:、本文档的示例 —— 必须完全一致,否则 profile 里那一行会指向不存在的包 |

GitHub 用户名是 xuliji,npm 用户名是 lijixu,两者不是同一个,改配置时别混。

首次发布(手动)

cd /Users/lijixu/Documents/bark-notify
npm test                # 15 条 node:test 用例
npm pack --dry-run      # 确认包内容:9 个文件,test/ 不会进包
npm publish             # publishConfig 已声明 public,不需要再加 --access public

后续发版

npm version patch       # 或 minor / major;会顺带打 git tag 并提交
git push --follow-tags
npm publish

DSH 侧升级:再跑一次 install_bundle(或在 Plugin Manager 里更新该 bundle),然后重启 DSH。

托管到 GitHub

仓库推上去(远端还没建的话,先在 GitHub 上建一个空的 bark-notify):

cd /Users/lijixu/Documents/bark-notify
git add -A
git commit -m "feat: 发布为 @lijixu/bark-notify,修复中止误报完成"
git branch -M main
git remote add origin https://github.com/xuliji/bark-notify.git   # 已有 origin 则用 git remote set-url
git push -u origin main

仓库里的 .github/workflows/ci.yml 会在 push / PR 时跑 npm test 与 npm pack --dry-run(Node 20 + 22)。自动发布按你的选择没加,npm 发布保持在终端手动执行 —— 这样第一个版本不用碰 npm 的 token / 2FA bypass 新规。

安装来源(install_bundle 的 target 支持哪些写法)

target 会被 dsh-plugin-manager 先解析成 install spec,支持以下形式:

| 形式 | 例子 | |---|---| | npm 包名 | @lijixu/bark-notify、@lijixu/[email protected] | | 绝对路径 / file: / link: | /Users/lijixu/Documents/bark-notify | | GitHub 简写 / git URL | github:xuliji/bark-notify、git+https://github.com/xuliji/bark-notify.git | | 仓库 URL | https://github.com/xuliji/bark-notify | | tarball(本地或远程) | …/lijixu-bark-notify-1.0.0.tgz、https://…/x.tgz |

(相对路径会被拒绝:Host 的工作目录和你在浏览器里输入的位置没有关系。)

三个坑

  • 🔑 不要把真实 Bark Key 写进仓库里的 cordis.patch.yml。 那个文件会随 npm 包公开分发出去。仓库里的 deviceKey 保持空占位符,真 Key 写在 profile 的 patch 层(~/.dsh/profiles/desktop/cordis.patch.yml,不在 git 里、升级 bundle 也不会丢),它的优先级高于 bundle 层。
  • 改了 plugin.js 必须重启 DSH。 DSH 按「模块代」缓存已加载的插件:重新安装同一个 bundle 只会重新应用行与配置,不会替换已加载的 JavaScript 模块(plugin_manager 会明确返回 restart-required)。发新版本时记得 bump version。
  • 不要把 @deepseek-ai/dsh* 写进 peerDependencies。 DSH 会拿这些 peer 对运行时版本做 semver 校验,不匹配就拦下安装并要求对 包名@版本 逐条授予版本豁免;豁免本身带风险。本插件保持零依赖,正是为了在任何 dsh 版本上都能直接安装。

配置

安装时的默认配置(本 bundle 的 cordis.patch.yml)里 deviceKey 是空占位符,必须填上你的 Bark Key 才会真正联网推送。

推荐做法是在 profile 的 patch 层(~/.dsh/profiles/desktop/cordis.patch.yml)追加一条同 id 覆盖,它会覆盖 bundle 层的配置,真 Key 不会进 git、升级本 bundle 时也不会丢:

- id: bark-notify
  name: '@lijixu/bark-notify'
  config:
    deviceKey: '你的 Bark Key'      # Bark App 首页 https://api.day.app/xxxxx 中的 xxxxx
    # 其余为可选覆盖
    # serverUrl: https://api.day.app
    # notifyOnFinish: true
    # notifyOnApproval: true
    # notifyOnError: true
    # notifyOnAbort: false
    # includeSubagents: false
    # settleMs: 1500
    # timeoutMs: 10000
    # group: DeepSeek Harness
    # sound: ''
    # level: active
    # icon: ''
    # url: ''

| 字段 | 默认值 | 说明 | |---|---|---| | serverUrl | https://api.day.app | Bark 服务器地址;自建 bark-server 改成自己的域名 | | deviceKey | 空 | 必填,Bark 设备 Key;为空时只记录日志、不联网 | | notifyOnFinish | true | Agent 运行结束是否推送 | | notifyOnApproval | true | 需要授权是否推送 | | notifyOnError | true | 运行出错是否推送 | | notifyOnAbort | false | 运行被中止(含手动停止)是否推送;关闭时中止不打扰,打开时改推 ⏹️ 已中止 | | includeSubagents | false | 是否也为子 Agent(subagent)推送 | | settleMs | 1500 | 空闲后延迟多久才推送,跳过「刚结束又立刻开始」的抖动;设为 0 立即推送 | | timeoutMs | 10000 | 单次推送请求超时 | | group | DeepSeek Harness | Bark 通知分组 | | sound | 空 | Bark 铃声名,空为系统默认 | | level | active | 中断级别:active / timeSensitive / passive / critical | | icon | 空 | 通知图标 URL | | url | 空 | 点击通知打开的 URL |

配置是每次推送时读取的:改完 YAML 重启 DSH 生效;插件自身不校验字段名,未知键会被忽略,字段类型不对则回退默认值。

推送内容示例

✅ 任务完成
Agent 本轮运行已结束
重构登录模块(7dbd389b)
🔔 需要授权
工具:bash
原因:在工作区外写入文件
重构登录模块(7dbd389b)
⚠️ 运行出错
第 3 轮 / 第 2 步出错
ENOENT: no such file or directory, open 'src/app.ts'
重构登录模块(7dbd389b)
⏹️ 已中止
运行已被手动中止
重构登录模块(7dbd389b)

会话标题取自可选的 sessionTitle 服务;服务缺失时退化为「会话 + 短 ID」。

实现要点(维护者必读)

  • 「跑完了」和「被停了」要靠日志区分:agent/status 只有 idle / running 两个状态,中止和正常结束在这里完全一样。真正的原因是 turn/end 的 reason(由 dsh-agent-loop 在 turn() 的 finally 里 append)。插件监听 session/event(post-commit、append 期间同步回调,因此一定早于随后的 idle)把原因按 Session 记进 WeakMap,在 agent/status 落到 idle 时消费一次:只有本次 idle 真的有过 turn/end 才谈得上推送,所以「被唤醒但没有活可干」的空转不会误报完成。
  • 子 Agent 判定必须用 header.origin === 'subagent',不能只看 header.parentSession:用户手动 fork 会话时 SessionController.fork() 也会写 parentSession(但不写 origin、不写 delegationDepth)。只按 parentSession 判断会把用户自己 fork 出来的会话当成子 Agent,默认配置下就再也收不到它的通知了。
  • 授权监听必须 prepend:approval/request 的瀑布链第一个监听器是 Host 启动时注册的「终止应答者」,它拿到人工决定后直接返回、不再调用 next()。因此排在链尾的监听器永远不会被执行,必须 ctx.on('approval/request', handler, { prepend: true }) 才能观察到请求,并原样调用 next() 把决定权交回去。
  • 零依赖:profile 里安装的 bundle 是软链到本目录、按真实路径解析的,@deepseek-ai/* 这类只存在于 dsh 安装目录里的包解析不到(实测 import 失败)。所以本插件不 import 任何模块,resolveSettings() 自己做默认值与校验;这也意味着它不会在 Plugin Manager 里投影出配置表单,配置请按上表写 YAML。
  • Bark HTTP API v2:POST {serverUrl}/push,JSON 体 { device_key, title, body, group?, sound?, level?, icon?, url? },返回 code: 200 视为成功;空字符串字段不会出现在请求体里。
  • HTTP 用进程内 fetch;请求带超时,并随插件卸载一起中止。
  • 监听器都注册在插件上下文里,卸载时自动注销;Agent 被 dispose 时清掉它的去抖定时器与状态,卸载时清空全部并把在途请求中止。
  • 子 Agent 默认不推送,避免一次任务产生大量通知。
  • 通知推送失败只记 warn 日志,不会影响 Agent 运行或授权流程。

目录结构

plugin.js             # 插件实现(零依赖,ESM)
cordis.patch.yml      # bundle 默认配置
locale/{en,zh}.json   # Plugin Manager 里展示的名称与描述
icon.svg              # 图标
test/plugin.test.js   # node:test 用例(不发布)

License

MIT