@heygaia/cli 0.5.0 → 0.7.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +47 -8
  2. package/dist/index.js +134 -47
  3. package/package.json +12 -5
package/dist/index.js CHANGED
@@ -1,52 +1,139 @@
1
1
  #!/usr/bin/env node
2
- import{Command as qi}from"commander";var ie={init:"Full setup from scratch (clone, configure, start)",setup:"Configure an existing GAIA repository",status:"Check health of all GAIA services",start:"Start GAIA services (self-host mode)",dev:"Run developer mode in Nx TUI (`gaia dev` or `gaia dev full`)",logs:"Stream logs for running GAIA services",stop:"Stop all GAIA services (safe mode by default)"};import{homedir as Ar}from"node:os";import{join as Tn,resolve as Cn}from"node:path";import{Command as In}from"commander";import{existsSync as qe,mkdirSync as Wo,readFileSync as ir,writeFileSync as wt}from"node:fs";import{homedir as Vo}from"node:os";import{join as bt}from"node:path";var j={PING:"ping",MCP_OPEN:"mcp.open",MCP_CLOSE:"mcp.close",MCP_MSG:"mcp.msg",REVOKE:"revoke",PONG:"pong",HELLO:"hello",MCP_OPENED:"mcp.opened",MCP_ERROR:"mcp.error"},Zt="https://api.heygaia.io",ye="filesystem",er=500,tr=6e4,rr=5e3,or=1e6,nr=5e6;var je=bt(Vo(),".gaia","bridge"),De=bt(je,"credentials.json"),xt=bt(je,"config.json");function sr(){qe(je)||Wo(je,{recursive:!0,mode:448})}function de(){if(!qe(De))return null;try{return JSON.parse(ir(De,"utf-8"))}catch{return null}}function xe(e){sr(),wt(De,JSON.stringify(e,null,2),{mode:384})}function ar(){qe(De)&&wt(De,"{}",{mode:384})}function q(){if(!qe(xt))return{servers:[]};try{return{servers:JSON.parse(ir(xt,"utf-8")).servers??[]}}catch{return{servers:[]}}}function cr(e){sr(),wt(xt,JSON.stringify(e,null,2),{mode:384})}function Ue(e){let t=q(),r=t.servers.findIndex(o=>o.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),cr(t)}function lr(e){let t=q(),r=t.servers.length;return t.servers=t.servers.filter(o=>o.key!==e),cr(t),t.servers.length<r}function pr(){return q().servers.find(e=>e.type==="filesystem"&&e.key===ye)}function He(e){if(e)return e.replace(/\/$/,"");let t=de();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??Zt).replace(/\/$/,"")}import{hostname as Xo,platform as Jo}from"node:os";var ur={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.5.0",type:"module",files:["dist","README.md"],scripts:{build:"esbuild src/index.ts --bundle --platform=node --target=node18 --format=esm --packages=external --outfile=dist/index.js --minify && chmod +x dist/index.js",check:"biome check src",dev:"tsx watch src/index.ts",fix:"biome check --write src",format:"biome format --write src",lint:"pnpm run check","lint:fix":"pnpm run fix",prepublishOnly:"pnpm run build",start:"NODE_ENV=production node dist/index.js","type-check":"tsc --noEmit"},dependencies:{"@inkjs/ui":"^2.0.0","@modelcontextprotocol/sdk":"^1.29.0",commander:"^14.0.3",execa:"^9.6.1",ink:"^6.8.0","ink-big-text":"^2.0.0","ink-gradient":"^3.0.0","ink-text-input":"^6.0.0",react:"19.1.0","react-dom":"19.1.0","simple-git":"^3.36.0",ws:"^8.21.0",zod:"^4.3.6"},devDependencies:{"@biomejs/biome":"^2.5.7","@types/node":"^24.13.3","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@types/ws":"^8.18.1",esbuild:"^0.25.12",tsx:"^4.23.11",typescript:"^7.0.2",vite:"^7.3.6",vitest:"^4.1.10"},bin:{gaia:"./dist/index.js"},engines:{node:">=20"},keywords:["ai-assistant","cli","gaia","setup"],license:"MIT",publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/theexperiencecompany/gaia.git",directory:"packages/cli"}};var ee=ur.version;var ke=class extends Error{constructor(r,o){super(r);this.status=o;this.name="ApiError"}};async function We(e,t,r,o){let n=await fetch(`${e}/api/v1${t}`,{method:"POST",headers:{"content-type":"application/json",...o?{authorization:`Bearer ${o}`}:{}},body:JSON.stringify(r)});if(!n.ok){let i=`${n.status} ${n.statusText}`;try{let a=await n.json();a.detail&&(i=a.detail)}catch{}throw new ke(i,n.status)}return await n.json()}function dr(e,t,r,o){return We(e,"/device/pair/start",{name:t,platform:r,daemon_version:o})}function mr(e,t){return We(e,"/device/pair/poll",{device_code:t})}function Ve(e,t){return We(e,"/device/token",{refresh_token:t})}function fr(e,t,r,o){return We(e,"/device/servers",{server_key:r,display_name:o},t)}async function Ko(e){await new Promise(t=>setTimeout(t,e))}function gr(){return!!de()?.refreshToken}async function Ye(e={}){let t=He(e.api),r=e.name||Xo(),o=await dr(t,r,Jo(),ee);console.info(`
3
- To pair this device, open:
4
- `),console.info(` ${o.verification_url}`),console.info(`
5
- and enter this code: ${o.user_code}
6
- `),console.info("Waiting for approval\u2026");let n=Date.now()+o.expires_in*1e3;for(;Date.now()<n;){await Ko(o.interval*1e3);let i;try{i=await mr(t,o.device_code)}catch(a){console.error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(i.status==="approved"&&i.device_id&&i.refresh_token){xe({apiUrl:t,deviceId:i.device_id,refreshToken:i.refresh_token}),console.info(`
7
- Paired as "${r}".
8
- `);return}if(i.status==="denied"||i.status==="expired")throw new Error(`pairing ${i.status}`)}throw new Error("pairing timed out")}import{randomInt as mn}from"node:crypto";import Cr from"ws";import{Client as cn}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as ln,StdioClientTransport as pn}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as un}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as dn}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as Qo,readdir as yr,readFile as hr,realpath as zo,stat as Zo,writeFile as en}from"node:fs/promises";import{dirname as vr,extname as tn,join as xr,resolve as rn,sep as on}from"node:path";import{McpServer as nn}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as we}from"zod";var sn={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},be=class extends Error{};async function Tt(e){try{return await zo(e)}catch{return null}}async function an(e){try{return(await Qo(e)).isSymbolicLink()}catch{return!1}}function Sr(e,t){return e===t||e.startsWith(t+on)}async function Xe(e,t,r){let o=rn(e),n=await Tt(o);if(n){if(t.some(a=>Sr(n,a)))return n;throw new be(`Path is outside your approved folders: ${e}`)}if(r)throw new be(`No such file or directory: ${e}`);let i=await Tt(vr(o));if(!i||!t.some(a=>Sr(i,a)))throw new be(`Path is outside your approved folders: ${e}`);if(await an(o))throw new be(`Refusing to write through a symlink: ${e}`);return xr(i,o.slice(vr(o).length+1))}async function wr(e,t,r,o){if(o.length>=r)return;let n;try{n=await yr(e,{withFileTypes:!0})}catch{return}for(let i of n){if(o.length>=r)return;let a=xr(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&o.push(a),i.isDirectory()&&!i.isSymbolicLink()&&await wr(a,t,r,o)}}function br(e){let t=new nn({name:"gaia-filesystem",version:"0.1.0"}),r=null,o=()=>(r||(r=Promise.all(e.allow.map(Tt)).then(i=>i.filter(a=>a!==null))),r),n=i=>({isError:!0,content:[{type:"text",text:i}]});return t.registerTool("list_directory",{description:"List the entries (files and folders) in a directory on the user's machine.",inputSchema:{path:we.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let a=await Xe(i,await o(),!0);return{content:[{type:"text",text:(await yr(a,{withFileTypes:!0})).map(p=>`${p.isDirectory()?"dir ":"file"} ${p.name}`).join(`
9
- `)||"(empty)"}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),t.registerTool("read_file",{description:"Read the contents of a text or image file on the user's machine.",inputSchema:{path:we.string().describe("Absolute path to a file")}},async({path:i})=>{try{let a=await Xe(i,await o(),!0),s=await Zo(a);if(!s.isFile())return n(`Not a file: ${i}`);let c=sn[tn(a).toLowerCase()];if(c){if(s.size>nr)return n(`Image is too large to read (${s.size} bytes).`);let f=await hr(a);return{content:[{type:"text",text:`Image file ${a} (${c}, ${s.size} bytes) \u2014 shown below.`},{type:"image",data:f.toString("base64"),mimeType:c}]}}return s.size>or?n(`File is too large to read (${s.size} bytes).`):{content:[{type:"text",text:await hr(a,"utf-8")}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),t.registerTool("search_files",{description:"Recursively find files/folders whose name contains a query, under a directory.",inputSchema:{path:we.string().describe("Absolute path to the directory to search under"),query:we.string().describe("Substring to match against names")}},async({path:i,query:a})=>{try{let s=await Xe(i,await o(),!0),c=[];return await wr(s,a,200,c),{content:[{type:"text",text:c.join(`
10
- `)||"(no matches)"}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),e.allowWrite&&t.registerTool("write_file",{description:"Write text to a file on the user's machine (overwrites if it exists).",inputSchema:{path:we.string().describe("Absolute path to the file to write"),content:we.string().describe("Text content to write")}},async({path:i,content:a})=>{try{let s=await Xe(i,await o(),!1);return await en(s,a,"utf-8"),{content:[{type:"text",text:`Wrote ${a.length} bytes to ${i}`}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),t}async function Ct(e){if(e.type==="url"){let n=new un(new URL(e.url));return{transport:n,close:()=>n.close()}}if(e.type==="stdio"){let n=new pn({command:e.command,args:e.args,env:{...ln(),...e.env}});return{transport:n,close:()=>n.close()}}let[t,r]=dn.createLinkedPair(),o=br(e);return await o.connect(r),{transport:t,close:async()=>{await o.close(),await t.close()}}}async function Tr(e){let t=await Ct(e),r=new cn({name:"gaia-bridge-test",version:"0.1.0"});try{await r.connect(t.transport);let{tools:o}=await r.listTools();return o.map(n=>n.name)}finally{try{await r.close(),await t.close()}catch{}}}var Je=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=er;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof ke&&t.status===401?(console.error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):console.error(`[gaia bridge] connection error: ${t instanceof Error?t.message:t}`)}if(this.stopped)break;await this.backoff()}}async stop(){this.stopped=!0,await this.closeAllSessions(),this.ws?.close()}async connectOnce(){let t=await Ve(this.creds.apiUrl,this.creds.refreshToken);this.creds={...this.creds,refreshToken:t.refresh_token},xe(this.creds);let r=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,o=new Cr(r,{headers:{authorization:`Bearer ${t.access_token}`}});this.ws=o,await new Promise((n,i)=>{let a=!1,s=!1,c=p=>{s||(s=!0,p())};o.on("open",()=>{a=!0,this.reconnectDelay=rr;let p=q().servers.map(f=>f.key);this.send({t:j.HELLO,servers:p}),console.error(`[gaia bridge] connected \u2014 exposing: ${p.join(", ")||"(nothing configured)"}`)}),o.on("message",p=>{this.onFrame(p.toString())}),o.on("close",()=>{this.closeAllSessions(),this.ws=null,c(()=>a?n():i(new Error("socket closed before open")))}),o.on("error",p=>{a||c(()=>i(p))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case j.PING:this.send({t:j.PONG});return;case j.MCP_OPEN:await this.openSession(r);return;case j.MCP_MSG:await this.forwardToServer(r);return;case j.MCP_CLOSE:await this.closeSession(r.sid);return;case j.REVOKE:console.error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;default:return}}async openSession(t){let r=t.sid,o=t.server,n=t.pod;if(!r||!o)return;let i=q().servers.find(a=>a.key===o);if(!i){this.send({t:j.MCP_ERROR,sid:r,pod:n,error:`Unknown server '${o}'`});return}try{let a=await Ct(i);a.transport.onmessage=s=>{this.send({t:j.MCP_MSG,sid:r,pod:n,data:JSON.stringify(s)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:j.MCP_ERROR,sid:r,pod:n,error:`Local server '${o}' exited`}),this.closeSession(r)},await a.transport.start(),this.sessions.set(r,a),this.send({t:j.MCP_OPENED,sid:r,pod:n})}catch(a){this.send({t:j.MCP_ERROR,sid:r,pod:n,error:a instanceof Error?a.message:String(a)})}}async forwardToServer(t){let r=t.sid?this.sessions.get(t.sid):void 0;if(!(!r||!t.data))try{let o=JSON.parse(t.data);await r.transport.send(o)}catch(o){console.error(`[gaia bridge] forward error: ${o instanceof Error?o.message:o}`)}}async closeSession(t){if(!t)return;let r=this.sessions.get(t);if(r){this.sessions.delete(t);try{await r.close()}catch{}}}async closeAllSessions(){let t=[...this.sessions.keys()];await Promise.all(t.map(r=>this.closeSession(r)))}send(t){this.ws?.readyState===Cr.OPEN&&this.ws.send(JSON.stringify(t))}async backoff(){let t=mn(this.reconnectDelay);console.error(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,tr)}};async function Ke(){let e=de();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");if(q().servers.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");pr()?.allowWrite&&console.error("[gaia bridge] filesystem WRITES are enabled for this device.");let t=await Ve(e.apiUrl,e.refreshToken);xe({...e,refreshToken:t.refresh_token});for(let n of q().servers)await fr(e.apiUrl,t.access_token,n.key,n.name);let r=new Je({...e,refreshToken:t.refresh_token}),o=async()=>{console.error(`
11
- [gaia bridge] shutting down\u2026`),await r.stop(),process.exit(0)};process.on("SIGINT",()=>void o()),process.on("SIGTERM",()=>void o()),await r.run()}import{basename as Rr}from"node:path";import{createInterface as Ir}from"node:readline/promises";import{Writable as fn}from"node:stream";async function me(e,t){let r=Ir({input:process.stdin,output:process.stdout});try{let o=t?` [${t}]`:"";return(await r.question(`${e}${o}: `)).trim()||t||""}finally{r.close()}}async function Er(e){process.stdout.write(`${e}: `);let t=new fn({write(o,n,i){i()}}),r=Ir({input:process.stdin,output:t,terminal:!0});try{let o=(await r.question("")).trim();return process.stdout.write(`
12
- `),o}finally{r.close()}}async function _e(e,t=!0){let r=await me(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function It(e,t){for(process.stdout.write(`
2
+ import{Command as JS,Option as ZS}from"commander";var G={up:"Install GAIA and start it (or resume an earlier run)",status:"Show whether GAIA is running and healthy",stop:"Stop GAIA (your data is kept)",start:"Start GAIA again after 'gaia stop'",update:"Move GAIA to a newer release (keeps your data and settings)",doctor:"Find problems with your install and how to fix them",logs:"Show GAIA's logs as they happen",bots:"Connect GAIA to Telegram, Discord or Slack",connect:"Import browser logins so GAIA's browser stays signed in",bridge:"Let GAIA use tools and files on this computer",backup:"Save GAIA's data and settings to a folder",restore:"Bring back GAIA's data and settings from a backup",init:"Set up a development copy of GAIA from scratch",setup:"Configure an existing development copy",dev:"Run GAIA from source with live reload"};import*as Ea from"node:path";var mt=[{volume:"gaia-selfhost_chroma_data",fileSuffix:"chroma_data",label:"Chroma",userData:!1},{volume:"gaia-selfhost_workspace",fileSuffix:"workspace",label:"Workspace",userData:!0},{volume:"gaia-selfhost_files",fileSuffix:"files",label:"Uploaded files",userData:!0}];function cr(e){return`mkdir -p /tmp/restore && tar xzf /backups/${e} -C /tmp/restore && { rm -rf /data/* 2>/dev/null; rm -rf /data/.[!.]* 2>/dev/null || true; } && cp -a /tmp/restore/. /data/ && rm -rf /tmp/restore`}import*as Y from"node:fs";import*as ye from"node:path";import{execa as ba}from"execa";import*as Ur from"node:fs";import*as sn from"node:path";var sd=/^\d{4}-\d{2}-\d{2}(T\d{2}-\d{2}-\d{2}Z)?$/,ad=".partial",ts={prefix:"mongo-",suffix:".gz"},rs={prefix:"postgres-",suffix:".sql"},os={prefix:"api-env-",suffix:".env"},ns=".tar.gz",cd=[ts,rs,os,...mt.map(e=>({prefix:`${e.fileSuffix}-`,suffix:ns}))];function an(e=new Date){return`${e.toISOString().slice(0,19).replaceAll(":","-")}Z`}function $t(e,t){let r=o=>sn.join(e,`${o.prefix}${t}${o.suffix}`);return{mongoFile:r(ts),postgresFile:r(rs),apiEnvFile:r(os),volumeFiles:mt.map(o=>cn(e,t,o))}}function cn(e,t,r){return{volume:r.volume,label:r.label,file:sn.join(e,`${r.fileSuffix}-${t}${ns}`)}}function ft(e){return`${e}${ad}`}function is(e){return Ur.existsSync(e)?Ur.readdirSync(e).flatMap(r=>cd.flatMap(({prefix:o,suffix:n})=>{if(!r.startsWith(o)||!r.endsWith(n))return[];let i=r.slice(o.length,r.length-n.length);return sd.test(i)?[i]:[]})).sort().at(-1):void 0}import*as jr from"node:fs";import*as cs from"node:os";import{execa as Lt}from"execa";var ss="/var/run/docker.sock",le={selfhost:"gaia-selfhost",developer:"gaia-dev"},ld=/\((healthy|unhealthy|health: starting)\)/;async function ls(e){return(await gt(e)).map(r=>({name:r.service,status:r.state==="running"?"running":"stopped",health:r.health}))}async function us(e){let{stdout:t}=await Lt("docker",["ps","--filter",`label=com.docker.compose.project=${e}`,"--format","{{.Ports}}"]),r=new Set;for(let o of t.matchAll(/:(\d+)->/g))r.add(Number(o[1]));return r}function ds(){return cs.platform()!=="linux"||!jr.existsSync(ss)?0:jr.statSync(ss).gid}async function gt(e){let{stdout:t}=await Lt("docker",["ps","-a","--filter",`label=com.docker.compose.project=${e}`,"--format",'{{.Label "com.docker.compose.service"}}|{{.State}}|{{.Status}}']);return ud(t)}function ud(e){let t=[];for(let r of e.trim().split(`
3
+ `)){if(!r)continue;let[o,n,i]=r.split("|");if(!o||!n)continue;let s=i?.match(ld)?.[1];t.push(s?{service:o,state:n,health:s}:{service:o,state:n})}return t}async function ps(){let{stdout:e}=await Lt("docker",["info","--format","{{.DockerRootDir}}"]),t=e.trim();if(!t)throw new Error("docker info returned an empty DockerRootDir");return t}async function ms(e){let{stdout:t}=await Lt("df",["-k",e]);return t}var as=26;async function dd(){let{stdout:e}=await Lt("docker",["version","--format","{{.Server.Version}}"]);return e.trim()}async function fs(){let e=await dd(),t=Number.parseInt(e,10);if(Number.isNaN(t)||t<as)throw new Error(`The code sandbox needs Docker Engine ${as} or newer (this daemon is ${e||"unknown"}): it mounts only each user's own files into their sandbox. Upgrade Docker, or run \`gaia up --no-code-sandbox\` and save an E2B key instead.`)}async function qr(e){let{stdout:t}=await Lt("docker",["volume","ls","--quiet","--filter",`name=^${e}$`]);return t.trim().split(`
4
+ `).includes(e)}import*as ks from"node:os";import{execa as bd}from"execa";import{spawn as gd}from"node:child_process";import*as mn from"node:os";import{execa as fn}from"execa";import*as Ss from"node:fs";import*as dn from"node:path";import*as Le from"fs";import*as hs from"os";import*as un from"path";var gs={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.7.0-beta.1",type:"module",files:["dist","README.md"],scripts:{"bake:logo":"node scripts/bake-logo.mjs",build:"node esbuild.config.mjs && chmod +x dist/index.js",check:"biome check src",dev:"tsx watch src/index.ts",fix:"biome check --write src",format:"biome format --write src",lint:"pnpm run check","lint:fix":"pnpm run fix",prepublishOnly:"pnpm run build",start:"NODE_ENV=production node dist/index.js","type-check":"tsc --noEmit"},dependencies:{"@inkjs/ui":"^2.0.0","@modelcontextprotocol/sdk":"^1.32.0",chalk:"^5.6.2",commander:"^14.0.3",execa:"^9.6.1",ink:"^6.8.0","ink-text-input":"^6.0.0","is-unicode-supported":"^2.1.0",react:"19.1.0","react-dom":"19.1.0",semver:"^7.8.5","simple-git":"^3.36.0","supports-hyperlinks":"^3.2.0","wrap-ansi":"^9.0.2",ws:"^8.21.0",zod:"^4.3.6"},devDependencies:{"@biomejs/biome":"^2.5.7","@gaia/shared":"workspace:*","@resvg/resvg-js":"^2.6.2","@types/node":"^24.13.3","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@types/semver":"^7.8.0","@types/ws":"^8.18.1",esbuild:"^0.25.12",tsx:"^4.23.11",typescript:"^7.0.2",vite:"^7.3.6",vitest:"^4.1.10"},bin:{gaia:"./dist/index.js"},engines:{node:">=20"},keywords:["ai-assistant","cli","gaia","setup"],license:"MIT",publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/theexperiencecompany/gaia.git",directory:"packages/cli"}};var O=gs.version,He=`v${O}`;var Ve=un.join(hs.homedir(),".gaia"),ln=un.join(Ve,"config.json");function md(){Le.existsSync(Ve)||Le.mkdirSync(Ve,{recursive:!0})}function $(){try{if(!Le.existsSync(ln))return null;let e=Le.readFileSync(ln,"utf-8");return JSON.parse(e)}catch{return null}}function Hr(e){md(),Le.writeFileSync(ln,`${JSON.stringify(e,null,2)}
5
+ `)}function Se(e){let r={...$()??{version:O,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Hr(r)}var lr=dn.join(Ve,"logs");function ht(e,t=new Date){Ss.mkdirSync(lr,{recursive:!0});let r=t.toISOString().slice(0,19).replaceAll(":","-");return dn.join(lr,`${e}-${r}.log`)}function Vr(e){let t="";return r=>{let o=(t+r).split(/\r?\n|\r/);t=o.pop()??"";for(let n of o)n.trim()&&e(n)}}import*as vs from"node:fs";import{execa as pn}from"execa";function ys(){return typeof process.getuid=="function"&&process.getuid()===0}async function fd(){ys()||!(await pn("sudo",["-n","true"],{reject:!1})).failed||await pn("sudo",["-v","-p","[sudo] password for %u: "],{stdio:"inherit"})}async function Mt(e,t,r,o){await fd();let[n,i]=ys()?[e,[...t]]:["sudo",["-n",e,...t]],s=vs.createWriteStream(r,{flags:"a"}),a=Vr(d=>o?.(d)),c=pn(n,i,{all:!0,reject:!1});c.all?.on("data",d=>{s.write(d),a(d.toString())});let l=await c;if(await new Promise(d=>s.end(d)),l.failed)throw new Error(`'${[e,...t].join(" ")}' failed (exit ${l.exitCode??"unknown"}). Its output is in ${r}`)}var re="docker",gn="GAIA_DOCKER_GROUP_RELAUNCHED",ws="GAIA_RESUMED_STEP";function bs(){return process.env[ws]||void 0}function Es(){return process.env[gn]==="1"}async function hn(){let{stdout:e}=await fn("id",["-nG",mn.userInfo().username]);return e.split(/\s+/).includes(re)}function xs(e){let t=e.stderr;return typeof t=="string"&&t.toLowerCase().includes("permission denied")}async function Cs(){if(process.env[gn]==="1")throw new Error(`Still no access to the Docker socket after joining the '${re}' group.
6
+ Check the socket's group with 'ls -l /var/run/docker.sock', then log out and back in and rerun.`);if(await hn())return;let e=mn.userInfo().username;try{await Mt("usermod",["-aG",re,e],ht("docker-group"))}catch(t){throw new Error(`Could not add ${e} to the '${re}' group: ${t.message}
7
+ Run 'sudo usermod -aG ${re} ${e}', log out and back in, then rerun.`)}}var hd=/^[A-Za-z_][A-Za-z0-9_]*$/;async function Sd(e){try{return await fn("sh",["-c",'command -v "$1"',"sh",e]),!0}catch{return!1}}async function vd(){try{return await fn("sudo",["-l","-g",re,"--",process.execPath]),!0}catch{return!1}}async function Is(){if(await Sd("sg"))return"sg";if(await vd())return"sudo";throw new Error(`Docker access was granted, but this login session predates it and cannot pick it up ('sg' is missing and sudo cannot switch to the '${re}' group).
8
+ Log out and back in (or run 'newgrp ${re}'), then rerun this command.`)}function yd(e){return`'${e.replaceAll("'","'\\''")}'`}function wd(e,t,r){return e==="sg"?["sg",[re,"-c",t.map(yd).join(" ")]]:["sudo",[`--preserve-env=${Object.keys(r).filter(n=>hd.test(n)).join(",")}`,"-g",re,"--",...t]]}function Sn(e,t){let r={...process.env,[gn]:"1",[ws]:e},[o,n]=wd(t,[process.execPath,...process.argv.slice(1)],r),i=gd(o,n,{stdio:"inherit",env:r});return new Promise((s,a)=>{i.on("error",a),i.on("exit",(c,l)=>{process.exit(c??(l?1:0))})})}var Ed=5e3,xd="https://orbstack.dev",vn="Run 'gaia up': it installs everything GAIA needs.";async function Q(){try{return await bd("docker",["info"],{timeout:Ed}),"ready"}catch(e){return e.code==="ENOENT"?"not-installed":xs(e)?"no-permission":"not-running"}}async function Me(e){let t=ks.platform()==="darwin";switch(e){case"not-installed":return{summary:"Docker isn't installed",state:"isn't installed",fix:t?`Install OrbStack (${xd}) or Docker Desktop, open it, then try again.`:vn};case"not-running":return{summary:"Docker isn't running",state:"isn't running",fix:t?"Open OrbStack or Docker Desktop, then try again.":"Start it with 'sudo systemctl start docker', then try again."};case"no-permission":return{summary:"Docker is running, but your user can't use it yet",state:"is running, but your user can't use it yet",fix:await hn()?`Your user just joined the '${re}' group. Log out and back in (or run 'newgrp ${re}' in this terminal), then try again.`:`Run 'sudo usermod -aG ${re} $USER', log out and back in, then try again.`}}}async function St(e){let t=await Me(e);return new Error(`${t.summary}.
9
+ ${t.fix}`)}import*as H from"fs";import*as Ft from"path";import*as ur from"node:fs";import*as yn from"node:path";var Rs=[{name:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"MONGO_DB",required:!0,category:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/"}]},{name:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",requiredInProd:!0,allRequired:!0,docsUrl:"https://redis.io/docs/connect/clients/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"REDIS_URL",required:!0,category:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",docsUrl:"https://redis.io/docs/connect/clients/"}]},{name:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"POSTGRES_URL",required:!1,category:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING"}]},{name:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.trychroma.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"CHROMADB_HOST",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"},{name:"CHROMADB_PORT",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"}]},{name:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.rabbitmq.com/uri-spec.html",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RABBITMQ_URL",required:!1,category:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",docsUrl:"https://www.rabbitmq.com/uri-spec.html"}]},{name:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",requiredInProd:!0,allRequired:!0,docsUrl:"https://workos.com/docs/reference/api-keys",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"WORKOS_API_KEY",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_CLIENT_ID",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_COOKIE_PASSWORD",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"}]},{name:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",requiredInProd:!0,allRequired:!0,docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"CLOUDINARY_CLOUD_NAME",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_KEY",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_SECRET",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"}]},{name:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SHARE_GRANT_SECRET",required:!1,category:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",docsUrl:null}]},{name:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",requiredInProd:!0,allRequired:!1,docsUrl:"https://deepgram.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"DEEPGRAM_API_KEY",required:!1,category:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",docsUrl:"https://deepgram.com/"}]},{name:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://platform.openai.com/api-keys",alternativeGroup:"Google AI",selfhostSetup:!0,variables:[{name:"OPENAI_API_KEY",required:!1,category:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",docsUrl:"https://platform.openai.com/api-keys"}]},{name:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://console.cloud.google.com/apis/credentials",alternativeGroup:"OpenAI Integration",selfhostSetup:!0,variables:[{name:"GOOGLE_API_KEY",required:!1,category:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",docsUrl:"https://console.cloud.google.com/apis/credentials"}]},{name:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",requiredInProd:!0,allRequired:!0,docsUrl:"https://tavily.com/#api",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"TAVILY_API_KEY",required:!1,category:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",docsUrl:"https://tavily.com/#api"}]},{name:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.firecrawl.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"FIRECRAWL_API_KEY",required:!1,category:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",docsUrl:"https://www.firecrawl.dev/"}]},{name:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.llamaindex.ai/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"LLAMA_INDEX_KEY",required:!1,category:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",docsUrl:"https://docs.llamaindex.ai/"}]},{name:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",requiredInProd:!0,allRequired:!0,docsUrl:"https://resend.com/docs/api-reference/api-keys",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RESEND_API_KEY",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"RESEND_AUDIENCE_ID",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"EMAIL_UNSUBSCRIBE_SECRET",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"}]},{name:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",requiredInProd:!0,allRequired:!0,docsUrl:"https://openweathermap.org/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"OPENWEATHER_API_KEY",required:!1,category:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",docsUrl:"https://openweathermap.org/api"}]},{name:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.composio.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"COMPOSIO_KEY",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"},{name:"COMPOSIO_WEBHOOK_SECRET",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"}]},{name:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",requiredInProd:!0,allRequired:!0,docsUrl:"https://e2b.dev/docs",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"E2B_API_KEY",required:!1,category:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",docsUrl:"https://e2b.dev/docs"}]},{name:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",requiredInProd:!1,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BROWSER_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_HOST_KEY",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_FALLBACK_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null}]},{name:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.dodopayments.com/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"DODO_PAYMENTS_API_KEY",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"},{name:"DODO_WEBHOOK_PAYMENTS_SECRET",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"}]},{name:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BLOG_BEARER_TOKEN",required:!1,category:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",docsUrl:null}]},{name:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.sentry.io/platforms/python/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SENTRY_DSN",required:!1,category:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",docsUrl:"https://docs.sentry.io/platforms/python/"}]},{name:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",requiredInProd:!1,allRequired:!0,docsUrl:"https://posthog.com/docs/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"POSTHOG_PROJECT_TOKEN",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"},{name:"POSTHOG_HOST",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"}]}];var wn={selfhost:{MONGO_DB:"mongodb://mongo:27017/gaia",REDIS_URL:"redis://redis:6379",POSTGRES_URL:"postgresql://postgres:postgres@postgres:5432/langgraph",CHROMADB_HOST:"chromadb",CHROMADB_PORT:"8000",RABBITMQ_URL:"amqp://guest:guest@rabbitmq:5672/"},developer:{MONGO_DB:"mongodb://localhost:27017/gaia",REDIS_URL:"redis://localhost:6379",POSTGRES_URL:"postgresql://postgres:postgres@localhost:5432/postgres",CHROMADB_HOST:"localhost",CHROMADB_PORT:"8080",RABBITMQ_URL:"amqp://guest:guest@localhost:5672/"}},Ts={selfhost:{HOST:"http://localhost:3000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://gaia-backend:8000"},developer:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://host.docker.internal:8000"}};function dr(e,t){return wn[t][e]??Ts[t][e]}function Wr(){return structuredClone(Rs)}function Ps(e){let t=yn.join(e,"apps","web",".env.local"),r=ur.existsSync(t)?t:yn.join(e,"apps","web",".env");if(!ur.existsSync(r))return[];let o=ur.readFileSync(r,"utf-8"),n=[],i="General";for(let s of o.split(`
10
+ `)){let a=s.trim();if(a.startsWith("#")&&!a.startsWith("#=")){let p=a.replace(/^#+\s*/,"").trim();p&&!p.startsWith("These are")&&(i=p);continue}if(!a||a.startsWith("#"))continue;let c=a.indexOf("=");if(c===-1)continue;let l=a.substring(0,c).trim(),d=a.substring(c+1).trim();n.push({name:l,value:d,category:i})}return n}function As(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function _s(e,t,r){let o=r==="selfhost"?new Set(Object.keys(wn.selfhost)):new Set;for(let[n,i]of Object.entries(t)){let s=Number(n),a=Number(i);for(let[c,l]of Object.entries(e)){if(o.has(c))continue;if(l===String(s)){e[c]=String(a);continue}let d=new RegExp(`:${s}(?=[/\\s]|$)`,"g");e[c]=l.replaceAll(d,`:${a}`)}}}function Ds(e,t){return e.map(r=>({...r,variables:r.variables.map(o=>{let n=dr(o.name,t);return{...o,defaultValue:n||o.defaultValue}})}))}function pr(){return Object.keys(wn.selfhost)}function Os(e){return{...Ts[e]}}function vt(e){let t={};if(!e)return t;for(let r of e.split(`
11
+ `)){let o=r.trim();if(!o||o.startsWith("#"))continue;let n=o.indexOf("=");if(n<=0)continue;let i=o.substring(0,n).trim(),s=o.substring(n+1).trim().replace(/^["']|["']$/g,"");i&&s&&(t[i]=s)}return t}var bn=384;function Kr(e){if(H.existsSync(e)){let t=`${e}.bak`;H.copyFileSync(e,t),H.chmodSync(t,bn)}}function Yr(e,t){H.writeFileSync(e,t,{encoding:"utf-8",mode:bn}),H.chmodSync(e,bn)}function Xr(e,t){Kr(t),Yr(t,H.readFileSync(e,"utf-8"))}function mr(e,t){let r=Ft.join(e,".env");Kr(r);let o=["# GAIA Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],n=["MONGO","REDIS","POSTGRES","CHROMADB","RABBITMQ","WORKOS","GOOGLE","OPENAI","INFISICAL","LANGSMITH","DISCORD","SLACK","TELEGRAM","CLOUDINARY","COMPOSIO","FIRECRAWL","LIVEKIT","DEEPGRAM","ELEVENLABS","RESEND","SENTRY","POSTHOG","E2B","DODO","NEXT_PUBLIC","GAIA"];function i(a){for(let l of n)if(a===l||a.startsWith(`${l}_`))return l;let c=a.split("_");return c.length===1?"Core":c[0]||"Core"}let s=new Map;for(let[a,c]of Object.entries(t)){let l=i(a);s.has(l)||s.set(l,[]);let p=/[\s#"'\\]/.test(c)||c===""?`"${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:c;s.get(l).push(`${a}=${p}`)}for(let[a,c]of s.entries())o.push(`# ${a} Configuration`),o.push(...c),o.push("");Yr(r,o.join(`
12
+ `))}function Ls(e,t,r){let o=Ft.join(e,"apps","web",".env.local");Kr(o);let n=Ps(e),i=As(t,r),s=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],a=new Map;for(let c of n){a.has(c.category)||a.set(c.category,[]);let l=i[c.name]??c.value;a.get(c.category).push({name:c.name,value:l})}if(n.length===0){s.push("# Core URLs");for(let[c,l]of Object.entries(i))s.push(`${c}=${l}`);s.push("")}else for(let[c,l]of a.entries()){s.push(`# ${c}`);for(let{name:d,value:p}of l)s.push(`${d}=${p}`);s.push("")}Yr(o,s.join(`
13
+ `))}var En={8e3:"API_HOST_PORT",5432:"POSTGRES_HOST_PORT",6379:"REDIS_HOST_PORT",27017:"MONGO_HOST_PORT",5672:"RABBITMQ_HOST_PORT",15672:"RABBITMQ_MGMT_PORT",8080:"CHROMADB_HOST_PORT",8083:"MONGO_EXPRESS_HOST_PORT",3e3:"WEB_HOST_PORT",3443:"HTTPS_HOST_PORT"},$s=Object.fromEntries(Object.entries(En).map(([e,t])=>[t,Number(e)])),kd="proxy";function Ms(e){return Ft.join(e,"infra","docker",".env")}function zr(e){let t=Ms(e);return H.existsSync(t)?vt(H.readFileSync(t,"utf-8")):{}}var xn="GAIA_VERSION",Rd="latest",Fs="GAIA_DOMAIN";function Nt(e){return zr(e)[Fs]||void 0}function Ie(e){return zr(e)[xn]??Rd}function Ns(e,t){let r=Ms(e);Kr(r);let o=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[n,i]of Object.entries(t))o.push(`${n}=${i}`);o.push(""),Yr(r,o.join(`
14
+ `))}function Bs(e,t,r){Ns(e,{...zr(e),[t]:r})}function Cn(e,t,r,o){let{NEXT_PUBLIC_APP_URL:n,...i}=zr(e);for(let[s,a]of Object.entries(t)){let c=Number(s),l=En[c];l&&(i[l]=String(a))}r==="selfhost"&&o&&(i.COMPOSE_PROFILES??=kd,i.DOCKER_SOCKET_GID=String(o.dockerSocketGid),o.domain&&(i[Fs]=o.domain)),Ns(e,i)}function We(e){let t={};for(let[r,o]of Object.entries(e)){let n=Number(r),i=En[n];i&&(t[i]=String(o))}return t}function Gs(e){let t=Ft.join(e,"infra","docker","docker-compose.yml");if(!H.existsSync(t))return;let r=H.readFileSync(t,"utf-8"),o=[{varName:"API_HOST_PORT",hostPort:8e3,containerPort:80},{varName:"CHROMADB_HOST_PORT",hostPort:8080,containerPort:8e3},{varName:"POSTGRES_HOST_PORT",hostPort:5432,containerPort:5432},{varName:"REDIS_HOST_PORT",hostPort:6379,containerPort:6379},{varName:"MONGO_HOST_PORT",hostPort:27017,containerPort:27017},{varName:"RABBITMQ_HOST_PORT",hostPort:5672,containerPort:5672},{varName:"MONGO_EXPRESS_HOST_PORT",hostPort:8083,containerPort:8081},{varName:"WEB_HOST_PORT",hostPort:3e3,containerPort:3e3}],n=!1;for(let{varName:i,hostPort:s,containerPort:a}of o){let c=`"${s}:${a}"`,l=`"\${${i}:-${s}}:${a}"`;r.includes(c)&&(r=r.replaceAll(c,l),n=!0)}{let i='"15672:15672"';r.includes(i)&&(r=r.replaceAll(i,'"${RABBITMQ_MGMT_PORT:-15672}:15672"'),n=!0)}n&&H.writeFileSync(t,r,"utf-8")}function F(e){let t=Ft.join(e,"infra","docker",".env"),r={};if(!H.existsSync(t))return r;let o=H.readFileSync(t,"utf-8");for(let n of o.split(`
15
+ `)){let i=n.trim();if(i&&!i.startsWith("#")){let[s,...a]=i.split("=");if(s&&$s[s]){let c=a.join("=").trim().replace(/^["']|["']$/g,""),l=Number(c);!Number.isNaN(l)&&l>0&&l<=65535&&(r[$s[s]]=l)}}}return r}import{execa as mp}from"execa";import*as ve from"fs";import*as ae from"path";import*as Bt from"node:fs";import*as fr from"node:path";import*as js from"node:crypto";var Us=["AGENT_SECRET","BOT_SESSION_TOKEN_SECRET","EMAIL_UNSUBSCRIBE_SECRET","SHARE_GRANT_SECRET","GAIA_BOT_API_KEY"],Pd=["INSTANCE_SECRET"];function In(){return js.randomBytes(32).toString("hex")}function Ad(e){return new Set(Object.keys(vt(e)))}function Qr(e){let t=Ad(e),r={},o=e===null?[...Us,...Pd]:Us;for(let n of o)t.has(n)||(r[n]=In());return r}var qs=["telegram","discord","slack"],Hs={telegram:["TELEGRAM_BOT_TOKEN"],discord:["DISCORD_BOT_TOKEN","DISCORD_CLIENT_ID"],slack:["SLACK_BOT_TOKEN","SLACK_APP_TOKEN","SLACK_SIGNING_SECRET"]},Tn={telegram:"TELEGRAM_BOT_USERNAME",discord:"DISCORD_CLIENT_ID",slack:"SLACK_WORKSPACE_URL"},_d={GAIA_BOT_API_KEY:"GAIA_BOT_API_KEY",GAIA_FRONTEND_URL:"FRONTEND_URL",RABBITMQ_URL:"RABBITMQ_URL"},Dd="BOT_LOG_HASH_SECRET";function ue(e){return`bot-${e}`}function gr(e,t){let r=t.find(i=>i.service===ue(e));if(!r)return{health:"failing",detail:"not created"};let o=[r.state,r.health].filter(Boolean).join(", ");return r.state!=="running"||r.health==="unhealthy"?{health:"failing",detail:o}:{health:r.health===void 0||r.health==="healthy"?"healthy":"starting",detail:o}}function Vs(e){return`docker-compose.${ue(e)}.yml`}function kn(e){return fr.join(e,"apps","api")}function Od(e){return fr.join(e,"apps","bots")}function Rn(e){let t=fr.join(e,".env");return Bt.existsSync(t)?vt(Bt.readFileSync(t,"utf-8")):{}}function Ws(e,t){let r={...e,...t.set};for(let o of t.unset??[])delete r[o];return r}function Jr(e,t){let r=kn(e),o=Rn(r),n=Ws(o,t);JSON.stringify(n)!==JSON.stringify(o)&&mr(r,n)}function hr(e,t={}){let r=fr.join(kn(e),".env");if(!Bt.existsSync(r))throw new Error(`${r} does not exist; run 'gaia up' to configure the install first.`);let o=Qr(Bt.readFileSync(r,"utf-8"));Object.keys(o).length>0&&Jr(e,{set:o});let n=Rn(kn(e)),i={};for(let[c,l]of Object.entries(_d)){let d=n[l];if(!d)throw new Error(`${l} is not set in apps/api/.env; run 'gaia up' to configure the install first.`);i[c]=d}let s=Od(e),a=Ws(Rn(s),t);a[Dd]??=In(),mr(s,{...a,...i})}var $d={proxy:"proxy","gaia-web":"web app","gaia-backend":"server",arq_worker:"background jobs",mongo:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB","bot-telegram":"Telegram bot","bot-discord":"Discord bot","bot-slack":"Slack bot"},Ld={mongodb:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB"};function Fe(e){return $d[e]??e}function Zr(e){return Ld[e]??e}import{execa as jd}from"execa";import{execa as Md}from"execa";import eo from"fs";import Fd from"simple-git";var Pn=.85,Nd=/Receiving objects:\s+(\d+)%[^,\r\n]*(?:,\s*([\d.]+\s*[KMG]iB))?/g,Bd=/Resolving deltas:\s+(\d+)%/g;function Gd(e){let t=[...e.matchAll(Bd)].at(-1);if(t?.[1]){let o=Number(t[1]);return{percent:Math.floor(Pn*100+o*(1-Pn)),label:"Unpacking the files"}}let r=[...e.matchAll(Nd)].at(-1);if(r?.[1]){let o=Number(r[1]),n=r[2]?.replace(/\s+/," ");return{percent:Math.floor(o*Pn),label:n?`${n} downloaded`:"Downloading"}}return null}async function to(e,t,r,o){if(eo.existsSync(e)){let n=`${e}/.git`;if(!eo.existsSync(n))throw new Error(`Directory ${e} exists but is not a git repository`);await Fd().cwd(e).pull(),r(100,"Already exists, pulled latest")}else try{let n=["clone","--progress"];o&&n.push("--branch",o),n.push(t,e);let i=Md("git",n);i.stderr?.on("data",s=>{let a=Gd(s.toString());a&&r(a.percent,a.label)}),await i,r(100,"Clone complete")}catch(n){throw eo.existsSync(e)&&eo.rmSync(e,{recursive:!0,force:!0}),n}}var Ys="https://github.com/theexperiencecompany/gaia.git",Ks="https://heygaia.io/install.sh",qd=/^\d+\.\d+\.\d+-beta\.\d+$/;function An(e){return qd.test(e)?"beta":"latest"}function Sr(e){return e==="beta"?`curl -fsSL ${Ks} | GAIA_CHANNEL=beta sh`:`curl -fsSL ${Ks} | sh`}function Xs(e){let t=An(e),r=[`For a newer release, update the CLI first (${Sr(t)}), then rerun 'gaia update'.`];return t==="beta"&&r.push(`This is a beta CLI. To move to the stable channel once a stable release newer than ${e} is out, install it with ${Sr("latest")} and rerun 'gaia update'.`),r}var Hd=2,Vd=/^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function ro(e){if(!Vd.test(e))throw new Error(`${e} is not a GAIA release tag (v<major>.<minor>.<patch>, e.g. v0.7.0): only a release has compose files that match its images.`);return`cli-${e}`}async function _n(e,t,r){let o=ro(t),n=await jd("git",["ls-remote","--exit-code","--tags",e,`refs/tags/${o}`],{cwd:r,reject:!1});if(n.exitCode!==0)throw n.exitCode===Hd?new Error(`GAIA ${t} has no published release: ${e} has no tag ${o}.
16
+ Install a released CLI (${Sr("latest")}) and rerun.`):new Error(`Could not read ${o} from ${e}: ${n.stderr.trim()}`)}function Dn(e,t){Bs(e,xn,t)}async function zs(e,t,r){await _n(t,He),await to(e,t,r,ro(He)),Dn(e,He)}var Wd=/ghcr\.io\/theexperiencecompany\/(gaia[\w-]*):([\w.-]+)/,Kd={gaia:"API","gaia-web":"web app"};function Js(e){let t=Wd.exec(e);return t?.[1]&&t[2]?{name:t[1],tag:t[2]}:null}function Qs(e){let t=Kd[e];return t?`GAIA's ${t} image (${e})`:`the ${e} image`}function Gt(e,t){let[r=e.image,o=""]=e.image.split(":");return e.kind==="wrong-cpu"?{cause:`${Qs(r)} at ${o} has no build for this computer's processor (${e.arch}).`,next:`Build it on this machine instead: ${t} (15-30 minutes).`}:{cause:`GAIA ${o} isn't published: ${Qs(r)} doesn't exist in the registry.`,next:`Update the CLI (${Sr(An(O))}) and run it again, or build from source: ${t}.`}}var Yd=(e,t)=>{let r=/no matching manifest for linux\/([\w]+)/.exec(e)?.[1];if(!r)return null;let o=Js(e);return o?Gt({kind:"wrong-cpu",image:`${o.name}:${o.tag}`,arch:r},t.rebuildCommand):{cause:`One of GAIA's images has no build for this computer's processor (${r}).`,next:`Build it on this machine instead: ${t.rebuildCommand} (15-30 minutes).`}},Xd=(e,t)=>{if(!/manifest unknown|: not found|failed to resolve reference|No such image/.test(e))return null;let r=Js(e);if(r)return Gt({kind:"not-published",image:`${r.name}:${r.tag}`},t.rebuildCommand);let o=/No such image: ([\w./-]+:[\w.-]+)/.exec(e)?.[1];return{cause:o?`The image ${o} was never built on this machine.`:"An image GAIA needs could not be found.",next:`Build the images here: ${t.rebuildCommand}.`}},zd=e=>{let t=/Bind for [\d.:[\]]*:(\d+) failed/.exec(e)?.[1]??/listen tcp[46]? [\d.:[\]]*:(\d+): bind: address already in use/.exec(e)?.[1];return!t&&!/port is already allocated|address already in use/.test(e)?null:{cause:`Port ${t??"GAIA needs"} is already used by another program.`,next:"Stop that program, or pick another port: gaia up --web-port <port>."}},Qd=[[/permission denied while trying to connect/i,{cause:"Docker refused your user.",next:"Log out and back in (or run 'newgrp docker'), then try again."}],[/Cannot connect to the Docker daemon|Is the docker daemon running/i,{cause:"Docker stopped running.",next:"Start Docker (sudo systemctl start docker, or open OrbStack / Docker Desktop), then try again."}],[/no space left on device/i,{cause:"The disk is full.",next:"Free some space ('docker system prune' removes unused images), then try again."}],[/toomanyrequests|rate limit/i,{cause:"The image registry is limiting downloads from this network.",next:"Wait a few minutes, then try again."}],[/i\/o timeout|TLS handshake timeout|no such host|network is unreachable|connection reset by peer|dial tcp/i,{cause:"GAIA's images could not be downloaded (network error).",next:"Check this machine's internet connection, then try again."}]],Jd=e=>{let t=/container ([\w-]+?)(?:-\d+)? is unhealthy/.exec(e)?.[1];if(!t)return null;let r=t.replace(/^gaia-(selfhost|dev)-/,"");return{cause:`GAIA's ${Fe(r)} didn't start.`,next:"Try: gaia doctor",service:r}};function Zd(e){return([...e].reverse().find(r=>/error|failed|denied/i.test(r))??e.at(-1)??"docker compose failed").trim()}function Zs(e,t,r){let o=[...e,...t].join(`
17
+ `);for(let n of[Yd,Xd,zd,Jd]){let i=n(o,r);if(i)return i}for(let[n,i]of Qd)if(n.test(o))return i;return{cause:`Docker Compose failed: ${e.at(-1)??Zd(t)}`,next:""}}var Ke=class extends Error{failure;logPath;constructor(t,r){let o=t.logTail?.length?["Its last log lines:",...t.logTail.map(n=>` ${n}`)]:[];super([t.cause,...o,`Full log: ${r}`,t.next].filter(Boolean).join(`
18
+ `)),this.name="ComposeError",this.failure=t,this.logPath=r}};import*as aa from"node:fs";import{execa as ca}from"execa";import na from"semver";function ea(){return{images:new Map,layers:new Map,steps:new Map,containers:new Map,started:new Set,finished:[],errors:[],downloadPercent:0}}var On="Image ",ta="Container ",ep=/^\[[^\]]*\d+\/\d+\]/,tp=/^gaia-(?:selfhost|dev)-(.+)-\d+$/;function rp(e){return e.slice(e.lastIndexOf("/")+1)}function op(e){let t=e.slice(ta.length);return tp.exec(t)?.[1]??t}function np(e,t){let r=(t.id??"").slice(On.length);if(t.status==="Error"){e.errors.push(`${r}: ${t.details??t.text??"error"}`);return}e.images.get(r)!=="ready"&&(t.text==="Pulled"||t.text==="Built"?(e.finished.push(`${t.text==="Built"?"Built":"Downloaded"} ${rp(r)}`),e.images.set(r,"ready")):e.images.set(r,t.text==="Building"?"building":"downloading"))}function ip(e,t){let r=t.id??"",o=e.layers.get(r)??{current:0,total:0,done:!1};t.text==="Downloading"&&t.total&&(o.total=t.total,o.current=t.current??o.current),(t.text==="Download complete"||t.text==="Pull complete")&&(o.done=!0,o.current=o.total),e.layers.set(r,o)}function sp(e,t){let r=op(t.id??""),o=["Started","Running","Healthy"].includes(t.text??"");t.status==="Error"&&e.errors.push(`${r}: ${t.details??t.text??"error"}`),t.text==="Started"&&!e.started.has(r)&&(e.started.add(r),e.finished.push(`Started ${Fe(r)}`)),e.containers.set(r,e.containers.get(r)===!0||o)}function ra(e,t){t.error&&t.message&&e.errors.push(t.message);for(let o of t.vertexes??[]){let n=e.steps.get(o.digest),i=o.name??n?.name;!i||!ep.test(i)||e.steps.set(o.digest,{name:i,done:n?.done===!0||!!o.completed})}let r=t.id??"";return r.startsWith(On)?np(e,t):r.startsWith(ta)?sp(e,t):t.parent_id?.startsWith(On)&&ip(e,t),e}function ap(e){return e>=1e9?`${(e/1e9).toFixed(1)} GB`:`${Math.round(e/1e6)} MB`}var cp=99;function lp(e){let t=[...e.layers.values()],r=t.filter(c=>c.total>0),o=r.reduce((c,l)=>c+l.current,0);if(r.length===0)return{downloaded:o,percent:0};let n=r.reduce((c,l)=>c+l.total,0)/r.length,i=t.filter(c=>c.total===0),s=r.reduce((c,l)=>c+l.total,0)+i.length*n,a=o+i.filter(c=>c.done).length*n;return{downloaded:o,percent:Math.min(cp,Math.floor(a/s*100))}}function oa(e){let t=[...e.steps.values()],r=t.filter(i=>i.done).length;if(t.length>0&&r<t.length)return{label:`Building GAIA from source: step ${r+1} of ${t.length}`,percent:Math.floor(r/t.length*100)};let o=[...e.images.values()];if(o.includes("building")&&!o.includes("downloading"))return{label:"Building GAIA from source: saving the images",percent:99};if(o.includes("downloading")){let i=o.filter(l=>l==="ready").length,{downloaded:s,percent:a}=lp(e);return e.downloadPercent=Math.max(e.downloadPercent,a),{label:`Downloading GAIA: ${s>0?`${ap(s)} so far`:"starting"} (${i} of ${o.length} images ready)`,percent:e.downloadPercent}}let n=[...e.containers.values()];if(n.length>0){let i=n.filter(Boolean).length;return{label:`Starting GAIA: ${i} of ${n.length} services up`,percent:Math.floor(i/n.length*100)}}return null}var ia="2.29.1",up=40,sa;function dp(){return sa??=(async()=>{let{stdout:e}=await ca("docker",["compose","version","--short"]),t=na.coerce(e.trim());if(!t||na.lt(t,ia))throw new Error(`GAIA needs Docker Compose ${ia} or newer; this machine has ${e.trim()||"an unknown version"}.
19
+ Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),sa}function pp(e){if(!e.startsWith("{"))return null;try{return JSON.parse(e)}catch{return null}}async function $n(e,t){await dp();let r=ht(t.logName),o=aa.createWriteStream(r);t.onLogFile?.(r);let n=ea(),i=[],s=Vr(l=>{let d=pp(l);if(!d){i.push(l),i.length>up&&i.shift();return}ra(n,d);let p=oa(n);p&&t.onProgress?.(p,n.finished)}),a=ca("docker",["compose","--progress","json",...e],{cwd:t.cwd,env:t.env,all:!0,reject:!1,timeout:t.timeoutMs});a.all?.on("data",l=>{o.write(l),s(l.toString())});let c=await a;if(s(`
20
+ `),await new Promise(l=>o.end(l)),c.timedOut)throw new Ke({cause:`Docker Compose was still running after ${Math.round((t.timeoutMs??0)/6e4)} minutes, so it was stopped.`,next:"Run it again; set GAIA_START_TIMEOUT_MIN to allow longer (0 = no limit)."},r);if(c.failed)throw new Ke(Zs(n.errors,i,{rebuildCommand:t.rebuildCommand}),r);return{startedServices:n.started.size}}import*as la from"node:os";function Ut(e,t=la.homedir()){return e===t?"~":e.startsWith(`${t}/`)?`~${e.slice(t.length)}`:e}var fp=e=>new Promise(t=>setTimeout(t,e)),pa="dev-start.log",no=".gaia-dev.pid";function io(e){let t=ae.join(e,".env");return ve.existsSync(t)?["--env-file",".env"]:[]}var gp=60;function hp(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:gp;return r===0?void 0:r*60*1e3}function jt(e={}){let t=$(),r=["docker-compose.selfhost.yml"];return e.build&&r.push("docker-compose.build.yml"),t?.codeSandbox===!0&&r.push("docker-compose.sandbox.yml"),r.push(...(t?.bots??[]).map(Vs)),r}function Ye(e){return e.flatMap(t=>["-f",t])}var ma="gaia-sandbox-workspace",ua="/legacy-sandbox-workspace";function Sp(e,t){return["compose",...Ye(e),...t,"run","--rm","--no-deps","-v",`${ma}:${ua}:ro`,"gaia-backend","python","-m","app.scripts.migrate_legacy_sandbox_workspace","--legacy-root",ua]}function vp(e,t,r){let o=[...Ye(e),...t,"up","-d","--remove-orphans"];return o.push(r?.build?"--build":"--no-build"),r?.pull&&o.push("--pull",r.pull),o}function Ln(e){let t=ae.join(e,no);if(!ve.existsSync(t))return null;try{let r=Number.parseInt(ve.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function oo(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function oe(e,t,r,o,n,i){if(t!=="selfhost")throw r?.("Developer mode must run in foreground."),new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'.");r?.(i?.build?"Building GAIA from source\u2026":"Starting GAIA\u2026");let s=ae.join(e,"infra/docker"),a=o&&Object.keys(o).length>0?We(o):void 0,c=$();c?.codeSandbox===!0&&await fs(),c?.bots?.length&&hr(e);let l=jt({build:i?.build}),d=io(s),p=[...Ye(l),...d],m=await $n(vp(l,d,i),{cwd:s,env:a,timeoutMs:hp(),logName:i?.build?"compose-build":"compose-up",rebuildCommand:i?.rebuildCommand??"gaia start --build",onLogFile:i?.onLogFile,onProgress:n}).catch(async g=>{throw await wp(g,p,s)});return await qr(ma)&&(r?.("Moving code-sandbox files into per-user workspaces\u2026"),await J("docker",Sp(l,d),s,void 0,void 0,a)),r?.("GAIA's services are running."),m}var yp=8;async function wp(e,t,r){if(!(e instanceof Ke)||!e.failure.service)return e;let{stdout:o}=await mp("docker",["compose",...t,"logs","--no-color","--no-log-prefix","--tail",String(yp),e.failure.service],{cwd:r}),n=o.split(`
21
+ `).filter(i=>i.trim());return new Ke({...e.failure,logTail:n},e.logPath)}function Mn(e){return["compose",...Ye(jt()),...io(e)]}async function fa(e,t,r,o){let n=ae.join(e,"infra/docker");await J("docker",[...Mn(n),"run","--rm","--no-deps",t,...r],n,void 0,o)}var bp=["gaia-backend","arq_worker","gaia-web"];async function ga(e,t,r){let o=ae.join(e,"infra/docker");await $n([...Ye(jt()),...io(o),"pull",...bp,...($()?.bots??[]).map(ue)],{cwd:o,env:{GAIA_VERSION:t},logName:"compose-pull",rebuildCommand:"gaia up --build",onProgress:r})}async function ha(e,t,r,o){let n=ae.join(e,"infra/docker"),i=await N(e),s=await Q();if(s==="ready"){t?.("Stopping GAIA's containers\u2026");let a=io(n),c=i==="selfhost"?["compose",...Ye(jt()),...a,"down"]:["compose",...a,"down"];await J("docker",c,n)}else{if(i==="selfhost")throw await St(s);if(s==="no-permission")throw await St(s)}i!=="selfhost"&&await Ep(e,t,r,o),t?.("All services stopped.")}async function Ep(e,t,r,o){t?.("Stopping GAIA-managed local processes (safe mode)\u2026");let n=Ln(e),i=n!==null&&await xp(e,n);try{ve.unlinkSync(ae.join(e,no))}catch{}if(!i){if(o?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports\u2026"),await Cp(e,[r?.[8e3]??8e3,r?.[3e3]??3e3]);return}t?.(n!==null?"Stored GAIA PID is stale. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.":"No GAIA-managed PID found. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.")}}async function xp(e,t){if(!oo(t))return!1;try{return process.platform==="win32"?(await J("taskkill",["/PID",String(t),"/T","/F"],e),!0):(da(t,"SIGTERM"),await fp(800),oo(t)&&da(t,"SIGKILL"),!0)}catch{return!1}}function da(e,t){try{process.kill(-e,t)}catch{process.kill(e,t)}}async function Cp(e,t){for(let r of t){let[o,n]=process.platform==="win32"?["powershell",["-Command",`Get-NetTCPConnection -LocalPort ${r} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`]]:["sh",["-c",`lsof -ti :${r} -sTCP:LISTEN | xargs kill 2>/dev/null || true`]];await J(o,n,e)}}async function N(e){let t=Ne(e);if(!ve.existsSync(t))return null;let r=ve.readFileSync(t,"utf-8"),o=r.match(/^SETUP_MODE=(.+)$/m);if(o?.[1]){let n=o[1].trim().replace(/^["']|["']$/g,"");if(n==="selfhost"||n==="developer")return n}return r.includes("mongodb://mongo:")?"selfhost":(r.includes("mongodb://localhost:"),"developer")}var Ip=8;function kp(e,t){return e.trimEnd().split(`
22
+ `).slice(-t).join(`
23
+ `)}async function J(e,t,r,o,n,i,s){let{spawn:a}=await import("child_process");return new Promise((c,l)=>{let d=a(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],env:i?{...process.env,...i}:void 0}),p="",m=0,g=!1,v;s&&(v=setTimeout(()=>{g=!0,d.kill("SIGTERM"),l(new Error(`Command timed out after ${Math.round(s/6e4)}m. Check \`docker compose logs\` to debug.`))},s)),d.stdout?.on("data",E=>{let w=E.toString();p+=w,n?.(w),m=Math.min(m+5,95),o?.(m)}),d.stderr?.on("data",E=>{let w=E.toString();p+=w,n?.(w),m=Math.min(m+5,95),o?.(m)}),d.on("close",E=>{v&&clearTimeout(v),!g&&(E===0?(o?.(100),c()):l(new Error(`Command failed with code ${E}:
24
+ ${kp(p,Ip)}`)))}),d.on("error",E=>{v&&clearTimeout(v),!g&&l(E)})})}var Rp="apps/api/app/config/settings_validator.py";function Ne(e){return ae.join(e,"apps","api",".env")}function Xe(e){return ve.existsSync(ae.join(e,Rp))}function Sa(e){let t=e;for(;t!==ae.dirname(t);){if(Xe(t))return t;t=ae.dirname(t)}return null}function va(){let e=$();return e?.repoPath?Xe(e.repoPath)?e.repoPath:(console.warn(`Warning: Saved repo path "${e.repoPath}" is no longer a valid GAIA installation. Resetting config.`),Se({repoPath:"",setupComplete:!1}),null):null}function qt(e){return Sa(e??process.cwd())??va()}function _(e){let t=Sa(e??process.cwd());return t&&ve.existsSync(Ne(t))?t:va()??t}function vr(e,t){if(!e)return"GAIA isn't installed yet";let r=Ut(e);return t?`${r} (${t==="selfhost"?"self-host":"developer"})`:`${r} (not set up yet: no apps/api/.env)`}function Tp(e,t=an()){let r=$t(e,t);return[`mkdir -p ${e}`,`docker compose -f docker-compose.selfhost.yml exec -T mongo mongodump --archive --gzip > ${r.mongoFile}`,`docker compose -f docker-compose.selfhost.yml exec -T postgres pg_dump -U postgres -d langgraph > ${r.postgresFile}`,`install -m 600 ../../apps/api/.env ${r.apiEnvFile}`,...r.volumeFiles.map(({volume:o,file:n})=>`docker run --rm -v ${o}:/data -v ${e}:/backups alpine tar czf /backups/${ye.basename(n)} -C /data .`)]}function Pp(e){return ye.join(e,"infra","docker")}function Ap(e,t){return t?ye.resolve(t):ye.join(e,"backups")}async function Fn(e={}){let t=_();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo or set the recorded install path.");let r=Pp(t),o=ye.join(r,"docker-compose.selfhost.yml");if(!Y.existsSync(o))throw new Error(`Compose file not found: ${o}`);let n=Ap(t,e.outputDir),i=an(),s=$t(n,i),a=Tp(n,i);if(e.dryRun)return{...s,commands:a,warnings:[]};let c=await Q();if(c!=="ready"){let p=await Me(c);throw new Error([`${p.summary}, so the databases cannot be backed up.`,p.fix,"Or run the backup commands yourself:",...a.map(m=>` ${m}`)].join(`
25
+ `))}await Y.promises.mkdir(n,{recursive:!0,mode:448});try{Y.chmodSync(n,448)}catch{}let l=[s.mongoFile,s.postgresFile,s.apiEnvFile,...s.volumeFiles.map(p=>p.file)],d;try{d=await _p(t,r,n,i,a)}catch(p){for(let m of l)Y.rmSync(ft(m),{force:!0});throw p}for(let p of[s.mongoFile,s.postgresFile,s.apiEnvFile,...d.volumeFiles.map(m=>m.file)])Y.renameSync(ft(p),p);return{...s,...d,commands:a}}async function _p(e,t,r,o,n){let i=$t(r,o);Dp(e,ft(i.apiEnvFile));try{await wa("docker",ya("mongo",["mongodump","--archive","--gzip"]),t,ft(i.mongoFile))}catch(c){throw new Error(`MongoDB backup failed: ${c.message}
26
+ Manual command: ${n[1]}`)}try{await wa("docker",ya("postgres",["pg_dump","-U","postgres","-d","langgraph"]),t,ft(i.postgresFile))}catch(c){throw new Error(`PostgreSQL backup failed: ${c.message}
27
+ Manual command: ${n[2]}`)}let s=[],a=[];for(let c of mt){let l=cn(r,o,c),d=ft(l.file);if(!await qr(c.volume)){a.push(`${c.label} volume ${c.volume} not found \u2014 nothing to back up`);continue}try{await ba("docker",["run","--rm","-v",`${c.volume}:/data`,"-v",`${ye.dirname(d)}:/backups`,"alpine","tar","czf",`/backups/${ye.basename(d)}`,"-C","/data","."],{cwd:t});try{Y.chmodSync(d,384)}catch{}s.push(l)}catch(p){Y.rmSync(d,{force:!0});let m=`${c.label} backup failed: ${p.message}`;if(c.userData)throw new Error(m);a.push(m)}}return{volumeFiles:s,warnings:a}}function Dp(e,t){let r=Ne(e);if(!Y.existsSync(r))throw new Error(`${r} not found \u2014 it holds INSTANCE_SECRET, without which the backup's stored credentials cannot be decrypted. Run gaia up to configure this install.`);Xr(r,t)}function ya(e,t){return["compose","-f","docker-compose.selfhost.yml","exec","-T",e,...t]}async function wa(e,t,r,o){Y.writeFileSync(o,"",{mode:384,flag:"wx"});try{await ba(e,t,{cwd:r,stdout:{file:o},buffer:{stdout:!1}})}catch(n){throw Y.rmSync(o,{force:!0}),n}}function R(e=""){process.stdout.write(`${e}
28
+ `)}function Op(e=""){process.stderr.write(`${e}
29
+ `)}async function xa(e={}){if(e.dryRun){let t=await Fn({outputDir:e.output,dryRun:!0});R("Backup commands (dry run \u2014 not executed):");for(let r of t.commands)R(` ${r}`);R(""),R(`Volumes (${mt.map(r=>r.volume).join(", ")}) are backed up via`),R(" docker run --rm -v <volume>:/data -v <output>:/backups alpine tar ..."),R(" and are skipped if the volume does not exist yet."),R(""),R("Run without --dry-run to execute inside the running containers,"),R("or copy-paste the commands from the directory containing infra/docker/");return}try{R("Starting GAIA backup\u2026");let t=await Fn({outputDir:e.output});R(`MongoDB dump: ${t.mongoFile}`),R(`PostgreSQL dump: ${t.postgresFile}`),R(`API settings (apps/api/.env): ${t.apiEnvFile}`);for(let{label:r,file:o}of t.volumeFiles)R(`${r} archive: ${o}`);if(t.warnings.length)for(let r of t.warnings)R(`Note: ${r}`);R(""),R("Backups complete. Store them off-host and access-controlled \u2014"),R(`${t.apiEnvFile} holds INSTANCE_SECRET, which decrypts the stored provider credentials.`),R(""),R("Restore with gaia restore --from <dir>, or manually from the repo root:"),R(` install -m 600 ${t.apiEnvFile} apps/api/.env`),R(` cat ${t.postgresFile} | docker compose -f infra/docker/docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`),R(` docker compose -f infra/docker/docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t.mongoFile}`);for(let{volume:r,file:o}of t.volumeFiles)R(` docker run --rm -v ${r}:/data -v $(dirname ${o}):/backups alpine sh -c "${cr(Ea.basename(o))}"`)}catch(t){Op(t.message),process.exitCode=1}}import{Argument as Wm,Command as Km}from"commander";async function de(e){try{await e()}catch(t){console.error(`Error: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}}import{supportsColor as Ka}from"chalk";import{supportsHyperlink as lm}from"supports-hyperlinks";import{networkInterfaces as Ca}from"node:os";var T=3e3,so=8e3,yr=3443;function yt(e,t){return`http://localhost:${e==="selfhost"?t[T]??T:t[so]??so}`}function ne(e,t){return`${yt(e,t)}/api/v1`}var $p=/^(docker\d+|br-[0-9a-f]+)$/;function Ia(e,t){return Object.entries(t).filter(([r])=>!$p.test(r)).flatMap(([,r])=>r??[]).filter(r=>r.family==="IPv4"&&!r.internal).map(r=>`http://${r.address}:${e}`)}function ka(e,t,r=Ca()){return[...t?[`https://${t}`]:[],`http://localhost:${e}`,...Ia(e,r)]}function Lp(e=process.env,t=process.platform){return e.SSH_CONNECTION||e.SSH_TTY?!0:t==="linux"&&!e.DISPLAY&&!e.WAYLAND_DISPLAY}function ze(e,t,r=Ca(),o=Lp()){if(t)return`https://${t}`;let n=`http://localhost:${e}`;return o?Ia(e,r)[0]??n:n}async function ao(e,t,r=5e3){return fetch(e,{...t,signal:AbortSignal.timeout(r)})}async function ke(e,t,r=5e3){try{let o=await ao(`${e}/setup/${t}`,void 0,r);return o.ok?{data:await o.json()}:{detail:`HTTP ${o.status} from /api/v1/setup/${t}`}}catch{return{detail:`Could not read setup ${t}`}}}import*as we from"node:fs";import*as Bn from"node:path";import Da from"semver";import*as Ta from"node:os";var Pa="https://ghcr.io",Aa="theexperiencecompany",_a=8e3,Mp=["gaia","gaia-web"],Fp=["application/vnd.oci.image.index.v1+json","application/vnd.docker.distribution.manifest.list.v2+json","application/vnd.oci.image.manifest.v1+json","application/vnd.docker.distribution.manifest.v2+json"].join(",");function co(e=Ta.arch()){return e==="x64"?"amd64":e}async function Np(e){let t=await fetch(`${Pa}/token?scope=repository:${Aa}/${e}:pull`,{signal:AbortSignal.timeout(_a)});if(!t.ok)throw new Error(`GHCR token request answered HTTP ${t.status}`);return(await t.json()).token}async function Ra(e,t,r){return fetch(`${Pa}/v2/${Aa}/${e}/${t}`,{headers:{Authorization:`Bearer ${r}`,Accept:Fp},signal:AbortSignal.timeout(_a)})}async function Bp(e,t){let r=await Np(e),o=await Ra(e,`manifests/${t}`,r);if(o.status===404)return[];if(!o.ok)throw new Error(`GHCR answered HTTP ${o.status} for ${e}:${t}`);let n=await o.json();if(n.manifests)return n.manifests.map(a=>a.platform?.architecture).filter(a=>!!a&&a!=="unknown");if(!n.config)return[];let i=await Ra(e,`blobs/${n.config.digest}`,r);if(!i.ok)throw new Error(`GHCR answered HTTP ${i.status} for ${e}:${t}'s config`);let{architecture:s}=await i.json();return s?[s]:[]}async function Ht(e,t=[],r=co()){let o=[...Mp,...t.map(n=>`gaia-bot-${n}`)];for(let n of o){let i=await Bp(n,e);if(i.length===0)return{kind:"not-published",image:`${n}:${e}`};if(!i.includes(r))return{kind:"wrong-cpu",image:`${n}:${e}`,arch:r}}return null}var Gp="https://registry.npmjs.org/@heygaia/cli/latest",Nn=Bn.join(Ve,"update-check.json"),Up=Bn.join(lr,"update-check.log"),jp=1440*60*1e3,qp=5e3;function Qe(e){return/^v\d/.test(e)?Da.parse(e.slice(1)):null}var Hp=/^[0-9a-f]{40}$/,Vp=12;function lo(e){return Hp.test(e)?e.slice(0,Vp):e}function Be(e,t){let r=Qe(e),o=Qe(t);return r!==null&&o!==null&&Da.gt(r,o)}function Oa(){if(!we.existsSync(Nn))return null;let e=JSON.parse(we.readFileSync(Nn,"utf-8"));return e.arch===co()?e:null}function $a(){return Oa()?.latest??null}async function Wp(){let e=await fetch(Gp,{signal:AbortSignal.timeout(qp)});if(!e.ok)throw new Error(`npm answered HTTP ${e.status}`);let{version:t}=await e.json(),r=`v${t}`;return await Ht(r)===null?r:null}function Kp(e){we.mkdirSync(lr,{recursive:!0}),we.appendFileSync(Up,`${new Date().toISOString()} update check failed: ${e.message}
30
+ `)}async function uo(){let e=Oa();if(e&&Date.now()-Date.parse(e.checkedAt)<jp)return e.latest;try{let t=await Wp();we.mkdirSync(Ve,{recursive:!0});let r={checkedAt:new Date().toISOString(),arch:co(),latest:t};return we.writeFileSync(Nn,JSON.stringify(r)),t}catch(t){return Kp(t),e?.latest??null}}var La=300,Yp="ai_models";function Xp(e,t){let r=e.features[Yp]?.in_use[0];return r?t?.providers[r]?.label??r:null}async function po(){let e=_(),t=e?await N(e):null;if(!e||!t)return{running:!1,installed:!1};let r=F(e),o=ne(t,r),[n,i]=await Promise.all([ke(o,"status",La),ke(o,"catalog",La)]);if("detail"in n)return{running:!1,installed:!0};let s=r[T]??T;return{running:!0,webUrl:ze(s,Nt(e)),provider:Xp(n.data,"data"in i?i.data:null)}}function mo(){uo();let e=_(),t=$a();return!e||!t?null:Be(t,Ie(e))?t:null}import{Chalk as nm}from"chalk";import zp from"is-unicode-supported";var y="cyan",wr=30,I="round",Vt=zp(),b={ok:Vt?"\u2713":"\u221A",fail:Vt?"\u2717":"x",warn:"!",skip:Vt?"\u2013":"-",pending:Vt?"\u25CB":"o",active:Vt?"\u25CF":"*",cancelled:Vt?"\u25A0":"#"},Ma={ok:"green",fail:"red",warn:"yellow",skip:"gray",pending:"gray",active:y,cancelled:"yellow"};import{Chalk as Qp}from"chalk";var Gn={large:[".........mmmmm.........","......mmmmmmmmmmm......",".....mmmmmmmmmmmmm.....","....ddddddmmmllllll....","...ddddddddmllllllll...","...ddddddd...lllllll...","....ddd.........lll....",".lll................dd.",".lll...............ddd.",".llll.............ddddm","mllll.............ddddm","mmlll.............ddddm","mmllll............dddmm",".mmlll...........dddmmm",".mmmml...........dmmmm.",".mmmmmd.........llmmmm.","..mmmmdd.......lllmmmm.","..mmmmddd.....llllmmm..","...mmmdddd...llllmmm...","....mmddddd.lllllmm....",".....mmdddd.llllmm.....","......mmddd.lllmm......"],small:["......mmmmmm......","....mmmmmmmmmm....","...ddddmmmmllll...","..dddddddlllllll..","..ddddd....lllll..","..................","lll............ddd","lll............ddd","llll..........dddd","mlll..........dddm","mlll..........dddm","mmml..........dmmm","mmmm..........mmmm",".mmmdd......llmmm.",".mmmddd....lllmmm.","..mmdddd..llllmm..","...mmddd..lllmm...","....mmdd..llmm...."]},Un={d:"#0f537c",m:"#059cda",l:"#02bdff"},jn={d:24,m:38,l:39};var Jp={d:"blue",m:"cyan",l:"cyanBright"},Zp={d:"bgBlue",m:"bgCyan",l:"bgCyanBright"},Ba="\u2580",Ga="\u2584",em="\u2588";function Fa(e){return e==="d"||e==="m"||e==="l"?e:null}function tm(e,t){return e===null&&t===null?{ch:" ",fg:null,bg:null}:e===t?{ch:" ",fg:null,bg:e}:e===null?{ch:Ga,fg:t,bg:null}:{ch:Ba,fg:e,bg:t}}function rm(e,t){return{ch:e!==null&&t!==null?em:e!==null?Ba:t!==null?Ga:" ",fg:null,bg:null}}function Na(e,{fg:t,bg:r}){let o=e;return t!==null&&(o=e.level===3?o.hex(Un[t]):e.level===2?o.ansi256(jn[t]):o[Jp[t]]),r!==null&&(o=e.level===3?o.bgHex(Un[r]):e.level===2?o.bgAnsi256(jn[r]):o[Zp[r]]),o}function om(e,t){let r="",o="",n=null;for(let i of t)n&&(i.fg!==n.fg||i.bg!==n.bg)&&(r+=Na(e,n)(o),o=""),n=i,o+=i.ch;return n?r+Na(e,n)(o):r}function Ua(e){return Gn[e][0].length}function ja(e,t){let r=Gn[e],o=new Qp({level:t}),n=[];for(let i=0;i<r.length;i+=2){let s=r[i]??"",a=r[i+1]??"",c=[...s].map((l,d)=>{let p=Fa(l),m=Fa(a[d]);return t===0?rm(p,m):tm(p,m)});n.push(om(o,c))}return n}var qa=3,Ha="Your proactive personal assistant",Va={truecolor:"#af8700",ansi256:136};function im(e,t){return t?`\x1B]8;;${e}\x1B\\${e}\x1B]8;;\x1B\\`:e}function sm(e){return e.level===3?e.hex(Va.truecolor):e.level===2?e.ansi256(Va.ansi256):e.yellow}function Wa(e,t){return{plain:`GAIA v${t}`,styled:`${e.bold("GAIA")} ${e.dim(`v${t}`)}`}}function am(e,t,r){if(!t.running){let n=t.installed?`${b.pending} Not running \xB7 start it with gaia start`:`${b.pending} Not installed \xB7 set it up with gaia up`;return{plain:n,styled:e.dim(n)}}let o=t.provider?` \xB7 ${t.provider}`:"";return{plain:`\u25CF Running at ${t.webUrl}${o}`,styled:`${e.green("\u25CF")} Running at ${im(t.webUrl,r)}${e.dim(o)}`}}function cm(e,t){let r=[Wa(t,e.version),{plain:Ha,styled:t.dim(Ha)}];if(e.status&&r.push(am(t,e.status,e.hyperlinks)),e.update){let o=`Update available: ${e.update} \xB7 run gaia update`;r.push({plain:o,styled:sm(t)(o)})}return r}function fo(e){let t=new nm({level:e.level}),r=cm(e,t),o=Ua(e.size)+qa+Math.max(...r.map(s=>[...s.plain].length));if(!e.isTTY||o>e.columns)return[Wa(t,e.version).styled];let n=ja(e.size,e.level),i=Math.floor((n.length-r.length)/2);return n.map((s,a)=>{let c=r[a-i];return c?`${s}${" ".repeat(qa)}${c.styled}`:s})}var um=80;function qn(){return process.env.NO_COLOR?0:Ka?Ka.level:0}function Hn(e){return{columns:e.columns||um,isTTY:e.isTTY===!0,hyperlinks:lm(e)}}async function dm({size:e="small",showStatus:t=!0,showUpdate:r=!0}={}){let o=Hn(process.stdout),n=t&&o.isTTY?await po():null;return["",...fo({size:e,level:qn(),...o,version:O,status:n,update:r?mo():null}),""]}async function wt(e){process.stdout.write(`${(await dm(e)).join(`
31
+ `)}
32
+ `)}async function Ya(){if(!process.stdout.isTTY){process.stdout.write(`${O}
33
+ `);return}await wt({size:"large"})}var pm="2048";function Xa(e){let t=new URL("https://discord.com/oauth2/authorize");return t.searchParams.set("client_id",e),t.searchParams.set("scope","bot applications.commands"),t.searchParams.set("permissions",pm),t.toString()}function za(e){return`https://t.me/${e}`}async function Vn(e,t){let r=await fetch(e,{...t,signal:AbortSignal.timeout(1e4)}),o=r.headers.get("content-type")?.includes("application/json");if(r.ok||o)return await r.json();throw new Error(`${new URL(e).hostname} answered HTTP ${r.status}. Try again in a minute.`)}async function Ja(e){let t=await Vn(`https://api.telegram.org/bot${e}/getMe`,{method:"GET"});if(!t.ok||!t.result)throw new Error(`Telegram rejected the bot token: ${t.description??"unknown error"}. Copy it again from @BotFather.`);return t.result.username}async function Za(e){let t=await Vn("https://discord.com/api/v10/applications/@me",{method:"GET",headers:{Authorization:`Bot ${e}`}});if(!t.id)throw new Error(`Discord rejected the bot token: ${t.message??"unknown error"}. Reset and copy it from the Developer Portal's Bot page.`);if(((t.flags??0)&786432)===0)throw new Error("Turn on Message Content Intent in the Discord Developer Portal (Bot page, Privileged Gateway Intents), then rerun this command.");return t.id}async function Qa(e,t){return await Vn(`https://slack.com/api/${e}`,{method:"POST",headers:{Authorization:`Bearer ${t}`}})}async function ec(e,t){let r=await Qa("auth.test",e);if(!r.ok||!r.team||!r.url)throw new Error(`Slack rejected the bot token (xoxb-): ${r.error??"unknown error"}.`);let o=await Qa("apps.connections.open",t);if(!o.ok)throw new Error(`Slack rejected the app token (xapp-): ${o.error??"unknown error"}. Enable Socket Mode and create an app-level token with connections:write.`);return{name:r.team,url:r.url}}import*as Kn from"node:fs";import*as Er from"node:os";import*as cc from"node:path";import{execa as ym}from"execa";var br="steps";function go(e){return e.currentState.data[br]??[]}function tc(e,t){e.updateData(br,t.map(r=>({...r,state:"pending"})))}function Ge(e,t,r){e.updateData(br,go(e).map(o=>o.id===t?{...o,...r}:o))}function bt(e,t,r={}){let o=Date.now(),n=go(e).find(i=>i.id===t);Ge(e,t,{state:"active",startedAt:n?.startedAt??o,...r})}function Et(e,t,r){let o=go(e).find(n=>n.id===t);Ge(e,t,{state:"done",endedAt:Date.now(),startedAt:o?.startedAt??Date.now(),detail:void 0,percent:void 0,hint:void 0,...r?{doneLabel:r}:{}})}function Wt(e){let t=go(e).find(r=>r.state==="active"||r.state==="waiting");t&&Ge(e,t.id,{state:"failed",endedAt:Date.now()})}function Kt(e){let t=Math.max(0,Math.floor(e/1e3));if(t<60)return`${t}s`;let r=Math.floor(t/60);return r<60?`${r}m ${String(t%60).padStart(2,"0")}s`:`${Math.floor(r/60)}h ${String(r%60).padStart(2,"0")}m`}function mm(e){let t=e.startedAt!==void 0&&e.endedAt!==void 0?` (${Kt(e.endedAt-e.startedAt)})`:"";return e.state==="active"?` ${e.label}\u2026`:e.state==="done"?`${b.ok} ${e.doneLabel}${t}`:e.state==="failed"?`${b.fail} ${e.label}${t}`:null}function pe(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function rc(e){if(pe())return;let t=e?`'gaia ${e}'`:"this command";console.error(`Error: ${t} needs an interactive terminal (TTY) to prompt for input.`),console.error("Re-run it from a regular shell session \u2014 not a pipe, redirect, or non-TTY environment."),process.exit(1)}function oc(e,t=""){let r=t,o="",n="",i=new Map;e.on("change",s=>{let a=s.data[br]??[];for(let c of a){if(i.get(c.id)===c.state)continue;i.set(c.id,c.state);let l=mm(c);l&&console.info(l)}a.length===0&&s.step&&s.step!==r&&(r=s.step,console.info(`
34
+ [${s.step}]`)),s.status&&s.status!==o&&(o=s.status,console.info(` ${s.status}`)),s.error&&s.error.message!==n&&(n=s.error.message,console.error(` Error: ${s.error.message}`))})}import{execa as xt}from"execa";var Re={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},nc={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",15672:"RabbitMQ Management",[T]:"Web Frontend",[yr]:"Web Frontend (HTTPS)",8080:"ChromaDB",8083:"Mongo Express"},fm={selfhost:[T,yr],developer:[so,5432,6379,27017,5672,15672,T,8080,8083]};async function ho(e,t={}){let r=await us(le[e]),o=fm[e].map(a=>t[a]??a),n=o.filter(a=>!r.has(a)),i=await gm(n),s=new Map(i.map(a=>[a.port,a]));return o.map(a=>s.get(a)??{port:a,service:nc[a]||`Port ${a}`,available:!0})}async function Wn(){try{return await xt("git",["--version"]),"success"}catch{return"error"}}async function ic(){try{return await xt("mise",["--version"]),"success"}catch{return"missing"}}async function sc(){if((await import("node:os")).platform()==="win32")try{return await xt("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await xt("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function gm(e){let t=await import("node:net"),r=[],o=n=>new Promise(i=>{let s=t.createServer();s.once("error",()=>i(!1)),s.once("listening",()=>{s.close(()=>i(!0))}),s.listen(n)});for(let n of e){let i=nc[n]||`Port ${n}`;if(await o(n))r.push({port:n,service:i,available:!0});else{let a=await hm(n),c=await Sm(n+1,n+100,o);r.push({port:n,service:i,available:!1,usedBy:a,alternative:c||void 0})}}return r}async function hm(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:o}=await xt("netstat",["-ano","-p","TCP"]),n=o.trim().split(`
35
+ `);for(let i of n)if(i.includes(`:${e}`)&&i.includes("LISTENING")){let s=i.trim().split(/\s+/),a=s[s.length-1];if(a)try{let{stdout:c}=await xt("tasklist",["/FI",`PID eq ${a}`,"/FO","CSV","/NH"]);return c.trim().split(",")[0]?.replace(/"/g,"")||`PID ${a}`}catch{return`PID ${a}`}}}catch{}return}try{let{stdout:o}=await xt("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),n=o.trim().split(`
36
+ `);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function Sm(e,t,r){for(let o=e;o<=t;o++)if(await r(o))return o;return null}var wm="https://get.docker.com",bm="https://orbstack.dev",Em="https://docs.docker.com/desktop/install/mac-install/",xm={git:"Git",docker:"Docker"},Yn="prerequisite_install_confirm",It="missingPrerequisites";function Cm(){return Kn.existsSync("/usr/bin/apt-get")||Kn.existsSync("/etc/debian_version")}function Ct(e,t,r){e.updateData("checks",{...e.currentState.data.checks,[t]:r})}function Xn(e){return e.map(t=>xm[t]).join(" and ")}function Im(){throw Er.platform()==="darwin"?new Error(`GAIA runs in Docker, which isn't installed yet.
37
+ \u2022 OrbStack (lightweight): ${bm}
38
+ \u2022 Docker Desktop: ${Em}
39
+ Install either, open it, then run this command again.`):new Error(`GAIA runs in Docker, which isn't installed yet. Install it from ${Re.docker}, then run this command again.`)}async function km(e,t,r){if(r.assumeYes)return;let o=Xn(t);if(!pe())throw new Error(`GAIA needs ${o}, and there is no terminal to ask before installing.
40
+ Rerun with --yes to install them, or install them first:
41
+ `+t.map(i=>` ${Re[i]}`).join(`
42
+ `));for(let i of t)Ct(e,i,"missing");if(e.updateData(It,t),await e.waitForInput(Yn)!=="install")throw new Error(`GAIA needs ${o}. Install ${t.length>1?"them":"it"}, then run this command again:
43
+ `+t.map(i=>` ${Re[i]}`).join(`
44
+ `))}async function Rm(e){e.setStatus("Installing Git\u2026");let t=ht("git-install");try{await Mt("apt-get",["update"],t),await Mt("apt-get",["install","-y","git"],t)}catch(r){throw new Error(`Git installation failed: ${r.message}
45
+ Install it by hand following ${Re.git}, then run this command again.`)}if(await Wn()!=="success")throw new Error(`Git was installed but 'git --version' still fails. Install it by hand following ${Re.git}, then run this command again.`)}function Tm(e){return e.includes("Executing docker install script")?"Starting Docker's installer":e.startsWith("+ ")?e.includes("docker-ce")?"Installing Docker":e.includes("apt-get")&&e.includes("update")?"Updating the package list":e.includes("gpg")||e.includes("docker.asc")?"Adding Docker's package source":e.includes("apt-get")&&e.includes("install")?"Installing what Docker needs":e.includes("systemctl")?"Starting Docker":null:null}async function Pm(e){let t=cc.join(Er.tmpdir(),"gaia-docker-install.sh"),r=ht("docker-install"),o=n=>e.setStatus(`${n}\u2026`);o("Downloading Docker's installer"),await ym("curl",["-fsSL",wm,"-o",t]);try{await Mt("sh",[t],r,n=>{let i=Tm(n);i&&o(i)})}catch(n){throw new Error(`Docker installation failed: ${n.message}
46
+ Install it by hand following ${Re.docker}, then run this command again.`)}}async function ac(e,t,r){Ct(e,t,"pending");try{let o=await r();return Ct(e,t,"success"),o}catch(o){throw Ct(e,t,"error"),o}}async function Am(e,t){if(t==="no-permission")return e.setStatus("Giving your user access to Docker (the docker group)\u2026"),await Cs(),e.updateData("dockerGroupSwitch",await Is()),e.setStatus("Docker access granted. Continuing with it\u2026"),"relaunch";if(t!=="ready")throw await St(t);return"ready"}async function So(e,t){let r=t.needGit&&await Wn()!=="success",o=await Q(),n=[];r&&n.push("git"),o==="not-installed"&&n.push("docker");let i=Er.platform()==="linux"&&Cm();if(r&&!i)throw Ct(e,"git","error"),new Error(`GAIA needs Git, which isn't installed. Install it from ${Re.git}, then run this command again.`);if(o==="not-installed"&&!i&&(Ct(e,"docker","error"),Im()),n.length>0)try{await km(e,n,t)}catch(s){for(let a of n)Ct(e,a,"error");throw s}return t.needGit&&await ac(e,"git",async()=>{r&&await Rm(e)}),ac(e,"docker",async()=>(o==="not-installed"&&(await Pm(e),e.setStatus("Docker installed. Checking that it runs\u2026"),o=await Q()),Am(e,o)))}var X=e=>new Promise(t=>setTimeout(t,e)),vo=(e,t="dependencyLogs")=>r=>{let o=e.currentState.data[t]||[],n=r.split(`
47
+ `).filter(i=>i.trim()!=="");e.updateData(t,[...o,...n].slice(-wr))};function lc(e){return(t,r)=>{e.updateData("dependencyPhase",t.label),e.updateData("dependencyProgress",t.percent),e.updateData("dependencyLogs",r.slice(-wr))}}async function yo(e){e.updateData("checks",{git:"pending"}),await X(500);try{return await So(e,{needGit:!0})==="ready"}catch(t){return e.setError(t),!1}}async function wo(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await ic();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise\u2026"),t=await sc()?"success":"error",e.updateData("checks",{...e.currentState.data.checks,mise:t})),t==="error"?(e.setError(new Error(`Developer mode requires Mise but it failed to install.
48
+ \u2022 Mise: ${Re.mise}`)),null):"success"}async function Yt(e,t){e.setStatus("Checking Ports\u2026");let r=await ho(t),o={},n=r.filter(i=>!i.available);if(n.length>0){let i=n.filter(a=>!a.alternative);if(i.length>0)return e.setError(new Error(`Cannot find free alternative ports for: ${i.map(a=>`${a.port} (${a.service})`).join(", ")}. Free these ports and try again.`)),null;if(e.updateData("portConflicts",r),await e.waitForInput("port_conflicts")==="abort")return e.setError(new Error("Port conflicts not resolved. Please free the ports and try again.")),null;for(let a of r)!a.available&&a.alternative&&(o[a.port]=a.alternative)}return e.updateData("portOverrides",o),e.setStatus("Git and Docker are ready"),await X(1e3),o}async function uc(e,t,r,o){e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration\u2026"),await J("mise",["trust"],t,void 0,o),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools\u2026"),await J("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},o),e.updateData("dependencyPhase","Running mise setup\u2026");let n=Object.keys(r).length>0?We(r):void 0;return await J("mise",["setup"],t,i=>{e.updateData("dependencyProgress",50+i*.5)},o,n),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0),!0}catch(n){return e.setError(new Error(`Failed to setup project: ${n.message}`)),!1}}import{createInterface as pc}from"node:readline/promises";import{Writable as _m}from"node:stream";async function Je(e,t){let r=pc({input:process.stdin,output:process.stdout});try{let o=t?` [${t}]`:"";return(await r.question(`${e}${o}: `)).trim()||t||""}finally{r.close()}}var dc=4,bo="\x1B",Dm="",Om=new Set(["\x7F","\b"]),$m=new RegExp(`${bo}\\[[0-9;]*[A-Za-z~]`,"g");function Lm(e){let t=e.length>dc*2?dc:0;return"\u2022".repeat(e.length-t)+e.slice(e.length-t)}async function Eo(e){if(process.stdout.write(`${e}
49
+ \u203A `),!process.stdin.isTTY){let t=pc({input:process.stdin,output:new _m({write:(r,o,n)=>n()})});try{return(await t.question("")).trim()}finally{t.close()}}return new Promise(t=>{let r="",o=(i,s)=>{process.stdin.off("data",n),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`\r\u203A ${s}${bo}[K
50
+ `),t(i)},n=i=>{let s=i.toString("utf-8").replace($m,"");if(s===Dm&&(o("",""),process.stdout.write(`\u25A0 Cancelled \xB7 nothing changed.
51
+ `),process.exit(130)),s===bo){o("","");return}for(let a of s){if(a==="\r"||a===`
52
+ `){o(r.trim(),Lm(r.trim()));return}Om.has(a)?r=r.slice(0,-1):a>=" "&&(r+=a)}process.stdout.write(`\r\u203A ${"\u2022".repeat(r.length)}${bo}[K`)};process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",n)})}async function Ze(e,t=!0){let r=await Je(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function xo(e,t){for(process.stdout.write(`
13
53
  ${e}
14
54
  `),t.forEach((r,o)=>{process.stdout.write(` ${o+1}. ${r}
15
- `)});;){let r=await me(`Choose 1-${t.length}`),o=Number.parseInt(r,10)-1;if(o>=0&&o<t.length)return o;process.stdout.write(`Invalid choice, try again.
16
- `)}}function gn(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function hn(e){let t=[],r="",o=null;for(let a of e.trim())o?a===o?o=null:r+=a:a==='"'||a==="'"?o=a:/\s/.test(a)?r&&(t.push(r),r=""):r+=a;r&&t.push(r);let[n,...i]=t;if(!n)throw new Error("Empty command");return{command:n,args:i}}function vn(e,t){let o=[...t].reverse().filter(n=>!n.startsWith("-"))[0]??e;return Rr(o).replace(/@[^@]*$/,"")}function Sn(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function Dr(e){for(;;){let t=await me("Name for this server",e),r=gn(t);if(!t||!r||r===ye){console.info("Pick a different name.");continue}if(!(q().servers.some(o=>o.key===r)&&!await _e(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function yn(e,t){if(Rr(e)!=="docker")return[];let r=[];for(let o=0;o<t.length;o++){let n=t[o];if(n!==void 0)if(n==="-e"||n==="--env"){let i=t[o+1];i&&!i.includes("=")&&r.push(i)}else n.startsWith("-e")&&n.length>2&&!n.includes("=")&&r.push(n.slice(2))}return[...new Set(r)]}async function Pr(e){let t=process.env[e];if(t!==void 0&&t!==""&&await _e(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await Er(` Paste ${e}`);if(r)return console.info(` Got it (${r.length} characters).`),r;console.info(" Empty \u2014 paste the value, or Ctrl+C to abort.")}}async function kr(e,t){let r={};for(let n of yn(e,t))console.info(`
17
- The command needs ${n}.`),r[n]=await Pr(n);let o=Object.keys(r).length?"Any other environment variables to add?":"Does the server need environment variables (API keys, tokens\u2026)?";if(!await _e(o,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let n=(await me(" Variable name")).trim();if(!n)break;if(n in r){console.info(" Already added.");continue}r[n]=await Pr(n)}return r}async function xn(){console.info(`
18
- Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await me("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=hn(e),o=await kr(t,r),{name:n,key:i}=await Dr(vn(t,r));return{type:"stdio",key:i,name:n,command:t,args:r,env:o}}async function wn(){let e=await me("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");let{name:t,key:r}=await Dr(Sn(e));return{type:"url",key:r,name:t,url:e}}async function bn(e){for(;;){console.info(`
19
- Testing the connection (this may download/start the server)\u2026`);try{let t=await Tr(e),r=t.slice(0,5).join(", ");return console.info(`Connected \u2014 ${t.length} tools found${r?` (${r}${t.length>5?", \u2026":""})`:""}.`),!0}catch(t){console.error(`Connection failed: ${t instanceof Error?t.message:t}`);let r=["Retry the test"];e.type==="stdio"&&r.push("Re-enter environment variables"),r.push("Save anyway (fix it later)","Abort");let o=r[await It("What now?",r)];if(o==="Re-enter environment variables"&&e.type==="stdio")e.env=await kr(e.command,e.args);else{if(o==="Save anyway (fix it later)")return!0;if(o==="Abort")return!1}}}}async function _r(){gr()||(console.info("This device isn't paired with GAIA yet \u2014 let's do that first."),await Ye());let t=await It("How does your MCP server run?",["A command starts it (stdio) \u2014 npx / uvx / docker / python \u2026","It's already running at a local URL \u2014 e.g. http://localhost:3000/mcp"])===0?await xn():await wn();if(!await bn(t))throw new Error("aborted");Ue(t),console.info(`
20
- Saved '${t.key}'.`),await _e("Connect to GAIA now (gaia bridge up)?")?await Ke():console.info("Run `gaia bridge up` whenever you're ready.")}function En(e){return e==="~"?Ar():e.startsWith("~/")?Tn(Ar(),e.slice(2)):e}function Pn(e,t){let r=e.map(o=>Cn(En(o)));Ue({type:"filesystem",key:ye,name:"Local Files",allow:r,allowWrite:t}),console.info(`Filesystem access configured for:
55
+ `)});;){let r=await Je(`Choose 1-${t.length}`),o=Number.parseInt(r,10)-1;if(o>=0&&o<t.length)return o;process.stdout.write(`Invalid choice, try again.
56
+ `)}}import Mm from"wrap-ansi";var Fm=40;function kt(e,t=0){let r=process.stdout.isTTY?process.stdout.columns:void 0;return!r||r-t<Fm?e:Mm(e,r-t,{hard:!0}).split(`
57
+ `).join(`
58
+ ${" ".repeat(t)}`)}var Nm={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},Bm=12e4,Gm=3e3,mc={telegram:[{key:"token",flag:"--token",label:"Telegram bot token",hint:"In Telegram, message @BotFather, send /newbot and copy the token it replies with."}],discord:[{key:"token",flag:"--token",label:"Discord bot token",hint:"At https://discord.com/developers/applications open your app > Bot > Reset Token. Turn on Message Content Intent on the same page."}],slack:[{key:"token",flag:"--token",label:"Slack bot token (xoxb-)",hint:"At https://api.slack.com/apps open your app > OAuth & Permissions > Bot User OAuth Token."},{key:"appToken",flag:"--app-token",label:"Slack app-level token (xapp-)",hint:"Turn on Socket Mode, then Basic Information > App-Level Tokens: create one with the connections:write scope."},{key:"signingSecret",flag:"--signing-secret",label:"Slack signing secret",hint:"Basic Information > App Credentials > Signing Secret."}]};function me(e=""){process.stdout.write(`${e}
59
+ `)}function zn(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Rt={telegram:"Telegram",discord:"Discord",slack:"Slack"},Um=3;async function jm(e,t){let r={...t};for(let o of mc[e]){if(r[o.key])continue;if(!pe())throw new Error(`Missing ${o.flag}. ${o.hint}`);me(),me(kt(o.hint));let n=await Eo(o.label);if(!n)throw new Error(`No ${o.label} entered. Nothing changed.`);r[o.key]=n}return r}async function qm(e,t){for(let r=1;;r++){let o=await jm(e,t);me(`Checking your ${Rt[e]} credentials\u2026`);try{return await Hm(e,o)}catch(n){let i=mc[e].some(a=>!t[a.key]),s=Um-r;if(!i||!pe()||s===0)throw n;me(`${b.fail} ${n.message} Paste ${s===1?"it":"them"} again (${s} ${s===1?"try":"tries"} left), or press Esc to stop.`)}}}async function Qn(){let e=_();if(!e||await N(e)!=="selfhost")throw new Error("No self-host GAIA install found. Run 'gaia up' first; chat bots run alongside it.");return e}async function Hm(e,t){let r=zn(t.token,"--token");if(e==="telegram"){let s=await Ja(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${za(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await Za(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${Xa(s)}`,"Then run /auth in Discord to link your GAIA account."]}}let o=zn(t.appToken,"--app-token"),n=zn(t.signingSecret,"--signing-secret"),i=await ec(r,o);return{botsEnv:{SLACK_BOT_TOKEN:r,SLACK_APP_TOKEN:o,SLACK_SIGNING_SECRET:n},handle:i.url,nextSteps:[`Running in the ${i.name} workspace. Run /auth in Slack to link your GAIA account.`]}}async function Vm(e){let t=le.selfhost,r=Date.now()+Bm;for(;;){let o=gr(e,await gt(t));if(o.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Rt[e]} bot did not come up (${o.detail}). See why with 'docker compose -p ${t} logs ${ue(e)}'; 'gaia bots remove ${e}' undoes the setup.`);await X(Gm)}}async function fc(e){await oe(e,"selfhost",t=>me(t),F(e),void 0,{pull:"missing"})}async function gc(e,t){let r=await Qn(),o=await qm(e,t);hr(r,{set:o.botsEnv}),Jr(r,{set:{[Tn[e]]:o.handle}});let n=$()?.bots??[];n.includes(e)||Se({bots:[...n,e]}),await fc(r);let i=Nm[e];i&&(me(`Registering the ${Rt[e]} bot's commands\u2026`),await fa(r,ue(e),i)),me(`Waiting for the ${Rt[e]} bot to connect\u2026`),await Vm(e),me(`${b.ok} The ${Rt[e]} bot is running`);for(let s of o.nextSteps)me(s)}async function hc(e){let t=await Qn(),r=$()?.bots??[];if(!r.includes(e))throw new Error(`The ${Rt[e]} bot is not enabled. See 'gaia bots list'.`);Se({bots:r.filter(o=>o!==e)}),hr(t,{unset:Hs[e]}),Jr(t,{unset:[Tn[e]]}),await fc(t),me(`${b.ok} The ${Rt[e]} bot is stopped and its credentials are deleted`)}async function Sc(){await Qn();let e=$()?.bots??[];if(e.length===0){me("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await gt(le.selfhost);for(let r of e)me(` ${r.padEnd(10)}${gr(r,t).detail}`)}function vc(){return new Wm("<platform>","chat platform").choices(qs)}var Cr=new Km("bots").description(G.bots).hook("preAction",()=>wt()).addHelpText("after",`
60
+ Examples:
61
+ gaia bots add telegram (asks for the token from @BotFather)
62
+ gaia bots add telegram --token <token from @BotFather>
63
+ gaia bots add discord --token <bot token>
64
+ gaia bots add slack --token xoxb-... --app-token xapp-... --signing-secret <secret>
65
+ `);Cr.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(vc()).option("--token <token>","Bot token (Slack: the xoxb- bot user token)").option("--app-token <token>","Slack: app-level token (xapp-)").option("--signing-secret <secret>","Slack: the app's signing secret").action(async(e,t)=>{await de(()=>gc(e,t))});Cr.command("list").alias("ls").description("Show the enabled bots and whether each is running").action(async()=>{await de(Sc)});Cr.command("remove").alias("rm").description("Stop a bot and delete its saved credentials").addArgument(vc()).action(async e=>{await de(()=>hc(e))});import{Command as rg}from"commander";import{existsSync as Ao,mkdirSync as hf,readFileSync as Pc,writeFileSync as ai}from"node:fs";import{homedir as Tc}from"node:os";import{join as ci}from"node:path";import{sep as Ym}from"node:path";var U={PING:"ping",MCP_OPEN:"mcp.open",MCP_CLOSE:"mcp.close",MCP_MSG:"mcp.msg",REVOKE:"revoke",SERVER_REMOVE:"server.remove",PONG:"pong",HELLO:"hello",MCP_OPENED:"mcp.opened",MCP_ERROR:"mcp.error",EXEC_OPEN:"exec.open",EXEC_STDOUT:"exec.stdout",EXEC_STDERR:"exec.stderr",EXEC_EXIT:"exec.exit"},Jn="https://api.heygaia.io",Tt="filesystem",Co=Ym,Zn=500,ei=6e4,ti=5e3,ri=1e6,oi=5e6,Io=9e4,ko=1e6;import{homedir as Xm}from"node:os";import{join as zm}from"node:path";var Qm={info:e=>console.error(e),error:e=>console.error(e)},ni={},Jm=null;function z(){return Jm??Qm}function Te(){return{stateDir:ni.stateDir??zm(Xm(),".gaia","bridge"),env:ni.env??process.env,shell:ni.shell??process.env.SHELL??"/bin/sh"}}import{Client as lf}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as uf,StdioClientTransport as df}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as pf}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as mf}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as Zm,readdir as Ec,readFile as yc,realpath as ef,stat as tf,writeFile as rf}from"node:fs/promises";import{dirname as wc,extname as of,join as xc,resolve as nf,sep as ii}from"node:path";import{McpServer as sf}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as Xt}from"zod";var af={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},zt=class extends Error{};async function si(e){try{return await ef(e)}catch{return null}}async function cf(e){try{return(await Zm(e)).isSymbolicLink()}catch{return!1}}function bc(e,t){return t===ii?e.startsWith(ii):e===t||e.startsWith(t+ii)}async function Ro(e,t,r){let o=nf(e),n=await si(o);if(n){if(t.some(s=>bc(n,s)))return n;throw new zt(`Path is outside your approved folders: ${e}`)}if(r)throw new zt(`No such file or directory: ${e}`);let i=await si(wc(o));if(!i||!t.some(s=>bc(i,s)))throw new zt(`Path is outside your approved folders: ${e}`);if(await cf(o))throw new zt(`Refusing to write through a symlink: ${e}`);return xc(i,o.slice(wc(o).length+1))}async function Cc(e,t,r,o){if(o.length>=r)return;let n;try{n=await Ec(e,{withFileTypes:!0})}catch{return}for(let i of n){if(o.length>=r)return;let s=xc(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&o.push(s),i.isDirectory()&&!i.isSymbolicLink()&&await Cc(s,t,r,o)}}function Ic(e){let t=new sf({name:"gaia-filesystem",version:"0.1.0"}),r=null,o=()=>(r||(r=Promise.all(e.allow.map(si)).then(i=>i.filter(s=>s!==null))),r),n=i=>({isError:!0,content:[{type:"text",text:i}]});return t.registerTool("list_directory",{description:"List the entries (files and folders) in a directory on the user's machine.",inputSchema:{path:Xt.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let s=await Ro(i,await o(),!0);return{content:[{type:"text",text:(await Ec(s,{withFileTypes:!0})).map(l=>`${l.isDirectory()?"dir ":"file"} ${l.name}`).join(`
66
+ `)||"(empty)"}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),t.registerTool("read_file",{description:"Read the contents of a text or image file on the user's machine.",inputSchema:{path:Xt.string().describe("Absolute path to a file")}},async({path:i})=>{try{let s=await Ro(i,await o(),!0),a=await tf(s);if(!a.isFile())return n(`Not a file: ${i}`);let c=af[of(s).toLowerCase()];if(c){if(a.size>oi)return n(`Image is too large to read (${a.size} bytes).`);let d=await yc(s);return{content:[{type:"text",text:`Image file ${s} (${c}, ${a.size} bytes) \u2014 shown below.`},{type:"image",data:d.toString("base64"),mimeType:c}]}}return a.size>ri?n(`File is too large to read (${a.size} bytes).`):{content:[{type:"text",text:await yc(s,"utf-8")}]}}catch(s){return n(s instanceof Error?s.message:String(s))}}),t.registerTool("search_files",{description:"Recursively find files/folders whose name contains a query, under a directory.",inputSchema:{path:Xt.string().describe("Absolute path to the directory to search under"),query:Xt.string().describe("Substring to match against names")}},async({path:i,query:s})=>{try{let a=await Ro(i,await o(),!0),c=[];return await Cc(a,s,200,c),{content:[{type:"text",text:c.join(`
67
+ `)||"(no matches)"}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),e.allowWrite&&t.registerTool("write_file",{description:"Write text to a file on the user's machine (overwrites if it exists).",inputSchema:{path:Xt.string().describe("Absolute path to the file to write"),content:Xt.string().describe("Text content to write")}},async({path:i,content:s})=>{try{let a=await Ro(i,await o(),!1);return await rf(a,s,"utf-8"),{content:[{type:"text",text:`Wrote ${s.length} bytes to ${i}`}]}}catch(a){return n(a instanceof Error?a.message:String(a))}}),t}var ff=new Set(["localhost","127.0.0.1","::1"]),kc=5;function et(e){let t=new URL(e);if(t.protocol!=="http:"&&t.protocol!=="https:")throw new Error(`url servers must be http(s), got ${t.protocol}`);let r=t.hostname.replace(/^\[|\]$/g,"");if(!ff.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function gf(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function Rc(e,t){let r=gf(e),o={...t,redirect:"manual"};for(let n=0;;n++){let i=await fetch(r,o);if(i.status<300||i.status>=400)return i;let s=i.headers.get("location"),a=s?new URL(s,r.href):null;if(await i.body?.cancel(),!a||a.origin!==r.origin)throw new Error(`refusing ${i.status} redirect to ${s??"(no location)"} \u2014 an MCP server must be addressed directly, not via a redirect`);if(n>=kc)throw new Error(`too many redirects (>${kc}) \u2014 refusing to follow`);r=a,o={...t,redirect:"manual"}}}async function To(e){if(e.type==="url"){let n=et(e.url),i=new pf(n,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:Rc});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let n=Te().env,i=new df({command:e.command,args:e.args,env:{...uf(),...n.PATH!==void 0?{PATH:n.PATH}:{},...n.HOME!==void 0?{HOME:n.HOME}:{},...e.env}});return{transport:i,close:()=>i.close()}}let[t,r]=mf.createLinkedPair(),o=Ic(e);return await o.connect(r),{transport:t,close:async()=>{await o.close(),await t.close()}}}async function Po(e){let t=await To(e),r=new lf({name:"gaia-bridge-test",version:"0.1.0"});try{await r.connect(t.transport);let{tools:o}=await r.listTools();return o.map(n=>n.name)}finally{try{await r.close(),await t.close()}catch{}}}function li(){return Te().stateDir}function ui(){return ci(li(),"credentials.json")}function Ac(){return ci(li(),"config.json")}function _c(){let e=li();Ao(e)||hf(e,{recursive:!0,mode:448})}function Pe(){let e=ui();if(!Ao(e))return null;try{return JSON.parse(Pc(e,"utf-8"))}catch{return null}}function Ir(e){_c(),ai(ui(),JSON.stringify(e,null,2),{mode:384})}function kr(){let e=ui();Ao(e)&&ai(e,"{}",{mode:384})}function Z(){let e=Ac();if(!Ao(e))return{servers:[]};try{return{servers:JSON.parse(Pc(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function Dc(e){_c(),ai(Ac(),JSON.stringify(e,null,2),{mode:384})}function _o(e){e.type==="url"&&et(e.url);let t=Z(),r=t.servers.findIndex(o=>o.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),Dc(t)}function Rr(e){let t=Z(),r=t.servers.length;return t.servers=t.servers.filter(o=>o.key!==e),Dc(t),t.servers.length<r}function di(e){return e==="~"?Tc():e.startsWith("~/")?ci(Tc(),e.slice(2)):e}function pi(e,t){return{type:"filesystem",key:Tt,name:"Local Files",allow:e,allowWrite:t}}function Tr(e){if(e)return e.replace(/\/$/,"");let t=Pe();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??Jn).replace(/\/$/,"")}import{hostname as yf,platform as wf}from"node:os";var Oc="x-request-id";function Sf(e){if(!e||typeof e!="object")return;let{message:t,code:r}=e;if(!(typeof t!="string"&&typeof r!="string"))return e}var be=class e extends Error{status;envelope;body;requestId;constructor(t,r,o={}){super(t,o.cause===void 0?void 0:{cause:o.cause}),this.name="ApiError",this.status=r,this.envelope=o.envelope,this.body=o.body??"",this.requestId=o.requestId}get code(){let t=this.envelope?.code;return typeof t=="string"?t:void 0}static fromBody(t,r,o={}){let n=Sf(r),i=n?.message??o.fallbackMessage??`API request failed: ${t}`;return new e(i,t,{envelope:n,body:typeof r=="string"?r:JSON.stringify(r??""),requestId:o.requestId,cause:o.cause})}};async function $c(e){if(!e.ok){let t=await e.text(),r=t;try{r=JSON.parse(t)}catch{}throw be.fromBody(e.status,r,{fallbackMessage:`${e.status} ${e.statusText}`,requestId:e.headers.get(Oc)??void 0})}return await e.json()}async function Do(e,t,r,o){let n=await fetch(`${e}/api/v1${t}`,{method:"POST",headers:{"content-type":"application/json",...o?{authorization:`Bearer ${o}`}:{}},body:JSON.stringify(r)});return $c(n)}async function vf(e,t,r){let o=await fetch(`${e}/api/v1${t}`,{method:"DELETE",headers:{authorization:`Bearer ${r}`}});return $c(o)}function mi(e,t,r,o){return Do(e,"/device/pair/start",{name:t,platform:r,daemon_version:o})}function fi(e,t){return Do(e,"/device/pair/poll",{device_code:t})}function gi(e,t){return Do(e,"/device/token",{refresh_token:t})}function hi(e,t,r,o,n){return Do(e,"/device/servers",{server_key:r,display_name:o,kind:n},t)}function Lc(e,t,r){return vf(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function bf(e){await new Promise(t=>setTimeout(t,e))}function Si(){return!!Pe()?.refreshToken}async function Mc(e,t){let r=Tr(t.api),o=t.name||yf(),n=await mi(r,o,wf(),t.daemonVersion);e.onPrompt(n.verification_url,n.user_code),e.onStatus?.("Waiting for approval\u2026");let i=Date.now()+n.expires_in*1e3;for(;Date.now()<i;){await bf(n.interval*1e3);let s;try{s=await fi(r,n.device_code)}catch(a){z().error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(s.status==="approved"&&s.device_id&&s.refresh_token){Ir({apiUrl:r,deviceId:s.device_id,refreshToken:s.refresh_token}),e.onStatus?.(`
68
+ Paired as "${o}".
69
+ `);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var Ef={onPrompt(e,t){console.info(`
70
+ To pair this device, open:
71
+ `),console.info(` ${e}`),console.info(`
72
+ and enter this code: ${t}
73
+ `)},onStatus(e){console.info(e)}};async function xf(){let e=_();if(!(!e||await N(e)!=="selfhost"))return yt("selfhost",F(e))}async function Qt(e={}){let t=e.api??(process.env.GAIA_API_URL?void 0:await xf());await Mc(Ef,{...e,...t!==void 0?{api:t}:{},daemonVersion:O})}import{spawn as Gf}from"node:child_process";import{existsSync as yi,mkdirSync as Uf,openSync as jf,readFileSync as qf,unlinkSync as qc,writeFileSync as Hf}from"node:fs";import{homedir as Vf}from"node:os";import{join as wi}from"node:path";import{mkdirSync as Fc,readFileSync as Cf,rmSync as Nc,writeFileSync as If}from"node:fs";import{dirname as kf,join as Bc}from"node:path";var Rf=3e4,Tf=3e4,Pf=50,Af=e=>new Promise(t=>setTimeout(t,e));function Gc(){return Bc(Te().stateDir,"credentials.lock")}function _f(){return Bc(Gc(),"stamp")}async function Df(e){let t=Gc(),r=_f();Fc(kf(t),{recursive:!0});let o=Date.now()+Tf;for(;;){try{Fc(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let n=null;try{let i=Number(Cf(r,"utf-8"));n=Number.isFinite(i)?Date.now()-i:Number.POSITIVE_INFINITY}catch(i){i?.code!=="ENOENT"&&(n=Number.POSITIVE_INFINITY)}if(n===null||n<Rf){if(Date.now()>o)throw new Error("another gaia process is rotating the device credential \u2014 try again");await Af(Pf);continue}try{Nc(t,{recursive:!0,force:!0})}catch{}}try{return If(r,String(Date.now()),{mode:384}),await e()}finally{try{Nc(t,{recursive:!0,force:!0})}catch{}}}async function Pr(){return Df(async()=>{let e=Pe();if(!e?.refreshToken)throw new be("not paired \u2014 run: gaia bridge login",401);let t=await gi(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return Ir(r),{creds:r,accessToken:t.access_token}})}async function Jt(){let e=Z().servers;if(e.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");let{creds:t,accessToken:r}=await Pr();await Promise.all(e.map(o=>hi(t.apiUrl,r,o.key,o.name,o.type)))}async function vi(e){let t=Rr(e);try{let{creds:r,accessToken:o}=await Pr();await Lc(r.apiUrl,o,e)}catch(r){z().info(`[gaia bridge] removed '${e}' locally; the cloud will reconcile on next connect (${r instanceof Error?r.message:String(r)})`)}return t}import{randomInt as Bf}from"node:crypto";import jc from"ws";import{spawn as Of}from"node:child_process";import{appendFileSync as $f,mkdirSync as Lf}from"node:fs";import{homedir as Mf}from"node:os";import{join as Ff}from"node:path";function Nf(e,t){try{let r=Te().stateDir;Lf(r,{recursive:!0,mode:448});let o=t?` (cwd: ${t})`:"";$f(Ff(r,"exec-audit.log"),`${new Date().toISOString()}${o} $ ${e}
74
+ `)}catch{}}async function Uc(e,t,r){Nf(e,t);let o=Of(Te().shell,["-c",e],{cwd:t||Mf(),env:Te().env,stdio:["ignore","pipe","pipe"]}),n=0,i=!1,s=c=>l=>{if(i)return;let d=ko-n,p=l.length>d?l.subarray(0,d):l;p.length>0&&(n+=p.length,r[c](p.toString("utf-8"))),n>=ko&&(i=!0,r.stderr(`
75
+ [gaia bridge] output truncated \u2014 cap reached
76
+ `),o.kill("SIGKILL"))};o.stdout.on("data",s("stdout")),o.stderr.on("data",s("stderr"));let a=setTimeout(()=>{r.stderr(`
77
+ [gaia bridge] killed \u2014 exceeded ${Io/1e3}s timeout
78
+ `),o.kill("SIGKILL")},Io);await new Promise(c=>{o.on("error",l=>{clearTimeout(a),r.stderr(`[gaia bridge] could not start command: ${l.message}
79
+ `),r.exit(127),c()}),o.on("close",l=>{clearTimeout(a),r.exit(l??-1),c()})})}var Ar=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=Zn;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof be&&t.status===401?(z().error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):z().error(`[gaia bridge] connection error: ${t instanceof Error?t.message:t}`)}if(this.stopped)break;await this.backoff()}}async stop(){this.stopped=!0,await this.closeAllSessions(),this.ws?.close()}async connectOnce(){let{creds:t,accessToken:r}=await Pr();this.creds=t;let o=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,n=new jc(o,{headers:{authorization:`Bearer ${r}`}});this.ws=n,await new Promise((i,s)=>{let a=!1,c=!1,l=d=>{c||(c=!0,d())};n.on("open",()=>{a=!0,this.reconnectDelay=ti;let d=Z().servers.map(p=>p.key);this.send({t:U.HELLO,servers:d}),z().info(`[gaia bridge] connected \u2014 exposing: ${d.join(", ")||"(nothing configured)"}`)}),n.on("message",d=>{this.guardRejection(this.onFrame(d.toString()),"frame handler error")}),n.on("close",()=>{this.guardRejection(this.closeAllSessions(),"session cleanup error"),this.ws=null,l(()=>a?i():s(new Error("socket closed before open")))}),n.on("error",d=>{a||l(()=>s(d))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case U.PING:this.send({t:U.PONG});return;case U.MCP_OPEN:await this.openSession(r);return;case U.MCP_MSG:await this.forwardToServer(r);return;case U.MCP_CLOSE:await this.closeSession(r.sid);return;case U.EXEC_OPEN:await this.runExec(r);return;case U.REVOKE:z().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case U.SERVER_REMOVE:r.key&&Rr(r.key)&&z().info(`[gaia bridge] removed server '${r.key}' (deleted in GAIA).`);return;default:return}}async openSession(t){let r=t.sid,o=t.server,n=t.pod;if(!r||!o)return;let i=Z().servers.find(a=>a.key===o);if(!i){this.send({t:U.MCP_ERROR,sid:r,pod:n,error:`Unknown server '${o}'`});return}let s=Date.now();z().info(`[gaia bridge] opening MCP session for '${o}'\u2026`);try{let a=await To(i);a.transport.onmessage=c=>{this.send({t:U.MCP_MSG,sid:r,pod:n,data:JSON.stringify(c)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:U.MCP_ERROR,sid:r,pod:n,error:`Local server '${o}' exited`}),this.guardRejection(this.closeSession(r),"session close error")},await a.transport.start(),this.sessions.set(r,a),this.send({t:U.MCP_OPENED,sid:r,pod:n}),z().info(`[gaia bridge] MCP session for '${o}' ready in ${Date.now()-s}ms`)}catch(a){let c=a instanceof Error?a.message:String(a);z().error(`[gaia bridge] MCP session for '${o}' failed after ${Date.now()-s}ms: ${c}`),this.send({t:U.MCP_ERROR,sid:r,pod:n,error:c})}}async forwardToServer(t){let r=t.sid?this.sessions.get(t.sid):void 0;if(!(!r||!t.data))try{let o=JSON.parse(t.data);await r.transport.send(o)}catch(o){z().error(`[gaia bridge] forward error: ${o instanceof Error?o.message:o}`)}}async runExec(t){let r=t.sid,o=t.pod,n=t.command;!r||!n||await Uc(n,t.cwd,{stdout:i=>this.send({t:U.EXEC_STDOUT,sid:r,pod:o,data:i}),stderr:i=>this.send({t:U.EXEC_STDERR,sid:r,pod:o,data:i}),exit:i=>this.send({t:U.EXEC_EXIT,sid:r,pod:o,code:i})})}async closeSession(t){if(!t)return;let r=this.sessions.get(t);if(r){this.sessions.delete(t);try{await r.close()}catch{}}}async closeAllSessions(){let t=[...this.sessions.keys()];await Promise.all(t.map(r=>this.closeSession(r)))}send(t){this.ws?.readyState===jc.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(o=>{z().error(`[gaia bridge] ${r}: ${o instanceof Error?o.message:o}`)})}async backoff(){let t=Bf(this.reconnectDelay);z().info(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,ei)}};var bi=wi(Vf(),".gaia","bridge"),Pt=wi(bi,"daemon.pid"),Hc=wi(bi,"daemon.log");function Ei(){if(!yi(Pt))return null;let e=Number(qf(Pt,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function Vc(){let e=Ei();return e?`Tunnel: running in the background (pid ${e}) \u2014 stop with: gaia bridge down`:"Tunnel: not running \u2014 start with: gaia bridge up"}function Wc(){let e=Ei();if(!e){yi(Pt)&&qc(Pt),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}yi(Pt)&&qc(Pt),console.info(`Stopped the bridge tunnel (pid ${e}).`)}async function Oo(){let e=Ei();if(e){console.info(`Bridge tunnel is already running (pid ${e}) \u2014 it already serves your configured servers, including any you just added. Nothing else to do.`);return}console.error("[gaia bridge] connected: GAIA can run commands and access files on this machine.");let t=Z().servers.filter(s=>s.type==="url"&&s.headers&&Object.keys(s.headers).length>0);t.length>0&&console.error(`[gaia bridge] forwarding request headers (credentials) to ${t.length} local url server(s).`);try{await Jt()}catch(s){if(s instanceof be&&s.status===401)console.error(`[gaia bridge] this device is no longer authorized (revoked or unpaired). Let's re-pair.
80
+ `),kr(),await Qt(),await Jt();else throw s}let r=process.argv[1];if(!r)throw new Error("cannot locate the gaia CLI entrypoint to start the daemon");Uf(bi,{recursive:!0,mode:448});let o=jf(Hc,"a"),n={detached:!0,stdio:["ignore",o,o]},i=Gf(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],n);i.unref(),Hf(Pt,String(i.pid??""),{mode:384}),console.info(`
81
+ Bridge tunnel started in the background (pid ${i.pid}).
82
+ Logs: ${Hc}
83
+ Stop: gaia bridge down`)}async function Kc(){let e=Pe();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new Ar(e),r=async()=>{await t.stop(),process.exit(0)};process.on("SIGINT",()=>void r()),process.on("SIGTERM",()=>void r()),await t.run()}import{basename as Qc}from"node:path";import{resolve as Wf}from"node:path";function xi(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function Ci(e){let t=[],r="",o=null;for(let s of e.trim())o?s===o?o=null:r+=s:s==='"'||s==="'"?o=s:/\s/.test(s)?r&&(t.push(r),r=""):r+=s;r&&t.push(r);let[n,...i]=t;if(!n)throw new Error("Empty command");return{command:n,args:i}}function Yc(e,t,r){let o={};for(let n of e??[]){let i=n.indexOf(t);if(i<=0)throw new Error(`invalid ${r} '${n}', expected KEY${t}VALUE`);o[n.slice(0,i).trim()]=n.slice(i+1)}return o}function Xc(e){let t=xi(e??"");if(!e||!t||t===Tt)throw new Error("--name is required and must contain letters or digits");return t}function zc(e){if(e.type==="stdio"){if(!e.command)throw new Error("--command is required for --type stdio");let{command:t,args:r}=Ci(e.command);return{type:"stdio",key:Xc(e.name),name:e.name,command:t,args:r,env:Yc(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");et(e.url);let t=Yc(e.header,":","--header");return Object.keys(t).length>0&&new URL(e.url).protocol==="http:"&&console.warn("warning: --header values travel unencrypted over local HTTP \u2014 prefer an https: URL for credential headers"),{type:"url",key:Xc(e.name),name:e.name,url:e.url,...Object.keys(t).length?{headers:t}:{}}}if(e.type==="filesystem"){let t=e.path??[];if(t.length===0)throw new Error("--path is required for --type filesystem");let r=t.includes(Co)?[Co]:t.map(o=>Wf(di(o)));return pi(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}function Kf(e,t){let o=[...t].reverse().filter(n=>!n.startsWith("-"))[0]??e;return Qc(o).replace(/@[^@]*$/,"")}function Yf(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function Jc(e){for(;;){let t=await Je("Name for this server",e),r=xi(t);if(!t||!r||r===Tt){console.info("Pick a different name.");continue}if(!(Z().servers.some(o=>o.key===r)&&!await Ze(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function Xf(e,t){if(Qc(e)!=="docker")return[];let r=[];for(let o=0;o<t.length;o++){let n=t[o];if(n!==void 0)if(n==="-e"||n==="--env"){let i=t[o+1];i&&!i.includes("=")&&r.push(i)}else n.startsWith("-e")&&n.length>2&&!n.includes("=")&&r.push(n.slice(2))}return[...new Set(r)]}async function Ii(e){let t=process.env[e];if(t!==void 0&&t!==""&&await Ze(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await Eo(` Paste ${e}`);if(r)return console.info(` Got it (${r.length} characters).`),r;console.info(" Empty \u2014 paste the value, or Ctrl+C to abort.")}}async function Zc(e,t){let r={};for(let n of Xf(e,t))console.info(`
84
+ The command needs ${n}.`),r[n]=await Ii(n);let o=Object.keys(r).length?"Any other environment variables to add?":"Does the server need environment variables (API keys, tokens\u2026)?";if(!await Ze(o,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let n=(await Je(" Variable name")).trim();if(!n)break;if(n in r){console.info(" Already added.");continue}r[n]=await Ii(n)}return r}async function zf(){console.info(`
85
+ Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await Je("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=Ci(e),o=await Zc(t,r),{name:n,key:i}=await Jc(Kf(t,r));return{type:"stdio",key:i,name:n,command:t,args:r,env:o}}async function Qf(){let e={};if(!await Ze("Does the server need request headers (e.g. Authorization)?",!1))return e;for(console.info("Enter each header's name; leave blank when done.");;){let t=(await Je(" Header name")).trim();if(!t)break;if(t in e){console.info(" Already added.");continue}e[t]=await Ii(t)}return e}async function Jf(){let e=await Je("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");et(e);let t=await Qf();if(Object.keys(t).length>0&&new URL(e).protocol==="http:"&&(console.info(`
86
+ Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await Ze("Send these headers over unencrypted HTTP anyway?",!1)))throw new Error("aborted \u2014 use an https: URL or drop the headers");let{name:r,key:o}=await Jc(Yf(e));return{type:"url",key:o,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function Zf(e){for(;;){console.info(`
87
+ Testing the connection (this may download/start the server)\u2026`);try{let t=await Po(e),r=t.slice(0,5).join(", ");return console.info(`Connected \u2014 ${t.length} tools found${r?` (${r}${t.length>5?", \u2026":""})`:""}.`),!0}catch(t){console.error(`Connection failed: ${t instanceof Error?t.message:t}`);let r=["Retry the test"];e.type==="stdio"&&r.push("Re-enter environment variables"),r.push("Save anyway (fix it later)","Abort");let o=r[await xo("What now?",r)];if(o==="Re-enter environment variables"&&e.type==="stdio")e.env=await Zc(e.command,e.args);else{if(o==="Save anyway (fix it later)")return!0;if(o==="Abort")return!1}}}}async function eg(e){let t=zc(e),r;try{r=await Po(t)}catch(o){throw new Error(`Could not start '${t.key}': ${o instanceof Error?o.message:o}`)}_o(t),await Jt(),console.info(`Saved '${t.key}' (${r.length} tools) and registered with GAIA. A running 'gaia bridge up' daemon serves it automatically; otherwise start one.`)}async function el(e={}){if(!Si()){if(e.type)throw new Error("This device isn't paired yet. Run `gaia bridge login` on it first.");console.info("This device isn't paired with GAIA yet, let's do that first."),await Qt()}if(e.type){await eg(e);return}let r=await xo("What do you want to connect?",["A command starts an MCP server (stdio) \u2014 npx / uvx / docker / python \u2026","An MCP server already running at a local URL \u2014 e.g. http://localhost:3000/mcp"])===0?await zf():await Jf();if(!await Zf(r))throw new Error("aborted");_o(r),console.info(`
88
+ Saved '${r.key}'.`);try{await Jt(),console.info("Registered with GAIA.")}catch(o){console.error(`Could not register with GAIA (will retry on \`gaia bridge up\`): ${o instanceof Error?o.message:o}`)}await Ze("Keep this device connected in the background now?")?await Oo():console.info("Run `gaia bridge up` whenever you're ready.")}function tg(e){let t=e.type==="url"?e.url:e.type==="stdio"?e.command:e.allow.join(", ");return`${e.name} \u2014 ${e.type} (${t})`}async function tl(e){if(e){let n=await vi(e);console.info(n?`Removed '${e}' from this device and GAIA.`:`No server '${e}'.`);return}let t=Z().servers;if(t.length===0){console.info("No servers configured \u2014 nothing to remove.");return}let r=await xo("Which server do you want to remove?",t.map(tg)),o=t[r];if(o){if(!await Ze(`Remove '${o.key}'?`,!1)){console.info("Left it in place.");return}await vi(o.key),console.info(`Removed '${o.key}'. The tunnel stops serving it right away, and GAIA drops it too.`)}}function og(){let e=Pe();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${Tr()})`:"Not paired \u2014 run: gaia bridge login"),console.info(Vc());let t=Z().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
89
+ Configured servers:`);for(let r of t)if(r.type==="filesystem")console.info(` [${r.key}] filesystem${r.allowWrite?" (rw)":" (ro)"}: ${r.allow.join(", ")}`);else if(r.type==="stdio"){let o=Object.keys(r.env);console.info(` [${r.key}] ${r.name}: ${r.command} ${r.args.join(" ")}`),o.length&&console.info(` env: ${o.join(", ")}`)}else{console.info(` [${r.key}] ${r.name}: ${r.url}`);let o=r.headers?Object.keys(r.headers):[];o.length&&console.info(` headers: ${o.join(", ")}`)}}var Ue=new rg("bridge").description(G.bridge).addHelpText("after",`
90
+ Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);Ue.command("add").description("Connect a local MCP server (guided; or non-interactive with --type)").option("--type <type>","stdio | url \u2014 enables non-interactive mode (no prompts)").option("--name <name>","display name").option("--command <command>","stdio: the command that starts the server").option("--url <url>","url: the local MCP server URL").option("--env <pair...>","stdio: KEY=VALUE env var (repeatable)").option("--header <pair...>","url: Header:Value request header (repeatable)").action(async e=>{await de(()=>el(e))});Ue.command("login").description("Pair this machine with your GAIA account").option("--api <url>","GAIA API base URL (default: this machine's self-host install, else GAIA Cloud)").option("--name <name>","Name to show for this device in Settings").action(async e=>{await de(async()=>{await Qt({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});Ue.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await de(og)});Ue.command("remove").alias("rm").description("Remove a configured server (interactive picker if no key given)").argument("[key]","Server key from `gaia bridge ls` (optional)").action(async e=>{await de(()=>tl(e))});Ue.command("up").alias("start").description("Connect with full file access + serve in the background (stop with: gaia bridge down)").option("--serve","(internal) hold the tunnel in the foreground; used by the background daemon").action(async e=>{await de(e.serve?Kc:Oo)});Ue.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await de(Wc)});Ue.command("logout").description("Forget local credentials").action(async()=>{await de(()=>{kr(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import{Command as ug}from"commander";import{createHash as ig}from"node:crypto";import*as fe from"node:fs/promises";import*as cl from"node:path";import*as ol from"node:os";import*as nl from"node:path";var ng="https://github.com/theexperiencecompany/gaia/releases/download",$o=`cli-v${O}`,ki="gaia-connect-SHA256SUMS",rl={"darwin-arm64":"gaia-connect-darwin-arm64","darwin-x64":"gaia-connect-darwin-amd64","linux-x64":"gaia-connect-linux-amd64","linux-arm64":"gaia-connect-linux-arm64","win32-x64":"gaia-connect-windows-amd64.exe"};function il(e,t){let r=rl[`${e}-${t}`];if(r===void 0)throw new Error(`gaia connect is not available for ${e}/${t}. Supported: ${Object.keys(rl).join(", ")}.`);return r}function Ri(e){return`${ng}/${$o}/${e}`}function sl(e){let t=e==="win32"?".exe":"";return nl.join(ol.homedir(),".gaia","bin",`gaia-connect-${O}${t}`)}async function al(e){let t=await fetch(e);if(!t.ok)throw new Error(`Download failed (${t.status} ${t.statusText}): ${e}`);return Buffer.from(await t.arrayBuffer())}function sg(e,t){for(let r of e.split(`
91
+ `)){let[o,...n]=r.trim().split(/\s+/);if(n.join(" ").replace(/^\*/,"")===t&&o!==void 0)return o.toLowerCase()}throw new Error(`${ki} on release ${$o} has no entry for ${t}.`)}function ag(e){return ig("sha256").update(e).digest("hex")}async function cg(e){try{return await fe.access(e),!0}catch{return!1}}async function ll(e,t){let r=sl(e);if(await cg(r))return r;let o=il(e,t);console.info(`Downloading gaia-connect (${$o})\u2026`);let[n,i]=await Promise.all([al(Ri(o)),al(Ri(ki)).then(l=>l.toString("utf-8"))]),s=sg(i,o),a=ag(n);if(a!==s)throw new Error(`Checksum mismatch for ${o}: expected ${s}, got ${a}. Refusing to run the download.`);await fe.mkdir(cl.dirname(r),{recursive:!0});let c=`${r}.${process.pid}.tmp`;try{await fe.writeFile(c,n),e!=="win32"&&await fe.chmod(c,448),await fe.rename(c,r)}catch(l){throw await fe.rm(c,{force:!0}),l}return r}import{spawn as lg}from"node:child_process";async function ul(e,t){return await new Promise((r,o)=>{let n=lg(e,t,{stdio:"inherit",shell:!1}),i=s=>{n.kill(s)};process.on("SIGINT",i),process.on("SIGTERM",i),n.on("error",s=>{process.off("SIGINT",i),process.off("SIGTERM",i),o(s)}),n.on("close",(s,a)=>{if(process.off("SIGINT",i),process.off("SIGTERM",i),a==="SIGINT"||a==="SIGTERM"){r(0);return}r(s??1)})})}async function dg(e){let t=await ll(process.platform,process.arch);return await ul(t,e)}var dl=new ug("connect").description(G.connect).allowUnknownOption().allowExcessArguments().argument("[args...]","flags forwarded to gaia-connect").addHelpText("after",`
92
+ Get an import code from GAIA -> Settings -> Browser -> Import, then run:
93
+ npx @heygaia/cli connect --token <code>
94
+
95
+ Flags forwarded to gaia-connect:
96
+ --token <code> single-use import code from GAIA
97
+ --api <origin> GAIA API base URL (default https://api.heygaia.io)
98
+ --browser <name> browser name (skips the picker)
99
+ --profile <name> profile name or directory (skips the picker)
100
+ --sites <domains> comma-separated domains to sync (default: all)
101
+ --json robot mode: no TUI, structured JSON on stdout
102
+ --list with --json: list browsers, or sessions with --browser
103
+ `).action(async e=>{try{process.exit(await dg(e))}catch(t){console.error(`Error: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}});import*as Mo from"fs";import*as pl from"path";import{spawn as pg}from"child_process";async function Zt(e,t,r,o,n,i=!1){await Lo([{cmd:e,args:t,cwd:r,env:o,onSpawn:n,detached:i}])}async function Lo(e){e.length!==0&&await new Promise((t,r)=>{let o=e.map(p=>pg(p.cmd,p.args,{cwd:p.cwd,stdio:"inherit",shell:!1,detached:p.detached??!1,env:p.env?{...process.env,...p.env}:process.env}));o.forEach((p,m)=>{e[m]?.onSpawn?.(p.pid)});let n=!1,i=0,s=!1,a,c=()=>{process.off("SIGINT",d),process.off("SIGTERM",d)},l=()=>{if(!s){s=!0;for(let[p,m]of o.entries()){let g=e[p];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGTERM"):m.kill("SIGTERM")}catch{}}a=setTimeout(()=>{for(let[p,m]of o.entries()){let g=e[p];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGKILL"):m.kill("SIGKILL")}catch{}}},1e3)}},d=()=>{l()};process.on("SIGINT",d),process.on("SIGTERM",d),o.forEach((p,m)=>{let g=e[m];p.on("error",v=>{n||(n=!0,c(),l(),r(v))}),p.on("close",(v,E)=>{if(i+=1,!(v===0||(E==="SIGINT"||E==="SIGTERM"||v===130||v===143||s))&&!n){n=!0,c(),l(),r(new Error(`Command failed with code ${String(v)}: ${g?.cmd??"unknown"} ${g?.args.join(" ")??""}`));return}i>=o.length&&!n&&(n=!0,c(),a&&clearTimeout(a),t())})})})}async function ml(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=qt();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await N(t);if(!r)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");if(r!=="developer")throw new Error("Developer mode is not enabled for this repo. Use 'gaia start' for self-host mode.");let o=pl.join(t,no);try{await Zt("mise",[e==="full"?"dev:full":"dev"],t,void 0,n=>{typeof n=="number"&&n>0&&Mo.writeFileSync(o,`${n}
104
+ `)},process.platform!=="win32")}finally{try{Mo.unlinkSync(o)}catch{}}}import Pg,{Chalk as Ag}from"chalk";import*as gl from"node:fs";import*as At from"node:os";import{execa as fl}from"execa";var mg={mongodb:{service:"mongo",cause:"a full disk is the usual cause; users, chats and settings live here"},postgres:{service:"postgres",cause:"a full disk is the usual cause; agent state lives here"},redis:{service:"redis",cause:"background jobs and reminders queue here and wait until it is back"},rabbitmq:{service:"rabbitmq",cause:"it takes up to a minute to boot after a restart, so rerun first"},chromadb:{service:"chromadb",cause:"memory and file search stay unavailable until it answers"}};function fg(e,t){let r=mg[e];return r?`Check its logs: docker compose -p ${t} logs ${r.service} (${r.cause}).`:`Check the API logs: docker compose -p ${t} logs gaia-backend`}async function Fo(e,t){let r;try{r=await fetch(`${e}/health/ready`,{signal:AbortSignal.timeout(5e3)})}catch(n){return{reachable:!1,detail:`Could not reach ${e}/health/ready: ${n.message}`}}if(!r.ok&&r.status!==503)return{reachable:!1,detail:`HTTP ${r.status} from ${e}/health/ready`};let o=await r.json();return{reachable:!0,ready:o.status==="ready",dependencies:o.dependencies.map(n=>n.ok?n:{...n,fix:fg(n.name,t)})}}var gg=2*1024*1024*1024,hg=4*1024*1024*1024,Sg=2*1024*1024*1024,hl={"gaia-selfhost":["chromadb","postgres","redis","mongo","rabbitmq","gaia-backend","gaia-web","arq_worker","proxy"],"gaia-dev":["chromadb","postgres","redis","mongo","rabbitmq"]};function Ti(e){return e==="running"?"running":e==="restarting"?"restarting":"stopped"}function vg(e,t){return t.every(r=>e.some(o=>o.service===r&&Ti(o.state)==="running"))}function yg(e,t){return t.map(r=>({service:r,info:e.find(o=>o.service===r)})).filter(({info:r})=>!r||Ti(r.state)!=="running").map(({service:r,info:o})=>o?`${r} ${Ti(o.state)}`:`${r} missing`).join(", ")}function Sl(e,t){return e[t]??t}async function vl(e,t={}){let r={id:"port-conflict",label:"Ports",severity:"blocker"},o;try{o=await ho(e,t)}catch{return{...r,state:"skipped",detail:"Could not check ports"}}let n=o.filter(s=>!s.available);if(n.length===0)return{...r,state:"ok",detail:"no conflicts"};let i=n.map(s=>`:${s.port} in use by ${s.usedBy??"unknown"}`).join(", ");return{...r,state:"fail",detail:i,fix:e==="selfhost"?"Free the port or re-run 'gaia up' with --web-port (or set WEB_HOST_PORT in infra/docker/.env).":"Free the port or set its *_HOST_PORT override in infra/docker/.env."}}function wg(e){return`Open http://localhost:${e}/setup in your browser to finish setting GAIA up.`}function bg(e,t,r){let n=[{label:"LLM provider configured",configured:t.some(i=>e.providers?.[i]?.configured===!0),missing:"no AI provider yet"},{label:"admin account created",configured:e.has_admin_account===!0,missing:"no admin account yet"}];return e.deployment.bills&&n.push({label:"plans seeded",configured:e.plans_seeded,missing:"billing plans not set up yet"}),n.map(i=>({...i,fix:i.configured?"":wg(r)}))}function Eg(e){let r=e.trim().split(`
105
+ `).filter(i=>i.trim().length>0).at(-1);if(!r)return null;let o=r.trim().split(/\s+/),n=Number(o[3]);return!Number.isFinite(n)||n<0?null:n}async function yl(e){let t={id:"docker-daemon",label:"Docker",severity:"blocker"};if(e==="ready")return{...t,state:"ok",detail:"running"};let r=await Me(e);return{...t,state:"fail",detail:r.state,fix:r.fix}}async function wl(e){let t={id:"compose-containers",label:"Containers",severity:"blocker"},r;try{r=await gt(e.project)}catch{return{...t,state:"skipped",detail:"they need Docker"}}return vg(r,e.expected)?{...t,state:"ok",detail:`${e.expected.length} services running`}:{...t,state:"fail",detail:yg(r,e.expected),fix:`Run 'gaia start' to bring the stack up, or check 'docker compose -p ${e.project} logs'.`}}function bl(e){let t={id:"compose-containers",label:"GAIA",severity:"blocker",state:"fail"};return e?{...t,detail:`${e} isn't set up yet (no apps/api/.env)`,fix:"Run 'gaia up' to finish setting it up, or 'gaia setup' for a development checkout."}:{...t,detail:"isn't installed yet",fix:vn}}async function El(e,t="gaia start"){let r={id:"api-health",label:"API",severity:"blocker"};try{let o=await ao(`${e}/ping`);return o.ok?{...r,state:"ok",detail:`answering at ${e}`}:{...r,state:"fail",detail:`answered HTTP ${o.status} at ${e}/ping`,fix:`See why with 'gaia logs', then restart it with '${t}'.`}}catch{return{...r,state:"fail",detail:`not answering at ${e}`,fix:`Start GAIA with '${t}'.`}}}async function xl(e){let t={id:"dependencies",label:"Dependencies",severity:"blocker"};if(!e.apiHealthy)return[{...t,state:"skipped",detail:"they need GAIA's API"}];let r=await Fo(e.origin,e.project);return r.reachable?r.dependencies.map(o=>({id:`dependency-${o.name}`,label:Zr(o.name),severity:"blocker",state:o.ok?"ok":"fail",detail:o.ok?`${Math.round(o.latency_ms)} ms`:`${o.error_type??"failed"} after ${Math.round(o.latency_ms)} ms`,fix:o.fix})):[{...t,state:"fail",detail:r.detail,fix:"Run 'gaia update': an API or proxy older than this CLI does not serve /health/ready."}]}async function Cl(e,t="gaia start"){let r={id:"web-reachable",label:"Web app",severity:"blocker"};try{let o=await ao(`http://localhost:${e}`,{method:"HEAD"});return o.ok?{...r,state:"ok",detail:`answering at http://localhost:${e}`}:{...r,state:"fail",detail:`answered HTTP ${o.status} at http://localhost:${e}`,fix:`See why with 'gaia logs', then restart it with '${t}'.`}}catch{return{...r,state:"fail",detail:`not answering at http://localhost:${e}`,fix:`Start GAIA with '${t}'.`}}}async function Il(e){let t={id:"setup-readiness",label:"Setup",severity:"warning"};if(!e.apiHealthy)return[{...t,state:"skipped",detail:"they need GAIA's API"}];let[r,o]=await Promise.all([ke(e.apiUrl,"status"),ke(e.apiUrl,"catalog")]);if("detail"in r)return[{...t,state:"skipped",detail:r.detail}];if("detail"in o)return[{...t,state:"skipped",detail:o.detail}];let n=bg(r.data,o.data.llm_provider_keys,e.webPort);if(n.every(s=>s.configured))return[{...t,state:"ok",detail:"finished"}];let i=n.filter(s=>!s.configured);return[{...t,state:"fail",detail:`not finished: ${i.map(s=>s.missing).join(", ")}`,fix:i[0]?.fix}]}async function Pi(e=gg){let t={id:"disk-headroom",label:"Disk space",severity:"blocker"},r;try{r=await ps()}catch{return{...t,state:"skipped",detail:"they need Docker"}}let o;try{let i=await ms(r),s=Eg(i);o=s===null?null:s*1024}catch{o=null}if(o===null)return{...t,state:"skipped",detail:`Could not read disk usage for ${r}`};let n=i=>`${(i/1024**3).toFixed(1)} GB`;return o>=e?{...t,state:"ok",detail:`${n(o)} free at ${r}`}:{...t,state:"fail",detail:`${n(o)} free at ${r}, need \u2265 ${n(e)}`,fix:"Free up disk space (e.g. 'docker system prune') before pulling/building images."}}function xg(e){let t=e.match(/^MemAvailable:\s+(\d+)\s+kB/m);if(t?.[1]){let o=Number(t[1]);if(Number.isFinite(o)&&o>=0)return o*1024}let r=e.match(/^MemTotal:\s+(\d+)\s+kB/m);if(r?.[1]){let o=Number(r[1]);if(Number.isFinite(o)&&o>=0)return o*1024}return null}function Cg(e){let t=e.match(/page size of (\d+) bytes/),r=t?.[1]?Number(t[1]):4096,o=e.match(/Pages free:\s+(\d+)/),n=e.match(/Pages inactive:\s+(\d+)/),i=e.match(/Pages speculative:\s+(\d+)/);if(!(o||n||i))return null;let s=l=>l?Number(l[1]):0,a=s(o),c=s(n);return!Number.isFinite(a)||!Number.isFinite(c)||!Number.isFinite(r)||r<=0?null:(a+c+s(i))*r}function Ai(e){try{return e()}catch{return null}}function Ig(){try{let e=gl.readFileSync("/proc/meminfo","utf-8"),t=xg(e);if(t!==null)return t}catch{}return Ai(()=>At.freemem())}async function kg(){try{let{stdout:e}=await fl("vm_stat",[]),t=Cg(e);if(t!==null)return t}catch{}try{let{stdout:e}=await fl("sysctl",["-n","hw.memsize"]),t=Number(e.trim());if(Number.isFinite(t)&&t>0)return t}catch{}return Ai(()=>At.totalmem())}async function Rg(){let e=At.platform();return e==="linux"?Ig():e==="darwin"?kg():Ai(()=>At.freemem())}async function _i(){let e=await Rg().catch(()=>null);if(e===null)return{id:"memory-headroom",label:"Memory",severity:"blocker",state:"skipped",detail:"Could not read available memory"};let t=r=>`${(r/1024**3).toFixed(1)} GB`;return e<Sg?{id:"memory-headroom",label:"Memory",severity:"blocker",state:"fail",detail:`${t(e)} free; GAIA needs at least 2 GB to start`,fix:"Close other apps or add RAM before starting GAIA."}:e<hg?{id:"memory-headroom",label:"Memory",severity:"warning",state:"fail",detail:`${t(e)} free; GAIA's API uses about 2.5 GB and may run out during chats`,fix:"Close other apps or add RAM."}:{id:"memory-headroom",label:"Memory",severity:"blocker",state:"ok",detail:`${t(e)} free`}}async function kl(e,t,r=uo){let o={id:"gaia-version",label:"GAIA version",severity:"warning"};if(!e)return{...o,state:"skipped",detail:"GAIA isn't installed"};if(t!=="selfhost")return{...o,state:"skipped",detail:"Developer checkout: update it with 'gaia update --git'"};let n=Ie(e);if(Qe(n)===null)return{...o,state:"ok",detail:`development build (${lo(n)})`};let i=await r();return i&&Be(i,n)?{...o,state:"fail",detail:`${i} is available (this install runs ${n})`,fix:"Run 'gaia update'. Your data and settings are kept."}:{...o,state:"ok",detail:n}}async function Rl(e,t){if(e.length===0)return[];let r;try{r=await gt(t)}catch{r=null}return e.map(o=>{let n={id:`bot-${o}`,label:Fe(ue(o)),severity:"warning"};if(!r)return{...n,state:"skipped",detail:"they need Docker"};let{health:i,detail:s}=gr(o,r);return i!=="failing"?{...n,state:"ok",detail:s}:{...n,state:"fail",detail:s,fix:`A rejected or revoked token keeps the bot restarting: check 'docker compose -p ${t} logs ${ue(o)}', then rerun 'gaia bots add ${o}' with a fresh token.`}})}function Tl(e){return e.results.some(t=>t.severity==="blocker"&&t.state==="fail")}async function Tg(){let e=_(),t=e?F(e):{},r=e?await N(e):null;return{repoPath:e,origin:yt(r??"selfhost",t),apiUrl:ne(r??"selfhost",t),webPort:Sl(t,3e3),overrides:t,mode:r,project:r?le[r]:null}}async function Pl(){let e=[],t=await Tg(),r=await Q();if(e.push(await yl(r)),e.push(r==="ready"?await vl(t.mode??"selfhost",t.overrides):{id:"port-conflict",label:"Ports",severity:"blocker",state:"skipped",detail:"they need Docker"}),!t.project||!t.mode){e.push(bl(t.repoPath));for(let i of["API","Setup","Web app"])e.push({label:i,severity:"blocker",state:"skipped",detail:"GAIA isn't installed"});return e.push(await Pi()),e.push(await _i()),{install:vr(t.repoPath,t.mode),installed:!1,results:e}}let o=t.mode==="developer"?"gaia dev":"gaia start";e.push(await wl({project:t.project,expected:hl[t.project]})),t.project===le.selfhost&&e.push(...await Rl($()?.bots??[],t.project));let n=await El(t.apiUrl,o);return e.push(n),e.push(...await xl({apiHealthy:n.state==="ok",origin:t.origin,project:t.project})),e.push(...await Il({apiHealthy:n.state==="ok",apiUrl:t.apiUrl,webPort:t.webPort})),e.push(await Cl(t.webPort,o)),e.push(await Pi()),e.push(await _i()),e.push(await kl(t.repoPath,t.mode)),{install:vr(t.repoPath,t.mode),installed:!0,results:e}}function tt(e=""){process.stdout.write(`${e}
106
+ `)}var Al=16,Oi=" ",ee=process.env.NO_COLOR!==void 0?new Ag({level:0}):Pg,_g={ok:ee.green,fail:ee.red,warn:ee.yellow,skip:ee.gray,pending:ee.gray,active:ee.cyan,cancelled:ee.yellow};function Dg(e){return e.state==="ok"?"ok":e.state==="skipped"?"skip":e.severity==="warning"?"warn":"fail"}var Di=Oi.length+2+Al;function Og(e,t){let r=Dg(e),o=e.detail?ee.gray(kt(e.detail,Di)):"";tt(`${Oi}${_g[r](b[r])} ${e.label.padEnd(Al)}${o}`),e.state==="fail"&&e.fix&&t?.fix!==e.fix&&tt(`${" ".repeat(Di)}${kt(e.fix,Di)}`)}function $g(e){let t=new Map;for(let r of e){let o=r.detail??"skipped";t.set(o,[...t.get(o)??[],r.label])}for(let[r,o]of t)tt(`${Oi}${ee.gray(b.skip)} ${ee.gray(`Not checked: ${o.join(", ")} (${r})`)}`)}function Lg(e){let t=e.results.filter(n=>n.severity==="blocker"&&n.state==="fail").length,r=e.results.filter(n=>n.severity==="warning"&&n.state==="fail").length;if(t===0&&r===0)return ee.green(`${b.ok} Everything checked out`);let o=[];return t>0&&o.push(ee.red(`${t} problem${t===1?"":"s"}`)),r>0&&o.push(ee.yellow(`${r} warning${r===1?"":"s"}`)),o.join(" \xB7 ")}function Mg(e){tt(),tt(e.installed?`${ee.bold("Checking")} ${e.install}`:ee.bold("Checking this computer")),tt();let t=e.results.filter(r=>r.state!=="skipped");t.forEach((r,o)=>{Og(r,t[o+1])}),$g(e.results.filter(r=>r.state==="skipped")),tt(),tt(Lg(e))}async function _l(){await wt();let e=await Pl();Mg(e),Tl(e)&&(process.exitCode=1)}import{render as uS}from"ink";import dS from"react";import{ThemeProvider as rS}from"@inkjs/ui";import{Box as Qo,Text as _t,useInput as oS}from"ink";import nS from"react";import{Box as De,Text as it}from"ink";import{Box as Fg,Text as Ng,useStdout as Bg}from"ink";import{useEffect as Gg,useState as Dl}from"react";import{jsx as Ol}from"react/jsx-runtime";var rt=({size:e="small",showStatus:t=!0,showUpdate:r=!0})=>{let{stdout:o}=Bg(),[n,i]=Dl(null),[s]=Dl(()=>r?mo():null);Gg(()=>{if(!t){i(null);return}let c=!0;return po().then(l=>{c&&i(l)}),()=>{c=!1}},[t]);let a=fo({size:e,level:qn(),...Hn(o),version:O,status:t?n:null,update:s});return Ol(Fg,{marginTop:1,marginBottom:1,children:Ol(Ng,{children:a.join(`
107
+ `)})})};import{Spinner as Wg}from"@inkjs/ui";import{Box as ot,Text as No}from"ink";import{useEffect as Kg,useState as Yg}from"react";import{Box as Ug,Text as jg}from"ink";import{jsx as $l}from"react/jsx-runtime";var ie=({kind:e})=>$l(Ug,{marginRight:1,children:$l(jg,{color:Ma[e],children:b[e]})});import{ProgressBar as qg}from"@inkjs/ui";import{Box as Ll,Text as Hg}from"ink";import{jsx as Ml,jsxs as Fl}from"react/jsx-runtime";var Vg=40,er=({percent:e})=>Fl(Ll,{children:[Ml(Ll,{width:Vg,children:Ml(qg,{value:e})}),Fl(Hg,{color:"gray",children:[" ",e,"%"]})]});import{jsx as K,jsxs as Nl}from"react/jsx-runtime";var Xg=40,zg=1e3;function Qg(e){let[t,r]=Yg(Date.now());return Kg(()=>{if(!e)return;let o=setInterval(()=>r(Date.now()),zg);return()=>clearInterval(o)},[e]),t}function Jg(e,t){return e.startedAt===void 0?"":Kt((e.endedAt??t)-e.startedAt)}var Zg=({step:e,waiting:t})=>e.state==="done"?K(ie,{kind:"ok"}):e.state==="failed"?K(ie,{kind:"fail"}):e.state==="active"&&!t?K(ot,{marginRight:1,children:K(Wg,{})}):K(ie,{kind:"pending"}),eh=({step:e,now:t,waiting:r,status:o})=>{let n=e.state==="active",i=e.state==="done"?e.doneLabel:e.label,s=e.detail??(n?o:void 0);return Nl(ot,{flexDirection:"column",children:[Nl(ot,{children:[K(Zg,{step:e,waiting:r}),K(ot,{width:Xg,children:K(No,{color:e.state==="pending"?"gray":void 0,bold:n,children:i})}),K(No,{color:"gray",children:Jg(e,t)})]}),n&&e.percent!==void 0&&K(ot,{marginLeft:2,children:K(er,{percent:e.percent})}),n&&s&&K(ot,{marginLeft:2,children:K(No,{color:"gray",wrap:"truncate",children:s})}),n&&e.hint&&K(ot,{marginLeft:2,children:K(No,{color:"gray",dimColor:!0,children:e.hint})})]})},Bl=({steps:e,waiting:t,status:r})=>{let o=Qg(e.some(n=>n.state==="active"));return K(ot,{flexDirection:"column",marginTop:1,children:e.map(n=>K(eh,{step:n,now:o,waiting:t,status:r},n.id))})};import{Spinner as Gl}from"@inkjs/ui";import{Box as j,Text as P,useInput as Ul}from"ink";import{useStdout as th}from"ink";var rh=100,oh=80;function Bo(){let{stdout:e}=th();return Math.min(e.columns||oh,rh)}import{jsx as x,jsxs as q}from"react/jsx-runtime";var Go=({checks:e})=>q(j,{flexDirection:"column",borderStyle:I,paddingX:1,borderColor:y,children:[x(P,{bold:!0,children:"System Checks"}),q(j,{flexDirection:"column",marginTop:1,children:[x($i,{label:"Git",status:e.git}),e.docker&&x($i,{label:"Docker",status:e.docker}),e.mise&&x($i,{label:"Mise",status:e.mise})]})]}),Uo=({status:e})=>q(j,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[x(P,{bold:!0,children:"Environment Setup"}),x(j,{marginTop:1,children:x(Gl,{label:e||"Configuring environment\u2026"})})]}),jl=({title:e,progress:t,phase:r})=>q(j,{flexDirection:"column",borderStyle:I,padding:1,borderColor:y,children:[x(P,{bold:!0,children:e}),q(j,{marginTop:1,flexDirection:"column",children:[x(er,{percent:t||0}),r&&x(P,{color:"gray",children:r})]})]}),Ae=({message:e})=>{let[t,...r]=e.split(`
108
+ `),o=Bo();return q(j,{flexDirection:"column",borderStyle:I,borderColor:"red",paddingX:1,marginTop:1,width:o,children:[q(j,{children:[x(ie,{kind:"fail"}),x(P,{bold:!0,children:t})]}),x(j,{flexDirection:"column",marginLeft:2,children:r.map(n=>x(P,{color:n.startsWith("Full log:")?"gray":void 0,children:n},n))})]})},nh={success:"ok",error:"fail",missing:"warn"},$i=({label:e,status:t})=>q(j,{children:[t==="pending"?x(j,{marginRight:1,children:x(Gl,{type:"dots"})}):x(ie,{kind:nh[t]}),x(P,{children:e})]}),tr=({portResults:e,onAccept:t,onAbort:r})=>{Ul((n,i)=>{i.return?t():i.escape&&r()});let o=e.filter(n=>!n.available);return q(j,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:"yellow",children:[x(j,{marginBottom:1,children:x(P,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>q(j,{children:[q(P,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?b.ok:n.alternative?b.warn:b.fail," "]}),q(P,{children:[n.service," (:",n.port,")"]}),!n.available&&q(P,{color:n.alternative?"gray":"red",children:[" ","- in use",n.usedBy?` by ${n.usedBy}`:"",n.alternative?` \u2192 will use :${n.alternative}`:" \u2014 NO ALTERNATIVE FOUND"]})]},n.port)),o.some(n=>!n.alternative)&&x(j,{marginTop:1,children:x(P,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!o.some(n=>!n.alternative)&&o.some(n=>n.alternative)&&x(j,{marginTop:1,children:x(P,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),x(j,{marginTop:1,children:q(P,{dimColor:!0,children:[x(P,{bold:!0,children:"Enter"})," continue \xB7 ",x(P,{bold:!0,children:"Esc"})," cancel"]})})]})},ih=({missing:e,onConfirm:t,onDecline:r})=>{Ul((i,s)=>{s.return&&t(),s.escape&&r()});let o=e.length>1?"them":"it",n=e.length>1?"aren't":"isn't";return q(j,{flexDirection:"column",marginTop:1,marginLeft:2,children:[q(P,{children:["GAIA needs ",x(P,{bold:!0,children:Xn(e)}),", which ",n," ","installed yet."]}),q(P,{children:["Install ",o," now? This uses sudo and takes a few minutes."]}),q(j,{marginTop:1,children:[x(P,{color:y,bold:!0,children:"Enter"}),q(P,{children:[" install ",o]}),x(P,{color:"gray",children:" \xB7 "}),x(P,{bold:!0,children:"Esc"}),x(P,{children:" I'll do it myself"})]})]})},rr=({inputId:e,missing:t,onConfirm:r,onDecline:o})=>e!==Yn||!t?.length?null:x(ih,{missing:t,onConfirm:r,onDecline:o});import{useEffect as sh,useState as ah}from"react";function _e(e){let[t,r]=ah(e.currentState);return sh(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),t}import*as Hl from"node:path";var Mi=["openrouter","gemini","openai","ollama","custom"],ch={openrouter:{key:"required",baseUrl:"unused",model:"unused"},gemini:{key:"required",baseUrl:"unused",model:"unused"},openai:{key:"required",baseUrl:"unused",model:"unused"},ollama:{key:"unused",baseUrl:"optional",model:"optional"},custom:{key:"required",baseUrl:"required",model:"required"}},jo={key:"--llm-key",baseUrl:"--llm-base-url",model:"--llm-model"};function Li(e,t){let r={key:e.llmKey,baseUrl:e.llmBaseUrl,model:e.llmModel}[t];return r!==void 0&&r!==""}function Vl(e){let t=Object.keys(jo);if(!e.llmProvider){let o=t.find(n=>Li(e,n));if(o)throw new Error(`${jo[o]} requires --llm-provider <${Mi.join("|")}>.`);return}let r=e.llmProvider;for(let o of t){let n=ch[r][o];if(n==="required"&&!Li(e,o))throw new Error(`--llm-provider ${r} requires ${jo[o]}.`);if(n==="unused"&&Li(e,o))throw new Error(`${jo[o]} is not used with --llm-provider ${r}.`)}if(e.noStart)throw new Error("--llm-provider saves the provider into the running instance, so it cannot be combined with --no-start. Drop --no-start, or configure the provider in the web setup wizard later.")}function lh(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var ql="GAIA_PROVIDER_API_KEY",_r={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},uh=/Could not save \w+: (.+)/;async function Wl(e,t){let r=Hl.join(e,"infra/docker");try{await J("docker",[...Mn(r),"exec","-T","-e",ql,"gaia-backend","python","-m","app.scripts.save_provider",...lh(t)],r,void 0,void 0,{[ql]:t.llmKey??""})}catch(o){let n=uh.exec(o.message)?.[1];throw n?new Error(n,{cause:o}):o}}var qo=[["gaia status","check health"],["gaia stop","stop GAIA"],["gaia doctor","find problems"],["gaia --help","all commands"]],dh="Your user was added to the 'docker' group. Other terminals get it after you log out and back in (or run 'newgrp docker'); until then, 'gaia status' there can't reach Docker.";function ph(e){return e.noStart?"GAIA is set up \xB7 nothing was started":e.stillStarting?"GAIA is still starting":e.startedServices===0?"GAIA is already running \xB7 nothing to do":`GAIA is running \xB7 ready in ${Kt(e.elapsedMs)}`}function mh(e){return e?"on, in local containers on this machine":"off \xB7 turn on: gaia up --code-sandbox, or add an E2B key in Settings"}function Ho(e){let t=[];if(e.noStart)t.push({label:"Next",text:"Start it with gaia start",tone:"primary"});else{e.stillStarting&&t.push({label:"Status",text:"It is still starting in the background. Check again with gaia status.",tone:"warn"});let r=`${e.webUrl}/setup`;t.push(e.setupComplete?{label:"Next",text:`Open ${e.webUrl}`,url:e.webUrl,tone:"primary"}:{label:"Next",text:`Open ${r} to create your admin account and pick an AI model.`,url:r,tone:"primary"});let o=e.reachableUrls.filter(n=>n!==e.webUrl);o.length>0&&t.push({label:"Also at",text:o.join(", "),tone:"dim"})}return e.savedProvider&&t.push({label:"AI",text:`${_r[e.savedProvider]} key saved \xB7 change it in Settings`}),t.push({label:"Code execution",text:mh(e.codeSandbox),tone:"dim"}),e.joinedDockerGroup&&t.push({label:"Docker",text:dh,tone:"warn"}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:ph(e),rows:t}}import{jsx as V,jsxs as nt}from"react/jsx-runtime";var fh=16,gh=14,Kl=30,hh={primary:void 0,warn:"yellow",dim:"gray"},Sh=({row:e})=>{let t=e.tone?hh[e.tone]:void 0;if(!e.url)return V(it,{color:t,children:e.text});let[r,o]=e.text.split(e.url);return nt(it,{color:t,children:[r,V(it,{color:"cyan",bold:!0,underline:!0,children:e.url}),o]})},vh=({outcome:e})=>{let t=Ho(e),r=t.tone==="success"?"green":y,o=Bo();return nt(De,{flexDirection:"column",marginTop:1,children:[nt(De,{flexDirection:"column",borderStyle:I,borderColor:r,paddingX:2,paddingY:1,width:o,children:[nt(it,{bold:!0,color:r,children:[t.tone==="success"?`${b.ok} `:"",t.headline]}),V(De,{flexDirection:"column",marginTop:1,children:t.rows.map(n=>nt(De,{marginBottom:n.tone==="primary"?1:0,children:[V(De,{width:fh,flexShrink:0,children:V(it,{bold:n.tone==="primary",children:n.label})}),V(Sh,{row:n})]},n.label))})]}),V(De,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:Kl*2+4,children:qo.map(([n,i])=>nt(De,{width:Kl,children:[V(De,{width:gh,children:V(it,{color:y,children:n})}),V(it,{color:"gray",children:i})]},n))})]})},yh=({state:e,store:t})=>e.inputRequest?.id==="port_conflicts"?e.data.portConflicts?V(tr,{portResults:e.data.portConflicts,onAccept:()=>t.submitInput("accept"),onAbort:()=>t.submitInput("abort")}):null:V(rr,{inputId:e.inputRequest?.id,missing:e.data[It],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),Yl=({store:e})=>{let t=_e(e),r=t.data.steps??[],o=t.data.upOutcome,n=t.data.logPath,i=t.data.finished===!0&&o!==void 0;return nt(De,{flexDirection:"column",width:"100%",children:[V(rt,{size:"large",showStatus:!1}),V(Bl,{steps:r,waiting:t.inputRequest!==null,status:t.status}),V(yh,{state:t,store:e}),n&&!i&&V(De,{marginTop:1,marginLeft:2,children:nt(it,{color:"gray",children:["Full log: ",n]})}),i&&V(vh,{outcome:o}),t.error&&V(Ae,{message:t.error.message})]})};import{Select as Bi,Spinner as _h}from"@inkjs/ui";import{Box as h,Text as f,useInput as or}from"ink";import Or from"ink-text-input";import{useEffect as Gi,useState as ce}from"react";import{Box as wh,Text as Fi,useInput as bh}from"ink";import{useEffect as Eh,useRef as xh,useState as Ch}from"react";import{jsx as Ih,jsxs as Ni}from"react/jsx-runtime";var Xl=8;function zl(e,t){return`${e} ${t}${e===1?"":"s"}`}var Vo=({logs:e})=>{let[t,r]=Ch(0),o=Math.min(e.length,Xl),n=e.length>Xl,i=xh(e.length);Eh(()=>{e.length!==i.current&&(i.current=e.length,r(0))},[e.length]),bh((c,l)=>{n&&(l.upArrow?r(d=>Math.min(d+1,e.length-o)):l.downArrow&&r(d=>Math.max(0,d-1)))});let s=Math.max(0,e.length-o-t),a=e.slice(s,s+o);return Ni(wh,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&Ni(Fi,{color:"gray",children:[zl(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>Ih(Fi,{color:"gray",wrap:"truncate",children:c},s+l)),t>0&&Ni(Fi,{color:"gray",children:[zl(t,"newer line")," (\u2193)"]})]})};import{Box as Dr,Text as Wo}from"ink";import{Box as kh,Text as Rh}from"ink";import{jsx as Ql}from"react/jsx-runtime";var Th=new Set(["Welcome","Finished"]),Jl=({status:e,step:t})=>Th.has(t)?null:Ql(kh,{width:"100%",paddingX:1,marginTop:1,children:Ql(Rh,{color:"gray",dimColor:!0,children:e})});import{jsx as st,jsxs as Ko}from"react/jsx-runtime";var Ph=[{id:"Welcome",label:"Welcome"},{id:"Prerequisites",label:"Prereqs"},{id:"Setup Mode",label:"Mode"},{id:"Repository Setup",label:"Repo"},{id:"Environment Setup",label:"Env"},{id:"Install Tools",label:"Tools"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Zl=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Ah=({currentStep:e,steps:t})=>{let r=t.findIndex(n=>n.id===e),o=r===t.length-1;return st(Dr,{marginBottom:1,flexWrap:"wrap",children:t.map(({id:n,label:i},s)=>{let a=s<r||o,c=s===r&&!o;return Ko(Dr,{flexShrink:0,children:[s>0&&st(Wo,{color:"gray",children:" \xB7 "}),a&&Ko(Wo,{color:"green",children:[b.ok," ",i]}),c&&st(Wo,{color:y,bold:!0,children:i}),!a&&!c&&st(Wo,{color:"gray",children:i})]},n)})})},Yo=({children:e,status:t,step:r,steps:o=Ph,header:n})=>Ko(Dr,{flexDirection:"column",height:"100%",width:"100%",children:[Ko(Dr,{flexGrow:1,flexDirection:"column",children:[st(rt,{...n}),st(Ah,{currentStep:r,steps:o}),st(Dr,{flexDirection:"column",flexGrow:1,children:e})]}),st(Jl,{status:t,step:r})]});import{jsx as u,jsxs as S}from"react/jsx-runtime";var Dh=({onConfirm:e})=>(or((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:y,children:[u(f,{bold:!0,children:"Welcome to GAIA Setup"}),S(h,{flexDirection:"column",marginTop:1,marginBottom:1,children:[u(f,{children:"This wizard will guide you through the setup process:"}),u(f,{children:" 1. Check prerequisites and choose setup mode"}),u(f,{children:" 2. Clone repository"}),u(f,{children:" 3. Configure environment variables"}),u(f,{children:" 4. Install tools and dependencies"})]}),u(f,{dimColor:!0,children:"~5-15 min depending on network speed"}),u(h,{marginTop:1,children:S(f,{color:y,children:[u(f,{bold:!0,children:"Enter"})," to start"]})})]})),Oh=({defaultValue:e,onSubmit:t})=>{let[r,o]=ce(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(f,{children:"Clone repository to:"}),u(f,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),S(h,{marginTop:1,children:[u(f,{color:y,children:"\u2192 "}),u(Or,{value:r,onChange:o,onSubmit:t})]})]})},$h=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:"yellow",children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),S(f,{children:["Found a GAIA installation at"," ",u(f,{color:"cyan",bold:!0,children:e})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"What would you like to do?"})}),u(h,{marginTop:1,children:u(Bi,{options:[{label:"Use existing installation",value:"use_existing"},{label:"Delete and re-clone",value:"delete_reclone"},{label:"Choose a different path",value:"different_path"},{label:"Exit setup",value:"exit"}],onChange:o=>t(o)})})]}),Lh=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:o})=>{or((s,a)=>{a.return&&o()});let n=t?.[3e3]??3e3,i=ne(e??"developer",t??{});return e==="selfhost"?S(h,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:"green",padding:1,children:[u(f,{bold:!0,color:"green",children:r?"GAIA is starting\u2026":"GAIA is running"}),u(h,{marginTop:1,children:u(f,{color:"green",children:r?"Containers are up but not answering yet":"\u2713 All services started"})}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Finish setup in your browser:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n,"/setup"]})]}),S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia doctor"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]}):S(h,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:y,padding:1,children:[u(f,{color:y,bold:!0,children:"You're all set!"}),S(h,{marginTop:1,children:[u(f,{bold:!0,children:"Run: "}),u(f,{color:"cyan",children:"$ gaia dev"})]}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]})},Ui=({phase:e,progress:t,isComplete:r,logs:o,title:n,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:y,children:n||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[u(h,{children:r?S(f,{color:"green",children:[b.ok," ",e]}):u(_h,{label:e||"Preparing\u2026"})}),!r&&t>0&&u(er,{percent:t}),!r&&o&&o.length>0&&u(Vo,{logs:o}),!r&&u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),ji=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(f,{bold:!0,children:"Setup Mode"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"How do you want to run GAIA?"})}),u(h,{marginTop:1,children:u(Bi,{options:[{label:"Self-Host \u2014 run everything in Docker",value:"selfhost"},{label:"Developer \u2014 local dev with hot reload",value:"developer"}],onChange:r=>e(r)})})]}),qi=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(f,{bold:!0,children:"Environment Variables Setup"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Choose how you want to configure environment variables:"})}),u(h,{marginTop:1,children:u(Bi,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),S(h,{marginTop:1,flexDirection:"column",children:[u(f,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),u(f,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),Hi=({onSubmit:e})=>{let[t,r]=ce({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=ce(0),[i,s]=ce(null),a=[{key:"INFISICAL_PROJECT_ID",description:"Found in your Infisical project settings"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_ID",description:"From Access Control \u2192 Machine Identities"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET",description:"Generated when creating the machine identity"}];or((l,d)=>{if(d.tab||d.downArrow)n(p=>p<a.length-1?p+1:p);else if(d.upArrow)n(p=>p>0?p-1:p);else if(d.return){if(o<a.length-1){n(m=>m+1);return}let p=a.filter(m=>!t[m.key].trim());if(p.length>0){s(`Required: ${p.map(g=>g.key).join(", ")}`);let m=a.findIndex(g=>!t[g.key].trim());m>=0&&n(m);return}e(t)}});let c=a[o];return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:y,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:y,children:"Infisical Configuration"})}),u(h,{marginBottom:1,children:u(f,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),S(h,{marginBottom:1,flexDirection:"column",children:[u(f,{color:"gray",children:"Configure your Infisical credentials."}),S(f,{color:"gray",dimColor:!0,children:["Visit"," ",u(f,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),a.map((l,d)=>{let p=l.key.includes("SECRET")||l.key.includes("TOKEN");return S(h,{flexDirection:"column",marginBottom:1,children:[u(h,{children:S(f,{color:d===o?y:"white",children:[d===o?"\u25B8 ":" ",l.key,":"]})}),u(h,{marginLeft:2,children:u(f,{color:"gray",dimColor:!0,children:l.description})}),d===o?u(h,{marginLeft:2,children:u(Or,{value:t[l.key],onChange:m=>{r(g=>({...g,[l.key]:m})),s(null)},placeholder:"Enter value\u2026",mask:p?"*":void 0})}):u(h,{marginLeft:2,children:u(f,{color:t[l.key]?"green":"gray",children:t[l.key]?p?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[l.key]}`:"(not set)"})})]},l.key)}),i&&u(h,{marginTop:1,children:u(f,{color:"red",children:i})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},Vi=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,i]=ce(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=ce(0),[c,l]=ce(null);Gi(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),or((m,g)=>{if(g.tab||g.downArrow)a(v=>v<e.variables.length-1?v+1:v);else if(g.upArrow)a(v=>v>0?v-1:v);else if(g.escape){let v=e.variables.filter(E=>E.required&&!n[E.name]?.trim());if(v.length>0){l(`Required fields cannot be skipped: ${v.map(E=>E.name).join(", ")}`);return}o(n)}});let d=()=>{if(s<e.variables.length-1)a(s+1);else{let m=e.variables.filter(g=>g.required&&!n[g.name]?.trim());if(m.length>0){l(`Required fields are missing: ${m.map(g=>g.name).join(", ")}`);return}l(null),o(n)}},p=e.variables.some(m=>m.required);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:c?"red":y,children:[S(h,{justifyContent:"space-between",children:[S(f,{bold:!0,children:["Configure ",e.name]}),S(f,{color:"gray",children:["Group ",t+1," / ",r]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:e.description})}),u(h,{marginTop:1,flexDirection:"column",children:e.variables.map((m,g)=>{let v=g===s,E=!!m.defaultValue;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:v?y:"gray",bold:v,children:[v?"\u279C ":" ",m.name]}),m.required&&S(f,{color:"red",bold:!0,children:[" ","*"]}),E&&!v&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),v&&u(h,{marginLeft:2,children:u(Or,{value:n[m.name]||"",onChange:w=>{i(C=>({...C,[m.name]:w})),c&&l(null)},onSubmit:d,placeholder:E?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[b.warn," ",c]})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," next \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate",!p&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Wi=({alternatives:e,onSubmit:t})=>{let[r,o]=ce(new Set),[n,i]=ce({}),[s,a]=ce(0),[c,l]=ce(null);Gi(()=>{let w={};for(let C of e)for(let M of C.variables)w[M.name]=M.defaultValue||"";i(w)},[e]);let d=[];for(let w=0;w<e.length;w++)if(d.push({type:"provider",categoryIndex:w}),r.has(w)){let C=e[w];if(C)for(let M=0;M<C.variables.length;M++)d.push({type:"field",categoryIndex:w,fieldIndex:M})}d.push({type:"submit"});let p=d[s],m=p?.type==="field",g=p?.type==="submit";or((w,C)=>{let M=Math.min(s,d.length-1);if(M!==s){a(M);return}if(m)C.upArrow?a(D=>Math.max(0,D-1)):(C.downArrow||C.tab)&&a(D=>Math.min(d.length-1,D+1));else if(g)C.upArrow?a(D=>Math.max(0,D-1)):(C.return||w===" ")&&E();else if(C.upArrow)a(D=>Math.max(0,D-1));else if(C.downArrow||C.tab)a(D=>Math.min(d.length-1,D+1));else if((C.return||w===" ")&&p?.type==="provider"){let D=p.categoryIndex;o(pt=>{let B=new Set(pt);return B.has(D)?B.delete(D):B.add(D),B}),c&&l(null)}});let v=()=>{c&&l(null),a(w=>Math.min(d.length-1,w+1))},E=()=>{let w=[],C={};for(let M of r){let D=e[M];if(!D)continue;if(D.variables.some(B=>n[B.name]?.trim())){w.push(D.name);for(let B of D.variables){let Gr=n[B.name];Gr&&(C[B.name]=Gr)}}}if(w.length===0){r.size===0?l("Enable at least one provider (press Space or Enter)"):l("Enter a value for at least one field");return}t(w,C)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:c?"red":y,children:[S(h,{justifyContent:"space-between",children:[u(f,{bold:!0,children:"Configure AI Provider"}),u(f,{color:"yellow",children:"* At least one required"})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),u(h,{marginTop:1,flexDirection:"column",children:e.map((w,C)=>{let M=r.has(C),D=d.findIndex(B=>B.type==="provider"&&B.categoryIndex===C),pt=s===D;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[u(f,{color:pt?y:void 0,bold:pt,children:pt?"\u279C ":" "}),u(f,{color:M?"green":"gray",children:M?`[${b.ok}]`:"[ ]"}),S(f,{color:M?y:"gray",bold:M,children:[" ",w.name]}),w.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",w.description]})]}),pt&&w.docsUrl&&S(h,{marginLeft:6,children:[u(f,{color:"yellow",children:"\u{1F4D6} "}),u(f,{color:"blue",underline:!0,children:w.docsUrl})]}),M&&u(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:w.variables.map((B,Gr)=>{let nd=d.findIndex(ar=>ar.type==="field"&&ar.categoryIndex===C&&ar.fieldIndex===Gr),Ot=s===nd,es=!!B.defaultValue,nn=n[B.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Ot?y:"gray",bold:Ot,children:[Ot?" \u279C ":" ",B.name]}),!Ot&&nn&&u(f,{color:"green",children:" \u2713"}),!Ot&&!nn&&es&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",B.defaultValue,")"]})]}),Ot&&u(h,{marginLeft:4,children:u(Or,{value:nn,onChange:ar=>{i(id=>({...id,[B.name]:ar})),c&&l(null)},onSubmit:v,placeholder:es?`Default: ${B.defaultValue}`:"Enter value\u2026"})})]},B.name)})})]},w.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[b.warn," ",c]})}),S(h,{marginTop:1,children:[u(f,{color:g?y:void 0,bold:g,children:g?"\u279C ":" "}),u(h,{borderStyle:I,borderColor:g?y:"gray",paddingX:2,children:u(f,{color:g?y:"gray",bold:g,children:"Continue \u2192"})})]}),u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},Ki=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[i,s]=ce(e.defaultValue||""),[a,c]=ce(null);Gi(()=>{s(e.defaultValue||""),c(null)},[e.name]),or((p,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}n()}});let l=p=>{if(e.required&&!p.trim()){c("This field is required");return}c(null),o(p)},d=!!e.defaultValue;return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:a?"red":y,children:[S(h,{justifyContent:"space-between",children:[S(h,{children:[u(f,{color:y,bold:!0,children:e.name}),e.required?u(f,{color:"red",children:" *"}):S(f,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),S(f,{color:"gray",children:[t+1,"/",r]})]}),u(h,{marginLeft:1,children:u(f,{color:"gray",children:e.description})}),S(h,{marginTop:1,children:[u(f,{color:y,children:"\u2192 "}),u(Or,{value:i,onChange:p=>{s(p),a&&c(null)},onSubmit:l,placeholder:d?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),a&&u(h,{marginTop:1,children:u(f,{color:"red",children:a})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm",!e.required&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},eu=({store:e})=>{let t=_e(e);return S(Yo,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&u(Dh,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&u(Go,{checks:t.data.checks}),u(rr,{inputId:t.inputRequest?.id,missing:t.data[It],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&u(tr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&u(Oh,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&u($h,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&u(jl,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&u(ji,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&u(qi,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&u(Hi,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&u(Ki,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&u(Vi,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&u(Wi,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&u(Uo,{status:t.status}),t.step==="Finished"&&u(Lh,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,stillStarting:t.data.stillStarting===!0,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&u(Ui,{title:t.step==="Install Tools"?"Installing Tools":"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.step==="Install Tools"?t.data.toolComplete||!1:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.error&&u(Ae,{message:t.error.message})]})};import{Spinner as Mh}from"@inkjs/ui";import{Box as nr,Text as $r}from"ink";import{jsx as at,jsxs as je}from"react/jsx-runtime";var tu=({store:e})=>{let t=_e(e),r=t.step==="Starting"||t.step==="Stopping",o=t.step==="Running"||t.step==="Stopped",n=t.data.dockerLogs??[];return je(nr,{flexDirection:"column",width:"100%",children:[at(rt,{showStatus:o}),r&&!t.error&&je(nr,{flexDirection:"column",marginTop:1,children:[at(Mh,{label:t.status||"Working\u2026"}),n.length>0&&at(Vo,{logs:n})]}),t.step==="Running"&&t.data.started&&je(nr,{flexDirection:"column",marginTop:1,children:[je(nr,{children:[at(ie,{kind:"ok"}),je($r,{children:["GAIA is running at"," ",at($r,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),je($r,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&je(nr,{flexDirection:"column",marginTop:1,children:[je(nr,{children:[at(ie,{kind:"ok"}),at($r,{children:t.status})]}),t.data.stopMode==="force-ports"&&je($r,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&at(Ae,{message:t.error.message})]})};import{Spinner as Fh}from"@inkjs/ui";import{Box as ct,Text as ge,useInput as Nh}from"ink";import{jsx as k,jsxs as Oe}from"react/jsx-runtime";var ru=({store:e})=>{let t=_e(e);return Oe(Yo,{status:t.status,step:t.step,steps:Zl,children:[t.step==="Detect Repo"&&Oe(ct,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:y,children:[k(ge,{bold:!0,children:"Detecting GAIA Repository"}),k(ct,{marginTop:1,children:k(Fh,{label:"Searching for repository\u2026"})}),t.data.repoPath&&k(ct,{marginTop:1,children:Oe(ge,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&k(Go,{checks:t.data.checks}),k(rr,{inputId:t.inputRequest?.id,missing:t.data[It],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&k(tr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&k(ji,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&k(qi,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&k(Hi,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&k(Ki,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&k(Vi,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&k(Wi,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&k(Uo,{status:t.status}),t.step==="Project Setup"&&k(Ui,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&k(Bh,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&k(Ae,{message:t.error.message})]})},Bh=({setupMode:e,portOverrides:t,onConfirm:r})=>{Nh((s,a)=>{a.return&&r()});let o=t?.[3e3]??3e3,n=ne(e??"developer",t??{}),i=e==="selfhost";return Oe(ct,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:y,padding:1,children:[k(ge,{color:y,bold:!0,children:"Setup Complete!"}),Oe(ct,{marginTop:1,children:[k(ge,{bold:!0,children:"Run: "}),k(ge,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Oe(ct,{marginTop:1,flexDirection:"column",children:[Oe(ge,{children:["Web:"," ",Oe(ge,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),Oe(ge,{children:["API:"," ",k(ge,{color:"cyan",bold:!0,children:n})]})]}),k(ct,{marginTop:1,children:k(ge,{color:"gray",children:i?"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup":"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),k(ct,{marginTop:1,children:Oe(ge,{dimColor:!0,children:[k(ge,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as Qh}from"@inkjs/ui";import{Box as te,Text as Ee,useInput as Jh}from"ink";var Gh=[{name:"API",port:8e3,type:"http",path:"/health"},{name:"Web",port:3e3,type:"http",path:"/"},{name:"PostgreSQL",port:5432,type:"tcp"},{name:"Redis",port:6379,type:"tcp"},{name:"MongoDB",port:27017,type:"tcp"},{name:"RabbitMQ",port:5672,type:"tcp"},{name:"ChromaDB",port:8080,type:"tcp"}];async function ou(e){return Promise.all(Gh.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?Uh(t.name,r,t.path):jh(t.name,r)}))}async function Uh(e,t,r){let o=Date.now();try{let n=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-o;return{name:e,port:t,status:n.ok?"up":"down",latency:i,details:n.ok?`HTTP ${n.status}`:`HTTP ${n.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function jh(e,t){let r=await import("node:net"),o=Date.now();return new Promise(n=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let s=Date.now()-o;i.destroy(),n({name:e,port:t,status:"up",latency:s})}),i.on("timeout",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function nu(e){let t=await Q();if(t!=="ready")return{access:t,problem:await Me(t),containers:[]};let r=await ls(le[e]);return{access:t,containers:r}}var Lr="statusFacts";async function qh(){let e=_(),t=e?await N(e):null,r=vr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let o=F(e),n=o[T]??T,[i,s,a]=await Promise.all([t==="developer"?ou(o):[],nu(t),Fo(yt(t,o),le[t])]),c=a.reachable?await ke(ne(t,o),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:Hh(s.containers)}:s,readiness:a,services:i,webUrl:ze(n,Nt(e)),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function Hh(e){let t=($()?.bots??[]).map(ue).filter(r=>!e.some(o=>o.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function Vh(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await qh();e.updateData(Lr,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function iu(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await Vh(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var Wh=["gaia-web","gaia-backend","arq_worker","proxy"],Kh=["mongo","postgres","redis","rabbitmq","chromadb"];function Xo(e,t,r){return t.some(n=>!n.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function su(e,t){return t.map(r=>e.find(o=>o.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:Fe(r.name)}))}function au(e,t){let r=e.readiness,o=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:Zr(i.name)})):su(t,Kh),n=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return Xo("Data",o,n??"See why with: gaia doctor")}function Yh(e){let t=e.filter(r=>r.name.startsWith("bot-"));return t.length===0?{label:"Bots",items:[],note:"none \xB7 add one: gaia bots add telegram",tone:"dim"}:Xo("Bots",t.map(r=>({ok:r.status==="running",name:Fe(r.name)})),"See why with: gaia doctor")}function cu(e){return e.setupComplete===null?null:e.setupComplete?{label:"Setup",items:[],note:"finished",tone:"ok"}:{label:"Setup",items:[],note:`not finished \xB7 open ${e.webUrl}/setup`,tone:"warn"}}function Xh(e,t){let r=t.containers,n=[Xo("App",su(r,Wh),"Start it: gaia start"),au(e,r),Yh(r)],i=cu(e);i&&n.push(i);let s=r.some(c=>c.status==="running"),a=n.some(c=>c.tone==="fail");return s?{headline:a?{kind:"fail",text:"GAIA is running, but part of it is down"}:{kind:"ok",text:"GAIA is running",url:e.webUrl},rows:n,unhealthy:a}:{headline:{kind:"fail",text:"GAIA isn't running \xB7 start it: gaia start"},rows:[],unhealthy:!0}}function zh(e){let t=e.services.map(o=>({ok:o.status==="up",name:`${o.name} :${o.port}`})),r=Xo("Local",t,"Start them: gaia dev");return{headline:r.tone==="fail"?{kind:"fail",text:"Part of the dev stack is down"}:{kind:"ok",text:"The dev stack is running",url:e.webUrl},rows:[r],unhealthy:r.tone==="fail"}}function zo(e){if(!e.installed)return{headline:{kind:"warn",text:`${e.install} \xB7 run: gaia up`},rows:[],unhealthy:!0};let t=e.docker;if(t?.problem){let r=e.readiness?.reachable===!0,o={label:"Docker",items:[],note:t.problem.state,tone:"warn"},n=cu(e);return{headline:r?{kind:"ok",text:"GAIA is running",url:e.webUrl}:{kind:"fail",text:t.problem.summary},hint:t.problem.fix,rows:r?[au(e,[]),...n?[n]:[],o]:[],unhealthy:!0}}return e.services.length>0?zh(e):Xh(e,t??{access:"ready",containers:[]})}import{jsx as A,jsxs as qe}from"react/jsx-runtime";var lu=8,uu={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},Zh=({row:e})=>qe(te,{flexDirection:"column",children:[qe(te,{flexWrap:"wrap",children:[A(te,{width:lu,flexShrink:0,children:A(Ee,{bold:!0,children:e.label})}),e.items.map(t=>qe(te,{marginRight:2,children:[A(ie,{kind:t.ok?"ok":"fail"}),A(Ee,{children:t.name})]},t.name)),e.items.length===0&&e.note&&qe(te,{children:[e.tone!=="dim"&&A(ie,{kind:e.tone==="warn"?"warn":"ok"}),A(Ee,{color:uu[e.tone],children:e.note})]})]}),e.items.length>0&&e.note&&A(te,{marginLeft:lu,children:A(Ee,{color:uu[e.tone],children:e.note})})]}),du=({store:e})=>{let t=_e(e),r=t.data[Lr],o=t.data.watch===!0,n=t.step==="Results"&&r!==void 0;Jh((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:o&&t.inputRequest!==null});let i=r?zo(r):null,s=i?.headline.kind??"ok";return qe(te,{flexDirection:"column",width:"100%",children:[A(rt,{showStatus:!1}),t.step==="Checking"&&A(te,{marginTop:1,marginLeft:2,children:A(Qh,{label:t.status})}),n&&i&&qe(te,{flexDirection:"column",marginTop:1,marginLeft:2,children:[qe(te,{children:[A(ie,{kind:s==="ok"?"active":s}),A(Ee,{bold:!0,children:i.headline.text})]}),i.headline.url&&A(te,{marginLeft:2,children:A(Ee,{color:y,children:i.headline.url})}),i.hint&&A(te,{marginLeft:2,children:A(Ee,{children:i.hint})}),i.rows.length>0&&A(te,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>A(Zh,{row:a},a.label))}),r.installed&&A(te,{marginTop:1,children:qe(Ee,{color:"gray",children:["Installed at ",r.install]})}),o&&A(te,{marginTop:1,children:qe(Ee,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",A(Ee,{bold:!0,children:"r"})," check again \xB7 ",A(Ee,{bold:!0,children:"q"})," quit"]})})]}),t.error&&A(Ae,{message:t.error.message})]})};import{defaultTheme as eS,extendTheme as tS}from"@inkjs/ui";var pu=tS(eS,{components:{Spinner:{styles:{frame:()=>({color:y})}},ProgressBar:{styles:{completed:()=>({color:y})}}}});import{jsx as se,jsxs as ir}from"react/jsx-runtime";var iS=["init","setup","status","start","stop","up"],Yi=class extends nS.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?ir(Qo,{flexDirection:"column",padding:1,children:[se(_t,{color:"red",bold:!0,children:"An unexpected error occurred:"}),se(_t,{color:"red",children:this.state.error.message}),this.state.error.stack&&se(Qo,{marginTop:1,children:se(_t,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},sS=({store:e,command:t})=>{switch(t){case"init":return se(eu,{store:e});case"setup":return se(ru,{store:e});case"status":return se(du,{store:e});case"start":case"stop":return se(tu,{store:e,command:t});case"up":return se(Yl,{store:e});default:return ir(Qo,{flexDirection:"column",padding:1,children:[ir(_t,{color:"red",children:["Unknown command: ",t]}),ir(Qo,{marginTop:1,flexDirection:"column",children:[se(_t,{bold:!0,children:"Available commands:"}),iS.map(r=>ir(_t,{children:[" ",se(_t,{color:"cyan",children:r})]},r))]})]})}},aS=({onCancel:e})=>(oS((t,r)=>{r.ctrl&&t==="c"&&e()}),null),mu=({store:e,command:t,onCancel:r})=>se(Yi,{children:ir(rS,{theme:pu,children:[se(aS,{onCancel:r}),se(sS,{store:e,command:t})]})});import{EventEmitter as cS}from"events";var lS=150,Xi=class extends cS{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;autoResolveInputs=new Map;answerResolvers=[];setAutoResolve(t,r="exit"){this.autoResolveInputs.set(t,r)}pushAnswerResolver(t){this.answerResolvers.push(t)}get currentState(){return this.state}scheduleEmit(){this.emitPending=!0,this.emitTimer||(this.emitTimer=setTimeout(()=>{this.emitTimer=null,this.emitPending&&(this.emitPending=!1,this.emit("change",this.state))},lS))}flush(){this.emitPending&&this.emitNow()}emitNow(){this.emitTimer&&(clearTimeout(this.emitTimer),this.emitTimer=null),this.emitPending=!1,this.emit("change",this.state)}setStep(t){this.state.step=t,this.emitNow()}setStatus(t){this.state.status=t,this.scheduleEmit()}setError(t){this.state.error=t,t!==null&&this.inputResolver&&(this.inputResolver(null),this.inputResolver=null,this.state.inputRequest=null),this.emitNow()}updateData(t,r){this.state.data={...this.state.data,[t]:r},this.scheduleEmit()}ask(t,r,o){return this.answerResolvers.map(i=>i(t,o)).find(i=>i!==void 0)===void 0&&!this.autoResolveInputs.has(t)&&this.setStatus(r),this.waitForInput(t,o)}waitForInput(t,r,o){if(this.autoResolveInputs.has(t))return this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t));for(let n of this.answerResolvers){let i=n(t,r);if(i!==void 0)return this.state.inputRequest=null,this.emitNow(),Promise.resolve(i)}return this.state.inputRequest={id:t,meta:r},this.emitNow(),new Promise(n=>{if(this.inputResolver=n,o!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),n(null))},o),s=this.inputResolver;this.inputResolver=a=>{clearTimeout(i),s(a)}}})}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},fu=()=>new Xi;async function he(e){let t=fu();if(e.whenNonInteractive==="fail"){rc(e.command),await gu(t,e);return}pe()?await gu(t,e):await pS(t,e)}async function pS(e,t){oc(e,bs());for(let[r,o]of t.autoResolve??[])e.setAutoResolve(r,o);try{await t.runFlow(e);let r=hu(e);r&&await Sn(e.currentState.step,r),t.onPlainComplete?.(e)}catch(r){e.setError(r)}Su(e)}async function gu(e,t){let r=()=>{},{unmount:o,clear:n}=uS(dS.createElement(mu,{store:e,command:t.command,onCancel:()=>r()}),{exitOnCtrlC:!1}),i=()=>{o();let a=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
109
+ ${b.cancelled} Cancelled.${a}
110
+ `),process.exit(130)};r=i,process.once("SIGINT",i),process.once("SIGTERM",i);try{await t.runFlow(e)}catch(a){e.setError(a)}finally{process.off("SIGINT",i),process.off("SIGTERM",i)}e.flush(),await new Promise(a=>setImmediate(a));let s=hu(e);s&&(n(),o(),await Sn(e.currentState.step,s)),o(),process.stdout.write(`
111
+ `),Su(e)}function hu(e){if(!e.currentState.error)return e.currentState.data.dockerGroupSwitch}function Su(e){let t=e.currentState.error?1:Number(process.exitCode??0),r=[process.stdout,process.stderr].filter(n=>n.writableLength>0);r.length===0&&process.exit(t);let o=r.length;for(let n of r)n.once("drain",()=>{o-=1,o===0&&process.exit(t)})}import*as lt from"fs";import*as yu from"os";import*as Dt from"path";import*as Jo from"node:fs";import*as vu from"node:path";var mS=e=>new Promise(t=>setTimeout(t,e));async function Zo(e){e.setStep("Setup Mode"),e.setStatus("Choose how to run GAIA\u2026");let t=await e.waitForInput("setup_mode");return e.updateData("setupMode",t),t}async function sr(e,t,r,o,n){e.setStep("Environment Setup"),e.setStatus("Configuring GAIA\u2026"),e.updateData("setupMode",r),e.setStatus("Configuring GAIA\u2026");let i=await e.waitForInput("env_method");e.updateData("envMethod",i);let s={ENV:r==="selfhost"?"selfhost":"development"};r==="selfhost"&&(s.AUTH_MODE="local");for(let d of pr()){let p=dr(d,r);p&&(s[d]=p)}Object.assign(s,Os(r));let a={};n?.domain&&(a.HOST=`https://${n.domain}`,a.FRONTEND_URL=`https://${n.domain}`),i==="infisical"?(await gS(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.")):await SS(e,a,r,n?.llmProvider===void 0);let c=Jo.existsSync(Ne(t))?Jo.readFileSync(Ne(t),"utf-8"):null,l=fS({defaults:s,existing:vt(c),existingMode:await N(t),answers:a,setupMode:r});o&&_s(l,o,r),r==="selfhost"&&Object.assign(l,Qr(c));try{await vS(e,t,l,r,o,n?.domain)}catch(d){e.setError(d);return}await mS(1e3)}function fS(e){let{defaults:t,existing:r,existingMode:o,answers:n,setupMode:i}=e,s=o===i;return{...s?t:r,...s?r:t,...n,SETUP_MODE:i}}async function gS(e,t){e.setStatus("Configuring Infisical\u2026");let r=await e.waitForInput("env_infisical");t.INFISICAL_PROJECT_ID=r.INFISICAL_PROJECT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_ID=r.INFISICAL_MACHINE_IDENTITY_CLIENT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET=r.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET}function hS(e){let t=[],r=new Set,o=new Set;for(let n of e)if(n.alternativeGroup&&!o.has(n.name)){let i=e.find(s=>s.name===n.alternativeGroup);i&&(t.push([n,i]),r.add(n.name),r.add(i.name),o.add(n.name),o.add(i.name))}return{alternativePairs:t,alternativeGroupNames:r}}async function SS(e,t,r,o){e.setStatus("Parsing environment variables\u2026");let n=Ds(Wr(),r).filter(g=>r!=="selfhost"||g.selfhostSetup),{alternativePairs:i,alternativeGroupNames:s}=hS(n),a=n.filter(g=>g.variables.length===1&&!s.has(g.name)),c=n.filter(g=>g.variables.length>1&&!s.has(g.name));for(let g of o?i:[]){e.updateData("alternativeGroups",g);let v=await e.ask("env_alternatives","Choose an AI provider\u2026");for(let[E,w]of Object.entries(v.values))w&&(t[E]=w)}let l=pr(),p=[...a.flatMap(g=>g.variables).filter(g=>!l.includes(g.name))].sort((g,v)=>g.required&&!v.required?-1:!g.required&&v.required?1:0);e.updateData("envVarTotal",p.length);for(let g=0;g<p.length;g++){let v=p[g];if(!v)continue;e.updateData("currentEnvVar",v),e.updateData("envVarIndex",g);let E=await e.ask("env_var",`Configuring ${v.name}\u2026`,{varName:v.name});(E||v.required||v.defaultValue)&&(t[v.name]=E||v.defaultValue||"")}let m=[...c].filter(g=>!g.variables.every(v=>l.includes(v.name))).sort((g,v)=>{let E=g.variables.some(C=>C.required),w=v.variables.some(C=>C.required);return E&&!w?-1:!E&&w?1:0});e.updateData("envGroupTotal",m.length);for(let g=0;g<m.length;g++){let v=m[g];if(!v)continue;e.updateData("currentEnvGroup",v),e.updateData("envGroupIndex",g);let E=await e.ask("env_group",`Configuring ${v.name}\u2026`,{groupName:v.name});for(let[w,C]of Object.entries(E)){let M=v.variables.find(D=>D.name===w);(C||M?.required||M?.defaultValue)&&(t[w]=C||M?.defaultValue||"")}}}async function vS(e,t,r,o,n,i){e.setStatus("Saving GAIA's settings\u2026");try{let s=vu.join(t,"apps","api");mr(s,r),e.setStatus("Saved GAIA's settings")}catch(s){throw new Error(`Failed to write API .env file: ${s.message}`)}if(o==="selfhost"){e.setStatus("Saving Docker's settings\u2026");try{Cn(t,n??{},o,{dockerSocketGid:ds(),domain:i}),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}return}e.setStatus("Saving the web app's settings\u2026");try{Ls(t,o,n),e.setStatus("Saved the web app's settings")}catch(s){throw new Error(`Failed to write web .env file: ${s.message}`)}if(n&&Object.keys(n).length>0){e.setStatus("Saving Docker's settings\u2026");try{Gs(t),Cn(t,n,o),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}}}var yS=5e3,wS=5*6e4,bS=5e3;async function ES(e,t={}){let r=t.intervalMs??yS,o=Date.now()+(t.timeoutMs??wS),n=new Map(e.map(i=>[i.label,i]));for(;;){if(await Promise.all([...n.values()].map(async i=>{await xS(i)&&n.delete(i.label)})),n.size===0)return{ready:!0};if(Date.now()>=o)return{ready:!1,stillStarting:[...n.keys()].join(", ")};t.onProgress?.([...n.keys()]),await X(r)}}async function xS(e){try{let t=await fetch(e.url,{signal:AbortSignal.timeout(bS)});return e.requireOk?t.ok:!0}catch{return!1}}async function en(e,t){let r=await ES([{label:"API",url:`${t.apiUrl}/ping`,requireOk:!0},{label:"Web",url:`http://localhost:${t.webPort}/login`,requireOk:!1}],{onProgress:o=>{CS(e,o)}});return e.updateData("dependencyPhase",r.ready?"GAIA is answering":`Still starting: ${r.stillStarting}`),e.updateData("dependencyComplete",!0),r}function CS(e,t){let r=`Waiting for ${t.join(" and ")} to come online\u2026`;e.setStatus(r),e.updateData("dependencyComplete",!1),e.updateData("dependencyPhase",r)}var IS=process.env.GAIA_CLI_DEV==="true";async function wu(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input\u2026"),await e.waitForInput("welcome");let r=vo(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await yo(e))return;let o=await Zo(e),n=await Yt(e,o);if(n===null||o==="developer"&&!await wo(e))return;let i="";if(IS){if(i=qt()||"",!i){e.setError(new Error("DEV_MODE: Could not find workspace root. Run from within the gaia repo."));return}e.setStep("Repository Setup"),e.setStatus("[DEV MODE] Using current workspace\u2026"),await X(500),e.setStatus("Repository ready")}else{e.setStep("Repository Setup");let a=o==="selfhost"?Dt.join(yu.homedir(),"gaia"):Dt.resolve("gaia"),c=!0;for(i=a;;){if(i=await e.waitForInput("repo_path",{default:a}),Dt.isAbsolute(i)||(i=Dt.resolve(i)),lt.existsSync(i)){if(!lt.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await X(2e3),e.setError(null);continue}if(Xe(i)){e.updateData("existingRepoPath",i);let p=await e.waitForInput("existing_repo");if(p==="use_existing"){c=!1;break}else if(p==="delete_reclone"){e.setStatus("Removing existing installation\u2026");try{lt.rmSync(i,{recursive:!0,force:!0})}catch(m){e.setError(new Error(`Failed to remove directory: ${m.message}
112
+ Try removing it manually: rm -rf "${i}"`));return}break}else{if(p==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(lt.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await X(2e3),e.setError(null);continue}}break}if(c){e.setStep("Repository Setup"),e.setStatus("Preparing repository\u2026"),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await to(i,"https://github.com/theexperiencecompany/gaia.git",(l,d)=>{e.updateData("repoProgress",l),d?(e.updateData("repoPhase",d),e.setStatus(`${d}\u2026`)):e.setStatus(`Cloning repository to ${i}... ${l}%`)},t),e.setStatus("Repository ready")}catch(l){e.setError(l);return}}else e.setStatus("Using the existing repository")}if(await X(1e3),await sr(e,i,o,n),e.currentState.error)return;if(o==="selfhost"){e.setStep("Project Setup"),e.setStatus("Building and starting all services in Docker\u2026"),e.updateData("dependencyPhase","Building and starting Docker services\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]),e.updateData("dependencyComplete",!1);let a=lc(e),c=!1;try{e.setStatus("Pulling pre-built images from registry\u2026"),await oe(i,"selfhost",p=>e.setStatus(p),n,a,{pull:"missing"}),c=!0}catch(p){let m=p.message?.split(`
113
+ `)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)\u2026`)}if(!c)try{await oe(i,"selfhost",p=>e.setStatus(p),n,a,{build:!0})}catch(p){e.setError(new Error(`Failed to start services: ${p.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let l=e.currentState.data.envMethod||"manual";Hr({version:O,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",o);let d=await en(e,{apiUrl:ne("selfhost",n),webPort:n[T]??T});e.updateData("stillStarting",!d.ready),e.setStep("Finished"),e.setStatus(d.ready?"Set up. GAIA is running.":"Containers are up but not answering yet \u2014 give it a minute, then open the setup link below."),await e.waitForInput("exit");return}e.setStep("Install Tools"),e.setStatus("Installing toolchain\u2026"),e.updateData("dependencyPhase","Initializing mise\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration\u2026"),await J("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)\u2026"),await J("mise",["install"],i,a=>{e.updateData("dependencyProgress",50+a*.5)},r),e.updateData("dependencyProgress",100),e.updateData("toolComplete",!0)}catch(a){e.setError(new Error(`Failed to install tools: ${a.message}`));return}await X(1e3),e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("repoPath",i),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyProgress",0),e.updateData("dependencyPhase","Running mise setup (all dependencies)\u2026");let a=Object.keys(n).length>0?We(n):void 0;await J("mise",["setup"],i,c=>{e.updateData("dependencyProgress",c)},r,a),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0)}catch(a){e.setError(new Error(`Failed to setup project: ${a.message}`));return}await X(1e3);let s=e.currentState.data.envMethod||"manual";Hr({version:O,setupComplete:!0,setupMethod:s,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function bu(e={}){await he({command:"init",whenNonInteractive:"fail",runFlow:t=>wu(t,e.branch)})}import*as xe from"node:fs";import*as Ce from"node:path";import{execa as tn}from"execa";function zi(e){if(e.fromDir){let t=Ce.resolve(e.fromDir),r=is(t);if(!r)return{volumeFiles:[]};let o=$t(t,r),n=i=>xe.existsSync(i)?i:void 0;return{mongoFile:e.mongoFile??n(o.mongoFile),postgresFile:e.postgresFile??n(o.postgresFile),apiEnvFile:e.apiEnvFile??n(o.apiEnvFile),volumeFiles:o.volumeFiles.filter(i=>xe.existsSync(i.file))}}return{mongoFile:e.mongoFile,postgresFile:e.postgresFile,apiEnvFile:e.apiEnvFile,volumeFiles:[]}}function Eu(e){return!e.mongoFile||e.apiEnvFile?[]:["Restoring MongoDB without the backup's apps/api/.env: the stored provider credentials decrypt only under the INSTANCE_SECRET they were saved with. If this install's apps/api/.env is not the one the dump was taken with, they will not decrypt. Pass the backup's api-env-<stamp>.env with --env, or restore with --from <dir>."]}function Qi(e){let{mongoFile:t,postgresFile:r,apiEnvFile:o,volumeFiles:n}=e,i=[];o&&i.push(`install -m 600 ${o} ../../apps/api/.env`),t&&i.push(`docker compose -f docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t}`),r&&(i.push("docker compose -f docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'"),i.push(`cat ${r} | docker compose -f docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`));for(let{volume:s,file:a}of n)i.push(`docker run --rm -v ${s}:/data -v ${Ce.dirname(a)}:/backups alpine sh -c "${cr(Ce.basename(a))}"`);return i}async function xu(e,t){let r=_();if(!r)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let o=Ce.join(r,"infra","docker"),n=Ce.join(o,"docker-compose.selfhost.yml");if(!xe.existsSync(n))throw new Error(`Compose file not found: ${n}`);let i=zi(e),{mongoFile:s,postgresFile:a,apiEnvFile:c,volumeFiles:l}=i,d=Qi(i);if(!s&&!a&&!c&&l.length===0)throw new Error(["No backup files specified.","Use --mongo <file> --postgres <file> or --from <backup-dir> containing mongo-*.gz and postgres-*.sql.","Example: gaia restore --from backups","Example: gaia restore --mongo backups/mongo-2026-08-27T09-30-00Z.gz --postgres backups/postgres-2026-08-27T09-30-00Z.sql"].join(`
114
+ `));if(c&&!xe.existsSync(c))throw new Error(`apps/api/.env backup not found: ${c}`);if(s&&!xe.existsSync(s))throw new Error(`Mongo backup not found: ${s}`);if(a&&!xe.existsSync(a))throw new Error(`Postgres backup not found: ${a}`);for(let{label:m,file:g}of l)if(!xe.existsSync(g))throw new Error(`${m} backup not found: ${g}`);if(e.dryRun)return{...i,commands:d};let p=await Q();if(p!=="ready"){let m=await Me(p);throw new Error([`${m.summary}, so nothing can be restored.`,m.fix,"Or run the restore commands yourself:",...d.map(g=>` ${g}`)].join(`
115
+ `))}if(c&&kS(c,r),s)try{let m=tn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","mongo","mongorestore","--archive","--gzip","--drop"],{cwd:o,stdin:"pipe",stderr:"pipe"}),g=xe.createReadStream(s);if(!m.stdin)throw new Error("Failed to pipe mongo restore stdin");g.pipe(m.stdin),await m}catch(m){throw new Error(`MongoDB restore failed: ${m.message}`)}if(a){try{await tn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph","-c","DROP SCHEMA public CASCADE; CREATE SCHEMA public;"],{cwd:o})}catch(m){throw new Error(`Postgres schema reset failed: ${m.message}`)}try{let m=tn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph"],{cwd:o,stdin:"pipe",stderr:"pipe"}),g=xe.createReadStream(a);if(!m.stdin)throw new Error("Failed to pipe postgres restore stdin");g.pipe(m.stdin),await m}catch(m){throw new Error(`PostgreSQL restore failed: ${m.message}`)}}for(let{file:m,volume:g,label:v}of l)try{await tn("docker",["run","--rm","-v",`${g}:/data`,"-v",`${Ce.dirname(m)}:/backups`,"alpine","sh","-c",cr(Ce.basename(m))],{cwd:o})}catch(E){throw new Error(`${v} restore failed: ${E.message}`)}return t("Restarting services so they load the restored data and settings\u2026"),await oe(r,"selfhost",t,F(r)),{...i,commands:d}}function kS(e,t){Xr(e,Ne(t))}function $e(e=""){process.stdout.write(`${e}
116
+ `)}function Cu(e=""){process.stderr.write(`${e}
117
+ `)}async function Iu(e={}){let t={mongoFile:e.mongo,postgresFile:e.postgres,apiEnvFile:e.env,fromDir:e.from},r=zi(t);for(let o of Eu(r))Cu(`Warning: ${o}`);if(e.dryRun){let o=Qi(r);if(o.length===0){$e("No backup files resolved. Use --from <dir> or --mongo/--postgres/--env <file>.");return}$e("Restore commands (dry run \u2014 not executed):");for(let n of o)$e(` ${n}`);return}try{$e("Starting GAIA restore\u2026");let o=await xu(t,n=>$e(` ${n}`));o.apiEnvFile&&$e(`Restored apps/api/.env from ${o.apiEnvFile}`),o.mongoFile&&$e(`Restored MongoDB from ${o.mongoFile}`),o.postgresFile&&$e(`Restored PostgreSQL from ${o.postgresFile}`);for(let{label:n,file:i}of o.volumeFiles)$e(`Restored ${n} from ${i}`);$e("Restore complete. Run 'gaia doctor' to confirm every dependency is ready.")}catch(o){Cu(o.message),process.exitCode=1}}async function ku(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository\u2026");let t=qt();if(!t){e.setError(new Error("Could not find GAIA repository. Run this command from within a cloned gaia repo, or use 'gaia init' to set up from scratch."));return}if(e.updateData("repoPath",t),e.setStatus(`Found repository at ${t}`),await X(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await yo(e))return;let r=await Zo(e),o=await Yt(e,r);if(o===null||r==="developer"&&!await wo(e)||(await sr(e,t,r,o),e.currentState.error))return;if(r==="selfhost"){let a=e.currentState.data.envMethod||"manual";Se({setupComplete:!0,setupMethod:a,repoPath:t}),e.updateData("setupMode",r),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia start' to start GAIA."),await e.waitForInput("exit");return}let n=vo(e);if(!await uc(e,t,o,n))return;await X(1e3);let s=e.currentState.data.envMethod||"manual";Se({setupComplete:!0,setupMethod:s,repoPath:t}),e.updateData("setupMode",r),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function Ru(){await he({command:"setup",whenNonInteractive:"fail",runFlow:ku})}async function Tu(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository\u2026");let r=_();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r);let o=await N(r);if(!o){e.setError(new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo."));return}if(o==="developer"){e.setError(new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'."));return}if(o==="selfhost"){e.setStatus("Checking Docker\u2026");let s=await Q();if(s!=="ready"){e.setError(await St(s));return}}let n=F(r),i=n[T]??T;e.updateData("setupMode",o),e.updateData("webUrl",ze(i,Nt(r))),e.updateData("dockerLogs",[]),e.setStatus("Starting GAIA\u2026");try{await oe(r,o,s=>e.setStatus(s),n,(s,a)=>{e.setStatus(s.label),e.updateData("dockerLogs",a.slice(-wr))},t)}catch(s){e.setError(new Error(`GAIA didn't start. ${s.message}`));return}e.setStep("Running"),e.setStatus("GAIA is running."),e.updateData("started",!0)}async function Pu(e){await he({command:"start",whenNonInteractive:"plain",runFlow:t=>Tu(t,e),cancelHint:"GAIA may be partly started. Run 'gaia start' again to finish, or 'gaia stop'."})}var Au=8;function ut(e=""){process.stdout.write(`${e}
118
+ `)}function _u(e){let t=e.currentState.data[Lr];return t?{facts:t,report:zo(t)}:null}function RS(e){let t=_u(e);if(!t)return;let{facts:r,report:o}=t,n=o.headline.kind==="ok"?b.active:b.fail;ut(`${n} ${o.headline.text}`),o.headline.url&&ut(` ${o.headline.url}`),o.hint&&ut(` ${o.hint}`),o.rows.length>0&&ut();for(let i of o.rows){let s=i.items.map(c=>`${c.ok?b.ok:b.fail} ${c.name}`).join(" "),a=i.items.length===0?i.note??"":"";ut(` ${i.label.padEnd(Au)}${s}${a}`.trimEnd()),i.items.length>0&&i.note&&ut(` ${" ".repeat(Au)}${i.note}`)}r.installed&&(ut(),ut(` Installed at ${r.install}`))}async function Du(e={}){await he({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:async t=>{await iu(t,e),_u(t)?.report.unhealthy&&(process.exitCode=1)},onPlainComplete:RS})}async function Ou(e,t){e.setStep("Stopping"),e.setStatus("Finding your GAIA install\u2026");let r=_();if(!r){e.setError(new Error("GAIA isn't installed here, so there is nothing to stop."));return}e.updateData("repoPath",r),e.updateData("stopMode",t?.forcePorts?"force-ports":"safe");let o=F(r);try{await ha(r,n=>e.setStatus(n),o,t)}catch(n){e.setError(new Error(`GAIA didn't stop. ${n.message}`));return}e.setStep("Stopped"),e.setStatus("GAIA stopped. Start it again with 'gaia start'."),e.updateData("stopped",!0)}async function $u(e){await he({command:"stop",whenNonInteractive:"plain",runFlow:t=>Ou(t,e),cancelHint:"GAIA may still be partly running. Run 'gaia stop' again."})}import*as rn from"fs";import*as on from"path";function TS(e){let t=on.join(e,".env");return rn.existsSync(t)?["--env-file",".env"]:[]}async function Lu(){let e=_();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await N(e);if(!t)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");let r=on.join(e,"infra","docker"),o=TS(r),n=F(e),i=Object.keys(n).length>0?We(n):void 0;if(t==="selfhost"){await Zt("docker",["compose",...Ye(jt()),...o,"logs","-f","--tail","200"],r,i);return}let s=["compose",...o,"logs","-f","--tail","200"],a=on.join(e,pa),c=Ln(e),l=typeof c=="number"&&oo(c);if(rn.existsSync(a)&&l){console.log("Streaming app and infrastructure logs\u2026"),process.platform==="win32"?await Lo([{cmd:"powershell",args:["-Command",`Get-Content -Path '${a.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]):await Lo([{cmd:"tail",args:["-n","200","-f",a],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]);return}rn.existsSync(a)&&!l?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await Zt("docker",s,r,i)):(console.log("No active developer process detected. Streaming Docker service logs. Run `gaia dev` in another terminal for live Nx app logs."),await Zt("docker",s,r,i))}import{execFile as OS}from"node:child_process";import*as qu from"node:os";import*as Mu from"node:os";import*as Fu from"node:path";var PS=80,AS=443,Nu=Fu.join(Mu.homedir(),"gaia");function Bu(){let e=$()?.repoPath;return e&&Xe(e)?e:null}function Gu(e){let t={};return e.domain&&(t[T]=PS,t[yr]=AS),e.webPort&&(t[T]=e.webPort),t}function _S(){return $()?.values??{}}function DS(e){return Wr().flatMap(t=>t.variables).find(t=>t.name===e)}function Uu(e){let{repoPath:t,interactive:r=pe(),setupMode:o="selfhost"}=e,n=_S(),i=new Set(pr()),s=new Map,a=l=>(s.has(l)||s.set(l,DS(l)?.required===!0),s.get(l)===!0),c=l=>{let d=n[l]??dr(l,o);if(d)return d;if(!r&&a(l))throw new Error(`${l} is required but could not be resolved in non-interactive mode \u2014 provide it via a GAIA flag or an apps/api/.env file.`);return""};return(l,d)=>{switch(l){case"setup_mode":return"selfhost";case"env_method":return"manual";case"env_alternatives":return{selectedGroups:[],values:{}};case"env_group":return{};case"env_var":{let p=d?.varName;return!p||i.has(p)?"":c(p)}case"repo_path":return t;case"existing_repo":return"use_existing";case"port_conflicts":return"accept";default:return}}}var Hu="gaia up --build",$S="usually 10-20 minutes \xB7 safe to leave running";function LS(e,t){let r=e.llmProvider?_r[e.llmProvider]:null;return[{id:"check",label:"Checking Git and Docker",doneLabel:"Git and Docker are ready"},t?{id:"download",label:"Downloading GAIA",doneLabel:"Downloaded GAIA"}:{id:"download",label:"Finding your install",doneLabel:"Using your install"},{id:"configure",label:"Configuring GAIA",doneLabel:"Configured GAIA"},...e.noStart?[]:[e.build?{id:"start",label:"Building GAIA (first time only)",doneLabel:"Built and started GAIA"}:{id:"start",label:"Starting GAIA",doneLabel:"Started GAIA"},{id:"wait",label:"Waiting for GAIA to answer",doneLabel:"GAIA is answering"}],...r?[{id:"provider",label:`Checking your ${r} key`,doneLabel:`Saved your ${r} key`}]:[]]}function Mr(e,t){Wt(e),e.setError(t)}async function Vu(e,t={}){Vl(t);let r=Date.now(),o=Bu(),n=o??Nu,i=!Xe(n);e.pushAnswerResolver(Uu({repoPath:n})),tc(e,LS(t,i)),e.setStep("Prerequisites"),bt(e,"check");try{if(await So(e,{needGit:i,assumeYes:t.yes===!0})==="relaunch")return}catch(m){Mr(e,m);return}if(!t.build&&!await MS(e,n,i))return;let s=await Yt(e,"selfhost");if(s===null){Wt(e);return}if(Object.assign(s,Gu(t)),!i&&n!==o&&!t.forceDevTree&&await N(n)==="developer"){Mr(e,new Error(`${n} is set up for development (apps/api/.env is in developer mode), and 'gaia up' would overwrite its settings.
119
+ Run it with --force-dev-tree to go ahead anyway.`));return}if(Et(e,"check"),e.setStep("Repository Setup"),bt(e,"download"),!await FS(e,n,i))return;if(Se(t.codeSandbox===void 0?{repoPath:n}:{repoPath:n,codeSandbox:t.codeSandbox}),Et(e,"download",i?void 0:`Using your install at ${Ut(n)}`),e.setStep("Environment Setup"),bt(e,"configure"),await sr(e,n,"selfhost",s,{llmProvider:t.llmProvider,domain:t.domain}),e.currentState.error){Wt(e);return}Et(e,"configure");let a=s[T]??T,c={webUrl:ze(a,t.domain),reachableUrls:ka(a,t.domain),noStart:t.noStart===!0,stillStarting:!1,setupComplete:!1,codeSandbox:$()?.codeSandbox===!0,joinedDockerGroup:Es(),elapsedMs:0,startedServices:0};if(t.noStart){ju(e,n,{...c,elapsedMs:Date.now()-r});return}e.setStep("Project Setup");try{c.startedServices=await GS(e,n,s,t)}catch(m){Mr(e,m);return}bt(e,"wait");let l=ne("selfhost",s),d=await en(e,{apiUrl:l,webPort:a});d.ready?Et(e,"wait"):Ge(e,"wait",{state:"failed",endedAt:Date.now()}),c.stillStarting=!d.ready,c.setupComplete=d.ready&&await US(l);let p=await BS(e,n,t,d.ready);if(!p&&t.llmProvider&&(c.savedProvider=t.llmProvider),ju(e,n,{...c,elapsedMs:Date.now()-r}),p){e.setError(p);return}d.ready&&NS(c.webUrl,t)}async function MS(e,t,r){let o=r?He:Ie(t);e.setStatus(`Checking that GAIA ${o} is available for this computer\u2026`);let n=await Ht(o,$()?.bots??[]);if(!n)return!0;let{cause:i,next:s}=Gt(n,Hu);return Mr(e,new Error(`${i}
120
+ ${s}`)),!1}async function FS(e,t,r){if(!r)return!0;Ge(e,"download",{detail:"Connecting to GitHub\u2026",percent:0});try{await zs(t,Ys,(o,n)=>{Ge(e,"download",n?{percent:o,detail:n}:{percent:o})})}catch(o){return Mr(e,new Error(`Couldn't download GAIA into ${t}: ${o.message}`)),!1}return!0}function NS(e,t){let r=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;!t.yes&&r&&qu.platform()==="darwin"&&OS("open",[`${e}/setup`],()=>{})}async function BS(e,t,r,o){let{llmProvider:n}=r;if(!n)return null;let i=_r[n];if(bt(e,"provider"),!o)return Wt(e),new Error(`GAIA didn't answer in time, so your ${i} key wasn't saved.
121
+ Once 'gaia status' shows it running, run 'gaia up' again with the same flags.`);try{await Wl(t,{...r,llmProvider:n})}catch(s){return Wt(e),new Error(`Your ${i} key wasn't saved: ${s.message}
122
+ Check the key and run 'gaia up --llm-provider ${n} --llm-key <key>' again, or add it on the setup page above.`)}return Et(e,"provider"),null}async function GS(e,t,r,o){bt(e,"start",o.build?{hint:$S}:{});let{startedServices:n}=await oe(t,"selfhost",i=>Ge(e,"start",{detail:i}),r,i=>Ge(e,"start",{detail:i.label,percent:i.percent}),{...o.build?{build:!0}:{pull:"missing"},rebuildCommand:Hu,onLogFile:i=>e.updateData("logPath",i)});return Et(e,"start",n===0?"GAIA was already running":void 0),n}async function US(e){let t=await ke(e,"status");return"data"in t&&!t.data.needs_setup}function ju(e,t,r){Se({version:O,setupComplete:!0,setupMethod:e.currentState.data.envMethod||"manual",repoPath:t}),e.updateData("setupMode","selfhost"),e.updateData("upOutcome",r),e.updateData("finished",!0),e.setStep("Finished")}var jS=16,qS=14;function Fr(e=""){process.stdout.write(`${e}
123
+ `)}function HS(e){let t=e.currentState.data.upOutcome;if(!t)return;let r=Ho(t);Fr(),Fr(`${r.tone==="success"?`${b.ok} `:""}${r.headline}`);for(let o of r.rows)Fr(` ${o.label.padEnd(jS)}${o.text}`);Fr();for(let[o,n]of qo)Fr(` ${o.padEnd(qS)}${n}`)}async function Wu(e={}){await he({command:"up",whenNonInteractive:"plain",runFlow:t=>Vu(t,e),cancelHint:"GAIA may be partly set up. Run 'gaia up' again to finish, or 'gaia stop'.",onPlainComplete:HS})}import*as td from"node:readline";import{execa as Nr}from"execa";var VS=["apps/web","apps/api","infra/docker"];function Ku(e){let{current:t,target:r,explicit:o,gap:n}=e;if(!o){if(Qe(t)===null)return{kind:"development-build"};if(!Be(r,t))return{kind:"up-to-date"}}return n?{kind:"unavailable",gap:n}:{kind:"offer",downgrade:Be(t,r)}}async function dt(e,t){let{stdout:r}=await Nr("git",t,{cwd:e});return r.trim()}async function Yu(e){let t=await Nr("git",["rev-parse","--is-inside-work-tree"],{cwd:e,reject:!1});return t.exitCode!==0||t.stdout.trim()!=="true"?!1:(await Nr("git",["remote","get-url","origin"],{cwd:e,reject:!1})).exitCode===0}function Xu(e){return e.split(`
124
+ `).map(t=>t.trim()).filter(Boolean)}async function WS(e,t){let r=await dt(e,["log",t,"--oneline","--",...VS]);return{commits:Xu(r)}}async function zu(e,t){let r=Ie(e),o=ro(t);if(!await Yu(e))return{repoPath:e,fromVersion:r,toVersion:t,checkout:null};await _n("origin",t,e);let n=`refs/tags/${o}`,i=await Nr("git",["fetch","--no-tags","origin",`+${n}:${n}`],{cwd:e,reject:!1});if(i.exitCode!==0)throw new Error(`Could not fetch ${o} from origin: ${i.stderr.trim()}`);let[s,a,c]=await Promise.all([dt(e,["rev-parse","HEAD"]),dt(e,["rev-parse",`${o}^{commit}`]),dt(e,["rev-parse","--short","HEAD"])]);return{repoPath:e,fromVersion:r,toVersion:t,checkout:{fromRef:c,toTag:o,atTag:s===a}}}function Qu(e){return e.fromVersion===e.toVersion&&(e.checkout===null||e.checkout.atTag)}async function Ju(e,t){if(e.checkout&&!e.checkout.atTag){let r=Xu(await dt(e.repoPath,["status","--porcelain","--untracked-files=no"]));if(r.length>0)throw new Error(`Local changes to tracked files would be overwritten:
21
125
  ${r.join(`
22
126
  `)}
23
- Writes: ${t?"ENABLED":"disabled (read-only)"}
24
- Run: gaia bridge up`)}function Rn(){let e=de();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${He()})`:"Not paired \u2014 run: gaia bridge login");let t=q().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
25
- Configured servers:`);for(let r of t)if(r.type==="filesystem")console.info(` [${r.key}] filesystem${r.allowWrite?" (rw)":" (ro)"}: ${r.allow.join(", ")}`);else if(r.type==="stdio"){let o=Object.keys(r.env);console.info(` [${r.key}] ${r.name}: ${r.command} ${r.args.join(" ")}`),o.length&&console.info(` env: ${o.join(", ")}`)}else console.info(` [${r.key}] ${r.name}: ${r.url}`)}async function fe(e){try{await e()}catch(t){console.error(`Error: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}}var te=new In("bridge").description("Connect this machine's local MCP servers and files to GAIA (outbound-only, no inbound ports)").addHelpText("after",`
26
- Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);te.command("add").description("Connect a local MCP server (guided \u2014 start here!)").action(async()=>{await fe(_r)});te.command("login").description("Pair this machine with your GAIA account").option("--api <url>","GAIA API base URL").option("--name <name>","Name to show for this device in Settings").action(async e=>{await fe(async()=>{await Ye({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});te.command("fs").description("Expose folders for file access (read-only unless --write)").argument("<dirs...>","Folders to expose, e.g. ~/Documents").option("--write","Allow GAIA to write to these folders").action(async(e,t)=>{await fe(()=>Pn(e,t.write===!0))});te.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await fe(Rn)});te.command("rm").alias("remove").description("Remove a configured server").argument("<key>","Server key from `gaia bridge ls`").action(async e=>{await fe(()=>{console.info(lr(e)?`Removed '${e}'`:`No server '${e}'`)})});te.command("up").alias("start").description("Connect and serve (holds the tunnel; Ctrl+C to stop)").action(async()=>{await fe(Ke)});te.command("logout").description("Forget local credentials").action(async()=>{await fe(()=>{ar(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import*as tt from"fs";import*as Qr from"path";import{spawn as Dn}from"child_process";async function Te(e,t,r,o,n,i=!1){await Qe([{cmd:e,args:t,cwd:r,env:o,onSpawn:n,detached:i}])}async function Qe(e){e.length!==0&&await new Promise((t,r)=>{let o=e.map(d=>Dn(d.cmd,d.args,{cwd:d.cwd,stdio:"inherit",shell:!1,detached:d.detached??!1,env:d.env?{...process.env,...d.env}:process.env}));o.forEach((d,m)=>{e[m]?.onSpawn?.(d.pid)});let n=!1,i=0,a=!1,s,c=()=>{process.off("SIGINT",f),process.off("SIGTERM",f)},p=()=>{if(!a){a=!0;for(let[d,m]of o.entries()){let S=e[d];try{process.platform!=="win32"&&S?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGTERM"):m.kill("SIGTERM")}catch{}}s=setTimeout(()=>{for(let[d,m]of o.entries()){let S=e[d];try{process.platform!=="win32"&&S?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGKILL"):m.kill("SIGKILL")}catch{}}},1e3)}},f=()=>{p()};process.on("SIGINT",f),process.on("SIGTERM",f),o.forEach((d,m)=>{let S=e[m];d.on("error",v=>{n||(n=!0,c(),p(),r(v))}),d.on("close",(v,y)=>{if(i+=1,!(v===0||(y==="SIGINT"||y==="SIGTERM"||v===130||v===143||a))&&!n){n=!0,c(),p(),r(new Error(`Command failed with code ${String(v)}: ${S?.cmd??"unknown"} ${S?.args.join(" ")??""}`));return}i>=o.length&&!n&&(n=!0,c(),s&&clearTimeout(s),t())})})})}import*as J from"fs";import*as W from"path";import*as re from"fs";import*as Or from"os";import*as Rt from"path";var Et=Rt.join(Or.homedir(),".gaia"),Pt=Rt.join(Et,"config.json");function kn(){re.existsSync(Et)||re.mkdirSync(Et,{recursive:!0})}function Dt(){try{if(!re.existsSync(Pt))return null;let e=re.readFileSync(Pt,"utf-8");return JSON.parse(e)}catch{return null}}function ze(e){kn(),re.writeFileSync(Pt,`${JSON.stringify(e,null,2)}
27
- `)}function Ae(e){let r={...Dt()??{version:ee,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};ze(r)}import*as F from"fs";import*as Ee from"path";import*as Ie from"node:fs";import*as Ce from"node:path";import{execa as Mr}from"execa";var kt={selfhost:{MONGO_DB:"mongodb://mongo:27017/gaia",REDIS_URL:"redis://redis:6379",POSTGRES_URL:"postgresql://postgres:postgres@postgres:5432/langgraph",CHROMADB_HOST:"chromadb",CHROMADB_PORT:"8000",RABBITMQ_URL:"amqp://guest:guest@rabbitmq:5672/"},developer:{MONGO_DB:"mongodb://localhost:27017/gaia",REDIS_URL:"redis://localhost:6379",POSTGRES_URL:"postgresql://postgres:postgres@localhost:5432/postgres",CHROMADB_HOST:"localhost",CHROMADB_PORT:"8080",RABBITMQ_URL:"amqp://guest:guest@localhost:5672/"}},Nr={selfhost:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://gaia-backend:80",SETUP_MODE:"selfhost"},developer:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://host.docker.internal:8000",SETUP_MODE:"developer"}};function _t(e,t){return kt[t][e]??Nr[t][e]}async function Lr(e){let t=Ce.join(e,"apps/api/scripts/dump_config_schema.py"),r=Ce.join(e,"apps/api/app/config/settings_validator.py"),o=Ce.join(e,"apps/api/app/config/settings.py");if(!Ie.existsSync(t))throw new Error("dump_config_schema.py not found in apps/api/scripts");try{try{let{stdout:n}=await Mr("python3",[t,r,o],{cwd:e});return JSON.parse(n)}catch{let{stdout:n}=await Mr("python",[t,r,o],{cwd:e});return JSON.parse(n)}}catch(n){throw new Error(`Failed to parse settings schema: ${n.message}. Ensure python is installed.`)}}function Br(e){let t=Ce.join(e,"apps","web",".env.local"),r=Ie.existsSync(t)?t:Ce.join(e,"apps","web",".env");if(!Ie.existsSync(r))return[];let o=Ie.readFileSync(r,"utf-8"),n=[],i="General";for(let a of o.split(`
28
- `)){let s=a.trim();if(s.startsWith("#")&&!s.startsWith("#=")){let d=s.replace(/^#+\s*/,"").trim();d&&!d.startsWith("These are")&&(i=d);continue}if(!s||s.startsWith("#"))continue;let c=s.indexOf("=");if(c===-1)continue;let p=s.substring(0,c).trim(),f=s.substring(c+1).trim();n.push({name:p,value:f,category:i})}return n}function Fr(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function $r(e,t,r){let o=r==="selfhost"?new Set(Object.keys(kt.selfhost)):new Set;for(let[n,i]of Object.entries(t)){let a=Number(n),s=Number(i);for(let[c,p]of Object.entries(e)){if(o.has(c))continue;if(p===String(a)){e[c]=String(s);continue}let f=new RegExp(`:${a}(?=[/\\s]|$)`,"g");e[c]=p.replaceAll(f,`:${s}`)}}}function Gr(e,t){return e.map(r=>({...r,variables:r.variables.map(o=>{let n=_t(o.name,t);return{...o,defaultValue:n||o.defaultValue}})}))}function At(){return Object.keys(kt.selfhost)}function jr(e){return{...Nr[e]}}function Ot(e){F.existsSync(e)&&F.copyFileSync(e,`${e}.bak`)}function Ur(e,t){let r=Ee.join(e,".env");Ot(r);let o=["# GAIA Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],n=["MONGO","REDIS","POSTGRES","CHROMADB","RABBITMQ","WORKOS","GOOGLE","OPENAI","INFISICAL","LANGSMITH","DISCORD","SLACK","TELEGRAM","CLOUDINARY","COMPOSIO","FIRECRAWL","LIVEKIT","DEEPGRAM","ELEVENLABS","RESEND","SENTRY","POSTHOG","E2B","DODO","NEXT_PUBLIC","GAIA"];function i(s){for(let p of n)if(s===p||s.startsWith(`${p}_`))return p;let c=s.split("_");return c.length===1?"Core":c[0]||"Core"}let a=new Map;for(let[s,c]of Object.entries(t)){let p=i(s);a.has(p)||a.set(p,[]);let d=/[\s#"'\\]/.test(c)||c===""?`"${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:c;a.get(p).push(`${s}=${d}`)}for(let[s,c]of a.entries())o.push(`# ${s} Configuration`),o.push(...c),o.push("");F.writeFileSync(r,o.join(`
29
- `),"utf-8")}function Hr(e,t,r){let o=Ee.join(e,"apps","web",".env.local");Ot(o);let n=Br(e),i=Fr(t,r),a=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],s=new Map;for(let c of n){s.has(c.category)||s.set(c.category,[]);let p=i[c.name]??c.value;s.get(c.category).push({name:c.name,value:p})}if(n.length===0){a.push("# Core URLs");for(let[c,p]of Object.entries(i))a.push(`${c}=${p}`);a.push("")}else for(let[c,p]of s.entries()){a.push(`# ${c}`);for(let{name:f,value:d}of p)a.push(`${f}=${d}`);a.push("")}F.writeFileSync(o,a.join(`
30
- `),"utf-8")}var Wr={8e3:"API_HOST_PORT",5432:"POSTGRES_HOST_PORT",6379:"REDIS_HOST_PORT",27017:"MONGO_HOST_PORT",5672:"RABBITMQ_HOST_PORT",8080:"CHROMADB_HOST_PORT",8083:"MONGO_EXPRESS_HOST_PORT",3e3:"WEB_HOST_PORT"};function Vr(e,t,r){let o=Ee.join(e,"infra","docker",".env");Ot(o);let n=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[i,a]of Object.entries(t)){let s=Number(i),c=Wr[s];c&&n.push(`${c}=${a}`)}if(r==="selfhost"){let i=t[8e3]??8e3;n.push(""),n.push("# Web build args"),n.push(`NEXT_PUBLIC_API_BASE_URL=http://localhost:${i}/api/v1/`)}n.push(""),F.writeFileSync(o,n.join(`
31
- `),"utf-8")}function se(e){let t={};for(let[r,o]of Object.entries(e)){let n=Number(r),i=Wr[n];i&&(t[i]=String(o))}return t}function Yr(e){let t=Ee.join(e,"infra","docker","docker-compose.yml");if(!F.existsSync(t))return;let r=F.readFileSync(t,"utf-8"),o=[{varName:"API_HOST_PORT",hostPort:8e3,containerPort:80},{varName:"CHROMADB_HOST_PORT",hostPort:8080,containerPort:8e3},{varName:"POSTGRES_HOST_PORT",hostPort:5432,containerPort:5432},{varName:"REDIS_HOST_PORT",hostPort:6379,containerPort:6379},{varName:"MONGO_HOST_PORT",hostPort:27017,containerPort:27017},{varName:"RABBITMQ_HOST_PORT",hostPort:5672,containerPort:5672},{varName:"MONGO_EXPRESS_HOST_PORT",hostPort:8083,containerPort:8081},{varName:"WEB_HOST_PORT",hostPort:3e3,containerPort:3e3}],n=!1;for(let{varName:i,hostPort:a,containerPort:s}of o){let c=`"${a}:${s}"`,p=`"\${${i}:-${a}}:${s}"`;r.includes(c)&&(r=r.replaceAll(c,p),n=!0)}n&&F.writeFileSync(t,r,"utf-8")}var qr={API_HOST_PORT:8e3,POSTGRES_HOST_PORT:5432,REDIS_HOST_PORT:6379,MONGO_HOST_PORT:27017,RABBITMQ_HOST_PORT:5672,CHROMADB_HOST_PORT:8080,MONGO_EXPRESS_HOST_PORT:8083,WEB_HOST_PORT:3e3};function ae(e){let t=Ee.join(e,"infra","docker",".env"),r={};if(!F.existsSync(t))return r;let o=F.readFileSync(t,"utf-8");for(let n of o.split(`
32
- `)){let i=n.trim();if(i&&!i.startsWith("#")){let[a,...s]=i.split("=");if(a&&qr[a]){let c=s.join("=").trim().replace(/^["']|["']$/g,""),p=Number(c);!Number.isNaN(p)&&p>0&&p<=65535&&(r[qr[a]]=p)}}}return r}var On=e=>new Promise(t=>setTimeout(t,e)),Xr="dev-start.log",et=".gaia-dev.pid";function Jr(e){let t=W.join(e,".env");return J.existsSync(t)?["--env-file",".env"]:[]}var Mn=60;function Nn(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:Mn;return r===0?void 0:r*60*1e3}function Ln(e,t){let r=["compose","-f","docker-compose.selfhost.yml",...e,"up","-d","--remove-orphans"];return t?.build&&r.push("--build"),t?.pull&&r.push("--pull","always"),r}function Mt(e){let t=W.join(e,et);if(!J.existsSync(t))return null;try{let r=Number.parseInt(J.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function Ze(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function Oe(e,t,r,o,n,i){if(t!=="selfhost")throw r?.("Developer mode must run in foreground."),new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'.");r?.(i?.build?"Building and starting all services in Docker...":"Starting all services in Docker (selfhost mode)...");let a=W.join(e,"infra/docker"),s=o&&Object.keys(o).length>0?se(o):void 0;await U("docker",Ln(Jr(a),i),a,void 0,n,s,Nn()),r?.("All services started in Docker!")}async function Kr(e,t,r,o){let n=W.join(e,"infra/docker"),i=await ge(e);t?.("Stopping Docker services...");try{let a=Jr(n),s=i==="selfhost"?["compose","-f","docker-compose.selfhost.yml",...a,"down"]:["compose",...a,"down"];await U("docker",s,n)}catch{}if(i!=="selfhost"){t?.("Stopping GAIA-managed local processes (safe mode)...");let a=W.join(e,et),s=!1,c=Mt(e),p=typeof c=="number";if(c&&Ze(c))try{if(process.platform==="win32")await U("taskkill",["/PID",String(c),"/T","/F"],e),s=!0;else{try{process.kill(-c,"SIGTERM"),s=!0}catch{process.kill(c,"SIGTERM"),s=!0}if(await On(800),Ze(c))try{process.kill(-c,"SIGKILL")}catch{process.kill(c,"SIGKILL")}}}catch{}try{J.unlinkSync(a)}catch{}if(!s&&o?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports...");try{let f=r?.[8e3]??8e3,d=r?.[3e3]??3e3;if(process.platform==="win32")for(let m of[f,d])try{await U("powershell",["-Command",`Get-NetTCPConnection -LocalPort ${m} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`],e)}catch{}else for(let m of[f,d])try{await U("sh",["-c",`lsof -ti :${m} -sTCP:LISTEN | xargs kill 2>/dev/null || true`],e)}catch{}}catch{}}else s||t?.(p?"Stored GAIA PID is stale. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.":"No GAIA-managed PID found. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.")}t?.("All services stopped.")}async function ge(e){let t=W.join(e,"apps","api",".env");if(!J.existsSync(t))return null;let r=J.readFileSync(t,"utf-8"),o=r.match(/^SETUP_MODE=(.+)$/m);if(o?.[1]){let n=o[1].trim().replace(/^["']|["']$/g,"");if(n==="selfhost"||n==="developer")return n}return r.includes("mongodb://mongo:")?"selfhost":(r.includes("mongodb://localhost:"),"developer")}async function U(e,t,r,o,n,i,a){let{spawn:s}=await import("child_process");return new Promise((c,p)=>{let f=s(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],shell:!0,env:i?{...process.env,...i}:void 0}),d="",m=0,S=!1,v;a&&(v=setTimeout(()=>{S=!0,f.kill("SIGTERM"),p(new Error(`Command timed out after ${Math.round(a/6e4)}m. Check \`docker compose logs\` to debug.`))},a)),f.stdout?.on("data",y=>{let w=y.toString();d+=w,n?.(w),m=Math.min(m+5,95),o?.(m)}),f.stderr?.on("data",y=>{let w=y.toString();d+=w,n?.(w),m=Math.min(m+5,95),o?.(m)}),f.on("close",y=>{v&&clearTimeout(v),!S&&(y===0?(o?.(100),c()):p(new Error(`Command failed with code ${y}: ${d.slice(-500)}`)))}),f.on("error",y=>{v&&clearTimeout(v),!S&&p(y)})})}function $(e){let t=e||process.cwd();for(;t!==W.dirname(t);){if(J.existsSync(W.join(t,"apps/api/app/config/settings_validator.py")))return t;t=W.dirname(t)}let r=Dt();if(r?.repoPath){if(J.existsSync(W.join(r.repoPath,"apps/api/app/config/settings_validator.py")))return r.repoPath;console.warn(`Warning: Saved repo path "${r.repoPath}" is no longer a valid GAIA installation. Resetting config.`),Ae({repoPath:"",setupComplete:!1})}return null}async function zr(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=$();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await ge(t);if(!r)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");if(r!=="developer")throw new Error("Developer mode is not enabled for this repo. Use 'gaia start' for self-host mode.");let o=Qr.join(t,et);try{await Te("mise",[e==="full"?"dev:full":"dev"],t,void 0,n=>{typeof n=="number"&&n>0&&tt.writeFileSync(o,`${n}
33
- `)},process.platform!=="win32")}finally{try{tt.unlinkSync(o)}catch{}}}import{render as fi}from"ink";import gi from"react";import{Box as ct,Text as ve}from"ink";import li from"react";import{ProgressBar as oo,Select as Bt,Spinner as Vn}from"@inkjs/ui";import{Box as g,Text as u,useInput as ce}from"ink";import Le from"ink-text-input";import{useEffect as Be,useRef as Yn,useState as B}from"react";import{Box as Me,Text as rt}from"ink";var x="#00bbff";import{Box as Bn,Text as Fn}from"ink";import{jsx as Zr}from"react/jsx-runtime";var eo=({status:e,step:t})=>t.toLowerCase()==="welcome"?null:Zr(Bn,{width:"100%",paddingX:1,marginTop:1,children:Zr(Fn,{color:"gray",dimColor:!0,children:e})});import{Box as $n}from"ink";import Gn from"ink-big-text";import jn from"ink-gradient";import{jsx as Nt}from"react/jsx-runtime";var Pe=()=>Nt($n,{flexDirection:"column",marginTop:1,marginBottom:1,children:Nt(jn,{colors:[x,"#b0eaff",x],children:Nt(Gn,{text:"GAIA",font:"3d"})})});import{jsx as he,jsxs as Ne}from"react/jsx-runtime";var qn=["Welcome","Prerequisites","Setup Mode","Repository Setup","Environment Setup","Install Tools","Project Setup","Finished"],to=["Detect Repo","Prerequisites","Environment Setup","Project Setup","Finished"],Un={Welcome:"Welcome",Prerequisites:"Prereqs","Setup Mode":"Mode","Repository Setup":"Repo","Environment Setup":"Env","Install Tools":"Tools","Project Setup":"Setup","Detect Repo":"Detect",Finished:"Done"},Hn=({currentStep:e,steps:t})=>{let r=t.indexOf(e);return he(Me,{marginBottom:1,flexWrap:"nowrap",children:t.map((o,n)=>{let i=n<r,a=n===r,s=Un[o]??o;return Ne(Me,{flexShrink:0,children:[n>0&&Ne(rt,{color:"gray",dimColor:!0,children:[" ","\xB7"," "]}),i&&Ne(rt,{color:"green",children:["\u2713 ",s]}),a&&he(rt,{color:x,bold:!0,children:s}),!i&&!a&&he(rt,{color:"gray",dimColor:!0,children:s})]},o)})})},ot=({children:e,status:t,step:r,steps:o=qn})=>Ne(Me,{flexDirection:"column",height:"100%",width:"100%",children:[Ne(Me,{flexGrow:1,flexDirection:"column",children:[he(Pe,{}),he(Hn,{currentStep:r,steps:o}),he(Me,{flexDirection:"column",flexGrow:1,children:e})]}),he(eo,{status:t,step:r})]});import{Spinner as ro}from"@inkjs/ui";import{Box as G,Text as M,useInput as Wn}from"ink";import{jsx as R,jsxs as H}from"react/jsx-runtime";var nt=({checks:e})=>H(G,{flexDirection:"column",borderStyle:"round",paddingX:1,borderColor:x,children:[R(M,{bold:!0,children:"System Checks"}),H(G,{flexDirection:"column",marginTop:1,children:[R(Lt,{label:"Git",status:e.git}),R(Lt,{label:"Docker",status:e.docker}),e.mise&&R(Lt,{label:"Mise",status:e.mise})]})]}),it=({status:e})=>H(G,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[R(M,{bold:!0,children:"Environment Setup"}),R(G,{marginTop:1,children:R(ro,{label:e||"Configuring environment..."})})]}),st=({message:e})=>H(G,{flexDirection:"column",borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[H(M,{color:"red",children:["Error: ",e]}),R(G,{marginTop:1,children:H(M,{dimColor:!0,children:[R(M,{bold:!0,children:"Enter"})," to exit"]})})]}),Lt=({label:e,status:t})=>H(G,{children:[R(G,{marginRight:1,children:t==="pending"?R(ro,{type:"dots"}):t==="success"?R(M,{color:"green",children:"\u2714"}):t==="error"?R(M,{color:"red",children:"\u2716"}):R(M,{color:"yellow",children:"\u26A0"})}),R(M,{children:e})]}),at=({portResults:e,onAccept:t,onAbort:r})=>{Wn((n,i)=>{i.return?t():i.escape&&r()});let o=e.filter(n=>!n.available);return H(G,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[R(G,{marginBottom:1,children:R(M,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>H(G,{children:[H(M,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?"\u2714":n.alternative?"\u26A0":"\u2716"," "]}),H(M,{children:[n.service," (:",n.port,")"]}),!n.available&&H(M,{color:n.alternative?"gray":"red",children:[" ","- in use",n.usedBy?` by ${n.usedBy}`:"",n.alternative?` \u2192 will use :${n.alternative}`:" \u2014 NO ALTERNATIVE FOUND"]})]},n.port)),o.some(n=>!n.alternative)&&R(G,{marginTop:1,children:R(M,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!o.some(n=>!n.alternative)&&o.some(n=>n.alternative)&&R(G,{marginTop:1,children:R(M,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),R(G,{marginTop:1,children:H(M,{dimColor:!0,children:[R(M,{bold:!0,children:"Enter"})," continue \xB7 ",R(M,{bold:!0,children:"ESC"})," abort"]})})]})};import{jsx as l,jsxs as h}from"react/jsx-runtime";var Xn=({onConfirm:e})=>(ce((t,r)=>{r.return&&e()}),h(g,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:x,children:[l(u,{bold:!0,children:"Welcome to GAIA Setup"}),h(g,{flexDirection:"column",marginTop:1,marginBottom:1,children:[l(u,{children:"This wizard will guide you through the setup process:"}),l(u,{children:" 1. Check prerequisites and choose setup mode"}),l(u,{children:" 2. Clone repository"}),l(u,{children:" 3. Configure environment variables"}),l(u,{children:" 4. Install tools and dependencies"})]}),l(u,{dimColor:!0,children:"~5-15 min depending on network speed"}),l(g,{marginTop:1,children:h(u,{color:x,children:[l(u,{bold:!0,children:"Enter"})," to start"]})})]})),Jn=({defaultValue:e,onSubmit:t})=>{let[r,o]=B(e);return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(u,{children:"Clone repository to:"}),l(u,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),h(g,{marginTop:1,children:[l(u,{color:x,children:"\u2192 "}),l(Le,{value:r,onChange:o,onSubmit:t})]})]})},Kn=({repoPath:e,onAction:t})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:"yellow",children:[l(g,{marginBottom:1,children:l(u,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),h(u,{children:["Found a GAIA installation at"," ",l(u,{color:"cyan",bold:!0,children:e})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"What would you like to do?"})}),l(g,{marginTop:1,children:l(Bt,{options:[{label:"Use existing installation",value:"use_existing"},{label:"Delete and re-clone",value:"delete_reclone"},{label:"Choose a different path",value:"different_path"},{label:"Exit setup",value:"exit"}],onChange:o=>t(o)})})]}),Qn=({setupMode:e,portOverrides:t,onConfirm:r})=>{ce((i,a)=>{a.return&&r()});let o=t?.[3e3]??3e3,n=t?.[8e3]??8e3;return e==="selfhost"?h(g,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:"green",padding:1,children:[l(u,{bold:!0,color:"green",children:"GAIA is Running!"}),l(g,{marginTop:1,children:l(u,{color:"green",children:"\u2713 All services started"})}),h(g,{marginTop:1,flexDirection:"column",children:[h(u,{children:["Web:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(u,{children:["API:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," to exit"]})})]}):h(g,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:x,padding:1,children:[l(u,{color:x,bold:!0,children:"You're all set!"}),h(g,{marginTop:1,children:[l(u,{bold:!0,children:"Run: "}),l(u,{color:"cyan",children:"$ gaia dev"})]}),h(g,{marginTop:1,flexDirection:"column",children:[h(u,{children:["Web:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),h(u,{children:["API:"," ",h(u,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," to exit"]})})]})},zn=8,Zn=({logs:e,height:t=zn})=>{let[r,o]=B(0),n=Yn(e.length);Be(()=>{e.length!==n.current&&(n.current=e.length,o(0))},[e.length]),ce((d,m)=>{m.upArrow?o(S=>Math.min(S+1,Math.max(0,e.length-t))):m.downArrow&&o(S=>Math.max(0,S-1))});let i=e.length,a=Math.max(0,i-t-r),s=Math.max(0,i-r),c=e.slice(a,s),p=a,f=r;return h(g,{flexDirection:"column",marginTop:1,marginLeft:1,children:[p>0&&h(u,{color:"gray",dimColor:!0,children:["\u2191 ",p," more line",p!==1?"s":""]}),l(g,{flexDirection:"column",height:t,overflow:"hidden",children:c.map((d,m)=>l(u,{color:"gray",wrap:"truncate",children:d},`${a}-${m}`))}),f>0?h(u,{color:"gray",dimColor:!0,children:["\u2193 ",f," more line",f!==1?"s":""]}):l(u,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},Ft=({phase:e,progress:t,isComplete:r,logs:o,title:n})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(g,{marginBottom:1,children:l(u,{bold:!0,color:x,children:n||"Installing Dependencies"})}),h(g,{flexDirection:"column",gap:1,children:[l(g,{children:r?h(u,{color:"green",children:["\u2713 ",e]}):l(Vn,{label:e||"Preparing..."})}),!r&&t>0&&l(g,{width:50,children:l(oo,{value:t})}),!r&&o&&o.length>0&&l(Zn,{logs:o}),!r&&l(g,{marginTop:1,children:l(u,{color:"gray",dimColor:!0,children:"This may take a few minutes..."})})]})]}),$t=({onSelect:e})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(u,{bold:!0,children:"Setup Mode"}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"How do you want to run GAIA?"})}),l(g,{marginTop:1,children:l(Bt,{options:[{label:"Self-Host \u2014 run everything in Docker",value:"selfhost"},{label:"Developer \u2014 local dev with hot reload",value:"developer"}],onChange:r=>e(r)})})]}),Gt=({onSelect:e})=>h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(u,{bold:!0,children:"Environment Variables Setup"}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"Choose how you want to configure environment variables:"})}),l(g,{marginTop:1,children:l(Bt,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),h(g,{marginTop:1,flexDirection:"column",children:[l(u,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),l(u,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),jt=({onSubmit:e})=>{let[t,r]=B({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=B(0),[i,a]=B(null),s=[{key:"INFISICAL_PROJECT_ID",description:"Found in your Infisical project settings"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_ID",description:"From Access Control \u2192 Machine Identities"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET",description:"Generated when creating the machine identity"}];ce((p,f)=>{if(f.tab||f.downArrow)n(d=>d<s.length-1?d+1:d);else if(f.upArrow)n(d=>d>0?d-1:d);else if(f.return){if(o<s.length-1){n(m=>m+1);return}let d=s.filter(m=>!t[m.key].trim());if(d.length>0){a(`Required: ${d.map(S=>S.key).join(", ")}`);let m=s.findIndex(S=>!t[S.key].trim());m>=0&&n(m);return}e(t)}});let c=s[o];return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:x,children:[l(g,{marginBottom:1,children:l(u,{bold:!0,color:x,children:"Infisical Configuration"})}),l(g,{marginBottom:1,children:l(u,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),h(g,{marginBottom:1,flexDirection:"column",children:[l(u,{color:"gray",children:"Configure your Infisical credentials."}),h(u,{color:"gray",dimColor:!0,children:["Visit"," ",l(u,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),s.map((p,f)=>{let d=p.key.includes("SECRET")||p.key.includes("TOKEN");return h(g,{flexDirection:"column",marginBottom:1,children:[l(g,{children:h(u,{color:f===o?x:"white",children:[f===o?"\u25B8 ":" ",p.key,":"]})}),l(g,{marginLeft:2,children:l(u,{color:"gray",dimColor:!0,children:p.description})}),f===o?l(g,{marginLeft:2,children:l(Le,{value:t[p.key],onChange:m=>{r(S=>({...S,[p.key]:m})),a(null)},placeholder:"Enter value...",mask:d?"*":void 0})}):l(g,{marginLeft:2,children:l(u,{color:t[p.key]?"green":"gray",children:t[p.key]?d?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[p.key]}`:"(not set)"})})]},p.key)}),i&&l(g,{marginTop:1,children:l(u,{color:"red",children:i})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," confirm \xB7 ",l(u,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},qt=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,i]=B(()=>{let m={};for(let S of e.variables)m[S.name]=S.defaultValue||"";return m}),[a,s]=B(0),[c,p]=B(null);Be(()=>{let m={};for(let S of e.variables)m[S.name]=S.defaultValue||"";i(m),s(0),p(null)},[e.name]),ce((m,S)=>{if(S.tab||S.downArrow)s(v=>v<e.variables.length-1?v+1:v);else if(S.upArrow)s(v=>v>0?v-1:v);else if(S.escape){let v=e.variables.filter(y=>y.required&&!n[y.name]?.trim());if(v.length>0){p(`Required fields cannot be skipped: ${v.map(y=>y.name).join(", ")}`);return}o(n)}});let f=()=>{if(a<e.variables.length-1)s(a+1);else{let m=e.variables.filter(S=>S.required&&!n[S.name]?.trim());if(m.length>0){p(`Required fields are missing: ${m.map(S=>S.name).join(", ")}`);return}p(null),o(n)}},d=e.variables.some(m=>m.required);return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:c?"red":x,children:[h(g,{justifyContent:"space-between",children:[h(u,{bold:!0,children:["Configure ",e.name]}),h(u,{color:"gray",children:["Group ",t+1," / ",r]})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:e.description})}),l(g,{marginTop:1,flexDirection:"column",children:e.variables.map((m,S)=>{let v=S===a,y=!!m.defaultValue;return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[h(u,{color:v?x:"gray",bold:v,children:[v?"\u279C ":" ",m.name]}),m.required&&h(u,{color:"red",bold:!0,children:[" ","*"]}),y&&!v&&h(u,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),v&&l(g,{marginLeft:2,children:l(Le,{value:n[m.name]||"",onChange:w=>{i(b=>({...b,[m.name]:w})),c&&p(null)},onSubmit:f,placeholder:y?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&l(g,{marginTop:1,children:h(u,{color:"red",bold:!0,children:["\u26A0 ",c]})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," next \xB7 ",l(u,{bold:!0,children:"\u2191\u2193"})," navigate",!d&&h(u,{children:[" ","\xB7 ",l(u,{bold:!0,children:"ESC"})," skip"]})]})})]})},Ut=({alternatives:e,onSubmit:t})=>{let[r,o]=B(new Set),[n,i]=B({}),[a,s]=B(0),[c,p]=B(null);Be(()=>{let w={};for(let b of e)for(let E of b.variables)w[E.name]=E.defaultValue||"";i(w)},[e]);let f=[];for(let w=0;w<e.length;w++)if(f.push({type:"provider",categoryIndex:w}),r.has(w)){let b=e[w];if(b)for(let E=0;E<b.variables.length;E++)f.push({type:"field",categoryIndex:w,fieldIndex:E})}f.push({type:"submit"});let d=f[a],m=d?.type==="field",S=d?.type==="submit";ce((w,b)=>{let E=Math.min(a,f.length-1);if(E!==a){s(E);return}if(m)b.upArrow?s(P=>Math.max(0,P-1)):(b.downArrow||b.tab)&&s(P=>Math.min(f.length-1,P+1));else if(S)b.upArrow?s(P=>Math.max(0,P-1)):(b.return||w===" ")&&y();else if(b.upArrow)s(P=>Math.max(0,P-1));else if(b.downArrow||b.tab)s(P=>Math.min(f.length-1,P+1));else if((b.return||w===" ")&&d?.type==="provider"){let P=d.categoryIndex;o(Z=>{let _=new Set(Z);return _.has(P)?_.delete(P):_.add(P),_}),c&&p(null)}});let v=()=>{c&&p(null),s(w=>Math.min(f.length-1,w+1))},y=()=>{let w=[],b={};for(let E of r){let P=e[E];if(!P)continue;if(P.variables.some(_=>n[_.name]?.trim())){w.push(P.name);for(let _ of P.variables){let Ge=n[_.name];Ge&&(b[_.name]=Ge)}}}if(w.length===0){r.size===0?p("Enable at least one provider (press Space or Enter)"):p("Enter a value for at least one field");return}t(w,b)};return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:c?"red":x,children:[h(g,{justifyContent:"space-between",children:[l(u,{bold:!0,children:"Configure AI Provider"}),l(u,{color:"yellow",children:"* At least one required"})]}),l(g,{marginTop:1,children:l(u,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),l(g,{marginTop:1,flexDirection:"column",children:e.map((w,b)=>{let E=r.has(b),P=f.findIndex(_=>_.type==="provider"&&_.categoryIndex===b),Z=a===P;return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[l(u,{color:Z?x:void 0,bold:Z,children:Z?"\u279C ":" "}),l(u,{color:E?"green":"gray",children:E?"[\u2714]":"[ ]"}),h(u,{color:E?x:"gray",bold:E,children:[" ",w.name]}),w.description&&h(u,{color:"gray",dimColor:!0,children:[" ","- ",w.description]})]}),Z&&w.docsUrl&&h(g,{marginLeft:6,children:[l(u,{color:"yellow",children:"\u{1F4D6} "}),l(u,{color:"blue",underline:!0,children:w.docsUrl})]}),E&&l(g,{marginLeft:4,flexDirection:"column",marginTop:1,children:w.variables.map((_,Ge)=>{let Uo=f.findIndex(Re=>Re.type==="field"&&Re.categoryIndex===b&&Re.fieldIndex===Ge),Se=a===Uo,zt=!!_.defaultValue,yt=n[_.name]||"";return h(g,{flexDirection:"column",marginBottom:1,children:[h(g,{children:[h(u,{color:Se?x:"gray",bold:Se,children:[Se?" \u279C ":" ",_.name]}),!Se&&yt&&l(u,{color:"green",children:" \u2713"}),!Se&&!yt&&zt&&h(u,{color:"gray",dimColor:!0,children:[" ","(default: ",_.defaultValue,")"]})]}),Se&&l(g,{marginLeft:4,children:l(Le,{value:yt,onChange:Re=>{i(Ho=>({...Ho,[_.name]:Re})),c&&p(null)},onSubmit:v,placeholder:zt?`Default: ${_.defaultValue}`:"Enter value..."})})]},_.name)})})]},w.name)})}),c&&l(g,{marginTop:1,children:h(u,{color:"red",bold:!0,children:["\u26A0 ",c]})}),h(g,{marginTop:1,children:[l(u,{color:S?x:void 0,bold:S,children:S?"\u279C ":" "}),l(g,{borderStyle:"round",borderColor:S?x:"gray",paddingX:2,children:l(u,{color:S?x:"gray",bold:S,children:"Continue \u2192"})})]}),l(g,{marginTop:1,children:l(u,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},Ht=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[i,a]=B(e.defaultValue||""),[s,c]=B(null);Be(()=>{a(e.defaultValue||""),c(null)},[e.name]),ce((d,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}n()}});let p=d=>{if(e.required&&!d.trim()){c("This field is required");return}c(null),o(d)},f=!!e.defaultValue;return h(g,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:"round",borderColor:s?"red":x,children:[h(g,{justifyContent:"space-between",children:[h(g,{children:[l(u,{color:x,bold:!0,children:e.name}),e.required?l(u,{color:"red",children:" *"}):h(u,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),h(u,{color:"gray",children:[t+1,"/",r]})]}),l(g,{marginLeft:1,children:l(u,{color:"gray",children:e.description})}),h(g,{marginTop:1,children:[l(u,{color:x,children:"\u2192 "}),l(Le,{value:i,onChange:d=>{a(d),s&&c(null)},onSubmit:p,placeholder:f?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),s&&l(g,{marginTop:1,children:l(u,{color:"red",children:s})}),l(g,{marginTop:1,children:h(u,{dimColor:!0,children:[l(u,{bold:!0,children:"Enter"})," confirm",!e.required&&h(u,{children:[" ","\xB7 ",l(u,{bold:!0,children:"ESC"})," skip"]})]})})]})},no=({store:e})=>{let[t,r]=B(e.currentState);return Be(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),ce((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),h(ot,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&l(Xn,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&l(nt,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&l(at,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&l(Jn,{defaultValue:t.inputRequest.meta.default,onSubmit:o=>e.submitInput(o)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&l(Kn,{repoPath:t.data.existingRepoPath,onAction:o=>e.submitInput(o)}),t.step==="Repository Setup"&&!t.inputRequest&&h(g,{flexDirection:"column",borderStyle:"round",padding:1,borderColor:x,children:[l(u,{bold:!0,children:"Cloning Repository"}),h(g,{marginTop:1,flexDirection:"column",children:[l(oo,{value:t.data.repoProgress||0}),t.data.repoPhase&&l(g,{marginTop:1,children:l(u,{color:"gray",children:t.data.repoPhase})})]})]}),t.inputRequest?.id==="setup_mode"&&l($t,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&l(Gt,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&l(jt,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&l(Ht,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:o=>e.submitInput(o),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&l(qt,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&l(Ut,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&l(it,{status:t.status}),t.step==="Finished"&&l(Qn,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&l(Ft,{title:t.step==="Install Tools"?"Installing Tools":"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.step==="Install Tools"?t.data.toolComplete||!1:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.error&&l(st,{message:t.error.message})]})};import{Spinner as ei}from"@inkjs/ui";import{Box as N,Text as C,useInput as io}from"ink";import{useEffect as so,useRef as ti,useState as ao}from"react";import{jsx as A,jsxs as T}from"react/jsx-runtime";var Wt=8,ri=({logs:e})=>{let[t,r]=ao(0),o=ti(e.length);so(()=>{e.length!==o.current&&(o.current=e.length,r(0))},[e.length]),io((f,d)=>{d.upArrow?r(m=>Math.min(m+1,Math.max(0,e.length-Wt))):d.downArrow&&r(m=>Math.max(0,m-1))});let n=e.length,i=Math.max(0,n-Wt-t),a=Math.max(0,n-t),s=e.slice(i,a),c=i,p=t;return T(N,{flexDirection:"column",marginTop:1,marginLeft:1,children:[c>0&&T(C,{color:"gray",dimColor:!0,children:["\u2191 ",c," more line",c!==1?"s":""]}),A(N,{flexDirection:"column",height:Wt,overflow:"hidden",children:s.map((f,d)=>A(C,{color:"gray",wrap:"truncate",children:f},i+d))}),p>0?T(C,{color:"gray",dimColor:!0,children:["\u2193 ",p," more line",p!==1?"s":""]}):A(C,{color:"gray",dimColor:!0,children:"\u2191\u2193 scroll"})]})},co=({store:e})=>{let[t,r]=ao(e.currentState);return so(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),io((o,n)=>{(n.return||n.escape)&&(t.data.started||t.data.stopped||t.error)&&e.submitInput("exit")}),T(N,{flexDirection:"column",width:"100%",children:[A(Pe,{}),(t.step==="Starting"||t.step==="Stopping")&&T(N,{flexDirection:"column",marginTop:1,paddingX:2,borderStyle:"round",borderColor:x,children:[A(ei,{label:t.status||"Working..."}),t.data.repoPath&&A(N,{marginTop:1,children:T(C,{color:"gray",children:["Repository: ",t.data.repoPath]})}),t.data.setupMode&&A(N,{children:T(C,{color:"gray",children:["Mode: ",t.data.setupMode]})}),t.data.dockerLogs&&t.data.dockerLogs.length>0&&A(ri,{logs:t.data.dockerLogs})]}),t.step==="Running"&&t.data.started&&T(N,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:"green",children:[T(C,{color:"green",bold:!0,children:["\u2713"," GAIA is running!"]}),t.data.setupMode!=="developer"&&T(N,{marginTop:1,flexDirection:"column",children:[T(C,{children:["Web:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),T(C,{children:["API:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),t.data.setupMode==="developer"&&T(N,{marginTop:1,flexDirection:"column",children:[T(N,{flexDirection:"column",children:[T(C,{children:["Web:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.webPort||3e3]})]}),T(C,{children:["API:"," ",T(C,{color:"cyan",bold:!0,children:["http://localhost:",t.data.apiPort||8e3]})]})]}),T(N,{marginTop:1,flexDirection:"column",children:[A(C,{color:"gray",children:"Use gaia dev / gaia dev full for foreground Nx TUI."}),T(C,{color:"gray",children:["Run ",A(C,{color:x,children:"gaia logs"})," to stream logs."]}),T(C,{color:"gray",children:["Run ",A(C,{color:x,children:"gaia stop"})," to shut down."]})]})]}),A(N,{marginTop:1,children:T(C,{dimColor:!0,children:[A(C,{bold:!0,children:"Enter"})," to exit"]})})]}),t.step==="Stopped"&&t.data.stopped&&T(N,{flexDirection:"column",marginTop:1,paddingX:2,paddingY:1,borderStyle:"round",borderColor:x,children:[T(C,{color:x,bold:!0,children:["\u2713"," ",t.status||"All GAIA services stopped."]}),t.data.stopMode==="force-ports"&&A(N,{marginTop:1,children:A(C,{color:"yellow",children:"Force-port cleanup was enabled and may have stopped non-GAIA listeners on app ports."})}),A(N,{marginTop:1,children:T(C,{dimColor:!0,children:[A(C,{bold:!0,children:"Enter"})," to exit"]})})]}),t.error&&T(N,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:[T(C,{color:"red",children:["Error: ",t.error.message]}),A(N,{marginTop:1,children:T(C,{dimColor:!0,children:[A(C,{bold:!0,children:"Enter"})," to exit"]})})]})]})};import{Spinner as oi}from"@inkjs/ui";import{Box as le,Text as V,useInput as lo}from"ink";import{useEffect as ni,useState as ii}from"react";import{jsx as D,jsxs as K}from"react/jsx-runtime";var po=({store:e})=>{let[t,r]=ii(e.currentState);return ni(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),lo((o,n)=>{(n.return||n.escape)&&t.error&&e.submitInput("exit")}),K(ot,{status:t.status,step:t.step,steps:to,children:[t.step==="Detect Repo"&&K(le,{flexDirection:"column",paddingX:2,borderStyle:"round",borderColor:x,children:[D(V,{bold:!0,children:"Detecting GAIA Repository"}),D(le,{marginTop:1,children:D(oi,{label:"Searching for repository..."})}),t.data.repoPath&&D(le,{marginTop:1,children:K(V,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&D(nt,{checks:t.data.checks}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&D(at,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&D($t,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_method"&&D(Gt,{onSelect:o=>e.submitInput(o)}),t.inputRequest?.id==="env_infisical"&&D(jt,{onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&D(Ht,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:o=>e.submitInput(o),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&D(qt,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:o=>e.submitInput(o)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&D(Ut,{alternatives:t.data.alternativeGroups,onSubmit:(o,n)=>e.submitInput({selectedGroups:o,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&D(it,{status:t.status}),t.step==="Project Setup"&&D(Ft,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&D(si,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&D(st,{message:t.error.message})]})},si=({setupMode:e,portOverrides:t,onConfirm:r})=>{lo((a,s)=>{s.return&&r()});let o=t?.[3e3]??3e3,n=t?.[8e3]??8e3,i=e==="selfhost";return K(le,{flexDirection:"column",marginTop:2,borderStyle:"round",borderColor:x,padding:1,children:[D(V,{color:x,bold:!0,children:"Setup Complete!"}),K(le,{marginTop:1,children:[D(V,{bold:!0,children:"Run: "}),D(V,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),K(le,{marginTop:1,flexDirection:"column",children:[K(V,{children:["Web:"," ",K(V,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),K(V,{children:["API:"," ",K(V,{color:"cyan",bold:!0,children:["http://localhost:",n]})]})]}),D(le,{marginTop:1,children:D(V,{color:"gray",children:i?"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup":"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),D(le,{marginTop:1,children:K(V,{dimColor:!0,children:[D(V,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as ai}from"@inkjs/ui";import{Box as O,Text as k,useInput as ci}from"ink";import{useEffect as uo,useState as Vt}from"react";import{jsx as I,jsxs as L}from"react/jsx-runtime";var mo=({store:e})=>{let[t,r]=Vt(e.currentState),[o,n]=Vt(!1),[i,a]=Vt(null);return uo(()=>{let s=()=>r({...e.currentState});return e.on("change",s),()=>{e.off("change",s)}},[e]),uo(()=>{n(!1),a(new Date().toLocaleTimeString())},[t.data.services]),ci((s,c)=>{(c.return||c.escape)&&t.step==="Results"&&e.submitInput("exit"),s==="r"&&t.step==="Results"&&t.data.refreshable&&!o&&(n(!0),e.submitInput("refresh"))}),L(O,{flexDirection:"column",width:"100%",children:[I(Pe,{}),t.step==="Checking"&&I(O,{marginTop:1,children:I(ai,{label:t.data.services?"Refreshing service health...":"Checking service health..."})}),t.step==="Results"&&t.data.services&&L(O,{flexDirection:"column",children:[L(O,{flexDirection:"column",borderStyle:"round",borderColor:x,paddingX:2,paddingY:1,children:[L(O,{justifyContent:"space-between",children:[I(k,{bold:!0,color:x,children:"GAIA Service Status"}),i&&L(k,{color:"gray",dimColor:!0,children:["checked ",i," \xB7 ",I(k,{bold:!0,children:"r"})," refresh"]})]}),L(O,{marginTop:1,flexDirection:"column",children:[L(O,{children:[I(O,{width:22,children:I(k,{bold:!0,children:"Service"})}),I(O,{width:10,children:I(k,{bold:!0,children:"Status"})}),I(O,{width:10,children:I(k,{bold:!0,children:"Latency"})})]}),I(k,{color:"gray",children:"\u2500".repeat(42)}),[...t.data.services].sort((s,c)=>s.status==="down"&&c.status!=="down"?-1:s.status!=="down"&&c.status==="down"?1:s.name.localeCompare(c.name)).map(s=>L(O,{children:[I(O,{width:22,children:L(k,{children:[s.name," (:",s.port,")"]})}),I(O,{width:10,children:I(k,{color:s.status==="up"?"green":"red",bold:!0,children:s.status==="up"?"\u2713 UP":"\u2717 DOWN"})}),I(O,{width:10,children:I(k,{color:"gray",children:s.latency?`${s.latency}ms`:"--"})})]},s.name))]})]}),t.data.docker&&L(O,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:2,paddingY:1,marginTop:1,children:[I(k,{bold:!0,children:"Docker Containers"}),L(k,{color:"gray",children:["Docker:"," ",t.data.docker.running?I(k,{color:"green",children:"Running"}):I(k,{color:"red",children:"Not running"})]}),t.data.docker.containers?.length>0&&I(O,{marginTop:1,flexDirection:"column",children:t.data.docker.containers.map(s=>L(O,{children:[L(k,{color:s.status==="running"?"green":"red",children:[s.status==="running"?"\u2713":"\u2717"," "]}),I(k,{children:s.name}),s.health&&L(k,{color:"gray",children:[" (",s.health,")"]})]},s.name))})]}),I(O,{marginTop:1,children:L(k,{dimColor:!0,children:[I(k,{bold:!0,children:"Enter"})," exit \xB7 ",I(k,{bold:!0,children:"r"})," refresh"]})})]}),t.error&&I(O,{borderStyle:"single",borderColor:"red",padding:1,marginTop:2,children:L(k,{color:"red",children:["Error: ",t.error.message]})})]})};import{jsx as Y,jsxs as Fe}from"react/jsx-runtime";var pi=["init","setup","status","start","stop"],Yt=class extends li.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Fe(ct,{flexDirection:"column",padding:1,children:[Y(ve,{color:"red",bold:!0,children:"An unexpected error occurred:"}),Y(ve,{color:"red",children:this.state.error.message}),this.state.error.stack&&Y(ct,{marginTop:1,children:Y(ve,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},ui=({store:e,command:t})=>{switch(t){case"init":return Y(no,{store:e});case"setup":return Y(po,{store:e});case"status":return Y(mo,{store:e});case"start":case"stop":return Y(co,{store:e,command:t});default:return Fe(ct,{flexDirection:"column",padding:1,children:[Fe(ve,{color:"red",children:["Unknown command: ",t]}),Fe(ct,{marginTop:1,flexDirection:"column",children:[Y(ve,{bold:!0,children:"Available commands:"}),pi.map(r=>Fe(ve,{children:[" ",Y(ve,{color:"cyan",children:r})]},r))]})]})}},fo=({store:e,command:t})=>Y(Yt,{children:Y(ui,{store:e,command:t})});import{EventEmitter as di}from"events";var mi=150,Xt=class extends di{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;autoResolveInputs=new Map;setAutoResolve(t,r="exit"){this.autoResolveInputs.set(t,r)}get currentState(){return this.state}scheduleEmit(){this.emitPending=!0,this.emitTimer||(this.emitTimer=setTimeout(()=>{this.emitTimer=null,this.emitPending&&(this.emitPending=!1,this.emit("change",this.state))},mi))}emitNow(){this.emitTimer&&(clearTimeout(this.emitTimer),this.emitTimer=null),this.emitPending=!1,this.emit("change",this.state)}setStep(t){this.state.step=t,this.emitNow()}setStatus(t){this.state.status=t,this.scheduleEmit()}setError(t){this.state.error=t,t!==null&&this.inputResolver&&(this.inputResolver(null),this.inputResolver=null,this.state.inputRequest=null),this.emitNow()}updateData(t,r){this.state.data={...this.state.data,[t]:r},this.scheduleEmit()}waitForInput(t,r,o){return this.autoResolveInputs.has(t)?(this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t))):(this.state.inputRequest={id:t,meta:r},this.emitNow(),new Promise(n=>{if(this.inputResolver=n,o!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),n(null))},o),a=this.inputResolver;this.inputResolver=s=>{clearTimeout(i),a(s)}}}))}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},go=()=>new Xt;function Jt(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function ho(e){if(Jt())return;let t=e?`'gaia ${e}'`:"this command";console.error(`Error: ${t} needs an interactive terminal (TTY) to prompt for input.`),console.error("Re-run it from a regular shell session \u2014 not a pipe, redirect, or non-TTY environment."),process.exit(1)}function vo(e){let t="",r="",o="";e.on("change",n=>{n.step&&n.step!==t&&(t=n.step,console.info(`
34
- [${n.step}]`)),n.status&&n.status!==r&&(r=n.status,console.info(` ${n.status}`)),n.error&&n.error.message!==o&&(o=n.error.message,console.error(` Error: ${n.error.message}`))})}var hi=50,vi=130;async function z(e){let t=go();if(e.whenNonInteractive==="fail"){ho(e.command),await So(t,e);return}Jt()?await So(t,e):await Si(t,e)}async function Si(e,t){vo(e);for(let[r,o]of t.autoResolve??[])e.setAutoResolve(r,o);try{await t.runFlow(e),t.onPlainComplete?.(e)}catch(r){e.setError(r)}yo(e)}async function So(e,t){let{unmount:r}=fi(gi.createElement(fo,{store:e,command:t.command})),o=()=>{r(),process.exit(vi)};process.once("SIGINT",o),process.once("SIGTERM",o),await new Promise(n=>setTimeout(n,hi));try{await t.runFlow(e)}catch(n){e.setError(n)}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}e.currentState.error&&await e.waitForInput("exit"),r(),yo(e)}function yo(e){let t=e.currentState.error?1:0,r=[process.stdout,process.stderr].filter(n=>n.writableLength>0);r.length===0&&process.exit(t);let o=r.length;for(let n of r)n.once("drain",()=>{o-=1,o===0&&process.exit(t)})}import*as ne from"fs";import*as Po from"os";import*as ue from"path";import*as xo from"path";var yi=e=>new Promise(t=>setTimeout(t,e));async function lt(e){e.setStep("Setup Mode"),e.setStatus("Choose how to run GAIA...");let t=await e.waitForInput("setup_mode");return e.updateData("setupMode",t),t}async function pt(e,t,r,o){e.setStep("Environment Setup"),e.setStatus("Configuring environment..."),e.updateData("setupMode",r),e.setStatus("Configuring environment variables...");let n=await e.waitForInput("env_method");e.updateData("envMethod",n);let i={};i.ENV="development";let a=At();for(let c of a){let p=_t(c,r);p&&(i[c]=p)}let s=jr(r);for(let[c,p]of Object.entries(s))i[c]=p;if(n==="infisical")await xi(e,i),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.");else try{await wi(e,t,i,r)}catch(c){e.setError(c);return}o&&$r(i,o,r);try{await bi(e,t,i,r,o)}catch(c){e.setError(c);return}await yi(1e3)}async function xi(e,t){e.setStatus("Configuring Infisical...");let r=await e.waitForInput("env_infisical");t.INFISICAL_PROJECT_ID=r.INFISICAL_PROJECT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_ID=r.INFISICAL_MACHINE_IDENTITY_CLIENT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET=r.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET}async function wi(e,t,r,o){e.setStatus("Parsing environment variables...");let n;try{n=await Lr(t),n=Gr(n,o)}catch(v){throw o==="selfhost"?new Error(`Manual environment setup requires Python to parse config schema.
35
- For self-host mode, we recommend using Infisical for secret management.
36
- Alternatively, install Python 3.11+ and try again.
37
-
38
- Original error: ${v.message}`):new Error(`Failed to parse settings: ${v.message}`)}let i=new Set,a=[],s=new Set;for(let v of n)if(v.alternativeGroup&&!s.has(v.name)){let y=n.find(w=>w.name===v.alternativeGroup);y&&(a.push([v,y]),i.add(v.name),i.add(y.name),s.add(v.name),s.add(y.name))}let c=n.filter(v=>v.variables.length===1&&!i.has(v.name)),p=n.filter(v=>v.variables.length>1&&!i.has(v.name));for(let v of a){e.updateData("alternativeGroups",v),e.setStatus("Choose an AI provider...");let y=await e.waitForInput("env_alternatives");for(let[w,b]of Object.entries(y.values))b&&(r[w]=b)}let f=At(),m=[...c.flatMap(v=>v.variables).filter(v=>!f.includes(v.name))].sort((v,y)=>v.required&&!y.required?-1:!v.required&&y.required?1:0);e.updateData("envVarTotal",m.length);for(let v=0;v<m.length;v++){let y=m[v];if(!y)continue;e.updateData("currentEnvVar",y),e.updateData("envVarIndex",v),e.setStatus(`Configuring ${y.name}...`);let w=await e.waitForInput("env_var",{varName:y.name});(w||y.required||y.defaultValue)&&(r[y.name]=w||y.defaultValue||"")}let S=[...p].filter(v=>!v.variables.every(y=>f.includes(y.name))).sort((v,y)=>{let w=v.variables.some(E=>E.required),b=y.variables.some(E=>E.required);return w&&!b?-1:!w&&b?1:0});e.updateData("envGroupTotal",S.length);for(let v=0;v<S.length;v++){let y=S[v];if(!y)continue;e.updateData("currentEnvGroup",y),e.updateData("envGroupIndex",v),e.setStatus(`Configuring ${y.name}...`);let w=await e.waitForInput("env_group",{groupName:y.name});for(let[b,E]of Object.entries(w)){let P=y.variables.find(Z=>Z.name===b);(E||P?.required||P?.defaultValue)&&(r[b]=E||P?.defaultValue||"")}}}async function bi(e,t,r,o,n){e.setStatus("Writing API environment file...");try{let a=xo.join(t,"apps","api");Ur(a,r),e.setStatus("API environment variables configured!")}catch(a){throw new Error(`Failed to write API .env file: ${a.message}`)}e.setStatus("Writing web environment file...");try{Hr(t,o,n),e.setStatus("Web environment variables configured!")}catch(a){throw new Error(`Failed to write web .env file: ${a.message}`)}let i=n&&Object.keys(n).length>0;if(i||o==="selfhost"){e.setStatus("Writing Docker Compose environment...");try{i&&Yr(t),Vr(t,n??{},o),e.setStatus("Docker Compose environment configured!")}catch(a){throw new Error(`Failed to write Docker Compose .env: ${a.message}`)}}}import{execa as oe}from"execa";var pe={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},Ti={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",3e3:"Web Frontend",8080:"ChromaDB",8083:"Mongo Express"};async function wo(){try{return await oe("git",["--version"]),"success"}catch{return"error"}}async function ut(){let e=!1,t=!1,r;try{await oe("docker",["--version"]),e=!0}catch{return{name:"Docker",installUrl:pe.docker,installed:!1,working:!1,errorMessage:"Docker is not installed"}}try{await oe("docker",["info"],{timeout:5e3}),t=!0}catch{r="Docker is installed but the daemon is not running. Please start Docker Desktop or the Docker daemon."}return{name:"Docker",installUrl:pe.docker,installed:e,working:t,errorMessage:r}}async function bo(){try{return await oe("mise",["--version"]),"success"}catch{return"missing"}}async function To(){if((await import("node:os")).platform()==="win32")try{return await oe("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await oe("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function Co(e){let t=await import("node:net"),r=[],o=n=>new Promise(i=>{let a=t.createServer();a.once("error",()=>i(!1)),a.once("listening",()=>{a.close(()=>i(!0))}),a.listen(n)});for(let n of e){let i=Ti[n]||`Port ${n}`;if(await o(n))r.push({port:n,service:i,available:!0});else{let s=await Ci(n),c=await Ii(n+1,n+100,o);r.push({port:n,service:i,available:!1,usedBy:s,alternative:c||void 0})}}return r}async function Ci(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:o}=await oe("netstat",["-ano","-p","TCP"]),n=o.trim().split(`
39
- `);for(let i of n)if(i.includes(`:${e}`)&&i.includes("LISTENING")){let a=i.trim().split(/\s+/),s=a[a.length-1];if(s)try{let{stdout:c}=await oe("tasklist",["/FI",`PID eq ${s}`,"/FO","CSV","/NH"]);return c.trim().split(",")[0]?.replace(/"/g,"")||`PID ${s}`}catch{return`PID ${s}`}}}catch{}return}try{let{stdout:o}=await oe("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),n=o.trim().split(`
40
- `);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function Ii(e,t,r){for(let o=e;o<=t;o++)if(await r(o))return o;return null}var X=e=>new Promise(t=>setTimeout(t,e)),dt=(e,t="dependencyLogs")=>r=>{let o=e.currentState.data[t]||[],n=r.split(`
41
- `).filter(i=>i.trim()!=="");e.updateData(t,[...o,...n].slice(-30))};async function mt(e){e.updateData("checks",{git:"pending",docker:"pending"}),await X(500);let t=await wo();e.updateData("checks",{...e.currentState.data.checks,git:t});let r=await ut(),o=r.working?"success":"error";e.updateData("checks",{...e.currentState.data.checks,docker:o}),r.working||e.updateData("dockerError",r.errorMessage);let n=[];if(t==="error"&&n.push({name:"Git"}),o==="error"&&n.push({name:"Docker",message:r.errorMessage}),n.length>0){let i=["Prerequisites failed:"];for(let a of n)i.push(` \u2022 ${a.name}: ${a.message||"Not installed or not working"}`);return i.push(`
42
- Installation guides:`),t==="error"&&i.push(` \u2022 Git: ${pe.git}`),o==="error"&&(r.installed?i.push(" \u2022 Docker: Start Docker Desktop or run 'sudo systemctl start docker'"):i.push(` \u2022 Docker: ${pe.docker}`)),e.setError(new Error(i.join(`
43
- `))),null}return{gitStatus:t,dockerStatus:o,dockerInfo:r}}async function ft(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await bo();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise..."),t=await To()?"success":"error",e.updateData("checks",{...e.currentState.data.checks,mise:t})),t==="error"?(e.setError(new Error(`Developer mode requires Mise but it failed to install.
44
- \u2022 Mise: ${pe.mise}`)),null):"success"}async function gt(e){e.setStatus("Checking Ports...");let r=await Co([8e3,5432,6379,27017,5672,3e3,8080,8083]),o={},n=r.filter(i=>!i.available);if(n.length>0){let i=n.filter(s=>!s.alternative);if(i.length>0)return e.setError(new Error(`Cannot find free alternative ports for: ${i.map(s=>`${s.port} (${s.service})`).join(", ")}. Free these ports and try again.`)),null;if(e.updateData("portConflicts",r),await e.waitForInput("port_conflicts")==="abort")return e.setError(new Error("Port conflicts not resolved. Please free the ports and try again.")),null;for(let s of r)!s.available&&s.alternative&&(o[s.port]=s.alternative)}return e.updateData("portOverrides",o),e.setStatus("Prerequisites check complete!"),await X(1e3),o}async function Io(e,t,r,o){e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project..."),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration..."),await U("mise",["trust"],t,void 0,o),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools..."),await U("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},o),e.updateData("dependencyPhase","Running mise setup...");let n=Object.keys(r).length>0?se(r):void 0;return await U("mise",["setup"],t,i=>{e.updateData("dependencyProgress",50+i*.5)},o,n),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Setup complete!"),e.updateData("dependencyComplete",!0),!0}catch(n){return e.setError(new Error(`Failed to setup project: ${n.message}`)),!1}}import{execa as Pi}from"execa";import ht from"fs";import Ri from"simple-git";async function Eo(e,t,r,o){if(ht.existsSync(e)){let n=`${e}/.git`;if(!ht.existsSync(n))throw new Error(`Directory ${e} exists but is not a git repository`);await Ri().cwd(e).pull(),r(100,"Already exists, pulled latest")}else try{let n=["clone","--progress"];o&&n.push("--branch",o),n.push(t,e);let i=Pi("git",n);i.stderr?.on("data",a=>{let s=a.toString();s.includes("Counting objects")?r(5,"Counting objects"):s.includes("Compressing objects")&&r(10,"Compressing objects");let c=s.match(/Receiving objects:\s+(\d+)%\s+\((\d+)\/(\d+)\)/);if(c?.[1]){let f=Math.min(100,parseInt(c[1],10)),d=c[2],m=c[3];r(10+Math.floor(f*.5),`Receiving objects: ${d}/${m}`)}let p=s.match(/Resolving deltas:\s+(\d+)%\s+\((\d+)\/(\d+)\)/);if(p?.[1]){let f=Math.min(100,parseInt(p[1],10)),d=p[2],m=p[3];r(60+Math.floor(f*.4),`Resolving deltas: ${d}/${m}`)}}),await i,r(100,"Clone complete")}catch(n){throw ht.existsSync(e)&&ht.rmSync(e,{recursive:!0,force:!0}),n}}var ki=process.env.GAIA_CLI_DEV==="true",_i=new RegExp("\x1B\\[[0-9;]*m","g");async function Ro(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input..."),await e.waitForInput("welcome");let r=dt(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements..."),!await mt(e))return;let o=await gt(e);if(o===null)return;let n=await lt(e);if(n==="developer"&&!await ft(e))return;let i="";if(ki){if(i=$()||"",!i){e.setError(new Error("DEV_MODE: Could not find workspace root. Run from within the gaia repo."));return}e.setStep("Repository Setup"),e.setStatus("[DEV MODE] Using current workspace..."),await X(500),e.setStatus("Repository ready!")}else{e.setStep("Repository Setup");let s=n==="selfhost"?ue.join(Po.homedir(),"gaia"):ue.resolve("gaia"),c=!0;for(i=s;;){if(i=await e.waitForInput("repo_path",{default:s}),ue.isAbsolute(i)||(i=ue.resolve(i)),ne.existsSync(i)){if(!ne.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await X(2e3),e.setError(null);continue}if(ne.existsSync(ue.join(i,"apps/api/app/config/settings_validator.py"))){e.updateData("existingRepoPath",i);let m=await e.waitForInput("existing_repo");if(m==="use_existing"){c=!1;break}else if(m==="delete_reclone"){e.setStatus("Removing existing installation...");try{ne.rmSync(i,{recursive:!0,force:!0})}catch(S){e.setError(new Error(`Failed to remove directory: ${S.message}
45
- Try removing it manually: rm -rf "${i}"`));return}break}else{if(m==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(ne.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await X(2e3),e.setError(null);continue}}break}if(c){e.setStep("Repository Setup"),e.setStatus("Preparing repository..."),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await Eo(i,"https://github.com/theexperiencecompany/gaia.git",(p,f)=>{e.updateData("repoProgress",p),f?(e.updateData("repoPhase",f),e.setStatus(`${f}...`)):e.setStatus(`Cloning repository to ${i}... ${p}%`)},t),e.setStatus("Repository ready!")}catch(p){e.setError(p);return}}else e.setStatus("Using existing repository!")}if(await X(1e3),await pt(e,i,n,o),e.currentState.error)return;if(n==="selfhost"){e.setStep("Project Setup"),e.setStatus("Building and starting all services in Docker..."),e.updateData("dependencyPhase","Building and starting Docker services..."),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]),e.updateData("dependencyComplete",!1);let s=f=>{let d=f.split(`
46
- `).map(S=>S.replace(_i,"").trim()).filter(S=>S.length>0);if(d.length===0)return;let m=e.currentState.data.dependencyLogs||[];e.updateData("dependencyLogs",[...m,...d].slice(-30))},c=!1;try{e.setStatus("Pulling pre-built images from registry..."),await Oe(i,"selfhost",f=>e.setStatus(f),o,s,{pull:!0}),c=!0}catch(f){let d=f.message?.split(`
47
- `)[0]??"unknown error";e.setStatus(`Registry pull failed (${d}) \u2014 building images locally (this takes a few minutes)...`)}if(!c)try{await Oe(i,"selfhost",f=>e.setStatus(f),o,s,{build:!0})}catch(f){e.setError(new Error(`Failed to start services: ${f.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let p=e.currentState.data.envMethod||"manual";ze({version:ee,setupComplete:!0,setupMethod:p,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",n),e.setStep("Finished"),e.setStatus("Setup complete! GAIA is running."),await e.waitForInput("exit");return}e.setStep("Install Tools"),e.setStatus("Installing toolchain..."),e.updateData("dependencyPhase","Initializing mise..."),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration..."),await U("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)..."),await U("mise",["install"],i,s=>{e.updateData("dependencyProgress",50+s*.5)},r),e.updateData("dependencyProgress",100),e.updateData("toolComplete",!0)}catch(s){e.setError(new Error(`Failed to install tools: ${s.message}`));return}await X(1e3),e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project..."),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("repoPath",i),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyProgress",0),e.updateData("dependencyPhase","Running mise setup (all dependencies)...");let s=Object.keys(o).length>0?se(o):void 0;await U("mise",["setup"],i,c=>{e.updateData("dependencyProgress",c)},r,s),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Setup complete!"),e.updateData("dependencyComplete",!0)}catch(s){e.setError(new Error(`Failed to setup project: ${s.message}`));return}await X(1e3);let a=e.currentState.data.envMethod||"manual";ze({version:ee,setupComplete:!0,setupMethod:a,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.setStep("Finished"),e.setStatus("Setup complete! Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function Do(e={}){await z({command:"init",whenNonInteractive:"fail",runFlow:t=>Ro(t,e.branch)})}async function ko(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository...");let t=$();if(!t){e.setError(new Error("Could not find GAIA repository. Run this command from within a cloned gaia repo, or use 'gaia init' to set up from scratch."));return}if(e.updateData("repoPath",t),e.setStatus(`Found repository at ${t}`),await X(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements..."),!await mt(e))return;let r=await gt(e);if(r===null)return;let o=await lt(e);if(o==="developer"&&!await ft(e)||(await pt(e,t,o,r),e.currentState.error))return;if(o==="selfhost"){let s=e.currentState.data.envMethod||"manual";Ae({setupComplete:!0,setupMethod:s,repoPath:t}),e.updateData("setupMode",o),e.setStep("Finished"),e.setStatus("Setup complete! Run 'gaia start' to build and start all services in Docker."),await e.waitForInput("exit");return}let n=dt(e);if(!await Io(e,t,r,n))return;await X(1e3);let a=e.currentState.data.envMethod||"manual";Ae({setupComplete:!0,setupMethod:a,repoPath:t}),e.updateData("setupMode",o),e.setStep("Finished"),e.setStatus("Setup complete! Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function _o(){await z({command:"setup",whenNonInteractive:"fail",runFlow:ko})}var Ai=new RegExp("\x1B\\[[0-9;]*m","g");async function Ao(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository...");let r=$();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r);let o=await ge(r);if(!o){e.setError(new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo."));return}if(o==="developer"){e.setError(new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'."));return}if(o==="selfhost"){e.setStatus("Checking Docker...");let c=await ut();if(!c.working){e.setError(new Error(c.errorMessage||`Docker is not running. Please start Docker and try again.
48
- ${pe.docker}`));return}}let n=ae(r),i=n[3e3]??3e3,a=n[8e3]??8e3;e.updateData("setupMode",o),e.updateData("webPort",i),e.updateData("apiPort",a),e.updateData("dockerLogs",[]),e.setStatus(`Starting GAIA in ${o} mode...`);let s=c=>{let p=c.split(`
49
- `).map(d=>d.replace(Ai,"").trim()).filter(d=>d.length>0);if(p.length===0)return;let f=e.currentState.data.dockerLogs||[];e.updateData("dockerLogs",[...f,...p].slice(-30))};try{await Oe(r,o,c=>{e.setStatus(c)},n,s,t),e.setStep("Running"),e.setStatus("GAIA is running!"),e.updateData("started",!0)}catch(c){e.setError(new Error(`Failed to start services: ${c.message}`));return}await e.waitForInput("exit")}async function Oo(e){await z({command:"start",whenNonInteractive:"plain",autoResolve:[["exit"]],runFlow:t=>Ao(t,e)})}import{execa as Qt}from"execa";var Kt=["gaia-backend","gaia-web","chromadb","postgres","redis","mongo","rabbitmq","arq_worker"];async function Mo(){try{let{stdout:e}=await Qt("docker",["inspect","--format","{{.Name}}|{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}",...Kt]),t=new Map;for(let r of e.trim().split(`
50
- `)){if(!r)continue;let[o,n,i]=r.split("|"),a=o?.replace(/^\//,"")??"";t.set(a,{name:a,status:n==="running"?"running":"stopped",health:i!=="none"?i:void 0})}return Kt.map(r=>t.get(r)??{name:r,status:"not_found"})}catch{let e=Kt.map(async t=>{try{let{stdout:r}=await Qt("docker",["inspect","--format","{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}",t]),[o,n]=r.trim().split("|");return{name:t,status:o==="running"?"running":"stopped",health:n!=="none"?n:void 0}}catch{return{name:t,status:"not_found"}}});return Promise.all(e)}}async function No(){try{return await Qt("docker",["info"]),!0}catch{return!1}}var Oi=[{name:"API",port:8e3,type:"http",path:"/health"},{name:"Web",port:3e3,type:"http",path:"/"},{name:"PostgreSQL",port:5432,type:"tcp"},{name:"Redis",port:6379,type:"tcp"},{name:"MongoDB",port:27017,type:"tcp"},{name:"RabbitMQ",port:5672,type:"tcp"},{name:"ChromaDB",port:8080,type:"tcp"}];async function Lo(e){let r=Oi.map(o=>({...o,port:e?.[o.port]??o.port})).map(o=>o.type==="http"?Mi(o.name,o.port,o.path):Ni(o.name,o.port));return Promise.all(r)}async function Mi(e,t,r){let o=Date.now();try{let n=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-o;return{name:e,port:t,status:n.ok?"up":"down",latency:i,details:n.ok?`HTTP ${n.status}`:`HTTP ${n.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function Ni(e,t){let r=await import("node:net"),o=Date.now();return new Promise(n=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let a=Date.now()-o;i.destroy(),n({name:e,port:t,status:"up",latency:a})}),i.on("timeout",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),n({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function Bo(){return await No()?{running:!0,containers:await Mo()}:{running:!1,containers:[]}}async function Li(e){e.setStep("Checking"),e.setStatus("Checking service health..."),e.updateData("refreshable",!1);let t=$(),r=t?ae(t):void 0,[o,n]=await Promise.all([Lo(r),Bo()]);e.updateData("services",o),e.updateData("docker",n);let i=o.filter(s=>s.status==="up").length,a=o.length;e.setStep("Results"),e.setStatus(`${i}/${a} services running`),e.updateData("refreshable",!0)}async function Fo(e){for(;await Li(e),await e.waitForInput("exit_or_refresh")==="refresh";);}async function $o(){await z({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:Fo,onPlainComplete:Bi})}function Bi(e){let t=e.currentState.data.services??[],r=e.currentState.data.docker;$i(t),Gi(r)}function Fi(e){return e==="up"?"UP":e==="down"?"DOWN":"UNKNOWN"}function $i(e){if(e.length!==0){console.log(`
51
- Services:`);for(let t of e){let r=Fi(t.status),o=t.latency===void 0?"--":`${t.latency}ms`,n=t.name.padEnd(12);console.log(` ${n} :${t.port} ${r} ${o}`)}}}function Gi(e){if(e){console.log(`
52
- Docker: ${e.running?"running":"not running"}`);for(let t of e.containers??[]){let r=t.health?` (${t.health})`:"",o=t.name.padEnd(14);console.log(` ${o} ${t.status}${r}`)}}}async function Go(e,t){e.setStep("Stopping"),e.setStatus("Locating GAIA repository...");let r=$();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r),e.updateData("stopMode",t?.forcePorts?"force-ports":"safe");let o=ae(r);try{await Kr(r,n=>{e.setStatus(n)},o,t),e.setStep("Stopped"),e.setStatus(t?.forcePorts?"All services stopped (force-port mode).":"All services stopped (safe mode)."),e.updateData("stopped",!0)}catch(n){e.setError(new Error(`Failed to stop services: ${n.message}`));return}await e.waitForInput("exit")}async function jo(e){await z({command:"stop",whenNonInteractive:"plain",autoResolve:[["exit"]],runFlow:t=>Go(t,e)})}import*as vt from"fs";import*as St from"path";function ji(e){let t=St.join(e,".env");return vt.existsSync(t)?["--env-file",".env"]:[]}async function qo(){let e=$();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await ge(e);if(!t)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");let r=St.join(e,"infra","docker"),o=ji(r),n=ae(e),i=Object.keys(n).length>0?se(n):void 0;if(t==="selfhost"){await Te("docker",["compose","-f","docker-compose.selfhost.yml",...o,"logs","-f","--tail","200"],r,i);return}let a=["compose",...o,"logs","-f","--tail","200"],s=St.join(e,Xr),c=Mt(e),p=typeof c=="number"&&Ze(c);if(vt.existsSync(s)&&p){console.log("Streaming app and infrastructure logs..."),process.platform==="win32"?await Qe([{cmd:"powershell",args:["-Command",`Get-Content -Path '${s.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:a,cwd:r,env:i}]):await Qe([{cmd:"tail",args:["-n","200","-f",s],cwd:e},{cmd:"docker",args:a,cwd:r,env:i}]);return}vt.existsSync(s)&&!p?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await Te("docker",a,r,i)):(console.log("No active developer process detected. Streaming Docker service logs. Run `gaia dev` in another terminal for live Nx app logs."),await Te("docker",a,r,i))}var Q=new qi;Q.name("gaia").description("CLI tool for setting up and managing GAIA").version(ee);Q.addCommand(te);Q.command("init").description(ie.init).option("--branch <branch>","Git branch to clone").action(async e=>{await Do({branch:e.branch})});Q.command("setup").description(ie.setup).action(async()=>{await _o()});Q.command("status").description(ie.status).action(async()=>{await $o()});Q.command("start").description(ie.start).option("-b, --build","Rebuild Docker images before starting").option("--pull","Pull latest base images before starting").action(async e=>{await Oo({build:e.build,pull:e.pull})});Q.command("dev [profile]").description(ie.dev).action(async e=>{try{await zr(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});Q.command("logs").description(ie.logs).action(async()=>{try{await qo()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});Q.command("stop").description(ie.stop).option("--force-ports","Aggressively stop processes listening on API/Web ports (may affect non-GAIA processes)").action(async e=>{await jo({forcePorts:e.forcePorts})});process.argv.slice(2).length||(Q.outputHelp(),process.exit(0));Q.parse();
127
+ Commit or discard them, or update this checkout yourself with 'gaia update --git'.`)}t(`Downloading GAIA ${e.toVersion}\u2026`),await ga(e.repoPath,e.toVersion),e.checkout&&!e.checkout.atTag&&(t(`Updating the setup files to ${e.toVersion}\u2026`),await dt(e.repoPath,["checkout","--detach",e.checkout.toTag])),t(`Switching to GAIA ${e.toVersion}\u2026`),Dn(e.repoPath,e.toVersion),t("Restarting GAIA\u2026"),await oe(e.repoPath,"selfhost",t,F(e.repoPath),void 0,{pull:"missing"})}async function Zu(e){if(!await Yu(e))throw new Error(`${e} is not a git checkout with an origin remote; run 'gaia update' without --git.`);if((await Nr("git",["symbolic-ref","-q","--short","HEAD"],{cwd:e,reject:!1})).exitCode!==0)throw new Error(`${e} is on a release tag, not a branch. Switch to one first: git -C ${e} checkout master`);return await dt(e,["fetch","origin"]),WS(e,"HEAD..@{upstream}")}async function ed(e,t){t("Pulling the latest commits (git pull --ff-only)\u2026"),await dt(e,["pull","--ff-only"]),t("Rebuilding images from this checkout and restarting\u2026"),await oe(e,"selfhost",t,F(e),void 0,{build:!0})}var Ji=10,KS="https://docs.heygaia.io/release-notes";function L(e=""){process.stdout.write(`${kt(e)}
128
+ `)}function Br(e=""){process.stderr.write(`${e}
129
+ `)}async function YS(e){let t=td.createInterface({input:process.stdin,output:process.stdout});t.on("SIGINT",()=>{t.close(),L(`
130
+ ${b.cancelled} Cancelled \xB7 nothing changed.`),process.exit(130)});let r=await new Promise(n=>{t.question(`${e} [y/N] `,i=>n(i))});t.close();let o=r.trim().toLowerCase();return o==="y"||o==="yes"}function XS(e){for(let t of e.commits.slice(0,Ji))L(` ${t}`);e.commits.length>Ji&&L(` ... and ${e.commits.length-Ji} more`)}async function rd(e,t){return e.yes?!0:pe()?YS(`
131
+ ${t}`):(L(`
132
+ No terminal to confirm in: rerun with --yes to apply.`),!1)}async function zS(e,t){let r=Ie(e),o=t.version??He,n=t.version!==void 0,s=n||Qe(r)!==null&&Be(o,r)?await Ht(o,$()?.bots??[]):null,a=Ku({current:r,target:o,explicit:n,gap:s});switch(a.kind){case"development-build":L(`This install runs a development build of GAIA (${lo(r)}), not a release, so there is nothing to update.`),L(`To switch it to the ${o} release: gaia update --version ${o}`);return;case"up-to-date":L(`GAIA ${r} is up to date.`);for(let l of Xs(O))L(l);return;case"unavailable":L(`${Gt(a.gap,"gaia up --build").cause} Nothing was changed.`),n&&(process.exitCode=1);return;case"offer":break}let c=await zu(e,o);if(Qu(c)){L(`GAIA ${r} is up to date.`);return}L(a.downgrade?`
133
+ Switch GAIA ${r} back to ${o}`:`
134
+ Update available: GAIA ${r} \u2192 ${o}`),L(`What's new: ${KS}`),L("Your data and settings are kept."),await rd(t,"Update and restart now?")&&(await Ju(c,l=>L(` ${l}`)),L(`
135
+ ${b.ok} GAIA is on ${o}.`),L("Run 'gaia doctor' to check that everything is ready."))}async function QS(e,t){let r=await Zu(e);if(r.commits.length===0){L("Already up to date with the upstream branch.");return}L(`
136
+ ${r.commits.length} new commit(s) touch the self-host stack:`),XS(r),L("The images are rebuilt from this checkout (slow on small machines)."),await rd(t,"Pull, rebuild and restart now?")&&(await ed(e,o=>L(` ${o}`)),L(`
137
+ Updated and restarted from source.`))}async function od(e={}){await wt({showUpdate:!1});let t=_();if(!t){Br("Error: No GAIA installation found."),Br("Fix: Run 'gaia up' to install GAIA first."),process.exitCode=1;return}if(e.git&&e.version){Br("Error: --version pins published images; --git builds from source. Pick one."),process.exitCode=1;return}L(`Checking for updates in ${Ut(t)}\u2026`);try{await(e.git?QS(t,e):zS(t,e))}catch(r){Br(`
138
+ Update failed: ${r.message}`),Br("Volumes are untouched. Fix the cause above, then rerun 'gaia update'."),process.exitCode=1}}var ev=new Set(["-V","--version"]),W=new JS,Zi="For contributors:";W.name("gaia").description("Run GAIA, your proactive personal assistant, on your own computer or server").option("-V, --version","Show the CLI's version").helpOption("-h, --help","Show help for a command").helpCommand("help [command]","Show help for a command").enablePositionalOptions().addHelpText("after",`
139
+ New here? Run: gaia up`);W.command("up").description(G.up).option("--yes","Answer yes to every question, including installing Git and Docker").addOption(new ZS("--llm-provider <provider>","AI provider to save once GAIA is running (checked first, as the setup page does)").choices(Mi)).option("--llm-key <key>","API key for --llm-provider (openrouter, gemini, openai, custom)").option("--llm-base-url <url>","Address of --llm-provider ollama (default http://host.docker.internal:11434) or custom").option("--llm-model <model>","Model for --llm-provider ollama (optional) or custom (required)").option("--web-port <port>","Port GAIA is served on (default 3000)",Number.parseInt).option("--domain <domain>","Serve GAIA at https://<domain> with an automatic certificate (uses ports 80 and 443)").option("-b, --build","Build GAIA from source on this machine instead of downloading it (slow)").option("--code-sandbox","Let GAIA run code in containers on this machine (gives it control of Docker; kept on later starts)").option("--no-code-sandbox","Turn that off again (running code then needs an E2B key)").option("--no-start","Set everything up, but don't start GAIA").option("--force-dev-tree","Allow 'gaia up' on a development copy of GAIA that isn't your install").action(async e=>{let{start:t,...r}=e;await Wu({...r,noStart:t===!1})});W.command("status").description(G.status).option("--watch","Stay open; press r to check again").action(async e=>{await Du({watch:e.watch})});W.command("stop").description(G.stop).option("--force-ports","Also stop whatever else listens on GAIA's ports (may stop other programs)").action(async e=>{await $u({forcePorts:e.forcePorts})});W.command("start").description(G.start).option("-b, --build","Build GAIA from source before starting (slow)").option("--pull","Download GAIA's images again before starting").action(async e=>{await Pu({build:e.build,pull:e.pull?"always":void 0})});W.command("update").description(G.update).option("--yes","Update without asking").option("--version <tag>","Move to this GAIA release (v<x.y.z>) instead of the one this CLI installs").option("--git","For development copies: pull the current branch and rebuild from source").action(async e=>{await od(e)});W.command("doctor").description(G.doctor).action(async()=>{await _l()});W.command("logs").description(G.logs).action(async()=>{try{await Lu()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});W.addCommand(Cr);W.addCommand(dl);W.addCommand(Ue);W.command("backup").description(G.backup).option("--output <dir>","Folder to save the backup in (default: ./backups)").option("--dry-run","Print the commands without running them").action(async e=>{await xa({output:e.output,dryRun:e.dryRun})});W.command("restore").description(G.restore).option("--mongo <file>","MongoDB archive file (mongodump --archive)").option("--postgres <file>","PostgreSQL dump file").option("--env <file>","The backup's apps/api/.env (api-env-<stamp>.env): its INSTANCE_SECRET decrypts the saved keys").option("--from <dir>","Restore everything from a backup folder (its newest backup)").option("--dry-run","Print the commands without running them").action(async e=>{await Iu({mongo:e.mongo,postgres:e.postgres,env:e.env,from:e.from,dryRun:e.dryRun})});W.command("init").helpGroup(Zi).description(G.init).option("--branch <branch>","Git branch to clone").action(async e=>{await bu({branch:e.branch})});W.command("setup").helpGroup(Zi).description(G.setup).action(async()=>{await Ru()});W.command("dev [profile]").helpGroup(Zi).description(G.dev).action(async e=>{try{await ml(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});ev.has(process.argv[2]??"")&&(await Ya(),process.exit(0));process.argv.slice(2).length||(W.outputHelp(),process.exit(0));W.parse();