Leask/Tabminal
GitHub: Leask/Tabminal
一个跨设备的云原生终端与 ACP 智能体工作区,提供持久会话、多主机集群管理及内置 AI 编码助手。
Stars: 365 | Forks: 28
# `t>` Tabminal
`Tabminal` 将持久的服务器端终端会话、内置的 workspace、多主机访问以及 [Agent Client Protocol (ACP)](https://agentclientprotocol.com/get-started/introduction) 集成整合到了一个 UI 中。它专为那些需要真实终端、真实文件和真实 agent 工具,但又不想被绑定在仅限桌面端客户端的用户而设计,让你可以通过智能、持久且丰富的体验,在桌面设备、平板或手机上进行编码。

## 它的功能
- 持久的终端会话,在刷新、重新连接和切换设备后依然保持存活。
- 内置的 workspace 标签页,用于管理文件、图像、agent 和固定的终端。
- 支持 ACP agent,提供受管终端、实时工具调用、diff、代码查看器、权限请求、计划和用量 HUD。
- 支持在单个 UI 中进行多主机 cluster 访问,并带有按主机的身份验证和心跳状态。
- 浏览器优先的移动端和平板 UX,包括紧凑型 workspace 模式和 PWA 安装支持。
- 原生于终端的 AI 助手,在配置了 OpenAI 或 OpenRouter 时,支持 shell 历史记录和自动修复流程。


## 当前亮点
### ACP Agent Workspace
Tabminal 现在拥有完整的 ACP agent 界面,而不仅仅是一个 AI 聊天框。
- Agent 标签页与文件和终端标签页并排存在于同一个 workspace 栏中。
- 工具调用可以内联渲染实时的终端输出、diff、代码/资源 payload 以及文件路径。
- `Jump in`(加入)可在受管终端会话仍在运行时将其移入该会话。
- Agent 计划、运行中终端摘要、斜杠命令菜单、权限和用量数据均是一等公民 UI 元素。
- Agent 编辑器支持由提供商定义的斜杠命令和键盘导航。
- Agent 状态在刷新后依然可以恢复,包括对话历史记录和受管终端关系。
目前内置的 agent 定义包括:
- Gemini CLI
- Codex CLI
- Claude Agent
- GitHub Copilot CLI
- ACP Test Agent (`TABMINAL_ENABLE_TEST_AGENT=1`)
每个定义都是按主机检测的。其可用性取决于该主机的 runtime 环境以及任何所需的本地身份验证或 API 密钥。
### 原生终端 AI 助手
Tabminal 仍然包含原始的原生终端助手路径。
- 在 shell 提示符前加上 `#` 前缀,即可向内置助手询问你当前的终端上下文。
- 失败的命令可以利用最近的历史记录和错误输出触发自动的 AI 后续跟进。
- 此路径使用你配置的 OpenAI 或 OpenRouter 密钥,并与 ACP agent 集成相互独立。
### 多主机 Cluster
一个 UI 即可管理多个 Tabminal 后端。
- 从侧边栏添加主机。
- 在任何已连接的主机上打开会话。
- 身份验证范围限定于主机。
- 主机控制全局登录模态框。
- 子主机的身份验证失败仅保留在该主机本地。
- 主机注册表持久化存储在主机上,并在刷新后恢复。
### 内置 Workspace
- 基于 Monaco 的文件编辑器
- 文件树和图像预览
- 终端、文件和 agent 标签页位于一个共享的 workspace 栏中
- 侧边栏中的受管终端预览
- 支持恢复状态的终端固定和 workspace 切换
### 移动端与平板 UX
- 支持 PWA 安装
- 感知安全区的响应式布局
- 针对小型或窄屏幕的紧凑型 workspace 模式
- 触摸友好的控件和虚拟键盘支持
- 小型屏幕的 agent 配置控件会折叠为仅显示图标的下拉选择器,以确保编辑器在平板和手机上依然可用
## 快速入门
### 环境要求
- Node.js `>= 22`
- 安全的环境。Tabminal 在设计上属于高权限应用。
- 可选的提供商凭证:
- 用于内置原生终端助手的 OpenAI 或 OpenRouter
- 用于网络搜索增强的 Google Search API key 和 CX
- 用于 ACP agent 的本地 CLI/身份验证,例如 Codex、Gemini、Claude 或 Copilot
### 安全警告
Tabminal 提供对主机文件系统的直接读/写访问权限,并能在该主机上运行命令。
- 不要将其直接暴露在公共互联网中。
- 使用 VPN、Tailscale 或诸如 Cloudflare Access 的 Zero Trust 层。
- 如果启用了 AI 功能,终端历史记录、路径、环境变量提示或最近的命令上下文可能会被发送到你配置的提供商处。
- 启动服务器必须提供 `--accept-terms`。
### 快速开始
仅终端:
```
npx tabminal --accept-terms
```
使用 OpenAI:
```
npx tabminal --openai-key "YOUR_API_KEY" --accept-terms
```
使用 OpenRouter:
```
npx tabminal --openrouter-key "YOUR_API_KEY" --accept-terms
```
### Docker
```
docker run --rm -it -p 9846:9846 \
leask/tabminal \
--accept-terms
```
启用 AI:
```
docker run --rm -it -p 9846:9846 \
leask/tabminal \
--openai-key "YOUR_API_KEY" \
--accept-terms
```
### 本地开发
```
git clone https://github.com/leask/tabminal.git
cd tabminal
npm install
npm start -- --accept-terms
```
## 配置
配置优先级如下:
1. 内置默认值
2. `~/.tabminal/config.json`
3. `./config.json`
4. CLI 标志
5. 环境变量
如果未提供密码,Tabminal 会在启动时生成一个临时密码并将其打印到终端。
### CLI 标志和环境变量
| 参数 | 环境变量 | 描述 | 默认值 |
| :--- | :--- | :--- | :--- |
| `-p`, `--port` | `TABMINAL_PORT` | 服务器端口 | `9846` |
| `-h`, `--host` | `TABMINAL_HOST` | 绑定地址 | `127.0.0.1` |
| `-a`, `--password` | `TABMINAL_PASSWORD` | 访问密码 | 启动时生成 |
| `-s`, `--shell` | `TABMINAL_SHELL` | 默认 shell 可执行文件 | 系统默认 |
| `-k`, `--openrouter-key` | `TABMINAL_OPENROUTER_KEY` | OpenRouter API key | `null` |
| `-o`, `--openai-key` | `TABMINAL_OPENAI_KEY` | OpenAI API key | `null` |
| `-u`, `--openai-api` | `TABMINAL_OPENAI_API` | OpenAI 兼容的 base URL | `null` |
| `-m`, `--model` | `TABMINAL_MODEL` | 内置助手模型 ID | 使用 OpenAI 时为 `gpt-5.2`,使用 OpenRouter 时为 `gemini-3-flash-preview` |
| `-f`, `--cloudflare-key` | `TABMINAL_CLOUDFLARE_KEY` | Cloudflare Tunnel token | `null` |
| `-g`, `--google-key` | `TABMINAL_GOOGLE_KEY` | Google Search API key | `null` |
| `-c`, `--google-cx` | `TABMINAL_GOOGLE_CX` | Google Search Engine ID | `null` |
| `-d`, `--debug` | `TABMINAL_DEBUG` | 启用调试日志 | `false` |
| `--heartbeat` | `TABMINAL_HEARTBEAT` | WebSocket 心跳间隔(以 ms 为单位),最小值为 `1000` | `10000` |
| `--history` | `TABMINAL_HISTORY` | 终端历史记录字符限制 | `1048576` |
| `-y`, `--accept-terms` | `TABMINAL_ACCEPT` / `TABMINAL_ACCEPT_TERMS` | 必须确认的风险接受声明 | `false` |
注意:
- `--openrouter-key` 和 `--openai-key` 互斥。
- `config.json` 也支持 `heartbeatInterval` / `heartbeat-interval` 和 `historyLimit` / `history-limit`。
### 持久化文件
Tabminal 将 runtime 状态存储在 `~/.tabminal/` 目录下:
- `config.json`:可选的家目录级别配置
- `cluster.json`:多主机注册表
- `agent-tabs.json`:ACP agent 标签页恢复状态
- `agent-config.json`:保存的按 agent 设置/配置的值
对于多主机:
- 主机 token 保留在浏览器的本地存储中。
- 子主机 token 持久化存储在主机的 `cluster.json` 中。
## ACP Agent 说明
ACP 的可用性是按主机发现的。如果后端的 runtime 环境与你的交互式 shell 不同,它可能会显示不同的结果。
典型要求:
- Codex:`codex login`
- Gemini:`gemini --acp` 或 `npx @google/gemini-cli@latest --acp`
- Claude:`npx @zed-industries/claude-code-acp@latest` 以及所需的 Anthropic 或 Vertex 配置
- Copilot:`copilot --acp --stdio` 或 `gh copilot -- --acp --stdio`
在 CLI 位于用户本地 bin 目录(例如 `~/.local/bin`)的主机上,Tabminal 会扩充 agent 的 runtime `PATH`,从而使发现更加可靠。
## 键盘快捷键
- `Ctrl + Shift + T`:新建终端
- `Ctrl + Shift + W`:关闭终端
- `Ctrl + Shift + E`:切换文件 workspace 面板
- `Ctrl + Shift + A`:打开 agent 菜单
- `Ctrl + Up / Down`:在 workspace 和终端之间移动焦点
- `Ctrl + Shift + [ / ]`:切换会话
- `Ctrl + Alt + [ / ]`:切换 workspace 标签页
- `Ctrl + Shift + ?`:显示快捷键帮助
- `Ctrl` / `Cmd` + `F`:在终端中查找
- `Esc`:在受支持的情况下停止正在运行的 ACP prompt,或关闭瞬态 agent UI(例如菜单)
### 触摸操作
- 虚拟键盘提供了适合终端使用的修饰键。
- Workspace 和 agent 控件针对触摸和紧凑型屏幕进行了优化。
## 架构概览
- 后端:[`Node.js`](https://nodejs.org/)、[`utilitas`](https://github.com/leask/utilitas)、[`Koa`](https://github.com/koajs/koa)、[`node-pty`](https://github.com/Tyriar/node-pty)、[`WebSocket`](https://github.com/websockets/ws)、[`ACP SDK`](https://github.com/acp-kit/acp-sdk)
- 前端:[`Vanilla JS 😝`](http://vanilla-js.com/)、[`xterm.js`](https://github.com/xtermjs/xterm.js)、[`Monaco Editor`](https://github.com/microsoft/monaco-editor)
- 持久化:`~/.tabminal` 下的主机本地文件
- 原生客户端和打包工作位于以下位置:
- `apps/Apple`
- `apps/ghostty-vendor`
## 故障排除
- 在 macOS 上,`node-pty` 可能需要执行:
chmod +x node_modules/node-pty/prebuilds/darwin-*/spawn-helper
- 如果子主机不断要求登录,请检查是否是 Cloudflare Access 或其他身份验证层要求对该主机进行交互式浏览器登录。
- 如果缺少 ACP agent,请验证该 CLI 是否已安装在后端主机上,并在该主机的 runtime 环境中可用。
## 质量检查
建议在发布更改前执行:
```
npm run lint
npm test
npm run build
```
## 许可证
[MIT](LICENSE)
更多截图

标签:MITM代理, 自定义脚本, 请求拦截