libretto 0.6.8 → 0.6.9
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/commands/execution.js +13 -1
- package/dist/cli/core/browser.js +23 -4
- package/dist/cli/core/providers/browserbase.js +1 -0
- package/dist/cli/core/providers/kernel.js +1 -0
- package/dist/cli/core/providers/libretto-cloud.js +4 -1
- package/package.json +1 -1
- package/skills/libretto/SKILL.md +1 -1
- package/skills/libretto-readonly/SKILL.md +1 -1
- package/src/cli/commands/execution.ts +13 -1
- package/src/cli/core/browser.ts +23 -3
- package/src/cli/core/providers/browserbase.ts +1 -0
- package/src/cli/core/providers/kernel.ts +1 -0
- package/src/cli/core/providers/libretto-cloud.ts +11 -1
- package/src/cli/core/providers/types.ts +12 -1
|
@@ -687,6 +687,15 @@ const runCommand = SimpleCLI.command({
|
|
|
687
687
|
`Creating ${providerName} browser session (session: ${ctx.session})...`
|
|
688
688
|
);
|
|
689
689
|
const providerSession = await provider.createSession();
|
|
690
|
+
ctx.logger.info("run-provider-session-created", {
|
|
691
|
+
provider: providerName,
|
|
692
|
+
sessionId: providerSession.sessionId,
|
|
693
|
+
cdpEndpoint: providerSession.cdpEndpoint,
|
|
694
|
+
liveViewUrl: providerSession.liveViewUrl
|
|
695
|
+
});
|
|
696
|
+
if (providerSession.liveViewUrl) {
|
|
697
|
+
console.log(`View live session: ${providerSession.liveViewUrl}`);
|
|
698
|
+
}
|
|
690
699
|
console.log(`Connecting to ${providerName} browser...`);
|
|
691
700
|
cdpEndpoint = providerSession.cdpEndpoint;
|
|
692
701
|
providerInfo = {
|
|
@@ -714,7 +723,10 @@ const runCommand = SimpleCLI.command({
|
|
|
714
723
|
} finally {
|
|
715
724
|
if (provider && providerInfo) {
|
|
716
725
|
try {
|
|
717
|
-
await provider.closeSession(providerInfo.sessionId);
|
|
726
|
+
const result = await provider.closeSession(providerInfo.sessionId);
|
|
727
|
+
if (result.replayUrl) {
|
|
728
|
+
console.log(`View recording: ${result.replayUrl}`);
|
|
729
|
+
}
|
|
718
730
|
} catch (cleanupErr) {
|
|
719
731
|
console.error(
|
|
720
732
|
`Failed to clean up ${providerInfo.name} session ${providerInfo.sessionId}:`,
|
package/dist/cli/core/browser.js
CHANGED
|
@@ -431,8 +431,12 @@ async function runOpenWithProvider(rawUrl, providerName, provider, session, logg
|
|
|
431
431
|
logger.info("open-provider-session-created", {
|
|
432
432
|
provider: providerName,
|
|
433
433
|
sessionId: providerSession.sessionId,
|
|
434
|
-
cdpEndpoint: providerSession.cdpEndpoint
|
|
434
|
+
cdpEndpoint: providerSession.cdpEndpoint,
|
|
435
|
+
liveViewUrl: providerSession.liveViewUrl
|
|
435
436
|
});
|
|
437
|
+
if (providerSession.liveViewUrl) {
|
|
438
|
+
console.log(`View live session: ${providerSession.liveViewUrl}`);
|
|
439
|
+
}
|
|
436
440
|
console.log(`Connecting to ${providerName} browser...`);
|
|
437
441
|
let browser = null;
|
|
438
442
|
try {
|
|
@@ -572,6 +576,7 @@ async function runClose(session, logger) {
|
|
|
572
576
|
console.log(`No browser running for session "${session}".`);
|
|
573
577
|
return;
|
|
574
578
|
}
|
|
579
|
+
let replayUrl;
|
|
575
580
|
if (state.provider) {
|
|
576
581
|
logger.info("close-provider", {
|
|
577
582
|
session,
|
|
@@ -580,7 +585,8 @@ async function runClose(session, logger) {
|
|
|
580
585
|
});
|
|
581
586
|
try {
|
|
582
587
|
const provider = getCloudProviderApi(state.provider.name);
|
|
583
|
-
await provider.closeSession(state.provider.sessionId);
|
|
588
|
+
const result = await provider.closeSession(state.provider.sessionId);
|
|
589
|
+
replayUrl = result.replayUrl;
|
|
584
590
|
} catch (err) {
|
|
585
591
|
logger.warn("close-provider-error", {
|
|
586
592
|
session,
|
|
@@ -601,8 +607,11 @@ async function runClose(session, logger) {
|
|
|
601
607
|
}
|
|
602
608
|
}
|
|
603
609
|
clearSessionState(session, logger);
|
|
604
|
-
logger.info("close-success", { session });
|
|
610
|
+
logger.info("close-success", { session, replayUrl });
|
|
605
611
|
console.log(`Browser closed (session: ${session}).`);
|
|
612
|
+
if (replayUrl) {
|
|
613
|
+
console.log(`View recording: ${replayUrl}`);
|
|
614
|
+
}
|
|
606
615
|
}
|
|
607
616
|
function waitForCloseSignalWindow(ms) {
|
|
608
617
|
return new Promise((r) => setTimeout(r, ms));
|
|
@@ -671,6 +680,7 @@ async function runCloseAll(logger, options) {
|
|
|
671
680
|
return;
|
|
672
681
|
}
|
|
673
682
|
const failedProviderSessions = /* @__PURE__ */ new Set();
|
|
683
|
+
const replayUrls = [];
|
|
674
684
|
for (const target of closable) {
|
|
675
685
|
if (target.provider) {
|
|
676
686
|
logger.info("close-all-provider", {
|
|
@@ -680,7 +690,13 @@ async function runCloseAll(logger, options) {
|
|
|
680
690
|
});
|
|
681
691
|
try {
|
|
682
692
|
const provider = getCloudProviderApi(target.provider.name);
|
|
683
|
-
await provider.closeSession(target.provider.sessionId);
|
|
693
|
+
const result = await provider.closeSession(target.provider.sessionId);
|
|
694
|
+
if (result.replayUrl) {
|
|
695
|
+
replayUrls.push({
|
|
696
|
+
session: target.session,
|
|
697
|
+
replayUrl: result.replayUrl
|
|
698
|
+
});
|
|
699
|
+
}
|
|
684
700
|
} catch (err) {
|
|
685
701
|
logger.warn("close-all-provider-error", {
|
|
686
702
|
session: target.session,
|
|
@@ -781,6 +797,9 @@ async function runCloseAll(logger, options) {
|
|
|
781
797
|
if (forceKilled > 0) {
|
|
782
798
|
console.log(`Force-killed ${forceKilled} session(s).`);
|
|
783
799
|
}
|
|
800
|
+
for (const { session, replayUrl } of replayUrls) {
|
|
801
|
+
console.log(`View recording (${session}): ${replayUrl}`);
|
|
802
|
+
}
|
|
784
803
|
}
|
|
785
804
|
async function runConnect(cdpUrl, session, logger, accessMode = "write-access") {
|
|
786
805
|
logger.info("connect-start", { cdpUrl, session, accessMode });
|
|
@@ -34,7 +34,8 @@ function createLibrettoCloudProvider() {
|
|
|
34
34
|
const { json } = await resp.json();
|
|
35
35
|
return {
|
|
36
36
|
sessionId: json.session_id,
|
|
37
|
-
cdpEndpoint: json.cdp_url
|
|
37
|
+
cdpEndpoint: json.cdp_url,
|
|
38
|
+
liveViewUrl: json.live_view_url ?? void 0
|
|
38
39
|
};
|
|
39
40
|
},
|
|
40
41
|
async closeSession(sessionId) {
|
|
@@ -52,6 +53,8 @@ function createLibrettoCloudProvider() {
|
|
|
52
53
|
`Libretto Cloud API error closing session ${sessionId} (${resp.status}): ${body}`
|
|
53
54
|
);
|
|
54
55
|
}
|
|
56
|
+
const { json } = await resp.json();
|
|
57
|
+
return { replayUrl: json.replay_url ?? void 0 };
|
|
55
58
|
}
|
|
56
59
|
};
|
|
57
60
|
}
|
package/package.json
CHANGED
package/skills/libretto/SKILL.md
CHANGED
|
@@ -882,6 +882,15 @@ export const runCommand = SimpleCLI.command({
|
|
|
882
882
|
`Creating ${providerName} browser session (session: ${ctx.session})...`,
|
|
883
883
|
);
|
|
884
884
|
const providerSession = await provider.createSession();
|
|
885
|
+
ctx.logger.info("run-provider-session-created", {
|
|
886
|
+
provider: providerName,
|
|
887
|
+
sessionId: providerSession.sessionId,
|
|
888
|
+
cdpEndpoint: providerSession.cdpEndpoint,
|
|
889
|
+
liveViewUrl: providerSession.liveViewUrl,
|
|
890
|
+
});
|
|
891
|
+
if (providerSession.liveViewUrl) {
|
|
892
|
+
console.log(`View live session: ${providerSession.liveViewUrl}`);
|
|
893
|
+
}
|
|
885
894
|
console.log(`Connecting to ${providerName} browser...`);
|
|
886
895
|
cdpEndpoint = providerSession.cdpEndpoint;
|
|
887
896
|
providerInfo = {
|
|
@@ -910,7 +919,10 @@ export const runCommand = SimpleCLI.command({
|
|
|
910
919
|
} finally {
|
|
911
920
|
if (provider && providerInfo) {
|
|
912
921
|
try {
|
|
913
|
-
await provider.closeSession(providerInfo.sessionId);
|
|
922
|
+
const result = await provider.closeSession(providerInfo.sessionId);
|
|
923
|
+
if (result.replayUrl) {
|
|
924
|
+
console.log(`View recording: ${result.replayUrl}`);
|
|
925
|
+
}
|
|
914
926
|
} catch (cleanupErr) {
|
|
915
927
|
console.error(
|
|
916
928
|
`Failed to clean up ${providerInfo.name} session ${providerInfo.sessionId}:`,
|
package/src/cli/core/browser.ts
CHANGED
|
@@ -590,8 +590,13 @@ export async function runOpenWithProvider(
|
|
|
590
590
|
provider: providerName,
|
|
591
591
|
sessionId: providerSession.sessionId,
|
|
592
592
|
cdpEndpoint: providerSession.cdpEndpoint,
|
|
593
|
+
liveViewUrl: providerSession.liveViewUrl,
|
|
593
594
|
});
|
|
594
595
|
|
|
596
|
+
if (providerSession.liveViewUrl) {
|
|
597
|
+
console.log(`View live session: ${providerSession.liveViewUrl}`);
|
|
598
|
+
}
|
|
599
|
+
|
|
595
600
|
console.log(`Connecting to ${providerName} browser...`);
|
|
596
601
|
|
|
597
602
|
let browser: Browser | null = null;
|
|
@@ -763,6 +768,7 @@ export async function runClose(
|
|
|
763
768
|
return;
|
|
764
769
|
}
|
|
765
770
|
|
|
771
|
+
let replayUrl: string | undefined;
|
|
766
772
|
if (state.provider) {
|
|
767
773
|
// Cloud provider session — close via provider API, no local pid to kill
|
|
768
774
|
logger.info("close-provider", {
|
|
@@ -772,7 +778,8 @@ export async function runClose(
|
|
|
772
778
|
});
|
|
773
779
|
try {
|
|
774
780
|
const provider = getCloudProviderApi(state.provider.name);
|
|
775
|
-
await provider.closeSession(state.provider.sessionId);
|
|
781
|
+
const result = await provider.closeSession(state.provider.sessionId);
|
|
782
|
+
replayUrl = result.replayUrl;
|
|
776
783
|
} catch (err) {
|
|
777
784
|
logger.warn("close-provider-error", {
|
|
778
785
|
session,
|
|
@@ -797,8 +804,11 @@ export async function runClose(
|
|
|
797
804
|
}
|
|
798
805
|
|
|
799
806
|
clearSessionState(session, logger);
|
|
800
|
-
logger.info("close-success", { session });
|
|
807
|
+
logger.info("close-success", { session, replayUrl });
|
|
801
808
|
console.log(`Browser closed (session: ${session}).`);
|
|
809
|
+
if (replayUrl) {
|
|
810
|
+
console.log(`View recording: ${replayUrl}`);
|
|
811
|
+
}
|
|
802
812
|
}
|
|
803
813
|
|
|
804
814
|
type ClosableSession = {
|
|
@@ -900,6 +910,7 @@ export async function runCloseAll(
|
|
|
900
910
|
|
|
901
911
|
// Close provider sessions via their APIs
|
|
902
912
|
const failedProviderSessions = new Set<string>();
|
|
913
|
+
const replayUrls: Array<{ session: string; replayUrl: string }> = [];
|
|
903
914
|
for (const target of closable) {
|
|
904
915
|
if (target.provider) {
|
|
905
916
|
logger.info("close-all-provider", {
|
|
@@ -909,7 +920,13 @@ export async function runCloseAll(
|
|
|
909
920
|
});
|
|
910
921
|
try {
|
|
911
922
|
const provider = getCloudProviderApi(target.provider.name);
|
|
912
|
-
await provider.closeSession(target.provider.sessionId);
|
|
923
|
+
const result = await provider.closeSession(target.provider.sessionId);
|
|
924
|
+
if (result.replayUrl) {
|
|
925
|
+
replayUrls.push({
|
|
926
|
+
session: target.session,
|
|
927
|
+
replayUrl: result.replayUrl,
|
|
928
|
+
});
|
|
929
|
+
}
|
|
913
930
|
} catch (err) {
|
|
914
931
|
logger.warn("close-all-provider-error", {
|
|
915
932
|
session: target.session,
|
|
@@ -1020,6 +1037,9 @@ export async function runCloseAll(
|
|
|
1020
1037
|
if (forceKilled > 0) {
|
|
1021
1038
|
console.log(`Force-killed ${forceKilled} session(s).`);
|
|
1022
1039
|
}
|
|
1040
|
+
for (const { session, replayUrl } of replayUrls) {
|
|
1041
|
+
console.log(`View recording (${session}): ${replayUrl}`);
|
|
1042
|
+
}
|
|
1023
1043
|
}
|
|
1024
1044
|
|
|
1025
1045
|
export async function runConnect(
|
|
@@ -37,11 +37,17 @@ export function createLibrettoCloudProvider(): ProviderApi {
|
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
const { json } = (await resp.json()) as {
|
|
40
|
-
json: {
|
|
40
|
+
json: {
|
|
41
|
+
session_id: string;
|
|
42
|
+
cdp_url: string;
|
|
43
|
+
live_view_url: string | null;
|
|
44
|
+
recording_url: string | null;
|
|
45
|
+
};
|
|
41
46
|
};
|
|
42
47
|
return {
|
|
43
48
|
sessionId: json.session_id,
|
|
44
49
|
cdpEndpoint: json.cdp_url,
|
|
50
|
+
liveViewUrl: json.live_view_url ?? undefined,
|
|
45
51
|
};
|
|
46
52
|
},
|
|
47
53
|
async closeSession(sessionId) {
|
|
@@ -59,6 +65,10 @@ export function createLibrettoCloudProvider(): ProviderApi {
|
|
|
59
65
|
`Libretto Cloud API error closing session ${sessionId} (${resp.status}): ${body}`,
|
|
60
66
|
);
|
|
61
67
|
}
|
|
68
|
+
const { json } = (await resp.json()) as {
|
|
69
|
+
json: { replay_url: string | null };
|
|
70
|
+
};
|
|
71
|
+
return { replayUrl: json.replay_url ?? undefined };
|
|
62
72
|
},
|
|
63
73
|
};
|
|
64
74
|
}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
export type ProviderSession = {
|
|
2
2
|
sessionId: string; // remote session id for cleanup
|
|
3
3
|
cdpEndpoint: string; // CDP WebSocket URL
|
|
4
|
+
// Provider-hosted URL for watching the session live while it's running.
|
|
5
|
+
// Only libretto-cloud surfaces this today; direct-SDK providers leave it
|
|
6
|
+
// undefined.
|
|
7
|
+
liveViewUrl?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type ProviderCloseResult = {
|
|
11
|
+
// Provider-hosted URL for playback of the session recording, surfaced on
|
|
12
|
+
// successful close. Undefined when the provider didn't capture a
|
|
13
|
+
// recording or doesn't return one on close.
|
|
14
|
+
replayUrl?: string;
|
|
4
15
|
};
|
|
5
16
|
|
|
6
17
|
export type ProviderApi = {
|
|
7
18
|
createSession(): Promise<ProviderSession>;
|
|
8
|
-
closeSession(sessionId: string): Promise<
|
|
19
|
+
closeSession(sessionId: string): Promise<ProviderCloseResult>;
|
|
9
20
|
};
|