@oya-ai/cli 1.0.130 → 1.0.133

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 +70 -13
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1931,9 +1931,8 @@ var Browser = class {
1931
1931
  /**
1932
1932
  * Replay a playbook with no LLM in the loop. Variables left out reuse the
1933
1933
  * recorded values where there are any. If a step no longer fits the page and
1934
- * `autoHeal` is on (the default), the agent finishes the task and its fix is
1935
- * saved as a draft (`healed`, `draft`); off, the step's error is thrown.
1936
- * Play `'<name>:draft'` to try a draft before promoting it.
1934
+ * `autoHeal` is on (the default), the agent finishes the task and its fix
1935
+ * replaces the broken steps in the playbook (`healed`); off, the step's error is thrown.
1937
1936
  */
1938
1937
  async play(name, data = {}, { autoHeal = true } = {}) {
1939
1938
  const path = `/api/browsers/${this.id}/playbooks/${segment(name, "name")}/play`;
@@ -2153,7 +2152,24 @@ var playbookApi = (http) => ({
2153
2152
  await http().request("DELETE", playbook(name));
2154
2153
  },
2155
2154
  /** Replace a playbook with the draft a healed replay saved. Try it first with `browser.play('<name>:draft')`. */
2156
- promote: async (name) => http().request("POST", `${playbook(name)}/promote`, {})
2155
+ promote: async (name) => http().request("POST", `${playbook(name)}/promote`, {}),
2156
+ ...transferApi(http)
2157
+ });
2158
+ var transferApi = (http) => ({
2159
+ /** The playbook as one JSON document, to move it to another environment with `import()`. Secrets travel by name only. */
2160
+ export: async (name) => http().request("GET", `${playbook(name)}/export`),
2161
+ /**
2162
+ * Save an exported playbook here, as `name` or the name it was exported with. A name
2163
+ * already taken is refused unless `overwrite` is true.
2164
+ */
2165
+ import: async (doc, options = {}) => http().request("POST", "/api/playbooks/import", { playbook: doc, ...options })
2166
+ });
2167
+ var llmApi = (http) => ({
2168
+ /**
2169
+ * The text for one free-text field, written by this key's model: what an exported
2170
+ * playbook calls as `oya.llm.answer(question, vars)` for a comment or a question's answer.
2171
+ */
2172
+ answer: async (question, values = {}, task) => (await http().request("POST", "/api/playbooks/answer", { question, values, task })).answer
2157
2173
  });
2158
2174
  var proxyApi = (http) => ({
2159
2175
  /** Every proxy this key can use, shared ones included. */
@@ -2226,7 +2242,7 @@ var jarCalls = (http) => ({
2226
2242
  /** Every cookie in the jar; `format: 'playwright'` is ready for `context.addCookies()`. */
2227
2243
  cookies: async (id, format = "json") => (await http().request("GET", `${jarPath(id)}&format=${encodeURIComponent(format)}`)).cookies,
2228
2244
  /** Merge cookies into the jar. The persona's browsers pick them up on their next visit to each site. */
2229
- importCookies: async (id, list2) => http().request("PUT", jarPath(id), { cookies: list2 })
2245
+ importCookies: async (id, list3) => http().request("PUT", jarPath(id), { cookies: list3 })
2230
2246
  });
2231
2247
  var cookieCalls = (http) => ({
2232
2248
  ...jarCalls(http),
@@ -2319,10 +2335,10 @@ function openLink(link) {
2319
2335
  });
2320
2336
  child.unref();
2321
2337
  }
2322
- async function waitForDesktop(list2, link, timeoutMs, persona) {
2338
+ async function waitForDesktop(list3, link, timeoutMs, persona) {
2323
2339
  const deadline = Date.now() + timeoutMs;
2324
2340
  while (Date.now() < deadline) {
2325
- const found = desktopOf(await list2(), persona);
2341
+ const found = desktopOf(await list3(), persona);
2326
2342
  if (found) return found;
2327
2343
  await new Promise((r) => setTimeout(r, READY_POLL_MS2));
2328
2344
  }
@@ -2334,7 +2350,7 @@ async function handleOn(http, id) {
2334
2350
  const started = { id, provider: DESKTOP_PROVIDER, persona: found.persona || "default", cdpUrl: found.cdpUrl };
2335
2351
  return new Browser(http, { ...started, status: "ready", reused: true }, false);
2336
2352
  }
2337
- var desktopApi = (http, list2) => ({
2353
+ var desktopApi = (http, list3) => ({
2338
2354
  /**
2339
2355
  * The person's own desktop browser, signed in to their sites. When it is not
2340
2356
  * connected yet this pairs it: it opens a link, the person clicks Connect in
@@ -2343,11 +2359,11 @@ var desktopApi = (http, list2) => ({
2343
2359
  * another persona is switched the same way: the link reconnects it as this one.
2344
2360
  */
2345
2361
  connect: async (options = {}) => {
2346
- const running = desktopOf(await list2(), options.persona);
2362
+ const running = desktopOf(await list3(), options.persona);
2347
2363
  if (running) return handleOn(http(), running.id);
2348
2364
  const link = await pairingLink(http(), options.persona);
2349
2365
  if (options.open !== false) openLink(link);
2350
- const found = await waitForDesktop(list2, link, options.timeoutMs ?? DESKTOP_TIMEOUT_MS, options.persona);
2366
+ const found = await waitForDesktop(list3, link, options.timeoutMs ?? DESKTOP_TIMEOUT_MS, options.persona);
2351
2367
  return handleOn(http(), found.id);
2352
2368
  }
2353
2369
  });
@@ -2380,6 +2396,8 @@ var Oya = class {
2380
2396
  control = controlApi(() => this.http);
2381
2397
  /** Playbooks saved with `browser.toPlaybook()`. */
2382
2398
  playbooks = playbookApi(() => this.http);
2399
+ /** This key's model for one-off text: `oya.llm.answer(question, vars)` fills a playbook's free-text field. */
2400
+ llm = llmApi(() => this.http);
2383
2401
  /**
2384
2402
  * Proxy exits for your personas. A persona takes one at first connect (by its
2385
2403
  * geo hint) or by `personas.pinProxy`, and keeps it.
@@ -2841,9 +2859,9 @@ var exportJar = async (oya, rest, flags) => {
2841
2859
  };
2842
2860
  function cookiesIn(file) {
2843
2861
  const parsed = readJsonFile(file);
2844
- const list2 = Array.isArray(parsed) ? parsed : parsed?.cookies;
2845
- if (!Array.isArray(list2)) throw usage(`${file} holds no list of cookies.`);
2846
- return list2;
2862
+ const list3 = Array.isArray(parsed) ? parsed : parsed?.cookies;
2863
+ if (!Array.isArray(list3)) throw usage(`${file} holds no list of cookies.`);
2864
+ return list3;
2847
2865
  }
2848
2866
  var importJar = async (oya, rest, flags) => {
2849
2867
  if (!rest[0] || !rest[1])
@@ -2873,6 +2891,39 @@ async function cmdCookies(args, flags) {
2873
2891
  await SUBCOMMANDS2[sub](client(flags), rest, flags);
2874
2892
  }
2875
2893
 
2894
+ // src/commands/playbooks.ts
2895
+ import { writeFileSync as writeFileSync6 } from "fs";
2896
+ var list2 = async (oya, _rest, flags) => {
2897
+ const playbooks = await oya.playbooks.list();
2898
+ out(flags, playbooks, () => {
2899
+ if (!playbooks.length) return console.log("No playbooks yet: save a run with browser.toPlaybook().");
2900
+ for (const p of playbooks) console.log(`${p.name} ${p.steps} steps ${p.variables.join(", ") || "(no inputs)"}`);
2901
+ });
2902
+ };
2903
+ var exportOne = async (oya, rest, flags) => {
2904
+ if (!rest[0]) throw usage("oya playbooks export needs a name: oya playbooks export <name> [--out <file>].");
2905
+ const doc = await oya.playbooks.export(rest[0]);
2906
+ const file = flagStr(flags, "out");
2907
+ if (!file) return console.log(JSON.stringify(doc, null, JSON_INDENT2));
2908
+ writeFileSync6(file, JSON.stringify(doc, null, JSON_INDENT2) + "\n");
2909
+ out(flags, { ok: true, name: rest[0], file }, () => console.log(`\u2705 ${rest[0]} written to ${file}`));
2910
+ };
2911
+ var importOne = async (oya, rest, flags) => {
2912
+ if (!rest[0])
2913
+ throw usage("oya playbooks import needs a file: oya playbooks import <file> [--name <name>] [--replace].");
2914
+ const doc = readJsonFile(rest[0]);
2915
+ const name = flagStr(flags, "name") || void 0;
2916
+ const saved = await oya.playbooks.import(doc, { name, overwrite: flags.replace === true });
2917
+ out(flags, saved, () => console.log(`\u2705 imported ${saved.name}: ${saved.steps} steps`));
2918
+ };
2919
+ var SUBCOMMANDS3 = { list: list2, export: exportOne, import: importOne };
2920
+ async function cmdPlaybooks(args, flags) {
2921
+ const [sub = "list", ...rest] = args;
2922
+ if (!Object.hasOwn(SUBCOMMANDS3, sub))
2923
+ throw usage(`Unknown playbooks subcommand "${sub}". Use list, export or import.`);
2924
+ await SUBCOMMANDS3[sub](client(flags), rest, flags);
2925
+ }
2926
+
2876
2927
  // src/commands/settings.ts
2877
2928
  function parsePairs(args) {
2878
2929
  const updates = {};
@@ -3034,6 +3085,11 @@ Personas and cookies
3034
3085
  oya cookies copy <from> <to> One persona's logins into another
3035
3086
  oya cookies clear <persona> Delete a persona's logins
3036
3087
 
3088
+ Playbooks
3089
+ oya playbooks List saved playbooks
3090
+ oya playbooks export <name> One playbook as JSON; [--out <file>]
3091
+ oya playbooks import <file> Save an export here; [--name <name>] [--replace]
3092
+
3037
3093
  Account
3038
3094
  oya config [key=value ...] Show or change this key's settings
3039
3095
  oya usage What this key has spent
@@ -3105,6 +3161,7 @@ var COMMANDS = {
3105
3161
  stop: cmdRm,
3106
3162
  personas: cmdPersonas,
3107
3163
  cookies: cmdCookies,
3164
+ playbooks: cmdPlaybooks,
3108
3165
  open: (_args, flags) => cmdOpen(flags),
3109
3166
  config: cmdConfig,
3110
3167
  usage: (_args, flags) => cmdUsage(flags),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oya-ai/cli",
3
- "version": "1.0.130",
3
+ "version": "1.0.133",
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.130",
53
+ "@oya-ai/browser": "1.0.133",
54
54
  "@types/node": "^20.19.43",
55
55
  "tsup": "^8.0.0",
56
56
  "typescript": "^5.4.0"