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

@preprocess-cn/nano-code-web

v0.1.7

Published

Web-based display plugin for nano-code

Downloads

826

Readme

nano-code-web

nano-code 的 Web 显示插件(v0.1.3)。通过 SSE(Server-Sent Events)将 nano-code 的 DisplayPlugin 事件推送到浏览器前端,提供图形化交互界面。

Architecture

nano-code 核心 → DisplayPlugin 事件 → display.ts → SSE → public/index.html

三层结构:

  1. src/server.tsNanoCodeWebServer: HTTP + SSE 服务器

    • GET /events — SSE 端点,推送实时事件
    • POST /input — 接收用户输入
    • POST /cancel — 取消当前请求
    • POST /confirm — 处理前端授权确认(Allow/Deny)
    • POST /question-answer — 处理前端问询对话框答案提交
    • POST /mode-toggle — 切换 plan/normal 模式(Shift+Tab)
    • GET / — 前端页面(先查找 public/dist/ 下同路径文件,存在即返回,否则返回 index.html
    • GET /vendor/* — 第三方 JS/CSS 库
    • GET /health — 健康检查
    • GET /web-files/* — 临时文件服务
  2. src/display.ts — DisplayPlugin 实现

    • 将 nano-code 的 onStart/onStreamChunk/onToolCall/onStatus 等事件广播为 SSE
    • 通过 NanoPlugin onBeforeToolCall/onAfterToolCall 追踪工具调用 ID
  3. public/index.html + public/app.js + public/dialog.js + public/style.css — 单页前端(v0.1.2 将 CSS/JS 从内联提取为独立文件)

    • 思考内容独立样式.msg.think)— 灰色斜体、左侧淡灰边框,视觉区分思考过程与回答
    • 调试消息独立样式.msg.debug)— 等宽字体、虚线边框,与系统消息样式分离
    • Markdown 渲染(markdown-it + highlight.js 语法高亮 + DOMPurify 安全消毒)
    • 流式输出优化:debounce(150ms)+ 代码块闭合检测(``` 成对时立即渲染)
    • 工具卡片点击展开/收拢(参数 + 返回结果)
    • 问询对话框(dialog.js 模块,三屏:选择 → 自定义输入 → 确认,Esc 取消)
    • 后台任务状态条(background:task 事件驱动,自动消隐)
    • Plan mode 指示器(● PLAN/○ normal,Shift+Tab 切换)
    • 状态栏(status:bar 事件驱动,显示 mode/tasks 等段落)
    • 浮动 Toast 通知(右上角,自动消失,支持堆叠与点击关闭)
    • 纯 vanilla JS,无框架依赖;第三方库(markdown-it、DOMPurify、highlight.js)通过构建脚本复制到 dist/vendor/ 本地加载,无需 CDN

Quick Start

构建

npm install
npm run build

构建输出 dist/display.js + dist/index.html + dist/app.js + dist/dialog.js + dist/style.css + dist/vendor/(markdown-it、DOMPurify、highlight.js 运行时库)。

配置 nano-code

.nano-code.yaml 中配置:

display:
  plugin: ./dist/display.js

启动

nano-code

终端会显示 Web UI 地址(默认 http://localhost:3030)。启动时可配合以下参数:

nano-code --think    # 显示思考过程
nano-code --debug    # 显示调试信息

配置选项

nano-code 通过 session:start 事件的 config 对象传递配置:

| 字段 | 类型 | 说明 | |------|------|------| | showThink | boolean | 是否显示 <think>...</think> 内容 | | debug | boolean | 是否显示调试事件 | | greeting | string | 会话欢迎语 | | hasTools | boolean | 是否有可用工具 |

多标签页同步

多个浏览器标签页连接同一后端时,所有页面的消息和状态保持同步:

  • 消息同步user:inputstream:chunk 等事件通过 broadcast() 发送给所有连接的 SSE 客户端
  • Plan mode 同步:切换 mode 时广播 status:bar 事件给所有在线客户端;新客户端连入时查询后端当前 mode 并直接推送
  • 广播健壮性broadcast() 使用倒序遍历 + try-catch 保护,单个客户端写失败不影响其他客户端,失效客户端自动移除

事件流

| SSE 事件 | 方向 | 说明 | |----------|------|------| | session:start | 后端 → 前端 | 新会话开始,包含配置 | | session:ready | 后端 → 前端 | 等待用户输入 | | session:stop | 后端 → 前端 | 会话结束 | | stream:chunk | 后端 → 前端 | LLM 文本输出流;showThink=true 时前端解析 <think> 标签并分离为独立样式 | | tool:call | 后端 → 前端 | 工具调用(显示工具卡片) | | tool:result | 后端 → 前端 | 工具调用结果(更新卡片状态) | | status | 后端 → 前端 | 状态更新(thinking/end/信息) | | error | 后端 → 前端 | 错误信息 | | debug | 后端 → 前端 | 调试信息(.msg.debug 等宽虚线边框样式) | | agent:turn_start | 后端 → 前端 | Agent 轮次开始 | | agent:turn_end | 后端 → 前端 | Agent 轮次结束 | | confirmation:request | 后端 → 前端 | 授权确认请求(Allow/Deny) | | question:dialog | 后端 → 前端 | 问询对话框(LLM 向用户提问) | | notify | 后端 → 前端 | 通知消息(浮动 Toast) | | notify:clear | 后端 → 前端 | 清除所有通知 | | background:task | 后端 → 前端 | 后台任务状态(started/completed/error) | | status:bar | 后端 → 前端 | 状态栏段落(mode/tasks 等) | | user:input | 后端 → 前端 | 用户输入(全局广播,用于历史重放) | | cancel | 前端 → 后端 | 取消请求(HTTP POST) | | confirm | 前端 → 后端 | 授权确认结果(HTTP POST) | | question-answer | 前端 → 后端 | 问询对话框答案提交(HTTP POST) | | mode-toggle | 前端 → 后端 | Plan mode 切换(HTTP POST) |

关键实现细节

前端重连与历史消息

前端断开后重新打开时,后端会将已广播的历史事件(stream:chunkuser:inputtool:call/resultstatusagent:turn_start/enderror)通过 onConnect 回调重新发送给新客户端。缓冲区上限 500 条,/clear 或新 session 时自动清空。

配合 nano-code 的 --continue / -c 标志使用时,restoreSession() 会通过 DisplayPlugin 回放已保存的对话消息,nano-code-web 将其广播为 SSE 事件并同时写入历史缓冲区,前端刷新后仍可看到历史。

广播容错

broadcast() 使用倒序遍历 + try-catch:

  • 单个客户端写失败(连接已关闭但尚未清理)不会阻塞其他客户端
  • 失效客户端自动从广播列表移除

工具调用双向广播

工具调用事件有两条路径到达 SSE:

  • NanoPlugin 路径onBeforeToolCall/onAfterToolCall):使用 OpenAI 格式(toolCall.function.nametoolCall.id),是工具卡片的主要来源
  • DisplayPlugin 路径onToolCall/onToolResult):DisplayPlugin 标准事件路径,作为 NanoPlugin 的补充

ToolCallBroadcaster 通过 ID 去重,确保同一工具调用只广播一次。

前端渲染

  • 消息气泡使用 white-space: pre-wrap 保留换行和空白
  • 工具卡片使用 flex-shrink: 0 避免在长对话滚动后被 flex 布局压缩
  • stream:chunk 遇到纯空白块时不创建新气泡(避免工具卡片旁的空白气泡)

开发

npm run dev    # tsc --watch 增量编译
npm test       # 运行所有测试(70 用例)

测试

# 全部测试(单元测试 + 前端集成测试)
npm test

# Playwright 前端集成测试
npx tsx --test tests/frontend.test.ts

# 工具卡片滚动高度测试
npx tsx --test tests/tool-card-scroll.test.ts

测试覆盖:

  • tests/display.test.ts — ThinkFilter(12 用例)+ ToolCallBroadcaster(12 用例,含历史回调)+ 环形缓冲区(9 用例)+ SSE 重放(4 用例)+ background:task(2 用例)+ question:dialog(1 用例)
  • tests/server.test.ts — NanoCodeWebServer(20 用例,含 question-answer / mode-toggle)
  • tests/frontend.test.ts — Playwright 前端渲染(9 用例)
  • tests/tool-card-scroll.test.ts — Playwright 滚动高度(1 用例)

项目文件结构

├── src/
│   ├── display.ts       # DisplayPlugin 实现(ThinkFilter、ToolCallBroadcaster、ask_user_question handler)
│   ├── server.ts        # HTTP/SSE 服务器
│   └── tool-display.ts  # 工具名/参数格式化
├── public/
│   ├── index.html       # 前端页面骨架
│   ├── app.js           # 前端主逻辑(消息渲染、事件处理)
│   ├── dialog.js        # 问询对话框模块(三屏:选择→输入→确认)
│   └── style.css        # 前端样式表
├── scripts/
│   └── copy-vendor.mjs  # 构建时将 markdown-it/DOMPurify/highlight.js 复制到 dist/vendor/
├── tests/
│   ├── display.test.ts
│   ├── server.test.ts
│   ├── frontend.test.ts
│   └── tool-card-scroll.test.ts
├── dist/             # 构建输出(含 vendor/ 第三方库)
├── vendor/           # highlight.js CDN 缓存(可选,构建时自动下载)
├── .nano-code.yaml   # nano-code 插件配置
├── README.md
└── ROADMAP.md

License

MIT