@gjsify/cli 0.4.16 → 0.4.18
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/cli.gjs.mjs +143 -142
- package/lib/commands/install.js +23 -4
- package/lib/commands/uninstall.js +17 -5
- package/lib/index.js +11 -1
- package/lib/utils/install-global.js +34 -1
- package/package.json +15 -15
package/lib/commands/install.js
CHANGED
|
@@ -354,6 +354,14 @@ async function workspaceInstall(cwd, args) {
|
|
|
354
354
|
// target in a shell script that picks the right interpreter (`gjs -m`
|
|
355
355
|
// for `.mjs` bundles, `node` for `.js` files).
|
|
356
356
|
const wsBinDir = join(cwd, 'node_modules', '.bin');
|
|
357
|
+
// Discover native prebuilds reachable from the workspace cwd so the
|
|
358
|
+
// workspace-local `node_modules/.bin/gjsify` shim sets GI_TYPELIB_PATH /
|
|
359
|
+
// LD_LIBRARY_PATH for them. Same rationale as the global launcher in
|
|
360
|
+
// install-global.ts — the bin shim invokes the CLI bundle via `gjs -m`
|
|
361
|
+
// directly, with no chance to set env after the fact, so without this
|
|
362
|
+
// preamble `imports.gi.GjsifyTerminal` etc. fail and process.stdout
|
|
363
|
+
// collapses to no-color, 80-col defaults.
|
|
364
|
+
const nativePrebuildDirs = detectNativePackages(cwd).map((p) => p.prebuildsDir);
|
|
357
365
|
let wsBinsCreated = 0;
|
|
358
366
|
for (const ws of workspaces) {
|
|
359
367
|
const m = ws.manifest;
|
|
@@ -375,7 +383,7 @@ async function workspaceInstall(cwd, args) {
|
|
|
375
383
|
rmSync(linkPath, { force: true });
|
|
376
384
|
}
|
|
377
385
|
catch { /* fine */ }
|
|
378
|
-
writeFileSync(linkPath, buildBinShim(ws.location, nodeTarget, gjsTarget), { mode: 0o755 });
|
|
386
|
+
writeFileSync(linkPath, buildBinShim(ws.location, nodeTarget, gjsTarget, nativePrebuildDirs), { mode: 0o755 });
|
|
379
387
|
chmodSync(linkPath, 0o755);
|
|
380
388
|
wsBinsCreated++;
|
|
381
389
|
}
|
|
@@ -441,16 +449,27 @@ function extractOverrides(rootManifest) {
|
|
|
441
449
|
merge(rootManifest.resolutions, 'resolutions');
|
|
442
450
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
443
451
|
}
|
|
444
|
-
function buildBinShim(wsLocation, nodeTarget, gjsTarget) {
|
|
452
|
+
function buildBinShim(wsLocation, nodeTarget, gjsTarget, nativePrebuildDirs = []) {
|
|
445
453
|
const nodeAbs = nodeTarget ? join(wsLocation, nodeTarget) : null;
|
|
446
454
|
const gjsAbs = gjsTarget ? join(wsLocation, gjsTarget) : null;
|
|
455
|
+
// GJS-only env preamble — Node ignores GI_TYPELIB_PATH so we scope the
|
|
456
|
+
// export to the gjs branch, keeping the shim minimal when no native pkgs
|
|
457
|
+
// exist or only the Node bin is in play.
|
|
458
|
+
const gjsPreamble = nativePrebuildDirs.length === 0
|
|
459
|
+
? ''
|
|
460
|
+
: (() => {
|
|
461
|
+
const joined = `'${nativePrebuildDirs.join(':').replace(/'/g, `'\\''`)}'`;
|
|
462
|
+
return (`GI_TYPELIB_PATH=${joined}\${GI_TYPELIB_PATH:+":$GI_TYPELIB_PATH"}\n` +
|
|
463
|
+
`LD_LIBRARY_PATH=${joined}\${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}\n` +
|
|
464
|
+
`export GI_TYPELIB_PATH LD_LIBRARY_PATH\n`);
|
|
465
|
+
})();
|
|
447
466
|
if (nodeAbs && gjsAbs) {
|
|
448
|
-
return `#!/bin/sh\nif [ -f "${nodeAbs}" ]; then\n exec node "${nodeAbs}" "$@"\nfi\
|
|
467
|
+
return `#!/bin/sh\nif [ -f "${nodeAbs}" ]; then\n exec node "${nodeAbs}" "$@"\nfi\n${gjsPreamble}exec gjs -m "${gjsAbs}" "$@"\n`;
|
|
449
468
|
}
|
|
450
469
|
if (nodeAbs)
|
|
451
470
|
return `#!/bin/sh\nexec node "${nodeAbs}" "$@"\n`;
|
|
452
471
|
if (gjsAbs)
|
|
453
|
-
return `#!/bin/sh\
|
|
472
|
+
return `#!/bin/sh\n${gjsPreamble}exec gjs -m "${gjsAbs}" "$@"\n`;
|
|
454
473
|
throw new Error('buildBinShim: either nodeTarget or gjsTarget must be provided');
|
|
455
474
|
}
|
|
456
475
|
/**
|
|
@@ -97,13 +97,18 @@ export const uninstallCommand = {
|
|
|
97
97
|
* #!/bin/sh
|
|
98
98
|
* exec '<absolute-path>' "$@"
|
|
99
99
|
*
|
|
100
|
-
* or (for `.gjs.mjs` / `.mjs` targets
|
|
100
|
+
* or (for `.gjs.mjs` / `.mjs` targets, with optional GI_TYPELIB_PATH /
|
|
101
|
+
* LD_LIBRARY_PATH preamble for native @gjsify/* prebuilds):
|
|
101
102
|
*
|
|
102
103
|
* #!/bin/sh
|
|
104
|
+
* GI_TYPELIB_PATH='<dirs>'${GI_TYPELIB_PATH:+":$GI_TYPELIB_PATH"}
|
|
105
|
+
* LD_LIBRARY_PATH='<dirs>'${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}
|
|
106
|
+
* export GI_TYPELIB_PATH LD_LIBRARY_PATH
|
|
103
107
|
* exec gjs -m '<absolute-path>' "$@"
|
|
104
108
|
*
|
|
105
|
-
* We
|
|
106
|
-
*
|
|
109
|
+
* We extract the single-quoted path on the `exec` line (NOT the first quoted
|
|
110
|
+
* string in the file, which with the preamble is the prebuild dir list) and
|
|
111
|
+
* check whether it's under `pkgDir`. Non-shim files (e.g. unrelated binaries
|
|
107
112
|
* the user installed via `npm install -g`) are skipped silently.
|
|
108
113
|
*/
|
|
109
114
|
function findBinShimsForPackage(binDir, pkgDir, verbose) {
|
|
@@ -126,8 +131,15 @@ function findBinShimsForPackage(binDir, pkgDir, verbose) {
|
|
|
126
131
|
const content = readFileSync(fullPath, 'utf-8');
|
|
127
132
|
if (!content.startsWith('#!/bin/sh'))
|
|
128
133
|
continue;
|
|
129
|
-
//
|
|
130
|
-
|
|
134
|
+
// Find the `exec [gjs -m] '<target>' "$@"` line; the path may
|
|
135
|
+
// contain `:` from the optional prebuild preamble lines, which
|
|
136
|
+
// is why we anchor to `exec ` rather than the first quoted run.
|
|
137
|
+
const execLine = content
|
|
138
|
+
.split('\n')
|
|
139
|
+
.find((line) => /^exec (?:gjs -m )?'/.test(line));
|
|
140
|
+
if (!execLine)
|
|
141
|
+
continue;
|
|
142
|
+
const m = execLine.match(/'([^']+)'/);
|
|
131
143
|
if (!m)
|
|
132
144
|
continue;
|
|
133
145
|
const target = m[1];
|
package/lib/index.js
CHANGED
|
@@ -8,9 +8,19 @@ import { APP_NAME } from './constants.js';
|
|
|
8
8
|
// cosmetic — the event loop holds the process up — but under GJS the
|
|
9
9
|
// script ends as soon as the top-level synchronous flow finishes, and
|
|
10
10
|
// fire-and-forget handlers silently exit before any async work runs.
|
|
11
|
-
|
|
11
|
+
const cli = yargs(hideBin(process.argv));
|
|
12
|
+
await cli
|
|
12
13
|
.scriptName(APP_NAME)
|
|
13
14
|
.strict()
|
|
15
|
+
// Use the full terminal width for help. yargs's default caps at 80
|
|
16
|
+
// (`Math.min(80, process.stdout.columns)`); we explicitly opt into
|
|
17
|
+
// the real terminal width so long option/description lines wrap at
|
|
18
|
+
// the actual terminal edge instead of an arbitrary 80-col limit.
|
|
19
|
+
// `terminalWidth()` reads `process.stdout.columns`, which under GJS
|
|
20
|
+
// is backed by @gjsify/terminal-native (ioctl TIOCGWINSZ) when the
|
|
21
|
+
// typelib is on GI_TYPELIB_PATH — see the global launcher in
|
|
22
|
+
// packages/infra/cli/src/utils/install-global.ts.
|
|
23
|
+
.wrap(cli.terminalWidth())
|
|
14
24
|
.command(create.command, create.description, create.builder, create.handler)
|
|
15
25
|
.command(install.command, install.description, install.builder, install.handler)
|
|
16
26
|
.command(build.command, build.description, build.builder, build.handler)
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import * as fs from 'node:fs';
|
|
24
24
|
import * as os from 'node:os';
|
|
25
25
|
import * as path from 'node:path';
|
|
26
|
+
import { detectNativePackages } from './detect-native-packages.js';
|
|
26
27
|
/**
|
|
27
28
|
* Compute the canonical global install layout for the current user. Honours
|
|
28
29
|
* `XDG_DATA_HOME` (per the XDG Base Directory Spec) plus
|
|
@@ -67,6 +68,18 @@ export function defaultGlobalLayout() {
|
|
|
67
68
|
export function linkGlobalBins(packageNames, layout) {
|
|
68
69
|
fs.mkdirSync(layout.binDir, { recursive: true });
|
|
69
70
|
const created = [];
|
|
71
|
+
// Discover @gjsify/* packages with native prebuilds (Vala/GObject typelibs
|
|
72
|
+
// + shared libs) under the global prefix. The launcher bakes their
|
|
73
|
+
// directories into GI_TYPELIB_PATH / LD_LIBRARY_PATH so `imports.gi.X`
|
|
74
|
+
// resolves at CLI startup — required for e.g. @gjsify/terminal-native,
|
|
75
|
+
// without which process.stdout.isTTY / columns / colors all fall back to
|
|
76
|
+
// the conservative env-only defaults (no colors, 80-col wrap).
|
|
77
|
+
//
|
|
78
|
+
// `runGjsBundle()` does the same dance for `gjsify run <bundle>` at
|
|
79
|
+
// runtime; here we do it at install time because the global launcher
|
|
80
|
+
// invokes the CLI bundle directly, with no opportunity to set env first.
|
|
81
|
+
const nativePrebuildDirs = detectNativePackages(layout.prefix).map((p) => p.prebuildsDir);
|
|
82
|
+
const envPreamble = buildLauncherEnvPreamble(nativePrebuildDirs);
|
|
70
83
|
for (const pkgName of packageNames) {
|
|
71
84
|
const pkgDir = path.join(layout.prefix, 'node_modules', pkgName);
|
|
72
85
|
const pkgJsonPath = path.join(pkgDir, 'package.json');
|
|
@@ -101,8 +114,11 @@ export function linkGlobalBins(packageNames, layout) {
|
|
|
101
114
|
// then tries to parse JavaScript as shell. Plain Node scripts
|
|
102
115
|
// with shebangs (lib/index.js) keep the direct-exec path.
|
|
103
116
|
const isGjsBundle = targetAbs.endsWith('.gjs.mjs') || targetAbs.endsWith('.mjs');
|
|
117
|
+
// Only GJS bundles need the GI typelib search path. Plain Node
|
|
118
|
+
// scripts ignore GI_TYPELIB_PATH, so skipping the preamble there
|
|
119
|
+
// keeps the launcher minimal.
|
|
104
120
|
const launcher = isGjsBundle
|
|
105
|
-
? `#!/bin/sh\
|
|
121
|
+
? `#!/bin/sh\n${envPreamble}exec gjs -m ${shQuote(targetAbs)} "$@"\n`
|
|
106
122
|
: `#!/bin/sh\nexec ${shQuote(targetAbs)} "$@"\n`;
|
|
107
123
|
fs.writeFileSync(linkPath, launcher);
|
|
108
124
|
fs.chmodSync(linkPath, 0o755);
|
|
@@ -114,6 +130,23 @@ export function linkGlobalBins(packageNames, layout) {
|
|
|
114
130
|
function shQuote(s) {
|
|
115
131
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
116
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Build the POSIX-sh `export` lines that prepend the given prebuild
|
|
135
|
+
* directories to GI_TYPELIB_PATH and LD_LIBRARY_PATH. Any pre-existing value
|
|
136
|
+
* inherited from the user's environment is preserved as a suffix so
|
|
137
|
+
* user-installed typelibs/libraries still resolve.
|
|
138
|
+
*
|
|
139
|
+
* Returns the empty string when no prebuilds were found — avoids emitting an
|
|
140
|
+
* inert assignment in the launcher.
|
|
141
|
+
*/
|
|
142
|
+
function buildLauncherEnvPreamble(prebuildsDirs) {
|
|
143
|
+
if (prebuildsDirs.length === 0)
|
|
144
|
+
return '';
|
|
145
|
+
const joined = shQuote(prebuildsDirs.join(':'));
|
|
146
|
+
return (`GI_TYPELIB_PATH=${joined}\${GI_TYPELIB_PATH:+":$GI_TYPELIB_PATH"}\n` +
|
|
147
|
+
`LD_LIBRARY_PATH=${joined}\${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}\n` +
|
|
148
|
+
`export GI_TYPELIB_PATH LD_LIBRARY_PATH\n`);
|
|
149
|
+
}
|
|
117
150
|
function pickBinMap(pkgName, pkgJson) {
|
|
118
151
|
const gjsifyEntry = pkgJson.gjsify;
|
|
119
152
|
if (gjsifyEntry?.bin !== undefined) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.18",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -37,18 +37,18 @@
|
|
|
37
37
|
"cli"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@gjsify/buffer": "^0.4.
|
|
41
|
-
"@gjsify/create-app": "^0.4.
|
|
42
|
-
"@gjsify/node-globals": "^0.4.
|
|
43
|
-
"@gjsify/node-polyfills": "^0.4.
|
|
44
|
-
"@gjsify/npm-registry": "^0.4.
|
|
45
|
-
"@gjsify/resolve-npm": "^0.4.
|
|
46
|
-
"@gjsify/rolldown-plugin-gjsify": "^0.4.
|
|
47
|
-
"@gjsify/rolldown-plugin-pnp": "^0.4.
|
|
48
|
-
"@gjsify/semver": "^0.4.
|
|
49
|
-
"@gjsify/tar": "^0.4.
|
|
50
|
-
"@gjsify/web-polyfills": "^0.4.
|
|
51
|
-
"@gjsify/workspace": "^0.4.
|
|
40
|
+
"@gjsify/buffer": "^0.4.18",
|
|
41
|
+
"@gjsify/create-app": "^0.4.18",
|
|
42
|
+
"@gjsify/node-globals": "^0.4.18",
|
|
43
|
+
"@gjsify/node-polyfills": "^0.4.18",
|
|
44
|
+
"@gjsify/npm-registry": "^0.4.18",
|
|
45
|
+
"@gjsify/resolve-npm": "^0.4.18",
|
|
46
|
+
"@gjsify/rolldown-plugin-gjsify": "^0.4.18",
|
|
47
|
+
"@gjsify/rolldown-plugin-pnp": "^0.4.18",
|
|
48
|
+
"@gjsify/semver": "^0.4.18",
|
|
49
|
+
"@gjsify/tar": "^0.4.18",
|
|
50
|
+
"@gjsify/web-polyfills": "^0.4.18",
|
|
51
|
+
"@gjsify/workspace": "^0.4.18",
|
|
52
52
|
"cosmiconfig": "^9.0.1",
|
|
53
53
|
"get-tsconfig": "^4.14.0",
|
|
54
54
|
"pkg-types": "^2.3.1",
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
"yargs": "^18.0.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@gjsify/unit": "^0.4.
|
|
59
|
+
"@gjsify/unit": "^0.4.18",
|
|
60
60
|
"@types/yargs": "^17.0.35",
|
|
61
61
|
"typescript": "^6.0.3"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@gjsify/rolldown-native": "^0.4.
|
|
64
|
+
"@gjsify/rolldown-native": "^0.4.18"
|
|
65
65
|
},
|
|
66
66
|
"peerDependenciesMeta": {
|
|
67
67
|
"@gjsify/rolldown-native": {
|