Superpowers 可视化头脑风暴伴侣:从实施计划到零依赖本地服务器的完整实现解析
【免费下载链接】superpowersAn agentic skills framework & software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers
本文以 Superpowers 仓库中的实施计划 2026-01-17-visual-brainstorming.md 为主线,解析"可视化头脑风暴伴侣"(Visual Brainstorming Companion)的设计目标、架构与任务拆解:一个本地 Node.js 服务器监视 HTML 文件变更并向浏览器推送界面,用户的点击、表单与输入通过 WebSocket 回流到服务器标准输出,供 Claude(或其他编码 Agent)在下一轮对话中读取。读完本文,你将掌握该功能的完整数据流、服务端与客户端关键代码、测试验证方式,以及当前仓库中该方案演进的零依赖实现细节。
目标与总体架构
计划文档开篇明确了三个核心要素:
- Goal:为 Claude 的头脑风暴会话提供一个基于浏览器的视觉伴侣——在终端对话旁边展示 mockup、原型和交互式选项;
- Architecture:Claude 把 HTML 写入临时文件,一个本地 Node.js 服务器监视该文件并附带自动注入的 helper 库提供服务;用户的交互通过 WebSocket 流向服务器 stdout,Claude 在后台任务输出中看到这些事件;
- Tech Stack:Node.js、Express、ws(WebSocket)、chokidar(文件监视)。
用数据流描述就是:
Agent 写 HTML 文件 ──> chokidar 检测到变更 ──> 向所有浏览器推送 reload 浏览器展示最新 HTML(helper.js 已注入) 用户点击/提交/输入 ──> helper.js 自动捕获 ──> WebSocket ──> 服务器 stdout 输出 JSON 事件 Agent 读取后台任务输出 ──> 获得结构化的用户反馈终端始终是主对话界面,浏览器只是视觉辅助("The terminal remains the primary conversation interface. The browser is a visual aid.")。
Task 1:服务器基础(Server Foundation)
计划中的第一个任务创建lib/brainstorm-server/(含package.json与index.js)。package.json声明了三个依赖:
{ "name": "brainstorm-server", "version": "1.0.0", "description": "Visual brainstorming companion server for Claude Code", "main": "index.js", "dependencies": { "chokidar": "^3.5.3", "express": "^4.18.2", "ws": "^8.14.2" } }最小可运行的index.js实现了五件关键事情,每一处都值得展开:
1. 环境变量驱动的端口与屏幕文件
const PORT = process.env.BRAINSTORM_PORT || 3333; const SCREEN_FILE = process.env.BRAINSTORM_SCREEN || '/tmp/brainstorm/screen.html'; const SCREEN_DIR = path.dirname(SCREEN_FILE);端口默认 3333,被监视的屏幕文件默认/tmp/brainstorm/screen.html。服务器启动时会自动创建目录并写入一个"等待中"默认页面("Waiting for Claude to push a screen...")。
2. WebSocket 客户端集合与事件转发
const clients = new Set(); wss.on('connection', (ws) => { clients.add(ws); ws.on('close', () => clients.delete(ws)); ws.on('message', (data) => { // User interaction event - write to stdout for Claude const event = JSON.parse(data.toString()); console.log(JSON.stringify({ type: 'user-event', ...event })); }); });注意事件被包裹为{ type: 'user-event', ...event }后写到 stdout——这是 Agent 消费用户反馈的唯一通道。
3. 页面路由与 helper 注入
app.get('/', (req, res) => { let html = fs.readFileSync(SCREEN_FILE, 'utf-8'); const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8'); const injection = `<script>\n${helperScript}\n</script>`; if (html.includes('</body>')) { html = html.replace('</body>', `${injection}\n</body>`); } else { html += injection; } res.type('html').send(html); });每次请求都重新读取屏幕文件并在</body>前注入 helper 脚本——Agent 无需在 HTML 中写任何交互代码。
4. 文件变更监视与浏览器刷新
chokidar.watch(SCREEN_FILE).on('change', () => { console.log(JSON.stringify({ type: 'screen-updated', file: SCREEN_FILE })); clients.forEach(ws => { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'reload' })); } }); });5. 绑定回环地址并输出结构化启动信息
server.listen(PORT, '127.0.0.1', () => { console.log(JSON.stringify({ type: 'server-started', port: PORT, url: `http://localhost:${PORT}` })); });服务器只绑定127.0.0.1,所有 stdout 输出都是单行 JSON(server-started/screen-updated/user-event),让 Agent 可以可靠地解析。计划要求运行cd lib/brainstorm-server && npm install安装依赖,再用timeout 3 node index.js验证能收到server-startedJSON。
Task 2:浏览器 Helper 库(自动事件捕获)
helper.js是一个自执行 IIFE,服务器注入后它完成了三件事:建立 WebSocket 连接、自动捕获用户交互、暴露显式 API。
连接与断线重连
(function() { const WS_URL = 'ws://' + window.location.host; let ws = null; let eventQueue = []; function connect() { ws = new WebSocket(WS_URL); ws.onopen = () => { // Send any queued events eventQueue.forEach(e => ws.send(JSON.stringify(e))); eventQueue = []; }; ws.onmessage = (msg) => { const data = JSON.parse(msg.data); if (data.type === 'reload') { window.location.reload(); } }; ws.onclose = () => { // Reconnect after 1 second setTimeout(connect, 1000); }; } // ...要点:收到reload消息即整页刷新;断线 1 秒后自动重连;连接未就绪时事件进入eventQueue,重连后补发——保证用户交互不因瞬时断连丢失。
三类自动捕获
// Auto-capture clicks on interactive elements document.addEventListener('click', (e) => { const target = e.target.closest('button, a, [data-choice], [role="button"], input[type="submit"]'); if (!target) return; // Don't capture regular link navigation if (target.tagName === 'A' && !target.dataset.choice) return; e.preventDefault(); send({ type: 'click', text: target.textContent.trim(), choice: target.dataset.choice || null, id: target.id || null, className: target.className || null }); });点击捕获用事件委托 +closest()匹配button, a, [data-choice], [role="button"], input[type="submit"];普通链接导航被排除,命中目标则preventDefault()后发送click事件,其中data-choice是"选项标识符"约定。
表单提交捕获:
document.addEventListener('submit', (e) => { e.preventDefault(); const form = e.target; const formData = new FormData(form); const data = {}; formData.forEach((value, key) => { data[key] = value; }); send({ type: 'submit', formId: form.id || null, formName: form.name || null, data: data }); });输入变更捕获带 500ms 防抖:
let inputTimeout = null; document.addEventListener('input', (e) => { const target = e.target; if (!target.matches('input, textarea, select')) return; clearTimeout(inputTimeout); inputTimeout = setTimeout(() => { send({ type: 'input', name: target.name || null, id: target.id || null, value: target.value, inputType: target.type || target.tagName.toLowerCase() }); }, 500); // 500ms debounce });显式 API
window.brainstorm = { send: send, choice: (value, metadata = {}) => send({ type: 'choice', value, ...metadata }) };除了全自动捕获,页面作者也可以显式调用brainstorm.send(...)或brainstorm.choice('custom', {extra: 'data'})发送任意结构化事件。计划要求用node -c lib/brainstorm-server/helper.js校验语法后提交。
Task 3:集成测试
计划为服务器编写位于tests/brainstorm-server/server.test.js的集成测试,思路是:用child_process.spawn拉起真实服务器(BRAINSTORM_PORT=3334、BRAINSTORM_SCREEN=/tmp/brainstorm-test/screen.html),采集其 stdout,然后依次断言:
- 启动消息:stdout 包含
server-started与端口号; - HTML 服务与注入:
GET /返回 200,body 含brainstorm内容且注入了 helper(body 中出现WebSocket字样); - 事件中继:通过真实 WebSocket 客户端发送
{ type: 'click', text: 'Test Button' },断言 stdout 出现user-event与Test Button; - 文件变更通知:修改屏幕文件后,断言第二个 WebSocket 客户端收到
{ type: 'reload' }消息。
测试用自写的fetch封装(基于http.get)、sleep与cleanup()(删除测试目录)辅助,finally块中server.kill()并清理,失败时process.exit(1)。运行方式:cd tests/brainstorm-server && npm install ws && node server.test.js。
当前仓库中该目录已扩展为更完整的测试套件,除server.test.js外还有 auth.test.js、lifecycle.test.js、ws-protocol.test.js、branding.test.js、helper.test.js 以及 start/stop 脚本的 shell 测试——可见测试面从"服务器基本行为"扩展到了认证、生命周期与 WebSocket 协议层。
Task 4:接入 Brainstorming Skill
计划将可视化伴侣作为 brainstorming skill 的可选能力:
- 新建
skills/brainstorming/visual-companion.md参考文档,覆盖启动服务器、推送屏幕、读取用户响应三类操作; - 在 SKILL.md 的 "Key Principles" 之后追加 "Visual Companion (Optional)" 小节,给出适用场景(UI/UX 选项对比、线框图、结构化反馈、点击原型)与四步用法。
计划文档中给出的参考文档草案包含以下关键内容,都值得完整保留:
启动服务器(作为后台任务):
node ${PLUGIN_ROOT}/lib/brainstorm-server/index.js然后告知用户:"I've started a visual companion at http://localhost:3333 - open it in a browser."
推送屏幕:把 HTML 写入/tmp/brainstorm/screen.html,服务器监视该文件并自动刷新浏览器。
读取用户响应:在后台任务输出中检查 JSON 事件,例如:
{"type":"user-event","type":"click","text":"Option A","choice":"optionA","timestamp":1234567890} {"type":"user-event","type":"submit","data":{"notes":"My feedback"},"timestamp":1234567891}事件类型共三种:click(点击按钮或data-choice元素)、submit(表单提交,含全部表单数据)、input(字段输入,500ms 防抖)。
HTML 模式(Patterns):
选项卡(Choice Cards):
<div class="options"> <button><div class="mockup"> <header><form> <label>Priority: <input type="range" name="priority" min="1" max="5"></label> <textarea name="notes" placeholder="Additional thoughts..."></textarea> <button type="submit">Submit</button> </form>显式 JavaScript:
<button onclick="brainstorm.choice('custom', {extra: 'data'})">Custom</button>验证步骤是grep -A5 "Visual Companion" skills/brainstorming/SKILL.md,确认新小节存在后提交。
Task 5 与 Summary:收尾
最后一个可选任务是确保.gitignore排除lib/brainstorm-server/node_modules/。计划文档的 Summary 部分归纳了完成后的四个产物:lib/brainstorm-server/下的服务器、自动注入的 helper 库、tests/brainstorm-server/下的测试,以及更新了 visual companion 小节与参考文档的 brainstorming skill。使用方法四步走:
- 后台启动服务器:
node lib/brainstorm-server/index.js & - 让用户打开
http://localhost:3333 - 把 HTML 写入
/tmp/brainstorm/screen.html - 检查任务输出中的用户事件
从源码看:当前仓库的演进实现
上面的计划描述的是 v1 形态(Express + ws + chokidar,固定端口 3333,单文件监视)。当前仓库中的实际实现已演进为零依赖版本,位置在 skills/brainstorming/scripts/server.cjs,配套 start-server.sh、stop-server.sh、frame-template.html 与 helper.js,用法详见 visual-companion.md。对照计划文档,演进点如下:
1. 手写 RFC 6455 协议替代 ws 库
server.cjs顶部直接实现了 WebSocket 帧编解码:computeAcceptKey(SHA1 + 魔数258EAFA5-...)、encodeFrame/decodeFrame(支持 7/16/64 位长度、客户端掩码校验、10MB 帧上限),handleUpgrade中手动返回101 Switching Protocols。decodeFrame强制要求客户端帧带掩码("Client frames must be masked"),并处理 TEXT / CLOSE / PING / PONG 帧与未知 opcode 的 1003 关闭。这使服务器在无任何 npm 依赖的情况下即可运行。
2. 单文件监视升级为目录 + 最新文件语义
计划中的chokidar.watch(SCREEN_FILE)单文件监视,演进为对CONTENT_DIR($SESSION_DIR/content)的原生fs.watch目录监视,并维护knownFiles集合区分"新屏幕"与"更新":
if (!knownFiles.has(filename)) { knownFiles.add(filename); console.log(JSON.stringify({ type: 'screen-added', file: filePath })); maybeOpenBrowser(); } else { console.log(JSON.stringify({ type: 'screen-updated', file: filePath })); } broadcast({ type: 'reload' });服务器始终提供按修改时间最新的 HTML 文件(getNewestScreen()),每个屏幕一个语义化文件名、永不复用——这与计划中"一个屏幕文件"的模型相比,让 Agent 可以积累一组屏幕而互不覆盖。代码注释还解释了为何不依赖事件类型:macOS 的fs.watch对新文件和覆盖都报rename,所以靠已知文件集合判断。
3. 会话密钥与内容片段/完整文档双模
计划版 URL 是裸的http://localhost:3333;现行实现要求 URL 携带?key=…会话密钥(32 字节随机十六进制),HTTP 与 WebSocket 升级都经过isAuthorized()的常量时间比较(crypto.timingSafeEqual),首次访问后密钥写入 HttpOnly + SameSite=Strict 的 cookie,cookie 名带实际绑定端口(brainstorm-key-<port>)以避免本地多服务器共享 cookie 串扰。未授权的请求收到 403 页(提示"需要完整 URL")。
内容侧也升级了:屏幕文件以<!DOCTYPE/<html开头则原样服务,否则自动包进 frame 模板——即 visual-companion.md 中"默认写内容片段(content fragments)"的规则。frame 模板(frame-template.html)提供明暗主题、头部连接状态灯,以及.options/.option/.cards/.card/.mockup/.split/.pros-cons/.mock-nav/.mock-input/.placeholder等 CSS 类,替代了计划版"自己写全部 HTML/CSS"的要求。
4. 客户端 helper 的健壮性增强
现行 helper.js 保留了计划版的核心语义(data-choice点击捕获、window.brainstorm显式 API、事件队列补发),但增强了:指数退避重连(500ms 起、翻倍、30s 封顶,nextReconnectDelay为纯函数并导出供单测)、15 秒未恢复则显示 "Companion paused" 墓碑层(tombstone)并在服务器同端口重启后自动恢复刷新、WebSocket 升级请求上带会话密钥(/?key=...)。同时toggleSelect实现了单选/多选(data-multiselect)的选中态管理。
5. 生命周期:守护、闲置超时与优雅停机
计划版的服务器需要 Agent 自己管理进程存活;现行实现内置了完整生命周期:
start-server.sh为每个会话生成独立目录(/tmp/brainstorm-$$-<ts>或--project-dir下的.superpowers/brainstorm/...),用nohup+disown后台启动并写 PID 文件,轮询日志等待server-startedJSON,且验证进程在短暂窗口后仍存活(捕获进程回收器);- 服务器接收
BRAINSTORM_OWNER_PID(harness 的祖先进程 PID),周期性检查宿主是否死亡——死了就自杀;start-server.sh还处理了 WSL/Tailscale/Windows MSYS2 下 PID 不可见的情形(owner-pid-invalid日志后降级为纯闲置超时); - 默认 4 小时无活动自动关闭(
--idle-timeout-minutes可调),关闭时先销毁所有已升级的 WebSocket socket再server.close()——否则进程会挂在打开的连接上,这正是 lifecycle.test.js 明确验证的行为; - 启动的
server-startedJSON 写入$STATE_DIR/server-info(0600 权限,含 URL 与密钥),shutdown时写server-stopped标记;stop-server.sh用每次启动生成的--brainstorm-server-id参数核对 PID 属于本服务器才肯发信号(防止 PID 复用误杀),且只清理/tmp下的临时会话,--project-dir的 mockup 文件保留供后续查看。
6. 端口策略
计划版固定 3333 端口;现行实现按BRAINSTORM_PORT→ 上次绑定端口(BRAINSTORM_PORT_FILE,让重启复用同端口、已打开的标签页自动重连)→ 随机高端口(49152 起)的顺序选取,EADDRINUSE时一次性回退随机端口(但若设了BRAINSTORM_TOKEN环境变量则拒绝回退,直接失败退出,避免密钥与端口错配)。
事件模型对照:计划版与现行版
| 维度 | 计划版(本文主体文档) | 现行仓库实现 |
|---|---|---|
| 传输依赖 | Express + ws + chokidar | 零依赖,手写 RFC 6455 +fs.watch |
| 屏幕来源 | 单文件/tmp/brainstorm/screen.html | content/目录中最新的 HTML 文件 |
| 内容要求 | 完整 HTML,注入 helper | 内容片段自动包 frame,或完整文档 |
| 访问控制 | 无(仅绑定 127.0.0.1) | ?key=会话密钥 + HttpOnly cookie + 常量时间比较 |
| 事件输出 | stdout{type:'user-event', ...} | stdout{source:'user-event', ...},且含choice的事件追加到$STATE_DIR/events(JSON Lines,新屏幕推入时清空) |
| 刷新机制 | chokidar 变更 → 广播 reload | 目录监视 + 100ms 防抖 → 广播 reload,区分 screen-added/updated |
| 进程管理 | Agent 自行后台运行 | start/stop 脚本、owner PID 守护、闲置超时、端口/密钥持久化 |
值得注意的一个细节:现行版把含choice字段的事件额外落盘到state_dir/events文件(见 server.cjs 的handleMessage),Agent 在下一轮直接读文件即可拿到浏览器交互的 JSON Lines 记录,与终端文本反馈合并——这比"盯着 stdout 滚动"更可靠,也是 visual-companion.md 中"主循环"(The Loop)的标准操作:每轮先确认server-info存在且server-stopped不存在 → 写新的语义化命名屏幕文件 → 提示用户查看并结束本轮 → 下一轮读取events与终端回复。
实践要点小结
- 计划文档的价值:2026-01-17-visual-brainstorming.md 展示了 Superpowers 自身的工程方法——每个任务带 Files / Steps / 验证命令 / commit 信息,可直接交给 Agent 逐任务执行(文档开头即声明需用
executing-plansskill); - 可复制的架构:HTML 文件作为"屏幕"单一事实源、文件变更作为推送触发器、stdout JSON 作为 Agent 可读的事件总线——三者解耦,使 Agent 侧不需要理解 WebSocket;
- 当前仓库的演进:从"固定 3333 端口的单文件服务器"到"带会话密钥、零依赖、可自愈的多屏幕会话服务",演进路径本身由 tests/brainstorm-server/ 下的测试与 docs/superpowers/plans/2026-03-11-zero-dep-brainstorm-server.md、docs/superpowers/plans/2026-06-10-visual-companion-auth-hardening.md 等后续计划文档记录,可继续沿仓库内的计划/规格文档追溯。
【免费下载链接】superpowersAn agentic skills framework & software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考