聪明在于学习,天才在于积累。所谓天才,实际上是依靠学习。—— 华罗庚

nodeterm:把终端与 AI 编码代理铺进一张无限画布

项目地址:https://github.com/eneskirca/nodeterm

终端本来是开发者最熟悉的工作空间之一。

可当终端标签不断增加,项目不断切换,多个命令同时运行,AI 编码代理也开始并行工作时,熟悉的窗口布局很容易变成一叠叠被遮住的上下文。某个任务正在构建,另一个任务在等待确认,一段代理会话跑到了哪里,某个分支又对应哪一个终端,往往需要在层层标签之间来回寻找。

nodeterm 尝试用一种更具空间感的方式回应这件事。

它是一个基于节点的终端管理器,将终端与 AI 编码代理放到可无限平移和缩放的画布上。每一个真实运行的终端都可以成为一个可拖动的节点,每一个项目既是一张画布,也是一块类似看板的实时会话面板。终端不再只是藏在标签栏后面的一行标题,而是可以被放置、分组、命名、缩放和持续保留的工作单元。

对于工作流容易分散、任务经常并行、需要长期维护上下文的人来说,nodeterm 不再把终端视作一摞窗口,而是将它们组织成一张可见的地图。

当终端不再是一叠隐藏的标签

传统终端标签的核心问题,不在于不能打开更多,而在于打开更多之后,上下文开始变得难以追踪。

哪个终端正在执行命令。

哪个终端属于某个项目。

哪个 AI 代理正在等待权限确认。

哪个任务已经完成。

哪个会话对应某个分支或工作树。

nodeterm 将这些问题放到了画布上处理。

每一个 shell 都以节点形式存在。用户可以将它放在画布中的任意位置,给它命名,将它与其他节点分组,也可以拉近或拉远视野。终端、代理、便签、编辑器、差异视图、网页与视频不再被限制在单一线性排列中,而是可以按项目、任务、分支或个人习惯摆放。

这种空间布局让工作区拥有了更直观的形状。

一个项目可以在画布左侧放置正在运行的开发服务,中间放置负责实现功能的代理,右侧放置与需求相关的便签和网页节点。另一个分支可以被放到独立分组中,与自己的终端、代理和编辑器一起存在。画布不要求所有任务排成队列,而是允许它们自然地分布。

一切都是节点

nodeterm 的核心表达很直接:一切都是节点。

在画布空白区域点击右键,可以创建终端,也可以创建 AI 代理。每个节点都运行在独立且持久化的 tmux 会话中。终端节点旁边可以放置便签、Monaco 编辑器、差异视图、网页节点和视频节点,让工作中的内容不只停留在命令输出里。

节点类型包括:

  • 终端节点
  • AI 代理节点
  • 便签节点
  • 分组节点
  • 编辑器节点
  • 差异视图节点
  • 网页与视频节点

终端节点使用 xterm 与 tmux,并支持 AI 命名。

代理节点支持 Claude Code、Codex、Gemini、GitHub Copilot、opencode、Grok 以及自定义代理。

便签节点可以与代理关联,为代理提供上下文。

分组节点能够与 git worktree 绑定,用于组织一个分支对应一个代理的工作方式。

编辑器节点基于 Monaco,并支持保存操作。

差异节点用于查看变更。

网页与视频节点则可以作为画布中的信息入口。

这些节点被放在同一个空间中,意味着任务不再只能以文件夹、窗口或标签的形式区分。它们也可以通过位置关系建立联系。

tmux 让会话持续存在

nodeterm 的终端连续性依托 tmux。

终端会话能够跨节点重新挂载持续运行,也能够跨应用重启保持存在。正在执行的进程不会因为节点临时离开画布而消失。即使应用退出,再次打开之后,会话依然能够回到原处。

机器重启后,nodeterm 会恢复滚动历史,并恢复代理会话。README 中还说明,代理会话可以通过 claude --resume 继续。

在 macOS 应用中,nodeterm 自带 tmux,因此不需要额外安装也能使用这一机制。如果系统中已经存在 tmux,则会优先使用系统中的 tmux。升级之前打开的终端会维持原有状态,直到节点被刷新。

这种持续性让终端不再只是短暂的命令容器。

它可以成为一个真正持续存在的工作节点。一个正在执行的任务可以留在画布里,等待下一次查看。一个代理会话可以在退出应用后继续保持。一个项目的终端布局也不会因为关闭窗口而失去踪迹。

AI 代理不只是输出文本,而是有状态的工作单元

当 AI 编码代理开始执行任务时,最重要的信息往往不是输出内容本身,而是它当前处于什么状态。

它是在运行。

它需要用户确认。

它已经结束。

它是否派生了子代理。

它还拥有多少上下文空间。

nodeterm 使用基于 hook 的状态机制,而不是依靠输出内容抓取来判断代理状态。代理节点可以显示脉冲式的 RUNNINGNEEDS YOU 状态标识,也可以呈现带实时记录的子代理卡片,以及每个节点的上下文计量器。

当代理需要用户介入时,系统可以发送操作系统通知。用户点击通知后,可以直接在节点中回答权限提示。一个回合结束时,应用也会告知用户任务已经完成。

在 MacBook 上,代理状态还会出现在刘海区域中。

这让代理不再像一个需要不断切回查看的黑盒窗口。它拥有清晰的可视化状态,也能够在真正需要人参与的时候发出信号。

让代理之间共享必要的上下文

复杂任务往往并不只有一个代理。

一个代理可能负责实现功能,另一个代理负责检查变更,第三个代理则处理另一个分支上的任务。当这些代理彼此独立运行时,如何让它们在需要时理解相关背景,便成为工作流的一部分。

nodeterm 提供上下文链接能力,使代理节点能够按需读取彼此的会话记录。

对于 Claude,nodeterm 还提供会话分支能力,并支持多个已登录 Claude 身份并行管理。代理也能够借助内置画布控制命令行工具操作画布,例如打开节点、生成团队以及验证彼此的工作。

在这种组织方式下,画布不是单纯摆放终端的位置。它也可以成为代理协作时的工作场地。节点之间的位置、分组与上下文链接,构成了一种能够被人理解,也能够被代理参与的工作结构。

一个项目,两种视图

在 nodeterm 中,每个项目都是一张画布,同时也是一块看板。

看板上的卡片不是静态任务记录,而是实时会话本身。用户可以在不同列之间拖动卡片,而对应的代理仍然继续运行。点击卡片后,可以打开实时卡片弹窗,查看真实会话、成员、截止日期、优先级与评论。

项目画布与看板之间可以通过快捷键切换:

1
⌘⇧B

画布更适合观察空间关系。

看板更适合观察任务流动。

同一个项目因此拥有两种可切换的表达方式。用户可以在画布里将终端、代理、文件与便签按照任务关系排布,也可以切换到看板,在列与卡片之间查看任务当前所处的位置。

会话仍然是同一批会话,只是被放进了不同的视角里。

看板中的 GitHub Issues

nodeterm 提供可选的 GitHub Issues 看板能力。

启用之后,Issue 可以以卡片形式进入看板,并支持标签与列之间的精确映射。看板中可以按全部内容、GitHub 内容和会话内容进行筛选。

卡片在列之间移动时,可以进行双向同步。Issue 的关闭与重新打开状态也能够同步。

这使看板不仅能够承载实时代理会话,也能够承载与项目任务相关的 Issue。实时执行中的工作与项目管理中的工作项,可以在同一个看板视图里并存。

从本机走向远程项目

nodeterm 支持远程项目与 SSH 项目。

用户可以通过 SSH 打开远程主机上的项目。终端、文件、git 操作,甚至看板都在远程主机上运行,而画布仍然保留在本地。

这种模式将画布与执行环境分开。

画布可以继续作为用户的本地交互界面,而实际终端、文件、仓库与代理可以位于远程主机。用户看到的是同样的节点结构,同样的项目组织方式,同样的终端与看板视图,只是工作实际发生在远程环境中。

在架构层面,nodeterm 为终端通信定义了 TerminalTransport 抽象。渲染层只依赖这一接口,不直接依赖 IPC 或 node-pty。

LocalTransport 用于连接本地主机。

RemoteTransport 用于通过 SSH 连接远程代理。

这种设计使远程项目能够接入画布,而不需要改动画布界面本身。

手机上的同一段实时会话

nodeterm 提供 iOS 配套应用。

用户可以通过二维码将手机与 nodeterm 配对。配对之后,手机可以连接到同一批正在运行的实时会话。会话不会变成另一个副本,而是继续指向原本的 tmux 会话。

在手机上,可以查看代理工作状态,可以响应 NEEDS YOU 状态,也可以向任意终端输入内容。移动端还提供推送通知与移动版看板视图。

会话通过中继进行端到端加密,而不是只依赖局域网连接。

这种连接方式让终端与代理不再被锁在桌面前。任务仍然可以在主机上运行,而用户可以在移动设备上跟进状态、查看进度或做出必要回应。

浏览器中的 Server Edition

nodeterm 不只是一款桌面应用。

它还提供 Server Edition,使同一张画布能够以无界面的形式运行在 Linux 或 macOS 主机上,并从任意浏览器访问。

在 Server Edition 中,终端、编辑器、源代码控制、看板与代理都运行在服务器上。用户通过浏览器连接这台主机,查看和操作同一套画布。

开发模式可以通过下面的命令启动:

1
npm run server:dev

启动后,可以打开本地地址:

1
http://127.0.0.1:8443

并设置密码。

Server Edition 使用单用户认证,包含密码与安全 Cookie,也提供 WebSocket 桥接。它采用与桌面应用相同的渲染器,因此桌面端与浏览器端并不是两个完全分离的界面系统。

终端、文件、编辑器、差异视图、完整 git 面板、看板和代理状态标识,都可以在浏览器中使用。

在 SSH 主机上接收代理通知

除了通过浏览器访问完整画布,nodeterm 的服务端还可以作为无界面的后台通知主机运行。

将它安装在可以通过 SSH 访问的 Linux 主机上后,手机可以接收该主机上代理的 RUNNINGNEEDS YOU 推送通知,并获得 Live Activity 覆盖。

这个模式不需要开放端口。hook 服务保持只绑定本地回环地址,推送则通过 HTTPS 发出,授权信息由手机通过 SSH 提供。

安装命令如下:

1
curl -fsSL https://raw.githubusercontent.com/eneskirca/nodeterm/main/scripts/install-server.sh | bash

该命令会完成安装、构建,并将服务作为 systemd 服务运行,启用 NODETERM_HEADLESS=1。再次运行同一命令可以进行更新。

这让远程主机上的代理不仅可以持续运行,也可以在需要用户参与时主动将状态送到手机上。

语音输入终端,但内容不会自动提交

终端操作通常依赖键盘,但 nodeterm 也提供了语音输入方式。

按住 ⌘⌥ 后说话,设备上的 Whisper 会在本地进行转写。转写结果会先显示给用户审阅,只有在用户明确点击发送后,内容才会进入终端。

语音不会离开本机。

这一流程不是将语音直接转化为自动执行的命令,而是保留审阅与发送两个步骤。用户可以先看到文本,再决定是否将其送往当前聚焦的终端。

默认快捷键为:

1
按住 ⌘⌥

在其他平台上,对应为:

1
Ctrl+Alt

从终端到源代码控制

nodeterm 还集成了源代码控制能力。

它提供类似 VS Code 的暂存与取消暂存操作,也支持丢弃变更、切换或创建分支、提交、推送、同步、发布、worktree 以及 gh 登录。这些能力由系统中的 git 提供支持。

源代码控制不再必须发生在画布之外。

项目中的终端、代理、编辑器、差异视图与 git 操作可以放在同一套工作空间中。一个分组可以绑定到 git worktree,一个代理可以对应一个分支,差异节点可以展示变更,git 面板则承接暂存、提交与同步。

此外,nodeterm 还支持通过用户自带的本地代理命令行工具,根据已暂存差异或捕获的终端输出生成 AI 提交信息与终端名称。相关代理会以只读方式运行。

机器电源也会感知代理状态

当代理长时间工作时,机器进入空闲休眠可能会中断任务。

nodeterm 在代理工作期间阻止机器因空闲而休眠,并在代理完成后释放这一状态。这个行为默认开启,也可以在初始设置流程或设置中的行为选项里切换。

README 同时说明,没有应用能够在笔记本电脑合盖时持续阻止机器睡眠。若需要长时间运行代理,机器应保持打开并接通电源,或者将代理运行在不会休眠的主机上,再通过 Server Edition 访问。

这项能力让应用不只关注终端窗口是否可见,也关注任务执行过程中的机器状态。代理仍在工作时,系统不应因为用户暂时离开而过早沉睡。

常用快捷键

nodeterm 提供命令面板、文件浏览器、Markdown 视图、撤销与重做等操作,并允许在设置中重新映射快捷键。

默认快捷键包括:

快捷键 操作
⌘K 命令面板
⌘T 新建终端
⌘⇧C 新建 Claude Code 会话
⌘⇧B 切换看板
⌘W 关闭选中的节点
⌘Z 撤销
⌘⇧Z 重做
⌘M 切换终端或编辑器中的 Markdown 视图
⌘⇧E 文件浏览器
⌘, 设置
⌘/ 快捷键设置
右键 打开空白区域或节点的操作菜单

这些快捷键让画布中的工作不必完全依赖鼠标。终端、代理、看板、文件浏览器与命令面板都可以在键盘操作中快速切换。

同一套核心,三种工作表面

nodeterm 的架构围绕多种运行表面展开。

桌面应用、浏览器 Server Edition 和移动配套应用,使用相同的核心与传输边界。

在 Electron 桌面应用中,代码分为三个上下文:

  • src/main 负责 Electron 壳
  • src/preload 是唯一桥梁,并提供 window.nodeTerminal
  • src/renderer 负责 React 界面

src/shared 保存三者共同使用的类型与 IPC 通道名称。

应用中的服务,包括 PTY、工作区与设置、git、代理和 hooks,都位于 src/core,并通过较小的平台接口进行组织。核心服务不导入 Electron。

Electron 是这一平台边界的一种实现。

浏览器 Server Edition 是另一种实现。

浏览器侧通过 WebSocket RPC 桥接运行,并由 src/renderer/bridge 在浏览器中填充 window.nodeTerminal

React Flow 是实时节点的唯一事实来源。项目会将序列化后的节点持久化到磁盘,而 tmux 则负责让会话在重启后继续存在。

这套结构让 nodeterm 能够保持一个代码库、一个渲染器,同时拥有桌面端、浏览器端和移动端三种工作表面。

从源码构建

nodeterm 支持 macOS 与 Linux,需要 Node.js 20 或更高版本。README 建议使用 tmux,因为它是会话跨重启持续存在的关键。

源码检出不包含打包的 tmux。在 macOS 上,可以执行一次 node scripts/build-tmux.mjs,将 tmux 构建到 resources/bin/tmux。也可以自行安装 tmux。

常用开发与构建命令如下:

1
2
3
4
5
6
7
8
9
npm install
npm run dev
npm run build
npm start
npm run typecheck
npm test
npm run dist
npm run dist:linux
npm run server:dev

其中:

  • npm install 会安装依赖,并在安装后根据 Electron ABI 重建 node-pty
  • npm run dev 会启动带渲染层热更新的开发模式
  • npm run build 会将生产构建输出到 out
  • npm start 用于预览生产构建
  • npm run typecheck 是快速正确性检查
  • npm test 会运行 vitest 单元测试与集成测试
  • npm run dist 会在本地生成未签名的 macOS 安装包
  • npm run dist:linux 会在 Linux 主机上生成 AppImage 与 .deb
  • npm run server:dev 会构建并启动浏览器 Server Edition,需要 Node.js 22 与 tmux

终端终于拥有了位置感

nodeterm 的价值,不只是让终端窗口变得可以拖动。

它试图为并行任务提供一种更适合观察的形态。

终端可以放在画布上。

代理可以显示运行状态与等待状态。

便签可以成为代理上下文。

编辑器与差异视图可以成为任务的一部分。

项目可以在画布与看板之间切换。

远程主机可以通过 SSH 接入。

手机可以连接到同一段实时会话。

浏览器可以访问服务器上的完整工作空间。

在这样的结构里,终端不再只是隐藏在标签栏深处的黑色窗口。它们有位置,有关系,有状态,也有持续存在的上下文。

当任务越来越多,代理越来越并行,真正需要整理的也许不只是命令,而是人对整个工作流的感知。

nodeterm 把这些原本分散在标签、窗口、远程主机和移动设备中的内容,重新铺进了一张可以平移、缩放、拖拽和持续保存的画布。