@oya-ai/cli 1.0.144 → 1.0.146

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 (2) hide show
  1. package/dist/index.js +71 -20
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -35,7 +35,8 @@ var SWITCHES = /* @__PURE__ */ new Set([
35
35
  "live",
36
36
  "preview",
37
37
  "replace",
38
- "version"
38
+ "version",
39
+ "yes"
39
40
  ]);
40
41
  var VALUE_FLAGS = {
41
42
  after: "--after 120",
@@ -568,12 +569,13 @@ function findRepoRoot(from = process.cwd()) {
568
569
  }
569
570
  return null;
570
571
  }
572
+ var DEFAULT_CLONE = () => join(process.cwd(), "oya-browser");
571
573
  var REPO_URL = "https://github.com/OyadotAI/oya-browser.git";
572
- async function locateRepo(dryRun = false) {
574
+ async function locateRepo(dryRun = false, yes = false) {
573
575
  const found = findRepoRoot();
574
576
  if (found) return found;
575
577
  console.log("\nThis does not look like an oya-browser checkout.");
576
- const where = await ask("Clone it to:", join(process.cwd(), "oya-browser"));
578
+ const where = yes ? DEFAULT_CLONE() : await ask("Clone it to:", DEFAULT_CLONE());
577
579
  if (dryRun) return wouldClone(where);
578
580
  if (existsSync(where)) throw new Error(`${where} already exists`);
579
581
  await run("git", ["clone", "--depth", "1", REPO_URL, where], { cwd: process.cwd() });
@@ -1304,17 +1306,56 @@ function printDone(publicUrl, apiKey) {
1304
1306
  console.log(` oya login --url ${publicUrl} --key ${apiKey}`);
1305
1307
  console.log(` oya ls && oya goto https://example.com
1306
1308
  `);
1309
+ console.log(`OYA_BASE_URL=${publicUrl}`);
1310
+ console.log(`OYA_API_KEY=${apiKey}`);
1311
+ }
1312
+
1313
+ // src/install/defaults.ts
1314
+ var NO_LLM = { provider: "skip", baseUrl: "", model: "" };
1315
+ function openaiFromEnv(env2) {
1316
+ const { base, model } = LLM_PRESETS.openai;
1317
+ const llm = { provider: "openai", baseUrl: env2.OPENAI_BASE_URL || base, model: env2.CHAT_MODEL || model };
1318
+ return { llm, secrets: { OPENAI_API_KEY: env2.OPENAI_API_KEY || "" } };
1319
+ }
1320
+ function llmFromEnv(env2) {
1321
+ if (env2.OPENAI_API_KEY) return openaiFromEnv(env2);
1322
+ if (!env2.ANTHROPIC_API_KEY) return { llm: NO_LLM, secrets: {} };
1323
+ const { base, model } = LLM_PRESETS.anthropic;
1324
+ return { llm: { provider: "anthropic", baseUrl: base, model }, secrets: { OPENAI_API_KEY: env2.ANTHROPIC_API_KEY } };
1325
+ }
1326
+ var LOCAL = {
1327
+ version: 1,
1328
+ host: "docker",
1329
+ database: "sqlite",
1330
+ fleet: "docker-workers",
1331
+ workers: 1,
1332
+ publicUrl: `http://localhost:${DEFAULT_PORT}`,
1333
+ optional: { captcha: "", recordingBucket: "", metrics: false }
1334
+ };
1335
+ function defaultInstall(env2 = process.env) {
1336
+ const { llm, secrets } = llmFromEnv(env2);
1337
+ return { answers: { ...LOCAL, optional: { ...LOCAL.optional }, llm }, secrets };
1307
1338
  }
1308
1339
 
1309
1340
  // src/install.ts
1310
1341
  var ANSWERS_FILE = "oya-install.json";
1311
- async function gather(configPath2, dryRun) {
1312
- const root = await locateRepo(dryRun);
1313
- const preset = configPath2 ? readJsonFile(configPath2) : {};
1342
+ function presetFor(m) {
1343
+ const saved = m.configPath ? readJsonFile(m.configPath) : {};
1344
+ return m.yes ? { ...defaultInstall().answers, ...saved } : saved;
1345
+ }
1346
+ function announce(root, m, replay) {
1314
1347
  banner("Oya Browser, self-host install", root);
1315
- if (configPath2) note(`replaying ${configPath2}`);
1316
- steps(configPath2 ? 0 : INTERVIEW_STEPS);
1317
- return { root, ...await interview(preset, !!configPath2) };
1348
+ if (m.configPath) note(`replaying ${m.configPath}`);
1349
+ if (m.yes) note("--yes: SQLite, Docker on this machine, no questions");
1350
+ steps(replay ? 0 : INTERVIEW_STEPS);
1351
+ }
1352
+ async function gather(m) {
1353
+ const root = await locateRepo(m.dryRun, m.yes);
1354
+ const replay = !!m.configPath || m.yes;
1355
+ announce(root, m, replay);
1356
+ const result = await interview(presetFor(m), replay);
1357
+ if (m.yes) result.secrets = { ...defaultInstall().secrets, ...result.secrets };
1358
+ return { root, ...result };
1318
1359
  }
1319
1360
  async function checkMachine(root, answers, dryRun) {
1320
1361
  const checks = await preflight(root, answers);
@@ -1329,21 +1370,28 @@ function warnLocalDatabase(answers, databaseUrl = "") {
1329
1370
  warn("DATABASE_URL points at localhost, which inside a container means the container itself.");
1330
1371
  note("Use host.docker.internal (macOS, Windows) or the host IP so the server can reach it.");
1331
1372
  }
1332
- async function guardKek(existing, answers, root, dryRun) {
1333
- if (existing.OYA_PROFILE_SECRET || answers.host !== "docker" || dryRun) return;
1373
+ function unattendedKek(volume) {
1374
+ if (process.env.OYA_PROFILE_SECRET) return process.env.OYA_PROFILE_SECRET;
1375
+ throw new Error(
1376
+ `${volume} holds encrypted data from an earlier install, and there is no .env with its OYA_PROFILE_SECRET.
1377
+ Re-run with OYA_PROFILE_SECRET=<the old secret> set, or without --yes to choose what to do.`
1378
+ );
1379
+ }
1380
+ async function guardKek(existing, answers, root, m) {
1381
+ if (existing.OYA_PROFILE_SECRET || answers.host !== "docker" || m.dryRun) return;
1334
1382
  const volume = await priorState();
1335
1383
  if (!volume) return;
1336
- const reused = await resolveKekConflict(volume, root);
1384
+ const reused = m.yes ? unattendedKek(volume) : await resolveKekConflict(volume, root);
1337
1385
  if (reused) existing.OYA_PROFILE_SECRET = reused;
1338
1386
  }
1339
- async function plan(flags, dryRun) {
1340
- const interviewed = await gather(typeof flags.config === "string" ? flags.config : null, dryRun);
1387
+ async function plan(m) {
1388
+ const interviewed = await gather(m);
1341
1389
  const { root, answers, secrets } = interviewed;
1342
- await checkMachine(root, answers, dryRun);
1390
+ await checkMachine(root, answers, m.dryRun);
1343
1391
  warnLocalDatabase(answers, secrets.DATABASE_URL);
1344
1392
  const envPath = join5(root, ".env");
1345
1393
  const existing = readEnv(envPath);
1346
- await guardKek(existing, answers, root, dryRun);
1394
+ await guardKek(existing, answers, root, m);
1347
1395
  return { ...interviewed, envPath, existing, env: buildEnv(answers, secrets, existing) };
1348
1396
  }
1349
1397
  function writeFiles(p) {
@@ -1370,10 +1418,11 @@ async function apply2(p) {
1370
1418
  printDone(p.answers.publicUrl, p.env.apiKey);
1371
1419
  }
1372
1420
  async function cmdInstall(flags) {
1373
- const dryRun = flags["dry-run"] === true;
1374
- const p = await plan(flags, dryRun);
1421
+ const configPath2 = typeof flags.config === "string" ? flags.config : null;
1422
+ const m = { configPath: configPath2, yes: flags.yes === true, dryRun: flags["dry-run"] === true };
1423
+ const p = await plan(m);
1375
1424
  printPlan(p.answers, p.envPath);
1376
- if (dryRun) return printDryRun(p.env.values);
1425
+ if (m.dryRun) return printDryRun(p.env.values);
1377
1426
  await apply2(p);
1378
1427
  }
1379
1428
 
@@ -3056,7 +3105,9 @@ var HELP = `oya, thousands of browsers, one API
3056
3105
  Usage: oya <command> [arguments] [options]
3057
3106
 
3058
3107
  Set up
3059
- oya install [--dry-run] [--config <file>] Stand up a self-hosted control plane
3108
+ oya install [--yes] [--dry-run] [--config <file>]
3109
+ Stand up a self-hosted control plane;
3110
+ --yes: SQLite + Docker here, no questions
3060
3111
  oya login [--key <key>] [--url <url>] Save an API key for this machine
3061
3112
  oya init Set your model, browser provider and sign-ins
3062
3113
  oya whoami Which control plane and key are in use, and from where
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oya-ai/cli",
3
- "version": "1.0.144",
3
+ "version": "1.0.146",
4
4
  "description": "Command line for the Oya browser control plane.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://oyabrowser.com",
@@ -50,7 +50,7 @@
50
50
  "access": "public"
51
51
  },
52
52
  "devDependencies": {
53
- "@oya-ai/browser": "1.0.144",
53
+ "@oya-ai/browser": "1.0.146",
54
54
  "@types/node": "^20.19.43",
55
55
  "tsup": "^8.0.0",
56
56
  "typescript": "^5.4.0"