claude-code-remote-pilot 0.2.11 → 0.2.13

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.
@@ -32,11 +32,14 @@ function tmuxInstallCmd() {
32
32
  return 'sudo apt-get install -y tmux';
33
33
  }
34
34
 
35
+ function isYes(answer) { return answer === '' || answer === 'y' || answer === 'yes'; }
36
+ function isNo(answer) { return answer === '' || answer === 'n' || answer === 'no'; }
37
+
35
38
  async function ensureDep(rl, cmd, label, installCmd) {
36
39
  if (has(cmd)) return;
37
40
  console.log(`\n${label} is not installed.`);
38
- const answer = await question(rl, 'Install it now? (y/n) ');
39
- if (answer !== 'y' && answer !== 'yes') {
41
+ const answer = await question(rl, 'Install it now? (Y/n) ');
42
+ if (!isYes(answer)) {
40
43
  console.log(`Run manually: ${installCmd}`);
41
44
  process.exit(1);
42
45
  }
@@ -67,8 +70,8 @@ async function setupTelegram(rl) {
67
70
  return saved;
68
71
  }
69
72
  console.log('\nTelegram notifications (optional).');
70
- const answer = await question(rl, 'Set up Telegram now? (y/n) ');
71
- if (answer !== 'y' && answer !== 'yes') { console.log('Skipping.\n'); return {}; }
73
+ const answer = await question(rl, 'Set up Telegram now? (y/N) ');
74
+ if (answer === '' || !isYes(answer)) { console.log('Skipping.\n'); return {}; }
72
75
  const token = await questionRaw(rl, 'Bot token: ');
73
76
  const chatId = await questionRaw(rl, 'Chat ID: ');
74
77
  config.saveTelegram(token, chatId);
@@ -180,8 +183,8 @@ async function handleExit(manager, rl) {
180
183
  console.log('');
181
184
  process.exit(0);
182
185
  }
183
- const answer = await questionRaw(rl, `\n Kill all ${sessions.length} session(s) before exiting? (y/n) `);
184
- if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
186
+ const answer = await question(rl, `\n Kill all ${sessions.length} session(s) before exiting? (y/N) `);
187
+ if (isYes(answer) && answer !== '') {
185
188
  manager.killAll();
186
189
  config.clearSessions();
187
190
  console.log(' All sessions killed.\n');
@@ -329,8 +332,8 @@ ${HELP}`);
329
332
  if (savedSessions.length) {
330
333
  console.log(`\n Found ${savedSessions.length} session(s) still running from last time:`);
331
334
  savedSessions.forEach(s => console.log(` ${s.name.padEnd(22)} ${s.path}`));
332
- const recover = await question(setupRl, ' Re-adopt and watch them? (y/n) ');
333
- if (recover === 'y' || recover === 'yes') {
335
+ const recover = await question(setupRl, ' Re-adopt and watch them? (Y/n) ');
336
+ if (isYes(recover)) {
334
337
  savedSessions.forEach(s => {
335
338
  try { manager.adopt(s.name, s.path); console.log(` ✓ Re-adopted "${s.name}"`); }
336
339
  catch (e) { console.log(` ✗ Could not adopt "${s.name}": ${e.message}`); }
@@ -341,9 +344,9 @@ ${HELP}`);
341
344
 
342
345
  const cwd = process.cwd();
343
346
  const defaultName = path.basename(cwd);
344
- const mount = await question(setupRl, `Mount current directory as a session? (${defaultName}) [y/n] `);
347
+ const mount = await question(setupRl, `Mount current directory as a session? (${defaultName}) [Y/n] `);
345
348
 
346
- if (mount === 'y' || mount === 'yes') {
349
+ if (isYes(mount)) {
347
350
  const rawName = await questionRaw(setupRl, `Session name [${defaultName}]: `);
348
351
  const session = manager.spawn(cwd, rawName || defaultName);
349
352
  console.log(` ✓ "${session.name}" started at ${session.path}`);
package/lib/Watcher.js CHANGED
@@ -6,7 +6,6 @@ const notifier = require('./notifier');
6
6
  const LIMIT_RE = /hit your limit|usage limit|rate limit|limit reached|try again|resets/i;
7
7
  const RESPONSE_RE = /do you want to proceed|esc to cancel|ctrl\+e to explain|❯\s*\d+\.\s*yes/i;
8
8
  const RUNNING_RE = /esc to interrupt/i;
9
- const IDLE_RE = /^\s*>\s*$/;
10
9
  // Claude Code footer: "tokens: ↑1,234 ↓567" or "↑1.2k ↓890"
11
10
  const TOKEN_RE = /↑\s*([\d.,]+[km]?)\s*↓\s*([\d.,]+[km]?)/i;
12
11
  // Limit reset time: "resets at 2:00 AM" or "resets at 14:30"
@@ -26,8 +25,6 @@ class Watcher {
26
25
  this.lastResumeAt = 0;
27
26
  this._timer = null;
28
27
  this._busy = false;
29
- this._prevOutputHash = '';
30
- this._outputUnchangedCount = 0;
31
28
  }
32
29
 
33
30
  _stripAnsi(text) {
@@ -98,25 +95,14 @@ class Watcher {
98
95
  const raw = this._capture();
99
96
  const text = this._stripAnsi(raw);
100
97
  const nonEmptyLines = text.split('\n').filter(l => l.trim());
101
- const lastLine = nonEmptyLines[nonEmptyLines.length - 1] || '';
102
98
  const recentLines = nonEmptyLines.slice(-5).join('\n');
103
99
 
104
- // Extract token usage from footer whenever Claude is running
100
+ // Extract token usage from footer whenever visible
105
101
  const tokenMatch = recentLines.match(TOKEN_RE);
106
102
  if (tokenMatch) {
107
103
  this.session.tokens = { sent: tokenMatch[1], received: tokenMatch[2] };
108
104
  }
109
105
 
110
- // Track output stability
111
- const outputHash = this._hash(recentLines);
112
- if (outputHash === this._prevOutputHash) {
113
- this._outputUnchangedCount++;
114
- } else {
115
- this._prevOutputHash = outputHash;
116
- this._outputUnchangedCount = 0;
117
- }
118
- const outputIsStable = this._outputUnchangedCount >= 2;
119
-
120
106
  if (LIMIT_RE.test(text)) {
121
107
  await this._handleLimit(text);
122
108
  } else if (RESPONSE_RE.test(recentLines)) {
@@ -130,14 +116,12 @@ class Watcher {
130
116
  this.session.status = 'running';
131
117
  this.session.resumeAt = null;
132
118
  }
133
- } else if (IDLE_RE.test(lastLine) || outputIsStable) {
119
+ } else {
120
+ // No "esc to interrupt" visible — Claude is not actively processing
134
121
  if (this.session.status !== 'idle') {
135
122
  this.session.status = 'idle';
136
123
  this.session.resumeAt = null;
137
124
  }
138
- } else if (this.session.status !== 'running') {
139
- this.session.status = 'running';
140
- this.session.resumeAt = null;
141
125
  }
142
126
  } finally {
143
127
  this._busy = false;
@@ -150,7 +134,6 @@ class Watcher {
150
134
  if ((Date.now() / 1000) - this.lastResumeAt < this.cooldown) return;
151
135
 
152
136
  this.lastHash = hash;
153
- this._outputUnchangedCount = 0;
154
137
  const wait = this._parseWait(text);
155
138
  const resetTime = this._parseResetTime(text);
156
139
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-remote-pilot",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Interactive Claude Code supervisor — spawn and monitor multiple Claude sessions from a single terminal.",
5
5
  "type": "commonjs",
6
6
  "bin": {