claude-code-remote-pilot 0.2.13 → 0.3.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/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ ## 0.3.1 — 2026-05-06
4
+
5
+ ### Changed
6
+ - Status check interval reduced from 30s → 5s (faster running/idle/limit detection)
7
+ - Watch screen refresh rate reduced from 2s → 1s
8
+
9
+ ---
10
+
11
+ ## 0.3.0 — 2026-05-06
12
+
13
+ ### Added
14
+ - **Session history**: every spawned or adopted session is persisted to `~/.claude-remote-pilot.json`. Sessions you've worked in before are remembered even after they end.
15
+ - **Offline sessions in watch**: the watch screen now shows offline sessions (from history but no longer running in tmux) alongside live sessions, in dim text.
16
+ - **Interactive watch**: press a number key (1–9) to select a session, then:
17
+ - Active session: `[t]` open terminal (tmux attach), `[k]` kill, `Esc` deselect
18
+ - Offline session: `[s]` re-spawn Claude at the saved path, `[r]` remove from history, `Esc` deselect
19
+ - **Auto-watch on start**: watch mode opens automatically after startup if there are any sessions (active or historical), so you land in the dashboard instead of a blank prompt.
20
+
21
+ ### Changed
22
+ - Watch exits cleanly with `q` back to the command prompt (no session list required first).
23
+ - Watch command also triggers when there are only offline sessions in history.
24
+
25
+ ---
26
+
27
+ ## 0.2.13 — previous
28
+
29
+ - Usage limit detection with auto-resume
30
+ - Token usage display in watch (`↑sent ↓received`)
31
+ - Configurable resume message
32
+ - Telegram notification persistence
33
+ - Session recovery after pilot restart
34
+ - Status detection: running / idle / needs-response / limit
package/README.md CHANGED
@@ -15,29 +15,32 @@ npx claude-code-remote-pilot
15
15
 
16
16
  ├── asks: mount current directory as a session?
17
17
  ├── asks: set up Telegram? (optional)
18
- └── starts interactive prompt
19
-
20
- claude-pilot> spawn ~/projects/api-refactor
21
- claude-pilot> spawn ~/projects/mobile-app
22
- claude-pilot> watch
18
+ └── opens watch dashboard automatically
23
19
  ```
24
20
 
21
+ Watch opens immediately. Press `q` to drop to the command prompt, then `watch` to return.
22
+
25
23
  ```
26
24
  Claude Code Remote Pilot
27
- ─────────────────────────────────────────────────────────────────
28
- SESSION STATUS DIRECTORY
29
- ─────────────────────────────────────────────────────────────────
30
- api-refactor running ~/projects/api-refactor
31
- mobile-app limit 42m ~/projects/mobile-app
32
- ─────────────────────────────────────────────────────────────────
33
- 2 sessions 14:23:05 q to exit
25
+ ───────────────────────────────────────────────────────────────────
26
+ # SESSION STATUS UP USAGE / RESET
27
+ ───────────────────────────────────────────────────────────────────
28
+ 1 api-refactor running 12m ↑1.2k ↓890
29
+ 2 mobile-app limit 3m 1h 4m resets 2:00 AM
30
+ 3 old-project offline —
31
+ ───────────────────────────────────────────────────────────────────
32
+ [1-3]: select session q: exit watch
34
33
  ```
35
34
 
36
- From any other terminal, interact with a session directly:
35
+ Press a number to select a session:
36
+ - **Active**: `[t]` open terminal · `[k]` kill · `Esc` back
37
+ - **Offline**: `[s]` re-spawn · `[r]` remove from history · `Esc` back
38
+
39
+ From any terminal, attach directly:
37
40
 
38
41
  ```bash
39
42
  tmux attach -t api-refactor
40
- # Ctrl+B then D to detach back to your terminal
43
+ # Ctrl+B then D to detach
41
44
  ```
42
45
 
43
46
  ---
@@ -100,7 +103,7 @@ sudo apt update && sudo apt install tmux
100
103
  |---|---|
101
104
  | `spawn <path> [name]` | Start Claude at a path. Name defaults to the directory name. |
102
105
  | `list` | One-shot status of all sessions. |
103
- | `watch` | Live-updating session monitor. Press `q` to exit. |
106
+ | `watch` | Live dashboard with offline session history. Press a number to select, `q` to exit. |
104
107
  | `attach <name>` | Open a tmux session in the current terminal. |
105
108
  | `kill <name>` | Stop a session. |
106
109
  | `help` | Show command reference. |
@@ -171,7 +174,7 @@ Start Claude without `--dangerously-skip-permissions` unless you know what you'r
171
174
  - [x] interactive REPL — spawn, watch, attach, kill
172
175
  - [x] multi-session support
173
176
  - [ ] web dashboard (sessions connect to pilot server)
174
- - [ ] persistent session state
177
+ - [x] persistent session history with offline session display
175
178
  - [ ] pluggable notification providers
176
179
  - [ ] safety / policy engine
177
180
 
@@ -103,6 +103,8 @@ function formatStatus(session) {
103
103
  const label = `limit ${Math.ceil(secs / 60)}m`;
104
104
  return { plain: label, colored: `${C.yellow}${label}${C.reset}` };
105
105
  }
106
+ case 'offline':
107
+ return { plain: 'offline', colored: `${C.dim}offline${C.reset}` };
106
108
  case 'ended':
107
109
  return { plain: 'ended', colored: `${C.dim}ended${C.reset}` };
108
110
  default:
@@ -131,46 +133,161 @@ function formatUsage(session) {
131
133
  return '';
132
134
  }
133
135
 
134
- function renderTable(sessions) {
136
+ // ─── watch mode ───────────────────────────────────────────────────────────────
137
+
138
+ function buildAllSessions(manager) {
139
+ const active = manager.list();
140
+ const activeNames = new Set(active.map(s => s.name));
141
+ const history = config.getHistory();
142
+ const offline = history
143
+ .filter(h => !activeNames.has(h.name))
144
+ .map(h => ({ name: h.name, path: h.path, status: 'offline', startedAt: h.lastSeen, resumeAt: null }));
145
+ return [...active, ...offline];
146
+ }
147
+
148
+ function renderWatchTable(allSessions, selectedIdx) {
135
149
  const NW = 18, SW = 14, UW = 7, TW = 16;
136
150
  const bar = ' ' + '─'.repeat(NW + SW + UW + TW + 10);
137
- const header = ` ${'SESSION'.padEnd(NW)} ${'STATUS'.padEnd(SW)} ${'UP'.padEnd(UW)} ${'USAGE / RESET'.padEnd(TW)}`;
138
- const rows = sessions.map(s => {
151
+ const header = ` ${'#'.padEnd(3)}${'SESSION'.padEnd(NW)} ${'STATUS'.padEnd(SW)} ${'UP'.padEnd(UW)} ${'USAGE / RESET'.padEnd(TW)}`;
152
+
153
+ const rows = allSessions.slice(0, 9).map((s, i) => {
154
+ const num = `${i + 1}`;
139
155
  const { plain, colored } = formatStatus(s);
140
156
  const pad = ' '.repeat(Math.max(0, SW - plain.length));
141
- const usage = formatUsage(s);
142
- return ` ${trunc(s.name, NW)} ${colored}${pad} ${uptime(s.startedAt).padEnd(UW)} ${trunc(usage, TW)}`;
157
+ const usage = s.status === 'offline' ? '' : formatUsage(s);
158
+ const up = s.status === 'offline' ? '—' : uptime(s.startedAt);
159
+ const sel = selectedIdx === i ? '▶' : ' ';
160
+ return ` ${sel}${num.padEnd(2)}${trunc(s.name, NW)} ${colored}${pad} ${up.padEnd(UW)} ${trunc(usage, TW)}`;
143
161
  });
144
- const footer = ` ${sessions.length} session${sessions.length !== 1 ? 's' : ''} ${new Date().toLocaleTimeString()} q to exit`;
162
+
163
+ let footer;
164
+ if (selectedIdx >= 0 && selectedIdx < allSessions.length) {
165
+ const sel = allSessions[selectedIdx];
166
+ if (sel.status === 'offline') {
167
+ footer = ` [s] spawn [r] remove from history Esc: back`;
168
+ } else {
169
+ footer = ` [t] terminal [k] kill Esc: back`;
170
+ }
171
+ } else {
172
+ footer = ` [1-${Math.min(allSessions.length, 9)}]: select session q: exit watch`;
173
+ }
174
+
145
175
  return ['\n', ' Claude Code Remote Pilot', bar, header, bar, ...rows, bar, footer, ''].join('\n');
146
176
  }
147
177
 
148
- // ─── watch mode ───────────────────────────────────────────────────────────────
149
-
150
178
  function startWatch(manager, rl) {
179
+ let selectedIdx = -1;
180
+ let allSessions = buildAllSessions(manager);
181
+ const timer = { id: null };
182
+
151
183
  function draw() {
184
+ allSessions = buildAllSessions(manager);
152
185
  process.stdout.write('\x1B[2J\x1B[0f');
153
- process.stdout.write(renderTable(manager.list()));
186
+ process.stdout.write(renderWatchTable(allSessions, selectedIdx));
154
187
  }
155
188
 
156
- draw();
157
- const interval = setInterval(draw, 2000);
189
+ function startTimer() {
190
+ timer.id = setInterval(draw, 1000);
191
+ }
158
192
 
159
- function exit() {
193
+ function stopTimer() {
194
+ clearInterval(timer.id);
195
+ timer.id = null;
196
+ }
197
+
198
+ function exitWatch() {
160
199
  process.stdin.removeListener('keypress', onKeypress);
161
- clearInterval(interval);
200
+ stopTimer();
162
201
  process.stdout.write('\x1B[2J\x1B[0f');
163
- // Clear any character readline buffered while we were in watch mode
164
202
  rl.write(null, { ctrl: true, name: 'u' });
165
203
  rl.prompt();
166
204
  }
167
205
 
206
+ function redraw() {
207
+ process.stdout.write('\x1B[2J\x1B[0f');
208
+ process.stdout.write(renderWatchTable(allSessions, selectedIdx));
209
+ }
210
+
168
211
  function onKeypress(str, key) {
169
- if (str === 'q' || str === 'Q' || (key && key.ctrl && key.name === 'c')) {
170
- exit();
212
+ if (!key) return;
213
+
214
+ if (key.ctrl && key.name === 'c') { exitWatch(); return; }
215
+
216
+ if (key.name === 'escape') {
217
+ selectedIdx = -1;
218
+ redraw();
219
+ return;
220
+ }
221
+
222
+ if (selectedIdx < 0) {
223
+ if (str === 'q' || str === 'Q') { exitWatch(); return; }
224
+ const n = parseInt(str);
225
+ if (!isNaN(n) && n >= 1 && n <= Math.min(allSessions.length, 9)) {
226
+ selectedIdx = n - 1;
227
+ redraw();
228
+ }
229
+ return;
230
+ }
231
+
232
+ const sel = allSessions[selectedIdx];
233
+
234
+ if (sel.status === 'offline') {
235
+ if (str === 's' || str === 'S') {
236
+ selectedIdx = -1;
237
+ stopTimer();
238
+ process.stdin.removeListener('keypress', onKeypress);
239
+ process.stdout.write('\x1B[2J\x1B[0f');
240
+ try {
241
+ const session = manager.spawn(sel.path, sel.name);
242
+ process.stdout.write(`\n ✓ "${session.name}" spawned.\n tmux attach -t ${session.name}\n\n`);
243
+ } catch (e) {
244
+ process.stdout.write(`\n Error: ${e.message}\n\n`);
245
+ }
246
+ setTimeout(() => {
247
+ allSessions = buildAllSessions(manager);
248
+ draw();
249
+ startTimer();
250
+ process.stdin.on('keypress', onKeypress);
251
+ }, 1500);
252
+ return;
253
+ }
254
+ if (str === 'r' || str === 'R') {
255
+ config.removeFromHistory(sel.name);
256
+ selectedIdx = -1;
257
+ allSessions = buildAllSessions(manager);
258
+ redraw();
259
+ return;
260
+ }
261
+ } else {
262
+ if (str === 't' || str === 'T') {
263
+ stopTimer();
264
+ process.stdin.removeListener('keypress', onKeypress);
265
+ rl.pause();
266
+ process.stdout.write('\x1B[2J\x1B[0f');
267
+ const child = spawn('tmux', ['attach-session', '-t', sel.name], { stdio: 'inherit' });
268
+ child.on('exit', () => {
269
+ process.stdout.write('\n');
270
+ rl.resume();
271
+ selectedIdx = -1;
272
+ allSessions = buildAllSessions(manager);
273
+ draw();
274
+ startTimer();
275
+ process.stdin.on('keypress', onKeypress);
276
+ });
277
+ return;
278
+ }
279
+ if (str === 'k' || str === 'K') {
280
+ try { manager.kill(sel.name); } catch {}
281
+ selectedIdx = -1;
282
+ allSessions = buildAllSessions(manager);
283
+ redraw();
284
+ return;
285
+ }
171
286
  }
172
287
  }
173
288
 
289
+ draw();
290
+ startTimer();
174
291
  process.stdin.on('keypress', onKeypress);
175
292
  }
176
293
 
@@ -208,20 +325,82 @@ const HELP = `
208
325
  exit Quit pilot (asks whether to kill sessions)
209
326
  `;
210
327
 
211
- function startREPL(manager) {
212
- const rl = readline.createInterface({
328
+ // ─── main ─────────────────────────────────────────────────────────────────────
329
+
330
+ async function main() {
331
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
332
+ console.log(`
333
+ Claude Code Remote Pilot
334
+
335
+ Usage:
336
+ claude-remote-pilot
337
+
338
+ Interactive commands:
339
+ ${HELP}`);
340
+ process.exit(0);
341
+ }
342
+
343
+ const setupRl = readline.createInterface({ input: process.stdin, output: process.stdout });
344
+
345
+ await ensureDep(setupRl, 'tmux', 'tmux', tmuxInstallCmd());
346
+ await ensureDep(setupRl, 'claude', 'Claude Code CLI', 'npm install -g @anthropic-ai/claude-code');
347
+ const telegram = await setupTelegram(setupRl);
348
+
349
+ const cfg = config.load();
350
+ const manager = new SessionManager({ telegram, resumeCommand: cfg.resumeCommand });
351
+
352
+ // Recover sessions from previous run
353
+ const savedSessions = (cfg.sessions || []).filter(s => {
354
+ try { execSync(`tmux has-session -t "${s.name}"`, { stdio: 'ignore' }); return true; }
355
+ catch { return false; }
356
+ });
357
+
358
+ if (savedSessions.length) {
359
+ console.log(`\n Found ${savedSessions.length} session(s) still running from last time:`);
360
+ savedSessions.forEach(s => console.log(` ${s.name.padEnd(22)} ${s.path}`));
361
+ const recover = await question(setupRl, ' Re-adopt and watch them? (Y/n) ');
362
+ if (isYes(recover)) {
363
+ savedSessions.forEach(s => {
364
+ try { manager.adopt(s.name, s.path); console.log(` ✓ Re-adopted "${s.name}"`); }
365
+ catch (e) { console.log(` ✗ Could not adopt "${s.name}": ${e.message}`); }
366
+ });
367
+ console.log('');
368
+ }
369
+ }
370
+
371
+ const cwd = process.cwd();
372
+ const defaultName = path.basename(cwd);
373
+ const mount = await question(setupRl, `Mount current directory as a session? (${defaultName}) [Y/n] `);
374
+
375
+ if (isYes(mount)) {
376
+ const rawName = await questionRaw(setupRl, `Session name [${defaultName}]: `);
377
+ const session = manager.spawn(cwd, rawName || defaultName);
378
+ console.log(` ✓ "${session.name}" started at ${session.path}`);
379
+ console.log(` tmux attach -t ${session.name}\n`);
380
+ }
381
+
382
+ setupRl.close();
383
+
384
+ console.log(' Type help for commands.\n');
385
+ const replRl = readline.createInterface({
213
386
  input: process.stdin,
214
387
  output: process.stdout,
215
388
  prompt: 'claude-pilot> ',
216
389
  });
217
390
 
218
- rl.prompt();
391
+ // Auto-enter watch if there are sessions to monitor
392
+ const allAtStart = buildAllSessions(manager);
393
+ if (allAtStart.length) {
394
+ startWatch(manager, replRl);
395
+ } else {
396
+ replRl.prompt();
397
+ }
219
398
 
220
- rl.on('line', async (line) => {
399
+ replRl.on('line', async (line) => {
221
400
  const parts = line.trim().split(/\s+/).filter(Boolean);
222
401
  const [cmd, ...args] = parts;
223
402
 
224
- if (!cmd) { rl.prompt(); return; }
403
+ if (!cmd) { replRl.prompt(); return; }
225
404
 
226
405
  try {
227
406
  switch (cmd) {
@@ -244,16 +423,16 @@ function startREPL(manager) {
244
423
  break;
245
424
  }
246
425
  case 'watch': {
247
- const sessions = manager.list();
248
- if (!sessions.length) { console.log(' No sessions.'); break; }
249
- startWatch(manager, rl);
426
+ const all = buildAllSessions(manager);
427
+ if (!all.length) { console.log(' No sessions.'); break; }
428
+ startWatch(manager, replRl);
250
429
  return;
251
430
  }
252
431
  case 'attach': {
253
432
  if (!args[0]) { console.log(' Usage: attach <name>'); break; }
254
- rl.pause();
433
+ replRl.pause();
255
434
  const child = spawn('tmux', ['attach-session', '-t', args[0]], { stdio: 'inherit' });
256
- child.on('exit', () => { process.stdout.write('\n'); rl.resume(); rl.prompt(); });
435
+ child.on('exit', () => { process.stdout.write('\n'); replRl.resume(); replRl.prompt(); });
257
436
  return;
258
437
  }
259
438
  case 'kill': {
@@ -264,10 +443,10 @@ function startREPL(manager) {
264
443
  }
265
444
  case 'resume': {
266
445
  if (args.length) {
267
- const cmd = args.join(' ');
268
- manager.resumeCommand = cmd;
269
- config.saveResumeCommand(cmd);
270
- console.log(` ✓ Resume message saved: "${cmd}"`);
446
+ const resumeMsg = args.join(' ');
447
+ manager.resumeCommand = resumeMsg;
448
+ config.saveResumeCommand(resumeMsg);
449
+ console.log(` ✓ Resume message saved: "${resumeMsg}"`);
271
450
  } else {
272
451
  console.log(` Current resume message: "${manager.resumeCommand || '(default)'}"`);
273
452
  }
@@ -279,7 +458,7 @@ function startREPL(manager) {
279
458
  }
280
459
  case 'exit':
281
460
  case 'quit': {
282
- await handleExit(manager, rl);
461
+ await handleExit(manager, replRl);
283
462
  return;
284
463
  }
285
464
  default:
@@ -289,74 +468,13 @@ function startREPL(manager) {
289
468
  console.error(` Error: ${err.message}`);
290
469
  }
291
470
 
292
- rl.prompt();
471
+ replRl.prompt();
293
472
  });
294
473
 
295
- rl.on('close', () => {
296
- // stdin closed (Ctrl+D) — can't ask interactively, keep sessions running
474
+ replRl.on('close', () => {
297
475
  console.log('\n Sessions keep running. Use tmux to attach.\n');
298
476
  process.exit(0);
299
477
  });
300
478
  }
301
479
 
302
- // ─── main ─────────────────────────────────────────────────────────────────────
303
-
304
- async function main() {
305
- if (process.argv.includes('--help') || process.argv.includes('-h')) {
306
- console.log(`
307
- Claude Code Remote Pilot
308
-
309
- Usage:
310
- claude-remote-pilot
311
-
312
- Interactive commands:
313
- ${HELP}`);
314
- process.exit(0);
315
- }
316
-
317
- const setupRl = readline.createInterface({ input: process.stdin, output: process.stdout });
318
-
319
- await ensureDep(setupRl, 'tmux', 'tmux', tmuxInstallCmd());
320
- await ensureDep(setupRl, 'claude', 'Claude Code CLI', 'npm install -g @anthropic-ai/claude-code');
321
- const telegram = await setupTelegram(setupRl);
322
-
323
- const cfg = config.load();
324
- const manager = new SessionManager({ telegram, resumeCommand: cfg.resumeCommand });
325
-
326
- // Recover sessions from previous run
327
- const savedSessions = (cfg.sessions || []).filter(s => {
328
- try { execSync(`tmux has-session -t "${s.name}"`, { stdio: 'ignore' }); return true; }
329
- catch { return false; }
330
- });
331
-
332
- if (savedSessions.length) {
333
- console.log(`\n Found ${savedSessions.length} session(s) still running from last time:`);
334
- savedSessions.forEach(s => console.log(` ${s.name.padEnd(22)} ${s.path}`));
335
- const recover = await question(setupRl, ' Re-adopt and watch them? (Y/n) ');
336
- if (isYes(recover)) {
337
- savedSessions.forEach(s => {
338
- try { manager.adopt(s.name, s.path); console.log(` ✓ Re-adopted "${s.name}"`); }
339
- catch (e) { console.log(` ✗ Could not adopt "${s.name}": ${e.message}`); }
340
- });
341
- console.log('');
342
- }
343
- }
344
-
345
- const cwd = process.cwd();
346
- const defaultName = path.basename(cwd);
347
- const mount = await question(setupRl, `Mount current directory as a session? (${defaultName}) [Y/n] `);
348
-
349
- if (isYes(mount)) {
350
- const rawName = await questionRaw(setupRl, `Session name [${defaultName}]: `);
351
- const session = manager.spawn(cwd, rawName || defaultName);
352
- console.log(` ✓ "${session.name}" started at ${session.path}`);
353
- console.log(` tmux attach -t ${session.name}\n`);
354
- }
355
-
356
- setupRl.close();
357
-
358
- console.log(' Type help for commands.\n');
359
- startREPL(manager);
360
- }
361
-
362
480
  main().catch(err => { console.error(err.message); process.exit(1); });
@@ -3,6 +3,7 @@ const { execSync } = require('child_process');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const Watcher = require('./Watcher');
6
+ const config = require('./config');
6
7
 
7
8
  const RESERVED = new Set(['spawn', 'list', 'watch', 'attach', 'kill', 'help', 'exit', 'quit', 'resume']);
8
9
 
@@ -44,6 +45,7 @@ class SessionManager {
44
45
  const watcher = this._makeWatcher(session);
45
46
  watcher.start();
46
47
  this.sessions.set(sessionName, { session, watcher });
48
+ config.addToHistory(sessionName, resolved);
47
49
  return session;
48
50
  }
49
51
 
@@ -57,6 +59,7 @@ class SessionManager {
57
59
  const watcher = this._makeWatcher(session);
58
60
  watcher.start();
59
61
  this.sessions.set(name, { session, watcher });
62
+ config.addToHistory(name, dirPath);
60
63
  return session;
61
64
  }
62
65
 
package/lib/Watcher.js CHANGED
@@ -16,7 +16,7 @@ class Watcher {
16
16
  this.session = session;
17
17
  this.telegram = opts.telegram || {};
18
18
  this.onEnded = opts.onEnded || (() => {});
19
- this.checkInterval = opts.checkInterval || 30000;
19
+ this.checkInterval = opts.checkInterval || 5000;
20
20
  this.fallbackWait = opts.fallbackWait || 300;
21
21
  this.cooldown = opts.cooldown || 180;
22
22
  this.captureLines = opts.captureLines || 500;
package/lib/config.js CHANGED
@@ -34,4 +34,20 @@ function saveResumeCommand(cmd) {
34
34
  save({ resumeCommand: cmd });
35
35
  }
36
36
 
37
- module.exports = { load, saveTelegram, saveSessions, clearSessions, saveResumeCommand };
37
+ function addToHistory(name, path) {
38
+ const cfg = load();
39
+ const history = (cfg.sessionHistory || []).filter(s => s.name !== name);
40
+ history.unshift({ name, path, lastSeen: new Date().toISOString() });
41
+ save({ sessionHistory: history.slice(0, 30) }); // cap at 30
42
+ }
43
+
44
+ function removeFromHistory(name) {
45
+ const cfg = load();
46
+ save({ sessionHistory: (cfg.sessionHistory || []).filter(s => s.name !== name) });
47
+ }
48
+
49
+ function getHistory() {
50
+ return load().sessionHistory || [];
51
+ }
52
+
53
+ module.exports = { load, saveTelegram, saveSessions, clearSessions, saveResumeCommand, addToHistory, removeFromHistory, getHistory };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-remote-pilot",
3
- "version": "0.2.13",
3
+ "version": "0.3.1",
4
4
  "description": "Interactive Claude Code supervisor — spawn and monitor multiple Claude sessions from a single terminal.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "bin/",
11
11
  "lib/",
12
12
  "README.md",
13
+ "CHANGELOG.md",
13
14
  "LICENSE"
14
15
  ],
15
16
  "scripts": {