# Pi Web Console

把 [Pi](https://pi.dev/)（一个极简、可扩展的终端编码 Agent）的**全部能力**通过 Web UI 暴露出来。架构与 Pi 官方集成规范一致：后端为每个会话孵化一个 `pi --mode rpc` 子进程，在 stdin/stdout 上做 **JSONL 双向桥接**，Web 前端经 WebSocket 与后端对话，从而**原生复用 Pi 的全部能力**，而不是重造一个 Agent。

> Pi 官方明确 RPC 模式（`--mode rpc`，stdin/stdout JSONL）是"把 Pi 嵌入 IDE / 外部 UI"的首选机制。本项目即是该机制在 Web 端的完整实现。

---

## 特性

- **原生复用 Pi 全部能力**：`prompt / steer / follow_up / abort / bash / set_model / set_thinking_level / compact / fork / clone / switch_session / export_html / get_tree / get_session_stats …` 全部 RPC 命令均可用。
- **流式渲染**：文本增量（`text_delta`）、思考过程（`thinking_delta`）、工具调用（`tool_execution_*`）实时呈现，支持 Markdown。
- **扩展 UI 子协议**：正确处理 `select / confirm / input / editor`（弹窗回填 `extension_ui_response`）以及 `notify / setStatus / setWidget / setTitle`。
- **会话管理**：新建 / 销毁 / 切换到磁盘上的历史会话（与 CLI 共享 `~/.pi/agent/sessions`），树形分支、分叉、克隆、导出 HTML。
- **模型与思考等级**：`get_available_models` / `get_available_thinking_levels` 驱动下拉框，`set_model` / `set_thinking_level` 即时切换。
- **用量统计**：Token 用量、成本、上下文占用（`get_session_stats`）。
- **一次性模式**：`pi --mode json`（print/JSON 事件流）做快速提问，不占用会话。
- **无密钥演示**：内置 `test/mock-pi.js` 模拟 pi 子进程，可端到端跑通整个链路。

---

## 架构

```
┌────────────┐   WebSocket (JSON)   ┌──────────────────────────────┐
│  浏览器前端  │ ◄────────────────────► │  Node 后端 (express + ws)   │
│  index.html │                      │  ┌────────────────────────┐ │
│  app.js     │                      │  │  SessionManager        │ │
└────────────┘                      │  │   ┌──────────────────┐ │ │
                                     │  │   │ PiRpcSession #1  │ │ │
        REST (健康检查 / 会话列表)      │  │   │  spawn pi        │ │ │
┌────────────┐                      │  │   │  --mode rpc      │ │ │
│ GET /api/*  │ ◄────────────────────┤  │   └────────┬─────────┘ │ │
└────────────┘                      │  └────────────┼───────────┘ │
                                     └───────────────┼─────────────┘
                                        stdin 命令 / stdout 事件+响应
                                                     │
                                        ┌────────────▼─────────────┐
                                        │   pi --mode rpc          │
                                        │   (JSONL over stdio)     │
                                        └──────────────────────────┘
```

- **一个会话 = 一个 `pi --mode rpc` 子进程**。会话生命周期与子进程绑定，父进程退出即自然终止。
- 后端只做**透明转发 + 请求/响应 id 关联**，不解析、不改造 Agent 语义——前端直接发 Pi RPC 命令对象。
- 严格 JSONL 帧解析：**仅以 `\n` 切分记录**、剥离尾部 `\r`，不使用会把 `U+2028/2029` 当换行的通用行读取器（如 Node `readline`）。

### WebSocket 协议（后端 ↔ 前端）

**客户端 → 服务端**

| type | 字段 | 说明 |
|---|---|---|
| `session.create` | `payload: { cwd?, name?, env? }` | 创建会话（spawn pi） |
| `session.destroy` | `runtimeId` | 销毁会话（kill 子进程） |
| `session.list` | — | 列出活跃 + 磁盘会话 |
| `session.deleteDisk` | `sessionFile` | 删除磁盘上的历史会话文件（.jsonl，路径受限 + 活跃占用保护） |
| `command` | `runtimeId, command, clientId?` | 转发 Pi RPC 命令 |
| `ui.response` | `runtimeId, response` | 回填 `extension_ui_response` |
| `oneshot` | `payload: { prompt, cwd?, model?, provider? }` | `pi --mode json` 一次性调用 |

**服务端 → 客户端**

| type | 字段 | 说明 |
|---|---|---|
| `hello` | `pi` | pi 可用性 / 版本 |
| `session.created` / `session.destroyed` / `session.exited` / `session.list` | — | 会话生命周期与列表 |
| `session.diskDeleted` | `sessionFile, removed` | 磁盘历史会话已删除（全端广播刷新） |
| `command.ack` | `id, clientId` | 命令已写出的实际 id |
| `response` | `runtimeId, response` | Pi 命令应答 |
| `event` | `runtimeId, event` | Pi Agent 事件流（原始透传） |
| `ui.request` | `runtimeId, request` | 扩展 UI 请求 |
| `stderr` | `runtimeId, text` | pi 子进程 stderr |
| `oneshot.event` / `oneshot.done` | — | 一次性调用事件流 |

---

## 快速开始

前置：Node ≥ 18，且已安装 Pi（`npm install -g --ignore-scripts @earendil-works/pi-coding-agent` 或 `curl -fsSL https://pi.dev/install.sh | sh`）。

```bash
cd pi-web-console
npm install
npm start
```

打开 http://127.0.0.1:4120 即可。点「＋ 新会话」，输入消息回车发送；运行中回车即 **Steer**，或用 **Follow-up / 中止** 按钮。

### 无 API 密钥演示（mock pi）

```bash
npm run demo
```

此时后端用 `node test/mock-pi.js` 模拟 pi 子进程，可完整体验聊天、工具卡、统计、树、分叉等交互，无需任何模型密钥。

### 作为 Pi 插件安装（`pi install`）

本项目内置了一个真正的 Pi Extension（`extensions/web-console.ts`），通过标准的包管理方式分发，无需单独 `git clone`：

```bash
pi install npm:pi-web-console        # 安装到 ~/.pi/agent/
# 或项目内安装（团队共享，随 pi 启动自动安装缺失包）：
pi install -l npm:pi-web-console
```

安装后在任意 pi 会话中输入：

```
/web-console
```

即会以子进程方式拉起 `server/index.js`（默认 `http://127.0.0.1:4120`），并尝试自动打开浏览器；工作目录、会话自动继承当前 pi 会话的 `cwd`。

- `/web-console 8080` — 指定端口启动
- `/web-console stop` — 停止
- 会话退出 / `/reload` 时会自动清理子进程

---

## 配置（`.env`）

复制 `.env.example` 为 `.env`，按需修改。关键项：

| 变量 | 默认 | 说明 |
|---|---|---|
| `HOST` / `PORT` | `127.0.0.1` / `4120` | 监听地址/端口。**默认仅本机** |
| `PI_BIN` | `pi` | pi 可执行文件，可带参数（如 `node test/mock-pi.js`） |
| `PI_SESSION_DIR` | `~/.pi/agent/sessions` | 会话目录（默认与 CLI 共享） |
| `DEFAULT_CWD` | 启动目录 | 新会话默认工作目录 |
| `ALLOWED_CWDS` | 空 | 白名单工作目录（安全） |
| `PI_APPROVE` | `false` | 是否 `--approve` 信任项目本地文件 |
| `PI_EXTRA_ARGS` | 空 | 透传给 pi 的额外参数（逗号分隔） |
| `AUTH_TOKEN` | 空 | 设置后 REST/WS 需携带 token |
| `MAX_SESSIONS` | `20` | 最大同时会话数 |

---

## 安全须知（重要）

⚠️ 本应用让浏览器驱动 `pi`，而 `pi` 可在机器上执行 `bash` 等工具。默认只绑定 `127.0.0.1`。**不要**在没有鉴权与可信网络的前提下暴露到公网。

- 保持 `HOST=127.0.0.1`；确需远程访问时务必设置 `AUTH_TOKEN` 并走 HTTPS 反向代理。
- 用 `ALLOWED_CWDS` 把会话限制在指定项目目录。
- 需要权限门禁/沙箱时，可结合 Pi 扩展（permission-gate、sandbox、protected-paths）或把 pi 跑进容器（见 Pi 官方 Containerization 文档）。

---

## 项目结构

```
pi-web-console/
├── server/
│   ├── index.js             # HTTP + WebSocket 服务入口、REST、鉴权
│   ├── config.js            # 环境配置
│   ├── jsonl.js             # 严格 JSONL 读取器（仅 \n 切分）
│   ├── pi-rpc-session.js    # PiRpcSession：spawn pi --mode rpc 并桥接
│   ├── session-manager.js   # 会话管理 + 磁盘会话枚举
│   ├── one-shot.js          # pi --mode json 一次性调用
│   └── check-pi.js          # pi 可用性探测
├── public/
│   ├── index.html
│   ├── css/style.css
│   └── js/ (app.js, ws.js, markdown.js)
└── test/
    ├── mock-pi.js           # 模拟 pi（无密钥演示/测试）
    └── smoke.mjs            # 后端桥接冒烟测试
```

---

## 测试

```bash
npm run smoke   # 用 mock pi 验证 JSONL 桥接（事件流 + 响应关联）
```

---

## 参考

- [Pi 官网](https://pi.dev/) · [RPC 模式文档](https://pi.dev/docs/latest/rpc) · [JSON 事件流](https://pi.dev/docs/latest/json)
- [Pi 源码（earendil-works/pi）](https://github.com/earendil-works/pi/tree/main/packages/coding-agent)
- 真实世界集成参考：[OpenClaw](https://github.com/OpenClaw/OpenClaw)
