omnikey-cli 1.0.27 → 1.0.29
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/README.md +116 -17
- package/backend-dist/agent/agentPrompts.js +6 -1
- package/backend-dist/agent/agentServer.js +52 -18
- package/backend-dist/agent/imageTool.js +167 -0
- package/backend-dist/agent/utils.js +13 -1
- package/backend-dist/ai-client.js +79 -0
- package/backend-dist/bucket-adapter/index.js +59 -0
- package/backend-dist/config.js +11 -0
- package/backend-dist/index.js +26 -5
- package/backend-dist/models/scheduledJob.js +97 -0
- package/backend-dist/scheduledJobExecutor.js +199 -0
- package/backend-dist/scheduledJobRoutes.js +186 -0
- package/backend-dist/web-search/browser-playwright.js +191 -80
- package/backend-dist/web-search/web-search-provider.js +15 -7
- package/dist/grantBrowserAccess.js +789 -0
- package/dist/index.js +35 -0
- package/dist/onboard.js +7 -6
- package/dist/scheduleJob.js +268 -0
- package/package.json +8 -7
- package/src/grantBrowserAccess.ts +936 -0
- package/src/index.ts +44 -0
- package/src/onboard.ts +8 -6
- package/src/scheduleJob.ts +309 -0
|
@@ -40,44 +40,12 @@ exports.isAnyBrowserRunning = isAnyBrowserRunning;
|
|
|
40
40
|
exports.isBrowserOpenWithUrl = isBrowserOpenWithUrl;
|
|
41
41
|
exports.fetchWithPlaywright = fetchWithPlaywright;
|
|
42
42
|
const axios_1 = __importDefault(require("axios"));
|
|
43
|
-
// Utility: Promise with timeout
|
|
44
|
-
async function withTimeout(promise, ms, label, log) {
|
|
45
|
-
let timeoutId;
|
|
46
|
-
return Promise.race([
|
|
47
|
-
promise,
|
|
48
|
-
new Promise((resolve) => {
|
|
49
|
-
timeoutId = setTimeout(() => {
|
|
50
|
-
log.warn('browser-playwright: fetch timed out', { label, ms });
|
|
51
|
-
resolve(null);
|
|
52
|
-
}, ms);
|
|
53
|
-
}),
|
|
54
|
-
]).then((result) => {
|
|
55
|
-
clearTimeout(timeoutId);
|
|
56
|
-
return result;
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Playwright-based web fetching using the user's installed browser profile.
|
|
61
|
-
*
|
|
62
|
-
* Key design decisions:
|
|
63
|
-
* 1. Detects which Chromium browsers are currently RUNNING and tries those
|
|
64
|
-
* first — the active browser is where the authenticated session lives.
|
|
65
|
-
* 2. Discovers the actual profile directory dynamically (Default, Profile 1,
|
|
66
|
-
* Profile 2 …) rather than hardcoding "Default".
|
|
67
|
-
* 3. Checks multiple executable locations (system /Applications and
|
|
68
|
-
* user ~/Applications).
|
|
69
|
-
* 4. Firefox is intentionally excluded from Playwright — headless Firefox
|
|
70
|
-
* on macOS has a known RenderCompositorSWGL rendering bug that causes
|
|
71
|
-
* 30-second timeouts. Cookies from Firefox are still extracted separately
|
|
72
|
-
* by browser-cookies.ts for the plain-HTTP fallback.
|
|
73
|
-
*
|
|
74
|
-
* macOS only. Returns null on other platforms.
|
|
75
|
-
*/
|
|
76
43
|
const child_process_1 = require("child_process");
|
|
77
44
|
const fs = __importStar(require("fs"));
|
|
78
45
|
const os = __importStar(require("os"));
|
|
79
46
|
const path = __importStar(require("path"));
|
|
80
47
|
const playwright_core_1 = __importDefault(require("playwright-core"));
|
|
48
|
+
const config_1 = require("../config");
|
|
81
49
|
const home = os.homedir();
|
|
82
50
|
const BROWSER_CATALOGUE = [
|
|
83
51
|
{
|
|
@@ -137,6 +105,44 @@ const BROWSER_CATALOGUE = [
|
|
|
137
105
|
userDataDir: path.join(home, 'Library/Application Support/Chromium'),
|
|
138
106
|
},
|
|
139
107
|
];
|
|
108
|
+
const WINDOWS_BROWSER_CATALOGUE = [
|
|
109
|
+
{
|
|
110
|
+
name: 'Chrome',
|
|
111
|
+
executablePaths: [
|
|
112
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
113
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
114
|
+
path.join(home, 'AppData', 'Local', 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
115
|
+
],
|
|
116
|
+
userDataDir: path.join(home, 'AppData', 'Local', 'Google', 'Chrome', 'User Data'),
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: 'Edge',
|
|
120
|
+
executablePaths: [
|
|
121
|
+
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
122
|
+
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
123
|
+
path.join(home, 'AppData', 'Local', 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
|
|
124
|
+
],
|
|
125
|
+
userDataDir: path.join(home, 'AppData', 'Local', 'Microsoft', 'Edge', 'User Data'),
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'Brave',
|
|
129
|
+
executablePaths: [
|
|
130
|
+
'C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe',
|
|
131
|
+
path.join(home, 'AppData', 'Local', 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
|
|
132
|
+
],
|
|
133
|
+
userDataDir: path.join(home, 'AppData', 'Local', 'BraveSoftware', 'Brave-Browser', 'User Data'),
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
function resolveExistingExecutablePath(paths) {
|
|
137
|
+
for (const p of paths) {
|
|
138
|
+
try {
|
|
139
|
+
if (fs.existsSync(p))
|
|
140
|
+
return p;
|
|
141
|
+
}
|
|
142
|
+
catch { }
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
140
146
|
// ─── Running browser detection ────────────────────────────────────────────────
|
|
141
147
|
/**
|
|
142
148
|
* Returns the names of browsers that are currently running.
|
|
@@ -145,6 +151,32 @@ const BROWSER_CATALOGUE = [
|
|
|
145
151
|
*/
|
|
146
152
|
function getRunningBrowserNames() {
|
|
147
153
|
const running = new Set();
|
|
154
|
+
if (process.platform === 'win32') {
|
|
155
|
+
// tasklist /FO CSV /NH outputs one "ImageName","PID",... line per process.
|
|
156
|
+
const exeMap = {
|
|
157
|
+
'chrome.exe': 'Chrome',
|
|
158
|
+
'msedge.exe': 'Edge',
|
|
159
|
+
'brave.exe': 'Brave',
|
|
160
|
+
'opera.exe': 'Opera',
|
|
161
|
+
'vivaldi.exe': 'Vivaldi',
|
|
162
|
+
};
|
|
163
|
+
try {
|
|
164
|
+
const out = (0, child_process_1.execSync)('tasklist /FO CSV /NH 2>nul', {
|
|
165
|
+
encoding: 'utf8',
|
|
166
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
167
|
+
});
|
|
168
|
+
for (const line of out.split('\n')) {
|
|
169
|
+
const exe = line.split(',')[0]?.replace(/"/g, '').trim().toLowerCase();
|
|
170
|
+
const name = exeMap[exe];
|
|
171
|
+
if (name)
|
|
172
|
+
running.add(name);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// tasklist failed — proceed without running-browser info
|
|
177
|
+
}
|
|
178
|
+
return running;
|
|
179
|
+
}
|
|
148
180
|
try {
|
|
149
181
|
// ps -axco command lists only the process name (no path, no args)
|
|
150
182
|
const output = (0, child_process_1.execSync)('ps -axco command', {
|
|
@@ -164,13 +196,11 @@ function getRunningBrowserNames() {
|
|
|
164
196
|
};
|
|
165
197
|
for (const [processName, browserName] of Object.entries(processMap)) {
|
|
166
198
|
if (processName === 'safari') {
|
|
167
|
-
// Only match the main Safari process exactly (case-insensitive, trimmed)
|
|
168
199
|
if (lines.some((l) => l.trim() === 'safari')) {
|
|
169
200
|
running.add(browserName);
|
|
170
201
|
}
|
|
171
202
|
}
|
|
172
203
|
else {
|
|
173
|
-
// For other browsers, allow exact match or substring match
|
|
174
204
|
if (lines.some((l) => l.trim() === processName || l.includes(processName))) {
|
|
175
205
|
running.add(browserName);
|
|
176
206
|
}
|
|
@@ -194,23 +224,60 @@ async function fetchWithCDP(url, browsersWithUrl, log) {
|
|
|
194
224
|
// Collect candidate ports:
|
|
195
225
|
// 1. DevToolsActivePort file (written when Chrome was started with --remote-debugging-port)
|
|
196
226
|
// 2. Well-known default ports developers commonly use
|
|
227
|
+
// 3. On Windows: all ports browser processes are currently listening on
|
|
197
228
|
const candidatePorts = [];
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
229
|
+
if (process.platform !== 'win32') {
|
|
230
|
+
// macOS: read DevToolsActivePort from confirmed-open browsers
|
|
231
|
+
for (const candidate of BROWSER_CATALOGUE) {
|
|
232
|
+
if (!browsersWithUrl.has(candidate.name))
|
|
233
|
+
continue;
|
|
234
|
+
if (candidate.name === 'Safari')
|
|
235
|
+
continue;
|
|
236
|
+
const portFile = path.join(candidate.userDataDir, 'DevToolsActivePort');
|
|
237
|
+
if (fs.existsSync(portFile)) {
|
|
238
|
+
try {
|
|
239
|
+
const raw = fs.readFileSync(portFile, 'utf8');
|
|
240
|
+
const port = parseInt(raw.split('\n')[0].trim(), 10);
|
|
241
|
+
if (!isNaN(port) && port > 0 && !candidatePorts.includes(port)) {
|
|
242
|
+
candidatePorts.push(port);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
catch { }
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// Windows: AppleScript is unavailable so browsersWithUrl is always empty.
|
|
250
|
+
// Read DevToolsActivePort from Windows browser paths directly, and also ask
|
|
251
|
+
// PowerShell for every TCP port the browser processes are listening on —
|
|
252
|
+
// this catches any --remote-debugging-port value, not just well-known ones.
|
|
253
|
+
if (process.platform === 'win32') {
|
|
254
|
+
for (const candidate of WINDOWS_BROWSER_CATALOGUE) {
|
|
255
|
+
const portFile = path.join(candidate.userDataDir, 'DevToolsActivePort');
|
|
256
|
+
if (fs.existsSync(portFile)) {
|
|
257
|
+
try {
|
|
258
|
+
const raw = fs.readFileSync(portFile, 'utf8');
|
|
259
|
+
const port = parseInt(raw.split('\n')[0].trim(), 10);
|
|
260
|
+
if (!isNaN(port) && port > 0 && !candidatePorts.includes(port)) {
|
|
261
|
+
candidatePorts.push(port);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch { }
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Enumerate all listening ports owned by browser processes via PowerShell.
|
|
268
|
+
try {
|
|
269
|
+
const psOut = (0, child_process_1.execSync)('powershell -NoProfile -NonInteractive -Command ' +
|
|
270
|
+
'"$p=Get-Process -Name chrome,msedge,brave,opera,vivaldi -EA SilentlyContinue;' +
|
|
271
|
+
'if($p){$p|%{$id=$_.Id;Get-NetTCPConnection -OwningProcess $id -State Listen -EA SilentlyContinue}}' +
|
|
272
|
+
'|Select-Object -ExpandProperty LocalPort|Sort-Object -Unique"', { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
273
|
+
for (const line of psOut.split('\n')) {
|
|
274
|
+
const port = parseInt(line.trim(), 10);
|
|
275
|
+
if (!isNaN(port) && port > 1024 && !candidatePorts.includes(port)) {
|
|
209
276
|
candidatePorts.push(port);
|
|
210
277
|
}
|
|
211
278
|
}
|
|
212
|
-
catch { }
|
|
213
279
|
}
|
|
280
|
+
catch { }
|
|
214
281
|
}
|
|
215
282
|
// Always probe the most common debug ports — many developers run Chrome with
|
|
216
283
|
// --remote-debugging-port=9222 and these checks are cheap (instant refusal if closed).
|
|
@@ -218,11 +285,22 @@ async function fetchWithCDP(url, browsersWithUrl, log) {
|
|
|
218
285
|
if (!candidatePorts.includes(p))
|
|
219
286
|
candidatePorts.push(p);
|
|
220
287
|
}
|
|
288
|
+
// User-configured port (set via `omnikey grant-browser-access`) gets tried first.
|
|
289
|
+
if (config_1.config.browserDebugPort && !candidatePorts.includes(config_1.config.browserDebugPort)) {
|
|
290
|
+
candidatePorts.unshift(config_1.config.browserDebugPort);
|
|
291
|
+
}
|
|
292
|
+
else if (config_1.config.browserDebugPort) {
|
|
293
|
+
// Already in the list — move it to the front so it is tried before auto-detected ports.
|
|
294
|
+
candidatePorts.splice(candidatePorts.indexOf(config_1.config.browserDebugPort), 1);
|
|
295
|
+
candidatePorts.unshift(config_1.config.browserDebugPort);
|
|
296
|
+
}
|
|
221
297
|
for (const port of candidatePorts) {
|
|
222
298
|
// Quick HTTP probe: /json/version returns immediately if the debug endpoint is up.
|
|
223
299
|
let endpointUp = false;
|
|
224
300
|
try {
|
|
225
|
-
|
|
301
|
+
// Use 127.0.0.1 explicitly — on Windows, `localhost` may resolve to ::1
|
|
302
|
+
// while Chrome binds its debug endpoint to 127.0.0.1 only.
|
|
303
|
+
const probe = await axios_1.default.get(`http://127.0.0.1:${port}/json/version`, { timeout: 800 });
|
|
226
304
|
endpointUp = probe.status === 200;
|
|
227
305
|
}
|
|
228
306
|
catch {
|
|
@@ -345,12 +423,12 @@ function getBrowsersWithUrlOpen(url, log) {
|
|
|
345
423
|
return false;
|
|
346
424
|
}
|
|
347
425
|
});
|
|
348
|
-
log.
|
|
426
|
+
log.info('browser-playwright: tab check', { browser: browserName, targetHostname, found });
|
|
349
427
|
if (found)
|
|
350
428
|
confirmed.add(browserName);
|
|
351
429
|
}
|
|
352
430
|
catch {
|
|
353
|
-
log.
|
|
431
|
+
log.warn('browser-playwright: AppleScript tab check failed — skipping browser', {
|
|
354
432
|
browser: browserName,
|
|
355
433
|
});
|
|
356
434
|
}
|
|
@@ -359,12 +437,62 @@ function getBrowsersWithUrlOpen(url, log) {
|
|
|
359
437
|
}
|
|
360
438
|
/**
|
|
361
439
|
* Returns true if the given URL's hostname is confirmed open in any running
|
|
362
|
-
* browser tab
|
|
363
|
-
*
|
|
440
|
+
* browser tab. On macOS this uses AppleScript; on Windows it queries the CDP
|
|
441
|
+
* debug endpoint's /json tab list (requires --remote-debugging-port).
|
|
364
442
|
*/
|
|
365
|
-
function isBrowserOpenWithUrl(url, log) {
|
|
443
|
+
async function isBrowserOpenWithUrl(url, log) {
|
|
444
|
+
if (process.platform === 'win32') {
|
|
445
|
+
return isBrowserOpenWithUrlWindows(url, log);
|
|
446
|
+
}
|
|
366
447
|
return getBrowsersWithUrlOpen(url, log).size > 0;
|
|
367
448
|
}
|
|
449
|
+
async function isBrowserOpenWithUrlWindows(url, log) {
|
|
450
|
+
let targetHostname;
|
|
451
|
+
try {
|
|
452
|
+
targetHostname = new URL(url).hostname;
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
// If no browser processes are running at all, skip the port probes.
|
|
458
|
+
if (getRunningBrowserNames().size === 0)
|
|
459
|
+
return false;
|
|
460
|
+
const candidatePorts = [];
|
|
461
|
+
if (config_1.config.browserDebugPort)
|
|
462
|
+
candidatePorts.push(config_1.config.browserDebugPort);
|
|
463
|
+
for (const p of [9222, 9229, 9333]) {
|
|
464
|
+
if (!candidatePorts.includes(p))
|
|
465
|
+
candidatePorts.push(p);
|
|
466
|
+
}
|
|
467
|
+
for (const port of candidatePorts) {
|
|
468
|
+
try {
|
|
469
|
+
const resp = await axios_1.default.get(`http://127.0.0.1:${port}/json`, {
|
|
470
|
+
timeout: 800,
|
|
471
|
+
});
|
|
472
|
+
if (!Array.isArray(resp.data))
|
|
473
|
+
continue;
|
|
474
|
+
const found = resp.data.some((tab) => {
|
|
475
|
+
try {
|
|
476
|
+
return new URL(tab.url ?? '').hostname === targetHostname;
|
|
477
|
+
}
|
|
478
|
+
catch {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
if (found) {
|
|
483
|
+
log.info('browser-playwright: Windows CDP tab check confirmed URL open', {
|
|
484
|
+
port,
|
|
485
|
+
hostname: targetHostname,
|
|
486
|
+
});
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
catch {
|
|
491
|
+
// Port not listening — skip
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
368
496
|
// ─── Strategy 0: Live-tab AppleScript extraction ──────────────────────────────
|
|
369
497
|
//
|
|
370
498
|
// When the user already has the URL open in a browser we can pull the rendered
|
|
@@ -441,7 +569,7 @@ function findTabLocation(appName, url) {
|
|
|
441
569
|
* URL open. Returns null if the URL is not open or extraction fails.
|
|
442
570
|
*/
|
|
443
571
|
async function fetchFromRunningBrowserTab(url, browsersWithUrl, log) {
|
|
444
|
-
if (
|
|
572
|
+
if (config_1.config.terminalPlatform !== 'macos' || browsersWithUrl.size === 0)
|
|
445
573
|
return null;
|
|
446
574
|
for (const browserName of browsersWithUrl) {
|
|
447
575
|
const info = BROWSER_APPLESCRIPT[browserName];
|
|
@@ -574,40 +702,23 @@ async function fetchFromRunningBrowserTab(url, browsersWithUrl, log) {
|
|
|
574
702
|
/**
|
|
575
703
|
* Fetches a URL using the user's browser session.
|
|
576
704
|
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
* Strategies in order:
|
|
582
|
-
* 0. Live-tab extraction — reads content directly from the open tab via
|
|
583
|
-
* AppleScript JS execution. No cookie decryption required.
|
|
584
|
-
* 1. Cookie injection — decrypts cookies and injects into a fresh headless
|
|
585
|
-
* Chromium context (handles cookie-based auth when live tab unavailable).
|
|
586
|
-
* 2. Profile copy — copies Local Storage + IndexedDB to a temp dir (handles
|
|
587
|
-
* localStorage/sessionStorage token auth flows).
|
|
588
|
-
* 3. Safari Playwright — WebKit with injected Safari cookies (Safari only).
|
|
705
|
+
* Strategies:
|
|
706
|
+
* -1. CDP via --remote-debugging-port — macOS + Windows; requires Chrome to be
|
|
707
|
+
* started with --remote-debugging-port=9222.
|
|
708
|
+
* 0. Live-tab AppleScript extraction — macOS only.
|
|
589
709
|
*/
|
|
590
710
|
async function fetchWithPlaywright(url, log) {
|
|
591
|
-
// Determine which browsers have the URL open right now.
|
|
592
711
|
const browsersWithUrl = getBrowsersWithUrlOpen(url, log);
|
|
593
712
|
log.info('browser-playwright: browsers with URL open', {
|
|
594
713
|
url,
|
|
595
714
|
browsers: [...browsersWithUrl],
|
|
596
715
|
});
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if (browsersWithUrl.size > 0) {
|
|
601
|
-
const cdpResult = await fetchWithCDP(url, browsersWithUrl, log);
|
|
602
|
-
if (cdpResult) {
|
|
603
|
-
return cdpResult.content;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
// ── Strategy 0: extract from the live tab directly ────────────────────────
|
|
716
|
+
const cdpResult = await fetchWithCDP(url, browsersWithUrl, log);
|
|
717
|
+
if (cdpResult)
|
|
718
|
+
return cdpResult.content;
|
|
607
719
|
const liveContent = await fetchFromRunningBrowserTab(url, browsersWithUrl, log);
|
|
608
|
-
if (liveContent)
|
|
720
|
+
if (liveContent)
|
|
609
721
|
return liveContent;
|
|
610
|
-
}
|
|
611
|
-
log.warn('browser-playwright: all strategies exhausted', { url });
|
|
722
|
+
log.warn('browser-playwright: all strategies exhausted — on Windows, launch Chrome with --remote-debugging-port=9222', { url });
|
|
612
723
|
return null;
|
|
613
724
|
}
|
|
@@ -170,7 +170,7 @@ async function fetchPlainHttp(url, log) {
|
|
|
170
170
|
// sites use redirects, 302s, custom error pages, or soft-blocks
|
|
171
171
|
// rather than a clean 401/403, so checking status codes alone is
|
|
172
172
|
// unreliable. Fall through to the browser-session path instead.
|
|
173
|
-
if (
|
|
173
|
+
if (isSelfHostedWithBrowserSession && (await (0, browser_playwright_1.isBrowserOpenWithUrl)(url, log))) {
|
|
174
174
|
return { html: null, authBlocked: true, finalUrl: url };
|
|
175
175
|
}
|
|
176
176
|
if (status === 401 || status === 403) {
|
|
@@ -192,19 +192,19 @@ async function fetchFromActiveTab(url, log) {
|
|
|
192
192
|
log.info('web_fetch: falling back to active-tab extraction', { url });
|
|
193
193
|
return (0, browser_playwright_1.fetchWithPlaywright)(url, log);
|
|
194
194
|
}
|
|
195
|
-
const
|
|
195
|
+
const isSelfHostedWithBrowserSession = config_1.config.isSelfHosted;
|
|
196
196
|
async function executeWebFetch(url, log) {
|
|
197
197
|
log.info('Executing web_fetch tool', { url });
|
|
198
198
|
// ── Step 1: plain HTTP request ────────────────────────────────────────────
|
|
199
199
|
const { html, authBlocked, finalUrl } = await fetchPlainHttp(url, log);
|
|
200
200
|
const plainText = html ? stripHtml(html) : '';
|
|
201
|
-
if (!
|
|
201
|
+
if (!isSelfHostedWithBrowserSession) {
|
|
202
202
|
if (authBlocked) {
|
|
203
|
-
log.warn('Error: page requires authentication. Run OmniKey in self-hosted mode on macOS to enable browser-session access.');
|
|
203
|
+
log.warn('Error: page requires authentication. Run OmniKey in self-hosted mode on macOS or Windows to enable browser-session access.');
|
|
204
204
|
}
|
|
205
205
|
return plainText.slice(0, exports.MAX_TOOL_CONTENT_CHARS) || 'No content retrieved';
|
|
206
206
|
}
|
|
207
|
-
// ── Step 2 (self-hosted
|
|
207
|
+
// ── Step 2 (self-hosted desktop): LLM auth check on plain response ────────
|
|
208
208
|
let looksUnauthenticated = false;
|
|
209
209
|
if (!authBlocked && plainText) {
|
|
210
210
|
log.info('web_fetch: performing LLM auth check on plain HTTP response', { url });
|
|
@@ -214,7 +214,7 @@ async function executeWebFetch(url, log) {
|
|
|
214
214
|
}
|
|
215
215
|
looksUnauthenticated = true;
|
|
216
216
|
}
|
|
217
|
-
// ── Step 3 (self-hosted
|
|
217
|
+
// ── Step 3 (self-hosted desktop): active-tab extraction ──────────────────
|
|
218
218
|
// Only attempted when there is evidence authentication is required.
|
|
219
219
|
const needsAuth = authBlocked || looksUnauthenticated;
|
|
220
220
|
if (needsAuth) {
|
|
@@ -226,7 +226,15 @@ async function executeWebFetch(url, log) {
|
|
|
226
226
|
}
|
|
227
227
|
// All strategies exhausted.
|
|
228
228
|
if (authBlocked) {
|
|
229
|
-
|
|
229
|
+
if (config_1.config.terminalPlatform === 'macos') {
|
|
230
|
+
log.warn('Error: page requires authentication. Open the page in Chrome and ensure "Allow JavaScript from Apple Events" is enabled (View → Developer → Allow JavaScript from Apple Events).');
|
|
231
|
+
}
|
|
232
|
+
else if (config_1.config.terminalPlatform === 'windows') {
|
|
233
|
+
log.warn('Error: page requires authentication. To enable live browser-session access on Windows, ' +
|
|
234
|
+
'launch Chrome with --remote-debugging-port=9222: right-click your Chrome shortcut → Properties, ' +
|
|
235
|
+
'and append "--remote-debugging-port=9222" to the Target field, then restart Chrome. ' +
|
|
236
|
+
'OmniKey will then read the authenticated tab directly.');
|
|
237
|
+
}
|
|
230
238
|
}
|
|
231
239
|
return plainText.slice(0, exports.MAX_TOOL_CONTENT_CHARS) || 'No content retrieved';
|
|
232
240
|
}
|