botmux 3.18.4 → 3.18.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.
- package/dist/.runtime-build-id +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +130 -21
- package/dist/cli.js.map +1 -1
- package/dist/core/binary-install-shape.d.ts +77 -0
- package/dist/core/binary-install-shape.d.ts.map +1 -0
- package/dist/core/binary-install-shape.js +117 -0
- package/dist/core/binary-install-shape.js.map +1 -0
- package/dist/core/binary-self-update.d.ts +82 -0
- package/dist/core/binary-self-update.d.ts.map +1 -0
- package/dist/core/binary-self-update.js +239 -0
- package/dist/core/binary-self-update.js.map +1 -0
- package/dist/core/maintenance.d.ts +88 -1
- package/dist/core/maintenance.d.ts.map +1 -1
- package/dist/core/maintenance.js +149 -8
- package/dist/core/maintenance.js.map +1 -1
- package/dist/core/release-download.d.ts +13 -0
- package/dist/core/release-download.d.ts.map +1 -0
- package/dist/core/release-download.js +130 -0
- package/dist/core/release-download.js.map +1 -0
- package/dist/dashboard/hd2d-assets.d.ts +2 -3
- package/dist/dashboard/hd2d-assets.d.ts.map +1 -1
- package/dist/dashboard/hd2d-assets.js +7 -109
- package/dist/dashboard/hd2d-assets.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +7 -1
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/settings-page.d.ts.map +1 -1
- package/dist/dashboard/web/settings-page.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard.js +120 -13
- package/dist/dashboard.js.map +1 -1
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +9 -12
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/utils/file-lock.d.ts +25 -0
- package/dist/utils/file-lock.d.ts.map +1 -1
- package/dist/utils/file-lock.js +34 -4
- package/dist/utils/file-lock.js.map +1 -1
- package/dist/utils/global-install.d.ts +19 -0
- package/dist/utils/global-install.d.ts.map +1 -1
- package/dist/utils/global-install.js +28 -1
- package/dist/utils/global-install.js.map +1 -1
- package/dist/utils/install-info.d.ts +37 -1
- package/dist/utils/install-info.d.ts.map +1 -1
- package/dist/utils/install-info.js +45 -3
- package/dist/utils/install-info.js.map +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the running compiled binary was installed, and therefore who owns updating it.
|
|
3
|
+
*
|
|
4
|
+
* · `npm-binary` — inside an npm/pnpm/Bun platform subpackage
|
|
5
|
+
* (`botmux-<plat>-<arch>[-musl]`). The manager owns the file;
|
|
6
|
+
* update by re-running it.
|
|
7
|
+
* · `curl-binary` — the standalone location install.sh writes. We own the file;
|
|
8
|
+
* update by replacing it.
|
|
9
|
+
* · `unknown` — anywhere else (a hand-copied binary, a distro package, a dev
|
|
10
|
+
* build run straight out of dist-bin/), or not a compiled
|
|
11
|
+
* binary at all. Fail closed.
|
|
12
|
+
*/
|
|
13
|
+
export type BinaryInstallShape = 'npm-binary' | 'curl-binary' | 'unknown';
|
|
14
|
+
/**
|
|
15
|
+
* Classify a binary path. Pure — the caller passes the path and the relevant
|
|
16
|
+
* environment, so every shape is unit-testable without a real install.
|
|
17
|
+
*
|
|
18
|
+
* @param execPath the running executable (`process.execPath`)
|
|
19
|
+
* @param env consulted for `BOTMUX_INSTALL_DIR` (install.sh honours it)
|
|
20
|
+
* @param home the home directory, for the default install dir
|
|
21
|
+
*/
|
|
22
|
+
export declare function classifyBinaryInstall(execPath: string, env?: NodeJS.ProcessEnv, home?: string): BinaryInstallShape;
|
|
23
|
+
/** Classify the running process. `unknown` for a non-compiled (Node) run, whose
|
|
24
|
+
* updates go through the package-manager path instead. */
|
|
25
|
+
export declare function currentBinaryInstallShape(): BinaryInstallShape;
|
|
26
|
+
/**
|
|
27
|
+
* Map a platform-subpackage binary path to the MAIN `botmux` package root beside
|
|
28
|
+
* it (`…/node_modules/botmux-linux-x64/botmux` → `…/node_modules/botmux`).
|
|
29
|
+
*
|
|
30
|
+
* WHY GO THROUGH THE MAIN PACKAGE instead of computing an npm `--prefix` here:
|
|
31
|
+
* `resolveGlobalInstallPlan` already classifies that path shape into the right
|
|
32
|
+
* manager and builds the right command — including pnpm's `--global-dir`, Bun's
|
|
33
|
+
* env pinning, and the POSIX-vs-Windows prefix difference — and all of it is
|
|
34
|
+
* unit-tested. Re-deriving a prefix here would be a second, diverging
|
|
35
|
+
* implementation of the same rules. It also means `pnpm i -g` / `bun add -g`
|
|
36
|
+
* installs keep resolving to THEIR manager rather than being forced onto npm.
|
|
37
|
+
*
|
|
38
|
+
* Returns null when the shape does not match, so callers fail closed.
|
|
39
|
+
*/
|
|
40
|
+
export declare function mainPackageRootForSubpackageBinary(execPath: string): string | null;
|
|
41
|
+
/**
|
|
42
|
+
* How the running process should update itself.
|
|
43
|
+
*
|
|
44
|
+
* · `package-manager` — hand off to npm/pnpm/Bun for `packageRoot`. Covers both a
|
|
45
|
+
* plain Node install AND a compiled binary living inside a package manager's
|
|
46
|
+
* tree (the manager owns that file).
|
|
47
|
+
* · `self-replace` — download the release asset and swap the binary.
|
|
48
|
+
* · `unsupported` — could not identify the install; callers keep their
|
|
49
|
+
* existing "unsupported install" behaviour.
|
|
50
|
+
*/
|
|
51
|
+
export type UpdateStrategy = {
|
|
52
|
+
kind: 'package-manager';
|
|
53
|
+
packageRoot: string;
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'self-replace';
|
|
56
|
+
target: string;
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'unsupported';
|
|
59
|
+
reason: 'unknown-binary-location';
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Decide the update strategy. Pure over its inputs so every branch is testable
|
|
63
|
+
* without a compiled binary.
|
|
64
|
+
*
|
|
65
|
+
* The Node path is deliberately left EXACTLY as it was: when this is not a
|
|
66
|
+
* standalone binary we return the running install root and callers resolve it
|
|
67
|
+
* through `resolveGlobalInstallPlan` as before — no behaviour change for npm
|
|
68
|
+
* `dist/cli.js` deployments or source checkouts.
|
|
69
|
+
*
|
|
70
|
+
* @param standalone is this a compiled single-file executable?
|
|
71
|
+
* @param execPath the running executable
|
|
72
|
+
* @param installRoot `botmuxInstallRoot()` — only meaningful when NOT standalone
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveUpdateStrategy(standalone: boolean, execPath: string, installRoot: string, env?: NodeJS.ProcessEnv, home?: string): UpdateStrategy;
|
|
75
|
+
/** Production wiring for {@link resolveUpdateStrategy}. */
|
|
76
|
+
export declare function currentUpdateStrategy(installRoot: string): UpdateStrategy;
|
|
77
|
+
//# sourceMappingURL=binary-install-shape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-install-shape.d.ts","sourceRoot":"","sources":["../../src/core/binary-install-shape.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,aAAa,GAAG,SAAS,CAAC;AAO1E;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,GAAE,MAAkB,GACvB,kBAAkB,CAyBpB;AAED;2DAC2D;AAC3D,wBAAgB,yBAAyB,IAAI,kBAAkB,CAG9D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIlF;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,yBAAyB,CAAA;CAAE,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,OAAO,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,GAAE,MAAkB,GACvB,cAAc,CAYhB;AAED,2DAA2D;AAC3D,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAEzE"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHERE the running compiled binary lives — the pure, dependency-free half of the
|
|
3
|
+
* self-update story.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `binary-self-update.ts` so it can be imported from
|
|
6
|
+
* `utils/global-install.ts` without closing an import cycle: the self-update
|
|
7
|
+
* module needs `restart-report` (for the repo slug) which reaches
|
|
8
|
+
* `utils/install-info.ts`, and `global-install.ts` is itself imported by
|
|
9
|
+
* `install-diagnostics.ts`. This file imports nothing but `node:os`/`node:path`
|
|
10
|
+
* plus the standalone check, so it is safe to depend on from anywhere.
|
|
11
|
+
*
|
|
12
|
+
* See `binary-self-update.ts` for the full rationale — in short: both installers
|
|
13
|
+
* ship the SAME compiled binary, so the module graph cannot tell them apart (both
|
|
14
|
+
* report an install root of `/`), and `process.execPath` can.
|
|
15
|
+
*/
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { isStandaloneBinary } from './self-spawn.js';
|
|
19
|
+
/** Default standalone install dir, matching install.sh's own default. */
|
|
20
|
+
function defaultInstallDir(home) {
|
|
21
|
+
return join(home, '.botmux', 'bin');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Classify a binary path. Pure — the caller passes the path and the relevant
|
|
25
|
+
* environment, so every shape is unit-testable without a real install.
|
|
26
|
+
*
|
|
27
|
+
* @param execPath the running executable (`process.execPath`)
|
|
28
|
+
* @param env consulted for `BOTMUX_INSTALL_DIR` (install.sh honours it)
|
|
29
|
+
* @param home the home directory, for the default install dir
|
|
30
|
+
*/
|
|
31
|
+
export function classifyBinaryInstall(execPath, env = process.env, home = homedir()) {
|
|
32
|
+
const path = execPath.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
33
|
+
if (!path)
|
|
34
|
+
return 'unknown';
|
|
35
|
+
// Platform subpackage: <anything>/node_modules/botmux-<plat>-<arch>[-musl]/botmux
|
|
36
|
+
// Anchored on `/node_modules/` so a user directory that merely happens to be
|
|
37
|
+
// named `botmux-linux-x64` is not mistaken for a package-manager-owned tree.
|
|
38
|
+
if (/\/node_modules\/botmux-(?:linux|darwin)-(?:x64|arm64)(?:-musl)?\/botmux$/.test(path)) {
|
|
39
|
+
return 'npm-binary';
|
|
40
|
+
}
|
|
41
|
+
// The standalone install location. `BOTMUX_INSTALL_DIR` is what install.sh
|
|
42
|
+
// honours, so an install that used it is recognised WHEN THAT VARIABLE IS STILL
|
|
43
|
+
// EXPORTED at runtime. ⚠️ It usually is not: `BOTMUX_INSTALL_DIR=/opt/bm sh
|
|
44
|
+
// install.sh` sets it for the installer only, so a later `botmux update` sees a
|
|
45
|
+
// bare environment and this falls through to `unknown` — fail-closed, so nothing
|
|
46
|
+
// is damaged, but self-update is unavailable for that install. Do not describe
|
|
47
|
+
// custom dirs as unconditionally covered; making them work without the variable
|
|
48
|
+
// would need a persisted install record, which is out of scope here.
|
|
49
|
+
for (const raw of [env.BOTMUX_INSTALL_DIR, defaultInstallDir(home)]) {
|
|
50
|
+
if (!raw)
|
|
51
|
+
continue;
|
|
52
|
+
const dir = raw.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
53
|
+
if (dir && path === `${dir}/botmux`)
|
|
54
|
+
return 'curl-binary';
|
|
55
|
+
}
|
|
56
|
+
return 'unknown';
|
|
57
|
+
}
|
|
58
|
+
/** Classify the running process. `unknown` for a non-compiled (Node) run, whose
|
|
59
|
+
* updates go through the package-manager path instead. */
|
|
60
|
+
export function currentBinaryInstallShape() {
|
|
61
|
+
if (!isStandaloneBinary())
|
|
62
|
+
return 'unknown';
|
|
63
|
+
return classifyBinaryInstall(process.execPath);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Map a platform-subpackage binary path to the MAIN `botmux` package root beside
|
|
67
|
+
* it (`…/node_modules/botmux-linux-x64/botmux` → `…/node_modules/botmux`).
|
|
68
|
+
*
|
|
69
|
+
* WHY GO THROUGH THE MAIN PACKAGE instead of computing an npm `--prefix` here:
|
|
70
|
+
* `resolveGlobalInstallPlan` already classifies that path shape into the right
|
|
71
|
+
* manager and builds the right command — including pnpm's `--global-dir`, Bun's
|
|
72
|
+
* env pinning, and the POSIX-vs-Windows prefix difference — and all of it is
|
|
73
|
+
* unit-tested. Re-deriving a prefix here would be a second, diverging
|
|
74
|
+
* implementation of the same rules. It also means `pnpm i -g` / `bun add -g`
|
|
75
|
+
* installs keep resolving to THEIR manager rather than being forced onto npm.
|
|
76
|
+
*
|
|
77
|
+
* Returns null when the shape does not match, so callers fail closed.
|
|
78
|
+
*/
|
|
79
|
+
export function mainPackageRootForSubpackageBinary(execPath) {
|
|
80
|
+
const path = execPath.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
81
|
+
const m = /^(.*\/node_modules)\/botmux-(?:linux|darwin)-(?:x64|arm64)(?:-musl)?\/botmux$/.exec(path);
|
|
82
|
+
return m ? `${m[1]}/botmux` : null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Decide the update strategy. Pure over its inputs so every branch is testable
|
|
86
|
+
* without a compiled binary.
|
|
87
|
+
*
|
|
88
|
+
* The Node path is deliberately left EXACTLY as it was: when this is not a
|
|
89
|
+
* standalone binary we return the running install root and callers resolve it
|
|
90
|
+
* through `resolveGlobalInstallPlan` as before — no behaviour change for npm
|
|
91
|
+
* `dist/cli.js` deployments or source checkouts.
|
|
92
|
+
*
|
|
93
|
+
* @param standalone is this a compiled single-file executable?
|
|
94
|
+
* @param execPath the running executable
|
|
95
|
+
* @param installRoot `botmuxInstallRoot()` — only meaningful when NOT standalone
|
|
96
|
+
*/
|
|
97
|
+
export function resolveUpdateStrategy(standalone, execPath, installRoot, env = process.env, home = homedir()) {
|
|
98
|
+
if (!standalone)
|
|
99
|
+
return { kind: 'package-manager', packageRoot: installRoot };
|
|
100
|
+
const shape = classifyBinaryInstall(execPath, env, home);
|
|
101
|
+
if (shape === 'npm-binary') {
|
|
102
|
+
const root = mainPackageRootForSubpackageBinary(execPath);
|
|
103
|
+
// The regex that produced `npm-binary` is the same one used here, so `root`
|
|
104
|
+
// cannot be null in practice; keep the guard so a future loosening of one
|
|
105
|
+
// pattern degrades to "unsupported" instead of dereferencing null.
|
|
106
|
+
if (root)
|
|
107
|
+
return { kind: 'package-manager', packageRoot: root };
|
|
108
|
+
}
|
|
109
|
+
if (shape === 'curl-binary')
|
|
110
|
+
return { kind: 'self-replace', target: execPath };
|
|
111
|
+
return { kind: 'unsupported', reason: 'unknown-binary-location' };
|
|
112
|
+
}
|
|
113
|
+
/** Production wiring for {@link resolveUpdateStrategy}. */
|
|
114
|
+
export function currentUpdateStrategy(installRoot) {
|
|
115
|
+
return resolveUpdateStrategy(isStandaloneBinary(), process.execPath, installRoot);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=binary-install-shape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-install-shape.js","sourceRoot":"","sources":["../../src/core/binary-install-shape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the running compiled binary lives, and therefore who owns updating it.
|
|
3
|
+
* The pure location classifier lives in `binary-install-shape.ts` so
|
|
4
|
+
* `utils/global-install.ts` can import it without closing an import cycle through
|
|
5
|
+
* this module (which reaches install-info via restart-report). Re-exported here so
|
|
6
|
+
* callers have one obvious import site for the whole self-update surface.
|
|
7
|
+
*/
|
|
8
|
+
export { classifyBinaryInstall, currentBinaryInstallShape, mainPackageRootForSubpackageBinary, resolveUpdateStrategy, currentUpdateStrategy, type BinaryInstallShape, type UpdateStrategy, } from './binary-install-shape.js';
|
|
9
|
+
/**
|
|
10
|
+
* Is this a musl libc host (Alpine and most slim Docker images)?
|
|
11
|
+
*
|
|
12
|
+
* WHY IT MATTERS: a glibc-linked binary does not run on musl at all — it dies in
|
|
13
|
+
* the loader with a message naming no cause. Downloading the wrong one turns a
|
|
14
|
+
* working install into a binary that cannot start, which is strictly worse than
|
|
15
|
+
* refusing to update.
|
|
16
|
+
*
|
|
17
|
+
* Mirrors the probe order in `scripts/postinstall-bin.mjs` and install.sh, and is
|
|
18
|
+
* deliberately conservative: only claim musl when positively observed, so a glibc
|
|
19
|
+
* box is never pushed onto the musl asset. Node's `process.report` header is a
|
|
20
|
+
* NEGATIVE signal only — measured on node:22-alpine it carries neither
|
|
21
|
+
* `glibcVersionRuntime` nor any musl key, so it can confirm glibc but never musl.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isMuslHost(platform?: NodeJS.Platform, probes?: {
|
|
24
|
+
glibcRuntime?: () => string | undefined;
|
|
25
|
+
listDir?: (dir: string) => string[];
|
|
26
|
+
exists?: (path: string) => boolean;
|
|
27
|
+
}): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The release asset name for a platform, matching the names release.yml uploads
|
|
30
|
+
* (`botmux-<os>-<arch>[-musl]`) and install.sh downloads. Returns null for a
|
|
31
|
+
* platform/arch with no published build rather than inventing a name that 404s.
|
|
32
|
+
*/
|
|
33
|
+
export declare function releaseAssetName(platform?: NodeJS.Platform, arch?: string, musl?: boolean): string | null;
|
|
34
|
+
/** Download base for a release tag, mirroring install.sh's URL construction. */
|
|
35
|
+
export declare function releaseAssetBaseUrl(version: string): string;
|
|
36
|
+
export interface BinarySelfUpdateResult {
|
|
37
|
+
/** The asset that was installed. */
|
|
38
|
+
asset: string;
|
|
39
|
+
/** Absolute path that was replaced. */
|
|
40
|
+
target: string;
|
|
41
|
+
/** Bytes written. */
|
|
42
|
+
bytes: number;
|
|
43
|
+
}
|
|
44
|
+
export interface BinarySelfUpdateDeps {
|
|
45
|
+
/** Fetch a URL as a readable stream (injected for tests). */
|
|
46
|
+
fetchStream?: (url: string) => Promise<NodeJS.ReadableStream>;
|
|
47
|
+
/** Read the published checksum for `asset`, or null when none is published. */
|
|
48
|
+
fetchChecksum?: (url: string) => Promise<string | null>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Replace the running standalone binary with `version`'s published asset.
|
|
52
|
+
*
|
|
53
|
+
* ── WHY A RENAME AND NOT A WRITE (do not "simplify" this) ─────────────────────
|
|
54
|
+
* MEASURED on Linux with a real ELF:
|
|
55
|
+
*
|
|
56
|
+
* open(target,'r+b').write(…) → OSError 26 ETXTBSY "Text file busy"
|
|
57
|
+
* rename(new, target) → succeeds; the running process keeps executing
|
|
58
|
+
* the old inode and finishes normally
|
|
59
|
+
*
|
|
60
|
+
* So the update MUST land as a rename over the path, never an in-place write:
|
|
61
|
+
* the kernel refuses to let us scribble on the executable of a live process, and
|
|
62
|
+
* a rename is also what makes the swap atomic for anything about to `exec` it.
|
|
63
|
+
* The temp file is created in the SAME directory as the target so the rename is
|
|
64
|
+
* within one filesystem (a cross-device rename fails with EXDEV, and copying
|
|
65
|
+
* would reintroduce the torn-file window this avoids).
|
|
66
|
+
*
|
|
67
|
+
* Checksum verification happens BEFORE the rename, so a truncated or tampered
|
|
68
|
+
* download is discarded while the working binary is still in place. A release
|
|
69
|
+
* that publishes no `.sha256` is a warning, not a failure — matching install.sh,
|
|
70
|
+
* which has always tolerated that.
|
|
71
|
+
*
|
|
72
|
+
* ── WHY NO `realpathSync(target)` ─────────────────────────────────────────────
|
|
73
|
+
* Renaming over a SYMLINK replaces the link itself and orphans its target
|
|
74
|
+
* (measured). That would matter if `target` could be a symlink — but the default
|
|
75
|
+
* target is `process.execPath`, which the OS has already resolved: MEASURED with a
|
|
76
|
+
* compiled binary invoked through a symlink, `process.execPath` reports the real
|
|
77
|
+
* file, never the link. So the symlink case is unreachable on the production path,
|
|
78
|
+
* and resolving again would only add a failure mode of its own (an unreadable
|
|
79
|
+
* parent dir). install.sh's plain `mv` has the same semantics.
|
|
80
|
+
*/
|
|
81
|
+
export declare function replaceStandaloneBinary(version: string, target?: string, deps?: BinarySelfUpdateDeps): Promise<BinarySelfUpdateResult>;
|
|
82
|
+
//# sourceMappingURL=binary-self-update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-self-update.d.ts","sourceRoot":"","sources":["../../src/core/binary-self-update.ts"],"names":[],"mappings":"AA0EA;;;;;;GAMG;AACH,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,kCAAkC,EAClC,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,2BAA2B,CAAC;AAInC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,MAAM,GAAE;IACN,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACxC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACpC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC/B,GACL,OAAO,CAoBT;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,IAAI,GAAE,MAAqB,EAC3B,IAAI,GAAE,OAA8B,GACnC,MAAM,GAAG,IAAI,CAMf;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAYD,MAAM,WAAW,sBAAsB;IACrC,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAC9D,+EAA+E;IAC/E,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAyB,EACjC,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAoDjC"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the RUNNING compiled binary was installed, and how to update it.
|
|
3
|
+
*
|
|
4
|
+
* ── WHY THIS EXISTS ────────────────────────────────────────────────────────────
|
|
5
|
+
* Every pre-existing update path (`botmux update`, the dashboard's
|
|
6
|
+
* `/api/update/run`, the scheduled maintenance auto-update) asks
|
|
7
|
+
* `resolveGlobalInstallPlan(botmuxInstallRoot())` which package manager owns the
|
|
8
|
+
* install. That question is answered by looking at the install ROOT — the
|
|
9
|
+
* directory holding `package.json` — and classifying its path shape
|
|
10
|
+
* (`…/lib/node_modules/botmux` ⇒ npm, `…/.pnpm/…` ⇒ pnpm, …).
|
|
11
|
+
*
|
|
12
|
+
* A compiled single-file executable has NO package.json on disk: the module graph
|
|
13
|
+
* lives in the virtual read-only `/$bunfs/`, so `packageRoot()` walks up to `/`
|
|
14
|
+
* and stops. MEASURED on the real published v3.18.4 binary and on a locally
|
|
15
|
+
* compiled probe — identical in both:
|
|
16
|
+
*
|
|
17
|
+
* botmuxInstallRoot() → "/"
|
|
18
|
+
* detectGlobalInstallManager("/") → "unknown"
|
|
19
|
+
* resolveGlobalInstallPlan("/") → throws UnsupportedGlobalInstallError
|
|
20
|
+
* botmuxCliEntry() → "/dist/cli.js" (does not exist)
|
|
21
|
+
*
|
|
22
|
+
* So on the real shipped artifact `botmux update` printed
|
|
23
|
+
* “无法安全识别当前安装方式(unknown)” and exited, the dashboard button greyed out
|
|
24
|
+
* with “supports npm/pnpm/Bun global installs only”, and the scheduled
|
|
25
|
+
* auto-update failed every single day (fail-safe — it never restarts onto a stale
|
|
26
|
+
* version — but it marks the day done, so it does not even retry).
|
|
27
|
+
*
|
|
28
|
+
* ── THE KEY INSIGHT: BOTH INSTALLERS SHIP THE SAME BINARY ─────────────────────
|
|
29
|
+
* It is tempting to think “npm users update with npm, curl users update with
|
|
30
|
+
* curl”, i.e. that the two installers produce different artifacts. They do not.
|
|
31
|
+
* `npm i -g botmux` has NO `bin` field any more (removed in #1047): it downloads
|
|
32
|
+
* a platform subpackage and its postinstall writes `~/.botmux/bin/botmux` as a
|
|
33
|
+
* launcher that `exec`s that subpackage's compiled binary. `install.sh` downloads
|
|
34
|
+
* the very same compiled binary from the GitHub Release. Same bytes, different
|
|
35
|
+
* location — which is exactly why classifying by MODULE GRAPH cannot work (both
|
|
36
|
+
* report `/`) and classifying by LOCATION can.
|
|
37
|
+
*
|
|
38
|
+
* `process.execPath` is the location of the running executable, and it is the one
|
|
39
|
+
* thing that still differs. MEASURED, compiled binaries invoked through each
|
|
40
|
+
* installer's own launcher:
|
|
41
|
+
*
|
|
42
|
+
* npm → /usr/lib/node_modules/botmux-linux-x64/botmux (subpackage dir)
|
|
43
|
+
* curl → ~/.botmux/bin/botmux (BOTMUX_INSTALL_DIR)
|
|
44
|
+
*
|
|
45
|
+
* Note it is the REAL binary path in both cases, not the launcher's: the launcher
|
|
46
|
+
* `exec`s the binary, so the process's execPath is the target. Verified by
|
|
47
|
+
* running a compiled probe through a launcher of exactly the shape postinstall
|
|
48
|
+
* writes.
|
|
49
|
+
*
|
|
50
|
+
* ── WHAT EACH SHAPE DOES TO UPDATE ─────────────────────────────────────────────
|
|
51
|
+
* · npm → hand back to npm (`npm i -g botmux@latest`). npm replaces the
|
|
52
|
+
* subpackage and re-runs postinstall, which re-points the launcher. We
|
|
53
|
+
* must NOT rewrite the binary ourselves: npm owns that tree, and a
|
|
54
|
+
* hand-written file there would be clobbered (or worse, left behind at
|
|
55
|
+
* a version npm's metadata disagrees with).
|
|
56
|
+
* · curl → replace the binary in place, the same way install.sh does: download
|
|
57
|
+
* the matching asset, verify its published SHA-256, then atomically
|
|
58
|
+
* rename over the target. Nothing else owns that path.
|
|
59
|
+
*
|
|
60
|
+
* A shape we cannot positively identify returns null, and every caller keeps its
|
|
61
|
+
* existing "unsupported install" behaviour. Fail closed: guessing wrong here
|
|
62
|
+
* means either writing into a tree npm owns, or downloading a binary for the
|
|
63
|
+
* wrong libc.
|
|
64
|
+
*/
|
|
65
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
66
|
+
import { createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, chmodSync, } from 'node:fs';
|
|
67
|
+
import { dirname, join } from 'node:path';
|
|
68
|
+
import { pipeline } from 'node:stream/promises';
|
|
69
|
+
import { GITHUB_REPO } from './restart-report.js';
|
|
70
|
+
import { getReleaseStream, resolveHttpProxy } from './release-download.js';
|
|
71
|
+
/**
|
|
72
|
+
* Where the running compiled binary lives, and therefore who owns updating it.
|
|
73
|
+
* The pure location classifier lives in `binary-install-shape.ts` so
|
|
74
|
+
* `utils/global-install.ts` can import it without closing an import cycle through
|
|
75
|
+
* this module (which reaches install-info via restart-report). Re-exported here so
|
|
76
|
+
* callers have one obvious import site for the whole self-update surface.
|
|
77
|
+
*/
|
|
78
|
+
export { classifyBinaryInstall, currentBinaryInstallShape, mainPackageRootForSubpackageBinary, resolveUpdateStrategy, currentUpdateStrategy, } from './binary-install-shape.js';
|
|
79
|
+
// ── Release asset selection ────────────────────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* Is this a musl libc host (Alpine and most slim Docker images)?
|
|
82
|
+
*
|
|
83
|
+
* WHY IT MATTERS: a glibc-linked binary does not run on musl at all — it dies in
|
|
84
|
+
* the loader with a message naming no cause. Downloading the wrong one turns a
|
|
85
|
+
* working install into a binary that cannot start, which is strictly worse than
|
|
86
|
+
* refusing to update.
|
|
87
|
+
*
|
|
88
|
+
* Mirrors the probe order in `scripts/postinstall-bin.mjs` and install.sh, and is
|
|
89
|
+
* deliberately conservative: only claim musl when positively observed, so a glibc
|
|
90
|
+
* box is never pushed onto the musl asset. Node's `process.report` header is a
|
|
91
|
+
* NEGATIVE signal only — measured on node:22-alpine it carries neither
|
|
92
|
+
* `glibcVersionRuntime` nor any musl key, so it can confirm glibc but never musl.
|
|
93
|
+
*/
|
|
94
|
+
export function isMuslHost(platform = process.platform, probes = {}) {
|
|
95
|
+
if (platform !== 'linux')
|
|
96
|
+
return false;
|
|
97
|
+
const glibcRuntime = probes.glibcRuntime ?? (() => {
|
|
98
|
+
try {
|
|
99
|
+
return process.report?.getReport?.()
|
|
100
|
+
?.header?.glibcVersionRuntime;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const listDir = probes.listDir ?? ((dir) => {
|
|
107
|
+
try {
|
|
108
|
+
return readdirSync(dir);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
const exists = probes.exists ?? ((p) => {
|
|
115
|
+
try {
|
|
116
|
+
return existsSync(p);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
if (glibcRuntime())
|
|
123
|
+
return false; // a reported glibc runtime settles it
|
|
124
|
+
for (const dir of ['/lib', '/usr/lib']) {
|
|
125
|
+
if (listDir(dir).some(f => f.startsWith('ld-musl-')))
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return exists('/etc/alpine-release');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The release asset name for a platform, matching the names release.yml uploads
|
|
132
|
+
* (`botmux-<os>-<arch>[-musl]`) and install.sh downloads. Returns null for a
|
|
133
|
+
* platform/arch with no published build rather than inventing a name that 404s.
|
|
134
|
+
*/
|
|
135
|
+
export function releaseAssetName(platform = process.platform, arch = process.arch, musl = isMuslHost(platform)) {
|
|
136
|
+
const os = platform === 'linux' ? 'linux' : platform === 'darwin' ? 'darwin' : null;
|
|
137
|
+
const cpu = arch === 'x64' ? 'x64' : arch === 'arm64' ? 'arm64' : null;
|
|
138
|
+
if (!os || !cpu)
|
|
139
|
+
return null;
|
|
140
|
+
// Only linux ships musl variants; darwin has no such split.
|
|
141
|
+
return `botmux-${os}-${cpu}${os === 'linux' && musl ? '-musl' : ''}`;
|
|
142
|
+
}
|
|
143
|
+
/** Download base for a release tag, mirroring install.sh's URL construction. */
|
|
144
|
+
export function releaseAssetBaseUrl(version) {
|
|
145
|
+
return `https://github.com/${GITHUB_REPO}/releases/download/v${version.replace(/^v/i, '')}`;
|
|
146
|
+
}
|
|
147
|
+
// ── The self-update itself ─────────────────────────────────────────────────────
|
|
148
|
+
const SELF_UPDATE_UA = 'botmux-self-update';
|
|
149
|
+
async function sha256File(path) {
|
|
150
|
+
const hash = createHash('sha256');
|
|
151
|
+
await pipeline(createReadStream(path), hash);
|
|
152
|
+
return hash.digest('hex');
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Replace the running standalone binary with `version`'s published asset.
|
|
156
|
+
*
|
|
157
|
+
* ── WHY A RENAME AND NOT A WRITE (do not "simplify" this) ─────────────────────
|
|
158
|
+
* MEASURED on Linux with a real ELF:
|
|
159
|
+
*
|
|
160
|
+
* open(target,'r+b').write(…) → OSError 26 ETXTBSY "Text file busy"
|
|
161
|
+
* rename(new, target) → succeeds; the running process keeps executing
|
|
162
|
+
* the old inode and finishes normally
|
|
163
|
+
*
|
|
164
|
+
* So the update MUST land as a rename over the path, never an in-place write:
|
|
165
|
+
* the kernel refuses to let us scribble on the executable of a live process, and
|
|
166
|
+
* a rename is also what makes the swap atomic for anything about to `exec` it.
|
|
167
|
+
* The temp file is created in the SAME directory as the target so the rename is
|
|
168
|
+
* within one filesystem (a cross-device rename fails with EXDEV, and copying
|
|
169
|
+
* would reintroduce the torn-file window this avoids).
|
|
170
|
+
*
|
|
171
|
+
* Checksum verification happens BEFORE the rename, so a truncated or tampered
|
|
172
|
+
* download is discarded while the working binary is still in place. A release
|
|
173
|
+
* that publishes no `.sha256` is a warning, not a failure — matching install.sh,
|
|
174
|
+
* which has always tolerated that.
|
|
175
|
+
*
|
|
176
|
+
* ── WHY NO `realpathSync(target)` ─────────────────────────────────────────────
|
|
177
|
+
* Renaming over a SYMLINK replaces the link itself and orphans its target
|
|
178
|
+
* (measured). That would matter if `target` could be a symlink — but the default
|
|
179
|
+
* target is `process.execPath`, which the OS has already resolved: MEASURED with a
|
|
180
|
+
* compiled binary invoked through a symlink, `process.execPath` reports the real
|
|
181
|
+
* file, never the link. So the symlink case is unreachable on the production path,
|
|
182
|
+
* and resolving again would only add a failure mode of its own (an unreadable
|
|
183
|
+
* parent dir). install.sh's plain `mv` has the same semantics.
|
|
184
|
+
*/
|
|
185
|
+
export async function replaceStandaloneBinary(version, target = process.execPath, deps = {}) {
|
|
186
|
+
const asset = releaseAssetName();
|
|
187
|
+
if (!asset) {
|
|
188
|
+
throw new Error(`当前平台没有发布二进制(${process.platform}-${process.arch})`);
|
|
189
|
+
}
|
|
190
|
+
const base = releaseAssetBaseUrl(version);
|
|
191
|
+
const proxy = resolveHttpProxy();
|
|
192
|
+
const fetchStream = deps.fetchStream
|
|
193
|
+
?? (async (url) => await getReleaseStream(url, proxy, SELF_UPDATE_UA));
|
|
194
|
+
const fetchChecksum = deps.fetchChecksum ?? (async (url) => {
|
|
195
|
+
try {
|
|
196
|
+
const res = await getReleaseStream(url, proxy, SELF_UPDATE_UA);
|
|
197
|
+
const chunks = [];
|
|
198
|
+
for await (const chunk of res)
|
|
199
|
+
chunks.push(Buffer.from(chunk));
|
|
200
|
+
// The file is "<sha256> <filename>"; take the first field.
|
|
201
|
+
const first = Buffer.concat(chunks).toString('utf-8').trim().split(/\s+/)[0] ?? '';
|
|
202
|
+
return /^[0-9a-f]{64}$/i.test(first) ? first.toLowerCase() : null;
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return null; // no checksum published (or unreachable) → warn, don't fail
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
// Same directory as the target: keeps the rename intra-filesystem (EXDEV).
|
|
209
|
+
const dir = dirname(target);
|
|
210
|
+
mkdirSync(dir, { recursive: true });
|
|
211
|
+
const tmp = join(dir, `.botmux-update.${process.pid}.${randomBytes(4).toString('hex')}.tmp`);
|
|
212
|
+
try {
|
|
213
|
+
const res = await fetchStream(`${base}/${asset}`);
|
|
214
|
+
await pipeline(res, createWriteStream(tmp));
|
|
215
|
+
const expected = await fetchChecksum(`${base}/${asset}.sha256`);
|
|
216
|
+
if (expected) {
|
|
217
|
+
const actual = await sha256File(tmp);
|
|
218
|
+
if (actual !== expected) {
|
|
219
|
+
throw new Error(`${asset} SHA-256 校验不通过(期望 ${expected},实际 ${actual})`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const bytes = statSync(tmp).size;
|
|
223
|
+
// A truncated download that still passed (no checksum published) would leave
|
|
224
|
+
// an unrunnable binary in place of a working one. The real assets are ~100MB+;
|
|
225
|
+
// anything under a megabyte is a GitHub error page, not an executable.
|
|
226
|
+
if (bytes < 1_000_000) {
|
|
227
|
+
throw new Error(`${asset} 下载内容异常(仅 ${bytes} 字节,疑似错误页而非二进制)`);
|
|
228
|
+
}
|
|
229
|
+
chmodSync(tmp, 0o755);
|
|
230
|
+
// Atomic swap. NOT a write to `target` — that is ETXTBSY (see header).
|
|
231
|
+
renameSync(tmp, target);
|
|
232
|
+
return { asset, target, bytes };
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
rmSync(tmp, { force: true });
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=binary-self-update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-self-update.js","sourceRoot":"","sources":["../../src/core/binary-self-update.ts"],"names":[],"mappings":"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"}
|