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,609 @@
|
|
|
1
|
+
# WebSocket Protocol
|
|
2
|
+
|
|
3
|
+
This document describes the full WebSocket protocol used for real-time communication between the browser client and the ai-or-die server.
|
|
4
|
+
|
|
5
|
+
## Connection
|
|
6
|
+
|
|
7
|
+
Clients connect to the WebSocket server at:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
ws://localhost:{port}?token={authToken}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or with HTTPS:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
wss://localhost:{port}?token={authToken}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If a `sessionId` query parameter is provided, the server will automatically join the client to that session after the connection handshake:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
ws://localhost:{port}?token={authToken}&sessionId={sessionId}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
All messages are JSON-encoded strings. Every message has a `type` field that identifies the message kind.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Client-to-Server Messages
|
|
30
|
+
|
|
31
|
+
### `create_session`
|
|
32
|
+
|
|
33
|
+
Create a new session and automatically join it.
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"type": "create_session",
|
|
38
|
+
"name": "My Session",
|
|
39
|
+
"workingDir": "/home/user/project"
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Field | Type | Required | Description |
|
|
44
|
+
|-------|------|----------|-------------|
|
|
45
|
+
| `name` | string | No | Human-readable session name. Defaults to `"Session {timestamp}"`. |
|
|
46
|
+
| `workingDir` | string | No | Working directory for the session. Must be within the server's base directory. Defaults to the selected working directory or the server's base folder. |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### `join_session`
|
|
51
|
+
|
|
52
|
+
Join an existing session. Receives the output buffer for replay.
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"type": "join_session",
|
|
57
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Field | Type | Required | Description |
|
|
62
|
+
|-------|------|----------|-------------|
|
|
63
|
+
| `sessionId` | string (UUID) | Yes | The ID of the session to join. |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### `leave_session`
|
|
68
|
+
|
|
69
|
+
Disconnect from the current session without stopping the CLI process.
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"type": "leave_session"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
No additional fields. The server removes the WebSocket connection from the session's connection set but leaves the CLI process running.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### `start_claude`
|
|
82
|
+
|
|
83
|
+
Start the Claude CLI in the current session.
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"type": "start_claude",
|
|
88
|
+
"options": {
|
|
89
|
+
"dangerouslySkipPermissions": false,
|
|
90
|
+
"cols": 120,
|
|
91
|
+
"rows": 40
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
| Field | Type | Required | Description |
|
|
97
|
+
|-------|------|----------|-------------|
|
|
98
|
+
| `options.dangerouslySkipPermissions` | boolean | No | Pass `--dangerously-skip-permissions` to the Claude CLI. Default `false`. |
|
|
99
|
+
| `options.cols` | number | No | Terminal width in columns. Default `80`. |
|
|
100
|
+
| `options.rows` | number | No | Terminal height in rows. Default `24`. |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### `start_codex`
|
|
105
|
+
|
|
106
|
+
Start the Codex CLI in the current session.
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"type": "start_codex",
|
|
111
|
+
"options": {
|
|
112
|
+
"dangerouslySkipPermissions": false,
|
|
113
|
+
"cols": 120,
|
|
114
|
+
"rows": 40
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Field | Type | Required | Description |
|
|
120
|
+
|-------|------|----------|-------------|
|
|
121
|
+
| `options.dangerouslySkipPermissions` | boolean | No | Pass `--dangerously-bypass-approvals-and-sandbox` to the Codex CLI. Default `false`. |
|
|
122
|
+
| `options.cols` | number | No | Terminal width in columns. Default `80`. |
|
|
123
|
+
| `options.rows` | number | No | Terminal height in rows. Default `24`. |
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### `start_agent`
|
|
128
|
+
|
|
129
|
+
Start the Cursor Agent CLI in the current session.
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"type": "start_agent",
|
|
134
|
+
"options": {
|
|
135
|
+
"cols": 120,
|
|
136
|
+
"rows": 40
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
| Field | Type | Required | Description |
|
|
142
|
+
|-------|------|----------|-------------|
|
|
143
|
+
| `options.cols` | number | No | Terminal width in columns. Default `80`. |
|
|
144
|
+
| `options.rows` | number | No | Terminal height in rows. Default `24`. |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `input`
|
|
149
|
+
|
|
150
|
+
Send user input (keystrokes) to the running CLI process.
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"type": "input",
|
|
155
|
+
"data": "hello world\r"
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
| Field | Type | Required | Description |
|
|
160
|
+
|-------|------|----------|-------------|
|
|
161
|
+
| `data` | string | Yes | Raw terminal input data. Use `\r` for Enter. |
|
|
162
|
+
|
|
163
|
+
The server validates that the sending WebSocket connection belongs to the target session and that a CLI process is actively running before forwarding the input. If no agent is running, the server responds with an `info` or `error` message.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### `resize`
|
|
168
|
+
|
|
169
|
+
Update the terminal dimensions for the running CLI process.
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"type": "resize",
|
|
174
|
+
"cols": 120,
|
|
175
|
+
"rows": 40
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
| Field | Type | Required | Description |
|
|
180
|
+
|-------|------|----------|-------------|
|
|
181
|
+
| `cols` | number | Yes | New terminal width in columns. |
|
|
182
|
+
| `rows` | number | Yes | New terminal height in rows. |
|
|
183
|
+
|
|
184
|
+
Resize is silently ignored if no agent is currently running.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### `stop`
|
|
189
|
+
|
|
190
|
+
Terminate the running CLI process in the current session.
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"type": "stop"
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
No additional fields. The server sends `SIGTERM` to the process, then `SIGKILL` after a 5-second timeout if the process has not exited. The appropriate `*_stopped` message is broadcast to all connected clients.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
### `ping`
|
|
203
|
+
|
|
204
|
+
Keepalive ping. The server responds with `pong`.
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"type": "ping"
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### `get_usage`
|
|
215
|
+
|
|
216
|
+
Request current usage statistics (token counts, costs, burn rate, session timer).
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"type": "get_usage"
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
No additional fields. The server reads Claude's JSONL usage logs, calculates analytics, and responds with a `usage_update` message.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Server-to-Client Messages
|
|
229
|
+
|
|
230
|
+
### `connected`
|
|
231
|
+
|
|
232
|
+
Sent immediately after the WebSocket connection is established.
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"type": "connected",
|
|
237
|
+
"connectionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
| Field | Type | Description |
|
|
242
|
+
|-------|------|-------------|
|
|
243
|
+
| `connectionId` | string (UUID) | Unique identifier for this WebSocket connection. |
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### `session_created`
|
|
248
|
+
|
|
249
|
+
Confirmation that a new session was created and the client has joined it.
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"type": "session_created",
|
|
254
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
255
|
+
"sessionName": "My Session",
|
|
256
|
+
"workingDir": "/home/user/project"
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Field | Type | Description |
|
|
261
|
+
|-------|------|-------------|
|
|
262
|
+
| `sessionId` | string (UUID) | The new session's unique identifier. |
|
|
263
|
+
| `sessionName` | string | The human-readable session name. |
|
|
264
|
+
| `workingDir` | string | The resolved working directory. |
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### `session_joined`
|
|
269
|
+
|
|
270
|
+
Confirmation that the client has joined an existing session. Includes the output buffer for replaying recent terminal output.
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"type": "session_joined",
|
|
275
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
276
|
+
"sessionName": "My Session",
|
|
277
|
+
"workingDir": "/home/user/project",
|
|
278
|
+
"active": true,
|
|
279
|
+
"outputBuffer": ["line1\r\n", "line2\r\n"]
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
| Field | Type | Description |
|
|
284
|
+
|-------|------|-------------|
|
|
285
|
+
| `sessionId` | string (UUID) | The session's unique identifier. |
|
|
286
|
+
| `sessionName` | string | The human-readable session name. |
|
|
287
|
+
| `workingDir` | string | The session's working directory. |
|
|
288
|
+
| `active` | boolean | Whether a CLI process is currently running. |
|
|
289
|
+
| `outputBuffer` | string[] | The last 200 lines of terminal output for replay. |
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### `session_left`
|
|
294
|
+
|
|
295
|
+
Confirmation that the client has left the current session.
|
|
296
|
+
|
|
297
|
+
```json
|
|
298
|
+
{
|
|
299
|
+
"type": "session_left"
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
### `claude_started`
|
|
306
|
+
|
|
307
|
+
Broadcast to all clients in the session when the Claude CLI process starts.
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"type": "claude_started",
|
|
312
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
### `codex_started`
|
|
319
|
+
|
|
320
|
+
Broadcast to all clients in the session when the Codex CLI process starts.
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"type": "codex_started",
|
|
325
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
### `agent_started`
|
|
332
|
+
|
|
333
|
+
Broadcast to all clients in the session when the Cursor Agent CLI process starts.
|
|
334
|
+
|
|
335
|
+
```json
|
|
336
|
+
{
|
|
337
|
+
"type": "agent_started",
|
|
338
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
### `output`
|
|
345
|
+
|
|
346
|
+
Terminal output from the running CLI process. Broadcast to all clients connected to the session.
|
|
347
|
+
|
|
348
|
+
```json
|
|
349
|
+
{
|
|
350
|
+
"type": "output",
|
|
351
|
+
"data": "\u001b[32mHello World\u001b[0m\r\n"
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
| Field | Type | Description |
|
|
356
|
+
|-------|------|-------------|
|
|
357
|
+
| `data` | string | Raw terminal output including ANSI escape sequences. |
|
|
358
|
+
|
|
359
|
+
This is the highest-frequency message type. Output is streamed in real time as the CLI process writes to its PTY.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
### `exit`
|
|
364
|
+
|
|
365
|
+
The CLI process has exited. Broadcast to all clients in the session.
|
|
366
|
+
|
|
367
|
+
```json
|
|
368
|
+
{
|
|
369
|
+
"type": "exit",
|
|
370
|
+
"code": 0,
|
|
371
|
+
"signal": null
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
| Field | Type | Description |
|
|
376
|
+
|-------|------|-------------|
|
|
377
|
+
| `code` | number | The process exit code. `0` indicates success. |
|
|
378
|
+
| `signal` | string \| null | The signal that terminated the process, if any (e.g., `"SIGTERM"`, `"SIGKILL"`). |
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
### `error`
|
|
383
|
+
|
|
384
|
+
An error occurred. Sent to the originating client or broadcast to the session depending on context.
|
|
385
|
+
|
|
386
|
+
```json
|
|
387
|
+
{
|
|
388
|
+
"type": "error",
|
|
389
|
+
"message": "Failed to start Claude Code: command not found"
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
| Field | Type | Description |
|
|
394
|
+
|-------|------|-------------|
|
|
395
|
+
| `message` | string | Human-readable error description. |
|
|
396
|
+
|
|
397
|
+
Common error scenarios:
|
|
398
|
+
- No session joined when trying to start a CLI or send input
|
|
399
|
+
- Agent already running in the session
|
|
400
|
+
- Session not found when joining
|
|
401
|
+
- CLI command not found on the system
|
|
402
|
+
- Path validation failure
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
### `claude_stopped` / `codex_stopped` / `agent_stopped`
|
|
407
|
+
|
|
408
|
+
Broadcast to all clients in the session when the corresponding CLI process is explicitly stopped via the `stop` message.
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"type": "claude_stopped"
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
These messages indicate the process was stopped by user action, as opposed to `exit` which indicates the process terminated on its own.
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
### `usage_update`
|
|
421
|
+
|
|
422
|
+
Response to `get_usage`. Contains comprehensive usage analytics.
|
|
423
|
+
|
|
424
|
+
```json
|
|
425
|
+
{
|
|
426
|
+
"type": "usage_update",
|
|
427
|
+
"sessionStats": {
|
|
428
|
+
"requests": 42,
|
|
429
|
+
"inputTokens": 150000,
|
|
430
|
+
"outputTokens": 85000,
|
|
431
|
+
"cacheCreationTokens": 12000,
|
|
432
|
+
"cacheReadTokens": 45000,
|
|
433
|
+
"cacheTokens": 57000,
|
|
434
|
+
"totalTokens": 235000,
|
|
435
|
+
"totalCost": 4.52,
|
|
436
|
+
"models": {
|
|
437
|
+
"sonnet": { "requests": 40, "inputTokens": 145000, "outputTokens": 82000, "cost": 4.10 },
|
|
438
|
+
"opus": { "requests": 2, "inputTokens": 5000, "outputTokens": 3000, "cost": 0.42 }
|
|
439
|
+
},
|
|
440
|
+
"sessionStartTime": "2025-01-15T10:00:00.000Z",
|
|
441
|
+
"lastUpdate": "2025-01-15T12:30:00.000Z",
|
|
442
|
+
"sessionNumber": 1,
|
|
443
|
+
"isExpired": false
|
|
444
|
+
},
|
|
445
|
+
"dailyStats": {
|
|
446
|
+
"requests": 120,
|
|
447
|
+
"totalTokens": 680000,
|
|
448
|
+
"totalCost": 12.80,
|
|
449
|
+
"periodHours": 24,
|
|
450
|
+
"hourlyRate": 5.0,
|
|
451
|
+
"tokensPerHour": 28333,
|
|
452
|
+
"costPerHour": 0.53
|
|
453
|
+
},
|
|
454
|
+
"sessionTimer": {
|
|
455
|
+
"startTime": "2025-01-15T10:00:00.000Z",
|
|
456
|
+
"elapsed": 9000000,
|
|
457
|
+
"remaining": 9000000,
|
|
458
|
+
"formatted": "02:30:00",
|
|
459
|
+
"remainingFormatted": "02:30",
|
|
460
|
+
"hours": 2,
|
|
461
|
+
"minutes": 30,
|
|
462
|
+
"seconds": 0,
|
|
463
|
+
"remainingMs": 9000000,
|
|
464
|
+
"sessionDurationHours": 5,
|
|
465
|
+
"sessionNumber": 1,
|
|
466
|
+
"isExpired": false,
|
|
467
|
+
"burnRate": 450.5,
|
|
468
|
+
"burnRateConfidence": 0.82,
|
|
469
|
+
"depletionTime": "2025-01-15T14:15:00.000Z",
|
|
470
|
+
"depletionConfidence": 0.75
|
|
471
|
+
},
|
|
472
|
+
"analytics": {
|
|
473
|
+
"currentSession": { "id": "session_1", "startTime": "...", "endTime": "...", "tokens": 235000, "remaining": -15000, "percentUsed": 106.8 },
|
|
474
|
+
"burnRate": { "current": 450.5, "trend": "stable", "history": [] },
|
|
475
|
+
"predictions": { "depletionTime": "...", "confidence": 0.75, "minutesRemaining": 105 },
|
|
476
|
+
"plan": { "type": "max20", "limits": { "tokens": 220000, "cost": 140.00, "messages": 2000 } }
|
|
477
|
+
},
|
|
478
|
+
"burnRate": { "rate": 450.5, "confidence": 0.82, "dataPoints": 42 },
|
|
479
|
+
"overlappingSessions": 0,
|
|
480
|
+
"plan": "max20",
|
|
481
|
+
"limits": { "tokens": 220000, "cost": 140.00, "messages": 2000, "algorithm": "fixed" }
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
### `session_deleted`
|
|
488
|
+
|
|
489
|
+
Sent to all clients connected to a session that has been deleted via the REST API.
|
|
490
|
+
|
|
491
|
+
```json
|
|
492
|
+
{
|
|
493
|
+
"type": "session_deleted",
|
|
494
|
+
"message": "Session has been deleted"
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
After receiving this message, the client's WebSocket connection is closed by the server.
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
### `pong`
|
|
503
|
+
|
|
504
|
+
Response to a `ping` message.
|
|
505
|
+
|
|
506
|
+
```json
|
|
507
|
+
{
|
|
508
|
+
"type": "pong"
|
|
509
|
+
}
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
### `info`
|
|
515
|
+
|
|
516
|
+
Informational message, typically sent when the user attempts to send input without a running agent.
|
|
517
|
+
|
|
518
|
+
```json
|
|
519
|
+
{
|
|
520
|
+
"type": "info",
|
|
521
|
+
"message": "No agent is running. Choose an option to start."
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## Message Flow Diagrams
|
|
528
|
+
|
|
529
|
+
### Full Session Lifecycle
|
|
530
|
+
|
|
531
|
+
```mermaid
|
|
532
|
+
sequenceDiagram
|
|
533
|
+
participant C as Client
|
|
534
|
+
participant S as Server
|
|
535
|
+
|
|
536
|
+
C->>S: WebSocket connect (?token=xxx)
|
|
537
|
+
S->>C: connected {connectionId}
|
|
538
|
+
|
|
539
|
+
C->>S: create_session {name, workingDir}
|
|
540
|
+
S->>C: session_created {sessionId, sessionName, workingDir}
|
|
541
|
+
|
|
542
|
+
C->>S: start_claude {options}
|
|
543
|
+
S->>C: claude_started {sessionId}
|
|
544
|
+
|
|
545
|
+
loop Terminal I/O
|
|
546
|
+
C->>S: input {data}
|
|
547
|
+
S->>C: output {data}
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
C->>S: resize {cols, rows}
|
|
551
|
+
|
|
552
|
+
C->>S: stop
|
|
553
|
+
S->>C: claude_stopped
|
|
554
|
+
|
|
555
|
+
Note over C,S: Or process exits naturally:
|
|
556
|
+
S->>C: exit {code, signal}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Multi-Client Session Sharing
|
|
560
|
+
|
|
561
|
+
```mermaid
|
|
562
|
+
sequenceDiagram
|
|
563
|
+
participant A as Client A
|
|
564
|
+
participant S as Server
|
|
565
|
+
participant B as Client B
|
|
566
|
+
|
|
567
|
+
A->>S: create_session
|
|
568
|
+
S->>A: session_created {sessionId: "abc"}
|
|
569
|
+
|
|
570
|
+
A->>S: start_claude
|
|
571
|
+
S->>A: claude_started
|
|
572
|
+
|
|
573
|
+
B->>S: join_session {sessionId: "abc"}
|
|
574
|
+
S->>B: session_joined {outputBuffer: [...]}
|
|
575
|
+
|
|
576
|
+
Note over A,B: Both clients receive output
|
|
577
|
+
S->>A: output {data}
|
|
578
|
+
S->>B: output {data}
|
|
579
|
+
|
|
580
|
+
Note over A,B: Either client can send input
|
|
581
|
+
B->>S: input {data}
|
|
582
|
+
S->>A: output {response}
|
|
583
|
+
S->>B: output {response}
|
|
584
|
+
|
|
585
|
+
A->>S: leave_session
|
|
586
|
+
S->>A: session_left
|
|
587
|
+
Note over S,B: CLI keeps running for Client B
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
## REST API Endpoints
|
|
591
|
+
|
|
592
|
+
The server also exposes REST endpoints for operations that do not require real-time streaming:
|
|
593
|
+
|
|
594
|
+
| Method | Endpoint | Description |
|
|
595
|
+
|--------|----------|-------------|
|
|
596
|
+
| `GET` | `/auth-status` | Check if authentication is required (no auth needed) |
|
|
597
|
+
| `POST` | `/auth-verify` | Validate an authentication token |
|
|
598
|
+
| `GET` | `/api/health` | Server health check with session/connection counts |
|
|
599
|
+
| `GET` | `/api/config` | Server configuration (folder mode, aliases, base folder) |
|
|
600
|
+
| `GET` | `/api/sessions/list` | List all sessions with metadata |
|
|
601
|
+
| `GET` | `/api/sessions/persistence` | Session storage metadata |
|
|
602
|
+
| `POST` | `/api/sessions/create` | Create a new session (REST alternative to WS) |
|
|
603
|
+
| `GET` | `/api/sessions/:id` | Get session details |
|
|
604
|
+
| `DELETE` | `/api/sessions/:id` | Delete a session and stop its CLI process |
|
|
605
|
+
| `GET` | `/api/folders` | Browse directories (with path validation) |
|
|
606
|
+
| `POST` | `/api/folders/select` | Select a working directory |
|
|
607
|
+
| `POST` | `/api/set-working-dir` | Set the server's default working directory |
|
|
608
|
+
| `POST` | `/api/create-folder` | Create a new directory |
|
|
609
|
+
| `POST` | `/api/close-session` | Clear the selected working directory |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ai-or-die Project History
|
|
2
|
+
|
|
3
|
+
This document records major architectural decisions, intended as a handoff reference for new contributors.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ai-or-die v0.1.0
|
|
8
|
+
|
|
9
|
+
Cortex is a universal AI coding terminal providing browser-based access to multiple CLI tools through a unified interface.
|
|
10
|
+
|
|
11
|
+
### Architecture
|
|
12
|
+
|
|
13
|
+
- **BaseBridge pattern**: All CLI tools extend a shared `BaseBridge` base class with cross-platform command discovery, session lifecycle, and process management. See [ADR-0001](../adrs/0001-bridge-base-class.md).
|
|
14
|
+
|
|
15
|
+
- **Multi-tool support**: Claude, Codex, Copilot, Gemini, and Terminal are supported via the bridge pattern. New tools can be added with a bridge subclass — no client code changes required. See [ADR-0003](../adrs/0003-multi-tool-architecture.md).
|
|
16
|
+
|
|
17
|
+
- **Dev Tunnels**: Remote access uses Microsoft Dev Tunnels (`devtunnel` CLI) instead of third-party tunnel providers. See [ADR-0002](../adrs/0002-devtunnels-over-ngrok.md).
|
|
18
|
+
|
|
19
|
+
- **Cross-platform**: Platform-specific code is centralized in `BaseBridge` using `os.homedir()`, `where`/`which` detection, and ConPTY on Windows. See [ADR-0004](../adrs/0004-cross-platform-support.md).
|
|
20
|
+
|
|
21
|
+
### Key Design Decisions
|
|
22
|
+
|
|
23
|
+
- Session persistence to `~/.ai-or-die/sessions.json` with atomic writes
|
|
24
|
+
- Dynamic UI card generation from server-reported tool availability
|
|
25
|
+
- Token-based auth enabled by default (auto-generated on startup)
|
|
26
|
+
- Express + WebSocket on a single port (default 7777)
|