@gjsify/cli 0.4.24 → 0.4.25
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 +1 -1
- package/lib/commands/install.js +27 -6
- package/package.json +15 -15
package/dist/cli.gjs.mjs
CHANGED
|
@@ -791,7 +791,7 @@ jobs:
|
|
|
791
791
|
`)}function lockfileToNodes(n){return Object.entries(n.packages).map(([n,a])=>({name:nameFromInstallPath(n),version:a.version,tarballUrl:a.resolved,integrity:a.integrity,installPath:n,dependencies:a.dependencies??{},optionalDependencies:{},bin:a.bin}))}function nameFromInstallPath(n){let a=n.lastIndexOf(`/node_modules/`);return a<0?n.replace(/^node_modules\//,``):n.slice(a+14)}function lockfileMatchesRequest(n,a){if(n.requested.length!==a.length)return!1;let S=[...n.requested].sort(),C=[...a].sort();return S.every((n,a)=>n===C[a])}function describeLockfileDrift(n,a){let S=new Set(n.requested),C=new Set(a),N=[],F=[];for(let n of C)S.has(n)||N.push(n);for(let n of S)C.has(n)||F.push(n);if(N.length===0&&F.length===0)return null;let I=[];return N.length>0&&I.push(` + ${N.sort().join(`
|
|
792
792
|
+ `)}`),F.length>0&&I.push(` - ${F.sort().join(`
|
|
793
793
|
- `)}`),I.join(`
|
|
794
|
-
`)}function parseSpec(n){if(n.startsWith(`@`)){let a=n.indexOf(`/`);if(a<0)throw Error(`Invalid spec (scoped name without slash): ${n}`);let S=n.indexOf(`@`,a);return S<0?{name:n,range:`latest`}:{name:n.slice(0,S),range:n.slice(S+1)||`latest`}}let a=n.indexOf(`@`);return a<0?{name:n,range:`latest`}:{name:n.slice(0,a),range:n.slice(a+1)||`latest`}}function pickVersion(n,a){if(n[`dist-tags`][a])return n[`dist-tags`][a];let S;try{S=new BE(a)}catch{throw Error(`Invalid version range for ${n.name}: ${a}`)}return maxSatisfying(Object.keys(n.versions).filter(n=>{try{return new SemVer(n),!0}catch{return!1}}),S)}async function downloadAndExtractAll(n,a,S,C){let N=[...n].sort((n,a)=>depth(n.installPath)-depth(a.installPath)||(n.installPath<a.installPath?-1:1)),F=[],I=Math.max(1,Math.min(XE,N.length)),H=0,W=N.findIndex(n=>depth(n.installPath)>1),K=W<0?N.length:W;for(;H<K;){let n=N[H++];if(!n)break;await extractOne(n,a,S,C)}for(let n=0;n<I;n++)F.push((async()=>{for(;;){let n=H++;if(n>=N.length)return;let F=N[n];if(!F)return;await extractOne(F,a,S,C)}})());await Promise.all(F)}async function extractOne(n,a,S,C){let N=jo(a,n.installPath);C(`fetch: %s@%s ← %s (→ %s)`,n.name,n.version,n.tarballUrl,n.installPath);let F=await fetchTarball(n.tarballUrl,{npmrc:S,integrity:n.integrity,onRetry:({attempt:a,error:S,delayMs:N})=>{C(`tarball %s@%s: retry %d after %dms (%s)`,n.name,n.version,a,N,errMsg(S))}});rmSync(N,{recursive:!0,force:!0}),mkdirSync(N,{recursive:!0}),await extractTarball(F,N)}function depth(n){return n.split(`/node_modules/`).length}async function linkBins(n,a,S){let C=jo(a,`node_modules`,`.bin`),N=0;for(let S of n){if(!S.bin||depth(S.installPath)!==1)continue;let n=normalizeBin$1(S.name,S.bin);if(n.size!==0){mkdirSync(C,{recursive:!0});for(let[F,I]of n){let n=jo(a,S.installPath,I);if(!existsSync(n))continue;try{chmodSync(n,493)}catch{}let H=jo(C,F);rmSync(H,{force:!0});let W=Mo(C,n);try{symlinkSync(W,H),N++}catch{copyFileSync(n,H),chmodSync(H,493),N++}}}}N>0&&S(`bin: linked %d entry(ies) under .bin/`,N)}function normalizeBin$1(n,a){let S=new Map;if(typeof a==`string`){let C=n.startsWith(`@`)?n.slice(n.indexOf(`/`)+1):n;return S.set(C,a),S}for(let[n,C]of Object.entries(a))S.set(n,C);return S}async function loadNpmrc$1(n){let a=homedir(),S={registry:n.registry??HE,scopes:{},authTokens:{},basicAuth:{}};for(let C of[jo(a,`.npmrc`),jo(n.prefix,`.npmrc`)])if(existsSync(C))try{let n=parseNpmrc(readFileSync(C,`utf-8`));S={...S,...n,scopes:{...S.scopes,...n.scopes}}}catch(n){Fe.warn(`gjsify install: ignoring malformed ${C}: ${n.message}`)}let C=process.env.npm_config_registry;return C&&(S.registry=C),n.registry&&(S.registry=n.registry),S}function makeLogger(n){return n?(n,...a)=>{let S=n.replace(/%s|%d/g,()=>String(a.shift()));process.stderr.write(`gjsify install: ${S}\n`)}:()=>{}}var XE,ZE,QE,$E=__esmMin(()=>{Ie(),As(),Ho(),Dp(),VE(),UE(),JE(),XE=Number(process.env.GJSIFY_INSTALL_CONCURRENCY??`8`)||8,ZE=`gjsify-lock.json`,QE=2,__name$1(normalizeBin$1,`normalizeBin`),__name$1(loadNpmrc$1,`loadNpmrc`)});Bx(),As(),Ho();const eD=process.env.GJSIFY_INSTALL_BACKEND??`native`;async function installPackages(n){if(eD===`npm`)return await installViaNpm(n),{installed:[]};let{installPackagesNative:a}=await Promise.resolve().then(()=>($E(),YE));return{installed:await a(n)}}async function installViaNpm({prefix:n,specs:a,verbose:S,registry:C}){if(a.length===0)throw Error(`installPackages: empty specs list`);writeFileSync(jo(n,`package.json`),JSON.stringify({name:`gjsify-dlx-cache`,version:`0.0.0`,private:!0},null,2)),C&&writeFileSync(jo(n,`.npmrc`),`registry=${C}\n`);let N=[`install`,`--no-package-lock`,`--no-audit`,`--no-fund`,`--prefix`,n,...S?[`--loglevel`,`verbose`]:[`--loglevel`,`warn`],...a];await new Promise((n,a)=>{let S=spawn(`npm`,N,{stdio:`inherit`});S.on(`close`,S=>{S===0?n():a(Error(`npm install exited with code ${S}`))}),S.on(`error`,n=>{let S=n.code===`ENOENT`?`npm not found on PATH — install Node.js or set GJSIFY_INSTALL_BACKEND=native (not yet supported)`:`npm install failed: ${n.message}`;a(Error(S))})})}Ie(),As(),Ho();const tD={command:`dlx <spec> [binOrArg] [extraArgs..]`,description:`Run the GJS bundle of an npm-published package without installing it locally.`,builder:n=>n.parserConfiguration({"populate--":!0}).positional(`spec`,{description:"Package spec (`name`, `name@version`, `@scope/name@spec`, or local path).",type:`string`,demandOption:!0}).positional(`binOrArg`,{description:"Optional bin name when the package defines `gjsify.bin` with multiple entries; otherwise treated as the first argument forwarded to the bundle. To pass a flag here (e.g. `--help`) use the `--` separator: `gjsify dlx <pkg> -- --help`.",type:`string`}).positional(`extraArgs`,{description:"Extra args forwarded to `gjs -m <bundle>`. Use `--` before flags to bypass gjsify-level parsing (`gjsify dlx <pkg> -- --help --verbose`).",type:`string`,array:!0}).option(`cache-max-age`,{description:`Cache TTL in minutes. Defaults to 7 days. Use 0 to bypass cache.`,type:`number`,default:1440*7}).option(`reinstall`,{description:`Bypass the cache for this run (alias for --cache-max-age=0).`,type:`boolean`,default:!1}).option(`frozen`,{description:`Use the project-local gjsify-lock.json verbatim — fail if missing or stale (no resolver pass).`,type:`boolean`,default:!1}).option(`verbose`,{description:`Verbose logging (passes --loglevel verbose to npm).`,type:`boolean`,default:!1}).option(`registry`,{description:`Registry URL override.`,type:`string`}),handler:async n=>{let a=parseSpec$1(n.spec),S=n.reinstall?0:n[`cache-max-age`],{pkgDir:C,cachedPkgName:N}=await ensurePkgDir(a,{verbose:n.verbose,registry:n.registry,cacheMaxAge:S,frozen:n.frozen}),F=(n[`--`]??[]).map(n=>String(n)),I=[...n.extraArgs??[],...F],{binName:H,extraArgs:W}=splitBinAndArgs(C,n.binOrArg,I),K=resolveGjsEntry(C,H);K.fromFallback&&Fe.warn(`[gjsify dlx] package "${N??a.kind}" has no \`gjsify\` field — falling back to package.json#main. Add \`gjsify.main\` to silence.`),await runGjsBundle(K.bundlePath,W)}};async function ensurePkgDir(n,a){if(n.kind===`local`)return{pkgDir:n.path,cachedPkgName:null};let S=cacheDirFor(createCacheKey({packages:[n.spec]})),C=a.cacheMaxAge>0?getValidCachedPkg(S,a.cacheMaxAge):void 0;if(C)return{pkgDir:resolveInstalledPkgDir(C,n.name),cachedPkgName:n.name};let N=makePrepareDir(S);return await installPackages({prefix:N,specs:[n.spec],verbose:a.verbose,registry:a.registry,lockfile:!0,frozen:a.frozen}),{pkgDir:resolveInstalledPkgDir(symlinkSwap(S,N),n.name),cachedPkgName:n.name}}function splitBinAndArgs(n,a,S){if(!a)return{binName:null,extraArgs:S};let C=jo(n,`package.json`);if(existsSync(C))try{let n=JSON.parse(readFileSync(C,`utf-8`)).gjsify?.bin;if(n&&Object.prototype.hasOwnProperty.call(n,a))return{binName:a,extraArgs:S}}catch{}return{binName:null,extraArgs:[a,...S]}}As(),Dp(),Ho();function defaultGlobalLayout(){let n=process.env.GJSIFY_GLOBAL_PREFIX,a=process.env.GJSIFY_GLOBAL_BIN_DIR,S=homedir(),C=process.env.XDG_DATA_HOME??jo(S,`.local`,`share`);return{prefix:n??jo(C,`gjsify`,`global`),binDir:a??jo(S,`.local`,`bin`)}}function linkGlobalBins(n,a){mkdirSync(a.binDir,{recursive:!0});let S=[],C=buildLauncherEnvPreamble(detectNativePackages(a.prefix).map(n=>n.prebuildsDir));for(let N of n){let n=jo(a.prefix,`node_modules`,N),F=jo(n,`package.json`);if(!existsSync(F))continue;let I=pickBinMap(N,readJson(F));if(!(!I||I.size===0))for(let[N,F]of I){let I=jo(n,F);if(!existsSync(I))continue;try{chmodSync(I,493)}catch{}let H=jo(a.binDir,N);rmSync(H,{force:!0}),writeFileSync(H,I.endsWith(`.gjs.mjs`)||I.endsWith(`.mjs`)?`#!/bin/sh\n${C}exec gjs -m ${shQuote(I)} "$@"\n`:`#!/bin/sh\nexec ${shQuote(I)} "$@"\n`),chmodSync(H,493),S.push({name:N,target:I,link:H})}}return S}function shQuote(n){return`'${n.replace(/'/g,`'\\''`)}'`}function buildLauncherEnvPreamble(n){if(n.length===0)return``;let a=shQuote(n.join(`:`));return`GI_TYPELIB_PATH=${a}\${GI_TYPELIB_PATH:+":$GI_TYPELIB_PATH"}\nLD_LIBRARY_PATH=${a}\${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}\nexport GI_TYPELIB_PATH LD_LIBRARY_PATH\n`}function pickBinMap(n,a){let S=a.gjsify;if(S?.bin!==void 0)return normalizeBin(n,S.bin);let C=a.bin;return C===void 0?null:normalizeBin(n,C)}function normalizeBin(n,a){let S=new Map;if(typeof a==`string`){let C=n.startsWith(`@`)?n.slice(n.indexOf(`/`)+1):n;return S.set(C,a),S}for(let[n,C]of Object.entries(a))S.set(n,C);return S}function readJson(n){return JSON.parse(readFileSync(n,`utf-8`))}function binDirOnPath(n){let a=process.env.PATH??``,S=process.platform===`win32`?`;`:`:`,C=Oo(n);return a.split(S).some(n=>n&&Oo(n)===C)}function specToPackageName(n){if(n.startsWith(`@`)){let a=n.indexOf(`/`);if(a<0)return n;let S=n.indexOf(`@`,a);return S<0?n:n.slice(0,S)}let a=n.indexOf(`@`);return a<0?n:n.slice(0,a)}Ie(),As(),Ho(),Bx();const nD={command:`install [packages..]`,description:`Install npm dependencies in the current project (or globally with -g), then run gjsify-aware post-checks.`,builder:n=>n.positional(`packages`,{description:`Optional package specs. With none, runs a full project install.`,type:`string`,array:!0}).option(`global`,{description:`Install into the user-global XDG location and symlink bins into ~/.local/bin.`,type:`boolean`,alias:`g`,default:!1}).option(`save-dev`,{type:`boolean`,alias:`D`}).option(`save-peer`,{type:`boolean`}).option(`save-optional`,{type:`boolean`,alias:`O`}).option(`immutable`,{description:`CI mode: install strictly from gjsify-lock.json, fail if the lockfile is missing or stale. Equivalent to yarn --immutable / npm ci --frozen-lockfile.`,type:`boolean`,default:!1}).option(`verbose`,{description:`Verbose install logging.`,type:`boolean`,default:!1}).option(`backend`,{description:"Install backend. `native` (default) routes through `@gjsify/{semver,npm-registry,tar}` — no Node/npm at runtime. `npm` shells out to `npm install` as an escape hatch for cases the native backend does not yet model (Yarn PnP repos, lifecycle scripts). Overrides `GJSIFY_INSTALL_BACKEND` if both are set.",type:`string`,choices:[`native`,`npm`]}),handler:async n=>{if(n.immutable&&(n.packages&&n.packages.length>0&&(Fe.error(`gjsify install --immutable does not accept package arguments. Remove the package names or drop --immutable.`),process.exit(1)),n.global&&(Fe.error(`gjsify install --immutable is incompatible with --global.`),process.exit(1))),n.global){(!n.packages||n.packages.length===0)&&(Fe.error(`gjsify install --global requires at least one <pkg> argument.`),process.exit(1));for(let a of[`save-dev`,`save-peer`,`save-optional`])n[a]&&Fe.warn(`gjsify install --global ignores --${a}: global installs do not modify a project package.json.`);await installGlobalAndLink(n.packages,{verbose:n.verbose});return}if((n.backend??process.env.GJSIFY_INSTALL_BACKEND??`native`)===`npm`){await projectInstallViaNpm(n),await runPostInstallChecks();return}await projectInstallNative(n),await runPostInstallChecks()}};function isWorkspaceRoot(n){let a=readPackageJson$3(jo(n,`package.json`));return a?a.workspaces!==void 0:!1}function depKindFromArgs(n){return n[`save-dev`]?`devDependencies`:n[`save-peer`]?`peerDependencies`:n[`save-optional`]?`optionalDependencies`:`dependencies`}async function projectInstallNative(n){let a=process.cwd(),S=jo(a,`package.json`);if(existsSync(jo(a,`.pnp.cjs`))||existsSync(jo(a,`.pnp.loader.mjs`)))throw Error("gjsify install: detected Yarn PnP (.pnp.cjs) — native install is not PnP-aware yet. Use `yarn install` or set GJSIFY_INSTALL_BACKEND=npm.");if((!n.packages||n.packages.length===0)&&isWorkspaceRoot(a)){await workspaceInstall(a,n);return}let C,N=readPackageJson$3(S),F=N?projectSpecsFromPackageJson(N):[];if(n.packages&&n.packages.length>0){let a=new Set(n.packages.map(n=>parseSpec$2(n).name));C=[...F.filter(n=>!a.has(parseSpec$2(n).name)),...n.packages]}else{if(!N)throw Error(`gjsify install: no package.json in ${a}`);if(C=F,C.length===0){Fe.log(`gjsify install: no dependencies declared in package.json — nothing to do.`);return}}mkdirSync(a,{recursive:!0});let I=await installPackages({prefix:a,specs:C,verbose:n.verbose,lockfile:!n.immutable,frozen:n.immutable});if(n.packages&&n.packages.length>0&&N){let C=depKindFromArgs(n);for(let a of n.packages){let{name:n,range:S}=parseSpec$2(a),F=I.installed.find(a=>a.name===n);addDependencyEntry(N,n,S??(F?defaultRangeFromVersion(F.version):`latest`),C)}writePackageJson$1(S,N),n.immutable||syncLockfileRequested(a,projectSpecsFromPackageJson(N))}}function syncLockfileRequested(n,a){let S=jo(n,`gjsify-lock.json`);if(existsSync(S))try{let n=JSON.parse(readFileSync(S,`utf-8`)),C=[...a].sort(),N=[...n.requested??[]].sort();if(C.length===N.length&&C.every((n,a)=>n===N[a]))return;n.requested=a,writeFileSync(S,JSON.stringify(n,null,2)+`
|
|
794
|
+
`)}function parseSpec(n){if(n.startsWith(`@`)){let a=n.indexOf(`/`);if(a<0)throw Error(`Invalid spec (scoped name without slash): ${n}`);let S=n.indexOf(`@`,a);return S<0?{name:n,range:`latest`}:{name:n.slice(0,S),range:n.slice(S+1)||`latest`}}let a=n.indexOf(`@`);return a<0?{name:n,range:`latest`}:{name:n.slice(0,a),range:n.slice(a+1)||`latest`}}function pickVersion(n,a){if(n[`dist-tags`][a])return n[`dist-tags`][a];let S;try{S=new BE(a)}catch{throw Error(`Invalid version range for ${n.name}: ${a}`)}return maxSatisfying(Object.keys(n.versions).filter(n=>{try{return new SemVer(n),!0}catch{return!1}}),S)}async function downloadAndExtractAll(n,a,S,C){let N=[...n].sort((n,a)=>depth(n.installPath)-depth(a.installPath)||(n.installPath<a.installPath?-1:1)),F=[],I=Math.max(1,Math.min(XE,N.length)),H=0,W=N.findIndex(n=>depth(n.installPath)>1),K=W<0?N.length:W;for(;H<K;){let n=N[H++];if(!n)break;await extractOne(n,a,S,C)}for(let n=0;n<I;n++)F.push((async()=>{for(;;){let n=H++;if(n>=N.length)return;let F=N[n];if(!F)return;await extractOne(F,a,S,C)}})());await Promise.all(F)}async function extractOne(n,a,S,C){let N=jo(a,n.installPath);C(`fetch: %s@%s ← %s (→ %s)`,n.name,n.version,n.tarballUrl,n.installPath);let F=await fetchTarball(n.tarballUrl,{npmrc:S,integrity:n.integrity,onRetry:({attempt:a,error:S,delayMs:N})=>{C(`tarball %s@%s: retry %d after %dms (%s)`,n.name,n.version,a,N,errMsg(S))}});rmSync(N,{recursive:!0,force:!0}),mkdirSync(N,{recursive:!0}),await extractTarball(F,N)}function depth(n){return n.split(`/node_modules/`).length}async function linkBins(n,a,S){let C=jo(a,`node_modules`,`.bin`),N=0;for(let S of n){if(!S.bin||depth(S.installPath)!==1)continue;let n=normalizeBin$1(S.name,S.bin);if(n.size!==0){mkdirSync(C,{recursive:!0});for(let[F,I]of n){let n=jo(a,S.installPath,I);if(!existsSync(n))continue;try{chmodSync(n,493)}catch{}let H=jo(C,F);rmSync(H,{force:!0});let W=Mo(C,n);try{symlinkSync(W,H),N++}catch{copyFileSync(n,H),chmodSync(H,493),N++}}}}N>0&&S(`bin: linked %d entry(ies) under .bin/`,N)}function normalizeBin$1(n,a){let S=new Map;if(typeof a==`string`){let C=n.startsWith(`@`)?n.slice(n.indexOf(`/`)+1):n;return S.set(C,a),S}for(let[n,C]of Object.entries(a))S.set(n,C);return S}async function loadNpmrc$1(n){let a=homedir(),S={registry:n.registry??HE,scopes:{},authTokens:{},basicAuth:{}};for(let C of[jo(a,`.npmrc`),jo(n.prefix,`.npmrc`)])if(existsSync(C))try{let n=parseNpmrc(readFileSync(C,`utf-8`));S={...S,...n,scopes:{...S.scopes,...n.scopes}}}catch(n){Fe.warn(`gjsify install: ignoring malformed ${C}: ${n.message}`)}let C=process.env.npm_config_registry;return C&&(S.registry=C),n.registry&&(S.registry=n.registry),S}function makeLogger(n){return n?(n,...a)=>{let S=n.replace(/%s|%d/g,()=>String(a.shift()));process.stderr.write(`gjsify install: ${S}\n`)}:()=>{}}var XE,ZE,QE,$E=__esmMin(()=>{Ie(),As(),Ho(),Dp(),VE(),UE(),JE(),XE=Number(process.env.GJSIFY_INSTALL_CONCURRENCY??`8`)||8,ZE=`gjsify-lock.json`,QE=2,__name$1(normalizeBin$1,`normalizeBin`),__name$1(loadNpmrc$1,`loadNpmrc`)});Bx(),As(),Ho();const eD=process.env.GJSIFY_INSTALL_BACKEND??`native`;async function installPackages(n){if(eD===`npm`)return await installViaNpm(n),{installed:[]};let{installPackagesNative:a}=await Promise.resolve().then(()=>($E(),YE));return{installed:await a(n)}}async function installViaNpm({prefix:n,specs:a,verbose:S,registry:C}){if(a.length===0)throw Error(`installPackages: empty specs list`);writeFileSync(jo(n,`package.json`),JSON.stringify({name:`gjsify-dlx-cache`,version:`0.0.0`,private:!0},null,2)),C&&writeFileSync(jo(n,`.npmrc`),`registry=${C}\n`);let N=[`install`,`--no-package-lock`,`--no-audit`,`--no-fund`,`--prefix`,n,...S?[`--loglevel`,`verbose`]:[`--loglevel`,`warn`],...a];await new Promise((n,a)=>{let S=spawn(`npm`,N,{stdio:`inherit`});S.on(`close`,S=>{S===0?n():a(Error(`npm install exited with code ${S}`))}),S.on(`error`,n=>{let S=n.code===`ENOENT`?`npm not found on PATH — install Node.js or set GJSIFY_INSTALL_BACKEND=native (not yet supported)`:`npm install failed: ${n.message}`;a(Error(S))})})}Ie(),As(),Ho();const tD={command:`dlx <spec> [binOrArg] [extraArgs..]`,description:`Run the GJS bundle of an npm-published package without installing it locally.`,builder:n=>n.parserConfiguration({"populate--":!0}).positional(`spec`,{description:"Package spec (`name`, `name@version`, `@scope/name@spec`, or local path).",type:`string`,demandOption:!0}).positional(`binOrArg`,{description:"Optional bin name when the package defines `gjsify.bin` with multiple entries; otherwise treated as the first argument forwarded to the bundle. To pass a flag here (e.g. `--help`) use the `--` separator: `gjsify dlx <pkg> -- --help`.",type:`string`}).positional(`extraArgs`,{description:"Extra args forwarded to `gjs -m <bundle>`. Use `--` before flags to bypass gjsify-level parsing (`gjsify dlx <pkg> -- --help --verbose`).",type:`string`,array:!0}).option(`cache-max-age`,{description:`Cache TTL in minutes. Defaults to 7 days. Use 0 to bypass cache.`,type:`number`,default:1440*7}).option(`reinstall`,{description:`Bypass the cache for this run (alias for --cache-max-age=0).`,type:`boolean`,default:!1}).option(`frozen`,{description:`Use the project-local gjsify-lock.json verbatim — fail if missing or stale (no resolver pass).`,type:`boolean`,default:!1}).option(`verbose`,{description:`Verbose logging (passes --loglevel verbose to npm).`,type:`boolean`,default:!1}).option(`registry`,{description:`Registry URL override.`,type:`string`}),handler:async n=>{let a=parseSpec$1(n.spec),S=n.reinstall?0:n[`cache-max-age`],{pkgDir:C,cachedPkgName:N}=await ensurePkgDir(a,{verbose:n.verbose,registry:n.registry,cacheMaxAge:S,frozen:n.frozen}),F=(n[`--`]??[]).map(n=>String(n)),I=[...n.extraArgs??[],...F],{binName:H,extraArgs:W}=splitBinAndArgs(C,n.binOrArg,I),K=resolveGjsEntry(C,H);K.fromFallback&&Fe.warn(`[gjsify dlx] package "${N??a.kind}" has no \`gjsify\` field — falling back to package.json#main. Add \`gjsify.main\` to silence.`),await runGjsBundle(K.bundlePath,W)}};async function ensurePkgDir(n,a){if(n.kind===`local`)return{pkgDir:n.path,cachedPkgName:null};let S=cacheDirFor(createCacheKey({packages:[n.spec]})),C=a.cacheMaxAge>0?getValidCachedPkg(S,a.cacheMaxAge):void 0;if(C)return{pkgDir:resolveInstalledPkgDir(C,n.name),cachedPkgName:n.name};let N=makePrepareDir(S);return await installPackages({prefix:N,specs:[n.spec],verbose:a.verbose,registry:a.registry,lockfile:!0,frozen:a.frozen}),{pkgDir:resolveInstalledPkgDir(symlinkSwap(S,N),n.name),cachedPkgName:n.name}}function splitBinAndArgs(n,a,S){if(!a)return{binName:null,extraArgs:S};let C=jo(n,`package.json`);if(existsSync(C))try{let n=JSON.parse(readFileSync(C,`utf-8`)).gjsify?.bin;if(n&&Object.prototype.hasOwnProperty.call(n,a))return{binName:a,extraArgs:S}}catch{}return{binName:null,extraArgs:[a,...S]}}As(),Dp(),Ho();function defaultGlobalLayout(){let n=process.env.GJSIFY_GLOBAL_PREFIX,a=process.env.GJSIFY_GLOBAL_BIN_DIR,S=homedir(),C=process.env.XDG_DATA_HOME??jo(S,`.local`,`share`);return{prefix:n??jo(C,`gjsify`,`global`),binDir:a??jo(S,`.local`,`bin`)}}function linkGlobalBins(n,a){mkdirSync(a.binDir,{recursive:!0});let S=[],C=buildLauncherEnvPreamble(detectNativePackages(a.prefix).map(n=>n.prebuildsDir));for(let N of n){let n=jo(a.prefix,`node_modules`,N),F=jo(n,`package.json`);if(!existsSync(F))continue;let I=pickBinMap(N,readJson(F));if(!(!I||I.size===0))for(let[N,F]of I){let I=jo(n,F);if(!existsSync(I))continue;try{chmodSync(I,493)}catch{}let H=jo(a.binDir,N);rmSync(H,{force:!0}),writeFileSync(H,I.endsWith(`.gjs.mjs`)||I.endsWith(`.mjs`)?`#!/bin/sh\n${C}exec gjs -m ${shQuote(I)} "$@"\n`:`#!/bin/sh\nexec ${shQuote(I)} "$@"\n`),chmodSync(H,493),S.push({name:N,target:I,link:H})}}return S}function shQuote(n){return`'${n.replace(/'/g,`'\\''`)}'`}function buildLauncherEnvPreamble(n){if(n.length===0)return``;let a=shQuote(n.join(`:`));return`GI_TYPELIB_PATH=${a}\${GI_TYPELIB_PATH:+":$GI_TYPELIB_PATH"}\nLD_LIBRARY_PATH=${a}\${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}\nexport GI_TYPELIB_PATH LD_LIBRARY_PATH\n`}function pickBinMap(n,a){let S=a.gjsify;if(S?.bin!==void 0)return normalizeBin(n,S.bin);let C=a.bin;return C===void 0?null:normalizeBin(n,C)}function normalizeBin(n,a){let S=new Map;if(typeof a==`string`){let C=n.startsWith(`@`)?n.slice(n.indexOf(`/`)+1):n;return S.set(C,a),S}for(let[n,C]of Object.entries(a))S.set(n,C);return S}function readJson(n){return JSON.parse(readFileSync(n,`utf-8`))}function binDirOnPath(n){let a=process.env.PATH??``,S=process.platform===`win32`?`;`:`:`,C=Oo(n);return a.split(S).some(n=>n&&Oo(n)===C)}function specToPackageName(n){if(n.startsWith(`@`)){let a=n.indexOf(`/`);if(a<0)return n;let S=n.indexOf(`@`,a);return S<0?n:n.slice(0,S)}let a=n.indexOf(`@`);return a<0?n:n.slice(0,a)}Ie(),As(),Ho(),Bx();const nD={command:`install [packages..]`,description:`Install npm dependencies in the current project (or globally with -g), then run gjsify-aware post-checks.`,builder:n=>n.positional(`packages`,{description:`Optional package specs. With none, runs a full project install.`,type:`string`,array:!0}).option(`global`,{description:`Install into the user-global XDG location and symlink bins into ~/.local/bin.`,type:`boolean`,alias:`g`,default:!1}).option(`save-dev`,{type:`boolean`,alias:`D`}).option(`save-peer`,{type:`boolean`}).option(`save-optional`,{type:`boolean`,alias:`O`}).option(`immutable`,{description:`CI mode: install strictly from gjsify-lock.json, fail if the lockfile is missing or stale. Equivalent to yarn --immutable / npm ci --frozen-lockfile.`,type:`boolean`,default:!1}).option(`verbose`,{description:`Verbose install logging.`,type:`boolean`,default:!1}).option(`backend`,{description:"Install backend. `native` (default) routes through `@gjsify/{semver,npm-registry,tar}` — no Node/npm at runtime. `npm` shells out to `npm install` as an escape hatch for cases the native backend does not yet model (Yarn PnP repos, lifecycle scripts). Overrides `GJSIFY_INSTALL_BACKEND` if both are set.",type:`string`,choices:[`native`,`npm`]}),handler:async n=>{if(n.immutable&&(n.packages&&n.packages.length>0&&(Fe.error(`gjsify install --immutable does not accept package arguments. Remove the package names or drop --immutable.`),process.exit(1)),n.global&&(Fe.error(`gjsify install --immutable is incompatible with --global.`),process.exit(1))),n.global){(!n.packages||n.packages.length===0)&&(Fe.error(`gjsify install --global requires at least one <pkg> argument.`),process.exit(1));for(let a of[`save-dev`,`save-peer`,`save-optional`])n[a]&&Fe.warn(`gjsify install --global ignores --${a}: global installs do not modify a project package.json.`);await installGlobalAndLink(n.packages,{verbose:n.verbose});return}if((n.backend??process.env.GJSIFY_INSTALL_BACKEND??`native`)===`npm`){await projectInstallViaNpm(n),await runPostInstallChecks();return}await projectInstallNative(n),await runPostInstallChecks()}};function isWorkspaceRoot(n){let a=readPackageJson$3(jo(n,`package.json`));return a?a.workspaces!==void 0:!1}function depKindFromArgs(n){return n[`save-dev`]?`devDependencies`:n[`save-peer`]?`peerDependencies`:n[`save-optional`]?`optionalDependencies`:`dependencies`}async function projectInstallNative(n){let a=process.cwd(),S=jo(a,`package.json`),C=[`.pnp.cjs`,`.pnp.loader.mjs`].filter(n=>existsSync(jo(a,n)));if(C.length>0)throw Error(`gjsify install uses the node_modules linker and cannot run in a Yarn PnP project (found ${C.join(`, `)} in ${a}).\n\n• If this project uses \`gjsify install\` to manage dependencies, these PnP files are stale residue from an earlier \`yarn install\` — remove them and re-run:\n rm -f .pnp.cjs .pnp.loader.mjs && rm -rf .yarn/cache .yarn/unplugged\n gjsify install\n\n• If instead you want Yarn to manage dependencies, set \`nodeLinker: node-modules\` in .yarnrc.yml and run \`yarn install\` (not \`gjsify install\`).`);if((!n.packages||n.packages.length===0)&&isWorkspaceRoot(a)){await workspaceInstall(a,n);return}let N,F=readPackageJson$3(S),I=F?projectSpecsFromPackageJson(F):[];if(n.packages&&n.packages.length>0){let a=new Set(n.packages.map(n=>parseSpec$2(n).name));N=[...I.filter(n=>!a.has(parseSpec$2(n).name)),...n.packages]}else{if(!F)throw Error(`gjsify install: no package.json in ${a}`);if(N=I,N.length===0){Fe.log(`gjsify install: no dependencies declared in package.json — nothing to do.`);return}}mkdirSync(a,{recursive:!0});let H=await installPackages({prefix:a,specs:N,verbose:n.verbose,lockfile:!n.immutable,frozen:n.immutable});if(n.packages&&n.packages.length>0&&F){let C=depKindFromArgs(n);for(let a of n.packages){let{name:n,range:S}=parseSpec$2(a),N=H.installed.find(a=>a.name===n);addDependencyEntry(F,n,S??(N?defaultRangeFromVersion(N.version):`latest`),C)}writePackageJson$1(S,F),n.immutable||syncLockfileRequested(a,projectSpecsFromPackageJson(F))}}function syncLockfileRequested(n,a){let S=jo(n,`gjsify-lock.json`);if(existsSync(S))try{let n=JSON.parse(readFileSync(S,`utf-8`)),C=[...a].sort(),N=[...n.requested??[]].sort();if(C.length===N.length&&C.every((n,a)=>n===N[a]))return;n.requested=a,writeFileSync(S,JSON.stringify(n,null,2)+`
|
|
795
795
|
`)}catch{}}async function workspaceInstall(n,a){let S=discoverWorkspaces(n,{includeRoot:!0});if(S.length===0)throw Error(`gjsify install: ${n} has a "workspaces" field but no workspaces were discovered`);let C=new Map(S.map(n=>[n.name,n])),N=new Set,F=[];for(let n of S){let a=n.manifest;for(let S of[`dependencies`,`devDependencies`,`optionalDependencies`]){let I=a[S];if(I){for(let[a,S]of Object.entries(I))if(typeof S==`string`){if(S.startsWith(`workspace:`)){let N=C.get(a);if(!N)throw Error(`gjsify install: ${n.name} declares "${a}: ${S}" but no workspace with that name exists`);F.push({fromWorkspaceName:n.name,depName:a,targetLocation:N.location});continue}/^(link|file|portal|git\+|https?):/.test(S)||N.add(`${a}@${S}`)}}}}Fe.log(`gjsify install: ${S.length} workspace(s), ${N.size} external dep spec(s), ${F.length} workspace symlink(s)`);let I=S.find(a=>a.location===n)?.manifest,H=extractOverrides(I);N.size>0?await installPackages({prefix:n,specs:[...N],verbose:a.verbose,lockfile:!a.immutable,frozen:a.immutable,overrides:H}):a.verbose&&Fe.log(`gjsify install: no external deps to fetch`);for(let n of F){let a=C.get(n.fromWorkspaceName);if(!a)continue;let S=jo(a.location,`node_modules`,n.depName);mkdirSync(Po(S),{recursive:!0});try{rmSync(S,{recursive:!0,force:!0})}catch{}symlinkSync(Mo(Po(S),n.targetLocation),S)}F.length>0&&Fe.log(`gjsify install: wired ${F.length} workspace symlink(s)`);let W=jo(n,`node_modules`),K=0;for(let a of S){if(a.location===n||!a.name)continue;let S=jo(W,a.name),C=!1;try{lstatSync(S),C=!0}catch{}C||(mkdirSync(Po(S),{recursive:!0}),symlinkSync(Mo(Po(S),a.location),S),K++)}K>0&&Fe.log(`gjsify install: hoisted ${K} workspace(s) to root node_modules/`);let q=jo(n,`node_modules`,`.bin`),Y=detectNativePackages(n).map(n=>n.prebuildsDir),X=0;for(let n of S){let a=n.manifest,S=a.gjsify?.bin,C=a.bin,N=mergeWorkspaceBins(n.name,S,C);if(N.size!==0){mkdirSync(q,{recursive:!0});for(let[a,{nodeTarget:S,gjsTarget:C}]of N){let N=jo(q,a);try{rmSync(N,{force:!0})}catch{}writeFileSync(N,buildBinShim(n.location,S,C,Y),{mode:493}),chmodSync(N,493),X++}}}X>0&&Fe.log(`gjsify install: linked ${X} workspace bin(s) into node_modules/.bin/`)}function extractOverrides(n){if(!n)return;let a={},merge=(n,S)=>{if(n)for(let[C,N]of Object.entries(n)){if(C.startsWith(`_`))continue;if(typeof N!=`string`){Fe.warn(`gjsify install: ${S}["${C}"] is not a string — nested override shape isn't supported yet, skipping`);continue}let n=C,F=C.startsWith(`@`)?C.indexOf(`@`,1):C.indexOf(`@`);F>0&&(n=C.slice(0,F)),a[n]=N}};return merge(n.overrides,`overrides`),merge(n.resolutions,`resolutions`),Object.keys(a).length>0?a:void 0}function buildBinShim(n,a,S,C=[]){let N=a?jo(n,a):null,F=S?jo(n,S):null,I=C.length===0?``:(()=>{let n=`'${C.join(`:`).replace(/'/g,`'\\''`)}'`;return`GI_TYPELIB_PATH=${n}\${GI_TYPELIB_PATH:+":$GI_TYPELIB_PATH"}\nLD_LIBRARY_PATH=${n}\${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}\nexport GI_TYPELIB_PATH LD_LIBRARY_PATH\n`})();if(N&&F)return`#!/bin/sh\nif [ -f "${N}" ]; then\n exec node "${N}" "$@"\nfi\n${I}exec gjs -m "${F}" "$@"\n`;if(N)return`#!/bin/sh\nexec node "${N}" "$@"\n`;if(F)return`#!/bin/sh\n${I}exec gjs -m "${F}" "$@"\n`;throw Error(`buildBinShim: either nodeTarget or gjsTarget must be provided`)}function mergeWorkspaceBins(n,a,S){let C=new Map,N=n.startsWith(`@`)?n.slice(n.indexOf(`/`)+1):n,get=n=>{let a=C.get(n);return a||(a={},C.set(n,a)),a};if(typeof S==`string`)get(N).nodeTarget=S;else if(S&&typeof S==`object`)for(let[n,a]of Object.entries(S))typeof a==`string`&&a.length>0&&(get(n).nodeTarget=a);if(typeof a==`string`)get(N).gjsTarget=a;else if(a&&typeof a==`object`)for(let[n,S]of Object.entries(a))typeof S==`string`&&S.length>0&&(get(n).gjsTarget=S);return C}async function projectInstallViaNpm(n){let a=[`install`];n[`save-dev`]&&a.push(`--save-dev`),n[`save-peer`]&&a.push(`--save-peer`),n[`save-optional`]&&a.push(`--save-optional`),n.verbose&&a.push(`--loglevel`,`verbose`),n.packages&&n.packages.length>0&&a.push(...n.packages),await spawnNpm(a)}async function spawnNpm(n){return new Promise((a,S)=>{let C=spawn(`npm`,n,{stdio:`inherit`});C.on(`close`,n=>{n===0?a():S(Error(`npm install exited with code ${n}`))}),C.on(`error`,n=>{let a=n.code===`ENOENT`?`npm not found on PATH — install Node.js first.`:`npm install failed: ${n.message}`;S(Error(a))})}).catch(n=>{Fe.error(n.message),process.exit(1)})}async function installGlobalAndLink(n,a){let S=defaultGlobalLayout();mkdirSync(S.prefix,{recursive:!0}),Fe.log(`gjsify install --global → ${S.prefix}`),Fe.log(` bins → ${S.binDir}`),await installPackages({prefix:S.prefix,specs:n,verbose:a.verbose});let C=linkGlobalBins(n.map(specToPackageName),S);if(C.length===0)Fe.warn("\nNo bins declared (neither `gjsify.bin` nor `bin` in package.json) — nothing was symlinked.");else{Fe.log(`\nLinked ${C.length} bin(s):`);for(let n of C)Fe.log(` • ${n.link} → ${n.target}`)}C.length>0&&!binDirOnPath(S.binDir)&&Fe.warn(`\nNote: ${S.binDir} is not on your PATH.\nAdd it to your shell rc file:\n export PATH="${S.binDir}:$PATH"`)}async function runPostInstallChecks(){Fe.log(`
|
|
796
796
|
--- gjsify post-install checks ---`);let n=runMinimalChecks().filter(n=>!n.found&&n.severity===`required`);if(n.length>0){Fe.warn(`Missing required system dependencies:
|
|
797
797
|
`);for(let a of n)Fe.warn(` ✗ ${a.name}`);let a=buildInstallCommand(detectPackageManager$2(),n);a&&Fe.warn(`\nInstall with:\n ${a}`)}else Fe.log(`System dependencies OK.`);let a=detectNativePackages(process.cwd());if(a.length>0){Fe.log(`\nDetected ${a.length} @gjsify/* package(s) with native prebuilds:`);for(let n of a)Fe.log(` • ${n.name}`);Fe.log("\nUse `gjsify run <bundle>` to launch with LD_LIBRARY_PATH/GI_TYPELIB_PATH set.")}}Ie(),Bx(),Dp();const rD={command:`foreach [script] [args..]`,description:"Run a workspace script across all (or filtered) workspaces. Drop-in for `yarn workspaces foreach`: -A/--all, -p/--parallel, -t/--topological, --include, --exclude, --no-private. Pass --exec to run an arbitrary command instead of a script.",builder:n=>n.positional(`script`,{description:"Script name to run in each workspace (`run <name>`-equivalent). With --exec, the command to run instead.",type:`string`}).positional(`args`,{description:`Extra arguments forwarded to each child invocation.`,type:`string`,array:!0}).option(`all`,{description:"Include workspaces declared as `private: true`.",type:`boolean`,alias:`A`,default:!1}).option(`parallel`,{description:`Run workspaces in parallel (capped by --jobs).`,type:`boolean`,alias:`p`,default:!1}).option(`topological`,{description:`Wait for each workspace's deps to finish before starting it (production deps only).`,type:`boolean`,alias:`t`,default:!1}).option(`topological-dev`,{description:`Like --topological but also respects devDependencies (often cyclic — use sparingly).`,type:`boolean`,default:!1}).option(`include`,{description:`Glob pattern to include workspaces by name (repeatable).`,type:`string`,array:!0}).option(`exclude`,{description:`Glob pattern to exclude workspaces by name (repeatable).`,type:`string`,array:!0}).option(`private`,{description:`Include private workspaces (default true). Pass --no-private to skip them.`,type:`boolean`,default:!0}).option(`verbose`,{description:`Echo every spawned command before running it.`,type:`boolean`,alias:`v`,default:!1}).option(`jobs`,{description:`Maximum concurrent workspaces in --parallel mode (default: cpu count).`,type:`number`,alias:`j`}).option(`exec`,{description:"Treat <script> [args..] as an arbitrary command (yarn `workspaces foreach exec`-equivalent) instead of a package.json script lookup. Workspace filtering by script presence is skipped. Use `-- <cmd> <args...>` to pass flags to the command without yargs intercepting them.",type:`boolean`,default:!1}).parserConfiguration({"populate--":!0}),handler:async n=>{let a=discoverWorkspaces(findWorkspaceRoot(process.cwd())??process.cwd()),S=n.exec===!0,C=n.script,N=n.args??[];if(S){let a=(n[`--`]??[]).filter(n=>typeof n==`string`);a.length>0&&(C?N=[...N,...a]:(C=a[0],N=[...N,...a.slice(1)])),C||(Fe.error("gjsify foreach --exec: missing command. Pass it after `--`, e.g. `gjsify foreach --exec -- npm publish --tag latest`."),process.exit(1))}let F=filterWorkspaces(a,{include:n.include,exclude:n.exclude,noPrivate:n.private===!1});if(!S){C||(Fe.error(`gjsify foreach: missing <script> positional. Pass --exec to run an arbitrary command instead.`),process.exit(1));let n=C;F=F.filter(a=>typeof(a.manifest.scripts??{})[n]==`string`)}if(F.length===0){Fe.log(`gjsify foreach: no workspaces match (${S?`exec`:`script`}="${C}", include=${JSON.stringify(n.include??[])}, exclude=${JSON.stringify(n.exclude??[])})`);return}(n.topological||n[`topological-dev`])&&(F=topologicalSort(buildDependencyGraph(F,{includeDev:n[`topological-dev`]===!0})));let I=n.verbose===!0,H=C;try{if(n.parallel&&!n.topological&&!n[`topological-dev`]){let a=n.jobs&&n.jobs>0?n.jobs:cpus().length;await runParallel(F,H,N,a,I,S)}else if(n.parallel){let a=n.jobs&&n.jobs>0?n.jobs:cpus().length;await runTopologicalParallel(F,H,N,a,I,n[`topological-dev`]===!0,S)}else await runSequential(F,H,N,I,S)}catch(n){Fe.error(n.message),process.exit(1)}process.exit(0)}};async function runSequential(n,a,S,C,N){for(let F of n)await runOne(F,a,S,!1,C,N)}async function runParallel(n,a,S,C,N,F){let I=0,H=[];for(let W=0;W<C;W++)H.push((async()=>{for(;I<n.length;)await runOne(n[I++],a,S,!0,N,F)})());await Promise.all(H)}async function runTopologicalParallel(n,a,S,C,N,F,I){let H=new Set(n.map(n=>n.name)),W=new Map;for(let a of n){let n=new Set,S=a.manifest;for(let a of[S.dependencies,F?S.devDependencies:void 0,S.optionalDependencies])if(a)for(let[S,C]of Object.entries(a))typeof C==`string`&&C.startsWith(`workspace:`)&&H.has(S)&&n.add(S);W.set(a.name,n)}let K=new Map(n.map(n=>[n.name,n])),q=new Set,Y=0;return new Promise((n,F)=>{let H=null,pump=()=>{if(!H){for(;Y<C;){let C=[...W.entries()].filter(([,n])=>[...n].every(n=>q.has(n))).map(([n])=>n);if(C.length===0)break;let X=C.sort()[0];W.delete(X),Y++,runOne(K.get(X),a,S,!0,N,I).then(()=>{if(Y--,q.add(X),W.size===0&&Y===0){n();return}pump()}).catch(n=>{H=n instanceof Error?n:Error(String(n)),Y===0&&F(H)})}W.size>0&&Y===0&&!H&&F(Error(`gjsify foreach --topological: stuck — workspaces ${[...W.keys()].join(`, `)} have unsatisfied deps in the selected set`))}};pump()})}async function runOne(n,a,S,C,N,F){if(F){N&&Fe.error(`[${n.name}] $ ${a} ${S.join(` `)}`),await spawnPrefixed(a,S,n.location,C?`[${n.name}] `:null);return}let I=detectPackageManager$1(),H=I===`gjsify`?[`run`,a,...S]:[`run`,a,...S.length>0?[`--`,...S]:[]];N&&Fe.error(`[${n.name}] $ ${I} ${H.join(` `)}`),await spawnPrefixed(I,H,n.location,C?`[${n.name}] `:null)}function detectPackageManager$1(){let n=process.env.npm_config_user_agent??``;return n.startsWith(`yarn/`)?`yarn`:n.startsWith(`gjsify/`)?`gjsify`:`npm`}__name$1(detectPackageManager$1,`detectPackageManager`);function spawnPrefixed(n,a,S,C){let N=process.env.FORCE_COLOR!==void 0||process.env.NO_COLOR!==void 0?{}:{FORCE_COLOR:`1`};return new Promise((F,I)=>{let H=spawn(n,a,{cwd:S,stdio:C?[`ignore`,`pipe`,`pipe`]:`inherit`,env:{...process.env,...N}});C&&H.stdout&&H.stderr&&(prefixLines(H.stdout,process.stdout,C),prefixLines(H.stderr,process.stderr,C)),H.on(`close`,S=>{S===0?F():I(Error(`${n} ${a.join(` `)} exited with code ${S}`))}),H.on(`error`,n=>I(n))})}function prefixLines(n,a,S){let C=``;n.setEncoding(`utf-8`),n.on(`data`,n=>{C+=n;let N;for(;(N=C.indexOf(`
|
package/lib/commands/install.js
CHANGED
|
@@ -121,12 +121,33 @@ function depKindFromArgs(args) {
|
|
|
121
121
|
async function projectInstallNative(args) {
|
|
122
122
|
const cwd = process.cwd();
|
|
123
123
|
const pkgPath = join(cwd, 'package.json');
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
// gjsify install is a node_modules-linker installer (like `npm install`
|
|
125
|
+
// or `yarn --nodeLinker node-modules`): it materialises a node_modules/
|
|
126
|
+
// tree + gjsify-lock.json. It deliberately does NOT produce a Yarn PnP
|
|
127
|
+
// install, and the two resolution strategies cannot coexist — a leftover
|
|
128
|
+
// `.pnp.cjs` makes Node ignore the node_modules/ tree we write, leaving a
|
|
129
|
+
// silently broken project.
|
|
130
|
+
//
|
|
131
|
+
// Native PnP *generation* (a byte-identical `.pnp.cjs` + `.yarn/cache/*.zip`
|
|
132
|
+
// that yarn itself would accept) is intentionally out of scope: it would
|
|
133
|
+
// mean replicating yarn's libzip-deterministic archives, SHA-512 cache
|
|
134
|
+
// keys, cache-version tracking and virtual-locator synthesis, and would
|
|
135
|
+
// only ever match a single yarn release. So we stop here with actionable
|
|
136
|
+
// guidance instead of half-doing it.
|
|
137
|
+
//
|
|
138
|
+
// We do NOT point users at `GJSIFY_INSTALL_BACKEND=npm` from this error:
|
|
139
|
+
// that backend chokes on `workspace:` specs (`EUNSUPPORTEDPROTOCOL`),
|
|
140
|
+
// which is exactly what the workspace repos that reach this branch have.
|
|
141
|
+
const pnpResidue = ['.pnp.cjs', '.pnp.loader.mjs'].filter((f) => existsSync(join(cwd, f)));
|
|
142
|
+
if (pnpResidue.length > 0) {
|
|
143
|
+
throw new Error(`gjsify install uses the node_modules linker and cannot run in a Yarn PnP ` +
|
|
144
|
+
`project (found ${pnpResidue.join(', ')} in ${cwd}).\n\n` +
|
|
145
|
+
`• If this project uses \`gjsify install\` to manage dependencies, these PnP ` +
|
|
146
|
+
`files are stale residue from an earlier \`yarn install\` — remove them and re-run:\n` +
|
|
147
|
+
` rm -f .pnp.cjs .pnp.loader.mjs && rm -rf .yarn/cache .yarn/unplugged\n` +
|
|
148
|
+
` gjsify install\n\n` +
|
|
149
|
+
`• If instead you want Yarn to manage dependencies, set \`nodeLinker: node-modules\` ` +
|
|
150
|
+
`in .yarnrc.yml and run \`yarn install\` (not \`gjsify install\`).`);
|
|
130
151
|
}
|
|
131
152
|
// Workspace install (no args, root pkg.json has `workspaces`).
|
|
132
153
|
// Project-local `gjsify install <pkg>` inside a workspace child still
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.25",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -120,18 +120,18 @@
|
|
|
120
120
|
"cli"
|
|
121
121
|
],
|
|
122
122
|
"dependencies": {
|
|
123
|
-
"@gjsify/buffer": "^0.4.
|
|
124
|
-
"@gjsify/create-app": "^0.4.
|
|
125
|
-
"@gjsify/node-globals": "^0.4.
|
|
126
|
-
"@gjsify/node-polyfills": "^0.4.
|
|
127
|
-
"@gjsify/npm-registry": "^0.4.
|
|
128
|
-
"@gjsify/resolve-npm": "^0.4.
|
|
129
|
-
"@gjsify/rolldown-plugin-gjsify": "^0.4.
|
|
130
|
-
"@gjsify/rolldown-plugin-pnp": "^0.4.
|
|
131
|
-
"@gjsify/semver": "^0.4.
|
|
132
|
-
"@gjsify/tar": "^0.4.
|
|
133
|
-
"@gjsify/web-polyfills": "^0.4.
|
|
134
|
-
"@gjsify/workspace": "^0.4.
|
|
123
|
+
"@gjsify/buffer": "^0.4.25",
|
|
124
|
+
"@gjsify/create-app": "^0.4.25",
|
|
125
|
+
"@gjsify/node-globals": "^0.4.25",
|
|
126
|
+
"@gjsify/node-polyfills": "^0.4.25",
|
|
127
|
+
"@gjsify/npm-registry": "^0.4.25",
|
|
128
|
+
"@gjsify/resolve-npm": "^0.4.25",
|
|
129
|
+
"@gjsify/rolldown-plugin-gjsify": "^0.4.25",
|
|
130
|
+
"@gjsify/rolldown-plugin-pnp": "^0.4.25",
|
|
131
|
+
"@gjsify/semver": "^0.4.25",
|
|
132
|
+
"@gjsify/tar": "^0.4.25",
|
|
133
|
+
"@gjsify/web-polyfills": "^0.4.25",
|
|
134
|
+
"@gjsify/workspace": "^0.4.25",
|
|
135
135
|
"cosmiconfig": "^9.0.1",
|
|
136
136
|
"get-tsconfig": "^4.14.0",
|
|
137
137
|
"pkg-types": "^2.3.1",
|
|
@@ -139,12 +139,12 @@
|
|
|
139
139
|
"yargs": "^18.0.0"
|
|
140
140
|
},
|
|
141
141
|
"devDependencies": {
|
|
142
|
-
"@gjsify/unit": "^0.4.
|
|
142
|
+
"@gjsify/unit": "^0.4.25",
|
|
143
143
|
"@types/yargs": "^17.0.35",
|
|
144
144
|
"typescript": "^6.0.3"
|
|
145
145
|
},
|
|
146
146
|
"peerDependencies": {
|
|
147
|
-
"@gjsify/rolldown-native": "^0.4.
|
|
147
|
+
"@gjsify/rolldown-native": "^0.4.25"
|
|
148
148
|
},
|
|
149
149
|
"peerDependenciesMeta": {
|
|
150
150
|
"@gjsify/rolldown-native": {
|