claude-code-remote-pilot 0.2.7 → 0.2.8

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.
@@ -6,6 +6,7 @@ const path = require('path');
6
6
  const fs = require('fs');
7
7
  const readline = require('readline');
8
8
  const SessionManager = require('../lib/SessionManager');
9
+ const config = require('../lib/config');
9
10
 
10
11
  // ─── dependency checks ────────────────────────────────────────────────────────
11
12
 
@@ -60,12 +61,18 @@ async function setupTelegram(rl) {
60
61
  if (process.env.TELEGRAM_BOT_TOKEN && process.env.TELEGRAM_CHAT_ID) {
61
62
  return { token: process.env.TELEGRAM_BOT_TOKEN, chatId: process.env.TELEGRAM_CHAT_ID };
62
63
  }
64
+ const saved = config.load().telegram;
65
+ if (saved && saved.token && saved.chatId) {
66
+ console.log(' Telegram: using saved config.\n');
67
+ return saved;
68
+ }
63
69
  console.log('\nTelegram notifications (optional).');
64
70
  const answer = await question(rl, 'Set up Telegram now? (y/n) ');
65
71
  if (answer !== 'y' && answer !== 'yes') { console.log('Skipping.\n'); return {}; }
66
72
  const token = await questionRaw(rl, 'Bot token: ');
67
73
  const chatId = await questionRaw(rl, 'Chat ID: ');
68
- console.log('Telegram configured.\n');
74
+ config.saveTelegram(token, chatId);
75
+ console.log(' Telegram configured and saved.\n');
69
76
  return { token, chatId };
70
77
  }
71
78
 
@@ -151,14 +158,17 @@ function startWatch(manager, rl) {
151
158
  async function handleExit(manager, rl) {
152
159
  const sessions = manager.list();
153
160
  if (!sessions.length) {
161
+ config.clearSessions();
154
162
  console.log('');
155
163
  process.exit(0);
156
164
  }
157
165
  const answer = await questionRaw(rl, `\n Kill all ${sessions.length} session(s) before exiting? (y/n) `);
158
166
  if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
159
167
  manager.killAll();
168
+ config.clearSessions();
160
169
  console.log(' All sessions killed.\n');
161
170
  } else {
171
+ config.saveSessions(sessions);
162
172
  console.log(' Sessions keep running. Use tmux to attach.\n');
163
173
  }
164
174
  process.exit(0);
@@ -279,6 +289,25 @@ ${HELP}`);
279
289
 
280
290
  const manager = new SessionManager({ telegram });
281
291
 
292
+ // Recover sessions from previous run
293
+ const savedSessions = (config.load().sessions || []).filter(s => {
294
+ try { execSync(`tmux has-session -t "${s.name}"`, { stdio: 'ignore' }); return true; }
295
+ catch { return false; }
296
+ });
297
+
298
+ if (savedSessions.length) {
299
+ console.log(`\n Found ${savedSessions.length} session(s) still running from last time:`);
300
+ savedSessions.forEach(s => console.log(` ${s.name.padEnd(22)} ${s.path}`));
301
+ const recover = await question(setupRl, ' Re-adopt and watch them? (y/n) ');
302
+ if (recover === 'y' || recover === 'yes') {
303
+ savedSessions.forEach(s => {
304
+ try { manager.adopt(s.name, s.path); console.log(` ✓ Re-adopted "${s.name}"`); }
305
+ catch (e) { console.log(` ✗ Could not adopt "${s.name}": ${e.message}`); }
306
+ });
307
+ console.log('');
308
+ }
309
+ }
310
+
282
311
  const cwd = process.cwd();
283
312
  const defaultName = path.basename(cwd);
284
313
  const mount = await question(setupRl, `Mount current directory as a session? (${defaultName}) [y/n] `);
@@ -51,6 +51,22 @@ class SessionManager {
51
51
  this.sessions.delete(name);
52
52
  }
53
53
 
54
+ adopt(name, dirPath) {
55
+ try { execSync(`tmux has-session -t "${name}"`, { stdio: 'ignore' }); }
56
+ catch { throw new Error(`tmux session "${name}" not found.`); }
57
+
58
+ if (this.sessions.has(name)) throw new Error(`Session "${name}" already being watched.`);
59
+
60
+ const session = { name, path: dirPath, status: 'running', startedAt: new Date(), resumeAt: null };
61
+ const watcher = new Watcher(session, {
62
+ telegram: this.telegram,
63
+ onEnded: (s) => this.sessions.delete(s.name),
64
+ });
65
+ watcher.start();
66
+ this.sessions.set(name, { session, watcher });
67
+ return session;
68
+ }
69
+
54
70
  killAll() {
55
71
  for (const name of [...this.sessions.keys()]) {
56
72
  try { this.kill(name); } catch {}
package/lib/config.js ADDED
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ const CONFIG_PATH = path.join(os.homedir(), '.claude-remote-pilot.json');
7
+
8
+ function load() {
9
+ try {
10
+ return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
11
+ } catch {
12
+ return {};
13
+ }
14
+ }
15
+
16
+ function save(data) {
17
+ const current = load();
18
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify({ ...current, ...data }, null, 2));
19
+ }
20
+
21
+ function saveTelegram(token, chatId) {
22
+ save({ telegram: { token, chatId } });
23
+ }
24
+
25
+ function saveSessions(sessions) {
26
+ save({ sessions: sessions.map(s => ({ name: s.name, path: s.path })) });
27
+ }
28
+
29
+ function clearSessions() {
30
+ save({ sessions: [] });
31
+ }
32
+
33
+ module.exports = { load, saveTelegram, saveSessions, clearSessions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-remote-pilot",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Interactive Claude Code supervisor — spawn and monitor multiple Claude sessions from a single terminal.",
5
5
  "type": "commonjs",
6
6
  "bin": {