claude-code-remote-pilot 0.2.9 → 0.2.10

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.
@@ -111,14 +111,21 @@ function trunc(str, len) {
111
111
  return str.length <= len ? str.padEnd(len) : str.slice(0, len - 1) + '…';
112
112
  }
113
113
 
114
+ function uptime(startedAt) {
115
+ const s = Math.floor((Date.now() - new Date(startedAt)) / 1000);
116
+ if (s < 60) return `${s}s`;
117
+ if (s < 3600) return `${Math.floor(s / 60)}m`;
118
+ return `${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m`;
119
+ }
120
+
114
121
  function renderTable(sessions) {
115
- const NW = 20, SW = 14;
116
- const bar = ' ' + '─'.repeat(NW + SW + 42);
117
- const header = ` ${'SESSION'.padEnd(NW)} ${'STATUS'.padEnd(SW)} DIRECTORY`;
122
+ const NW = 18, SW = 14, UW = 8;
123
+ const bar = ' ' + '─'.repeat(NW + SW + UW + 34);
124
+ const header = ` ${'SESSION'.padEnd(NW)} ${'STATUS'.padEnd(SW)} ${'UP'.padEnd(UW)} DIRECTORY`;
118
125
  const rows = sessions.map(s => {
119
126
  const { plain, colored } = formatStatus(s);
120
127
  const pad = ' '.repeat(Math.max(0, SW - plain.length));
121
- return ` ${trunc(s.name, NW)} ${colored}${pad} ${trunc(s.path, 40)}`;
128
+ return ` ${trunc(s.name, NW)} ${colored}${pad} ${uptime(s.startedAt).padEnd(UW)} ${trunc(s.path, 32)}`;
122
129
  });
123
130
  const footer = ` ${sessions.length} session${sessions.length !== 1 ? 's' : ''} ${new Date().toLocaleTimeString()} q to exit`;
124
131
  return ['\n', ' Claude Code Remote Pilot', bar, header, bar, ...rows, bar, footer, ''].join('\n');
package/lib/Watcher.js CHANGED
@@ -25,6 +25,12 @@ class Watcher {
25
25
  this.lastResumeAt = 0;
26
26
  this._timer = null;
27
27
  this._busy = false;
28
+ this._prevOutputHash = '';
29
+ this._outputUnchangedCount = 0;
30
+ }
31
+
32
+ _stripAnsi(text) {
33
+ return text.replace(/\x1b\[[0-9;]*[mGKHFABCDJsuhl]/g, '').replace(/\x1b[()][AB012]/g, '');
28
34
  }
29
35
 
30
36
  start() {
@@ -73,12 +79,22 @@ class Watcher {
73
79
  return;
74
80
  }
75
81
 
76
- const text = this._capture();
82
+ const raw = this._capture();
83
+ const text = this._stripAnsi(raw);
77
84
  const nonEmptyLines = text.split('\n').filter(l => l.trim());
78
85
  const lastLine = nonEmptyLines[nonEmptyLines.length - 1] || '';
79
- // Only check recent lines for transient UI elements
80
86
  const recentLines = nonEmptyLines.slice(-5).join('\n');
81
87
 
88
+ // Track whether output is changing between checks
89
+ const outputHash = this._hash(recentLines);
90
+ if (outputHash === this._prevOutputHash) {
91
+ this._outputUnchangedCount++;
92
+ } else {
93
+ this._prevOutputHash = outputHash;
94
+ this._outputUnchangedCount = 0;
95
+ }
96
+ const outputIsStable = this._outputUnchangedCount >= 2;
97
+
82
98
  if (LIMIT_RE.test(text)) {
83
99
  await this._handleLimit(text);
84
100
  } else if (RESPONSE_RE.test(recentLines)) {
@@ -92,7 +108,7 @@ class Watcher {
92
108
  this.session.status = 'running';
93
109
  this.session.resumeAt = null;
94
110
  }
95
- } else if (IDLE_RE.test(lastLine)) {
111
+ } else if (IDLE_RE.test(lastLine) || outputIsStable) {
96
112
  if (this.session.status !== 'idle') {
97
113
  this.session.status = 'idle';
98
114
  this.session.resumeAt = null;
@@ -112,6 +128,7 @@ class Watcher {
112
128
  if ((Date.now() / 1000) - this.lastResumeAt < this.cooldown) return;
113
129
 
114
130
  this.lastHash = hash;
131
+ this._outputUnchangedCount = 0; // reset — we're intentionally waiting
115
132
  const wait = this._parseWait(text);
116
133
  this.session.status = 'limit';
117
134
  this.session.resumeAt = Date.now() + wait * 1000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-remote-pilot",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Interactive Claude Code supervisor — spawn and monitor multiple Claude sessions from a single terminal.",
5
5
  "type": "commonjs",
6
6
  "bin": {