claude-code-remote-pilot 0.2.1 → 0.2.3
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 +18 -8
- package/lib/SessionManager.js +3 -0
- package/lib/Watcher.js +14 -5
- package/package.json +1 -1
package/bin/claude-pilot.js
CHANGED
|
@@ -75,19 +75,29 @@ const C = {
|
|
|
75
75
|
reset: '\x1b[0m',
|
|
76
76
|
green: '\x1b[32m',
|
|
77
77
|
yellow: '\x1b[33m',
|
|
78
|
+
blue: '\x1b[34m',
|
|
79
|
+
orange: '\x1b[38;5;208m',
|
|
78
80
|
dim: '\x1b[2m',
|
|
79
81
|
};
|
|
80
82
|
|
|
81
83
|
function formatStatus(session) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
switch (session.status) {
|
|
85
|
+
case 'running':
|
|
86
|
+
return { plain: 'running', colored: `${C.green}running${C.reset}` };
|
|
87
|
+
case 'idle':
|
|
88
|
+
return { plain: 'idle', colored: `${C.blue}idle${C.reset}` };
|
|
89
|
+
case 'needs-response':
|
|
90
|
+
return { plain: 'needs response', colored: `${C.orange}needs response${C.reset}` };
|
|
91
|
+
case 'limit': {
|
|
92
|
+
const secs = session.resumeAt ? Math.max(0, Math.round((session.resumeAt - Date.now()) / 1000)) : 0;
|
|
93
|
+
const label = `limit ${Math.ceil(secs / 60)}m`;
|
|
94
|
+
return { plain: label, colored: `${C.yellow}${label}${C.reset}` };
|
|
95
|
+
}
|
|
96
|
+
case 'ended':
|
|
97
|
+
return { plain: 'ended', colored: `${C.dim}ended${C.reset}` };
|
|
98
|
+
default:
|
|
99
|
+
return { plain: session.status, colored: session.status };
|
|
87
100
|
}
|
|
88
|
-
if (session.status === 'needs-input') return { plain: 'needs input', colored: `${C.yellow}needs input${C.reset}` };
|
|
89
|
-
if (session.status === 'ended') return { plain: 'ended', colored: `${C.dim}ended${C.reset}` };
|
|
90
|
-
return { plain: session.status, colored: session.status };
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
function trunc(str, len) {
|
package/lib/SessionManager.js
CHANGED
|
@@ -4,6 +4,8 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const Watcher = require('./Watcher');
|
|
6
6
|
|
|
7
|
+
const RESERVED = new Set(['spawn', 'list', 'watch', 'attach', 'kill', 'help', 'exit', 'quit']);
|
|
8
|
+
|
|
7
9
|
function sanitizeName(name) {
|
|
8
10
|
return name.replace(/[.:\s]/g, '-');
|
|
9
11
|
}
|
|
@@ -19,6 +21,7 @@ class SessionManager {
|
|
|
19
21
|
if (!fs.existsSync(resolved)) throw new Error(`Path not found: ${resolved}`);
|
|
20
22
|
|
|
21
23
|
const sessionName = sanitizeName(name || path.basename(resolved));
|
|
24
|
+
if (RESERVED.has(sessionName)) throw new Error(`"${sessionName}" is a reserved command name. Choose a different session name.`);
|
|
22
25
|
if (this.sessions.has(sessionName)) throw new Error(`Session "${sessionName}" already exists.`);
|
|
23
26
|
|
|
24
27
|
// Kill stale tmux session from a previous crashed run
|
package/lib/Watcher.js
CHANGED
|
@@ -4,7 +4,10 @@ const crypto = require('crypto');
|
|
|
4
4
|
const notifier = require('./notifier');
|
|
5
5
|
|
|
6
6
|
const LIMIT_RE = /hit your limit|usage limit|rate limit|limit reached|try again|resets/i;
|
|
7
|
-
const
|
|
7
|
+
const RESPONSE_RE = /\?\s*$|do you want|shall i|should i|please confirm|yes\/no|\(y\/n\)|approve|allow this/i;
|
|
8
|
+
const PERM_RE = /permission|do you want to proceed|approve this action/i;
|
|
9
|
+
// Claude Code shows ">" or "❯" alone on the last line when idle/waiting for next prompt
|
|
10
|
+
const IDLE_RE = /^\s*[>❯]\s*$/;
|
|
8
11
|
|
|
9
12
|
class Watcher {
|
|
10
13
|
constructor(session, opts = {}) {
|
|
@@ -68,14 +71,20 @@ class Watcher {
|
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
const text = this._capture();
|
|
74
|
+
const lastLine = text.split('\n').filter(l => l.trim()).pop() || '';
|
|
71
75
|
|
|
72
76
|
if (LIMIT_RE.test(text)) {
|
|
73
77
|
await this._handleLimit(text);
|
|
74
|
-
} else if (PERM_RE.test(text)) {
|
|
75
|
-
if (this.session.status !== 'needs-
|
|
76
|
-
this.session.status = 'needs-
|
|
78
|
+
} else if (PERM_RE.test(text) || RESPONSE_RE.test(lastLine)) {
|
|
79
|
+
if (this.session.status !== 'needs-response') {
|
|
80
|
+
this.session.status = 'needs-response';
|
|
77
81
|
notifier.send(this.telegram.token, this.telegram.chatId,
|
|
78
|
-
`Pilot: "${this.session.name}" needs
|
|
82
|
+
`Pilot: "${this.session.name}" needs your response.`);
|
|
83
|
+
}
|
|
84
|
+
} else if (IDLE_RE.test(lastLine)) {
|
|
85
|
+
if (this.session.status !== 'idle') {
|
|
86
|
+
this.session.status = 'idle';
|
|
87
|
+
this.session.resumeAt = null;
|
|
79
88
|
}
|
|
80
89
|
} else if (this.session.status !== 'running') {
|
|
81
90
|
this.session.status = 'running';
|
package/package.json
CHANGED