ai-or-die 0.1.0
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/.cursor/commands/commit-push.md +18 -0
- package/.github/agents/architect.md +26 -0
- package/.github/agents/engineer.md +29 -0
- package/.github/agents/qa-reviewer.md +31 -0
- package/.github/agents/researcher.md +30 -0
- package/.github/agents/troubleshooter.md +33 -0
- package/.github/copilot-instructions.md +55 -0
- package/.github/pull_request_template.md +21 -0
- package/.github/workflows/build-binaries.yml +76 -0
- package/.github/workflows/ci.yml +70 -0
- package/.github/workflows/release-on-main.yml +73 -0
- package/.prompts/log.md +9 -0
- package/AGENTS.md +84 -0
- package/CHANGELOG.md +25 -0
- package/CLAUDE.md +130 -0
- package/CONTRIBUTING.md +76 -0
- package/LICENSE +22 -0
- package/README.md +165 -0
- package/bin/ai-or-die.js +203 -0
- package/docs/.nojekyll +1 -0
- package/docs/README.md +37 -0
- package/docs/adrs/0000-template.md +35 -0
- package/docs/adrs/0001-bridge-base-class.md +53 -0
- package/docs/adrs/0002-devtunnels-over-ngrok.md +56 -0
- package/docs/adrs/0003-multi-tool-architecture.md +71 -0
- package/docs/adrs/0004-cross-platform-support.md +101 -0
- package/docs/adrs/0005-single-binary-distribution.md +58 -0
- package/docs/agent-instructions/00-philosophy.md +55 -0
- package/docs/agent-instructions/01-research-and-web.md +49 -0
- package/docs/agent-instructions/02-testing-and-validation.md +63 -0
- package/docs/agent-instructions/03-tooling-and-pipelines.md +59 -0
- package/docs/architecture/bridge-pattern.md +510 -0
- package/docs/architecture/overview.md +216 -0
- package/docs/architecture/websocket-protocol.md +609 -0
- package/docs/history/README.md +26 -0
- package/docs/specs/authentication.md +167 -0
- package/docs/specs/bridges.md +210 -0
- package/docs/specs/client-app.md +308 -0
- package/docs/specs/e2e-testing.md +311 -0
- package/docs/specs/server.md +334 -0
- package/docs/specs/session-store.md +170 -0
- package/docs/specs/usage-analytics.md +342 -0
- package/nul +0 -0
- package/package.json +54 -0
- package/scripts/build-sea.js +187 -0
- package/scripts/pty-sea-shim.js +21 -0
- package/scripts/publish-both.sh +21 -0
- package/scripts/release-pr.sh +73 -0
- package/scripts/smoke-test-binary.js +190 -0
- package/scripts/validate.ps1 +25 -0
- package/scripts/validate.sh +16 -0
- package/sea-bootstrap.js +54 -0
- package/site/ADVANCED_ANALYTICS.md +174 -0
- package/site/index.html +151 -0
- package/site/script.js +17 -0
- package/site/style.css +60 -0
- package/src/base-bridge.js +340 -0
- package/src/claude-bridge.js +48 -0
- package/src/codex-bridge.js +27 -0
- package/src/copilot-bridge.js +29 -0
- package/src/gemini-bridge.js +26 -0
- package/src/public/app.js +2123 -0
- package/src/public/auth.js +244 -0
- package/src/public/icon-generator.js +26 -0
- package/src/public/icons.js +36 -0
- package/src/public/index.html +397 -0
- package/src/public/manifest.json +45 -0
- package/src/public/plan-detector.js +186 -0
- package/src/public/service-worker.js +108 -0
- package/src/public/session-manager.js +1124 -0
- package/src/public/splits.js +574 -0
- package/src/public/style.css +2090 -0
- package/src/server.js +1269 -0
- package/src/terminal-bridge.js +49 -0
- package/src/usage-analytics.js +494 -0
- package/src/usage-reader.js +895 -0
- package/src/utils/auth.js +123 -0
- package/src/utils/session-store.js +181 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Architecture Overview
|
|
2
|
+
|
|
3
|
+
ai-or-die is a Node.js web application that provides browser-based access to multiple AI CLI tools through a unified terminal interface. It wraps CLI processes (Claude, Codex, Copilot, Gemini, Terminal, and others) in pseudo-terminals and streams their I/O over WebSockets to xterm.js terminals running in the browser.
|
|
4
|
+
|
|
5
|
+
## System Architecture
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
graph TB
|
|
9
|
+
subgraph Browser["Browser Client"]
|
|
10
|
+
UI["app.js<br/>Main Interface Controller"]
|
|
11
|
+
SM["session-manager.js<br/>Tab Management & Notifications"]
|
|
12
|
+
PD["plan-detector.js<br/>Plan Mode Approval UI"]
|
|
13
|
+
XT["xterm.js<br/>Terminal Emulator"]
|
|
14
|
+
AUTH["auth.js<br/>Token Authentication"]
|
|
15
|
+
SW["service-worker.js<br/>PWA / Offline Support"]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
subgraph Transport["Transport Layer"]
|
|
19
|
+
WS["WebSocket (ws)"]
|
|
20
|
+
HTTP["Express HTTP API"]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
subgraph Server["Server Layer"]
|
|
24
|
+
SRV["ClaudeCodeWebServer<br/>src/server.js"]
|
|
25
|
+
SS["SessionStore<br/>~/.claude-code-web/sessions.json"]
|
|
26
|
+
UR["UsageReader<br/>~/.claude/projects/.../*.jsonl"]
|
|
27
|
+
UA["UsageAnalytics<br/>Burn Rate & Predictions"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
subgraph Bridges["Bridge Layer"]
|
|
31
|
+
CB["ClaudeBridge<br/>src/claude-bridge.js"]
|
|
32
|
+
XB["CodexBridge<br/>src/codex-bridge.js"]
|
|
33
|
+
CPB["CopilotBridge<br/>src/copilot-bridge.js"]
|
|
34
|
+
GB["GeminiBridge<br/>src/gemini-bridge.js"]
|
|
35
|
+
TB["TerminalBridge<br/>src/terminal-bridge.js"]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
subgraph CLIs["CLI Processes (node-pty)"]
|
|
39
|
+
CLAUDE["claude CLI"]
|
|
40
|
+
CODEX["codex CLI"]
|
|
41
|
+
COPILOT["copilot CLI"]
|
|
42
|
+
GEMINI["gemini CLI"]
|
|
43
|
+
TERMINAL["terminal CLI"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
UI <--> WS
|
|
47
|
+
SM <--> UI
|
|
48
|
+
PD <--> UI
|
|
49
|
+
XT <--> UI
|
|
50
|
+
AUTH --> HTTP
|
|
51
|
+
AUTH --> WS
|
|
52
|
+
|
|
53
|
+
WS <--> SRV
|
|
54
|
+
HTTP <--> SRV
|
|
55
|
+
|
|
56
|
+
SRV --> SS
|
|
57
|
+
SRV --> UR
|
|
58
|
+
SRV --> UA
|
|
59
|
+
SRV --> CB
|
|
60
|
+
SRV --> XB
|
|
61
|
+
SRV --> CPB
|
|
62
|
+
SRV --> GB
|
|
63
|
+
SRV --> TB
|
|
64
|
+
|
|
65
|
+
CB <--> CLAUDE
|
|
66
|
+
XB <--> CODEX
|
|
67
|
+
CPB <--> COPILOT
|
|
68
|
+
GB <--> GEMINI
|
|
69
|
+
TB <--> TERMINAL
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Component Relationships
|
|
73
|
+
|
|
74
|
+
```mermaid
|
|
75
|
+
graph LR
|
|
76
|
+
subgraph Entry["Entry Point"]
|
|
77
|
+
BIN["bin/ai-or-die.js<br/>Commander.js CLI"]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
subgraph Core["Core Server"]
|
|
81
|
+
SRV["ClaudeCodeWebServer"]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
subgraph Persistence["Persistence"]
|
|
85
|
+
SS["SessionStore"]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
subgraph Analytics["Usage Analytics"]
|
|
89
|
+
UR["UsageReader"]
|
|
90
|
+
UA["UsageAnalytics"]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
subgraph Bridges["Bridges"]
|
|
94
|
+
CB["ClaudeBridge"]
|
|
95
|
+
XB["CodexBridge"]
|
|
96
|
+
CPB["CopilotBridge"]
|
|
97
|
+
GB["GeminiBridge"]
|
|
98
|
+
TB["TerminalBridge"]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
BIN -->|"startServer(options)"| SRV
|
|
102
|
+
SRV -->|"saves/loads sessions"| SS
|
|
103
|
+
SRV -->|"reads JSONL logs"| UR
|
|
104
|
+
SRV -->|"burn rate, predictions"| UA
|
|
105
|
+
SRV -->|"spawns claude"| CB
|
|
106
|
+
SRV -->|"spawns codex"| XB
|
|
107
|
+
SRV -->|"spawns copilot"| CPB
|
|
108
|
+
SRV -->|"spawns gemini"| GB
|
|
109
|
+
SRV -->|"spawns terminal"| TB
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Data Flow
|
|
113
|
+
|
|
114
|
+
### User Input Flow
|
|
115
|
+
|
|
116
|
+
```mermaid
|
|
117
|
+
sequenceDiagram
|
|
118
|
+
participant User as Browser User
|
|
119
|
+
participant XT as xterm.js
|
|
120
|
+
participant WS as WebSocket
|
|
121
|
+
participant SRV as Server
|
|
122
|
+
participant Bridge as Bridge (Claude/Codex/Copilot/Gemini/Terminal)
|
|
123
|
+
participant PTY as node-pty Process
|
|
124
|
+
|
|
125
|
+
User->>XT: Types in terminal
|
|
126
|
+
XT->>WS: {type: "input", data: keystrokes}
|
|
127
|
+
WS->>SRV: handleMessage()
|
|
128
|
+
SRV->>SRV: Validate session membership
|
|
129
|
+
SRV->>Bridge: sendInput(sessionId, data)
|
|
130
|
+
Bridge->>PTY: process.write(data)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Output Broadcast Flow
|
|
134
|
+
|
|
135
|
+
```mermaid
|
|
136
|
+
sequenceDiagram
|
|
137
|
+
participant PTY as node-pty Process
|
|
138
|
+
participant Bridge as Bridge
|
|
139
|
+
participant SRV as Server
|
|
140
|
+
participant WS1 as WebSocket Client A
|
|
141
|
+
participant WS2 as WebSocket Client B
|
|
142
|
+
|
|
143
|
+
PTY->>Bridge: onData(output)
|
|
144
|
+
Bridge->>SRV: onOutput callback
|
|
145
|
+
SRV->>SRV: Append to session outputBuffer
|
|
146
|
+
SRV->>SRV: broadcastToSession()
|
|
147
|
+
par Broadcast to all connected clients
|
|
148
|
+
SRV->>WS1: {type: "output", data: output}
|
|
149
|
+
SRV->>WS2: {type: "output", data: output}
|
|
150
|
+
end
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Session Lifecycle
|
|
154
|
+
|
|
155
|
+
```mermaid
|
|
156
|
+
stateDiagram-v2
|
|
157
|
+
[*] --> Created: create_session
|
|
158
|
+
Created --> Joined: join_session
|
|
159
|
+
Joined --> AgentRunning: start_claude / start_codex / start_copilot / start_gemini / start_terminal
|
|
160
|
+
AgentRunning --> AgentRunning: input / output
|
|
161
|
+
AgentRunning --> Stopped: stop / exit
|
|
162
|
+
Stopped --> AgentRunning: start_claude / start_codex / start_copilot / start_gemini / start_terminal
|
|
163
|
+
Joined --> Left: leave_session
|
|
164
|
+
Left --> Joined: join_session
|
|
165
|
+
Joined --> Deleted: DELETE /api/sessions/:id
|
|
166
|
+
Stopped --> Deleted: DELETE /api/sessions/:id
|
|
167
|
+
Deleted --> [*]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Technology Stack
|
|
171
|
+
|
|
172
|
+
| Layer | Technology | Purpose |
|
|
173
|
+
|-------|-----------|---------|
|
|
174
|
+
| **CLI Entry** | Commander.js | Parse command-line arguments (`--port`, `--auth`, `--https`, etc.) |
|
|
175
|
+
| **HTTP Server** | Express 4.x | REST API, static file serving, authentication middleware |
|
|
176
|
+
| **WebSocket** | ws 8.x | Bidirectional real-time communication between browser and server |
|
|
177
|
+
| **PTY** | node-pty 1.x | Spawn CLI tools in pseudo-terminals with full ANSI/256-color support |
|
|
178
|
+
| **Terminal UI** | xterm.js | Browser-based terminal emulator with fit addon and web links |
|
|
179
|
+
| **Session IDs** | uuid v4 | Unique identifiers for sessions and WebSocket connections |
|
|
180
|
+
| **Tunneling** | devtunnel CLI | Optional public tunnel for remote access |
|
|
181
|
+
| **CORS** | cors | Cross-origin request handling |
|
|
182
|
+
| **PWA** | Service Worker | Progressive Web App support for offline/installable experience |
|
|
183
|
+
|
|
184
|
+
## Key Design Decisions
|
|
185
|
+
|
|
186
|
+
### 1. Bridge-per-CLI Architecture
|
|
187
|
+
|
|
188
|
+
Each supported CLI tool has its own bridge class that extends `BaseBridge` (`ClaudeBridge`, `CodexBridge`, `CopilotBridge`, `GeminiBridge`, `TerminalBridge`). All bridges share an identical interface (`startSession`, `sendInput`, `resize`, `stopSession`, `cleanup`), making it straightforward to add new tools. The server routes messages to the correct bridge based on the `session.agent` field.
|
|
189
|
+
|
|
190
|
+
### 2. Session-Centric Model
|
|
191
|
+
|
|
192
|
+
Sessions are the central organizing concept. A session represents a working directory plus an optional running CLI process. Multiple WebSocket connections can join the same session simultaneously, enabling multi-device access to the same terminal. Sessions persist to disk (`~/.claude-code-web/sessions.json`) and survive server restarts, though the CLI processes themselves do not persist.
|
|
193
|
+
|
|
194
|
+
### 3. Output Buffering for Reconnection
|
|
195
|
+
|
|
196
|
+
Each session maintains a rolling output buffer (last 1000 lines). When a client joins an existing session, the server replays the last 200 lines from the buffer, allowing the user to see recent context without needing the CLI process to re-emit output.
|
|
197
|
+
|
|
198
|
+
### 4. node-pty over child_process
|
|
199
|
+
|
|
200
|
+
The application uses `node-pty` instead of `child_process.spawn` because CLI tools like Claude Code produce rich terminal output (ANSI escape codes, 256-color sequences, cursor movement). A real pseudo-terminal is required to faithfully capture and replay this output. The PTY is configured with `xterm-256color` TERM and `truecolor` COLORTERM.
|
|
201
|
+
|
|
202
|
+
### 5. Authentication by Default
|
|
203
|
+
|
|
204
|
+
The server generates a random authentication token on startup if none is provided. All HTTP endpoints (except `/auth-status`) and WebSocket connections require this token. This prevents accidental exposure of the terminal interface, which has full access to the underlying CLI tools.
|
|
205
|
+
|
|
206
|
+
### 6. Path Validation and Sandboxing
|
|
207
|
+
|
|
208
|
+
The folder browser and working directory selection enforce that all paths remain within the base directory where the server was started (`process.cwd()`). Directory traversal attempts are rejected at both the API and session creation levels.
|
|
209
|
+
|
|
210
|
+
### 7. Graceful Shutdown with Escalation
|
|
211
|
+
|
|
212
|
+
When stopping a CLI process, the server sends `SIGTERM` first, then escalates to `SIGKILL` after a 5-second timeout if the process has not exited. This matches standard Unix process management and gives CLI tools a chance to clean up.
|
|
213
|
+
|
|
214
|
+
### 8. Auto-Save with Atomic Writes
|
|
215
|
+
|
|
216
|
+
Sessions are automatically saved to disk every 30 seconds. The save operation writes to a temporary file first, then renames it atomically to prevent corruption from interrupted writes. Sessions older than 7 days are discarded on load.
|