@gjsify/cli 0.44.0 → 0.45.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.
Files changed (73) hide show
  1. package/dist/cli.gjs.mjs +192 -165
  2. package/lib/commands/gettext.d.ts +2 -1
  3. package/lib/commands/gettext.js +105 -47
  4. package/lib/commands/onboard.d.ts +7 -0
  5. package/lib/commands/onboard.js +349 -96
  6. package/lib/commands/ship.d.ts +3 -0
  7. package/lib/commands/ship.js +833 -54
  8. package/lib/commands/trust.d.ts +6 -0
  9. package/lib/commands/trust.js +1 -1
  10. package/lib/types/config-data.d.ts +63 -1
  11. package/lib/utils/msgfmt-merge.d.ts +35 -0
  12. package/lib/utils/msgfmt-merge.js +102 -0
  13. package/lib/utils/npm-otp.d.ts +27 -2
  14. package/lib/utils/npm-otp.js +82 -7
  15. package/lib/utils/onboard-discovery.d.ts +68 -0
  16. package/lib/utils/onboard-discovery.js +178 -0
  17. package/lib/utils/onboard-probe.d.ts +118 -1
  18. package/lib/utils/onboard-probe.js +153 -4
  19. package/lib/utils/prompt-output.d.ts +12 -0
  20. package/lib/utils/prompt-output.js +54 -0
  21. package/lib/utils/prompt.js +22 -2
  22. package/lib/utils/publishable-packages.d.ts +1 -1
  23. package/lib/utils/publishable-packages.js +1 -0
  24. package/lib/utils/resolve-npm-package.d.ts +56 -0
  25. package/lib/utils/resolve-npm-package.js +69 -0
  26. package/lib/utils/ship/app-runtime.d.ts +214 -0
  27. package/lib/utils/ship/app-runtime.js +429 -0
  28. package/lib/utils/ship/depends.d.ts +50 -0
  29. package/lib/utils/ship/depends.js +117 -3
  30. package/lib/utils/ship/discover.js +18 -1
  31. package/lib/utils/ship/dmg.d.ts +71 -0
  32. package/lib/utils/ship/dmg.js +181 -0
  33. package/lib/utils/ship/flatpak.js +1 -1
  34. package/lib/utils/ship/formats.d.ts +85 -7
  35. package/lib/utils/ship/formats.js +734 -15
  36. package/lib/utils/ship/launcher.d.ts +13 -3
  37. package/lib/utils/ship/launcher.js +362 -17
  38. package/lib/utils/ship/layout.d.ts +268 -0
  39. package/lib/utils/ship/layout.js +351 -0
  40. package/lib/utils/ship/localize-metadata.d.ts +22 -0
  41. package/lib/utils/ship/localize-metadata.js +126 -0
  42. package/lib/utils/ship/mime.js +1 -9
  43. package/lib/utils/ship/msi.d.ts +126 -0
  44. package/lib/utils/ship/msi.js +417 -0
  45. package/lib/utils/ship/node-runtime.d.ts +71 -0
  46. package/lib/utils/ship/node-runtime.js +122 -0
  47. package/lib/utils/ship/payload.d.ts +156 -5
  48. package/lib/utils/ship/payload.js +580 -14
  49. package/lib/utils/ship/plan.d.ts +21 -0
  50. package/lib/utils/ship/plan.js +20 -7
  51. package/lib/utils/ship/plist.d.ts +58 -0
  52. package/lib/utils/ship/plist.js +198 -0
  53. package/lib/utils/ship/rpm.js +9 -3
  54. package/lib/utils/ship/schemas.d.ts +61 -0
  55. package/lib/utils/ship/schemas.js +118 -0
  56. package/lib/utils/ship/scripts.js +7 -3
  57. package/lib/utils/ship/settings.d.ts +19 -1
  58. package/lib/utils/ship/settings.js +12 -1
  59. package/lib/utils/ship/share-dirs.d.ts +23 -0
  60. package/lib/utils/ship/share-dirs.js +46 -0
  61. package/lib/utils/ship/signing.d.ts +195 -0
  62. package/lib/utils/ship/signing.js +317 -0
  63. package/lib/utils/ship/stage-manifest.d.ts +40 -12
  64. package/lib/utils/ship/stage-manifest.js +99 -13
  65. package/lib/utils/ship/stage-writer.d.ts +48 -0
  66. package/lib/utils/ship/stage-writer.js +71 -1
  67. package/lib/utils/ship/types.d.ts +158 -13
  68. package/lib/utils/ship/xml.d.ts +7 -0
  69. package/lib/utils/ship/xml.js +25 -0
  70. package/lib/utils/ship/zip.d.ts +69 -0
  71. package/lib/utils/ship/zip.js +245 -0
  72. package/lib/utils/trust-registry.js +5 -0
  73. package/package.json +19 -19
@@ -14,3 +14,59 @@ export interface ResolveNpmPackageOptions {
14
14
  * `pathToFileURL().href` before a dynamic `import(...)`.
15
15
  */
16
16
  export declare function resolveNpmPackage(specifier: string, opts?: ResolveNpmPackageOptions): string | null;
17
+ /**
18
+ * The anchor a resolution was asked from — see {@link resolveInstalledPackage}.
19
+ *
20
+ * `'nowhere'` is a directory inside no project. Under Node it can only fail;
21
+ * under Bun it is where the sixth anchor shows itself.
22
+ */
23
+ export type PackageAnchor = 'project' | 'nowhere';
24
+ export interface ResolveInstalledPackageOptions extends ResolveNpmPackageOptions {
25
+ /**
26
+ * TEST SEAM — resolve `specifier` from one anchor, or `null`.
27
+ *
28
+ * Injected so Bun's behaviour below is reproducible from Node: a fake that
29
+ * answers the SAME path for both anchors is exactly what Bun does for a
30
+ * package the project never installed, and it is the only way to red this
31
+ * guard on a runtime that does not have the defect.
32
+ */
33
+ resolve?: (specifier: string, anchor: PackageAnchor) => string | null;
34
+ }
35
+ /**
36
+ * Resolve a bare specifier the way {@link resolveNpmPackage} does, but refuse an
37
+ * answer the RUNTIME invented rather than the project provided.
38
+ *
39
+ * THE SIXTH ANCHOR, which the list above does not mention because it is not
40
+ * ours. Bun auto-installs: `createRequire(<anchor>).resolve('<name>')` falls back
41
+ * to Bun's global install cache instead of throwing, so a package the project
42
+ * never declared resolves anyway. Measured, bun 1.3.14 vs node 24.19.0, asking
43
+ * for `@gjsify/node-gi` from a scratch directory:
44
+ *
45
+ * node → MODULE_NOT_FOUND
46
+ * bun → ~/.bun/install/cache/@gjsify/node-gi@0.44.0@@@1/index.js
47
+ *
48
+ * And it is not only the empty-directory case. A real project with a
49
+ * `package.json` and no `node_modules` — a fresh clone, or any Bun project
50
+ * relying on auto-install — gets the same cache hit, as does one that DECLARES
51
+ * the dependency without installing it. Only a `package.json` beside an EMPTY
52
+ * `node_modules` throws.
53
+ *
54
+ * WHY THAT MATTERS HERE AND NOT FOR {@link resolveNpmPackage}'s other callers.
55
+ * Resolving `rolldown` from a cache is fine: it is a TOOL, it runs and is
56
+ * forgotten. `@gjsify/node-gi`, `@gjsify/gtk-runtime-*` and
57
+ * `@gjsify/node-runtime-*` are PAYLOAD — `utils/ship/app-runtime.ts` copies
58
+ * their bytes into a `.app` that gets redistributed. A cache hit there ships
59
+ * files the project never declared, at whatever version that runtime happened to
60
+ * cache, and silently: the "install `<name>`" line that should have been printed
61
+ * never is. It is also #910's shape one level up, an addon paired with a closure
62
+ * it was not built against.
63
+ *
64
+ * THE DISCRIMINATOR IS A CONTROL, not a list of cache paths. Hardcoding
65
+ * `~/.bun/install/cache` would be this file guessing at another runtime's
66
+ * layout and going stale the first time Bun moves it. Asking the same question
67
+ * from a directory inside no project asks the RUNTIME instead: if both anchors
68
+ * answer with the identical path, the project contributed nothing to that
69
+ * answer. Under Node the control can only throw, so this is a strict no-op
70
+ * there — the resolution it returns is byte-identical to `resolveNpmPackage`'s.
71
+ */
72
+ export declare function resolveInstalledPackage(specifier: string, opts?: ResolveInstalledPackageOptions): string | null;
@@ -23,6 +23,7 @@
23
23
  // (parent-dir walker).
24
24
  import { createRequire } from 'node:module';
25
25
  import { pathToFileURL } from 'node:url';
26
+ import { tmpdir } from 'node:os';
26
27
  import { delimiter, join, resolve } from 'node:path';
27
28
  import { findWorkspaceRoot } from './workspace-root.js';
28
29
  /**
@@ -92,3 +93,71 @@ function tryResolveFromDir(specifier, dir) {
92
93
  return null;
93
94
  }
94
95
  }
96
+ /**
97
+ * A directory that is inside no project, for the control probe.
98
+ *
99
+ * It does not have to EXIST — measured under bun 1.3.14, a non-existent path
100
+ * still reaches the cache, so this costs no filesystem access. It must have a
101
+ * parent, though: an anchor at the filesystem root (`/__r__.js`) throws even
102
+ * under Bun, which would make the control silently useless.
103
+ */
104
+ const CONTROL_ANCHOR = join(tmpdir(), '.gjsify-nonexistent-control-anchor', '__gjsify_resolve__.js');
105
+ /**
106
+ * Resolve a bare specifier the way {@link resolveNpmPackage} does, but refuse an
107
+ * answer the RUNTIME invented rather than the project provided.
108
+ *
109
+ * THE SIXTH ANCHOR, which the list above does not mention because it is not
110
+ * ours. Bun auto-installs: `createRequire(<anchor>).resolve('<name>')` falls back
111
+ * to Bun's global install cache instead of throwing, so a package the project
112
+ * never declared resolves anyway. Measured, bun 1.3.14 vs node 24.19.0, asking
113
+ * for `@gjsify/node-gi` from a scratch directory:
114
+ *
115
+ * node → MODULE_NOT_FOUND
116
+ * bun → ~/.bun/install/cache/@gjsify/node-gi@0.44.0@@@1/index.js
117
+ *
118
+ * And it is not only the empty-directory case. A real project with a
119
+ * `package.json` and no `node_modules` — a fresh clone, or any Bun project
120
+ * relying on auto-install — gets the same cache hit, as does one that DECLARES
121
+ * the dependency without installing it. Only a `package.json` beside an EMPTY
122
+ * `node_modules` throws.
123
+ *
124
+ * WHY THAT MATTERS HERE AND NOT FOR {@link resolveNpmPackage}'s other callers.
125
+ * Resolving `rolldown` from a cache is fine: it is a TOOL, it runs and is
126
+ * forgotten. `@gjsify/node-gi`, `@gjsify/gtk-runtime-*` and
127
+ * `@gjsify/node-runtime-*` are PAYLOAD — `utils/ship/app-runtime.ts` copies
128
+ * their bytes into a `.app` that gets redistributed. A cache hit there ships
129
+ * files the project never declared, at whatever version that runtime happened to
130
+ * cache, and silently: the "install `<name>`" line that should have been printed
131
+ * never is. It is also #910's shape one level up, an addon paired with a closure
132
+ * it was not built against.
133
+ *
134
+ * THE DISCRIMINATOR IS A CONTROL, not a list of cache paths. Hardcoding
135
+ * `~/.bun/install/cache` would be this file guessing at another runtime's
136
+ * layout and going stale the first time Bun moves it. Asking the same question
137
+ * from a directory inside no project asks the RUNTIME instead: if both anchors
138
+ * answer with the identical path, the project contributed nothing to that
139
+ * answer. Under Node the control can only throw, so this is a strict no-op
140
+ * there — the resolution it returns is byte-identical to `resolveNpmPackage`'s.
141
+ */
142
+ export function resolveInstalledPackage(specifier, opts = {}) {
143
+ const resolve = opts.resolve ??
144
+ ((spec, anchor) => anchor === 'project'
145
+ ? resolveNpmPackage(spec, { cwd: opts.cwd, bundleUrl: opts.bundleUrl })
146
+ : tryResolveFromFile(spec, CONTROL_ANCHOR));
147
+ const hit = resolve(specifier, 'project');
148
+ if (hit === null)
149
+ return null;
150
+ const control = resolve(specifier, 'nowhere');
151
+ return control !== null && control === hit ? null : hit;
152
+ }
153
+ /** `createRequire(<file>).resolve(specifier)`, or `null`. The file need not exist. */
154
+ function tryResolveFromFile(specifier, anchorFile) {
155
+ try {
156
+ return createRequire(pathToFileURL(anchorFile).href).resolve(specifier);
157
+ }
158
+ catch {
159
+ // Not resolvable from a directory in no project — which is the answer
160
+ // this probe wants on every runtime without a global-cache fallback.
161
+ return null;
162
+ }
163
+ }
@@ -0,0 +1,214 @@
1
+ import type { Layout, LayoutIdentity } from './layout.js';
2
+ import { type ResolveInstalledPackageOptions } from '../resolve-npm-package.js';
3
+ import type { StagedFile } from './types.js';
4
+ /**
5
+ * The targets a relocated GTK closure is published for.
6
+ *
7
+ * The same three `@gjsify/gtk-runtime-*` packages node-gi resolves, and
8
+ * deliberately NOT derived from {@link NODE_RUNTIME_TARGETS}: the two lists agree
9
+ * today by coincidence of which platforms lack a dependable system stack, and
10
+ * deriving one from the other would make a future Linux GTK bundle silently imply
11
+ * a bundled Linux interpreter (which `node-runtime.ts` refuses on purpose).
12
+ */
13
+ export declare const GTK_RUNTIME_TARGETS: readonly ["darwin-arm64", "darwin-x64", "win32-x64"];
14
+ export type GtkRuntimeTarget = (typeof GTK_RUNTIME_TARGETS)[number];
15
+ /** Is this `<platform>-<arch>` one of the published GTK-closure targets? */
16
+ export declare function isGtkRuntimeTarget(target: string): target is GtkRuntimeTarget;
17
+ /** The npm name carrying the relocated closure for a target. One spelling, derived. */
18
+ export declare function gtkRuntimePackageName(target: GtkRuntimeTarget): string;
19
+ /** The addon's filename, node-gi's `ADDON_FILENAME`. Identical in every prebuild. */
20
+ export declare const NODE_GI_ADDON_FILENAME = "node_gi.node";
21
+ /** The package whose `prebuilds/<target>/` holds the addon and, in CI, the closure beside it. */
22
+ export declare const NODE_GI_PACKAGE = "@gjsify/node-gi";
23
+ /** Where the relocated GTK closure is, once found. */
24
+ export interface ResolvedGtkRuntime {
25
+ /** What produced the hit — an env var name, or the npm name it was resolved from. */
26
+ source: string;
27
+ /** The bundle directory: the one holding `lib/`, `girepository-1.0/`, `share/`. */
28
+ dir: string;
29
+ /** `<dir>/lib` on darwin, `<dir>/bin` on win32 — the loadable-code directory. */
30
+ libDir: string;
31
+ /** `<dir>/girepository-1.0`. */
32
+ typelibDir: string;
33
+ }
34
+ /** Where the node-gi addon is, once found. */
35
+ export interface ResolvedNodeGiAddon {
36
+ /** The npm name it was resolved from. */
37
+ source: string;
38
+ /** Absolute path to `node_gi.node`. */
39
+ addonPath: string;
40
+ }
41
+ export interface ResolveRuntimeOptions {
42
+ /** Project directory to resolve from — the consumer's, not gjsify's. */
43
+ cwd?: string;
44
+ /** Environment to read the overrides from. Injected so it is testable. */
45
+ env?: Record<string, string | undefined>;
46
+ /**
47
+ * TEST SEAM, passed through to {@link resolveInstalledPackage} — resolve a
48
+ * specifier from one anchor. A fake answering the SAME path for both anchors
49
+ * is Bun's global-cache behaviour, which is otherwise unreachable from Node.
50
+ */
51
+ resolve?: ResolveInstalledPackageOptions['resolve'];
52
+ }
53
+ /**
54
+ * Locate the relocated GTK closure for `target`, or `null`.
55
+ *
56
+ * The search order MIRRORS `resolveGtkRuntimeBundle()` rather than inventing a
57
+ * second one, because the two have to agree: this function decides what gets
58
+ * copied into the bundle, and that function decides what the bundle finds at
59
+ * runtime. Four candidates, first complete hit wins:
60
+ *
61
+ * 1. `GJSIFY_GTK_RUNTIME` — an explicit bundle directory, for a maintainer
62
+ * holding an unpublished or patched closure. The same variable the launcher
63
+ * later EXPORTS, and the same precedence it has there.
64
+ * 2. `@gjsify/node-gi`'s own `prebuilds/<target>/gtk`. This is the layout the
65
+ * macOS CI legs stage by hand (`node-gi.yml`: download the bundle artifact
66
+ * into `prebuilds/darwin-<arch>/gtk`, the addon beside it), so a job that has
67
+ * prepared node-gi for a conformance run has, by that act alone, prepared it
68
+ * for a ship run.
69
+ * 3. the sibling monorepo directory `../gtk-runtime-<target>/gtk`, which is what
70
+ * an in-repo `npm run build:bundle` writes.
71
+ * 4. the published `@gjsify/gtk-runtime-<target>` package's `gtk/`.
72
+ *
73
+ * A candidate counts only when it holds BOTH the loadable-code directory and the
74
+ * typelib directory — node-gi's own probe, restated here rather than weakened,
75
+ * because a directory that passes here and fails there is a `.app` that ships
76
+ * 200 MB and still cannot open a window.
77
+ */
78
+ export declare function resolveGtkRuntime(target: GtkRuntimeTarget, options?: ResolveRuntimeOptions): ResolvedGtkRuntime | null;
79
+ /**
80
+ * Locate the node-gi addon built for `target`, or `null`.
81
+ *
82
+ * ONE source, and no override. The addon and the closure ship as a matched pair —
83
+ * the addon's `@rpath` is `@loader_path/gtk/lib`, so it names the very directory
84
+ * the closure occupies — and `@gjsify/node-gi` publishes `prebuilds/` for all five
85
+ * of its platforms in ONE package, so resolving the package by name is already
86
+ * enough to reach a foreign target's binary from a Linux host. A second
87
+ * environment knob here would be a way to pair an addon with a closure it was not
88
+ * built against, which is #910's failure shape wearing a convenience.
89
+ */
90
+ export declare function resolveNodeGiAddon(target: GtkRuntimeTarget, options?: ResolveRuntimeOptions): ResolvedNodeGiAddon | null;
91
+ /** node-gi's JavaScript, as package-relative paths. */
92
+ export interface ResolvedNodeGiPackage {
93
+ source: string;
94
+ /** The package root the files are relative to. */
95
+ root: string;
96
+ /** POSIX-separated, package-relative — `package.json`, the root `.js`, `overrides/**`. */
97
+ files: string[];
98
+ }
99
+ /**
100
+ * The files a SHIPPED `.app` needs from `@gjsify/node-gi`, or `null`.
101
+ *
102
+ * NOT the published tarball. `files` in node-gi's manifest also lists `src/`,
103
+ * `binding.gyp` and `scripts/install.mjs` — the inputs to `node-gyp`, which a
104
+ * `.app` never runs — and the `.d.ts` declarations, which nothing inside a bundle
105
+ * compiles against. And it lists `prebuilds/`, which this module stages into
106
+ * `Contents/Frameworks` instead, where a `.app` keeps loadable code.
107
+ *
108
+ * So the rule is what `require('@gjsify/node-gi/<subpath>')` can REACH:
109
+ * `package.json` (the `exports` map is what resolves every subpath), every `.js`
110
+ * at the package root (every `exports` target is one), and `overrides/`, which
111
+ * `gi.js` loads at runtime. `tests/e2e/ship-macos` holds that rule against the
112
+ * REAL package's `exports` map, so a node-gi release that adds an entry outside
113
+ * this set fails there rather than in a `.app` a stranger downloaded.
114
+ */
115
+ export declare function resolveNodeGiPackage(options?: ResolveRuntimeOptions): ResolvedNodeGiPackage | null;
116
+ /**
117
+ * Where each piece of the runtime lands inside the bundle — STAGE-relative.
118
+ *
119
+ * PURE, and derived from `Layout.dirs` rather than from a second set of string
120
+ * literals, so the paths the launcher exports and the paths the stager writes
121
+ * cannot drift: they are computed here once and both callers read this result.
122
+ *
123
+ * `Contents/Frameworks/node-gi/prebuilds/<target>/` is node-gi's OWN sibling
124
+ * layout reproduced verbatim inside `dirs.native`. It is not a naming preference:
125
+ * `resolveGtkRuntimeBundle()` probes `<dir>/lib` and `<dir>/girepository-1.0`,
126
+ * the addon's `@rpath` is `@loader_path/gtk/lib`, and `loaders.cache` addresses
127
+ * each pixbuf loader relative to the bundle toplevel. Reproducing the shape is
128
+ * what makes every one of those relations still true after the copy.
129
+ */
130
+ export interface AppRuntimePaths {
131
+ /** `<App>.app/Contents/Frameworks/node-gi` — the package root the layout imitates. */
132
+ nodeGiRoot: string;
133
+ /**
134
+ * `<App>.app/Contents/Resources/lib/node_modules/@gjsify/node-gi` — where
135
+ * node-gi's JAVASCRIPT goes.
136
+ *
137
+ * Not a preference: `require('@gjsify/node-gi/gi')` from the staged bundle at
138
+ * `Contents/Resources/lib/<bundle>.mjs` walks `node_modules` upward from that
139
+ * file's own directory, and this is the FIRST directory that walk visits. Any
140
+ * other location works only by accident of what sits above the bundle.
141
+ */
142
+ nodeGiPackageDir: string;
143
+ /** `<nodeGiRoot>/prebuilds/<target>` — the addon and the closure, siblings. */
144
+ prebuildDir: string;
145
+ /** `<prebuildDir>/gtk` — what `GJSIFY_GTK_RUNTIME` names. */
146
+ gtkDir: string;
147
+ /** `<prebuildDir>/node_gi.node` — what `NODE_GI_NATIVE` pins. */
148
+ addonPath: string;
149
+ /**
150
+ * `<App>.app/Contents/MacOS/node`, or `<program dir>/node.exe` — beside the
151
+ * launcher that execs it, under the name the target's own release uses.
152
+ */
153
+ interpreterPath: string;
154
+ /** Node's own LICENSE, under `Contents/Resources` (macOS) or `share/` (Windows). */
155
+ interpreterLicensePath: string;
156
+ }
157
+ export declare function appRuntimePaths(layout: Layout, identity: LayoutIdentity, target: GtkRuntimeTarget): AppRuntimePaths;
158
+ /** What the launcher must export and exec, once the runtime is staged. Absent member = not staged. */
159
+ export interface LauncherRuntime {
160
+ /** Stage-relative path of the interpreter the bundle carries. */
161
+ interpreter?: string;
162
+ /** Stage-relative path of the GTK closure — `GJSIFY_GTK_RUNTIME`. */
163
+ gtkRuntimeDir?: string;
164
+ /** Stage-relative path of the node-gi addon — `NODE_GI_NATIVE`. */
165
+ nodeGiAddon?: string;
166
+ }
167
+ /** The staged runtime, and an account of what was and was not found. */
168
+ export interface StagedAppRuntime {
169
+ /** Stage-relative files, already placed — they never passed through the prefix-relative plan. */
170
+ files: StagedFile[];
171
+ /** What the launcher can now name. */
172
+ launcher: LauncherRuntime;
173
+ /** One line per piece that WAS found, naming where it came from. */
174
+ found: string[];
175
+ /** One line per piece that was not, naming the package to install. */
176
+ missing: string[];
177
+ }
178
+ export interface StageAppRuntimeInput {
179
+ layout: Layout;
180
+ identity: LayoutIdentity;
181
+ /** `${layout.os}-${settings.arch}` — the target the payload was built for. */
182
+ target: GtkRuntimeTarget;
183
+ /** Project directory the three packages are resolved from. */
184
+ cwd: string;
185
+ /** Injected so the overrides are testable. */
186
+ env?: Record<string, string | undefined>;
187
+ /** Passed to every discovery below — see {@link ResolveRuntimeOptions.resolve}. */
188
+ resolve?: ResolveRuntimeOptions['resolve'];
189
+ /** The interpreter, already resolved — see `node-runtime.ts`. `null` when absent. */
190
+ interpreter: {
191
+ source: string;
192
+ nodePath: string;
193
+ licensePath: string;
194
+ } | null;
195
+ }
196
+ /**
197
+ * Stage the interpreter, the GTK closure and the addon into one bundle.
198
+ *
199
+ * PARTIAL BY DESIGN, and reported. An all-or-nothing rule would drop a 200 MB
200
+ * closure that IS present because an interpreter that is not shares the milestone
201
+ * with it, and would do it at exit 0 — while a bundle carrying the closure and no
202
+ * interpreter is a real, useful intermediate (it runs wherever a Node is on
203
+ * `PATH`, which is every developer's machine and no stranger's). So each piece is
204
+ * staged when found and named when not, and `commands/ship.ts` keeps
205
+ * `Layout.runtimeGap` for precisely the case where the interpreter is still
206
+ * missing.
207
+ *
208
+ * TREE-PRESERVING for the closure and FLAT for the other two, which is the whole
209
+ * distinction this module exists to draw: `listFilesRecursive` walks the bundle
210
+ * and every relative path is carried through unchanged, so
211
+ * `lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.so` is still four levels
212
+ * under `gtk/` on the other side of the copy.
213
+ */
214
+ export declare function stageAppRuntime(input: StageAppRuntimeInput): StagedAppRuntime;