@bitmagic/cli 0.1.53-dev.4 → 0.1.53-dev.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +88 -18
  2. package/dist/cli.d.ts +10 -0
  3. package/dist/cli.js +2 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/publish.d.ts +7 -2
  6. package/dist/commands/publish.js +39 -7
  7. package/dist/commands/publish.js.map +1 -1
  8. package/dist/commands/reset-account.js +25 -8
  9. package/dist/commands/reset-account.js.map +1 -1
  10. package/dist/commands/self-update.d.ts +67 -0
  11. package/dist/commands/self-update.js +196 -0
  12. package/dist/commands/self-update.js.map +1 -0
  13. package/dist/commands/upgrade.js +5 -2
  14. package/dist/commands/upgrade.js.map +1 -1
  15. package/dist/editor/cli-update.d.ts +32 -0
  16. package/dist/editor/cli-update.js +67 -0
  17. package/dist/editor/cli-update.js.map +1 -0
  18. package/dist/editor/publish-panel.d.ts +31 -0
  19. package/dist/editor/publish-panel.js +69 -0
  20. package/dist/editor/publish-panel.js.map +1 -0
  21. package/dist/editor/server.js +38 -0
  22. package/dist/editor/server.js.map +1 -1
  23. package/dist/editor/shell-page.js +112 -3
  24. package/dist/editor/shell-page.js.map +1 -1
  25. package/dist/publish/record.d.ts +22 -0
  26. package/dist/publish/record.js +62 -0
  27. package/dist/publish/record.js.map +1 -0
  28. package/dist/render/qr-output.d.ts +44 -0
  29. package/dist/render/qr-output.js +71 -0
  30. package/dist/render/qr-output.js.map +1 -0
  31. package/dist/render/qr-png.d.ts +37 -0
  32. package/dist/render/qr-png.js +111 -0
  33. package/dist/render/qr-png.js.map +1 -0
  34. package/dist/render/qr-terminal.d.ts +8 -1
  35. package/dist/render/qr-terminal.js +8 -1
  36. package/dist/render/qr-terminal.js.map +1 -1
  37. package/dist/scaffold/project-files.js +36 -27
  38. package/dist/scaffold/project-files.js.map +1 -1
  39. package/dist/update/check.js +2 -1
  40. package/dist/update/check.js.map +1 -1
  41. package/dist/update/notice.d.ts +31 -1
  42. package/dist/update/notice.js +39 -5
  43. package/dist/update/notice.js.map +1 -1
  44. package/dist/update/self-install.d.ts +175 -0
  45. package/dist/update/self-install.js +335 -0
  46. package/dist/update/self-install.js.map +1 -0
  47. package/package.json +4 -4
@@ -0,0 +1,175 @@
1
+ /** The npm package this CLI is published as. */
2
+ export declare const PACKAGE_NAME = "@bitmagic/cli";
3
+ /** Does this path exist? Injected so classification is testable without a filesystem. */
4
+ export type Exists = (candidate: string) => boolean;
5
+ /**
6
+ * Where the running build lives, and what may be done about it.
7
+ *
8
+ * A discriminated union rather than one shape with optional fields, because the difference that
9
+ * matters is precisely "is there an install to act on": the three inert kinds have no prefix, no
10
+ * bin directory and no reinstall, and a caller that forgets to check would otherwise be handed
11
+ * `undefined` to pass to a package manager.
12
+ *
13
+ * `verifyDir` is deliberately separate from `packageDir`. They are the same directory for npm,
14
+ * but pnpm writes each version into its own store directory and moves a symlink — so the path
15
+ * that holds the NEW version after an update is the link, not the resolved directory this process
16
+ * is executing out of. Reading the wrong one would report every successful pnpm update as a
17
+ * failure.
18
+ */
19
+ export type InstallLocation = {
20
+ kind: 'npm-global';
21
+ /** The resolved @bitmagic/cli directory. */
22
+ packageDir: string;
23
+ /** Read back after an update to confirm the version actually moved. */
24
+ verifyDir: string;
25
+ /** The node_modules that must be writable for an install to succeed. */
26
+ modulesRoot: string;
27
+ /** npm's `--prefix`. */
28
+ prefix: string;
29
+ } | {
30
+ kind: 'pnpm-global';
31
+ packageDir: string;
32
+ verifyDir: string;
33
+ modulesRoot: string;
34
+ /** pnpm's `--global-dir`. */
35
+ globalDir: string;
36
+ /** pnpm's `--global-bin-dir`, or undefined when it could not be proven. */
37
+ binDir: string | undefined;
38
+ }
39
+ /** Run through `npx`: nothing is installed, so there is nothing to update. */
40
+ | {
41
+ kind: 'npx';
42
+ packageDir: string;
43
+ }
44
+ /** A checkout or a `pnpm link` — updated with git and a build, not with a registry install. */
45
+ | {
46
+ kind: 'linked-dev';
47
+ packageDir: string;
48
+ }
49
+ /** A shape this does not recognise. Refused rather than guessed at. */
50
+ | {
51
+ kind: 'unknown';
52
+ packageDir: string;
53
+ };
54
+ /** The kinds that name a real install a package manager can be pointed at. */
55
+ export type UpdatableLocation = Extract<InstallLocation, {
56
+ kind: 'npm-global' | 'pnpm-global';
57
+ }>;
58
+ export declare function isUpdatable(location: InstallLocation): location is UpdatableLocation;
59
+ /**
60
+ * This package's own directory on disk.
61
+ *
62
+ * `../../package.json` resolves to this package's manifest from both `dist/update/` and
63
+ * `src/update/`, which is the same specifier — and the same reason — as
64
+ * `cli-version.ts`'s `currentCliVersion`. Node resolves symlinks here, so under pnpm this is the
65
+ * store directory rather than the linked one; `classifyInstall` is written for that.
66
+ */
67
+ export declare function packageDirFrom(moduleUrl: string): string;
68
+ /**
69
+ * Read the install shape straight off the resolved package path.
70
+ *
71
+ * Order matters: an npx cache and a checkout both sit under directory names that would otherwise
72
+ * be read as an ordinary install, so they are excluded first. The remaining two are told apart by
73
+ * the store layout each package manager writes, not by asking which manager is on PATH — that
74
+ * question has the same wrong answer as the one this module exists to stop asking.
75
+ */
76
+ export declare function classifyInstall(packageDir: string, exists?: Exists): InstallLocation;
77
+ /**
78
+ * pnpm refuses `add -g` without a global bin directory it can write, and there is no way to read
79
+ * back the one an install used — `PNPM_HOME` is a shell variable, and the whole point here is that
80
+ * the shell may tell us nothing. So it is recovered from the disk instead: the directory holding
81
+ * the `bitmagic` command that this install produced.
82
+ *
83
+ * `<globalDir>/bin` is the README's two-root recipe (`--global-dir ~/.bitmagic-cli/prod
84
+ * --global-bin-dir ~/.bitmagic-cli/prod/bin`); the parent of `globalDir` is pnpm's own default,
85
+ * where `~/Library/pnpm/global` pairs with `~/Library/pnpm`.
86
+ *
87
+ * Undefined when neither holds the command — the caller then refuses rather than installing into
88
+ * a guessed root, which is the failure mode this module exists to prevent.
89
+ */
90
+ export declare function pnpmBinDir(globalDir: string, exists?: Exists): string | undefined;
91
+ /** An executable and the arguments that must come before the package manager's own subcommand. */
92
+ export interface ManagerCommand {
93
+ command: string;
94
+ leadingArgs: string[];
95
+ /**
96
+ * True when nothing could be found on disk and the name was left for PATH to resolve — i.e. the
97
+ * one case where this is back to guessing, and the messages say so.
98
+ */
99
+ fromPath: boolean;
100
+ }
101
+ /**
102
+ * npm, found without consulting PATH.
103
+ *
104
+ * npm ships inside the node installation, so the node binary executing this process names it —
105
+ * and running that script with `process.execPath` is the whole fix: it is by construction the same
106
+ * node, and therefore the same global prefix, this CLI was installed into, whatever nvm did or did
107
+ * not do to PATH.
108
+ *
109
+ * The install's own prefix is tried first, because that is where the package demonstrably lives;
110
+ * the node's own tree is the fallback for the ordinary case where a global prefix carries no npm
111
+ * of its own.
112
+ */
113
+ export declare function npmCommand(execPath: string, installPrefix: string | undefined, exists?: Exists): ManagerCommand;
114
+ /**
115
+ * pnpm, which — unlike npm — is not bundled with node and so cannot be located from `execPath`.
116
+ *
117
+ * The best that can be done is the directory pnpm itself installed the `bitmagic` command into,
118
+ * which for a default install is also where the `pnpm` command lives. Failing that the name is
119
+ * left to PATH; a pnpm user whose shell has no pnpm gets a clear refusal naming the resolved
120
+ * global dir, which is still strictly better than an install silently landing elsewhere.
121
+ */
122
+ export declare function pnpmCommand(globalDir: string, binDir: string | undefined, exists?: Exists): ManagerCommand;
123
+ /** The manager that owns `location`, resolved without PATH wherever that is possible. */
124
+ export declare function managerFor(location: UpdatableLocation, execPath: string, exists?: Exists): ManagerCommand;
125
+ /**
126
+ * Install `spec` into exactly this location.
127
+ *
128
+ * The target is named explicitly (`--prefix` / `--global-dir`) even though the executable resolved
129
+ * above already implies it, because the two say different things: the executable decides which
130
+ * npm runs, the flag decides where it writes. The README's side-by-side recipe puts two installs
131
+ * under one node, so only the flag can tell them apart.
132
+ *
133
+ * `--prefer-online` is not belt-and-braces. The CLI pins its three `@bitmagic/*` dependencies to
134
+ * exact versions and publishes last, so for a few minutes after a release an installer holding a
135
+ * stale packument resolves the new CLI and then fails ETARGET on a dependency that is already
136
+ * there — see docs/npm-publishing.md, "The first minutes after a release". Forcing the refetch is
137
+ * the documented fix.
138
+ */
139
+ export declare function installArgs(location: UpdatableLocation, spec: string): string[];
140
+ /** The mirror of `installArgs`, for `bitmagic reset-account`'s "start over like a new creator". */
141
+ export declare function uninstallArgs(location: UpdatableLocation): string[];
142
+ /** What a spawned package manager did. Shaped so a test can supply one without a subprocess. */
143
+ export interface SpawnOutcome {
144
+ status: number | null;
145
+ stdout: string;
146
+ stderr: string;
147
+ /** Set when the process could not be started at all — e.g. no `pnpm` on PATH. */
148
+ error: Error | undefined;
149
+ }
150
+ export type SpawnManager = (command: string, args: string[]) => SpawnOutcome;
151
+ /**
152
+ * Output is CAPTURED, not inherited — the same rule, for the same reason, as
153
+ * `reset-account`'s uninstall: under `--json` this CLI's stdout is contractually one document, and
154
+ * a subprocess writing its own progress there would corrupt it. Nothing is printed unless the
155
+ * install fails, and then it goes out through the `Output` seam like every other line.
156
+ */
157
+ export declare const realSpawnManager: SpawnManager;
158
+ /**
159
+ * The version sitting in `dir` right now, read off the disk.
160
+ *
161
+ * Deliberately not `currentCliVersion()`: that reports the manifest this process loaded at start,
162
+ * which after an update is the OLD one. Reading the file again is the only way to tell an install
163
+ * that moved from one that reported success and did nothing — the silent no-op that this whole
164
+ * module exists to make impossible.
165
+ */
166
+ export declare function readInstalledVersion(dir: string, readFile?: (p: string) => string): string | null;
167
+ /** Whether `dir` can be written to, checked before spawning an install that would fail on it. */
168
+ export declare function isWritable(dir: string, access?: (p: string) => void): boolean;
169
+ /**
170
+ * npm's answer when a version it can see on the registry is not yet in its cached packument. The
171
+ * documented remedy is to retry, which is what the caller does — once, and only for this.
172
+ */
173
+ export declare function isStalePackumentFailure(outcome: SpawnOutcome): boolean;
174
+ /** Where this build actually is. The one impure entry point; everything above it is a pure rule. */
175
+ export declare function resolveInstall(moduleUrl: string, exists?: Exists): InstallLocation;
@@ -0,0 +1,335 @@
1
+ /**
2
+ * Where this CLI is installed, and how to reinstall it *there*.
3
+ *
4
+ * The problem this module exists for: until now every update path in the CLI was a printed
5
+ * string — `npm i -g @bitmagic/cli` — for a person or an agent to run in some other shell. That
6
+ * only works if the `npm` on that shell's PATH owns this install, and on a machine using nvm it
7
+ * routinely does not. A coding agent's non-interactive shell sources no profile, so nvm never
8
+ * loads, `npm` resolves to Homebrew's (or to nothing), and the install lands in a prefix whose
9
+ * `bin/` is not the one the creator's `bitmagic` comes from. npm reports success, the next
10
+ * `bitmagic` run is still the old build, and nothing anywhere says so.
11
+ *
12
+ * The fix is to stop asking the shell. `process.execPath` is the node binary running right now and
13
+ * `import.meta.url` is inside the installed package; between them the prefix, the package manager
14
+ * and the target directory are all derivable, and neither depends on the environment. This is how
15
+ * npm updates itself, and it is why every function here takes its inputs as arguments instead of
16
+ * reading them from a lookup that a stripped PATH can change the answer to.
17
+ *
18
+ * Everything that decides is a pure function over a path plus an `exists` probe, so the install
19
+ * shapes this has to survive — nvm, Homebrew, pnpm's two-root side-by-side recipe from the README,
20
+ * an npx cache, a repo checkout — are a test table rather than six machines.
21
+ */
22
+ import { spawnSync } from 'child_process';
23
+ import * as fs from 'fs';
24
+ import * as path from 'path';
25
+ import { createRequire } from 'module';
26
+ /** The npm package this CLI is published as. */
27
+ export const PACKAGE_NAME = '@bitmagic/cli';
28
+ const realExists = (candidate) => fs.existsSync(candidate);
29
+ export function isUpdatable(location) {
30
+ return location.kind === 'npm-global' || location.kind === 'pnpm-global';
31
+ }
32
+ /**
33
+ * This package's own directory on disk.
34
+ *
35
+ * `../../package.json` resolves to this package's manifest from both `dist/update/` and
36
+ * `src/update/`, which is the same specifier — and the same reason — as
37
+ * `cli-version.ts`'s `currentCliVersion`. Node resolves symlinks here, so under pnpm this is the
38
+ * store directory rather than the linked one; `classifyInstall` is written for that.
39
+ */
40
+ export function packageDirFrom(moduleUrl) {
41
+ return path.dirname(createRequire(moduleUrl).resolve('../../package.json'));
42
+ }
43
+ const DIGITS = /^\d+$/;
44
+ /**
45
+ * Read the install shape straight off the resolved package path.
46
+ *
47
+ * Order matters: an npx cache and a checkout both sit under directory names that would otherwise
48
+ * be read as an ordinary install, so they are excluded first. The remaining two are told apart by
49
+ * the store layout each package manager writes, not by asking which manager is on PATH — that
50
+ * question has the same wrong answer as the one this module exists to stop asking.
51
+ */
52
+ export function classifyInstall(packageDir, exists = realExists) {
53
+ const segments = packageDir.split(path.sep);
54
+ // `npx @bitmagic/cli` unpacks into npm's `_npx` cache and throws it away. There is no install
55
+ // here for an update to move, and reinstalling into the cache would achieve nothing.
56
+ if (segments.includes('_npx'))
57
+ return { kind: 'npx', packageDir };
58
+ // The published package is `dist` + `LICENSE.md` + `README.md` + `package.json`; `src/` only
59
+ // exists in the repo. Catches both a checkout run directly and a `pnpm link -g` of one.
60
+ if (exists(path.join(packageDir, 'src')))
61
+ return { kind: 'linked-dev', packageDir };
62
+ const pnpm = classifyPnpm(segments);
63
+ if (pnpm !== null)
64
+ return { ...pnpm, packageDir, binDir: pnpmBinDir(pnpm.globalDir, exists) };
65
+ // A `.pnpm` store that `classifyPnpm` did not claim is a project's, not the machine's. It is
66
+ // shaped enough like an npm tree for the check below to read a "prefix" out of it — which would
67
+ // be a package directory inside the store, and installing there would corrupt one project's
68
+ // dependencies on behalf of a command the creator meant for their whole machine.
69
+ if (segments.includes('.pnpm'))
70
+ return { kind: 'unknown', packageDir };
71
+ const npm = classifyNpm(segments, exists);
72
+ if (npm !== null)
73
+ return { ...npm, packageDir };
74
+ return { kind: 'unknown', packageDir };
75
+ }
76
+ /**
77
+ * pnpm's global store: `<globalDir>/<n>/node_modules/.pnpm/@bitmagic+cli@<v>/node_modules/@bitmagic/cli`.
78
+ *
79
+ * The numbered directory is pnpm's store-layout version, and requiring it is what separates a
80
+ * GLOBAL pnpm install from a project-local one — a `.pnpm` directory inside a project's
81
+ * node_modules has no such parent, and reinstalling globally on its behalf would be wrong.
82
+ */
83
+ function classifyPnpm(segments) {
84
+ const store = segments.indexOf('.pnpm');
85
+ if (store < 2)
86
+ return null;
87
+ if (segments[store - 1] !== 'node_modules')
88
+ return null;
89
+ if (!DIGITS.test(segments[store - 2] ?? ''))
90
+ return null;
91
+ const modulesRoot = segments.slice(0, store).join(path.sep);
92
+ return {
93
+ kind: 'pnpm-global',
94
+ verifyDir: path.join(modulesRoot, '@bitmagic', 'cli'),
95
+ modulesRoot,
96
+ globalDir: segments.slice(0, store - 2).join(path.sep),
97
+ };
98
+ }
99
+ /**
100
+ * npm's global root: `<prefix>/lib/node_modules/@bitmagic/cli` on unix, and
101
+ * `<prefix>/node_modules/@bitmagic/cli` on Windows, where the prefix is the node installation
102
+ * itself rather than a `lib` inside it.
103
+ *
104
+ * That second shape is also what a project-local dependency looks like, and the two have to be
105
+ * told apart: a node prefix has no `package.json` beside its `node_modules`, and a project does.
106
+ * Without the distinction, a CLI listed as a project's devDependency would answer `self-update`
107
+ * by installing globally into the project directory. The unix shape needs no such check — nothing
108
+ * puts a project's manifest two levels above its own `lib/node_modules`.
109
+ */
110
+ function classifyNpm(segments, exists) {
111
+ const end = segments.length;
112
+ if (segments[end - 1] !== 'cli' || segments[end - 2] !== '@bitmagic')
113
+ return null;
114
+ if (segments[end - 3] !== 'node_modules')
115
+ return null;
116
+ const modulesRoot = segments.slice(0, end - 2).join(path.sep);
117
+ const underLib = segments[end - 4] === 'lib';
118
+ const prefix = segments.slice(0, underLib ? end - 4 : end - 3).join(path.sep);
119
+ if (prefix === '')
120
+ return null;
121
+ if (!underLib && exists(path.join(prefix, 'package.json')))
122
+ return null;
123
+ return {
124
+ kind: 'npm-global',
125
+ verifyDir: path.join(modulesRoot, '@bitmagic', 'cli'),
126
+ modulesRoot,
127
+ prefix,
128
+ };
129
+ }
130
+ /**
131
+ * pnpm refuses `add -g` without a global bin directory it can write, and there is no way to read
132
+ * back the one an install used — `PNPM_HOME` is a shell variable, and the whole point here is that
133
+ * the shell may tell us nothing. So it is recovered from the disk instead: the directory holding
134
+ * the `bitmagic` command that this install produced.
135
+ *
136
+ * `<globalDir>/bin` is the README's two-root recipe (`--global-dir ~/.bitmagic-cli/prod
137
+ * --global-bin-dir ~/.bitmagic-cli/prod/bin`); the parent of `globalDir` is pnpm's own default,
138
+ * where `~/Library/pnpm/global` pairs with `~/Library/pnpm`.
139
+ *
140
+ * Undefined when neither holds the command — the caller then refuses rather than installing into
141
+ * a guessed root, which is the failure mode this module exists to prevent.
142
+ */
143
+ export function pnpmBinDir(globalDir, exists = realExists) {
144
+ const candidates = [path.join(globalDir, 'bin'), path.dirname(globalDir)];
145
+ return candidates.find((dir) => exists(path.join(dir, 'bitmagic')));
146
+ }
147
+ /**
148
+ * How far above the node binary to look for the npm that ships with it.
149
+ *
150
+ * One level covers nvm, fnm and a plain tarball install (`<prefix>/bin/node` beside
151
+ * `<prefix>/lib/node_modules/npm`). Homebrew needs four: `process.execPath` is the RESOLVED path,
152
+ * so a `/opt/homebrew/bin/node` symlink reports itself as
153
+ * `/opt/homebrew/Cellar/node/<version>/bin/node` — and the Cellar directory has no `lib/node_modules`
154
+ * at all, because Homebrew links npm into the prefix rather than keeping it with the keg. Six is
155
+ * that case with room to spare, and still far short of anywhere a stray npm could plausibly sit.
156
+ */
157
+ const NODE_ROOT_SEARCH_DEPTH = 6;
158
+ /** `dir` and its ancestors, nearest first, stopping at the filesystem root. */
159
+ function selfAndAncestors(dir, depth) {
160
+ const roots = [];
161
+ let current = dir;
162
+ for (let i = 0; i <= depth; i += 1) {
163
+ roots.push(current);
164
+ const parent = path.dirname(current);
165
+ if (parent === current)
166
+ break;
167
+ current = parent;
168
+ }
169
+ return roots;
170
+ }
171
+ /**
172
+ * npm, found without consulting PATH.
173
+ *
174
+ * npm ships inside the node installation, so the node binary executing this process names it —
175
+ * and running that script with `process.execPath` is the whole fix: it is by construction the same
176
+ * node, and therefore the same global prefix, this CLI was installed into, whatever nvm did or did
177
+ * not do to PATH.
178
+ *
179
+ * The install's own prefix is tried first, because that is where the package demonstrably lives;
180
+ * the node's own tree is the fallback for the ordinary case where a global prefix carries no npm
181
+ * of its own.
182
+ */
183
+ export function npmCommand(execPath, installPrefix, exists = realExists) {
184
+ const roots = [
185
+ ...(installPrefix === undefined ? [] : [installPrefix]),
186
+ ...selfAndAncestors(path.dirname(execPath), NODE_ROOT_SEARCH_DEPTH),
187
+ ];
188
+ for (const root of roots) {
189
+ // `lib/node_modules` on unix; `node_modules` directly under the prefix on Windows.
190
+ for (const middle of [['lib', 'node_modules'], ['node_modules']]) {
191
+ const script = path.join(root, ...middle, 'npm', 'bin', 'npm-cli.js');
192
+ if (exists(script))
193
+ return { command: execPath, leadingArgs: [script], fromPath: false };
194
+ }
195
+ }
196
+ return { command: 'npm', leadingArgs: [], fromPath: true };
197
+ }
198
+ /**
199
+ * pnpm, which — unlike npm — is not bundled with node and so cannot be located from `execPath`.
200
+ *
201
+ * The best that can be done is the directory pnpm itself installed the `bitmagic` command into,
202
+ * which for a default install is also where the `pnpm` command lives. Failing that the name is
203
+ * left to PATH; a pnpm user whose shell has no pnpm gets a clear refusal naming the resolved
204
+ * global dir, which is still strictly better than an install silently landing elsewhere.
205
+ */
206
+ export function pnpmCommand(globalDir, binDir, exists = realExists) {
207
+ const candidates = [binDir, path.dirname(globalDir)].filter((dir) => dir !== undefined);
208
+ for (const dir of candidates) {
209
+ const binary = path.join(dir, 'pnpm');
210
+ if (exists(binary))
211
+ return { command: binary, leadingArgs: [], fromPath: false };
212
+ }
213
+ return { command: 'pnpm', leadingArgs: [], fromPath: true };
214
+ }
215
+ /** The manager that owns `location`, resolved without PATH wherever that is possible. */
216
+ export function managerFor(location, execPath, exists = realExists) {
217
+ return location.kind === 'npm-global'
218
+ ? npmCommand(execPath, location.prefix, exists)
219
+ : pnpmCommand(location.globalDir, location.binDir, exists);
220
+ }
221
+ /**
222
+ * Install `spec` into exactly this location.
223
+ *
224
+ * The target is named explicitly (`--prefix` / `--global-dir`) even though the executable resolved
225
+ * above already implies it, because the two say different things: the executable decides which
226
+ * npm runs, the flag decides where it writes. The README's side-by-side recipe puts two installs
227
+ * under one node, so only the flag can tell them apart.
228
+ *
229
+ * `--prefer-online` is not belt-and-braces. The CLI pins its three `@bitmagic/*` dependencies to
230
+ * exact versions and publishes last, so for a few minutes after a release an installer holding a
231
+ * stale packument resolves the new CLI and then fails ETARGET on a dependency that is already
232
+ * there — see docs/npm-publishing.md, "The first minutes after a release". Forcing the refetch is
233
+ * the documented fix.
234
+ */
235
+ export function installArgs(location, spec) {
236
+ if (location.kind === 'pnpm-global') {
237
+ return [
238
+ 'add',
239
+ '-g',
240
+ '--global-dir',
241
+ location.globalDir,
242
+ ...(location.binDir === undefined ? [] : ['--global-bin-dir', location.binDir]),
243
+ spec,
244
+ ];
245
+ }
246
+ return ['install', '-g', '--prefix', location.prefix, spec, '--prefer-online'];
247
+ }
248
+ /** The mirror of `installArgs`, for `bitmagic reset-account`'s "start over like a new creator". */
249
+ export function uninstallArgs(location) {
250
+ if (location.kind === 'pnpm-global') {
251
+ return [
252
+ 'remove',
253
+ '-g',
254
+ '--global-dir',
255
+ location.globalDir,
256
+ ...(location.binDir === undefined ? [] : ['--global-bin-dir', location.binDir]),
257
+ PACKAGE_NAME,
258
+ ];
259
+ }
260
+ return ['uninstall', '-g', '--prefix', location.prefix, PACKAGE_NAME];
261
+ }
262
+ /**
263
+ * npm's own environment overrides are stripped before it runs.
264
+ *
265
+ * When the CLI is invoked from an npm script (an agent doing `npm run something` that shells out),
266
+ * npm exports its whole config as `npm_config_*`. `npm_config_prefix` in particular names the
267
+ * prefix of the OUTER npm, which is exactly the wrong answer here and exactly the confusion this
268
+ * module removes. Only the prefix keys are dropped: a corporate `npm_config_registry` is a
269
+ * legitimate setting that an update must keep honouring.
270
+ */
271
+ function environmentWithoutNpmPrefix() {
272
+ const env = { ...process.env };
273
+ delete env.npm_config_prefix;
274
+ delete env.npm_config_global_prefix;
275
+ delete env.NPM_CONFIG_PREFIX;
276
+ return env;
277
+ }
278
+ /**
279
+ * Output is CAPTURED, not inherited — the same rule, for the same reason, as
280
+ * `reset-account`'s uninstall: under `--json` this CLI's stdout is contractually one document, and
281
+ * a subprocess writing its own progress there would corrupt it. Nothing is printed unless the
282
+ * install fails, and then it goes out through the `Output` seam like every other line.
283
+ */
284
+ export const realSpawnManager = (command, args) => {
285
+ const result = spawnSync(command, args, { encoding: 'utf-8', env: environmentWithoutNpmPrefix() });
286
+ return {
287
+ status: result.status,
288
+ stdout: result.stdout ?? '',
289
+ stderr: result.stderr ?? '',
290
+ error: result.error,
291
+ };
292
+ };
293
+ /**
294
+ * The version sitting in `dir` right now, read off the disk.
295
+ *
296
+ * Deliberately not `currentCliVersion()`: that reports the manifest this process loaded at start,
297
+ * which after an update is the OLD one. Reading the file again is the only way to tell an install
298
+ * that moved from one that reported success and did nothing — the silent no-op that this whole
299
+ * module exists to make impossible.
300
+ */
301
+ export function readInstalledVersion(dir, readFile = (p) => fs.readFileSync(p, 'utf-8')) {
302
+ try {
303
+ const parsed = JSON.parse(readFile(path.join(dir, 'package.json')));
304
+ if (typeof parsed !== 'object' || parsed === null)
305
+ return null;
306
+ const version = parsed.version;
307
+ return typeof version === 'string' ? version : null;
308
+ }
309
+ catch {
310
+ return null;
311
+ }
312
+ }
313
+ /** Whether `dir` can be written to, checked before spawning an install that would fail on it. */
314
+ export function isWritable(dir, access = (p) => fs.accessSync(p, fs.constants.W_OK)) {
315
+ try {
316
+ access(dir);
317
+ return true;
318
+ }
319
+ catch {
320
+ return false;
321
+ }
322
+ }
323
+ /**
324
+ * npm's answer when a version it can see on the registry is not yet in its cached packument. The
325
+ * documented remedy is to retry, which is what the caller does — once, and only for this.
326
+ */
327
+ export function isStalePackumentFailure(outcome) {
328
+ const text = `${outcome.stdout}\n${outcome.stderr}`;
329
+ return text.includes('ETARGET') || text.includes('No matching version found');
330
+ }
331
+ /** Where this build actually is. The one impure entry point; everything above it is a pure rule. */
332
+ export function resolveInstall(moduleUrl, exists = realExists) {
333
+ return classifyInstall(packageDirFrom(moduleUrl), exists);
334
+ }
335
+ //# sourceMappingURL=self-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-install.js","sourceRoot":"","sources":["../../src/update/self-install.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitmagic/cli",
3
- "version": "0.1.53-dev.4",
3
+ "version": "0.1.53-dev.6",
4
4
  "description": "Build Bitmagic games from your own agent tool",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Bitmagic Oy",
@@ -23,9 +23,9 @@
23
23
  "fflate": "^0.8.2",
24
24
  "playwright-core": "^1.59.1",
25
25
  "tar": "^7.4.3",
26
- "@bitmagic/animation-forger": "0.1.8-dev.4",
27
- "@bitmagic/asset-core": "0.2.8-dev.4",
28
- "@bitmagic/world-forger": "0.1.13-dev.4"
26
+ "@bitmagic/asset-core": "0.2.8-dev.6",
27
+ "@bitmagic/world-forger": "0.1.13-dev.6",
28
+ "@bitmagic/animation-forger": "0.1.8-dev.6"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@eslint/js": "^9.38.0",