gstack × Conductor 侧边栏集成设计:让 Chrome 侧边栏成为 Agent 会话的实时视窗
【免费下载链接】gstackUse Garry Tan's exact Claude Code setup: 23 opinionated tools that serve as CEO, Designer, Eng Manager, Release Manager, Doc Engineer, and QA项目地址: https://gitcode.com/GitHub_Trending/gs/gstack
本文基于 gstack 仓库中的设计文档 CONDUCTOR_CHROME_SIDEBAR_INTEGRATION.md,完整解析 gstack 的 Chrome 侧边栏如何从"独立运行的第二个 Claude 实例"演进为 Conductor 主会话的实时视窗:读完后你将理解三项核心 API 需求(会话事件订阅、消息注入、工作区注册)的设计动机与契约细节,以及 gstack 侧已完成的扩展架构(SSE 事件渲染、双令牌鉴权、PTY 终端)如何与之对接。
1. 问题背景:双窗口盲点与"两个互不说话的 Agent"
在 gstack 工作流中,Claude 常在 Conductor 工作区内并行干活——编辑文件、跑测试、浏览你的应用。当前$B connect启动的 Chrome 侧边栏只能让你看到 browse 命令流,但当 Claude 在 Conductor 工作区里做 QA、看你的网站时,你只能盯着 Conductor 的聊天窗口看工具调用一条条滚过,却看不到浏览器里实际发生了什么。
原始设计文档指出,这里存在一个结构性问题:
侧边栏目前运行的是它自己独立的 Claude 实例。它看不到主 Conductor 会话在做什么,主会话也看不到侧边栏在做什么——这是两个互不通信的独立 Agent。
这个"双实例"架构在仓库早期设计中有迹可循。GSTACK_BROWSER_V0.md 的架构图显示,侧边栏 Agent 是一个claude -p子进程包装器("Future: BoomLooper" 即预留的替换点),而 SIDEBAR_MESSAGE_FLOW.md 记录了现行实现:侧边栏的主界面是一个交互式claudePTY(xterm.js + 独立的terminal-agent.ts子进程持有claude子进程)。这些实现都证明了"侧边栏自有 Agent"的路线是可行的,但正是它造成了上下文割裂。
修复方向在设计文档中一句话概括:让侧边栏成为 Conductor 会话的"视窗"(window into the session),而不是另一个独立的东西。
2. 核心设计:向 Conductor 提出的三项 API 需求
设计文档把需求收敛为三个接口能力,全部围绕"一个 Agent、两个视图"的目标。
2.1 需求一:让我们看到 Agent 正在做什么(事件订阅)
侧边栏需要一条从 Conductor 会话到扩展的事件管道,文档给出的形态是 SSE 流或 WebSocket,事件随会话发生实时推送,典型事件包括:
- "Claude 正在编辑
src/App.tsx" - "Claude 正在运行
npm test" - "Claude 说:我会修复这个 CSS 问题……"
关键前提是:侧边栏已经具备渲染这些事件的能力——工具调用渲染为紧凑徽章(badge),文本渲染为聊天气泡。缺的只是那根"管子"。
配套的 CONDUCTOR_SESSION_API.md 把这一需求落地成了具体的 API 契约:一个 SSE 端点GET http://127.0.0.1:{PORT}/workspace/{ID}/session/stream,以 NDJSON 事件重放 Claude Code 的会话流。事件类型直接复用 Claude Code 的--output-format stream-json格式,无需发明新 schema:
event: assistant data: {"type":"assistant","content":"Let me check that page...","truncated":true} event: tool_use data: {"type":"tool_use","name":"Bash","input":"$B snapshot","truncated_input":true} event: tool_result data: {"type":"tool_result","name":"Bash","output":"[snapshot output...]","truncated_output":true} event: turn_complete data: {"type":"turn_complete","input_tokens":1234,"output_tokens":567,"cost_usd":0.02}这条契约在 gstack 侧有现成的对接面:extension/sidepanel.js 已经用EventSource消费 browse 服务器的/activity/streamSSE 流,并带after=游标参数实现断点续传(withCredentials: true携带一次性 view-only cookie 鉴权)。换成 Conductor 的会话流只是换一个 URL——渲染层逻辑不变。
2.2 需求二:让我们向会话中发送消息(消息注入)
当用户在 Chrome 侧边栏输入"点击另一个按钮"时,这条消息应当以用户在 workspace 聊天框中亲自输入的身份出现在 Conductor 会话里,Agent 在下一轮自行拾取并执行。
设计文档称之为"魔法时刻"(the magic moment):用户正盯着 Chrome 看,发现了不对的地方,直接在侧边栏输入纠正指令,Claude 立刻响应——全程无需切换窗口。这条需求是"一个 Agent、两个视图"体验闭环的另一半:需求一只管看,需求二才让用户能改。
2.3 需求三:从目录创建 Conductor 工作区
$B connect启动时已会为文件隔离创建一个 git worktree。需求三是把这个 worktree注册为 Conductor 工作区,让用户能在 Conductor 的文件树中看到侧边栏 Agent 的文件改动。文档同时点明其战略意义:这为多浏览器会话(multiple browser sessions)打好地基——每个浏览器会话拥有各自独立的工作区。
3. 为什么这件事重要:把黑盒变成可视过程
设计文档用三个要点说明收益,核心是消除/qa与/design-review这类技能的"黑盒感"(Claude 说"我发现了 3 个问题",但你不知道它在看什么):
- 实时观看 Claude 测试你的应用——每一次点击、每一次导航、每一张截图都同步呈现在你正看着的 Chrome 里;
- 可以随时打断——"不,测一下移动端视图""跳过那个页面",无需切换窗口;
- 一个 Agent,两个视图——正在改你代码的那个 Claude,就是正在控制浏览器的那个 Claude。没有上下文复制,没有状态陈旧(stale state)。
4. gstack 侧的现状:几乎零改动即可对接
设计文档明确列出了 gstack 侧已完成并随版本发布的组件清单,这也是"把侧边栏变成会话视窗"成本如此之低的根本原因:
| 已建成的 gstack 侧组件 | 说明 |
|---|---|
| Chrome 扩展自动加载 | $B connect运行时自动装载(manifest 中key字段固定扩展 ID,服务端仅向固定 Origin 发放令牌) |
| 侧边栏自动打开 | 用户零配置 |
| 流式事件渲染器 | 工具调用、文本、结果的 SSE 驱动渲染 |
| 聊天输入 + 消息队列 | 输入缓冲与排队 |
| 重连逻辑 + 状态横幅 | 断线自动恢复 |
| 会话管理 | 带持久化聊天历史 |
| Agent 生命周期 | spawn / stop / kill / 超时检测 |
仓库中这些组件都有对应实体可查证:
- extension/manifest.json:Manifest V3,
sidePanel权限 + 固定key(对应POST /extension-token的 pinned-origin 发令牌机制),host_permissions仅放行http://127.0.0.1:*/与ws://127.0.0.1:*/,与 browse 服务器的本地信任模型一致; - extension/sidepanel.js:
EventSource消费/activity/stream,先取 view-only cookie 再开流,after=参数续传; - extension/sidepanel-terminal.js 与 extension/background.js:PTY 终端与服务引导(
/health探活 →/extension-token换令牌 →POST /pty-session→ WebSocket 握手); - SIDEBAR_MESSAGE_FLOW.md:完整的启动时序、双令牌模型与威胁模型文档。
文档结论是:gstack 侧唯一要做的改动,是把数据源从"本地claude -p子进程"换成"Conductor 会话流"。扩展代码保持不变。
值得注意的安全设计同样来自现有实现:SIDEBAR_MESSAGE_FLOW.md 中的双令牌模型(AUTH_TOKEN用于/pty-session,短生命周期gstack-pty.<token>经Sec-WebSocket-Protocol传递用于/ws升级鉴权,二者严格不互通)正是为"令牌泄漏不能升级为 shell 访问"而设计的分层隔离——Conductor 侧新增 SSE 端点时沿用同样的本地信任模型即可。
5. Conductor 侧的 API 契约与关键设计决策
CONDUCTOR_SESSION_API.md 给出了 Conductor 需要交付的完整服务端契约,这里完整保留其核心内容。
5.1 会话流端点与截断策略
GET http://127.0.0.1:{PORT}/workspace/{ID}/session/stream(SSE,NDJSON 事件,如 2.1 节所示)。内容截断规则:工具输入/输出在流中上限 500 字符,完整数据保留在 Conductor 的 UI 中。文档把截断明确定义为隐私特性(privacy feature)——长代码输出、文件内容、敏感工具结果永远不离开 Conductor 的完整 UI;侧边栏是"摘要视图,不是替代品"(300px 宽的面板里长内容没有意义)。
5.2 工作区发现端点
GET http://127.0.0.1:{PORT}/api/workspaces列出活跃工作区:
{ "workspaces": [ { "id": "abc123", "name": "gstack", "branch": "garrytan/chrome-extension-ctrl", "directory": "/Users/garry/gstack", "pid": 12345, "active": true } ] }扩展通过匹配 browse 服务器 git 仓库(来自/health响应)与工作区的 directory 或 name 来自动选中工作区。
5.3 安全模型
- 仅本地回环(Localhost-only):与 Claude Code 自身 debug 输出同一信任模型;
- 默认无鉴权:若 Conductor 希望加鉴权,可在 workspace 列表里附带 Bearer token,扩展在 SSE 请求中携带;
- 内容截断即隐私控制:长内容不出 Conductor 完整 UI。
5.4 设计决策表
| 决策项 | 选择 | 理由 |
|---|---|---|
| 传输层 | SSE(而非 WebSocket) | 单向、自动重连、更简单 |
| 格式 | Claude 的 stream-json | Conductor 内部本就在解析它;无新 schema |
| 发现机制 | HTTP 端点(而非文件) | Chrome 扩展无法读文件系统 |
| 鉴权 | 无(localhost) | 与 browse 服务器、CDP 端口、Claude Code 一致 |
| 截断 | 500 字符 | 侧边栏约 300px 宽,长内容无用 |
6. gstack 中已存在的 Conductor 集成点
有意思的是,gstack 并非第一次与 Conductor 打交道——仓库中已有若干为 Conductor 环境专门编写的适配代码,可以印证"Conductor 会话"在 gstack 心智模型中的位置:
- lib/is-conductor.ts:Conductor 宿主检测的单一事实来源。Conductor(一个并行运行多个 coding agent 的 Mac 应用)会在会话环境中设置
CONDUCTOR_WORKSPACE_PATH/CONDUCTOR_PORT;该辅助函数在调用时读取传入 env(而非模块加载时快照),原因注释写得很清楚——ESM 会把静态 import 提升,加载期读取无法被测试用process.env.X = ...固定; - lib/conductor-env-shim.ts:Conductor 工作区不继承用户交互式 shell 环境,
ANTHROPIC_API_KEY/OPENAI_API_KEY可能缺失而GSTACK_前缀形式存在。该 shim 在标准名空缺时把GSTACK_ANTHROPIC_API_KEY等提升为标准名,供子进程(gbrain embed、@anthropic-ai/claude-agent-sdk等)拾取; - conductor.json:为 Conductor 宿主声明的脚本钩子(
setup/archive映射到bin/dev-setup、bin/dev-teardown); - test/is-conductor.test.ts 与 test/conductor-env-shim.test.ts:对上述两个适配点的单测覆盖。
从源码结构看,这些适配层说明 gstack 已把 Conductor 视为一等宿主(first-class host);本文所述的侧边栏集成,是把这种关系从"环境检测"深化到"会话级实时桥接"。
7. 实施路径与工作量估算
综合 CONDUCTOR_SESSION_API.md,两侧分工与步骤如下。
扩展侧(gstack,5 步)——当 Conductor API 就绪后:
- 侧边栏通过端口探测或手动输入发现 Conductor;
- 拉取
/api/workspaces,与 browse 服务器的仓库匹配; - 对
/workspace/{id}/session/stream打开EventSource; - 渲染:assistant 消息、工具名 + 图标、轮次边界、成本;
- 优雅降级:Conductor 不可达时显示 "Connect Conductor for full session view"。
服务端(Conductor):1) 按工作区重放 Claude Code stream-json 的 SSE 端点;2)/api/workspaces发现端点;3) 500 字符截断逻辑。
工作量估算(原文档结论):Conductor 工程 2–3 天,gstack 集成 1 天;扩展侧约 200 行改动(集中在sidepanel.js),服务端约 100–200 行——前提是 Conductor 内部已捕获 Claude Code 的 stream-json(它为自己的 UI 渲染本来就在捕获)。
8. 小结
这份设计文档的价值在于把"看 Agent 干活"从产品愿景压缩成了三项可验收的接口需求:事件订阅(看)、消息注入(说)、工作区注册(文件树可见)。gstack 侧的扩展、SSE 渲染器、双令牌鉴权、PTY 生命周期均已就位并被 SIDEBAR_MESSAGE_FLOW.md 完整文档化,因此整个集成的剩余工作量几乎全部落在 Conductor 的会话流导出端点上。实现完成后,"一个 Agent、两个视图"——在 Conductor 里写代码的 Claude 与在 Chrome 里被观察的 Claude——将是同一个 Agent,/qa与/design-review的每一次点击和截图都将实时可见、随时可打断。
【免费下载链接】gstackUse Garry Tan's exact Claude Code setup: 23 opinionated tools that serve as CEO, Designer, Eng Manager, Release Manager, Doc Engineer, and QA项目地址: https://gitcode.com/GitHub_Trending/gs/gstack
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考