aigo 1.0.0 → 1.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/Makefile ADDED
@@ -0,0 +1,4 @@
1
+ .PHONY: publish-minor
2
+ publish-minor:
3
+ npm version minor
4
+ npm publish
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # vigo
1
+ # aigo
2
2
 
3
3
  Stream AI coding assistants to the web - run Claude Code or Cursor Agent remotely from any device.
4
4
 
5
- **vigo** wraps Claude Code or Cursor Agent in a tmux session and streams it to your browser via WebSocket, letting you access your AI coding sessions from your phone, tablet, or any browser.
5
+ **aigo** wraps Claude Code or Cursor Agent in a tmux session and streams it to your browser via WebSocket, letting you access your AI coding sessions from your phone, tablet, or any browser.
6
6
 
7
7
  ## Quick Start
8
8
 
@@ -14,13 +14,13 @@ npm install
14
14
  npm link
15
15
 
16
16
  # Start Claude Code with web access (ngrok tunnel enabled by default)
17
- vigo claude
17
+ aigo claude
18
18
 
19
19
  # Or start Cursor Agent
20
- vigo cursor
20
+ aigo cursor
21
21
 
22
22
  # Local only (no tunnel)
23
- vigo --tunnel none claude
23
+ aigo --tunnel none claude
24
24
  ```
25
25
 
26
26
  ## Requirements
@@ -29,7 +29,8 @@ vigo --tunnel none claude
29
29
  - **tmux** installed and in PATH
30
30
  - **Claude Code CLI** installed (`claude` command) - for Claude Code support
31
31
  - **Cursor Agent CLI** installed (`agent` command) - for Cursor support
32
- - **ngrok** (required for default remote access) - sign up at [ngrok.com](https://ngrok.com)
32
+ - **ngrok** (default for remote access) - sign up at [ngrok.com](https://ngrok.com)
33
+ - **cloudflared** (alternative to ngrok) - free, no signup required
33
34
 
34
35
  ### Installing tmux
35
36
 
@@ -56,6 +57,23 @@ brew install ngrok
56
57
  ngrok config add-authtoken YOUR_TOKEN
57
58
  ```
58
59
 
60
+ ### Installing cloudflared
61
+
62
+ cloudflared is a free alternative to ngrok that doesn't require signup:
63
+
64
+ ```bash
65
+ # macOS
66
+ brew install cloudflared
67
+
68
+ # Ubuntu/Debian
69
+ curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
70
+ sudo dpkg -i cloudflared.deb
71
+
72
+ # Or download from https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
73
+ ```
74
+
75
+ No authentication required for quick tunnels (trycloudflare.com).
76
+
59
77
  ### Installing Cursor Agent CLI
60
78
 
61
79
  ```bash
@@ -72,10 +90,10 @@ export CURSOR_API_KEY=your_api_key_here
72
90
  ## Usage
73
91
 
74
92
  ```
75
- vigo [options] claude [claude-args]
76
- vigo [options] cursor [cursor-args]
77
- vigo [options] agent [agent-args]
78
- vigo [options] --attach <session>
93
+ aigo [options] claude [claude-args]
94
+ aigo [options] cursor [cursor-args]
95
+ aigo [options] agent [agent-args]
96
+ aigo [options] --attach <session>
79
97
 
80
98
  Tools:
81
99
  claude Use Claude Code CLI
@@ -97,26 +115,26 @@ Options:
97
115
 
98
116
  ```bash
99
117
  # Claude Code Examples (ngrok tunnel by default)
100
- vigo claude # Start Claude with ngrok tunnel
101
- vigo --tunnel none claude # Local only (no tunnel)
102
- vigo -p 8080 -s myproject claude # Custom port and session
103
- vigo claude --model sonnet # Pass args to Claude
118
+ aigo claude # Start Claude with ngrok tunnel
119
+ aigo --tunnel none claude # Local only (no tunnel)
120
+ aigo -p 8080 -s myproject claude # Custom port and session
121
+ aigo claude --model sonnet # Pass args to Claude
104
122
 
105
123
  # Cursor Agent Examples
106
- vigo cursor # Start Cursor Agent with ngrok tunnel
107
- vigo --tunnel cloudflared cursor # Use cloudflared instead of ngrok
108
- vigo -p 8080 -s myproject cursor # Custom port and session
109
- vigo cursor --model gpt-5 # Pass args to Cursor Agent
124
+ aigo cursor # Start Cursor Agent with ngrok tunnel
125
+ aigo --tunnel cloudflared cursor # Use cloudflared instead of ngrok
126
+ aigo -p 8080 -s myproject cursor # Custom port and session
127
+ aigo cursor --model gpt-5 # Pass args to Cursor Agent
110
128
 
111
129
  # General Examples
112
- vigo --attach myproject # Attach to existing tmux session
113
- vigo -P mypass123 claude # Custom password
114
- vigo -T 15 -E 30 cursor # 15min lock, 30min exit timeout
115
- vigo -T 0 -E 0 claude # Disable timeouts (default behavior)
130
+ aigo --attach myproject # Attach to existing tmux session
131
+ aigo -P mypass123 claude # Custom password
132
+ aigo -T 15 -E 30 cursor # 15min lock, 30min exit timeout
133
+ aigo -T 0 -E 0 claude # Disable timeouts (default behavior)
116
134
 
117
135
  # Run multiple sessions (ports auto-selected)
118
- vigo -s project-a claude # Gets port 3000
119
- vigo -s project-b cursor # Gets port 3001 (auto)
136
+ aigo -s project-a claude # Gets port 3000
137
+ aigo -s project-b cursor # Gets port 3001 (auto)
120
138
  ```
121
139
 
122
140
  ## Configuration
@@ -144,17 +162,42 @@ export const config = {
144
162
  };
145
163
  ```
146
164
 
165
+ ## Tunnel Options
166
+
167
+ aigo supports two tunnel providers for remote access:
168
+
169
+ | Feature | ngrok | cloudflared |
170
+ |---------|-------|-------------|
171
+ | Signup required | Yes | No |
172
+ | Free tier limits | 1 tunnel, rate limits | Unlimited quick tunnels |
173
+ | Custom domains | Paid plans | Requires Cloudflare account |
174
+ | URL format | `*.ngrok-free.app` | `*.trycloudflare.com` |
175
+ | Authentication | Required (authtoken) | Not required |
176
+
177
+ **Recommendation:** Use cloudflared for quick testing (no signup needed). Use ngrok if you need stable URLs or have an existing account.
178
+
179
+ ```bash
180
+ # Use cloudflared (no signup required)
181
+ aigo --tunnel cloudflared claude
182
+
183
+ # Use ngrok (default, requires signup)
184
+ aigo claude
185
+
186
+ # Local only (no tunnel)
187
+ aigo --tunnel none claude
188
+ ```
189
+
147
190
  ## How It Works
148
191
 
149
- 1. **vigo** creates a tmux session and runs `claude` or `agent` inside it
192
+ 1. **aigo** creates a tmux session and runs `claude` or `agent` inside it
150
193
  2. A local web server starts, serving an xterm.js terminal
151
194
  3. The server attaches to the tmux session via node-pty
152
195
  4. Your browser connects via WebSocket for real-time terminal streaming
153
- 5. ngrok creates a public HTTPS tunnel for remote access (default)
196
+ 5. A tunnel (ngrok or cloudflared) creates a public HTTPS URL for remote access
154
197
 
155
198
  ```
156
199
  ┌────────────────────────────────────────┐
157
- vigo - Claude Code Web Terminal │
200
+ aigo - Claude Code Web Terminal │
158
201
  ├────────────────────────────────────────┤
159
202
  │ Session: claude-code │
160
203
  │ Local: http://localhost:3000 │
@@ -171,7 +214,7 @@ Access URL:
171
214
 
172
215
  | Feature | Claude Code | Cursor Agent |
173
216
  |---------|-------------|--------------|
174
- | Command | `vigo claude` | `vigo cursor` |
217
+ | Command | `aigo claude` | `aigo cursor` |
175
218
  | CLI Binary | `claude` | `agent` |
176
219
  | Authentication | Claude API key / OAuth | Browser login or `CURSOR_API_KEY` |
177
220
  | Models | Claude models | Multiple (GPT-5, Claude, etc.) via subscription |
@@ -181,7 +224,7 @@ Access URL:
181
224
 
182
225
  ## Security
183
226
 
184
- vigo uses multiple layers of security:
227
+ aigo uses multiple layers of security:
185
228
 
186
229
  1. **URL Token** - A random 4-character token in the URL path (`/t/<token>`)
187
230
  2. **Password** - A 6-character alphanumeric password (or custom password via `-P`)
@@ -194,17 +237,17 @@ vigo uses multiple layers of security:
194
237
  - Password uses unambiguous characters (no 0/O, 1/l/I)
195
238
  - Lock screen requires re-entering password after inactivity (when enabled)
196
239
  - Session auto-terminates and kills tmux after extended inactivity (when enabled)
197
- - HTTPS via ngrok (encrypted in transit)
240
+ - HTTPS via tunnel (encrypted in transit)
198
241
 
199
242
  **Recommendations:**
200
- - Use HTTPS (ngrok provides this automatically)
243
+ - Use HTTPS (both ngrok and cloudflared provide this automatically)
201
244
  - Don't share your access URL or password publicly
202
245
  - Use strong custom passwords for sensitive sessions
203
246
  - Enable timeouts (`-T 15 -E 30`) for shared or sensitive environments
204
247
 
205
248
  ## Session Timeouts
206
249
 
207
- vigo has two optional timeout mechanisms (both disabled by default for persistent sessions):
250
+ aigo has two optional timeout mechanisms (both disabled by default for persistent sessions):
208
251
 
209
252
  ### Lock Timeout (default: disabled)
210
253
  When enabled with `-T <minutes>`, the session locks after the specified period of no interaction (mouse movement, typing, etc.) and requires password re-entry. The WebSocket connection stays open, so you don't lose any terminal state.
@@ -215,11 +258,11 @@ When enabled with `-E <minutes>`, the session completely terminates after the sp
215
258
  - Claude Code / Cursor Agent is stopped
216
259
  - The server exits
217
260
 
218
- Enable timeouts for security in shared environments: `vigo -T 15 -E 30 claude`
261
+ Enable timeouts for security in shared environments: `aigo -T 15 -E 30 claude`
219
262
 
220
263
  ## Browser Notifications
221
264
 
222
- vigo can send browser notifications when:
265
+ aigo can send browser notifications when:
223
266
  - The AI assistant is waiting for input
224
267
  - The WebSocket connection is lost
225
268
 
@@ -227,10 +270,11 @@ Notifications are only sent when the browser tab is not active. Allow notificati
227
270
 
228
271
  ## Mobile Controls
229
272
 
230
- When accessing vigo from a mobile device (phone or tablet), control buttons appear at the bottom of the screen:
273
+ When accessing aigo from a mobile device (phone or tablet), control buttons appear at the bottom of the screen:
231
274
 
232
275
  | Button | Action | Description |
233
276
  |--------|--------|-------------|
277
+ | **History** | View Buffer | Opens a fullscreen modal showing the terminal scrollback buffer (useful when TUI scrolling doesn't work on mobile) |
234
278
  | **Mode** | `Shift+Tab` | Toggle between chat/edit modes in Claude Code or switch modes in Cursor Agent |
235
279
  | **Enter** | `Enter` | Send Enter key to confirm prompts or submit input |
236
280
  | **Stop** | `Ctrl+C` | Interrupt the current operation (stop running commands or cancel AI responses) |
@@ -238,6 +282,17 @@ When accessing vigo from a mobile device (phone or tablet), control buttons appe
238
282
 
239
283
  These buttons are useful because mobile keyboards don't easily support modifier key combinations like Ctrl+C or Shift+Tab.
240
284
 
285
+ ### History Button
286
+
287
+ The **History** button is particularly useful on mobile devices where terminal scrolling often doesn't work properly with TUI applications like Claude Code or Cursor Agent. When pressed:
288
+
289
+ 1. Opens a fullscreen modal overlay
290
+ 2. Captures the entire terminal scrollback buffer from tmux
291
+ 3. Displays the content in a scrollable view with ANSI codes stripped for readability
292
+ 4. Press **Close** or the **ESC** key to return to the terminal
293
+
294
+ This provides an alternative way to review previous AI responses and conversation history without relying on terminal scrolling.
295
+
241
296
  The buttons are automatically shown based on:
242
297
  - Touch screen capability
243
298
  - Mobile user agent detection
@@ -246,34 +301,34 @@ The buttons are automatically shown based on:
246
301
 
247
302
  ## Running Persistently
248
303
 
249
- To keep vigo running indefinitely (even after closing your terminal), run it inside tmux or use a process manager:
304
+ To keep aigo running indefinitely (even after closing your terminal), run it inside tmux or use a process manager:
250
305
 
251
306
  ```bash
252
- # Run vigo inside its own tmux session
253
- tmux new-session -d -s vigo-server 'vigo claude'
307
+ # Run aigo inside its own tmux session
308
+ tmux new-session -d -s aigo-server 'aigo claude'
254
309
 
255
310
  # Attach to check status
256
- tmux attach -t vigo-server
311
+ tmux attach -t aigo-server
257
312
 
258
313
  # Or use pm2 for auto-restart on crash
259
- pm2 start "vigo claude" --name vigo-session
314
+ pm2 start "aigo claude" --name aigo-session
260
315
  ```
261
316
 
262
- When the vigo server stays running, your ngrok URL remains stable and you can return to the same URL anytime.
317
+ When the aigo server stays running, your tunnel URL remains stable and you can return to the same URL anytime. Note: cloudflared quick tunnel URLs change on restart, while ngrok URLs persist within a session.
263
318
 
264
319
  ## Auto Port Selection
265
320
 
266
- If the default port (3000) or your specified port is already in use, vigo automatically finds the next available port:
321
+ If the default port (3000) or your specified port is already in use, aigo automatically finds the next available port:
267
322
 
268
323
  ```
269
324
  ⚠ Port 3000 in use, using port 3001 instead
270
325
  ```
271
326
 
272
- This allows running multiple vigo sessions simultaneously without manual port management.
327
+ This allows running multiple aigo sessions simultaneously without manual port management.
273
328
 
274
329
  ## Exiting and Cleanup
275
330
 
276
- vigo provides different exit behaviors depending on how you terminate the session:
331
+ aigo provides different exit behaviors depending on how you terminate the session:
277
332
 
278
333
  ### Exit Behavior Summary
279
334
 
@@ -290,7 +345,7 @@ Click the **Exit** button in the top-right corner of the web interface to:
290
345
  2. Kill the PTY process
291
346
  3. Kill the tmux session
292
347
  4. Close all WebSocket connections
293
- 5. Shut down the vigo server
348
+ 5. Shut down the aigo server
294
349
  6. Exit the process
295
350
 
296
351
  **Result:** Everything is cleaned up - tmux session, server, and process all terminate. The web client shows a "Session Ended" message.
@@ -299,7 +354,7 @@ This is useful when you're completely done with a session and want to free all r
299
354
 
300
355
  ### Session Persistence (Ctrl+C on console)
301
356
 
302
- When you press `Ctrl+C` on the terminal running vigo:
357
+ When you press `Ctrl+C` on the terminal running aigo:
303
358
  1. The web server stops
304
359
  2. The tunnel closes (if running)
305
360
  3. **The tmux session keeps running!**
@@ -310,9 +365,9 @@ When you press `Ctrl+C` on the terminal running vigo:
310
365
  Re-attach later:
311
366
 
312
367
  ```bash
313
- # Via vigo (starts new web server for existing session)
314
- vigo --attach claude-code
315
- vigo --attach cursor-agent
368
+ # Via aigo (starts new web server for existing session)
369
+ aigo --attach claude-code
370
+ aigo --attach cursor-agent
316
371
 
317
372
  # Or directly with tmux (local terminal only)
318
373
  tmux attach -t claude-code
@@ -401,7 +456,7 @@ ngrok config add-authtoken YOUR_TOKEN
401
456
 
402
457
  Free ngrok accounts are limited to 1 simultaneous tunnel. If you see this error, it means an ngrok process from a previous session is still running.
403
458
 
404
- vigo will detect this and show you the command to kill it:
459
+ aigo will detect this and show you the command to kill it:
405
460
 
406
461
  ```
407
462
  Error: An ngrok process is already running.
@@ -411,7 +466,7 @@ To kill the existing ngrok process, run:
411
466
  kill 12345
412
467
 
413
468
  Or to run without a tunnel:
414
- vigo --tunnel none cursor
469
+ aigo --tunnel none cursor
415
470
  ```
416
471
 
417
472
  You can also find and kill ngrok manually:
@@ -427,6 +482,21 @@ kill <pid>
427
482
  pkill -f "ngrok http"
428
483
  ```
429
484
 
485
+ ### cloudflared connection issues
486
+
487
+ If cloudflared fails to connect:
488
+
489
+ ```bash
490
+ # Check if cloudflared is installed
491
+ which cloudflared
492
+
493
+ # Test a quick tunnel manually
494
+ cloudflared tunnel --url http://localhost:3000
495
+
496
+ # Check for firewall issues (verbose output)
497
+ cloudflared tunnel --url http://localhost:3000 --loglevel debug
498
+ ```
499
+
430
500
  ### WebSocket connection fails
431
501
 
432
502
  - Check that the server is running
@@ -441,13 +511,23 @@ Try resizing your browser window to trigger a terminal resize.
441
511
 
442
512
  ```bash
443
513
  # Run without installing globally
444
- node bin/vigo.js claude
445
- node bin/vigo.js cursor
514
+ node bin/aigo.js claude
515
+ node bin/aigo.js cursor
446
516
 
447
517
  # Watch for changes (requires nodemon)
448
- npx nodemon bin/vigo.js claude
518
+ npx nodemon bin/aigo.js claude
449
519
  ```
450
520
 
521
+ ### Publishing
522
+
523
+ Bump the minor version and publish to npm:
524
+
525
+ ```bash
526
+ make publish-minor
527
+ ```
528
+
529
+ This runs `npm version minor` (updates `package.json` and creates a git commit/tag) then `npm publish`.
530
+
451
531
  ## License
452
532
 
453
533
  MIT
package/bin/vigo.js CHANGED
@@ -21,7 +21,7 @@ function printBanner(info) {
21
21
  const timeoutStr = `lock:${lockStr} exit:${exitStr}`;
22
22
 
23
23
  const toolTitle = info.tool === 'cursor' ? 'Cursor Agent' : 'Claude Code';
24
- const header = `vigo - ${toolTitle} Web Terminal`;
24
+ const header = `aigo - ${toolTitle} Web Terminal`;
25
25
 
26
26
  console.log('');
27
27
  console.log('┌────────────────────────────────────────┐');
@@ -45,13 +45,13 @@ function printBanner(info) {
45
45
 
46
46
  function printHelp() {
47
47
  console.log(`
48
- vigo v${VERSION} - Stream Claude Code or Cursor Agent to the web
48
+ aigo v${VERSION} - Stream Claude Code or Cursor Agent to the web
49
49
 
50
50
  Usage:
51
- vigo [options] claude [claude-args]
52
- vigo [options] cursor [cursor-args]
53
- vigo [options] agent [agent-args]
54
- vigo [options] --attach <session>
51
+ aigo [options] claude [claude-args]
52
+ aigo [options] cursor [cursor-args]
53
+ aigo [options] agent [agent-args]
54
+ aigo [options] --attach <session>
55
55
 
56
56
  Tools:
57
57
  claude Use Claude Code CLI
@@ -69,28 +69,28 @@ Options:
69
69
  --version, -v Show version
70
70
 
71
71
  Examples:
72
- vigo claude Start Claude Code with ngrok tunnel
73
- vigo cursor Start Cursor Agent with ngrok tunnel
74
- vigo --tunnel none claude Local only (no tunnel)
75
- vigo -p 8080 -s myproject cursor Custom port and session
76
- vigo claude --model sonnet Pass args to Claude
77
- vigo cursor --model gpt-5 Pass args to Cursor Agent
78
- vigo --attach myproject Attach to existing session
79
- vigo -P mypass123 cursor Custom password
72
+ aigo claude Start Claude Code with ngrok tunnel
73
+ aigo cursor Start Cursor Agent with ngrok tunnel
74
+ aigo --tunnel none claude Local only (no tunnel)
75
+ aigo -p 8080 -s myproject cursor Custom port and session
76
+ aigo claude --model sonnet Pass args to Claude
77
+ aigo cursor --model gpt-5 Pass args to Cursor Agent
78
+ aigo --attach myproject Attach to existing session
79
+ aigo -P mypass123 cursor Custom password
80
80
  `);
81
81
  }
82
82
 
83
83
  async function main() {
84
- const { vigoArgs, toolArgs, tool } = parseArgs(process.argv.slice(2));
84
+ const { aigoArgs, toolArgs, tool } = parseArgs(process.argv.slice(2));
85
85
 
86
86
  // Handle help and version
87
- if (vigoArgs.help) {
87
+ if (aigoArgs.help) {
88
88
  printHelp();
89
89
  process.exit(0);
90
90
  }
91
91
 
92
- if (vigoArgs.version) {
93
- console.log(`vigo v${VERSION}`);
92
+ if (aigoArgs.version) {
93
+ console.log(`aigo v${VERSION}`);
94
94
  process.exit(0);
95
95
  }
96
96
 
@@ -110,7 +110,7 @@ async function main() {
110
110
  const toolConfig = config.tools[activeTool];
111
111
 
112
112
  // Check if the tool CLI is installed (for non-attach mode)
113
- if (!vigoArgs.attach && activeTool === 'cursor') {
113
+ if (!aigoArgs.attach && activeTool === 'cursor') {
114
114
  if (!isAgentInstalled()) {
115
115
  console.error('Error: Cursor Agent CLI is not installed or not in PATH');
116
116
  console.error('');
@@ -135,9 +135,9 @@ async function main() {
135
135
  }
136
136
  }
137
137
 
138
- const sessionName = vigoArgs.session || toolConfig.defaultSession;
139
- const requestedPort = vigoArgs.port || config.defaultPort;
140
- const tunnelType = vigoArgs.tunnel || config.defaultTunnel;
138
+ const sessionName = aigoArgs.session || toolConfig.defaultSession;
139
+ const requestedPort = aigoArgs.port || config.defaultPort;
140
+ const tunnelType = aigoArgs.tunnel || config.defaultTunnel;
141
141
 
142
142
  // Find available port
143
143
  let port;
@@ -156,8 +156,8 @@ async function main() {
156
156
 
157
157
  // Use custom password or generate password from config
158
158
  let password;
159
- if (vigoArgs.password) {
160
- password = vigoArgs.password;
159
+ if (aigoArgs.password) {
160
+ password = aigoArgs.password;
161
161
  } else {
162
162
  password = '';
163
163
  const randomBytes = crypto.randomBytes(config.passwordLength);
@@ -167,12 +167,12 @@ async function main() {
167
167
  }
168
168
 
169
169
  // Timeout settings (in minutes) - use config defaults
170
- const lockTimeout = vigoArgs.timeout !== null ? vigoArgs.timeout : config.lockTimeout;
171
- const exitTimeout = vigoArgs.exitTimeout !== null ? vigoArgs.exitTimeout : config.exitTimeout;
170
+ const lockTimeout = aigoArgs.timeout !== null ? aigoArgs.timeout : config.lockTimeout;
171
+ const exitTimeout = aigoArgs.exitTimeout !== null ? aigoArgs.exitTimeout : config.exitTimeout;
172
172
 
173
173
  // Handle --attach mode
174
- if (vigoArgs.attach) {
175
- const attachSession = typeof vigoArgs.attach === 'string' ? vigoArgs.attach : sessionName;
174
+ if (aigoArgs.attach) {
175
+ const attachSession = typeof aigoArgs.attach === 'string' ? aigoArgs.attach : sessionName;
176
176
  if (!hasSession(attachSession)) {
177
177
  console.error(`Error: tmux session '${attachSession}' does not exist`);
178
178
  console.error(`Create it first with: tmux new-session -s ${attachSession}`);
@@ -190,7 +190,7 @@ async function main() {
190
190
  }
191
191
  }
192
192
 
193
- const actualSession = vigoArgs.attach || sessionName;
193
+ const actualSession = aigoArgs.attach || sessionName;
194
194
 
195
195
  // Start web server
196
196
  console.log(`✓ Starting web server on port ${port}...`);
@@ -223,7 +223,7 @@ async function main() {
223
223
  }
224
224
  console.error('');
225
225
  console.error('Or to run without a tunnel:');
226
- console.error(' vigo --tunnel none cursor');
226
+ console.error(' aigo --tunnel none cursor');
227
227
  console.error('');
228
228
  process.exit(1);
229
229
  }
@@ -261,7 +261,7 @@ async function main() {
261
261
  }
262
262
 
263
263
  console.log(`tmux session '${actualSession}' is still running.`);
264
- console.log(`Re-attach with: vigo --attach ${actualSession}`);
264
+ console.log(`Re-attach with: aigo --attach ${actualSession}`);
265
265
  console.log(`Or directly: tmux attach -t ${actualSession}`);
266
266
  server.close();
267
267
  process.exit(0);
package/lib/cli.js CHANGED
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Parse command line arguments, separating vigo args from tool args
2
+ * Parse command line arguments, separating aigo args from tool args
3
3
  *
4
- * Example: vigo --port 8080 --tunnel ngrok claude --model sonnet
5
- * Example: vigo --port 8080 cursor --model gpt-5
4
+ * Example: aigo --port 8080 --tunnel ngrok claude --model sonnet
5
+ * Example: aigo --port 8080 cursor --model gpt-5
6
6
  * Returns:
7
- * vigoArgs: { port: 8080, tunnel: 'ngrok' }
7
+ * aigoArgs: { port: 8080, tunnel: 'ngrok' }
8
8
  * toolArgs: ['--model', 'sonnet']
9
9
  * tool: 'claude' | 'cursor' | null
10
10
  */
11
11
  export function parseArgs(args) {
12
- const vigoArgs = {
12
+ const aigoArgs = {
13
13
  port: null,
14
14
  session: null,
15
15
  tunnel: null,
@@ -39,31 +39,31 @@ export function parseArgs(args) {
39
39
  break;
40
40
  }
41
41
 
42
- // Parse vigo options
42
+ // Parse aigo options
43
43
  if (arg === '--port' || arg === '-p') {
44
- vigoArgs.port = parseInt(args[++i], 10);
44
+ aigoArgs.port = parseInt(args[++i], 10);
45
45
  } else if (arg === '--session' || arg === '-s') {
46
- vigoArgs.session = args[++i];
46
+ aigoArgs.session = args[++i];
47
47
  } else if (arg === '--tunnel' || arg === '-t') {
48
- vigoArgs.tunnel = args[++i];
48
+ aigoArgs.tunnel = args[++i];
49
49
  } else if (arg === '--attach' || arg === '-a') {
50
50
  const next = args[i + 1];
51
51
  // Check if next arg is a session name (not another flag)
52
52
  if (next && !next.startsWith('-')) {
53
- vigoArgs.attach = args[++i];
53
+ aigoArgs.attach = args[++i];
54
54
  } else {
55
- vigoArgs.attach = true; // Use default session name
55
+ aigoArgs.attach = true; // Use default session name
56
56
  }
57
57
  } else if (arg === '--password' || arg === '-P') {
58
- vigoArgs.password = args[++i];
58
+ aigoArgs.password = args[++i];
59
59
  } else if (arg === '--timeout' || arg === '-T') {
60
- vigoArgs.timeout = parseInt(args[++i], 10);
60
+ aigoArgs.timeout = parseInt(args[++i], 10);
61
61
  } else if (arg === '--exit-timeout' || arg === '-E') {
62
- vigoArgs.exitTimeout = parseInt(args[++i], 10);
62
+ aigoArgs.exitTimeout = parseInt(args[++i], 10);
63
63
  } else if (arg === '--help' || arg === '-h') {
64
- vigoArgs.help = true;
64
+ aigoArgs.help = true;
65
65
  } else if (arg === '--version' || arg === '-v') {
66
- vigoArgs.version = true;
66
+ aigoArgs.version = true;
67
67
  }
68
68
 
69
69
  i++;
@@ -71,7 +71,7 @@ export function parseArgs(args) {
71
71
 
72
72
  // For backward compatibility, also export as claudeArgs/foundClaude
73
73
  return {
74
- vigoArgs,
74
+ aigoArgs,
75
75
  toolArgs,
76
76
  tool,
77
77
  // Backward compatibility
package/lib/config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * vigo configuration
2
+ * aigo configuration
3
3
  *
4
- * Edit these values to customize vigo's default behavior.
4
+ * Edit these values to customize aigo's default behavior.
5
5
  */
6
6
 
7
7
  export const config = {
package/lib/server.js CHANGED
@@ -3,6 +3,7 @@ import { createServer } from 'http';
3
3
  import { WebSocketServer } from 'ws';
4
4
  import path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
+ import { execSync } from 'child_process';
6
7
  import pty from 'node-pty';
7
8
  import { getTmuxPath, killSession } from './tmux.js';
8
9
 
@@ -234,6 +235,31 @@ export function startServer({ port, token, password, session, lockTimeout, exitT
234
235
  }, 500);
235
236
  return;
236
237
  }
238
+
239
+ // Handle history capture request
240
+ if (parsed.type === 'capture_history') {
241
+ updateActivity();
242
+ try {
243
+ const tmuxBin = getTmuxPath() || 'tmux';
244
+ // Capture entire scrollback buffer from tmux session
245
+ // -p: print to stdout, -S -: start from beginning, -E -: end at bottom
246
+ const historyData = execSync(
247
+ `${tmuxBin} capture-pane -t "${session}:0" -p -S - -E -`,
248
+ { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 } // 10MB max
249
+ );
250
+ ws.send(JSON.stringify({
251
+ type: 'history_data',
252
+ data: historyData
253
+ }));
254
+ } catch (err) {
255
+ console.error('Failed to capture history:', err.message);
256
+ ws.send(JSON.stringify({
257
+ type: 'history_error',
258
+ error: 'Failed to capture terminal history'
259
+ }));
260
+ }
261
+ return;
262
+ }
237
263
  } catch {
238
264
  // Not JSON - treat as terminal input
239
265
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aigo",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Stream Claude Code to the web - run Claude remotely from any device",
5
5
  "type": "module",
6
6
  "bin": {
package/public/index.html CHANGED
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
- <title>vigo - Claude Code Terminal</title>
6
+ <title>aigo - Claude Code Terminal</title>
7
7
  <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>▸</text></svg>">
8
8
 
9
9
  <!-- xterm.js from CDN (use older compatible CDN paths) -->
@@ -478,12 +478,126 @@
478
478
  background: #ff5555;
479
479
  color: white;
480
480
  }
481
+
482
+ /* History button */
483
+ #mobile-history-btn {
484
+ color: #00ffff;
485
+ border-color: #00ffff;
486
+ }
487
+
488
+ #mobile-history-btn:hover,
489
+ #mobile-history-btn:active {
490
+ background: #00ffff;
491
+ color: var(--bg-primary);
492
+ }
493
+
494
+ /* History modal overlay */
495
+ #history-overlay {
496
+ display: none;
497
+ position: fixed;
498
+ top: 0;
499
+ left: 0;
500
+ right: 0;
501
+ bottom: 0;
502
+ background: var(--bg-primary);
503
+ z-index: 300;
504
+ flex-direction: column;
505
+ }
506
+
507
+ #history-overlay.visible {
508
+ display: flex;
509
+ }
510
+
511
+ .history-header {
512
+ display: flex;
513
+ align-items: center;
514
+ justify-content: space-between;
515
+ padding: 12px 16px;
516
+ background: var(--bg-secondary);
517
+ border-bottom: 1px solid var(--border);
518
+ flex-shrink: 0;
519
+ }
520
+
521
+ .history-title {
522
+ color: #00ffff;
523
+ font-size: 16px;
524
+ font-weight: 600;
525
+ }
526
+
527
+ .history-close-btn {
528
+ padding: 8px 16px;
529
+ background: transparent;
530
+ color: var(--text-secondary);
531
+ border: 1px solid var(--border);
532
+ border-radius: 4px;
533
+ font-family: inherit;
534
+ font-size: 13px;
535
+ cursor: pointer;
536
+ transition: all 0.2s;
537
+ }
538
+
539
+ .history-close-btn:hover {
540
+ color: var(--text-primary);
541
+ border-color: var(--text-primary);
542
+ }
543
+
544
+ .history-content {
545
+ flex: 1;
546
+ overflow-y: auto;
547
+ padding: 16px;
548
+ -webkit-overflow-scrolling: touch;
549
+ }
550
+
551
+ .history-text {
552
+ white-space: pre-wrap;
553
+ word-wrap: break-word;
554
+ font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', monospace;
555
+ font-size: 13px;
556
+ line-height: 1.5;
557
+ color: var(--text-primary);
558
+ }
559
+
560
+ .history-loading {
561
+ display: flex;
562
+ justify-content: center;
563
+ align-items: center;
564
+ height: 100%;
565
+ color: var(--text-secondary);
566
+ }
567
+
568
+ .history-loading .spinner {
569
+ width: 24px;
570
+ height: 24px;
571
+ border: 2px solid var(--border);
572
+ border-top-color: #00ffff;
573
+ border-radius: 50%;
574
+ animation: spin 1s linear infinite;
575
+ margin-right: 12px;
576
+ }
577
+
578
+ /* Custom scrollbar for history */
579
+ .history-content::-webkit-scrollbar {
580
+ width: 8px;
581
+ }
582
+
583
+ .history-content::-webkit-scrollbar-track {
584
+ background: var(--bg-primary);
585
+ }
586
+
587
+ .history-content::-webkit-scrollbar-thumb {
588
+ background: var(--border);
589
+ border-radius: 4px;
590
+ }
591
+
592
+ .history-content::-webkit-scrollbar-thumb:hover {
593
+ background: #2a2a35;
594
+ }
481
595
  </style>
482
596
  </head>
483
597
  <body>
484
598
  <div id="app">
485
599
  <header id="header">
486
- <div class="logo">vigo</div>
600
+ <div class="logo">aigo</div>
487
601
  <div class="header-right">
488
602
  <div id="status" class="connecting">
489
603
  <span class="dot"></span>
@@ -528,11 +642,27 @@
528
642
 
529
643
  <!-- Mobile control buttons -->
530
644
  <div id="mobile-controls">
645
+ <button id="mobile-history-btn" class="mobile-btn" title="View terminal history">History</button>
531
646
  <button id="mobile-mode-toggle" class="mobile-btn" title="Switch mode (Shift+Tab)">Mode</button>
532
647
  <button id="mobile-enter-btn" class="mobile-btn" title="Send Enter key">Enter</button>
533
648
  <button id="mobile-stop-btn" class="mobile-btn" title="Stop (Ctrl+C)">Stop</button>
534
649
  <button id="mobile-exit-btn" class="mobile-btn" title="Exit session">Exit</button>
535
650
  </div>
651
+
652
+ <!-- History modal overlay -->
653
+ <div id="history-overlay">
654
+ <div class="history-header">
655
+ <div class="history-title">Terminal History</div>
656
+ <button id="history-close-btn" class="history-close-btn">Close</button>
657
+ </div>
658
+ <div class="history-content">
659
+ <div class="history-loading">
660
+ <div class="spinner"></div>
661
+ <span>Loading history...</span>
662
+ </div>
663
+ <pre class="history-text" style="display: none;"></pre>
664
+ </div>
665
+ </div>
536
666
  </div>
537
667
 
538
668
  <!-- xterm.js scripts from CDN (non-scoped package names for UMD globals) -->
@@ -1,5 +1,5 @@
1
1
  /**
2
- * vigo terminal client
2
+ * aigo terminal client
3
3
  * Connects to the WebSocket server and renders the terminal
4
4
  */
5
5
 
@@ -52,6 +52,12 @@
52
52
  const mobileEnterBtn = document.getElementById('mobile-enter-btn');
53
53
  const mobileStopBtn = document.getElementById('mobile-stop-btn');
54
54
  const mobileExitBtn = document.getElementById('mobile-exit-btn');
55
+ const mobileHistoryBtn = document.getElementById('mobile-history-btn');
56
+ const historyOverlay = document.getElementById('history-overlay');
57
+ const historyCloseBtn = document.getElementById('history-close-btn');
58
+ const historyContent = historyOverlay.querySelector('.history-content');
59
+ const historyLoading = historyOverlay.querySelector('.history-loading');
60
+ const historyText = historyOverlay.querySelector('.history-text');
55
61
 
56
62
  // Terminal setup
57
63
  const terminal = new Terminal({
@@ -261,7 +267,7 @@
261
267
  const notification = new Notification(title, {
262
268
  body: body,
263
269
  icon: 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">▸</text></svg>',
264
- tag: 'vigo-notification',
270
+ tag: 'aigo-notification',
265
271
  requireInteraction: false
266
272
  });
267
273
 
@@ -289,7 +295,7 @@
289
295
  // Check patterns
290
296
  for (const pattern of idlePatterns) {
291
297
  if (pattern.test(outputBuffer)) {
292
- showNotification('vigo', 'Claude Code is waiting for input');
298
+ showNotification('aigo', 'Claude Code is waiting for input');
293
299
  outputBuffer = ''; // Reset to avoid repeated notifications
294
300
  return;
295
301
  }
@@ -453,10 +459,70 @@
453
459
  }
454
460
  });
455
461
 
456
- // ESC to close exit confirm
462
+ // Strip ANSI escape codes from text for clean display
463
+ function stripAnsiCodes(text) {
464
+ // Remove ANSI escape sequences (colors, cursor movement, etc.)
465
+ return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '')
466
+ .replace(/\x1b\][^\x07]*\x07/g, '') // OSC sequences
467
+ .replace(/\x1b[PX^_].*?\x1b\\/g, '') // DCS, SOS, PM, APC sequences
468
+ .replace(/\x1b./g, ''); // Other escape sequences
469
+ }
470
+
471
+ // Show history modal
472
+ function showHistoryModal() {
473
+ historyOverlay.classList.add('visible');
474
+ historyLoading.style.display = 'flex';
475
+ historyText.style.display = 'none';
476
+ historyText.textContent = '';
477
+
478
+ // Request history from server
479
+ if (ws && ws.readyState === WebSocket.OPEN && authenticated) {
480
+ ws.send(JSON.stringify({ type: 'capture_history' }));
481
+ }
482
+ }
483
+
484
+ // Hide history modal
485
+ function hideHistoryModal() {
486
+ historyOverlay.classList.remove('visible');
487
+ terminal.focus();
488
+ }
489
+
490
+ // Display history data in the modal
491
+ function displayHistoryData(data) {
492
+ historyLoading.style.display = 'none';
493
+ historyText.style.display = 'block';
494
+ // Strip ANSI codes for clean, readable text
495
+ historyText.textContent = stripAnsiCodes(data);
496
+ // Scroll to bottom to show most recent content
497
+ historyContent.scrollTop = historyContent.scrollHeight;
498
+ }
499
+
500
+ // Display history error
501
+ function displayHistoryError(error) {
502
+ historyLoading.style.display = 'none';
503
+ historyText.style.display = 'block';
504
+ historyText.textContent = `Error: ${error}`;
505
+ }
506
+
507
+ // Mobile history button handler
508
+ mobileHistoryBtn.addEventListener('click', () => {
509
+ if (ws && ws.readyState === WebSocket.OPEN && authenticated && !isLocked) {
510
+ mobileButtonFeedback(mobileHistoryBtn);
511
+ showHistoryModal();
512
+ }
513
+ });
514
+
515
+ // History close button handler
516
+ historyCloseBtn.addEventListener('click', hideHistoryModal);
517
+
518
+ // ESC to close exit confirm or history
457
519
  document.addEventListener('keydown', (e) => {
458
- if (e.key === 'Escape' && exitOverlay.classList.contains('visible')) {
459
- hideExitConfirm();
520
+ if (e.key === 'Escape') {
521
+ if (historyOverlay.classList.contains('visible')) {
522
+ hideHistoryModal();
523
+ } else if (exitOverlay.classList.contains('visible')) {
524
+ hideExitConfirm();
525
+ }
460
526
  }
461
527
  });
462
528
 
@@ -606,6 +672,16 @@
606
672
  showCleanupComplete();
607
673
  return;
608
674
  }
675
+
676
+ if (msg.type === 'history_data') {
677
+ displayHistoryData(msg.data);
678
+ return;
679
+ }
680
+
681
+ if (msg.type === 'history_error') {
682
+ displayHistoryError(msg.error);
683
+ return;
684
+ }
609
685
  } catch {
610
686
  // Not JSON, treat as terminal data
611
687
  }
@@ -630,7 +706,7 @@
630
706
 
631
707
  if (event.code !== 1000) {
632
708
  // Notify user of unexpected disconnect
633
- showNotification('vigo', 'Connection lost. Attempting to reconnect...');
709
+ showNotification('aigo', 'Connection lost. Attempting to reconnect...');
634
710
  scheduleReconnect();
635
711
  } else {
636
712
  showOverlay(true, 'Session ended.', true);
@@ -737,7 +813,7 @@
737
813
  connect();
738
814
 
739
815
  // Expose for debugging
740
- window.vigoTerminal = {
816
+ window.aigoTerminal = {
741
817
  terminal,
742
818
  fitAddon,
743
819
  reconnect: () => {
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- **vigo** is a CLI tool that lets you run Claude Code remotely from any device. It wraps Claude in a tmux session and streams it to your browser via WebSocket.
5
+ **aigo** is a CLI tool that lets you run Claude Code remotely from any device. It wraps Claude in a tmux session and streams it to your browser via WebSocket.
6
6
 
7
7
  ```bash
8
8
  # Start Claude Code accessible from anywhere
9
- vigo --tunnel ngrok claude --model sonnet
9
+ aigo --tunnel ngrok claude --model sonnet
10
10
 
11
11
  # Output:
12
12
  # ✓ tmux session: claude-code
@@ -19,8 +19,8 @@ vigo --tunnel ngrok claude --model sonnet
19
19
  ## CLI Interface
20
20
 
21
21
  ```
22
- vigo [vigo-options] claude [claude-args]
23
- vigo [vigo-options] --attach <session>
22
+ aigo [aigo-options] claude [claude-args]
23
+ aigo [aigo-options] --attach <session>
24
24
 
25
25
  Vigo Options:
26
26
  --port, -p <port> Web server port (default: 3000)
@@ -30,19 +30,19 @@ Vigo Options:
30
30
  --help, -h Show help
31
31
 
32
32
  Examples:
33
- vigo claude # Basic: start claude in tmux + web server
34
- vigo --tunnel ngrok claude # With ngrok tunnel
35
- vigo -p 8080 -s myproject claude # Custom port and session
36
- vigo claude --model sonnet # Pass args to claude
37
- vigo --attach myproject # Attach to existing session
33
+ aigo claude # Basic: start claude in tmux + web server
34
+ aigo --tunnel ngrok claude # With ngrok tunnel
35
+ aigo -p 8080 -s myproject claude # Custom port and session
36
+ aigo claude --model sonnet # Pass args to claude
37
+ aigo --attach myproject # Attach to existing session
38
38
  ```
39
39
 
40
40
  ## Architecture
41
41
 
42
42
  ```mermaid
43
43
  flowchart TB
44
- subgraph cli [vigo CLI]
45
- CLI[bin/vigo.js]
44
+ subgraph cli [aigo CLI]
45
+ CLI[bin/aigo.js]
46
46
  CLI --> TMUX_MGR[tmux manager]
47
47
  CLI --> SERVER[web server]
48
48
  CLI --> TUNNEL[tunnel manager]
@@ -78,10 +78,10 @@ flowchart TB
78
78
  ## Project Structure
79
79
 
80
80
  ```
81
- vigo/
81
+ aigo/
82
82
  ├── package.json # dependencies + bin entry
83
83
  ├── bin/
84
- │ └── vigo.js # CLI entry point (#!/usr/bin/env node)
84
+ │ └── aigo.js # CLI entry point (#!/usr/bin/env node)
85
85
  ├── lib/
86
86
  │ ├── cli.js # Argument parsing
87
87
  │ ├── tmux.js # tmux session management
@@ -95,25 +95,25 @@ vigo/
95
95
 
96
96
  ## Implementation Details
97
97
 
98
- ### 1. CLI Entry Point (bin/vigo.js)
98
+ ### 1. CLI Entry Point (bin/aigo.js)
99
99
 
100
100
  - Shebang for direct execution: `#!/usr/bin/env node`
101
- - Parse arguments, separating vigo args from claude args
101
+ - Parse arguments, separating aigo args from claude args
102
102
  - Orchestrate: tmux → server → tunnel (if requested)
103
103
  - Handle graceful shutdown (Ctrl+C kills tunnel, keeps tmux alive)
104
104
 
105
105
  ### 2. Argument Parsing (lib/cli.js)
106
106
 
107
107
  ```javascript
108
- // vigo --port 8080 --tunnel ngrok claude --model sonnet --allowedTools Bash
108
+ // aigo --port 8080 --tunnel ngrok claude --model sonnet --allowedTools Bash
109
109
  //
110
110
  // Parsed as:
111
- // vigoArgs = { port: 8080, tunnel: 'ngrok', session: 'claude-code' }
111
+ // aigoArgs = { port: 8080, tunnel: 'ngrok', session: 'claude-code' }
112
112
  // claudeArgs = ['--model', 'sonnet', '--allowedTools', 'Bash']
113
113
  ```
114
114
 
115
115
  - Split on `claude` keyword
116
- - Everything before = vigo options
116
+ - Everything before = aigo options
117
117
  - Everything after = passed to claude CLI
118
118
 
119
119
  ### 3. tmux Manager (lib/tmux.js)
@@ -164,7 +164,7 @@ console.log(`Tunnel URL: ${tunnel.url}`);
164
164
 
165
165
  ## Token Security
166
166
 
167
- - Generated once per `vigo` invocation
167
+ - Generated once per `aigo` invocation
168
168
  - 32 bytes from `crypto.randomBytes()` → 64 char hex
169
169
  - Embedded in URL path: `/t/<token>`
170
170
  - Required for both HTTP and WebSocket
@@ -176,12 +176,12 @@ console.log(`Tunnel URL: ${tunnel.url}`);
176
176
  # 1. Install globally (or use npx)
177
177
  npm install -g .
178
178
 
179
- # 2. Run vigo with Claude
180
- vigo --tunnel ngrok claude --model sonnet
179
+ # 2. Run aigo with Claude
180
+ aigo --tunnel ngrok claude --model sonnet
181
181
 
182
182
  # 3. Output shows access URL
183
183
  # ┌─────────────────────────────────────────────────┐
184
- # │ vigo - Claude Code Web Terminal │
184
+ # │ aigo - Claude Code Web Terminal │
185
185
  # ├─────────────────────────────────────────────────┤
186
186
  # │ tmux session: claude-code │
187
187
  # │ Local server: http://localhost:3000 │
@@ -194,18 +194,18 @@ vigo --tunnel ngrok claude --model sonnet
194
194
  # 4. Open URL on phone/tablet - full Claude Code access!
195
195
 
196
196
  # 5. Ctrl+C stops server + tunnel, tmux session persists
197
- # Re-attach later with: vigo --attach claude-code
197
+ # Re-attach later with: aigo --attach claude-code
198
198
  ```
199
199
 
200
200
  ## Dependencies
201
201
 
202
202
  ```json
203
203
  {
204
- "name": "vigo",
204
+ "name": "aigo",
205
205
  "version": "1.0.0",
206
206
  "type": "module",
207
207
  "bin": {
208
- "vigo": "./bin/vigo.js"
208
+ "aigo": "./bin/aigo.js"
209
209
  },
210
210
  "dependencies": {
211
211
  "express": "^4.21.0",
@@ -226,14 +226,14 @@ No build step. Frontend loads xterm.js from CDN.
226
226
  ### New CLI option
227
227
 
228
228
  ```bash
229
- vigo --tunnel relay claude # Use self-hosted WebRTC relay
229
+ aigo --tunnel relay claude # Use self-hosted WebRTC relay
230
230
  ```
231
231
 
232
232
  ### Architecture
233
233
 
234
234
  ```mermaid
235
235
  sequenceDiagram
236
- participant Local as vigo (local)
236
+ participant Local as aigo (local)
237
237
  participant Signal as Railway Signaling Server
238
238
  participant Browser as Mobile Browser
239
239
 
@@ -248,7 +248,7 @@ sequenceDiagram
248
248
  ### Components to add
249
249
 
250
250
  1. **Signaling server** (new repo, deploy to Railway)
251
- 2. **WebRTC module** in vigo (`lib/webrtc.js`)
251
+ 2. **WebRTC module** in aigo (`lib/webrtc.js`)
252
252
  3. **Frontend WebRTC client**
253
253
 
254
254
  ### Benefits
@@ -1,22 +1,22 @@
1
- # Cursor CLI Support for vigo
1
+ # Cursor CLI Support for aigo
2
2
 
3
3
  ## Overview
4
4
 
5
- Add support for Cursor Agent CLI alongside Claude Code, allowing vigo to stream either tool to a browser via WebSocket. This enables users with Cursor subscriptions to access Cursor's AI features remotely.
5
+ Add support for Cursor Agent CLI alongside Claude Code, allowing aigo to stream either tool to a browser via WebSocket. This enables users with Cursor subscriptions to access Cursor's AI features remotely.
6
6
 
7
7
  ## Architecture Comparison
8
8
 
9
9
  ```mermaid
10
10
  flowchart TB
11
11
  subgraph current [Current: Claude Code]
12
- vigo1[vigo] --> tmux1[tmux session]
12
+ aigo1[aigo] --> tmux1[tmux session]
13
13
  tmux1 --> claude[claude CLI]
14
14
  claude --> ws1[WebSocket]
15
15
  ws1 --> browser1[Browser xterm.js]
16
16
  end
17
17
 
18
18
  subgraph new [New: Cursor Agent]
19
- vigo2[vigo] --> tmux2[tmux session]
19
+ aigo2[aigo] --> tmux2[tmux session]
20
20
  tmux2 --> agent[agent CLI]
21
21
  agent --> ws2[WebSocket]
22
22
  ws2 --> browser2[Browser xterm.js]
@@ -95,10 +95,10 @@ export function getCursorAgentPath() {
95
95
 
96
96
  **For Cursor CLI:**
97
97
 
98
- 1. **Browser login (recommended for interactive)**: User runs `agent login` before starting vigo
98
+ 1. **Browser login (recommended for interactive)**: User runs `agent login` before starting aigo
99
99
  2. **API key (for headless/automation)**: Set `CURSOR_API_KEY` environment variable
100
100
 
101
- vigo should:
101
+ aigo should:
102
102
 
103
103
  - Check if authentication is configured before starting
104
104
  - Provide clear error messages if not authenticated
@@ -108,18 +108,18 @@ vigo should:
108
108
 
109
109
  ```bash
110
110
  # Start Claude Code (existing)
111
- vigo claude
111
+ aigo claude
112
112
 
113
113
  # Start Cursor Agent (new)
114
- vigo cursor
114
+ aigo cursor
115
115
  # or
116
- vigo agent
116
+ aigo agent
117
117
 
118
118
  # With tunnel for remote access
119
- vigo --tunnel ngrok cursor
119
+ aigo --tunnel ngrok cursor
120
120
 
121
121
  # Pass arguments to Cursor Agent
122
- vigo cursor --model gpt-5
122
+ aigo cursor --model gpt-5
123
123
  ```
124
124
 
125
125
  ## Requirements Update
@@ -134,6 +134,6 @@ Add to README:
134
134
 
135
135
  1. [lib/cli.js](lib/cli.js) - Add cursor/agent command detection
136
136
  2. [lib/tmux.js](lib/tmux.js) - Generalize command execution
137
- 3. [bin/vigo.js](bin/vigo.js) - Update startup logic for both tools
137
+ 3. [bin/aigo.js](bin/aigo.js) - Update startup logic for both tools
138
138
  4. [README.md](README.md) - Document Cursor support
139
139
  5. [lib/cursor.js](lib/cursor.js) - Cursor-specific utilities
@@ -0,0 +1,64 @@
1
+ # History View Button for Mobile
2
+
3
+ ## Problem
4
+ Terminal scrolling doesn't work well on mobile devices with TUI applications like Claude Code and Cursor Agent, making it difficult to view previous messages.
5
+
6
+ ## Solution
7
+ Add a "History" button that opens a modal overlay displaying the terminal scrollback buffer captured directly from tmux using `tmux capture-pane`.
8
+
9
+ ## Architecture
10
+
11
+ ```mermaid
12
+ sequenceDiagram
13
+ participant User
14
+ participant Frontend as WebClient
15
+ participant Server as Node Server
16
+ participant Tmux
17
+
18
+ User->>Frontend: Clicks History button
19
+ Frontend->>Server: WebSocket message type: "capture_history"
20
+ Server->>Tmux: capture-pane -t session:0 -p -S - -E -
21
+ Tmux-->>Server: Scrollback buffer text
22
+ Server-->>Frontend: WebSocket message type: "history_data"
23
+ Frontend->>User: Shows modal with scrollable history
24
+ ```
25
+
26
+ ## Implementation
27
+
28
+ ### 1. Backend - Add history capture endpoint ([lib/server.js](lib/server.js))
29
+
30
+ Add a new WebSocket message handler for `capture_history` that runs:
31
+ ```bash
32
+ tmux capture-pane -t <session>:0 -p -S - -E -
33
+ ```
34
+
35
+ This captures the entire scrollback buffer (tested and confirmed working - returns all terminal output including Claude/Cursor responses).
36
+
37
+ ### 2. Frontend - Add History button ([public/index.html](public/index.html))
38
+
39
+ Add a new mobile button styled like the existing controls:
40
+ - Button label: "History"
41
+ - Color: Use a distinct color (cyan `#00ffff`)
42
+ - Position: Add to the existing mobile controls row
43
+
44
+ ### 3. Frontend - Add modal overlay ([public/index.html](public/index.html))
45
+
46
+ Create a fullscreen modal that:
47
+ - Has a dark background matching the terminal theme
48
+ - Contains a scrollable text area with monospace font
49
+ - Has a "Close" button at the top
50
+ - Strips ANSI escape codes for clean display
51
+
52
+ ### 4. Frontend - Handle history messages ([public/terminal.js](public/terminal.js))
53
+
54
+ - Send `capture_history` request when History button is clicked
55
+ - Receive `history_data` response and display in modal
56
+ - Strip ANSI escape codes for readable plain text display
57
+
58
+ ## Key Files Modified
59
+ - [lib/server.js](lib/server.js) - Add tmux capture-pane handler
60
+ - [public/index.html](public/index.html) - Add History button and modal HTML/CSS
61
+ - [public/terminal.js](public/terminal.js) - Add click handler and modal logic
62
+ - [README.md](README.md) - Document the new History feature
63
+
64
+ ## Status: Completed