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

@khorsheed/dsh-worktrees

v0.3.1

Published

Worktree status visibility: a per-session repo/worktree badge in the session header plus a right-sidebar worktrees tab (the selected worktree's pending changes with diffs, IDE-style repository commit log, full repo browse) and a local-files browser, over

Readme

@khorsheed/dsh-worktrees

English | 中文

这个会话在哪个 worktree 上干活、有没有还没提交的改动——抬头看一眼就知道。

多 worktree 并行开发时,「当前会话对着哪个分支、有多少未提交内容」以前要去终端敲 git 才知道。这个插件把答案放进会话头部:一个分支胶囊徽标(带合并 diff 行数,有改动时变警告色),点开是右栏的 worktrees 页面——待提交改动带 diff、IDE 风格提交记录、仓库全量文件浏览。一切展示都是只读的 git 事实,插件自己不写仓库;唯一能改仓库的能力(建/删 worktree)收在按会话授予的 ./tool 组合入口(模型工具行)里,且删除永远要先确认。

特性

  • 会话头部徽标(conversation.session.header.utilities 槽,仅仓库会话渲染)——分支名 + 未提交/已提交合并的 diff 行数;hover 显示两段明细;有改动时计数变警告色,干净时保持常态。刷新不靠周期轮询(一次 summary 要跑 5–6 个 git 调用):右栏 tab 的每次刷新、宿主转发的 api-session/status(轮次边界)与 api-session/activity(用户消息)、窗口重新聚焦/可见都会触发重读。
  • 一键直达改动——点分支胶囊经 ctx.sidebarRight.openTab 打开右栏 worktrees tab(也可以从右栏 guide 页进入)。
  • 工作树待提交档——当前选中工作树的全部未提交改动(工作树维度,刻意不做会话过滤),VS Code Source Control 风格:叶子带 A/M/D/?? 徽标和行数;点文件,右侧详情在「改动 | 内容」双视图间切换(彩色 diff / 官方 CodeBlock),左树同时收起为图标栏、再点恢复;顶部切换器换 worktree,列表跟着换。
  • 仓库提交记录档——本检出的提交历史(git log HEAD,最近 200 条:短 sha + subject + 相对时间 + 分支/tag 装饰),分支并入 base 后依然有用;选中提交内联展开其提交文件树(带真实增删行数与提交正文),点文件看该提交的 diff 与当时内容。
  • 仓库文件档——git ls-files 的全量跟踪文件树,点文件看内容;图片直接内联预览。
  • 详情面板「重新加载」手势——重读当前文件的当前视图(diff 走 diff Remote,内容/图片走 read Remote);重读期间旧内容保持显示、按钮禁用并旋转,失败保留旧内容并报进既有错误槽。钉死在某一提交的文件内容不可变,不提供此手势。
  • git 动作行——刷新 / 复制分支名 / 在文件夹中显示(每页一次的官方 open-in-app 探测确认宿主有文件管理器时才显示)。
  • 「切换到此工作树」指引——切换器指向别的 worktree 后,可一键向会话追加一条不唤醒 agent 的上下文通知(生产者归属 kind worktrees),agent 在下一个自然轮次就知道用新 workdir 干活——零额外模型调用。
  • 按 preset 自隐——徽标与右栏 tab 类型默认读官方 pluginInventory 组合判据:当前会话的 preset 组合授予了本包的 @khorsheed/dsh-worktrees/tool 工具行才显示;组合数据读不到一律保持显示(fail-open)。tab 类型是注册级自隐(guide 枚举注册表,隐藏即注销;已打开的 tab 按会话存储,未授予会话的布局里本就没有它)。
  • 树默认只展开第一层,随时「展开全部 / 收起全部」;所有文件列表一次拿全(客户端 trie),仅单文件 diff 按需拉取。文件预览与「文件列表」插件共用同一个内容面板 @khorsheed/dsh-client-ui-content-preview。

安装

dsh plugin --profile web add @khorsheed/dsh-worktrees

重启 web 实例后生效;卸载即精确还原之前的组合:

dsh plugin --profile web remove @khorsheed/dsh-worktrees

一个组合里 worktrees 行只能挂一次:官方镜像(npm 发布线与 upstream master)都不挂这行,上面的 add 就是安装路径;已用其他方式挂过该 id 的组合不要再 add——重复的 loader entry id 会炸 boot。拿不准先查:dsh --profile web --dump-config | grep worktrees 无输出即可安全 add。

模型工具的两种形态:模型可见的 worktrees 工具不在 profile 根注册——它由本包的 ./tool 子路径行承载,在 agent preset 组合里按会话授予(迁移路径:在目标 preset 的 agent.cordis.yml 加 - id: worktrees-tool / name: '@khorsheed/dsh-worktrees/tool';dev 的 dev preset 已带此行)。0.2.x 及以前该行是独立伴生包 @khorsheed/dsh-worktrees-tool(0.3.0 起回并进本包,旧包名已在 npm deprecate,行 id 不变、组合状态不受影响)。徽标/服务/Remote 行为不变;右栏 tab 类型与徽标共用同一判据做注册级自隐。

模型工具(./tool 子路径行)

preset 组合里引用 @khorsheed/dsh-worktrees/tool 的会话获得模型可见的 worktrees 工具——其余会话零感知:

  • 一个工具,四个动作——list / switch / create / remove:列出会话仓库的全部 worktree(路径、分支、是否 main、脏文件数、stale 提示);切换会话跟随的 worktree(徽标/tab 联动);git worktree add 建新 worktree 并切过去;确认后删除。
  • 删除有服务侧硬闸门——remove 必须带 confirm: true,main worktree 与有未提交改动的 worktree 一律被服务拒绝(代码强制,不只是提示词约定)。
  • core 缺席就 pending,不炸——行对 core 服务声明 inject = ['worktrees']:core 未挂载时该行保持 pending(注册表审计显示 waiting for worktrees),preset 组合照常挂载、不报错;core 出现后行自动激活。core 与本行同包,正常安装永远不会缺席。
  • 归因到本包——工具携带 dsh.tool.origin 来源标记(owner = @khorsheed/dsh-worktrees),能力目录据此归因。

配置

| 字段 | 默认 | 说明 | |---|---|---| | baseRef | main | 「已提交」段(base...HEAD)与 ahead/behind 的基准分支;设为 '' 则完全禁用已提交段 | | visiblePresets | [] | 徽标与右栏 tab 显隐的手动 override。缺省或空数组 = 走组合判据:读官方 pluginInventory 的 preset 组合数据,当前会话的 preset 组合里有 @khorsheed/dsh-worktrees/tool 行则显示、没有则隐藏;组合数据不可得(无 namespace、RPC 失败、preset 组缺席或 broken)、没有 preset 的会话以及无会话的首页状态都保持显示(fail-open)。配了非空名单则退回试点语义:preset id 不在列表里的会话不渲染徽标、不注册 tab 类型。配置经 Remote 的 badgeConfig 方法到达浏览器端——web 引导不给 client 条目传 config |

Compatibility

  • npm 发布线(@deepseek-ai/[email protected]):✅ 完整——改动/提交/仓库视图迁移至官方右栏 tab 面(page-type 注册进 ctx.sidebarRightTabs,body 进 keyed sidebar.right.pane.tab 槽位,徽标点按经 ctx.sidebarRight.openTab 打开);「在文件夹中显示」手势改走官方 open-in-app 路由探测(GET /open-in-app/apps + POST /open-in-app/open,仅目录),恢复了 0.1.2 上被迫隐藏的手势。徽标留在 conversation.session.header.utilities:0.1.5 的 header corner 是 single 槽,默认 web 组合里已被 ui-sidebar-right 的 ExpandButton 占用,而 single 槽语义是遮蔽(同优先级注册即抛错,不同优先级替换占用者),无法共存。徽标与右栏 tab 显隐默认读官方 pluginInventory 组合判据(tab 为注册级:guide 枚举注册表,隐藏即注销;0.1.5 实测:dev preset 显示、standard 隐藏、切换干净翻转)。全量构建测试通过;minHost 前移至 0.1.5-rc.1,旧宿主请停留在旧发布线。
  • 源码线(deepseek-harness master):✅(verifiedHost: 0.1.7-rc.2)。headless profile 无浏览器消费方,本插件不贡献任何东西。徽标与右栏 tab 显隐判据:默认读官方 pluginInventory.list() 的 preset 组合数据(组合里有 @khorsheed/dsh-worktrees/tool 行则显示);visiblePresets 非空时是手动 override(读会话投影 projectionValues.agentPreset);两条路径读不到都保持显示(fail-open)。Session V4 适配:directAgent 上下文消息的 source 改为生产者归属 kind worktrees(保留 form: 'notice' 一行通知形态;V4 原生准入在落盘写入时拒收退役的 kind: 'plugin' 包装;0.1.5 宿主的 user/message 准入只查 kind 非空,两条线都能落盘,且两条线的渲染器都把未知非 user kind 归为上下文注入行、以 kind 为标签)。

版本线对照:0.2.0 起支持宿主 0.1.5-rc.1 及以后;宿主 0.1.2-rc.1 请停留在 0.1.0-rc.9。

已知限制

  • 会话的 worktree 切换是内存态——active-worktree override 只活在宿主进程里,宿主重启后会话回落到其静态 cwd,需重新切换。
  • 预览有 2 MiB 上限——仓库文件的内容/图片读取超过上限即拒绝;git 无关的本地文件读取按上限截断并标注不完整,二进制文件显示非文本占位。
  • 没有周期轮询——插件自有事件进不了官方 Remote 事件转发白名单(上游 seam S17),徽标的新鲜度靠上述触发器维持;轮次之间的纯外部 git 变动要等下一个触发点才上屏。
  • headless profile 不适用——全部表面都是 web UI,无浏览器消费方的组合里本插件不贡献任何东西(也不会报错)。
  • ./tool 行只管会话工作目录的仓库——工具从会话 cwd 推导目标仓库,不能指向任意路径的仓库;会话没有工作目录时调用返回 { error: 'worktrees: session has no working directory' };「删除前先征得用户同意」写在工具描述里,服务侧强制的只是三条硬规则(confirm: true、拒删 main worktree、拒删有未提交改动的 worktree)。

实现原理

架构。 Host 半部分是服务核心 WorktreesService(ctx.provide('worktrees'))加 WorktreesRemoteService Typert Remote(cordis key worktreesRemote,wire 命名空间 worktrees,浏览器调 remote.worktrees.*)。服务无状态——worktree 注册表就是 git worktree list 本身;Remote 是薄适配层,从调用方 agent 解析会话工作目录(会话的 active-worktree override 优先,回落 header.cwd)后委托给服务核心,零逻辑复制。所有 git 命令都在解析出的仓库 toplevel 内执行,客户端给的路径一律先过 assertSafePath(拒绝绝对路径与 ..)再参与 diff/读取——表面永远逃不出会话仓库。Remote 另带一组 git 无关的本地文件方法(listLocalDirectory / readLocalFile / readLocalImage):绝对路径、同样过校验、不绑定会话,任何会话或全局框架都可调用。

客户端。 经官方 ctx.remote.$mount 自挂载生成的 Remote contribution,无需改动任何核心包;组合里去掉本插件即移除它添加的所有表面。徽标注册进 conversation.session.header.utilities(order -20,最左);右栏 tab 走官方两段式注册——类型进 ctx.sidebarRightTabs(套注册级显隐开关),body 进 keyed sidebar.right.pane.tab 槽位。「在文件夹中显示」用 ui-content-preview 的 OpenInAppProbe(apply 时每页一次探测,结果经 snapshot store 供各表面订阅);预览内核同样是 ui-content-preview 的 ContentPane。host→client 失效通知借用官方 api/remotes 白名单转发的两个事件(api-session/status 轮次边界、api-session/activity 用户消息);$on 能力是探测出来的,老宿主没有它时徽标靠其余触发器照常工作。

指引 agent。 directAgent 把一条 durable user/message(surfaceOp: 'append')追加进会话而不唤醒它:生产者归属 source kind worktrees、form: 'notice' 一行形态,transcript 立即渲染为上下文注入行,并在下一个模型边界折进上下文。读侧 isWorktreesSource 三种形态都认:新 kind、V3→V4 迁移形态 plugin:@khorsheed/dsh-worktrees、以及 0.1.5 宿主原位提供的 V3 包装(kind: 'plugin' + plugin 字段)。

模型工具在 ./tool 子路径行。 工具定义工厂 defineWorktreesTool(service) 住在内部模块 ./tool-definition.ts(不进 exports 面),可挂载行是 ./tool 导出(name / inject = ['worktrees'] / apply,零 ctx.provide——preset 挂载面的 isolate-realm 规则只拒服务行,工具行可裸放 preset,官方 tool-bash 行同构),由各 agent preset 的 agent.cordis.yml 按名引用——能力按会话授予,profile 根永远没有这行。对 core 服务是声明式 inject(同族 companion 例外):preset 的 standing scope 在注册表激活时挂载,早于 profile 靠后 bundle 行提供 core,一次性 ctx.get 探测曾在此竞态下看到 ABSENT 并静默惰死(2026-09-27 3080 实证);声明式 inject 让行 pending 到 core 提供再激活,行内守卫仅留作防御性直调路径。工具注册走 ctx.inject(['tools']) 延迟注入。四个动作:list(路径/分支/是否主检出/脏文件数/是否已并回 base)、switch(会话徽标与 tab 跟随)、create(git worktree add,可 -b 新分支,随后切换)、remove(confirm: true 必填;主 worktree 与有未提交改动的 worktree 一律拒绝)。

健康探针与身份。 ./invariant 子路径注册 invariant companion:加载时探测 PATH 上的 git 二进制——整个插件都是 git 读取器,没有 git 的宿主永远答不出任何查询,与其到处空徽标不如加载期响亮失败。身份三角:cordis.patch.yml 行 id worktrees ↔ tsdown clientBundle('@khorsheed/dsh-worktrees') ↔ invariant 的 PACKAGE_NAME。

导出。 . 导出插件本体(apply/Config/name);/client 导出浏览器半部分(apply/inject、WorktreesBadge/WorktreesTab/WorktreesController);/tool 导出按会话授予的模型工具行;/types 是 Remote 线上类型词汇表(含 WorktreesService 类型);/typert、/remote 是生成的 Remote 两侧。

开发

隶属 dsh-plugins monorepo(packages/worktrees)。问题与贡献请移步该仓库。

变更记录

见 CHANGELOG.md。