@volter/world-runtime 2.0.54 → 3.0.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/dist/known-external-services.json +5 -4
- package/dist/src/actions-runner-cli.d.ts +2 -0
- package/dist/src/actions-runner-cli.js +25 -0
- package/dist/src/actions-runner.d.ts +18 -0
- package/dist/src/actions-runner.js +281 -0
- package/dist/src/ancestry.js +1 -1
- package/dist/src/app-url.js +1 -1
- package/dist/src/backings.d.ts +29 -0
- package/dist/src/backings.js +45 -0
- package/dist/src/branch.js +3 -2
- package/dist/src/browser-proxy-cli.js +1 -1
- package/dist/src/catalog-index.d.ts +38 -0
- package/dist/src/catalog-index.js +37 -0
- package/dist/src/catalog.d.ts +16 -3
- package/dist/src/catalog.js +69 -26
- package/dist/src/changeset.d.ts +1 -1
- package/dist/src/changeset.js +9 -11
- package/dist/src/cli-args.d.ts +4 -0
- package/dist/src/cli-args.js +18 -0
- package/dist/src/cli-commands.d.ts +1 -0
- package/dist/src/cli-commands.js +1216 -0
- package/dist/src/cli.js +8 -1300
- package/dist/src/configs.js +1 -1
- package/dist/src/console-apart.d.ts +2 -2
- package/dist/src/console-apart.js +5 -5
- package/dist/src/consumers.js +1 -1
- package/dist/src/covers.d.ts +1 -1
- package/dist/src/covers.js +94 -30
- package/dist/src/env-output.d.ts +1 -1
- package/dist/src/env-output.js +2 -2
- package/dist/src/fixture-env.js +18 -26
- package/dist/src/host-cli.js +4 -2
- package/dist/src/host-fault-fixture.js +6 -0
- package/dist/src/host-ready.d.ts +8 -2
- package/dist/src/host-ready.js +16 -4
- package/dist/src/host-worker.js +6 -1
- package/dist/src/host.d.ts +2 -0
- package/dist/src/host.js +9 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +2 -2
- package/dist/src/init.d.ts +33 -23
- package/dist/src/init.js +228 -96
- package/dist/src/lifecycle-record.js +2 -2
- package/dist/src/local-branches.js +1 -1
- package/dist/src/origin.d.ts +1 -1
- package/dist/src/origin.js +12 -10
- package/dist/src/pack-facts.d.ts +30 -6
- package/dist/src/pack-facts.js +13 -3
- package/dist/src/pglite-backing.js +2 -1
- package/dist/src/placeholder.d.ts +1 -1
- package/dist/src/placeholder.js +12 -4
- package/dist/src/project-inspect.d.ts +1 -1
- package/dist/src/project-inspect.js +2 -2
- package/dist/src/redirect-proxy.d.ts +5 -0
- package/dist/src/redirect-proxy.js +8 -1
- package/dist/src/redis-backing.js +4 -2
- package/dist/src/reflect.js +1 -1
- package/dist/src/root.d.ts +11 -33
- package/dist/src/root.js +28 -59
- package/dist/src/runtime-test-support.js +1 -1
- package/dist/src/runtime.d.ts +7 -1
- package/dist/src/runtime.js +317 -53
- package/dist/src/schema.d.ts +27 -5
- package/dist/src/schema.js +13 -12
- package/dist/src/served-world.d.ts +11 -35
- package/dist/src/served-world.js +54 -141
- package/dist/src/tail.js +1 -1
- package/dist/src/up-cli.d.ts +3 -0
- package/dist/src/up-cli.js +55 -0
- package/dist/src/websocket-relay.d.ts +1 -1
- package/dist/src/world-origins.d.ts +1 -1
- package/dist/src/world-origins.js +1 -1
- package/dist/src/world-view.d.ts +1 -1
- package/dist/src/world-view.js +2 -2
- package/known-external-services.json +5 -4
- package/package.json +11 -11
- package/src/actions-runner-cli.ts +24 -0
- package/src/actions-runner.ts +244 -0
- package/src/ancestry.ts +1 -1
- package/src/app-url.ts +1 -1
- package/src/backings.ts +55 -0
- package/src/branch.ts +3 -2
- package/src/browser-proxy-cli.ts +1 -1
- package/src/catalog-index.ts +44 -0
- package/src/catalog.ts +67 -24
- package/src/changeset.ts +10 -13
- package/src/cli-args.ts +17 -0
- package/src/cli-commands.ts +1070 -0
- package/src/cli.ts +9 -1139
- package/src/configs.ts +1 -1
- package/src/console-apart.ts +5 -5
- package/src/consumers.ts +1 -1
- package/src/covers.ts +83 -30
- package/src/env-output.ts +2 -2
- package/src/fixture-env.ts +18 -26
- package/src/host-cli.ts +4 -2
- package/src/host-ready.ts +13 -4
- package/src/host-worker.ts +6 -2
- package/src/host.ts +11 -2
- package/src/index.ts +2 -2
- package/src/init.ts +222 -101
- package/src/lifecycle-record.ts +2 -2
- package/src/local-branches.ts +1 -1
- package/src/origin.ts +12 -10
- package/src/pack-facts.ts +22 -6
- package/src/pglite-backing.ts +2 -1
- package/src/placeholder.ts +13 -4
- package/src/project-inspect.ts +2 -2
- package/src/redirect-proxy.ts +9 -1
- package/src/redis-backing.ts +4 -2
- package/src/reflect.ts +1 -1
- package/src/root.ts +33 -65
- package/src/runtime-test-support.ts +1 -1
- package/src/runtime.ts +261 -55
- package/src/schema.ts +26 -13
- package/src/served-world.ts +50 -130
- package/src/tail.ts +1 -1
- package/src/up-cli.ts +55 -0
- package/src/websocket-relay.ts +1 -1
- package/src/world-origins.ts +1 -1
- package/src/world-view.ts +3 -3
package/dist/src/catalog.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
// The catalog — where the twins a world can run come from (docs/concepts/worlds.md
|
|
2
|
-
// #the-config-and-the-running-world). Two sources answer one interface:
|
|
3
|
-
//
|
|
2
|
+
// #the-config-and-the-running-world). Two sources answer one interface: a pack-repository CHECKOUT and an
|
|
3
|
+
// INSTALLED catalog (`@volter/twin-<vendor>` packages under
|
|
4
4
|
// `node_modules`, walked up from the world root — hoisting-proof, and independent of the
|
|
5
5
|
// packages' `exports` maps, which do not expose `package.json`). A world born in an app repo
|
|
6
6
|
// names its twins as packages and the runtime resolves them at boot; a world born here names the
|
|
7
|
-
// checkout
|
|
7
|
+
// selected checkout paths.
|
|
8
8
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
9
9
|
import { spawnSync } from 'node:child_process';
|
|
10
10
|
import { dirname, join, resolve } from 'node:path';
|
|
11
|
+
import { overlayPackFacts } from "./pack-facts.js";
|
|
12
|
+
import { installedPackageDir, isDerivedPack, packRepository } from '@volter/world-core/runtime';
|
|
11
13
|
export const TWIN_PACKAGE_PREFIX = '@volter/twin-';
|
|
12
|
-
/** Packages under the `@volter/twin-` prefix that are NOT twins. */
|
|
13
14
|
export function twinPackageName(vendor) { return `${TWIN_PACKAGE_PREFIX}${vendor}`; }
|
|
15
|
+
/** A derived (Protocol 3) pack carries the surface derive-pack generated from its spec. */
|
|
16
|
+
const major = (version) => Number(/^(\d+)/.exec(version ?? '')?.[1] ?? 0);
|
|
14
17
|
function packageVersion(dir) {
|
|
15
18
|
const p = join(dir, 'package.json');
|
|
16
19
|
if (!existsSync(p))
|
|
@@ -23,7 +26,8 @@ function packageVersion(dir) {
|
|
|
23
26
|
return undefined;
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
|
-
|
|
29
|
+
/** A twin a catalog lists: a derived pack with its CLI. */
|
|
30
|
+
function isPackDir(dir) { return packCli(dir) !== undefined && isDerivedPack(dir); }
|
|
27
31
|
function manifest(dir) { const p = join(dir, 'package.json'); if (!existsSync(p))
|
|
28
32
|
return undefined; try {
|
|
29
33
|
return JSON.parse(readFileSync(p, 'utf8'));
|
|
@@ -51,18 +55,7 @@ export function packCli(dir) {
|
|
|
51
55
|
return existsSync(join(dir, 'src', 'cli.ts')) ? join(dir, 'src', 'cli.ts') : undefined;
|
|
52
56
|
}
|
|
53
57
|
/** The nearest `node_modules/<name>` above `from` that holds a package.json — node's own walk. */
|
|
54
|
-
export
|
|
55
|
-
let dir = resolve(from);
|
|
56
|
-
for (;;) {
|
|
57
|
-
const candidate = join(dir, 'node_modules', ...name.split('/'));
|
|
58
|
-
if (existsSync(join(candidate, 'package.json')))
|
|
59
|
-
return candidate;
|
|
60
|
-
const up = dirname(dir);
|
|
61
|
-
if (up === dir)
|
|
62
|
-
return undefined;
|
|
63
|
-
dir = up;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
58
|
+
export const findInstalledPackage = installedPackageDir;
|
|
66
59
|
/** Every installed `@volter/twin-<vendor>` visible from `from`, nearest wins. */
|
|
67
60
|
function installedTwins(from) {
|
|
68
61
|
const found = new Map();
|
|
@@ -74,6 +67,8 @@ function installedTwins(from) {
|
|
|
74
67
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
75
68
|
continue;
|
|
76
69
|
const name = `@volter/${entry.name}`;
|
|
70
|
+
if (name === '@volter/twin-standard')
|
|
71
|
+
continue; // the platform's standard is tooling, not a vendor pack
|
|
77
72
|
if (!name.startsWith(TWIN_PACKAGE_PREFIX))
|
|
78
73
|
continue; // the platform's packages are `@volter/world-*`: outside the prefix by name
|
|
79
74
|
const vendor = name.slice(TWIN_PACKAGE_PREFIX.length);
|
|
@@ -98,17 +93,18 @@ function fnv1a(text) {
|
|
|
98
93
|
return h.toString(16).padStart(8, '0');
|
|
99
94
|
}
|
|
100
95
|
export function checkoutCatalog(root) {
|
|
101
|
-
const packsDir = resolve(root
|
|
96
|
+
const packsDir = resolve(root);
|
|
102
97
|
const vendors = () => readdirSync(packsDir, { withFileTypes: true })
|
|
103
|
-
.filter((entry) => entry.isDirectory() && isPackDir(join(packsDir, entry.name)))
|
|
98
|
+
.filter((entry) => (entry.isDirectory() || entry.isSymbolicLink()) && manifest(join(packsDir, entry.name))?.name === twinPackageName(entry.name) && isPackDir(join(packsDir, entry.name)))
|
|
104
99
|
.map((entry) => entry.name)
|
|
105
100
|
.sort();
|
|
106
101
|
return {
|
|
107
102
|
kind: 'checkout',
|
|
108
103
|
root: resolve(root),
|
|
109
104
|
vendors,
|
|
110
|
-
packDir: (vendor) => (isPackDir(join(packsDir, vendor)) ? join(packsDir, vendor) : undefined),
|
|
105
|
+
packDir: (vendor) => (/^[a-z][a-z0-9-]*$/.test(vendor) && manifest(join(packsDir, vendor))?.name === twinPackageName(vendor) && isPackDir(join(packsDir, vendor)) ? join(packsDir, vendor) : undefined),
|
|
111
106
|
version: (vendor) => packageVersion(join(packsDir, vendor)),
|
|
107
|
+
kindOf: () => 'checkout',
|
|
112
108
|
sha: () => {
|
|
113
109
|
const proc = spawnSync('git', ['-C', root, 'rev-parse', 'HEAD'], { windowsHide: true, encoding: 'utf8' });
|
|
114
110
|
const sha = proc.status === 0 ? proc.stdout.trim() : '';
|
|
@@ -124,20 +120,67 @@ export function installedCatalog(root) {
|
|
|
124
120
|
vendors: () => [...twins.keys()].sort(),
|
|
125
121
|
packDir: (vendor) => twins.get(vendor),
|
|
126
122
|
version: (vendor) => { const dir = twins.get(vendor); return dir === undefined ? undefined : packageVersion(dir); },
|
|
123
|
+
kindOf: () => 'installed',
|
|
127
124
|
sha: () => `installed-${fnv1a([...twins.keys()].sort().map((v) => `${v}@${packageVersion(twins.get(v)) ?? '?'}`).join(','))}`,
|
|
128
125
|
};
|
|
129
126
|
}
|
|
130
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* One catalog over several sources (docs/contributing/architecture.md, "The catalog: where twins come from"): each
|
|
129
|
+
* vendor is served by the pack of the higher major; on a tie the earlier source keeps it. `kind` is the first source's.
|
|
130
|
+
*/
|
|
131
|
+
export function mergedCatalog(sources) {
|
|
132
|
+
const chosen = new Map();
|
|
133
|
+
for (const source of sources) {
|
|
134
|
+
for (const vendor of source.vendors()) {
|
|
135
|
+
const held = chosen.get(vendor);
|
|
136
|
+
if (held === undefined) {
|
|
137
|
+
chosen.set(vendor, source);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (major(source.version(vendor)) > major(held.version(vendor)))
|
|
141
|
+
chosen.set(vendor, source);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const of = (vendor) => chosen.get(vendor);
|
|
145
|
+
return {
|
|
146
|
+
kind: sources[0].kind,
|
|
147
|
+
root: sources[0].root,
|
|
148
|
+
vendors: () => [...chosen.keys()].sort(),
|
|
149
|
+
packDir: (vendor) => of(vendor)?.packDir(vendor),
|
|
150
|
+
version: (vendor) => of(vendor)?.version(vendor),
|
|
151
|
+
kindOf: (vendor) => of(vendor)?.kindOf(vendor) ?? sources[0].kind,
|
|
152
|
+
sha: () => sources.map((s) => s.sha()).join('+'),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/** Overlays one facts file on the kernel's (a file that does not read is skipped: the kernel's facts stand). */
|
|
156
|
+
export function overlayPackFactsFile(file) {
|
|
157
|
+
try {
|
|
158
|
+
overlayPackFacts(JSON.parse(readFileSync(file, 'utf8')).packs ?? {});
|
|
159
|
+
}
|
|
160
|
+
catch { /* the kernel's facts stand */ }
|
|
161
|
+
}
|
|
162
|
+
/** The facts file a released pack carries (`generated/pack-facts.json`, written by pack-release), when it has one. */
|
|
163
|
+
export function packFactsFile(dir) {
|
|
164
|
+
const file = join(dir, 'generated', 'pack-facts.json');
|
|
165
|
+
return existsSync(file) ? file : undefined;
|
|
166
|
+
}
|
|
167
|
+
/** The catalog for a World root: its pack repository (or the one beside its platform checkout), merged with installed
|
|
168
|
+
* packages. Only the selected packs' own facts are overlaid on the kernel's. */
|
|
131
169
|
export function resolveCatalog(root) {
|
|
132
170
|
const resolved = resolve(root);
|
|
133
|
-
if (existsSync(join(resolved, 'packages', 'twin')))
|
|
134
|
-
return checkoutCatalog(resolved);
|
|
135
171
|
const installed = installedCatalog(resolved);
|
|
136
|
-
|
|
137
|
-
|
|
172
|
+
const repo = packRepository(resolved);
|
|
173
|
+
const catalog = repo === undefined ? installed : mergedCatalog([checkoutCatalog(repo), installed]);
|
|
174
|
+
for (const vendor of catalog.vendors()) {
|
|
175
|
+
const file = packFactsFile(catalog.packDir(vendor));
|
|
176
|
+
if (file)
|
|
177
|
+
overlayPackFactsFile(file);
|
|
178
|
+
}
|
|
179
|
+
if (catalog.vendors().length === 0) {
|
|
180
|
+
throw new Error(`No twins found for ${resolved}: no pack repository and no \`@volter/twin-<vendor>\` package installed above it. `
|
|
138
181
|
+ `Install the twins your app needs (e.g. \`bun add -d @volter/twin-stripe\`) and run init again.`);
|
|
139
182
|
}
|
|
140
|
-
return
|
|
183
|
+
return catalog;
|
|
141
184
|
}
|
|
142
185
|
/** The pack directory a service boots from: its `package` resolved from the world root at boot. */
|
|
143
186
|
export function resolveServicePackage(root, pkg) {
|
package/dist/src/changeset.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChangesetApplication, RebaseReport, Changeset, ChangesetApproval, ChangesetReadiness, ChangesetVerification, ChangesetVerifier, LedgerDelta, LedgerRef, ReplayReport, WorldMarker } from '@volter/world-core';
|
|
1
|
+
import type { ChangesetApplication, RebaseReport, Changeset, ChangesetApproval, ChangesetReadiness, ChangesetVerification, ChangesetVerifier, LedgerDelta, LedgerRef, ReplayReport, WorldMarker } from '@volter/world-core/runtime';
|
|
2
2
|
export type WorldRootOptions = {
|
|
3
3
|
root?: string;
|
|
4
4
|
};
|
package/dist/src/changeset.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { worldChangesetRules } from "./configs.js";
|
|
2
|
-
import { blobDigest, captureHistory, captureParentHistory, getActiveBlobStore, getActiveWorldStore,
|
|
2
|
+
import { blobDigest, captureHistory, captureParentHistory, getActiveBlobStore, getActiveWorldStore, withHistoryLocks, worldPaths } from '@volter/world-core/runtime';
|
|
3
3
|
// `volter-world mark` / `diff` / `changeset` — the WORLD-side verbs over the changeset
|
|
4
4
|
// primitive (docs/concepts/the-model.md v0). Thin, exactly like `covers` and `tail` are thin: all
|
|
5
5
|
// the state logic (markers, deltas, content hashing, replay) lives in @volter/world-core's
|
|
@@ -24,12 +24,12 @@ import { blobDigest, captureHistory, captureParentHistory, getActiveBlobStore, g
|
|
|
24
24
|
// here that WRITES, and it writes only through the control plane's kernel write path.
|
|
25
25
|
import { tmpdir } from 'node:os';
|
|
26
26
|
import { join, relative, resolve } from 'node:path';
|
|
27
|
-
import { approveChangeset, rebaseChangeset, buildChangeset, captureMarker, changesetHashMatches, changesetReadiness, diffLedgers, normalizeChangeset, replayChangeset, runChangesetVerifiers, stateDirName, withApplication, withVerification, worldBootMarker, assertSafeChangesetName, assertMarkerBelongsTo, CHANGESET_KIND, MARKER_KIND, WORLD_BOOT_MARKER_ID, } from '@volter/world-core';
|
|
27
|
+
import { approveChangeset, rebaseChangeset, buildChangeset, captureMarker, changesetHashMatches, changesetReadiness, diffLedgers, normalizeChangeset, replayChangeset, runChangesetVerifiers, stateDirName, withApplication, withVerification, worldBootMarker, assertSafeChangesetName, assertMarkerBelongsTo, CHANGESET_KIND, MARKER_KIND, WORLD_BOOT_MARKER_ID, } from '@volter/world-core/runtime';
|
|
28
28
|
import { instanceDir, listWorlds, statusWorld } from "./runtime.js";
|
|
29
29
|
import { fetchFromOrigin } from "./origin.js";
|
|
30
30
|
import { fetchReady, isPathRemote, landChangeset, landReceipts, localWorld, TOKEN_HEADER } from "./served-world.js";
|
|
31
31
|
import { loadWorldChecks } from "./root.js";
|
|
32
|
-
import { readBranchMeta, readTree, rebaseBranch, runChecks, wholeLog, writeBranchMeta } from '@volter/world-core';
|
|
32
|
+
import { readBranchMeta, readTree, rebaseBranch, runChecks, wholeLog, writeBranchMeta } from '@volter/world-core/runtime';
|
|
33
33
|
function resolveRoot(root) {
|
|
34
34
|
return resolve(root ?? process.cwd());
|
|
35
35
|
}
|
|
@@ -44,7 +44,7 @@ function requireWorld(name, root) {
|
|
|
44
44
|
if (!/World instance not found/.test(String(error.message)))
|
|
45
45
|
throw error;
|
|
46
46
|
const known = listWorlds(root).map((world) => world.name);
|
|
47
|
-
throw new Error(`World "${name}" not found in ${root}${known.length ? ` (known worlds: ${known.join(', ')})` : ' (no worlds here)'} —
|
|
47
|
+
throw new Error(`World "${name}" not found in ${root}${known.length ? ` (known worlds: ${known.join(', ')})` : ' (no worlds here)'} — start it with \`volter world up\` in the app's folder (the operator's own: \`volter-world up <config> --env-out <path> --name ${name}\`)`);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
/** Every state service a world service currently records actions under (often exactly one). */
|
|
@@ -166,7 +166,7 @@ export function createWorldChangeset(world, name, options = {}) {
|
|
|
166
166
|
// re-cutting an existing name (overwrite) starts from that changeset's own base, not from its cut
|
|
167
167
|
const base = options.base ?? (getActiveWorldStore().exists(path) ? readChangesetFile(path).base : undefined);
|
|
168
168
|
const delta = diffWorld(world, { root, ...(base === undefined ? {} : { base }) });
|
|
169
|
-
// where the parent log stands for each twin the changeset touches (
|
|
169
|
+
// where the parent log stands for each twin the changeset touches (the cut position a rebase reads from)
|
|
170
170
|
const cutInstance = requireWorld(world, root);
|
|
171
171
|
const cut = {};
|
|
172
172
|
for (const a of delta.actions)
|
|
@@ -555,13 +555,11 @@ export function rebaseWorldChangeset(name, options = {}) {
|
|
|
555
555
|
const root = resolveRoot(options.root);
|
|
556
556
|
const located = findWorldChangeset(name, { root, ...(options.world ? { world: options.world } : {}) });
|
|
557
557
|
// the branch first: its pointer moves to the parent's current position (what a fetch brought in)
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const controlRoot = join(inst.dirs.data, service);
|
|
558
|
+
const inst = requireWorld(located.world, root);
|
|
559
|
+
const moved = [...new Set(located.changeset.actions.map((e) => e.service))].map((service) => ({ st: located.changeset.actions.find((e) => e.service === service)?.stateService ?? service, controlRoot: join(inst.dirs.data, service) }));
|
|
560
|
+
withHistoryLocks(moved.map(({ st, controlRoot }) => worldPaths(st, controlRoot).dir), () => {
|
|
561
|
+
for (const { st, controlRoot } of moved)
|
|
563
562
|
rebaseBranch(st, controlRoot, { origin: Boolean(readBranchMeta(st, controlRoot)?.origin) });
|
|
564
|
-
}
|
|
565
563
|
});
|
|
566
564
|
if (!changesetHashMatches(located.changeset))
|
|
567
565
|
throw new Error(`Refusing to rebase changeset "${name}": its stored contentHash does not match its body — the object drifted after authoring`);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The command line's option readers, shared by `up` (./up-cli.ts) and every other command (./cli-commands.ts). */
|
|
2
|
+
/** An option's value, written `--name value` or `--name=value`. */
|
|
3
|
+
export declare function optionValue(args: string[], name: string, fallback?: string): string;
|
|
4
|
+
export declare function ownerOption(args: string[]): string | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The command line's option readers, shared by `up` (./up-cli.ts) and every other command (./cli-commands.ts). */
|
|
2
|
+
/** An option's value, written `--name value` or `--name=value`. */
|
|
3
|
+
export function optionValue(args, name, fallback = '') {
|
|
4
|
+
const joined = args.find((arg) => arg.startsWith(`${name}=`));
|
|
5
|
+
if (joined !== undefined)
|
|
6
|
+
return joined.slice(name.length + 1);
|
|
7
|
+
const index = args.indexOf(name);
|
|
8
|
+
return index >= 0 && index + 1 < args.length ? args[index + 1] : fallback;
|
|
9
|
+
}
|
|
10
|
+
export function ownerOption(args) {
|
|
11
|
+
const index = args.indexOf('--owner');
|
|
12
|
+
if (index < 0)
|
|
13
|
+
return undefined;
|
|
14
|
+
const label = args[index + 1];
|
|
15
|
+
if (!label || label.startsWith('--'))
|
|
16
|
+
throw new Error('--owner requires a task label');
|
|
17
|
+
return label;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function main(): Promise<void>;
|