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

opencode-session-spawn

v2.6.0

Published

opencode 会话生成原语(V1+V2 双模兼容):创建新顶层会话并注入起始语句、向指定会话注入消息、只读列举派生会话,用于无人值守长任务编排(V1:工具 spawn_session / notify_parent / notify_session / list_sessions + 命令 @spawn;V2:工具 spawn_session / notify_parent / notify_session + 命令 /spawn)。

Readme

opencode-session-spawn

opencode 插件(V1 + V2 双模兼容,同一 npm 包):会话生成原语。做四件事——创建一个新的顶层会话,并把起始语句注入为该会话首条消息(新会话保持顶层,会出现在会话列表中,便于人工查看;V1 下默认还会让 UI 选中它);子会话反向通知父会话(notify_parent:注入一条 [relay] 消息并唤醒父会话);向任意指定会话注入并唤醒它(notify_session:父/任意会话向已知会话投递指令/纠偏/叫停);以及只读列举派生会话(list_sessions:按父链接发现直接 / 传递派生的会话 id,仅 V1)。

它的用途是无人值守长任务编排:当一条任务超出单会话上下文时,当前会话的模型可以在需要时自行生成一段交接语句、调用工具开出一个新会话继续,新会话拿到语句立即开跑;子会话完成 / 受阻时可用 notify_parent 回调 spawn 它的会话;父会话也可用 list_sessions(V1)找回(可能由中间会话间接派生的)会话 id,再用 notify_session 向指定会话投递纠偏 / 叫停指令。插件不落文书、不读文书、不追踪链、无状态文件——需要交接文书时,把「读取某份文书路径」等引导写进起始语句即可,与其他工具天然兼容。

双模(V1 / V2)兼容

同一份代码、同一个包,default 导出 { id, setup, server }:

| 宿主 | 加载方式 | 行为 | |---|---|---| | V1(opencode ≥1.18.29 对象入口) | 读 default.server,调 server(input, options) 取 V1 Hooks | 现 2.5.0 全部功能:4 工具(spawn_session / notify_parent / notify_session / list_sessions)+ @spawn 文本命令(含 @relay spawn) | | V2(opencode 2.x) | 读 default = { id, setup },调 setup(ctx) | 3 工具(spawn_session / notify_parent / notify_session)+ 注册型命令 /spawn;平台缺口按下表显式降级 |

opencode 1.19.x 过渡版会同时调用 server() 与 setup(ctx)(后者传入的上下文尚不完整,无 tool/session 域)。插件已做能力探测:上下文不支持 V2 注册 API 时 setup 直接返回,由 server() 承担,不会报错。

V2 能力矩阵与降级(显式记录)

| 能力 | V1 | V2 | |---|---|---| | 建会话 + 注入起始语句 | client.session.create({ body, query }) → promptAsync(回退 prompt) | ctx.session.create({ title, metadata, model, location }) → ctx.session.prompt({ sessionID, text }) | | agent 参数 | 注入时 body.agent(单条消息模式) | 注入前 ctx.session.switchAgent(会话级切换,会持久改变目标会话 agent;V2 prompt 无 per-message agent 字段) | | 父链接 metadata.spawnParentID | ✅ | ✅ | | 创建后自动选中新会话 | tui.selectSession(回退 tui.publish) | ❌ 无对应 API(no-op,不自动选中/打开;select 参数保留仅为对齐) | | tui.showToast 反馈 | ✅ | ❌ 无 tui 命名空间;工具以返回文本反馈;/spawn 命令以 ctx.session.synthetic(resume:false,不唤醒)写入一条 [session-spawn] … 注记 | | list_sessions 工具 | ✅(client.session.list) | ❌ V2 插件域无 session.list;不注册该工具,请用内置会话列表/搜索 | | @spawn 文本命令 | ✅ chat.message 拦截(兼容 @relay spawn) | ❌ 不兼容;改用注册型命令 /spawn(见下「为什么 V2 没有 @spawn 文本兼容」) |

为什么 V2 没有 @spawn 文本兼容:V2 的 chat.message 对应物是 ctx.session.hook("prompt", …),它没有显式取消 API。实测(opencode 2.0.30):把 event.prompt.text 置空仍会触发一次模型请求;抛错能让 prompt 请求返回 500(消息不入队但用户看到报错)。两者都不「干净」,且 V1 的 chat.message 本来就只是旁路观察(消息仍会进当前会话),故 V2 只保留注册型命令 /spawn,不做文本兼容。

入口与工具

| 入口 / 工具 | 用法 | 谁触发 | V1 | V2 | |------|------|--------|----|----| | 工具 spawn_session | spawn_session({ prompt, title?, agent?, directory?, model?, select? }) | 模型自主调用 | ✅ | ✅ | | 工具 notify_parent | notify_parent({ text }) | 子会话模型自主调用 | ✅ | ✅ | | 工具 notify_session | notify_session({ sessionID, text, prefix?, agent? }) | 父 / 任意会话模型自主调用 | ✅ | ✅ | | 工具 list_sessions | list_sessions({ parentSessionID?, recursive?, directory? }) | 模型自主调用(只读发现派生会话 id) | ✅ | ❌(平台缺口,不注册) | | 文本命令 | @spawn [--agent <名称>] [--title <标题>] [--no-select] <起始语句>(兼容 @relay spawn) | 人工触发 | ✅ | ❌ | | 注册命令 | /spawn [--agent <名称>] [--title <标题>] [--no-select] <起始语句> | 人工触发 | — | ✅ |

参数 / 行为:

  • prompt(必填):注入新会话的起始语句。可内含读取文件、复述要点、执行下一步等引导。
  • title(可选):新会话标题。缺省取 prompt 首行(清洗非法字符、截断 60)。
  • agent(可选,工具参数):新会话以某 agent/模式启动(如 leader)。仅在传了非空白值时透传,交服务端校验。V1 为注入时单条消息模式;V2 为注入前调用 ctx.session.switchAgent(会话级)。
  • directory(可选,工具参数):新会话绑定的项目目录(如 D:\dev\bbcare)。仅在传了非空白值时透传,交服务端校验。
  • model(可选,工具参数):新会话使用的模型,格式 provider/model(如 deepseek/deepseek-v4-flash、opencode/big-pickle),透传为 { providerID, id };空 / 无 / 视为未传,缺省由服务端默认。
  • select(可选,工具参数,默认 true):仅 V1。创建后让 UI 选中新会话——优先 client.tui.selectSession({ sessionID }),缺失则回退 client.tui.publish({ type: "tui.session.select", properties: { sessionID } });失败 / 不可用仅记录,不影响创建与注入。TUI 即时生效;桌面端 app 尚未消费该事件(上游 issue #45963),当前为 no-op,接线后自动打开/切换到该会话 tab。命令 --no-select 可关闭。V2 无对应 API,参数保留仅为对齐(恒不自动选中)。
  • 父链接(自动,非参数):spawn_session 把调用者会话 id 写入新会话 metadata.spawnParentID(context.sessionID 非空白时)。不写 parentID——桌面端会话列表只拉取顶层会话,写 parentID 会让新会话变成「子会话」而从列表消失(v2.2.0 的可见性回归);metadata 不影响列表。命令入口(@spawn / /spawn)无父链接(人工语义,与 v2.5.0 一致)。
  • 命令 flag 说明:--agent / --title 值均为单个 token(不处理引号/空格);--no-select 为布尔开关;仅解析命令后前导 flag,起始语句内部再出现的 --xxx 原样保留;flag 缺值或起始语句为空 → V1 warning toast / V2 synthetic 注记,且不建会话。--title 优先于起始语句首行。
  • 内部调用(spawn):createSession →(V1 可选 select)→ inject;agent / directory / model / metadata 未传时不出现对应键。V1 优先 promptAsync(异步 fire-and-forget,不阻塞父会话),缺失则回退同步 prompt;V2 用 ctx.session.prompt(服务端 inbox 承接,同样不阻塞)。
  • notify_parent 行为:仅能通知父会话(不提供任意 session id 参数);读取自身 metadata.spawnParentID(旧会话回退 parentID)后,向父会话注入 [relay] <text> 并唤醒它;父会话以服务端默认模式(build)被唤醒;空文本 / 无父会话 / 读取或注入失败 → 返回错误文本(不抛);无重试 / 队列 / 追踪(保持无状态原语)。
  • notify_session 行为:向指定会话注入一条消息并唤醒它,与 notify_parent 相对(父 / 任意会话 → 指定会话)。先校验目标存在,再向其注入文本并唤醒;prefix: false 关闭 [relay] 前缀(默认加),可选 agent 指定唤醒模式(V1 单条消息模式 / V2 会话级切换)。空 sessionID / 空 text / 目标=自身 / 目标不存在 / 读取或注入失败 → 返回错误文本(不抛),一律不注入。默认允许任意 sessionID(用户明确要求「任意」):可向非派生会话注入,误用可能致互喷 / 环路——请仅对自己已知 / 派生的会话使用,收到通知后按需行动、勿自动回发。
  • list_sessions 行为(仅 V1):只读列举会话。数据来自 SDK client.session.list({ query: { directory? } })(不查 opencode.db、不落状态文件);按 metadata.spawnParentID 过滤(不用 session.children——它走真 parentID,而本插件故意不写 parentID)。parentSessionID 缺省 = 当前会话;recursive: false(默认)只列直接子会话,true 沿 spawnParentID BFS 列全部传递后代(visited 去重防环)。返回紧凑表格文本(每行 id | title | directory | parent | updated),无匹配 → 无匹配会话。旧客户端 list 不带 metadata 时,逐个 session.get 回退读取(N+1,会话量小可接受)。V2 不注册该工具(V2 插件域无 session.list),请用内置会话列表/搜索。
  • create 失败 → 不建会话;create 成功但注入失败 → 保留已建会话并提示 id,不产生重复会话。

安装(部署到桌面版)

方式 A:npm 包注册(推荐,自动更新)

V1 配置(plugin 单数数组):

{
  "plugin": ["opencode-session-spawn"]
}

V2 配置(plugins 复数数组;字符串或 { "package": "..." } 对象):

{
  "plugins": ["opencode-session-spawn"]
}

opencode 启动时自动把最新发布安装到包缓存(~/.cache/opencode/packages/opencode-session-spawn/),重启桌面版生效。发布新版本后重启即自动更新;若缓存未刷新,删除 ~/.cache/opencode/packages/opencode-session-spawn@latest 后重启强制重装。

方式 B:本地目录注册(开发用)

file:///绝对路径 指向本仓库目录(含 package.json):

// V1
{ "plugin": ["file:///E:/dev/fun-projs/opencode-session-spawn"] }
// V2(本地插件目标必须是目录;opencode 1.19.x/2.x 均支持)
{ "plugins": ["file:///E:/dev/fun-projs/opencode-session-spawn"] }

开发与生产验证统一走 test/test.mjs + RELAY_MAIN(见下节)。本地文件形态(单个 .mjs)在 V2 会被拒绝:configured plugin path must be a directory。

编排示例

模型在长任务中决定交接,直接调用工具(可选 agent / directory):

spawn_session({
  prompt: `你是本任务的接手会话。先读取交接文书:
E:\\proj\\handoff\\migration-3.md
通读后复述要点(已完成/未完成/下一步第 1 件事),确认后继续执行。`,
  title: "[迁移] 第 3 棒",
  agent: "leader",
  directory: "D:\\dev\\bbcare"
})

或人工在会话里发(V1;前导 flag 可省略、顺序不限):

@spawn --agent leader --title "[P1-10] sprint" 读取 handoff/migration-3.md 后继续迁移任务

V2 用注册型命令(同样支持 --agent / --title / --no-select):

/spawn --agent leader --title "[P1-10] sprint" 读取 handoff/migration-3.md 后继续迁移任务

父子回复约定(防环路):父会话在起始语句里要求「子会话收尾 / 受阻时调用 notify_parent」;子会话执行:

notify_parent({ text: "P1-10 已完成,验收报告见 runs/P1-10-acceptance.md" })

父会话会收到一条 [relay] … 消息并以服务端默认模式被唤醒;收到通知后按需行动,不要自动回发通知(notify_parent 只向父会话发送,避免环路)。

父会话向指定(可能由中间会话间接派生的)会话投递纠偏 / 叫停:

list_sessions({ recursive: true })   // V1:找回派生会话 id(默认只列直接子会话;recursive 含全部传递后代)
notify_session({ sessionID: "ses_xxx", text: "停止当前分支并汇报进度" })
notify_session({ sessionID: "ses_yyy", text: "仅执行下列修正:…", prefix: false })

list_sessions 只读、走 SDK(不查数据库),按 metadata.spawnParentID 发现会话(V1 专属);notify_session 目标须已存在,默认加 [relay] 前缀(prefix: false 关闭),亦可带 agent 指定唤醒模式。

开发与测试

npm install          # 安装 devDependency @opencode-ai/plugin(仅 V1 工具注册用;V2 路径懒加载该依赖)
node test/test.mjs   # 211 断言(A–M 分组:V1 行为 A–K + 双模契约 L + V2 setup M)
  • test/test.mjs 默认经相对路径 ../index.js 测项目版;环境变量 RELAY_MAIN 覆盖为其他路径(tarball 解包版 / 包缓存活实例)。RELAY_MAIN 目标须能向上解析到 @opencode-ai/plugin(解包放项目内即可)。
  • 以尾部 ==== 结果: N 通过, 0 失败 ==== 为准。
  • V2 行为由 mock ctx(tool/command transform 编辑器 + session.create/get/prompt/synthetic/switchAgent 假实现)驱动 default.setup() 断言。

发布

bump 版本号(package.json 与 index.js 头注释同步)→ node test/test.mjs 全绿 → npm pack 解包核对哈希 + RELAY_MAIN 回归全绿 → commit → push → npm publish(不打 git tag;先 npm whoami 确认登录态,凭据不入库)→ 重启桌面版实测 @spawn(V1)/ spawn_session / /spawn(V2);实测不过修复补丁重发。详见 AGENTS.md。

历史

前身 opencode-session-relay 的接力链、两阶段交接文书、空闲事件驱动、哨兵兜底、@relay status/leave/refresh/verify 等机制已全部移除,仅保留「建会话 + 注入语句」这一核心原语。

  • v2.6.0(2026-10-17):V1+V2 双模兼容(同一分支、同一 npm 包)。default 导出改为 { id, setup, server }:V2 宿主走 setup(ctx)(注册 3 工具 + 注册型命令 /spawn;@opencode-ai/plugin 懒加载解耦);V1 宿主走 server(input, options)(行为与 2.5.0 完全一致:4 工具 + @spawn)。V2 平台缺口显式降级:无自动选中、无 toast(命令以 synthetic(resume:false) 注记)、无 list_sessions、不做 @spawn 文本兼容(实测 prompt hook 无干净取消 API)。opencode 1.19.x 过渡版同时调 server/setup,已做能力探测防冲突。
  • v2.5.0(2026-10-14):新增工具 notify_session(向任意指定 sessionID 注入 [relay] 消息并唤醒;prefix / agent 可选;先校验目标存在;默认允许任意会话)与 list_sessions(只读、走 SDK client.session.list、按 metadata.spawnParentID 发现直接 / 传递派生的会话,不查数据库)。用于「父 / 任意会话 → 指定会话」的纠偏 / 叫停通道与会话发现(填补 notify_parent 只能上行、task 操作不了 spawn_session 顶层会话的缺口)。
  • v2.4.0(2026-09-15):创建后默认让 UI 选中新会话(client.tui.selectSession,回退 tui.publish 事件;select: false / @spawn --no-select 关闭)。TUI 即时生效;桌面端 app 尚未消费 tui.session.select(上游 issue #45963),当前为 no-op,接线后自动开 tab。
  • v2.3.0(2026-09-15):父链接由 parentID 改为 metadata.spawnParentID(修复 v2.2.0 可见性回归:写 parentID 会让新会话变成子会话、从桌面端会话列表消失;且子会话默认不能再开 task 子代理,会破坏编排);notify_parent 兼容旧会话的 parentID 回退;新增可选 model 参数(provider/model)。
  • v2.2.0:新增 notify_parent 反向通知;spawn_session 自动挂 parentID。
  • v2.1.0:spawn_session 支持 agent / directory;命令 @spawn 支持 --agent / --title。