halo-agent 1.1.0 → 1.2.0
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/index.js +129 -24
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -291,6 +291,122 @@ async function runInit() {
|
|
|
291
291
|
console.log('Run "halo-agent start" to begin.\n');
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
// Is Chrome running without the --remote-debugging-port=9222 flag?
|
|
295
|
+
// Returns true ONLY when we're certain a restart is needed.
|
|
296
|
+
async function detectChromeRunningWithoutDebug() {
|
|
297
|
+
const { execSync } = require('child_process');
|
|
298
|
+
try {
|
|
299
|
+
if (process.platform === 'darwin') {
|
|
300
|
+
execSync('pgrep -x "Google Chrome"', { stdio: 'ignore' });
|
|
301
|
+
const psOut = execSync('ps aux', { encoding: 'utf8' });
|
|
302
|
+
return !psOut.includes('--remote-debugging-port=9222');
|
|
303
|
+
}
|
|
304
|
+
if (process.platform === 'win32') {
|
|
305
|
+
const out = execSync('tasklist /FI "IMAGENAME eq chrome.exe"', { encoding: 'utf8' });
|
|
306
|
+
if (!/chrome\.exe/i.test(out)) return false;
|
|
307
|
+
// Windows tasklist doesn't show full cmdline; use wmic as a fallback.
|
|
308
|
+
try {
|
|
309
|
+
const wmic = execSync('wmic process where "name=\'chrome.exe\'" get CommandLine', { encoding: 'utf8' });
|
|
310
|
+
return !wmic.includes('--remote-debugging-port=9222');
|
|
311
|
+
} catch { return true; } // can't introspect — safer to offer restart
|
|
312
|
+
}
|
|
313
|
+
// Linux
|
|
314
|
+
try { execSync('pgrep -x chrome', { stdio: 'ignore' }); } catch { return false; }
|
|
315
|
+
try {
|
|
316
|
+
const ps = execSync('ps -eo args', { encoding: 'utf8' });
|
|
317
|
+
return !ps.includes('--remote-debugging-port=9222');
|
|
318
|
+
} catch { return true; }
|
|
319
|
+
} catch {
|
|
320
|
+
return false; // pgrep failed → Chrome not running
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Terminal Y/n prompt for the consent before we touch Chrome.
|
|
325
|
+
function offerChromeRestart() {
|
|
326
|
+
return new Promise((resolve) => {
|
|
327
|
+
console.log('');
|
|
328
|
+
console.log('Chrome is running, but without the debug flag the agent needs.');
|
|
329
|
+
console.log('I can restart Chrome for you — your tabs will reopen automatically');
|
|
330
|
+
console.log('(if your "On startup" setting is "Continue where you left off").');
|
|
331
|
+
console.log('');
|
|
332
|
+
const readline = require('readline');
|
|
333
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
334
|
+
rl.question('Restart Chrome now? [Y/n] ', (ans) => {
|
|
335
|
+
rl.close();
|
|
336
|
+
const a = (ans || '').trim().toLowerCase();
|
|
337
|
+
resolve(a === '' || a === 'y' || a === 'yes');
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Graceful quit (preserves tabs), wait until the process is actually gone,
|
|
343
|
+
// then relaunch with the debug flag. Cross-platform.
|
|
344
|
+
async function restartChromeWithDebugFlag() {
|
|
345
|
+
const { execSync, spawnSync } = require('child_process');
|
|
346
|
+
const { launchChrome, isChromeDebuggable } = require('./browser');
|
|
347
|
+
|
|
348
|
+
console.log('Restarting Chrome…');
|
|
349
|
+
if (process.platform === 'darwin') {
|
|
350
|
+
// AppleScript graceful quit — respects Chrome's restore-tabs behavior.
|
|
351
|
+
try {
|
|
352
|
+
spawnSync('osascript', ['-e', 'tell application "Google Chrome" to quit'], { stdio: 'ignore' });
|
|
353
|
+
} catch { /* fall through to pkill if osascript missing */ }
|
|
354
|
+
} else if (process.platform === 'win32') {
|
|
355
|
+
// Windows: send WM_CLOSE via taskkill (no /F so it's graceful).
|
|
356
|
+
try { spawnSync('taskkill', ['/IM', 'chrome.exe'], { stdio: 'ignore' }); } catch {}
|
|
357
|
+
} else {
|
|
358
|
+
try { spawnSync('pkill', ['-x', 'chrome'], { stdio: 'ignore' }); } catch {}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Poll until Chrome is gone (up to 10s). If it lingers, the user has a
|
|
362
|
+
// "leave site?" prompt or modal — we surface that rather than force-killing.
|
|
363
|
+
const gone = await waitForChromeGone(10_000);
|
|
364
|
+
if (!gone) {
|
|
365
|
+
console.error('Chrome didn’t quit (you may have an unsaved-changes prompt).');
|
|
366
|
+
console.error('Click through any prompts in Chrome, then run `halo-agent start` again.');
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Relaunch with the debug flag + Default profile. Uses the existing
|
|
371
|
+
// browser.js logic so the path-finding stays in one place.
|
|
372
|
+
await new Promise(r => setTimeout(r, 800)); // brief breath
|
|
373
|
+
launchChrome();
|
|
374
|
+
|
|
375
|
+
// Wait for the new Chrome to expose CDP. Up to ~15s.
|
|
376
|
+
for (let i = 0; i < 30; i++) {
|
|
377
|
+
if (await isChromeDebuggable()) {
|
|
378
|
+
console.log('Chrome is back, debugging enabled.');
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
await new Promise(r => setTimeout(r, 500));
|
|
382
|
+
}
|
|
383
|
+
console.error('Chrome relaunched but CDP didn’t come up in time.');
|
|
384
|
+
console.error('Try running `halo-agent start` again — Chrome may have just been slow.');
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async function waitForChromeGone(timeoutMs) {
|
|
389
|
+
const { execSync } = require('child_process');
|
|
390
|
+
const probe = () => {
|
|
391
|
+
try {
|
|
392
|
+
if (process.platform === 'darwin') execSync('pgrep -x "Google Chrome"', { stdio: 'ignore' });
|
|
393
|
+
else if (process.platform === 'win32') {
|
|
394
|
+
const out = execSync('tasklist /FI "IMAGENAME eq chrome.exe"', { encoding: 'utf8' });
|
|
395
|
+
if (!/chrome\.exe/i.test(out)) return false;
|
|
396
|
+
} else execSync('pgrep -x chrome', { stdio: 'ignore' });
|
|
397
|
+
return true; // pgrep succeeded → still running
|
|
398
|
+
} catch {
|
|
399
|
+
return false; // pgrep failed → process gone
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
const start = Date.now();
|
|
403
|
+
while (Date.now() - start < timeoutMs) {
|
|
404
|
+
if (!probe()) return true;
|
|
405
|
+
await new Promise(r => setTimeout(r, 300));
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
|
|
294
410
|
async function runStart() {
|
|
295
411
|
const config = loadConfig();
|
|
296
412
|
if (!config || !config.token) {
|
|
@@ -301,33 +417,22 @@ async function runStart() {
|
|
|
301
417
|
console.log('\nHALO Agent starting...');
|
|
302
418
|
console.log('Connecting to your Chrome browser...\n');
|
|
303
419
|
|
|
304
|
-
// Pre-check:
|
|
420
|
+
// Pre-check: Chrome must be running with --remote-debugging-port=9222 for
|
|
421
|
+
// CDP to work. If it's running WITHOUT that flag, Chrome can't have it
|
|
422
|
+
// added retroactively — it's a Chrome architecture limit. We offer to
|
|
423
|
+
// restart Chrome gracefully (preserves tabs via Chrome's "Continue where
|
|
424
|
+
// you left off" setting) and relaunch with the flag.
|
|
305
425
|
const { isChromeDebuggable } = require('./browser');
|
|
306
426
|
const alreadyDebuggable = await isChromeDebuggable();
|
|
307
427
|
if (!alreadyDebuggable) {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
try {
|
|
317
|
-
const psOut = execSync('ps aux', { encoding: 'utf8' });
|
|
318
|
-
chromeHasDebugFlag = psOut.includes('--remote-debugging-port=9222');
|
|
319
|
-
} catch {}
|
|
320
|
-
}
|
|
321
|
-
if (chromeRunning && !chromeHasDebugFlag) {
|
|
322
|
-
console.error('Chrome is already running WITHOUT remote debugging enabled.\n');
|
|
323
|
-
console.error('You need to fully quit Chrome first, then relaunch it with the debug flag.\n');
|
|
324
|
-
console.error('Run these commands:\n');
|
|
325
|
-
console.error(' pkill -a -i "Google Chrome"');
|
|
326
|
-
console.error(' sleep 2');
|
|
327
|
-
console.error(' "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --profile-directory=Default &');
|
|
328
|
-
console.error(' sleep 4');
|
|
329
|
-
console.error(' node index.js start\n');
|
|
330
|
-
process.exit(1);
|
|
428
|
+
const needsRestart = await detectChromeRunningWithoutDebug();
|
|
429
|
+
if (needsRestart) {
|
|
430
|
+
const ok = await offerChromeRestart();
|
|
431
|
+
if (!ok) {
|
|
432
|
+
console.error('\nOK — leaving Chrome alone. Run `halo-agent start` again after you’ve quit Chrome.');
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
await restartChromeWithDebugFlag();
|
|
331
436
|
}
|
|
332
437
|
}
|
|
333
438
|
|