@visualautomate/cli 0.4.1 → 0.5.1
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 +30 -20
- package/dist/index.js +95 -34
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -4,14 +4,14 @@ Build and publish VisualAutomate plugins.
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install -g @visualautomate/cli
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
vsa login
|
|
8
|
+
vsa init my-step
|
|
9
9
|
cd my-step
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
vsa dev # the sandbox, and a run again on every save
|
|
11
|
+
vsa push
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
`va`
|
|
14
|
+
`va` and `visualautomate` are the same command.
|
|
15
15
|
|
|
16
16
|
That is the whole toolchain. There is nothing else to install: the CLI carries
|
|
17
17
|
the SDK inside it, compiles your TypeScript itself, and writes the type
|
|
@@ -79,20 +79,25 @@ my-app/ an app's repository
|
|
|
79
79
|
…
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
At the root of an app's repository every module runs, one after another
|
|
83
|
-
|
|
82
|
+
At the root of an app's repository every module runs, one after another. Name one
|
|
83
|
+
to run only that: `vsa test send-message`, or any short name that picks it out —
|
|
84
|
+
`vsa test send`. `--module <name>` is the same thing. `index.js` in a repository is run as written,
|
|
84
85
|
unbundled, because that is the file the sandbox loads.
|
|
85
86
|
|
|
86
87
|
## `dev`
|
|
87
88
|
|
|
88
|
-
`test`, and again on every save. Only the module whose folder changed runs
|
|
89
|
-
again; a change anywhere else runs them all. Ctrl+C stops it.
|
|
90
|
-
|
|
91
89
|
```bash
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
vsa dev # every module in modules/
|
|
91
|
+
vsa dev send-message # one of them; the shortest name that picks it will do
|
|
92
|
+
vsa dev --tier boosted # a bigger machine
|
|
93
|
+
vsa dev --local # on this machine's Node, without the sandbox
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
Everything in one command: it starts Docker if it is not running, fetches the
|
|
97
|
+
sandbox image the first time, runs every module, and runs them again on every
|
|
98
|
+
save. Only the module whose folder changed runs again; a change anywhere else
|
|
99
|
+
runs them all. Ctrl+C stops it.
|
|
100
|
+
|
|
96
101
|
`context.connections` and `context.media` are **not** simulated. One is
|
|
97
102
|
somebody's OAuth account and the other is an ffmpeg container; pretending to be
|
|
98
103
|
either would produce a plugin that passes here and fails on a canvas. Asking for
|
|
@@ -140,14 +145,17 @@ Keeps storage and state between runs, in `.visualautomate/` next to the plugin:
|
|
|
140
145
|
Once that folder exists it is used without the flag. Delete it to start over,
|
|
141
146
|
and add it to `.gitignore`.
|
|
142
147
|
|
|
143
|
-
##
|
|
148
|
+
## The sandbox on your machine
|
|
149
|
+
|
|
150
|
+
`dev` uses it by default; `test` does with `--docker`:
|
|
144
151
|
|
|
145
152
|
```bash
|
|
146
|
-
|
|
147
|
-
|
|
153
|
+
vsa dev
|
|
154
|
+
vsa test --docker
|
|
155
|
+
vsa dev --tier boosted
|
|
148
156
|
```
|
|
149
157
|
|
|
150
|
-
|
|
158
|
+
Your plugin runs inside the plugin sandbox image,
|
|
151
159
|
`ghcr.io/visualautomate/plugin-sandbox`, at the version of this CLI:
|
|
152
160
|
|
|
153
161
|
- the Node version the platform runs plugins on, with every allowed npm
|
|
@@ -157,10 +165,12 @@ Runs the test inside the plugin sandbox image,
|
|
|
157
165
|
- no Linux capabilities, a read-only filesystem apart from your project and a
|
|
158
166
|
small `/tmp`, and nothing else from your machine.
|
|
159
167
|
|
|
160
|
-
A step that runs out of memory or time here does the same on the platform.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
A step that runs out of memory or time here does the same on the platform.
|
|
169
|
+
|
|
170
|
+
Docker does not have to be running: `dev` starts Docker Desktop and waits for it,
|
|
171
|
+
then fetches the image if this machine does not have it. `--image` uses a
|
|
172
|
+
different image, for example one you built yourself. The watcher stays on your
|
|
173
|
+
machine, and each run starts a fresh container.
|
|
164
174
|
|
|
165
175
|
`context.media` is not available locally, in or out of Docker.
|
|
166
176
|
|
package/dist/index.js
CHANGED
|
@@ -1822,6 +1822,14 @@ var ENTRIES = ["plugin.ts", "plugin.js", "index.ts", "index.js"];
|
|
|
1822
1822
|
function entryIn(dir) {
|
|
1823
1823
|
return ENTRIES.map((file2) => join(dir, file2)).find((file2) => existsSync(file2)) ?? null;
|
|
1824
1824
|
}
|
|
1825
|
+
function matchFolders(folders, name) {
|
|
1826
|
+
const wanted = name.trim().toLowerCase();
|
|
1827
|
+
const exact = folders.filter((folder) => folder.toLowerCase() === wanted);
|
|
1828
|
+
if (exact.length > 0) return exact;
|
|
1829
|
+
const prefix = folders.filter((folder) => folder.toLowerCase().startsWith(wanted));
|
|
1830
|
+
if (prefix.length > 0) return prefix;
|
|
1831
|
+
return folders.filter((folder) => folder.toLowerCase().includes(wanted));
|
|
1832
|
+
}
|
|
1825
1833
|
function findTargets(cwd, only) {
|
|
1826
1834
|
const dir = resolve(cwd);
|
|
1827
1835
|
const modulesDir = join(dir, "modules");
|
|
@@ -1830,16 +1838,16 @@ function findTargets(cwd, only) {
|
|
|
1830
1838
|
if (folders.length === 0) {
|
|
1831
1839
|
throw new Error("There is a modules/ folder here, but none of its folders has a manifest.json.");
|
|
1832
1840
|
}
|
|
1833
|
-
const chosen = only ? folders
|
|
1841
|
+
const chosen = only ? matchFolders(folders, only) : folders;
|
|
1834
1842
|
if (only && chosen.length === 0) {
|
|
1835
|
-
throw new Error(`No module "${only}"
|
|
1843
|
+
throw new Error(`No module matches "${only}". This repository has: ${folders.join(", ")}.`);
|
|
1836
1844
|
}
|
|
1837
1845
|
return chosen.map((folder) => targetIn(join(modulesDir, folder), `modules/${folder}`)).filter(Boolean);
|
|
1838
1846
|
}
|
|
1839
1847
|
const target = targetIn(dir, basename(dir));
|
|
1840
1848
|
if (!target) {
|
|
1841
1849
|
throw new Error(
|
|
1842
|
-
"Nothing to test here: no plugin.ts, plugin.js or index.js, and no modules/ folder.\nRun this in a
|
|
1850
|
+
"Nothing to test here: no plugin.ts, plugin.js or index.js, and no modules/ folder.\nRun this in a module's folder, at the root of its repository, or run `vsa init <name>`."
|
|
1843
1851
|
);
|
|
1844
1852
|
}
|
|
1845
1853
|
return [target];
|
|
@@ -2139,6 +2147,35 @@ function explainExit(code, tier) {
|
|
|
2139
2147
|
if (code === 125) return "\u2717 Docker could not start the container. Is the image available? Try: docker pull " + IMAGE;
|
|
2140
2148
|
return null;
|
|
2141
2149
|
}
|
|
2150
|
+
function ensureDocker(say, waitMs = 12e4) {
|
|
2151
|
+
const problem = dockerProblem();
|
|
2152
|
+
if (!problem) return null;
|
|
2153
|
+
if (problem.includes("not installed")) return problem;
|
|
2154
|
+
say("Docker is not running. Starting Docker Desktop\u2026");
|
|
2155
|
+
const started = spawnSync("docker", ["desktop", "start"], { encoding: "utf8" });
|
|
2156
|
+
if (started.status !== 0) {
|
|
2157
|
+
say("Could not start it from here \u2014 start Docker Desktop yourself; this will carry on when it is up.");
|
|
2158
|
+
}
|
|
2159
|
+
const until = Date.now() + waitMs;
|
|
2160
|
+
while (Date.now() < until) {
|
|
2161
|
+
spawnSync(process.execPath, ["-e", "setTimeout(() => {}, 1000)"]);
|
|
2162
|
+
if (!dockerProblem()) {
|
|
2163
|
+
say("Docker is ready.");
|
|
2164
|
+
return null;
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
return "Docker did not come up in time. Start Docker Desktop and try again.";
|
|
2168
|
+
}
|
|
2169
|
+
function hasImage(image) {
|
|
2170
|
+
return spawnSync("docker", ["image", "inspect", image], { stdio: "ignore" }).status === 0;
|
|
2171
|
+
}
|
|
2172
|
+
function pullImage(image, say) {
|
|
2173
|
+
if (hasImage(image)) return null;
|
|
2174
|
+
say(`Fetching ${image} \u2014 once, about 700 MB.`);
|
|
2175
|
+
const pulled = spawnSync("docker", ["pull", image], { stdio: "inherit" });
|
|
2176
|
+
if (pulled.status === 0) return null;
|
|
2177
|
+
return `Could not fetch ${image}. Check your connection, or pass --image with one you have.`;
|
|
2178
|
+
}
|
|
2142
2179
|
function runInDocker(run) {
|
|
2143
2180
|
const result = spawnSync("docker", dockerArgs(run), { stdio: "inherit" });
|
|
2144
2181
|
const code = result.status ?? 1;
|
|
@@ -2148,7 +2185,7 @@ function runInDocker(run) {
|
|
|
2148
2185
|
}
|
|
2149
2186
|
|
|
2150
2187
|
// src/index.ts
|
|
2151
|
-
var VERSION = true ? "0.
|
|
2188
|
+
var VERSION = true ? "0.5.1" : "0.0.0-dev";
|
|
2152
2189
|
var DEFAULT_API_URL = "https://visualautomate.com";
|
|
2153
2190
|
function configPath() {
|
|
2154
2191
|
return join3(homedir(), ".visualautomate", "config.json");
|
|
@@ -2472,9 +2509,16 @@ function packageLoader(dir) {
|
|
|
2472
2509
|
}
|
|
2473
2510
|
};
|
|
2474
2511
|
}
|
|
2512
|
+
function imageFor(flags) {
|
|
2513
|
+
return flags.image || `${IMAGE}:${VERSION}`;
|
|
2514
|
+
}
|
|
2515
|
+
function prepareSandbox(flags) {
|
|
2516
|
+
const docker = ensureDocker(ok);
|
|
2517
|
+
if (docker) fail(docker);
|
|
2518
|
+
const image = pullImage(imageFor(flags), ok);
|
|
2519
|
+
if (image) fail(image);
|
|
2520
|
+
}
|
|
2475
2521
|
function dockerRunFor(flags, args) {
|
|
2476
|
-
const problem = dockerProblem();
|
|
2477
|
-
if (problem) fail(problem);
|
|
2478
2522
|
let tier;
|
|
2479
2523
|
try {
|
|
2480
2524
|
tier = tierOf(flags.tier);
|
|
@@ -2483,7 +2527,7 @@ function dockerRunFor(flags, args) {
|
|
|
2483
2527
|
}
|
|
2484
2528
|
return {
|
|
2485
2529
|
cwd: process.cwd(),
|
|
2486
|
-
image: flags
|
|
2530
|
+
image: imageFor(flags),
|
|
2487
2531
|
tier,
|
|
2488
2532
|
args,
|
|
2489
2533
|
user: typeof process.getuid === "function" && typeof process.getgid === "function" ? { uid: process.getuid(), gid: process.getgid() } : void 0
|
|
@@ -2502,28 +2546,41 @@ function runTargetsInDocker(targets, all, flags) {
|
|
|
2502
2546
|
}
|
|
2503
2547
|
return passed;
|
|
2504
2548
|
}
|
|
2505
|
-
function targetsOrFail(flags) {
|
|
2549
|
+
function targetsOrFail(args, flags) {
|
|
2506
2550
|
try {
|
|
2507
|
-
return findTargets(process.cwd(), flags.module);
|
|
2551
|
+
return findTargets(process.cwd(), args[0] ?? flags.module);
|
|
2508
2552
|
} catch (error) {
|
|
2509
2553
|
fail(error instanceof Error ? error.message : String(error));
|
|
2510
2554
|
}
|
|
2511
2555
|
}
|
|
2512
|
-
|
|
2513
|
-
|
|
2556
|
+
function sayWhatRuns(targets, picked) {
|
|
2557
|
+
if (targets.length === 1) {
|
|
2558
|
+
ok(`Running ${targets[0].name}`);
|
|
2559
|
+
return;
|
|
2560
|
+
}
|
|
2561
|
+
ok(`Running ${targets.length} modules: ${targets.map((t) => t.name.replace(/^modules\//, "")).join(", ")}`);
|
|
2562
|
+
if (!picked) ok(`One of them: vsa dev ${targets[0].name.replace(/^modules\//, "")}`);
|
|
2563
|
+
}
|
|
2564
|
+
async function cmdTest(args, flags) {
|
|
2565
|
+
const targets = targetsOrFail(args, flags);
|
|
2566
|
+
if (flags.docker) prepareSandbox(flags);
|
|
2514
2567
|
const passed = flags.docker ? runTargetsInDocker(targets, targets, flags) : await runTargets(targets, flags);
|
|
2515
2568
|
if (!passed) process.exitCode = 1;
|
|
2516
2569
|
}
|
|
2517
|
-
async function cmdDev(flags) {
|
|
2570
|
+
async function cmdDev(args, flags) {
|
|
2518
2571
|
const root = process.cwd();
|
|
2519
|
-
|
|
2572
|
+
const picked = args[0] ?? flags.module;
|
|
2573
|
+
let targets = targetsOrFail(args, flags);
|
|
2574
|
+
const inSandbox = flags.local !== "true";
|
|
2575
|
+
if (inSandbox) prepareSandbox(flags);
|
|
2520
2576
|
const header = () => {
|
|
2521
2577
|
process.stdout.write("\x1Bc");
|
|
2522
|
-
ok(`
|
|
2578
|
+
ok(`vsa dev \u2014 ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} \u2014 Ctrl+C to stop`);
|
|
2523
2579
|
};
|
|
2524
|
-
const run = async (chosen) =>
|
|
2580
|
+
const run = async (chosen) => inSandbox ? runTargetsInDocker(chosen, targets, flags) : runTargets(chosen, flags);
|
|
2525
2581
|
header();
|
|
2526
|
-
|
|
2582
|
+
ok(inSandbox ? `in ${imageFor(flags)}, tier ${flags.tier || "standard"}` : "on this machine, not in the sandbox");
|
|
2583
|
+
sayWhatRuns(targets, Boolean(picked));
|
|
2527
2584
|
await run(targets);
|
|
2528
2585
|
const ignored = [`${sep2}node_modules${sep2}`, `${sep2}.git${sep2}`, `${sep2}dist${sep2}`, `${sep2}.visualautomate${sep2}`];
|
|
2529
2586
|
const pending = /* @__PURE__ */ new Set();
|
|
@@ -2538,7 +2595,7 @@ async function cmdDev(flags) {
|
|
|
2538
2595
|
const changed = [...pending];
|
|
2539
2596
|
pending.clear();
|
|
2540
2597
|
try {
|
|
2541
|
-
targets = findTargets(root,
|
|
2598
|
+
targets = findTargets(root, picked);
|
|
2542
2599
|
} catch (error) {
|
|
2543
2600
|
header();
|
|
2544
2601
|
ok(`\u2717 ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -2656,29 +2713,33 @@ ${text.slice(0, 500)}`);
|
|
|
2656
2713
|
}
|
|
2657
2714
|
function printHelp() {
|
|
2658
2715
|
console.log(`
|
|
2659
|
-
|
|
2716
|
+
vsa \u2014 build and publish VisualAutomate plugins
|
|
2717
|
+
|
|
2718
|
+
vsa login sign this machine in
|
|
2719
|
+
vsa init <name> [--template] start a plugin
|
|
2720
|
+
vsa dev [<module>] the sandbox, and a run again on every save
|
|
2721
|
+
vsa test [<module>] run it once, as the platform's check does
|
|
2722
|
+
vsa push publish it
|
|
2723
|
+
vsa whoami which account this is
|
|
2724
|
+
vsa logout forget the token
|
|
2725
|
+
vsa --version this CLI's version
|
|
2660
2726
|
|
|
2661
|
-
|
|
2662
|
-
visualautomate init <name> [--template] start a plugin
|
|
2663
|
-
visualautomate test [--module <name>] run it here, as the platform's check does
|
|
2664
|
-
visualautomate dev [--module <name>] run it again on every save
|
|
2665
|
-
visualautomate --version this CLI's version
|
|
2666
|
-
visualautomate push publish it
|
|
2667
|
-
visualautomate whoami which account this is
|
|
2668
|
-
visualautomate logout forget the token
|
|
2727
|
+
\`va\` and \`visualautomate\` are the same command.
|
|
2669
2728
|
|
|
2670
2729
|
Templates: ${Object.keys(TEMPLATES).join(", ")}
|
|
2671
2730
|
|
|
2672
2731
|
\`test\` and \`dev\` work in a plugin made with \`init\`, at the root of a plugin's
|
|
2673
2732
|
GitHub repository, and at the root of an app's repository, where every folder
|
|
2674
|
-
in modules/ is run (or the one
|
|
2733
|
+
in modules/ is run (or the one you name: vsa dev send-message). The run's settings come
|
|
2675
2734
|
from visualautomate.test.json, test.json, or --input <file>.
|
|
2676
2735
|
|
|
2677
|
-
Options for \`
|
|
2678
|
-
--
|
|
2679
|
-
--tier <name>
|
|
2680
|
-
--image <ref>
|
|
2736
|
+
Options for \`dev\` and \`test\`:
|
|
2737
|
+
--module <name> the same as naming it: vsa dev send-message
|
|
2738
|
+
--tier <name> the sandbox's size: standard, boosted, high or max
|
|
2739
|
+
--image <ref> a different sandbox image
|
|
2681
2740
|
--persist keep storage and state in .visualautomate/ between runs
|
|
2741
|
+
--local \`dev\` without the sandbox, on this machine's Node
|
|
2742
|
+
--docker \`test\` inside the sandbox, as \`dev\` does
|
|
2682
2743
|
|
|
2683
2744
|
Environment (for CI, where there is no browser):
|
|
2684
2745
|
VISUALAUTOMATE_API_TOKEN use instead of \`login\`
|
|
@@ -2718,17 +2779,17 @@ async function main() {
|
|
|
2718
2779
|
case "new":
|
|
2719
2780
|
return cmdInit(args, flags);
|
|
2720
2781
|
case "test":
|
|
2721
|
-
return cmdTest(flags);
|
|
2782
|
+
return cmdTest(args, flags);
|
|
2722
2783
|
case "dev":
|
|
2723
2784
|
case "watch":
|
|
2724
|
-
return cmdDev(flags);
|
|
2785
|
+
return cmdDev(args, flags);
|
|
2725
2786
|
case "push":
|
|
2726
2787
|
case "publish":
|
|
2727
2788
|
return cmdPush(flags);
|
|
2728
2789
|
// `plugin test` and `plugin push` are accepted as aliases.
|
|
2729
2790
|
case "plugin": {
|
|
2730
2791
|
const sub = args.shift();
|
|
2731
|
-
if (sub === "test") return cmdTest(flags);
|
|
2792
|
+
if (sub === "test") return cmdTest(args, flags);
|
|
2732
2793
|
if (sub === "push") return cmdPush(flags);
|
|
2733
2794
|
printHelp();
|
|
2734
2795
|
return;
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visualautomate/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Build and publish VisualAutomate plugins.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"visualautomate": "
|
|
9
|
-
"va": "
|
|
8
|
+
"visualautomate": "dist/index.js",
|
|
9
|
+
"va": "dist/index.js",
|
|
10
|
+
"vsa": "dist/index.js"
|
|
10
11
|
},
|
|
11
12
|
"files": [
|
|
12
13
|
"dist",
|