@stacksjs/launchpad
Version:
Like Homebrew, but faster.
645 lines (572 loc) • 86.2 kB
JavaScript
// @bun
import{p as N0,q as R0,r as C0,s as B0,t as x0}from"../chunk-x48ph7z5.js";import"../chunk-7ne7xtmq.js";import{u as DJ}from"../chunk-xcf3khvr.js";import{v as GZ,w as TJ,x as A0,y as F0,z as w0}from"../chunk-wnwbsmkf.js";import{A as bJ}from"../chunk-sj98d84b.js";import{B as UJ}from"../chunk-sjvnrpb6.js";import{C as HZ,D as TZ,E as qZ,F as LZ,G as _Z,H as dZ,I as hZ,J as gZ,K as pZ,L as lZ,M as cZ,N as d}from"../chunk-83b6axd0.js";import"../chunk-kd525svk.js";import{$ as eZ,U as nZ,V as oZ,W as iZ,X as tZ,Y as aZ,Z as rZ,_ as sZ,aa as J0,ba as X0,ca as Z0,da as $0,ea as Q0,fa as U0,ga as z0,ha as Y0,ia as W0,ja as V0,ka as K0,la as G0,ma as O0,na as H0,oa as T0,pa as q0,qa as L0,ra as _0,sa as M0}from"../chunk-2q79gpta.js";import{ta as zJ,ua as MZ}from"../chunk-6qxbw28k.js";import{Aa as NZ,Ba as RZ,Ca as CZ,Da as BZ,Ea as xZ,Fa as IZ,Ga as EZ,Ha as jZ,Ia as yZ,Ja as SZ,Ka as ZJ,La as a,Ma as DZ,Na as bZ,Oa as kZ,Pa as VJ,Qa as P,Ra as KJ,Sa as GJ,Ta as uZ,Ua as fZ,Va as vZ,Wa as PZ,Xa as mZ,xa as AZ,ya as FZ,za as wZ}from"../chunk-wkk6vc0r.js";import{Ya as i}from"../chunk-f8dcmgkp.js";import"../chunk-fhet42vs.js";import{$a as OZ,ab as B}from"../chunk-b9hx8gsj.js";import{bb as E,cb as I}from"../chunk-8pxdwzvm.js";import{execSync as v}from"child_process";import _J from"crypto";import O from"fs";import{homedir as JJ}from"os";import K from"path";import Q from"process";function n(J){let X=O.existsSync(J)?O.realpathSync(J):J,U=_J.createHash("md5").update(X).digest("hex");return`${K.basename(X)}_${U.slice(0,8)}`}function p(J,X){try{let $=O.readFileSync(J,"utf8").split(/\r?\n/),Z=[],Y=!1,z=!1,V=0;for(let W=0;W<$.length;W++){let H=$[W],_=H.length-H.trimStart().length,G=H.trim();if(!Y){if(G.startsWith(`${X}:`))Y=!0,V=_;continue}if(_<=V&&G.endsWith(":"))break;if(!z&&G.startsWith("commands:")){z=!0;continue}if(z){let q=G.match(/command:\s*"([^"]+)"/),L=G.match(/command:\s*'([^']+)'/);if(q||L){let F=q?.[1]||L?.[1];if(F&&F.length>0)Z.push({command:F})}}}return Z}catch{return[]}}function $J(J,X){if(J.length===0)return[];let U=K.join(X,"pkgs");if(!O.existsSync(U))return J;let $=[];for(let Z of J){let[Y]=Z.split("@"),z=K.join(U,Y);if(!O.existsSync(z)){$.push(Z);continue}try{if(O.readdirSync(z,{withFileTypes:!0}).filter((W)=>W.isDirectory()&&W.name.startsWith("v")).length===0)$.push(Z)}catch{$.push(Z)}}return $}function XJ(J,X,U,$){let Z=$J(J,U),Y=$J(X,$);return{needsLocal:Z.length>0,needsGlobal:Y.length>0,missingLocal:Z,missingGlobal:Y}}async function MJ(J){let X=K.join(J,"artisan"),U=K.join(J,"composer.json"),$=K.join(J,"app");if(!O.existsSync(X)||!O.existsSync(U)||!O.existsSync($))return{isLaravel:!1,suggestions:[]};let Z=[],Y=K.join(J,".env");if(!O.existsSync(Y)){let W=K.join(J,".env.example");if(O.existsSync(W))Z.push("Copy .env.example to .env and configure database settings")}if(O.existsSync(Y))try{let W=O.readFileSync(Y,"utf8"),_=W.match(/^APP_KEY=(.*)$/m)?.[1]?.trim();if(!_||_===""||_==="base64:")try{v("php --version",{cwd:J,stdio:"pipe"}),v("php artisan --version",{cwd:J,stdio:"pipe"}),v("php artisan key:generate --force",{cwd:J,stdio:"pipe"});let L=O.readFileSync(Y,"utf8").match(/^APP_KEY=(.*)$/m)?.[1]?.trim();if(L&&L!==""&&L!=="base64:")Z.push("\u2705 Generated Laravel application encryption key automatically");else Z.push("\u26A0\uFE0F Run: php artisan key:generate to set application encryption key")}catch{Z.push("\u26A0\uFE0F Generate application encryption key: php artisan key:generate")}else if(_&&_.length>10)Z.push("\u2705 Laravel application encryption key is configured");if(W.includes("DB_CONNECTION=mysql")&&!W.includes("DB_PASSWORD="))Z.push("Configure MySQL database credentials in .env file");if(W.includes("DB_CONNECTION=pgsql")&&!W.includes("DB_PASSWORD="))Z.push("Configure PostgreSQL database credentials in .env file");if(W.includes("DB_CONNECTION=sqlite")){let G=W.match(/DB_DATABASE=(.+)/)?.[1]?.trim();if(G&&!O.existsSync(G))Z.push(`Create SQLite database file: touch ${G}`)}}catch{}try{let W=K.join(J,"database"),H=K.join(W,"migrations");if(O.existsSync(H)){if(O.readdirSync(H).filter((G)=>G.endsWith(".php")).length>0){Z.push("Run database migrations: php artisan migrate");let G=K.join(W,"seeders");if(O.existsSync(G)){if(O.readdirSync(G).filter((L)=>L.endsWith(".php")&&L!=="DatabaseSeeder.php").length>0)Z.push("Seed database with test data: php artisan db:seed")}}}}catch{}let z=B.preSetup;if(z?.enabled&&Q.env.LAUNCHPAD_SHELL_INTEGRATION!=="1"){let W=await b(J,z.commands||[]);Z.push(...W)}let V=B.postSetup;if(V?.enabled&&Q.env.LAUNCHPAD_SHELL_INTEGRATION!=="1"){await c(J,K.join(Q.env.HOME||"",".local","share","launchpad","envs",n(J)));let W=await b(J,V.commands||[]);Z.push(...W)}return{isLaravel:!0,suggestions:Z}}async function c(J,X){try{let U=await import("fs"),$=await import("path"),Z=$.join(X,"php.ini");if(!U.existsSync(Z)){let Y=$.join(J,".env"),z="";try{if(U.existsSync(Y))z=U.readFileSync(Y,"utf8").match(/^DB_CONNECTION=(.*)$/m)?.[1]?.trim().toLowerCase()||""}catch{}let V=["; Launchpad php.ini (auto-generated at activation time)","memory_limit = 512M","max_execution_time = 300","upload_max_filesize = 64M","post_max_size = 64M","display_errors = On","error_reporting = E_ALL",""];if(z==="pgsql"||z==="postgres"||z==="postgresql")V.push("extension=pdo_pgsql","extension=pgsql");else if(z==="mysql"||z==="mariadb")V.push("extension=pdo_mysql","extension=mysqli");else if(z==="sqlite")V.push("extension=pdo_sqlite","extension=sqlite3");U.writeFileSync(Z,V.join(`
`))}}catch{}}async function b(J,X){let U=[];async function $(){try{let Z="127.0.0.1",Y="5432";try{let{parseEnvFile:_}=await import("../chunk-njxv4pay.js"),G=_(K.join(J,".env"));Z=G.DB_HOST||Z,Y=G.DB_PORT||Y}catch{}let{findBinaryInPath:z}=await import("../chunk-wkk6vc0r.js"),V=z("pg_isready")||"pg_isready";if(Q.env.LAUNCHPAD_DEBUG==="1")try{Q.stderr.write(`\uD83D\uDC1E waitForPostgresIfNeeded: PATH=${Q.env.PATH}
`),Q.stderr.write(`\uD83D\uDC1E waitForPostgresIfNeeded: host=${Z} port=${Y} pg_isready=${V}
`)}catch{}let W=!1;for(let _=0;_<20&&!W;_++){let G=await new Promise((q)=>{let{spawn:L}=I("child_process"),F=L(V,["-h",Z,"-p",String(Y)],{stdio:"pipe"});F.on("close",(T)=>q(T===0)),F.on("error",()=>q(!1))});if(W=G,Q.env.LAUNCHPAD_DEBUG==="1")try{Q.stderr.write(`\uD83D\uDC1E pg_isready attempt ${_+1}: ${G?"ok":"fail"}
`)}catch{}if(!W)await new Promise((q)=>setTimeout(q,250+_*150))}if(!W){let _=await import("net");if(Q.env.LAUNCHPAD_DEBUG==="1")try{Q.stderr.write(`\uD83D\uDC1E pg_isready not ready, falling back to TCP probe
`)}catch{}for(let G=0;G<20&&!W;G++){let q=await new Promise((L)=>{let F=_.connect({host:Z,port:Number(Y),timeout:1000},()=>{F.end(),L(!0)});F.on("error",()=>L(!1)),F.on("timeout",()=>{F.destroy(),L(!1)})});if(W=q,Q.env.LAUNCHPAD_DEBUG==="1")try{Q.stderr.write(`\uD83D\uDC1E TCP probe attempt ${G+1}: ${q?"ok":"fail"}
`)}catch{}if(!W)await new Promise((L)=>setTimeout(L,250+G*150))}}if(W)await new Promise((_)=>setTimeout(_,250));let H=z("psql")||"psql";if(H){if(Q.env.LAUNCHPAD_DEBUG==="1")try{Q.stderr.write(`\uD83D\uDC1E using psql binary: ${H}
`)}catch{}for(let _=0;_<8;_++){let G=await new Promise((q)=>{let{spawn:L}=I("child_process"),F=L(H,["-h",Z,"-p",String(Y),"-U","postgres","-tAc","SELECT 1"],{stdio:"ignore"});F.on("close",(T)=>q(T===0)),F.on("error",()=>q(!1))});if(Q.env.LAUNCHPAD_DEBUG==="1")try{Q.stderr.write(`\uD83D\uDC1E psql SELECT 1 attempt ${_+1}: ${G?"ok":"fail"}
`)}catch{}if(G)break;await new Promise((q)=>setTimeout(q,300+_*200))}}}catch{}}for(let Z of X)try{if(!AJ(Z.condition,J))continue;let z=Q.env.LAUNCHPAD_SHELL_INTEGRATION==="1";try{Q.stderr.write(`
\uD83D\uDD27 Post-setup: ${Z.name||Z.command}
`)}catch{}let V=n(J),W=K.join(Q.env.HOME||"",".local","share","launchpad","envs",V),H=K.join(Q.env.HOME||"",".local","share","launchpad","global"),_=K.join(W,"bin"),G=K.join(W,"sbin"),q=K.join(H,"bin"),L=K.join(H,"sbin"),F=[_,G,q,L,Q.env.PATH||""].filter(Boolean).join(":"),T={...Q.env,PATH:F};if(!T.DB_HOST)T.DB_HOST="127.0.0.1";if(!T.DB_PORT)T.DB_PORT="5432";if(!T.DB_USERNAME&&!T.DB_USER)T.DB_USERNAME="root";if(!T.DB_PASSWORD)T.DB_PASSWORD="";try{let C=K.basename(J).replace(/\W/g,"_");if(!T.DATABASE_URL){let N=T.DB_USERNAME||"root",x=T.DB_PASSWORD||"",y=x?`${N}:${x}`:`${N}`;T.DATABASE_URL=`pgsql://${y}@${T.DB_HOST}:${T.DB_PORT}/${C}`}}catch{}if(!T.PGHOST)T.PGHOST=T.DB_HOST;if(!T.PGPORT)T.PGPORT=T.DB_PORT;if(!T.PGUSER)T.PGUSER=T.DB_USERNAME||T.DB_USER||"postgres";if(!T.PGPASSWORD&&T.DB_PASSWORD!==void 0)T.PGPASSWORD=T.DB_PASSWORD;if(Z.runInBackground)v(Z.command,{cwd:J,env:T,stdio:z?["ignore",2,2]:"inherit"}),U.push(`\uD83D\uDE80 Running in background: ${Z.description}`);else{if(Z.command.includes("artisan")&&Z.command.includes("migrate")){try{Q.stderr.write(`\u23F3 Ensuring database is ready before running migrations...
`)}catch{}await $(),await new Promise((C)=>setTimeout(C,500))}try{v(Z.command,{cwd:J,env:T,stdio:z?["ignore",2,2]:"inherit"})}catch(C){try{Q.stderr.write(`\uD83D\uDC1E Migration failed; collecting diagnostics...
`),Q.stderr.write(`\uD83D\uDC1E PATH=${T.PATH}
`),Q.stderr.write(`\uD83D\uDC1E DB env: HOST=${T.DB_HOST} PORT=${T.DB_PORT} USERNAME=${T.DB_USERNAME||T.DB_USER||""} DATABASE_URL=${T.DATABASE_URL||""}
`)}catch{}try{let{spawnSync:N}=await import("child_process"),x=N(T.PG_ISREADY||"pg_isready",["-h",T.DB_HOST||"127.0.0.1","-p",T.DB_PORT||"5432"]);Q.stderr.write(`\uD83D\uDC1E pg_isready exit=${x.status} stdout=${(x.stdout||"").toString()} stderr=${(x.stderr||"").toString()}
`)}catch{}try{let{spawnSync:N}=await import("child_process"),x=N("psql",["-h",T.DB_HOST||"127.0.0.1","-p",T.DB_PORT||"5432","-U","postgres","-tAc","SELECT 1"]);Q.stderr.write(`\uD83D\uDC1E psql check exit=${x.status} stdout=${(x.stdout||"").toString()} stderr=${(x.stderr||"").toString()}
`)}catch{}try{let N=K.join(JJ(),".local","share","launchpad","logs","postgres.log");if(O.existsSync(N)){let y=O.readFileSync(N,"utf8").split(/\r?\n/).slice(-100).join(`
`);Q.stderr.write(`\uD83D\uDC1E tail -100 postgres.log:
${y}
`)}}catch{}throw C}U.push(`\u2705 ${Z.description}`)}}catch(Y){if(Z.required){if(U.push(`\u274C Failed (required): ${Z.description}`),Y instanceof Error)U.push(` Error: ${Y.message}`)}else if(U.push(`\u26A0\uFE0F Skipped (optional): ${Z.description}`),Y instanceof Error)try{Q.stderr.write(`\u26A0\uFE0F ${Y.message}
`)}catch{}}return U}function AJ(J,X){if(!J||J==="always")return!0;switch(J){case"always":return!0;case"hasUnrunMigrations":return FJ(X);case"hasSeeders":return wJ(X);case"needsStorageLink":return NJ(X);case"isProduction":return RJ(X);default:return!1}}function FJ(J){try{let X=K.join(J,"database","migrations");if(!O.existsSync(X))return!1;if(O.readdirSync(X).filter(($)=>$.endsWith(".php")).length===0)return!1;try{return v("php artisan migrate:status",{cwd:J,stdio:"pipe",encoding:"utf8"}).includes("| N |")}catch{return!0}}catch{return!1}}function wJ(J){try{let X=K.join(J,"database","seeders");if(!O.existsSync(X))return!1;let U=O.readdirSync(X).filter((Z)=>Z.endsWith(".php"));if(U.length===0)return!1;let $=K.join(X,"DatabaseSeeder.php");if(O.existsSync($))return O.readFileSync($,"utf8").includes("$this->call(")||U.length>1;return U.length>0}catch{return!1}}function NJ(J){try{let X=K.join(J,"public","storage"),U=K.join(J,"storage","app","public");return O.existsSync(U)&&(!O.existsSync(X)||!O.lstatSync(X).isSymbolicLink())}catch{return!1}}function RJ(J){try{let X=K.join(J,".env");if(!O.existsSync(X))return!1;let Z=O.readFileSync(X,"utf8").match(/^APP_ENV=(.*)$/m)?.[1]?.trim();return Z==="production"||Z==="prod"}catch{return!1}}async function CJ(J,X={}){let{dryrun:U=!1,quiet:$=!1,shellOutput:Z=!1,skipGlobal:Y=Q.env.NODE_ENV==="test"||Q.env.LAUNCHPAD_SKIP_GLOBAL_AUTO_SCAN==="true"||Q.env.LAUNCHPAD_ENABLE_GLOBAL_AUTO_SCAN!=="true"}=X;if(Z){if(Q.env.LAUNCHPAD_SHELL_INTEGRATION="1",Q.env.NODE_ENV==="test")Q.env.LAUNCHPAD_DISABLE_CLEANUP="1"}let z=Q.env.LAUNCHPAD_SHELL_INTEGRATION==="1",V=$||z;if(z&&$){let W=Q.stderr.write.bind(Q.stderr),H=console.log.bind(console);Q.stderr.write=function(_,G,q){let L=_.toString();if(L.includes("\uD83D\uDD04")||L.includes("\u2B07\uFE0F")||L.includes("\uD83D\uDD27")||L.includes("\uD83D\uDE80")||L.includes("\u23F3")||L.includes("\u2705")||L.includes("\u26A0\uFE0F")||L.includes("\u274C")||L.includes("%")||L.includes("bytes")||L.includes("Installing")||L.includes("Downloading")||L.includes("Extracting")||L.startsWith("\r"))return W(_,G,q);if(typeof q==="function")Q.nextTick(q);return!0},console.log=function(..._){let G=_.join(" ");if(G.includes("\uD83D\uDD04")||G.includes("\u2B07\uFE0F")||G.includes("\uD83D\uDD27")||G.includes("\uD83D\uDE80")||G.includes("\u23F3")||G.includes("\u2705")||G.includes("\u26A0\uFE0F")||G.includes("\u274C")||G.includes("%")||G.includes("bytes"))W(`${G}
`)},Q.on("exit",()=>{Q.stderr.write=W,console.log=H})}try{let W=UJ(J);try{if(W){let A=p(W,"preSetup");if(A.length>0)await b(K.dirname(W),A)}let M=B.preSetup;if(M?.enabled&&!Z&&!$&&W)await b(K.dirname(W),M.commands||[])}catch{}if(!W){if(!$&&!Z)console.log("No dependency file found");else if(Z)console.log("No dependency file found");return}let H=K.dirname(W);if(Z){let M=n(J),A=K.join(Q.env.HOME||"",".local","share","launchpad","envs",M),R=K.join(Q.env.HOME||"",".local","share","launchpad","global"),j=O.existsSync(K.join(A,"bin")),f=O.existsSync(K.join(R,"bin"));if(j){let{default:LJ}=await import("../chunk-xcf3khvr.js"),g;try{g=await LJ({string:H})}catch{g={pkgs:[],env:{}}}if(O.existsSync(K.join(A,".launchpad_ready"))){await c(H,A);try{await e(H,g,!0),await s(H,A,!0)}catch{}}l(J,j?K.join(A,"bin"):"",j?K.join(A,"sbin"):"",M,g,f?K.join(R,"bin"):"",f?K.join(R,"sbin"):"");return}}let{default:_}=await import("../chunk-xcf3khvr.js"),G;try{G=await _({string:H})}catch(M){if(B.verbose&&!z)console.warn(`Failed to parse dependency file: ${M instanceof Error?M.message:String(M)}`);G={pkgs:[],env:{}}}let q=[];if(!Y&&!z){let M=[K.join(JJ(),".dotfiles"),K.join(JJ())];for(let A of M)if(O.existsSync(A))try{let R=await _({string:A});if(R.pkgs.length>0){if(q.push(R),B.verbose)console.warn(`Found ${R.pkgs.length} packages in global location: ${A}`)}}catch{}}let L=[],F=[];for(let M of G.pkgs){let A="";if(M.constraint)if(typeof M.constraint==="string")A=M.constraint;else A=String(M.constraint)||"*";else A="*";if(A==="[object Object]"||A.includes("[object"))A="*";let R=`${M.project}@${A}`;if(M.global&&!Y)L.push(R);else F.push(R)}if(!z)for(let M of q)for(let A of M.pkgs){let R="";if(A.constraint)if(typeof A.constraint==="string")R=A.constraint;else R=String(A.constraint)||"*";else R="*";if(R==="[object Object]"||R.includes("[object"))R="*";let j=`${A.project}@${R}`;if(A.global&&!Y)L.push(j);else F.push(j)}let T=n(J),C=K.join(Q.env.HOME||"",".local","share","launchpad","envs",T),N=K.join(Q.env.HOME||"",".local","share","launchpad","global");if(Z){if(F.length===0&&L.length===0){let M=K.join(C,"bin"),A=K.join(C,"sbin"),R=K.join(N,"bin"),j=K.join(N,"sbin");l(J,M,A,T,G,R,j);return}if(z){let M=K.join(C,"bin"),A=K.join(C,"sbin"),R=K.join(N,"bin"),j=K.join(N,"sbin"),f=XJ(F,L,C,N);if(f.needsLocal||f.needsGlobal)await QJ(f.missingLocal,f.missingGlobal,C,N,U,$);if(B.verbose)console.log("\uD83D\uDD0D Checking for PHP installations to create shims...");await BJ(C);try{await e(H,G,!0)}catch{}await c(H,C);try{await s(H,C,!0)}catch{}l(J,M,A,T,G,R,j);return}}if(F.length>0||L.length>0){await QJ(F,L,C,N,U,$);try{console.log()}catch{}}let x=B.preActivation;if(W){let M=p(W,"postSetup");if(M.length>0)await b(H,M)}if(x?.enabled&&!z)await b(H,x.commands||[]);if(W){let M=p(W,"preActivation");if(M.length>0)await b(H,M)}if(!z){let M=Q.env.LAUNCHPAD_PROCESSING;if(Q.env.LAUNCHPAD_PROCESSING="0",await e(H,G,!V),M===void 0)delete Q.env.LAUNCHPAD_PROCESSING;else Q.env.LAUNCHPAD_PROCESSING=M}if(await c(H,C),!z)await s(H,C,z);try{await O.promises.mkdir(K.join(C),{recursive:!0}),await O.promises.writeFile(K.join(C,".launchpad_ready"),"1")}catch{}let y=await MJ(H);if(y.isLaravel){if(y.suggestions.length>0&&!V)console.log(`
\uD83C\uDFAF Laravel project detected! Helpful commands:`),y.suggestions.forEach((M)=>{console.log(` \u2022 ${M}`)}),console.log()}if(Z){let M=K.join(C,"bin"),A=K.join(C,"sbin"),R=K.join(N,"bin"),j=K.join(N,"sbin");l(J,M,A,T,G,R,j)}else{let{config:M}=await import("../chunk-b9hx8gsj.js"),A=(M.shellActivationMessage||"\u2705 Environment activated for {path}").replace("{path}",Q.cwd());if(console.log(A),W){let j=p(W,"postActivation");if(j.length>0)await b(H,j)}let R=M.postActivation;if(R?.enabled)await b(H,R.commands||[])}}catch(W){let H=W instanceof Error&&(W.message.includes("Failed to install")||W.message.includes("Failed to download")||W.message.includes("No suitable version")||W.message.includes("nonexistent-package"));if(!V)if(H)console.warn("Warning: Failed to install some packages:",W instanceof Error?W.message:String(W));else console.error("Failed to set up development environment:",W instanceof Error?W.message:String(W));if(Z)console.log("# Environment setup failed, using system fallback"),console.log("# Ensure basic system paths are available"),console.log("for sys_path in /usr/local/bin /usr/bin /bin /usr/sbin /sbin; do"),console.log(' if [[ -d "$sys_path" && ":$PATH:" != *":$sys_path:"* ]]; then'),console.log(' export PATH="$PATH:$sys_path"'),console.log(" fi"),console.log("done"),console.log("# Clear command hash to ensure fresh lookups"),console.log("hash -r 2>/dev/null || true");if(!Z&&!H)throw W}}async function QJ(J,X,U,$,Z,Y){let z=Q.env.LAUNCHPAD_SHELL_INTEGRATION==="1";zJ();let V=null;if(z&&(J.length>0||X.length>0)){let G=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],q=0;V=setInterval(()=>{Q.stderr.write(`\r${G[q]} Installing packages...`),q=(q+1)%G.length},150)}let W=!0,H=!0;if(X.length>0){if(!Y&&!z)console.log(`Installing ${X.length} global packages...`);if(V){if(clearInterval(V),V=null,z&&Q.env.LAUNCHPAD_DISABLE_CLEANUP!=="1")Q.stderr.write("\r\x1B[K")}try{await d(X,$)}catch(G){if(W=!1,!Y&&!z)console.warn(`Failed to install some global packages: ${G instanceof Error?G.message:String(G)}`)}}if(J.length>0){if(!Y&&!z)console.log(`Installing ${J.length} local packages...`);if(V){if(clearInterval(V),V=null,z&&Q.env.LAUNCHPAD_DISABLE_CLEANUP!=="1")Q.stderr.write("\r\x1B[K")}try{await d(J,U)}catch(G){if(H=!1,!Y&&!z)console.warn(`Failed to install some local packages: ${G instanceof Error?G.message:String(G)}`)}}if(V){if(clearInterval(V),V=null,z&&Q.env.LAUNCHPAD_DISABLE_CLEANUP!=="1")Q.stderr.write("\r\x1B[K")}let _=!1;if(X.length>0){if(XJ([],X,"",$).needsGlobal||!W)_=!0}if(J.length>0){if(XJ(J,[],U,"").needsLocal||!H)_=!0}if(_&&!Y)if(await new Promise((G)=>setTimeout(G,50)),z){if(Q.stderr.write(`Environment not ready
`),J.length>0)Q.stderr.write(`Local packages need installation
`);if(X.length>0)Q.stderr.write(`Global packages need installation
`);Q.stderr.write(`Generating minimal shell environment for development
`)}else{if(console.warn("Environment not ready"),J.length>0)console.warn("Local packages need installation");if(X.length>0)console.warn("Global packages need installation");console.warn("Generating minimal shell environment for development")}}function l(J,X,U,$,Z,Y,z){Q.stdout.write(`# Launchpad environment setup for ${J}
`),Q.stdout.write(`if [[ -z "$LAUNCHPAD_ORIGINAL_PATH" ]]; then
`),Q.stdout.write(` export LAUNCHPAD_ORIGINAL_PATH="$PATH"
`),Q.stdout.write(`fi
`),Q.stdout.write(`# Ensure we have basic system paths if LAUNCHPAD_ORIGINAL_PATH is empty
`),Q.stdout.write(`if [[ -z "$LAUNCHPAD_ORIGINAL_PATH" ]]; then
`),Q.stdout.write(` export LAUNCHPAD_ORIGINAL_PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
`),Q.stdout.write(`fi
`);let V=[];if(O.existsSync(X))V.push(X);if(O.existsSync(U))V.push(U);if(Y&&O.existsSync(Y))V.push(Y);if(z&&O.existsSync(z))V.push(z);V.push("$LAUNCHPAD_ORIGINAL_PATH"),Q.stdout.write(`export PATH="${V.join(":")}"
`),Q.stdout.write(`# Ensure critical system binaries are always available
`),Q.stdout.write(`for sys_path in /usr/local/bin /usr/bin /bin /usr/sbin /sbin; do
`),Q.stdout.write(` if [[ -d "$sys_path" && ":$PATH:" != *":$sys_path:"* ]]; then
`),Q.stdout.write(` export PATH="$PATH:$sys_path"
`),Q.stdout.write(` fi
`),Q.stdout.write(`done
`);let W=[],H=K.dirname(X),_=[K.join(H,"lib"),K.join(H,"lib64")];for(let q of _)if(O.existsSync(q))W.push(q);if(Y){let q=K.dirname(Y),L=[K.join(q,"lib"),K.join(q,"lib64")];for(let F of L)if(O.existsSync(F))W.push(F)}let G=[K.dirname(X),Y?K.dirname(Y):null].filter(Boolean);for(let q of G)try{let L=O.readdirSync(q,{withFileTypes:!0}).filter((F)=>F.isDirectory()&&!["bin","sbin","lib","lib64","share","include","etc"].includes(F.name));for(let F of L){let T=K.join(q,F.name);if(O.existsSync(T)){let C=O.readdirSync(T,{withFileTypes:!0}).filter((N)=>N.isDirectory()&&N.name.startsWith("v"));for(let N of C){let x=K.join(T,N.name),y=[K.join(x,"lib"),K.join(x,"lib64")];for(let M of y)if(O.existsSync(M)&&!W.includes(M))W.push(M)}}}}catch{}if(Q.env.NODE_ENV==="test"&&X&&O.existsSync(X)){let q=K.dirname(X);try{let L=O.readdirSync(q,{withFileTypes:!0});for(let F of L)if(F.isDirectory()&&!["bin","sbin","share","include","etc","pkgs"].includes(F.name)){let T=K.join(q,F.name);if(O.existsSync(T)){let C=O.readdirSync(T,{withFileTypes:!0}).filter((N)=>N.isDirectory()&&N.name.startsWith("v"));for(let N of C){let x=K.join(T,N.name),y=K.join(x,"lib"),M=K.join(x,"lib64");if(O.existsSync(y)&&!W.includes(y))W.push(y);if(O.existsSync(M)&&!W.includes(M))W.push(M)}}}}catch{}}if(W.length>0){let q=W.join(":");Q.stdout.write(`# Set up dynamic library paths for package dependencies
`),Q.stdout.write(`if [[ -z "$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH" ]]; then
`),Q.stdout.write(` export LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH"
`),Q.stdout.write(`fi
`),Q.stdout.write(`if [[ -z "$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH" ]]; then
`),Q.stdout.write(` export LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH"
`),Q.stdout.write(`fi
`),Q.stdout.write(`if [[ -z "$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH" ]]; then
`),Q.stdout.write(` export LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
`),Q.stdout.write(`fi
`),Q.stdout.write(`export DYLD_LIBRARY_PATH="${q}\${LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH:+:$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH}"
`),Q.stdout.write(`export DYLD_FALLBACK_LIBRARY_PATH="${q}\${LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH:+:$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH}"
`),Q.stdout.write(`export LD_LIBRARY_PATH="${q}\${LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH:+:$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH}"
`)}if(Q.stdout.write(`export LAUNCHPAD_ENV_BIN_PATH="${X}"
`),Q.stdout.write(`export LAUNCHPAD_PROJECT_DIR="${J}"
`),Q.stdout.write(`export LAUNCHPAD_PROJECT_HASH="${$}"
`),Z&&Z.env)for(let[q,L]of Object.entries(Z.env))Q.stdout.write(`export ${q}=${L}
`);Q.stdout.write(`
# Deactivation function for directory checking
`),Q.stdout.write(`_launchpad_dev_try_bye() {
`),Q.stdout.write(` case "$PWD" in
`),Q.stdout.write(` "${J}"*)
`),Q.stdout.write(` # Still in project directory, don't deactivate
`),Q.stdout.write(` return 0
`),Q.stdout.write(` ;;
`),Q.stdout.write(` *)
`),Q.stdout.write(` # Left project directory, deactivate
`),Q.stdout.write(` if [[ -n "$LAUNCHPAD_ORIGINAL_PATH" ]]; then
`),Q.stdout.write(` export PATH="$LAUNCHPAD_ORIGINAL_PATH"
`),Q.stdout.write(` fi
`),Q.stdout.write(` # Restore original library paths
`),Q.stdout.write(` if [[ -n "$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH" ]]; then
`),Q.stdout.write(` export DYLD_LIBRARY_PATH="$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH"
`),Q.stdout.write(` else
`),Q.stdout.write(` unset DYLD_LIBRARY_PATH
`),Q.stdout.write(` fi
`),Q.stdout.write(` if [[ -n "$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH" ]]; then
`),Q.stdout.write(` export DYLD_FALLBACK_LIBRARY_PATH="$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH"
`),Q.stdout.write(` else
`),Q.stdout.write(` unset DYLD_FALLBACK_LIBRARY_PATH
`),Q.stdout.write(` fi
`),Q.stdout.write(` if [[ -n "$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH" ]]; then
`),Q.stdout.write(` export LD_LIBRARY_PATH="$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH"
`),Q.stdout.write(` else
`),Q.stdout.write(` unset LD_LIBRARY_PATH
`),Q.stdout.write(` fi
`),Q.stdout.write(` unset LAUNCHPAD_ENV_BIN_PATH
`),Q.stdout.write(` unset LAUNCHPAD_PROJECT_DIR
`),Q.stdout.write(` unset LAUNCHPAD_PROJECT_HASH
`),Q.stdout.write(` unset LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH
`),Q.stdout.write(` unset LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH
`),Q.stdout.write(` unset LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH
`),Q.stdout.write(` echo "dev environment deactivated"
`),Q.stdout.write(` ;;
`),Q.stdout.write(` esac
`),Q.stdout.write(`}
`)}async function BJ(J){let X=await import("path"),U=await import("fs");try{let $=X.join(J,"php.net");if(!U.existsSync($))return;let Z=U.readdirSync($).filter((z)=>{let V=X.join($,z);return U.statSync(V).isDirectory()&&z.startsWith("v")});if(Z.length===0)return;let{PrecompiledBinaryDownloader:Y}=await import("../chunk-xbhy1cqk.js");for(let z of Z){let V=X.join($,z),W=z.replace(/^v/,""),H=X.join(V,"bin");if(U.existsSync(H)){let _=new Y(J);console.log(`\uD83D\uDD17 Creating PHP ${W} shims with proper library paths...`),await _.createPhpShims(V,W),await _.validatePhpInstallation(V,W)}}}catch($){console.warn(`\u26A0\uFE0F Failed to create PHP shims: ${$ instanceof Error?$.message:String($)}`)}}async function s(J,X,U){try{let $=B.postSetup;if(!$?.enabled)return;let Z=K.join(X,"pkgs"),Y=K.join(Z,".post_setup_done");if(O.existsSync(Y))return;try{O.mkdirSync(Z,{recursive:!0})}catch{}let z=await b(J,$.commands||[]);z&&z.length>0;try{O.writeFileSync(Y,new Date().toISOString())}catch{}}catch{}}async function e(J,X,U){try{if(!X?.services?.enabled||!X.services.autoStart||X.services.autoStart.length===0)return;let $=X.services.autoStart||[];if(U&&$.length>0)console.log(`\uD83D\uDE80 Auto-starting services: ${$.join(", ")}`);let Z=X?.pkgs?.some((V)=>V.project.includes("postgres")||V.project.includes("postgresql")),Y=X?.pkgs?.some((V)=>V.project.includes("redis")),{startService:z}=await import("../chunk-2q79gpta.js");for(let V of $)try{if(U)console.log(`\uD83D\uDE80 Starting ${V} service...`);if(await z(V)){if(U)console.log(`\u2705 ${V} service started successfully`);if((V==="postgres"||V==="postgresql")&&Z)Q.env.LAUNCHPAD_PG_READY="1"}else if(U)console.warn(`\u26A0\uFE0F Failed to start ${V} service`)}catch(W){if(U)console.warn(`\u26A0\uFE0F Error starting ${V}: ${W instanceof Error?W.message:String(W)}`)}}catch{}}import{spawnSync as xJ}from"child_process";import{existsSync as YJ}from"fs";import{join as IJ}from"path";import w from"process";function EJ(){if(typeof w!=="undefined"&&w.argv?.[1]&&(w.argv[1].includes(".test.")||w.argv[1].includes("/test/")))return"launchpad";if(typeof w!=="undefined"&&w.argv?.[1]&&w.argv[1].includes("/bin/cli.ts"))return w.argv[1];if(typeof w!=="undefined"&&w.argv?.[1]&&(w.argv[1].includes("launchpad")||w.argv[1].includes("$bunfs"))&&!w.argv[1].includes(".test.")&&!w.argv[1].includes(".ts")){let X=["/usr/local/bin/launchpad",`${w.env.HOME}/.bun/bin/launchpad`,`${w.env.HOME}/.local/bin/launchpad`];for(let U of X)if(YJ(U))return U;try{let U=xJ("which",["launchpad"],{encoding:"utf8",timeout:500});if(U.status===0&&U.stdout.trim()){let $=U.stdout.trim();if(!$.startsWith("./")&&!$.includes("/packages/"))return $}}catch{}if(typeof w!=="undefined"&&w.argv?.[1]&&!w.argv[1].includes("$bunfs")&&!w.argv[1].includes("/$bunfs"))return w.argv[1]}if(typeof w!=="undefined"&&w.argv0&&w.argv0.includes("launchpad"))return w.argv0;let J=["/usr/local/bin/launchpad",`${w.env.HOME}/.bun/bin/launchpad`,`${w.env.HOME}/.local/bin/launchpad`];for(let X of J)if(YJ(X))return X;return"launchpad"}function jJ(J=!1){let X=EJ(),U="/usr/bin/grep -v '^$' 2>/dev/null",$=J?"":' || "$NODE_ENV" == "test"',Z=typeof w!=="undefined"&&w.env?.LAUNCHPAD_SHOW_ENV_MESSAGES!=="false"?"true":"false",Y=(typeof w!=="undefined"&&w.env?.LAUNCHPAD_SHELL_ACTIVATION_MESSAGE||'\u2705 Environment activated for \\033[3m$(basename "$project_dir")\\033[0m').replace("{path}",'$(basename "$project_dir")'),z=typeof w!=="undefined"&&w.env?.LAUNCHPAD_SHELL_DEACTIVATION_MESSAGE||"Environment deactivated";return`
# Launchpad shell integration - Performance Optimized
# Ultra-fast init guard: avoid any heavy work during initial shell startup
if [[ -z "$__LAUNCHPAD_INIT_DONE" ]]; then
export __LAUNCHPAD_INIT_DONE=1
# Preload minimal global paths only; defer scans to first cd
if [[ -d "$HOME/.local/share/launchpad/global/bin" ]]; then
case ":$PATH:" in
*":$HOME/.local/share/launchpad/global/bin:"*) ;;
*) export PATH="$HOME/.local/share/launchpad/global/bin:$PATH" ;;
esac
fi
if [[ -d "$HOME/.local/share/launchpad/global/sbin" ]]; then
case ":$PATH:" in
*":$HOME/.local/share/launchpad/global/sbin:"*) ;;
*) export PATH="$HOME/.local/share/launchpad/global/sbin:$PATH" ;;
esac
fi
fi
# Exit early if shell integration is disabled or in test mode
if [[ "$LAUNCHPAD_DISABLE_SHELL_INTEGRATION" == "1"${$} ]]; then
return 0 2>/dev/null || exit 0
fi
# Additional safety check - exit if this is being called during CLI operations
if [[ "$*" == *"--version"* || "$*" == *"--help"* ]]; then
return 0 2>/dev/null || exit 0
fi
# Performance optimization: aggressive caching with global path caching
__launchpad_cache_dir=""
__launchpad_cache_timestamp=0
__launchpad_setup_in_progress=""
__launchpad_timeout_count=0
__launchpad_env_ready_cache=""
__launchpad_env_ready_timestamp=0
__launchpad_global_setup_done=""
# Global path caching variables
__launchpad_global_paths_cache=""
__launchpad_global_paths_timestamp=0
# Ultra-fast environment activation cache (survives shell restarts)
__launchpad_persistent_cache_dir="$HOME/.cache/launchpad/shell_cache"
mkdir -p "$__launchpad_persistent_cache_dir" 2>/dev/null
# Environment variable optimization - batch export
__launchpad_set_env() {
local env_file="$1"
if [[ -f "$env_file" ]]; then
# Use single eval for better performance
eval "$(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$env_file" | sed 's/^/export /')" 2>/dev/null || true
fi
}
# Optimized PATH management with duplicate prevention
__launchpad_update_path() {
local project_bin="$1"
if [[ -d "$project_bin" ]]; then
# Only update PATH if not already present
if [[ ":$PATH:" != *":$project_bin:"* ]]; then
export PATH="$project_bin:$PATH"
fi
fi
}
# Fast library path update for quick activation (no expensive find operations)
__launchpad_update_library_paths_fast() {
local env_dir="$1"
# Prevent zsh nomatch warnings inside this function (restores on return)
if [[ -n "$ZSH_VERSION" ]]; then
setopt localoptions nonomatch
fi
if [[ ! -d "$env_dir" ]]; then
# nothing to do
return 0
fi
# Build library paths from direct lib directories only (fast path)
local lib_paths=""
for lib_dir in "$env_dir/lib" "$env_dir/lib64"; do
if [[ -d "$lib_dir" ]]; then
if [[ -z "$lib_paths" ]]; then
lib_paths="$lib_dir"
else
lib_paths="$lib_paths:$lib_dir"
fi
fi
done
# Set up library path environment variables if we have paths
if [[ -n "$lib_paths" ]]; then
# Store original values if not already stored
if [[ -z "$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH" ]]; then
export LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH"
fi
if [[ -z "$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH" ]]; then
export LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH"
fi
if [[ -z "$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH" ]]; then
export LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
fi
# Handle existing library paths correctly
if [[ -n "$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH" ]]; then
export DYLD_LIBRARY_PATH="$lib_paths:$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH"
else
export DYLD_LIBRARY_PATH="$lib_paths"
fi
if [[ -n "$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH" ]]; then
export DYLD_FALLBACK_LIBRARY_PATH="$lib_paths:$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH"
else
export DYLD_FALLBACK_LIBRARY_PATH="$lib_paths:/usr/local/lib:/lib:/usr/lib"
fi
if [[ -n "$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH" ]]; then
export LD_LIBRARY_PATH="$lib_paths:$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH"
else
export LD_LIBRARY_PATH="$lib_paths"
fi
fi
}
# Comprehensive library path management with deduplication
__launchpad_update_library_paths() {
local env_dir="$1"
if [[ ! -d "$env_dir" ]]; then
return 0
fi
# Build library paths from environment directories
local lib_paths=""
# Add direct lib directories first
for lib_dir in "$env_dir/lib" "$env_dir/lib64"; do
if [[ -d "$lib_dir" ]]; then
# Avoid duplicate paths in library path variables
if [[ ":$lib_paths:" != *":$lib_dir:"* ]]; then
if [[ -z "$lib_paths" ]]; then
lib_paths="$lib_dir"
else
lib_paths="$lib_paths:$lib_dir"
fi
fi
fi
done
# Scan for package-specific library directories efficiently
if [[ -d "$env_dir" ]]; then
# Filter out known non-package directories early
while IFS= read -r -d '' domain_dir; do
local domain_name=$(basename "$domain_dir")
# Skip known non-package directories
if [[ "$domain_name" != "bin" && "$domain_name" != "sbin" && "$domain_name" != "lib" && "$domain_name" != "lib64" && "$domain_name" != "share" && "$domain_name" != "include" && "$domain_name" != "etc" && "$domain_name" != "pkgs" && "$domain_name" != ".tmp" && "$domain_name" != ".cache" ]]; then
# Find version directories and validate they have proper libraries
for version_dir in $(find "$domain_dir" -maxdepth 1 -name "v*" -type d 2>/dev/null); do
if [[ -d "$version_dir" ]]; then
for lib_dir in "$version_dir/lib" "$version_dir/lib64"; do
if [[ -d "$lib_dir" ]]; then
# Validate that this lib directory has actual library files
# Skip if it only contains broken/placeholder files
local has_valid_libs=false
# Check for common library patterns that indicate a working installation
if [[ -n "$(find "$lib_dir" -name "*.dylib" -size +100c 2>/dev/null | head -1)" ]] || [[ -n "$(find "$lib_dir" -name "*.so*" -size +100c 2>/dev/null | head -1)" ]] || [[ -n "$(find "$lib_dir" -name "*.a" -size +100c 2>/dev/null | head -1)" ]]; then
has_valid_libs=true
fi
# Special case: If this is a source-built package (like our PHP), always include it
if [[ "$domain_name" == "php.net" ]] && [[ -f "$version_dir/bin/php" ]]; then
has_valid_libs=true
fi
# Add to library paths if it has valid libraries and avoid duplicates
if [[ "$has_valid_libs" == "true" ]] && [[ ":$lib_paths:" != *":$lib_dir:"* ]]; then
if [[ -z "$lib_paths" ]]; then
lib_paths="$lib_dir"
else
lib_paths="$lib_paths:$lib_dir"
fi
fi
fi
done
fi
done
fi
done < <(find "$env_dir" -maxdepth 1 -type d -print0 2>/dev/null)
fi
# Set up library path environment variables if we have paths
if [[ -n "$lib_paths" ]]; then
# Store original values if not already stored
if [[ -z "$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH" ]]; then
export LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH"
fi
if [[ -z "$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH" ]]; then
export LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH"
fi
if [[ -z "$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH" ]]; then
export LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
fi
# Handle existing library paths correctly
if [[ -n "$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH" ]]; then
export DYLD_LIBRARY_PATH="$lib_paths:$LAUNCHPAD_ORIGINAL_DYLD_LIBRARY_PATH"
else
export DYLD_LIBRARY_PATH="$lib_paths"
fi
if [[ -n "$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH" ]]; then
export DYLD_FALLBACK_LIBRARY_PATH="$lib_paths:$LAUNCHPAD_ORIGINAL_DYLD_FALLBACK_LIBRARY_PATH"
else
export DYLD_FALLBACK_LIBRARY_PATH="$lib_paths:/usr/local/lib:/lib:/usr/lib"
fi
if [[ -n "$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH" ]]; then
export LD_LIBRARY_PATH="$lib_paths:$LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH"
else
export LD_LIBRARY_PATH="$lib_paths"
fi
fi
}
# Optimized global setup (run once per shell session)
__launchpad_setup_global_deps() {
# Skip if already done in this shell session
if [[ -n "$__launchpad_global_setup_done" ]]; then
return 0
fi
# Check the standard global environment
local global_env_dir="$HOME/.local/share/launchpad/global"
if [[ -d "$global_env_dir/bin" ]]; then
__launchpad_update_path "$global_env_dir/bin"
fi
if [[ -d "$global_env_dir/sbin" ]]; then
__launchpad_update_path "$global_env_dir/sbin"
fi
# Setup library paths for global dependencies
__launchpad_update_library_paths "$global_env_dir"
# Mark global setup as complete
__launchpad_global_setup_done="1"
}
# Fast global path cache (cached for entire shell session)
__launchpad_global_paths_cache=""
__launchpad_global_paths_loaded=""
# Fast global path management for quick activation (no expensive find operations)
__launchpad_ensure_global_path_fast() {
# Skip if already loaded in this shell session
if [[ -n "$__launchpad_global_paths_loaded" ]]; then
return 0
fi
# Add standard global environment to PATH if it exists (fast path only)
local global_env_dir="$HOME/.local/share/launchpad/global"
if [[ -d "$global_env_dir/bin" ]]; then
__launchpad_update_path "$global_env_dir/bin"
fi
if [[ -d "$global_env_dir/sbin" ]]; then
__launchpad_update_path "$global_env_dir/sbin"
fi
# Mark as loaded for this shell session
__launchpad_global_paths_loaded="1"
# Always ensure critical system paths are available
__launchpad_ensure_system_path
}
# Force refresh global paths (for use after installing new global dependencies)
__launchpad_refresh_global_paths() {
# Clear cache to force immediate refresh
__launchpad_global_paths_cache=""
__launchpad_global_paths_timestamp=0
__launchpad_global_paths_loaded=""
# Refresh global paths immediately
__launchpad_ensure_global_path
# Refresh command hash table
hash -r 2>/dev/null || true
}
# Ultra-fast global path management with aggressive caching
__launchpad_ensure_global_path() {
local current_time=$(date +%s)
# Use cached global paths if they're less than 10 minutes old
if [[ -n "$__launchpad_global_paths_cache" && $((current_time - __launchpad_global_paths_timestamp)) -lt 600 ]]; then
# Apply cached paths quickly without expensive filesystem operations
for cached_path in $__launchpad_global_paths_cache; do
__launchpad_update_path "$cached_path"
done
__launchpad_ensure_system_path
return 0
fi
# Rebuild global paths cache (expensive operation)
local global_paths=""
local global_env_dir="$HOME/.local/share/launchpad/global"
# Discover all available global paths
if [[ -d "$global_env_dir" ]]; then
# Find global binary directories efficiently
while IFS= read -r -d '' domain_dir; do
local domain_name=$(basename "$domain_dir")
# Skip known non-package directories
if [[ "$domain_name" != "bin" && "$domain_name" != "sbin" && "$domain_name" != "lib" && "$domain_name" != "lib64" && "$domain_name" != "share" && "$domain_name" != "include" && "$domain_name" != "etc" && "$domain_name" != "pkgs" && "$domain_name" != ".tmp" && "$domain_name" != ".cache" ]]; then
# Find version directories
for version_dir in $(find "$domain_dir" -maxdepth 1 -name "v*" -type d 2>/dev/null | sort -V | tail -1); do
if [[ -d "$version_dir/bin" ]]; then
global_paths="$global_paths $version_dir/bin"
fi
if [[ -d "$version_dir/sbin" ]]; then
global_paths="$global_paths $version_dir/sbin"
fi
done
fi
done < <(find "$global_env_dir" -maxdepth 1 -type d -print0 2>/dev/null)
# Add standard global binary directories
if [[ -d "$global_env_dir/bin" ]]; then
global_paths="$global_paths $global_env_dir/bin"
fi
if [[ -d "$global_env_dir/sbin" ]]; then
global_paths="$global_paths $global_env_dir/sbin"
fi
fi
# Cache the discovered paths for future use
__launchpad_global_paths_cache="$global_paths"
__launchpad_global_paths_timestamp="$current_time"
# Apply the discovered paths
for global_path in $global_paths; do
__launchpad_update_path "$global_path"
done
# Always ensure critical system paths are available
__launchpad_ensure_system_path
}
# Optimized dependency file finder with aggressive caching
__launchpad_find_deps_file() {
local dir="$1"
local current_time=$(date +%s)
# Use very aggressive cache (10 minutes for most directories, 2 hours for dev/test)
local deps_cache_duration=600 # 10 minutes default
if [[ "$dir" == *"test"* || "$dir" == *"launchpad"* || "$NODE_ENV" == "test" ]]; then
deps_cache_duration=7200 # 2 hours for test/development environments
fi
if [[ -n "$__launchpad_cache_dir" && "$__launchpad_cache_dir" == "$dir" && $((current_time - __launchpad_cache_timestamp)) -lt $deps_cache_duration ]]; then
echo "$__launchpad_cache_dir"
return 0
fi
# Clear cache for new search
__launchpad_cache_dir=""
__launchpad_cache_timestamp=0
while [[ "$dir" != "/" ]]; do
# Check Launchpad-specific dependency files first (highest priority)
for pattern in "dependencies" "deps" "pkgx" "launchpad"; do
for ext in "yaml" "yml"; do
local file="$dir/$pattern.$ext"
if [[ -f "$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
done
# Check Node.js/JavaScript projects (require package.json explicitly)
if [[ -f "$dir/package.json" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
# Check Python projects
for file in "pyproject.toml" "requirements.txt" "setup.py" "Pipfile" "Pipfile.lock"; do
if [[ -f "$dir/$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
# Check Rust projects
if [[ -f "$dir/Cargo.toml" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
# Check Go projects
for file in "go.mod" "go.sum"; do
if [[ -f "$dir/$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
# Check Ruby projects
if [[ -f "$dir/Gemfile" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
# Check Deno projects
for file in "deno.json" "deno.jsonc"; do
if [[ -f "$dir/$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
# Check GitHub Actions
for file in "action.yml" "action.yaml"; do
if [[ -f "$dir/$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
# Check Kubernetes/Docker projects
for file in "skaffold.yaml" "skaffold.yml"; do
if [[ -f "$dir/$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
# Check common version files (useful signals for project directories)
for file in ".nvmrc" ".node-version" ".ruby-version" ".python-version" ".terraform-version"; do
if [[ -f "$dir/$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
# Check package manager lock/config files (secondary signals)
for file in "yarn.lock" "bun.lockb" ".yarnrc"; do
if [[ -f "$dir/$file" ]]; then
__launchpad_cache_dir="$dir"
__launchpad_cache_timestamp=$current_time
echo "$dir"
return 0
fi
done
# Do not treat other standalone files as a project to avoid false positives (e.g. $HOME)
dir="$(/usr/bin/dirname "$dir")"
done
return 1
}
# Ultra-fast project change handler with aggressive caching
__launchpad_chpwd() {
local project_dir
project_dir=$(__launchpad_find_deps_file "$PWD")
if [[ -n "$project_dir" ]]; then
# Check if we're entering a new project or if this is the first time
if [[ "$LAUNCHPAD_CURRENT_PROJECT" != "$project_dir" ]]; then
export LAUNCHPAD_CURRENT_PROJECT="$project_dir"
# Ensure we have a valid original PATH before activation
if [[ -z "$LAUNCHPAD_ORIGINAL_PATH" ]]; then
export LAUNCHPAD_ORIGINAL_PATH="$PATH"
fi
# Check if setup is already in progress to avoid duplicate work
if [[ "$__launchpad_setup_in_progress" == "$project_dir" ]]; then
return 0
fi
# Avoid zsh glob nomatch errors inside this handler
if [[ -n "$ZSH_VERSION" ]]; then
setopt localoptions nonomatch
fi
# Ultra-fast activation: compute environment path and check if ready
# Resolve to physical path and compute MD5 (matches generateProjectHash in dump.ts)
local real_project_dir
real_project_dir=$(cd "$project_dir" 2>/dev/null && pwd -P || echo "$project_dir")
local project_basename
project_basename=$(basename "$real_project_dir")
local md5hash
if command -v md5 >/dev/null 2>&1; then
md5hash=$(md5 -q -s "$real_project_dir" 2>/dev/null || md5 -q "$real_project_dir" 2>/dev/null)
fi
if [[ -z "$md5hash" ]] && command -v md5sum >/dev/null 2>&1; then
md5hash=$(printf "%s" "$real_project_dir" | md5sum 2>/dev/null | awk '{print $1}')
fi
if [[ -z "$md5hash" ]] && command -v openssl >/dev/null 2>&1; then
md5hash=$(printf "%s" "$real_project_dir" | openssl md5 2>/dev/null | awk '{print $2}')
fi
if [[ -z "$md5hash" ]]; then
md5hash="00000000"
fi
local project_hash="\${project_basename}_$(echo "$md5hash" | cut -c1-8)"
local env_dir="$HOME/.local/share/launchpad/envs/$project_hash"
# Fallback: if md5-based env dir doesn't exist, try to locate legacy env by basename prefix
if [[ ! -d "$env_dir/bin" ]]; then
local envs_root="$HOME/.local/share/launchpad/envs"
if [[ -d "$envs_root" ]]; then
local found_env=""
# Iterate safely (no globs) and match prefix
for candidate in "$envs_root"/*; do
if [[ -d "$candidate" ]]; then
local base=$(basename "$candidate")
case "$base" in
"\${project_basename}_"*)
if [[ -d