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

hiwork-im

v0.2.0

Published

HiWork 助理插件:把企业微信智能机器人接进桌面端,用手机远程指挥本机 HiWork 干活,结果回到原聊天。

Readme

hiwork-im(HiWork 助理)

企业微信智能机器人接到你电脑上的 HiWork:在手机上发一句话,本机的 HiWork 干活,结果回到原来的聊天里。

面向的是「人不在电脑前」的场景——开会、通勤、出差时,用手机把电脑上的活派出去。

  • 设计文档:hiwork-desktop/docs/superpowers/specs/2026-09-22-hiwork-im-design.md
  • 实施计划:hiwork-desktop/docs/superpowers/plans/2026-09-23-hiwork-im-m0.md

M0 能做什么

| 能力 | 说明 | | --- | --- | | 扫码接入 | 在企业微信里扫一下,机器人就接到了本机(不用抄任何字段) | | 手动填入 | 从管理后台复制 Bot IDSecret 填两个框(扫码不可用时的常驻退路) | | 远程干活 | 私聊机器人 → 本机的助理会话执行 → 答复回到聊天 | | 主动投递 | 助理可以主动发消息给你(会话里的 Agent 工具 / 助理页 / 定时任务) | | 助理页 | 中央「助理」,分历史会话配置两个分区(下方;历史在前、也是默认分区) | | 设置区 | 设置 → 助理:与助理页同源的紧凑视图 |

助理页的两个分区:

顺序与默认:历史会话在前、且是默认分区(打开助理页第一眼要回答的是「它替我干了什么」, 配置是一次性设完就很少再动的东西)。默认页签必须是最左边那个,否则打开时高亮落在第二个上, 看着像「自动选错了」——tests/client-view.spec.tsx 有一条用例盯着这个不变量。

| 分区 | 内容 | | --- | --- | | 配置 | 接入状态(连接态 / 绑定人 / 工作区 / 生效权限 / 最近活动)、默认模型(选哪条线路的哪个模型,只影响助理下一次执行)、目录权限、工作目录(默认 <DSH_HOME>/assistant,改后要新建助理会话才生效——会话的工作目录在创建时就写死了;页面会明说并给「在新目录新建助理会话」按钮)、单次任务时长上限、助理人设与自定义指令、以及「发一条」「解绑」 | | 历史会话 | 运行记录(时间、状态、耗时、答复摘要),可跳回原生会话看全过程;支持删除(单条即点即删、勾选批量、清空——后两者有 inline 二次确认)。删的只是这份索引,原生会话里的完整过程不受影响;进行中的记录删不掉(回合收尾时会被写回,所以 UI 直接不给入口) |

接入状态在配置分区里,不在页级:它回答的是「这台电脑上的助理接进来没有」,而绑定、 权限、模型、工作目录都是围绕它的设置;放在页级会让两个分区都为它让位,也没法跟着分区收起。 只要拿到了快照就渲染分区(已绑定 / 未绑定 / 通道被关掉都是同一套骨架)——少渲染一组标签条 的代价是绑定/解绑那一刻整个页面换形状,用户会以为自己点错了地方。

两处口径写在 src/config.ts 顶部:「未设置」≠「设成默认值」非法值不静默降级fail closed(一次请求里任一项不合法就整次拒绝,不写存储)。

M0 不做:群聊、文件回传、卡片交互、审批卡、多通道(微信个人号/飞书)、跨设备会话切换。 理由见设计文档 §11。

安装(尚未发布到 npm)

本插件还没发布,装法是把打包产物挂进 DSH profile。

# 1) 打包
pnpm install && pnpm build && pnpm pack      # 产出 hiwork-im-<版本>.tgz

# 2) 装进 profile(CLI 的 ~/.dsh/profiles/web、桌面端的 ~/.hiwork/profiles/<name>,两个都要装)
#    推荐:解包 + rsync —— 桌面端运行中也能安全更新,不重算依赖树、不动 lockfile
rm -rf /tmp/hiwork-im-pkg && mkdir -p /tmp/hiwork-im-pkg
tar -xzf hiwork-im-0.1.0.tgz -C /tmp/hiwork-im-pkg
rsync -a --delete /tmp/hiwork-im-pkg/package/ ~/.dsh/profiles/web/node_modules/hiwork-im/
rsync -a --delete /tmp/hiwork-im-pkg/package/ ~/.hiwork/profiles/<name>/node_modules/hiwork-im/
md5 -q ~/.hiwork/profiles/<name>/node_modules/hiwork-im/lib/index.js   # 与本地 lib/index.js 比对,别只看版本号

pnpm add file:*.tgz 也能用,但有两个坑(都实测过):必须用桌面端自带的 pnpm 11,它在 /Applications/HiWork.app/Contents/Resources/node/pnpm-package/bin/pnpm.cjs(用随包的 node 跑), 不在 dsh-runtime/node_modules/.bin/ 下;用系统 pnpm 10 会报 UNEXPECTED_STORE。 另外同名版本不会重装,先 rm -rf <profile>/node_modules/hiwork-im 再 add。

装完在 profile 的 package.json 里把 hiwork-im 加进 dsh.profile.bundles,重启即生效。

用法

  1. 打开中央「助理」→ 点扫码接入(或手动填入)。扫码后机器人就绑好了,状态卡变成「已连接」。
  2. 在企业微信里找到这个机器人,发一句话,例如:帮我看看工作区里有哪些文件
  3. 本机 HiWork 执行,答复回到聊天。点助理页里的「查看会话」可以看完整过程。

解绑:助理页 → 解绑(二次确认)。解绑只断开渠道与清除凭据,不删除助理会话的历史

安全模型(请读完再用)

  1. 凭据单向:机器人 Secret 只落在 DSH 凭据域(ctx.credentials)。存储域、日志、错误文案、 以及给浏览器的一切响应里都不会出现它——出站要过一道禁止键剥离(secret / secretRef / token …), 凭据引用名本身也由 botId 哈希派生(引用名会出现在诊断输出里,塞明文等于泄漏一半)。
  2. 来源校验:只响应绑定者本人的私聊。群聊、陌生人、以及 senderId 与绑定记录不符的消息一律静默忽略。 绑定记录里会记下授权人的渠道 id(ownerPeerId)用于这条校验。
  3. 远程任务自动执行:与定时任务同理,IM 派发的回合没有人坐在电脑前点确认,因此回合内会设置 权限预设并把审批策略设为 never(否则每个工具调用都会卡在确认上,而你不在电脑前)。 这是本插件最大的能力面——被绑定的机器人等同于「能在这台电脑上派活的人」。 请把机器人当成你自己的凭据来保管:不要把它拉进群、不要转发扫码入口给别人; 怀疑泄漏时立刻解绑(解绑会同时清掉凭据)。
  4. 不给浏览器真值:Web 半边不发任何 HTTP、不读环境变量,一切经 loopback RPC; 它拿到的快照里只有掩码(wow_ab…cd)。

开发

pnpm install
pnpm typecheck          # tsc --noEmit(strict + exactOptionalPropertyTypes + noUncheckedIndexedAccess)
pnpm build              # host → lib/index.js(自包含),client → lib/client.js
pnpm test               # vitest
pnpm verify             # typecheck → build → test(提交前跑这个)
pnpm pack               # 产出 tgz
  • 仓库约定:分支 dev(remote 名 origin);注释、文案、commit 全中文。
  • 两个半边src/**(Host)与 src/client/**(Web),各自独立打包。 client 半边对官方包只做 type-only import,运行时只 import react 与本地模块。
  • 冻结契约src/protocol.ts 是唯一事实源(RPC 频道与端点、feature/设置区座位、存储域与表名、 错误码)。改它等于改契约,要同步 client 侧常量与对撞测试。
  • 凭据纪律:任何新增的 RPC 响应都要过 stripForbidden;任何新增的日志都不得打印 secret。

测试要「有牙」

守卫类断言写完必须做一次变异验证——把实现改坏,确认用例真的变红。本仓库已实测过的三条:

| 变异 | 期望结果 | | --- | --- | | resolveBinding 在凭据缺失时回退到 env | tests/credential.spec.ts 变红 | | 幂等记录写在发送之前 | tests/delivery.spec.ts 变红 | | 短路 stripForbidden | tests/rpc.spec.ts 变红 | | 配置里时长上下界判断恒假 | tests/config.spec.ts / tests/service-config.spec.ts 变红 | | 保存配置时跳过「目录是否存在」检查 | tests/service-config.spec.ts 变红 | | 选目录时不看能力形态(拿 ok 当通过) | 同上(只看 ok 看不出来:能力对象上没有 pick,会变成 internal——所以要断言错误码) | | 换助理会话时不清「会话实际用的目录」 | 同上(第一次写这条断言时是假绿:那个字段本来就没值) | | 配置的模型被宿主默认覆盖 | tests/turn.spec.ts 变红 | | 去掉 agent.ctx 这条人设取法 | tests/turn.spec.ts 变红 | | 分区容器去掉 flex: 1(页面根有界且不滚) | tests/client-css-classes.spec.ts 变红 | | 配置分区去掉 overflow-x: hidden | 同上 | | 表单控件去掉 box-sizing: border-box | 同上 |

**假件必须照真件建模,宽窄两个方向都会骗人。**本轮实测踩到的两类:

| 假件失真 | 后果 | | --- | --- | | 假 Host 的 setup 收到 undefined(真机收到带 systemPrompt 的真 ctx) | 全部人设用例都在走真机上返回 undefined 的那条兜底,绿着放过一个真机不生效的路径 | | 假 systemPrompt 重名注册不抛错、撤销不摘段落 | 「先撤旧的再注册」的顺序错了也测不出来 |

对照:假件的 mount 现在会把提示词服务装到 agentCtx 上、假 agent 自带 ctx与传给 setup 的是同一个对象(真机实测 agent.ctx === agentCtx)、重名注册会抛、撤销会摘段落。 遇到「测试全绿但真机不生效」,先怀疑假件比真件还是,再怀疑实现。

版式问题的判据在真引擎里,不在单测里。「内容重叠 / 没有滚动条」这类事 jsdom 测不出来 (它没有排版引擎),只能起真页面量几何:.hiwork-im-tabpanel > .hiwork-im-stackclientHeight vs scrollHeight、每个卡片列的「直接子元素覆盖范围」vs「它自己的盒子」 (差 > 0 就是压到下一块上了)。两处都量过再改,改完再量一次。

单测能钉住的是规则本身tests/client-css-classes.spec.ts 的「分区骨架与滚动」一组): flex: 1 / overflow-y: auto / overflow-x: hidden / flex: none 这几条, 以及「凡 width: 100% 且带横向内边距或边框的规则都必须 border-box」—— 最后这条是实测出来的:.hiwork-im-inputborder-box 会比容器宽 22px, 把外层顶出横向溢出,多出一条横向滚动条。

做法:改一处 → pnpm exec vitest run <spec> 看是否变红 → 改回来再跑一次确认回绿。 (注意:pnpm exec vitest run ... | tail 的退出码是 tail 的,判定要看输出里的 Tests N failed,或者写成 ... > /tmp/out.txt 2>&1; echo $?。)

目录

src/
  protocol.ts          冻结契约(频道/端点/座位/存储/错误码)
  types.ts             跨半边结构契约
  context.ts           对 DSH 运行时的结构端口(窄化类型,便于造假件)
  store.ts             存储域 hiwork_im:settings / runs / deliveries
  credential.ts        凭据层(secret 的唯一落点、掩码、引用名派生)
  config.ts            助理配置的解析与校验(纯函数,三条口径:未设置≠默认 / 不降级 / fail closed)
  persona.ts           助理人设(注册进助理会话自己的系统提示词作用域,不进用户消息)
  turn.ts              无人值守回合(agents.create → followup → whenIdle → 摘要)
  delivery.ts          主动投递(幂等)
  rpc.ts               loopback RPC 分发 + 出站禁止键剥离
  service.ts           装配与生命周期
  channel/types.ts     渠道抽象(M1 的第二通道实现同一接口)
  channel/wecom/       企业微信智能机器人(长连接 / 扫码 / 归一化 / 本地状态)
  client/              Web 半边(助理页 + 设置区)
tests/                 vitest(含假 Host:tests/support.ts)