@heygaia/cli 0.7.0-beta.1 → 0.7.0-beta.3

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 (2) hide show
  1. package/dist/index.js +113 -107
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,94 +1,98 @@
1
1
  #!/usr/bin/env node
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(`
2
+ import{Command as ry,Option as oy}from"commander";var U={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 Ba from"node:path";import _d from"is-unicode-supported";var w="cyan",gr=30,I="round",Ut=_d(),y={ok:Ut?"\u2713":"\u221A",fail:Ut?"\u2717":"x",warn:"!",skip:Ut?"\u2013":"-",pending:Ut?"\u25CB":"o",active:Ut?"\u25CF":"*",cancelled:Ut?"\u25A0":"#"},ms={ok:"green",fail:"red",warn:"yellow",skip:"gray",pending:"gray",active:w,cancelled:"yellow"};function le(e){let[t="",...r]=e.split(`
3
+ `),o=[`${y.fail} ${t}`,...r.map(n=>` ${n}`)];process.stderr.write(`${o.join(`
4
+ `)}
5
+ `)}var yt=[{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 hr(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 be from"node:path";import{execa as Fa}from"execa";import*as Kr from"node:fs";import*as gn from"node:path";var Dd=/^\d{4}-\d{2}-\d{2}(T\d{2}-\d{2}-\d{2}Z)?$/,Od=".partial",fs={prefix:"mongo-",suffix:".gz"},gs={prefix:"postgres-",suffix:".sql"},hs={prefix:"api-env-",suffix:".env"},Ss=".tar.gz",$d=[fs,gs,hs,...yt.map(e=>({prefix:`${e.fileSuffix}-`,suffix:Ss}))];function hn(e=new Date){return`${e.toISOString().slice(0,19).replaceAll(":","-")}Z`}function jt(e,t){let r=o=>gn.join(e,`${o.prefix}${t}${o.suffix}`);return{mongoFile:r(fs),postgresFile:r(gs),apiEnvFile:r(hs),volumeFiles:yt.map(o=>Sn(e,t,o))}}function Sn(e,t,r){return{volume:r.volume,label:r.label,file:gn.join(e,`${r.fileSuffix}-${t}${Ss}`)}}function wt(e){return`${e}${Od}`}function vs(e){return Kr.existsSync(e)?Kr.readdirSync(e).flatMap(r=>$d.flatMap(({prefix:o,suffix:n})=>{if(!r.startsWith(o)||!r.endsWith(n))return[];let i=r.slice(o.length,r.length-n.length);return Dd.test(i)?[i]:[]})).sort().at(-1):void 0}import*as Yr from"node:fs";import*as bs from"node:os";import{execa as qt}from"execa";var ys="/var/run/docker.sock",pe={selfhost:"gaia-selfhost",developer:"gaia-dev"},Ld=/\((healthy|unhealthy|health: starting)\)/;async function Es(e){return(await bt(e)).map(r=>({name:r.service,status:r.state==="running"?"running":"stopped",health:r.health}))}async function xs(e){let{stdout:t}=await qt("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 Cs(){return bs.platform()!=="linux"||!Yr.existsSync(ys)?0:Yr.statSync(ys).gid}async function bt(e){let{stdout:t}=await qt("docker",["ps","-a","--filter",`label=com.docker.compose.project=${e}`,"--format",'{{.Label "com.docker.compose.service"}}|{{.State}}|{{.Status}}']);return Md(t)}function Md(e){let t=[];for(let r of e.trim().split(`
6
+ `)){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 Is(){let{stdout:e}=await qt("docker",["info","--format","{{.DockerRootDir}}"]),t=e.trim();if(!t)throw new Error("docker info returned an empty DockerRootDir");return t}async function ks(e){let{stdout:t}=await qt("df",["-k",e]);return t}var ws=26;async function Nd(){let{stdout:e}=await qt("docker",["version","--format","{{.Server.Version}}"]);return e.trim()}async function Rs(){let e=await Nd(),t=Number.parseInt(e,10);if(Number.isNaN(t)||t<ws)throw new Error(`The code sandbox needs Docker Engine ${ws} 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 zr(e){let{stdout:t}=await qt("docker",["volume","ls","--quiet","--filter",`name=^${e}$`]);return t.trim().split(`
7
+ `).includes(e)}import*as Bs from"node:os";import{execa as Kd}from"execa";import{spawn as Ud}from"node:child_process";import*as En from"node:os";import{execa as xn}from"execa";import*as Ps from"node:fs";import*as wn from"node:path";import*as Ge from"fs";import*as As from"os";import*as yn from"path";var Ts={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.7.0-beta.3",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 $=Ts.version,Ke=`v${$}`;var Ye=yn.join(As.homedir(),".gaia"),vn=yn.join(Ye,"config.json");function Bd(){Ge.existsSync(Ye)||Ge.mkdirSync(Ye,{recursive:!0})}function L(){try{if(!Ge.existsSync(vn))return null;let e=Ge.readFileSync(vn,"utf-8");return JSON.parse(e)}catch{return null}}function Xr(e){Bd(),Ge.writeFileSync(vn,`${JSON.stringify(e,null,2)}
8
+ `)}function ye(e){let r={...L()??{version:$,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Xr(r)}var Sr=wn.join(Ye,"logs");function Et(e,t=new Date){Ps.mkdirSync(Sr,{recursive:!0});let r=t.toISOString().slice(0,19).replaceAll(":","-");return wn.join(Sr,`${e}-${r}.log`)}function Jr(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 _s from"node:fs";import{execa as bn}from"execa";function Ds(){return typeof process.getuid=="function"&&process.getuid()===0}async function Gd(){Ds()||!(await bn("sudo",["-n","true"],{reject:!1})).failed||await bn("sudo",["-v","-p","[sudo] password for %u: "],{stdio:"inherit"})}async function Ht(e,t,r,o){await Gd();let[n,i]=Ds()?[e,[...t]]:["sudo",["-n",e,...t]],s=_s.createWriteStream(r,{flags:"a"}),a=Jr(d=>o?.(d)),c=bn(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",Cn="GAIA_DOCKER_GROUP_RELAUNCHED",Os="GAIA_RESUMED_STEP",$s="GAIA_RESUMED_STEP_STARTS";function Qr(){return process.env[Os]||void 0}function Zr(){let e=process.env[$s];return e?JSON.parse(e):{}}function Ls(){return process.env[Cn]==="1"}async function In(){let{stdout:e}=await xn("id",["-nG",En.userInfo().username]);return e.split(/\s+/).includes(re)}function Ms(e){let t=e.stderr;return typeof t=="string"&&t.toLowerCase().includes("permission denied")}async function Ns(){if(process.env[Cn]==="1")throw new Error(`Still no access to the Docker socket after joining the '${re}' group.
9
+ Check the socket's group with 'ls -l /var/run/docker.sock', then log out and back in and rerun.`);if(await In())return;let e=En.userInfo().username;try{await Ht("usermod",["-aG",re,e],Et("docker-group"))}catch(t){throw new Error(`Could not add ${e} to the '${re}' group: ${t.message}
10
+ Run 'sudo usermod -aG ${re} ${e}', log out and back in, then rerun.`)}}var jd=/^[A-Za-z_][A-Za-z0-9_]*$/;async function qd(e){try{return await xn("sh",["-c",'command -v "$1"',"sh",e]),!0}catch{return!1}}async function Hd(){try{return await xn("sudo",["-l","-g",re,"--",process.execPath]),!0}catch{return!1}}async function Fs(){if(await qd("sg"))return"sg";if(await Hd())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).
11
+ Log out and back in (or run 'newgrp ${re}'), then rerun this command.`)}function Vd(e){return`'${e.replaceAll("'","'\\''")}'`}function Wd(e,t,r){return e==="sg"?["sg",[re,"-c",t.map(Vd).join(" ")]]:["sudo",[`--preserve-env=${Object.keys(r).filter(n=>jd.test(n)).join(",")}`,"-g",re,"--",...t]]}function kn(e,t,r){let o={...process.env,[Cn]:"1",[Os]:e,[$s]:JSON.stringify(r)},[n,i]=Wd(t,[process.execPath,...process.argv.slice(1)],o),s=Ud(n,i,{stdio:"inherit",env:o});return new Promise((a,c)=>{s.on("error",c),s.on("exit",(l,d)=>{process.exit(l??(d?1:0))})})}var Yd=5e3,zd="https://orbstack.dev",Rn="Run 'gaia up': it installs everything GAIA needs.";async function J(){try{return await Kd("docker",["info"],{timeout:Yd}),"ready"}catch(e){return e.code==="ENOENT"?"not-installed":Ms(e)?"no-permission":"not-running"}}async function Ue(e){let t=Bs.platform()==="darwin";switch(e){case"not-installed":return{summary:"Docker isn't installed",state:"isn't installed",fix:t?`Install OrbStack (${zd}) or Docker Desktop, open it, then try again.`:Rn};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 In()?`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 xt(e){let t=await Ue(e);return new Error(`${t.summary}.
12
+ ${t.fix}`)}import*as V from"fs";import*as Vt from"path";import*as vr from"node:fs";import*as Tn from"node:path";var Gs=[{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 An={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/"}},Us={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 yr(e,t){return An[t][e]??Us[t][e]}function eo(){return structuredClone(Gs)}function js(e){let t=Tn.join(e,"apps","web",".env.local"),r=vr.existsSync(t)?t:Tn.join(e,"apps","web",".env");if(!vr.existsSync(r))return[];let o=vr.readFileSync(r,"utf-8"),n=[],i="General";for(let s of o.split(`
13
+ `)){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 qs(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function Hs(e,t,r){let o=r==="selfhost"?new Set(Object.keys(An.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 Vs(e,t){return e.map(r=>({...r,variables:r.variables.map(o=>{let n=yr(o.name,t);return{...o,defaultValue:n||o.defaultValue}})}))}function wr(){return Object.keys(An.selfhost)}function Ws(e){return{...Us[e]}}function Ct(e){let t={};if(!e)return t;for(let r of e.split(`
14
+ `)){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 Pn=384;function to(e){if(V.existsSync(e)){let t=`${e}.bak`;V.copyFileSync(e,t),V.chmodSync(t,Pn)}}function ro(e,t){V.writeFileSync(e,t,{encoding:"utf-8",mode:Pn}),V.chmodSync(e,Pn)}function oo(e,t){to(t),ro(t,V.readFileSync(e,"utf-8"))}function br(e,t){let r=Vt.join(e,".env");to(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("");ro(r,o.join(`
15
+ `))}function Ys(e,t,r){let o=Vt.join(e,"apps","web",".env.local");to(o);let n=js(e),i=qs(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("")}ro(o,s.join(`
16
+ `))}var _n={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"},Ks=Object.fromEntries(Object.entries(_n).map(([e,t])=>[t,Number(e)])),Qd="proxy";function zs(e){return Vt.join(e,"infra","docker",".env")}function no(e){let t=zs(e);return V.existsSync(t)?Ct(V.readFileSync(t,"utf-8")):{}}var Dn="GAIA_VERSION",Zd="latest",Xs="GAIA_DOMAIN";function Js(e){return no(e)[Xs]||void 0}function Te(e){return no(e)[Dn]??Zd}function Qs(e,t){let r=zs(e);to(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(""),ro(r,o.join(`
17
+ `))}function Zs(e,t,r){Qs(e,{...no(e),[t]:r})}function On(e,t,r,o){let{NEXT_PUBLIC_APP_URL:n,...i}=no(e);for(let[s,a]of Object.entries(t)){let c=Number(s),l=_n[c];l&&(i[l]=String(a))}r==="selfhost"&&o&&(i.COMPOSE_PROFILES??=Qd,i.DOCKER_SOCKET_GID=String(o.dockerSocketGid),o.domain&&(i[Xs]=o.domain)),Qs(e,i)}function ze(e){let t={};for(let[r,o]of Object.entries(e)){let n=Number(r),i=_n[n];i&&(t[i]=String(o))}return t}function ea(e){let t=Vt.join(e,"infra","docker","docker-compose.yml");if(!V.existsSync(t))return;let r=V.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&&V.writeFileSync(t,r,"utf-8")}function N(e){let t=Vt.join(e,"infra","docker",".env"),r={};if(!V.existsSync(t))return r;let o=V.readFileSync(t,"utf-8");for(let n of o.split(`
18
+ `)){let i=n.trim();if(i&&!i.startsWith("#")){let[s,...a]=i.split("=");if(s&&Ks[s]){let c=a.join("=").trim().replace(/^["']|["']$/g,""),l=Number(c);!Number.isNaN(l)&&l>0&&l<=65535&&(r[Ks[s]]=l)}}}return r}import{execa as Vp}from"execa";import*as we from"fs";import*as ue from"path";import*as Wt from"node:fs";import*as Er from"node:path";import*as ra from"node:crypto";var ta=["AGENT_SECRET","BOT_SESSION_TOKEN_SECRET","EMAIL_UNSUBSCRIBE_SECRET","SHARE_GRANT_SECRET","GAIA_BOT_API_KEY"],tp=["INSTANCE_SECRET"];function $n(){return ra.randomBytes(32).toString("hex")}function rp(e){return new Set(Object.keys(Ct(e)))}function io(e){let t=rp(e),r={},o=e===null?[...ta,...tp]:ta;for(let n of o)t.has(n)||(r[n]=$n());return r}var oa=["telegram","discord","slack"],na={telegram:["TELEGRAM_BOT_TOKEN"],discord:["DISCORD_BOT_TOKEN","DISCORD_CLIENT_ID"],slack:["SLACK_BOT_TOKEN","SLACK_APP_TOKEN","SLACK_SIGNING_SECRET"]},Nn={telegram:"TELEGRAM_BOT_USERNAME",discord:"DISCORD_CLIENT_ID",slack:"SLACK_WORKSPACE_URL"},op={GAIA_BOT_API_KEY:"GAIA_BOT_API_KEY",GAIA_FRONTEND_URL:"FRONTEND_URL",RABBITMQ_URL:"RABBITMQ_URL"},np="BOT_LOG_HASH_SECRET";function me(e){return`bot-${e}`}function xr(e,t){let r=t.find(i=>i.service===me(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 ia(e){return`docker-compose.${me(e)}.yml`}function Ln(e){return Er.join(e,"apps","api")}function ip(e){return Er.join(e,"apps","bots")}function Mn(e){let t=Er.join(e,".env");return Wt.existsSync(t)?Ct(Wt.readFileSync(t,"utf-8")):{}}function sa(e,t){let r={...e,...t.set};for(let o of t.unset??[])delete r[o];return r}function so(e,t){let r=Ln(e),o=Mn(r),n=sa(o,t);JSON.stringify(n)!==JSON.stringify(o)&&br(r,n)}function Cr(e,t={}){let r=Er.join(Ln(e),".env");if(!Wt.existsSync(r))throw new Error(`${r} does not exist; run 'gaia up' to configure the install first.`);let o=io(Wt.readFileSync(r,"utf-8"));Object.keys(o).length>0&&so(e,{set:o});let n=Mn(Ln(e)),i={};for(let[c,l]of Object.entries(op)){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=ip(e),a=sa(Mn(s),t);a[np]??=$n(),br(s,{...a,...i})}var sp={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"},ap={mongodb:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB"};function Ae(e){return sp[e]??e}function ao(e){return ap[e]??e}import*as aa from"node:os";function Pe(e,t=aa.homedir()){return e===t?"~":e.startsWith(`${t}/`)?`~${e.slice(t.length)}`:e}import{execa as hp}from"execa";import{execa as lp}from"execa";import co from"fs";import up from"simple-git";var cp={KiB:1024,MiB:1048576,GiB:1073741824};function It(e){return e>=1e9?`${(e/1e9).toFixed(1)} GB`:`${Math.round(e/1e6)} MB`}function ca(e){let t=/^([\d.]+)\s*(KiB|MiB|GiB)$/.exec(e.trim());return!t?.[1]||!t[2]?null:Number(t[1])*cp[t[2]]}var Fn=.85,dp=/Receiving objects:\s+(\d+)%[^,\r\n]*(?:,\s*([\d.]+\s*[KMG]iB))?/g,pp=/Resolving deltas:\s+(\d+)%/g,mp=/remote: (?:Enumerating|Counting|Compressing) objects:/;function fp(e){let t=[...e.matchAll(pp)].at(-1);if(t?.[1]){let o=Number(t[1]);return{percent:Math.floor(Fn*100+o*(1-Fn)),label:"Unpacking the files"}}let r=[...e.matchAll(dp)].at(-1);if(r?.[1]){let o=Number(r[1]),n=r[2]?ca(r[2]):null;return{percent:Math.floor(o*Fn),label:n===null?"Downloading":`${It(n)} so far`}}return mp.test(e)?{percent:0,label:"GitHub is preparing the download"}:null}async function lo(e,t,r,o){if(co.existsSync(e)){let n=`${e}/.git`;if(!co.existsSync(n))throw new Error(`Directory ${e} exists but is not a git repository`);await up().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=lp("git",n);i.stderr?.on("data",s=>{let a=fp(s.toString());a&&r(a.percent,a.label)}),await i,r(100,"Clone complete")}catch(n){throw co.existsSync(e)&&co.rmSync(e,{recursive:!0,force:!0}),n}}var ua="https://github.com/theexperiencecompany/gaia.git",la="https://heygaia.io/install.sh",Sp=/^\d+\.\d+\.\d+-beta\.\d+$/;function Bn(e){return Sp.test(e)?"beta":"latest"}function Ir(e){return e==="beta"?`curl -fsSL ${la} | GAIA_CHANNEL=beta sh`:`curl -fsSL ${la} | sh`}function da(e){let t=Bn(e),r=[`For a newer release, update the CLI first (${Ir(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 ${Ir("latest")} and rerun 'gaia update'.`),r}var vp=2,yp=/^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function Kt(e){if(!yp.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 Gn(e,t,r){let o=Kt(t),n=await hp("git",["ls-remote","--exit-code","--tags",e,`refs/tags/${o}`],{cwd:r,reject:!1});if(n.exitCode!==0)throw n.exitCode===vp?new Error(`GAIA ${t} has no published release: ${e} has no tag ${o}.
19
+ Install a released CLI (${Ir("latest")}) and rerun.`):new Error(`Could not read ${o} from ${e}: ${n.stderr.trim()}`)}function Un(e,t){Zs(e,Dn,t)}async function pa(e,t,r){await Gn(t,Ke),await lo(e,t,r,Kt(Ke)),Un(e,Ke)}var wp=/ghcr\.io\/theexperiencecompany\/(gaia[\w-]*):([\w.-]+)/,bp={gaia:"API","gaia-web":"web app"};function fa(e){let t=wp.exec(e);return t?.[1]&&t[2]?{name:t[1],tag:t[2]}:null}function ma(e){let t=bp[e];return t?`GAIA's ${t} image (${e})`:`the ${e} image`}function Yt(e,t){let[r=e.image,o=""]=e.image.split(":");return e.kind==="wrong-cpu"?{cause:`${ma(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: ${ma(r)} doesn't exist in the registry.`,next:`Update the CLI (${Ir(Bn($))}) and run it again, or build from source: ${t}.`}}var Ep=(e,t)=>{let r=/no matching manifest for linux\/([\w]+)/.exec(e)?.[1];if(!r)return null;let o=fa(e);return o?Yt({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).`}},xp=(e,t)=>{if(!/manifest unknown|: not found|failed to resolve reference|No such image/.test(e))return null;let r=fa(e);if(r)return Yt({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}.`}},Cp=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>."}},Ip=[[/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."}]],kp=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 ${Ae(r)} didn't start.`,next:"Try: gaia doctor",service:r}};function Rp(e){return([...e].reverse().find(r=>/error|failed|denied/i.test(r))??e.at(-1)??"docker compose failed").trim()}function ga(e,t,r){let o=[...e,...t].join(`
20
+ `);for(let n of[Ep,xp,Cp,kp]){let i=n(o,r);if(i)return i}for(let[n,i]of Ip)if(n.test(o))return i;return{cause:`Docker Compose failed: ${e.at(-1)??Rp(t)}`,next:""}}var Xe=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: ${Pe(r)}`,t.next].filter(Boolean).join(`
21
+ `)),this.name="ComposeError",this.failure=t,this.logPath=r}};import*as Ca from"node:fs";import{execa as Ia}from"execa";import ba from"semver";function Sa(){return{images:new Map,layers:new Map,steps:new Map,containers:new Map,started:new Set,awaitingHealth:new Set,stopping:new Map,finished:[],errors:[],downloadPercent:0}}var uo="Image ",va="Container ",Tp=/^\[[^\]]*\d+\/\d+\]/,Ap=/^gaia-(?:selfhost|dev)-(.+)-\d+$/,Pp=new Set(["Stopping","Removing"]),ha=new Set(["Stopped","Removed"]),_p=2;function Dp(e){return e.slice(e.lastIndexOf("/")+1)}function Op(e){let t=e.slice(va.length);return Ap.exec(t)?.[1]??t}function $p(e,t){let r=(t.id??"").slice(uo.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"} ${Dp(r)}`),e.images.set(r,"ready")):e.images.set(r,t.text==="Building"?"building":"downloading"))}function Lp(e,t){let r=t.id??"",o=e.layers.get(r)??{image:(t.parent_id??"").slice(uo.length),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"||t.text==="Already exists")&&(o.done=!0,o.current=o.total),e.layers.set(r,o)}function Mp(e,t){let r=Op(t.id??""),o=t.text??"";if(Pp.has(o)||ha.has(o)){e.stopping.set(r,e.stopping.get(r)===!0||ha.has(o));return}let n=["Started","Running","Healthy"].includes(t.text??"");t.status==="Error"&&e.errors.push(`${r}: ${t.details??t.text??"error"}`),t.text==="Waiting"&&e.awaitingHealth.add(r),t.text==="Healthy"&&e.awaitingHealth.delete(r),t.text==="Started"&&!e.started.has(r)&&(e.started.add(r),e.finished.push(`Started ${Ae(r)}`)),e.containers.set(r,e.containers.get(r)===!0||n)}function ya(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||!Tp.test(i)||e.steps.set(o.digest,{name:i,done:n?.done===!0||!!o.completed})}let r=t.id??"";return r.startsWith(uo)?$p(e,t):r.startsWith(va)?Mp(e,t):t.parent_id?.startsWith(uo)&&Lp(e,t),e}var Np=99;function Fp(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(Np,Math.floor(a/s*100))}}function jn(e){let t=e.slice(0,_p).map(Ae),r=e.length-t.length;return r>0?`${t.join(", ")} and ${r} more`:t.join(" and ")}function Bp(e){let t=[...e].filter(([,i])=>!i).map(([i])=>i),r=e.size-t.length,o=`${r} of ${e.size} stopped`,n=Math.floor(r/e.size*100);return t.length===0?{stage:"stopping",label:`Stopping GAIA: ${o}`,percent:n}:{stage:"stopping",label:`Stopping GAIA: waiting on ${jn(t)} (${o})`,percent:n}}function Gp(e){let t=[...e.containers],r=t.filter(([,s])=>s).length,o=`${r} of ${t.length} up`,n=Math.floor(r/t.length*100),i=t.filter(([,s])=>!s).map(([s])=>s);return e.awaitingHealth.size>0?{stage:"starting",label:`Starting GAIA: waiting for ${jn([...e.awaitingHealth])} to be ready (${o})`,percent:n}:i.length>0?{stage:"starting",label:`Starting GAIA: starting ${jn(i)} (${o})`,percent:n}:{stage:"starting",label:`Starting GAIA: ${r} of ${t.length} services up`,percent:n}}function Up(e){let t=[...e.layers.values()];return[...e.images].filter(([,o])=>o==="downloading").map(([o])=>o).every(o=>t.some(n=>n.image===o)&&t.every(n=>n.image!==o||n.done))}function wa(e){if(e.stopping.size>0)return Bp(e.stopping);let t=[...e.steps.values()],r=t.filter(n=>n.done).length;if(t.length>0&&r<t.length)return{stage:"building",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{stage:"building",label:"Building GAIA from source: saving the images",percent:99};if(o.includes("downloading")){let n=o.filter(l=>l==="ready").length,{downloaded:i,percent:s}=Fp(e);e.downloadPercent=Math.max(e.downloadPercent,s);let a=`${n} of ${o.length} ready`;return Up(e)?{stage:"unpacking",label:`Unpacking GAIA's images: ${It(i)} downloaded (${a})`,percent:e.downloadPercent}:{stage:"downloading",label:`Downloading GAIA's images: ${i>0?`${It(i)} so far`:"starting"} (${a})`,percent:e.downloadPercent}}return e.containers.size>0?Gp(e):null}var Ea="2.29.1",jp=40,xa;function qp(){return xa??=(async()=>{let{stdout:e}=await Ia("docker",["compose","version","--short"]),t=ba.coerce(e.trim());if(!t||ba.lt(t,Ea))throw new Error(`GAIA needs Docker Compose ${Ea} or newer; this machine has ${e.trim()||"an unknown version"}.
22
+ Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),xa}function Hp(e){if(!e.startsWith("{"))return null;try{return JSON.parse(e)}catch{return null}}async function po(e,t){await qp();let r=Et(t.logName),o=Ca.createWriteStream(r);t.onLogFile?.(r);let n=Sa(),i=[],s=Jr(l=>{let d=Hp(l);if(!d){i.push(l),i.length>jp&&i.shift();return}ya(n,d);let p=wa(n);p&&t.onProgress?.(p,n.finished)}),a=Ia("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(`
23
+ `),await new Promise(l=>o.end(l)),c.timedOut)throw new Xe({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 Xe(ga(n.errors,i,{rebuildCommand:t.rebuildCommand}),r);return{startedServices:n.started.size}}var Wp=e=>new Promise(t=>setTimeout(t,e)),Ta="dev-start.log",fo=".gaia-dev.pid",Aa="gaia start --build";function go(e){let t=ue.join(e,".env");return we.existsSync(t)?["--env-file",".env"]:[]}var Kp=60;function Yp(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:Kp;return r===0?void 0:r*60*1e3}function zt(e={}){let t=L(),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(ia)),r}function Je(e){return e.flatMap(t=>["-f",t])}var Pa="gaia-sandbox-workspace",ka="/legacy-sandbox-workspace";function zp(e,t){return["compose",...Je(e),...t,"run","--rm","--no-deps","-v",`${Pa}:${ka}:ro`,"gaia-backend","python","-m","app.scripts.migrate_legacy_sandbox_workspace","--legacy-root",ka]}function Xp(e,t,r){let o=[...Je(e),...t,"up","-d","--remove-orphans"];return o.push(r?.build?"--build":"--no-build"),r?.pull&&o.push("--pull",r.pull),o}function qn(e){let t=ue.join(e,fo);if(!we.existsSync(t))return null;try{let r=Number.parseInt(we.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function mo(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=ue.join(e,"infra/docker"),a=o&&Object.keys(o).length>0?ze(o):void 0,c=L();c?.codeSandbox===!0&&await Rs(),c?.bots?.length&&Cr(e);let l=zt({build:i?.build}),d=go(s),p=[...Je(l),...d],m=await po(Xp(l,d,i),{cwd:s,env:a,timeoutMs:Yp(),logName:i?.build?"compose-build":"compose-up",rebuildCommand:i?.rebuildCommand??Aa,onLogFile:i?.onLogFile,onProgress:n}).catch(async g=>{throw await Qp(g,p,s)});return await zr(Pa)&&(r?.("Moving code-sandbox files into per-user workspaces\u2026"),await ne("docker",zp(l,d),s,void 0,void 0,a)),r?.("GAIA's services are running."),m}var Jp=8;async function Qp(e,t,r){if(!(e instanceof Xe)||!e.failure.service)return e;let{stdout:o}=await Vp("docker",["compose",...t,"logs","--no-color","--no-log-prefix","--tail",String(Jp),e.failure.service],{cwd:r}),n=o.split(`
24
+ `).filter(i=>i.trim());return new Xe({...e.failure,logTail:n},e.logPath)}function Hn(e){return["compose",...Je(zt()),...go(e)]}async function _a(e,t,r,o){let n=ue.join(e,"infra/docker");await ne("docker",[...Hn(n),"run","--rm","--no-deps",t,...r],n,void 0,o)}var Zp=["gaia-backend","arq_worker","gaia-web"];async function Da(e,t,r){let o=ue.join(e,"infra/docker");await po([...Je(zt()),...go(o),"pull",...Zp,...(L()?.bots??[]).map(me)],{cwd:o,env:{GAIA_VERSION:t},logName:"compose-pull",rebuildCommand:"gaia up --build",onProgress:r})}async function Oa(e,t,r,o){let n=ue.join(e,"infra/docker"),i=await F(e),s=await J();if(s==="ready"){t?.("Stopping GAIA's containers\u2026");let a=go(n),c=i==="selfhost"?Je(zt()):[];await po([...c,...a,"down"],{cwd:n,logName:"compose-down",rebuildCommand:Aa,onProgress:l=>t?.(l.label)})}else{if(i==="selfhost")throw await xt(s);if(s==="no-permission")throw await xt(s)}i!=="selfhost"&&await em(e,t,r,o),t?.("All services stopped.")}async function em(e,t,r,o){t?.("Stopping GAIA-managed local processes (safe mode)\u2026");let n=qn(e),i=n!==null&&await tm(e,n);try{we.unlinkSync(ue.join(e,fo))}catch{}if(!i){if(o?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports\u2026"),await rm(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 tm(e,t){if(!mo(t))return!1;try{return process.platform==="win32"?(await ne("taskkill",["/PID",String(t),"/T","/F"],e),!0):(Ra(t,"SIGTERM"),await Wp(800),mo(t)&&Ra(t,"SIGKILL"),!0)}catch{return!1}}function Ra(e,t){try{process.kill(-e,t)}catch{process.kill(e,t)}}async function rm(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 ne(o,n,e)}}async function F(e){let t=je(e);if(!we.existsSync(t))return null;let r=we.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 om=8;function nm(e,t){return e.trimEnd().split(`
22
25
  `).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(`
26
+ `)}async function ne(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 b=E.toString();p+=b,n?.(b),m=Math.min(m+5,95),o?.(m)}),d.stderr?.on("data",E=>{let b=E.toString();p+=b,n?.(b),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}:
27
+ ${nm(p,om)}`)))}),d.on("error",E=>{v&&clearTimeout(v),!g&&l(E)})})}var im="apps/api/app/config/settings_validator.py";function je(e){return ue.join(e,"apps","api",".env")}function Qe(e){return we.existsSync(ue.join(e,im))}function $a(e){let t=e;for(;t!==ue.dirname(t);){if(Qe(t))return t;t=ue.dirname(t)}return null}function La(){let e=L();return e?.repoPath?Qe(e.repoPath)?e.repoPath:(console.warn(`Warning: Saved repo path "${e.repoPath}" is no longer a valid GAIA installation. Resetting config.`),ye({repoPath:"",setupComplete:!1}),null):null}function Xt(e){return $a(e??process.cwd())??La()}function _(e){let t=$a(e??process.cwd());return t&&we.existsSync(je(t))?t:La()??t}function kr(e,t){if(!e)return"GAIA isn't installed yet";let r=Pe(e);return t?`${r} (${t==="selfhost"?"self-host":"developer"})`:`${r} (not set up yet: no apps/api/.env)`}function sm(e,t=hn()){let r=jt(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/${be.basename(n)} -C /data .`)]}function am(e){return be.join(e,"infra","docker")}function cm(e,t){return t?be.resolve(t):be.join(e,"backups")}async function Vn(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=am(t),o=be.join(r,"docker-compose.selfhost.yml");if(!Y.existsSync(o))throw new Error(`Compose file not found: ${o}`);let n=cm(t,e.outputDir),i=hn(),s=jt(n,i),a=sm(n,i);if(e.dryRun)return{...s,commands:a,warnings:[]};let c=await J();if(c!=="ready"){let p=await Ue(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(`
28
+ `))}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 lm(t,r,n,i,a)}catch(p){for(let m of l)Y.rmSync(wt(m),{force:!0});throw p}for(let p of[s.mongoFile,s.postgresFile,s.apiEnvFile,...d.volumeFiles.map(m=>m.file)])Y.renameSync(wt(p),p);return{...s,...d,commands:a}}async function lm(e,t,r,o,n){let i=jt(r,o);um(e,wt(i.apiEnvFile));try{await Na("docker",Ma("mongo",["mongodump","--archive","--gzip"]),t,wt(i.mongoFile))}catch(c){throw new Error(`MongoDB backup failed: ${c.message}
29
+ Manual command: ${n[1]}`)}try{await Na("docker",Ma("postgres",["pg_dump","-U","postgres","-d","langgraph"]),t,wt(i.postgresFile))}catch(c){throw new Error(`PostgreSQL backup failed: ${c.message}
30
+ Manual command: ${n[2]}`)}let s=[],a=[];for(let c of yt){let l=Sn(r,o,c),d=wt(l.file);if(!await zr(c.volume)){a.push(`${c.label} volume ${c.volume} not found \u2014 nothing to back up`);continue}try{await Fa("docker",["run","--rm","-v",`${c.volume}:/data`,"-v",`${be.dirname(d)}:/backups`,"alpine","tar","czf",`/backups/${be.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 um(e,t){let r=je(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.`);oo(r,t)}function Ma(e,t){return["compose","-f","docker-compose.selfhost.yml","exec","-T",e,...t]}async function Na(e,t,r,o){Y.writeFileSync(o,"",{mode:384,flag:"wx"});try{await Fa(e,t,{cwd:r,stdout:{file:o},buffer:{stdout:!1}})}catch(n){throw Y.rmSync(o,{force:!0}),n}}function T(e=""){process.stdout.write(`${e}
31
+ `)}async function Ga(e={}){if(e.dryRun){let t=await Vn({outputDir:e.output,dryRun:!0});T("Backup commands (dry run \u2014 not executed):");for(let r of t.commands)T(` ${r}`);T(""),T(`Volumes (${yt.map(r=>r.volume).join(", ")}) are backed up via`),T(" docker run --rm -v <volume>:/data -v <output>:/backups alpine tar ..."),T(" and are skipped if the volume does not exist yet."),T(""),T("Run without --dry-run to execute inside the running containers,"),T("or copy-paste the commands from the directory containing infra/docker/");return}try{T("Starting GAIA backup\u2026");let t=await Vn({outputDir:e.output});T(`MongoDB dump: ${t.mongoFile}`),T(`PostgreSQL dump: ${t.postgresFile}`),T(`API settings (apps/api/.env): ${t.apiEnvFile}`);for(let{label:r,file:o}of t.volumeFiles)T(`${r} archive: ${o}`);if(t.warnings.length)for(let r of t.warnings)T(`Note: ${r}`);T(""),T("Backups complete. Store them off-host and access-controlled \u2014"),T(`${t.apiEnvFile} holds INSTANCE_SECRET, which decrypts the stored provider credentials.`),T(""),T("Restore with gaia restore --from <dir>, or manually from the repo root:"),T(` install -m 600 ${t.apiEnvFile} apps/api/.env`),T(` cat ${t.postgresFile} | docker compose -f infra/docker/docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`),T(` 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)T(` docker run --rm -v ${r}:/data -v $(dirname ${o}):/backups alpine sh -c "${hr(Ba.basename(o))}"`)}catch(t){le(t.message),process.exitCode=1}}import{Argument as Df,Command as Of}from"commander";async function ie(e){try{await e()}catch(t){le(t instanceof Error?t.message:String(t)),process.exit(1)}}import{supportsColor as pc}from"chalk";import{supportsHyperlink as Hm}from"supports-hyperlinks";import dm from"wrap-ansi";var pm=40,mm=80,fm=24;function Rr(e){return{columns:e.columns||mm,rows:e.rows||fm}}function Jt(e,t){return dm(e,t,{hard:!0})}function Ze(e,t=0){let r=process.stdout.isTTY?process.stdout.columns:void 0;return!r||r-t<pm?e:Jt(e,r-t).split(`
32
+ `).join(`
33
+ ${" ".repeat(t)}`)}import{networkInterfaces as Ua}from"node:os";var A=3e3,ho=8e3,Tr=3443;function kt(e,t){return`http://localhost:${e==="selfhost"?t[A]??A:t[ho]??ho}`}function se(e,t){return`${kt(e,t)}/api/v1`}var gm=/^(docker\d+|br-[0-9a-f]+)$/;function ja(e,t){return Object.entries(t).filter(([r])=>!gm.test(r)).flatMap(([,r])=>r??[]).filter(r=>r.family==="IPv4"&&!r.internal).map(r=>`http://${r.address}:${e}`)}function qa(e,t,r=Ua()){return[...t?[`https://${t}`]:[],`http://localhost:${e}`,...ja(e,r)]}function hm(e=process.env,t=process.platform){return e.SSH_CONNECTION||e.SSH_TTY?!0:t==="linux"&&!e.DISPLAY&&!e.WAYLAND_DISPLAY}function Wn(e,t,r=Ua(),o=hm()){if(t)return`https://${t}`;let n=`http://localhost:${e}`;return o?ja(e,r)[0]??n:n}function et(e,t){return Wn(t,Js(e))}async function So(e,t,r=5e3){return fetch(e,{...t,signal:AbortSignal.timeout(r)})}async function _e(e,t,r=5e3){try{let o=await So(`${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 Ee from"node:fs";import*as Yn from"node:path";import za from"semver";import*as Va from"node:os";var Wa="https://ghcr.io",Ka="theexperiencecompany",Ya=8e3,Sm=["gaia","gaia-web"],vm=["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 vo(e=Va.arch()){return e==="x64"?"amd64":e}async function ym(e){let t=await fetch(`${Wa}/token?scope=repository:${Ka}/${e}:pull`,{signal:AbortSignal.timeout(Ya)});if(!t.ok)throw new Error(`GHCR token request answered HTTP ${t.status}`);return(await t.json()).token}async function Ha(e,t,r){return fetch(`${Wa}/v2/${Ka}/${e}/${t}`,{headers:{Authorization:`Bearer ${r}`,Accept:vm},signal:AbortSignal.timeout(Ya)})}async function wm(e,t){let r=await ym(e),o=await Ha(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 Ha(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 Qt(e,t=[],r=vo()){let o=[...Sm,...t.map(n=>`gaia-bot-${n}`)];for(let n of o){let i=await wm(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 bm="https://registry.npmjs.org/@heygaia/cli/latest",Kn=Yn.join(Ye,"update-check.json"),Em=Yn.join(Sr,"update-check.log"),xm=1440*60*1e3,Cm=5e3;function tt(e){return/^v\d/.test(e)?za.parse(e.slice(1)):null}var Im=/^[0-9a-f]{40}$/,km=12;function yo(e){return Im.test(e)?e.slice(0,km):e}function qe(e,t){let r=tt(e),o=tt(t);return r!==null&&o!==null&&za.gt(r,o)}function Xa(){if(!Ee.existsSync(Kn))return null;let e=JSON.parse(Ee.readFileSync(Kn,"utf-8"));return e.arch===vo()?e:null}function Ja(){return Xa()?.latest??null}async function Rm(){let e=await fetch(bm,{signal:AbortSignal.timeout(Cm)});if(!e.ok)throw new Error(`npm answered HTTP ${e.status}`);let{version:t}=await e.json(),r=`v${t}`;return await Qt(r)===null?r:null}function Tm(e){Ee.mkdirSync(Sr,{recursive:!0}),Ee.appendFileSync(Em,`${new Date().toISOString()} update check failed: ${e.message}
34
+ `)}async function wo(){let e=Xa();if(e&&Date.now()-Date.parse(e.checkedAt)<xm)return e.latest;try{let t=await Rm();Ee.mkdirSync(Ye,{recursive:!0});let r={checkedAt:new Date().toISOString(),arch:vo(),latest:t};return Ee.writeFileSync(Kn,JSON.stringify(r)),t}catch(t){return Tm(t),e?.latest??null}}var Qa=300,Am="ai_models";function Pm(e,t){let r=e.features[Am]?.in_use[0];return r?t?.providers[r]?.label??r:null}async function bo(){let e=_(),t=e?await F(e):null;if(!e||!t)return{running:!1,installed:!1};let r=N(e),o=se(t,r),[n,i]=await Promise.all([_e(o,"status",Qa),_e(o,"catalog",Qa)]);if("detail"in n)return{running:!1,installed:!0};let s=r[A]??A;return{running:!0,webUrl:et(e,s),provider:Pm(n.data,"data"in i?i.data:null)}}function Eo(){wo();let e=_(),t=Ja();return!e||!t?null:qe(t,Te(e))?t:null}import{Chalk as Fm}from"chalk";import{Chalk as _m}from"chalk";var zn={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...."]},Xn={d:"#0f537c",m:"#059cda",l:"#02bdff"},Jn={d:24,m:38,l:39};var Dm={d:"blue",m:"cyan",l:"cyanBright"},Om={d:"bgBlue",m:"bgCyan",l:"bgCyanBright"},tc="\u2580",rc="\u2584",$m="\u2588";function Za(e){return e==="d"||e==="m"||e==="l"?e:null}function Lm(e,t){return e===null&&t===null?{ch:" ",fg:null,bg:null}:e===t?{ch:" ",fg:null,bg:e}:e===null?{ch:rc,fg:t,bg:null}:{ch:tc,fg:e,bg:t}}function Mm(e,t){return{ch:e!==null&&t!==null?$m:e!==null?tc:t!==null?rc:" ",fg:null,bg:null}}function ec(e,{fg:t,bg:r}){let o=e;return t!==null&&(o=e.level===3?o.hex(Xn[t]):e.level===2?o.ansi256(Jn[t]):o[Dm[t]]),r!==null&&(o=e.level===3?o.bgHex(Xn[r]):e.level===2?o.bgAnsi256(Jn[r]):o[Om[r]]),o}function Nm(e,t){let r="",o="",n=null;for(let i of t)n&&(i.fg!==n.fg||i.bg!==n.bg)&&(r+=ec(e,n)(o),o=""),n=i,o+=i.ch;return n?r+ec(e,n)(o):r}function oc(e){return zn[e][0].length}function nc(e,t){let r=zn[e],o=new _m({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=Za(l),m=Za(a[d]);return t===0?Mm(p,m):Lm(p,m)});n.push(Nm(o,c))}return n}var ic=3,Bm=40,sc=" \xB7 ",ac="Your proactive personal assistant",cc={truecolor:"#af8700",ansi256:136};function Gm(e,t){return t?`\x1B]8;;${e}\x1B\\${e}\x1B]8;;\x1B\\`:e}function Um(e){return e.level===3?e.hex(cc.truecolor):e.level===2?e.ansi256(cc.ansi256):e.yellow}function lc(e,t){return{plain:`GAIA v${t}`,styled:`${e.bold("GAIA")} ${e.dim(`v${t}`)}`}}function jm(e,t,r){if(!t.running){let n=t.installed?`${y.pending} Not running \xB7 start it with gaia start`:`${y.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 ${Gm(t.webUrl,r)}${e.dim(o)}`}}function uc(e,t){let r=[];if(e.status&&r.push(jm(t,e.status,e.hyperlinks)),e.update){let o=`Update available: ${e.update} \xB7 run gaia update`;r.push({plain:o,styled:Um(t)(o)})}return r}function dc(e){return[...e.plain].length}function qm(e,t){let r=lc(t,e.version);for(let o of uc(e,t)){let n={plain:`${r.plain}${sc}${o.plain}`,styled:`${r.styled}${t.dim(sc)}${o.styled}`};if(dc(n)>e.columns)break;r=n}return r.styled}function xo(e){let t=new Fm({level:e.level}),r=[lc(t,e.version),{plain:ac,styled:t.dim(ac)},...uc(e,t)],o=oc(e.size)+ic+Math.max(...r.map(dc));if(!e.isTTY||e.rows<Bm||o>e.columns)return[qm(e,t)];let n=nc(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(ic)}${c.styled}`:s})}function Qn(){return process.env.NO_COLOR?0:pc?pc.level:0}function Zn(e){return{isTTY:e.isTTY===!0,hyperlinks:Hm(e)}}async function Vm({size:e="small",showStatus:t=!0,showUpdate:r=!0}={}){let o={...Rr(process.stdout),...Zn(process.stdout)},n=t&&o.isTTY?await bo():null;return["",...xo({size:e,level:Qn(),...o,version:$,status:n,update:r?Eo():null}),""]}async function Rt(e){process.stdout.write(`${(await Vm(e)).join(`
31
35
  `)}
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.
36
+ `)}async function mc(){if(!process.stdout.isTTY){process.stdout.write(`${$}
37
+ `);return}await Rt({size:"large"})}var Wm="2048";function fc(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",Wm),t.toString()}function gc(e){return`https://t.me/${e}`}async function ei(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 Sc(e){let t=await ei(`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 vc(e){let t=await ei("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 hc(e,t){return await ei(`https://slack.com/api/${e}`,{method:"POST",headers:{Authorization:`Bearer ${t}`}})}async function yc(e,t){let r=await hc("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 hc("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 ii from"node:fs";import*as _r from"node:os";import*as Pc from"node:path";import{execa as af}from"execa";import*as ae from"node:fs";import*as wc from"node:path";var ri="/var/log/dpkg.log",ti="/var/cache/apt/archives",Km=1e3,Ym=1e6,zm=/^\S+ \S+ (unpack|configure) ([^:\s]+)/,Xm={unpack:"unpacking",configure:"setting up"};function Jm(e){let t=zm.exec(e);return!t?.[1]||!t[2]?null:`${Xm[t[1]]} ${t[2]}`}function bc(e){return ae.existsSync(e)?ae.statSync(e).size:0}function Qm(e){return ae.existsSync(ti)?ae.readdirSync(ti).filter(t=>t.endsWith(".deb")).map(t=>ae.statSync(wc.join(ti,t))).filter(t=>t.ctimeMs>=e).reduce((t,r)=>t+r.size,0):0}function Zm(e){let t=bc(ri),r=t<e?0:e;if(t===r)return{activity:null,offset:r};let o=Buffer.alloc(t-r),n=ae.openSync(ri,"r");try{ae.readSync(n,o,0,o.length,r)}finally{ae.closeSync(n)}return{activity:o.toString().split(`
38
+ `).map(Jm).findLast(a=>a!==null)??null,offset:t}}function Ec(e){let t=Date.now(),r=bc(ri),o=0,n=setInterval(()=>{let i=Zm(r);if(r=i.offset,i.activity){e(i.activity);return}let s=Qm(t);s>=Ym&&s>o&&(o=s,e(`downloading packages: ${It(s)}`))},Km);return()=>clearInterval(n)}var Ar="steps";function Pr(e){return e.currentState.data[Ar]??[]}function xc(e,t){let r=Zr();e.updateData(Ar,t.map(o=>({...o,state:"pending",startedAt:r[o.id]})))}function oi(e){return Object.fromEntries(Pr(e).flatMap(t=>t.startedAt===void 0?[]:[[t.id,t.startedAt]]))}function He(e,t,r){e.updateData(Ar,Pr(e).map(o=>o.id===t?{...o,...r}:o))}function rt(e,t,r={}){let o=Date.now(),n=Pr(e).find(i=>i.id===t);He(e,t,{state:"active",startedAt:n?.startedAt??o,...r})}function Tt(e,t,r){let o=Pr(e).find(n=>n.id===t);He(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 ot(e,t){let r=Pr(e).find(o=>o.state==="active"||o.state==="waiting");r&&He(e,r.id,{state:t,endedAt:Date.now()})}function nt(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 ef(e){let t=e.startedAt!==void 0&&e.endedAt!==void 0?` (${nt(e.endedAt-e.startedAt)})`:"";return e.state==="active"?` ${e.label}\u2026`:e.state==="done"?`${y.ok} ${e.doneLabel}${t}`:e.state==="failed"?`${y.fail} ${e.label}${t}`:e.state==="cancelled"?`${y.cancelled} ${e.label}${t}`:null}function fe(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function Cc(e){if(fe())return;let t=e?`'gaia ${e}'`:"this command";le(`${t} needs an interactive terminal to ask its questions.
39
+ Run it from a regular terminal, not a pipe or a script.`),process.exit(1)}function Ic(e,t=""){let r=t,o="",n="",i=new Map;e.on("change",s=>{let a=s.data[Ar]??[];for(let c of a){if(i.get(c.id)===c.state)continue;i.set(c.id,c.state);let l=ef(c);l&&console.info(l)}a.length===0&&s.step&&s.step!==r&&(r=s.step,console.info(`
40
+ [${s.step}]`)),s.status&&s.status!==o&&(o=s.status,console.info(` ${s.status}`)),s.error&&s.error.message!==n&&(n=s.error.message,le(s.error.message))})}import{execa as At}from"execa";var De={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},kc={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",15672:"RabbitMQ Management",[A]:"Web Frontend",[Tr]:"Web Frontend (HTTPS)",8080:"ChromaDB",8083:"Mongo Express"},tf={selfhost:[A,Tr],developer:[ho,5432,6379,27017,5672,15672,A,8080,8083]};async function Co(e,t={}){let r=await xs(pe[e]),o=tf[e].map(a=>t[a]??a),n=o.filter(a=>!r.has(a)),i=await rf(n),s=new Map(i.map(a=>[a.port,a]));return o.map(a=>s.get(a)??{port:a,service:kc[a]||`Port ${a}`,available:!0})}async function ni(){try{return await At("git",["--version"]),"success"}catch{return"error"}}async function Rc(){try{return await At("mise",["--version"]),"success"}catch{return"missing"}}async function Tc(){if((await import("node:os")).platform()==="win32")try{return await At("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await At("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function rf(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=kc[n]||`Port ${n}`;if(await o(n))r.push({port:n,service:i,available:!0});else{let a=await of(n),c=await nf(n+1,n+100,o);r.push({port:n,service:i,available:!1,usedBy:a,alternative:c||void 0})}}return r}async function of(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:o}=await At("netstat",["-ano","-p","TCP"]),n=o.trim().split(`
41
+ `);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 At("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 At("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),n=o.trim().split(`
42
+ `);if(n.length>1)return n[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function nf(e,t,r){for(let o=e;o<=t;o++)if(await r(o))return o;return null}var cf="https://get.docker.com",lf="https://orbstack.dev",uf="https://docs.docker.com/desktop/install/mac-install/",df={git:"Git",docker:"Docker"},si="prerequisite_install_confirm",_t="missingPrerequisites";function pf(){return ii.existsSync("/usr/bin/apt-get")||ii.existsSync("/etc/debian_version")}function Pt(e,t,r){e.updateData("checks",{...e.currentState.data.checks,[t]:r})}function Zt(e){return e.map(t=>df[t]).join(" and ")}function mf(){throw _r.platform()==="darwin"?new Error(`GAIA runs in Docker, which isn't installed yet.
43
+ \u2022 OrbStack (lightweight): ${lf}
44
+ \u2022 Docker Desktop: ${uf}
45
+ Install either, open it, then run this command again.`):new Error(`GAIA runs in Docker, which isn't installed yet. Install it from ${De.docker}, then run this command again.`)}async function ff(e,t,r){if(r.assumeYes)return;let o=Zt(t);if(!fe())throw new Error(`GAIA needs ${o}, and there is no terminal to ask before installing.
40
46
  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(`
47
+ `+t.map(i=>` ${De[i]}`).join(`
48
+ `));for(let i of t)Pt(e,i,"missing");if(e.updateData(_t,t),await e.waitForInput(si)!=="install")throw new Error(`GAIA needs ${o}. Install ${t.length>1?"them":"it"}, then run this command again:
49
+ `+t.map(i=>` ${De[i]}`).join(`
50
+ `))}async function _c(e,t,r){let o=Ec(n=>e.setStatus(`${t()} \xB7 ${n}`));try{await r()}finally{o()}}async function gf(e){let t="Installing Git: updating the package list";e.setStatus(`${t}\u2026`);let r=Et("git-install");try{await _c(e,()=>t,async()=>{await Ht("apt-get",["update"],r),t="Installing Git",e.setStatus(`${t}\u2026`),await Ht("apt-get",["install","-y","git"],r)})}catch(o){throw new Error(`Git installation failed: ${o.message}
51
+ Install it by hand following ${De.git}, then run this command again.`)}if(await ni()!=="success")throw new Error(`Git was installed but 'git --version' still fails. Install it by hand following ${De.git}, then run this command again.`)}function hf(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 Sf(e){let t=Pc.join(_r.tmpdir(),"gaia-docker-install.sh"),r=Et("docker-install"),o="Downloading Docker's installer",n=i=>{o=i,e.setStatus(`${i}\u2026`)};n(o),await af("curl",["-fsSL",cf,"-o",t]);try{await _c(e,()=>o,()=>Ht("sh",[t],r,i=>{let s=hf(i);s&&n(s)}))}catch(i){throw new Error(`Docker installation failed: ${i.message}
52
+ Install it by hand following ${De.docker}, then run this command again.`)}}async function Ac(e,t,r){Pt(e,t,"pending");try{let o=await r();return Pt(e,t,"success"),o}catch(o){throw Pt(e,t,"error"),o}}async function vf(e,t){if(t==="no-permission")return e.setStatus("Giving your user access to Docker (the docker group)\u2026"),await Ns(),e.updateData("dockerGroupSwitch",await Fs()),e.setStatus("Docker access granted. Continuing with it\u2026"),"relaunch";if(t!=="ready")throw await xt(t);return"ready"}async function Io(e,t){let r=t.needGit&&await ni()!=="success",o=await J(),n=[];r&&n.push("git"),o==="not-installed"&&n.push("docker");let i=_r.platform()==="linux"&&pf();if(r&&!i)throw Pt(e,"git","error"),new Error(`GAIA needs Git, which isn't installed. Install it from ${De.git}, then run this command again.`);if(o==="not-installed"&&!i&&(Pt(e,"docker","error"),mf()),n.length>0){try{await ff(e,n,t)}catch(s){for(let a of n)Pt(e,a,"error");throw s}t.onInstallStart?.(n)}return t.needGit&&await Ac(e,"git",async()=>{r&&await gf(e)}),Ac(e,"docker",async()=>(o==="not-installed"&&(await Sf(e),e.setStatus("Docker installed. Checking that it runs\u2026"),o=await J()),vf(e,o)))}var z=e=>new Promise(t=>setTimeout(t,e)),ko=(e,t="dependencyLogs")=>r=>{let o=e.currentState.data[t]||[],n=r.split(`
53
+ `).filter(i=>i.trim()!=="");e.updateData(t,[...o,...n].slice(-gr))};function Dc(e){return(t,r)=>{e.updateData("dependencyPhase",t.label),e.updateData("dependencyProgress",t.percent),e.updateData("dependencyLogs",r.slice(-gr))}}async function Ro(e){e.updateData("checks",{git:"pending"}),await z(500);try{return await Io(e,{needGit:!0})==="ready"}catch(t){return e.setError(t),!1}}async function To(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await Rc();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise\u2026"),t=await Tc()?"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.
54
+ \u2022 Mise: ${De.mise}`)),null):"success"}async function er(e,t){e.setStatus("Checking Ports\u2026");let r=await Co(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 z(1e3),o}async function Oc(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 ne("mise",["trust"],t,void 0,o),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools\u2026"),await ne("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?ze(r):void 0;return await ne("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 Lc}from"node:readline/promises";import{Writable as yf}from"node:stream";async function it(e,t){let r=Lc({input:process.stdin,output:process.stdout});try{let o=t?` [${t}]`:"";return(await r.question(`${e}${o}: `)).trim()||t||""}finally{r.close()}}var $c=4,Ao="\x1B",wf="",bf=new Set(["\x7F","\b"]),Ef=new RegExp(`${Ao}\\[[0-9;]*[A-Za-z~]`,"g");function xf(e){let t=e.length>$c*2?$c:0;return"\u2022".repeat(e.length-t)+e.slice(e.length-t)}async function Po(e){if(process.stdout.write(`${e}
55
+ \u203A `),!process.stdin.isTTY){let t=Lc({input:process.stdin,output:new yf({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}${Ao}[K
56
+ `),t(i)},n=i=>{let s=i.toString("utf-8").replace(Ef,"");(s===wf||s===Ao)&&(o("",""),process.stdout.write(`${y.cancelled} Cancelled \xB7 nothing changed.
57
+ `),process.exit(130));for(let a of s){if(a==="\r"||a===`
58
+ `){o(r.trim(),xf(r.trim()));return}bf.has(a)?r=r.slice(0,-1):a>=" "&&(r+=a)}process.stdout.write(`\r\u203A ${"\u2022".repeat(r.length)}${Ao}[K`)};process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",n)})}async function st(e,t=!0){let r=await it(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function _o(e,t){for(process.stdout.write(`
53
59
  ${e}
54
60
  `),t.forEach((r,o)=>{process.stdout.write(` ${o+1}. ${r}
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",`
61
+ `)});;){let r=await it(`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.
62
+ `)}}var Cf={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},If=12e4,kf=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 ge(e=""){process.stdout.write(`${e}
63
+ `)}function ai(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Dt={telegram:"Telegram",discord:"Discord",slack:"Slack"},Rf=3;async function Tf(e,t,r){let o={...t},n=0;for(let i of Mc[e]){if(o[i.key])continue;if(!fe())throw new Error(`Missing ${i.flag}. ${i.hint}`);r&&(n>0&&ge(),ge(Ze(i.hint))),n++;let s=await Po(i.label);if(!s)throw new Error(`No ${i.label} entered. Nothing changed.`);o[i.key]=s}return o}async function Af(e,t){for(let r=1;;r++){let o=await Tf(e,t,r===1);ge(`Checking your ${Dt[e]} credentials\u2026`);try{return await Pf(e,o)}catch(n){let i=Mc[e].filter(a=>!t[a.key]),s=Rf-r;if(i.length===0||!fe()||s===0)throw n;ge(Ze(`${y.fail} ${n.message} Paste ${i.length===1?"it":"them"} again (${s} ${s===1?"try":"tries"} left), or press Esc to stop.`,2))}}}async function ci(){let e=_();if(!e||await F(e)!=="selfhost")throw new Error("No self-host GAIA install found. Run 'gaia up' first; chat bots run alongside it.");return e}async function Pf(e,t){let r=ai(t.token,"--token");if(e==="telegram"){let s=await Sc(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${gc(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await vc(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${fc(s)}`,"Then run /auth in Discord to link your GAIA account."]}}let o=ai(t.appToken,"--app-token"),n=ai(t.signingSecret,"--signing-secret"),i=await yc(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 _f(e){let t=pe.selfhost,r=Date.now()+If;for(;;){let o=xr(e,await bt(t));if(o.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Dt[e]} bot did not come up (${o.detail}). See why with 'docker compose -p ${t} logs ${me(e)}'; 'gaia bots remove ${e}' undoes the setup.`);await z(kf)}}async function Nc(e){await oe(e,"selfhost",t=>ge(t),N(e),void 0,{pull:"missing"})}async function Fc(e,t){let r=await ci(),o=await Af(e,t);Cr(r,{set:o.botsEnv}),so(r,{set:{[Nn[e]]:o.handle}});let n=L()?.bots??[];n.includes(e)||ye({bots:[...n,e]}),await Nc(r);let i=Cf[e];i&&(ge(`Registering the ${Dt[e]} bot's commands\u2026`),await _a(r,me(e),i)),ge(`Waiting for the ${Dt[e]} bot to connect\u2026`),await _f(e),ge(`${y.ok} The ${Dt[e]} bot is running`);for(let s of o.nextSteps)ge(s)}async function Bc(e){let t=await ci(),r=L()?.bots??[];if(!r.includes(e))throw new Error(`The ${Dt[e]} bot is not enabled. See 'gaia bots list'.`);ye({bots:r.filter(o=>o!==e)}),Cr(t,{unset:na[e]}),so(t,{unset:[Nn[e]]}),await Nc(t),ge(`${y.ok} The ${Dt[e]} bot is stopped and its credentials are deleted`)}async function Gc(){await ci();let e=L()?.bots??[];if(e.length===0){ge("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await bt(pe.selfhost);for(let r of e)ge(` ${r.padEnd(10)}${xr(r,t).detail}`)}function Uc(){return new Df("<platform>","chat platform").choices(oa)}var Or=new Of("bots").description(U.bots).hook("preAction",()=>Rt()).addHelpText("after",`
60
64
  Examples:
61
65
  gaia bots add telegram (asks for the token from @BotFather)
62
66
  gaia bots add telegram --token <token from @BotFather>
63
67
  gaia bots add discord --token <bot token>
64
68
  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?.(`
69
+ `);Or.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(Uc()).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 ie(()=>Fc(e,t))});Or.command("list").alias("ls").description("Show the enabled bots and whether each is running").action(async()=>{await ie(Gc)});Or.command("remove").alias("rm").description("Stop a bot and delete its saved credentials").addArgument(Uc()).action(async e=>{await ie(()=>Bc(e))});import{Command as Ug}from"commander";import{existsSync as Fo,mkdirSync as tg,readFileSync as Qc,writeFileSync as vi}from"node:fs";import{homedir as Jc}from"node:os";import{join as yi}from"node:path";import{sep as $f}from"node:path";var j={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"},li="https://api.heygaia.io",Ot="filesystem",Do=$f,ui=500,di=6e4,pi=5e3,mi=1e6,fi=5e6,Oo=9e4,$o=1e6;import{homedir as Lf}from"node:os";import{join as Mf}from"node:path";var Nf={info:e=>console.error(e),error:e=>console.error(e)},gi={},Ff=null;function X(){return Ff??Nf}function Oe(){return{stateDir:gi.stateDir??Mf(Lf(),".gaia","bridge"),env:gi.env??process.env,shell:gi.shell??process.env.SHELL??"/bin/sh"}}import{Client as Yf}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as zf,StdioClientTransport as Xf}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as Jf}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as Qf}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as Bf,readdir as Vc,readFile as jc,realpath as Gf,stat as Uf,writeFile as jf}from"node:fs/promises";import{dirname as qc,extname as qf,join as Wc,resolve as Hf,sep as hi}from"node:path";import{McpServer as Vf}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as tr}from"zod";var Wf={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},rr=class extends Error{};async function Si(e){try{return await Gf(e)}catch{return null}}async function Kf(e){try{return(await Bf(e)).isSymbolicLink()}catch{return!1}}function Hc(e,t){return t===hi?e.startsWith(hi):e===t||e.startsWith(t+hi)}async function Lo(e,t,r){let o=Hf(e),n=await Si(o);if(n){if(t.some(s=>Hc(n,s)))return n;throw new rr(`Path is outside your approved folders: ${e}`)}if(r)throw new rr(`No such file or directory: ${e}`);let i=await Si(qc(o));if(!i||!t.some(s=>Hc(i,s)))throw new rr(`Path is outside your approved folders: ${e}`);if(await Kf(o))throw new rr(`Refusing to write through a symlink: ${e}`);return Wc(i,o.slice(qc(o).length+1))}async function Kc(e,t,r,o){if(o.length>=r)return;let n;try{n=await Vc(e,{withFileTypes:!0})}catch{return}for(let i of n){if(o.length>=r)return;let s=Wc(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&o.push(s),i.isDirectory()&&!i.isSymbolicLink()&&await Kc(s,t,r,o)}}function Yc(e){let t=new Vf({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:tr.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let s=await Lo(i,await o(),!0);return{content:[{type:"text",text:(await Vc(s,{withFileTypes:!0})).map(l=>`${l.isDirectory()?"dir ":"file"} ${l.name}`).join(`
70
+ `)||"(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:tr.string().describe("Absolute path to a file")}},async({path:i})=>{try{let s=await Lo(i,await o(),!0),a=await Uf(s);if(!a.isFile())return n(`Not a file: ${i}`);let c=Wf[qf(s).toLowerCase()];if(c){if(a.size>fi)return n(`Image is too large to read (${a.size} bytes).`);let d=await jc(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>mi?n(`File is too large to read (${a.size} bytes).`):{content:[{type:"text",text:await jc(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:tr.string().describe("Absolute path to the directory to search under"),query:tr.string().describe("Substring to match against names")}},async({path:i,query:s})=>{try{let a=await Lo(i,await o(),!0),c=[];return await Kc(a,s,200,c),{content:[{type:"text",text:c.join(`
71
+ `)||"(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:tr.string().describe("Absolute path to the file to write"),content:tr.string().describe("Text content to write")}},async({path:i,content:s})=>{try{let a=await Lo(i,await o(),!1);return await jf(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 Zf=new Set(["localhost","127.0.0.1","::1"]),zc=5;function at(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(!Zf.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function eg(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function Xc(e,t){let r=eg(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>=zc)throw new Error(`too many redirects (>${zc}) \u2014 refusing to follow`);r=a,o={...t,redirect:"manual"}}}async function Mo(e){if(e.type==="url"){let n=at(e.url),i=new Jf(n,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:Xc});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let n=Oe().env,i=new Xf({command:e.command,args:e.args,env:{...zf(),...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]=Qf.createLinkedPair(),o=Yc(e);return await o.connect(r),{transport:t,close:async()=>{await o.close(),await t.close()}}}async function No(e){let t=await Mo(e),r=new Yf({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 wi(){return Oe().stateDir}function bi(){return yi(wi(),"credentials.json")}function Zc(){return yi(wi(),"config.json")}function el(){let e=wi();Fo(e)||tg(e,{recursive:!0,mode:448})}function $e(){let e=bi();if(!Fo(e))return null;try{return JSON.parse(Qc(e,"utf-8"))}catch{return null}}function $r(e){el(),vi(bi(),JSON.stringify(e,null,2),{mode:384})}function Lr(){let e=bi();Fo(e)&&vi(e,"{}",{mode:384})}function Q(){let e=Zc();if(!Fo(e))return{servers:[]};try{return{servers:JSON.parse(Qc(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function tl(e){el(),vi(Zc(),JSON.stringify(e,null,2),{mode:384})}function Bo(e){e.type==="url"&&at(e.url);let t=Q(),r=t.servers.findIndex(o=>o.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),tl(t)}function Mr(e){let t=Q(),r=t.servers.length;return t.servers=t.servers.filter(o=>o.key!==e),tl(t),t.servers.length<r}function Ei(e){return e==="~"?Jc():e.startsWith("~/")?yi(Jc(),e.slice(2)):e}function xi(e,t){return{type:"filesystem",key:Ot,name:"Local Files",allow:e,allowWrite:t}}function Nr(e){if(e)return e.replace(/\/$/,"");let t=$e();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??li).replace(/\/$/,"")}import{hostname as ng,platform as ig}from"node:os";var rl="x-request-id";function rg(e){if(!e||typeof e!="object")return;let{message:t,code:r}=e;if(!(typeof t!="string"&&typeof r!="string"))return e}var xe=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=rg(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 ol(e){if(!e.ok){let t=await e.text(),r=t;try{r=JSON.parse(t)}catch{}throw xe.fromBody(e.status,r,{fallbackMessage:`${e.status} ${e.statusText}`,requestId:e.headers.get(rl)??void 0})}return await e.json()}async function Go(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 ol(n)}async function og(e,t,r){let o=await fetch(`${e}/api/v1${t}`,{method:"DELETE",headers:{authorization:`Bearer ${r}`}});return ol(o)}function Ci(e,t,r,o){return Go(e,"/device/pair/start",{name:t,platform:r,daemon_version:o})}function Ii(e,t){return Go(e,"/device/pair/poll",{device_code:t})}function ki(e,t){return Go(e,"/device/token",{refresh_token:t})}function Ri(e,t,r,o,n){return Go(e,"/device/servers",{server_key:r,display_name:o,kind:n},t)}function nl(e,t,r){return og(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function sg(e){await new Promise(t=>setTimeout(t,e))}function Ti(){return!!$e()?.refreshToken}async function il(e,t){let r=Nr(t.api),o=t.name||ng(),n=await Ci(r,o,ig(),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 sg(n.interval*1e3);let s;try{s=await Ii(r,n.device_code)}catch(a){X().error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(s.status==="approved"&&s.device_id&&s.refresh_token){$r({apiUrl:r,deviceId:s.device_id,refreshToken:s.refresh_token}),e.onStatus?.(`
68
72
  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(`
73
+ `);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var ag={onPrompt(e,t){console.info(`
70
74
  To pair this device, open:
71
75
  `),console.info(` ${e}`),console.info(`
72
76
  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(`
77
+ `)},onStatus(e){console.info(e)}};async function cg(){let e=_();if(!(!e||await F(e)!=="selfhost"))return kt("selfhost",N(e))}async function or(e={}){let t=e.api??(process.env.GAIA_API_URL?void 0:await cg());await il(ag,{...e,...t!==void 0?{api:t}:{},daemonVersion:$})}import{spawn as Ig}from"node:child_process";import{existsSync as Pi,mkdirSync as kg,openSync as Rg,readFileSync as Tg,unlinkSync as pl,writeFileSync as Ag}from"node:fs";import{homedir as Pg}from"node:os";import{join as _i}from"node:path";import{mkdirSync as sl,readFileSync as lg,rmSync as al,writeFileSync as ug}from"node:fs";import{dirname as dg,join as cl}from"node:path";var pg=3e4,mg=3e4,fg=50,gg=e=>new Promise(t=>setTimeout(t,e));function ll(){return cl(Oe().stateDir,"credentials.lock")}function hg(){return cl(ll(),"stamp")}async function Sg(e){let t=ll(),r=hg();sl(dg(t),{recursive:!0});let o=Date.now()+mg;for(;;){try{sl(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let n=null;try{let i=Number(lg(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<pg){if(Date.now()>o)throw new Error("another gaia process is rotating the device credential \u2014 try again");await gg(fg);continue}try{al(t,{recursive:!0,force:!0})}catch{}}try{return ug(r,String(Date.now()),{mode:384}),await e()}finally{try{al(t,{recursive:!0,force:!0})}catch{}}}async function Fr(){return Sg(async()=>{let e=$e();if(!e?.refreshToken)throw new xe("not paired \u2014 run: gaia bridge login",401);let t=await ki(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return $r(r),{creds:r,accessToken:t.access_token}})}async function nr(){let e=Q().servers;if(e.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");let{creds:t,accessToken:r}=await Fr();await Promise.all(e.map(o=>Ri(t.apiUrl,r,o.key,o.name,o.type)))}async function Ai(e){let t=Mr(e);try{let{creds:r,accessToken:o}=await Fr();await nl(r.apiUrl,o,e)}catch(r){X().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 Cg}from"node:crypto";import dl from"ws";import{spawn as vg}from"node:child_process";import{appendFileSync as yg,mkdirSync as wg}from"node:fs";import{homedir as bg}from"node:os";import{join as Eg}from"node:path";function xg(e,t){try{let r=Oe().stateDir;wg(r,{recursive:!0,mode:448});let o=t?` (cwd: ${t})`:"";yg(Eg(r,"exec-audit.log"),`${new Date().toISOString()}${o} $ ${e}
78
+ `)}catch{}}async function ul(e,t,r){xg(e,t);let o=vg(Oe().shell,["-c",e],{cwd:t||bg(),env:Oe().env,stdio:["ignore","pipe","pipe"]}),n=0,i=!1,s=c=>l=>{if(i)return;let d=$o-n,p=l.length>d?l.subarray(0,d):l;p.length>0&&(n+=p.length,r[c](p.toString("utf-8"))),n>=$o&&(i=!0,r.stderr(`
75
79
  [gaia bridge] output truncated \u2014 cap reached
76
80
  `),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
+ [gaia bridge] killed \u2014 exceeded ${Oo/1e3}s timeout
82
+ `),o.kill("SIGKILL")},Oo);await new Promise(c=>{o.on("error",l=>{clearTimeout(a),r.stderr(`[gaia bridge] could not start command: ${l.message}
83
+ `),r.exit(127),c()}),o.on("close",l=>{clearTimeout(a),r.exit(l??-1),c()})})}var Br=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=ui;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof xe&&t.status===401?(X().error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):X().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 Fr();this.creds=t;let o=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,n=new dl(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=pi;let d=Q().servers.map(p=>p.key);this.send({t:j.HELLO,servers:d}),X().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 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.EXEC_OPEN:await this.runExec(r);return;case j.REVOKE:X().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case j.SERVER_REMOVE:r.key&&Mr(r.key)&&X().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=Q().servers.find(a=>a.key===o);if(!i){this.send({t:j.MCP_ERROR,sid:r,pod:n,error:`Unknown server '${o}'`});return}let s=Date.now();X().info(`[gaia bridge] opening MCP session for '${o}'\u2026`);try{let a=await Mo(i);a.transport.onmessage=c=>{this.send({t:j.MCP_MSG,sid:r,pod:n,data:JSON.stringify(c)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:j.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:j.MCP_OPENED,sid:r,pod:n}),X().info(`[gaia bridge] MCP session for '${o}' ready in ${Date.now()-s}ms`)}catch(a){let c=a instanceof Error?a.message:String(a);X().error(`[gaia bridge] MCP session for '${o}' failed after ${Date.now()-s}ms: ${c}`),this.send({t:j.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){X().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 ul(n,t.cwd,{stdout:i=>this.send({t:j.EXEC_STDOUT,sid:r,pod:o,data:i}),stderr:i=>this.send({t:j.EXEC_STDERR,sid:r,pod:o,data:i}),exit:i=>this.send({t:j.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===dl.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(o=>{X().error(`[gaia bridge] ${r}: ${o instanceof Error?o.message:o}`)})}async backoff(){let t=Cg(this.reconnectDelay);X().info(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,di)}};var Di=_i(Pg(),".gaia","bridge"),$t=_i(Di,"daemon.pid"),ml=_i(Di,"daemon.log");function Oi(){if(!Pi($t))return null;let e=Number(Tg($t,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function fl(){let e=Oi();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 gl(){let e=Oi();if(!e){Pi($t)&&pl($t),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}Pi($t)&&pl($t),console.info(`Stopped the bridge tunnel (pid ${e}).`)}async function Uo(){let e=Oi();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=Q().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 nr()}catch(s){if(s instanceof xe&&s.status===401)console.error(`[gaia bridge] this device is no longer authorized (revoked or unpaired). Let's re-pair.
84
+ `),Lr(),await or(),await nr();else throw s}let r=process.argv[1];if(!r)throw new Error("cannot locate the gaia CLI entrypoint to start the daemon");kg(Di,{recursive:!0,mode:448});let o=Rg(ml,"a"),n={detached:!0,stdio:["ignore",o,o]},i=Ig(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],n);i.unref(),Ag($t,String(i.pid??""),{mode:384}),console.info(`
81
85
  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",`
86
+ Logs: ${ml}
87
+ Stop: gaia bridge down`)}async function hl(){let e=$e();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new Br(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 wl}from"node:path";import{resolve as _g}from"node:path";function $i(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function Li(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 Sl(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 vl(e){let t=$i(e??"");if(!e||!t||t===Ot)throw new Error("--name is required and must contain letters or digits");return t}function yl(e){if(e.type==="stdio"){if(!e.command)throw new Error("--command is required for --type stdio");let{command:t,args:r}=Li(e.command);return{type:"stdio",key:vl(e.name),name:e.name,command:t,args:r,env:Sl(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");at(e.url);let t=Sl(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:vl(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(Do)?[Do]:t.map(o=>_g(Ei(o)));return xi(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}function Dg(e,t){let o=[...t].reverse().filter(n=>!n.startsWith("-"))[0]??e;return wl(o).replace(/@[^@]*$/,"")}function Og(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function bl(e){for(;;){let t=await it("Name for this server",e),r=$i(t);if(!t||!r||r===Ot){console.info("Pick a different name.");continue}if(!(Q().servers.some(o=>o.key===r)&&!await st(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function $g(e,t){if(wl(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 Mi(e){let t=process.env[e];if(t!==void 0&&t!==""&&await st(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await Po(` 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 El(e,t){let r={};for(let n of $g(e,t))console.info(`
88
+ The command needs ${n}.`),r[n]=await Mi(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 st(o,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let n=(await it(" Variable name")).trim();if(!n)break;if(n in r){console.info(" Already added.");continue}r[n]=await Mi(n)}return r}async function Lg(){console.info(`
89
+ Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await it("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=Li(e),o=await El(t,r),{name:n,key:i}=await bl(Dg(t,r));return{type:"stdio",key:i,name:n,command:t,args:r,env:o}}async function Mg(){let e={};if(!await st("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 it(" Header name")).trim();if(!t)break;if(t in e){console.info(" Already added.");continue}e[t]=await Mi(t)}return e}async function Ng(){let e=await it("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");at(e);let t=await Mg();if(Object.keys(t).length>0&&new URL(e).protocol==="http:"&&(console.info(`
90
+ Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await st("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 bl(Og(e));return{type:"url",key:o,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function Fg(e){for(;;){console.info(`
91
+ Testing the connection (this may download/start the server)\u2026`);try{let t=await No(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 _o("What now?",r)];if(o==="Re-enter environment variables"&&e.type==="stdio")e.env=await El(e.command,e.args);else{if(o==="Save anyway (fix it later)")return!0;if(o==="Abort")return!1}}}}async function Bg(e){let t=yl(e),r;try{r=await No(t)}catch(o){throw new Error(`Could not start '${t.key}': ${o instanceof Error?o.message:o}`)}Bo(t),await nr(),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 xl(e={}){if(!Ti()){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 or()}if(e.type){await Bg(e);return}let r=await _o("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 Lg():await Ng();if(!await Fg(r))throw new Error("aborted");Bo(r),console.info(`
92
+ Saved '${r.key}'.`);try{await nr(),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 st("Keep this device connected in the background now?")?await Uo():console.info("Run `gaia bridge up` whenever you're ready.")}function Gg(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 Cl(e){if(e){let n=await Ai(e);console.info(n?`Removed '${e}' from this device and GAIA.`:`No server '${e}'.`);return}let t=Q().servers;if(t.length===0){console.info("No servers configured \u2014 nothing to remove.");return}let r=await _o("Which server do you want to remove?",t.map(Gg)),o=t[r];if(o){if(!await st(`Remove '${o.key}'?`,!1)){console.info("Left it in place.");return}await Ai(o.key),console.info(`Removed '${o.key}'. The tunnel stops serving it right away, and GAIA drops it too.`)}}function jg(){let e=$e();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${Nr()})`:"Not paired \u2014 run: gaia bridge login"),console.info(fl());let t=Q().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
93
+ 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 Ve=new Ug("bridge").description(U.bridge).addHelpText("after",`
94
+ Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);Ve.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 ie(()=>xl(e))});Ve.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 ie(async()=>{await or({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});Ve.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await ie(jg)});Ve.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 ie(()=>Cl(e))});Ve.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 ie(e.serve?hl:Uo)});Ve.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await ie(gl)});Ve.command("logout").description("Forget local credentials").action(async()=>{await ie(()=>{Lr(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import{Command as zg}from"commander";import{createHash as Hg}from"node:crypto";import*as he from"node:fs/promises";import*as _l from"node:path";import*as kl from"node:os";import*as Rl from"node:path";var qg="https://github.com/theexperiencecompany/gaia/releases/download",jo=`cli-v${$}`,Ni="gaia-connect-SHA256SUMS",Il={"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 Tl(e,t){let r=Il[`${e}-${t}`];if(r===void 0)throw new Error(`gaia connect is not available for ${e}/${t}. Supported: ${Object.keys(Il).join(", ")}.`);return r}function Fi(e){return`${qg}/${jo}/${e}`}function Al(e){let t=e==="win32"?".exe":"";return Rl.join(kl.homedir(),".gaia","bin",`gaia-connect-${$}${t}`)}async function Pl(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 Vg(e,t){for(let r of e.split(`
95
+ `)){let[o,...n]=r.trim().split(/\s+/);if(n.join(" ").replace(/^\*/,"")===t&&o!==void 0)return o.toLowerCase()}throw new Error(`${Ni} on release ${jo} has no entry for ${t}.`)}function Wg(e){return Hg("sha256").update(e).digest("hex")}async function Kg(e){try{return await he.access(e),!0}catch{return!1}}async function Dl(e,t){let r=Al(e);if(await Kg(r))return r;let o=Tl(e,t);console.info(`Downloading gaia-connect (${jo})\u2026`);let[n,i]=await Promise.all([Pl(Fi(o)),Pl(Fi(Ni)).then(l=>l.toString("utf-8"))]),s=Vg(i,o),a=Wg(n);if(a!==s)throw new Error(`Checksum mismatch for ${o}: expected ${s}, got ${a}. Refusing to run the download.`);await he.mkdir(_l.dirname(r),{recursive:!0});let c=`${r}.${process.pid}.tmp`;try{await he.writeFile(c,n),e!=="win32"&&await he.chmod(c,448),await he.rename(c,r)}catch(l){throw await he.rm(c,{force:!0}),l}return r}import{spawn as Yg}from"node:child_process";async function Ol(e,t){return await new Promise((r,o)=>{let n=Yg(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 Xg(e){let t=await Dl(process.platform,process.arch);return await Ol(t,e)}var $l=new zg("connect").description(U.connect).allowUnknownOption().allowExcessArguments().argument("[args...]","flags forwarded to gaia-connect").addHelpText("after",`
92
96
  Get an import code from GAIA -> Settings -> Browser -> Import, then run:
93
97
  npx @heygaia/cli connect --token <code>
94
98
 
@@ -100,40 +104,42 @@ Flags forwarded to gaia-connect:
100
104
  --sites <domains> comma-separated domains to sync (default: all)
101
105
  --json robot mode: no TUI, structured JSON on stdout
102
106
  --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:
107
+ `).action(e=>ie(async()=>process.exit(await Xg(e))));import*as Ho from"fs";import*as Ll from"path";import{spawn as Jg}from"child_process";async function ir(e,t,r,o,n,i=!1){await qo([{cmd:e,args:t,cwd:r,env:o,onSpawn:n,detached:i}])}async function qo(e){e.length!==0&&await new Promise((t,r)=>{let o=e.map(p=>Jg(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=Xt();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await F(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=Ll.join(t,fo);try{await ir("mise",[e==="full"?"dev:full":"dev"],t,void 0,n=>{typeof n=="number"&&n>0&&Ho.writeFileSync(o,`${n}
108
+ `)},process.platform!=="win32")}finally{try{Ho.unlinkSync(o)}catch{}}}import fh,{Chalk as gh}from"chalk";import*as Fl from"node:fs";import*as Lt from"node:os";import{execa as Nl}from"execa";var Qg={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 Zg(e,t){let r=Qg[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 Vo(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:Zg(n.name,t)})}}var eh=2*1024*1024*1024,th=4*1024*1024*1024,rh=2*1024*1024*1024,Bl={"gaia-selfhost":["chromadb","postgres","redis","mongo","rabbitmq","gaia-backend","gaia-web","arq_worker","proxy"],"gaia-dev":["chromadb","postgres","redis","mongo","rabbitmq"]};function Bi(e){return e==="running"?"running":e==="restarting"?"restarting":"stopped"}function oh(e,t){return t.every(r=>e.some(o=>o.service===r&&Bi(o.state)==="running"))}function nh(e,t){return t.map(r=>({service:r,info:e.find(o=>o.service===r)})).filter(({info:r})=>!r||Bi(r.state)!=="running").map(({service:r,info:o})=>o?`${r} ${Bi(o.state)}`:`${r} missing`).join(", ")}function Gl(e,t){return e[t]??t}async function Ul(e,t={}){let r={id:"port-conflict",label:"Ports",severity:"blocker"},o;try{o=await Co(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 ih(e){return`Open ${e}/setup in your browser to finish setting GAIA up.`}function sh(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?"":ih(r)}))}function ah(e){let r=e.trim().split(`
109
+ `).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 jl(e){let t={id:"docker-daemon",label:"Docker",severity:"blocker"};if(e==="ready")return{...t,state:"ok",detail:"running"};let r=await Ue(e);return{...t,state:"fail",detail:r.state,fix:r.fix}}async function ql(e){let t={id:"compose-containers",label:"Containers",severity:"blocker"},r;try{r=await bt(e.project)}catch{return{...t,state:"skipped",detail:"they need Docker"}}return oh(r,e.expected)?{...t,state:"ok",detail:`${e.expected.length} services running`}:{...t,state:"fail",detail:nh(r,e.expected),fix:`Run 'gaia start' to bring the stack up, or check 'docker compose -p ${e.project} logs'.`}}function Hl(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:Rn}}async function Vl(e,t="gaia start"){let r={id:"api-health",label:"API",severity:"blocker"};try{let o=await So(`${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 Wl(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 Vo(e.origin,e.project);return r.reachable?r.dependencies.map(o=>({id:`dependency-${o.name}`,label:ao(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 Kl(e,t="gaia start"){let r={id:"web-reachable",label:"Web app",severity:"blocker"};try{let o=await So(`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 Yl(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([_e(e.apiUrl,"status"),_e(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=sh(r.data,o.data.llm_provider_keys,e.webUrl);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 Gi(e=eh){let t={id:"disk-headroom",label:"Disk space",severity:"blocker"},r;try{r=await Is()}catch{return{...t,state:"skipped",detail:"they need Docker"}}let o;try{let i=await ks(r),s=ah(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 ch(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 lh(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 Ui(e){try{return e()}catch{return null}}function uh(){try{let e=Fl.readFileSync("/proc/meminfo","utf-8"),t=ch(e);if(t!==null)return t}catch{}return Ui(()=>Lt.freemem())}async function dh(){try{let{stdout:e}=await Nl("vm_stat",[]),t=lh(e);if(t!==null)return t}catch{}try{let{stdout:e}=await Nl("sysctl",["-n","hw.memsize"]),t=Number(e.trim());if(Number.isFinite(t)&&t>0)return t}catch{}return Ui(()=>Lt.totalmem())}async function ph(){let e=Lt.platform();return e==="linux"?uh():e==="darwin"?dh():Ui(()=>Lt.freemem())}async function ji(){let e=await ph().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<rh?{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<th?{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 zl(e,t,r=wo){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=Te(e);if(tt(n)===null)return{...o,state:"ok",detail:`development build (${yo(n)})`};let i=await r();return i&&qe(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 Xl(e,t){if(e.length===0)return[];let r;try{r=await bt(t)}catch{r=null}return e.map(o=>{let n={id:`bot-${o}`,label:Ae(me(o)),severity:"warning"};if(!r)return{...n,state:"skipped",detail:"they need Docker"};let{health:i,detail:s}=xr(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 ${me(o)}', then rerun 'gaia bots add ${o}' with a fresh token.`}})}function Jl(e){return e.results.some(t=>t.severity==="blocker"&&t.state==="fail")}async function mh(){let e=_(),t=e?N(e):{},r=e?await F(e):null;return{repoPath:e,origin:kt(r??"selfhost",t),apiUrl:se(r??"selfhost",t),webPort:Gl(t,3e3),overrides:t,mode:r,project:r?pe[r]:null}}async function Ql(){let e=[],t=await mh(),r=await J();if(e.push(await jl(r)),e.push(r==="ready"?await Ul(t.mode??"selfhost",t.overrides):{id:"port-conflict",label:"Ports",severity:"blocker",state:"skipped",detail:"they need Docker"}),!t.repoPath||!t.project||!t.mode){e.push(Hl(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 Gi()),e.push(await ji()),{install:kr(t.repoPath,t.mode),installed:!1,results:e}}let o=t.mode==="developer"?"gaia dev":"gaia start";e.push(await ql({project:t.project,expected:Bl[t.project]})),t.project===pe.selfhost&&e.push(...await Xl(L()?.bots??[],t.project));let n=await Vl(t.apiUrl,o);return e.push(n),e.push(...await Wl({apiHealthy:n.state==="ok",origin:t.origin,project:t.project})),e.push(...await Yl({apiHealthy:n.state==="ok",apiUrl:t.apiUrl,webUrl:et(t.repoPath,t.webPort)})),e.push(await Kl(t.webPort,o)),e.push(await Gi()),e.push(await ji()),e.push(await zl(t.repoPath,t.mode)),{install:kr(t.repoPath,t.mode),installed:!0,results:e}}function Mt(e=""){process.stdout.write(`${e}
110
+ `)}var Zl=16,Hi=" ",Z=process.env.NO_COLOR!==void 0?new gh({level:0}):fh,hh={ok:Z.green,fail:Z.red,warn:Z.yellow,skip:Z.gray,pending:Z.gray,active:Z.cyan,cancelled:Z.yellow};function Sh(e){return e.state==="ok"?"ok":e.state==="skipped"?"skip":e.severity==="warning"?"warn":"fail"}var qi=Hi.length+2+Zl;function vh(e,t){let r=Sh(e),o=e.detail?Z.gray(Ze(e.detail,qi)):"";Mt(`${Hi}${hh[r](y[r])} ${e.label.padEnd(Zl)}${o}`),e.state==="fail"&&e.fix&&t?.fix!==e.fix&&Mt(`${" ".repeat(qi)}${Ze(e.fix,qi)}`)}function yh(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)Mt(`${Hi}${Z.gray(y.skip)} ${Z.gray(`Not checked: ${o.join(", ")} (${r})`)}`)}function wh(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 Z.green(`${y.ok} Everything checked out`);let o=[];return t>0&&o.push(Z.red(`${t} problem${t===1?"":"s"}`)),r>0&&o.push(Z.yellow(`${r} warning${r===1?"":"s"}`)),o.join(" \xB7 ")}function bh(e){Mt(e.installed?`${Z.bold("Checking")} ${e.install}`:Z.bold("Checking this computer")),Mt();let t=e.results.filter(r=>r.state!=="skipped");t.forEach((r,o)=>{vh(r,t[o+1])}),yh(e.results.filter(r=>r.state==="skipped")),Mt(),Mt(wh(e))}async function eu(){await Rt();let e=await Ql();bh(e),Jl(e)&&(process.exitCode=1)}import{render as ev}from"ink";import tv from"react";import{ThemeProvider as WS}from"@inkjs/ui";import{Box as an,Text as Ft,useInput as KS}from"ink";import YS from"react";import{Box as Ce,Static as Zh,Text as dt}from"ink";import{Box as Ih,Text as kh,useStdout as Rh}from"ink";import{useEffect as Th,useState as tu}from"react";import{useStdout as Eh}from"ink";import{useEffect as xh,useState as Ch}from"react";function Wo(){let{stdout:e}=Eh(),[t,r]=Ch(()=>Rr(e));return xh(()=>{let o=()=>r(Rr(e));return e.on("resize",o),()=>{e.off("resize",o)}},[e]),t}import{jsx as ru}from"react/jsx-runtime";var ct=({size:e="small",showStatus:t=!0,showUpdate:r=!0})=>{let{stdout:o}=Rh(),n=Wo(),[i,s]=tu(null),[a]=tu(()=>r?Eo():null);Th(()=>{if(!t){s(null);return}let l=!0;return bo().then(d=>{l&&s(d)}),()=>{l=!1}},[t]);let c=xo({size:e,level:Qn(),...n,...Zn(o),version:$,status:t?i:null,update:a});return ru(Ih,{marginTop:1,children:ru(kh,{children:c.join(`
111
+ `)})})};import{Spinner as $h}from"@inkjs/ui";import{Box as lt,Text as Ko}from"ink";import{useEffect as Lh,useState as Mh}from"react";import{Box as Ah,Text as Ph}from"ink";import{jsx as ou}from"react/jsx-runtime";var ee=({kind:e})=>ou(Ah,{marginRight:1,children:ou(Ph,{color:ms[e],children:y[e]})});import{ProgressBar as _h}from"@inkjs/ui";import{Box as nu,Text as Dh}from"ink";import{jsx as iu,jsxs as su}from"react/jsx-runtime";var Oh=40,sr=({percent:e})=>su(nu,{children:[iu(nu,{width:Oh,children:iu(_h,{value:e})}),su(Dh,{color:"gray",children:[" ",e,"%"]})]});import{jsx as W,jsxs as au}from"react/jsx-runtime";var Nh=40,Fh=1e3;function Vi(e){let[t,r]=Mh(Date.now());return Lh(()=>{if(!e)return;let o=setInterval(()=>r(Date.now()),Fh);return()=>clearInterval(o)},[e]),t}function Bh(e,t){return e.startedAt===void 0?"":nt((e.endedAt??t)-e.startedAt)}var Gh=({step:e,waiting:t})=>e.state==="done"?W(ee,{kind:"ok"}):e.state==="failed"?W(ee,{kind:"fail"}):e.state==="cancelled"?W(ee,{kind:"cancelled"}):e.state==="active"&&!t?W(lt,{marginRight:1,children:W($h,{})}):W(ee,{kind:"pending"}),Wi=({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 au(lt,{flexDirection:"column",children:[au(lt,{children:[W(Gh,{step:e,waiting:r}),W(lt,{width:Nh,children:W(Ko,{color:e.state==="pending"?"gray":void 0,bold:n,children:i})}),!(n&&r)&&W(Ko,{color:"gray",children:Bh(e,t)})]}),n&&e.percent!==void 0&&W(lt,{marginLeft:2,children:W(sr,{percent:e.percent})}),n&&s&&W(lt,{marginLeft:2,children:W(Ko,{color:"gray",wrap:"truncate",children:s})}),n&&e.hint&&W(lt,{marginLeft:2,children:W(Ko,{color:"gray",dimColor:!0,children:e.hint})})]})};function cu(e){let t=e.findIndex(o=>o.state!=="done"),r=t===-1?e.length:t;return{finished:e.slice(0,r),live:e.slice(r)}}var lu=({steps:e,waiting:t,status:r})=>{let o=Vi(e.some(n=>n.state==="active"));return W(lt,{flexDirection:"column",children:e.map(n=>W(Wi,{step:n,now:o,waiting:t,status:r},n.id))})};import{Spinner as uu}from"@inkjs/ui";import{Box as q,Text as P,useInput as du}from"ink";var Uh=100;function Yo(){return Math.min(Wo().columns,Uh)}import{jsx as x,jsxs as H}from"react/jsx-runtime";var zo=({checks:e})=>H(q,{flexDirection:"column",borderStyle:I,paddingX:1,borderColor:w,children:[x(P,{bold:!0,children:"System Checks"}),H(q,{flexDirection:"column",marginTop:1,children:[x(Ki,{label:"Git",status:e.git}),e.docker&&x(Ki,{label:"Docker",status:e.docker}),e.mise&&x(Ki,{label:"Mise",status:e.mise})]})]}),Xo=({status:e})=>H(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[x(P,{bold:!0,children:"Environment Setup"}),x(q,{marginTop:1,children:x(uu,{label:e||"Configuring environment\u2026"})})]}),pu=({title:e,progress:t,phase:r})=>H(q,{flexDirection:"column",borderStyle:I,padding:1,borderColor:w,children:[x(P,{bold:!0,children:e}),H(q,{marginTop:1,flexDirection:"column",children:[x(sr,{percent:t||0}),r&&x(P,{color:"gray",children:r})]})]}),jh=6,Le=({message:e})=>{let[t="",...r]=e.split(`
112
+ `),o=Yo(),n=o-jh;return H(q,{flexDirection:"column",borderStyle:I,borderColor:"red",paddingX:1,marginTop:1,width:o,children:[H(q,{children:[x(ee,{kind:"fail"}),x(P,{bold:!0,children:Jt(t,n)})]}),x(q,{flexDirection:"column",marginLeft:2,children:r.map(i=>x(P,{color:i.startsWith("Full log:")?"gray":void 0,children:Jt(i,n)},i))})]})},qh={success:"ok",error:"fail",missing:"warn"},Ki=({label:e,status:t})=>H(q,{children:[t==="pending"?x(q,{marginRight:1,children:x(uu,{type:"dots"})}):x(ee,{kind:qh[t]}),x(P,{children:e})]}),ar=({portResults:e,onAccept:t,onAbort:r})=>{du((n,i)=>{i.return?t():i.escape&&r()});let o=e.filter(n=>!n.available);return H(q,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:"yellow",children:[x(q,{marginBottom:1,children:x(P,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(n=>H(q,{children:[H(P,{color:n.available?"green":n.alternative?"yellow":"red",children:[n.available?y.ok:n.alternative?y.warn:y.fail," "]}),H(P,{children:[n.service," (:",n.port,")"]}),!n.available&&H(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(q,{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(q,{marginTop:1,children:x(P,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),x(q,{marginTop:1,children:H(P,{dimColor:!0,children:[x(P,{bold:!0,children:"Enter"})," continue \xB7 ",x(P,{bold:!0,children:"Esc"})," cancel"]})})]})},Hh=({missing:e,onConfirm:t,onDecline:r})=>{du((i,s)=>{s.return&&t(),s.escape&&r()});let o=e.length>1?"them":"it",n=e.length>1?"aren't":"isn't";return H(q,{flexDirection:"column",marginTop:1,marginLeft:2,children:[H(P,{children:["GAIA needs ",x(P,{bold:!0,children:Zt(e)}),", which ",n," ","installed yet."]}),H(P,{children:["Install ",o," now? This uses sudo and takes a few minutes."]}),H(q,{marginTop:1,children:[x(P,{color:w,bold:!0,children:"Enter"}),H(P,{children:[" install ",o]}),x(P,{color:"gray",children:" \xB7 "}),x(P,{bold:!0,children:"Esc"}),x(P,{children:" I'll do it myself"})]})]})},cr=({inputId:e,missing:t,onConfirm:r,onDecline:o})=>e!==si||!t?.length?null:x(Hh,{missing:t,onConfirm:r,onDecline:o});import{useEffect as Vh,useState as Wh}from"react";function Me(e){let[t,r]=Wh(e.currentState);return Vh(()=>{let o=()=>r({...e.currentState});return e.on("change",o),()=>{e.off("change",o)}},[e]),t}import*as fu from"node:path";var zi=["openrouter","gemini","openai","ollama","custom"],Kh={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 Yi(e,t){let r={key:e.llmKey,baseUrl:e.llmBaseUrl,model:e.llmModel}[t];return r!==void 0&&r!==""}function gu(e){let t=Object.keys(Jo);if(!e.llmProvider){let o=t.find(n=>Yi(e,n));if(o)throw new Error(`${Jo[o]} requires --llm-provider <${zi.join("|")}>.`);return}let r=e.llmProvider;for(let o of t){let n=Kh[r][o];if(n==="required"&&!Yi(e,o))throw new Error(`--llm-provider ${r} requires ${Jo[o]}.`);if(n==="unused"&&Yi(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 Yh(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var mu="GAIA_PROVIDER_API_KEY",lr={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},zh=/Could not save \w+: (.+)/;async function hu(e,t){let r=fu.join(e,"infra/docker");try{await ne("docker",[...Hn(r),"exec","-T","-e",mu,"gaia-backend","python","-m","app.scripts.save_provider",...Yh(t)],r,void 0,void 0,{[mu]:t.llmKey??""})}catch(o){let n=zh.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"]],Xh="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 Jh(e){if(e.noStart)return"GAIA is set up \xB7 nothing was started";if(e.stillStarting)return"GAIA is still starting";let t=e.startedServices===0?"GAIA is already running":`GAIA is running \xB7 ready in ${nt(e.elapsedMs)}`;return e.unsavedProvider?`${t} \xB7 your ${lr[e.unsavedProvider]} key wasn't saved`:e.startedServices===0?`${t} \xB7 nothing to do`:t}function Qh(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 Zo(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:`${lr[e.savedProvider]} key saved \xB7 change it in Settings`}),t.push({label:"Code execution",text:Qh(e.codeSandbox),tone:"dim"}),e.joinedDockerGroup&&t.push({label:"Docker",text:Xh,tone:"warn"}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:Jh(e),rows:t}}import{jsx as B,jsxs as ut}from"react/jsx-runtime";var eS={kind:"header"},Su=16,tS=6,rS=14,vu=30,oS={primary:void 0,warn:"yellow",dim:"gray"},nS=({row:e,width:t})=>{let r=e.tone?oS[e.tone]:void 0,o=Jt(e.text,t);if(!e.url)return B(dt,{color:r,children:o});let[n,i]=o.split(e.url);return ut(dt,{color:r,children:[n,B(dt,{color:"cyan",bold:!0,underline:!0,children:e.url}),i]})},iS=({outcome:e})=>{let t=Zo(e),r=t.tone==="success"?"green":w,o=Yo();return ut(Ce,{flexDirection:"column",marginTop:1,children:[ut(Ce,{flexDirection:"column",borderStyle:I,borderColor:r,paddingX:2,paddingY:1,width:o,children:[ut(dt,{bold:!0,color:r,children:[t.tone==="success"?`${y.ok} `:"",t.headline]}),B(Ce,{flexDirection:"column",marginTop:1,children:t.rows.map(n=>ut(Ce,{marginBottom:n.tone==="primary"?1:0,children:[B(Ce,{width:Su,flexShrink:0,children:B(dt,{bold:n.tone==="primary",children:n.label})}),B(nS,{row:n,width:o-tS-Su})]},n.label))})]}),B(Ce,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:vu*2+4,children:Qo.map(([n,i])=>ut(Ce,{width:vu,children:[B(Ce,{width:rS,children:B(dt,{color:w,children:n})}),B(dt,{color:"gray",children:i})]},n))})]})},sS=({state:e,store:t})=>e.inputRequest?.id==="port_conflicts"?e.data.portConflicts?B(ar,{portResults:e.data.portConflicts,onAccept:()=>t.submitInput("accept"),onAbort:()=>t.submitInput("abort")}):null:B(cr,{inputId:e.inputRequest?.id,missing:e.data[_t],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),yu=({store:e})=>{let t=Me(e),r=t.data.steps??[],o=t.data.upOutcome,n=t.data.logPath,i=t.data.finished===!0&&o!==void 0,{finished:s,live:a}=cu(r),c=[...Qr()?[]:[eS],...s.map(l=>({kind:"step",step:l}))];return ut(Ce,{flexDirection:"column",width:"100%",children:[B(Zh,{items:c,children:l=>l.kind==="header"?B(Ce,{marginBottom:1,children:B(ct,{size:"large",showStatus:!1})},"header"):B(Wi,{step:l.step,now:Date.now(),waiting:!1,status:""},l.step.id)}),B(lu,{steps:a,waiting:t.inputRequest!==null,status:t.status}),B(sS,{state:t,store:e}),n&&!i&&!t.error&&B(Ce,{marginTop:1,marginLeft:2,children:ut(dt,{color:"gray",children:["Full log: ",Pe(n)]})}),i&&B(iS,{outcome:o}),t.error&&B(Le,{message:t.error.message})]})};import{Select as Qi,Spinner as vS}from"@inkjs/ui";import{Box as h,Text as f,useInput as ur}from"ink";import Ur from"ink-text-input";import{useEffect as Zi,useState as de}from"react";import{Box as aS,Text as Xi,useInput as cS}from"ink";import{useEffect as lS,useRef as uS,useState as dS}from"react";import{jsx as pS,jsxs as Ji}from"react/jsx-runtime";var wu=8;function bu(e,t){return`${e} ${t}${e===1?"":"s"}`}var en=({logs:e})=>{let[t,r]=dS(0),o=Math.min(e.length,wu),n=e.length>wu,i=uS(e.length);lS(()=>{e.length!==i.current&&(i.current=e.length,r(0))},[e.length]),cS((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 Ji(aS,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&Ji(Xi,{color:"gray",children:[bu(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>pS(Xi,{color:"gray",wrap:"truncate",children:c},s+l)),t>0&&Ji(Xi,{color:"gray",children:[bu(t,"newer line")," (\u2193)"]})]})};import{Box as Gr,Text as tn}from"ink";import{Box as mS,Text as fS}from"ink";import{jsx as Eu}from"react/jsx-runtime";var gS=new Set(["Welcome","Finished"]),xu=({status:e,step:t})=>gS.has(t)?null:Eu(mS,{width:"100%",paddingX:1,marginTop:1,children:Eu(fS,{color:"gray",dimColor:!0,children:e})});import{jsx as pt,jsxs as rn}from"react/jsx-runtime";var hS=[{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"}],Cu=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],SS=({currentStep:e,steps:t})=>{let r=t.findIndex(n=>n.id===e),o=r===t.length-1;return pt(Gr,{marginY:1,flexWrap:"wrap",children:t.map(({id:n,label:i},s)=>{let a=s<r||o,c=s===r&&!o;return rn(Gr,{flexShrink:0,children:[s>0&&pt(tn,{color:"gray",children:" \xB7 "}),a&&rn(tn,{color:"green",children:[y.ok," ",i]}),c&&pt(tn,{color:w,bold:!0,children:i}),!a&&!c&&pt(tn,{color:"gray",children:i})]},n)})})},on=({children:e,status:t,step:r,steps:o=hS,header:n})=>rn(Gr,{flexDirection:"column",height:"100%",width:"100%",children:[rn(Gr,{flexGrow:1,flexDirection:"column",children:[pt(ct,{...n}),pt(SS,{currentStep:r,steps:o}),pt(Gr,{flexDirection:"column",flexGrow:1,children:e})]}),pt(xu,{status:t,step:r})]});import{jsx as u,jsxs as S}from"react/jsx-runtime";var yS=({onConfirm:e})=>(ur((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:w,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:w,children:[u(f,{bold:!0,children:"Enter"})," to start"]})})]})),wS=({defaultValue:e,onSubmit:t})=>{let[r,o]=de(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,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:w,children:"\u2192 "}),u(Ur,{value:r,onChange:o,onSubmit:t})]})]})},bS=({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(Qi,{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)})})]}),ES=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:o})=>{ur((s,a)=>{a.return&&o()});let n=t?.[3e3]??3e3,i=se(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:w,padding:1,children:[u(f,{color:w,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"]})})]})},es=({phase:e,progress:t,isComplete:r,logs:o,title:n,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:w,children:n||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[u(h,{children:r?S(f,{color:"green",children:[y.ok," ",e]}):u(vS,{label:e||"Preparing\u2026"})}),!r&&t>0&&u(sr,{percent:t}),!r&&o&&o.length>0&&u(en,{logs:o}),!r&&u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),ts=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,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(Qi,{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)})})]}),rs=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:w,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(Qi,{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)"})]})]}),os=({onSubmit:e})=>{let[t,r]=de({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[o,n]=de(0),[i,s]=de(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"}];ur((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:w,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:w,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?w:"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(Ur,{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"]})})]})},ns=({category:e,currentIndex:t,totalGroups:r,onSubmit:o})=>{let[n,i]=de(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=de(0),[c,l]=de(null);Zi(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),ur((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":w,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?w:"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(Ur,{value:n[m.name]||"",onChange:b=>{i(C=>({...C,[m.name]:b})),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:[y.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"]})]})})]})},is=({alternatives:e,onSubmit:t})=>{let[r,o]=de(new Set),[n,i]=de({}),[s,a]=de(0),[c,l]=de(null);Zi(()=>{let b={};for(let C of e)for(let M of C.variables)b[M.name]=M.defaultValue||"";i(b)},[e]);let d=[];for(let b=0;b<e.length;b++)if(d.push({type:"provider",categoryIndex:b}),r.has(b)){let C=e[b];if(C)for(let M=0;M<C.variables.length;M++)d.push({type:"field",categoryIndex:b,fieldIndex:M})}d.push({type:"submit"});let p=d[s],m=p?.type==="field",g=p?.type==="submit";ur((b,C)=>{let M=Math.min(s,d.length-1);if(M!==s){a(M);return}if(m)C.upArrow?a(O=>Math.max(0,O-1)):(C.downArrow||C.tab)&&a(O=>Math.min(d.length-1,O+1));else if(g)C.upArrow?a(O=>Math.max(0,O-1)):(C.return||b===" ")&&E();else if(C.upArrow)a(O=>Math.max(0,O-1));else if(C.downArrow||C.tab)a(O=>Math.min(d.length-1,O+1));else if((C.return||b===" ")&&p?.type==="provider"){let O=p.categoryIndex;o(vt=>{let G=new Set(vt);return G.has(O)?G.delete(O):G.add(O),G}),c&&l(null)}});let v=()=>{c&&l(null),a(b=>Math.min(d.length-1,b+1))},E=()=>{let b=[],C={};for(let M of r){let O=e[M];if(!O)continue;if(O.variables.some(G=>n[G.name]?.trim())){b.push(O.name);for(let G of O.variables){let Wr=n[G.name];Wr&&(C[G.name]=Wr)}}}if(b.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(b,C)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:I,borderColor:c?"red":w,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((b,C)=>{let M=r.has(C),O=d.findIndex(G=>G.type==="provider"&&G.categoryIndex===C),vt=s===O;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[u(f,{color:vt?w:void 0,bold:vt,children:vt?"\u279C ":" "}),u(f,{color:M?"green":"gray",children:M?`[${y.ok}]`:"[ ]"}),S(f,{color:M?w:"gray",bold:M,children:[" ",b.name]}),b.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",b.description]})]}),vt&&b.docsUrl&&S(h,{marginLeft:6,children:[u(f,{color:"yellow",children:"\u{1F4D6} "}),u(f,{color:"blue",underline:!0,children:b.docsUrl})]}),M&&u(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:b.variables.map((G,Wr)=>{let Ad=d.findIndex(fr=>fr.type==="field"&&fr.categoryIndex===C&&fr.fieldIndex===Wr),Gt=s===Ad,ps=!!G.defaultValue,fn=n[G.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Gt?w:"gray",bold:Gt,children:[Gt?" \u279C ":" ",G.name]}),!Gt&&fn&&u(f,{color:"green",children:" \u2713"}),!Gt&&!fn&&ps&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",G.defaultValue,")"]})]}),Gt&&u(h,{marginLeft:4,children:u(Ur,{value:fn,onChange:fr=>{i(Pd=>({...Pd,[G.name]:fr})),c&&l(null)},onSubmit:v,placeholder:ps?`Default: ${G.defaultValue}`:"Enter value\u2026"})})]},G.name)})})]},b.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),S(h,{marginTop:1,children:[u(f,{color:g?w:void 0,bold:g,children:g?"\u279C ":" "}),u(h,{borderStyle:I,borderColor:g?w:"gray",paddingX:2,children:u(f,{color:g?w:"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"})})]})},ss=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:o,onSkip:n})=>{let[i,s]=de(e.defaultValue||""),[a,c]=de(null);Zi(()=>{s(e.defaultValue||""),c(null)},[e.name]),ur((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":w,children:[S(h,{justifyContent:"space-between",children:[S(h,{children:[u(f,{color:w,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:w,children:"\u2192 "}),u(Ur,{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"]})]})})]})},Iu=({store:e})=>{let t=Me(e);return S(on,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&u(yS,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&u(zo,{checks:t.data.checks}),u(cr,{inputId:t.inputRequest?.id,missing:t.data[_t],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&u(ar,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&u(wS,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&u(bS,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&u(pu,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&u(ts,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&u(rs,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&u(os,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&u(ss,{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(ns,{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(is,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&u(Xo,{status:t.status}),t.step==="Finished"&&u(ES,{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(es,{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(Le,{message:t.error.message})]})};import{Spinner as xS}from"@inkjs/ui";import{Box as Nt,Text as dr}from"ink";import{useState as CS}from"react";import{jsx as mt,jsxs as Ie}from"react/jsx-runtime";var ku=({store:e})=>{let t=Me(e),r=t.step==="Starting"||t.step==="Stopping",o=t.step==="Running"||t.step==="Stopped",n=t.data.dockerLogs??[],[i]=CS(Date.now),s=Vi(r);return Ie(Nt,{flexDirection:"column",width:"100%",children:[mt(ct,{showStatus:o}),r&&!t.error&&Ie(Nt,{flexDirection:"column",marginTop:1,children:[Ie(Nt,{children:[mt(xS,{label:t.status||"Working\u2026"}),Ie(dr,{color:"gray",children:[" ",nt(s-i)]})]}),n.length>0&&mt(en,{logs:n})]}),t.step==="Running"&&t.data.started&&Ie(Nt,{flexDirection:"column",marginTop:1,children:[Ie(Nt,{children:[mt(ee,{kind:"ok"}),Ie(dr,{children:["GAIA is running at"," ",mt(dr,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),Ie(dr,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&Ie(Nt,{flexDirection:"column",marginTop:1,children:[Ie(Nt,{children:[mt(ee,{kind:"ok"}),mt(dr,{children:t.status})]}),t.data.stopMode==="force-ports"&&Ie(dr,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&mt(Le,{message:t.error.message})]})};import{Spinner as IS}from"@inkjs/ui";import{Box as ft,Text as Se,useInput as kS}from"ink";import{jsx as k,jsxs as Ne}from"react/jsx-runtime";var Ru=({store:e})=>{let t=Me(e);return Ne(on,{status:t.status,step:t.step,steps:Cu,children:[t.step==="Detect Repo"&&Ne(ft,{flexDirection:"column",paddingX:2,borderStyle:I,borderColor:w,children:[k(Se,{bold:!0,children:"Detecting GAIA Repository"}),k(ft,{marginTop:1,children:k(IS,{label:"Searching for repository\u2026"})}),t.data.repoPath&&k(ft,{marginTop:1,children:Ne(Se,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&k(zo,{checks:t.data.checks}),k(cr,{inputId:t.inputRequest?.id,missing:t.data[_t],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&k(ar,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&k(ts,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&k(rs,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&k(os,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&k(ss,{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(ns,{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(is,{alternatives:t.data.alternativeGroups,onSubmit:(r,o)=>e.submitInput({selectedGroups:r,values:o})}),t.step==="Environment Setup"&&!t.inputRequest&&k(Xo,{status:t.status}),t.step==="Project Setup"&&k(es,{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(RS,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&k(Le,{message:t.error.message})]})},RS=({setupMode:e,portOverrides:t,onConfirm:r})=>{kS((s,a)=>{a.return&&r()});let o=t?.[3e3]??3e3,n=se(e??"developer",t??{}),i=e==="selfhost";return Ne(ft,{flexDirection:"column",marginTop:2,borderStyle:I,borderColor:w,padding:1,children:[k(Se,{color:w,bold:!0,children:"Setup Complete!"}),Ne(ft,{marginTop:1,children:[k(Se,{bold:!0,children:"Run: "}),k(Se,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Ne(ft,{marginTop:1,flexDirection:"column",children:[Ne(Se,{children:["Web:"," ",Ne(Se,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),Ne(Se,{children:["API:"," ",k(Se,{color:"cyan",bold:!0,children:n})]})]}),k(ft,{marginTop:1,children:k(Se,{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(ft,{marginTop:1,children:Ne(Se,{dimColor:!0,children:[k(Se,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as BS}from"@inkjs/ui";import{Box as te,Text as Fe,useInput as GS}from"ink";var TS=[{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 Tu(e){return Promise.all(TS.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?AS(t.name,r,t.path):PS(t.name,r)}))}async function AS(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 PS(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 Au(e){let t=await J();if(t!=="ready")return{access:t,problem:await Ue(t),containers:[]};let r=await Es(pe[e]);return{access:t,containers:r}}var jr="statusFacts";async function _S(){let e=_(),t=e?await F(e):null,r=kr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let o=N(e),n=o[A]??A,[i,s,a]=await Promise.all([t==="developer"?Tu(o):[],Au(t),Vo(kt(t,o),pe[t])]),c=a.reachable?await _e(se(t,o),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:DS(s.containers)}:s,readiness:a,services:i,webUrl:et(e,n),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function DS(e){let t=(L()?.bots??[]).map(me).filter(r=>!e.some(o=>o.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function OS(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await _S();e.updateData(jr,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function Pu(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await OS(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var $S=["gaia-web","gaia-backend","arq_worker","proxy"],LS=["mongo","postgres","redis","rabbitmq","chromadb"];function nn(e,t,r){return t.some(n=>!n.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function _u(e,t){return t.map(r=>e.find(o=>o.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:Ae(r.name)}))}function Du(e,t){let r=e.readiness,o=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:ao(i.name)})):_u(t,LS),n=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return nn("Data",o,n??"See why with: gaia doctor")}function MS(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"}:nn("Bots",t.map(r=>({ok:r.status==="running",name:Ae(r.name)})),"See why with: gaia doctor")}function Ou(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 NS(e,t){let r=t.containers,n=[nn("App",_u(r,$S),"Start it: gaia start"),Du(e,r),MS(r)],i=Ou(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 FS(e){let t=e.services.map(o=>({ok:o.status==="up",name:`${o.name} :${o.port}`})),r=nn("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 sn(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=Ou(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?[Du(e,[]),...n?[n]:[],o]:[],unhealthy:!0}}return e.services.length>0?FS(e):NS(e,t??{access:"ready",containers:[]})}import{jsx as D,jsxs as We}from"react/jsx-runtime";var US=8,jS={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},qS=({row:e})=>We(te,{children:[D(te,{width:US,flexShrink:0,children:D(Fe,{bold:!0,children:e.label})}),We(te,{flexDirection:"column",flexShrink:1,children:[e.items.length>0&&D(te,{flexWrap:"wrap",children:e.items.map(t=>We(te,{marginRight:2,flexShrink:0,children:[D(ee,{kind:t.ok?"ok":"fail"}),D(Fe,{children:t.name})]},t.name))}),e.note&&We(te,{children:[e.items.length===0&&e.tone!=="dim"&&D(ee,{kind:e.tone==="warn"?"warn":"ok"}),D(Fe,{color:jS[e.tone],children:e.note})]})]})]}),$u=({store:e})=>{let t=Me(e),r=t.data[jr],o=t.data.watch===!0,n=t.step==="Results"&&r!==void 0;GS((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:o&&t.inputRequest!==null});let i=r?sn(r):null,s=i?.headline.kind??"ok";return We(te,{flexDirection:"column",width:"100%",children:[D(ct,{showStatus:!1}),t.step==="Checking"&&D(te,{marginTop:1,marginLeft:2,children:D(BS,{label:t.status})}),n&&i&&We(te,{flexDirection:"column",marginTop:1,marginLeft:2,children:[We(te,{children:[D(ee,{kind:s==="ok"?"active":s}),D(Fe,{bold:!0,children:i.headline.text})]}),i.headline.url&&D(te,{marginLeft:2,children:D(Fe,{color:w,children:i.headline.url})}),i.hint&&D(te,{marginLeft:2,children:D(Fe,{children:i.hint})}),i.rows.length>0&&D(te,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>D(qS,{row:a},a.label))}),r.installed&&D(te,{marginTop:1,children:We(Fe,{color:"gray",children:["Installed at ",r.install]})}),o&&D(te,{marginTop:1,children:We(Fe,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",D(Fe,{bold:!0,children:"r"})," check again \xB7 ",D(Fe,{bold:!0,children:"q"})," quit"]})})]}),t.error&&D(Le,{message:t.error.message})]})};import{defaultTheme as HS,extendTheme as VS}from"@inkjs/ui";var Lu=VS(HS,{components:{Spinner:{styles:{frame:()=>({color:w})}},ProgressBar:{styles:{completed:()=>({color:w})}}}});import{jsx as ce,jsxs as pr}from"react/jsx-runtime";var zS=["init","setup","status","start","stop","up"],as=class extends YS.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?pr(an,{flexDirection:"column",padding:1,children:[ce(Ft,{color:"red",bold:!0,children:"An unexpected error occurred:"}),ce(Ft,{color:"red",children:this.state.error.message}),this.state.error.stack&&ce(an,{marginTop:1,children:ce(Ft,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},XS=({store:e,command:t})=>{switch(t){case"init":return ce(Iu,{store:e});case"setup":return ce(Ru,{store:e});case"status":return ce($u,{store:e});case"start":case"stop":return ce(ku,{store:e,command:t});case"up":return ce(yu,{store:e});default:return pr(an,{flexDirection:"column",padding:1,children:[pr(Ft,{color:"red",children:["Unknown command: ",t]}),pr(an,{marginTop:1,flexDirection:"column",children:[ce(Ft,{bold:!0,children:"Available commands:"}),zS.map(r=>pr(Ft,{children:[" ",ce(Ft,{color:"cyan",children:r})]},r))]})]})}},JS=({onCancel:e})=>(KS((t,r)=>{r.ctrl&&t==="c"&&e()}),null),Mu=({store:e,command:t,onCancel:r})=>ce(as,{children:pr(WS,{theme:Lu,children:[ce(JS,{onCancel:r}),ce(XS,{store:e,command:t})]})});import{EventEmitter as QS}from"events";var ZS=150,cs=class extends QS{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))},ZS))}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())}},Nu=()=>new cs;async function ve(e){let t=Nu();if(e.whenNonInteractive==="fail"){Cc(e.command),await Bu(t,e);return}fe()?await Bu(t,e):await rv(t,e)}async function rv(e,t){Ic(e,Qr());for(let[r,o]of t.autoResolve??[])e.setAutoResolve(r,o);try{await t.runFlow(e);let r=Uu(e);r&&await kn(e.currentState.step,r,oi(e)),t.onPlainComplete?.(e)}catch(r){e.setError(r)}ju(e)}var Gu=30,ov=Math.ceil(1e3/Gu);async function Fu(e){e.flush(),await new Promise(t=>setTimeout(t,2*ov))}async function Bu(e,t){let r=async()=>{},{unmount:o,clear:n}=ev(tv.createElement(Mu,{store:e,command:t.command,onCancel:()=>void r()}),{exitOnCtrlC:!1,maxFps:Gu}),i=async()=>{ot(e,"cancelled"),await Fu(e),o();let a=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
113
+ ${y.cancelled} Cancelled.${a}
114
+ `),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)}await Fu(e);let s=Uu(e);s&&(n(),o(),await kn(e.currentState.step,s,oi(e))),o(),process.stdout.write(`
115
+ `),ju(e)}function Uu(e){if(!e.currentState.error)return e.currentState.data.dockerGroupSwitch}function ju(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 gt from"fs";import*as Hu from"os";import*as Bt from"path";import*as cn from"node:fs";import*as qu from"node:path";var nv=e=>new Promise(t=>setTimeout(t,e));async function ln(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 mr(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 wr()){let p=yr(d,r);p&&(s[d]=p)}Object.assign(s,Ws(r));let a={};n?.domain&&(a.HOST=`https://${n.domain}`,a.FRONTEND_URL=`https://${n.domain}`),i==="infisical"?(await sv(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.")):await cv(e,a,r,n?.llmProvider===void 0);let c=cn.existsSync(je(t))?cn.readFileSync(je(t),"utf-8"):null,l=iv({defaults:s,existing:Ct(c),existingMode:await F(t),answers:a,setupMode:r});o&&Hs(l,o,r),r==="selfhost"&&Object.assign(l,io(c));try{await lv(e,t,l,r,o,n?.domain)}catch(d){e.setError(d);return}await nv(1e3)}function iv(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 sv(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 av(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 cv(e,t,r,o){e.setStatus("Parsing environment variables\u2026");let n=Vs(eo(),r).filter(g=>r!=="selfhost"||g.selfhostSetup),{alternativePairs:i,alternativeGroupNames:s}=av(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,b]of Object.entries(v.values))b&&(t[E]=b)}let l=wr(),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),b=v.variables.some(C=>C.required);return E&&!b?-1:!E&&b?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[b,C]of Object.entries(E)){let M=v.variables.find(O=>O.name===b);(C||M?.required||M?.defaultValue)&&(t[b]=C||M?.defaultValue||"")}}}async function lv(e,t,r,o,n,i){e.setStatus("Saving GAIA's settings\u2026");try{let s=qu.join(t,"apps","api");br(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{On(t,n??{},o,{dockerSocketGid:Cs(),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{Ys(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{ea(t),On(t,n,o),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}}}var uv=5e3,dv=5*6e4,pv=5e3;async function mv(e,t={}){let r=t.intervalMs??uv,o=Date.now()+(t.timeoutMs??dv),n=new Map(e.map(i=>[i.label,i]));for(;;){if(await Promise.all([...n.values()].map(async i=>{await fv(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 z(r)}}async function fv(e){try{let t=await fetch(e.url,{signal:AbortSignal.timeout(pv)});return e.requireOk?t.ok:!0}catch{return!1}}async function un(e,t){let r=await mv([{label:"API",url:`${t.apiUrl}/ping`,requireOk:!0},{label:"Web",url:`http://localhost:${t.webPort}/login`,requireOk:!1}],{onProgress:o=>{gv(e,o)}});return e.updateData("dependencyPhase",r.ready?"GAIA is answering":`Still starting: ${r.stillStarting}`),e.updateData("dependencyComplete",!0),r}function gv(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 hv=process.env.GAIA_CLI_DEV==="true";async function Vu(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input\u2026"),await e.waitForInput("welcome");let r=ko(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await Ro(e))return;let o=await ln(e),n=await er(e,o);if(n===null||o==="developer"&&!await To(e))return;let i="";if(hv){if(i=Xt()||"",!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 z(500),e.setStatus("Repository ready")}else{e.setStep("Repository Setup");let a=o==="selfhost"?Bt.join(Hu.homedir(),"gaia"):Bt.resolve("gaia"),c=!0;for(i=a;;){if(i=await e.waitForInput("repo_path",{default:a}),Bt.isAbsolute(i)||(i=Bt.resolve(i)),gt.existsSync(i)){if(!gt.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await z(2e3),e.setError(null);continue}if(Qe(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{gt.rmSync(i,{recursive:!0,force:!0})}catch(m){e.setError(new Error(`Failed to remove directory: ${m.message}
116
+ 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(gt.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await z(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 lo(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 z(1e3),await mr(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=Dc(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(`
117
+ `)[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";Xr({version:$,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",o);let d=await un(e,{apiUrl:se("selfhost",n),webPort:n[A]??A});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 ne("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)\u2026"),await ne("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 z(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?ze(n):void 0;await ne("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 z(1e3);let s=e.currentState.data.envMethod||"manual";Xr({version:$,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 Wu(e={}){await ve({command:"init",whenNonInteractive:"fail",runFlow:t=>Vu(t,e.branch)})}import*as ke from"node:fs";import*as Re from"node:path";import{execa as dn}from"execa";function ls(e){if(e.fromDir){let t=Re.resolve(e.fromDir),r=vs(t);if(!r)return{volumeFiles:[]};let o=jt(t,r),n=i=>ke.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=>ke.existsSync(i.file))}}return{mongoFile:e.mongoFile,postgresFile:e.postgresFile,apiEnvFile:e.apiEnvFile,volumeFiles:[]}}function Ku(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 us(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 ${Re.dirname(a)}:/backups alpine sh -c "${hr(Re.basename(a))}"`);return i}async function Yu(e,t){let r=_();if(!r)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let o=Re.join(r,"infra","docker"),n=Re.join(o,"docker-compose.selfhost.yml");if(!ke.existsSync(n))throw new Error(`Compose file not found: ${n}`);let i=ls(e),{mongoFile:s,postgresFile:a,apiEnvFile:c,volumeFiles:l}=i,d=us(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(`
118
+ `));if(c&&!ke.existsSync(c))throw new Error(`apps/api/.env backup not found: ${c}`);if(s&&!ke.existsSync(s))throw new Error(`Mongo backup not found: ${s}`);if(a&&!ke.existsSync(a))throw new Error(`Postgres backup not found: ${a}`);for(let{label:m,file:g}of l)if(!ke.existsSync(g))throw new Error(`${m} backup not found: ${g}`);if(e.dryRun)return{...i,commands:d};let p=await J();if(p!=="ready"){let m=await Ue(p);throw new Error([`${m.summary}, so nothing can be restored.`,m.fix,"Or run the restore commands yourself:",...d.map(g=>` ${g}`)].join(`
119
+ `))}if(c&&Sv(c,r),s)try{let m=dn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","mongo","mongorestore","--archive","--gzip","--drop"],{cwd:o,stdin:"pipe",stderr:"pipe"}),g=ke.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 dn("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=dn("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph"],{cwd:o,stdin:"pipe",stderr:"pipe"}),g=ke.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 dn("docker",["run","--rm","-v",`${g}:/data`,"-v",`${Re.dirname(m)}:/backups`,"alpine","sh","-c",hr(Re.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,N(r)),{...i,commands:d}}function Sv(e,t){oo(e,je(t))}function Be(e=""){process.stdout.write(`${e}
120
+ `)}function vv(e=""){process.stderr.write(`${e}
121
+ `)}async function zu(e={}){let t={mongoFile:e.mongo,postgresFile:e.postgres,apiEnvFile:e.env,fromDir:e.from},r=ls(t);for(let o of Ku(r))vv(`${y.warn} ${o}`);if(e.dryRun){let o=us(r);if(o.length===0){Be("No backup files resolved. Use --from <dir> or --mongo/--postgres/--env <file>.");return}Be("Restore commands (dry run \u2014 not executed):");for(let n of o)Be(` ${n}`);return}try{Be("Starting GAIA restore\u2026");let o=await Yu(t,n=>Be(` ${n}`));o.apiEnvFile&&Be(`Restored apps/api/.env from ${o.apiEnvFile}`),o.mongoFile&&Be(`Restored MongoDB from ${o.mongoFile}`),o.postgresFile&&Be(`Restored PostgreSQL from ${o.postgresFile}`);for(let{label:n,file:i}of o.volumeFiles)Be(`Restored ${n} from ${i}`);Be("Restore complete. Run 'gaia doctor' to confirm every dependency is ready.")}catch(o){le(o.message),process.exitCode=1}}async function Xu(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository\u2026");let t=Xt();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 z(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await Ro(e))return;let r=await ln(e),o=await er(e,r);if(o===null||r==="developer"&&!await To(e)||(await mr(e,t,r,o),e.currentState.error))return;if(r==="selfhost"){let a=e.currentState.data.envMethod||"manual";ye({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=ko(e);if(!await Oc(e,t,o,n))return;await z(1e3);let s=e.currentState.data.envMethod||"manual";ye({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 Ju(){await ve({command:"setup",whenNonInteractive:"fail",runFlow:Xu})}async function Qu(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 F(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 J();if(s!=="ready"){e.setError(await xt(s));return}}let n=N(r),i=n[A]??A;e.updateData("setupMode",o),e.updateData("webUrl",et(r,i)),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(-gr))},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 Zu(e){await ve({command:"start",whenNonInteractive:"plain",runFlow:t=>Qu(t,e),cancelHint:"GAIA may be partly started. Run 'gaia start' again to finish, or 'gaia stop'."})}var ed=8;function ht(e=""){process.stdout.write(`${e}
122
+ `)}function td(e){let t=e.currentState.data[jr];return t?{facts:t,report:sn(t)}:null}function yv(e){let t=td(e);if(!t)return;let{facts:r,report:o}=t,n=o.headline.kind==="ok"?y.active:y.fail;ht(`${n} ${o.headline.text}`),o.headline.url&&ht(` ${o.headline.url}`),o.hint&&ht(` ${o.hint}`),o.rows.length>0&&ht();for(let i of o.rows){let s=i.items.map(c=>`${c.ok?y.ok:y.fail} ${c.name}`).join(" "),a=i.items.length===0?i.note??"":"";ht(` ${i.label.padEnd(ed)}${s}${a}`.trimEnd()),i.items.length>0&&i.note&&ht(` ${" ".repeat(ed)}${i.note}`)}r.installed&&(ht(),ht(` Installed at ${r.install}`))}async function rd(e={}){await ve({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:async t=>{await Pu(t,e),td(t)?.report.unhealthy&&(process.exitCode=1)},onPlainComplete:yv})}async function od(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=N(r);try{await Oa(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 nd(e){await ve({command:"stop",whenNonInteractive:"plain",runFlow:t=>od(t,e),cancelHint:"GAIA may still be partly running. Run 'gaia stop' again."})}import*as pn from"fs";import*as mn from"path";function wv(e){let t=mn.join(e,".env");return pn.existsSync(t)?["--env-file",".env"]:[]}async function id(){let e=_();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await F(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=mn.join(e,"infra","docker"),o=wv(r),n=N(e),i=Object.keys(n).length>0?ze(n):void 0;if(t==="selfhost"){await ir("docker",["compose",...Je(zt()),...o,"logs","-f","--tail","200"],r,i);return}let s=["compose",...o,"logs","-f","--tail","200"],a=mn.join(e,Ta),c=qn(e),l=typeof c=="number"&&mo(c);if(pn.existsSync(a)&&l){console.log("Streaming app and infrastructure logs\u2026"),process.platform==="win32"?await qo([{cmd:"powershell",args:["-Command",`Get-Content -Path '${a.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]):await qo([{cmd:"tail",args:["-n","200","-f",a],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]);return}pn.existsSync(a)&&!l?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await ir("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 ir("docker",s,r,i))}import{execFile as Iv}from"node:child_process";import*as md from"node:os";import*as sd from"node:os";import*as ad from"node:path";var bv=80,Ev=443,cd=ad.join(sd.homedir(),"gaia");function ld(){let e=L()?.repoPath;return e&&Qe(e)?e:null}function ud(e){let t={};return e.domain&&(t[A]=bv,t[Tr]=Ev),e.webPort&&(t[A]=e.webPort),t}function xv(){return L()?.values??{}}function Cv(e){return eo().flatMap(t=>t.variables).find(t=>t.name===e)}function dd(e){let{repoPath:t,interactive:r=fe(),setupMode:o="selfhost"}=e,n=xv(),i=new Set(wr()),s=new Map,a=l=>(s.has(l)||s.set(l,Cv(l)?.required===!0),s.get(l)===!0),c=l=>{let d=n[l]??yr(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 fd="gaia up --build",kv="usually 10-20 minutes \xB7 safe to leave running",Rv={building:"Building GAIA",downloading:"Downloading GAIA's images",unpacking:"Unpacking GAIA's images",starting:"Starting GAIA",stopping:"Stopping GAIA"};function Tv(e,t){let r=e.llmProvider?lr[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",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 qr(e,t){ot(e,"failed"),e.setError(t)}async function gd(e,t={}){gu(t);let r=Math.min(Date.now(),...Object.values(Zr())),o=ld(),n=o??cd,i=!Qe(n);e.pushAnswerResolver(dd({repoPath:n})),xc(e,Tv(t,i)),e.setStep("Prerequisites"),rt(e,"check");try{if(await Io(e,{needGit:i,assumeYes:t.yes===!0,onInstallStart:g=>rt(e,"check",{label:`Installing ${Zt(g)}`,doneLabel:`Installed ${Zt(g)}`,startedAt:Date.now()})})==="relaunch")return}catch(m){qr(e,m);return}if(!t.build&&!await Av(e,n,i))return;let s=await er(e,"selfhost");if(s===null){ot(e,"failed");return}if(Object.assign(s,ud(t)),!i&&n!==o&&!t.forceDevTree&&await F(n)==="developer"){qr(e,new Error(`${n} is set up for development (apps/api/.env is in developer mode), and 'gaia up' would overwrite its settings.
123
+ Run it with --force-dev-tree to go ahead anyway.`));return}if(Tt(e,"check"),e.setStep("Repository Setup"),rt(e,"download"),!await Pv(e,n,i))return;if(ye(t.codeSandbox===void 0?{repoPath:n}:{repoPath:n,codeSandbox:t.codeSandbox}),Tt(e,"download",i?void 0:`Using your install at ${Pe(n)}`),e.setStep("Environment Setup"),rt(e,"configure"),await mr(e,n,"selfhost",s,{llmProvider:t.llmProvider,domain:t.domain}),e.currentState.error){ot(e,"failed");return}Tt(e,"configure");let a=s[A]??A,c={webUrl:Wn(a,t.domain),reachableUrls:qa(a,t.domain),noStart:t.noStart===!0,stillStarting:!1,setupComplete:!1,codeSandbox:L()?.codeSandbox===!0,joinedDockerGroup:Ls(),elapsedMs:0,startedServices:0};if(t.noStart){pd(e,n,{...c,elapsedMs:Date.now()-r});return}e.setStep("Project Setup");try{c.startedServices=await Ov(e,n,s,t)}catch(m){qr(e,m);return}rt(e,"wait");let l=se("selfhost",s),d=await un(e,{apiUrl:l,webPort:a});d.ready?Tt(e,"wait"):He(e,"wait",{state:"failed",endedAt:Date.now()}),c.stillStarting=!d.ready,c.setupComplete=d.ready&&await $v(l);let p=await Dv(e,n,t,d.ready);if(t.llmProvider&&(p?c.unsavedProvider=t.llmProvider:c.savedProvider=t.llmProvider),pd(e,n,{...c,elapsedMs:Date.now()-r}),p){e.setError(p);return}d.ready&&_v(c.webUrl,t)}async function Av(e,t,r){let o=r?Ke:Te(t);e.setStatus(`Checking that GAIA ${o} is available for this computer\u2026`);let n=await Qt(o,L()?.bots??[]);if(!n)return!0;let{cause:i,next:s}=Yt(n,fd);return qr(e,new Error(`${i}
124
+ ${s}`)),!1}async function Pv(e,t,r){if(!r)return!0;He(e,"download",{detail:"Connecting to GitHub\u2026",percent:0});try{await pa(t,ua,(o,n)=>{He(e,"download",n?{percent:o,detail:n}:{percent:o})})}catch(o){return qr(e,new Error(`Couldn't download GAIA into ${t}: ${o.message}`)),!1}return!0}function _v(e,t){let r=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;!t.yes&&r&&md.platform()==="darwin"&&Iv("open",[`${e}/setup`],()=>{})}async function Dv(e,t,r,o){let{llmProvider:n}=r;if(!n)return null;let i=lr[n];if(rt(e,"provider"),!o)return ot(e,"failed"),new Error(`GAIA didn't answer in time, so your ${i} key wasn't saved.
125
+ Once 'gaia status' shows it running, run 'gaia up' again with the same flags.`);try{await hu(t,{...r,llmProvider:n})}catch(s){return ot(e,"failed"),new Error(`Your ${i} key wasn't saved: ${s.message}
126
+ Check the key and run 'gaia up --llm-provider ${n} --llm-key <key>' again, or add it on the setup page above.`)}return Tt(e,"provider"),null}async function Ov(e,t,r,o){rt(e,"start",o.build?{hint:kv}:{});let{startedServices:n}=await oe(t,"selfhost",i=>He(e,"start",{detail:i}),r,i=>He(e,"start",{label:Rv[i.stage],detail:i.label,percent:i.percent}),{...o.build?{build:!0}:{pull:"missing"},rebuildCommand:fd,onLogFile:i=>e.updateData("logPath",i)});return Tt(e,"start",n===0?"GAIA was already running":void 0),n}async function $v(e){let t=await _e(e,"status");return"data"in t&&!t.data.needs_setup}function pd(e,t,r){ye({version:$,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 Lv=16,Mv=14;function Hr(e=""){process.stdout.write(`${e}
127
+ `)}function Nv(e){let t=e.currentState.data.upOutcome;if(!t)return;let r=Zo(t);Hr(),Hr(`${r.tone==="success"?`${y.ok} `:""}${r.headline}`);for(let o of r.rows)Hr(` ${o.label.padEnd(Lv)}${o.text}`);Hr();for(let[o,n]of Qo)Hr(` ${o.padEnd(Mv)}${n}`)}async function hd(e={}){await ve({command:"up",whenNonInteractive:"plain",runFlow:t=>gd(t,e),cancelHint:"GAIA may be partly set up. Run 'gaia up' again to finish, or 'gaia stop'.",onPlainComplete:Nv})}import*as kd from"node:readline";var Fv="https://api.github.com/repos/theexperiencecompany/gaia/releases/tags",Bv=5e3,Gv=5,Uv=["Features","Bug Fixes"],jv=/^\* (.+)$/,qv=/^\*\*[^*]+:\*\*\s*/,Hv=/(\s*\(\[[^\]]+\]\([^)]+\)\))+$/;function Vv(e){let t=e.replace(qv,"").replace(Hv,"");return t.charAt(0).toUpperCase()+t.slice(1)}function Wv(e){let t=new Map,r="";for(let o of e.split(`
128
+ `)){let n=/^#{2,3} (.+)$/.exec(o.trim());if(n?.[1]){r=n[1];continue}let i=jv.exec(o.trim())?.[1];i&&t.set(r,[...t.get(r)??[],Vv(i)])}return Uv.flatMap(o=>t.get(o)??[]).slice(0,Gv)}async function Sd(e){let t=await fetch(`${Fv}/${Kt(e)}`,{headers:{Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Bv)});if(!t.ok)throw new Error(`GitHub answered HTTP ${t.status}`);let{body:r}=await t.json();return Wv(r??"")}import{execa as Vr}from"execa";var Kv=["apps/web","apps/api","infra/docker"];function vd(e){let{current:t,target:r,explicit:o,gap:n}=e;if(!o){if(tt(t)===null)return{kind:"development-build"};if(!qe(r,t))return{kind:"up-to-date"}}return n?{kind:"unavailable",gap:n}:{kind:"offer",downgrade:qe(t,r)}}async function St(e,t){let{stdout:r}=await Vr("git",t,{cwd:e});return r.trim()}async function yd(e){let t=await Vr("git",["rev-parse","--is-inside-work-tree"],{cwd:e,reject:!1});return t.exitCode!==0||t.stdout.trim()!=="true"?!1:(await Vr("git",["remote","get-url","origin"],{cwd:e,reject:!1})).exitCode===0}function wd(e){return e.split(`
129
+ `).map(t=>t.trim()).filter(Boolean)}async function Yv(e,t){let r=await St(e,["log",t,"--oneline","--",...Kv]);return{commits:wd(r)}}async function bd(e,t){let r=Te(e),o=Kt(t);if(!await yd(e))return{repoPath:e,fromVersion:r,toVersion:t,checkout:null};await Gn("origin",t,e);let n=`refs/tags/${o}`,i=await Vr("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([St(e,["rev-parse","HEAD"]),St(e,["rev-parse",`${o}^{commit}`]),St(e,["rev-parse","--short","HEAD"])]);return{repoPath:e,fromVersion:r,toVersion:t,checkout:{fromRef:c,toTag:o,atTag:s===a}}}function Ed(e){return e.fromVersion===e.toVersion&&(e.checkout===null||e.checkout.atTag)}async function xd(e,t){if(e.checkout&&!e.checkout.atTag){let r=wd(await St(e.repoPath,["status","--porcelain","--untracked-files=no"]));if(r.length>0)throw new Error(`Local changes to tracked files would be overwritten:
125
130
  ${r.join(`
126
131
  `)}
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?`
132
+ Commit or discard them, or update this checkout yourself with 'gaia update --git'.`)}t(`Downloading GAIA ${e.toVersion}\u2026`),await Da(e.repoPath,e.toVersion),e.checkout&&!e.checkout.atTag&&(t(`Updating the setup files to ${e.toVersion}\u2026`),await St(e.repoPath,["checkout","--detach",e.checkout.toTag])),t(`Switching to GAIA ${e.toVersion}\u2026`),Un(e.repoPath,e.toVersion),t("Restarting GAIA\u2026"),await oe(e.repoPath,"selfhost",t,N(e.repoPath),void 0,{pull:"missing"})}async function Cd(e){if(!await yd(e))throw new Error(`${e} is not a git checkout with an origin remote; run 'gaia update' without --git.`);if((await Vr("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 St(e,["fetch","origin"]),Yv(e,"HEAD..@{upstream}")}async function Id(e,t){t("Pulling the latest commits (git pull --ff-only)\u2026"),await St(e,["pull","--ff-only"]),t("Rebuilding images from this checkout and restarting\u2026"),await oe(e,"selfhost",t,N(e),void 0,{build:!0})}var zv=5,Xv="https://docs.heygaia.io/release-notes";function R(e=""){process.stdout.write(`${Ze(e)}
133
+ `)}async function Jv(e){let t=kd.createInterface({input:process.stdin,output:process.stdout});t.on("SIGINT",()=>{t.close(),R(`
134
+ ${y.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 Qv(e,t){let r=t?e.commits:e.commits.slice(0,zv);for(let n of r)R(` ${n}`);let o=e.commits.length-r.length;o>0&&R(` and ${o} more (--verbose lists them)`)}async function Zv(e){try{for(let t of await Sd(e))R(` - ${t}`)}catch(t){R(` (couldn't read what's new in ${e}: ${t.message})`)}}async function Rd(e,t){return e.yes?!0:fe()?Jv(`
135
+ ${t}`):(R(`
136
+ No terminal to confirm in: rerun with --yes to apply.`),!1)}async function ey(e,t){let r=Te(e),o=t.version??Ke,n=t.version!==void 0,s=n||tt(r)!==null&&qe(o,r)?await Qt(o,L()?.bots??[]):null,a=vd({current:r,target:o,explicit:n,gap:s});switch(a.kind){case"development-build":R(`This install runs a development build of GAIA (${yo(r)}), not a release, so there is nothing to update.`),R(`To switch it to the ${o} release: gaia update --version ${o}`);return;case"up-to-date":R(`GAIA ${r} is up to date.`);for(let l of da($))R(l);return;case"unavailable":R(`${Yt(a.gap,"gaia up --build").cause} Nothing was changed.`),n&&(process.exitCode=1);return;case"offer":break}let c=await bd(e,o);if(Ed(c)){R(`GAIA ${r} is up to date.`);return}R(a.downgrade?`
133
137
  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();
138
+ Update available: GAIA ${r} \u2192 ${o}`),await Zv(o),R(`What's new: ${Xv}`),R("Your data and settings are kept."),await Rd(t,"Update and restart now?")&&(await xd(c,l=>R(` ${l}`)),R(`
139
+ ${y.ok} GAIA is on ${o}.`),R("Run 'gaia doctor' to check that everything is ready."))}async function ty(e,t){let r=await Cd(e);if(r.commits.length===0){R("Already up to date with the upstream branch.");return}R(`
140
+ ${r.commits.length} new commit(s) touch the self-host stack:`),Qv(r,t.verbose===!0),R("The images are rebuilt from this checkout (slow on small machines)."),await Rd(t,"Pull, rebuild and restart now?")&&(await Id(e,o=>R(` ${o}`)),R(`
141
+ Updated and restarted from source.`))}async function Td(e={}){await Rt({showUpdate:!1});let t=_();if(!t){le(`GAIA isn't installed here, so there is nothing to update.
142
+ Install it with 'gaia up'.`),process.exitCode=1;return}if(e.git&&e.version){le(`--version and --git can't be used together.
143
+ --version moves to a published release; --git builds from source. Pick one.`),process.exitCode=1;return}R(`Checking for updates in ${Pe(t)}\u2026`);try{await(e.git?ty(t,e):ey(t,e))}catch(r){R(),le(`GAIA wasn't updated: ${r.message}
144
+ Your data is untouched. Fix the cause above, then run 'gaia update' again.`),process.exitCode=1}}var ny=new Set(["-V","--version"]),K=new ry,ds="For contributors:",iy=20;K.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").configureHelp({minWidthToWrap:iy}).enablePositionalOptions().addHelpText("after",`
145
+ New here? Run: gaia up`);K.command("up").description(U.up).option("--yes","Answer yes to every question, including installing Git and Docker").addOption(new oy("--llm-provider <provider>","AI provider to save once GAIA is running (checked first, as the setup page does)").choices(zi)).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 hd({...r,noStart:t===!1})});K.command("status").description(U.status).option("--watch","Stay open; press r to check again").action(async e=>{await rd({watch:e.watch})});K.command("stop").description(U.stop).option("--force-ports","Also stop whatever else listens on GAIA's ports (may stop other programs)").action(async e=>{await nd({forcePorts:e.forcePorts})});K.command("start").description(U.start).option("-b, --build","Build GAIA from source before starting (slow)").option("--pull","Download GAIA's images again before starting").action(async e=>{await Zu({build:e.build,pull:e.pull?"always":void 0})});K.command("update").description(U.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").option("--verbose","With --git, list every new commit").action(async e=>{await Td(e)});K.command("doctor").description(U.doctor).action(async()=>{await eu()});K.command("logs").description(U.logs).action(async()=>{try{await id()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});K.addCommand(Or);K.addCommand($l);K.addCommand(Ve);K.command("backup").description(U.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 Ga({output:e.output,dryRun:e.dryRun})});K.command("restore").description(U.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 zu({mongo:e.mongo,postgres:e.postgres,env:e.env,from:e.from,dryRun:e.dryRun})});K.command("init").helpGroup(ds).description(U.init).option("--branch <branch>","Git branch to clone").action(async e=>{await Wu({branch:e.branch})});K.command("setup").helpGroup(ds).description(U.setup).action(async()=>{await Ju()});K.command("dev [profile]").helpGroup(ds).description(U.dev).action(async e=>{try{await Ml(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});ny.has(process.argv[2]??"")&&(await mc(),process.exit(0));process.argv.slice(2).length||(K.outputHelp(),process.exit(0));K.parse();