libretto 0.6.24 → 0.6.26

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.
Files changed (63) hide show
  1. package/README.md +9 -1
  2. package/README.template.md +9 -1
  3. package/dist/cli/commands/browser.js +17 -10
  4. package/dist/cli/commands/cloud-credentials.js +70 -0
  5. package/dist/cli/commands/deploy.js +24 -2
  6. package/dist/cli/commands/execution.js +9 -30
  7. package/dist/cli/commands/import-chrome-profiles.js +46 -0
  8. package/dist/cli/commands/profiles.js +71 -0
  9. package/dist/cli/commands/shared.js +1 -3
  10. package/dist/cli/core/browser.js +89 -75
  11. package/dist/cli/core/daemon/daemon.js +47 -35
  12. package/dist/cli/core/daemon/ipc.js +3 -0
  13. package/dist/cli/core/deploy-artifact.js +85 -22
  14. package/dist/cli/core/profiles.js +47 -0
  15. package/dist/cli/core/prompt.js +9 -0
  16. package/dist/cli/core/providers/libretto-cloud.js +6 -2
  17. package/dist/cli/core/session-logs.js +325 -0
  18. package/dist/cli/core/telemetry.js +110 -311
  19. package/dist/cli/core/workflow-runner/runner.js +65 -0
  20. package/dist/cli/router.js +9 -1
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +12 -0
  23. package/dist/shared/workflow/auth-profile-name.d.ts +3 -0
  24. package/dist/shared/workflow/auth-profile-name.js +29 -0
  25. package/dist/shared/workflow/auth-profile-state.d.ts +20 -0
  26. package/dist/shared/workflow/auth-profile-state.js +105 -0
  27. package/dist/shared/workflow/authenticate.d.ts +17 -0
  28. package/dist/shared/workflow/authenticate.js +37 -0
  29. package/dist/shared/workflow/credentials.d.ts +5 -0
  30. package/dist/shared/workflow/credentials.js +68 -0
  31. package/dist/shared/workflow/workflow.d.ts +16 -1
  32. package/dist/shared/workflow/workflow.js +56 -4
  33. package/package.json +1 -1
  34. package/skills/libretto/SKILL.md +3 -4
  35. package/skills/libretto/references/auth-profiles.md +61 -11
  36. package/skills/libretto/references/code-generation-rules.md +31 -1
  37. package/skills/libretto-readonly/SKILL.md +1 -1
  38. package/src/cli/commands/browser.ts +19 -11
  39. package/src/cli/commands/cloud-credentials.ts +82 -0
  40. package/src/cli/commands/deploy.ts +41 -2
  41. package/src/cli/commands/execution.ts +10 -31
  42. package/src/cli/commands/import-chrome-profiles.ts +46 -0
  43. package/src/cli/commands/profiles.ts +90 -0
  44. package/src/cli/commands/shared.ts +4 -8
  45. package/src/cli/core/browser.ts +102 -91
  46. package/src/cli/core/daemon/config.ts +4 -1
  47. package/src/cli/core/daemon/daemon.ts +52 -44
  48. package/src/cli/core/daemon/ipc.ts +15 -0
  49. package/src/cli/core/deploy-artifact.ts +131 -32
  50. package/src/cli/core/profiles.ts +53 -0
  51. package/src/cli/core/prompt.ts +15 -0
  52. package/src/cli/core/providers/libretto-cloud.ts +6 -2
  53. package/src/cli/core/providers/types.ts +4 -1
  54. package/src/cli/core/session-logs.ts +445 -0
  55. package/src/cli/core/telemetry.ts +142 -413
  56. package/src/cli/core/workflow-runner/runner.ts +86 -1
  57. package/src/cli/router.ts +8 -0
  58. package/src/index.ts +10 -0
  59. package/src/shared/workflow/auth-profile-name.ts +27 -0
  60. package/src/shared/workflow/auth-profile-state.ts +144 -0
  61. package/src/shared/workflow/authenticate.ts +63 -0
  62. package/src/shared/workflow/credentials.ts +91 -0
  63. package/src/shared/workflow/workflow.ts +89 -4
@@ -5,16 +5,31 @@ import {
5
5
  type CDPSession,
6
6
  type Page,
7
7
  } from "playwright";
8
- import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
9
- import { mkdir, writeFile } from "node:fs/promises";
10
- import { dirname, join } from "node:path";
8
+ import {
9
+ existsSync,
10
+ readFileSync,
11
+ unlinkSync,
12
+ writeFileSync,
13
+ } from "node:fs";
11
14
  import { createServer } from "node:net";
15
+ import { join } from "node:path";
12
16
  import { isWindowsNamedPipePath } from "../../shared/ipc/socket-transport.js";
13
17
  import type { LoggerApi } from "../../shared/logger/index.js";
14
18
  import type { SessionAccessMode } from "../../shared/state/index.js";
15
19
  import type { Experiments } from "./experiments.js";
16
- import { getSessionProviderClosePath, PROFILES_DIR } from "./context.js";
20
+ import { getSessionProviderClosePath } from "./context.js";
17
21
  import { readLibrettoConfig } from "./config.js";
22
+ import {
23
+ captureAuthProfileStorageState,
24
+ parseAuthProfileSites,
25
+ } from "../../shared/workflow/auth-profile-state.js";
26
+ import {
27
+ formatMissingLocalAuthProfileMessage,
28
+ getProfilePath,
29
+ hasProfile,
30
+ normalizeProfileName,
31
+ writeProfile,
32
+ } from "./profiles.js";
18
33
  import {
19
34
  getCloudProviderApi,
20
35
  getProviderStartupTimeoutMs,
@@ -111,14 +126,6 @@ export function normalizeDomain(url: URL): string {
111
126
  return url.hostname.replace(/^www\./, "");
112
127
  }
113
128
 
114
- export function getProfilePath(domain: string): string {
115
- return join(PROFILES_DIR, `${domain}.json`);
116
- }
117
-
118
- export function hasProfile(domain: string): boolean {
119
- return existsSync(getProfilePath(domain));
120
- }
121
-
122
129
  async function tryConnectToCDP(
123
130
  endpoint: string,
124
131
  logger: LoggerApi,
@@ -403,7 +410,7 @@ export async function runOpen(
403
410
  options: {
404
411
  viewport?: { width: number; height: number };
405
412
  accessMode?: SessionAccessMode;
406
- authProfileDomain?: string;
413
+ authProfileName?: string;
407
414
  experiments: Experiments;
408
415
  },
409
416
  ): Promise<void> {
@@ -427,40 +434,43 @@ export async function runOpen(
427
434
 
428
435
  const browserMode = headed ? "headed" : "headless";
429
436
 
430
- // When --auth-profile is provided, use that domain for profile lookup
431
- // instead of deriving it from the URL.
432
- const authDomain = options?.authProfileDomain
433
- ? normalizeDomain(normalizeUrl(options.authProfileDomain))
437
+ // When --auth-profile is provided, use that named profile instead of
438
+ // deriving a legacy domain profile from the URL.
439
+ const authProfileName = options?.authProfileName
440
+ ? normalizeProfileName(options.authProfileName)
434
441
  : undefined;
435
- if (authDomain) {
436
- const authProfilePath = getProfilePath(authDomain);
437
- if (!existsSync(authProfilePath)) {
442
+ if (authProfileName) {
443
+ const authProfilePath = getProfilePath(authProfileName);
444
+ if (!hasProfile(authProfileName)) {
438
445
  throw new Error(
439
- `No saved auth profile for "${authDomain}". ` +
440
- `Save one first: libretto open https://${authDomain} --headed --session <name>, ` +
441
- `log in, then run: libretto save ${authDomain} --session <name>`,
446
+ formatMissingLocalAuthProfileMessage({
447
+ profileName: authProfileName,
448
+ profilePath: authProfilePath,
449
+ session,
450
+ }),
442
451
  );
443
452
  }
444
453
  }
445
454
 
446
455
  const supportsSavedProfile =
447
456
  parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
448
- const domain = authDomain ?? (supportsSavedProfile ? normalizeDomain(parsedUrl) : undefined);
449
- const profilePath = domain ? getProfilePath(domain) : undefined;
450
- const useProfile = domain ? hasProfile(domain) : false;
457
+ const profileName =
458
+ authProfileName ?? (supportsSavedProfile ? normalizeDomain(parsedUrl) : undefined);
459
+ const profilePath = profileName ? getProfilePath(profileName) : undefined;
460
+ const useProfile = profileName ? hasProfile(profileName) : false;
451
461
 
452
462
  logger.info("open-launching", {
453
463
  url,
454
464
  mode: browserMode,
455
465
  session,
456
466
  port,
457
- domain,
467
+ profileName,
458
468
  useProfile,
459
469
  profilePath: useProfile ? profilePath : undefined,
460
470
  });
461
471
 
462
472
  if (useProfile) {
463
- console.log(`Loading saved profile for ${domain}`);
473
+ console.log(`Loading saved profile ${profileName}`);
464
474
  }
465
475
  console.log(`Launching ${browserMode} browser (session: ${session})...`);
466
476
 
@@ -607,83 +617,84 @@ export async function runOpenWithProvider(
607
617
  }
608
618
 
609
619
  export async function runSave(
610
- urlOrDomain: string,
620
+ profileName: string,
611
621
  session: string,
612
622
  logger: LoggerApi,
623
+ options: { sites: string } = { sites: "" },
613
624
  ): Promise<void> {
614
- logger.info("save-start", { urlOrDomain, session });
615
- const { browser, context, page } = await connect(session, logger);
616
-
617
- try {
618
- await new Promise((r) => setTimeout(r, 500));
619
-
620
- const domain = normalizeDomain(normalizeUrl(urlOrDomain));
621
- const profilePath = getProfilePath(domain);
625
+ const normalizedProfileName = normalizeProfileName(profileName);
626
+ const sites = parseAuthProfileSites(options.sites);
627
+ if (sites.length === 0) {
628
+ throw new Error("Pass at least one site with --sites <site[,site]>.");
629
+ }
622
630
 
623
- const cdpSession = await context.newCDPSession(page);
624
- const { cookies: rawCookies } = await cdpSession.send(
625
- "Network.getAllCookies",
631
+ logger.info("save-start", { profileName: normalizedProfileName, session, sites });
632
+ const state = readSessionStateOrThrow(session);
633
+ if (!state.daemonSocketPath) {
634
+ throw new Error(
635
+ `Session "${session}" has no daemon socket. Close and reopen the session, then run libretto save again.`,
626
636
  );
637
+ }
638
+ const client = await DaemonClient.connect(state.daemonSocketPath);
627
639
 
628
- const cookies = rawCookies.map((c: any) => {
629
- const cookie = { ...c };
630
- if (cookie.partitionKey && typeof cookie.partitionKey === "object") {
631
- delete cookie.partitionKey;
632
- }
633
- return cookie;
634
- });
635
-
636
- await cdpSession.detach();
637
-
638
- const origins: Array<{
639
- origin: string;
640
- localStorage: Array<{ name: string; value: string }>;
641
- }> = [];
642
-
643
- for (const ctx of browser.contexts()) {
644
- for (const pg of ctx.pages()) {
645
- try {
646
- const origin = new URL(pg.url()).origin;
647
- const localStorage = await pg.evaluate(() => {
648
- const items: Array<{ name: string; value: string }> = [];
649
- for (let i = 0; i < window.localStorage.length; i++) {
650
- const key = window.localStorage.key(i);
651
- if (key) {
652
- items.push({
653
- name: key,
654
- value: window.localStorage.getItem(key) || "",
655
- });
656
- }
657
- }
658
- return items;
659
- });
660
- if (localStorage.length > 0) {
661
- origins.push({ origin, localStorage });
662
- }
663
- } catch {
664
- // Skip pages that can't be accessed.
665
- }
666
- }
667
- }
668
-
669
- const state = { cookies, origins };
670
- await mkdir(dirname(profilePath), { recursive: true });
671
- await writeFile(profilePath, JSON.stringify(state, null, 2));
640
+ try {
641
+ const storageState = await client.captureAuthProfileStorageState({ sites });
642
+ const profilePath = await writeProfile(normalizedProfileName, storageState);
672
643
 
673
644
  logger.info("save-success", {
674
- domain,
645
+ profileName: normalizedProfileName,
646
+ sites,
675
647
  profilePath,
676
- cookieCount: cookies.length,
677
- originCount: origins.length,
648
+ cookieCount: storageState.cookies?.length ?? 0,
649
+ originCount: storageState.origins?.length ?? 0,
678
650
  });
679
- console.log(`Profile saved for ${domain}`);
651
+ console.log(`Profile saved: ${normalizedProfileName}`);
680
652
  console.log(` Location: ${profilePath}`);
681
- console.log(` Cookies: ${cookies.length}, Origins: ${origins.length}`);
653
+ console.log(` Sites: ${sites.join(", ")}`);
654
+ console.log(
655
+ ` Cookies: ${storageState.cookies?.length ?? 0}, Origins: ${storageState.origins?.length ?? 0}`,
656
+ );
682
657
  } catch (err) {
683
- logger.error("save-error", { error: err, urlOrDomain, session });
658
+ logger.error("save-error", { error: err, profileName, session, sites });
684
659
  throw err;
685
660
  } finally {
686
- disconnectBrowser(browser, logger, session);
661
+ client.destroy();
662
+ }
663
+ }
664
+
665
+ export async function runFetchChromeProfile(
666
+ profileName: string,
667
+ cdpUrl: string,
668
+ logger: LoggerApi,
669
+ options: { sites: string },
670
+ ): Promise<void> {
671
+ const normalizedProfileName = normalizeProfileName(profileName);
672
+ const sites = parseAuthProfileSites(options.sites);
673
+ if (sites.length === 0) {
674
+ throw new Error("Pass at least one site with --sites <site[,site]>.");
675
+ }
676
+
677
+ logger.info("fetch-chrome-profile-start", {
678
+ profileName: normalizedProfileName,
679
+ cdpUrl,
680
+ sites,
681
+ });
682
+ const browser = await chromium.connectOverCDP(cdpUrl);
683
+ try {
684
+ const context = browser.contexts()[0];
685
+ if (!context) {
686
+ throw new Error("Connected Chrome instance has no browser context.");
687
+ }
688
+ const state = await captureAuthProfileStorageState(context, sites);
689
+ const profilePath = await writeProfile(normalizedProfileName, state);
690
+ console.log(`Profile fetched: ${normalizedProfileName}`);
691
+ console.log(` Location: ${profilePath}`);
692
+ console.log(` Sites: ${sites.join(", ")}`);
693
+ console.log(
694
+ ` Cookies: ${state.cookies?.length ?? 0}, Origins: ${state.origins?.length ?? 0}`,
695
+ );
696
+ } finally {
697
+ disconnectBrowser(browser, logger);
687
698
  }
688
699
  }
689
700
 
@@ -40,6 +40,8 @@ export type DaemonBrowserProviderConfig = {
40
40
  kind: "provider";
41
41
  providerName: string;
42
42
  initialUrl?: string;
43
+ authProfileName?: string;
44
+ authProfilePersist?: boolean;
43
45
  };
44
46
 
45
47
  export type DaemonWorkflowConfig = {
@@ -48,7 +50,8 @@ export type DaemonWorkflowConfig = {
48
50
  visualize?: boolean;
49
51
  stayOpenOnSuccess?: boolean;
50
52
  tsconfigPath?: string;
51
- authProfileDomain?: string;
53
+ authProfileName?: string;
54
+ authProfilePersist?: boolean;
52
55
  };
53
56
 
54
57
  export type DaemonConfig = {
@@ -55,13 +55,13 @@ import {
55
55
  type DaemonExecResult,
56
56
  type DaemonToCliApi,
57
57
  } from "./ipc.js";
58
- import { wrapPageForActionLogging } from "../telemetry.js";
58
+ import { wrapPageForActionLogging } from "../session-logs.js";
59
59
  import {
60
+ formatMissingLocalAuthProfileMessage,
60
61
  getProfilePath,
61
62
  hasProfile,
62
- normalizeDomain,
63
- normalizeUrl,
64
- } from "../browser.js";
63
+ normalizeProfileName,
64
+ } from "../profiles.js";
65
65
  import { handlePages } from "./pages.js";
66
66
  import { handleExec, handleReadonlyExec } from "./exec.js";
67
67
  import { DaemonExecRepl } from "./exec-repl.js";
@@ -90,6 +90,7 @@ import {
90
90
  } from "../workflow-runtime.js";
91
91
  import { WorkflowController } from "../workflow-runner/runner.js";
92
92
  import { validateWorkflowInput } from "../../../shared/workflow/workflow.js";
93
+ import { captureAuthProfileStorageState } from "../../../shared/workflow/auth-profile-state.js";
93
94
 
94
95
  function isOperationalPage(page: Page): boolean {
95
96
  const url = page.url();
@@ -119,34 +120,17 @@ class UserFacingStartupError extends Error {
119
120
  }
120
121
  }
121
122
 
122
- function getMissingLocalAuthProfileError(args: {
123
- normalizedDomain: string;
124
- profilePath: string;
125
- session: string;
126
- }): string {
127
- return [
128
- `Local auth profile not found for domain "${args.normalizedDomain}".`,
129
- `Expected profile file: ${args.profilePath}`,
130
- "To create it:",
131
- ` 1. libretto open https://${args.normalizedDomain} --headed --session ${args.session}`,
132
- " 2. Log in manually in the browser window.",
133
- ` 3. libretto save ${args.normalizedDomain} --session ${args.session}`,
134
- ].join("\n");
135
- }
136
-
137
123
  function resolveAuthProfileStorageStatePath(args: {
138
- authProfileDomain?: string;
124
+ authProfileName?: string;
139
125
  session: string;
140
126
  }): string | undefined {
141
- if (!args.authProfileDomain) return undefined;
142
- const normalizedDomain = normalizeDomain(
143
- normalizeUrl(args.authProfileDomain),
144
- );
145
- const profilePath = getProfilePath(normalizedDomain);
146
- if (!hasProfile(normalizedDomain)) {
127
+ if (!args.authProfileName) return undefined;
128
+ const profileName = normalizeProfileName(args.authProfileName);
129
+ const profilePath = getProfilePath(profileName);
130
+ if (!hasProfile(profileName)) {
147
131
  throw new UserFacingStartupError(
148
- getMissingLocalAuthProfileError({
149
- normalizedDomain,
132
+ formatMissingLocalAuthProfileMessage({
133
+ profileName,
150
134
  profilePath,
151
135
  session: args.session,
152
136
  }),
@@ -379,6 +363,12 @@ class BrowserDaemon {
379
363
  workflow?: DaemonWorkflowConfig;
380
364
  }): Promise<BrowserDaemon> {
381
365
  const { session, browser: config } = args;
366
+ const storageStatePath =
367
+ config.storageStatePath ??
368
+ resolveAuthProfileStorageStatePath({
369
+ authProfileName: args.workflow?.authProfileName,
370
+ session,
371
+ });
382
372
  const windowPositionArg = config.windowPosition
383
373
  ? `--window-position=${config.windowPosition.x},${config.windowPosition.y}`
384
374
  : undefined;
@@ -396,13 +386,6 @@ class BrowserDaemon {
396
386
  ],
397
387
  });
398
388
 
399
- const storageStatePath =
400
- config.storageStatePath ??
401
- resolveAuthProfileStorageStatePath({
402
- authProfileDomain: args.workflow?.authProfileDomain,
403
- session,
404
- });
405
-
406
389
  const context = await browser.newContext({
407
390
  ...(storageStatePath ? { storageState: storageStatePath } : {}),
408
391
  viewport: {
@@ -491,7 +474,10 @@ class BrowserDaemon {
491
474
  getProviderSession: () => providerSession,
492
475
  });
493
476
  try {
494
- providerSession = await provider.createSession();
477
+ providerSession = await provider.createSession({
478
+ authProfileName: config.authProfileName,
479
+ authProfilePersist: config.authProfilePersist,
480
+ });
495
481
  const browser = await chromium.connectOverCDP(
496
482
  providerSession.cdpEndpoint,
497
483
  );
@@ -665,6 +651,10 @@ class BrowserDaemon {
665
651
  this.withRequestTimeout(() => handlePages(this.pageById, this.page)),
666
652
  exec: (args) => this.runExec(args),
667
653
  readonlyExec: (args) => this.runReadonlyExec(args),
654
+ captureAuthProfileStorageState: (args) =>
655
+ this.withRequestTimeout(() =>
656
+ captureAuthProfileStorageState(this.context, args.sites),
657
+ ),
668
658
  snapshot: (args) => this.runSnapshot(args),
669
659
  getWorkflowStatus: () => this.getWorkflowStatus(),
670
660
  resumeWorkflow: () => this.resumeWorkflow(),
@@ -810,6 +800,7 @@ class BrowserDaemon {
810
800
  page: this.page,
811
801
  context: this.context,
812
802
  logger: this.logger,
803
+ refreshLocalAuthProfiles: !this.externallyManaged,
813
804
  onLog: (event) => {
814
805
  void this.broadcast("workflowOutput", event);
815
806
  },
@@ -942,12 +933,29 @@ async function main(): Promise<void> {
942
933
  config.browser.kind === "launch" ? config.browser.headed : false;
943
934
 
944
935
  let loadedWorkflow: ExportedLibrettoWorkflow | undefined;
936
+ let workflowConfig = config.workflow;
937
+ let browserConfig = config.browser;
945
938
  if (config.workflow) {
946
939
  try {
947
940
  loadedWorkflow = await loadDefaultWorkflow(
948
941
  getAbsoluteIntegrationPath(config.workflow.integrationPath),
949
942
  );
950
943
  validateWorkflowInput(loadedWorkflow, config.workflow.params ?? {});
944
+ const authProfileName = loadedWorkflow.authProfileName;
945
+ const authProfilePersist =
946
+ loadedWorkflow.authProfileRefresh === true;
947
+ workflowConfig = {
948
+ ...config.workflow,
949
+ authProfileName,
950
+ authProfilePersist,
951
+ };
952
+ if (config.browser.kind === "provider") {
953
+ browserConfig = {
954
+ ...config.browser,
955
+ authProfileName,
956
+ authProfilePersist,
957
+ };
958
+ }
951
959
  } catch (error) {
952
960
  throw new UserFacingStartupError(
953
961
  error instanceof Error ? error.message : String(error),
@@ -956,30 +964,30 @@ async function main(): Promise<void> {
956
964
  }
957
965
 
958
966
  const daemon =
959
- config.browser.kind === "provider"
967
+ browserConfig.kind === "provider"
960
968
  ? await BrowserDaemon.connectToProvider({
961
969
  session: config.session,
962
970
  experiments: config.experiments,
963
- browser: config.browser,
971
+ browser: browserConfig,
964
972
  })
965
- : config.browser.kind === "connect"
973
+ : browserConfig.kind === "connect"
966
974
  ? await BrowserDaemon.connectToEndpoint({
967
975
  session: config.session,
968
976
  experiments: config.experiments,
969
- browser: config.browser,
977
+ browser: browserConfig,
970
978
  })
971
979
  : await BrowserDaemon.launchBrowser({
972
980
  session: config.session,
973
981
  experiments: config.experiments,
974
- browser: config.browser,
975
- workflow: config.workflow,
982
+ browser: browserConfig,
983
+ workflow: workflowConfig,
976
984
  });
977
985
 
978
- if (config.workflow) {
986
+ if (workflowConfig) {
979
987
  void waitForSessionState(config.session)
980
988
  .then(() =>
981
989
  daemon.startWorkflow({
982
- workflow: config.workflow!,
990
+ workflow: workflowConfig,
983
991
  headed,
984
992
  loadedWorkflow,
985
993
  }),
@@ -10,6 +10,7 @@ import { connectToIpcSocket } from "../../../shared/ipc/socket-transport.js";
10
10
  import type { LoggerApi } from "../../../shared/logger/index.js";
11
11
  import type { SnapshotDiff } from "../../../shared/snapshot/diff-snapshots.js";
12
12
  import type { Snapshot } from "../../../shared/snapshot/types.js";
13
+ import type { AuthProfileStorageState } from "../../../shared/workflow/auth-profile-state.js";
13
14
  import { REPO_ROOT } from "../context.js";
14
15
  import type { WorkflowStatus } from "../workflow-runner/runner.js";
15
16
  import type { DaemonConfig } from "./config.js";
@@ -43,6 +44,10 @@ export type DaemonSnapshotResult = {
43
44
  snapshot: Snapshot;
44
45
  };
45
46
 
47
+ export type DaemonCaptureAuthProfileStorageStateArgs = {
48
+ sites: string[];
49
+ };
50
+
46
51
  export type DaemonCloseResult = { replayUrl?: string };
47
52
 
48
53
  export type DaemonCommandResult<T> =
@@ -56,6 +61,9 @@ export type CliToDaemonApi = {
56
61
  pages(): DaemonPageSummary[];
57
62
  exec(args: DaemonExecArgs): DaemonExecResult;
58
63
  readonlyExec(args: DaemonReadonlyExecArgs): DaemonExecResult;
64
+ captureAuthProfileStorageState(
65
+ args: DaemonCaptureAuthProfileStorageStateArgs,
66
+ ): AuthProfileStorageState;
59
67
  snapshot(args: DaemonSnapshotArgs): DaemonSnapshotResult;
60
68
  getWorkflowStatus(): WorkflowStatus;
61
69
  resumeWorkflow(): void;
@@ -207,6 +215,7 @@ export type DaemonResultMap = {
207
215
  pages: DaemonPageSummary[];
208
216
  exec: DaemonExecSuccess;
209
217
  "readonly-exec": DaemonExecSuccess;
218
+ captureAuthProfileStorageState: AuthProfileStorageState;
210
219
  snapshot: DaemonSnapshotResult;
211
220
  };
212
221
 
@@ -445,6 +454,12 @@ export class DaemonClient {
445
454
  return this.ipc.call.readonlyExec(args);
446
455
  }
447
456
 
457
+ async captureAuthProfileStorageState(
458
+ args: DaemonCaptureAuthProfileStorageStateArgs,
459
+ ): Promise<AuthProfileStorageState> {
460
+ return this.ipc.call.captureAuthProfileStorageState(args);
461
+ }
462
+
448
463
  async snapshot(
449
464
  args: DaemonSnapshotArgs = {},
450
465
  ): Promise<DaemonResultMap["snapshot"]> {