halo-agent 1.2.2 → 1.3.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/browser.js +36 -26
- package/index.js +7 -25
- package/package.json +1 -1
package/browser.js
CHANGED
|
@@ -3,10 +3,19 @@
|
|
|
3
3
|
const { chromium } = require('playwright');
|
|
4
4
|
const { execSync, spawnSync, spawn } = require('child_process');
|
|
5
5
|
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
6
8
|
|
|
7
9
|
const CDP_PORT = 9222;
|
|
8
10
|
const CDP_URL = `http://localhost:${CDP_PORT}`;
|
|
9
11
|
|
|
12
|
+
// Dedicated user-data-dir for the agent's Chrome. Fully isolated from the
|
|
13
|
+
// user's real Chrome so it can run side-by-side without profile-lock
|
|
14
|
+
// collisions (which silently disable --remote-debugging-port). The
|
|
15
|
+
// user logs into Workday / LinkedIn here ONCE on first run and the
|
|
16
|
+
// session persists across runs because this dir is on disk, not /tmp.
|
|
17
|
+
const AGENT_PROFILE_DIR = path.join(os.homedir(), '.halo-agent', 'chrome-profile');
|
|
18
|
+
|
|
10
19
|
/**
|
|
11
20
|
* Check if Chrome is already running with remote debugging on CDP_PORT.
|
|
12
21
|
*/
|
|
@@ -42,12 +51,22 @@ function findChromeMac() {
|
|
|
42
51
|
*/
|
|
43
52
|
function launchChrome() {
|
|
44
53
|
const platform = process.platform;
|
|
45
|
-
|
|
54
|
+
|
|
55
|
+
// Ensure the dedicated profile dir exists. Chrome will populate it on
|
|
56
|
+
// first launch (and persist cookies/logins there across runs).
|
|
57
|
+
try { fs.mkdirSync(AGENT_PROFILE_DIR, { recursive: true }); } catch {}
|
|
58
|
+
|
|
59
|
+
// Note: we use --user-data-dir (a full isolated dir), NOT --profile-directory
|
|
60
|
+
// (which is a sub-profile name inside the default user-data-dir and would
|
|
61
|
+
// still collide with the user's running Chrome and silently drop the
|
|
62
|
+
// --remote-debugging-port flag).
|
|
63
|
+
const baseFlags = [
|
|
46
64
|
`--remote-debugging-port=${CDP_PORT}`,
|
|
47
|
-
|
|
65
|
+
`--user-data-dir=${AGENT_PROFILE_DIR}`,
|
|
48
66
|
'--no-first-run',
|
|
49
67
|
'--no-default-browser-check',
|
|
50
|
-
|
|
68
|
+
'--no-default-browser-check',
|
|
69
|
+
];
|
|
51
70
|
|
|
52
71
|
if (platform === 'darwin') {
|
|
53
72
|
const chromePath = findChromeMac();
|
|
@@ -55,22 +74,11 @@ function launchChrome() {
|
|
|
55
74
|
console.error('[halo-agent] Chrome not found. Install Google Chrome from https://www.google.com/chrome/');
|
|
56
75
|
return;
|
|
57
76
|
}
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
// the
|
|
62
|
-
|
|
63
|
-
// see it. `open -na` forces a fresh app instance and `--args` passes
|
|
64
|
-
// flags through reliably — this is the only correct way to launch
|
|
65
|
-
// Chrome with custom flags on macOS.
|
|
66
|
-
const splitFlags = [
|
|
67
|
-
`--remote-debugging-port=${CDP_PORT}`,
|
|
68
|
-
'--profile-directory=Default',
|
|
69
|
-
'--no-first-run',
|
|
70
|
-
'--no-default-browser-check',
|
|
71
|
-
'--restore-last-session', // bring back the windows the user just had
|
|
72
|
-
];
|
|
73
|
-
spawn('open', ['-na', chromePath, '--args', ...splitFlags], {
|
|
77
|
+
// `open -na` forces a fresh app instance (LaunchServices would otherwise
|
|
78
|
+
// reactivate the existing Chrome and drop our flags). Because we point
|
|
79
|
+
// at a dedicated --user-data-dir, this instance does NOT collide with
|
|
80
|
+
// the user's everyday Chrome — they can run side-by-side cleanly.
|
|
81
|
+
spawn('open', ['-na', chromePath, '--args', ...baseFlags], {
|
|
74
82
|
detached: true,
|
|
75
83
|
stdio: 'ignore',
|
|
76
84
|
}).unref();
|
|
@@ -82,10 +90,12 @@ function launchChrome() {
|
|
|
82
90
|
];
|
|
83
91
|
const chromePath = chromePaths.find(p => { try { fs.accessSync(p); return true; } catch { return false; } });
|
|
84
92
|
if (!chromePath) { console.error('[halo-agent] Chrome not found on Windows.'); return; }
|
|
85
|
-
|
|
93
|
+
const winFlags = baseFlags.map(f => f.includes(' ') ? `"${f}"` : f).join(' ');
|
|
94
|
+
spawn(`"${chromePath}" ${winFlags}`, [], { shell: true, detached: true, stdio: 'ignore' }).unref();
|
|
86
95
|
} else {
|
|
87
96
|
// Linux
|
|
88
|
-
|
|
97
|
+
const linuxFlags = baseFlags.map(f => f.includes(' ') ? `"${f}"` : f).join(' ');
|
|
98
|
+
spawn(`google-chrome ${linuxFlags}`, [], { shell: true, detached: true, stdio: 'ignore' }).unref();
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
101
|
|
|
@@ -166,11 +176,11 @@ async function connectToChrome(retries = 10, opts = {}) {
|
|
|
166
176
|
|
|
167
177
|
console.log(''); // newline after dots
|
|
168
178
|
throw new Error(
|
|
169
|
-
`Could not connect to Chrome after ${retries} attempts.\n` +
|
|
170
|
-
`
|
|
171
|
-
`
|
|
172
|
-
`
|
|
173
|
-
`
|
|
179
|
+
`Could not connect to the agent's Chrome on port ${CDP_PORT} after ${retries} attempts.\n` +
|
|
180
|
+
`The agent uses an isolated Chrome profile at ${AGENT_PROFILE_DIR}.\n` +
|
|
181
|
+
`If a previous run is still alive, kill it:\n\n` +
|
|
182
|
+
` pkill -f "user-data-dir=${AGENT_PROFILE_DIR}"\n\n` +
|
|
183
|
+
`Then run \`halo-agent start\` again.\n`
|
|
174
184
|
);
|
|
175
185
|
}
|
|
176
186
|
|
package/index.js
CHANGED
|
@@ -453,34 +453,16 @@ async function runStart() {
|
|
|
453
453
|
console.log('\nHALO Agent starting...');
|
|
454
454
|
console.log('Connecting to your Chrome browser...\n');
|
|
455
455
|
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
const { isChromeDebuggable } = require('./browser');
|
|
462
|
-
// weRestartedIt: tracks whether THIS process launched/restarted Chrome.
|
|
463
|
-
// When true, connectToChrome must NOT launch again — that's the double-
|
|
464
|
-
// launch bug that was spawning extra Chrome windows.
|
|
465
|
-
let weRestartedIt = false;
|
|
466
|
-
const alreadyDebuggable = await isChromeDebuggable();
|
|
467
|
-
if (!alreadyDebuggable) {
|
|
468
|
-
const needsRestart = await detectChromeRunningWithoutDebug();
|
|
469
|
-
if (needsRestart) {
|
|
470
|
-
const ok = await offerChromeRestart();
|
|
471
|
-
if (!ok) {
|
|
472
|
-
console.error('\nOK — leaving Chrome alone. Run `halo-agent start` again after you’ve quit Chrome.');
|
|
473
|
-
process.exit(1);
|
|
474
|
-
}
|
|
475
|
-
await restartChromeWithDebugFlag();
|
|
476
|
-
weRestartedIt = true;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
456
|
+
// The agent runs its own isolated Chrome instance (separate --user-data-dir
|
|
457
|
+
// at ~/.halo-agent/chrome-profile) so it never collides with the user's
|
|
458
|
+
// everyday Chrome. First launch will be a blank profile — the user logs
|
|
459
|
+
// into Workday / LinkedIn ONCE in the agent's Chrome and those sessions
|
|
460
|
+
// persist across runs. No need to detect or restart the user's Chrome.
|
|
480
461
|
let chromeConn;
|
|
481
462
|
try {
|
|
482
|
-
chromeConn = await connectToChrome(10
|
|
463
|
+
chromeConn = await connectToChrome(10);
|
|
483
464
|
console.log('\nConnected to Chrome. Polling for queued jobs...');
|
|
465
|
+
console.log('First time? Log into Workday/LinkedIn in this Chrome window — sessions persist.');
|
|
484
466
|
console.log('Go to your HALO dashboard and click "Auto-Apply" on any job.\n');
|
|
485
467
|
} catch (err) {
|
|
486
468
|
console.error('\nCould not connect to Chrome:', err.message);
|