@vosjs/cli 0.83.2 → 0.84.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/README.md +7 -1
- package/dist/{chunk-HDJFCTOG.js → chunk-DM7ADA77.js} +245 -49
- package/dist/chunk-DM7ADA77.js.map +1 -0
- package/dist/cli.js +3 -3
- package/dist/index.js +1 -1
- package/dist/{run-7ZKIV6EU.js → run-J5Z32LEB.js} +2 -2
- package/package.json +5 -5
- package/dist/chunk-HDJFCTOG.js.map +0 -1
- /package/dist/{run-7ZKIV6EU.js.map → run-J5Z32LEB.js.map} +0 -0
package/README.md
CHANGED
|
@@ -192,6 +192,12 @@ vos look https://app.acme.com/projects --session acme --click '[data-testid="new
|
|
|
192
192
|
|
|
193
193
|
It writes `<out>/look.png` (the viewport; `--out look` by default) and lists every control in view (buttons, links, tabs, menu items, checkboxes, switches, options, fields, editable regions, and anything with a test id) with its tag, role, accessible name, test id, link path and query, rect in viewport px, whether it is disabled, inside an open dialog or covered by something on top of it, and ONE proposed selector: its test id; else its `aria-label`, inside the open dialog it sits in; else a link's own `href`, query kept (two tiles to `?vos=a` and `?vos=b` are two links); else role and name (`role=button[name="Continue"]`, what `page.locator` reads), narrowed by its dialog or landmark when that is what makes it one; else a field's own `name` or `placeholder`, a written id, or its words inside its dialog or landmark. Never a position in the tree. Each proposal is counted with the recorder's own selector engine and marked `UNIQUE` (it reaches this element and no other) or `AMBIGUOUS` (it reaches others too, and the recorder would take the first). A control whose words hold an address, a key or a card number is listed with those words withheld, and the frame's exposures are said the way a rehearsal says them. Looking never spends or destroys: a `--click` whose target's words begin with a stem that does (delet, remov, revok, eras, discard, publish, deploy, purchas, subscri, unsubscri, pay, buy, generat, submit, send, transfer, upgrad, confirm, leav, destroy, so `Allow deleting` and `Revoke` are caught with `Delete`), or say move to trash, empty trash or cancel subscription, is refused in words before it is pressed (exit 2), and `--type` fills a field without pressing Enter. A look cannot know every spend: `Make a video` or `Create` on a primary button may start paid work and passes, because refusing every Make would refuse half of every app. The list is a floor under looking; in a recorded flow, a step's `guard: "spend"` in `actions.json` is the fence. A sign-in in front of the page is the wall check's verdict, exit 4; the sign-in page is still looked at, since it is what a `setup` step scripts past. `--wait <ms>` adds a pause before the look for a page that animates in; `--json` prints the whole look as one done event (`url`, `screenshot`, `controls`, `exposures`, `wall`).
|
|
194
194
|
|
|
195
|
+
**Past a step that creates: `vos look --actions actions.json --until <step id>`.** The state a flow is about often exists only after a click that makes something (the dialog that shows a new key appears after Create), and `--click` takes one hand-written step. `--until` walks the script's own steps the way a rehearsal does, on the same door (its `setup`, its `mask`, `--session` or `--storage-state`, a `guard: "spend"` step hovered and never pressed), stops after the step whose `id` it names, and looks at the page as that step left it; the steps after it never run. The URL and viewport are the script's unless given. The walk clicks for real, so the script's `teardown` runs after the look and its line ends the report. A step skipped on the way is named and exits 2 (the page may not be the one the script reaches), a step that is never reached says why, and an `--until` that names no step lists the ids the script has. It never takes `--click` or `--type` beside it.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
vos look --actions actions.json --until create --session acme # the page after the step with "id": "create"
|
|
199
|
+
```
|
|
200
|
+
|
|
195
201
|
**`setup`: the steps that run before the camera rolls.** A sign-in form, a cookie banner, the "choose your editor" modal, an onboarding tour: things a take must get past and must not show. `actions.json` takes `setup: [...]` beside `steps`, with the verbs `goto`, `click`, `type`, `press`, `wait`, and the guard `if`. They run after the first navigation and before a frame is captured, as plain actions with no cursor, no frames, no pace and nothing in `meta.steps`; then the recorder opens `url` again and the take begins where the setup left it. A `type` step's `text` may be `{ "env": "DEMO_PASSWORD" }`, read from the shell at run time and never logged or stored (the log names the field, never the value; a literal typed into a password field is refused by `validate`, because `actions.json` is committed and pushed with the take). A selector that never appears fails the take before anything is recorded (exit 2), because a take that begins at a half-finished sign-in is the wall by another name; rehearse the setup with `--dry-run` like everything else. This is rung 2 of the session ladder made scriptable: a local or self-hosted instance with a seeded user, no state file needed.
|
|
196
202
|
|
|
197
203
|
```json
|
|
@@ -544,7 +550,7 @@ vos assets ls [--kind <kind>] [--q <text>] [--sort size] | usage | why <id> #
|
|
|
544
550
|
vos recipe push <FILE.md> --folder <slug> | --asset <id> # the one recipe write: create, or replace in place
|
|
545
551
|
```
|
|
546
552
|
|
|
547
|
-
`push` is polymorphic by a deterministic sniff, never a flag: a take directory (a `doc.json` carrying `source`) pushes recording and document through the take pipeline; a `config.json` (or a directory holding one) pushes the program, and a `doc.json` beside it that carries `program` (a program document: overlays, objects, audio, speed, tween edits, its own length; `program.config` omitted on disk) rides along, lint-gated. `fetch` and `pull` write a program document back the same way. `pull` takes `--since <versionId>` (walk the changelog from that base instead of the tracked one) and `--check` (print what changed and stop: nothing on disk moves) on both paths. A program push LANDS where `vos.json` says: a directory that tracks a vos iterates it, so the fetch, edit, check, push, pull loop needs no flags, and making something separate from the same config is the explicit `--remix-of` door. Program pushes take `--vos`, `--title`, `--slug`, `--desc`, `--tags`, `--folder`, `--remix-of`, `--base`, `--label`, `--note`, `--override <id>` (repeatable) and `--claimable`; take pushes take `--title`, `--label`, `--note`, `--folder`, `--override`, `--yes`, `--bake` and `--claimable`. Both take `--wait`. A take push first asks the platform which `@vosjs/studio-core` it renders with (`GET /api/engine`, public, `{ studioCore, core }`) and refuses (exit 2), before anything uploads, a take that uses a field newer than it: the program a push compiles plays right, but the platform's studio lowers the stored document again with its own release, so it would show an anchored caption at its fallback start or play a clip with a loudness target at its gain, and every version saved from the studio would keep it that way. `--bake` sends a copy any renderer plays: every such field the take uses, said in what an older release reads (an anchored caption at the start it plays at in this cut with its `{elapsed}` filled, a loudness target as its gain, up to 1), whatever the platform answered, behind, current or nothing at all, and it never touches `doc.json`. The table of fields and their releases is `DOC_FEATURES` in `@vosjs/studio-core`. A platform that cannot say (no such endpoint, a refusal, no answer in 2 s) is warned of and pushed to. A new vos pushed without `--folder` lands unfiled, at the root of the shelf, and the done line says so. `--folder` takes a project on your own shelf (its slug or id) or anyone's project by its address, `<handle>/<slug>` as its page on vos.so names it: the server answers where the push lands, CONTINUING that project when the key is its owner's and otherwise STARTING the person's own from it (a private project made once, named after it, with the recipes they may read copied in, never its videos). The push says which.
|
|
553
|
+
`push` is polymorphic by a deterministic sniff, never a flag: a take directory (a `doc.json` carrying `source`) pushes recording and document through the take pipeline; a `config.json` (or a directory holding one) pushes the program, and a `doc.json` beside it that carries `program` (a program document: overlays, objects, audio, speed, tween edits, its own length; `program.config` omitted on disk) rides along, lint-gated. `fetch` and `pull` write a program document back the same way. `pull` takes `--since <versionId>` (walk the changelog from that base instead of the tracked one) and `--check` (print what changed and stop: nothing on disk moves) on both paths. A program push LANDS where `vos.json` says: a directory that tracks a vos iterates it, so the fetch, edit, check, push, pull loop needs no flags, and making something separate from the same config is the explicit `--remix-of` door. Program pushes take `--vos`, `--title`, `--slug`, `--desc`, `--tags`, `--folder`, `--remix-of`, `--base`, `--label`, `--note`, `--override <id>` (repeatable) and `--claimable`; take pushes take `--title`, `--desc`, `--prompt`, `--label`, `--note`, `--folder`, `--override`, `--yes`, `--bake` and `--claimable`. Both take `--wait`. `--desc` (up to 500 characters, checked before anything uploads) and `--prompt` are the watch page's words, kept on the vos and never on a version: a first push creates the vos with them, a later push that names them replaces them, one that names neither leaves them as they are, on a program and a take alike. A take push first asks the platform which `@vosjs/studio-core` it renders with (`GET /api/engine`, public, `{ studioCore, core }`) and refuses (exit 2), before anything uploads, a take that uses a field newer than it: the program a push compiles plays right, but the platform's studio lowers the stored document again with its own release, so it would show an anchored caption at its fallback start or play a clip with a loudness target at its gain, and every version saved from the studio would keep it that way. `--bake` sends a copy any renderer plays: every such field the take uses, said in what an older release reads (an anchored caption at the start it plays at in this cut with its `{elapsed}` filled, a loudness target as its gain, up to 1), whatever the platform answered, behind, current or nothing at all, and it never touches `doc.json`. The table of fields and their releases is `DOC_FEATURES` in `@vosjs/studio-core`. A platform that cannot say (no such endpoint, a refusal, no answer in 2 s) is warned of and pushed to. A new vos pushed without `--folder` lands unfiled, at the root of the shelf, and the done line says so. `--folder` takes a project on your own shelf (its slug or id) or anyone's project by its address, `<handle>/<slug>` as its page on vos.so names it: the server answers where the push lands, CONTINUING that project when the key is its owner's and otherwise STARTING the person's own from it (a private project made once, named after it, with the recipes they may read copied in, never its videos). The push says which.
|
|
548
554
|
|
|
549
555
|
**A program's files are declared, never typed into a function.** `config.json` names each file it uses in `assets` (`"assets": { "logo": { "ref": "./logo.png", "kind": "image" }, "shots": { "ref": ["./shots/1.png", "./shots/2.png"] } }`) and reads `ctx.assets.logo`, or `"$assets.logo"` in an element, object or font. On disk a `ref` is a path in the config's own directory or below, so `vos render`, `vos still` and `vos preview` serve the file to the page from disk. A path that climbs out of that directory (`../`, an absolute path, a link that points away) is not served and not uploaded, and a config loaded from a URL reads no local file: a program's code runs in a page, and what the page is served the program can send anywhere. `vos push` uploads each local file (content-addressed, so a re-push sends nothing: pictures, SVG, video, sound, `.glb` models, fonts and HDR environments) and what it stores names the hosted file as `asset:<id>`, the one spelling the platform resolves for every render; the config on disk keeps its paths. A file an element names as `src` or a font names as `url` is lifted into the manifest on the way (the element then names `"$assets.<name>"`), and a path in `data` that is a file beside the config is uploaded and rewritten to the hosted file's path, so every place a program can name a file crosses. A file typed inside a function cannot be rewritten: `vos push` says so, with the manifest line to write. `vos fetch --media` brings a program's hosted files home under `assets/` and re-points the manifest at them (`assets/.hosted.json` remembers which hosted file each one is, so a later fetch replaces one that changed); without `--media` the manifest keeps `asset:<id>` and a local render reads each file with your key. `vos check` says when a `"$assets.<name>"` names nothing, when a declared path is not a file, and when a function names a hosted file in code instead of the manifest: a file named only in code does not load on a render of a private program and does not follow a remix. A `--claimable` push carries them too, through the claim's own upload session (below).
|
|
550
556
|
|
|
@@ -148,9 +148,9 @@ function landedLines(l) {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// src/plugin/run.ts
|
|
151
|
-
import { mkdir as mkdir13, readFile as
|
|
151
|
+
import { mkdir as mkdir13, readFile as readFile19, rm as rm7 } from "fs/promises";
|
|
152
152
|
import { existsSync as existsSync30 } from "fs";
|
|
153
|
-
import { dirname as
|
|
153
|
+
import { dirname as dirname12, join as join33, resolve as resolve21 } from "path";
|
|
154
154
|
import {
|
|
155
155
|
END_CARD_FROM as END_CARD_FROM2,
|
|
156
156
|
docOutputDuration as docOutputDuration5,
|
|
@@ -7926,10 +7926,19 @@ function printChanges(r, changes, protectedIds) {
|
|
|
7926
7926
|
r.event({ event: "protected", nodes: protectedIds });
|
|
7927
7927
|
}
|
|
7928
7928
|
}
|
|
7929
|
+
var DESCRIPTION_MAX = 500;
|
|
7930
|
+
function descriptionProblem(desc) {
|
|
7931
|
+
if (desc === void 0) return null;
|
|
7932
|
+
if (!desc.trim())
|
|
7933
|
+
return "--desc is empty: give the sentence that says what the video shows";
|
|
7934
|
+
if (desc.length > DESCRIPTION_MAX)
|
|
7935
|
+
return `--desc is ${desc.length} characters and a vos keeps ${DESCRIPTION_MAX}: shorten it`;
|
|
7936
|
+
return null;
|
|
7937
|
+
}
|
|
7929
7938
|
function takePushRefusal(ask) {
|
|
7930
7939
|
if (ask.programOnly.length) {
|
|
7931
7940
|
const list = ask.programOnly.map((f) => `--${f}`).join(", ");
|
|
7932
|
-
return `${list} ${ask.programOnly.length > 1 ? "belong" : "belongs"} to a PROGRAM push (a config.json); a take push reads --vos, --title, --label, --note, --folder, --override and --yes`;
|
|
7941
|
+
return `${list} ${ask.programOnly.length > 1 ? "belong" : "belongs"} to a PROGRAM push (a config.json); a take push reads --vos, --title, --desc, --prompt, --label, --note, --folder, --override and --yes`;
|
|
7933
7942
|
}
|
|
7934
7943
|
if (ask.vos !== void 0 && ask.trackedVosId !== null && ask.trackedVosId !== ask.vos)
|
|
7935
7944
|
return `this take tracks vos ${ask.trackedVosId} (its vos.json), not ${ask.vos}. Drop --vos to push there, or remove vos.json to adopt ${ask.vos} instead`;
|
|
@@ -8104,7 +8113,8 @@ async function pushTake(dir, flags, r) {
|
|
|
8104
8113
|
...folderId ? { folderId } : {},
|
|
8105
8114
|
...flags.label ? { label: flags.label } : {},
|
|
8106
8115
|
...flags.note ? { note: flags.note } : {},
|
|
8107
|
-
...flags.prompt ? { prompt: flags.prompt } : {}
|
|
8116
|
+
...flags.prompt ? { prompt: flags.prompt } : {},
|
|
8117
|
+
...flags.description ? { description: flags.description } : {}
|
|
8108
8118
|
}
|
|
8109
8119
|
});
|
|
8110
8120
|
if (created.status !== 201) {
|
|
@@ -8155,14 +8165,18 @@ async function pushTake(dir, flags, r) {
|
|
|
8155
8165
|
);
|
|
8156
8166
|
}
|
|
8157
8167
|
serverWarnings(pushed.json, (l) => r.log(l));
|
|
8158
|
-
|
|
8168
|
+
const words2 = {
|
|
8169
|
+
...flags.prompt ? { prompt: flags.prompt } : {},
|
|
8170
|
+
...flags.description ? { description: flags.description } : {}
|
|
8171
|
+
};
|
|
8172
|
+
if (Object.keys(words2).length) {
|
|
8159
8173
|
const set = await api(ctx, `/vos/${state.vosId}`, {
|
|
8160
8174
|
method: "PATCH",
|
|
8161
|
-
body:
|
|
8175
|
+
body: words2
|
|
8162
8176
|
});
|
|
8163
8177
|
if (set.status !== 200)
|
|
8164
8178
|
r.warn(
|
|
8165
|
-
`could not set the
|
|
8179
|
+
`could not set the ${Object.keys(words2).join(" and ")} (${set.status}): ${String(set.json.error ?? "")}${detailLine(set.json)}`
|
|
8166
8180
|
);
|
|
8167
8181
|
}
|
|
8168
8182
|
const version = pushed.json.version;
|
|
@@ -8380,6 +8394,7 @@ async function pushTakeClaimable(dir, flags, r) {
|
|
|
8380
8394
|
const body = { title, config, doc: docForPush };
|
|
8381
8395
|
if (state?.vosId) body.remixOfId = state.vosId;
|
|
8382
8396
|
if (flags.prompt) body.prompt = flags.prompt;
|
|
8397
|
+
if (flags.description) body.description = flags.description;
|
|
8383
8398
|
if (flags.share) body.share = true;
|
|
8384
8399
|
const origin = platformOrigin(flags);
|
|
8385
8400
|
r.log(`creating a claimable push of ${title}\u2026`);
|
|
@@ -8918,9 +8933,11 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
|
|
|
8918
8933
|
});
|
|
8919
8934
|
if (pushTarget.kind === "refuse") throw new UsageError(pushTarget.why);
|
|
8920
8935
|
const vosId = pushTarget.kind === "version" ? pushTarget.vosId : null;
|
|
8921
|
-
|
|
8936
|
+
const descProblem = descriptionProblem(desc);
|
|
8937
|
+
if (descProblem) throw new UsageError(descProblem);
|
|
8938
|
+
if (vosId && (tagsFlag || folderRef)) {
|
|
8922
8939
|
throw new UsageError(
|
|
8923
|
-
"--
|
|
8940
|
+
"--tags/--folder apply when CREATING a vos. On an existing one: vos folder move <id> --to <folder> for filing; edit tags on vos.so"
|
|
8924
8941
|
);
|
|
8925
8942
|
}
|
|
8926
8943
|
if (vosId) {
|
|
@@ -8966,13 +8983,18 @@ with their key: vos push ${source} --vos ${String(created2.id ?? "<id>")}`
|
|
|
8966
8983
|
if (res.status !== 201)
|
|
8967
8984
|
throw new Error(apiError(`push version to ${vosId}`, res));
|
|
8968
8985
|
serverWarnings(res.body, say(r));
|
|
8969
|
-
|
|
8986
|
+
const words2 = {
|
|
8987
|
+
...prompt ? { prompt } : {},
|
|
8988
|
+
...desc ? { description: desc } : {}
|
|
8989
|
+
};
|
|
8990
|
+
if (Object.keys(words2).length) {
|
|
8970
8991
|
const set = await apiJson(origin, `/api/vos/${vosId}`, {
|
|
8971
8992
|
method: "PATCH",
|
|
8972
8993
|
key,
|
|
8973
|
-
body:
|
|
8994
|
+
body: words2
|
|
8974
8995
|
});
|
|
8975
|
-
if (set.status !== 200)
|
|
8996
|
+
if (set.status !== 200)
|
|
8997
|
+
r.warn(apiError(`set the ${Object.keys(words2).join(" and ")}`, set));
|
|
8976
8998
|
}
|
|
8977
8999
|
const version = res.body.version ?? {};
|
|
8978
9000
|
if (typeof version.id === "string") {
|
|
@@ -13129,8 +13151,8 @@ async function cmdActions(argv) {
|
|
|
13129
13151
|
if (!m) throw new UsageError("--viewport expects WxH, e.g. 1280x720");
|
|
13130
13152
|
viewport = { width: Number(m[1]), height: Number(m[2]) };
|
|
13131
13153
|
}
|
|
13132
|
-
const { readFile:
|
|
13133
|
-
const text = await
|
|
13154
|
+
const { readFile: readFile20 } = await import("fs/promises");
|
|
13155
|
+
const text = await readFile20(resolve14(input), "utf8");
|
|
13134
13156
|
const { records, problems } = parseAgentBrowserLog(text);
|
|
13135
13157
|
for (const p of problems) r.log(` ${p}`);
|
|
13136
13158
|
const result = convertAgentBrowser(records, {
|
|
@@ -13167,9 +13189,9 @@ function summary2(result) {
|
|
|
13167
13189
|
}
|
|
13168
13190
|
async function cmdActionsScript(input, flags) {
|
|
13169
13191
|
const r = createReporter(flags.json === true);
|
|
13170
|
-
const { readFile:
|
|
13192
|
+
const { readFile: readFile20 } = await import("fs/promises");
|
|
13171
13193
|
const { shotList, formatShotList } = await import("./shotList-PL7XP6AC.js");
|
|
13172
|
-
const raw = JSON.parse(await
|
|
13194
|
+
const raw = JSON.parse(await readFile20(resolve14(input), "utf8"));
|
|
13173
13195
|
const errors = validateActions(raw);
|
|
13174
13196
|
if (errors.length) throw new UsageError(`${input}:
|
|
13175
13197
|
${errors.join("\n ")}`);
|
|
@@ -16911,9 +16933,10 @@ async function cmdAudio(argv) {
|
|
|
16911
16933
|
}
|
|
16912
16934
|
|
|
16913
16935
|
// src/plugin/look.ts
|
|
16914
|
-
import { mkdir as mkdir12 } from "fs/promises";
|
|
16936
|
+
import { mkdir as mkdir12, mkdtemp as mkdtemp3, readFile as readFile18, rm as rm6 } from "fs/promises";
|
|
16915
16937
|
import { existsSync as existsSync27 } from "fs";
|
|
16916
|
-
import {
|
|
16938
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
16939
|
+
import { dirname as dirname10, join as join30, resolve as resolve20 } from "path";
|
|
16917
16940
|
import { headersFor, urlSchemeProblem } from "@vosjs/render-core/record";
|
|
16918
16941
|
function quote(value) {
|
|
16919
16942
|
return `"${value.replace(/\s+/g, " ").replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
@@ -17316,19 +17339,19 @@ async function lookAt(page, url, opts) {
|
|
|
17316
17339
|
});
|
|
17317
17340
|
const ran = [];
|
|
17318
17341
|
if (!wall || wall.level === "soft") {
|
|
17319
|
-
for (const
|
|
17320
|
-
const all = page.locator(
|
|
17342
|
+
for (const step of opts.steps ?? []) {
|
|
17343
|
+
const all = page.locator(step.selector);
|
|
17321
17344
|
const target = all.first();
|
|
17322
17345
|
try {
|
|
17323
17346
|
await target.waitFor({ state: "visible", timeout: STEP_TIMEOUT_MS });
|
|
17324
17347
|
} catch {
|
|
17325
17348
|
throw new UsageError(
|
|
17326
|
-
`--${
|
|
17349
|
+
`--${step.do} ${step.selector}: no visible element matches it after ${STEP_TIMEOUT_MS / 1e3} s. Look without the step and take a selector from the list`
|
|
17327
17350
|
);
|
|
17328
17351
|
}
|
|
17329
17352
|
const count = await all.count();
|
|
17330
17353
|
const note = count > 1 ? `the first of ${count} matches` : void 0;
|
|
17331
|
-
if (
|
|
17354
|
+
if (step.do === "click") {
|
|
17332
17355
|
const words2 = await target.evaluate(
|
|
17333
17356
|
(el) => [
|
|
17334
17357
|
el.getAttribute("aria-label"),
|
|
@@ -17344,25 +17367,37 @@ async function lookAt(page, url, opts) {
|
|
|
17344
17367
|
if (word) {
|
|
17345
17368
|
const label = words2.find((w) => spendWord([w])) ?? word;
|
|
17346
17369
|
throw new LookRefusal(
|
|
17347
|
-
refusalLine(
|
|
17370
|
+
refusalLine(step.selector, label.slice(0, 60), word)
|
|
17348
17371
|
);
|
|
17349
17372
|
}
|
|
17350
|
-
log(`click ${
|
|
17373
|
+
log(`click ${step.selector}${note ? ` (${note})` : ""}`);
|
|
17351
17374
|
await target.click({ timeout: STEP_TIMEOUT_MS });
|
|
17352
17375
|
} else {
|
|
17353
17376
|
log(
|
|
17354
|
-
`type ${
|
|
17377
|
+
`type ${step.text.length} chars into ${step.selector}${note ? ` (${note})` : ""}`
|
|
17355
17378
|
);
|
|
17356
|
-
await target.fill(
|
|
17379
|
+
await target.fill(step.text, { timeout: STEP_TIMEOUT_MS });
|
|
17357
17380
|
}
|
|
17358
17381
|
ran.push({
|
|
17359
|
-
do:
|
|
17360
|
-
selector:
|
|
17382
|
+
do: step.do,
|
|
17383
|
+
selector: step.selector,
|
|
17361
17384
|
...note ? { note } : {}
|
|
17362
17385
|
});
|
|
17363
17386
|
settled = await settle(page);
|
|
17364
17387
|
}
|
|
17365
17388
|
}
|
|
17389
|
+
return inspectPage(page, {
|
|
17390
|
+
url,
|
|
17391
|
+
outDir: opts.outDir,
|
|
17392
|
+
waitMs: opts.waitMs,
|
|
17393
|
+
wall,
|
|
17394
|
+
steps: ran,
|
|
17395
|
+
settled
|
|
17396
|
+
});
|
|
17397
|
+
}
|
|
17398
|
+
async function inspectPage(page, opts) {
|
|
17399
|
+
const { url, wall, settled } = opts;
|
|
17400
|
+
const ran = opts.steps;
|
|
17366
17401
|
if (opts.waitMs && opts.waitMs > 0) await page.waitForTimeout(opts.waitMs);
|
|
17367
17402
|
await mkdir12(opts.outDir, { recursive: true });
|
|
17368
17403
|
const screenshot = join30(opts.outDir, "look.png");
|
|
@@ -17420,7 +17455,27 @@ async function lookAt(page, url, opts) {
|
|
|
17420
17455
|
settled
|
|
17421
17456
|
};
|
|
17422
17457
|
}
|
|
17423
|
-
var USAGE5 = "vos look <url> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--click <selector>]... [--type <selector>=<text>]... [--wait <ms>] [--out <dir>] [--json]";
|
|
17458
|
+
var USAGE5 = "vos look <url> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--click <selector>]... [--type <selector>=<text>]... [--wait <ms>] [--out <dir>] [--json]\n vos look [url] --actions actions.json --until <step id> [--session <name> | --storage-state <file>] [--viewport WxH] [--headed] [--wait <ms>] [--out <dir>] [--json]";
|
|
17459
|
+
function untilProblem(given, steps) {
|
|
17460
|
+
if (given.until !== void 0 && given.actions === void 0)
|
|
17461
|
+
return "--until names a step of a script: pass the script with --actions actions.json";
|
|
17462
|
+
if (given.actions === void 0) return null;
|
|
17463
|
+
if (given.clicks)
|
|
17464
|
+
return "--actions walks the script; --click and --type walk by hand. Pass one";
|
|
17465
|
+
if (given.until === void 0)
|
|
17466
|
+
return "--actions needs --until <step id>: the step whose page you want to see";
|
|
17467
|
+
if (!steps) return null;
|
|
17468
|
+
if (steps.some((s) => s.id === given.until)) return null;
|
|
17469
|
+
const ids = steps.map((s) => s.id).filter((id) => !!id);
|
|
17470
|
+
return `--until ${given.until}: no step in ${given.actions} has that id. ${ids.length ? `Its ids: ${ids.join(", ")}` : 'Its steps have no ids; give the step you want an "id"'}`;
|
|
17471
|
+
}
|
|
17472
|
+
function walkedSteps(steps) {
|
|
17473
|
+
return steps.map((s) => ({
|
|
17474
|
+
do: s.id ? `${s.do} (${s.id})` : s.do,
|
|
17475
|
+
selector: s.selector ?? "",
|
|
17476
|
+
...s.skipped ? { note: `SKIPPED: ${s.reason ?? "not found"}` } : s.guard ? { note: `guarded (${s.guard}), hovered, not pressed` } : {}
|
|
17477
|
+
}));
|
|
17478
|
+
}
|
|
17424
17479
|
function lookReport(r) {
|
|
17425
17480
|
const inDialog = r.controls.filter((c) => c.inDialog).length;
|
|
17426
17481
|
const head = `Looked at ${r.landed} (${r.viewport.width}\xD7${r.viewport.height}): ${r.screenshot}${r.settled ? "" : "\n note: the page never held still for 0.8 s; looked at it as it was"}`;
|
|
@@ -17449,12 +17504,30 @@ async function cmdLook(argv) {
|
|
|
17449
17504
|
);
|
|
17450
17505
|
void multi.click;
|
|
17451
17506
|
void multi.type;
|
|
17452
|
-
const
|
|
17507
|
+
const actionsArg = strFlag(flags, "actions");
|
|
17508
|
+
const untilId = strFlag(flags, "until");
|
|
17509
|
+
const early = untilProblem({
|
|
17510
|
+
actions: actionsArg,
|
|
17511
|
+
until: untilId,
|
|
17512
|
+
clicks: steps.length
|
|
17513
|
+
});
|
|
17514
|
+
if (early) throw new UsageError(early);
|
|
17515
|
+
let actions;
|
|
17516
|
+
if (actionsArg) {
|
|
17517
|
+
actions = await loadLookActions(resolve20(actionsArg));
|
|
17518
|
+
const bad = untilProblem(
|
|
17519
|
+
{ actions: actionsArg, until: untilId, clicks: 0 },
|
|
17520
|
+
actions.steps
|
|
17521
|
+
);
|
|
17522
|
+
if (bad) throw new UsageError(bad);
|
|
17523
|
+
}
|
|
17524
|
+
const url = positionals[0] ?? actions?.url;
|
|
17453
17525
|
if (!url) throw new UsageError(USAGE5);
|
|
17454
17526
|
const scheme = urlSchemeProblem(url);
|
|
17455
17527
|
if (scheme) throw new UsageError(scheme);
|
|
17456
17528
|
const r = createReporter(flags.json === true);
|
|
17457
|
-
const
|
|
17529
|
+
const viewportFlag = strFlag(flags, "viewport");
|
|
17530
|
+
const viewport = !viewportFlag && actions?.viewport ? actions.viewport : parseViewport2(viewportFlag);
|
|
17458
17531
|
const outDir = resolve20(strFlag(flags, "out") ?? "look");
|
|
17459
17532
|
const headed = flags.headed === true;
|
|
17460
17533
|
const waitRaw = strFlag(flags, "wait");
|
|
@@ -17485,6 +17558,22 @@ async function cmdLook(argv) {
|
|
|
17485
17558
|
throw new UsageError(e instanceof Error ? e.message : String(e));
|
|
17486
17559
|
}
|
|
17487
17560
|
const browserArgs = (multi["browser-arg"] ?? []).filter(Boolean);
|
|
17561
|
+
if (actions && untilId && actionsArg)
|
|
17562
|
+
return lookUntil({
|
|
17563
|
+
r,
|
|
17564
|
+
url,
|
|
17565
|
+
actions,
|
|
17566
|
+
actionsPath: resolve20(actionsArg),
|
|
17567
|
+
untilId,
|
|
17568
|
+
viewport,
|
|
17569
|
+
outDir,
|
|
17570
|
+
waitMs,
|
|
17571
|
+
headed,
|
|
17572
|
+
storageState,
|
|
17573
|
+
sessionName,
|
|
17574
|
+
headers,
|
|
17575
|
+
browserArgs
|
|
17576
|
+
});
|
|
17488
17577
|
const inContext = async (ctx) => {
|
|
17489
17578
|
if (Object.keys(headers).length)
|
|
17490
17579
|
await ctx.route("**/*", async (route) => {
|
|
@@ -17531,6 +17620,108 @@ async function cmdLook(argv) {
|
|
|
17531
17620
|
);
|
|
17532
17621
|
return result.wall?.level === "hard" ? EXIT_WALL : EXIT_OK;
|
|
17533
17622
|
}
|
|
17623
|
+
async function loadLookActions(file) {
|
|
17624
|
+
let raw;
|
|
17625
|
+
try {
|
|
17626
|
+
raw = JSON.parse(await readFile18(file, "utf8"));
|
|
17627
|
+
} catch (e) {
|
|
17628
|
+
throw new UsageError(
|
|
17629
|
+
`--actions ${file}: ${e instanceof Error ? e.message : String(e)}`
|
|
17630
|
+
);
|
|
17631
|
+
}
|
|
17632
|
+
const errors = validateActions(raw);
|
|
17633
|
+
if (!errors.length) errors.push(...jsSyntaxProblems(raw));
|
|
17634
|
+
if (errors.length)
|
|
17635
|
+
throw new UsageError(`invalid actions file:
|
|
17636
|
+
${errors.join("\n ")}`);
|
|
17637
|
+
return raw;
|
|
17638
|
+
}
|
|
17639
|
+
async function lookUntil(o) {
|
|
17640
|
+
const { r } = o;
|
|
17641
|
+
const actions = { ...o.actions, viewport: o.viewport };
|
|
17642
|
+
let wall = null;
|
|
17643
|
+
let looked = null;
|
|
17644
|
+
const scratch = await mkdtemp3(join30(tmpdir4(), "vos-look-"));
|
|
17645
|
+
r.log(
|
|
17646
|
+
`walking ${o.actionsPath} to step ${o.untilId} (a rehearsal: guarded steps hovered, never pressed)\u2026`
|
|
17647
|
+
);
|
|
17648
|
+
const browser = await launchBrowser(o.browserArgs, { headless: !o.headed });
|
|
17649
|
+
let rec;
|
|
17650
|
+
try {
|
|
17651
|
+
const walk = (context2) => recordTake(browser, o.url, actions, takePaths(scratch), r.log, {
|
|
17652
|
+
actionsDir: dirname10(o.actionsPath),
|
|
17653
|
+
storageState: o.storageState,
|
|
17654
|
+
headers: o.headers,
|
|
17655
|
+
context: context2,
|
|
17656
|
+
dryRun: true,
|
|
17657
|
+
stopOnHang: true,
|
|
17658
|
+
onEvent: (e) => r.event(e),
|
|
17659
|
+
onArrival: (arrival) => {
|
|
17660
|
+
const verdict = wallVerdict(arrival);
|
|
17661
|
+
if (verdict && verdict.level === "hard") throw new WallError(verdict);
|
|
17662
|
+
if (verdict) r.log(` WARNING: ${verdict.message}`);
|
|
17663
|
+
wall = verdict;
|
|
17664
|
+
return verdict;
|
|
17665
|
+
},
|
|
17666
|
+
until: {
|
|
17667
|
+
id: o.untilId,
|
|
17668
|
+
at: async (raw) => {
|
|
17669
|
+
const page = raw;
|
|
17670
|
+
const settled = await settle(page);
|
|
17671
|
+
looked = await inspectPage(page, {
|
|
17672
|
+
url: o.url,
|
|
17673
|
+
outDir: o.outDir,
|
|
17674
|
+
waitMs: o.waitMs,
|
|
17675
|
+
wall,
|
|
17676
|
+
steps: [],
|
|
17677
|
+
settled
|
|
17678
|
+
});
|
|
17679
|
+
}
|
|
17680
|
+
}
|
|
17681
|
+
});
|
|
17682
|
+
rec = o.sessionName ? await withSession(o.sessionName, (ctx) => walk(ctx), {
|
|
17683
|
+
headless: !o.headed,
|
|
17684
|
+
viewport: o.viewport
|
|
17685
|
+
}) : await walk(void 0);
|
|
17686
|
+
} finally {
|
|
17687
|
+
await browser.close();
|
|
17688
|
+
await rm6(scratch, { recursive: true, force: true });
|
|
17689
|
+
}
|
|
17690
|
+
const result = looked;
|
|
17691
|
+
const ran = walkedSteps(rec.meta.steps ?? []);
|
|
17692
|
+
const skipped = rec.skipped.length;
|
|
17693
|
+
const teardown = rec.teardown ? `
|
|
17694
|
+
${teardownLine(rec.teardown)}` : "";
|
|
17695
|
+
if (!result) {
|
|
17696
|
+
const why = rec.stopped ? rec.stopped.reason : "the walk ended before it reached that step";
|
|
17697
|
+
r.done(
|
|
17698
|
+
{
|
|
17699
|
+
ok: false,
|
|
17700
|
+
until: o.untilId,
|
|
17701
|
+
steps: ran,
|
|
17702
|
+
skipped: rec.skipped,
|
|
17703
|
+
...rec.teardown ? { teardown: rec.teardown } : {}
|
|
17704
|
+
},
|
|
17705
|
+
`NOT LOOKED: step ${o.untilId} was never reached: ${why}.${ran.length ? `
|
|
17706
|
+
walked: ${ran.map((s) => `${s.do}${s.selector ? ` ${s.selector}` : ""}${s.note ? ` (${s.note})` : ""}`).join(", then ")}` : ""}
|
|
17707
|
+
Rehearse the script (vos record --actions ${o.actionsPath} --dry-run) to see where it stops.${teardown}`
|
|
17708
|
+
);
|
|
17709
|
+
return EXIT_USAGE;
|
|
17710
|
+
}
|
|
17711
|
+
const full = { ...result, steps: ran };
|
|
17712
|
+
const warn = skipped ? `
|
|
17713
|
+
WARNING: ${skipped} step${skipped === 1 ? " was" : "s were"} SKIPPED on the way, so this may not be the page the script reaches. Fix ${skipped === 1 ? "it" : "them"}, then look again.` : "";
|
|
17714
|
+
r.done(
|
|
17715
|
+
{
|
|
17716
|
+
ok: skipped === 0 && (!full.wall || full.wall.level === "soft"),
|
|
17717
|
+
until: o.untilId,
|
|
17718
|
+
...full,
|
|
17719
|
+
...rec.teardown ? { teardown: rec.teardown } : {}
|
|
17720
|
+
},
|
|
17721
|
+
`${lookReport(full)}${warn}${teardown}`
|
|
17722
|
+
);
|
|
17723
|
+
return skipped ? EXIT_USAGE : EXIT_OK;
|
|
17724
|
+
}
|
|
17534
17725
|
|
|
17535
17726
|
// src/plugin/machineCmd.ts
|
|
17536
17727
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
@@ -17548,7 +17739,7 @@ import { chromium as chromium2 } from "playwright";
|
|
|
17548
17739
|
|
|
17549
17740
|
// src/plugin/machine.ts
|
|
17550
17741
|
import { existsSync as existsSync28, readFileSync as readFileSync10, readdirSync as readdirSync6, statSync as statSync8 } from "fs";
|
|
17551
|
-
import { dirname as
|
|
17742
|
+
import { dirname as dirname11, join as join31 } from "path";
|
|
17552
17743
|
var AGENT_NAMES = [
|
|
17553
17744
|
"claude",
|
|
17554
17745
|
"cursor",
|
|
@@ -17768,7 +17959,7 @@ function bundledSkillsVersion(dir) {
|
|
|
17768
17959
|
}
|
|
17769
17960
|
}
|
|
17770
17961
|
function bundledSkillsDir(from) {
|
|
17771
|
-
let dir =
|
|
17962
|
+
let dir = dirname11(from);
|
|
17772
17963
|
for (let i = 0; i < 6; i++) {
|
|
17773
17964
|
const pkg = join31(dir, "package.json");
|
|
17774
17965
|
if (existsSync28(pkg)) {
|
|
@@ -17781,7 +17972,7 @@ function bundledSkillsDir(from) {
|
|
|
17781
17972
|
} catch {
|
|
17782
17973
|
}
|
|
17783
17974
|
}
|
|
17784
|
-
const up =
|
|
17975
|
+
const up = dirname11(dir);
|
|
17785
17976
|
if (up === dir) break;
|
|
17786
17977
|
dir = up;
|
|
17787
17978
|
}
|
|
@@ -18503,7 +18694,7 @@ lint-gated, so a bad override fails like a bad doc.json):
|
|
|
18503
18694
|
first ready loop (the house backdrop the studio opens on), or a flat ground offline
|
|
18504
18695
|
`;
|
|
18505
18696
|
async function loadActions(file) {
|
|
18506
|
-
const raw = JSON.parse(await
|
|
18697
|
+
const raw = JSON.parse(await readFile19(file, "utf8"));
|
|
18507
18698
|
const errors = validateActions(raw);
|
|
18508
18699
|
if (!errors.length) errors.push(...jsSyntaxProblems(raw));
|
|
18509
18700
|
if (errors.length)
|
|
@@ -18725,7 +18916,7 @@ function reRecord(outDir, flags, r) {
|
|
|
18725
18916
|
...from ? {
|
|
18726
18917
|
reuse: {
|
|
18727
18918
|
from,
|
|
18728
|
-
doc: JSON.parse(await
|
|
18919
|
+
doc: JSON.parse(await readFile19(from, "utf8"))
|
|
18729
18920
|
}
|
|
18730
18921
|
} : {}
|
|
18731
18922
|
});
|
|
@@ -18832,7 +19023,7 @@ async function cmdRecord(argv) {
|
|
|
18832
19023
|
);
|
|
18833
19024
|
const hostedActions = await scriptForHost(
|
|
18834
19025
|
actions,
|
|
18835
|
-
|
|
19026
|
+
dirname12(resolve21(actionsPath))
|
|
18836
19027
|
).catch((e) => {
|
|
18837
19028
|
throw new UsageError(e instanceof Error ? e.message : String(e));
|
|
18838
19029
|
});
|
|
@@ -18942,7 +19133,7 @@ async function cmdRecord(argv) {
|
|
|
18942
19133
|
sessionName,
|
|
18943
19134
|
actions,
|
|
18944
19135
|
(context2) => recordTake(browser2, url, actions, takePaths(outDir), r.log, {
|
|
18945
|
-
actionsDir:
|
|
19136
|
+
actionsDir: dirname12(resolve21(actionsPath)),
|
|
18946
19137
|
storageState,
|
|
18947
19138
|
headers,
|
|
18948
19139
|
context: context2,
|
|
@@ -19050,7 +19241,7 @@ ${lines.join("\n")}
|
|
|
19050
19241
|
sessionName,
|
|
19051
19242
|
actions,
|
|
19052
19243
|
(context2) => recordTake(browser, url, actions, paths, r.log, {
|
|
19053
|
-
actionsDir:
|
|
19244
|
+
actionsDir: dirname12(resolve21(actionsPath)),
|
|
19054
19245
|
maxDurationSeconds,
|
|
19055
19246
|
storageState,
|
|
19056
19247
|
headers,
|
|
@@ -19189,7 +19380,7 @@ async function cmdCreate2(argv) {
|
|
|
19189
19380
|
sessionName,
|
|
19190
19381
|
actions,
|
|
19191
19382
|
(context2) => recordTake(browser, url, actions, paths, r.log, {
|
|
19192
|
-
actionsDir:
|
|
19383
|
+
actionsDir: dirname12(resolve21(actionsPath)),
|
|
19193
19384
|
maxDurationSeconds,
|
|
19194
19385
|
storageState,
|
|
19195
19386
|
headers,
|
|
@@ -19316,7 +19507,7 @@ async function cmdPlan(argvIn) {
|
|
|
19316
19507
|
);
|
|
19317
19508
|
const r = createReporter(flags.json === true);
|
|
19318
19509
|
if (flags.fresh === true) {
|
|
19319
|
-
await
|
|
19510
|
+
await rm7(join33(dir, "doc.json"), { force: true });
|
|
19320
19511
|
r.log("note: --fresh discarded the existing doc.json");
|
|
19321
19512
|
}
|
|
19322
19513
|
let reuse;
|
|
@@ -19329,7 +19520,7 @@ async function cmdPlan(argvIn) {
|
|
|
19329
19520
|
}
|
|
19330
19521
|
reuse = {
|
|
19331
19522
|
from,
|
|
19332
|
-
doc: JSON.parse(await
|
|
19523
|
+
doc: JSON.parse(await readFile19(from, "utf8"))
|
|
19333
19524
|
};
|
|
19334
19525
|
}
|
|
19335
19526
|
const style = await resolveStyleRef(flags);
|
|
@@ -19801,7 +19992,7 @@ async function resolveDocRef(ref, flags, what) {
|
|
|
19801
19992
|
return {
|
|
19802
19993
|
from: file,
|
|
19803
19994
|
doc: migrateHostedDoc4(
|
|
19804
|
-
JSON.parse(await
|
|
19995
|
+
JSON.parse(await readFile19(file, "utf8"))
|
|
19805
19996
|
)
|
|
19806
19997
|
};
|
|
19807
19998
|
}
|
|
@@ -19853,7 +20044,7 @@ async function cmdDigest(argv) {
|
|
|
19853
20044
|
const take = await loadTake(dir);
|
|
19854
20045
|
if (!take.doc) throw new UsageError(`${dir} has no doc.json \u2014 run plan first`);
|
|
19855
20046
|
const transcriptPath = strFlag(flags, "transcript");
|
|
19856
|
-
const transcript = transcriptPath ? parseTranscript(JSON.parse(await
|
|
20047
|
+
const transcript = transcriptPath ? parseTranscript(JSON.parse(await readFile19(transcriptPath, "utf8"))) : null;
|
|
19857
20048
|
const style = await resolveStyleRef(flags);
|
|
19858
20049
|
const noFrames = flags["no-frames"] === true;
|
|
19859
20050
|
let browser = null;
|
|
@@ -19966,7 +20157,7 @@ async function cmdCallout(argv) {
|
|
|
19966
20157
|
`no register: put a BRAND.md beside the take (vos brand <url> --out BRAND.md; its bgA and accent are the ground and the accent), or pass --ground #hex --accent #hex`
|
|
19967
20158
|
);
|
|
19968
20159
|
const codeFile = strFlag(flags, "code-file");
|
|
19969
|
-
const code = codeFile ? await
|
|
20160
|
+
const code = codeFile ? await readFile19(codeFile, "utf8") : strFlag(flags, "code");
|
|
19970
20161
|
const words2 = {
|
|
19971
20162
|
kicker: strFlag(flags, "kicker"),
|
|
19972
20163
|
title: strFlag(flags, "title"),
|
|
@@ -20079,7 +20270,7 @@ async function cmdValidate(argv) {
|
|
|
20079
20270
|
}
|
|
20080
20271
|
if (!isTakeDir(target) && existsSync30(join33(target, "config.json"))) {
|
|
20081
20272
|
const parsed = JSON.parse(
|
|
20082
|
-
await
|
|
20273
|
+
await readFile19(join33(target, "config.json"), "utf8")
|
|
20083
20274
|
);
|
|
20084
20275
|
const pre = preflightConfig(parsed);
|
|
20085
20276
|
const problems2 = pre.ok ? [] : pre.issues.map((i) => `config.json: ${i}`);
|
|
@@ -20237,16 +20428,19 @@ async function cmdPush3(argv) {
|
|
|
20237
20428
|
const dir = positionals[0];
|
|
20238
20429
|
if (!dir)
|
|
20239
20430
|
throw new UsageError(
|
|
20240
|
-
"vos push <take> [--vos|--title|--label|--note|--prompt|--folder|--override|--yes|--key|--api|--bake|--claimable [--share]]"
|
|
20431
|
+
"vos push <take> [--vos|--title|--desc|--label|--note|--prompt|--folder|--override|--yes|--key|--api|--bake|--claimable [--share]]"
|
|
20241
20432
|
);
|
|
20242
20433
|
const refusal = takePushRefusal({
|
|
20243
20434
|
vos: strFlag(flags, "vos"),
|
|
20244
20435
|
trackedVosId: readSyncState(resolve21(dir))?.vosId ?? null,
|
|
20245
|
-
programOnly: ["slug", "
|
|
20436
|
+
programOnly: ["slug", "tags", "base", "remix-of", "still"].filter(
|
|
20246
20437
|
(name) => hasFlag(flags, name)
|
|
20247
20438
|
)
|
|
20248
20439
|
});
|
|
20249
20440
|
if (refusal) throw new UsageError(refusal);
|
|
20441
|
+
const description = strFlag(flags, "desc");
|
|
20442
|
+
const descProblem = descriptionProblem(description);
|
|
20443
|
+
if (descProblem) throw new UsageError(descProblem);
|
|
20250
20444
|
const r = createReporter(flags.json === true);
|
|
20251
20445
|
if (flags.claimable === true) {
|
|
20252
20446
|
const iterating = ["vos", "folder", "override", "base"].filter(
|
|
@@ -20263,6 +20457,7 @@ async function cmdPush3(argv) {
|
|
|
20263
20457
|
origin: strFlag(flags, "origin"),
|
|
20264
20458
|
title: strFlag(flags, "title"),
|
|
20265
20459
|
prompt: strFlag(flags, "prompt"),
|
|
20460
|
+
description,
|
|
20266
20461
|
share: flags.share === true,
|
|
20267
20462
|
bake: flags.bake === true
|
|
20268
20463
|
},
|
|
@@ -20293,6 +20488,7 @@ reference and the only credential.`
|
|
|
20293
20488
|
folder: strFlag(flags, "folder"),
|
|
20294
20489
|
overrides,
|
|
20295
20490
|
prompt: strFlag(flags, "prompt"),
|
|
20491
|
+
description,
|
|
20296
20492
|
bake: flags.bake === true
|
|
20297
20493
|
},
|
|
20298
20494
|
r
|
|
@@ -20684,4 +20880,4 @@ export {
|
|
|
20684
20880
|
verbHelp,
|
|
20685
20881
|
run
|
|
20686
20882
|
};
|
|
20687
|
-
//# sourceMappingURL=chunk-
|
|
20883
|
+
//# sourceMappingURL=chunk-DM7ADA77.js.map
|