libretto 0.5.6 → 0.6.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/dist/cli/commands/browser.js +31 -6
- package/dist/cli/commands/execution.js +54 -15
- package/dist/cli/commands/setup.js +78 -64
- package/dist/cli/commands/status.js +1 -1
- package/dist/cli/core/browser.js +163 -10
- package/dist/cli/core/config.js +1 -0
- package/dist/cli/core/providers/browserbase.js +53 -0
- package/dist/cli/core/providers/index.js +48 -0
- package/dist/cli/core/providers/kernel.js +46 -0
- package/dist/cli/core/providers/libretto-cloud.js +58 -0
- package/dist/cli/core/providers/types.js +0 -0
- package/dist/cli/core/session.js +9 -0
- package/dist/cli/workers/run-integration-runtime.js +3 -1
- package/dist/cli/workers/run-integration-worker-protocol.js +3 -1
- package/dist/shared/run/browser.d.ts +6 -1
- package/dist/shared/run/browser.js +39 -1
- package/dist/shared/state/session-state.d.ts +11 -1
- package/dist/shared/state/session-state.js +9 -2
- package/package.json +1 -1
- package/src/cli/commands/browser.ts +35 -7
- package/src/cli/commands/execution.ts +54 -14
- package/src/cli/commands/setup.ts +81 -64
- package/src/cli/commands/status.ts +3 -1
- package/src/cli/core/browser.ts +197 -9
- package/src/cli/core/config.ts +1 -0
- package/src/cli/core/providers/browserbase.ts +57 -0
- package/src/cli/core/providers/index.ts +62 -0
- package/src/cli/core/providers/kernel.ts +49 -0
- package/src/cli/core/providers/libretto-cloud.ts +61 -0
- package/src/cli/core/providers/types.ts +9 -0
- package/src/cli/core/session.ts +13 -0
- package/src/cli/workers/run-integration-runtime.ts +2 -0
- package/src/cli/workers/run-integration-worker-protocol.ts +2 -0
- package/src/shared/run/browser.ts +45 -0
- package/src/shared/state/session-state.ts +7 -0
|
@@ -5,9 +5,14 @@ import {
|
|
|
5
5
|
runCloseAll as runCloseAllWithLogger,
|
|
6
6
|
runConnect as runConnectWithLogger,
|
|
7
7
|
runOpen,
|
|
8
|
+
runOpenWithProvider,
|
|
8
9
|
runPages,
|
|
9
10
|
runSave
|
|
10
11
|
} from "../core/browser.js";
|
|
12
|
+
import {
|
|
13
|
+
resolveProviderName,
|
|
14
|
+
getCloudProviderApi
|
|
15
|
+
} from "../core/providers/index.js";
|
|
11
16
|
import { readLibrettoConfig } from "../core/config.js";
|
|
12
17
|
import { createLoggerForSession, withSessionLogger } from "../core/context.js";
|
|
13
18
|
import {
|
|
@@ -65,6 +70,10 @@ const openInput = SimpleCLI.input({
|
|
|
65
70
|
}),
|
|
66
71
|
viewport: SimpleCLI.option(z.string().optional(), {
|
|
67
72
|
help: "Viewport size as WIDTHxHEIGHT (e.g. 1920x1080)"
|
|
73
|
+
}),
|
|
74
|
+
provider: SimpleCLI.option(z.string().optional(), {
|
|
75
|
+
help: "Browser provider (local, kernel, browserbase)",
|
|
76
|
+
aliases: ["-p"]
|
|
68
77
|
})
|
|
69
78
|
}
|
|
70
79
|
}).refine(
|
|
@@ -82,12 +91,28 @@ const openCommand = SimpleCLI.command({
|
|
|
82
91
|
}).input(openInput).use(withAutoSession()).handle(async ({ input, ctx }) => {
|
|
83
92
|
warnIfInstalledSkillOutOfDate();
|
|
84
93
|
assertSessionAvailableForStart(ctx.session, ctx.logger);
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
viewport
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
const providerName = resolveProviderName(input.provider);
|
|
95
|
+
if (providerName === "local") {
|
|
96
|
+
const headed = input.headed || !input.headless;
|
|
97
|
+
const viewport = parseViewportArg(input.viewport);
|
|
98
|
+
await runOpen(input.url, headed, ctx.session, ctx.logger, {
|
|
99
|
+
viewport,
|
|
100
|
+
accessMode: resolveRequestedSessionMode(
|
|
101
|
+
input.readOnly,
|
|
102
|
+
input.writeAccess
|
|
103
|
+
)
|
|
104
|
+
});
|
|
105
|
+
} else {
|
|
106
|
+
const provider = getCloudProviderApi(providerName);
|
|
107
|
+
await runOpenWithProvider(
|
|
108
|
+
input.url,
|
|
109
|
+
providerName,
|
|
110
|
+
provider,
|
|
111
|
+
ctx.session,
|
|
112
|
+
ctx.logger,
|
|
113
|
+
resolveRequestedSessionMode(input.readOnly, input.writeAccess)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
91
116
|
});
|
|
92
117
|
const connectInput = SimpleCLI.input({
|
|
93
118
|
positionals: [
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
wrapPageForActionLogging
|
|
26
26
|
} from "../core/telemetry.js";
|
|
27
27
|
import { readLibrettoConfig } from "../core/config.js";
|
|
28
|
+
import { resolveProviderName, getCloudProviderApi } from "../core/providers/index.js";
|
|
28
29
|
import { createReadonlyExecHelpers } from "../core/readonly-exec.js";
|
|
29
30
|
import { SimpleCLI } from "../framework/simple-cli.js";
|
|
30
31
|
import {
|
|
@@ -462,7 +463,9 @@ async function runIntegrationFromFile(args, logger) {
|
|
|
462
463
|
visualize: args.visualize,
|
|
463
464
|
authProfileDomain: args.authProfileDomain,
|
|
464
465
|
viewport: args.viewport,
|
|
465
|
-
accessMode: args.accessMode
|
|
466
|
+
accessMode: args.accessMode,
|
|
467
|
+
cdpEndpoint: args.cdpEndpoint,
|
|
468
|
+
provider: args.provider
|
|
466
469
|
});
|
|
467
470
|
const worker = spawn(
|
|
468
471
|
process.execPath,
|
|
@@ -625,6 +628,10 @@ const runInput = SimpleCLI.input({
|
|
|
625
628
|
}),
|
|
626
629
|
viewport: SimpleCLI.option(z.string().optional(), {
|
|
627
630
|
help: "Viewport size as WIDTHxHEIGHT (e.g. 1920x1080)"
|
|
631
|
+
}),
|
|
632
|
+
provider: SimpleCLI.option(z.string().optional(), {
|
|
633
|
+
help: "Browser provider (local, kernel, browserbase)",
|
|
634
|
+
aliases: ["-p"]
|
|
628
635
|
})
|
|
629
636
|
}
|
|
630
637
|
}).refine(
|
|
@@ -670,20 +677,52 @@ const runCommand = SimpleCLI.command({
|
|
|
670
677
|
parseViewportArg(input.viewport),
|
|
671
678
|
ctx.logger
|
|
672
679
|
);
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
680
|
+
const providerName = resolveProviderName(input.provider);
|
|
681
|
+
let cdpEndpoint;
|
|
682
|
+
let providerInfo;
|
|
683
|
+
let provider;
|
|
684
|
+
if (providerName !== "local") {
|
|
685
|
+
provider = getCloudProviderApi(providerName);
|
|
686
|
+
console.log(
|
|
687
|
+
`Creating ${providerName} browser session (session: ${ctx.session})...`
|
|
688
|
+
);
|
|
689
|
+
const providerSession = await provider.createSession();
|
|
690
|
+
console.log(`Connecting to ${providerName} browser...`);
|
|
691
|
+
cdpEndpoint = providerSession.cdpEndpoint;
|
|
692
|
+
providerInfo = {
|
|
693
|
+
name: providerName,
|
|
694
|
+
sessionId: providerSession.sessionId
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
try {
|
|
698
|
+
await runIntegrationFromFile(
|
|
699
|
+
{
|
|
700
|
+
integrationPath: input.integrationFile,
|
|
701
|
+
session: ctx.session,
|
|
702
|
+
params,
|
|
703
|
+
tsconfigPath: input.tsconfig,
|
|
704
|
+
headless: cdpEndpoint ? true : headlessMode ?? false,
|
|
705
|
+
visualize,
|
|
706
|
+
authProfileDomain: input.authProfile,
|
|
707
|
+
viewport,
|
|
708
|
+
accessMode: input.readOnly ? "read-only" : input.writeAccess ? "write-access" : readLibrettoConfig().sessionMode ?? "write-access",
|
|
709
|
+
cdpEndpoint,
|
|
710
|
+
provider: providerInfo
|
|
711
|
+
},
|
|
712
|
+
ctx.logger
|
|
713
|
+
);
|
|
714
|
+
} finally {
|
|
715
|
+
if (provider && providerInfo) {
|
|
716
|
+
try {
|
|
717
|
+
await provider.closeSession(providerInfo.sessionId);
|
|
718
|
+
} catch (cleanupErr) {
|
|
719
|
+
console.error(
|
|
720
|
+
`Failed to clean up ${providerInfo.name} session ${providerInfo.sessionId}:`,
|
|
721
|
+
cleanupErr instanceof Error ? cleanupErr.message : cleanupErr
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
687
726
|
});
|
|
688
727
|
const resumeInput = SimpleCLI.input({
|
|
689
728
|
positionals: [],
|
|
@@ -60,6 +60,14 @@ function promptUser(rl, question) {
|
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
+
function providerLabel(provider) {
|
|
64
|
+
const choice = PROVIDER_CHOICES.find((c) => c.provider === provider);
|
|
65
|
+
return choice?.label ?? provider;
|
|
66
|
+
}
|
|
67
|
+
function sourceEnvVar(source) {
|
|
68
|
+
if (source.startsWith("env:")) return source.slice(4);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
63
71
|
function ensurePinnedDefaultModel(status) {
|
|
64
72
|
if (status.source !== "config") {
|
|
65
73
|
writeAiConfig(status.model);
|
|
@@ -68,17 +76,23 @@ function ensurePinnedDefaultModel(status) {
|
|
|
68
76
|
return status;
|
|
69
77
|
}
|
|
70
78
|
function printHealthySummary(status) {
|
|
71
|
-
|
|
72
|
-
|
|
79
|
+
const envVar = sourceEnvVar(status.source);
|
|
80
|
+
if (envVar) {
|
|
81
|
+
console.log(
|
|
82
|
+
`\u2713 Detected ${envVar}. Using ${providerLabel(status.provider)}.`
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
console.log(`\u2713 Using ${providerLabel(status.provider)} (${status.model}).`);
|
|
86
|
+
}
|
|
73
87
|
console.log(
|
|
74
|
-
"
|
|
88
|
+
"To change: npx libretto ai configure openai | anthropic | gemini | vertex"
|
|
75
89
|
);
|
|
76
90
|
}
|
|
77
91
|
function printInvalidAiConfigWarning(status) {
|
|
78
92
|
if (status.kind !== "invalid-config") return;
|
|
79
|
-
console.log("
|
|
93
|
+
console.log("! Existing AI config is invalid:");
|
|
80
94
|
for (const line of status.message.split("\n")) {
|
|
81
|
-
console.log(`
|
|
95
|
+
console.log(` ${line}`);
|
|
82
96
|
}
|
|
83
97
|
}
|
|
84
98
|
function buildRepairPlan(status) {
|
|
@@ -98,49 +112,47 @@ function buildRepairPlan(status) {
|
|
|
98
112
|
return { kind: "no-repair-needed" };
|
|
99
113
|
}
|
|
100
114
|
function formatMissingCredentialsMessage(plan) {
|
|
101
|
-
return
|
|
102
|
-
` \u2717 ${plan.provider} is configured (model: ${plan.model}), but ${plan.envVar} is not set.`
|
|
103
|
-
].join("\n");
|
|
115
|
+
return `\u2717 ${plan.provider} is configured (model: ${plan.model}), but ${plan.envVar} is not set.`;
|
|
104
116
|
}
|
|
105
117
|
function printSnapshotApiStatus() {
|
|
106
118
|
const status = resolveAiSetupStatus();
|
|
107
|
-
const envPath = join(REPO_ROOT, ".env");
|
|
108
|
-
console.log("\nSnapshot analysis:");
|
|
109
119
|
console.log(
|
|
110
|
-
"
|
|
120
|
+
"\nLibretto uses a sub-agent to analyze DOM snapshots. The model is determined by environment variables."
|
|
111
121
|
);
|
|
112
|
-
console.log(` Credentials are loaded from process env and ${envPath}.`);
|
|
113
122
|
if (status.kind === "ready") {
|
|
114
|
-
|
|
115
|
-
printHealthySummary(
|
|
123
|
+
console.log();
|
|
124
|
+
printHealthySummary(status);
|
|
125
|
+
ensurePinnedDefaultModel(status);
|
|
116
126
|
return true;
|
|
117
127
|
}
|
|
118
128
|
const plan = buildRepairPlan(status);
|
|
119
129
|
if (plan.kind === "repair-missing-credentials") {
|
|
130
|
+
console.log();
|
|
120
131
|
console.log(formatMissingCredentialsMessage(plan));
|
|
121
132
|
console.log(
|
|
122
|
-
`
|
|
133
|
+
` To fix: add ${plan.envVar} to .env, or run \`npx libretto setup\` interactively to repair.`
|
|
123
134
|
);
|
|
124
135
|
return false;
|
|
125
136
|
}
|
|
126
137
|
if (plan.kind === "repair-invalid-config") {
|
|
127
138
|
printInvalidAiConfigWarning(status);
|
|
128
|
-
console.log("
|
|
139
|
+
console.log(" Run `npx libretto setup` interactively to reconfigure.");
|
|
129
140
|
return false;
|
|
130
141
|
}
|
|
131
|
-
console.log(
|
|
132
|
-
console.log("
|
|
133
|
-
console.log("
|
|
134
|
-
console.log("
|
|
135
|
-
console.log("
|
|
142
|
+
console.log();
|
|
143
|
+
console.log("\u2717 No snapshot API credentials detected.");
|
|
144
|
+
console.log(" Add one provider to .env:");
|
|
145
|
+
console.log(" OPENAI_API_KEY=...");
|
|
146
|
+
console.log(" ANTHROPIC_API_KEY=...");
|
|
147
|
+
console.log(" GEMINI_API_KEY=... # or GOOGLE_GENERATIVE_AI_API_KEY");
|
|
136
148
|
console.log(
|
|
137
|
-
"
|
|
149
|
+
" GOOGLE_CLOUD_PROJECT=... # plus application default credentials for Vertex"
|
|
138
150
|
);
|
|
139
151
|
console.log(
|
|
140
|
-
"
|
|
152
|
+
" Or run `npx libretto ai configure openai | anthropic | gemini | vertex` to set a specific model."
|
|
141
153
|
);
|
|
142
154
|
console.log(
|
|
143
|
-
"
|
|
155
|
+
" Run `npx libretto setup` interactively to set up credentials."
|
|
144
156
|
);
|
|
145
157
|
return false;
|
|
146
158
|
}
|
|
@@ -157,42 +169,45 @@ function writeEnvVar(envVar, value, envPath) {
|
|
|
157
169
|
);
|
|
158
170
|
writeFileSync(envPath, updated);
|
|
159
171
|
console.log(`
|
|
160
|
-
|
|
172
|
+
\u2713 Updated ${envVar} in ${envPath}`);
|
|
161
173
|
} else {
|
|
162
174
|
const separator = envContent && !envContent.endsWith("\n") ? "\n" : "";
|
|
163
175
|
appendFileSync(envPath, `${separator}${envLine}
|
|
164
176
|
`);
|
|
165
177
|
console.log(`
|
|
166
|
-
|
|
178
|
+
\u2713 Added ${envVar} to ${envPath}`);
|
|
167
179
|
}
|
|
168
180
|
process.env[envVar] = value;
|
|
169
181
|
}
|
|
170
182
|
async function promptForCredential(rl, choice, envPath, modelOverride) {
|
|
171
183
|
console.log(`
|
|
172
|
-
|
|
173
|
-
console.log(
|
|
184
|
+
${choice.label} selected.`);
|
|
185
|
+
console.log(`${choice.envHint}
|
|
174
186
|
`);
|
|
175
|
-
const apiKeyValue = await promptUser(rl, `
|
|
187
|
+
const apiKeyValue = await promptUser(rl, `Enter your ${choice.envVar}: `);
|
|
176
188
|
if (!apiKeyValue) {
|
|
177
|
-
console.log("\
|
|
189
|
+
console.log("\nNo value entered. Skipping API key setup.");
|
|
178
190
|
return false;
|
|
179
191
|
}
|
|
180
192
|
writeEnvVar(choice.envVar, apiKeyValue, envPath);
|
|
181
193
|
loadSnapshotEnv();
|
|
182
194
|
const model = modelOverride ?? DEFAULT_SNAPSHOT_MODELS[choice.provider];
|
|
183
195
|
writeAiConfig(model);
|
|
184
|
-
console.log(
|
|
196
|
+
console.log(`\u2713 Snapshot API ready: ${model}`);
|
|
197
|
+
console.log(
|
|
198
|
+
"To change: npx libretto ai configure openai | anthropic | gemini | vertex"
|
|
199
|
+
);
|
|
185
200
|
return true;
|
|
186
201
|
}
|
|
187
202
|
async function promptProviderSelection(rl, envPath) {
|
|
188
203
|
console.log(
|
|
189
|
-
"
|
|
204
|
+
"Which model provider would you like to use for snapshot analysis?\n"
|
|
190
205
|
);
|
|
191
206
|
for (const choice of PROVIDER_CHOICES) {
|
|
192
|
-
console.log(`
|
|
207
|
+
console.log(` ${choice.key}) ${choice.label}`);
|
|
193
208
|
}
|
|
194
|
-
console.log("
|
|
195
|
-
const answer = await promptUser(rl, "
|
|
209
|
+
console.log(" s) Skip for now\n");
|
|
210
|
+
const answer = await promptUser(rl, "Choice: ");
|
|
196
211
|
if (answer.toLowerCase() === "s" || !answer) {
|
|
197
212
|
printSkipMessage();
|
|
198
213
|
return false;
|
|
@@ -200,32 +215,33 @@ async function promptProviderSelection(rl, envPath) {
|
|
|
200
215
|
const selected = PROVIDER_CHOICES.find((choice) => choice.key === answer);
|
|
201
216
|
if (!selected) {
|
|
202
217
|
console.log(`
|
|
203
|
-
|
|
218
|
+
Unknown choice "${answer}". Skipping API setup.`);
|
|
204
219
|
return false;
|
|
205
220
|
}
|
|
206
221
|
return promptForCredential(rl, selected, envPath);
|
|
207
222
|
}
|
|
208
223
|
function printSkipMessage() {
|
|
209
224
|
console.log(
|
|
210
|
-
"\
|
|
225
|
+
"\nSkipped. You can set up API credentials later by rerunning `npx libretto setup`."
|
|
211
226
|
);
|
|
212
|
-
console.log("
|
|
213
|
-
console.log("
|
|
214
|
-
console.log("
|
|
215
|
-
console.log("
|
|
227
|
+
console.log("Or add credentials directly to your .env file:");
|
|
228
|
+
console.log(" OPENAI_API_KEY=...");
|
|
229
|
+
console.log(" ANTHROPIC_API_KEY=...");
|
|
230
|
+
console.log(" GEMINI_API_KEY=...");
|
|
216
231
|
console.log(
|
|
217
|
-
"
|
|
232
|
+
" Or run `npx libretto ai configure openai | anthropic | gemini | vertex` to set a specific model."
|
|
218
233
|
);
|
|
219
234
|
}
|
|
220
235
|
async function runInteractiveApiSetup() {
|
|
221
236
|
const status = resolveAiSetupStatus();
|
|
222
237
|
const envPath = join(REPO_ROOT, ".env");
|
|
223
|
-
console.log(
|
|
224
|
-
|
|
225
|
-
|
|
238
|
+
console.log(
|
|
239
|
+
"\nLibretto uses a sub-agent to analyze DOM snapshots. The model is determined by environment variables."
|
|
240
|
+
);
|
|
226
241
|
if (status.kind === "ready") {
|
|
227
|
-
|
|
228
|
-
printHealthySummary(
|
|
242
|
+
console.log();
|
|
243
|
+
printHealthySummary(status);
|
|
244
|
+
ensurePinnedDefaultModel(status);
|
|
229
245
|
return;
|
|
230
246
|
}
|
|
231
247
|
const plan = buildRepairPlan(status);
|
|
@@ -237,11 +253,11 @@ async function runInteractiveApiSetup() {
|
|
|
237
253
|
if (plan.kind === "repair-missing-credentials") {
|
|
238
254
|
console.log(formatMissingCredentialsMessage(plan));
|
|
239
255
|
console.log("");
|
|
240
|
-
console.log("
|
|
241
|
-
console.log(`
|
|
242
|
-
console.log("
|
|
243
|
-
console.log("
|
|
244
|
-
const answer = await promptUser(rl, "
|
|
256
|
+
console.log("How would you like to fix this?\n");
|
|
257
|
+
console.log(` 1) Enter ${plan.envVar}`);
|
|
258
|
+
console.log(" 2) Switch to a different provider");
|
|
259
|
+
console.log(" s) Skip for now\n");
|
|
260
|
+
const answer = await promptUser(rl, "Choice: ");
|
|
245
261
|
if (answer === "1") {
|
|
246
262
|
const matchingChoice = PROVIDER_CHOICES.find(
|
|
247
263
|
(c) => c.provider === plan.provider
|
|
@@ -261,28 +277,28 @@ async function runInteractiveApiSetup() {
|
|
|
261
277
|
if (plan.kind === "repair-invalid-config") {
|
|
262
278
|
printInvalidAiConfigWarning(status);
|
|
263
279
|
console.log(
|
|
264
|
-
"\
|
|
280
|
+
"\nWould you like to reconfigure with a fresh provider selection?\n"
|
|
265
281
|
);
|
|
266
282
|
await promptProviderSelection(rl, envPath);
|
|
267
283
|
return;
|
|
268
284
|
}
|
|
269
|
-
console.log("
|
|
285
|
+
console.log("\u2717 No snapshot API credentials detected.\n");
|
|
270
286
|
await promptProviderSelection(rl, envPath);
|
|
271
287
|
} finally {
|
|
272
288
|
rl.close();
|
|
273
289
|
}
|
|
274
290
|
}
|
|
275
291
|
function installBrowsers() {
|
|
276
|
-
console.log("
|
|
292
|
+
console.log("Installing Playwright Chromium...");
|
|
277
293
|
const result = spawnSync("npx", ["playwright", "install", "chromium"], {
|
|
278
294
|
stdio: "inherit",
|
|
279
295
|
shell: true
|
|
280
296
|
});
|
|
281
297
|
if (result.status === 0) {
|
|
282
|
-
console.log("
|
|
298
|
+
console.log("\u2713 Playwright Chromium installed");
|
|
283
299
|
} else {
|
|
284
300
|
console.error(
|
|
285
|
-
"
|
|
301
|
+
"\u2717 Failed to install Playwright Chromium. Run manually: npx playwright install chromium"
|
|
286
302
|
);
|
|
287
303
|
}
|
|
288
304
|
}
|
|
@@ -306,16 +322,13 @@ function detectAgentDirs(root) {
|
|
|
306
322
|
function copySkills() {
|
|
307
323
|
const agentDirs = detectAgentDirs(REPO_ROOT);
|
|
308
324
|
if (agentDirs.length === 0) {
|
|
309
|
-
console.log(
|
|
310
|
-
"\nSkills: No .agents/ or .claude/ directory found in repo root \u2014 skipping."
|
|
311
|
-
);
|
|
312
325
|
return;
|
|
313
326
|
}
|
|
314
327
|
let skillsRoot;
|
|
315
328
|
try {
|
|
316
329
|
skillsRoot = getPackageSkillsRoot();
|
|
317
330
|
} catch (e) {
|
|
318
|
-
console.error(
|
|
331
|
+
console.error(`\u2717 ${e instanceof Error ? e.message : String(e)}`);
|
|
319
332
|
return;
|
|
320
333
|
}
|
|
321
334
|
const skillNames = readdirSync(skillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
@@ -330,7 +343,7 @@ function copySkills() {
|
|
|
330
343
|
cpSync(sourceDir, skillDest, { recursive: true });
|
|
331
344
|
const fileCount = readdirSync(skillDest).length;
|
|
332
345
|
console.log(
|
|
333
|
-
|
|
346
|
+
`\u2713 Copied ${fileCount} skill files to ${agentName}/skills/${skillName}/`
|
|
334
347
|
);
|
|
335
348
|
}
|
|
336
349
|
}
|
|
@@ -347,12 +360,11 @@ const setupInput = SimpleCLI.input({
|
|
|
347
360
|
const setupCommand = SimpleCLI.command({
|
|
348
361
|
description: "Set up libretto in the current project"
|
|
349
362
|
}).input(setupInput).handle(async ({ input }) => {
|
|
350
|
-
console.log("Setting up libretto...\n");
|
|
351
363
|
ensureLibrettoSetup();
|
|
352
364
|
if (!input.skipBrowsers) {
|
|
353
365
|
installBrowsers();
|
|
354
366
|
} else {
|
|
355
|
-
console.log("
|
|
367
|
+
console.log("Skipping browser installation (--skip-browsers)");
|
|
356
368
|
}
|
|
357
369
|
copySkills();
|
|
358
370
|
if (process.stdin.isTTY) {
|
|
@@ -365,6 +377,8 @@ const setupCommand = SimpleCLI.command({
|
|
|
365
377
|
);
|
|
366
378
|
}
|
|
367
379
|
}
|
|
380
|
+
console.log(`
|
|
381
|
+
Config set up at ${LIBRETTO_CONFIG_PATH}`);
|
|
368
382
|
console.log("\n\u2713 libretto setup complete");
|
|
369
383
|
});
|
|
370
384
|
export {
|
|
@@ -45,7 +45,7 @@ function printOpenSessions(sessions) {
|
|
|
45
45
|
}
|
|
46
46
|
for (const session of sessions) {
|
|
47
47
|
const statusLabel = session.status ? ` [${session.status}]` : "";
|
|
48
|
-
const endpoint = `http://127.0.0.1:${session.port}`;
|
|
48
|
+
const endpoint = session.provider ? `${session.provider.name} (${session.cdpEndpoint})` : `http://127.0.0.1:${session.port}`;
|
|
49
49
|
console.log(` ${session.session}${statusLabel} \u2014 ${endpoint}`);
|
|
50
50
|
}
|
|
51
51
|
}
|