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

@zhin.js/adapter-sandbox

v1.1.17

Published

Zhin.js Sandbox adapter for Plugin Runtime (WebSocket /sandbox)

Downloads

3,601

Readme

@zhin.js/adapter-sandbox

Zhin.js Sandbox 适配器,基于 WebSocket 的本地测试适配器;浏览器端聊天 UI 在 Remote Console(Host 仅 Console API)中打开 Sandbox 窗口调试。

功能特性

  • Node Host:WebSocket /sandbox
  • 浏览器端 React 聊天 UI
  • 支持多客户端同时连接
  • 无需第三方平台账号,即开即用
  • 适合本地开发和插件调试

安装

pnpm add @zhin.js/adapter-sandbox

前置条件

Sandbox 不需要外部账号。只需由 zhin runtime start 装配 HTTP Host,并确保浏览器能访问启动日志中的 Host 地址。

依赖

Plugin Runtime(新,zhin runtime start)

  • @zhin.js/adapter — 约定式 adapters/sandbox/index.ts
  • @zhin.js/host-http — Root 提供的 httpHostToken(WebSocket /sandbox + Console HTTP)
  • @zhin.js/core — Endpoint.emit(...) 入站、outboundMessageToken 出站
  • @zhin.js/page + pages/index/index.tsx — ADR 0046 约定页(definePage;路由 /sandbox)

Root 在 zhin runtime start 时装载 @zhin.js/host-http、ConsoleRuntime 与 ClientBuildModuleRuntime。打开 http://<host>:<port>/console 可浏览页面;Sandbox 页 (路由 /sandbox,与 WebSocket /sandbox 同 path:GET 开页、Upgrade 走 WS)内置聊天壳。

旧 client/(register(api) / pageManager.addEntry)仅保留给 legacy Host 栈参考, 不是 Plugin Runtime 生产入口。

旧 Host 栈(已删除)

原 legacy 插件包 @zhin.js/host-router(HTTP 服务)与 @zhin.js/host-api(Host 侧 Console API,addEntry 注册 Sandbox 扩展)已删除;zhin dev 现由 @zhin.js/cli 自动装配 Console/HTTP Host(@zhin.js/host-http + @zhin.js/pagemanager),无需安装任何 Host 插件。

  • @zhin.js/client — Remote Console 客户端 SDK(UI 在 zhin-console 仓库)

出站 wire 只做 JSON 封装;旧 segment-mapper(canonical segments)归一化上移到 gateway/core 渲染链。

Sandbox 声明 html: direct,聊天页在隔离 iframe 中展示 canonical html,因此 JSX 卡片无需截图引擎即可预览。允许内联样式和 data/blob 图片;组件脚本、事件属性、外部资源、表单提交和父页面访问均被限制。高度按内容调整,超过 1200px 可在框内滚动。

配置

推荐(与 minimal-bot 一致):sandbox.endpoints: [],运行时提供默认 sandbox-bot endpoint,无需额外账号配置。

configVersion: 2
# zhin.config.yml(Plugin Runtime)
plugins:
  sandbox: "@zhin.js/adapter-sandbox"
sandbox:
  endpoints: []

可选:若需在启动时即在 bot 列表显示固定名称的离线占位 bot,可显式配置:

configVersion: 2
plugins:
  sandbox: "@zhin.js/adapter-sandbox"
sandbox:
  endpoints:
    - id: sandbox-bot
      owner: sandbox-user

使用方式

  1. 启动 Zhin 实例:pnpm dev(终端会打印 Host 地址,一般为 http://127.0.0.1:8086)
  2. 打开 Remote Console,API Base 与 Host 地址一致,Token 与 http.token / HTTP_TOKEN 一致
  3. 在 Console 沙盒 页连接后发送消息进行测试

浏览器客户端连接到默认 sandbox-bot,也可以通过多个显式 endpoint 使用不同 WebSocket 路径。

每个 endpoint 通过 Root 提供的 HTTP Host(httpHostToken)挂载一个 WebSocket 路径,协议见下文「消息格式(wire 协议)」。

消息格式(wire 协议)

Console 沙盒页和自己写的测试客户端都用这套协议。每个 WebSocket 文本帧是一个 UTF-8 JSON 对象。

连接

  • 地址:ws://<host>:<port>/sandbox。同一个 HTTP Host 上的第一个 Sandbox endpoint 挂在 /sandbox,其余 endpoint 挂在 /sandbox/<endpoint id>(重名时依次加 -2、-3),启动日志会打印 ws mounted <path>。
  • 鉴权:Host 配置了 token 时,握手请求需带 Authorization: Bearer <token> 或查询参数 ?token=<token>,否则返回 401。demo 权限的 token 只能连 /sandbox,而且是只读的:消息会被接收,但不会进入命令和 Agent,服务端回一条 type: "error"。
  • 单连接:endpoint 使用固定名称(默认),同一 endpoint 只保留最新的浏览器连接。新连接接入时,旧连接以关闭码 4000(replaced by new sandbox client)断开;endpoint 停止时以 1001 断开;插件热重载使当前 generation 退役时,Host 以 1012 断开,客户端重连即可。

客户端 → 服务端:发送消息

{
  "type": "group",
  "id": "test-group",
  "content": [{ "type": "text", "data": { "text": "/hello" } }],
  "messageId": "client-msg-001",
  "timestamp": 1700000000000
}

| 字段 | 类型 | 说明 | | --- | --- | --- | | type | private | group | channel | direct | guild | 会话类型,默认 private。direct 按 private 处理,guild 按 channel 处理 | | id | string | 会话 id,默认使用 endpoint 的 owner(默认 sandbox-user) | | content | string 或消息段数组 | 消息段格式为 { "type": string, "data": object };字符串等同于一个 text 段 | | text | string | 可选。没有 content 时作为纯文本;content 里没有文本段时也用它作为消息文本 | | messageId | string | 可选。客户端生成的消息 id,须匹配 ^[A-Za-z0-9._:-]{1,160}$,不匹配时忽略;填写后作为这条入站消息的 id,引用回复时可据此定位 | | timestamp | number | 可选。毫秒时间戳,默认取服务端收到的时间 | | agentRun | object | 可选。Agent 试验台运行配置,见下表 |

  • 帧内容不是 JSON 时,整段文本按一条纯文本消息处理。
  • 消息的发送者固定为 endpoint 的 owner。
  • 按钮回传:content 中的 { "type": "action", "data": { "id": "...", "payload": "..." } } 段会作为交互动作交给命令或 Agent;只填 id 或 payload 时,另一个取相同的值。消息里没有文本时,payload 作为消息文本。

agentRun 字段:

| 字段 | 取值 | 默认 | | --- | --- | --- | | workingDirectory | string,最长 4096 字符 | "" | | safetyMode | read-only | workspace-write | danger-full-access | workspace-write | | approvalMode | ask | auto | bypass | ask | | networkAccess | boolean | false;safetyMode 为 danger-full-access 时恒为 true |

无法识别的取值按默认值处理。

服务端 → 客户端

连接就绪:每次连接成功后发送一次。

{
  "type": "ready",
  "id": "sandbox-user",
  "endpoint": "sandbox-bot",
  "workingDirectory": "/path/to/bot",
  "canExecute": true,
  "shellIsolation": { "available": false, "provider": "docker", "message": "Docker daemon is unavailable" },
  "content": [{ "type": "text", "data": { "text": "已连接 Sandbox「sandbox-bot」…" } }],
  "timestamp": 1700000000000
}

canExecute 表示当前连接是否为 full 权限(能运行命令和 Agent 任务);shellIsolation 是 Docker 隔离环境的探测结果,仅供展示。

回复消息:

{
  "type": "group",
  "id": "test-group",
  "bot": "sandbox-bot",
  "endpoint": "sandbox-bot",
  "content": [{ "type": "text", "data": { "text": "Hello!" } }],
  "timestamp": 1700000000001
}
  • type / id 是回复所在的会话(direct 已归一为 private,guild 已归一为 channel),客户端按这两个字段把消息放进对应会话;bot 是 endpoint id,endpoint 是收到消息的连接名。
  • content 是消息段数组。文本、html(JSX 卡片,见上文 html: direct)、按钮等段原样透传。
  • image / audio / video / file 段只读 data.media(MediaRef):url 原样透传;base64 补上 base64:// 前缀后内联;path 由服务端读取文件后转成 base64 内联;其他类型和缺少 data.media 的媒体段会被丢弃,并在日志中记录 sandbox_outbound_media_dropped。
  • 插件直接发送完整消息对象时,其他字段会原样保留。

只读连接的提示:demo 权限的连接发送消息后,服务端回复:

{
  "type": "error",
  "id": "sandbox-user",
  "endpoint": "sandbox-bot",
  "content": [{ "type": "text", "data": { "text": "当前连接是只读演示权限,不能运行 Agent 任务。" } }],
  "timestamp": 1700000000000
}

适用场景

  • 本地开发调试插件逻辑
  • 测试命令和 AI 工具调用
  • 不依赖外部平台的功能验证

AI 工具

技能说明见 skills/sandbox/SKILL.md(本地沙箱调试约束)。

故障排查

| 现象 | 排查 | | --- | --- | | Console 无法连接 | 以启动日志中的 Host、端口和 token 为准 | | Sandbox 页面空白 | 检查 HTTP Host 是否因端口占用软降级,以及鉴权/CORS 错误 | | 刷新后没有历史消息 | 核对 Endpoint 与频道,并检查 history RPC 与 recovery gap 日志 | | 命令或工具未生效 | 在运行时能力页确认它已进入当前 generation |

许可证

MIT License