@volter/world 3.0.40 → 3.0.42
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/src/cli.d.ts +1 -1
- package/dist/src/cli.js +28 -8
- package/package.json +5 -5
- package/src/cli.ts +24 -6
package/dist/src/cli.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export declare const HELP = "volter \u2014 run your app against a world of twins\n\nworld \u2014 the twins your app needs, running together (the world of the current directory)\n volter world init [--install] [--name <world>] [--allow-unknown] detect the app's vendors (installing their twins when none are), write .volter/world.json\n volter world up [--sandbox] [--no-seed] start the twins on this branch (loads the default data the first time)\n volter world run [--verbose] -- <command...> run the app or its tests inside the world\n volter world activate eval \"$(volter world activate)\": vendor CLIs and curl in this shell reach the twins\n volter world shell a subshell with the world active\n volter world init --bare <org>/<world> --twins a,b a world with no app: a shared world for a team, or one standing in for a vendor\n volter world serve [--port <p>] [--console-port <c>] [--origin <url>] serve this world on a URL under /<org>/<world>/ for apps; prints the token and the console (on loopback: view's front, no token in the browser)\n volter world view [--port <p>] [--host <h>] [--no-open] [--no-origins] [--origin <url>] step into this world in a browser: its twins' own UIs, timeline, clock, branches (a non-loopback --host serves them on one origin)\n volter world console [<https://host/org/world>] [--port <p>] the console on this machine for a World served elsewhere (default: this world's origin); needs @volter/world-console\n volter world status world, branch, origin, unpushed changes, what is running\n volter world log [--receipts] [--json] every write the app made; --receipts adds each change's receipt\n volter world diff [--json] what changed since the default data (or the last mark)\n volter world seed load the default data\n volter world reset back to the default data\n volter world down [--purge] stop the twins (--purge forgets this branch's state)\n volter world branch [<name>] list branches, or make one from here and check it out\n volter world checkout <name> switch branches\n volter world replay <changeset> --into <branch> feed a changeset's changes into another branch's twins\n volter world clock show | set <iso> | advance <N s|m|h|d> | shift <N s|m|h|d> | clear the world's clock: set, not observed\n volter world clone <url> --token <token> [--admin-token <t>] connect this world to a remote and fetch its history (the admin token copies the whole tree at once)\n volter world fetch what the remote observed since the last fetch\n volter world origin where this world clones from and pushes to\n volter world changeset [<name>] -m \"<message>\" cut the unpushed changes into a reviewable changeset\n volter world pull [--token <token>] fetch, then move this branch onto what came in (git's pull)\n volter world push [<name>] [--token <token>] [--force] push to the remote, which deploys and answers with receipts\n volter world rebase [<changeset>] rebase this branch onto its moved base, or a changeset onto the moved remote\n volter world verify <changeset> run the world's checks over a changeset and record the result\n volter world approve <changeset> --as <principal> sign a changeset's current hash\n volter world deploy [<changeset>] perform landed changes against each twin's root, by its policy\n\ntwin \u2014 one twin: in this world, or on its own\n volter twin <vendor> the twin's URL, root, deploy policy, whether a credential is sealed\n volter twin <vendor> root <url> [--deploy auto|gated|hold] [--scope <path>] the vendor's real account behind this twin (--none clears it)\n volter twin <vendor> credential seal a credential read from stdin beside the world; never readable back\n volter twin <vendor> refresh observe the root now\n volter twin <vendor> serve [--port <p>] [--read-only] serve the twin; your SDK talks to it at http://127.0.0.1:<p>\n\nagents \u2014 your coding agent, driving the same verbs\n volter agents install [--claude] [--cursor] [--vscode] [--codex] [--yes] put the volter-world skill and the MCP server into the agents found here\n volter mcp the MCP server (stdio) an agent starts: the verbs above as tools\n\nremote \u2014 the worlds this one pushes to and fetches from, by name\n volter login <platform url> [--token <personal token>] sign the CLI into the hosted platform: approve it in the browser (or a token made under Account, for CI)\n volter whoami the platform the CLI is signed into, as whom, and its orgs\n volter logout revoke the CLI's token at the platform and forget it here\n volter remote add <name> <url|path|org/world> [--token <token>] [--create] name a remote; org/world (or world, in one org) resolves through the platform you logged into; --create makes it there from this world's twins\n volter open [<org>/<world>] [--no-open] a World's dashboard: a hosted one through the platform, else this world's (as view)\n volter completion bash|zsh|fish|powershell print a completion script for your shell\n volter remote remove <name> forget it\n volter remote list every remote, with its URL and whether a token is stored\n (the hosting product's serve answers here for one release: volter remote serve)\n\n --world <dir> the world root, when the cwd is not inside it\n --branch <name> act on that branch instead of the checked-out one\n --json machine-readable output where offered\n --version the command's version\n";
|
|
2
|
+
export declare const HELP = "volter \u2014 run your app against a world of twins\n\nworld \u2014 the twins your app needs, running together (the world of the current directory)\n volter world init [--install] [--name <world>] [--allow-unknown] detect the app's vendors (installing their twins when none are), write .volter/world.json\n volter world up [--sandbox] [--no-seed] start the twins on this branch (loads the default data the first time)\n volter world run [--verbose] -- <command...> run the app or its tests inside the world\n volter world activate eval \"$(volter world activate)\": vendor CLIs and curl in this shell reach the twins\n volter world shell a subshell with the world active\n volter world init --bare <org>/<world> --twins a,b a world with no app: a shared world for a team, or one standing in for a vendor\n volter world serve [--port <p>] [--console-port <c>] [--origin <url>] serve this world on a URL under /<org>/<world>/ for apps; prints the token and the console (on loopback: view's front, no token in the browser)\n volter world view [--port <p>] [--host <h>] [--no-open] [--no-origins] [--origin <url>] step into this world in a browser: its twins' own UIs, timeline, clock, branches (a non-loopback --host serves them on one origin)\n volter world console [<https://host/org/world>] [--port <p>] the console on this machine for a World served elsewhere (default: this world's origin); needs @volter/world-console\n volter world status world, branch, origin, unpushed changes, what is running\n volter world log [--receipts] [--json] every write the app made; --receipts adds each change's receipt\n volter world diff [--json] what changed since the default data (or the last mark)\n volter world seed load the default data\n volter world reset back to the default data\n volter world down [--purge] stop the twins (--purge forgets this branch's state)\n volter world branch [<name>] list branches, or make one from here and check it out\n volter world checkout <name> switch branches\n volter world replay <changeset> --into <branch> feed a changeset's changes into another branch's twins\n volter world clock show | set <iso> | advance <N s|m|h|d> | shift <N s|m|h|d> | clear the world's clock: set, not observed\n volter world clone <url> --token <token> [--admin-token <t>] connect this world to a remote and fetch its history (the admin token copies the whole tree at once)\n volter world fetch what the remote observed since the last fetch\n volter world origin where this world clones from and pushes to\n volter world changeset [<name>] -m \"<message>\" cut the unpushed changes into a reviewable changeset\n volter world pull [--token <token>] fetch, then move this branch onto what came in (git's pull)\n volter world push [<name>] [--token <token>] [--force] push to the remote, which deploys and answers with receipts\n volter world rebase [<changeset>] rebase this branch onto its moved base, or a changeset onto the moved remote\n volter world verify <changeset> run the world's checks over a changeset and record the result\n volter world approve <changeset> --as <principal> sign a changeset's current hash\n volter world deploy [<changeset>] perform landed changes against each twin's root, by its policy\n\ntwin \u2014 one twin: in this world, or on its own\n volter twin submit --source <id> --vendor <vendor> --package <name> --version <exact> prepare a catalog submission\n volter twin <vendor> the twin's URL, root, deploy policy, whether a credential is sealed\n volter twin <vendor> root <url> [--deploy auto|gated|hold] [--scope <path>] the vendor's real account behind this twin (--none clears it)\n volter twin <vendor> credential seal a credential read from stdin beside the world; never readable back\n volter twin <vendor> refresh observe the root now\n volter twin <vendor> serve [--port <p>] [--read-only] serve the twin; your SDK talks to it at http://127.0.0.1:<p>\n\nagents \u2014 your coding agent, driving the same verbs\n volter agents install [--claude] [--cursor] [--vscode] [--codex] [--yes] put the volter-world skill and the MCP server into the agents found here\n volter mcp the MCP server (stdio) an agent starts: the verbs above as tools\n\nremote \u2014 the worlds this one pushes to and fetches from, by name\n volter login <platform url> [--token <personal token>] sign the CLI into the hosted platform: approve it in the browser (or a token made under Account, for CI)\n volter whoami the platform the CLI is signed into, as whom, and its orgs\n volter logout revoke the CLI's token at the platform and forget it here\n volter remote add <name> <url|path|org/world> [--token <token>] [--create] name a remote; org/world (or world, in one org) resolves through the platform you logged into; --create makes it there from this world's twins\n volter open [<org>/<world>] [--no-open] a World's dashboard: a hosted one through the platform, else this world's (as view)\n volter completion bash|zsh|fish|powershell print a completion script for your shell\n volter remote remove <name> forget it\n volter remote list every remote, with its URL and whether a token is stored\n (the hosting product's serve answers here for one release: volter remote serve)\n\n --world <dir> the world root, when the cwd is not inside it\n --branch <name> act on that branch instead of the checked-out one\n --json machine-readable output where offered\n --version the command's version\n";
|
package/dist/src/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// verb. `volter world …` acts on the world of the cwd the way git acts on the repository of the
|
|
4
4
|
// cwd; `volter twin <vendor> …` runs one twin on its own; `volter remote …` is the hosted remote.
|
|
5
5
|
// One client of `World`; it adds nothing the SDK does not have.
|
|
6
|
-
import { detectRepoVendors, errorMessage, formatInitReport, resolveCatalog, findInstalledPackage, packCli, serveConsoleFor } from '@volter/world-runtime';
|
|
6
|
+
import { detectRepoVendors, errorMessage, formatInitReport, resolveCatalog, findInstalledPackage, packCli, serveConsoleFor, catalogDefaults, CATALOG_INDEX_PACKAGE } from '@volter/world-runtime';
|
|
7
7
|
import { readFileSync, realpathSync } from 'node:fs';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { spawn, spawnSync } from 'node:child_process';
|
|
@@ -70,6 +70,7 @@ world — the twins your app needs, running together (the world of the current
|
|
|
70
70
|
volter world deploy [<changeset>] perform landed changes against each twin's root, by its policy
|
|
71
71
|
|
|
72
72
|
twin — one twin: in this world, or on its own
|
|
73
|
+
volter twin submit --source <id> --vendor <vendor> --package <name> --version <exact> prepare a catalog submission
|
|
73
74
|
volter twin <vendor> the twin's URL, root, deploy policy, whether a credential is sealed
|
|
74
75
|
volter twin <vendor> root <url> [--deploy auto|gated|hold] [--scope <path>] the vendor's real account behind this twin (--none clears it)
|
|
75
76
|
volter twin <vendor> credential seal a credential read from stdin beside the world; never readable back
|
|
@@ -595,6 +596,14 @@ async function worldCommand(verb, args) {
|
|
|
595
596
|
/** `volter twin <vendor> <verb…>`: the twin's own CLI (serve), found the way a world finds it. */
|
|
596
597
|
async function twinCommand(args) {
|
|
597
598
|
const [vendor, ...rest] = args;
|
|
599
|
+
if (vendor === 'submit') {
|
|
600
|
+
const catalog = findInstalledPackage(process.cwd(), CATALOG_INDEX_PACKAGE);
|
|
601
|
+
const cli = catalog && join(catalog, 'bin', 'twin-catalog.mjs');
|
|
602
|
+
if (!cli || !existsSync(cli))
|
|
603
|
+
throw new Error('Install @volter/twin-catalog to submit a twin; its catalog-owned CLI prepares the submission file.');
|
|
604
|
+
process.exitCode = await passthrough([process.execPath, cli, 'submit', ...rest]);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
598
607
|
if (!vendor || vendor.startsWith('-'))
|
|
599
608
|
throw new Error('volter twin: which twin? (volter twin stripe serve --port 12111)');
|
|
600
609
|
const verb = rest[0];
|
|
@@ -965,19 +974,30 @@ ${Object.entries(tree).map(([n, v]) => ` '${n}' = @(${v.map((x) => `'${x}'`).
|
|
|
965
974
|
* depends on and names in its env (the signatures ship with the command), and the twins for them are installed with
|
|
966
975
|
* the app's own package manager: asked at a terminal, or at once with `--install` (a script's or an agent's way). */
|
|
967
976
|
async function installDetectedTwins(app, install) {
|
|
977
|
+
let installed = new Set();
|
|
968
978
|
try {
|
|
969
|
-
|
|
970
|
-
|
|
979
|
+
installed = new Set(resolveCatalog(app).vendors());
|
|
980
|
+
}
|
|
981
|
+
catch (error) {
|
|
982
|
+
if (!(error instanceof Error) || !error.message.startsWith('No twins found for '))
|
|
983
|
+
throw error;
|
|
971
984
|
}
|
|
972
|
-
catch { /* no twins here yet */ }
|
|
973
985
|
const found = detectRepoVendors(app).detected;
|
|
974
|
-
const vendors = [...found.keys()].filter((v) => /^[a-z0-9][a-z0-9-]*$/.test(v)).sort();
|
|
986
|
+
const vendors = [...found.keys()].filter((v) => !installed.has(v) && /^[a-z0-9][a-z0-9-]*$/.test(v)).sort();
|
|
975
987
|
if (vendors.length === 0)
|
|
976
988
|
return; // init says what it found and how to add a twin by hand
|
|
977
|
-
const
|
|
989
|
+
const index = findInstalledPackage(app, CATALOG_INDEX_PACKAGE) ?? findInstalledPackage(fileURLToPath(new URL('.', import.meta.url)), CATALOG_INDEX_PACKAGE);
|
|
990
|
+
const recommended = index ? catalogDefaults(index, vendors) : undefined;
|
|
991
|
+
const pkgs = vendors.map((vendor) => {
|
|
992
|
+
const choice = recommended?.[vendor];
|
|
993
|
+
if (recommended && !choice)
|
|
994
|
+
throw new Error(`${vendor}: no approved stable default in the installed catalog; choose an implementation explicitly`);
|
|
995
|
+
return choice ? `${choice.name}@${choice.version}` : `@volter/twin-${vendor}`;
|
|
996
|
+
});
|
|
978
997
|
const has = (file) => existsSync(join(app, file));
|
|
979
998
|
// the app's own package manager, by its lockfile; npm where there is none
|
|
980
|
-
const
|
|
999
|
+
const invocation = has('bun.lock') || has('bun.lockb') ? ['bun', 'add', '-d'] : has('pnpm-lock.yaml') ? ['pnpm', 'add', '-D'] : has('yarn.lock') ? ['yarn', 'add', '-D'] : ['npm', 'install', '-D'];
|
|
1000
|
+
const command = [...invocation, ...pkgs].join(' ');
|
|
981
1001
|
out(`detected ${vendors.map((v) => `${v} (${(found.get(v) ?? []).slice(0, 2).join(', ')})`).join('; ')}`);
|
|
982
1002
|
out(`twins ${pkgs.join(' ')}`);
|
|
983
1003
|
let yes = install;
|
|
@@ -992,7 +1012,7 @@ async function installDetectedTwins(app, install) {
|
|
|
992
1012
|
then run volter world init again (or volter world init --install does both)`);
|
|
993
1013
|
// one command line built from the checked names above: nothing of anyone's input reaches the shell
|
|
994
1014
|
// a dependency's install script is not Volter's: it never sees the person's vault sign-in
|
|
995
|
-
const ran = spawnSync(
|
|
1015
|
+
const ran = spawnSync(invocation[0], [...invocation.slice(1), ...pkgs], { cwd: app, stdio: 'inherit', windowsHide: true, env: withoutVaultSignIn(process.env) });
|
|
996
1016
|
if (ran.status !== 0)
|
|
997
1017
|
throw new Error(`${command} failed (exit ${ran.status ?? 'none'})`);
|
|
998
1018
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.42",
|
|
4
4
|
"description": "Run your app against a world of twins. `World` and `Repo` — one method per verb: init, up, run, log, diff, reset, branch, checkout, clone, fetch, changeset, push — and the `volter` command, one client of them.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"volter",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.30.1",
|
|
33
|
-
"@volter/world-core": "3.0.
|
|
34
|
-
"@volter/world-runtime": "3.0.
|
|
33
|
+
"@volter/world-core": "3.0.42",
|
|
34
|
+
"@volter/world-runtime": "3.0.42",
|
|
35
35
|
"zod": "^4.6.5"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@volter/world-console": "3.0.
|
|
38
|
+
"@volter/world-console": "3.0.37"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
|
41
41
|
"@volter/world-console": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@volter/world-console": "3.0.
|
|
46
|
+
"@volter/world-console": "3.0.37"
|
|
47
47
|
},
|
|
48
48
|
"bin": {
|
|
49
49
|
"volter": "dist/src/cli.js"
|
package/src/cli.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// verb. `volter world …` acts on the world of the cwd the way git acts on the repository of the
|
|
4
4
|
// cwd; `volter twin <vendor> …` runs one twin on its own; `volter remote …` is the hosted remote.
|
|
5
5
|
// One client of `World`; it adds nothing the SDK does not have.
|
|
6
|
-
import { detectRepoVendors, errorMessage, formatInitReport, resolveCatalog, findInstalledPackage, packCli, serveConsoleFor } from '@volter/world-runtime';
|
|
6
|
+
import { detectRepoVendors, errorMessage, formatInitReport, resolveCatalog, findInstalledPackage, packCli, serveConsoleFor, catalogDefaults, CATALOG_INDEX_PACKAGE } from '@volter/world-runtime';
|
|
7
7
|
import { readFileSync, realpathSync } from 'node:fs';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { spawn, spawnSync } from 'node:child_process';
|
|
@@ -62,6 +62,7 @@ world — the twins your app needs, running together (the world of the current
|
|
|
62
62
|
volter world deploy [<changeset>] perform landed changes against each twin's root, by its policy
|
|
63
63
|
|
|
64
64
|
twin — one twin: in this world, or on its own
|
|
65
|
+
volter twin submit --source <id> --vendor <vendor> --package <name> --version <exact> prepare a catalog submission
|
|
65
66
|
volter twin <vendor> the twin's URL, root, deploy policy, whether a credential is sealed
|
|
66
67
|
volter twin <vendor> root <url> [--deploy auto|gated|hold] [--scope <path>] the vendor's real account behind this twin (--none clears it)
|
|
67
68
|
volter twin <vendor> credential seal a credential read from stdin beside the world; never readable back
|
|
@@ -429,6 +430,13 @@ async function worldCommand(verb: string, args: string[]): Promise<void> {
|
|
|
429
430
|
/** `volter twin <vendor> <verb…>`: the twin's own CLI (serve), found the way a world finds it. */
|
|
430
431
|
async function twinCommand(args: string[]): Promise<void> {
|
|
431
432
|
const [vendor, ...rest] = args;
|
|
433
|
+
if (vendor === 'submit') {
|
|
434
|
+
const catalog = findInstalledPackage(process.cwd(), CATALOG_INDEX_PACKAGE);
|
|
435
|
+
const cli = catalog && join(catalog, 'bin', 'twin-catalog.mjs');
|
|
436
|
+
if (!cli || !existsSync(cli)) throw new Error('Install @volter/twin-catalog to submit a twin; its catalog-owned CLI prepares the submission file.');
|
|
437
|
+
process.exitCode = await passthrough([process.execPath, cli, 'submit', ...rest]);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
432
440
|
if (!vendor || vendor.startsWith('-')) throw new Error('volter twin: which twin? (volter twin stripe serve --port 12111)');
|
|
433
441
|
const verb = rest[0];
|
|
434
442
|
// the twin IN THIS WORLD: its root, its credential, a refresh, its status
|
|
@@ -703,14 +711,24 @@ ${Object.entries(tree).map(([n, v]) => ` '${n}' = @(${v.map((x) => `'${x}'`).
|
|
|
703
711
|
* depends on and names in its env (the signatures ship with the command), and the twins for them are installed with
|
|
704
712
|
* the app's own package manager: asked at a terminal, or at once with `--install` (a script's or an agent's way). */
|
|
705
713
|
async function installDetectedTwins(app: string, install: boolean): Promise<void> {
|
|
706
|
-
|
|
714
|
+
let installed = new Set<string>();
|
|
715
|
+
try { installed = new Set(resolveCatalog(app).vendors()); } catch (error) {
|
|
716
|
+
if (!(error instanceof Error) || !error.message.startsWith('No twins found for ')) throw error;
|
|
717
|
+
}
|
|
707
718
|
const found = detectRepoVendors(app).detected;
|
|
708
|
-
const vendors = [...found.keys()].filter((v) => /^[a-z0-9][a-z0-9-]*$/.test(v)).sort();
|
|
719
|
+
const vendors = [...found.keys()].filter((v) => !installed.has(v) && /^[a-z0-9][a-z0-9-]*$/.test(v)).sort();
|
|
709
720
|
if (vendors.length === 0) return; // init says what it found and how to add a twin by hand
|
|
710
|
-
const
|
|
721
|
+
const index = findInstalledPackage(app, CATALOG_INDEX_PACKAGE) ?? findInstalledPackage(fileURLToPath(new URL('.', import.meta.url)), CATALOG_INDEX_PACKAGE);
|
|
722
|
+
const recommended = index ? catalogDefaults(index, vendors) : undefined;
|
|
723
|
+
const pkgs = vendors.map((vendor) => {
|
|
724
|
+
const choice = recommended?.[vendor];
|
|
725
|
+
if (recommended && !choice) throw new Error(`${vendor}: no approved stable default in the installed catalog; choose an implementation explicitly`);
|
|
726
|
+
return choice ? `${choice.name}@${choice.version}` : `@volter/twin-${vendor}`;
|
|
727
|
+
});
|
|
711
728
|
const has = (file: string): boolean => existsSync(join(app, file));
|
|
712
729
|
// the app's own package manager, by its lockfile; npm where there is none
|
|
713
|
-
const
|
|
730
|
+
const invocation = has('bun.lock') || has('bun.lockb') ? ['bun', 'add', '-d'] : has('pnpm-lock.yaml') ? ['pnpm', 'add', '-D'] : has('yarn.lock') ? ['yarn', 'add', '-D'] : ['npm', 'install', '-D'];
|
|
731
|
+
const command = [...invocation, ...pkgs].join(' ');
|
|
714
732
|
out(`detected ${vendors.map((v) => `${v} (${(found.get(v) ?? []).slice(0, 2).join(', ')})`).join('; ')}`);
|
|
715
733
|
out(`twins ${pkgs.join(' ')}`);
|
|
716
734
|
let yes = install;
|
|
@@ -724,7 +742,7 @@ async function installDetectedTwins(app: string, install: boolean): Promise<void
|
|
|
724
742
|
then run volter world init again (or volter world init --install does both)`);
|
|
725
743
|
// one command line built from the checked names above: nothing of anyone's input reaches the shell
|
|
726
744
|
// a dependency's install script is not Volter's: it never sees the person's vault sign-in
|
|
727
|
-
const ran = spawnSync(
|
|
745
|
+
const ran = spawnSync(invocation[0]!, [...invocation.slice(1), ...pkgs], { cwd: app, stdio: 'inherit', windowsHide: true, env: withoutVaultSignIn(process.env) });
|
|
728
746
|
if (ran.status !== 0) throw new Error(`${command} failed (exit ${ran.status ?? 'none'})`);
|
|
729
747
|
}
|
|
730
748
|
|