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.
- package/bin/claude-pilot.js +13 -10
- package/lib/Watcher.js +3 -20
- package/package.json +1 -1
package/bin/claude-pilot.js
CHANGED
|
@@ -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? (
|
|
39
|
-
if (answer
|
|
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/
|
|
71
|
-
if (answer
|
|
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
|
|
184
|
-
if (answer
|
|
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? (
|
|
333
|
-
if (recover
|
|
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}) [
|
|
347
|
+
const mount = await question(setupRl, `Mount current directory as a session? (${defaultName}) [Y/n] `);
|
|
345
348
|
|
|
346
|
-
if (mount
|
|
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
|
|
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
|
|
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