pi-web-ui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +163 -0
- package/bin/pi-web-ui.mjs +9 -0
- package/deploy/com.xingshuyin.pi-web-ui.plist +48 -0
- package/deploy/pi-web-ui.service +31 -0
- package/dist/server/agent-service.js +1155 -0
- package/dist/server/index.js +214 -0
- package/dist/server/protocol.js +6 -0
- package/dist/server/serialize.js +157 -0
- package/dist/server/terminals.js +286 -0
- package/package.json +78 -0
- package/web/dist/assets/index-C-MVz-pL.css +41 -0
- package/web/dist/assets/index-xKwKMfic.js +116 -0
- package/web/dist/index.html +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xing-shuyin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# pi-web-ui
|
|
2
|
+
|
|
3
|
+
A web chat interface for the [pi coding agent](https://pi.dev), built directly on
|
|
4
|
+
the **pi SDK** ([`@earendil-works/pi-coding-agent`](https://www.npmjs.com/package/@earendil-works/pi-coding-agent)) โ
|
|
5
|
+
no subprocess, no JSON-RPC shim. The agent runs in the server process and streams
|
|
6
|
+
events to the browser over WebSocket.
|
|
7
|
+
|
|
8
|
+
Inspired by [Pintra (pi-vsc)](https://github.com/bilalbentoumi/pi-vsc), which does
|
|
9
|
+
the same thing inside VS Code by spawning `pi --mode rpc`. This project instead
|
|
10
|
+
uses the SDK's `createAgentSessionRuntime` API in-process (the SDK docs recommend
|
|
11
|
+
this over RPC for Node.js apps), so you get type safety, direct state access, and
|
|
12
|
+
your existing pi auth/config/extensions โ nothing extra to install or configure.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- ๐ง Full agent loop with **thinking** blocks (collapsible) and streaming text
|
|
17
|
+
- ๐ Tool execution cards with **live output streaming**, status (queued โ running โ done/error), and copyable arguments
|
|
18
|
+
- ๐ฌ Session **history persisted per browser** (localStorage clientId + per-client session dirs) โ refresh or restart and your chats come back. The conversation panel also lists the pi CLI/TUI sessions for the current folder (tagged `TUI`), so you can resume a terminal conversation from the web UI
|
|
19
|
+
- ๐ Model & thinking-level cycling (same as pi's TUI), new chat, abort/stop
|
|
20
|
+
- ๐ Markdown rendering with GFM tables, syntax-highlighted code blocks and copy buttons
|
|
21
|
+
- ๐ Workspace-aware: the agent reads/edits/runs code in a configurable directory using **your** `~/.pi/agent` auth, models, skills and extensions
|
|
22
|
+
- ๐ Multiple browser clients each get an isolated session (private session dir per clientId)
|
|
23
|
+
- ๐ฅ Built-in **terminal** (xterm.js + node-pty, no VS Code needed): three panes โ a
|
|
24
|
+
**command list** on the left (user-defined commands with `${pwd}` support, persisted in
|
|
25
|
+
the project's `.pi/commands.json`), the **terminal** in the middle, and a VSCode-style
|
|
26
|
+
**tab strip** on the right for multiple concurrent shells. Switch between chat and
|
|
27
|
+
terminal views with the toggle in the top bar.
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
Requires Node.js โฅ 20.11 and a configured pi install (run `pi` once to log in).
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install
|
|
35
|
+
npm run dev # server on :8787, web UI on :5173 (auto-proxied)
|
|
36
|
+
# open http://localhost:5173
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Production:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm run build # compiles server (tsc) + frontend (vite)
|
|
43
|
+
npm start # serves everything on http://localhost:8787
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
| Env var | Default | Description |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `PORT` | `8787` | HTTP/WebSocket port |
|
|
51
|
+
| `PI_WEB_CWD` | server's cwd | The workspace directory the agent operates in (read/edit/bash/write) |
|
|
52
|
+
| `PI_WEB_DATA_DIR` | `<cwd>/.pi-web` | Where per-client session dirs are stored |
|
|
53
|
+
| `PI_WEB_INLINE_FILE_MAX` | `12288` (12KB) | Text attachments at or below this size are inlined into the model context; larger files are passed as path references and the model reads them on demand (saves tokens for small edits) |
|
|
54
|
+
| `PI_CODING_AGENT_DIR` | `~/.pi/agent` | pi config dir (auth.json, models.json, skills, extensions) |
|
|
55
|
+
|
|
56
|
+
Example โ point the agent at a project:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
PI_WEB_CWD=/path/to/your/project npm run dev
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Architecture
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Browser (React + Vite)
|
|
66
|
+
โ WebSocket JSON โ snapshot-driven protocol (server/protocol.ts)
|
|
67
|
+
โผ
|
|
68
|
+
server/index.ts express static + ws endpoint
|
|
69
|
+
โ
|
|
70
|
+
server/agent-service.ts per-client ClientSession:
|
|
71
|
+
โ createAgentSessionRuntime({ sessionManager: SessionManager.continueRecent(cwd, sessionDir) })
|
|
72
|
+
โ session.subscribe(events) โ throttled full-state snapshots + live tool deltas
|
|
73
|
+
โผ
|
|
74
|
+
@earendil-works/pi-coding-agent (SDK, in-process)
|
|
75
|
+
โ ModelRuntime (auth from ~/.pi/agent) ยท tools ยท extensions ยท skills
|
|
76
|
+
โผ
|
|
77
|
+
your LLM provider
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Key design points:
|
|
81
|
+
|
|
82
|
+
- **Snapshot-driven UI.** The server is the source of truth: after every SDK
|
|
83
|
+
event it schedules a throttled (60 ms) full-state snapshot, and the browser
|
|
84
|
+
renders purely from snapshots. Reconnects just re-request `get_state`. Large
|
|
85
|
+
payloads (tool output, text) are capped during serialization (`server/serialize.ts`).
|
|
86
|
+
- **Size-aware attachments.** Clicking + on a file queues it as an attachment
|
|
87
|
+
(shown as chips above the input). On send, the server attaches each file as an
|
|
88
|
+
independent custom message (SDK `sendCustomMessage` + `nextTurn` asides) โ the
|
|
89
|
+
user message stays clean, and each file renders as its own collapsible card:
|
|
90
|
+
small text files (โค `PI_WEB_INLINE_FILE_MAX`, default 12KB) are inlined so the
|
|
91
|
+
model sees them immediately; larger files are passed as a `<file path=...>`
|
|
92
|
+
reference and the model reads them on demand with its `read` tool, so attaching
|
|
93
|
+
a 5 MB file costs only a few tokens until the model actually looks at it.
|
|
94
|
+
Images are always attached as image content.
|
|
95
|
+
- **Live tool output.** `bash_execution_update` / `tool_execution_update` events
|
|
96
|
+
are forwarded as lightweight `tool_delta` messages so terminal output streams
|
|
97
|
+
in real time; the final output arrives in the toolResult message on the next
|
|
98
|
+
snapshot, which supersedes the delta buffer.
|
|
99
|
+
- **Isolated sessions.** Each browser client gets `sessions/<clientId>/` under
|
|
100
|
+
the data dir, resumed on reconnect via `SessionManager.continueRecent`.
|
|
101
|
+
- **Everything you already have.** No separate auth step โ the SDK reads
|
|
102
|
+
`~/.pi/agent/auth.json` and loads your global extensions/skills automatically.
|
|
103
|
+
|
|
104
|
+
## Terminal
|
|
105
|
+
|
|
106
|
+
Toggle the terminal view from the top bar (ๅฏน่ฏ/็ป็ซฏ). It replaces the chat layout
|
|
107
|
+
with three panes:
|
|
108
|
+
|
|
109
|
+
- **Left โ ๅฝไปค (commands)**: click a command to open a terminal tab in its directory and
|
|
110
|
+
run it. Add/edit/delete commands in the panel; they are saved to
|
|
111
|
+
`<project>/.pi/commands.json` (committed to the repo, shared with teammates):
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"commands": [
|
|
116
|
+
{ "name": "dev", "command": "npm run dev", "cwd": "${pwd}" },
|
|
117
|
+
{ "name": "test", "command": "npm test", "cwd": "${pwd}/server" },
|
|
118
|
+
{ "name": "build", "command": "npm run build", "cwd": "~/other-project" }
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`${pwd}` resolves to the agent's current working directory (the one shown in the chat
|
|
124
|
+
view's file panel, changeable via set_cwd); `~` and relative paths also work. The `+`
|
|
125
|
+
button at the top of the command panel creates a new entry.
|
|
126
|
+
|
|
127
|
+
- **Middle โ the terminal**: each tab is a real PTY (your `$SHELL`); output streams live
|
|
128
|
+
and you can type, Ctrl+C, resize, etc. exactly like a desktop terminal.
|
|
129
|
+
|
|
130
|
+
- **Right โ ็ป็ซฏ (tabs)**: VSCode-style vertical tab strip. `+` opens a plain shell in the
|
|
131
|
+
current directory. Closing a tab kills its process.
|
|
132
|
+
|
|
133
|
+
Notes:
|
|
134
|
+
|
|
135
|
+
- Running commands keep running while you switch back to the chat view.
|
|
136
|
+
- Terminals are killed when the last browser tab for a client disconnects (no orphaned
|
|
137
|
+
dev servers), so a dropped connection resets the terminal view.
|
|
138
|
+
|
|
139
|
+
## Protocol
|
|
140
|
+
|
|
141
|
+
See `server/protocol.ts` for the full wire format. Client โ server: `hello`,
|
|
142
|
+
`prompt`, `abort`, `new_chat`, `cycle_model`, `cycle_thinking`, `get_state`,
|
|
143
|
+
`list_sessions`, `switch_session`, `list_files`, `list_models`, `set_model`,
|
|
144
|
+
`set_thinking`, `set_cwd`, `complete_path`, `dialog_response`,
|
|
145
|
+
`terminal_create`, `terminal_input`, `terminal_resize`, `terminal_kill`,
|
|
146
|
+
`run_command`, `list_commands`, `save_commands`.
|
|
147
|
+
Server โ client: `ready`, `snapshot` (full `UiState`), `tool_delta`, `notice`,
|
|
148
|
+
`terminal_output`, `terminal_exit`, `commands`.
|
|
149
|
+
|
|
150
|
+
## Scripts
|
|
151
|
+
|
|
152
|
+
| Script | What it does |
|
|
153
|
+
| --- | --- |
|
|
154
|
+
| `npm run dev` | server (tsx watch) + Vite dev server with WS proxy |
|
|
155
|
+
| `npm run build` | type-check + build frontend and server |
|
|
156
|
+
| `npm start` | run the production server (serves `web/dist`) |
|
|
157
|
+
| `npm run typecheck` | `tsc --noEmit` for both server and web |
|
|
158
|
+
| `node terminal-smoke-test.mjs` | WS-level terminal/commands protocol test (build first) |
|
|
159
|
+
| `node terminal-browser-test.mjs` | headless-browser E2E of the terminal view (build first) |
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* pi-web-ui CLI entry.
|
|
4
|
+
*
|
|
5
|
+
* Starts the production server (serves the built frontend + WebSocket API).
|
|
6
|
+
* Env vars: PORT (default 8787), PI_WEB_CWD, PI_WEB_DATA_DIR, PI_CODING_AGENT_DIR.
|
|
7
|
+
* See README.md for details.
|
|
8
|
+
*/
|
|
9
|
+
import "../dist/server/index.js";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<!--
|
|
4
|
+
pi-web-ui launchd agent โ macOS auto-start at login.
|
|
5
|
+
|
|
6
|
+
Install:
|
|
7
|
+
npm i -g pi-web-ui
|
|
8
|
+
cp deploy/com.xingshuyin.pi-web-ui.plist ~/Library/LaunchAgents/
|
|
9
|
+
# edit ProgramArguments / WorkingDirectory / PI_WEB_CWD for your setup
|
|
10
|
+
launchctl load ~/Library/LaunchAgents/com.xingshuyin.pi-web-ui.plist
|
|
11
|
+
# (or: launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.xingshuyin.pi-web-ui.plist)
|
|
12
|
+
|
|
13
|
+
Find the pi-web-ui binary path with: which pi-web-ui
|
|
14
|
+
-->
|
|
15
|
+
<plist version="1.0">
|
|
16
|
+
<dict>
|
|
17
|
+
<key>Label</key>
|
|
18
|
+
<string>com.xingshuyin.pi-web-ui</string>
|
|
19
|
+
|
|
20
|
+
<key>ProgramArguments</key>
|
|
21
|
+
<array>
|
|
22
|
+
<string>/usr/local/bin/pi-web-ui</string>
|
|
23
|
+
</array>
|
|
24
|
+
|
|
25
|
+
<key>RunAtLoad</key>
|
|
26
|
+
<true/>
|
|
27
|
+
|
|
28
|
+
<!-- Restart if it crashes -->
|
|
29
|
+
<key>KeepAlive</key>
|
|
30
|
+
<true/>
|
|
31
|
+
|
|
32
|
+
<key>WorkingDirectory</key>
|
|
33
|
+
<string>/Users/YOUR_USER</string>
|
|
34
|
+
|
|
35
|
+
<key>EnvironmentVariables</key>
|
|
36
|
+
<dict>
|
|
37
|
+
<key>PORT</key>
|
|
38
|
+
<string>8787</string>
|
|
39
|
+
<key>PI_WEB_CWD</key>
|
|
40
|
+
<string>/Users/YOUR_USER</string>
|
|
41
|
+
</dict>
|
|
42
|
+
|
|
43
|
+
<key>StandardOutPath</key>
|
|
44
|
+
<string>/tmp/pi-web-ui.log</string>
|
|
45
|
+
<key>StandardErrorPath</key>
|
|
46
|
+
<string>/tmp/pi-web-ui.err</string>
|
|
47
|
+
</dict>
|
|
48
|
+
</plist>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# pi-web-ui systemd unit โ Linux auto-start on boot.
|
|
2
|
+
#
|
|
3
|
+
# Install (adjust User/WorkingDirectory/Environment to taste):
|
|
4
|
+
# sudo npm i -g pi-web-ui
|
|
5
|
+
# sudo cp deploy/pi-web-ui.service /etc/systemd/system/
|
|
6
|
+
# sudo systemctl daemon-reload
|
|
7
|
+
# sudo systemctl enable --now pi-web-ui
|
|
8
|
+
# sudo systemctl status pi-web-ui
|
|
9
|
+
#
|
|
10
|
+
# Logs: journalctl -u pi-web-ui -f
|
|
11
|
+
|
|
12
|
+
[Unit]
|
|
13
|
+
Description=pi-web-ui โ web chat for the pi coding agent
|
|
14
|
+
After=network.target
|
|
15
|
+
|
|
16
|
+
[Service]
|
|
17
|
+
Type=simple
|
|
18
|
+
# Run as an unprivileged user (change to your user, e.g. yourname)
|
|
19
|
+
User=YOUR_USER
|
|
20
|
+
# The workspace the agent operates in (read/edit/bash/write)
|
|
21
|
+
WorkingDirectory=/home/YOUR_USER
|
|
22
|
+
Environment=PORT=8787
|
|
23
|
+
# Point at your pi config dir if it's not the default ~/.pi/agent
|
|
24
|
+
#Environment=PI_CODING_AGENT_DIR=/home/YOUR_USER/.pi/agent
|
|
25
|
+
ExecStart=/usr/bin/pi-web-ui
|
|
26
|
+
Restart=on-failure
|
|
27
|
+
RestartSec=5
|
|
28
|
+
# npm global bin may live elsewhere (nvm, etc.) โ find with: which pi-web-ui
|
|
29
|
+
|
|
30
|
+
[Install]
|
|
31
|
+
WantedBy=multi-user.target
|