@adhdev/daemon-core 0.5.30 → 0.5.32
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/package.json
CHANGED
|
@@ -24,15 +24,13 @@ import { LOG } from '../logging/logger.js';
|
|
|
24
24
|
let pty: any;
|
|
25
25
|
try {
|
|
26
26
|
pty = require('node-pty');
|
|
27
|
-
// node-pty
|
|
27
|
+
// node-pty ships spawn-helper without +x on macOS (npm umask issue) — fix it
|
|
28
28
|
if (os.platform() !== 'win32') {
|
|
29
29
|
try {
|
|
30
30
|
const fs = require('fs');
|
|
31
|
-
// require.resolve('node-pty') → .../node-pty/lib/index.js
|
|
32
|
-
// prebuilds/ is at .../node-pty/prebuilds/, not .../node-pty/lib/prebuilds/
|
|
33
31
|
const ptyDir = path.resolve(path.dirname(require.resolve('node-pty')), '..');
|
|
34
|
-
const
|
|
35
|
-
const helper = path.join(ptyDir, 'prebuilds',
|
|
32
|
+
const platformArch = `${os.platform()}-${os.arch()}`;
|
|
33
|
+
const helper = path.join(ptyDir, 'prebuilds', platformArch, 'spawn-helper');
|
|
36
34
|
if (fs.existsSync(helper)) {
|
|
37
35
|
const stat = fs.statSync(helper);
|
|
38
36
|
if (!(stat.mode & 0o111)) {
|
|
@@ -43,7 +41,7 @@ try {
|
|
|
43
41
|
} catch { /* best-effort */ }
|
|
44
42
|
}
|
|
45
43
|
} catch {
|
|
46
|
-
LOG.error('CLI', '[ProviderCliAdapter] node-pty not found.
|
|
44
|
+
LOG.error('CLI', '[ProviderCliAdapter] node-pty not found. Terminal features disabled.');
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
export interface CliChatMessage {
|
|
@@ -97,9 +95,16 @@ export interface CliProviderModule {
|
|
|
97
95
|
|
|
98
96
|
function stripAnsi(str: string): string {
|
|
99
97
|
// eslint-disable-next-line no-control-regex
|
|
100
|
-
return str
|
|
98
|
+
return str
|
|
99
|
+
// Cursor movement sequences → space (prevents word concatenation)
|
|
100
|
+
.replace(/\x1B\[\d*[A-HJKSTfG]/g, ' ')
|
|
101
|
+
// SGR and other CSI sequences → remove
|
|
102
|
+
.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, '')
|
|
103
|
+
// OSC sequences (title bar etc)
|
|
101
104
|
.replace(/\x1B\][^\x07]*\x07/g, '')
|
|
102
|
-
.replace(/\x1B\][^\x1B]*\x1B\\/g, '')
|
|
105
|
+
.replace(/\x1B\][^\x1B]*\x1B\\/g, '')
|
|
106
|
+
// Collapse multiple spaces
|
|
107
|
+
.replace(/ +/g, ' ');
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
function findBinary(name: string): string {
|
|
@@ -471,6 +476,10 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
471
476
|
}
|
|
472
477
|
|
|
473
478
|
// ─── Phase 2: Approval detect
|
|
479
|
+
// DEBUG: log recent output for approval pattern debugging
|
|
480
|
+
if (cleanData.trim().length > 5) {
|
|
481
|
+
LOG.debug('CLI', `[${this.cliType}] output chunk (${cleanData.length}): ${cleanData.slice(0, 300).replace(/\n/g, '\\n')}`);
|
|
482
|
+
}
|
|
474
483
|
const hasApproval = patterns.approval.some(p => p.test(this.recentOutputBuffer));
|
|
475
484
|
if (hasApproval && this.currentStatus !== 'waiting_approval') {
|
|
476
485
|
const inCooldown = this.lastApprovalResolvedAt && (Date.now() - this.lastApprovalResolvedAt) < this.timeouts.approvalCooldown;
|
|
@@ -149,7 +149,8 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
149
149
|
this.monitor.reset();
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
private completedDebounceTimer: NodeJS.Timeout | null = null;
|
|
153
|
+
private completedDebouncePending: { chatTitle: string; duration: number; timestamp: number } | null = null;
|
|
153
154
|
|
|
154
155
|
private detectStatusTransition(): void {
|
|
155
156
|
const now = Date.now();
|
|
@@ -161,7 +162,14 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
161
162
|
if (newStatus !== this.lastStatus) {
|
|
162
163
|
LOG.info('CLI', `[${this.type}] status: ${this.lastStatus} → ${newStatus}`);
|
|
163
164
|
if (this.lastStatus === 'idle' && newStatus === 'generating') {
|
|
164
|
-
|
|
165
|
+
// Cancel any pending completed event (multi-step: idle→generating resume)
|
|
166
|
+
if (this.completedDebouncePending) {
|
|
167
|
+
LOG.info('CLI', `[${this.type}] cancelled pending completed (resumed generating)`);
|
|
168
|
+
if (this.completedDebounceTimer) { clearTimeout(this.completedDebounceTimer); this.completedDebounceTimer = null; }
|
|
169
|
+
this.completedDebouncePending = null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!this.generatingStartedAt) this.generatingStartedAt = now;
|
|
165
173
|
// Defer the generating_started event — if idle comes back within 1s,
|
|
166
174
|
// the whole started→completed pair was a false positive from PTY noise
|
|
167
175
|
if (this.generatingDebounceTimer) clearTimeout(this.generatingDebounceTimer);
|
|
@@ -180,6 +188,10 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
180
188
|
this.pushEvent({ event: 'agent:generating_started', ...this.generatingDebouncePending });
|
|
181
189
|
this.generatingDebouncePending = null;
|
|
182
190
|
}
|
|
191
|
+
// Cancel any pending completed
|
|
192
|
+
if (this.completedDebounceTimer) { clearTimeout(this.completedDebounceTimer); this.completedDebounceTimer = null; }
|
|
193
|
+
this.completedDebouncePending = null;
|
|
194
|
+
|
|
183
195
|
if (!this.generatingStartedAt) this.generatingStartedAt = now;
|
|
184
196
|
const modal = adapterStatus.activeModal;
|
|
185
197
|
LOG.info('CLI', `[${this.type}] approval modal: "${modal?.message?.slice(0, 80) ?? 'none'}"`);
|
|
@@ -195,15 +207,27 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
195
207
|
LOG.info('CLI', `[${this.type}] suppressed short generating (${now - this.generatingStartedAt}ms)`);
|
|
196
208
|
if (this.generatingDebounceTimer) { clearTimeout(this.generatingDebounceTimer); this.generatingDebounceTimer = null; }
|
|
197
209
|
this.generatingDebouncePending = null;
|
|
210
|
+
this.generatingStartedAt = 0;
|
|
198
211
|
} else {
|
|
199
|
-
|
|
200
|
-
this.
|
|
212
|
+
// Debounce completed — wait 2s, if still idle then emit
|
|
213
|
+
if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
|
|
214
|
+
this.completedDebouncePending = { chatTitle, duration, timestamp: now };
|
|
215
|
+
this.completedDebounceTimer = setTimeout(() => {
|
|
216
|
+
if (this.completedDebouncePending) {
|
|
217
|
+
LOG.info('CLI', `[${this.type}] completed in ${this.completedDebouncePending.duration}s`);
|
|
218
|
+
this.pushEvent({ event: 'agent:generating_completed', ...this.completedDebouncePending });
|
|
219
|
+
this.completedDebouncePending = null;
|
|
220
|
+
this.generatingStartedAt = 0;
|
|
221
|
+
}
|
|
222
|
+
this.completedDebounceTimer = null;
|
|
223
|
+
}, 2000);
|
|
201
224
|
}
|
|
202
|
-
this.generatingStartedAt = 0;
|
|
203
225
|
} else if (newStatus === 'stopped') {
|
|
204
226
|
// Cancel any pending debounce
|
|
205
227
|
if (this.generatingDebounceTimer) { clearTimeout(this.generatingDebounceTimer); this.generatingDebounceTimer = null; }
|
|
206
228
|
this.generatingDebouncePending = null;
|
|
229
|
+
if (this.completedDebounceTimer) { clearTimeout(this.completedDebounceTimer); this.completedDebounceTimer = null; }
|
|
230
|
+
this.completedDebouncePending = null;
|
|
207
231
|
this.pushEvent({ event: 'agent:stopped', chatTitle, timestamp: now });
|
|
208
232
|
}
|
|
209
233
|
this.lastStatus = newStatus;
|