libretto 0.6.9 → 0.6.11
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/dist/cli/cli.js +2 -0
- package/dist/cli/commands/auth.js +535 -0
- package/dist/cli/commands/billing.js +74 -0
- package/dist/cli/commands/browser.js +8 -3
- package/dist/cli/commands/deploy.js +2 -7
- package/dist/cli/commands/execution.js +99 -136
- package/dist/cli/commands/snapshot.js +38 -126
- package/dist/cli/core/ai-model.js +0 -3
- package/dist/cli/core/auth-fetch.js +195 -0
- package/dist/cli/core/auth-storage.js +52 -0
- package/dist/cli/core/browser.js +128 -202
- package/dist/cli/core/daemon/config.js +6 -0
- package/dist/cli/core/daemon/daemon.js +298 -0
- package/dist/cli/core/daemon/exec.js +86 -0
- package/dist/cli/core/daemon/index.js +16 -0
- package/dist/cli/core/daemon/ipc.js +171 -0
- package/dist/cli/core/daemon/pages.js +15 -0
- package/dist/cli/core/daemon/snapshot.js +86 -0
- package/dist/cli/core/daemon/spawn.js +90 -0
- package/dist/cli/core/exec-compiler.js +111 -0
- package/dist/cli/core/prompt.js +72 -0
- package/dist/cli/core/providers/libretto-cloud.js +2 -6
- package/dist/cli/core/readonly-exec.js +1 -1
- package/dist/cli/router.js +4 -0
- package/dist/cli/workers/run-integration-runtime.js +0 -5
- package/dist/shared/state/session-state.d.ts +1 -0
- package/dist/shared/state/session-state.js +2 -1
- package/docs/browser-automation-approaches.md +435 -0
- package/docs/releasing.md +117 -0
- package/package.json +4 -3
- package/skills/libretto/SKILL.md +14 -1
- package/skills/libretto-readonly/SKILL.md +1 -1
- package/src/cli/cli.ts +2 -0
- package/src/cli/commands/auth.ts +787 -0
- package/src/cli/commands/billing.ts +133 -0
- package/src/cli/commands/browser.ts +8 -2
- package/src/cli/commands/deploy.ts +2 -7
- package/src/cli/commands/execution.ts +126 -186
- package/src/cli/commands/snapshot.ts +46 -143
- package/src/cli/core/ai-model.ts +4 -5
- package/src/cli/core/auth-fetch.ts +283 -0
- package/src/cli/core/auth-storage.ts +102 -0
- package/src/cli/core/browser.ts +159 -242
- package/src/cli/core/daemon/config.ts +46 -0
- package/src/cli/core/daemon/daemon.ts +429 -0
- package/src/cli/core/daemon/exec.ts +128 -0
- package/src/cli/core/daemon/index.ts +24 -0
- package/src/cli/core/daemon/ipc.ts +294 -0
- package/src/cli/core/daemon/pages.ts +21 -0
- package/src/cli/core/daemon/snapshot.ts +114 -0
- package/src/cli/core/daemon/spawn.ts +171 -0
- package/src/cli/core/exec-compiler.ts +169 -0
- package/src/cli/core/prompt.ts +94 -0
- package/src/cli/core/providers/libretto-cloud.ts +2 -6
- package/src/cli/core/readonly-exec.ts +2 -1
- package/src/cli/router.ts +4 -0
- package/src/cli/workers/run-integration-runtime.ts +0 -6
- package/src/shared/state/session-state.ts +1 -0
- package/dist/cli/core/browser-daemon.js +0 -122
- package/src/cli/core/browser-daemon.ts +0 -198
package/dist/cli/core/browser.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
chromium
|
|
3
3
|
} from "playwright";
|
|
4
|
-
import {
|
|
4
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
-
import { createRequire } from "node:module";
|
|
8
6
|
import { createServer } from "node:net";
|
|
9
|
-
import { spawn } from "node:child_process";
|
|
10
7
|
import { PROFILES_DIR } from "./context.js";
|
|
11
8
|
import { readLibrettoConfig } from "./config.js";
|
|
12
9
|
import {
|
|
@@ -20,6 +17,7 @@ import {
|
|
|
20
17
|
writeSessionState
|
|
21
18
|
} from "./session.js";
|
|
22
19
|
import { getCloudProviderApi } from "./providers/index.js";
|
|
20
|
+
import { DaemonClient, spawnSessionDaemon } from "./daemon/index.js";
|
|
23
21
|
const CLOSE_WAIT_MS = 1500;
|
|
24
22
|
const FORCE_CLOSE_WAIT_MS = 300;
|
|
25
23
|
async function pickFreePort() {
|
|
@@ -143,20 +141,6 @@ async function resolvePageReferences(pages) {
|
|
|
143
141
|
);
|
|
144
142
|
return refs;
|
|
145
143
|
}
|
|
146
|
-
async function listOpenPages(session, logger) {
|
|
147
|
-
const { browser, page: activePage } = await connect(session, logger);
|
|
148
|
-
try {
|
|
149
|
-
const pages = browser.contexts().flatMap((ctx) => ctx.pages()).filter(isOperationalPage);
|
|
150
|
-
const pageRefs = await resolvePageReferences(pages);
|
|
151
|
-
return pageRefs.map(({ id, page }) => ({
|
|
152
|
-
id,
|
|
153
|
-
url: page.url(),
|
|
154
|
-
active: page === activePage
|
|
155
|
-
}));
|
|
156
|
-
} finally {
|
|
157
|
-
disconnectBrowser(browser, logger, session);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
144
|
async function connect(session, logger, timeoutMs = 1e4, options) {
|
|
161
145
|
logger.info("connect", { session, timeoutMs });
|
|
162
146
|
const state = readSessionStateOrThrow(session);
|
|
@@ -242,7 +226,15 @@ async function connect(session, logger, timeoutMs = 1e4, options) {
|
|
|
242
226
|
}
|
|
243
227
|
async function runPages(session, logger) {
|
|
244
228
|
logger.info("pages-start", { session });
|
|
245
|
-
const
|
|
229
|
+
const state = readSessionStateOrThrow(session);
|
|
230
|
+
let pageSummaries;
|
|
231
|
+
if (!state.daemonSocketPath) {
|
|
232
|
+
throw new Error(
|
|
233
|
+
`Session "${session}" has no daemon socket. The browser daemon may have crashed. Close and reopen the session: libretto close --session ${session}`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
const client = new DaemonClient(state.daemonSocketPath);
|
|
237
|
+
pageSummaries = await client.pages();
|
|
246
238
|
if (pageSummaries.length === 0) {
|
|
247
239
|
console.log("No pages found.");
|
|
248
240
|
return;
|
|
@@ -302,8 +294,17 @@ async function runOpen(rawUrl, headed, session, logger, options) {
|
|
|
302
294
|
const port = await pickFreePort();
|
|
303
295
|
const runLogPath = logFileForSession(session);
|
|
304
296
|
const browserMode = headed ? "headed" : "headless";
|
|
297
|
+
const authDomain = options?.authProfileDomain ? normalizeDomain(normalizeUrl(options.authProfileDomain)) : void 0;
|
|
298
|
+
if (authDomain) {
|
|
299
|
+
const authProfilePath = getProfilePath(authDomain);
|
|
300
|
+
if (!existsSync(authProfilePath)) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`No saved auth profile for "${authDomain}". Save one first: libretto open https://${authDomain} --headed --session <name>, log in, then run: libretto save ${authDomain} --session <name>`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
305
306
|
const supportsSavedProfile = parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
|
|
306
|
-
const domain = supportsSavedProfile ? normalizeDomain(parsedUrl) : void 0;
|
|
307
|
+
const domain = authDomain ?? (supportsSavedProfile ? normalizeDomain(parsedUrl) : void 0);
|
|
307
308
|
const profilePath = domain ? getProfilePath(domain) : void 0;
|
|
308
309
|
const useProfile = domain ? hasProfile(domain) : false;
|
|
309
310
|
logger.info("open-launching", {
|
|
@@ -319,106 +320,46 @@ async function runOpen(rawUrl, headed, session, logger, options) {
|
|
|
319
320
|
console.log(`Loading saved profile for ${domain}`);
|
|
320
321
|
}
|
|
321
322
|
console.log(`Launching ${browserMode} browser (session: ${session})...`);
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
323
|
+
const { pid, socketPath: daemonSocketPath } = await spawnSessionDaemon({
|
|
324
|
+
config: {
|
|
325
|
+
port,
|
|
326
|
+
url,
|
|
327
|
+
session,
|
|
328
|
+
headed,
|
|
329
|
+
viewport,
|
|
330
|
+
storageStatePath: useProfile ? profilePath : void 0,
|
|
331
|
+
windowPosition
|
|
332
|
+
},
|
|
330
333
|
session,
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
process.execPath,
|
|
339
|
-
["--import", tsxImportPath, daemonEntryPath, JSON.stringify(daemonConfig)],
|
|
340
|
-
{
|
|
341
|
-
detached: true,
|
|
342
|
-
stdio: ["ignore", "ignore", childStderrFd]
|
|
343
|
-
}
|
|
344
|
-
);
|
|
345
|
-
child.unref();
|
|
346
|
-
closeSync(childStderrFd);
|
|
347
|
-
logger.info("open-child-spawned", { pid: child.pid, port, session });
|
|
348
|
-
let childSpawnError = null;
|
|
349
|
-
let childEarlyExit = null;
|
|
350
|
-
child.on("error", (err) => {
|
|
351
|
-
childSpawnError = err;
|
|
352
|
-
logger.error("open-child-spawn-error", { error: err, session, port });
|
|
334
|
+
logger,
|
|
335
|
+
logPath: runLogPath,
|
|
336
|
+
// The daemon launches Chromium, installs telemetry, navigates to
|
|
337
|
+
// the URL, and only then starts IPC. Navigation alone can take up
|
|
338
|
+
// to 45s (page.setDefaultNavigationTimeout), so the IPC timeout
|
|
339
|
+
// must cover launch + navigation.
|
|
340
|
+
ipcTimeoutMs: 6e4
|
|
353
341
|
});
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
logger.warn("open-child-exited", {
|
|
357
|
-
code,
|
|
358
|
-
signal,
|
|
359
|
-
session,
|
|
342
|
+
writeSessionState(
|
|
343
|
+
{
|
|
360
344
|
port,
|
|
361
|
-
pid
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
const earlyExit = childEarlyExit;
|
|
377
|
-
if (earlyExit !== null) {
|
|
378
|
-
const status = earlyExit.code ?? earlyExit.signal ?? "unknown";
|
|
379
|
-
throw new Error(
|
|
380
|
-
`Browser child process exited before startup (status: ${status}). Check logs: ${runLogPath}`
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
await new Promise((r) => setTimeout(r, cdpPollIntervalMs));
|
|
384
|
-
const ready = await fetch(`http://127.0.0.1:${port}/json/version`).then(() => true).catch(() => false);
|
|
385
|
-
if (i > 0 && i % 5 === 0) {
|
|
386
|
-
logger.info("open-waiting-for-cdp", { attempt: i, port, session });
|
|
387
|
-
}
|
|
388
|
-
if (ready) {
|
|
389
|
-
writeSessionState(
|
|
390
|
-
{
|
|
391
|
-
port,
|
|
392
|
-
pid: child.pid,
|
|
393
|
-
session,
|
|
394
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
395
|
-
status: "active",
|
|
396
|
-
mode: accessMode,
|
|
397
|
-
viewport
|
|
398
|
-
},
|
|
399
|
-
logger
|
|
400
|
-
);
|
|
401
|
-
logger.info("open-success", {
|
|
402
|
-
url,
|
|
403
|
-
mode: browserMode,
|
|
404
|
-
session,
|
|
405
|
-
port,
|
|
406
|
-
pid: child.pid
|
|
407
|
-
});
|
|
408
|
-
console.log(`Browser open (${browserMode}): ${url}`);
|
|
409
|
-
await new Promise((r) => setTimeout(r, 2e3));
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
logger.error("open-timeout", {
|
|
345
|
+
pid,
|
|
346
|
+
session,
|
|
347
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
348
|
+
status: "active",
|
|
349
|
+
mode: accessMode,
|
|
350
|
+
viewport,
|
|
351
|
+
daemonSocketPath
|
|
352
|
+
},
|
|
353
|
+
logger
|
|
354
|
+
);
|
|
355
|
+
logger.info("open-success", {
|
|
356
|
+
url,
|
|
357
|
+
mode: browserMode,
|
|
414
358
|
session,
|
|
415
359
|
port,
|
|
416
|
-
pid
|
|
417
|
-
attempts: cdpMaxAttempts
|
|
360
|
+
pid
|
|
418
361
|
});
|
|
419
|
-
|
|
420
|
-
`Failed to connect to browser after ${Math.ceil(cdpStartupTimeoutMs / 1e3)}s. Check startup logs: ${runLogPath}`
|
|
421
|
-
);
|
|
362
|
+
console.log(`Browser open (${browserMode}): ${url}`);
|
|
422
363
|
}
|
|
423
364
|
async function runOpenWithProvider(rawUrl, providerName, provider, session, logger, accessMode = "write-access") {
|
|
424
365
|
const parsedUrl = normalizeUrl(rawUrl);
|
|
@@ -438,64 +379,38 @@ async function runOpenWithProvider(rawUrl, providerName, provider, session, logg
|
|
|
438
379
|
console.log(`View live session: ${providerSession.liveViewUrl}`);
|
|
439
380
|
}
|
|
440
381
|
console.log(`Connecting to ${providerName} browser...`);
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
sessionId: providerSession.sessionId
|
|
474
|
-
}
|
|
475
|
-
},
|
|
476
|
-
logger
|
|
477
|
-
);
|
|
478
|
-
disconnectBrowser(browser, logger, session);
|
|
479
|
-
} catch (err) {
|
|
480
|
-
if (browser) {
|
|
481
|
-
disconnectBrowser(browser, logger, session);
|
|
482
|
-
}
|
|
483
|
-
logger.warn("open-provider-cleanup-after-error", {
|
|
484
|
-
provider: providerName,
|
|
485
|
-
sessionId: providerSession.sessionId,
|
|
486
|
-
error: err
|
|
487
|
-
});
|
|
488
|
-
try {
|
|
489
|
-
await provider.closeSession(providerSession.sessionId);
|
|
490
|
-
} catch (cleanupErr) {
|
|
491
|
-
logger.warn("open-provider-cleanup-failed", {
|
|
492
|
-
provider: providerName,
|
|
493
|
-
sessionId: providerSession.sessionId,
|
|
494
|
-
error: cleanupErr
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
throw err;
|
|
498
|
-
}
|
|
382
|
+
const runLogPath = logFileForSession(session);
|
|
383
|
+
const { pid, socketPath: daemonSocketPath } = await spawnSessionDaemon({
|
|
384
|
+
config: {
|
|
385
|
+
mode: "connect",
|
|
386
|
+
session,
|
|
387
|
+
cdpEndpoint: providerSession.cdpEndpoint,
|
|
388
|
+
url
|
|
389
|
+
},
|
|
390
|
+
session,
|
|
391
|
+
logger,
|
|
392
|
+
logPath: runLogPath,
|
|
393
|
+
// Remote CDP connection + navigation; must cover both.
|
|
394
|
+
ipcTimeoutMs: 6e4,
|
|
395
|
+
onFailure: () => provider.closeSession(providerSession.sessionId)
|
|
396
|
+
});
|
|
397
|
+
writeSessionState(
|
|
398
|
+
{
|
|
399
|
+
port: 0,
|
|
400
|
+
pid,
|
|
401
|
+
cdpEndpoint: providerSession.cdpEndpoint,
|
|
402
|
+
session,
|
|
403
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
404
|
+
status: "active",
|
|
405
|
+
mode: accessMode,
|
|
406
|
+
daemonSocketPath,
|
|
407
|
+
provider: {
|
|
408
|
+
name: providerName,
|
|
409
|
+
sessionId: providerSession.sessionId
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
logger
|
|
413
|
+
);
|
|
499
414
|
logger.info("open-provider-success", {
|
|
500
415
|
url,
|
|
501
416
|
provider: providerName,
|
|
@@ -576,6 +491,11 @@ async function runClose(session, logger) {
|
|
|
576
491
|
console.log(`No browser running for session "${session}".`);
|
|
577
492
|
return;
|
|
578
493
|
}
|
|
494
|
+
if (state.pid != null) {
|
|
495
|
+
logger.info("close-killing", { session, pid: state.pid, port: state.port });
|
|
496
|
+
sendSignalToProcessGroupOrPid(state.pid, "SIGTERM", logger, session);
|
|
497
|
+
await waitForCloseSignalWindow(CLOSE_WAIT_MS);
|
|
498
|
+
}
|
|
579
499
|
let replayUrl;
|
|
580
500
|
if (state.provider) {
|
|
581
501
|
logger.info("close-provider", {
|
|
@@ -599,13 +519,8 @@ async function runClose(session, logger) {
|
|
|
599
519
|
`Failed to close remote ${state.provider.name} session "${state.provider.sessionId}" for session "${session}". State preserved with status "cleanup-failed". Retry with: libretto close --session ${session}`
|
|
600
520
|
);
|
|
601
521
|
}
|
|
602
|
-
} else {
|
|
603
|
-
logger.info("close-killing", { session, pid: state.pid, port: state.port });
|
|
604
|
-
if (state.pid != null) {
|
|
605
|
-
sendSignalToProcessGroupOrPid(state.pid, "SIGTERM", logger, session);
|
|
606
|
-
await waitForCloseSignalWindow(CLOSE_WAIT_MS);
|
|
607
|
-
}
|
|
608
522
|
}
|
|
523
|
+
unlinkDaemonSocket(state.daemonSocketPath, logger, session);
|
|
609
524
|
clearSessionState(session, logger);
|
|
610
525
|
logger.info("close-success", { session, replayUrl });
|
|
611
526
|
console.log(`Browser closed (session: ${session}).`);
|
|
@@ -650,16 +565,32 @@ function resolveClosableSessions(logger) {
|
|
|
650
565
|
session,
|
|
651
566
|
pid: state.pid,
|
|
652
567
|
port: state.port,
|
|
653
|
-
provider: state.provider
|
|
568
|
+
provider: state.provider,
|
|
569
|
+
daemonSocketPath: state.daemonSocketPath
|
|
654
570
|
});
|
|
655
571
|
}
|
|
656
572
|
return { closable, clearedUnreadableStates };
|
|
657
573
|
}
|
|
574
|
+
function unlinkDaemonSocket(socketPath, logger, session) {
|
|
575
|
+
if (!socketPath) return;
|
|
576
|
+
try {
|
|
577
|
+
unlinkSync(socketPath);
|
|
578
|
+
} catch (err) {
|
|
579
|
+
if (err.code !== "ENOENT") {
|
|
580
|
+
logger.warn("close-socket-unlink-failed", {
|
|
581
|
+
session,
|
|
582
|
+
socketPath,
|
|
583
|
+
error: err
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
658
588
|
function clearStoppedSessionStates(sessions, logger, skip) {
|
|
659
589
|
let cleared = 0;
|
|
660
590
|
for (const session of sessions) {
|
|
661
591
|
if (skip?.has(session.session)) continue;
|
|
662
592
|
if (session.pid == null || !isPidRunning(session.pid)) {
|
|
593
|
+
unlinkDaemonSocket(session.daemonSocketPath, logger, session.session);
|
|
663
594
|
clearSessionState(session.session, logger);
|
|
664
595
|
cleared += 1;
|
|
665
596
|
}
|
|
@@ -713,20 +644,18 @@ async function runCloseAll(logger, options) {
|
|
|
713
644
|
}
|
|
714
645
|
}
|
|
715
646
|
for (const target of closable) {
|
|
716
|
-
if (target.
|
|
647
|
+
if (target.pid == null) continue;
|
|
717
648
|
logger.info("close-all-sigterm", {
|
|
718
649
|
session: target.session,
|
|
719
650
|
pid: target.pid,
|
|
720
651
|
port: target.port
|
|
721
652
|
});
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
);
|
|
729
|
-
}
|
|
653
|
+
sendSignalToProcessGroupOrPid(
|
|
654
|
+
target.pid,
|
|
655
|
+
"SIGTERM",
|
|
656
|
+
logger,
|
|
657
|
+
target.session
|
|
658
|
+
);
|
|
730
659
|
}
|
|
731
660
|
await waitForCloseSignalWindow(CLOSE_WAIT_MS);
|
|
732
661
|
let survivors = closable.filter(
|
|
@@ -845,36 +774,34 @@ async function runConnect(cdpUrl, session, logger, accessMode = "write-access")
|
|
|
845
774
|
endpoint
|
|
846
775
|
});
|
|
847
776
|
}
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
`CDP endpoint at ${endpoint} is reachable but Playwright could not connect. Check that the URL is a Chrome DevTools Protocol endpoint.`
|
|
852
|
-
);
|
|
853
|
-
}
|
|
854
|
-
const pages = resolveOperationalPages(browser);
|
|
855
|
-
logger.info("connect-pages", {
|
|
777
|
+
const runLogPath = logFileForSession(session);
|
|
778
|
+
const { pid, socketPath: daemonSocketPath, client } = await spawnSessionDaemon({
|
|
779
|
+
config: { mode: "connect", session, cdpEndpoint: endpoint },
|
|
856
780
|
session,
|
|
857
|
-
|
|
858
|
-
|
|
781
|
+
logger,
|
|
782
|
+
logPath: runLogPath,
|
|
783
|
+
ipcTimeoutMs: 1e4
|
|
859
784
|
});
|
|
860
|
-
disconnectBrowser(browser, logger, session);
|
|
861
785
|
writeSessionState(
|
|
862
786
|
{
|
|
863
787
|
port,
|
|
788
|
+
pid,
|
|
864
789
|
cdpEndpoint: endpoint,
|
|
865
790
|
session,
|
|
866
791
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
867
792
|
status: "active",
|
|
868
|
-
mode: accessMode
|
|
793
|
+
mode: accessMode,
|
|
794
|
+
daemonSocketPath
|
|
869
795
|
},
|
|
870
796
|
logger
|
|
871
797
|
);
|
|
798
|
+
const pages = await client.pages();
|
|
872
799
|
logger.info("connect-success", { cdpUrl: endpoint, session, port });
|
|
873
800
|
console.log(`Connected to ${endpoint} (session: ${session})`);
|
|
874
801
|
console.log(` Pages found: ${pages.length}`);
|
|
875
802
|
if (pages.length > 0) {
|
|
876
803
|
for (const p of pages.slice(0, 5)) {
|
|
877
|
-
console.log(` ${p.url
|
|
804
|
+
console.log(` ${p.url}`);
|
|
878
805
|
}
|
|
879
806
|
if (pages.length > 5) {
|
|
880
807
|
console.log(` ... and ${pages.length - 5} more`);
|
|
@@ -895,7 +822,6 @@ export {
|
|
|
895
822
|
getProfilePath,
|
|
896
823
|
getScreenshotBaseName,
|
|
897
824
|
hasProfile,
|
|
898
|
-
listOpenPages,
|
|
899
825
|
normalizeDomain,
|
|
900
826
|
normalizeUrl,
|
|
901
827
|
resolvePath,
|