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

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