@stacksjs/launchpad
Version:
Like Homebrew, but faster.
563 lines (508 loc) • 64.6 kB
JavaScript
// @bun
import{s as i8,t as t8,u as r8,v as s8,w as a8}from"../chunk-s2bxmfad.js";import{A as o8,B as n8,x as l8,y as D0,z as p8}from"../chunk-0sthbje6.js";import{E as S8,F as U0,G as u8,H as D8,I as _8,J as y8,K as v8,L as P8,M as f8,N as k8,O as m8,P as d8,Q as h8,R as g8,S as c8,T as E0,U as Q0}from"../chunk-nn4zj7f2.js";import{V as C8,W as G,X as q0}from"../chunk-7h9a332h.js";import{Y as K0,Z as Y0}from"../chunk-e2w1vagk.js";import w,{createWriteStream as y0}from"fs";import{arch as v0,platform as t}from"os";import A from"path";import P0 from"process";import{pipeline as f0}from"stream/promises";var G0=A.join(P0.env.HOME||".",".cache","launchpad"),r=A.join(G0,"github-bun-releases.json"),k0=3600000,L0=A.join(G0,"binaries","bun");function m0(W){try{return w.mkdirSync(W,{recursive:!0}),!0}catch{return!1}}function d0(){if(!w.existsSync(r))return!1;try{let W=w.statSync(r);return Date.now()-W.mtimeMs<k0}catch{return!1}}function h0(){try{if(d0()){let W=w.readFileSync(r,"utf-8");return JSON.parse(W)}}catch(W){if(G.verbose)console.warn(`Failed to read GitHub cache: ${W instanceof Error?W.message:String(W)}`)}return null}function g0(W){try{w.mkdirSync(G0,{recursive:!0}),w.writeFileSync(r,JSON.stringify(W))}catch(Q){if(G.verbose)console.warn(`Failed to update GitHub cache: ${Q instanceof Error?Q.message:String(Q)}`)}}function c0(W,Q){let X=A.join(L0,W,Q);if(w.existsSync(X)){if(G.verbose)console.warn(`Found cached binary: ${X}`);return X}return null}function l0(W,Q,X){let J=A.join(L0,W),Z=A.join(J,Q);try{if(w.mkdirSync(J,{recursive:!0}),w.copyFileSync(X,Z),G.verbose)console.warn(`Cached binary to: ${Z}`);return Z}catch(O){if(G.verbose)console.warn(`Failed to cache binary: ${O instanceof Error?O.message:String(O)}`);return X}}async function p0(){let W=h0();if(W&&W.tag_name){if(G.verbose)console.warn("Using cached GitHub release data");return W.tag_name.replace(/^bun-v?/,"")}let Q=await fetch("https://api.github.com/repos/oven-sh/bun/releases/latest");if(!Q.ok)throw new Error(`Failed to fetch latest Bun version: ${Q.statusText}`);let X=await Q.json();return g0(X),X.tag_name.replace(/^bun-v?/,"")}function o0(W){let Q=t(),X=v0()==="arm64"?"aarch64":"x64";if(G.verbose)console.warn(`Platform: ${Q}, Architecture: ${X}`);let J;switch(Q){case"darwin":J=`bun-darwin-${X}.zip`;break;case"linux":J=`bun-linux-${X}.zip`;break;case"win32":J="bun-windows-x64.zip";break;default:throw new Error(`Unsupported platform: ${Q}`)}let Z=`https://github.com/oven-sh/bun/releases/download/v${W}/${J}`;return{filename:J,url:Z}}async function dW(W,Q){if(!m0(W))throw new Error(`Invalid installation path: ${W}`);let X=Q||await p0();if(G.verbose)console.warn(`Installing Bun version ${X}`);let{filename:J,url:Z}=o0(X),O=c0(X,J),q=A.join(W,"bin");w.mkdirSync(q,{recursive:!0});let U=A.join(W,"temp");w.mkdirSync(U,{recursive:!0});let H;try{if(O){if(G.verbose)console.warn(`Using cached Bun v${X} from: ${O}`);else console.log(`\uD83D\uDCE6 Using cached Bun v${X}...`);H=A.join(U,J),w.copyFileSync(O,H)}else{if(G.verbose)console.warn(`Downloading from: ${Z}`);else console.log(`\uD83D\uDCE6 Downloading Bun v${X}...`);H=A.join(U,J);let K=await fetch(Z);if(!K.ok)throw new Error(`Failed to download Bun: ${K.statusText}`);let E=y0(H);if(await f0(K.body,E),G.verbose)console.warn(`Downloaded to ${H}`);l0(X,J,H)}if(J.endsWith(".zip")){let{exec:K}=await import("child_process"),{promisify:E}=await import("util"),R=E(K);await R(`unzip -o "${H}" -d "${U}"`);let V=t()==="win32"?"bun-*.exe":"bun-*",N=t()==="win32"?"bun.exe":"bun",D=A.join(U,"bun-*"),{stdout:C}=await R(`ls -d ${D}`),L=C.trim().split(`
`)[0],F=A.join(L,V),$=A.join(q,N);if(w.existsSync($))w.unlinkSync($);await R(`cp ${F} ${$}`),await R(`chmod +x ${$}`)}return w.rmSync(U,{recursive:!0,force:!0}),[A.join(q,t()==="win32"?"bun.exe":"bun")]}catch(K){if(w.existsSync(U))w.rmSync(U,{recursive:!0,force:!0});throw K}}import o from"fs";import k from"path";import W0 from"process";function s(W){if(!/\s/.test(W)&&!/['"$><]/.test(W))return W;if(!W.includes('"'))return`"${W}"`;if(!W.includes("'"))return`'${W}'`;return W=W.replaceAll('"',"\\\""),`"${W}"`}var{semver:r0}=globalThis.Bun;import{readdirSync as s0,readFileSync as R0,statSync as a0}from"fs";import{homedir as e0}from"os";import{join as WW,resolve as QW}from"path";import XW from"process";function m(W){return Object.prototype.toString.call(W).slice(8,-1)}function p(W){return m(W)==="Array"}function _(W){if(m(W)!=="Object")return!1;let Q=Object.getPrototypeOf(W);return!!Q&&Q.constructor===Object&&Q===Object.prototype}function d(W){return m(W)==="String"}function M0(W){return m(W)==="Number"&&!isNaN(W)}function n0(W){return m(W)==="Null"}function i0(W,Q,X,J,Z){return(O)=>W(O)||Q(O)||!!X&&X(O)||!!J&&J(O)||!!Z&&Z(O)}function t0(W){return m(W)==="Undefined"}var cW=i0(n0,t0);class b{range;constructor(W){this.range=W}toString(){return this.range}satisfies(W){return r0.satisfies(W,this.range)}}class h{string;constructor(W){this.string=QW(W)}isDirectory(){try{return a0(this.string).isDirectory()}catch{return!1}}async read(){return R0(this.string,"utf8")}async readYAML(){let W=await this.read();return V0(W)}async readYAMLAll(){return(await this.read()).split(/^---$/m).map((X)=>V0(X.trim())).filter(Boolean)}async*ls(){try{let W=s0(this.string,{withFileTypes:!0});for(let Q of W)yield[new h(WW(this.string,Q.name)),{name:Q.name,isFile:Q.isFile(),isSymlink:Q.isSymbolicLink(),isDirectory:Q.isDirectory()}]}catch{}}static home(){return new h(e0())}}function V0(W){try{if(W.trim().startsWith("{"))return JSON.parse(W);let Q=W.split(`
`),X={},J=[{obj:X,key:null,indent:-1}];for(let Z of Q){let O=Z.trim();if(!O||O.startsWith("#"))continue;let q=Z.length-Z.trimStart().length;while(J.length>1&&J[J.length-1].indent>=q)J.pop();let U=J[J.length-1];if(O.startsWith("- ")){let K=O.substring(2).trim(),E=null,R=null;for(let V=J.length-1;V>=0;V--){let N=J[V];if(N.indent<q){let D=Object.keys(N.obj),C=D[D.length-1];if(C){E=C,R=N.obj;break}}}if(E&&R){if(!Array.isArray(R[E]))R[E]=[];R[E].push(K)}continue}let H=O.indexOf(":");if(H>0){let K=O.substring(0,H).trim(),R=O.substring(H+1).trim().replace(/^["']|["']$/g,"");if(R==="")U.obj[K]={},J.push({obj:U.obj[K],key:null,indent:q});else U.obj[K]=R}}return X}catch{return{}}}function ZW(W){try{let Q=W.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm,"");return JSON.parse(Q)}catch{return{}}}function a(W){let Q=W.lastIndexOf("@");if(Q>0){let X=W.substring(0,Q),J=W.substring(Q+1);return{project:X,constraint:new b(J)}}return{project:W,constraint:new b("*")}}function JW(W,Q){try{return{project:W,constraint:new b(Q)}}catch{return}}async function*qW(W){try{let X=R0(W,"utf8").split(`
`);for(let J of X)yield J}catch{}}async function e(W){let Q=W instanceof h?W:new h(W.string);if(!Q.isDirectory())throw new Error(`not a directory: ${Q.string}`);let X=new b("*"),J=!1,Z=[],O={};for await(let[$,{name:Y,isFile:z,isSymlink:T,isDirectory:B}]of Q.ls())if(z||T)switch(Y){case"deno.json":case"deno.jsonc":await H($);break;case".nvmrc":case".node-version":await K($,"nodejs.org");break;case".ruby-version":await K($,"ruby-lang.org");break;case".python-version":await E($);break;case".terraform-version":await R($);break;case"package.json":await V($);break;case"action.yml":case"action.yaml":await D($);break;case"Cargo.toml":Z.push({project:"rust-lang.org",constraint:X}),await L($);break;case"skaffold.yaml":Z.push({project:"skaffold.dev",constraint:X}),await N($);break;case"go.mod":case"go.sum":Z.push({project:"go.dev",constraint:X}),await L($);break;case"requirements.txt":case"pipfile":case"pipfile.lock":case"setup.py":Z.push({project:"pip.pypa.io",constraint:X}),await L($);break;case"pyproject.toml":await C($);break;case"Gemfile":Z.push({project:"ruby-lang.org",constraint:X}),await L($);break;case".yarnrc":Z.push({project:"classic.yarnpkg.com",constraint:X}),await L($);break;case"yarn.lock":Z.push({project:"yarnpkg.com",constraint:X});break;case".yarnrc.yml":Z.push({project:"yarnpkg.com",constraint:X}),await L($);break;case"bun.lock":case"bun.lockb":Z.push({project:"bun.sh",constraint:new b(">=1")});break;case"pnpm-lock.yaml":Z.push({project:"pnpm.io",constraint:X});break;case"pixi.toml":Z.push({project:"prefix.dev",constraint:X}),await L($);break;case"pkgx.yml":case"pkgx.yaml":case".pkgx.yml":case".pkgx.yaml":case"launchpad.yml":case"launchpad.yaml":case".launchpad.yml":case".launchpad.yaml":case"dependencies.yml":case"dependencies.yaml":case".dependencies.yml":case".dependencies.yaml":case"deps.yml":case"deps.yaml":case".deps.yml":case".deps.yaml":await F(await $.readYAML());break;case"cdk.json":Z.push({project:"aws.amazon.com/cdk",constraint:X});break;case"justfile":case"Justfile":Z.push({project:"just.systems",constraint:X});break;case"Taskfile.yml":Z.push({project:"taskfile.dev",constraint:X});break;case"uv.lock":Z.push({project:"astral.sh/uv",constraint:X});break}else if(B)switch(Y){case".git":if(XW.platform!=="darwin")Z.push({project:"git-scm.org",constraint:X});break;case".hg":Z.push({project:"mercurial-scm.org",constraint:X});break;case".svn":Z.push({project:"apache.org/subversion",constraint:X});break}if(J&&!Z.some(($)=>$.project==="bun.sh")&&!Z.some(($)=>$.project==="nodejs.org"))Z.push({project:"nodejs.org",constraint:X});let q=new Map;for(let $ of Z){let Y=q.get($.project);if(!Y)q.set($.project,$);else{let z=Y.constraint.toString(),T=$.constraint.toString();if(/^\d+\.\d+(?:\.\d+)?$/.test(T)&&!/^\d+\.\d+(?:\.\d+)?$/.test(z))q.set($.project,$);else if(z==="*"&&T!=="*")q.set($.project,$);else if(/^[><=^~]/.test(z)&&/^\d+\.\d+(?:\.\d+)?$/.test(T))q.set($.project,$)}}return{pkgs:Array.from(q.values()),env:O};async function H($){Z.push({project:"deno.land",constraint:X});let Y=ZW(await $.read());if(_(Y)&&Y.pkgx){let z=Y.pkgx;if(d(z)||p(z))z={dependencies:z};await F(z)}}async function K($,Y){let z=(await $.read()).trim();if(z.startsWith("v"))z=z.slice(1);if(z.match(/^\d/))z=`@${z}`;z=`${Y}${z}`,Z.push(a(z))}async function E($){let z=(await $.read()).trim().split(`
`);for(let T of z){if(T=T.trim(),!T)continue;if(T.startsWith("#"))continue;T=`python.org@${T}`;try{Z.push(a(T));break}catch{}}}async function R($){let z=`terraform.io@${(await $.read()).trim()}`;Z.push(a(z))}async function V($){let Y=JSON.parse(await $.read()),z={};if(Y?.engines){if(Y.engines.node)z["nodejs.org"]=Y.engines.node;if(Y.engines.npm)z["npmjs.com"]=Y.engines.npm;if(Y.engines.yarn)z["yarnpkg.com"]=Y.engines.yarn;if(Y.engines.pnpm)z["pnpm.io"]=Y.engines.pnpm}if(Y?.packageManager){let f=Y.packageManager.match(/^(?<pkg>[^@]+)@(?<version>[^+]+)/);if(f){let{pkg:z0,version:l}=f.groups;switch(z0){case"npm":z["npmjs.com"]=l;break;case"yarn":z["yarnpkg.com"]=l;break;case"pnpm":z["pnpm.io"]=l;break}}}if(Y?.volta){if(Y.volta.node)z["nodejs.org"]=Y.volta.node;if(Y.volta.npm)z["npmjs.com"]=Y.volta.npm;if(Y.volta.yarn)z["yarnpkg.com"]=Y.volta.yarn;if(Y.volta.pnpm)z["pnpm.io"]=Y.volta.pnpm}let T=Y?.pkgx;if(d(T)||p(T))T={dependencies:T};if(T?.dependencies){if(_(T.dependencies))Object.assign(z,T.dependencies)}let B=Object.keys(z).length>0?{dependencies:z,...T?.env&&{env:T.env}}:T;await F(B),J=!0}async function N($){let Y=await $.readYAMLAll(),z=[];for(let B of Y){if(!_(B))continue;if(B.build?.local?.useDockerCLI?.toString()==="true"||B.deploy?.docker)z.push({project:"docker.com/cli",constraint:new b("*")});if(B.deploy?.kubectl)z.push({project:"kubernetes.io/kubectl",constraint:new b("*")});if(B.deploy?.kubeContext?.match("minikube"))z.push({project:"kubernetes.io/minikube",constraint:new b("*")});if(B.deploy?.helm||B.manifests?.helm)z.push({project:"helm.sh",constraint:new b("*")});if(B.deploy?.kpt||B.manifests?.kpt)z.push({project:"kpt.dev",constraint:new b("*")});if(B.manifests?.kustomize)z.push({project:"kubernetes.io/kustomize",constraint:new b("*")})}let T=Array.from(new Map(z.map((B)=>[B.project,B])).values());Z.push(...T)}async function D($){let Y=await $.readYAML();if(!_(Y))return;let z=Y.runs?.using?.match(/node(\d+)/);if(z?.[1])Z.push({project:"nodejs.org",constraint:new b(`^${z?.[1]}`)});await F(Y.pkgx)}async function C($){let Y=await $.read();if(Z.push({project:"python.org",constraint:X}),Y.includes("poetry.core.masonry.api"))Z.push({project:"python-poetry.org",constraint:X});else Z.push({project:"pip.pypa.io",constraint:X});await L($)}async function L($){let Y;for await(let z of qW($.string))if(Y!==void 0){if(/^(?:(?:#|\/\/)\s*)?---(?:\s*\*\/)?$/.test(z.trim())){let T=V0(Y);if(_(T)&&T.pkgx)T=d(T.pkgx)||p(T.pkgx)?{dependencies:T.pkgx}:T.pkgx;return await F(T)}Y+=z?.replace(/^(#|\/\/)/,""),Y+=`
`}else if(/^(?:(?:\/\*|#|\/\/)\s*)?---/.test(z.trim()))Y=""}async function F($){if(!_($))return;let Y=await UW($);for(let[T,B]of Object.entries(Y.env)){if(M0(B))B=B.toString();if(d(B))O[T]=z(B)}Z.push(...Y.deps);function z(T){let B=[{from:"{{home}}",to:h.home().string},{from:"{{srcroot}}",to:Q.string}],f=T;for(let{from:z0,to:l}of B)f=f.replace(new RegExp(z0,"g"),l);return OW(f),f}}}function OW(W){let Q=0;while(!0){let X=W.indexOf("$",Q);if(X===-1)break;Q=X;let J=W.substring(Q),Z=/^\$\{[A-Z_]\w*\}/i.test(J),O=/^\$[A-Z_]\w*/i.test(J);if(!Z&&!O)throw new Error("Invalid dollar sign usage detected.");Q++}}function UW(W){let Q=$W(W.dependencies),X=_(W.env)?W.env:{};return{deps:Q,env:X}}function $W(W){if(d(W))W=W.split(/\s+/).filter((X)=>X);function Q(X){if(X.endsWith("@latest"))X=X.slice(0,-6);return a(X)}if(p(W))W=W.map(Q).reduce((X,J)=>{return X[J.project]=J.constraint.toString(),X},{});if(!_(W))return[];return Object.entries(W).map(([X,J])=>{if(/^@?latest$/.test(J))J="*";return JW(X,J)}).filter(Boolean)}function zW(W){return{"bun.sh":"bun","nodejs.org":"node","npmjs.com":"npm","yarnpkg.com":"yarn","pnpm.io":"pnpm","python.org":"python","pip.pypa.io":"pip","rust-lang.org":"rustc","go.dev":"go","ruby-lang.org":"ruby"}[W]||W.split(".")[0].split("/").pop()||W}async function KW(W,Q){let X=k.join(Q,"bin");await o.promises.mkdir(X,{recursive:!0});let J=[],Z=[],O={"wget.com":"gnu.org/wget","git.com":"git-scm.org","npm.com":"npmjs.com","yarn.com":"yarnpkg.com","docker.com":"docker.io","postgres.org":"postgresql.org","mysql.com":"mysql.org","redis.com":"redis.io","nginx.com":"nginx.org","apache.com":"apache.org","golang.org":"go.dev","rust.org":"rust-lang.org","ruby.org":"ruby-lang.org","rails.com":"rubyonrails.org","vim.com":"vim.org","neovim.com":"neovim.io","vscode.com":"code.visualstudio.com"};for(let q of W)try{if(G.verbose)console.log(`\uD83D\uDD04 Installing ${q.project}@${q.version} (direct installation)...`);let U=q.version?`${q.project}@${q.version}`:q.project,H=await Q0([U],Q);if(H.length>0){if(J.push(`${q.project}@${q.version}`),q.project==="bun.sh"&&H.length>0)try{await new Promise((V)=>setTimeout(V,25));let K=H[0];if(await Bun.spawn([K,"--version"],{stdio:["ignore","pipe","pipe"]}).exited===0){if(G.verbose)console.log(`\u2705 Verified ${q.project}@${q.version} is working`)}}catch(K){if(G.verbose)console.log(`\u26A0\uFE0F Warning: Could not verify ${q.project} binary: ${K}`)}console.log(`\u2705 Installed ${q.project}@${q.version}`)}else{let K=O[q.project],E=`No binaries found after installation of ${q.project}`;Z.push({project:q.project,error:E,suggestion:K}),console.error(`\u274C ${E}`)}}catch(U){let H=U instanceof Error?U.message:String(U),K=O[q.project];Z.push({project:q.project,error:H,suggestion:K}),console.error(`\u274C Failed to install ${q.project}: ${H}`)}return{successful:J,failed:Z}}async function N0(W,Q){let X=await e({string:W});if(X.pkgs.length===0&&Object.keys(X.env).length===0)console.error("no devenv detected"),W0.exit(1);function J(V){if(V.startsWith("^")||V.startsWith("~"))return V.slice(1);if(V.startsWith(">="))return V.slice(2);return V}let Z=X.pkgs.map((V)=>`+${V.project}@${J(V.constraint.toString())}`);if(Q.dryrun){console.log(Z.join(" "));return}function O(V){let N=k.basename(V),C=Bun.hash(V).toString(16).padStart(16,"0").slice(0,8);return`${N.replace(/[^\w-.]/g,"-").toLowerCase()}_${C}`}let q=O(W),U=k.join(W0.env.HOME||"~",".local","share","launchpad","envs",q);if(!Q.quiet&&G.verbose)console.log("\uD83D\uDE80 Installing packages for project environment..."),console.log(`\uD83D\uDCCD Installation prefix: ${U}`);let H=X.pkgs.map((V)=>({project:V.project,version:J(V.constraint.toString()),command:zW(V.project)}));try{let{successful:V,failed:N}=await KW(H,U);if(!Q.quiet&&G.verbose){if(V.length>0&&N.length===0)console.log("\u2705 All packages installed successfully!");else if(V.length>0&&N.length>0){console.log(`\u26A0\uFE0F Partial installation: ${V.length} succeeded, ${N.length} failed`),console.log("\u2705 Successfully installed:");for(let L of V)console.log(` \u2705 ${L}`);console.log(""),console.log("\u274C Failed to install:");for(let{project:L,error:F,suggestion:$}of N)if(console.log(` \u274C ${L}: ${F}`),$)console.log(` \uD83D\uDCA1 Did you mean '${$}'? Update your dependencies file.`)}else if(N.length>0){console.log("\u274C All package installations failed!");for(let{project:L,error:F,suggestion:$}of N)if(console.log(` \u274C ${L}: ${F}`),$)console.log(` \uD83D\uDCA1 Did you mean '${$}'? Update your dependencies file.`)}}if(V.length===0)console.error(""),console.error("\u274C No packages were successfully installed. Environment setup aborted."),console.error("\uD83D\uDD27 Please fix the package specifications in your dependencies file and try again."),W0.exit(1);let D=["dependencies.yaml","dependencies.yml","pkgx.yaml","pkgx.yml",".pkgx.yaml",".pkgx.yml",".launchpad.yaml","launchpad.yaml",".launchpad.yml","launchpad.yml","deps.yml","deps.yaml",".deps.yml",".deps.yaml"],C;for(let L of D){let F=k.join(W,L);if(o.existsSync(F)){C=F;break}}if(C)try{let L=o.readFileSync(C,"utf-8"),F=Bun.hash(L).toString(16).padStart(16,"0").slice(0,8),$=k.join(U,".deps_hash");if(o.mkdirSync(U,{recursive:!0}),o.writeFileSync($,F),!Q.quiet&&G.verbose)console.log(`\uD83D\uDCDD Stored dependency hash: ${F}`)}catch{if(!Q.quiet&&G.verbose)console.log("\u26A0\uFE0F Warning: Could not store dependency hash for smart caching")}}catch(V){console.error("\u274C Installation failed:",V instanceof Error?V.message:String(V)),console.error(""),console.error("\uD83D\uDD27 Please fix the package specifications in your dependencies file and try again."),W0.exit(1)}let K="";for(let[V,N]of Object.entries(X.env))K+=`${V}=${s(N)}
`;let E=k.join(U,"bin"),R=k.join(U,"sbin");console.log(`
# Project-specific environment for ${W}
# This creates an isolated environment that gets properly deactivated
# Store original PATH before any modifications (critical for proper restoration)
if [ -z "$_LAUNCHPAD_ORIGINAL_PATH" ]; then
export _LAUNCHPAD_ORIGINAL_PATH="$PATH"
fi
# Store original environment variables for restoration
_LAUNCHPAD_ORIGINAL_ENV=""${Object.keys(X.env).map((V)=>`
if [ -n "$${V}" ]; then
_LAUNCHPAD_ORIGINAL_ENV="$_LAUNCHPAD_ORIGINAL_ENV ${V}=$${V}"
else
_LAUNCHPAD_ORIGINAL_ENV="$_LAUNCHPAD_ORIGINAL_ENV ${V}=__UNSET__"
fi`).join("")}
# Set up project-specific PATH
export PATH="${E}:${R}:$_LAUNCHPAD_ORIGINAL_PATH"
# Create deactivation function
_pkgx_dev_try_bye() {
# Check if we're still in the project directory or a subdirectory
case "$PWD" in
"${W}"|"${W}/"*)
# Still in project directory, don't deactivate
return 1
;;
*)
# Only show deactivation message if not silent
if [ "$1" != "silent" ]; then
if [ "${G.showShellMessages?"true":"false"}" = "true" ]; then
echo -e "\\033[31m${G.shellDeactivationMessage}\\033[0m" >&2
fi
fi
# Restore original PATH
if [ -n "$_LAUNCHPAD_ORIGINAL_PATH" ]; then
export PATH="$_LAUNCHPAD_ORIGINAL_PATH"
unset _LAUNCHPAD_ORIGINAL_PATH
fi
# Restore original environment variables
if [ -n "$_LAUNCHPAD_ORIGINAL_ENV" ]; then
for env_var in $_LAUNCHPAD_ORIGINAL_ENV; do
if [ -n "$env_var" ]; then
key="\${env_var%%=*}"
value="\${env_var#*=}"
if [ "$value" = "__UNSET__" ]; then
unset "$key"
else
export "$key"="$value"
fi
fi
done
unset _LAUNCHPAD_ORIGINAL_ENV
fi
# Clean up project-specific environment variables${Object.keys(X.env).length>0?`
${Object.keys(X.env).map((V)=>` unset ${V}`).join(`
`)}`:""}
unset -f _pkgx_dev_try_bye
;;
esac
}
set -a
${K}
set +a
# If we detect we're in the activated project directory, confirm activation
if [ "\${PWD}" = "${W}" ]; then
if [ "${G.showShellMessages?"true":"false"}" = "true" ]; then
echo "${G.shellActivationMessage.replace("{path}",`\\033[3m${W}\\033[0m`)}" >&2
fi
# Give the shell a moment to recognize the new PATH before prompt detection
# This helps prevent Starship timeout warnings when detecting tool versions
sleep 0.1
fi`)}import{existsSync as n,readFileSync as YW,writeFileSync as F0}from"fs";import{homedir as GW,platform as VW}from"os";import{join as H0}from"path";import w0 from"process";async function I0(W,{dryrun:Q}){let X=!1,J=HW();for(let[Z,O]of J)try{let q="";if(n(Z))q=YW(Z,"utf8");let U=q.includes("# https://github.com/pkgxdev/dev");if(W==="install"){if(U){console.error("hook already integrated:",Z);continue}if(!Q){let H=q.endsWith(`
`)?q:`${q}
`;F0(Z,`${H}
${O} # https://github.com/pkgxdev/dev
`)}X=!0,console.error(`${Z} << \`${O}\``)}else if(W==="uninstall"){if(!U)continue;let K=q.split(`
`).filter((E)=>!E.includes("# https://github.com/pkgxdev/dev"));if(!Q)F0(Z,K.join(`
`));X=!0,console.error("removed hook:",Z)}}catch(q){console.error(`Failed to process ${Z}:`,q instanceof Error?q.message:q)}if(Q&&X)console.error("%cthis was a dry-run. %cnothing was changed.","color: #5f5fff","color: initial");else switch(W){case"uninstall":if(!X)console.error("nothing to deintegrate found");break;case"install":if(X)console.log("now %crestart your terminal%c for `dev` hooks to take effect","color: #5f5fff","color: initial")}}function HW(){let W=n("/opt/homebrew/bin/dev")||n("/usr/local/bin/dev")?'eval "$(dev --shellcode)"':n("/usr/local/bin/launchpad")?'eval "$(launchpad dev:shellcode)"':'eval "$(pkgx --quiet dev --shellcode)"',Q=GW(),X=w0.env.ZDOTDIR||Q,J=[H0(X,".zshrc"),W],O=[J,[H0(Q,".bashrc"),W],[H0(Q,".bash_profile"),W]].filter(([q])=>n(q));if(O.length===0){if(VW()==="darwin")return[J];console.error("no `.shellrc` files found"),w0.exit(1)}return O}import{existsSync as X0}from"fs";import A0,{join as I}from"path";import v from"process";var TW=["dependencies.yaml","dependencies.yml","pkgx.yaml","pkgx.yml",".pkgx.yaml",".pkgx.yml",".launchpad.yaml","launchpad.yaml",".launchpad.yml","launchpad.yml","deps.yml","deps.yaml",".deps.yml",".deps.yaml"];function BW(){let W=(v.env.PATH||"").split(":").filter(Boolean),Q=v.cwd(),J=[I(Q,"launchpad"),I(Q,"..","launchpad"),I(Q,"packages","launchpad","bin","cli.ts")].find((O)=>{try{return X0(O)}catch{return!1}});if(J){let O=J;if(O.startsWith("./")||!A0.isAbsolute(O))O=A0.resolve(O);let q=v.env.HOME||v.env.USERPROFILE||"~",H=[I(q,".bun","bin","bun"),I("/usr/local/bin","bun"),I("/opt/homebrew/bin","bun"),I(q,".local","bin","bun"),...W.map((K)=>I(K,"bun")).filter((K)=>!K.includes(".pkgx")&&!K.includes("/tmp/"))].find((K)=>{try{return X0(K)}catch{return!1}});if(H)return`"${H}" "${O}"`;else return`if command -v bun >/dev/null 2>&1; then bun "${O}"; else echo "\u274C Bun not found. Install bun: curl -fsSL https://bun.sh/install | bash" >&2 && false; fi`}let Z=W.map((O)=>I(O,"launchpad")).find((O)=>{try{return X0(O)}catch{return!1}});if(Z)return"launchpad";if(Z=W.map((O)=>I(O,"dev")).find((O)=>{try{return X0(O)}catch{return!1}}),Z)return"dev";return'echo "\u274C Launchpad not found. Install bun to use local development: curl -fsSL https://bun.sh/install | bash" >&2 && false'}function j0(){let W=BW(),Q=TW.join(" "),X=G.showShellMessages?"true":"false",J=G.shellActivationMessage||"Environment activated for {path}",Z=G.shellDeactivationMessage||"dev environment deactivated";return`
# Global variable to prevent infinite loops
_PKGX_ACTIVATING=""
_pkgx_chpwd_hook() {
# Prevent infinite loops during activation
if [ -n "$_PKGX_ACTIVATING" ]; then
return 0
fi
# Check if we're currently in an active dev environment
local was_active=false
local current_env_dir=""
if type _pkgx_dev_try_bye >/dev/null 2>&1; then
was_active=true
# Try to extract the current environment directory from the function
# First try launchpad-style function (with case statement and quoted paths)
current_env_dir=$(declare -f _pkgx_dev_try_bye | grep -o '"/[^"]*"' | head -1 | sed 's/"//g')
# If that fails, we might have a pkgx fallback function
# In this case, we can't reliably determine the original directory,
# so we'll treat any directory with deps as a potential switch
if [ -z "$current_env_dir" ]; then
# For pkgx fallback functions, we'll use a more aggressive approach
# and assume the current environment should be deactivated if we find
# a different dependency file
current_env_dir="__unknown__"
fi
fi
# Find dependency files in current directory
local deps_file=""
for file in ${Q}; do
if [ -f "$PWD/$file" ]; then
deps_file="$PWD/$file"
break
fi
done
# DEACTIVATION LOGIC: Check if we should deactivate the current environment
local adjusting_env=false
if [ "$was_active" = true ] && [ -n "$current_env_dir" ]; then
if [ "$current_env_dir" = "__unknown__" ]; then
# We have an active environment but don't know its directory (pkgx fallback)
# If we found a dependency file, assume we need to switch environments
if [ -n "$deps_file" ]; then
echo "\uD83D\uDD04 Adjusting development environment..." >&2
adjusting_env=true
_pkgx_dev_try_bye silent
was_active=false
fi
else
# We know the current environment directory (launchpad-created function)
# Check if current directory has its own dependency file (nested environment)
if [ -n "$deps_file" ] && [ "$PWD" != "$current_env_dir" ]; then
# We're in a subdirectory with its own dependency file, switch environments
echo "\uD83D\uDD04 Adjusting development environment..." >&2
adjusting_env=true
_pkgx_dev_try_bye silent
was_active=false
elif [ -z "$deps_file" ]; then
# Check if we're outside the project directory tree
case "$PWD" in
"$current_env_dir"|"$current_env_dir/"*)
# Still in the same project directory tree, keep active
;;
*)
# Outside the project directory tree, deactivate
_pkgx_dev_try_bye
was_active=false
;;
esac
else
# We have a dependency file and we're in the same directory as the active environment
# No need to reactivate - just return early
return 0
fi
fi
fi
# ACTIVATION LOGIC: Only run if we're not already active and we found a dependency file
if [ "$was_active" = false ] && [ -n "$deps_file" ]; then
# Ensure ~/.local/bin exists and is in PATH
mkdir -p "$HOME/.local/bin"
if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
export PATH="$HOME/.local/bin:$PATH"
fi
# Generate readable project hash for better user experience
local project_hash=""
local project_name=$(basename "$PWD")
local clean_project_name=$(echo "$project_name" | sed 's/[^a-zA-Z0-9._-]/-/g' | tr '[:upper:]' '[:lower:]')
# Create a simple hash using Bun's hash function for consistency
# This ensures perfect consistency between shell and TypeScript hash generation
local hash_input="$PWD"
local short_hash=""
# Try to use Bun's hash function for consistency
if command -v bun >/dev/null 2>&1; then
short_hash=$(echo -n "$hash_input" | bun -e "
const input = await Bun.stdin.text();
const hash = Bun.hash(input);
console.log(hash.toString(16).padStart(16, '0').slice(0, 8));
" 2>/dev/null)
fi
# Fallback: try to find bun in common locations if not in PATH
if [ -z "$short_hash" ]; then
local bun_paths=(
"$HOME/.bun/bin/bun"
"/usr/local/bin/bun"
"/opt/homebrew/bin/bun"
"$HOME/.local/bin/bun"
)
for bun_path in "\${bun_paths[@]}"; do
if [ -x "$bun_path" ]; then
short_hash=$(echo -n "$hash_input" | "$bun_path" -e "
const input = await Bun.stdin.text();
const hash = Bun.hash(input);
console.log(hash.toString(16).padStart(16, '0').slice(0, 8));
" 2>/dev/null)
if [ -n "$short_hash" ]; then
break
fi
fi
done
fi
# Final fallback: use base64 with better collision avoidance if Bun is not available
if [ -z "$short_hash" ]; then
local full_hash=$(echo -n "$hash_input" | base64 2>/dev/null | tr -d '\\n' | tr '/+=' '___')
if [ -n "$full_hash" ]; then
# Take characters from the middle to avoid suffix collisions
local hash_len=\${#full_hash}
local start_pos=$((hash_len / 3))
short_hash=$(echo "$full_hash" | cut -c$((start_pos + 1))-$((start_pos + 8)))
fi
fi
if [ -n "$short_hash" ] && [ -n "$clean_project_name" ]; then
project_hash="\${clean_project_name}_\${short_hash}"
fi
local env_cache_dir=""
if [ -n "$project_hash" ]; then
env_cache_dir="$HOME/.local/share/launchpad/envs/$project_hash"
fi
# Also check for base64-encoded directory for backward compatibility
local base64_hash=""
if [ ! -d "$env_cache_dir/bin" ] && [ ! -d "$env_cache_dir/sbin" ]; then
base64_hash=$(echo -n "$PWD" | base64 2>/dev/null | tr -d '\\n' | tr '/+=' '___')
if [ -n "$base64_hash" ]; then
local base64_cache_dir="$HOME/.local/share/launchpad/envs/$base64_hash"
# Check if base64 cache has actual binaries
if [ -d "$base64_cache_dir" ]; then
local base64_has_binaries=false
if [ -d "$base64_cache_dir/bin" ] && [ "$(ls -A "$base64_cache_dir/bin" 2>/dev/null)" ]; then
base64_has_binaries=true
elif [ -d "$base64_cache_dir/sbin" ] && [ "$(ls -A "$base64_cache_dir/sbin" 2>/dev/null)" ]; then
base64_has_binaries=true
fi
if [ "$base64_has_binaries" = true ]; then
env_cache_dir="$base64_cache_dir"
fi
fi
fi
fi
# If packages are already installed, check if they match current dependencies
if [ -n "$env_cache_dir" ] && [ -d "$env_cache_dir" ]; then
# Check if there are actual binaries installed, not just empty directories
local has_binaries=false
if [ -d "$env_cache_dir/bin" ] && [ "$(ls -A "$env_cache_dir/bin" 2>/dev/null)" ]; then
has_binaries=true
elif [ -d "$env_cache_dir/sbin" ] && [ "$(ls -A "$env_cache_dir/sbin" 2>/dev/null)" ]; then
has_binaries=true
fi
# Check if cached environment matches current dependencies
local deps_match=true
if [ "$has_binaries" = true ] && [ -f "$deps_file" ]; then
# Create a simple hash of the dependency file content for comparison
local current_deps_hash=""
if command -v bun >/dev/null 2>&1; then
current_deps_hash=$(cat "$deps_file" | bun -e "
const input = await Bun.stdin.text();
const hash = Bun.hash(input);
console.log(hash.toString(16).padStart(16, '0').slice(0, 8));
" 2>/dev/null)
fi
# Fallback hash method if bun is not available
if [ -z "$current_deps_hash" ]; then
current_deps_hash=$(cat "$deps_file" | base64 2>/dev/null | tr -d '\\n' | tr '/+=' '___' | cut -c1-8)
fi
# Check if we have a stored hash for this environment
local stored_hash=""
if [ -f "$env_cache_dir/.deps_hash" ]; then
stored_hash=$(cat "$env_cache_dir/.deps_hash" 2>/dev/null)
fi
# If hashes don't match, we need to regenerate
if [ "$current_deps_hash" != "$stored_hash" ]; then
deps_match=false
echo "\uD83D\uDD04 Dependencies changed, updating environment..." >&2
fi
fi
if [ "$has_binaries" = true ] && [ "$deps_match" = true ]; then
# Fast path: packages already installed and match current dependencies
_launchpad_fast_activate "$PWD" "$env_cache_dir"
else
# Cache directory exists but no binaries - treat as slow path
# Only show "Setting up development environment..." if we're not adjusting
if [ "$adjusting_env" = false ]; then
echo "\uD83D\uDD04 Setting up development environment..." >&2
fi
# Set flag to prevent recursive calls
export _PKGX_ACTIVATING="$PWD"
if [[ "${W}" == *"launchpad"* ]]; then
# Try to run launchpad dev:dump with proper error handling
local launchpad_output=""
local exit_code=0
# Capture only stdout, let stderr (progress bars) pass through to user
launchpad_output=$(eval "${W} dev:dump \\"$PWD\\"") || exit_code=$?
if [ $exit_code -eq 0 ] && [ -n "$launchpad_output" ]; then
# If launchpad succeeds, extract just the shell script part using system sed
local shell_script=""
shell_script=$(echo "$launchpad_output" | /usr/bin/sed -n '/^[[:space:]]*#.*Project-specific environment/,$p' 2>/dev/null || echo "$launchpad_output" | sed -n '/^[[:space:]]*#.*Project-specific environment/,$p')
if [ -n "$shell_script" ]; then
eval "$shell_script"
else
echo "\u26A0\uFE0F Launchpad succeeded but no shell script found" >&2
echo " Try running: launchpad dev:dump" >&2
fi
else
# If launchpad fails, show generic error message
local project_name=$(basename "$PWD")
echo "\u26A0\uFE0F Cannot set up development environment for $project_name" >&2
echo "\uD83D\uDCA1 To fix this:" >&2
echo " \u2022 Install bun: curl -fsSL https://bun.sh/install | bash" >&2
echo " \u2022 Or compile launchpad globally: bun run compile" >&2
echo " \u2022 Or run manually: launchpad dev:dump" >&2
fi
else
# For other dev commands, try with basic error handling
local dev_output=""
local dev_exit_code=0
dev_output=$(eval "${W} dump" 2>&1) || dev_exit_code=$?
if [ $dev_exit_code -eq 0 ] && [ -n "$dev_output" ]; then
eval "$dev_output"
else
echo "\u26A0\uFE0F Dev command failed (exit code: $dev_exit_code)" >&2
if [ -n "$dev_output" ]; then
echo " Error: $dev_output" >&2
fi
fi
fi
# Clear the flag after activation
unset _PKGX_ACTIVATING
fi
fi
fi
}
# Fast activation function for already-installed packages
_launchpad_fast_activate() {
local cwd="$1"
local env_dir="$2"
# Store original PATH before any modifications (critical for proper restoration)
if [ -z "$_LAUNCHPAD_ORIGINAL_PATH" ]; then
export _LAUNCHPAD_ORIGINAL_PATH="$PATH"
fi
# Build PATH with only existing directories for better performance
local new_path=""
if [ -d "$env_dir/bin" ]; then
new_path="$env_dir/bin"
fi
if [ -d "$env_dir/sbin" ]; then
if [ -n "$new_path" ]; then
new_path="$new_path:$env_dir/sbin"
else
new_path="$env_dir/sbin"
fi
fi
# Set up project-specific PATH
if [ -n "$new_path" ]; then
export PATH="$new_path:$_LAUNCHPAD_ORIGINAL_PATH"
else
export PATH="$_LAUNCHPAD_ORIGINAL_PATH"
fi
# Create the deactivation function with proper directory checking
# Use a here-document to properly capture the cwd variable
eval "$(cat <<EOF
_pkgx_dev_try_bye() {
case "\\$PWD" in
"$cwd"|"$cwd/"*)
return 1
;;
*)
if [ "\\$1" != "silent" ]; then
if [ "${X}" = "true" ]; then
echo -e "\\\\033[31m${Z}\\\\033[0m" >&2
fi
fi
if [ -n "\\$_LAUNCHPAD_ORIGINAL_PATH" ]; then
export PATH="\\$_LAUNCHPAD_ORIGINAL_PATH"
unset _LAUNCHPAD_ORIGINAL_PATH
fi
unset -f _pkgx_dev_try_bye
;;
esac
}
EOF
)"
# Show activation message if enabled
if [ "${X}" = "true" ]; then
# Replace {path} placeholder with actual path using sed with | delimiter
# Use basename for cleaner display and add color coding
local project_name=$(basename "$cwd")
local message="${J}"
message=$(echo "$message" | sed "s|{path}|$project_name|g")
printf "\\033[32m%s\\033[0m\\n" "$message" >&2
fi
}
# Function for better error messaging when launchpad fails
_launchpad_show_help() {
local project_name=$(basename "$PWD")
echo "\u26A0\uFE0F Cannot set up development environment for $project_name" >&2
echo "\uD83D\uDCA1 To fix this:" >&2
echo " \u2022 Install bun: curl -fsSL https://bun.sh/install | bash" >&2
echo " \u2022 Or compile launchpad globally: bun run compile" >&2
echo " \u2022 Or run manually: launchpad dev:dump" >&2
}
dev() {
case "$1" in
off)
if type -f _pkgx_dev_try_bye >/dev/null 2>&1; then
PWD=/ _pkgx_dev_try_bye
else
echo "no devenv" >&2
fi;;
''|on)
if [ "$2" ]; then
eval "${W} \\"$@\\""
elif ! type -f _pkgx_dev_try_bye >/dev/null 2>&1; then
if [[ "${W}" == *"launchpad"* ]]; then
# Try to run launchpad dev:dump with proper error handling
local launchpad_output=""
local exit_code=0
# Capture only stdout, let stderr (progress bars) pass through to user
launchpad_output=$(eval "${W} dev:dump \\"$PWD\\"") || exit_code=$?
if [ $exit_code -eq 0 ] && [ -n "$launchpad_output" ]; then
# If launchpad succeeds, extract just the shell script part using system sed
local shell_script=""
shell_script=$(echo "$launchpad_output" | /usr/bin/sed -n '/^[[:space:]]*#.*Project-specific environment/,$p' 2>/dev/null || echo "$launchpad_output" | sed -n '/^[[:space:]]*#.*Project-specific environment/,$p')
if [ -n "$shell_script" ]; then
eval "$shell_script"
else
echo "\u26A0\uFE0F Launchpad succeeded but no shell script found" >&2
echo " Try running: launchpad dev:dump" >&2
fi
else
# If launchpad fails, show generic error message
local project_name=$(basename "$PWD")
echo "\u26A0\uFE0F Cannot set up development environment for $project_name" >&2
echo "\uD83D\uDCA1 To fix this:" >&2
echo " \u2022 Install bun: curl -fsSL https://bun.sh/install | bash" >&2
echo " \u2022 Or compile launchpad globally: bun run compile" >&2
echo " \u2022 Or run manually: launchpad dev:dump" >&2
fi
else
# For other dev commands, try with basic error handling
local dev_output=""
local dev_exit_code=0
dev_output=$(eval "${W} dump" 2>&1) || dev_exit_code=$?
if [ $dev_exit_code -eq 0 ] && [ -n "$dev_output" ]; then
eval "$dev_output"
else
echo "\u26A0\uFE0F Dev command failed (exit code: $dev_exit_code)" >&2
if [ -n "$dev_output" ]; then
echo " Error: $dev_output" >&2
fi
fi
fi
else
echo "devenv already active" >&2
fi;;
*)
# Pass all other commands directly to dev/launchpad
eval "${W} \\"$@\\"";;
esac
}
if [ -n "$ZSH_VERSION" ] && [ "$(emulate)" = "zsh" ]; then
eval 'typeset -ag chpwd_functions
if [[ -z "\${chpwd_functions[(r)_pkgx_chpwd_hook]+1}" ]]; then
chpwd_functions=( _pkgx_chpwd_hook \${chpwd_functions[@]} )
fi
# Check for dependency files on shell startup (no background jobs, no delays)
if ! type _pkgx_dev_try_bye >/dev/null 2>&1; then
for file in ${Q}; do
if [ -f "$PWD/$file" ]; then
_pkgx_chpwd_hook
break
fi
done
fi'
elif [ -n "$BASH_VERSION" ] && [ "$POSIXLY_CORRECT" != y ] ; then
eval 'cd() {
builtin cd "$@" || return
_pkgx_chpwd_hook
}
# Check for dependency files on shell startup (no background jobs, no delays)
if ! type _pkgx_dev_try_bye >/dev/null 2>&1; then
for file in ${Q}; do
if [ -f "$PWD/$file" ]; then
_pkgx_chpwd_hook
break
fi
done
fi'
else
POSIXLY_CORRECT=y
echo "launchpad: dev: warning: unsupported shell" >&2
fi
`.trim()}function EW(){let W=v.env.XDG_DATA_HOME?.trim();if(W)return I(W,"launchpad","dev");return I(LW(),"launchpad","dev")}function LW(){let W=v.env.HOME||"~";switch(v.platform){case"darwin":return I(W,"Library","Application Support");case"win32":{let Q=v.env.LOCALAPPDATA;if(Q)return Q;else return I(W,"AppData","Local")}default:return I(W,".local","share")}}import u from"fs";import O0 from"os";import P from"path";import i from"process";import y from"fs";import{EOL as NW}from"os";import J0 from"path";import C0 from"process";import x from"fs";import{homedir as MW,platform as T0}from"os";import M from"path";import j from"process";function b1(){let W="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",Q="";switch(T0()){case"darwin":Q="/opt/homebrew";break;case"linux":Q=`/home/linuxbrew/.linuxbrew:${MW()}/.linuxbrew`;break}if(Q)Q=j.env.HOMEBREW_PREFIX??Q,W=`${Q}/bin:${W}`;return W}function g(W){return(j.env.PATH||"").split(M.delimiter).includes(W)}function B0(W){let Q=M.normalize(W).toLowerCase();return["/tmp/","/temp/","\\tmp\\","\\temp\\","launchpad-test-","/var/folders/",j.env.TMPDIR?.toLowerCase()||"",j.env.TEMP?.toLowerCase()||"",j.env.TMP?.toLowerCase()||""].filter(Boolean).some((J)=>Q.includes(J))}function b0(W){if(!G.autoAddToPath){if(G.verbose)console.warn("Skipping adding to PATH (autoAddToPath is disabled)");return!1}if(B0(W)){if(G.verbose)console.warn(`Skipping temporary directory: ${W}`);return!1}try{if(T0()==="win32")return RW(W);let Q=j.env.HOME||j.env.USERPROFILE||"~";if(Q==="~"){if(G.verbose)console.warn("Could not determine home directory");return!1}let X=`export PATH="${W}:$PATH"`,J="";if(x.existsSync(M.join(Q,".zshrc")))J=M.join(Q,".zshrc");else if(x.existsSync(M.join(Q,".bashrc")))J=M.join(Q,".bashrc");else if(x.existsSync(M.join(Q,".bash_profile")))J=M.join(Q,".bash_profile");if(J){let Z=x.readFileSync(J,"utf-8");if(!(Z.includes(X)||Z.includes(`PATH="${W}:`)||Z.includes(`PATH=${W}:`)||Z.includes(`PATH="$PATH:${W}"`)||Z.includes(`PATH=$PATH:${W}`)||Z.match(new RegExp(`PATH="[^"]*${W.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}[^"]*"`))||Z.match(new RegExp(`PATH=[^\\s]*${W.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}[^\\s]*`)))){if(x.appendFileSync(J,`
# Added by launchpad
${X}
`),G.verbose)console.warn(`Added ${W} to your PATH in ${J}`);return!0}if(G.verbose)console.warn(`${W} is already in PATH configuration`);return!0}if(G.verbose)console.warn("Could not find shell configuration file");return!1}catch(Q){if(G.verbose)console.error(`Could not update shell configuration: ${Q instanceof Error?Q.message:String(Q)}`);return!1}}function RW(W){try{if(G.verbose)console.warn("Adding to Windows PATH requires running a PowerShell command with administrator privileges");return console.warn("To add this directory to your PATH on Windows, run the following in an Administrator PowerShell:"),console.warn(`[System.Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';${W.replace(/\//g,"\\")}', [System.EnvironmentVariableTarget]::Machine)`),!1}catch(Q){if(G.verbose)console.error(`Error providing Windows PATH instructions: ${Q instanceof Error?Q.message:String(Q)}`);return!1}}function x0(){return j.env.SHELL||""}function Z0(){let W=j.env.XDG_DATA_HOME;if(W)return M.join(W,"launchpad","dev");let Q=j.env.HOME||j.env.USERPROFILE;if(!Q)throw new Error("Could not determine home directory");switch(T0()){case"darwin":return M.join(Q,"Library","Application Support","launchpad","dev");case"win32":{let X=j.env.LOCALAPPDATA;if(X)return M.join(X,"launchpad","dev");return M.join(Q,"AppData","Local","launchpad","dev")}default:return M.join(Q,".local","share","launchpad","dev")}}async function x1(){let W=j.cwd(),Q=Z0(),X=M.join(Q,W.slice(1),"dev.launchpad.activated");return x.existsSync(X)}async function C1(){let W=Z0(),Q=[];if(!x.existsSync(W))return Q;function X(J,Z=""){try{let O=x.readdirSync(J,{withFileTypes:!0});for(let q of O){let U=M.join(J,q.name),H=M.join(Z,q.name);if(q.isDirectory())X(U,H);else if(q.isFile()&&q.name==="dev.launchpad.activated"){let K=M.join("/",Z);Q.push(K)}}}catch{}}return X(W),Q}async function S1(){let W=j.cwd(),Q=Z0(),X=M.join(Q,W.slice(1)),J=M.join(X,"dev.launchpad.activated");if(x.existsSync(J))try{x.unlinkSync(J);try{x.rmdirSync(X)}catch{}return!0}catch{return!1}return!1}async function u1(W){let Q=Z0(),X=M.join(Q,W.slice(1)),J=M.join(X,"dev.launchpad.activated");try{return x.mkdirSync(X,{recursive:!0}),x.writeFileSync(J,new Date().toISOString()),!0}catch{return!1}}async function h1(W,Q){if(W.length===0)throw new Error("No packages specified");let X=J0.join(Q,"bin");y.mkdirSync(X,{recursive:!0});try{if(await Q0(W,Q),G.verbose)console.warn(`Installed packages: ${W.join(", ")}`);let J=[],Z=J0.join(Q,"bin");if(y.existsSync(Z)){let O=y.readdirSync(Z,{withFileTypes:!0});for(let q of O){if(!q.isFile())continue;let U=J0.join(Z,q.name);if(!wW(U))continue;let H=J0.join(X,q.name);if(y.existsSync(H)&&!G.forceReinstall){if(G.verbose)console.warn(`Shim for ${q.name} already exists at ${H}. Skipping.`);continue}let K=W.find((R)=>{let[V]=R.split("@");return q.name.includes(V)||V.includes(q.name)})||W[0],E=FW(K,q.name,U);if(y.writeFileSync(H,E,{mode:493}),J.push(H),G.verbose)console.warn(`Created shim for ${q.name} at ${H}`)}}else if(G.verbose)console.warn(`No binaries found in ${Z}`);if(J.length>0&&!g(X)){let O=B0(X);if(G.autoAddToPath&&!O)if(b0(X)){console.log(`Added ${X} to your PATH. You may need to restart your terminal or source your shell configuration file.`);let U=x0();if(U.includes("zsh"))console.log("Run this command to update your PATH in the current session:"),console.log(" source ~/.zshrc");else if(U.includes("bash"))console.log("Run this command to update your PATH in the current session:"),console.log(" source ~/.bashrc # or ~/.bash_profile")}else console.log(`Could not add ${X} to your PATH automatically.`),console.log("Please add it manually to your shell configuration file:"),console.log(` echo 'export PATH="${X}:$PATH"' >> ~/.zshrc # or your shell config file`);else if(!O)console.log(`Note: ${X} is not in your PATH.`),console.log("To use the installed shims, add it to your PATH:"),console.log(` echo 'export PATH="${X}:$PATH"' >> ~/.zshrc # or your shell config file`)}return J}catch(J){throw new Error(`Failed to create shims: ${J instanceof Error?J.message:String(J)}`)}}function FW(W,Q,X){return`#!/bin/sh
# Shim for ${W} - ${Q}
# Created by Launchpad
# Try the direct binary path first if it exists
if [ -x "${X}" ]; then
exec "${X}" "$@"
fi
# Final fallback to system command if available
if command -v "${Q}" >/dev/null 2>&1 && [ "$(command -v "${Q}")" != "$0" ]; then
echo "\u26A0\uFE0F Launchpad binary failed, using system version..." >&2
exec "$(command -v "${Q}")" "$@"
fi
# If all else fails, provide helpful error message
echo "\u274C ${Q} not found. Install ${W} with: launchpad install ${W}" >&2
exit 127
${NW}`}function wW(W){try{return(y.statSync(W).mode&y.constants.S_IXUSR)!==0}catch{return!1}}function S0(){if(G.shimPath){if(G.shimPath.startsWith("~")){let W=C0.env.HOME||C0.env.USERPROFILE||"";return new q0(G.shimPath.replace(/^~/,W))}return new q0(G.shimPath)}return q0.home().join(".local/bin")}async function r1(){let W=[];W.push(await IW()),W.push(await AW()),W.push(await jW()),W.push(await bW()),W.push(await xW()),W.push(await CW()),W.push(await SW());let Q={passed:W.filter((J)=>J.status==="pass").length,warnings:W.filter((J)=>J.status==="warn").length,failed:W.filter((J)=>J.status==="fail").length},X="healthy";if(Q.failed>0)X="critical";else if(Q.warnings>0)X="issues";return{overall:X,results:W,summary:Q}}async function IW(){try{let W=U0(),Q=P.join(W.string,"bin"),X=P.join(W.string,"sbin");if(!u.existsSync(W.string))return{name:"Installation Directory",status:"fail",message:`Installation directory does not exist: ${W.string}`,suggestion:'Run "launchpad bootstrap" to set up the installation directory'};if(!u.existsSync(Q))return{name:"Installation Directory",status:"warn",message:`Binary directory missing: ${Q}`,suggestion:'Run "launchpad bootstrap" to create missing directories'};if(!u.existsSync(X))return{name:"Installation Directory",status:"warn",message:`System binary directory missing: ${X}`,suggestion:'Run "launchpad bootstrap" to create missing directories'};try{let J=P.join(W.string,".launchpad-test");u.writeFileSync(J,"test"),u.unlinkSync(J)}catch{return{name:"Installation Directory",status:"fail",message:`Installation directory is not writable: ${W.string}`,suggestion:"Check directory permissions or run with appropriate privileges"}}return{name:"Installation Directory",status:"pass",message:`Installation directory is properly configured: ${W.string}`}}catch(W){return{name:"Installation Directory",status:"fail",message:`Error checking installation directory: ${W instanceof Error?W.message:String(W)}`}}}async function AW(){try{let W=U0(),Q=P.join(W.string,"bin"),X=P.join(W.string,"sbin"),J=g(Q),Z=g(X);if(!J&&!Z)return{name:"PATH Configuration",status:"fail",message:"Neither bin nor sbin directories are in PATH",suggestion:`Add ${Q} to your PATH environment variable`};if(!J)return{name:"PATH Configuration",status:"warn",message:`Binary directory not in PATH: ${Q}`,suggestion:`Add ${Q} to your PATH environment variable`};if(!Z)return{name:"PATH Configuration",status:"warn",message:`System binary directory not in PATH: ${X}`,suggestion:`Consider adding ${X} to your PATH environment variable`};retu