@heygaia/cli 0.7.0-beta.4 → 0.7.0-beta.6

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 +117 -117
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,106 +1,106 @@
1
1
  #!/usr/bin/env node
2
- import pE from"chalk";import{Command as mE,Option as fE}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",uninstall:"Remove GAIA from this computer (asks before deleting your data)",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 ml from"node:path";import Em from"is-unicode-supported";var w="cyan",Lr=30,T="round",it=Em(),y={ok:it?"\u2713":"\u221A",fail:it?"\u2717":"x",warn:"!",skip:it?"\u2013":"-",pending:it?"\u25CB":"o",active:it?"\u25CF":"*",cancelled:it?"\u25A0":"#"},hi={done:it?"\u2501":"=",rest:it?"\u2500":"-"},Mr={ok:"green",fail:"red",warn:"yellow",skip:"gray",pending:"gray",active:w,cancelled:"yellow"};function he(e){let[t="",...r]=e.split(`
2
+ import NE from"chalk";import{Command as FE,Option as BE}from"commander";var j={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",uninstall:"Remove GAIA from this computer (asks before deleting your data)",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 bl from"node:path";import $m from"is-unicode-supported";var w="cyan",Cn="handedOver",$r=30,_="round",st=$m(),y={ok:st?"\u2713":"\u221A",fail:st?"\u2717":"x",warn:"!",skip:st?"\u2013":"-",pending:st?"\u25CB":"o",active:st?"\u25CF":"*",cancelled:st?"\u25A0":"#"},yi={done:st?"\u2501":"=",rest:st?"\u2500":"-"},Lr={ok:"green",fail:"red",warn:"yellow",skip:"gray",pending:"gray",active:w,cancelled:"yellow"};function ye(e){let[t="",...r]=e.split(`
3
3
  `),n=[`${y.fail} ${t}`,...r.map(o=>` ${o}`)];process.stderr.write(`${n.join(`
4
4
  `)}
5
- `)}var Ct=[{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 Nr(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 X from"node:fs";import*as De from"node:path";import{execa as pl}from"execa";import*as kn from"node:fs";import*as Si from"node:path";var xm=/^\d{4}-\d{2}-\d{2}(T\d{2}-\d{2}-\d{2}Z)?$/,Im=".partial",_a={prefix:"mongo-",suffix:".gz"},Da={prefix:"postgres-",suffix:".sql"},Oa={prefix:"api-env-",suffix:".env"},$a=".tar.gz",km=[_a,Da,Oa,...Ct.map(e=>({prefix:`${e.fileSuffix}-`,suffix:$a}))];function vi(e=new Date){return`${e.toISOString().slice(0,19).replaceAll(":","-")}Z`}function Zt(e,t){let r=n=>Si.join(e,`${n.prefix}${t}${n.suffix}`);return{mongoFile:r(_a),postgresFile:r(Da),apiEnvFile:r(Oa),volumeFiles:Ct.map(n=>yi(e,t,n))}}function yi(e,t,r){return{volume:r.volume,label:r.label,file:Si.join(e,`${r.fileSuffix}-${t}${$a}`)}}function At(e){return`${e}${Im}`}function La(e){return kn.existsSync(e)?kn.readdirSync(e).flatMap(r=>km.flatMap(({prefix:n,suffix:o})=>{if(!r.startsWith(n)||!r.endsWith(o))return[];let i=r.slice(n.length,r.length-o.length);return xm.test(i)?[i]:[]})).sort().at(-1):void 0}import*as Rn from"node:fs";import*as Fa from"node:os";import{execa as er}from"execa";var Ma="/var/run/docker.sock",be={selfhost:"gaia-selfhost",developer:"gaia-dev"},Rm=/\((healthy|unhealthy|health: starting)\)/;async function Ba(e){return(await Pt(e)).map(r=>({name:r.service,status:r.state==="running"?"running":"stopped",health:r.health}))}async function Ga(e){let{stdout:t}=await er("docker",["ps","--filter",`label=com.docker.compose.project=${e}`,"--format","{{.Ports}}"]),r=new Set;for(let n of t.matchAll(/:(\d+)->/g))r.add(Number(n[1]));return r}function Ua(){return Fa.platform()!=="linux"||!Rn.existsSync(Ma)?0:Rn.statSync(Ma).gid}async function Pt(e){let{stdout:t}=await er("docker",["ps","-a","--filter",`label=com.docker.compose.project=${e}`,"--format",'{{.Label "com.docker.compose.service"}}|{{.State}}|{{.Status}}']);return Cm(t)}function Cm(e){let t=[];for(let r of e.trim().split(`
6
- `)){if(!r)continue;let[n,o,i]=r.split("|");if(!n||!o)continue;let s=i?.match(Rm)?.[1];t.push(s?{service:n,state:o,health:s}:{service:n,state:o})}return t}async function ja(){let{stdout:e}=await er("docker",["info","--format","{{.DockerRootDir}}"]),t=e.trim();if(!t)throw new Error("docker info returned an empty DockerRootDir");return t}async function qa(e){let{stdout:t}=await er("df",["-k",e]);return t}var Na=26;async function Am(){let{stdout:e}=await er("docker",["version","--format","{{.Server.Version}}"]);return e.trim()}async function Ha(){let e=await Am(),t=Number.parseInt(e,10);if(Number.isNaN(t)||t<Na)throw new Error(`The code sandbox needs Docker Engine ${Na} 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 Cn(e){let{stdout:t}=await er("docker",["volume","ls","--quiet","--filter",`name=^${e}$`]);return t.trim().split(`
7
- `).includes(e)}import*as vc from"node:os";import{execa as Vm}from"execa";import{spawn as Bm}from"node:child_process";import*as Ti from"node:os";import{execa as _i}from"execa";import*as lc from"node:fs";import*as Ai from"node:path";import*as Ze from"fs";import*as cc from"os";import*as Ci from"path";var Va={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.7.0-beta.4",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"}};import*as j from"fs";import*as st from"path";import*as Fr from"node:fs";import*as wi from"node:path";var Wa=[{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 bi={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/"}},Ka={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 Br(e,t){return bi[t][e]??Ka[t][e]}function An(){return structuredClone(Wa)}function Ya(e){let t=wi.join(e,"apps","web",".env.local"),r=Fr.existsSync(t)?t:wi.join(e,"apps","web",".env");if(!Fr.existsSync(r))return[];let n=Fr.readFileSync(r,"utf-8"),o=[],i="General";for(let s of n.split(`
8
- `)){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(),u=a.substring(c+1).trim();o.push({name:l,value:u,category:i})}return o}function za(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function Xa(e,t,r){let n=r==="selfhost"?new Set(Object.keys(bi.selfhost)):new Set;for(let[o,i]of Object.entries(t)){let s=Number(o),a=Number(i);for(let[c,l]of Object.entries(e)){if(n.has(c))continue;if(l===String(s)){e[c]=String(a);continue}let u=new RegExp(`:${s}(?=[/\\s]|$)`,"g");e[c]=l.replaceAll(u,`:${a}`)}}}function Ja(e,t){return e.map(r=>({...r,variables:r.variables.map(n=>{let o=Br(n.name,t);return{...n,defaultValue:o||n.defaultValue}})}))}function Gr(){return Object.keys(bi.selfhost)}function Qa(e){return{...Ka[e]}}var Dm=[".test",".example",".invalid",".localhost",".local",".internal",".home.arpa"],Za="docker cp gaia-selfhost-proxy-1:/data/caddy/pki/authorities/local/root.crt gaia-root.crt";function Pn(e){let t=e.toLowerCase();return Dm.some(r=>t.endsWith(r))}function Tt(e){let t={};if(!e)return t;for(let r of e.split(`
9
- `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<=0)continue;let i=n.substring(0,o).trim(),s=n.substring(o+1).trim().replace(/^["']|["']$/g,"");i&&s&&(t[i]=s)}return t}var Ei=384;function Tn(e){if(j.existsSync(e)){let t=`${e}.bak`;j.copyFileSync(e,t),j.chmodSync(t,Ei)}}function _n(e,t){j.mkdirSync(st.dirname(e),{recursive:!0}),j.writeFileSync(e,t,{encoding:"utf-8",mode:Ei}),j.chmodSync(e,Ei)}function Dn(e,t){Tn(t),_n(t,j.readFileSync(e,"utf-8"))}function Ur(e,t){let r=st.join(e,".env");Tn(r);let n=["# GAIA Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],o=["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 o)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())n.push(`# ${a} Configuration`),n.push(...c),n.push("");_n(r,n.join(`
10
- `))}function rc(e,t,r){let n=st.join(e,"apps","web",".env.local");Tn(n);let o=Ya(e),i=za(t,r),s=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],a=new Map;for(let c of o){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(o.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:u,value:p}of l)s.push(`${u}=${p}`);s.push("")}_n(n,s.join(`
11
- `))}var xi={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"},ec=Object.fromEntries(Object.entries(xi).map(([e,t])=>[t,Number(e)])),Om="proxy";function nc(e){return st.join(e,"infra","docker",".env")}function On(e){let t=nc(e);return j.existsSync(t)?Tt(j.readFileSync(t,"utf-8")):{}}var _t="GAIA_VERSION",$m="latest",oc="GAIA_DOMAIN",tc="GAIA_CADDY_GLOBAL_OPTIONS",Lm="local_certs";function $n(e){return On(e)[oc]||void 0}function Be(e){return On(e)[_t]??$m}function ic(e,t){let r=nc(e);Tn(r);let n=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[o,i]of Object.entries(t))n.push(`${o}=${i}`);n.push(""),_n(r,n.join(`
12
- `))}function sc(e,t,r){ic(e,{...On(e),[t]:r})}function Ii(e,t,r,n){let{NEXT_PUBLIC_APP_URL:o,...i}=On(e);for(let[s,a]of Object.entries(t)){let c=Number(s),l=xi[c];l&&(i[l]=String(a))}r==="selfhost"&&n&&(i.COMPOSE_PROFILES??=Om,i.DOCKER_SOCKET_GID=String(n.dockerSocketGid),n.domain&&(i[oc]=n.domain,Pn(n.domain)?i[tc]=Lm:delete i[tc])),ic(e,i)}function at(e){let t={};for(let[r,n]of Object.entries(e)){let o=Number(r),i=xi[o];i&&(t[i]=String(n))}return t}function ac(e){let t=st.join(e,"infra","docker","docker-compose.yml");if(!j.existsSync(t))return;let r=j.readFileSync(t,"utf-8"),n=[{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}],o=!1;for(let{varName:i,hostPort:s,containerPort:a}of n){let c=`"${s}:${a}"`,l=`"\${${i}:-${s}}:${a}"`;r.includes(c)&&(r=r.replaceAll(c,l),o=!0)}{let i='"15672:15672"';r.includes(i)&&(r=r.replaceAll(i,'"${RABBITMQ_MGMT_PORT:-15672}:15672"'),o=!0)}o&&j.writeFileSync(t,r,"utf-8")}function A(e){let t=st.join(e,"infra","docker",".env"),r={};if(!j.existsSync(t))return r;let n=j.readFileSync(t,"utf-8");for(let o of n.split(`
13
- `)){let i=o.trim();if(i&&!i.startsWith("#")){let[s,...a]=i.split("=");if(s&&ec[s]){let c=a.join("=").trim().replace(/^["']|["']$/g,""),l=Number(c);!Number.isNaN(l)&&l>0&&l<=65535&&(r[ec[s]]=l)}}}return r}var R=Va.version;function ki(e,t){return e[_t]||`v${t}`}var Ge=ki(process.env,R);var Ee=Ci.join(cc.homedir(),".gaia"),Ri=Ci.join(Ee,"config.json");function Nm(){Ze.existsSync(Ee)||Ze.mkdirSync(Ee,{recursive:!0})}function C(){try{if(!Ze.existsSync(Ri))return null;let e=Ze.readFileSync(Ri,"utf-8");return JSON.parse(e)}catch{return null}}function Ln(e){Nm(),Ze.writeFileSync(Ri,`${JSON.stringify(e,null,2)}
14
- `)}function Se(e){let r={...C()??{version:R,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Ln(r)}var jr=Ai.join(Ee,"logs");function Ue(e,t=new Date){lc.mkdirSync(jr,{recursive:!0});let r=t.toISOString().slice(0,19).replaceAll(":","-");return Ai.join(jr,`${e}-${r}.log`)}function Mn(e){let t="";return r=>{let n=(t+r).split(/\r?\n|\r/);t=n.pop()??"";for(let o of n)o.trim()&&e(o)}}import*as uc from"node:fs";import{execa as Pi}from"execa";function dc(){return typeof process.getuid=="function"&&process.getuid()===0}async function Fm(){dc()||!(await Pi("sudo",["-n","true"],{reject:!1})).failed||await Pi("sudo",["-v","-p","[sudo] password for %u: "],{stdio:"inherit"})}async function q(e,t,r,n){await Fm();let[o,i]=dc()?[e,[...t]]:["sudo",["-n",e,...t]],s=uc.createWriteStream(r,{flags:"a"}),a=Mn(u=>n?.(u)),c=Pi(o,i,{all:!0,reject:!1});c.all?.on("data",u=>{s.write(u),a(u.toString())});let l=await c;if(await new Promise(u=>s.end(u)),l.failed)throw new Error(`'${[e,...t].join(" ")}' failed (exit ${l.exitCode??"unknown"}). Its output is in ${r}`)}var oe="docker",Di="GAIA_DOCKER_GROUP_RELAUNCHED",pc="GAIA_RESUMED_STEP",mc="GAIA_RESUMED_STEPS";function Nn(){return process.env[pc]||void 0}function Fn(){let e=process.env[mc];return e?JSON.parse(e):{}}function fc(){return process.env[Di]==="1"}async function Oi(){let{stdout:e}=await _i("id",["-nG",Ti.userInfo().username]);return e.split(/\s+/).includes(oe)}function gc(e){let t=e.stderr;return typeof t=="string"&&t.toLowerCase().includes("permission denied")}async function hc(){if(process.env[Di]==="1")throw new Error(`Still no access to the Docker socket after joining the '${oe}' group.
15
- Check the socket's group with 'ls -l /var/run/docker.sock', then log out and back in and rerun.`);if(await Oi())return;let e=Ti.userInfo().username;try{await q("usermod",["-aG",oe,e],Ue("docker-group"))}catch(t){throw new Error(`Could not add ${e} to the '${oe}' group: ${t.message}
16
- Run 'sudo usermod -aG ${oe} ${e}', log out and back in, then rerun.`)}}var Gm=/^[A-Za-z_][A-Za-z0-9_]*$/;async function Um(e){try{return await _i("sh",["-c",'command -v "$1"',"sh",e]),!0}catch{return!1}}async function jm(){try{return await _i("sudo",["-l","-g",oe,"--",process.execPath]),!0}catch{return!1}}async function Sc(){if(await Um("sg"))return"sg";if(await jm())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 '${oe}' group).
17
- Log out and back in (or run 'newgrp ${oe}'), then rerun this command.`)}function qm(e){return`'${e.replaceAll("'","'\\''")}'`}function Hm(e,t,r){return e==="sg"?["sg",[oe,"-c",t.map(qm).join(" ")]]:["sudo",[`--preserve-env=${Object.keys(r).filter(o=>Gm.test(o)).join(",")}`,"-g",oe,"--",...t]]}function $i(e,t,r){let n={...process.env,[Di]:"1",[pc]:e,[mc]:JSON.stringify(r)},[o,i]=Hm(t,[process.execPath,...process.argv.slice(1)],n),s=Bm(o,i,{stdio:"inherit",env:n});return new Promise((a,c)=>{s.on("error",c),s.on("exit",(l,u)=>{process.exit(l??(u?1:0))})})}var Wm=5e3,Km="https://orbstack.dev",Li="Run 'gaia up': it installs everything GAIA needs.";async function Z(){try{return await Vm("docker",["info"],{timeout:Wm}),"ready"}catch(e){return e.code==="ENOENT"?"not-installed":gc(e)?"no-permission":"not-running"}}async function et(e){let t=vc.platform()==="darwin";switch(e){case"not-installed":return{summary:"Docker isn't installed",state:"isn't installed",fix:t?`Install OrbStack (${Km}) or Docker Desktop, open it, then try again.`:Li};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 Oi()?`Your user just joined the '${oe}' group. Log out and back in (or run 'newgrp ${oe}' in this terminal), then try again.`:`Run 'sudo usermod -aG ${oe} $USER', log out and back in, then try again.`}}}async function Dt(e){let t=await et(e);return new Error(`${t.summary}.
18
- ${t.fix}`)}import{execa as cg}from"execa";import*as Ie from"fs";import*as ae from"path";import*as tr from"node:fs";import*as qr from"node:path";import*as wc from"node:crypto";var yc=["AGENT_SECRET","BOT_SESSION_TOKEN_SECRET","EMAIL_UNSUBSCRIBE_SECRET","SHARE_GRANT_SECRET","GAIA_BOT_API_KEY"],Ym=["INSTANCE_SECRET"];function Mi(){return wc.randomBytes(32).toString("hex")}function zm(e){return new Set(Object.keys(Tt(e)))}function Bn(e){let t=zm(e),r={},n=e===null?[...yc,...Ym]:yc;for(let o of n)t.has(o)||(r[o]=Mi());return r}var bc=["telegram","discord","slack"],Ec={telegram:["TELEGRAM_BOT_TOKEN"],discord:["DISCORD_BOT_TOKEN","DISCORD_CLIENT_ID"],slack:["SLACK_BOT_TOKEN","SLACK_APP_TOKEN","SLACK_SIGNING_SECRET"]},Bi={telegram:"TELEGRAM_BOT_USERNAME",discord:"DISCORD_CLIENT_ID",slack:"SLACK_WORKSPACE_URL"},Xm={GAIA_BOT_API_KEY:"GAIA_BOT_API_KEY",GAIA_FRONTEND_URL:"FRONTEND_URL",RABBITMQ_URL:"RABBITMQ_URL"},Jm="BOT_LOG_HASH_SECRET";function xe(e){return`bot-${e}`}function Hr(e,t){let r=t.find(i=>i.service===xe(e));if(!r)return{health:"failing",detail:"not created"};let n=[r.state,r.health].filter(Boolean).join(", ");return r.state!=="running"||r.health==="unhealthy"?{health:"failing",detail:n}:{health:r.health===void 0||r.health==="healthy"?"healthy":"starting",detail:n}}function xc(e){return`docker-compose.${xe(e)}.yml`}function Ni(e){return qr.join(e,"apps","api")}function Qm(e){return qr.join(e,"apps","bots")}function Fi(e){let t=qr.join(e,".env");return tr.existsSync(t)?Tt(tr.readFileSync(t,"utf-8")):{}}function Ic(e,t){let r={...e,...t.set};for(let n of t.unset??[])delete r[n];return r}function Gn(e,t){let r=Ni(e),n=Fi(r),o=Ic(n,t);JSON.stringify(o)!==JSON.stringify(n)&&Ur(r,o)}function Vr(e,t={}){let r=qr.join(Ni(e),".env");if(!tr.existsSync(r))throw new Error(`${r} does not exist; run 'gaia up' to configure the install first.`);let n=Bn(tr.readFileSync(r,"utf-8"));Object.keys(n).length>0&&Gn(e,{set:n});let o=Fi(Ni(e)),i={};for(let[c,l]of Object.entries(Xm)){let u=o[l];if(!u)throw new Error(`${l} is not set in apps/api/.env; run 'gaia up' to configure the install first.`);i[c]=u}let s=Qm(e),a=Ic(Fi(s),t);a[Jm]??=Mi(),Ur(s,{...a,...i})}var Zm={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"},ef={mongodb:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB"};function je(e){return Zm[e]??e}function Un(e){return ef[e]??e}import*as kc from"node:os";function _(e,t=kc.homedir()){return e===t?"~":e.startsWith(`${t}/`)?`~${e.slice(t.length)}`:e}import{execa as uf}from"execa";import{execa as rf}from"execa";import qn from"fs";import nf from"simple-git";var tf={KiB:1024,MiB:1048576,GiB:1073741824};function qe(e){return e>=1e9?`${(e/1e9).toFixed(1)} GB`:`${Math.round(e/1e6)} MB`}function jn(e,t,r){let[n,o,i]=t>=1e9?[1e9,"GB",1]:t>=1e6?[1e6,"MB",0]:[1e3,"KB",0],s=a=>(a/n).toFixed(i);return`${s(e)} / ${r?"~":""}${s(t)} ${o}`}function Rc(e){let t=/^([\d.]+)\s*(KiB|MiB|GiB)$/.exec(e.trim());return!t?.[1]||!t[2]?null:Number(t[1])*tf[t[2]]}var Gi=.85,of=/Receiving objects:\s+(\d+)%[^,\r\n]*(?:,\s*([\d.]+\s*[KMG]iB))?/g,sf=/Resolving deltas:\s+(\d+)%/g,af=/remote: (?:Enumerating|Counting|Compressing) objects:/;function cf(e){let t=[...e.matchAll(sf)].at(-1);if(t?.[1]){let n=Number(t[1]);return{percent:Math.floor(Gi*100+n*(1-Gi)),label:"Unpacking the files"}}let r=[...e.matchAll(of)].at(-1);if(r?.[1]){let n=Number(r[1]),o=r[2]?Rc(r[2]):null;return{percent:Math.floor(n*Gi),label:o===null?"Downloading":`${qe(o)} so far`}}return af.test(e)?{percent:0,label:"GitHub is preparing the download"}:null}async function Hn(e,t,r,n){if(qn.existsSync(e)){let o=`${e}/.git`;if(!qn.existsSync(o))throw new Error(`Directory ${e} exists but is not a git repository`);await nf().cwd(e).pull(),r(100,"Already exists, pulled latest")}else try{let o=["clone","--progress"];n&&o.push("--branch",n),o.push(t,e);let i=rf("git",o);i.stderr?.on("data",s=>{let a=cf(s.toString());a&&r(a.percent,a.label)}),await i,r(100,"Clone complete")}catch(o){throw qn.existsSync(e)&&qn.rmSync(e,{recursive:!0,force:!0}),o}}var Ac="https://github.com/theexperiencecompany/gaia.git",Cc="https://heygaia.io/install.sh",df=/^\d+\.\d+\.\d+-beta\.\d+$/;function Ui(e){return df.test(e)?"beta":"latest"}function Wr(e){return e==="beta"?`curl -fsSL ${Cc} | GAIA_CHANNEL=beta sh`:`curl -fsSL ${Cc} | sh`}function Pc(e){let t=Ui(e),r=[`For a newer release, update the CLI first (${Wr(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 ${Wr("latest")} and rerun 'gaia update'.`),r}var pf=2,mf=/^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function ct(e){if(!mf.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 ff(e,t,r){let n=ct(t),o=await uf("git",["ls-remote","--exit-code","--tags",e,`refs/tags/${n}`],{cwd:r,reject:!1});if(o.exitCode!==0)throw o.exitCode===pf?new Error(`GAIA ${t} has no published release: ${e} has no tag ${n}.
19
- Install a released CLI (${Wr("latest")}) and rerun.`):new Error(`Could not read ${n} from ${e}: ${o.stderr.trim()}`)}function Kr(e,t){sc(e,_t,t)}async function Tc(e,t,r){await ff(t,Ge),await Hn(e,t,r,ct(Ge)),Kr(e,Ge)}var gf=/ghcr\.io\/theexperiencecompany\/(gaia[\w-]*):([\w.-]+)/,hf={gaia:"API","gaia-web":"web app"};function Dc(e){let t=gf.exec(e);return t?.[1]&&t[2]?{name:t[1],tag:t[2]}:null}function _c(e){let t=hf[e];return t?`GAIA's ${t} image (${e})`:`the ${e} image`}function rr(e,t){let[r=e.image,n=""]=e.image.split(":");return e.kind==="wrong-cpu"?{cause:`${_c(r)} at ${n} has no build for this computer's processor (${e.arch}).`,next:`Build it on this machine instead: ${t} (15-30 minutes).`}:{cause:`GAIA ${n} isn't published: ${_c(r)} doesn't exist in the registry.`,next:`Update the CLI (${Wr(Ui(R))}) and run it again, or build from source: ${t}.`}}var Sf=(e,t)=>{let r=/no matching manifest for linux\/([\w]+)/.exec(e)?.[1];if(!r)return null;let n=Dc(e);return n?rr({kind:"wrong-cpu",image:`${n.name}:${n.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).`}},vf=(e,t)=>{if(!/manifest unknown|: not found|failed to resolve reference|No such image/.test(e))return null;let r=Dc(e);if(r)return rr({kind:"not-published",image:`${r.name}:${r.tag}`},t.rebuildCommand);let n=/No such image: ([\w./-]+:[\w.-]+)/.exec(e)?.[1];return{cause:n?`The image ${n} was never built on this machine.`:"An image GAIA needs could not be found.",next:`Build the images here: ${t.rebuildCommand}.`}},yf=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>."}},wf=[[/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."}]],bf=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 ${je(r)} didn't start.`,next:"Try: gaia doctor",service:r}};function Ef(e){return([...e].reverse().find(r=>/error|failed|denied/i.test(r))??e.at(-1)??"docker compose failed").trim()}function Oc(e,t,r){let n=[...e,...t].join(`
20
- `);for(let o of[Sf,vf,yf,bf]){let i=o(n,r);if(i)return i}for(let[o,i]of wf)if(o.test(n))return i;return{cause:`Docker Compose failed: ${e.at(-1)??Ef(t)}`,next:""}}var lt=class extends Error{failure;logPath;constructor(t,r){let n=t.logTail?.length?["Its last log lines:",...t.logTail.map(o=>` ${o}`)]:[];super([t.cause,...n,`Full log: ${_(r)}`,t.next].filter(Boolean).join(`
21
- `)),this.name="ComposeError",this.failure=t,this.logPath=r}};import*as jc from"node:fs";import{execa as qc}from"execa";import Bc from"semver";function Lc(e=new Map){return{images:new Map,layers:new Map,steps:new Map,containers:new Map,started:new Set,awaitingHealth:new Set,stopping:new Map,finished:[],errors:[],expectedLayers:e,downloadTotal:0}}var Vn="Image ",Mc="Container ",xf=/^\[[^\]]*\d+\/\d+\]/,If=/^gaia-(?:selfhost|dev)-(.+)-\d+$/,kf=new Set(["Stopping","Removing"]),$c=new Set(["Stopped","Removed"]),Rf=2;function Cf(e){return e.slice(e.lastIndexOf("/")+1)}function Af(e){let t=e.slice(Mc.length);return If.exec(t)?.[1]??t}function Pf(e,t){let r=(t.id??"").slice(Vn.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"} ${Cf(r)}`),e.images.set(r,"ready")):e.images.set(r,t.text==="Building"?"building":"downloading"))}function Tf(e,t){let r=t.id??"",n=e.layers.get(r)??{image:(t.parent_id??"").slice(Vn.length),current:0,total:0,done:!1,present:!1};t.text==="Downloading"&&t.total&&(n.total=t.total,n.current=t.current??n.current),t.text==="Already exists"&&(n.present=!0),(t.text==="Download complete"||t.text==="Pull complete"||t.text==="Already exists")&&(n.done=!0,n.current=n.total),e.layers.set(r,n)}function _f(e,t){let r=Af(t.id??""),n=t.text??"";if(kf.has(n)||$c.has(n)){e.stopping.set(r,e.stopping.get(r)===!0||$c.has(n));return}let o=["Started","Running","Healthy"].includes(t.text??"");t.status==="Error"&&e.errors.push(`${r}: ${t.details??t.text??"error"}`),t.text==="Waiting"&&e.awaitingHealth.add(r),t.text==="Healthy"&&e.awaitingHealth.delete(r),t.text==="Started"&&!e.started.has(r)&&(e.started.add(r),e.finished.push(`Started ${je(r)}`)),e.containers.set(r,e.containers.get(r)===!0||o)}function Nc(e,t){t.error&&t.message&&e.errors.push(t.message);for(let n of t.vertexes??[]){let o=e.steps.get(n.digest),i=n.name??o?.name;!i||!xf.test(i)||e.steps.set(n.digest,{name:i,done:o?.done===!0||!!n.completed})}let r=t.id??"";return r.startsWith(Vn)?Pf(e,t):r.startsWith(Mc)?_f(e,t):t.parent_id?.startsWith(Vn)&&Tf(e,t),e}var Df=99;function Of(e){let t=0,r=0;for(let[n,o]of e.expectedLayers){let i=e.layers.get(n);i?.present||(r+=o,t+=i?.done?o:Math.min(i?.current??0,o))}return{downloaded:t,total:r,estimated:!1}}function $f(e){let t=[...e.layers.values()].filter(c=>!c.present),r=t.filter(c=>c.total>0),n=r.reduce((c,l)=>c+l.current,0),o=t.filter(c=>c.total===0),i=r.reduce((c,l)=>c+l.total,0),s=r.length>0?i/r.length:0,a=Math.round(i+o.length*s);return e.downloadTotal=Math.max(e.downloadTotal,a),{downloaded:n,total:e.downloadTotal,estimated:o.length>0}}function ji(e){let t=e.slice(0,Rf).map(je),r=e.length-t.length;return r>0?`${t.join(", ")} and ${r} more`:t.join(" and ")}function Lf(e){let t=[...e].filter(([,i])=>!i).map(([i])=>i),r=e.size-t.length,n=`${r} of ${e.size} stopped`,o=Math.floor(r/e.size*100);return t.length===0?{stage:"stopping",label:`Stopping GAIA: ${n}`,percent:o}:{stage:"stopping",label:`Stopping GAIA: waiting on ${ji(t)} (${n})`,percent:o}}function Mf(e){let t=[...e.containers],r=t.filter(([,c])=>c).length,n=`${r} of ${t.length} up`,o=Math.floor(r/t.length*100),i={done:r,total:t.length,unit:"services",estimated:!1},s=t.filter(([,c])=>!c).map(([c])=>c),a=e.awaitingHealth.size>0?`waiting for ${ji([...e.awaitingHealth])} to be ready`:s.length>0?`starting ${ji(s)}`:null;return{stage:"starting",label:a?`Starting GAIA: ${a} (${n})`:`Starting GAIA: ${r} of ${t.length} services up`,detail:a??`${r} of ${t.length} services up`,percent:o,amount:i}}function Nf(e){let t=[...e.layers.values()];return[...e.images].filter(([,n])=>n==="downloading").map(([n])=>n).every(n=>t.some(o=>o.image===n)&&t.every(o=>o.image!==n||o.done))}function Fc(e){if(e.stopping.size>0)return Lf(e.stopping);let t=[...e.steps.values()],r=t.filter(o=>o.done).length;if(t.length>0&&r<t.length)return{stage:"building",label:`Building GAIA from source: step ${r+1} of ${t.length}`,percent:Math.floor(r/t.length*100)};let n=[...e.images.values()];if(n.includes("building")&&!n.includes("downloading"))return{stage:"building",label:"Building GAIA from source: saving the images",percent:99};if(n.includes("downloading")){let o=n.filter(u=>u==="ready").length,i=e.expectedLayers.size>0?Of(e):$f(e),s={done:i.downloaded,total:i.total,unit:"bytes",estimated:i.estimated},a=s.total>0?Math.min(Df,Math.floor(s.done/s.total*100)):0,c=`${o} of ${n.length} ready`;return Nf(e)?{stage:"unpacking",label:`Unpacking GAIA's images: ${qe(i.downloaded)} downloaded (${c})`,detail:`Unpacking \xB7 ${o} of ${n.length} images ready`,percent:a,amount:s}:{stage:"downloading",label:`Downloading GAIA's images: ${s.total>0?jn(s.done,s.total,s.estimated):"starting"} (${c})`,detail:`${o} of ${n.length} images ready`,percent:a,...s.total>0?{amount:s}:{}}}return e.containers.size>0?Mf(e):null}var Gc="2.29.1",Ff=40,Uc;function Bf(){return Uc??=(async()=>{let{stdout:e}=await qc("docker",["compose","version","--short"]),t=Bc.coerce(e.trim());if(!t||Bc.lt(t,Gc))throw new Error(`GAIA needs Docker Compose ${Gc} or newer; this machine has ${e.trim()||"an unknown version"}.
22
- Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),Uc}function Gf(e){if(!e.startsWith("{"))return null;try{return JSON.parse(e)}catch{return null}}async function Wn(e,t){await Bf();let r=Ue(t.logName),n=jc.createWriteStream(r);t.onLogFile?.(r);let o=t.pullSize;o&&"unknown"in o&&n.write(`gaia: the download's size is an estimate: ${o.unknown}
23
- `);let i=Lc(o&&"layers"in o?o.layers:void 0),s=[],a=Mn(u=>{let p=Gf(u);if(!p){s.push(u),s.length>Ff&&s.shift();return}Nc(i,p);let m=Fc(i);m&&t.onProgress?.(m,i.finished)}),c=qc("docker",["compose","--progress","json",...e],{cwd:t.cwd,env:t.env,all:!0,reject:!1,timeout:t.timeoutMs});c.all?.on("data",u=>{n.write(u),a(u.toString())});let l=await c;if(a(`
24
- `),await new Promise(u=>n.end(u)),l.timedOut)throw new lt({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(l.failed)throw new lt(Oc(i.errors,s,{rebuildCommand:t.rebuildCommand}),r);return{startedServices:i.started.size}}import{execa as Xc}from"execa";import*as Vc from"node:os";var Wc="https://ghcr.io",Kc="theexperiencecompany",Yc=8e3,Uf=["gaia","gaia-web"],jf=["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 nr(e=Vc.arch()){return e==="x64"?"amd64":e}async function qf(e){let t=await fetch(`${Wc}/token?scope=repository:${Kc}/${e}:pull`,{signal:AbortSignal.timeout(Yc)});if(!t.ok)throw new Error(`GHCR token request answered HTTP ${t.status}`);return(await t.json()).token}async function Hc(e,t,r){return fetch(`${Wc}/v2/${Kc}/${e}/${t}`,{headers:{Authorization:`Bearer ${r}`,Accept:jf},signal:AbortSignal.timeout(Yc)})}async function Hf(e,t){let r=await qf(e),n=await Hc(e,`manifests/${t}`,r);if(n.status===404)return[];if(!n.ok)throw new Error(`GHCR answered HTTP ${n.status} for ${e}:${t}`);let o=await n.json();if(o.manifests)return o.manifests.map(a=>a.platform?.architecture).filter(a=>!!a&&a!=="unknown");if(!o.config)return[];let i=await Hc(e,`blobs/${o.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 or(e,t=[],r=nr()){let n=[...Uf,...t.map(o=>`gaia-bot-${o}`)];for(let o of n){let i=await Hf(o,e);if(i.length===0)return{kind:"not-published",image:`${o}:${e}`};if(!i.includes(r))return{kind:"wrong-cpu",image:`${o}:${e}`,arch:r}}return null}var Jc=8e3,qi="docker.io",Vf="registry-1.docker.io",Wf=12,Kf=["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 Yf(e){let[t=e,r]=e.split("@"),n=t.indexOf("/"),o=n===-1?"":t.slice(0,n),i=o.includes(".")||o.includes(":")||o==="localhost",s=i?o:qi,a=i?t.slice(n+1):t,c=a.lastIndexOf(":"),l=c===-1?"latest":a.slice(c+1);return c!==-1&&(a=a.slice(0,c)),s===qi&&!a.includes("/")&&(a=`library/${a}`),{host:s===qi?Vf:s,repository:a,reference:r??l}}function zf(e){if(!e.startsWith("Bearer "))return null;let t=Object.fromEntries([...e.matchAll(/(\w+)="([^"]*)"/g)].map(n=>[n[1],n[2]]));if(!t.realm)return null;let r=new URL(t.realm);for(let n of["service","scope"])t[n]&&r.searchParams.set(n,t[n]);return r.toString()}async function Qc(e,t,r){return fetch(`https://${e.host}/v2/${e.repository}/manifests/${t}`,{headers:{Accept:Kf,...r?{Authorization:`Bearer ${r}`}:{}},signal:AbortSignal.timeout(Jc)})}async function Xf(e){let t=await Qc(e,e.reference,null);if(t.status!==401)return null;let r=zf(t.headers.get("www-authenticate")??"");if(!r)throw new Error(`${e.host} asked for credentials it did not name`);let n=await fetch(r,{signal:AbortSignal.timeout(Jc)});if(!n.ok)throw new Error(`${e.host} token request answered HTTP ${n.status}`);let o=await n.json();return o.token??o.access_token??null}async function zc(e,t,r){let n=await Qc(e,t,r);if(!n.ok)throw new Error(`${e.host} answered HTTP ${n.status} for ${e.repository}@${t}`);return await n.json()}async function Jf(e,t=nr()){let r=Yf(e),n=await Xf(r),o=await zc(r,r.reference,n);if(o.manifests){let i=o.manifests.find(s=>s.platform?.os==="linux"&&s.platform.architecture===t);if(!i)throw new Error(`${e} has no linux/${t} image`);o=await zc(r,i.digest,n)}return new Map((o.layers??[]).map(i=>[i.digest.replace(/^sha256:/,"").slice(0,Wf),i.size]))}async function Qf(e){let t=await Promise.all(e.map(r=>Jf(r)));return new Map(t.flatMap(r=>[...r]))}async function Zf(e){let t=await Promise.all(e.map(r=>Xc("docker",["image","inspect",r],{reject:!1})));return e.filter((r,n)=>t[n]?.exitCode!==0)}async function Hi(e,t,r,n){try{let{stdout:o}=await Xc("docker",["compose",...t,"config","--format","json"],{cwd:e,env:r}),{services:i}=JSON.parse(o),s=[...new Set(Object.entries(i).filter(([c])=>!n.services||n.services.includes(c)).flatMap(([,c])=>c.image?[c.image]:[]))],a=n.always?s:await Zf(s);return{layers:await Qf(a)}}catch(o){return{unknown:o.message}}}import*as Ot from"node:fs";import*as se from"node:fs/promises";import*as ie from"node:path";import{execa as Zc}from"execa";import{z as zn}from"zod";import{createHash as eg}from"node:crypto";var Yr=class extends Error{constructor(r,n,o){super(`Download failed (${r} ${o}): ${n}`);this.status=r;this.url=n;this.name="DownloadError"}};async function ir(e,t){let r=await fetch(e);if(!r.ok||!r.body)throw new Yr(r.status,e,r.statusText);let n=Number(r.headers.get("content-length")),o=Number.isFinite(n)&&n>0?n:null,i=[],s=0;for await(let a of r.body)i.push(a),s+=a.byteLength,t?.({received:s,total:o});return Buffer.concat(i)}function Kn(e,t,r){for(let n of e.split(`
25
- `)){let[o,...i]=n.trim().split(/\s+/);if(i.join(" ").replace(/^\*/,"")===t&&o!==void 0)return o.toLowerCase()}throw new Error(`${r} has no entry for ${t}.`)}function Yn(e,t,r){let n=eg("sha256").update(e).digest("hex");if(n!==t)throw new Error(`Checksum mismatch for ${r}: expected ${t}, got ${n}. Refusing to use the download.`)}var Wi="gaia-selfhost.json",Vi="GAIA_BUNDLE_BASE_URL",tg="https://github.com/theexperiencecompany/gaia/releases/download",rg=404,ng=zn.object({version:zn.string(),files:zn.array(zn.string())});function Xn(e,t){let r=[],n=ki(e,t);n!==`v${t}`&&r.push(`Installing GAIA ${n}'s images, not v${t}'s (${_t})`);let o=e[Vi];return o&&r.push(`Setup files from ${o} (${Vi})`),r}function og(e,t=process.env){let r=ct(e),n=`gaia-selfhost-${e.slice(1)}.tar.gz`,o=(t[Vi]??`${tg}/${r}`).replace(/\/+$/,"");return{asset:n,bundle:`${o}/${n}`,checksum:`${o}/${n}.sha256`}}async function ig(e,t){let{asset:r,bundle:n,checksum:o}=og(e);try{let i=(await ir(o)).toString("utf-8"),s=Kn(i,r,o),a=await ir(n,t);return Yn(a,s,r),a}catch(i){throw i instanceof Yr&&i.status===rg?new Error(`GAIA ${e} has no published setup files: ${i.url} answered 404.`):i}}function Ki(e){let t=ie.join(e,Wi);return Ot.existsSync(t)?ng.parse(JSON.parse(Ot.readFileSync(t,"utf-8"))):null}async function sg(e,t,r){await se.rm(t,{recursive:!0,force:!0}),await se.mkdir(t,{recursive:!0}),await Zc("tar",["-xzf","-","-C",t],{input:e});let n=Ki(t);if(!n)throw new Error(`The setup files for GAIA ${r} have no manifest.`);if(n.version!==r)throw new Error(`The setup files downloaded for GAIA ${r} are for GAIA ${n.version}, not ${r}.`);let o=n.files.filter(i=>!Ot.existsSync(ie.join(t,i)));if(o.length>0)throw new Error(`The setup files for GAIA ${r} are missing ${o.join(", ")}.`);return n}async function ag(e,t){for(let r=t;r.startsWith(`${e}${ie.sep}`);r=ie.dirname(r))if(Ot.existsSync(r)){if((await se.readdir(r)).length>0)return;await se.rmdir(r)}}async function Jn(e,t,r,n){await se.mkdir(r,{recursive:!0});let o=new Set(e.files);for(let i of n.filter(s=>!o.has(s))){let s=ie.join(r,i);await se.rm(s,{recursive:!0,force:!0}),await ag(r,ie.dirname(s))}for(let i of e.files){let s=ie.join(r,i);await se.mkdir(ie.dirname(s),{recursive:!0}),await se.rename(ie.join(t,i),s)}await se.rm(t,{recursive:!0,force:!0})}async function Qn(e,t,r){let n=await ig(t,r),o=ie.join(e,".gaia-selfhost-staging");return{manifest:await sg(n,o,t),stagingDir:o}}async function el(e){if(!Ot.existsSync(ie.join(e,".git")))throw new Error(`${e} holds GAIA's source without its git history, so 'gaia update' can't tell its files from yours.
26
- Install the release with 'gaia up' in a new directory and copy apps/api/.env into it, or update this one from source.`);let t=s=>Zc("git",s,{cwd:e,reject:!1}),r=await t(["symbolic-ref","-q","--short","HEAD"]);if(r.exitCode===void 0)throw new Error(`${e} is a git checkout, and moving it to release files needs git to tell its files from yours. Install git and run 'gaia update' again.`);if(r.exitCode===0)throw new Error(`${e} is a source checkout on the branch ${r.stdout.trim()}, and 'gaia update' would replace it with release files.
5
+ `)}var kt=[{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 Mr(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 J from"node:fs";import*as Le from"node:path";import{execa as wl}from"execa";import*as kn from"node:fs";import*as wi from"node:path";var Lm=/^\d{4}-\d{2}-\d{2}(T\d{2}-\d{2}-\d{2}Z)?$/,Mm=".partial",Ma={prefix:"mongo-",suffix:".gz"},Na={prefix:"postgres-",suffix:".sql"},Fa={prefix:"api-env-",suffix:".env"},Ba=".tar.gz",Nm=[Ma,Na,Fa,...kt.map(e=>({prefix:`${e.fileSuffix}-`,suffix:Ba}))];function bi(e=new Date){return`${e.toISOString().slice(0,19).replaceAll(":","-")}Z`}function Zt(e,t){let r=n=>wi.join(e,`${n.prefix}${t}${n.suffix}`);return{mongoFile:r(Ma),postgresFile:r(Na),apiEnvFile:r(Fa),volumeFiles:kt.map(n=>Ei(e,t,n))}}function Ei(e,t,r){return{volume:r.volume,label:r.label,file:wi.join(e,`${r.fileSuffix}-${t}${Ba}`)}}function At(e){return`${e}${Mm}`}function Ga(e){return kn.existsSync(e)?kn.readdirSync(e).flatMap(r=>Nm.flatMap(({prefix:n,suffix:o})=>{if(!r.startsWith(n)||!r.endsWith(o))return[];let i=r.slice(n.length,r.length-o.length);return Lm.test(i)?[i]:[]})).sort().at(-1):void 0}import*as Pn from"node:fs";import*as ja from"node:os";import{execa as er}from"execa";var An="/var/run/docker.sock",Ee={selfhost:"gaia-selfhost",developer:"gaia-dev"},Fm=/\((healthy|unhealthy|health: starting)\)/;async function qa(e){return(await Pt(e)).map(r=>({name:r.service,status:r.state==="running"?"running":"stopped",health:r.health}))}async function Ha(e){let{stdout:t}=await er("docker",["ps","--filter",`label=com.docker.compose.project=${e}`,"--format","{{.Ports}}"]),r=new Set;for(let n of t.matchAll(/:(\d+)->/g))r.add(Number(n[1]));return r}function Va(){return ja.platform()!=="linux"||!Pn.existsSync(An)?0:Pn.statSync(An).gid}async function Pt(e){let{stdout:t}=await er("docker",["ps","-a","--filter",`label=com.docker.compose.project=${e}`,"--format",'{{.Label "com.docker.compose.service"}}|{{.State}}|{{.Status}}']);return Bm(t)}function Bm(e){let t=[];for(let r of e.trim().split(`
6
+ `)){if(!r)continue;let[n,o,i]=r.split("|");if(!n||!o)continue;let s=i?.match(Fm)?.[1];t.push(s?{service:n,state:o,health:s}:{service:n,state:o})}return t}async function Wa(){let{stdout:e}=await er("docker",["info","--format","{{.DockerRootDir}}"]),t=e.trim();if(!t)throw new Error("docker info returned an empty DockerRootDir");return t}async function Ka(e){let{stdout:t}=await er("df",["-k",e]);return t}var Ua=26;async function Gm(){let{stdout:e}=await er("docker",["version","--format","{{.Server.Version}}"]);return e.trim()}async function Ya(){let e=await Gm(),t=Number.parseInt(e,10);if(Number.isNaN(t)||t<Ua)throw new Error(`The code sandbox needs Docker Engine ${Ua} 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 Tn(e){let{stdout:t}=await er("docker",["volume","ls","--quiet","--filter",`name=^${e}$`]);return t.trim().split(`
7
+ `).includes(e)}import*as Ic from"node:os";import{execa as sf}from"execa";import{spawn as Jm}from"node:child_process";import{constants as hc,promises as Qm}from"node:fs";import*as jr from"node:os";import{execa as Oi}from"execa";import*as mc from"node:fs";import*as _i from"node:path";import*as et from"fs";import*as pc from"os";import*as Ti from"path";var za={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.7.0-beta.6",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"}};import*as q from"fs";import*as at from"path";import*as Nr from"node:fs";import*as xi from"node:path";var Xa=[{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 Ii={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/"}},Ja={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 Fr(e,t){return Ii[t][e]??Ja[t][e]}function _n(){return structuredClone(Xa)}function Qa(e){let t=xi.join(e,"apps","web",".env.local"),r=Nr.existsSync(t)?t:xi.join(e,"apps","web",".env");if(!Nr.existsSync(r))return[];let n=Nr.readFileSync(r,"utf-8"),o=[],i="General";for(let s of n.split(`
8
+ `)){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();o.push({name:l,value:d,category:i})}return o}function Za(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function ec(e,t,r){let n=r==="selfhost"?new Set(Object.keys(Ii.selfhost)):new Set;for(let[o,i]of Object.entries(t)){let s=Number(o),a=Number(i);for(let[c,l]of Object.entries(e)){if(n.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 tc(e,t){return e.map(r=>({...r,variables:r.variables.map(n=>{let o=Fr(n.name,t);return{...n,defaultValue:o||n.defaultValue}})}))}function Br(){return Object.keys(Ii.selfhost)}function rc(e){return{...Ja[e]}}var Hm=[".test",".example",".invalid",".localhost",".local",".internal",".home.arpa"],nc="docker cp gaia-selfhost-proxy-1:/data/caddy/pki/authorities/local/root.crt gaia-root.crt";function Dn(e){let t=e.toLowerCase();return Hm.some(r=>t.endsWith(r))}function Tt(e){let t={};if(!e)return t;for(let r of e.split(`
9
+ `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<=0)continue;let i=n.substring(0,o).trim(),s=n.substring(o+1).trim().replace(/^["']|["']$/g,"");i&&s&&(t[i]=s)}return t}var Ri=384;function On(e){if(q.existsSync(e)){let t=`${e}.bak`;q.copyFileSync(e,t),q.chmodSync(t,Ri)}}function $n(e,t){q.mkdirSync(at.dirname(e),{recursive:!0}),q.writeFileSync(e,t,{encoding:"utf-8",mode:Ri}),q.chmodSync(e,Ri)}function Ln(e,t){On(t),$n(t,q.readFileSync(e,"utf-8"))}function Gr(e,t){let r=at.join(e,".env");On(r);let n=["# GAIA Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],o=["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 o)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())n.push(`# ${a} Configuration`),n.push(...c),n.push("");$n(r,n.join(`
10
+ `))}function sc(e,t,r){let n=at.join(e,"apps","web",".env.local");On(n);let o=Qa(e),i=Za(t,r),s=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],a=new Map;for(let c of o){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(o.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("")}$n(n,s.join(`
11
+ `))}var Ci={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"},oc=Object.fromEntries(Object.entries(Ci).map(([e,t])=>[t,Number(e)])),Vm="proxy";function ac(e){return at.join(e,"infra","docker",".env")}function Mn(e){let t=ac(e);return q.existsSync(t)?Tt(q.readFileSync(t,"utf-8")):{}}var _t="GAIA_VERSION",Wm="latest",cc="GAIA_DOMAIN",ic="GAIA_CADDY_GLOBAL_OPTIONS",Km="local_certs";function Nn(e){return Mn(e)[cc]||void 0}function Ue(e){return Mn(e)[_t]??Wm}function lc(e,t){let r=ac(e);On(r);let n=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[o,i]of Object.entries(t))n.push(`${o}=${i}`);n.push(""),$n(r,n.join(`
12
+ `))}function uc(e,t,r){lc(e,{...Mn(e),[t]:r})}function ki(e,t,r,n){let{NEXT_PUBLIC_APP_URL:o,...i}=Mn(e);for(let[s,a]of Object.entries(t)){let c=Number(s),l=Ci[c];l&&(i[l]=String(a))}r==="selfhost"&&n&&(i.COMPOSE_PROFILES??=Vm,i.DOCKER_SOCKET_GID=String(n.dockerSocketGid),n.domain&&(i[cc]=n.domain,Dn(n.domain)?i[ic]=Km:delete i[ic])),lc(e,i)}function ct(e){let t={};for(let[r,n]of Object.entries(e)){let o=Number(r),i=Ci[o];i&&(t[i]=String(n))}return t}function dc(e){let t=at.join(e,"infra","docker","docker-compose.yml");if(!q.existsSync(t))return;let r=q.readFileSync(t,"utf-8"),n=[{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}],o=!1;for(let{varName:i,hostPort:s,containerPort:a}of n){let c=`"${s}:${a}"`,l=`"\${${i}:-${s}}:${a}"`;r.includes(c)&&(r=r.replaceAll(c,l),o=!0)}{let i='"15672:15672"';r.includes(i)&&(r=r.replaceAll(i,'"${RABBITMQ_MGMT_PORT:-15672}:15672"'),o=!0)}o&&q.writeFileSync(t,r,"utf-8")}function k(e){let t=at.join(e,"infra","docker",".env"),r={};if(!q.existsSync(t))return r;let n=q.readFileSync(t,"utf-8");for(let o of n.split(`
13
+ `)){let i=o.trim();if(i&&!i.startsWith("#")){let[s,...a]=i.split("=");if(s&&oc[s]){let c=a.join("=").trim().replace(/^["']|["']$/g,""),l=Number(c);!Number.isNaN(l)&&l>0&&l<=65535&&(r[oc[s]]=l)}}}return r}var A=za.version;function Ai(e,t){return e[_t]||`v${t}`}var je=Ai(process.env,A);var xe=Ti.join(pc.homedir(),".gaia"),Pi=Ti.join(xe,"config.json");function zm(){et.existsSync(xe)||et.mkdirSync(xe,{recursive:!0})}function P(){try{if(!et.existsSync(Pi))return null;let e=et.readFileSync(Pi,"utf-8");return JSON.parse(e)}catch{return null}}function Fn(e){zm(),et.writeFileSync(Pi,`${JSON.stringify(e,null,2)}
14
+ `)}function we(e){let r={...P()??{version:A,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Fn(r)}var Ur=_i.join(xe,"logs");function qe(e,t=new Date){mc.mkdirSync(Ur,{recursive:!0});let r=t.toISOString().slice(0,19).replaceAll(":","-");return _i.join(Ur,`${e}-${r}.log`)}function Bn(e){let t="";return r=>{let n=(t+r).split(/\r?\n|\r/);t=n.pop()??"";for(let o of n)o.trim()&&e(o)}}import*as fc from"node:fs";import{execa as Di}from"execa";function gc(){return typeof process.getuid=="function"&&process.getuid()===0}async function Xm(){gc()||!(await Di("sudo",["-n","true"],{reject:!1})).failed||await Di("sudo",["-v","-p","[sudo] password for %u: "],{stdio:"inherit"})}async function H(e,t,r,n){await Xm();let[o,i]=gc()?[e,[...t]]:["sudo",["-n",e,...t]],s=fc.createWriteStream(r,{flags:"a"}),a=Bn(d=>n?.(d)),c=Di(o,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 se="docker",$i="GAIA_DOCKER_GROUP_RELAUNCHED",Sc="GAIA_RESUMED_STEP",vc="GAIA_RESUMED_STEPS";function Gn(){return process.env[Sc]||void 0}function Un(){let e=process.env[vc];return e?JSON.parse(e):{}}async function jn(){let{stdout:e}=await Oi("id",["-nG",jr.userInfo().username]);return e.split(/\s+/).includes(se)}function yc(e){let t=e.stderr;return typeof t=="string"&&t.toLowerCase().includes("permission denied")}async function wc(){if(process.env[$i]==="1")throw new Error(`Still no access to the Docker socket after joining the '${se}' group.
15
+ Check the socket's group with 'ls -l /var/run/docker.sock', then log out and back in and rerun.`);if(await jn())return;let e=jr.userInfo().username;try{await H("usermod",["-aG",se,e],qe("docker-group"))}catch(t){throw new Error(`Could not add ${e} to the '${se}' group: ${t.message}
16
+ Run 'sudo usermod -aG ${se} ${e}', log out and back in, then rerun.`)}}var Zm=/^[A-Za-z_][A-Za-z0-9_]*$/;async function ef(e){try{return await Oi("sh",["-c",'command -v "$1"',"sh",e]),!0}catch{return!1}}async function tf(){try{return await Oi("sudo",["-l","-g",se,"--",process.execPath]),!0}catch{return!1}}async function bc(){return await ef("sg")?"sg":await tf()?"sudo":null}async function Ec(){let e=await bc();if(e)return e;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 '${se}' group).
17
+ Log out and back in (or run 'newgrp ${se}'), then rerun this command.`)}function rf(e){return`'${e.replaceAll("'","'\\''")}'`}function nf(e,t,r){return e==="sg"?["sg",[se,"-c",t.map(rf).join(" ")]]:["sudo",[`--preserve-env=${Object.keys(r).filter(o=>Zm.test(o)).join(",")}`,"-g",se,"--",...t]]}function qn(e,t){let r={...process.env,[$i]:"1",...t&&{[Sc]:t.step,[vc]:JSON.stringify(t.steps)}},[n,o]=nf(e,[process.execPath,...process.argv.slice(1)],r),i=Jm(n,o,{stdio:"inherit",env:r});return new Promise((s,a)=>{i.on("error",a),i.on("exit",(c,l)=>{process.exit(c??(l?1:0))})})}async function of(){try{return await Qm.access(An,hc.R_OK|hc.W_OK),!1}catch(e){let t=e.code;if(t==="ENOENT")return!1;if(t==="EACCES")return!0;throw e}}async function xc(){if(jr.platform()!=="linux"||process.env[$i]==="1"||process.env.DOCKER_HOST||!await of()||!await jn())return;let e=await bc();e&&await qn(e)}var af=5e3,cf="https://orbstack.dev",Li="Run 'gaia up': it installs everything GAIA needs.";async function ee(){try{return await sf("docker",["info"],{timeout:af}),"ready"}catch(e){return e.code==="ENOENT"?"not-installed":yc(e)?"no-permission":"not-running"}}async function tt(e){let t=Ic.platform()==="darwin";switch(e){case"not-installed":return{summary:"Docker isn't installed",state:"isn't installed",fix:t?`Install OrbStack (${cf}) or Docker Desktop, open it, then try again.`:Li};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 jn()?`Your user just joined the '${se}' group. Log out and back in (or run 'newgrp ${se}' in this terminal), then try again.`:`Run 'sudo usermod -aG ${se} $USER', log out and back in, then try again.`}}}async function Dt(e){let t=await tt(e);return new Error(`${t.summary}.
18
+ ${t.fix}`)}import{execa as Ig}from"execa";import*as Ce from"fs";import*as le from"path";import*as tr from"node:fs";import*as qr from"node:path";import*as Cc from"node:crypto";var Rc=["AGENT_SECRET","BOT_SESSION_TOKEN_SECRET","EMAIL_UNSUBSCRIBE_SECRET","SHARE_GRANT_SECRET","GAIA_BOT_API_KEY"],lf=["INSTANCE_SECRET"];function Mi(){return Cc.randomBytes(32).toString("hex")}function uf(e){return new Set(Object.keys(Tt(e)))}function Hn(e){let t=uf(e),r={},n=e===null?[...Rc,...lf]:Rc;for(let o of n)t.has(o)||(r[o]=Mi());return r}var kc=["telegram","discord","slack"],Ac={telegram:["TELEGRAM_BOT_TOKEN"],discord:["DISCORD_BOT_TOKEN","DISCORD_CLIENT_ID"],slack:["SLACK_BOT_TOKEN","SLACK_APP_TOKEN","SLACK_SIGNING_SECRET"]},Bi={telegram:"TELEGRAM_BOT_USERNAME",discord:"DISCORD_CLIENT_ID",slack:"SLACK_WORKSPACE_URL"},df={GAIA_BOT_API_KEY:"GAIA_BOT_API_KEY",GAIA_FRONTEND_URL:"FRONTEND_URL",RABBITMQ_URL:"RABBITMQ_URL"},pf="BOT_LOG_HASH_SECRET";function Ie(e){return`bot-${e}`}function Hr(e,t){let r=t.find(i=>i.service===Ie(e));if(!r)return{health:"failing",detail:"not created"};let n=[r.state,r.health].filter(Boolean).join(", ");return r.state!=="running"||r.health==="unhealthy"?{health:"failing",detail:n}:{health:r.health===void 0||r.health==="healthy"?"healthy":"starting",detail:n}}function Pc(e){return`docker-compose.${Ie(e)}.yml`}function Ni(e){return qr.join(e,"apps","api")}function mf(e){return qr.join(e,"apps","bots")}function Fi(e){let t=qr.join(e,".env");return tr.existsSync(t)?Tt(tr.readFileSync(t,"utf-8")):{}}function Tc(e,t){let r={...e,...t.set};for(let n of t.unset??[])delete r[n];return r}function Vn(e,t){let r=Ni(e),n=Fi(r),o=Tc(n,t);JSON.stringify(o)!==JSON.stringify(n)&&Gr(r,o)}function Vr(e,t={}){let r=qr.join(Ni(e),".env");if(!tr.existsSync(r))throw new Error(`${r} does not exist; run 'gaia up' to configure the install first.`);let n=Hn(tr.readFileSync(r,"utf-8"));Object.keys(n).length>0&&Vn(e,{set:n});let o=Fi(Ni(e)),i={};for(let[c,l]of Object.entries(df)){let d=o[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=mf(e),a=Tc(Fi(s),t);a[pf]??=Mi(),Gr(s,{...a,...i})}var ff={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"},gf={mongodb:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB"};function $e(e){return ff[e]??e}function Wn(e){return gf[e]??e}import*as _c from"node:os";function F(e,t=_c.homedir()){return e===t?"~":e.startsWith(`${t}/`)?`~${e.slice(t.length)}`:e}import{execa as If}from"execa";import{execa as Sf}from"execa";import Kn from"fs";import vf from"simple-git";var hf={KiB:1024,MiB:1048576,GiB:1073741824};function Re(e){return e>=1e9?`${(e/1e9).toFixed(1)} GB`:`${Math.round(e/1e6)} MB`}function Ot(e,t,r){let[n,o,i]=t>=1e9?[1e9,"GB",1]:t>=1e6?[1e6,"MB",0]:[1e3,"KB",0],s=a=>(a/n).toFixed(i);return`${s(e)} / ${r?"~":""}${s(t)} ${o}`}function Dc(e){let t=/^([\d.]+)\s*(KiB|MiB|GiB)$/.exec(e.trim());return!t?.[1]||!t[2]?null:Number(t[1])*hf[t[2]]}var Gi=.85,yf=/Receiving objects:\s+(\d+)%[^,\r\n]*(?:,\s*([\d.]+\s*[KMG]iB))?/g,wf=/Resolving deltas:\s+(\d+)%/g,bf=/remote: (?:Enumerating|Counting|Compressing) objects:/;function Ef(e){let t=[...e.matchAll(wf)].at(-1);if(t?.[1]){let n=Number(t[1]);return{percent:Math.floor(Gi*100+n*(1-Gi)),label:"Unpacking the files"}}let r=[...e.matchAll(yf)].at(-1);if(r?.[1]){let n=Number(r[1]),o=r[2]?Dc(r[2]):null;return{percent:Math.floor(n*Gi),label:o===null?"Downloading":`${Re(o)} so far`}}return bf.test(e)?{percent:0,label:"GitHub is preparing the download"}:null}async function Yn(e,t,r,n){if(Kn.existsSync(e)){let o=`${e}/.git`;if(!Kn.existsSync(o))throw new Error(`Directory ${e} exists but is not a git repository`);await vf().cwd(e).pull(),r(100,"Already exists, pulled latest")}else try{let o=["clone","--progress"];n&&o.push("--branch",n),o.push(t,e);let i=Sf("git",o);i.stderr?.on("data",s=>{let a=Ef(s.toString());a&&r(a.percent,a.label)}),await i,r(100,"Clone complete")}catch(o){throw Kn.existsSync(e)&&Kn.rmSync(e,{recursive:!0,force:!0}),o}}var $c="https://github.com/theexperiencecompany/gaia.git",Oc="https://heygaia.io/install.sh",Rf=/^\d+\.\d+\.\d+-beta\.\d+$/;function Ui(e){return Rf.test(e)?"beta":"latest"}function Wr(e){return e==="beta"?`curl -fsSL ${Oc} | GAIA_CHANNEL=beta sh`:`curl -fsSL ${Oc} | sh`}function Lc(e){let t=Ui(e),r=[`For a newer release, update the CLI first (${Wr(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 ${Wr("latest")} and rerun 'gaia update'.`),r}var Cf=2,kf=/^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function lt(e){if(!kf.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 Af(e,t,r){let n=lt(t),o=await If("git",["ls-remote","--exit-code","--tags",e,`refs/tags/${n}`],{cwd:r,reject:!1});if(o.exitCode!==0)throw o.exitCode===Cf?new Error(`GAIA ${t} has no published release: ${e} has no tag ${n}.
19
+ Install a released CLI (${Wr("latest")}) and rerun.`):new Error(`Could not read ${n} from ${e}: ${o.stderr.trim()}`)}function Kr(e,t){uc(e,_t,t)}async function Mc(e,t,r){await Af(t,je),await Yn(e,t,r,lt(je)),Kr(e,je)}var Pf=/ghcr\.io\/theexperiencecompany\/(gaia[\w-]*):([\w.-]+)/,Tf={gaia:"API","gaia-web":"web app"};function Fc(e){let t=Pf.exec(e);return t?.[1]&&t[2]?{name:t[1],tag:t[2]}:null}function Nc(e){let t=Tf[e];return t?`GAIA's ${t} image (${e})`:`the ${e} image`}function rr(e,t){let[r=e.image,n=""]=e.image.split(":");return e.kind==="wrong-cpu"?{cause:`${Nc(r)} at ${n} has no build for this computer's processor (${e.arch}).`,next:`Build it on this machine instead: ${t} (15-30 minutes).`}:{cause:`GAIA ${n} isn't published: ${Nc(r)} doesn't exist in the registry.`,next:`Update the CLI (${Wr(Ui(A))}) and run it again, or build from source: ${t}.`}}var _f=(e,t)=>{let r=/no matching manifest for linux\/([\w]+)/.exec(e)?.[1];if(!r)return null;let n=Fc(e);return n?rr({kind:"wrong-cpu",image:`${n.name}:${n.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).`}},Df=(e,t)=>{if(!/manifest unknown|: not found|failed to resolve reference|No such image/.test(e))return null;let r=Fc(e);if(r)return rr({kind:"not-published",image:`${r.name}:${r.tag}`},t.rebuildCommand);let n=/No such image: ([\w./-]+:[\w.-]+)/.exec(e)?.[1];return{cause:n?`The image ${n} was never built on this machine.`:"An image GAIA needs could not be found.",next:`Build the images here: ${t.rebuildCommand}.`}},Of=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>."}},$f=[[/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."}]],Lf=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 ${$e(r)} didn't start.`,next:"Try: gaia doctor",service:r}};function Mf(e){return([...e].reverse().find(r=>/error|failed|denied/i.test(r))??e.at(-1)??"docker compose failed").trim()}function Bc(e,t,r){let n=[...e,...t].join(`
20
+ `);for(let o of[_f,Df,Of,Lf]){let i=o(n,r);if(i)return i}for(let[o,i]of $f)if(o.test(n))return i;return{cause:`Docker Compose failed: ${e.at(-1)??Mf(t)}`,next:""}}var ut=class extends Error{failure;logPath;constructor(t,r){let n=t.logTail?.length?["Its last log lines:",...t.logTail.map(o=>` ${o}`)]:[];super([t.cause,...n,`Full log: ${F(r)}`,t.next].filter(Boolean).join(`
21
+ `)),this.name="ComposeError",this.failure=t,this.logPath=r}};import*as Xc from"node:fs";import{execa as Jc}from"execa";import Kc from"semver";function jc(e=new Map){return{images:new Map,layers:new Map,steps:new Map,containers:new Map,started:new Set,starting:new Set,awaitingHealth:new Set,stopping:new Map,finished:[],errors:[],expectedLayers:e,downloadTotal:0}}var zn="Image ",qc="Container ",Nf=/^\[[^\]]*\d+\/\d+\]/,Ff=/^gaia-(?:selfhost|dev)-(.+)-\d+$/,Bf=new Set(["Stopping","Removing"]),Gc=new Set(["Stopped","Removed"]),Gf=2;function Hc(e){return e.slice(e.lastIndexOf("/")+1)}function Uf(e){let t=Hc(e.split("@")[0]??e),r=t.indexOf(":");return r===-1?t:t.slice(0,r)}function jf(e,t,r){let n=Math.floor(e/t*100);return`${String(n).padStart(3)}% ${Ot(e,t,r)}`}function Uc(e){let t=[...e.layers];return[...e.images].map(([r,n])=>{let o={id:r,label:Uf(r)},i=t.filter(([,c])=>c.image===r&&!c.present).map(([c,l])=>({layer:l,size:e.expectedLayers.get(c)??l.total})),s=i.reduce((c,{size:l})=>c+l,0),a=i.reduce((c,{layer:l,size:d})=>c+(l.done?d:Math.min(l.current,d)),0);if(n==="ready")return{...o,state:"done",...s>0?{note:Re(s)}:{}};if(n==="building")return{...o,state:"active",note:"building"};if(i.length>0&&i.every(({layer:c})=>c.done))return{...o,state:"active",note:"unpacking"};if(a>0&&s>0){let c=i.some(({size:l})=>l===0);return{...o,state:"active",note:jf(a,s,c)}}return{...o,state:"pending",note:"waiting"}})}function qf(e){return[...e.containers].map(([t,r])=>{let n={id:t,label:$e(t)};return e.awaitingHealth.has(t)?{...n,state:"active",note:"getting ready"}:r?{...n,state:"done"}:e.starting.has(t)?{...n,state:"active",note:"starting"}:{...n,state:"pending",note:"waiting"}})}function Hf(e){let t=e.slice(qc.length);return Ff.exec(t)?.[1]??t}function Vf(e,t){let r=(t.id??"").slice(zn.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"} ${Hc(r)}`),e.images.set(r,"ready")):e.images.set(r,t.text==="Building"?"building":"downloading"))}function Wf(e,t){let r=t.id??"",n=e.layers.get(r)??{image:(t.parent_id??"").slice(zn.length),current:0,total:0,done:!1,present:!1};t.text==="Downloading"&&t.total&&(n.total=t.total,n.current=t.current??n.current),t.text==="Already exists"&&(n.present=!0),(t.text==="Download complete"||t.text==="Pull complete"||t.text==="Already exists")&&(n.done=!0,n.current=n.total),e.layers.set(r,n)}function Kf(e,t){let r=Hf(t.id??""),n=t.text??"";if(Bf.has(n)||Gc.has(n)){e.stopping.set(r,e.stopping.get(r)===!0||Gc.has(n));return}let o=["Started","Running","Healthy"].includes(t.text??"");t.status==="Error"&&e.errors.push(`${r}: ${t.details??t.text??"error"}`),t.text==="Starting"&&e.starting.add(r),o&&e.starting.delete(r),t.text==="Waiting"&&e.awaitingHealth.add(r),t.text==="Healthy"&&e.awaitingHealth.delete(r),t.text==="Started"&&!e.started.has(r)&&(e.started.add(r),e.finished.push(`Started ${$e(r)}`)),e.containers.set(r,e.containers.get(r)===!0||o)}function Vc(e,t){t.error&&t.message&&e.errors.push(t.message);for(let n of t.vertexes??[]){let o=e.steps.get(n.digest),i=n.name??o?.name;!i||!Nf.test(i)||e.steps.set(n.digest,{name:i,done:o?.done===!0||!!n.completed})}let r=t.id??"";return r.startsWith(zn)?Vf(e,t):r.startsWith(qc)?Kf(e,t):t.parent_id?.startsWith(zn)&&Wf(e,t),e}var Yf=99;function zf(e){let t=0,r=0;for(let[n,o]of e.expectedLayers){let i=e.layers.get(n);i?.present||(r+=o,t+=i?.done?o:Math.min(i?.current??0,o))}return{downloaded:t,total:r,estimated:!1}}function Xf(e){let t=[...e.layers.values()].filter(c=>!c.present),r=t.filter(c=>c.total>0),n=r.reduce((c,l)=>c+l.current,0),o=t.filter(c=>c.total===0),i=r.reduce((c,l)=>c+l.total,0),s=r.length>0?i/r.length:0,a=Math.round(i+o.length*s);return e.downloadTotal=Math.max(e.downloadTotal,a),{downloaded:n,total:e.downloadTotal,estimated:o.length>0}}function ji(e){let t=e.slice(0,Gf).map($e),r=e.length-t.length;return r>0?`${t.join(", ")} and ${r} more`:t.join(" and ")}function Jf(e){let t=[...e].filter(([,i])=>!i).map(([i])=>i),r=e.size-t.length,n=`${r} of ${e.size} stopped`,o=Math.floor(r/e.size*100);return t.length===0?{stage:"stopping",label:`Stopping GAIA: ${n}`,percent:o}:{stage:"stopping",label:`Stopping GAIA: waiting on ${ji(t)} (${n})`,percent:o}}function Qf(e){let t=[...e.containers],r=t.filter(([,c])=>c).length,n=`${r} of ${t.length} up`,o=Math.floor(r/t.length*100),i={done:r,total:t.length,unit:"services",estimated:!1},s=t.filter(([,c])=>!c).map(([c])=>c),a=e.awaitingHealth.size>0?`waiting for ${ji([...e.awaitingHealth])} to be ready`:s.length>0?`starting ${ji(s)}`:null;return{stage:"starting",label:a?`Starting GAIA: ${a} (${n})`:`Starting GAIA: ${r} of ${t.length} services up`,detail:a??`${r} of ${t.length} services up`,percent:o,amount:i,parts:qf(e)}}function Zf(e){let t=[...e.layers.values()];return[...e.images].filter(([,n])=>n==="downloading").map(([n])=>n).every(n=>t.some(o=>o.image===n)&&t.every(o=>o.image!==n||o.done))}function Wc(e){if(e.stopping.size>0)return Jf(e.stopping);let t=[...e.steps.values()],r=t.filter(o=>o.done).length;if(t.length>0&&r<t.length)return{stage:"building",label:`Building GAIA from source: step ${r+1} of ${t.length}`,percent:Math.floor(r/t.length*100)};let n=[...e.images.values()];if(n.includes("building")&&!n.includes("downloading"))return{stage:"building",label:"Building GAIA from source: saving the images",percent:99};if(n.includes("downloading")){let o=n.filter(d=>d==="ready").length,i=e.expectedLayers.size>0?zf(e):Xf(e),s={done:i.downloaded,total:i.total,unit:"bytes",estimated:i.estimated},a=s.total>0?Math.min(Yf,Math.floor(s.done/s.total*100)):0,c=`${o} of ${n.length} ready`;return Zf(e)?{stage:"unpacking",label:`Unpacking GAIA's images: ${Re(i.downloaded)} downloaded (${c})`,detail:`Unpacking \xB7 ${o} of ${n.length} images ready`,percent:a,amount:s,parts:Uc(e)}:{stage:"downloading",label:`Downloading GAIA's images: ${s.total>0?Ot(s.done,s.total,s.estimated):"starting"} (${c})`,detail:`${o} of ${n.length} images ready`,percent:a,...s.total>0?{amount:s}:{},parts:Uc(e)}}return e.containers.size>0?Qf(e):null}var Yc="2.29.1",eg=40,zc;function tg(){return zc??=(async()=>{let{stdout:e}=await Jc("docker",["compose","version","--short"]),t=Kc.coerce(e.trim());if(!t||Kc.lt(t,Yc))throw new Error(`GAIA needs Docker Compose ${Yc} or newer; this machine has ${e.trim()||"an unknown version"}.
22
+ Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),zc}function rg(e){if(!e.startsWith("{"))return null;try{return JSON.parse(e)}catch{return null}}async function Xn(e,t){await tg();let r=qe(t.logName),n=Xc.createWriteStream(r),o=t.pullSize;o&&"unknown"in o&&n.write(`gaia: the download's size is an estimate: ${o.unknown}
23
+ `);let i=jc(o&&"layers"in o?o.layers:void 0),s=[],a=Bn(d=>{let p=rg(d);if(!p){s.push(d),s.length>eg&&s.shift();return}Vc(i,p);let m=Wc(i);m&&t.onProgress?.(m,i.finished)}),c=Jc("docker",["compose","--progress","json",...e],{cwd:t.cwd,env:t.env,all:!0,reject:!1,timeout:t.timeoutMs});c.all?.on("data",d=>{n.write(d),a(d.toString())});let l=await c;if(a(`
24
+ `),await new Promise(d=>n.end(d)),l.timedOut)throw new ut({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(l.failed)throw new ut(Bc(i.errors,s,{rebuildCommand:t.rebuildCommand}),r);return{startedServices:i.started.size}}import{execa as ol}from"execa";import*as Zc from"node:os";var el="https://ghcr.io",tl="theexperiencecompany",rl=8e3,ng=["gaia","gaia-web"],og=["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 nr(e=Zc.arch()){return e==="x64"?"amd64":e}async function ig(e){let t=await fetch(`${el}/token?scope=repository:${tl}/${e}:pull`,{signal:AbortSignal.timeout(rl)});if(!t.ok)throw new Error(`GHCR token request answered HTTP ${t.status}`);return(await t.json()).token}async function Qc(e,t,r){return fetch(`${el}/v2/${tl}/${e}/${t}`,{headers:{Authorization:`Bearer ${r}`,Accept:og},signal:AbortSignal.timeout(rl)})}async function sg(e,t){let r=await ig(e),n=await Qc(e,`manifests/${t}`,r);if(n.status===404)return[];if(!n.ok)throw new Error(`GHCR answered HTTP ${n.status} for ${e}:${t}`);let o=await n.json();if(o.manifests)return o.manifests.map(a=>a.platform?.architecture).filter(a=>!!a&&a!=="unknown");if(!o.config)return[];let i=await Qc(e,`blobs/${o.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 or(e,t=[],r=nr()){let n=[...ng,...t.map(o=>`gaia-bot-${o}`)];for(let o of n){let i=await sg(o,e);if(i.length===0)return{kind:"not-published",image:`${o}:${e}`};if(!i.includes(r))return{kind:"wrong-cpu",image:`${o}:${e}`,arch:r}}return null}var il=8e3,qi="docker.io",ag="registry-1.docker.io",cg=12,lg=["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 ug(e){let[t=e,r]=e.split("@"),n=t.indexOf("/"),o=n===-1?"":t.slice(0,n),i=o.includes(".")||o.includes(":")||o==="localhost",s=i?o:qi,a=i?t.slice(n+1):t,c=a.lastIndexOf(":"),l=c===-1?"latest":a.slice(c+1);return c!==-1&&(a=a.slice(0,c)),s===qi&&!a.includes("/")&&(a=`library/${a}`),{host:s===qi?ag:s,repository:a,reference:r??l}}function dg(e){if(!e.startsWith("Bearer "))return null;let t=Object.fromEntries([...e.matchAll(/(\w+)="([^"]*)"/g)].map(n=>[n[1],n[2]]));if(!t.realm)return null;let r;try{r=new URL(t.realm)}catch(n){throw new Error(`registry token realm is not a URL: ${t.realm}`,{cause:n})}for(let n of["service","scope"])t[n]&&r.searchParams.set(n,t[n]);return r.toString()}async function sl(e,t,r){return fetch(`https://${e.host}/v2/${e.repository}/manifests/${t}`,{headers:{Accept:lg,...r?{Authorization:`Bearer ${r}`}:{}},signal:AbortSignal.timeout(il)})}async function pg(e){let t=await sl(e,e.reference,null);if(t.status!==401)return null;let r=dg(t.headers.get("www-authenticate")??"");if(!r)throw new Error(`${e.host} asked for credentials it did not name`);let n=await fetch(r,{signal:AbortSignal.timeout(il)});if(!n.ok)throw new Error(`${e.host} token request answered HTTP ${n.status}`);let o=await n.json();return o.token??o.access_token??null}async function nl(e,t,r){let n=await sl(e,t,r);if(!n.ok)throw new Error(`${e.host} answered HTTP ${n.status} for ${e.repository}@${t}`);return await n.json()}async function mg(e,t=nr()){let r=ug(e),n=await pg(r),o=await nl(r,r.reference,n);if(o.manifests){let i=o.manifests.find(s=>s.platform?.os==="linux"&&s.platform.architecture===t);if(!i)throw new Error(`${e} has no linux/${t} image`);o=await nl(r,i.digest,n)}return new Map((o.layers??[]).map(i=>[i.digest.replace(/^sha256:/,"").slice(0,cg),i.size]))}async function fg(e){let t=await Promise.all(e.map(r=>mg(r)));return new Map(t.flatMap(r=>[...r]))}async function gg(e){let t=await Promise.all(e.map(r=>ol("docker",["image","inspect",r],{reject:!1})));return e.filter((r,n)=>t[n]?.exitCode!==0)}async function Hi(e,t,r,n){try{let{stdout:o}=await ol("docker",["compose",...t,"config","--format","json"],{cwd:e,env:r}),{services:i}=JSON.parse(o),s=n.services&&new Set(n.services),a=[...new Set(Object.entries(i).filter(([l])=>!s||s.has(l)).flatMap(([,l])=>l.image?[l.image]:[]))],c=n.always?a:await gg(a);return{layers:await fg(c)}}catch(o){return{unknown:o.message}}}import*as $t from"node:fs";import*as ce from"node:fs/promises";import*as ae from"node:path";import{execa as al}from"execa";import{z as Zn}from"zod";import{createHash as hg}from"node:crypto";var Yr=class extends Error{constructor(r,n,o){super(`Download failed (${r} ${o}): ${n}`);this.status=r;this.url=n;this.name="DownloadError"}};async function ir(e,t){let r=await fetch(e);if(!r.ok||!r.body)throw new Yr(r.status,e,r.statusText);let n=Number(r.headers.get("content-length")),o=Number.isFinite(n)&&n>0?n:null,i=[],s=0;for await(let a of r.body)i.push(a),s+=a.byteLength,t?.({received:s,total:o});return Buffer.concat(i)}function Jn(e,t,r){for(let n of e.split(`
25
+ `)){let[o,...i]=n.trim().split(/\s+/);if(i.join(" ").replace(/^\*/,"")===t&&o!==void 0)return o.toLowerCase()}throw new Error(`${r} has no entry for ${t}.`)}function Qn(e,t,r){let n=hg("sha256").update(e).digest("hex");if(n!==t)throw new Error(`Checksum mismatch for ${r}: expected ${t}, got ${n}. Refusing to use the download.`)}var Wi="gaia-selfhost.json",Vi="GAIA_BUNDLE_BASE_URL",Sg="https://github.com/theexperiencecompany/gaia/releases/download",vg=404,yg=Zn.object({version:Zn.string(),files:Zn.array(Zn.string())});function eo(e,t){let r=[],n=Ai(e,t);n!==`v${t}`&&r.push(`Installing GAIA ${n}'s images, not v${t}'s (${_t})`);let o=e[Vi];return o&&r.push(`Setup files from ${o} (${Vi})`),r}function wg(e,t=process.env){let r=lt(e),n=`gaia-selfhost-${e.slice(1)}.tar.gz`,o=(t[Vi]??`${Sg}/${r}`).replace(/\/+$/,"");return{asset:n,bundle:`${o}/${n}`,checksum:`${o}/${n}.sha256`}}async function bg(e,t){let{asset:r,bundle:n,checksum:o}=wg(e);try{let i=(await ir(o)).toString("utf-8"),s=Jn(i,r,o),a=await ir(n,t);return Qn(a,s,r),a}catch(i){throw i instanceof Yr&&i.status===vg?new Error(`GAIA ${e} has no published setup files: ${i.url} answered 404.`):i}}function Ki(e){let t=ae.join(e,Wi);return $t.existsSync(t)?yg.parse(JSON.parse($t.readFileSync(t,"utf-8"))):null}async function Eg(e,t,r){await ce.rm(t,{recursive:!0,force:!0}),await ce.mkdir(t,{recursive:!0}),await al("tar",["-xzf","-","-C",t],{input:e});let n=Ki(t);if(!n)throw new Error(`The setup files for GAIA ${r} have no manifest.`);if(n.version!==r)throw new Error(`The setup files downloaded for GAIA ${r} are for GAIA ${n.version}, not ${r}.`);let o=n.files.filter(i=>!$t.existsSync(ae.join(t,i)));if(o.length>0)throw new Error(`The setup files for GAIA ${r} are missing ${o.join(", ")}.`);return n}async function xg(e,t){for(let r=t;r.startsWith(`${e}${ae.sep}`);r=ae.dirname(r))if($t.existsSync(r)){if((await ce.readdir(r)).length>0)return;await ce.rmdir(r)}}async function to(e,t,r,n){await ce.mkdir(r,{recursive:!0});let o=new Set(e.files);for(let i of n.filter(s=>!o.has(s))){let s=ae.join(r,i);await ce.rm(s,{recursive:!0,force:!0}),await xg(r,ae.dirname(s))}for(let i of e.files){let s=ae.join(r,i);await ce.mkdir(ae.dirname(s),{recursive:!0}),await ce.rename(ae.join(t,i),s)}await ce.rm(t,{recursive:!0,force:!0})}async function ro(e,t,r){let n=await bg(t,r),o=ae.join(e,".gaia-selfhost-staging");return{manifest:await Eg(n,o,t),stagingDir:o}}async function cl(e){if(!$t.existsSync(ae.join(e,".git")))throw new Error(`${e} holds GAIA's source without its git history, so 'gaia update' can't tell its files from yours.
26
+ Install the release with 'gaia up' in a new directory and copy apps/api/.env into it, or update this one from source.`);let t=s=>al("git",s,{cwd:e,reject:!1}),r=await t(["symbolic-ref","-q","--short","HEAD"]);if(r.exitCode===void 0)throw new Error(`${e} is a git checkout, and moving it to release files needs git to tell its files from yours. Install git and run 'gaia update' again.`);if(r.exitCode===0)throw new Error(`${e} is a source checkout on the branch ${r.stdout.trim()}, and 'gaia update' would replace it with release files.
27
27
  Update it from source with 'gaia update --git'.`);let o=(await t(["status","--porcelain","--untracked-files=no"])).stdout.split(`
28
28
  `).filter(s=>s.trim());if(o.length>0)throw new Error(`Local changes to these files would be lost when ${e} moves to release files:
29
29
  ${o.join(`
30
30
  `)}
31
- Commit or discard them, or keep updating from source with 'gaia update --git'.`);let i=await t(["ls-files","-z"]);if(i.exitCode!==0)throw new Error(`Could not list the files of ${e}: ${i.stderr.trim()}`);return[...i.stdout.split("\0").filter(Boolean),".git"]}var lg=e=>new Promise(t=>setTimeout(t,e)),nl="dev-start.log",eo=".gaia-dev.pid",ol="gaia start --build";function ug(e){return e?.remove?["down","--rmi","all","--remove-orphans",...e.remove.volumes?["--volumes"]:[]]:["down"]}function to(e){let t=ae.join(e,".env");return Ie.existsSync(t)?["--env-file",".env"]:[]}var dg=60;function pg(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:dg;return r===0?void 0:r*60*1e3}function ar(e={}){let t=C(),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(xc)),r}function ut(e){return e.flatMap(t=>["-f",t])}var il="gaia-sandbox-workspace",tl="/legacy-sandbox-workspace";function mg(e,t){return["compose",...ut(e),...t,"run","--rm","--no-deps","-v",`${il}:${tl}:ro`,"gaia-backend","python","-m","app.scripts.migrate_legacy_sandbox_workspace","--legacy-root",tl]}function fg(e,t,r){let n=[...ut(e),...t,"up","-d","--remove-orphans"];return n.push(r?.build?"--build":"--no-build"),r?.pull&&n.push("--pull",r.pull),n}function Yi(e){let t=ae.join(e,eo);if(!Ie.existsSync(t))return null;try{let r=Number.parseInt(Ie.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function Zn(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function ce(e,t,r,n,o,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=n&&Object.keys(n).length>0?at(n):void 0,c=C();c?.codeSandbox===!0&&await Ha(),c?.bots?.length&&Vr(e);let l=ar({build:i?.build});i?.build&&Xi(e);let u=to(s),p=[...ut(l),...u],m=i?.build?void 0:await Hi(s,p,a,{always:i?.pull==="always"}),g=await Wn(fg(l,u,i),{cwd:s,env:a,timeoutMs:pg(),logName:i?.build?"compose-build":"compose-up",rebuildCommand:i?.rebuildCommand??ol,onLogFile:i?.onLogFile,onProgress:o,pullSize:m}).catch(async v=>{throw await hg(v,p,s)});return await Cn(il)&&(r?.("Moving code-sandbox files into per-user workspaces\u2026"),await le("docker",mg(l,u),s,void 0,void 0,a)),r?.("GAIA's services are running."),g}var gg=8;async function hg(e,t,r){if(!(e instanceof lt)||!e.failure.service)return e;let{stdout:n}=await cg("docker",["compose",...t,"logs","--no-color","--no-log-prefix","--tail",String(gg),e.failure.service],{cwd:r}),o=n.split(`
32
- `).filter(i=>i.trim());return new lt({...e.failure,logTail:o},e.logPath)}function zi(e){return["compose",...ut(ar()),...to(e)]}async function sl(e,t,r,n){let o=ae.join(e,"infra/docker");await le("docker",[...zi(o),"run","--rm","--no-deps",t,...r],o,void 0,n)}var Sg=["gaia-backend","arq_worker","gaia-web"];async function al(e,t,r){let n=ae.join(e,"infra/docker"),o=[...ut(ar()),...to(n)],i=[...Sg,...(C()?.bots??[]).map(xe)],s={GAIA_VERSION:t};await Wn([...o,"pull",...i],{cwd:n,env:s,logName:"compose-pull",rebuildCommand:"gaia up --build",onProgress:r,pullSize:await Hi(n,o,s,{services:i,always:!0})})}async function ro(e,t,r,n){let o=ae.join(e,"infra/docker"),i=await $(e),s=await Z();if(s==="ready"){t?.("Stopping GAIA's containers\u2026");let a=to(o),c=i==="selfhost"?ut(ar()):[];await Wn([...c,...a,...ug(n)],{cwd:o,logName:"compose-down",rebuildCommand:ol,onProgress:l=>t?.(l.label)})}else{if(i==="selfhost")throw await Dt(s);if(s==="no-permission")throw await Dt(s)}i!=="selfhost"&&await vg(e,t,r,n),t?.("All services stopped.")}async function vg(e,t,r,n){t?.("Stopping GAIA-managed local processes (safe mode)\u2026");let o=Yi(e),i=o!==null&&await yg(e,o);try{Ie.unlinkSync(ae.join(e,eo))}catch{}if(!i){if(n?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports\u2026"),await wg(e,[r?.[8e3]??8e3,r?.[3e3]??3e3]);return}t?.(o!==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 yg(e,t){if(!Zn(t))return!1;try{return process.platform==="win32"?(await le("taskkill",["/PID",String(t),"/T","/F"],e),!0):(rl(t,"SIGTERM"),await lg(800),Zn(t)&&rl(t,"SIGKILL"),!0)}catch{return!1}}function rl(e,t){try{process.kill(-e,t)}catch{process.kill(e,t)}}async function wg(e,t){for(let r of t){let[n,o]=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 le(n,o,e)}}async function $(e){let t=tt(e);if(!Ie.existsSync(t))return null;let r=Ie.readFileSync(t,"utf-8"),n=r.match(/^SETUP_MODE=(.+)$/m);if(n?.[1]){let o=n[1].trim().replace(/^["']|["']$/g,"");if(o==="selfhost"||o==="developer")return o}return r.includes("mongodb://mongo:")?"selfhost":(r.includes("mongodb://localhost:"),"developer")}var bg=8;function Eg(e,t){return e.trimEnd().split(`
31
+ Commit or discard them, or keep updating from source with 'gaia update --git'.`);let i=await t(["ls-files","-z"]);if(i.exitCode!==0)throw new Error(`Could not list the files of ${e}: ${i.stderr.trim()}`);return[...i.stdout.split("\0").filter(Boolean),".git"]}var Rg=e=>new Promise(t=>setTimeout(t,e)),dl="dev-start.log",oo=".gaia-dev.pid",pl="gaia start --build";function Cg(e){return e?.remove?["down","--rmi","all","--remove-orphans",...e.remove.volumes?["--volumes"]:[]]:["down"]}function io(e){let t=le.join(e,".env");return Ce.existsSync(t)?["--env-file",".env"]:[]}var kg=60;function Ag(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:kg;return r===0?void 0:r*60*1e3}function ar(e={}){let t=P(),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(Pc)),r}function dt(e){return e.flatMap(t=>["-f",t])}var ml="gaia-sandbox-workspace",ll="/legacy-sandbox-workspace";function Pg(e,t){return["compose",...dt(e),...t,"run","--rm","--no-deps","-v",`${ml}:${ll}:ro`,"gaia-backend","python","-m","app.scripts.migrate_legacy_sandbox_workspace","--legacy-root",ll]}function Tg(e,t,r){let n=[...dt(e),...t,"up","-d","--remove-orphans"];return n.push(r?.build?"--build":"--no-build"),r?.pull&&n.push("--pull",r.pull),n}function Yi(e){let t=le.join(e,oo);if(!Ce.existsSync(t))return null;try{let r=Number.parseInt(Ce.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function no(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function ue(e,t,r,n,o,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=n&&Object.keys(n).length>0?ct(n):void 0,c=P();c?.codeSandbox===!0&&await Ya(),c?.bots?.length&&Vr(e);let l=ar({build:i?.build});i?.build&&Xi(e);let d=io(s),p=[...dt(l),...d],m=i?.build?void 0:await Hi(s,p,a,{always:i?.pull==="always"}),g=await Xn(Tg(l,d,i),{cwd:s,env:a,timeoutMs:Ag(),logName:i?.build?"compose-build":"compose-up",rebuildCommand:i?.rebuildCommand??pl,onProgress:o,pullSize:m}).catch(async v=>{throw await Dg(v,p,s)});return await Tn(ml)&&(r?.("Moving code-sandbox files into per-user workspaces\u2026"),await de("docker",Pg(l,d),s,void 0,void 0,a)),r?.("GAIA's services are running."),g}var _g=8;async function Dg(e,t,r){if(!(e instanceof ut)||!e.failure.service)return e;let{stdout:n}=await Ig("docker",["compose",...t,"logs","--no-color","--no-log-prefix","--tail",String(_g),e.failure.service],{cwd:r}),o=n.split(`
32
+ `).filter(i=>i.trim());return new ut({...e.failure,logTail:o},e.logPath)}function zi(e){return["compose",...dt(ar()),...io(e)]}async function fl(e,t,r,n){let o=le.join(e,"infra/docker");await de("docker",[...zi(o),"run","--rm","--no-deps",t,...r],o,void 0,n)}var Og=["gaia-backend","arq_worker","gaia-web"];async function gl(e,t,r){let n=le.join(e,"infra/docker"),o=[...dt(ar()),...io(n)],i=[...Og,...(P()?.bots??[]).map(Ie)],s={GAIA_VERSION:t};await Xn([...o,"pull",...i],{cwd:n,env:s,logName:"compose-pull",rebuildCommand:"gaia up --build",onProgress:r,pullSize:await Hi(n,o,s,{services:i,always:!0})})}async function so(e,t,r,n){let o=le.join(e,"infra/docker"),[i,s]=await Promise.all([$(e),ee()]);if(s==="ready"){t?.("Stopping GAIA's containers\u2026");let a=io(o),c=i==="selfhost"?dt(ar()):[];await Xn([...c,...a,...Cg(n)],{cwd:o,logName:"compose-down",rebuildCommand:pl,onProgress:l=>t?.(l.label)})}else{if(i==="selfhost")throw await Dt(s);if(s==="no-permission")throw await Dt(s)}i!=="selfhost"&&await $g(e,t,r,n),t?.("All services stopped.")}async function $g(e,t,r,n){t?.("Stopping GAIA-managed local processes (safe mode)\u2026");let o=Yi(e),i=o!==null&&await Lg(e,o);try{Ce.unlinkSync(le.join(e,oo))}catch{}if(!i){if(n?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports\u2026"),await Mg(e,[r?.[8e3]??8e3,r?.[3e3]??3e3]);return}t?.(o!==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 Lg(e,t){if(!no(t))return!1;try{return process.platform==="win32"?(await de("taskkill",["/PID",String(t),"/T","/F"],e),!0):(ul(t,"SIGTERM"),await Rg(800),no(t)&&ul(t,"SIGKILL"),!0)}catch{return!1}}function ul(e,t){try{process.kill(-e,t)}catch{process.kill(e,t)}}async function Mg(e,t){for(let r of t){let[n,o]=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 de(n,o,e)}}async function $(e){let t=rt(e);if(!Ce.existsSync(t))return null;let r=Ce.readFileSync(t,"utf-8"),n=r.match(/^SETUP_MODE=(.+)$/m);if(n?.[1]){let o=n[1].trim().replace(/^["']|["']$/g,"");if(o==="selfhost"||o==="developer")return o}return r.includes("mongodb://mongo:")?"selfhost":(r.includes("mongodb://localhost:"),"developer")}var Ng=8;function Fg(e,t){return e.trimEnd().split(`
33
33
  `).slice(-t).join(`
34
- `)}async function le(e,t,r,n,o,i,s){let{spawn:a}=await import("child_process");return new Promise((c,l)=>{let u=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,u.kill("SIGTERM"),l(new Error(`Command timed out after ${Math.round(s/6e4)}m. Check \`docker compose logs\` to debug.`))},s)),u.stdout?.on("data",E=>{let b=E.toString();p+=b,o?.(b),m=Math.min(m+5,95),n?.(m)}),u.stderr?.on("data",E=>{let b=E.toString();p+=b,o?.(b),m=Math.min(m+5,95),n?.(m)}),u.on("close",E=>{v&&clearTimeout(v),!g&&(E===0?(n?.(100),c()):l(new Error(`Command failed with code ${E}:
35
- ${Eg(p,bg)}`)))}),u.on("error",E=>{v&&clearTimeout(v),!g&&l(E)})})}var xg="apps/api/app/config/settings_validator.py";function tt(e){return ae.join(e,"apps","api",".env")}function sr(e){return Ie.existsSync(ae.join(e,xg))}function Xi(e){if(!sr(e))throw new Error(`Building GAIA needs its source, and ${_(e)} holds only a release's setup files.
36
- Get the source with 'gaia init', then build there.`)}function cr(e){return Ie.existsSync(ae.join(e,Wi))||sr(e)}function cl(e,t){let r=e;for(;r!==ae.dirname(r);){if(t(r))return r;r=ae.dirname(r)}return null}function ll(){let e=C();return e?.repoPath?cr(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 lr(e){let t=cl(e??process.cwd(),sr);if(t)return t;let r=ll();return r&&sr(r)?r:null}function L(e){let t=cl(e??process.cwd(),cr);return t&&Ie.existsSync(tt(t))?t:ll()??t}function zr(e,t){if(!e)return"GAIA isn't installed yet";let r=_(e);return t?`${r} (${t==="selfhost"?"self-host":"developer"})`:`${r} (not set up yet: no apps/api/.env)`}function Ig(e,t=vi()){let r=Zt(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:n,file:o})=>`docker run --rm -v ${n}:/data -v ${e}:/backups alpine tar czf /backups/${De.basename(o)} -C /data .`)]}function kg(e){return De.join(e,"infra","docker")}function Rg(e,t){return t?De.resolve(t):De.join(e,"backups")}async function Xr(e={}){let t=L();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=kg(t),n=De.join(r,"docker-compose.selfhost.yml");if(!X.existsSync(n))throw new Error(`Compose file not found: ${n}`);let o=Rg(t,e.outputDir),i=vi(),s=Zt(o,i),a=Ig(o,i);if(e.dryRun)return{...s,commands:a,warnings:[]};let c=await Z();if(c!=="ready"){let p=await et(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(`
37
- `))}await X.promises.mkdir(o,{recursive:!0,mode:448});try{X.chmodSync(o,448)}catch{}let l=[s.mongoFile,s.postgresFile,s.apiEnvFile,...s.volumeFiles.map(p=>p.file)],u;try{u=await Cg(t,r,o,i,a)}catch(p){for(let m of l)X.rmSync(At(m),{force:!0});throw p}for(let p of[s.mongoFile,s.postgresFile,s.apiEnvFile,...u.volumeFiles.map(m=>m.file)])X.renameSync(At(p),p);return{...s,...u,commands:a}}async function Cg(e,t,r,n,o){let i=Zt(r,n);Ag(e,At(i.apiEnvFile));try{await dl("docker",ul("mongo",["mongodump","--archive","--gzip"]),t,At(i.mongoFile))}catch(c){throw new Error(`MongoDB backup failed: ${c.message}
38
- Manual command: ${o[1]}`)}try{await dl("docker",ul("postgres",["pg_dump","-U","postgres","-d","langgraph"]),t,At(i.postgresFile))}catch(c){throw new Error(`PostgreSQL backup failed: ${c.message}
39
- Manual command: ${o[2]}`)}let s=[],a=[];for(let c of Ct){let l=yi(r,n,c),u=At(l.file);if(!await Cn(c.volume)){a.push(`${c.label} volume ${c.volume} not found \u2014 nothing to back up`);continue}try{await pl("docker",["run","--rm","-v",`${c.volume}:/data`,"-v",`${De.dirname(u)}:/backups`,"alpine","tar","czf",`/backups/${De.basename(u)}`,"-C","/data","."],{cwd:t});try{X.chmodSync(u,384)}catch{}s.push(l)}catch(p){X.rmSync(u,{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 Ag(e,t){let r=tt(e);if(!X.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.`);Dn(r,t)}function ul(e,t){return["compose","-f","docker-compose.selfhost.yml","exec","-T",e,...t]}async function dl(e,t,r,n){X.writeFileSync(n,"",{mode:384,flag:"wx"});try{await pl(e,t,{cwd:r,stdout:{file:n},buffer:{stdout:!1}})}catch(o){throw X.rmSync(n,{force:!0}),o}}function D(e=""){process.stdout.write(`${e}
40
- `)}async function fl(e={}){if(e.dryRun){let t=await Xr({outputDir:e.output,dryRun:!0});D("Backup commands (dry run \u2014 not executed):");for(let r of t.commands)D(` ${r}`);D(""),D(`Volumes (${Ct.map(r=>r.volume).join(", ")}) are backed up via`),D(" docker run --rm -v <volume>:/data -v <output>:/backups alpine tar ..."),D(" and are skipped if the volume does not exist yet."),D(""),D("Run without --dry-run to execute inside the running containers,"),D("or copy-paste the commands from the directory containing infra/docker/");return}try{D("Starting GAIA backup\u2026");let t=await Xr({outputDir:e.output});D(`MongoDB dump: ${t.mongoFile}`),D(`PostgreSQL dump: ${t.postgresFile}`),D(`API settings (apps/api/.env): ${t.apiEnvFile}`);for(let{label:r,file:n}of t.volumeFiles)D(`${r} archive: ${n}`);if(t.warnings.length)for(let r of t.warnings)D(`Note: ${r}`);D(""),D("Backups complete. Store them off-host and access-controlled \u2014"),D(`${t.apiEnvFile} holds INSTANCE_SECRET, which decrypts the stored provider credentials.`),D(""),D("Restore with gaia restore --from <dir>, or manually from the repo root:"),D(` install -m 600 ${t.apiEnvFile} apps/api/.env`),D(` cat ${t.postgresFile} | docker compose -f infra/docker/docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`),D(` docker compose -f infra/docker/docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t.mongoFile}`);for(let{volume:r,file:n}of t.volumeFiles)D(` docker run --rm -v ${r}:/data -v $(dirname ${n}):/backups alpine sh -c "${Nr(ml.basename(n))}"`)}catch(t){he(t.message),process.exitCode=1}}import{Argument as Yh,Command as zh}from"commander";async function ue(e){try{await e()}catch(t){he(t instanceof Error?t.message:String(t)),process.exit(1)}}import nh from"chalk";import{supportsHyperlink as oh}from"supports-hyperlinks";import Pg from"wrap-ansi";var Tg=40,_g=80,Dg=24;function Jr(e){return{columns:e.columns||_g,rows:e.rows||Dg}}function Ji(e,t){return Pg(e,t,{hard:!0})}function dt(e,t=0){let r=process.stdout.isTTY?process.stdout.columns:void 0;return!r||r-t<Tg?e:Ji(e,r-t).split(`
34
+ `)}async function de(e,t,r,n,o,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,o?.(b),m=Math.min(m+5,95),n?.(m)}),d.stderr?.on("data",E=>{let b=E.toString();p+=b,o?.(b),m=Math.min(m+5,95),n?.(m)}),d.on("close",E=>{v&&clearTimeout(v),!g&&(E===0?(n?.(100),c()):l(new Error(`Command failed with code ${E}:
35
+ ${Fg(p,Ng)}`)))}),d.on("error",E=>{v&&clearTimeout(v),!g&&l(E)})})}var Bg="apps/api/app/config/settings_validator.py";function rt(e){return le.join(e,"apps","api",".env")}function sr(e){return Ce.existsSync(le.join(e,Bg))}function Xi(e){if(!sr(e))throw new Error(`Building GAIA needs its source, and ${F(e)} holds only a release's setup files.
36
+ Get the source with 'gaia init', then build there.`)}function cr(e){return Ce.existsSync(le.join(e,Wi))||sr(e)}function hl(e,t){let r=e;for(;r!==le.dirname(r);){if(t(r))return r;r=le.dirname(r)}return null}function Sl(){let e=P();return e?.repoPath?cr(e.repoPath)?e.repoPath:(console.warn(`Warning: Saved repo path "${e.repoPath}" is no longer a valid GAIA installation. Resetting config.`),we({repoPath:"",setupComplete:!1}),null):null}function lr(e){let t=hl(e??process.cwd(),sr);if(t)return t;let r=Sl();return r&&sr(r)?r:null}function L(e){let t=hl(e??process.cwd(),cr);return t&&Ce.existsSync(rt(t))?t:Sl()??t}function zr(e,t){if(!e)return"GAIA isn't installed yet";let r=F(e);return t?`${r} (${t==="selfhost"?"self-host":"developer"})`:`${r} (not set up yet: no apps/api/.env)`}function Gg(e,t=bi()){let r=Zt(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:n,file:o})=>`docker run --rm -v ${n}:/data -v ${e}:/backups alpine tar czf /backups/${Le.basename(o)} -C /data .`)]}function Ug(e){return Le.join(e,"infra","docker")}function jg(e,t){return t?Le.resolve(t):Le.join(e,"backups")}async function Xr(e={}){let t=L();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=Ug(t),n=Le.join(r,"docker-compose.selfhost.yml");if(!J.existsSync(n))throw new Error(`Compose file not found: ${n}`);let o=jg(t,e.outputDir),i=bi(),s=Zt(o,i),a=Gg(o,i);if(e.dryRun)return{...s,commands:a,warnings:[]};let c=await ee();if(c!=="ready"){let p=await tt(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(`
37
+ `))}await J.promises.mkdir(o,{recursive:!0,mode:448});try{J.chmodSync(o,448)}catch{}let l=[s.mongoFile,s.postgresFile,s.apiEnvFile,...s.volumeFiles.map(p=>p.file)],d;try{d=await qg(t,r,o,i,a)}catch(p){for(let m of l)J.rmSync(At(m),{force:!0});throw p}for(let p of[s.mongoFile,s.postgresFile,s.apiEnvFile,...d.volumeFiles.map(m=>m.file)])J.renameSync(At(p),p);return{...s,...d,commands:a}}async function qg(e,t,r,n,o){let i=Zt(r,n);Hg(e,At(i.apiEnvFile));try{await yl("docker",vl("mongo",["mongodump","--archive","--gzip"]),t,At(i.mongoFile))}catch(c){throw new Error(`MongoDB backup failed: ${c.message}
38
+ Manual command: ${o[1]}`)}try{await yl("docker",vl("postgres",["pg_dump","-U","postgres","-d","langgraph"]),t,At(i.postgresFile))}catch(c){throw new Error(`PostgreSQL backup failed: ${c.message}
39
+ Manual command: ${o[2]}`)}let s=[],a=[];for(let c of kt){let l=Ei(r,n,c),d=At(l.file);if(!await Tn(c.volume)){a.push(`${c.label} volume ${c.volume} not found \u2014 nothing to back up`);continue}try{await wl("docker",["run","--rm","-v",`${c.volume}:/data`,"-v",`${Le.dirname(d)}:/backups`,"alpine","tar","czf",`/backups/${Le.basename(d)}`,"-C","/data","."],{cwd:t});try{J.chmodSync(d,384)}catch{}s.push(l)}catch(p){J.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 Hg(e,t){let r=rt(e);if(!J.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.`);Ln(r,t)}function vl(e,t){return["compose","-f","docker-compose.selfhost.yml","exec","-T",e,...t]}async function yl(e,t,r,n){J.writeFileSync(n,"",{mode:384,flag:"wx"});try{await wl(e,t,{cwd:r,stdout:{file:n},buffer:{stdout:!1}})}catch(o){throw J.rmSync(n,{force:!0}),o}}function D(e=""){process.stdout.write(`${e}
40
+ `)}async function El(e={}){if(e.dryRun){let t=await Xr({outputDir:e.output,dryRun:!0});D("Backup commands (dry run \u2014 not executed):");for(let r of t.commands)D(` ${r}`);D(""),D(`Volumes (${kt.map(r=>r.volume).join(", ")}) are backed up via`),D(" docker run --rm -v <volume>:/data -v <output>:/backups alpine tar ..."),D(" and are skipped if the volume does not exist yet."),D(""),D("Run without --dry-run to execute inside the running containers,"),D("or copy-paste the commands from the directory containing infra/docker/");return}try{D("Starting GAIA backup\u2026");let t=await Xr({outputDir:e.output});D(`MongoDB dump: ${t.mongoFile}`),D(`PostgreSQL dump: ${t.postgresFile}`),D(`API settings (apps/api/.env): ${t.apiEnvFile}`);for(let{label:r,file:n}of t.volumeFiles)D(`${r} archive: ${n}`);if(t.warnings.length)for(let r of t.warnings)D(`Note: ${r}`);D(""),D("Backups complete. Store them off-host and access-controlled \u2014"),D(`${t.apiEnvFile} holds INSTANCE_SECRET, which decrypts the stored provider credentials.`),D(""),D("Restore with gaia restore --from <dir>, or manually from the repo root:"),D(` install -m 600 ${t.apiEnvFile} apps/api/.env`),D(` cat ${t.postgresFile} | docker compose -f infra/docker/docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`),D(` docker compose -f infra/docker/docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t.mongoFile}`);for(let{volume:r,file:n}of t.volumeFiles)D(` docker run --rm -v ${r}:/data -v $(dirname ${n}):/backups alpine sh -c "${Mr(bl.basename(n))}"`)}catch(t){ye(t.message),process.exitCode=1}}import{Argument as dS,Command as pS}from"commander";async function pe(e){try{await e()}catch(t){ye(t instanceof Error?t.message:String(t)),process.exit(1)}}import yh from"chalk";import{supportsHyperlink as wh}from"supports-hyperlinks";import Vg from"wrap-ansi";var Wg=40,Kg=80,Yg=24;function Jr(e){return{columns:e.columns||Kg,rows:e.rows||Yg}}function Ji(e,t){return Vg(e,t,{hard:!0})}function pt(e,t=0){let r=process.stdout.isTTY?process.stdout.columns:void 0;return!r||r-t<Wg?e:Ji(e,r-t).split(`
41
41
  `).join(`
42
- ${" ".repeat(t)}`)}import{networkInterfaces as gl}from"node:os";var O=3e3,no=8e3,Qr=3443;function $t(e,t){return`http://localhost:${e==="selfhost"?t[O]??O:t[no]??no}`}function de(e,t){return`${$t(e,t)}/api/v1`}var Qi=/^(docker\d+|br-[0-9a-f]+)$/;function hl(e,t){return Object.entries(t).filter(([r])=>!Qi.test(r)).flatMap(([,r])=>r??[]).filter(r=>r.family==="IPv4"&&!r.internal).map(r=>`http://${r.address}:${e}`)}function Sl(e,t,r=gl()){return[...t?[`https://${t}`]:[],`http://localhost:${e}`,...hl(e,r)]}function Og(e=process.env,t=process.platform){return e.SSH_CONNECTION||e.SSH_TTY?!0:t==="linux"&&!e.DISPLAY&&!e.WAYLAND_DISPLAY}function Zi(e,t,r=gl(),n=Og()){if(t)return`https://${t}`;let o=`http://localhost:${e}`;return n?hl(e,r)[0]??o:o}function pt(e,t){return Zi(t,$n(e))}async function oo(e,t,r=5e3){return fetch(e,{...t,signal:AbortSignal.timeout(r)})}async function He(e,t,r=5e3){try{let n=await oo(`${e}/setup/${t}`,void 0,r);return n.ok?{data:await n.json()}:{detail:`HTTP ${n.status} from /api/v1/setup/${t}`}}catch{return{detail:`Could not read setup ${t}`}}}import*as Oe from"node:fs";import*as ts from"node:path";import vl from"semver";var $g="https://registry.npmjs.org/@heygaia/cli/latest",es=ts.join(Ee,"update-check.json"),Lg=ts.join(jr,"update-check.log"),Mg=1440*60*1e3,Ng=5e3;function mt(e){return/^v\d/.test(e)?vl.parse(e.slice(1)):null}var Fg=/^[0-9a-f]{40}$/,Bg=12;function io(e){return Fg.test(e)?e.slice(0,Bg):e}function rt(e,t){let r=mt(e),n=mt(t);return r!==null&&n!==null&&vl.gt(r,n)}function yl(){if(!Oe.existsSync(es))return null;let e=JSON.parse(Oe.readFileSync(es,"utf-8"));return e.arch===nr()?e:null}function wl(){return yl()?.latest??null}async function Gg(){let e=await fetch($g,{signal:AbortSignal.timeout(Ng)});if(!e.ok)throw new Error(`npm answered HTTP ${e.status}`);let{version:t}=await e.json(),r=`v${t}`;return await or(r)===null?r:null}function Ug(e){Oe.mkdirSync(jr,{recursive:!0}),Oe.appendFileSync(Lg,`${new Date().toISOString()} update check failed: ${e.message}
43
- `)}async function so(){let e=yl();if(e&&Date.now()-Date.parse(e.checkedAt)<Mg)return e.latest;try{let t=await Gg();Oe.mkdirSync(Ee,{recursive:!0});let r={checkedAt:new Date().toISOString(),arch:nr(),latest:t};return Oe.writeFileSync(es,JSON.stringify(r)),t}catch(t){return Ug(t),e?.latest??null}}var bl=300,jg="ai_models";function qg(e,t){let r=e.features[jg]?.in_use[0];return r?t?.providers[r]?.label??r:null}async function ao(){let e=L(),t=e?await $(e):null;if(!e||!t)return{running:!1,installed:!1};let r=A(e),n=de(t,r),[o,i]=await Promise.all([He(n,"status",bl),He(n,"catalog",bl)]);if("detail"in o)return{running:!1,installed:!0};let s=r[O]??O;return{running:!0,webUrl:pt(e,s),provider:qg(o.data,"data"in i?i.data:null)}}function co(){so();let e=L(),t=wl();return!e||!t?null:rt(t,Be(e))?t:null}import{Chalk as Jg}from"chalk";import{Chalk as Hg}from"chalk";var rs={large:["......mmmmmmmmm......","....mmmmmmmmmmmmm....","...ddddddmmmllllll...","..dddddddd.llllllll..","...ddddd.....lllll...",".ll...............dd.","llll.............dddd","mlll.............dddm","mllll...........ddddm","mllll...........ddddm","mmmll...........ddmmm","mmmmm...........mmmmm",".mmmmdd.......llmmmm.",".mmmmddd.....lllmmmm.","..mmmdddd...llllmmm..","...mmmdddd.llllmmm...",".....mmddd.lllmm.....","....................."],small:["...mmmmmmmmm...","..dddddmlllll..","..dddd...llll..","...............","ll...........dd","lll.........ddd","mll.........ddm","mml.........dmm","mmmd.......lmmm",".mmddd...lllmm.","..mmddd.lllmm..","...mddd.lllm..."]},ns={d:"#0f537c",m:"#059cda",l:"#02bdff"},os={d:24,m:38,l:39};var Vg={d:"blue",m:"cyan",l:"cyanBright"},Wg={d:"bgBlue",m:"bgCyan",l:"bgCyanBright"},Il="\u2580",kl="\u2584",Kg="\u2588";function El(e){return e==="d"||e==="m"||e==="l"?e:null}function Yg(e,t){return e===null&&t===null?{ch:" ",fg:null,bg:null}:e===t?{ch:" ",fg:null,bg:e}:e===null?{ch:kl,fg:t,bg:null}:{ch:Il,fg:e,bg:t}}function zg(e,t){return{ch:e!==null&&t!==null?Kg:e!==null?Il:t!==null?kl:" ",fg:null,bg:null}}function xl(e,{fg:t,bg:r}){let n=e;return t!==null&&(n=e.level===3?n.hex(ns[t]):e.level===2?n.ansi256(os[t]):n[Vg[t]]),r!==null&&(n=e.level===3?n.bgHex(ns[r]):e.level===2?n.bgAnsi256(os[r]):n[Wg[r]]),n}function Xg(e,t){let r="",n="",o=null;for(let i of t)o&&(i.fg!==o.fg||i.bg!==o.bg)&&(r+=xl(e,o)(n),n=""),o=i,n+=i.ch;return o?r+xl(e,o)(n):r}function Rl(e){return rs[e][0].length}function Cl(e,t){let r=rs[e],n=new Hg({level:t}),o=[];for(let i=0;i<r.length;i+=2){let s=r[i]??"",a=r[i+1]??"",c=[...s].map((l,u)=>{let p=El(l),m=El(a[u]);return t===0?zg(p,m):Yg(p,m)});o.push(Xg(n,c))}return o}var Al=3,Qg=40,Pl=" \xB7 ",Tl="Your proactive personal assistant",_l={truecolor:"#af8700",ansi256:136};function Zg(e,t){return t?`\x1B]8;;${e}\x1B\\${e}\x1B]8;;\x1B\\`:e}function eh(e){return e.level===3?e.hex(_l.truecolor):e.level===2?e.ansi256(_l.ansi256):e.yellow}function Dl(e,t){return{plain:`GAIA v${t}`,styled:`${e.bold("GAIA")} ${e.dim(`v${t}`)}`}}function th(e,t,r){if(!t.running){let o=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:o,styled:e.dim(o)}}let n=t.provider?` \xB7 ${t.provider}`:"";return{plain:`\u25CF Running at ${t.webUrl}${n}`,styled:`${e.green("\u25CF")} Running at ${Zg(t.webUrl,r)}${e.dim(n)}`}}function Ol(e,t){let r=[];if(e.status&&r.push(th(t,e.status,e.hyperlinks)),e.update){let n=`Update available: ${e.update} \xB7 run gaia update`;r.push({plain:n,styled:eh(t)(n)})}return r}function $l(e){return[...e.plain].length}function rh(e,t){let r=Dl(t,e.version);for(let n of Ol(e,t)){let o={plain:`${r.plain}${Pl}${n.plain}`,styled:`${r.styled}${t.dim(Pl)}${n.styled}`};if($l(o)>e.columns)break;r=o}return r.styled}function lo(e){let t=new Jg({level:e.level}),r=[Dl(t,e.version),{plain:Tl,styled:t.dim(Tl)},...Ol(e,t)],n=Rl(e.size)+Al+Math.max(...r.map($l));if(!e.isTTY||e.rows<Qg||n>e.columns)return[rh(e,t)];let o=Cl(e.size,e.level),i=Math.floor((o.length-r.length)/2);return o.map((s,a)=>{let c=r[a-i];return c?`${s}${" ".repeat(Al)}${c.styled}`:s})}function is(e){return{isTTY:e.isTTY===!0,hyperlinks:oh(e)}}async function ih({size:e="small",showStatus:t=!0,showUpdate:r=!0}={}){let n={...Jr(process.stdout),...is(process.stdout)},o=t&&n.isTTY?await ao():null;return["",...lo({size:e,level:nh.level,...n,version:R,status:o,update:r?co():null}),""]}async function Lt(e){process.stdout.write(`${(await ih(e)).join(`
42
+ ${" ".repeat(t)}`)}import{networkInterfaces as xl}from"node:os";var O=3e3,ao=8e3,Qr=3443;function Lt(e,t){return`http://localhost:${e==="selfhost"?t[O]??O:t[ao]??ao}`}function me(e,t){return`${Lt(e,t)}/api/v1`}var Qi=/^(docker\d+|br-[0-9a-f]+)$/;function Zi(e){return`http://localhost:${e}`}function es(e,t=xl()){return Object.entries(t).filter(([r])=>!Qi.test(r)).flatMap(([,r])=>r??[]).filter(r=>r.family==="IPv4"&&!r.internal).map(r=>`http://${r.address}:${e}`)}function zg(e=process.env,t=process.platform){return e.SSH_CONNECTION||e.SSH_TTY?!0:t==="linux"&&!e.DISPLAY&&!e.WAYLAND_DISPLAY}function ts(e,t,r=xl(),n=zg()){if(t)return`https://${t}`;let o=Zi(e);return n?es(e,r)[0]??o:o}function mt(e,t){return ts(t,Nn(e))}async function co(e,t,r=5e3){return fetch(e,{...t,signal:AbortSignal.timeout(r)})}async function He(e,t,r=5e3){try{let n=await co(`${e}/setup/${t}`,void 0,r);return n.ok?{data:await n.json()}:{detail:`HTTP ${n.status} from /api/v1/setup/${t}`}}catch{return{detail:`Could not read setup ${t}`}}}import*as Me from"node:fs";import*as ns from"node:path";import Il from"semver";var Xg="https://registry.npmjs.org/@heygaia/cli/latest",rs=ns.join(xe,"update-check.json"),Jg=ns.join(Ur,"update-check.log"),Qg=1440*60*1e3,Zg=5e3;function ft(e){return/^v\d/.test(e)?Il.parse(e.slice(1)):null}var eh=/^[0-9a-f]{40}$/,th=12;function lo(e){return eh.test(e)?e.slice(0,th):e}function nt(e,t){let r=ft(e),n=ft(t);return r!==null&&n!==null&&Il.gt(r,n)}function Rl(){if(!Me.existsSync(rs))return null;let e=JSON.parse(Me.readFileSync(rs,"utf-8"));return e.arch===nr()?e:null}function Cl(){return Rl()?.latest??null}async function rh(){let e=await fetch(Xg,{signal:AbortSignal.timeout(Zg)});if(!e.ok)throw new Error(`npm answered HTTP ${e.status}`);let{version:t}=await e.json(),r=`v${t}`;return await or(r)===null?r:null}function nh(e){Me.mkdirSync(Ur,{recursive:!0}),Me.appendFileSync(Jg,`${new Date().toISOString()} update check failed: ${e.message}
43
+ `)}async function uo(){let e=Rl();if(e&&Date.now()-Date.parse(e.checkedAt)<Qg)return e.latest;try{let t=await rh();Me.mkdirSync(xe,{recursive:!0});let r={checkedAt:new Date().toISOString(),arch:nr(),latest:t};return Me.writeFileSync(rs,JSON.stringify(r)),t}catch(t){return nh(t),e?.latest??null}}var kl=300,oh="ai_models";function ih(e,t){let r=e.features[oh]?.in_use[0];return r?t?.providers[r]?.label??r:null}async function po(){let e=L(),t=e?await $(e):null;if(!e||!t)return{running:!1,installed:!1};let r=k(e),n=me(t,r),[o,i]=await Promise.all([He(n,"status",kl),He(n,"catalog",kl)]);if("detail"in o)return{running:!1,installed:!0};let s=r[O]??O;return{running:!0,webUrl:mt(e,s),provider:ih(o.data,"data"in i?i.data:null)}}function mo(){uo();let e=L(),t=Cl();return!e||!t?null:nt(t,Ue(e))?t:null}import{Chalk as mh}from"chalk";import{Chalk as sh}from"chalk";var os=[".........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......"],is={d:"#0f537c",m:"#059cda",l:"#02bdff"},ss={d:24,m:38,l:39};var ah={d:"blue",m:"cyan",l:"cyanBright"},ch={d:"bgBlue",m:"bgCyan",l:"bgCyanBright"},Tl="\u2580",_l="\u2584",lh="\u2588";function Al(e){return e==="d"||e==="m"||e==="l"?e:null}function uh(e,t){return e===null&&t===null?{ch:" ",fg:null,bg:null}:e===t?{ch:" ",fg:null,bg:e}:e===null?{ch:_l,fg:t,bg:null}:{ch:Tl,fg:e,bg:t}}function dh(e,t){return{ch:e!==null&&t!==null?lh:e!==null?Tl:t!==null?_l:" ",fg:null,bg:null}}function Pl(e,{fg:t,bg:r}){let n=e;return t!==null&&(n=e.level===3?n.hex(is[t]):e.level===2?n.ansi256(ss[t]):n[ah[t]]),r!==null&&(n=e.level===3?n.bgHex(is[r]):e.level===2?n.bgAnsi256(ss[r]):n[ch[r]]),n}function ph(e,t){let r="",n="",o=null;for(let i of t)o&&(i.fg!==o.fg||i.bg!==o.bg)&&(r+=Pl(e,o)(n),n=""),o=i,n+=i.ch;return o?r+Pl(e,o)(n):r}var Dl=os[0].length;function Ol(e){let t=os,r=new sh({level:e}),n=[];for(let o=0;o<t.length;o+=2){let i=t[o]??"",s=t[o+1]??"",a=[...i].map((c,l)=>{let d=Al(c),p=Al(s[l]);return e===0?dh(d,p):uh(d,p)});n.push(ph(r,a))}return n}var $l=3,fh=40,Ll=" \xB7 ",Ml="Your proactive personal assistant",Nl={truecolor:"#af8700",ansi256:136};function gh(e,t){return t?`\x1B]8;;${e}\x1B\\${e}\x1B]8;;\x1B\\`:e}function hh(e){return e.level===3?e.hex(Nl.truecolor):e.level===2?e.ansi256(Nl.ansi256):e.yellow}function Fl(e,t){return{plain:`GAIA v${t}`,styled:`${e.bold("GAIA")} ${e.dim(`v${t}`)}`}}function Sh(e,t,r){if(!t.running){let o=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:o,styled:e.dim(o)}}let n=t.provider?` \xB7 ${t.provider}`:"";return{plain:`\u25CF Running at ${t.webUrl}${n}`,styled:`${e.green("\u25CF")} Running at ${gh(t.webUrl,r)}${e.dim(n)}`}}function Bl(e,t){let r=[];if(e.status&&r.push(Sh(t,e.status,e.hyperlinks)),e.update){let n=`Update available: ${e.update} \xB7 run gaia update`;r.push({plain:n,styled:hh(t)(n)})}return r}function Gl(e){return[...e.plain].length}function vh(e,t){let r=Fl(t,e.version);for(let n of Bl(e,t)){let o={plain:`${r.plain}${Ll}${n.plain}`,styled:`${r.styled}${t.dim(Ll)}${n.styled}`};if(Gl(o)>e.columns)break;r=o}return r.styled}function fo(e){let t=new mh({level:e.level}),r=[Fl(t,e.version),{plain:Ml,styled:t.dim(Ml)},...Bl(e,t)],n=Dl+$l+Math.max(...r.map(Gl));if(!e.isTTY||e.rows<fh||n>e.columns)return[vh(e,t)];let o=Ol(e.level),i=Math.floor((o.length-r.length)/2);return o.map((s,a)=>{let c=r[a-i];return c?`${s}${" ".repeat($l)}${c.styled}`:s})}function as(e){return{isTTY:e.isTTY===!0,hyperlinks:wh(e)}}async function bh({showStatus:e=!0,showUpdate:t=!0}={}){let r={...Jr(process.stdout),...as(process.stdout)},n=e&&r.isTTY?await po():null;return["",...fo({level:yh.level,...r,version:A,status:n,update:t?mo():null}),""]}async function Mt(e){process.stdout.write(`${(await bh(e)).join(`
44
44
  `)}
45
- `)}async function Ll(){if(!process.stdout.isTTY){process.stdout.write(`${R}
46
- `);return}await Lt({size:"large"})}var sh="2048";function Ml(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",sh),t.toString()}function Nl(e){return`https://t.me/${e}`}async function ss(e,t){let r=await fetch(e,{...t,signal:AbortSignal.timeout(1e4)}),n=r.headers.get("content-type")?.includes("application/json");if(r.ok||n)return await r.json();throw new Error(`${new URL(e).hostname} answered HTTP ${r.status}. Try again in a minute.`)}async function Bl(e){let t=await ss(`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 Gl(e){let t=await ss("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 Fl(e,t){return await ss(`https://slack.com/api/${e}`,{method:"POST",headers:{Authorization:`Bearer ${t}`}})}async function Ul(e,t){let r=await Fl("auth.test",e);if(!r.ok||!r.team||!r.url)throw new Error(`Slack rejected the bot token (xoxb-): ${r.error??"unknown error"}.`);let n=await Fl("apps.connections.open",t);if(!n.ok)throw new Error(`Slack rejected the app token (xapp-): ${n.error??"unknown error"}. Enable Socket Mode and create an app-level token with connections:write.`);return{name:r.team,url:r.url}}import*as tn from"node:fs";import*as nn from"node:os";import*as Ql from"node:path";import{execa as Eh}from"execa";import*as pe from"node:fs";import*as jl from"node:path";import{execa as ah}from"execa";var cs="/var/log/dpkg.log",as="/var/cache/apt/archives",ch=1e3,lh=/^\S+ \S+ (unpack|configure) ([^:\s]+)/,uh={unpack:"unpacking",configure:"setting up"};function dh(e){let t=lh.exec(e);return!t?.[1]||!t[2]?null:`${uh[t[1]]} ${t[2]}`}var ph=/apt-get\s+(?:-\S+\s+)*install\s+([^>]+)/;function ql(e){let t=ph.exec(e);return t?.[1]?t[1].split(/\s+/).filter(r=>r&&!r.startsWith("-")):null}function mh(e){return e.split(`
47
- `).map(t=>Number(t.split(" ")[2])).filter(t=>Number.isFinite(t)).reduce((t,r)=>t+r,0)}async function Hl(e){let{stdout:t}=await ah("apt-get",["install","--print-uris","-qq","-y",...e]);return mh(t)}function Vl(e){return pe.existsSync(e)?pe.statSync(e).size:0}function fh(e){return pe.existsSync(as)?pe.readdirSync(as).filter(t=>t.endsWith(".deb")).map(t=>pe.statSync(jl.join(as,t))).filter(t=>t.ctimeMs>=e).reduce((t,r)=>t+r.size,0):0}function gh(e){let t=Vl(cs),r=t<e?0:e;if(t===r)return{activity:null,offset:r};let n=Buffer.alloc(t-r),o=pe.openSync(cs,"r");try{pe.readSync(o,n,0,n.length,r)}finally{pe.closeSync(o)}return{activity:n.toString().split(`
48
- `).map(dh).findLast(a=>a!==null)??null,offset:t}}function ls(e){let t=Date.now(),r=Vl(cs),n=null,o=setInterval(()=>{let i=gh(r);r=i.offset,n=i.activity??n,e({downloaded:fh(t),dpkg:n})},ch);return()=>clearInterval(o)}var Mt="steps";function Zr(e){return e.currentState.data[Mt]??[]}function uo(e,t){let r=Fn();e.updateData(Mt,t.map(n=>({...n,...r[n.id],state:"pending"})))}function us(e){return Object.fromEntries(Zr(e).flatMap(t=>t.startedAt===void 0?[]:[[t.id,{startedAt:t.startedAt,doneLabel:t.doneLabel,minor:t.minor}]]))}function ve(e,t,r){e.updateData(Mt,Zr(e).map(n=>n.id===t?{...n,...r}:n))}function me(e,t,r={}){let n=Date.now(),o=Zr(e).find(i=>i.id===t);ve(e,t,{state:"active",startedAt:o?.startedAt??n,...r})}function ke(e,t,r){let n=Zr(e).find(o=>o.id===t);ve(e,t,{state:"done",endedAt:Date.now(),startedAt:n?.startedAt??Date.now(),detail:void 0,percent:void 0,amount:void 0,etaMs:void 0,hint:void 0,...r?{doneLabel:r}:{}})}function en(e,t){ve(e,t,{state:"skipped",endedAt:Date.now()})}function Ve(e,t){let r=Zr(e).find(n=>n.state==="active"||n.state==="waiting");r&&ve(e,r.id,{state:t,endedAt:Date.now()})}function ft(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 hh(e){let t=e.startedAt!==void 0&&e.endedAt!==void 0?` (${ft(e.endedAt-e.startedAt)})`:"";return e.state==="active"?` ${e.label}\u2026`:e.state==="done"?`${y.ok} ${e.doneLabel}${t}`:e.state==="failed"?`${y.fail} ${e.label}${t}`:e.state==="cancelled"?`${y.cancelled} ${e.label}${t}`:null}function fe(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function Wl(e){if(fe())return;let t=e?`'gaia ${e}'`:"this command";he(`${t} needs an interactive terminal to ask its questions.
49
- Run it from a regular terminal, not a pipe or a script.`),process.exit(1)}function Kl(e,t=""){let r=t,n="",o="",i=new Map;e.on("change",s=>{let a=s.data[Mt]??[];for(let c of a){let l=`${c.state}:${c.state==="active"?c.label:""}`;if(i.get(c.id)===l)continue;i.set(c.id,l);let u=hh(c);u&&console.info(u)}a.length===0&&s.step&&s.step!==r&&(r=s.step,console.info(`
50
- [${s.step}]`)),s.status&&s.status!==n&&(n=s.status,console.info(` ${s.status}`)),s.error&&s.error.message!==o&&(o=s.error.message,he(s.error.message))})}import{execa as Nt}from"execa";var We={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},Yl={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",15672:"RabbitMQ Management",[O]:"Web Frontend",[Qr]:"Web Frontend (HTTPS)",8080:"ChromaDB",8083:"Mongo Express"},Sh={selfhost:[O,Qr],developer:[no,5432,6379,27017,5672,15672,O,8080,8083]};async function po(e,t={}){let r=await Ga(be[e]),n=Sh[e].map(a=>t[a]??a),o=n.filter(a=>!r.has(a)),i=await vh(o),s=new Map(i.map(a=>[a.port,a]));return n.map(a=>s.get(a)??{port:a,service:Yl[a]||`Port ${a}`,available:!0})}async function ds(){try{return await Nt("git",["--version"]),"success"}catch{return"error"}}async function zl(){try{return await Nt("mise",["--version"]),"success"}catch{return"missing"}}async function Xl(){if((await import("node:os")).platform()==="win32")try{return await Nt("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await Nt("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function vh(e){let t=await import("node:net"),r=[],n=o=>new Promise(i=>{let s=t.createServer();s.once("error",()=>i(!1)),s.once("listening",()=>{s.close(()=>i(!0))}),s.listen(o)});for(let o of e){let i=Yl[o]||`Port ${o}`;if(await n(o))r.push({port:o,service:i,available:!0});else{let a=await yh(o),c=await wh(o+1,o+100,n);r.push({port:o,service:i,available:!1,usedBy:a,alternative:c||void 0})}}return r}async function yh(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:n}=await Nt("netstat",["-ano","-p","TCP"]),o=n.trim().split(`
51
- `);for(let i of o)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 Nt("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:n}=await Nt("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),o=n.trim().split(`
52
- `);if(o.length>1)return o[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function wh(e,t,r){for(let n=e;n<=t;n++)if(await r(n))return n;return null}var xh="https://get.docker.com",Ih="https://orbstack.dev",kh="https://docs.docker.com/desktop/install/mac-install/",Rh="setting up docker-ce",Ch={git:"Git",docker:"Docker"},ps="prerequisite_install_confirm",Bt="missingPrerequisites",rn=class extends Error{constructor(t){super(t),this.name="PrerequisiteDeclined"}};function ms(){return tn.existsSync("/usr/bin/apt-get")||tn.existsSync("/etc/debian_version")}function Ft(e,t,r){e.updateData("checks",{...e.currentState.data.checks,[t]:r})}function ur(e){return e.map(t=>Ch[t]).join(" and ")}function Ah(){throw nn.platform()==="darwin"?new Error(`GAIA runs in Docker, which isn't installed yet.
53
- \u2022 OrbStack (lightweight): ${Ih}
54
- \u2022 Docker Desktop: ${kh}
55
- Install either, open it, then run this command again.`):new Error(`GAIA runs in Docker, which isn't installed yet. Install it from ${We.docker}, then run this command again.`)}async function Ph(e,t,r){if(r.assumeYes)return;let n=ur(t);if(!fe())throw new Error(`GAIA needs ${n}, and there is no terminal to ask before installing.
45
+ `)}async function Ul(){if(!process.stdout.isTTY){process.stdout.write(`${A}
46
+ `);return}await Mt()}var Eh="2048";function jl(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",Eh),t.toString()}function ql(e){return`https://t.me/${e}`}async function cs(e,t){let r=await fetch(e,{...t,signal:AbortSignal.timeout(1e4)}),n=r.headers.get("content-type")?.includes("application/json");if(r.ok||n)return await r.json();throw new Error(`${new URL(e).hostname} answered HTTP ${r.status}. Try again in a minute.`)}async function Vl(e){let t=await cs(`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 Wl(e){let t=await cs("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 Hl(e,t){return await cs(`https://slack.com/api/${e}`,{method:"POST",headers:{Authorization:`Bearer ${t}`}})}async function Kl(e,t){let r=await Hl("auth.test",e);if(!r.ok||!r.team||!r.url)throw new Error(`Slack rejected the bot token (xoxb-): ${r.error??"unknown error"}.`);let n=await Hl("apps.connections.open",t);if(!n.ok)throw new Error(`Slack rejected the app token (xapp-): ${n.error??"unknown error"}. Enable Socket Mode and create an app-level token with connections:write.`);return{name:r.team,url:r.url}}import*as tn from"node:fs";import*as nn from"node:os";import*as iu from"node:path";import{execa as Fh}from"execa";import*as fe from"node:fs";import*as Yl from"node:path";import{execa as xh}from"execa";var us="/var/log/dpkg.log",ls="/var/cache/apt/archives",Ih=1e3,Rh=/^\S+ \S+ (unpack|configure) ([^:\s]+)/,Ch={unpack:"unpacking",configure:"setting up"};function kh(e){let t=Rh.exec(e);return!t?.[1]||!t[2]?null:`${Ch[t[1]]} ${t[2]}`}var Ah=/apt-get\s+(?:-\S+\s+)*install\s+([^>]+)/;function zl(e){let t=Ah.exec(e);return t?.[1]?t[1].split(/\s+/).filter(r=>r&&!r.startsWith("-")):null}function Ph(e){return e.split(`
47
+ `).map(t=>Number(t.split(" ")[2])).filter(t=>Number.isFinite(t)).reduce((t,r)=>t+r,0)}async function Xl(e){let{stdout:t}=await xh("apt-get",["install","--print-uris","-qq","-y",...e]);return Ph(t)}function Jl(e){return fe.existsSync(e)?fe.statSync(e).size:0}function Th(e){return fe.existsSync(ls)?fe.readdirSync(ls).filter(t=>t.endsWith(".deb")).map(t=>fe.statSync(Yl.join(ls,t))).filter(t=>t.ctimeMs>=e).reduce((t,r)=>t+r.size,0):0}function _h(e){let t=Jl(us),r=t<e?0:e;if(t===r)return{activity:null,offset:r};let n=Buffer.alloc(t-r),o=fe.openSync(us,"r");try{fe.readSync(o,n,0,n.length,r)}finally{fe.closeSync(o)}return{activity:n.toString().split(`
48
+ `).map(kh).findLast(a=>a!==null)??null,offset:t}}function ds(e){let t=Date.now(),r=Jl(us),n=null,o=setInterval(()=>{let i=_h(r);r=i.offset,n=i.activity??n,e({downloaded:Th(t),dpkg:n})},Ih);return()=>clearInterval(o)}var Nt="steps";function Zr(e){return e.currentState.data[Nt]??[]}function go(e,t){let r=Un();e.updateData(Nt,t.map(n=>({...n,...r[n.id],state:"pending"})))}function ps(e){return Object.fromEntries(Zr(e).flatMap(t=>t.startedAt===void 0?[]:[[t.id,{startedAt:t.startedAt,label:t.label,doneLabel:t.doneLabel,minor:t.minor,substeps:t.substeps}]]))}function te(e,t,r){e.updateData(Nt,Zr(e).map(n=>n.id===t?{...n,...r}:n))}function ge(e,t,r={}){let n=Date.now(),o=Zr(e).find(i=>i.id===t);e.setStatus(""),te(e,t,{state:"active",startedAt:o?.startedAt??n,...r})}function ke(e,t,r){let n=Zr(e).find(o=>o.id===t);te(e,t,{state:"done",endedAt:Date.now(),startedAt:n?.startedAt??Date.now(),detail:void 0,percent:void 0,amount:void 0,etaMs:void 0,hint:void 0,substeps:void 0,...r?{doneLabel:r}:{}})}function Ql(e,t,r,n,o){let i=r.findIndex(s=>s.id===n);te(e,t,{substeps:r.map((s,a)=>({...s,state:a<i?"done":a===i?"active":"pending",...a===i&&o?{note:o}:{}}))})}function en(e,t){te(e,t,{state:"skipped",endedAt:Date.now()})}function Ve(e,t){let r=Zr(e).find(n=>n.state==="active"||n.state==="waiting");r&&te(e,r.id,{state:t,endedAt:Date.now()})}function gt(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 Dh(e){let t=e.startedAt!==void 0&&e.endedAt!==void 0?` (${gt(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 he(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function Zl(e){if(he())return;let t=e?`'gaia ${e}'`:"this command";ye(`${t} needs an interactive terminal to ask its questions.
49
+ Run it from a regular terminal, not a pipe or a script.`),process.exit(1)}function eu(e,t=""){let r=t,n="",o="",i=new Map;e.on("change",s=>{let a=s.data[Nt]??[];for(let c of a){let l=`${c.state}:${c.state==="active"?c.label:""}`;if(i.get(c.id)===l)continue;i.set(c.id,l);let d=Dh(c);d&&console.info(d)}a.length===0&&s.step&&s.step!==r&&(r=s.step,console.info(`
50
+ [${s.step}]`)),s.status&&s.status!==n&&(n=s.status,console.info(` ${s.status}`)),s.error&&s.error.message!==o&&(o=s.error.message,ye(s.error.message))})}import{execa as Ft}from"execa";var We={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},tu={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",15672:"RabbitMQ Management",[O]:"Web Frontend",[Qr]:"Web Frontend (HTTPS)",8080:"ChromaDB",8083:"Mongo Express"},Oh={selfhost:[O,Qr],developer:[ao,5432,6379,27017,5672,15672,O,8080,8083]};async function ho(e,t={}){let r=await Ha(Ee[e]),n=Oh[e].map(a=>t[a]??a),o=n.filter(a=>!r.has(a)),i=await $h(o),s=new Map(i.map(a=>[a.port,a]));return n.map(a=>s.get(a)??{port:a,service:tu[a]||`Port ${a}`,available:!0})}async function ms(){try{return await Ft("git",["--version"]),"success"}catch{return"error"}}async function ru(){try{return await Ft("mise",["--version"]),"success"}catch{return"missing"}}async function nu(){if((await import("node:os")).platform()==="win32")try{return await Ft("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await Ft("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function $h(e){let t=await import("node:net"),r=[],n=o=>new Promise(i=>{let s=t.createServer();s.once("error",()=>i(!1)),s.once("listening",()=>{s.close(()=>i(!0))}),s.listen(o)});for(let o of e){let i=tu[o]||`Port ${o}`;if(await n(o))r.push({port:o,service:i,available:!0});else{let a=await Lh(o),c=await Mh(o+1,o+100,n);r.push({port:o,service:i,available:!1,usedBy:a,alternative:c||void 0})}}return r}async function Lh(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:n}=await Ft("netstat",["-ano","-p","TCP"]),o=n.trim().split(`
51
+ `);for(let i of o)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 Ft("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:n}=await Ft("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),o=n.trim().split(`
52
+ `);if(o.length>1)return o[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function Mh(e,t,r){for(let n=e;n<=t;n++)if(await r(n))return n;return null}var Bh="https://get.docker.com",Gh="https://orbstack.dev",Uh="https://docs.docker.com/desktop/install/mac-install/",jh="setting up docker-ce",qh={git:"Git",docker:"Docker"},fs="prerequisite_install_confirm",Gt="missingPrerequisites",rn=class extends Error{constructor(t){super(t),this.name="PrerequisiteDeclined"}};function gs(){return tn.existsSync("/usr/bin/apt-get")||tn.existsSync("/etc/debian_version")}function Bt(e,t,r){e.updateData("checks",{...e.currentState.data.checks,[t]:r})}function ur(e){return e.map(t=>qh[t]).join(" and ")}function Hh(){throw nn.platform()==="darwin"?new Error(`GAIA runs in Docker, which isn't installed yet.
53
+ \u2022 OrbStack (lightweight): ${Gh}
54
+ \u2022 Docker Desktop: ${Uh}
55
+ Install either, open it, then run this command again.`):new Error(`GAIA runs in Docker, which isn't installed yet. Install it from ${We.docker}, then run this command again.`)}async function Vh(e,t,r){if(r.assumeYes)return;let n=ur(t);if(!he())throw new Error(`GAIA needs ${n}, and there is no terminal to ask before installing.
56
56
  Rerun with --yes to install them, or install them first:
57
57
  `+t.map(i=>` ${We[i]}`).join(`
58
- `));for(let i of t)Ft(e,i,"missing");if(e.updateData(Bt,t),await e.waitForInput(ps)!=="install")throw new rn(`Skipped installing ${n}. Install ${t.length>1?"them":"it"} (${t.map(i=>We[i]).join(", ")}), then run ${r.rerunCommand?`'${r.rerunCommand}'`:"this command"} again.`)}function Zl(e){return e.dpkg?e.dpkg:e.downloaded>0?`${qe(e.downloaded)} downloaded`:void 0}async function Th(e){let t="Installing Git";e({label:t,detail:"updating the package list"});let r=Ue("git-install"),n=ls(o=>e({label:t,detail:Zl(o)}));try{await q("apt-get",["update"],r),e({label:t}),await q("apt-get",["install","-y","git"],r)}catch(o){throw new Error(`Git installation failed: ${o.message}
59
- Install it by hand following ${We.git}, then run this command again.`)}finally{n()}if(await ds()!=="success")throw new Error(`Git was installed but 'git --version' still fails. Install it by hand following ${We.git}, then run this command again.`)}function _h(e){if(e.includes("Executing docker install script"))return{stage:"preparing",detail:"starting Docker's installer"};if(!e.startsWith("+ "))return null;let t=ql(e);return t?.includes("docker-ce")?{stage:"downloading",packages:t}:e.includes("apt-get")&&e.includes("update")?{stage:"preparing",detail:"updating the package list"}:e.includes("gpg")||e.includes("docker.asc")?{stage:"preparing",detail:"adding Docker's package source"}:t?{stage:"preparing",detail:"installing what Docker needs"}:e.includes("systemctl")?{stage:"starting"}:null}function Dh(e,t){let r=()=>{},n=null,o=!1,i=a=>{if(a.dpkg&&(o=!0),a.dpkg===Rh){e({label:"Starting Docker"});return}if(o){e({label:"Installing Docker",detail:a.dpkg??void 0});return}if(n===null){e({label:"Downloading Docker",detail:Zl(a)});return}let c=Math.max(n,a.downloaded);e({label:"Downloading Docker",amount:{done:a.downloaded,total:c,unit:"bytes",estimated:!1}})};return{onLine:a=>{let c=_h(a);if(c){if(c.stage==="preparing"){e({label:"Preparing to install Docker",detail:c.detail});return}if(r(),c.stage==="starting"){e({label:"Starting Docker"});return}i({downloaded:0,dpkg:null}),r=ls(i),Hl(c.packages).then(l=>{n=l},l=>tn.appendFileSync(t,`gaia: could not read Docker's download size: ${l.message}
60
- `))}},stop:()=>r()}}async function Oh(e){let t=Ql.join(nn.tmpdir(),"gaia-docker-install.sh"),r=Ue("docker-install");e({label:"Preparing to install Docker",detail:"downloading Docker's installer"}),await Eh("curl",["-fsSL",xh,"-o",t]);let n=Dh(e,r);try{await q("sh",[t],r,n.onLine)}catch(o){throw new Error(`Docker installation failed: ${o.message}
61
- Install it by hand following ${We.docker}, then run this command again.`)}finally{n.stop()}}async function Jl(e,t,r){Ft(e,t,"pending");try{let n=await r();return Ft(e,t,"success"),n}catch(n){throw Ft(e,t,"error"),n}}async function $h(e,t){if(t==="no-permission")return e.setStatus("Giving your user access to Docker (the docker group)\u2026"),await hc(),e.updateData("dockerGroupSwitch",await Sc()),e.setStatus("Docker access granted. Continuing with it\u2026"),"relaunch";if(t!=="ready")throw await Dt(t);return"ready"}async function mo(e,t){let r=t.needGit&&await ds()!=="success",n=await Z(),o=[];r&&o.push("git"),n==="not-installed"&&o.push("docker");let i=nn.platform()==="linux"&&ms();if(r&&!i)throw Ft(e,"git","error"),new Error(`GAIA needs Git, which isn't installed. Install it from ${We.git}, then run this command again.`);if(n==="not-installed"&&!i&&(Ft(e,"docker","error"),Ah()),o.length>0){try{await Ph(e,o,t)}catch(a){for(let c of o)Ft(e,c,"error");throw a}t.onInstallStart?.(o)}let s=t.onInstallProgress??(a=>e.setStatus(`${a.label}${a.detail?` \xB7 ${a.detail}`:""}\u2026`));return t.needGit&&await Jl(e,"git",async()=>{r&&await Th(s)}),Jl(e,"docker",async()=>(n==="not-installed"&&(await Oh(s),e.setStatus("Docker installed. Checking that it runs\u2026"),n=await Z()),$h(e,n)))}var J=e=>new Promise(t=>setTimeout(t,e)),fo=(e,t="dependencyLogs")=>r=>{let n=e.currentState.data[t]||[],o=r.split(`
62
- `).filter(i=>i.trim()!=="");e.updateData(t,[...n,...o].slice(-Lr))};function eu(e){return(t,r)=>{e.updateData("dependencyPhase",t.label),e.updateData("dependencyProgress",t.percent),e.updateData("dependencyLogs",r.slice(-Lr))}}async function go(e){e.updateData("checks",{git:"pending"}),await J(500);try{return await mo(e,{needGit:!0})==="ready"}catch(t){return e.setError(t),!1}}async function ho(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await zl();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise\u2026"),t=await Xl()?"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.
63
- \u2022 Mise: ${We.mise}`)),null):"success"}async function dr(e,t){e.setStatus("Checking Ports\u2026");let r=await po(t),n={},o=r.filter(i=>!i.available);if(o.length>0){let i=o.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&&(n[a.port]=a.alternative)}return e.updateData("portOverrides",n),e.setStatus("Git and Docker are ready"),await J(1e3),n}async function tu(e,t,r,n){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 le("mise",["trust"],t,void 0,n),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools\u2026"),await le("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},n),e.updateData("dependencyPhase","Running mise setup\u2026");let o=Object.keys(r).length>0?at(r):void 0;return await le("mise",["setup"],t,i=>{e.updateData("dependencyProgress",50+i*.5)},n,o),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0),!0}catch(o){return e.setError(new Error(`Failed to setup project: ${o.message}`)),!1}}import{createInterface as nu}from"node:readline/promises";import{Writable as Lh}from"node:stream";async function gt(e,t){let r=nu({input:process.stdin,output:process.stdout});try{let n=t?` [${t}]`:"";return(await r.question(`${e}${n}: `)).trim()||t||""}finally{r.close()}}var ru=4,So="\x1B",Mh="",Nh=new Set(["\x7F","\b"]),Fh=new RegExp(`${So}\\[[0-9;]*[A-Za-z~]`,"g");function Bh(e){let t=e.length>ru*2?ru:0;return"\u2022".repeat(e.length-t)+e.slice(e.length-t)}async function vo(e){if(process.stdout.write(`${e}
64
- \u203A `),!process.stdin.isTTY){let t=nu({input:process.stdin,output:new Lh({write:(r,n,o)=>o()})});try{return(await t.question("")).trim()}finally{t.close()}}return new Promise(t=>{let r="",n=(i,s)=>{process.stdin.off("data",o),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`\r\u203A ${s}${So}[K
65
- `),t(i)},o=i=>{let s=i.toString("utf-8").replace(Fh,"");(s===Mh||s===So)&&(n("",""),process.stdout.write(`${y.cancelled} Cancelled \xB7 nothing changed.
58
+ `));for(let i of t)Bt(e,i,"missing");if(e.updateData(Gt,t),await e.waitForInput(fs)!=="install")throw new rn(`Skipped installing ${n}. Install ${t.length>1?"them":"it"} (${t.map(i=>We[i]).join(", ")}), then run ${r.rerunCommand?`'${r.rerunCommand}'`:"this command"} again.`)}var su={prepare:"Preparing the install",download:"Downloading packages",install:"Installing packages",start:"Starting the Docker service",check:"Checking Docker answers"},hs=["prepare","download","install","start","check"].map(e=>({id:e,label:su[e]}));function au(e){return e.dpkg?.split(" ").at(-1)}async function Wh(e){e({stage:"prepare",note:"package lists"});let t=qe("git-install"),r=!1,n=ds(o=>{r&&e(o.dpkg?{stage:"install",note:au(o)}:{stage:"download",note:Re(o.downloaded)})});try{await H("apt-get",["update"],t),r=!0,e({stage:"download"}),await H("apt-get",["install","-y","git"],t)}catch(o){throw new Error(`Git installation failed: ${o.message}
59
+ Install it by hand following ${We.git}, then run this command again.`)}finally{n()}if(await ms()!=="success")throw new Error(`Git was installed but 'git --version' still fails. Install it by hand following ${We.git}, then run this command again.`)}function Kh(e){if(e.includes("Executing docker install script"))return{stage:"preparing",detail:"running Docker's script"};if(!e.startsWith("+ "))return null;let t=zl(e);return t?.includes("docker-ce")?{stage:"downloading",packages:t}:e.includes("apt-get")&&e.includes("update")?{stage:"preparing",detail:"package lists"}:e.includes("gpg")||e.includes("docker.asc")?{stage:"preparing",detail:"package source"}:t?{stage:"preparing",detail:"what Docker needs"}:e.includes("systemctl")?{stage:"starting"}:null}function Yh(e){let t=hs.map(n=>n.id),r=0;return n=>{let o=t.indexOf(n.stage);o<r||(r=o,e(n))}}function zh(e,t){let r=Yh(e),n=()=>{},o=null,i=a=>{if(a.dpkg===jh){r({stage:"start"});return}if(a.dpkg){r({stage:"install",note:au(a)});return}r({stage:"download",note:o===null?Re(a.downloaded):Ot(a.downloaded,Math.max(o,a.downloaded),!1)})};return{onLine:a=>{let c=Kh(a);if(c){if(c.stage==="preparing"){r({stage:"prepare",note:c.detail});return}if(n(),c.stage==="starting"){r({stage:"start"});return}i({downloaded:0,dpkg:null}),n=ds(i),Xl(c.packages).then(l=>{o=l},l=>tn.appendFileSync(t,`gaia: could not read Docker's download size: ${l.message}
60
+ `))}},stop:()=>n()}}async function Xh(e){let t=iu.join(nn.tmpdir(),"gaia-docker-install.sh"),r=qe("docker-install");e({stage:"prepare",note:"Docker's script"}),await Fh("curl",["-fsSL",Bh,"-o",t]);let n=zh(e,r);try{await H("sh",[t],r,n.onLine)}catch(o){throw new Error(`Docker installation failed: ${o.message}
61
+ Install it by hand following ${We.docker}, then run this command again.`)}finally{n.stop()}}async function ou(e,t,r){Bt(e,t,"pending");try{let n=await r();return Bt(e,t,"success"),n}catch(n){throw Bt(e,t,"error"),n}}async function Jh(e,t){if(t==="no-permission")return e.setStatus("Giving your user access to Docker (the docker group)\u2026"),await wc(),e.updateData("dockerGroupSwitch",await Ec()),e.setStatus("Docker access granted. Continuing with it\u2026"),"relaunch";if(t!=="ready")throw await Dt(t);return"ready"}async function So(e,t){let r=t.needGit&&await ms()!=="success",n=await ee(),o=[];r&&o.push("git"),n==="not-installed"&&o.push("docker");let i=nn.platform()==="linux"&&gs();if(r&&!i)throw Bt(e,"git","error"),new Error(`GAIA needs Git, which isn't installed. Install it from ${We.git}, then run this command again.`);if(n==="not-installed"&&!i&&(Bt(e,"docker","error"),Hh()),o.length>0){try{await Vh(e,o,t)}catch(a){for(let c of o)Bt(e,c,"error");throw a}t.onInstallStart?.(o)}let s=t.onInstallProgress??(a=>e.setStatus(`${su[a.stage]}${a.note?` \xB7 ${a.note}`:""}\u2026`));return t.needGit&&await ou(e,"git",async()=>{r&&await Wh(s)}),ou(e,"docker",async()=>(n==="not-installed"&&(await Xh(s),s({stage:"check"}),n=await ee()),Jh(e,n)))}var Q=e=>new Promise(t=>setTimeout(t,e)),vo=(e,t="dependencyLogs")=>r=>{let n=e.currentState.data[t]||[],o=r.split(`
62
+ `).filter(i=>i.trim()!=="");e.updateData(t,[...n,...o].slice(-$r))};function cu(e){return(t,r)=>{e.updateData("dependencyPhase",t.label),e.updateData("dependencyProgress",t.percent),e.updateData("dependencyLogs",r.slice(-$r))}}async function yo(e){e.updateData("checks",{git:"pending"}),await Q(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 ru();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise\u2026"),t=await nu()?"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.
63
+ \u2022 Mise: ${We.mise}`)),null):"success"}async function dr(e,t){e.setStatus("Checking Ports\u2026");let r=await ho(t),n={},o=r.filter(i=>!i.available);if(o.length>0){let i=o.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&&(n[a.port]=a.alternative)}return e.updateData("portOverrides",n),e.setStatus("Git and Docker are ready"),await Q(1e3),n}async function lu(e,t,r,n){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 de("mise",["trust"],t,void 0,n),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools\u2026"),await de("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},n),e.updateData("dependencyPhase","Running mise setup\u2026");let o=Object.keys(r).length>0?ct(r):void 0;return await de("mise",["setup"],t,i=>{e.updateData("dependencyProgress",50+i*.5)},n,o),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0),!0}catch(o){return e.setError(new Error(`Failed to setup project: ${o.message}`)),!1}}import{createInterface as du}from"node:readline/promises";import{Writable as Qh}from"node:stream";async function ht(e,t){let r=du({input:process.stdin,output:process.stdout});try{let n=t?` [${t}]`:"";return(await r.question(`${e}${n}: `)).trim()||t||""}finally{r.close()}}var uu=4,bo="\x1B",Zh="",eS=new Set(["\x7F","\b"]),tS=new RegExp(`${bo}\\[[0-9;]*[A-Za-z~]`,"g");function rS(e){let t=e.length>uu*2?uu:0;return"\u2022".repeat(e.length-t)+e.slice(e.length-t)}async function Eo(e){if(process.stdout.write(`${e}
64
+ \u203A `),!process.stdin.isTTY){let t=du({input:process.stdin,output:new Qh({write:(r,n,o)=>o()})});try{return(await t.question("")).trim()}finally{t.close()}}return new Promise(t=>{let r="",n=(i,s)=>{process.stdin.off("data",o),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`\r\u203A ${s}${bo}[K
65
+ `),t(i)},o=i=>{let s=i.toString("utf-8").replace(tS,"");(s===Zh||s===bo)&&(n("",""),process.stdout.write(`${y.cancelled} Cancelled \xB7 nothing changed.
66
66
  `),process.exit(130));for(let a of s){if(a==="\r"||a===`
67
- `){n(r.trim(),Bh(r.trim()));return}Nh.has(a)?r=r.slice(0,-1):a>=" "&&(r+=a)}process.stdout.write(`\r\u203A ${"\u2022".repeat(r.length)}${So}[K`)};process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",o)})}async function ht(e,t=!0){let r=await gt(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function yo(e,t){for(process.stdout.write(`
67
+ `){n(r.trim(),rS(r.trim()));return}eS.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",o)})}async function St(e,t=!0){let r=await ht(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function xo(e,t){for(process.stdout.write(`
68
68
  ${e}
69
69
  `),t.forEach((r,n)=>{process.stdout.write(` ${n+1}. ${r}
70
- `)});;){let r=await gt(`Choose 1-${t.length}`),n=Number.parseInt(r,10)-1;if(n>=0&&n<t.length)return n;process.stdout.write(`Invalid choice, try again.
71
- `)}}var Gh={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},Uh=12e4,jh=3e3,ou={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 Re(e=""){process.stdout.write(`${e}
72
- `)}function fs(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Gt={telegram:"Telegram",discord:"Discord",slack:"Slack"},qh=3;async function Hh(e,t,r){let n={...t},o=0;for(let i of ou[e]){if(n[i.key])continue;if(!fe())throw new Error(`Missing ${i.flag}. ${i.hint}`);r&&(o>0&&Re(),Re(dt(i.hint))),o++;let s=await vo(i.label);if(!s)throw new Error(`No ${i.label} entered. Nothing changed.`);n[i.key]=s}return n}async function Vh(e,t){for(let r=1;;r++){let n=await Hh(e,t,r===1);Re(`Checking your ${Gt[e]} credentials\u2026`);try{return await Wh(e,n)}catch(o){let i=ou[e].filter(a=>!t[a.key]),s=qh-r;if(i.length===0||!fe()||s===0)throw o;Re(dt(`${y.fail} ${o.message} Paste ${i.length===1?"it":"them"} again (${s} ${s===1?"try":"tries"} left), or press Esc to stop.`,2))}}}async function gs(){let e=L();if(!e||await $(e)!=="selfhost")throw new Error("No self-host GAIA install found. Run 'gaia up' first; chat bots run alongside it.");return e}async function Wh(e,t){let r=fs(t.token,"--token");if(e==="telegram"){let s=await Bl(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${Nl(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await Gl(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${Ml(s)}`,"Then run /auth in Discord to link your GAIA account."]}}let n=fs(t.appToken,"--app-token"),o=fs(t.signingSecret,"--signing-secret"),i=await Ul(r,n);return{botsEnv:{SLACK_BOT_TOKEN:r,SLACK_APP_TOKEN:n,SLACK_SIGNING_SECRET:o},handle:i.url,nextSteps:[`Running in the ${i.name} workspace. Run /auth in Slack to link your GAIA account.`]}}async function Kh(e){let t=be.selfhost,r=Date.now()+Uh;for(;;){let n=Hr(e,await Pt(t));if(n.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Gt[e]} bot did not come up (${n.detail}). See why with 'docker compose -p ${t} logs ${xe(e)}'; 'gaia bots remove ${e}' undoes the setup.`);await J(jh)}}async function iu(e){await ce(e,"selfhost",t=>Re(t),A(e),void 0,{pull:"missing"})}async function su(e,t){let r=await gs(),n=await Vh(e,t);Vr(r,{set:n.botsEnv}),Gn(r,{set:{[Bi[e]]:n.handle}});let o=C()?.bots??[];o.includes(e)||Se({bots:[...o,e]}),await iu(r);let i=Gh[e];i&&(Re(`Registering the ${Gt[e]} bot's commands\u2026`),await sl(r,xe(e),i)),Re(`Waiting for the ${Gt[e]} bot to connect\u2026`),await Kh(e),Re(`${y.ok} The ${Gt[e]} bot is running`);for(let s of n.nextSteps)Re(s)}async function au(e){let t=await gs(),r=C()?.bots??[];if(!r.includes(e))throw new Error(`The ${Gt[e]} bot is not enabled. See 'gaia bots list'.`);Se({bots:r.filter(n=>n!==e)}),Vr(t,{unset:Ec[e]}),Gn(t,{unset:[Bi[e]]}),await iu(t),Re(`${y.ok} The ${Gt[e]} bot is stopped and its credentials are deleted`)}async function cu(){await gs();let e=C()?.bots??[];if(e.length===0){Re("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await Pt(be.selfhost);for(let r of e)Re(` ${r.padEnd(10)}${Hr(r,t).detail}`)}function lu(){return new Yh("<platform>","chat platform").choices(bc)}var sn=new zh("bots").description(U.bots).hook("preAction",()=>Lt()).addHelpText("after",`
70
+ `)});;){let r=await ht(`Choose 1-${t.length}`),n=Number.parseInt(r,10)-1;if(n>=0&&n<t.length)return n;process.stdout.write(`Invalid choice, try again.
71
+ `)}}var nS={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},oS=12e4,iS=3e3,pu={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 Ae(e=""){process.stdout.write(`${e}
72
+ `)}function Ss(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Ut={telegram:"Telegram",discord:"Discord",slack:"Slack"},sS=3;async function aS(e,t,r){let n={...t},o=0;for(let i of pu[e]){if(n[i.key])continue;if(!he())throw new Error(`Missing ${i.flag}. ${i.hint}`);r&&(o>0&&Ae(),Ae(pt(i.hint))),o++;let s=await Eo(i.label);if(!s)throw new Error(`No ${i.label} entered. Nothing changed.`);n[i.key]=s}return n}async function cS(e,t){for(let r=1;;r++){let n=await aS(e,t,r===1);Ae(`Checking your ${Ut[e]} credentials\u2026`);try{return await lS(e,n)}catch(o){let i=pu[e].filter(a=>!t[a.key]),s=sS-r;if(i.length===0||!he()||s===0)throw o;Ae(pt(`${y.fail} ${o.message} Paste ${i.length===1?"it":"them"} again (${s} ${s===1?"try":"tries"} left), or press Esc to stop.`,2))}}}async function vs(){let e=L();if(!e||await $(e)!=="selfhost")throw new Error("No self-host GAIA install found. Run 'gaia up' first; chat bots run alongside it.");return e}async function lS(e,t){let r=Ss(t.token,"--token");if(e==="telegram"){let s=await Vl(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${ql(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await Wl(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${jl(s)}`,"Then run /auth in Discord to link your GAIA account."]}}let n=Ss(t.appToken,"--app-token"),o=Ss(t.signingSecret,"--signing-secret"),i=await Kl(r,n);return{botsEnv:{SLACK_BOT_TOKEN:r,SLACK_APP_TOKEN:n,SLACK_SIGNING_SECRET:o},handle:i.url,nextSteps:[`Running in the ${i.name} workspace. Run /auth in Slack to link your GAIA account.`]}}async function uS(e){let t=Ee.selfhost,r=Date.now()+oS;for(;;){let n=Hr(e,await Pt(t));if(n.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Ut[e]} bot did not come up (${n.detail}). See why with 'docker compose -p ${t} logs ${Ie(e)}'; 'gaia bots remove ${e}' undoes the setup.`);await Q(iS)}}async function mu(e){await ue(e,"selfhost",t=>Ae(t),k(e),void 0,{pull:"missing"})}async function fu(e,t){let r=await vs(),n=await cS(e,t);Vr(r,{set:n.botsEnv}),Vn(r,{set:{[Bi[e]]:n.handle}});let o=P()?.bots??[];o.includes(e)||we({bots:[...o,e]}),await mu(r);let i=nS[e];i&&(Ae(`Registering the ${Ut[e]} bot's commands\u2026`),await fl(r,Ie(e),i)),Ae(`Waiting for the ${Ut[e]} bot to connect\u2026`),await uS(e),Ae(`${y.ok} The ${Ut[e]} bot is running`);for(let s of n.nextSteps)Ae(s)}async function gu(e){let t=await vs(),r=P()?.bots??[];if(!r.includes(e))throw new Error(`The ${Ut[e]} bot is not enabled. See 'gaia bots list'.`);we({bots:r.filter(n=>n!==e)}),Vr(t,{unset:Ac[e]}),Vn(t,{unset:[Bi[e]]}),await mu(t),Ae(`${y.ok} The ${Ut[e]} bot is stopped and its credentials are deleted`)}async function hu(){await vs();let e=P()?.bots??[];if(e.length===0){Ae("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await Pt(Ee.selfhost);for(let r of e)Ae(` ${r.padEnd(10)}${Hr(r,t).detail}`)}function Su(){return new dS("<platform>","chat platform").choices(kc)}var sn=new pS("bots").description(j.bots).hook("preAction",()=>Mt()).addHelpText("after",`
73
73
  Examples:
74
74
  gaia bots add telegram (asks for the token from @BotFather)
75
75
  gaia bots add telegram --token <token from @BotFather>
76
76
  gaia bots add discord --token <bot token>
77
77
  gaia bots add slack --token xoxb-... --app-token xapp-... --signing-secret <secret>
78
- `);sn.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(lu()).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 ue(()=>su(e,t))});sn.command("list").alias("ls").description("Show the enabled bots and whether each is running").action(async()=>{await ue(cu)});sn.command("remove").alias("rm").description("Stop a bot and delete its saved credentials").addArgument(lu()).action(async e=>{await ue(()=>au(e))});import{Command as nv}from"commander";import{existsSync as Ro,mkdirSync as SS,readFileSync as wu,writeFileSync as ks}from"node:fs";import{homedir as yu}from"node:os";import{join as Rs}from"node:path";import{sep as Xh}from"node:path";var H={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"},hs="https://api.heygaia.io",Ut="filesystem",wo=Xh,Ss=500,vs=6e4,ys=5e3,ws=1e6,bs=5e6,bo=9e4,Eo=1e6;import{homedir as Jh}from"node:os";import{join as Qh}from"node:path";var Zh={info:e=>console.error(e),error:e=>console.error(e)},Es={},eS=null;function Q(){return eS??Zh}function Ke(){return{stateDir:Es.stateDir??Qh(Jh(),".gaia","bridge"),env:Es.env??process.env,shell:Es.shell??process.env.SHELL??"/bin/sh"}}import{Client as uS}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as dS,StdioClientTransport as pS}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as mS}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as fS}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as tS,readdir as mu,readFile as uu,realpath as rS,stat as nS,writeFile as oS}from"node:fs/promises";import{dirname as du,extname as iS,join as fu,resolve as sS,sep as xs}from"node:path";import{McpServer as aS}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as pr}from"zod";var cS={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},mr=class extends Error{};async function Is(e){try{return await rS(e)}catch{return null}}async function lS(e){try{return(await tS(e)).isSymbolicLink()}catch{return!1}}function pu(e,t){return t===xs?e.startsWith(xs):e===t||e.startsWith(t+xs)}async function xo(e,t,r){let n=sS(e),o=await Is(n);if(o){if(t.some(s=>pu(o,s)))return o;throw new mr(`Path is outside your approved folders: ${e}`)}if(r)throw new mr(`No such file or directory: ${e}`);let i=await Is(du(n));if(!i||!t.some(s=>pu(i,s)))throw new mr(`Path is outside your approved folders: ${e}`);if(await lS(n))throw new mr(`Refusing to write through a symlink: ${e}`);return fu(i,n.slice(du(n).length+1))}async function gu(e,t,r,n){if(n.length>=r)return;let o;try{o=await mu(e,{withFileTypes:!0})}catch{return}for(let i of o){if(n.length>=r)return;let s=fu(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&n.push(s),i.isDirectory()&&!i.isSymbolicLink()&&await gu(s,t,r,n)}}function hu(e){let t=new aS({name:"gaia-filesystem",version:"0.1.0"}),r=null,n=()=>(r||(r=Promise.all(e.allow.map(Is)).then(i=>i.filter(s=>s!==null))),r),o=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:pr.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let s=await xo(i,await n(),!0);return{content:[{type:"text",text:(await mu(s,{withFileTypes:!0})).map(l=>`${l.isDirectory()?"dir ":"file"} ${l.name}`).join(`
79
- `)||"(empty)"}]}}catch(s){return o(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:pr.string().describe("Absolute path to a file")}},async({path:i})=>{try{let s=await xo(i,await n(),!0),a=await nS(s);if(!a.isFile())return o(`Not a file: ${i}`);let c=cS[iS(s).toLowerCase()];if(c){if(a.size>bs)return o(`Image is too large to read (${a.size} bytes).`);let u=await uu(s);return{content:[{type:"text",text:`Image file ${s} (${c}, ${a.size} bytes) \u2014 shown below.`},{type:"image",data:u.toString("base64"),mimeType:c}]}}return a.size>ws?o(`File is too large to read (${a.size} bytes).`):{content:[{type:"text",text:await uu(s,"utf-8")}]}}catch(s){return o(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:pr.string().describe("Absolute path to the directory to search under"),query:pr.string().describe("Substring to match against names")}},async({path:i,query:s})=>{try{let a=await xo(i,await n(),!0),c=[];return await gu(a,s,200,c),{content:[{type:"text",text:c.join(`
80
- `)||"(no matches)"}]}}catch(a){return o(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:pr.string().describe("Absolute path to the file to write"),content:pr.string().describe("Text content to write")}},async({path:i,content:s})=>{try{let a=await xo(i,await n(),!1);return await oS(a,s,"utf-8"),{content:[{type:"text",text:`Wrote ${s.length} bytes to ${i}`}]}}catch(a){return o(a instanceof Error?a.message:String(a))}}),t}var gS=new Set(["localhost","127.0.0.1","::1"]),Su=5;function St(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(!gS.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function hS(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function vu(e,t){let r=hS(e),n={...t,redirect:"manual"};for(let o=0;;o++){let i=await fetch(r,n);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(o>=Su)throw new Error(`too many redirects (>${Su}) \u2014 refusing to follow`);r=a,n={...t,redirect:"manual"}}}async function Io(e){if(e.type==="url"){let o=St(e.url),i=new mS(o,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:vu});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let o=Ke().env,i=new pS({command:e.command,args:e.args,env:{...dS(),...o.PATH!==void 0?{PATH:o.PATH}:{},...o.HOME!==void 0?{HOME:o.HOME}:{},...e.env}});return{transport:i,close:()=>i.close()}}let[t,r]=fS.createLinkedPair(),n=hu(e);return await n.connect(r),{transport:t,close:async()=>{await n.close(),await t.close()}}}async function ko(e){let t=await Io(e),r=new uS({name:"gaia-bridge-test",version:"0.1.0"});try{await r.connect(t.transport);let{tools:n}=await r.listTools();return n.map(o=>o.name)}finally{try{await r.close(),await t.close()}catch{}}}function Cs(){return Ke().stateDir}function As(){return Rs(Cs(),"credentials.json")}function bu(){return Rs(Cs(),"config.json")}function Eu(){let e=Cs();Ro(e)||SS(e,{recursive:!0,mode:448})}function Ye(){let e=As();if(!Ro(e))return null;try{return JSON.parse(wu(e,"utf-8"))}catch{return null}}function an(e){Eu(),ks(As(),JSON.stringify(e,null,2),{mode:384})}function cn(){let e=As();Ro(e)&&ks(e,"{}",{mode:384})}function ee(){let e=bu();if(!Ro(e))return{servers:[]};try{return{servers:JSON.parse(wu(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function xu(e){Eu(),ks(bu(),JSON.stringify(e,null,2),{mode:384})}function Co(e){e.type==="url"&&St(e.url);let t=ee(),r=t.servers.findIndex(n=>n.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),xu(t)}function ln(e){let t=ee(),r=t.servers.length;return t.servers=t.servers.filter(n=>n.key!==e),xu(t),t.servers.length<r}function Ps(e){return e==="~"?yu():e.startsWith("~/")?Rs(yu(),e.slice(2)):e}function Ts(e,t){return{type:"filesystem",key:Ut,name:"Local Files",allow:e,allowWrite:t}}function un(e){if(e)return e.replace(/\/$/,"");let t=Ye();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??hs).replace(/\/$/,"")}import{hostname as wS,platform as bS}from"node:os";var Iu="x-request-id";function vS(e){if(!e||typeof e!="object")return;let{message:t,code:r}=e;if(!(typeof t!="string"&&typeof r!="string"))return e}var $e=class e extends Error{status;envelope;body;requestId;constructor(t,r,n={}){super(t,n.cause===void 0?void 0:{cause:n.cause}),this.name="ApiError",this.status=r,this.envelope=n.envelope,this.body=n.body??"",this.requestId=n.requestId}get code(){let t=this.envelope?.code;return typeof t=="string"?t:void 0}static fromBody(t,r,n={}){let o=vS(r),i=o?.message??n.fallbackMessage??`API request failed: ${t}`;return new e(i,t,{envelope:o,body:typeof r=="string"?r:JSON.stringify(r??""),requestId:n.requestId,cause:n.cause})}};async function ku(e){if(!e.ok){let t=await e.text(),r=t;try{r=JSON.parse(t)}catch{}throw $e.fromBody(e.status,r,{fallbackMessage:`${e.status} ${e.statusText}`,requestId:e.headers.get(Iu)??void 0})}return await e.json()}async function Ao(e,t,r,n){let o=await fetch(`${e}/api/v1${t}`,{method:"POST",headers:{"content-type":"application/json",...n?{authorization:`Bearer ${n}`}:{}},body:JSON.stringify(r)});return ku(o)}async function yS(e,t,r){let n=await fetch(`${e}/api/v1${t}`,{method:"DELETE",headers:{authorization:`Bearer ${r}`}});return ku(n)}function _s(e,t,r,n){return Ao(e,"/device/pair/start",{name:t,platform:r,daemon_version:n})}function Ds(e,t){return Ao(e,"/device/pair/poll",{device_code:t})}function Os(e,t){return Ao(e,"/device/token",{refresh_token:t})}function $s(e,t,r,n,o){return Ao(e,"/device/servers",{server_key:r,display_name:n,kind:o},t)}function Ru(e,t,r){return yS(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function ES(e){await new Promise(t=>setTimeout(t,e))}function Ls(){return!!Ye()?.refreshToken}async function Cu(e,t){let r=un(t.api),n=t.name||wS(),o=await _s(r,n,bS(),t.daemonVersion);e.onPrompt(o.verification_url,o.user_code),e.onStatus?.("Waiting for approval\u2026");let i=Date.now()+o.expires_in*1e3;for(;Date.now()<i;){await ES(o.interval*1e3);let s;try{s=await Ds(r,o.device_code)}catch(a){Q().error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(s.status==="approved"&&s.device_id&&s.refresh_token){an({apiUrl:r,deviceId:s.device_id,refreshToken:s.refresh_token}),e.onStatus?.(`
78
+ `);sn.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(Su()).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 pe(()=>fu(e,t))});sn.command("list").alias("ls").description("Show the enabled bots and whether each is running").action(async()=>{await pe(hu)});sn.command("remove").alias("rm").description("Stop a bot and delete its saved credentials").addArgument(Su()).action(async e=>{await pe(()=>gu(e))});import{Command as wv}from"commander";import{existsSync as To,mkdirSync as $S,readFileSync as Au,writeFileSync as As}from"node:fs";import{homedir as ku}from"node:os";import{join as Ps}from"node:path";import{sep as mS}from"node:path";var V={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"},ys="https://api.heygaia.io",jt="filesystem",Io=mS,ws=500,bs=6e4,Es=5e3,xs=1e6,Is=5e6,Ro=9e4,Co=1e6;import{homedir as fS}from"node:os";import{join as gS}from"node:path";var hS={info:e=>console.error(e),error:e=>console.error(e)},Rs={},SS=null;function Z(){return SS??hS}function Ke(){return{stateDir:Rs.stateDir??gS(fS(),".gaia","bridge"),env:Rs.env??process.env,shell:Rs.shell??process.env.SHELL??"/bin/sh"}}import{Client as kS}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as AS,StdioClientTransport as PS}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as TS}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as _S}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as vS,readdir as bu,readFile as vu,realpath as yS,stat as wS,writeFile as bS}from"node:fs/promises";import{dirname as yu,extname as ES,join as Eu,resolve as xS,sep as Cs}from"node:path";import{McpServer as IS}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as pr}from"zod";var RS={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},mr=class extends Error{};async function ks(e){try{return await yS(e)}catch{return null}}async function CS(e){try{return(await vS(e)).isSymbolicLink()}catch{return!1}}function wu(e,t){return t===Cs?e.startsWith(Cs):e===t||e.startsWith(t+Cs)}async function ko(e,t,r){let n=xS(e),o=await ks(n);if(o){if(t.some(s=>wu(o,s)))return o;throw new mr(`Path is outside your approved folders: ${e}`)}if(r)throw new mr(`No such file or directory: ${e}`);let i=await ks(yu(n));if(!i||!t.some(s=>wu(i,s)))throw new mr(`Path is outside your approved folders: ${e}`);if(await CS(n))throw new mr(`Refusing to write through a symlink: ${e}`);return Eu(i,n.slice(yu(n).length+1))}async function xu(e,t,r,n){if(n.length>=r)return;let o;try{o=await bu(e,{withFileTypes:!0})}catch{return}for(let i of o){if(n.length>=r)return;let s=Eu(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&n.push(s),i.isDirectory()&&!i.isSymbolicLink()&&await xu(s,t,r,n)}}function Iu(e){let t=new IS({name:"gaia-filesystem",version:"0.1.0"}),r=null,n=()=>(r||(r=Promise.all(e.allow.map(ks)).then(i=>i.filter(s=>s!==null))),r),o=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:pr.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let s=await ko(i,await n(),!0);return{content:[{type:"text",text:(await bu(s,{withFileTypes:!0})).map(l=>`${l.isDirectory()?"dir ":"file"} ${l.name}`).join(`
79
+ `)||"(empty)"}]}}catch(s){return o(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:pr.string().describe("Absolute path to a file")}},async({path:i})=>{try{let s=await ko(i,await n(),!0),a=await wS(s);if(!a.isFile())return o(`Not a file: ${i}`);let c=RS[ES(s).toLowerCase()];if(c){if(a.size>Is)return o(`Image is too large to read (${a.size} bytes).`);let d=await vu(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>xs?o(`File is too large to read (${a.size} bytes).`):{content:[{type:"text",text:await vu(s,"utf-8")}]}}catch(s){return o(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:pr.string().describe("Absolute path to the directory to search under"),query:pr.string().describe("Substring to match against names")}},async({path:i,query:s})=>{try{let a=await ko(i,await n(),!0),c=[];return await xu(a,s,200,c),{content:[{type:"text",text:c.join(`
80
+ `)||"(no matches)"}]}}catch(a){return o(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:pr.string().describe("Absolute path to the file to write"),content:pr.string().describe("Text content to write")}},async({path:i,content:s})=>{try{let a=await ko(i,await n(),!1);return await bS(a,s,"utf-8"),{content:[{type:"text",text:`Wrote ${s.length} bytes to ${i}`}]}}catch(a){return o(a instanceof Error?a.message:String(a))}}),t}var DS=new Set(["localhost","127.0.0.1","::1"]),Ru=5;function vt(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(!DS.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function OS(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function Cu(e,t){let r=OS(e),n={...t,redirect:"manual"};for(let o=0;;o++){let i=await fetch(r,n);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(o>=Ru)throw new Error(`too many redirects (>${Ru}) \u2014 refusing to follow`);r=a,n={...t,redirect:"manual"}}}async function Ao(e){if(e.type==="url"){let o=vt(e.url),i=new TS(o,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:Cu});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let o=Ke().env,i=new PS({command:e.command,args:e.args,env:{...AS(),...o.PATH!==void 0?{PATH:o.PATH}:{},...o.HOME!==void 0?{HOME:o.HOME}:{},...e.env}});return{transport:i,close:()=>i.close()}}let[t,r]=_S.createLinkedPair(),n=Iu(e);return await n.connect(r),{transport:t,close:async()=>{await n.close(),await t.close()}}}async function Po(e){let t=await Ao(e),r=new kS({name:"gaia-bridge-test",version:"0.1.0"});try{await r.connect(t.transport);let{tools:n}=await r.listTools();return n.map(o=>o.name)}finally{try{await r.close(),await t.close()}catch{}}}function Ts(){return Ke().stateDir}function _s(){return Ps(Ts(),"credentials.json")}function Pu(){return Ps(Ts(),"config.json")}function Tu(){let e=Ts();To(e)||$S(e,{recursive:!0,mode:448})}function Ye(){let e=_s();if(!To(e))return null;try{return JSON.parse(Au(e,"utf-8"))}catch{return null}}function an(e){Tu(),As(_s(),JSON.stringify(e,null,2),{mode:384})}function cn(){let e=_s();To(e)&&As(e,"{}",{mode:384})}function re(){let e=Pu();if(!To(e))return{servers:[]};try{return{servers:JSON.parse(Au(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function _u(e){Tu(),As(Pu(),JSON.stringify(e,null,2),{mode:384})}function _o(e){e.type==="url"&&vt(e.url);let t=re(),r=t.servers.findIndex(n=>n.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),_u(t)}function ln(e){let t=re(),r=t.servers.length;return t.servers=t.servers.filter(n=>n.key!==e),_u(t),t.servers.length<r}function Ds(e){return e==="~"?ku():e.startsWith("~/")?Ps(ku(),e.slice(2)):e}function Os(e,t){return{type:"filesystem",key:jt,name:"Local Files",allow:e,allowWrite:t}}function un(e){if(e)return e.replace(/\/$/,"");let t=Ye();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??ys).replace(/\/$/,"")}import{hostname as NS,platform as FS}from"node:os";var Du="x-request-id";function LS(e){if(!e||typeof e!="object")return;let{message:t,code:r}=e;if(!(typeof t!="string"&&typeof r!="string"))return e}var Ne=class e extends Error{status;envelope;body;requestId;constructor(t,r,n={}){super(t,n.cause===void 0?void 0:{cause:n.cause}),this.name="ApiError",this.status=r,this.envelope=n.envelope,this.body=n.body??"",this.requestId=n.requestId}get code(){let t=this.envelope?.code;return typeof t=="string"?t:void 0}static fromBody(t,r,n={}){let o=LS(r),i=o?.message??n.fallbackMessage??`API request failed: ${t}`;return new e(i,t,{envelope:o,body:typeof r=="string"?r:JSON.stringify(r??""),requestId:n.requestId,cause:n.cause})}};async function Ou(e){if(!e.ok){let t=await e.text(),r=t;try{r=JSON.parse(t)}catch{}throw Ne.fromBody(e.status,r,{fallbackMessage:`${e.status} ${e.statusText}`,requestId:e.headers.get(Du)??void 0})}return await e.json()}async function Do(e,t,r,n){let o=await fetch(`${e}/api/v1${t}`,{method:"POST",headers:{"content-type":"application/json",...n?{authorization:`Bearer ${n}`}:{}},body:JSON.stringify(r)});return Ou(o)}async function MS(e,t,r){let n=await fetch(`${e}/api/v1${t}`,{method:"DELETE",headers:{authorization:`Bearer ${r}`}});return Ou(n)}function $s(e,t,r,n){return Do(e,"/device/pair/start",{name:t,platform:r,daemon_version:n})}function Ls(e,t){return Do(e,"/device/pair/poll",{device_code:t})}function Ms(e,t){return Do(e,"/device/token",{refresh_token:t})}function Ns(e,t,r,n,o){return Do(e,"/device/servers",{server_key:r,display_name:n,kind:o},t)}function $u(e,t,r){return MS(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function BS(e){await new Promise(t=>setTimeout(t,e))}function Fs(){return!!Ye()?.refreshToken}async function Lu(e,t){let r=un(t.api),n=t.name||NS(),o=await $s(r,n,FS(),t.daemonVersion);e.onPrompt(o.verification_url,o.user_code),e.onStatus?.("Waiting for approval\u2026");let i=Date.now()+o.expires_in*1e3;for(;Date.now()<i;){await BS(o.interval*1e3);let s;try{s=await Ls(r,o.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){an({apiUrl:r,deviceId:s.device_id,refreshToken:s.refresh_token}),e.onStatus?.(`
81
81
  Paired as "${n}".
82
- `);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var xS={onPrompt(e,t){console.info(`
82
+ `);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var GS={onPrompt(e,t){console.info(`
83
83
  To pair this device, open:
84
84
  `),console.info(` ${e}`),console.info(`
85
85
  and enter this code: ${t}
86
- `)},onStatus(e){console.info(e)}};async function IS(){let e=L();if(!(!e||await $(e)!=="selfhost"))return $t("selfhost",A(e))}async function fr(e={}){let t=e.api??(process.env.GAIA_API_URL?void 0:await IS());await Cu(xS,{...e,...t!==void 0?{api:t}:{},daemonVersion:R})}import{spawn as US}from"node:child_process";import{existsSync as Ns,mkdirSync as jS,openSync as qS,readFileSync as HS,unlinkSync as $u,writeFileSync as VS}from"node:fs";import{homedir as WS}from"node:os";import{join as Fs}from"node:path";import{mkdirSync as Au,readFileSync as kS,rmSync as Pu,writeFileSync as RS}from"node:fs";import{dirname as CS,join as Tu}from"node:path";var AS=3e4,PS=3e4,TS=50,_S=e=>new Promise(t=>setTimeout(t,e));function _u(){return Tu(Ke().stateDir,"credentials.lock")}function DS(){return Tu(_u(),"stamp")}async function OS(e){let t=_u(),r=DS();Au(CS(t),{recursive:!0});let n=Date.now()+PS;for(;;){try{Au(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let o=null;try{let i=Number(kS(r,"utf-8"));o=Number.isFinite(i)?Date.now()-i:Number.POSITIVE_INFINITY}catch(i){i?.code!=="ENOENT"&&(o=Number.POSITIVE_INFINITY)}if(o===null||o<AS){if(Date.now()>n)throw new Error("another gaia process is rotating the device credential \u2014 try again");await _S(TS);continue}try{Pu(t,{recursive:!0,force:!0})}catch{}}try{return RS(r,String(Date.now()),{mode:384}),await e()}finally{try{Pu(t,{recursive:!0,force:!0})}catch{}}}async function dn(){return OS(async()=>{let e=Ye();if(!e?.refreshToken)throw new $e("not paired \u2014 run: gaia bridge login",401);let t=await Os(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return an(r),{creds:r,accessToken:t.access_token}})}async function gr(){let e=ee().servers;if(e.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");let{creds:t,accessToken:r}=await dn();await Promise.all(e.map(n=>$s(t.apiUrl,r,n.key,n.name,n.type)))}async function Ms(e){let t=ln(e);try{let{creds:r,accessToken:n}=await dn();await Ru(r.apiUrl,n,e)}catch(r){Q().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 GS}from"node:crypto";import Ou from"ws";import{spawn as $S}from"node:child_process";import{appendFileSync as LS,mkdirSync as MS}from"node:fs";import{homedir as NS}from"node:os";import{join as FS}from"node:path";function BS(e,t){try{let r=Ke().stateDir;MS(r,{recursive:!0,mode:448});let n=t?` (cwd: ${t})`:"";LS(FS(r,"exec-audit.log"),`${new Date().toISOString()}${n} $ ${e}
87
- `)}catch{}}async function Du(e,t,r){BS(e,t);let n=$S(Ke().shell,["-c",e],{cwd:t||NS(),env:Ke().env,stdio:["ignore","pipe","pipe"]}),o=0,i=!1,s=c=>l=>{if(i)return;let u=Eo-o,p=l.length>u?l.subarray(0,u):l;p.length>0&&(o+=p.length,r[c](p.toString("utf-8"))),o>=Eo&&(i=!0,r.stderr(`
86
+ `)},onStatus(e){console.info(e)}};async function US(){let e=L();if(!(!e||await $(e)!=="selfhost"))return Lt("selfhost",k(e))}async function fr(e={}){let t=e.api??(process.env.GAIA_API_URL?void 0:await US());await Lu(GS,{...e,...t!==void 0?{api:t}:{},daemonVersion:A})}import{spawn as ov}from"node:child_process";import{existsSync as Gs,mkdirSync as iv,openSync as sv,readFileSync as av,unlinkSync as ju,writeFileSync as cv}from"node:fs";import{homedir as lv}from"node:os";import{join as Us}from"node:path";import{mkdirSync as Mu,readFileSync as jS,rmSync as Nu,writeFileSync as qS}from"node:fs";import{dirname as HS,join as Fu}from"node:path";var VS=3e4,WS=3e4,KS=50,YS=e=>new Promise(t=>setTimeout(t,e));function Bu(){return Fu(Ke().stateDir,"credentials.lock")}function zS(){return Fu(Bu(),"stamp")}async function XS(e){let t=Bu(),r=zS();Mu(HS(t),{recursive:!0});let n=Date.now()+WS;for(;;){try{Mu(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let o=null;try{let i=Number(jS(r,"utf-8"));o=Number.isFinite(i)?Date.now()-i:Number.POSITIVE_INFINITY}catch(i){i?.code!=="ENOENT"&&(o=Number.POSITIVE_INFINITY)}if(o===null||o<VS){if(Date.now()>n)throw new Error("another gaia process is rotating the device credential \u2014 try again");await YS(KS);continue}try{Nu(t,{recursive:!0,force:!0})}catch{}}try{return qS(r,String(Date.now()),{mode:384}),await e()}finally{try{Nu(t,{recursive:!0,force:!0})}catch{}}}async function dn(){return XS(async()=>{let e=Ye();if(!e?.refreshToken)throw new Ne("not paired \u2014 run: gaia bridge login",401);let t=await Ms(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return an(r),{creds:r,accessToken:t.access_token}})}async function gr(){let e=re().servers;if(e.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");let{creds:t,accessToken:r}=await dn();await Promise.all(e.map(n=>Ns(t.apiUrl,r,n.key,n.name,n.type)))}async function Bs(e){let t=ln(e);try{let{creds:r,accessToken:n}=await dn();await $u(r.apiUrl,n,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 nv}from"node:crypto";import Uu from"ws";import{spawn as JS}from"node:child_process";import{appendFileSync as QS,mkdirSync as ZS}from"node:fs";import{homedir as ev}from"node:os";import{join as tv}from"node:path";function rv(e,t){try{let r=Ke().stateDir;ZS(r,{recursive:!0,mode:448});let n=t?` (cwd: ${t})`:"";QS(tv(r,"exec-audit.log"),`${new Date().toISOString()}${n} $ ${e}
87
+ `)}catch{}}async function Gu(e,t,r){rv(e,t);let n=JS(Ke().shell,["-c",e],{cwd:t||ev(),env:Ke().env,stdio:["ignore","pipe","pipe"]}),o=0,i=!1,s=c=>l=>{if(i)return;let d=Co-o,p=l.length>d?l.subarray(0,d):l;p.length>0&&(o+=p.length,r[c](p.toString("utf-8"))),o>=Co&&(i=!0,r.stderr(`
88
88
  [gaia bridge] output truncated \u2014 cap reached
89
89
  `),n.kill("SIGKILL"))};n.stdout.on("data",s("stdout")),n.stderr.on("data",s("stderr"));let a=setTimeout(()=>{r.stderr(`
90
- [gaia bridge] killed \u2014 exceeded ${bo/1e3}s timeout
91
- `),n.kill("SIGKILL")},bo);await new Promise(c=>{n.on("error",l=>{clearTimeout(a),r.stderr(`[gaia bridge] could not start command: ${l.message}
92
- `),r.exit(127),c()}),n.on("close",l=>{clearTimeout(a),r.exit(l??-1),c()})})}var pn=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=Ss;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof $e&&t.status===401?(Q().error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):Q().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 dn();this.creds=t;let n=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,o=new Ou(n,{headers:{authorization:`Bearer ${r}`}});this.ws=o,await new Promise((i,s)=>{let a=!1,c=!1,l=u=>{c||(c=!0,u())};o.on("open",()=>{a=!0,this.reconnectDelay=ys;let u=ee().servers.map(p=>p.key);this.send({t:H.HELLO,servers:u}),Q().info(`[gaia bridge] connected \u2014 exposing: ${u.join(", ")||"(nothing configured)"}`)}),o.on("message",u=>{this.guardRejection(this.onFrame(u.toString()),"frame handler error")}),o.on("close",()=>{this.guardRejection(this.closeAllSessions(),"session cleanup error"),this.ws=null,l(()=>a?i():s(new Error("socket closed before open")))}),o.on("error",u=>{a||l(()=>s(u))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case H.PING:this.send({t:H.PONG});return;case H.MCP_OPEN:await this.openSession(r);return;case H.MCP_MSG:await this.forwardToServer(r);return;case H.MCP_CLOSE:await this.closeSession(r.sid);return;case H.EXEC_OPEN:await this.runExec(r);return;case H.REVOKE:Q().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case H.SERVER_REMOVE:r.key&&ln(r.key)&&Q().info(`[gaia bridge] removed server '${r.key}' (deleted in GAIA).`);return;default:return}}async openSession(t){let r=t.sid,n=t.server,o=t.pod;if(!r||!n)return;let i=ee().servers.find(a=>a.key===n);if(!i){this.send({t:H.MCP_ERROR,sid:r,pod:o,error:`Unknown server '${n}'`});return}let s=Date.now();Q().info(`[gaia bridge] opening MCP session for '${n}'\u2026`);try{let a=await Io(i);a.transport.onmessage=c=>{this.send({t:H.MCP_MSG,sid:r,pod:o,data:JSON.stringify(c)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:H.MCP_ERROR,sid:r,pod:o,error:`Local server '${n}' exited`}),this.guardRejection(this.closeSession(r),"session close error")},await a.transport.start(),this.sessions.set(r,a),this.send({t:H.MCP_OPENED,sid:r,pod:o}),Q().info(`[gaia bridge] MCP session for '${n}' ready in ${Date.now()-s}ms`)}catch(a){let c=a instanceof Error?a.message:String(a);Q().error(`[gaia bridge] MCP session for '${n}' failed after ${Date.now()-s}ms: ${c}`),this.send({t:H.MCP_ERROR,sid:r,pod:o,error:c})}}async forwardToServer(t){let r=t.sid?this.sessions.get(t.sid):void 0;if(!(!r||!t.data))try{let n=JSON.parse(t.data);await r.transport.send(n)}catch(n){Q().error(`[gaia bridge] forward error: ${n instanceof Error?n.message:n}`)}}async runExec(t){let r=t.sid,n=t.pod,o=t.command;!r||!o||await Du(o,t.cwd,{stdout:i=>this.send({t:H.EXEC_STDOUT,sid:r,pod:n,data:i}),stderr:i=>this.send({t:H.EXEC_STDERR,sid:r,pod:n,data:i}),exit:i=>this.send({t:H.EXEC_EXIT,sid:r,pod:n,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===Ou.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(n=>{Q().error(`[gaia bridge] ${r}: ${n instanceof Error?n.message:n}`)})}async backoff(){let t=GS(this.reconnectDelay);Q().info(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,vs)}};var Bs=Fs(WS(),".gaia","bridge"),jt=Fs(Bs,"daemon.pid"),Lu=Fs(Bs,"daemon.log");function Gs(){if(!Ns(jt))return null;let e=Number(HS(jt,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function Mu(){let e=Gs();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 Nu(){let e=Gs();if(!e){Ns(jt)&&$u(jt),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}Ns(jt)&&$u(jt),console.info(`Stopped the bridge tunnel (pid ${e}).`)}async function Po(){let e=Gs();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=ee().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 gr()}catch(s){if(s instanceof $e&&s.status===401)console.error(`[gaia bridge] this device is no longer authorized (revoked or unpaired). Let's re-pair.
93
- `),cn(),await fr(),await gr();else throw s}let r=process.argv[1];if(!r)throw new Error("cannot locate the gaia CLI entrypoint to start the daemon");jS(Bs,{recursive:!0,mode:448});let n=qS(Lu,"a"),o={detached:!0,stdio:["ignore",n,n]},i=US(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],o);i.unref(),VS(jt,String(i.pid??""),{mode:384}),console.info(`
90
+ [gaia bridge] killed \u2014 exceeded ${Ro/1e3}s timeout
91
+ `),n.kill("SIGKILL")},Ro);await new Promise(c=>{n.on("error",l=>{clearTimeout(a),r.stderr(`[gaia bridge] could not start command: ${l.message}
92
+ `),r.exit(127),c()}),n.on("close",l=>{clearTimeout(a),r.exit(l??-1),c()})})}var pn=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=ws;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof Ne&&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 dn();this.creds=t;let n=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,o=new Uu(n,{headers:{authorization:`Bearer ${r}`}});this.ws=o,await new Promise((i,s)=>{let a=!1,c=!1,l=d=>{c||(c=!0,d())};o.on("open",()=>{a=!0,this.reconnectDelay=Es;let d=re().servers.map(p=>p.key);this.send({t:V.HELLO,servers:d}),Z().info(`[gaia bridge] connected \u2014 exposing: ${d.join(", ")||"(nothing configured)"}`)}),o.on("message",d=>{this.guardRejection(this.onFrame(d.toString()),"frame handler error")}),o.on("close",()=>{this.guardRejection(this.closeAllSessions(),"session cleanup error"),this.ws=null,l(()=>a?i():s(new Error("socket closed before open")))}),o.on("error",d=>{a||l(()=>s(d))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case V.PING:this.send({t:V.PONG});return;case V.MCP_OPEN:await this.openSession(r);return;case V.MCP_MSG:await this.forwardToServer(r);return;case V.MCP_CLOSE:await this.closeSession(r.sid);return;case V.EXEC_OPEN:await this.runExec(r);return;case V.REVOKE:Z().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case V.SERVER_REMOVE:r.key&&ln(r.key)&&Z().info(`[gaia bridge] removed server '${r.key}' (deleted in GAIA).`);return;default:return}}async openSession(t){let r=t.sid,n=t.server,o=t.pod;if(!r||!n)return;let i=re().servers.find(a=>a.key===n);if(!i){this.send({t:V.MCP_ERROR,sid:r,pod:o,error:`Unknown server '${n}'`});return}let s=Date.now();Z().info(`[gaia bridge] opening MCP session for '${n}'\u2026`);try{let a=await Ao(i);a.transport.onmessage=c=>{this.send({t:V.MCP_MSG,sid:r,pod:o,data:JSON.stringify(c)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:V.MCP_ERROR,sid:r,pod:o,error:`Local server '${n}' exited`}),this.guardRejection(this.closeSession(r),"session close error")},await a.transport.start(),this.sessions.set(r,a),this.send({t:V.MCP_OPENED,sid:r,pod:o}),Z().info(`[gaia bridge] MCP session for '${n}' ready in ${Date.now()-s}ms`)}catch(a){let c=a instanceof Error?a.message:String(a);Z().error(`[gaia bridge] MCP session for '${n}' failed after ${Date.now()-s}ms: ${c}`),this.send({t:V.MCP_ERROR,sid:r,pod:o,error:c})}}async forwardToServer(t){let r=t.sid?this.sessions.get(t.sid):void 0;if(!(!r||!t.data))try{let n=JSON.parse(t.data);await r.transport.send(n)}catch(n){Z().error(`[gaia bridge] forward error: ${n instanceof Error?n.message:n}`)}}async runExec(t){let r=t.sid,n=t.pod,o=t.command;!r||!o||await Gu(o,t.cwd,{stdout:i=>this.send({t:V.EXEC_STDOUT,sid:r,pod:n,data:i}),stderr:i=>this.send({t:V.EXEC_STDERR,sid:r,pod:n,data:i}),exit:i=>this.send({t:V.EXEC_EXIT,sid:r,pod:n,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===Uu.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(n=>{Z().error(`[gaia bridge] ${r}: ${n instanceof Error?n.message:n}`)})}async backoff(){let t=nv(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,bs)}};var js=Us(lv(),".gaia","bridge"),qt=Us(js,"daemon.pid"),qu=Us(js,"daemon.log");function qs(){if(!Gs(qt))return null;let e=Number(av(qt,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function Hu(){let e=qs();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 Vu(){let e=qs();if(!e){Gs(qt)&&ju(qt),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}Gs(qt)&&ju(qt),console.info(`Stopped the bridge tunnel (pid ${e}).`)}async function Oo(){let e=qs();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=re().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 gr()}catch(s){if(s instanceof Ne&&s.status===401)console.error(`[gaia bridge] this device is no longer authorized (revoked or unpaired). Let's re-pair.
93
+ `),cn(),await fr(),await gr();else throw s}let r=process.argv[1];if(!r)throw new Error("cannot locate the gaia CLI entrypoint to start the daemon");iv(js,{recursive:!0,mode:448});let n=sv(qu,"a"),o={detached:!0,stdio:["ignore",n,n]},i=ov(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],o);i.unref(),cv(qt,String(i.pid??""),{mode:384}),console.info(`
94
94
  Bridge tunnel started in the background (pid ${i.pid}).
95
- Logs: ${Lu}
96
- Stop: gaia bridge down`)}async function Fu(){let e=Ye();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new pn(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 ju}from"node:path";import{resolve as KS}from"node:path";function Us(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function js(e){let t=[],r="",n=null;for(let s of e.trim())n?s===n?n=null:r+=s:s==='"'||s==="'"?n=s:/\s/.test(s)?r&&(t.push(r),r=""):r+=s;r&&t.push(r);let[o,...i]=t;if(!o)throw new Error("Empty command");return{command:o,args:i}}function Bu(e,t,r){let n={};for(let o of e??[]){let i=o.indexOf(t);if(i<=0)throw new Error(`invalid ${r} '${o}', expected KEY${t}VALUE`);n[o.slice(0,i).trim()]=o.slice(i+1)}return n}function Gu(e){let t=Us(e??"");if(!e||!t||t===Ut)throw new Error("--name is required and must contain letters or digits");return t}function Uu(e){if(e.type==="stdio"){if(!e.command)throw new Error("--command is required for --type stdio");let{command:t,args:r}=js(e.command);return{type:"stdio",key:Gu(e.name),name:e.name,command:t,args:r,env:Bu(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");St(e.url);let t=Bu(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:Gu(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(wo)?[wo]:t.map(n=>KS(Ps(n)));return Ts(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}function YS(e,t){let n=[...t].reverse().filter(o=>!o.startsWith("-"))[0]??e;return ju(n).replace(/@[^@]*$/,"")}function zS(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function qu(e){for(;;){let t=await gt("Name for this server",e),r=Us(t);if(!t||!r||r===Ut){console.info("Pick a different name.");continue}if(!(ee().servers.some(n=>n.key===r)&&!await ht(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function XS(e,t){if(ju(e)!=="docker")return[];let r=[];for(let n=0;n<t.length;n++){let o=t[n];if(o!==void 0)if(o==="-e"||o==="--env"){let i=t[n+1];i&&!i.includes("=")&&r.push(i)}else o.startsWith("-e")&&o.length>2&&!o.includes("=")&&r.push(o.slice(2))}return[...new Set(r)]}async function qs(e){let t=process.env[e];if(t!==void 0&&t!==""&&await ht(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await vo(` 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 Hu(e,t){let r={};for(let o of XS(e,t))console.info(`
97
- The command needs ${o}.`),r[o]=await qs(o);let n=Object.keys(r).length?"Any other environment variables to add?":"Does the server need environment variables (API keys, tokens\u2026)?";if(!await ht(n,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let o=(await gt(" Variable name")).trim();if(!o)break;if(o in r){console.info(" Already added.");continue}r[o]=await qs(o)}return r}async function JS(){console.info(`
98
- Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await gt("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=js(e),n=await Hu(t,r),{name:o,key:i}=await qu(YS(t,r));return{type:"stdio",key:i,name:o,command:t,args:r,env:n}}async function QS(){let e={};if(!await ht("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 gt(" Header name")).trim();if(!t)break;if(t in e){console.info(" Already added.");continue}e[t]=await qs(t)}return e}async function ZS(){let e=await gt("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");St(e);let t=await QS();if(Object.keys(t).length>0&&new URL(e).protocol==="http:"&&(console.info(`
99
- Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await ht("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:n}=await qu(zS(e));return{type:"url",key:n,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function ev(e){for(;;){console.info(`
100
- Testing the connection (this may download/start the server)\u2026`);try{let t=await ko(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 n=r[await yo("What now?",r)];if(n==="Re-enter environment variables"&&e.type==="stdio")e.env=await Hu(e.command,e.args);else{if(n==="Save anyway (fix it later)")return!0;if(n==="Abort")return!1}}}}async function tv(e){let t=Uu(e),r;try{r=await ko(t)}catch(n){throw new Error(`Could not start '${t.key}': ${n instanceof Error?n.message:n}`)}Co(t),await gr(),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 Vu(e={}){if(!Ls()){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 fr()}if(e.type){await tv(e);return}let r=await yo("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 JS():await ZS();if(!await ev(r))throw new Error("aborted");Co(r),console.info(`
101
- Saved '${r.key}'.`);try{await gr(),console.info("Registered with GAIA.")}catch(n){console.error(`Could not register with GAIA (will retry on \`gaia bridge up\`): ${n instanceof Error?n.message:n}`)}await ht("Keep this device connected in the background now?")?await Po():console.info("Run `gaia bridge up` whenever you're ready.")}function rv(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 Wu(e){if(e){let o=await Ms(e);console.info(o?`Removed '${e}' from this device and GAIA.`:`No server '${e}'.`);return}let t=ee().servers;if(t.length===0){console.info("No servers configured \u2014 nothing to remove.");return}let r=await yo("Which server do you want to remove?",t.map(rv)),n=t[r];if(n){if(!await ht(`Remove '${n.key}'?`,!1)){console.info("Left it in place.");return}await Ms(n.key),console.info(`Removed '${n.key}'. The tunnel stops serving it right away, and GAIA drops it too.`)}}function ov(){let e=Ye();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${un()})`:"Not paired \u2014 run: gaia bridge login"),console.info(Mu());let t=ee().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
102
- 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 n=Object.keys(r.env);console.info(` [${r.key}] ${r.name}: ${r.command} ${r.args.join(" ")}`),n.length&&console.info(` env: ${n.join(", ")}`)}else{console.info(` [${r.key}] ${r.name}: ${r.url}`);let n=r.headers?Object.keys(r.headers):[];n.length&&console.info(` headers: ${n.join(", ")}`)}}var nt=new nv("bridge").description(U.bridge).addHelpText("after",`
103
- Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);nt.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 ue(()=>Vu(e))});nt.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 ue(async()=>{await fr({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});nt.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await ue(ov)});nt.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 ue(()=>Wu(e))});nt.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 ue(e.serve?Fu:Po)});nt.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await ue(Nu)});nt.command("logout").description("Forget local credentials").action(async()=>{await ue(()=>{cn(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import{Command as cv}from"commander";import*as Ce from"node:fs/promises";import*as Qu from"node:path";import*as Yu from"node:os";import*as zu from"node:path";var iv="https://github.com/theexperiencecompany/gaia/releases/download",To=`cli-v${R}`,Hs="gaia-connect-SHA256SUMS",Ku={"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 Xu(e,t){let r=Ku[`${e}-${t}`];if(r===void 0)throw new Error(`gaia connect is not available for ${e}/${t}. Supported: ${Object.keys(Ku).join(", ")}.`);return r}function Vs(e){return`${iv}/${To}/${e}`}function Ju(e){let t=e==="win32"?".exe":"";return zu.join(Yu.homedir(),".gaia","bin",`gaia-connect-${R}${t}`)}async function sv(e){try{return await Ce.access(e),!0}catch{return!1}}async function Zu(e,t){let r=Ju(e);if(await sv(r))return r;let n=Xu(e,t);console.info(`Downloading gaia-connect (${To})\u2026`);let[o,i]=await Promise.all([ir(Vs(n)),ir(Vs(Hs)).then(a=>a.toString("utf-8"))]);Yn(o,Kn(i,n,`${Hs} on release ${To}`),n),await Ce.mkdir(Qu.dirname(r),{recursive:!0});let s=`${r}.${process.pid}.tmp`;try{await Ce.writeFile(s,o),e!=="win32"&&await Ce.chmod(s,448),await Ce.rename(s,r)}catch(a){throw await Ce.rm(s,{force:!0}),a}return r}import{spawn as av}from"node:child_process";async function ed(e,t){return await new Promise((r,n)=>{let o=av(e,t,{stdio:"inherit",shell:!1}),i=s=>{o.kill(s)};process.on("SIGINT",i),process.on("SIGTERM",i),o.on("error",s=>{process.off("SIGINT",i),process.off("SIGTERM",i),n(s)}),o.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 lv(e){let t=await Zu(process.platform,process.arch);return await ed(t,e)}var td=new cv("connect").description(U.connect).allowUnknownOption().allowExcessArguments().argument("[args...]","flags forwarded to gaia-connect").addHelpText("after",`
95
+ Logs: ${qu}
96
+ Stop: gaia bridge down`)}async function Wu(){let e=Ye();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new pn(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 Xu}from"node:path";import{resolve as uv}from"node:path";function Hs(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function Vs(e){let t=[],r="",n=null;for(let s of e.trim())n?s===n?n=null:r+=s:s==='"'||s==="'"?n=s:/\s/.test(s)?r&&(t.push(r),r=""):r+=s;r&&t.push(r);let[o,...i]=t;if(!o)throw new Error("Empty command");return{command:o,args:i}}function Ku(e,t,r){let n={};for(let o of e??[]){let i=o.indexOf(t);if(i<=0)throw new Error(`invalid ${r} '${o}', expected KEY${t}VALUE`);n[o.slice(0,i).trim()]=o.slice(i+1)}return n}function Yu(e){let t=Hs(e??"");if(!e||!t||t===jt)throw new Error("--name is required and must contain letters or digits");return t}function zu(e){if(e.type==="stdio"){if(!e.command)throw new Error("--command is required for --type stdio");let{command:t,args:r}=Vs(e.command);return{type:"stdio",key:Yu(e.name),name:e.name,command:t,args:r,env:Ku(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");vt(e.url);let t=Ku(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:Yu(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(Io)?[Io]:t.map(n=>uv(Ds(n)));return Os(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}function dv(e,t){let n=[...t].reverse().filter(o=>!o.startsWith("-"))[0]??e;return Xu(n).replace(/@[^@]*$/,"")}function pv(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function Ju(e){for(;;){let t=await ht("Name for this server",e),r=Hs(t);if(!t||!r||r===jt){console.info("Pick a different name.");continue}if(!(re().servers.some(n=>n.key===r)&&!await St(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function mv(e,t){if(Xu(e)!=="docker")return[];let r=[];for(let n=0;n<t.length;n++){let o=t[n];if(o!==void 0)if(o==="-e"||o==="--env"){let i=t[n+1];i&&!i.includes("=")&&r.push(i)}else o.startsWith("-e")&&o.length>2&&!o.includes("=")&&r.push(o.slice(2))}return[...new Set(r)]}async function Ws(e){let t=process.env[e];if(t!==void 0&&t!==""&&await St(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await 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 Qu(e,t){let r={};for(let o of mv(e,t))console.info(`
97
+ The command needs ${o}.`),r[o]=await Ws(o);let n=Object.keys(r).length?"Any other environment variables to add?":"Does the server need environment variables (API keys, tokens\u2026)?";if(!await St(n,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let o=(await ht(" Variable name")).trim();if(!o)break;if(o in r){console.info(" Already added.");continue}r[o]=await Ws(o)}return r}async function fv(){console.info(`
98
+ Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await ht("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=Vs(e),n=await Qu(t,r),{name:o,key:i}=await Ju(dv(t,r));return{type:"stdio",key:i,name:o,command:t,args:r,env:n}}async function gv(){let e={};if(!await St("Does the server need request headers (e.g. Authorization)?",!1))return e;for(console.info("Enter each header's name; leave blank when done.");;){let t=(await ht(" Header name")).trim();if(!t)break;if(t in e){console.info(" Already added.");continue}e[t]=await Ws(t)}return e}async function hv(){let e=await ht("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");vt(e);let t=await gv();if(Object.keys(t).length>0&&new URL(e).protocol==="http:"&&(console.info(`
99
+ Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await St("Send these headers over unencrypted HTTP anyway?",!1)))throw new Error("aborted \u2014 use an https: URL or drop the headers");let{name:r,key:n}=await Ju(pv(e));return{type:"url",key:n,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function Sv(e){for(;;){console.info(`
100
+ 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 n=r[await xo("What now?",r)];if(n==="Re-enter environment variables"&&e.type==="stdio")e.env=await Qu(e.command,e.args);else{if(n==="Save anyway (fix it later)")return!0;if(n==="Abort")return!1}}}}async function vv(e){let t=zu(e),r;try{r=await Po(t)}catch(n){throw new Error(`Could not start '${t.key}': ${n instanceof Error?n.message:n}`)}_o(t),await gr(),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 Zu(e={}){if(!Fs()){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 fr()}if(e.type){await vv(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 fv():await hv();if(!await Sv(r))throw new Error("aborted");_o(r),console.info(`
101
+ Saved '${r.key}'.`);try{await gr(),console.info("Registered with GAIA.")}catch(n){console.error(`Could not register with GAIA (will retry on \`gaia bridge up\`): ${n instanceof Error?n.message:n}`)}await St("Keep this device connected in the background now?")?await Oo():console.info("Run `gaia bridge up` whenever you're ready.")}function yv(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 ed(e){if(e){let o=await Bs(e);console.info(o?`Removed '${e}' from this device and GAIA.`:`No server '${e}'.`);return}let t=re().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(yv)),n=t[r];if(n){if(!await St(`Remove '${n.key}'?`,!1)){console.info("Left it in place.");return}await Bs(n.key),console.info(`Removed '${n.key}'. The tunnel stops serving it right away, and GAIA drops it too.`)}}function bv(){let e=Ye();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${un()})`:"Not paired \u2014 run: gaia bridge login"),console.info(Hu());let t=re().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
102
+ 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 n=Object.keys(r.env);console.info(` [${r.key}] ${r.name}: ${r.command} ${r.args.join(" ")}`),n.length&&console.info(` env: ${n.join(", ")}`)}else{console.info(` [${r.key}] ${r.name}: ${r.url}`);let n=r.headers?Object.keys(r.headers):[];n.length&&console.info(` headers: ${n.join(", ")}`)}}var ot=new wv("bridge").description(j.bridge).addHelpText("after",`
103
+ Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);ot.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 pe(()=>Zu(e))});ot.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 pe(async()=>{await fr({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});ot.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await pe(bv)});ot.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 pe(()=>ed(e))});ot.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 pe(e.serve?Wu:Oo)});ot.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await pe(Vu)});ot.command("logout").description("Forget local credentials").action(async()=>{await pe(()=>{cn(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import{Command as Rv}from"commander";import*as Pe from"node:fs/promises";import*as sd from"node:path";import*as rd from"node:os";import*as nd from"node:path";var Ev="https://github.com/theexperiencecompany/gaia/releases/download",$o=`cli-v${A}`,Ks="gaia-connect-SHA256SUMS",td={"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 od(e,t){let r=td[`${e}-${t}`];if(r===void 0)throw new Error(`gaia connect is not available for ${e}/${t}. Supported: ${Object.keys(td).join(", ")}.`);return r}function Ys(e){return`${Ev}/${$o}/${e}`}function id(e){let t=e==="win32"?".exe":"";return nd.join(rd.homedir(),".gaia","bin",`gaia-connect-${A}${t}`)}async function xv(e){try{return await Pe.access(e),!0}catch{return!1}}async function ad(e,t){let r=id(e);if(await xv(r))return r;let n=od(e,t);console.info(`Downloading gaia-connect (${$o})\u2026`);let[o,i]=await Promise.all([ir(Ys(n)),ir(Ys(Ks)).then(a=>a.toString("utf-8"))]);Qn(o,Jn(i,n,`${Ks} on release ${$o}`),n),await Pe.mkdir(sd.dirname(r),{recursive:!0});let s=`${r}.${process.pid}.tmp`;try{await Pe.writeFile(s,o),e!=="win32"&&await Pe.chmod(s,448),await Pe.rename(s,r)}catch(a){throw await Pe.rm(s,{force:!0}),a}return r}import{spawn as Iv}from"node:child_process";async function cd(e,t){return await new Promise((r,n)=>{let o=Iv(e,t,{stdio:"inherit",shell:!1}),i=s=>{o.kill(s)};process.on("SIGINT",i),process.on("SIGTERM",i),o.on("error",s=>{process.off("SIGINT",i),process.off("SIGTERM",i),n(s)}),o.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 Cv(e){let t=await ad(process.platform,process.arch);return await cd(t,e)}var ld=new Rv("connect").description(j.connect).allowUnknownOption().allowExcessArguments().argument("[args...]","flags forwarded to gaia-connect").addHelpText("after",`
104
104
  Get an import code from GAIA -> Settings -> Browser -> Import, then run:
105
105
  npx @heygaia/cli connect --token <code>
106
106
 
@@ -112,13 +112,13 @@ Flags forwarded to gaia-connect:
112
112
  --sites <domains> comma-separated domains to sync (default: all)
113
113
  --json robot mode: no TUI, structured JSON on stdout
114
114
  --list with --json: list browsers, or sessions with --browser
115
- `).action(e=>ue(async()=>process.exit(await lv(e))));import*as Do from"fs";import*as rd from"path";import{spawn as uv}from"child_process";async function hr(e,t,r,n,o,i=!1){await _o([{cmd:e,args:t,cwd:r,env:n,onSpawn:o,detached:i}])}async function _o(e){e.length!==0&&await new Promise((t,r)=>{let n=e.map(p=>uv(p.cmd,p.args,{cwd:p.cwd,stdio:"inherit",shell:!1,detached:p.detached??!1,env:p.env?{...process.env,...p.env}:process.env}));n.forEach((p,m)=>{e[m]?.onSpawn?.(p.pid)});let o=!1,i=0,s=!1,a,c=()=>{process.off("SIGINT",u),process.off("SIGTERM",u)},l=()=>{if(!s){s=!0;for(let[p,m]of n.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 n.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)}},u=()=>{l()};process.on("SIGINT",u),process.on("SIGTERM",u),n.forEach((p,m)=>{let g=e[m];p.on("error",v=>{o||(o=!0,c(),l(),r(v))}),p.on("close",(v,E)=>{if(i+=1,!(v===0||(E==="SIGINT"||E==="SIGTERM"||v===130||v===143||s))&&!o){o=!0,c(),l(),r(new Error(`Command failed with code ${String(v)}: ${g?.cmd??"unknown"} ${g?.args.join(" ")??""}`));return}i>=n.length&&!o&&(o=!0,c(),a&&clearTimeout(a),t())})})})}async function nd(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=lr();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await $(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 n=rd.join(t,eo);try{await hr("mise",[e==="full"?"dev:full":"dev"],t,void 0,o=>{typeof o=="number"&&o>0&&Do.writeFileSync(n,`${o}
116
- `)},process.platform!=="win32")}finally{try{Do.unlinkSync(n)}catch{}}}import te from"chalk";import*as id from"node:fs";import*as qt from"node:os";import{execa as od}from"execa";var dv={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 pv(e,t){let r=dv[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 Oo(e,t){let r;try{r=await fetch(`${e}/health/ready`,{signal:AbortSignal.timeout(5e3)})}catch(o){return{reachable:!1,detail:`Could not reach ${e}/health/ready: ${o.message}`}}if(!r.ok&&r.status!==503)return{reachable:!1,detail:`HTTP ${r.status} from ${e}/health/ready`};let n=await r.json();return{reachable:!0,ready:n.status==="ready",dependencies:n.dependencies.map(o=>o.ok?o:{...o,fix:pv(o.name,t)})}}var mv=2*1024*1024*1024,fv=4*1024*1024*1024,gv=2*1024*1024*1024,sd={"gaia-selfhost":["chromadb","postgres","redis","mongo","rabbitmq","gaia-backend","gaia-web","arq_worker","proxy"],"gaia-dev":["chromadb","postgres","redis","mongo","rabbitmq"]};function Ws(e){return e==="running"?"running":e==="restarting"?"restarting":"stopped"}function hv(e,t){return t.every(r=>e.some(n=>n.service===r&&Ws(n.state)==="running"))}function Sv(e,t){return t.map(r=>({service:r,info:e.find(n=>n.service===r)})).filter(({info:r})=>!r||Ws(r.state)!=="running").map(({service:r,info:n})=>n?`${r} ${Ws(n.state)}`:`${r} missing`).join(", ")}function ad(e,t){return e[t]??t}async function cd(e,t={}){let r={id:"port-conflict",label:"Ports",severity:"blocker"},n;try{n=await po(e,t)}catch{return{...r,state:"skipped",detail:"Could not check ports"}}let o=n.filter(s=>!s.available);if(o.length===0)return{...r,state:"ok",detail:"no conflicts"};let i=o.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 vv(e){return`Open ${e}/setup in your browser to finish setting GAIA up.`}function yv(e,t,r){let o=[{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&&o.push({label:"plans seeded",configured:e.plans_seeded,missing:"billing plans not set up yet"}),o.map(i=>({...i,fix:i.configured?"":vv(r)}))}function wv(e){let r=e.trim().split(`
117
- `).filter(i=>i.trim().length>0).at(-1);if(!r)return null;let n=r.trim().split(/\s+/),o=Number(n[3]);return!Number.isFinite(o)||o<0?null:o}async function ld(e){let t={id:"docker-daemon",label:"Docker",severity:"blocker"};if(e==="ready")return{...t,state:"ok",detail:"running"};let r=await et(e);return{...t,state:"fail",detail:r.state,fix:r.fix}}async function ud(e){let t={id:"compose-containers",label:"Containers",severity:"blocker"},r;try{r=await Pt(e.project)}catch{return{...t,state:"skipped",detail:"they need Docker"}}return hv(r,e.expected)?{...t,state:"ok",detail:`${e.expected.length} services running`}:{...t,state:"fail",detail:Sv(r,e.expected),fix:`Run 'gaia start' to bring the stack up, or check 'docker compose -p ${e.project} logs'.`}}function dd(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:Li}}async function pd(e,t="gaia start"){let r={id:"api-health",label:"API",severity:"blocker"};try{let n=await oo(`${e}/ping`);return n.ok?{...r,state:"ok",detail:`answering at ${e}`}:{...r,state:"fail",detail:`answered HTTP ${n.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 md(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 Oo(e.origin,e.project);return r.reachable?r.dependencies.map(n=>({id:`dependency-${n.name}`,label:Un(n.name),severity:"blocker",state:n.ok?"ok":"fail",detail:n.ok?`${Math.round(n.latency_ms)} ms`:`${n.error_type??"failed"} after ${Math.round(n.latency_ms)} ms`,fix:n.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 fd(e,t="gaia start"){let r={id:"web-reachable",label:"Web app",severity:"blocker"};try{let n=await oo(`http://localhost:${e}`,{method:"HEAD"});return n.ok?{...r,state:"ok",detail:`answering at http://localhost:${e}`}:{...r,state:"fail",detail:`answered HTTP ${n.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 gd(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,n]=await Promise.all([He(e.apiUrl,"status"),He(e.apiUrl,"catalog")]);if("detail"in r)return[{...t,state:"skipped",detail:r.detail}];if("detail"in n)return[{...t,state:"skipped",detail:n.detail}];let o=yv(r.data,n.data.llm_provider_keys,e.webUrl);if(o.every(s=>s.configured))return[{...t,state:"ok",detail:"finished"}];let i=o.filter(s=>!s.configured);return[{...t,state:"fail",detail:`not finished: ${i.map(s=>s.missing).join(", ")}`,fix:i[0]?.fix}]}async function Ks(e=mv){let t={id:"disk-headroom",label:"Disk space",severity:"blocker"},r;try{r=await ja()}catch{return{...t,state:"skipped",detail:"they need Docker"}}let n;try{let i=await qa(r),s=wv(i);n=s===null?null:s*1024}catch{n=null}if(n===null)return{...t,state:"skipped",detail:`Could not read disk usage for ${r}`};let o=i=>`${(i/1024**3).toFixed(1)} GB`;return n>=e?{...t,state:"ok",detail:`${o(n)} free at ${r}`}:{...t,state:"fail",detail:`${o(n)} free at ${r}, need \u2265 ${o(e)}`,fix:"Free up disk space (e.g. 'docker system prune') before pulling/building images."}}function bv(e){let t=e.match(/^MemAvailable:\s+(\d+)\s+kB/m);if(t?.[1]){let n=Number(t[1]);if(Number.isFinite(n)&&n>=0)return n*1024}let r=e.match(/^MemTotal:\s+(\d+)\s+kB/m);if(r?.[1]){let n=Number(r[1]);if(Number.isFinite(n)&&n>=0)return n*1024}return null}function Ev(e){let t=e.match(/page size of (\d+) bytes/),r=t?.[1]?Number(t[1]):4096,n=e.match(/Pages free:\s+(\d+)/),o=e.match(/Pages inactive:\s+(\d+)/),i=e.match(/Pages speculative:\s+(\d+)/);if(!(n||o||i))return null;let s=l=>l?Number(l[1]):0,a=s(n),c=s(o);return!Number.isFinite(a)||!Number.isFinite(c)||!Number.isFinite(r)||r<=0?null:(a+c+s(i))*r}function Ys(e){try{return e()}catch{return null}}function xv(){try{let e=id.readFileSync("/proc/meminfo","utf-8"),t=bv(e);if(t!==null)return t}catch{}return Ys(()=>qt.freemem())}async function Iv(){try{let{stdout:e}=await od("vm_stat",[]),t=Ev(e);if(t!==null)return t}catch{}try{let{stdout:e}=await od("sysctl",["-n","hw.memsize"]),t=Number(e.trim());if(Number.isFinite(t)&&t>0)return t}catch{}return Ys(()=>qt.totalmem())}async function kv(){let e=qt.platform();return e==="linux"?xv():e==="darwin"?Iv():Ys(()=>qt.freemem())}async function zs(){let e=await kv().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<gv?{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<fv?{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 hd(e,t,r=so){let n={id:"gaia-version",label:"GAIA version",severity:"warning"};if(!e)return{...n,state:"skipped",detail:"GAIA isn't installed"};if(t!=="selfhost")return{...n,state:"skipped",detail:"Developer checkout: update it with 'gaia update --git'"};let o=Be(e);if(mt(o)===null)return{...n,state:"ok",detail:`development build (${io(o)})`};let i=await r();return i&&rt(i,o)?{...n,state:"fail",detail:`${i} is available (this install runs ${o})`,fix:"Run 'gaia update'. Your data and settings are kept."}:{...n,state:"ok",detail:o}}async function Sd(e,t){if(e.length===0)return[];let r;try{r=await Pt(t)}catch{r=null}return e.map(n=>{let o={id:`bot-${n}`,label:je(xe(n)),severity:"warning"};if(!r)return{...o,state:"skipped",detail:"they need Docker"};let{health:i,detail:s}=Hr(n,r);return i!=="failing"?{...o,state:"ok",detail:s}:{...o,state:"fail",detail:s,fix:`A rejected or revoked token keeps the bot restarting: check 'docker compose -p ${t} logs ${xe(n)}', then rerun 'gaia bots add ${n}' with a fresh token.`}})}function vd(e){return e.results.some(t=>t.severity==="blocker"&&t.state==="fail")}async function Rv(){let e=L(),t=e?A(e):{},r=e?await $(e):null;return{repoPath:e,origin:$t(r??"selfhost",t),apiUrl:de(r??"selfhost",t),webPort:ad(t,3e3),overrides:t,mode:r,project:r?be[r]:null}}async function yd(){let e=[],t=await Rv(),r=await Z();if(e.push(await ld(r)),e.push(r==="ready"?await cd(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(dd(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 Ks()),e.push(await zs()),{install:zr(t.repoPath,t.mode),installed:!1,results:e}}let n=t.mode==="developer"?"gaia dev":"gaia start";e.push(await ud({project:t.project,expected:sd[t.project]})),t.project===be.selfhost&&e.push(...await Sd(C()?.bots??[],t.project));let o=await pd(t.apiUrl,n);return e.push(o),e.push(...await md({apiHealthy:o.state==="ok",origin:t.origin,project:t.project})),e.push(...await gd({apiHealthy:o.state==="ok",apiUrl:t.apiUrl,webUrl:pt(t.repoPath,t.webPort)})),e.push(await fd(t.webPort,n)),e.push(await Ks()),e.push(await zs()),e.push(await hd(t.repoPath,t.mode)),{install:zr(t.repoPath,t.mode),installed:!0,results:e}}function Ht(e=""){process.stdout.write(`${e}
118
- `)}var wd=16,Js=" ",Cv={ok:te.green,fail:te.red,warn:te.yellow,skip:te.gray,pending:te.gray,active:te.cyan,cancelled:te.yellow};function Av(e){return e.state==="ok"?"ok":e.state==="skipped"?"skip":e.severity==="warning"?"warn":"fail"}var Xs=Js.length+2+wd;function Pv(e,t){let r=Av(e),n=e.detail?te.gray(dt(e.detail,Xs)):"";Ht(`${Js}${Cv[r](y[r])} ${e.label.padEnd(wd)}${n}`),e.state==="fail"&&e.fix&&t?.fix!==e.fix&&Ht(`${" ".repeat(Xs)}${dt(e.fix,Xs)}`)}function Tv(e){let t=new Map;for(let r of e){let n=r.detail??"skipped";t.set(n,[...t.get(n)??[],r.label])}for(let[r,n]of t)Ht(`${Js}${te.gray(y.skip)} ${te.gray(`Not checked: ${n.join(", ")} (${r})`)}`)}function _v(e){let t=e.results.filter(o=>o.severity==="blocker"&&o.state==="fail").length,r=e.results.filter(o=>o.severity==="warning"&&o.state==="fail").length;if(t===0&&r===0)return te.green(`${y.ok} Everything checked out`);let n=[];return t>0&&n.push(te.red(`${t} problem${t===1?"":"s"}`)),r>0&&n.push(te.yellow(`${r} warning${r===1?"":"s"}`)),n.join(" \xB7 ")}function Dv(e){Ht(e.installed?`${te.bold("Checking")} ${e.install}`:te.bold("Checking this computer")),Ht();let t=e.results.filter(r=>r.state!=="skipped");t.forEach((r,n)=>{Pv(r,t[n+1])}),Tv(e.results.filter(r=>r.state==="skipped")),Ht(),Ht(_v(e))}async function bd(){await Lt();let e=await yd();Dv(e),vd(e)&&(process.exitCode=1)}import{render as xb}from"ink";import Ib from"react";import{ThemeProvider as gb}from"@inkjs/ui";import{Box as ui,Text as Xt,useInput as hb}from"ink";import Sb from"react";import{ConfirmInput as _y}from"@inkjs/ui";import{Box as wt,Static as Dy,Text as aa}from"ink";import{Box as Mo,Text as mn}from"ink";import{useStdout as Ov}from"ink";import{useEffect as $v,useState as Lv}from"react";function $o(){let{stdout:e}=Ov(),[t,r]=Lv(()=>Jr(e));return $v(()=>{let n=()=>r(Jr(e));return e.on("resize",n),()=>{e.off("resize",n)}},[e]),t}var Mv=100;function Lo(){return Math.min($o().columns,Mv)}import{jsx as Sr,jsxs as No}from"react/jsx-runtime";var Ed=16,Nv=6,Fv={primary:void 0,warn:"yellow",dim:"gray"},Bv=({row:e,width:t})=>{let r=e.tone?Fv[e.tone]:void 0,n=Ji(e.text,t);if(!e.url)return Sr(mn,{color:r,children:n});let[o,i]=n.split(e.url);return No(mn,{color:r,children:[o,Sr(mn,{color:"cyan",bold:!0,underline:!0,children:e.url}),i]})},Fo=({headline:e,rows:t,accent:r,success:n})=>{let o=Lo();return No(Mo,{flexDirection:"column",borderStyle:T,borderColor:r,paddingX:2,paddingY:1,width:o,children:[No(mn,{bold:!0,color:r,children:[n?`${y.ok} `:"",e]}),Sr(Mo,{flexDirection:"column",marginTop:1,children:t.map(i=>No(Mo,{marginBottom:i.tone==="primary"?1:0,children:[Sr(Mo,{width:Ed,flexShrink:0,children:Sr(mn,{bold:i.tone==="primary",children:i.label})}),Sr(Bv,{row:i,width:o-Nv-Ed})]},i.label))})]})};import{Spinner as Wv,StatusMessage as Rd}from"@inkjs/ui";import{Box as vt,Text as Vt}from"ink";import{useEffect as Kv,useState as Yv}from"react";function vr(e=Date.now){let t=[];return{update(r,n){let o=e();for(t.push({at:o,done:r});t.length>2&&o-(t[1]?.at??o)>=1e4;)t.shift();let i=t[0];if(!i||o-i.at<2e3)return null;let s=(r-i.done)/(o-i.at);return s<=0?null:Math.round(Math.max(0,n-r)/s)}}}function xd(e){return e<6e4?"less than a minute left":e<36e5?`about ${Math.round(e/6e4)} min left`:`about ${Math.round(e/36e5)} h left`}function Qs(e,t){return t!==void 0?t:e.total<=0?0:Math.min(100,Math.floor(e.done/e.total*100))}function fn(e,t={}){let r=e.unit==="bytes"?jn(e.done,e.total,e.estimated):`${e.done} / ${e.total} services`,n=t.etaMs!==void 0&&t.etaMs!==null?` \xB7 ${xd(t.etaMs)}`:"";return`${Qs(e,t.percent)}% ${r}${n}`}import{Box as Gv,Text as Uv}from"ink";import{jsx as Id}from"react/jsx-runtime";var Ae=({kind:e})=>Id(Gv,{marginRight:1,children:Id(Uv,{color:Mr[e],children:y[e]})});import{ProgressBar as jv}from"@inkjs/ui";import{Box as kd,Text as qv}from"ink";import{jsx as Zs,jsxs as Vv}from"react/jsx-runtime";var Hv=30,yr=({percent:e,caption:t})=>Vv(kd,{children:[Zs(kd,{width:Hv,children:Zs(jv,{value:e})}),Zs(qv,{dimColor:!0,children:` ${t??`${e}%`}`})]});import{jsx as Y,jsxs as gn}from"react/jsx-runtime";var ea=32,zv=1e3,Xv=2e3;function ta(e){let[t,r]=Yv(Date.now());return Kv(()=>{if(!e)return;let n=setInterval(()=>r(Date.now()),zv);return()=>clearInterval(n)},[e]),t}function ra(e,t){return e.startedAt===void 0?"":ft((e.endedAt??t)-e.startedAt)}function Jv(e){return e.state==="skipped"?!1:e.minor?Qv(e)>=Xv:!0}function Qv(e){return e.startedAt===void 0||e.endedAt===void 0?0:e.endedAt-e.startedAt}function Bo(e){let t=e.findIndex(n=>n.state!=="done"&&n.state!=="skipped"),r=t===-1?e.length:t;return{finished:e.slice(0,r).filter(Jv),live:e.slice(r)}}function Go(e,t){if(t.minor)return null;let r=e.filter(o=>!o.minor&&o.state!=="skipped"),n=r.findIndex(o=>o.id===t.id);return n===-1?null:`step ${n+1} of ${r.length}`}var Uo=({step:e})=>Y(Rd,{variant:"success",children:gn(Vt,{dimColor:!0,children:[e.doneLabel.padEnd(ea),ra(e,Date.now())]})}),Zv=({step:e})=>{let t=gn(Vt,{children:[e.label.padEnd(ea),Y(Vt,{dimColor:!0,children:ra(e,Date.now())})]});return e.state==="failed"?Y(Rd,{variant:"error",children:t}):gn(vt,{children:[Y(Ae,{kind:"cancelled"}),t]})},jo=({step:e,counter:t,waiting:r,status:n})=>{let o=ta(!r);if(e.state==="failed"||e.state==="cancelled")return Y(Zv,{step:e});let i=e.detail??(n||void 0),s=[t,r?null:ra(e,o)].filter(Boolean).join(" \xB7 ");return gn(vt,{flexDirection:"column",children:[gn(vt,{children:[r?Y(Ae,{kind:"pending"}):Y(vt,{marginRight:1,children:Y(Wv,{})}),Y(vt,{width:ea,children:Y(Vt,{bold:!0,children:e.label})}),Y(Vt,{dimColor:!0,children:s})]}),e.amount&&Y(vt,{marginLeft:2,marginTop:1,children:Y(yr,{percent:Qs(e.amount,e.percent),caption:fn(e.amount,{percent:e.percent,etaMs:e.etaMs})})}),i&&Y(vt,{marginLeft:2,marginTop:e.amount?0:1,children:Y(Vt,{dimColor:!0,wrap:"truncate",children:i})}),e.hint&&Y(vt,{marginLeft:2,children:Y(Vt,{dimColor:!0,children:e.hint})})]})};import{Alert as Cd,ConfirmInput as ey,Spinner as Ad}from"@inkjs/ui";import{Box as K,Text as V,useInput as ty}from"ink";import{jsx as I,jsxs as z}from"react/jsx-runtime";var qo=({checks:e})=>z(K,{flexDirection:"column",borderStyle:T,paddingX:1,borderColor:w,children:[I(V,{bold:!0,children:"System Checks"}),z(K,{flexDirection:"column",marginTop:1,children:[I(na,{label:"Git",status:e.git}),e.docker&&I(na,{label:"Docker",status:e.docker}),e.mise&&I(na,{label:"Mise",status:e.mise})]})]}),Ho=({status:e})=>z(K,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[I(V,{bold:!0,children:"Environment Setup"}),I(K,{marginTop:1,children:I(Ad,{label:e||"Configuring environment\u2026"})})]}),Pd=({title:e,progress:t,phase:r})=>z(K,{flexDirection:"column",borderStyle:T,padding:1,borderColor:w,children:[I(V,{bold:!0,children:e}),z(K,{marginTop:1,flexDirection:"column",children:[I(yr,{percent:t||0}),r&&I(V,{color:"gray",children:r})]})]}),Pe=({message:e})=>{let[t="",...r]=e.split(`
119
- `),n=Lo();return r.length===0?I(K,{marginTop:1,width:n,children:I(Cd,{variant:"error",children:t})}):I(K,{marginTop:1,width:n,children:I(Cd,{variant:"error",title:t,children:r.map((o,i)=>z(V,{color:o.startsWith("Full log:")?"gray":void 0,children:[i>0?`
120
- `:"",o]},o))})})},ry={success:"ok",error:"fail",missing:"warn"},na=({label:e,status:t})=>z(K,{children:[t==="pending"?I(K,{marginRight:1,children:I(Ad,{type:"dots"})}):I(Ae,{kind:ry[t]}),I(V,{children:e})]}),wr=({portResults:e,onAccept:t,onAbort:r})=>{ty((o,i)=>{i.return?t():i.escape&&r()});let n=e.filter(o=>!o.available);return z(K,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:"yellow",children:[I(K,{marginBottom:1,children:I(V,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(o=>z(K,{children:[z(V,{color:o.available?"green":o.alternative?"yellow":"red",children:[o.available?y.ok:o.alternative?y.warn:y.fail," "]}),z(V,{children:[o.service," (:",o.port,")"]}),!o.available&&z(V,{color:o.alternative?"gray":"red",children:[" ","- in use",o.usedBy?` by ${o.usedBy}`:"",o.alternative?` \u2192 will use :${o.alternative}`:" \u2014 NO ALTERNATIVE FOUND"]})]},o.port)),n.some(o=>!o.alternative)&&I(K,{marginTop:1,children:I(V,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!n.some(o=>!o.alternative)&&n.some(o=>o.alternative)&&I(K,{marginTop:1,children:I(V,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),I(K,{marginTop:1,children:z(V,{dimColor:!0,children:[I(V,{bold:!0,children:"Enter"})," continue \xB7 ",I(V,{bold:!0,children:"Esc"})," cancel"]})})]})},ny=({missing:e,onConfirm:t,onDecline:r})=>{let n=e.length>1?"aren't":"isn't";return z(K,{flexDirection:"column",marginTop:1,children:[z(V,{children:["GAIA needs ",I(V,{bold:!0,children:ur(e)}),", which ",n," ","installed yet."]}),z(K,{children:[z(V,{children:["Install ",e.length>1?"them":"it"," now?"," ",I(V,{dimColor:!0,children:"(uses sudo, a few minutes)"})," "]}),I(ey,{onConfirm:t,onCancel:r})]})]})},br=({inputId:e,missing:t,onConfirm:r,onDecline:n})=>e!==ps||!t?.length?null:I(ny,{missing:t,onConfirm:r,onDecline:n});import{useEffect as oy,useState as iy}from"react";function Te(e){let[t,r]=iy(e.currentState);return oy(()=>{let n=()=>r({...e.currentState});return e.on("change",n),()=>{e.off("change",n)}},[e]),t}import*as Ir from"node:fs";import*as Qd from"node:os";import*as kr from"node:path";import*as Td from"node:os";import*as _d from"node:path";var sy=80,ay=443,Dd=_d.join(Td.homedir(),"gaia");function Vo(){let e=C()?.repoPath;return e&&cr(e)?e:null}function Od(e){let t={};return e.domain&&(t[O]=sy,t[Qr]=ay),e.webPort&&(t[O]=e.webPort),t}function cy(){return C()?.values??{}}function ly(e){return An().flatMap(t=>t.variables).find(t=>t.name===e)}function $d(e){let{repoPath:t,interactive:r=fe(),setupMode:n="selfhost"}=e,o=cy(),i=new Set(Gr()),s=new Map,a=l=>(s.has(l)||s.set(l,ly(l)?.required===!0),s.get(l)===!0),c=l=>{let u=o[l]??Br(l,n);if(u)return u;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,u)=>{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=u?.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}}}import*as Wt from"node:fs";import*as qd from"node:http";import*as Kt from"node:path";import{execa as xr}from"execa";import*as Er from"node:fs";import*as Ld from"node:os";import*as Md from"node:path";import{execa as oa}from"execa";var hn="gaia-local-name-ipv6.service",ia=`/etc/systemd/system/${hn}`,uy=["temporary","deprecated","tentative","dadfailed"];function dy(e){return/\bdev (\S+)/.exec(e)?.[1]??null}function py(e,t){let r=e.split(`
121
- `).map(o=>/^\d+:\s+(\S+)\s+inet6\s+([0-9a-f:]+)\/\d+\s+(.*)$/.exec(o)).filter(o=>o!==null).map(([,o="",i="",s=""])=>({device:o,address:i,flags:s})).filter(({device:o,flags:i})=>!Qi.test(o)&&!uy.some(s=>i.split(/\s+/).includes(s)));return(r.find(({device:o})=>o===t)??r[0])?.address??null}function my(e,t,r){return`[Unit]
115
+ `).action(e=>pe(async()=>process.exit(await Cv(e))));import*as Mo from"fs";import*as ud from"path";import{spawn as kv}from"child_process";async function hr(e,t,r,n,o,i=!1){await Lo([{cmd:e,args:t,cwd:r,env:n,onSpawn:o,detached:i}])}async function Lo(e){e.length!==0&&await new Promise((t,r)=>{let n=e.map(p=>kv(p.cmd,p.args,{cwd:p.cwd,stdio:"inherit",shell:!1,detached:p.detached??!1,env:p.env?{...process.env,...p.env}:process.env}));n.forEach((p,m)=>{e[m]?.onSpawn?.(p.pid)});let o=!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 n.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 n.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),n.forEach((p,m)=>{let g=e[m];p.on("error",v=>{o||(o=!0,c(),l(),r(v))}),p.on("close",(v,E)=>{if(i+=1,!(v===0||(E==="SIGINT"||E==="SIGTERM"||v===130||v===143||s))&&!o){o=!0,c(),l(),r(new Error(`Command failed with code ${String(v)}: ${g?.cmd??"unknown"} ${g?.args.join(" ")??""}`));return}i>=n.length&&!o&&(o=!0,c(),a&&clearTimeout(a),t())})})})}async function dd(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=lr();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await $(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 n=ud.join(t,oo);try{await hr("mise",[e==="full"?"dev:full":"dev"],t,void 0,o=>{typeof o=="number"&&o>0&&Mo.writeFileSync(n,`${o}
116
+ `)},process.platform!=="win32")}finally{try{Mo.unlinkSync(n)}catch{}}}import ne from"chalk";import*as md from"node:fs";import*as Ht from"node:os";import{execa as pd}from"execa";var Av={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 Pv(e,t){let r=Av[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 No(e,t){let r;try{r=await fetch(`${e}/health/ready`,{signal:AbortSignal.timeout(5e3)})}catch(o){return{reachable:!1,detail:`Could not reach ${e}/health/ready: ${o.message}`}}if(!r.ok&&r.status!==503)return{reachable:!1,detail:`HTTP ${r.status} from ${e}/health/ready`};let n=await r.json();return{reachable:!0,ready:n.status==="ready",dependencies:n.dependencies.map(o=>o.ok?o:{...o,fix:Pv(o.name,t)})}}var Tv=2*1024*1024*1024,_v=4*1024*1024*1024,Dv=2*1024*1024*1024,fd={"gaia-selfhost":["chromadb","postgres","redis","mongo","rabbitmq","gaia-backend","gaia-web","arq_worker","proxy"],"gaia-dev":["chromadb","postgres","redis","mongo","rabbitmq"]};function zs(e){return e==="running"?"running":e==="restarting"?"restarting":"stopped"}function Ov(e,t){return t.every(r=>e.some(n=>n.service===r&&zs(n.state)==="running"))}function $v(e,t){return t.map(r=>({service:r,info:e.find(n=>n.service===r)})).filter(({info:r})=>!r||zs(r.state)!=="running").map(({service:r,info:n})=>n?`${r} ${zs(n.state)}`:`${r} missing`).join(", ")}function gd(e,t){return e[t]??t}async function hd(e,t={}){let r={id:"port-conflict",label:"Ports",severity:"blocker"},n;try{n=await ho(e,t)}catch{return{...r,state:"skipped",detail:"Could not check ports"}}let o=n.filter(s=>!s.available);if(o.length===0)return{...r,state:"ok",detail:"no conflicts"};let i=o.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 Lv(e){return`Open ${e}/setup in your browser to finish setting GAIA up.`}function Mv(e,t,r){let o=[{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&&o.push({label:"plans seeded",configured:e.plans_seeded,missing:"billing plans not set up yet"}),o.map(i=>({...i,fix:i.configured?"":Lv(r)}))}function Nv(e){let r=e.trim().split(`
117
+ `).filter(i=>i.trim().length>0).at(-1);if(!r)return null;let n=r.trim().split(/\s+/),o=Number(n[3]);return!Number.isFinite(o)||o<0?null:o}async function Sd(e){let t={id:"docker-daemon",label:"Docker",severity:"blocker"};if(e==="ready")return{...t,state:"ok",detail:"running"};let r=await tt(e);return{...t,state:"fail",detail:r.state,fix:r.fix}}async function vd(e){let t={id:"compose-containers",label:"Containers",severity:"blocker"},r;try{r=await Pt(e.project)}catch{return{...t,state:"skipped",detail:"they need Docker"}}return Ov(r,e.expected)?{...t,state:"ok",detail:`${e.expected.length} services running`}:{...t,state:"fail",detail:$v(r,e.expected),fix:`Run 'gaia start' to bring the stack up, or check 'docker compose -p ${e.project} logs'.`}}function yd(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:Li}}async function wd(e,t="gaia start"){let r={id:"api-health",label:"API",severity:"blocker"};try{let n=await co(`${e}/ping`);return n.ok?{...r,state:"ok",detail:`answering at ${e}`}:{...r,state:"fail",detail:`answered HTTP ${n.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 bd(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 No(e.origin,e.project);return r.reachable?r.dependencies.map(n=>({id:`dependency-${n.name}`,label:Wn(n.name),severity:"blocker",state:n.ok?"ok":"fail",detail:n.ok?`${Math.round(n.latency_ms)} ms`:`${n.error_type??"failed"} after ${Math.round(n.latency_ms)} ms`,fix:n.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 Ed(e,t="gaia start"){let r={id:"web-reachable",label:"Web app",severity:"blocker"};try{let n=await co(`http://localhost:${e}`,{method:"HEAD"});return n.ok?{...r,state:"ok",detail:`answering at http://localhost:${e}`}:{...r,state:"fail",detail:`answered HTTP ${n.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 xd(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,n]=await Promise.all([He(e.apiUrl,"status"),He(e.apiUrl,"catalog")]);if("detail"in r)return[{...t,state:"skipped",detail:r.detail}];if("detail"in n)return[{...t,state:"skipped",detail:n.detail}];let o=Mv(r.data,n.data.llm_provider_keys,e.webUrl);if(o.every(s=>s.configured))return[{...t,state:"ok",detail:"finished"}];let i=o.filter(s=>!s.configured);return[{...t,state:"fail",detail:`not finished: ${i.map(s=>s.missing).join(", ")}`,fix:i[0]?.fix}]}async function Xs(e=Tv){let t={id:"disk-headroom",label:"Disk space",severity:"blocker"},r;try{r=await Wa()}catch{return{...t,state:"skipped",detail:"they need Docker"}}let n;try{let i=await Ka(r),s=Nv(i);n=s===null?null:s*1024}catch{n=null}if(n===null)return{...t,state:"skipped",detail:`Could not read disk usage for ${r}`};let o=i=>`${(i/1024**3).toFixed(1)} GB`;return n>=e?{...t,state:"ok",detail:`${o(n)} free at ${r}`}:{...t,state:"fail",detail:`${o(n)} free at ${r}, need \u2265 ${o(e)}`,fix:"Free up disk space (e.g. 'docker system prune') before pulling/building images."}}function Fv(e){let t=e.match(/^MemAvailable:\s+(\d+)\s+kB/m);if(t?.[1]){let n=Number(t[1]);if(Number.isFinite(n)&&n>=0)return n*1024}let r=e.match(/^MemTotal:\s+(\d+)\s+kB/m);if(r?.[1]){let n=Number(r[1]);if(Number.isFinite(n)&&n>=0)return n*1024}return null}function Bv(e){let t=e.match(/page size of (\d+) bytes/),r=t?.[1]?Number(t[1]):4096,n=e.match(/Pages free:\s+(\d+)/),o=e.match(/Pages inactive:\s+(\d+)/),i=e.match(/Pages speculative:\s+(\d+)/);if(!(n||o||i))return null;let s=l=>l?Number(l[1]):0,a=s(n),c=s(o);return!Number.isFinite(a)||!Number.isFinite(c)||!Number.isFinite(r)||r<=0?null:(a+c+s(i))*r}function Js(e){try{return e()}catch{return null}}function Gv(){try{let e=md.readFileSync("/proc/meminfo","utf-8"),t=Fv(e);if(t!==null)return t}catch{}return Js(()=>Ht.freemem())}async function Uv(){try{let{stdout:e}=await pd("vm_stat",[]),t=Bv(e);if(t!==null)return t}catch{}try{let{stdout:e}=await pd("sysctl",["-n","hw.memsize"]),t=Number(e.trim());if(Number.isFinite(t)&&t>0)return t}catch{}return Js(()=>Ht.totalmem())}async function jv(){let e=Ht.platform();return e==="linux"?Gv():e==="darwin"?Uv():Js(()=>Ht.freemem())}async function Qs(){let e=await jv().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<Dv?{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<_v?{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 Id(e,t,r=uo){let n={id:"gaia-version",label:"GAIA version",severity:"warning"};if(!e)return{...n,state:"skipped",detail:"GAIA isn't installed"};if(t!=="selfhost")return{...n,state:"skipped",detail:"Developer checkout: update it with 'gaia update --git'"};let o=Ue(e);if(ft(o)===null)return{...n,state:"ok",detail:`development build (${lo(o)})`};let i=await r();return i&&nt(i,o)?{...n,state:"fail",detail:`${i} is available (this install runs ${o})`,fix:"Run 'gaia update'. Your data and settings are kept."}:{...n,state:"ok",detail:o}}async function Rd(e,t){if(e.length===0)return[];let r;try{r=await Pt(t)}catch{r=null}return e.map(n=>{let o={id:`bot-${n}`,label:$e(Ie(n)),severity:"warning"};if(!r)return{...o,state:"skipped",detail:"they need Docker"};let{health:i,detail:s}=Hr(n,r);return i!=="failing"?{...o,state:"ok",detail:s}:{...o,state:"fail",detail:s,fix:`A rejected or revoked token keeps the bot restarting: check 'docker compose -p ${t} logs ${Ie(n)}', then rerun 'gaia bots add ${n}' with a fresh token.`}})}function Cd(e){return e.results.some(t=>t.severity==="blocker"&&t.state==="fail")}async function qv(){let e=L(),t=e?k(e):{},r=e?await $(e):null;return{repoPath:e,origin:Lt(r??"selfhost",t),apiUrl:me(r??"selfhost",t),webPort:gd(t,3e3),overrides:t,mode:r,project:r?Ee[r]:null}}async function kd(){let e=[],[t,r]=await Promise.all([qv(),ee()]);if(e.push(await Sd(r)),e.push(r==="ready"?await hd(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(yd(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 Xs()),e.push(await Qs()),{install:zr(t.repoPath,t.mode),installed:!1,results:e}}let n=t.mode==="developer"?"gaia dev":"gaia start";e.push(await vd({project:t.project,expected:fd[t.project]})),t.project===Ee.selfhost&&e.push(...await Rd(P()?.bots??[],t.project));let o=await wd(t.apiUrl,n);return e.push(o),e.push(...await bd({apiHealthy:o.state==="ok",origin:t.origin,project:t.project})),e.push(...await xd({apiHealthy:o.state==="ok",apiUrl:t.apiUrl,webUrl:mt(t.repoPath,t.webPort)})),e.push(await Ed(t.webPort,n)),e.push(await Xs()),e.push(await Qs()),e.push(await Id(t.repoPath,t.mode)),{install:zr(t.repoPath,t.mode),installed:!0,results:e}}function Vt(e=""){process.stdout.write(`${e}
118
+ `)}var Ad=16,ea=" ",Hv={ok:ne.green,fail:ne.red,warn:ne.yellow,skip:ne.gray,pending:ne.gray,active:ne.cyan,cancelled:ne.yellow};function Vv(e){return e.state==="ok"?"ok":e.state==="skipped"?"skip":e.severity==="warning"?"warn":"fail"}var Zs=ea.length+2+Ad;function Wv(e,t){let r=Vv(e),n=e.detail?ne.gray(pt(e.detail,Zs)):"";Vt(`${ea}${Hv[r](y[r])} ${e.label.padEnd(Ad)}${n}`),e.state==="fail"&&e.fix&&t?.fix!==e.fix&&Vt(`${" ".repeat(Zs)}${pt(e.fix,Zs)}`)}function Kv(e){let t=new Map;for(let r of e){let n=r.detail??"skipped";t.set(n,[...t.get(n)??[],r.label])}for(let[r,n]of t)Vt(`${ea}${ne.gray(y.skip)} ${ne.gray(`Not checked: ${n.join(", ")} (${r})`)}`)}function Yv(e){let t=e.results.filter(o=>o.severity==="blocker"&&o.state==="fail").length,r=e.results.filter(o=>o.severity==="warning"&&o.state==="fail").length;if(t===0&&r===0)return ne.green(`${y.ok} Everything checked out`);let n=[];return t>0&&n.push(ne.red(`${t} problem${t===1?"":"s"}`)),r>0&&n.push(ne.yellow(`${r} warning${r===1?"":"s"}`)),n.join(" \xB7 ")}function zv(e){Vt(e.installed?`${ne.bold("Checking")} ${e.install}`:ne.bold("Checking this computer")),Vt();let t=e.results.filter(r=>r.state!=="skipped");t.forEach((r,n)=>{Wv(r,t[n+1])}),Kv(e.results.filter(r=>r.state==="skipped")),Vt(),Vt(Yv(e))}async function Pd(){await Mt();let e=await kd();zv(e),Cd(e)&&(process.exitCode=1)}import{render as Kb}from"ink";import Yb from"react";import{ThemeProvider as Bb}from"@inkjs/ui";import{Box as mi,Text as Xt,useInput as Gb}from"ink";import Ub from"react";import{ConfirmInput as Zy}from"@inkjs/ui";import{Box as Yt,Static as ew,Text as ua}from"ink";import{Box as Go,Text as mn}from"ink";import{useStdout as Xv}from"ink";import{useEffect as Jv,useState as Qv}from"react";function Fo(){let{stdout:e}=Xv(),[t,r]=Qv(()=>Jr(e));return Jv(()=>{let n=()=>r(Jr(e));return e.on("resize",n),()=>{e.off("resize",n)}},[e]),t}var Zv=100;function Bo(){return Math.min(Fo().columns,Zv)}import{jsx as Sr,jsxs as Uo}from"react/jsx-runtime";var Td=16,ey=6,ty={primary:void 0,warn:"yellow",dim:"gray"},ry=({row:e,width:t})=>{let r=e.tone?ty[e.tone]:void 0,n=Ji(e.text,t);if(!e.url)return Sr(mn,{color:r,children:n});let[o,i]=n.split(e.url);return Uo(mn,{color:r,children:[o,Sr(mn,{color:"cyan",bold:!0,underline:!0,children:e.url}),i]})},jo=({headline:e,rows:t,accent:r,success:n})=>{let o=Bo();return Uo(Go,{flexDirection:"column",borderStyle:_,borderColor:r,paddingX:2,paddingY:1,width:o,children:[Uo(mn,{bold:!0,color:r,children:[n?`${y.ok} `:"",e]}),Sr(Go,{flexDirection:"column",marginTop:1,children:t.map(i=>Uo(Go,{marginBottom:i.tone==="primary"?1:0,children:[Sr(Go,{width:Td,flexShrink:0,children:Sr(mn,{bold:i.tone==="primary",children:i.label})}),Sr(ry,{row:i,width:o-ey-Td})]},i.label))})]})};import{Spinner as ly}from"@inkjs/ui";import{Box as Te,Text as wr}from"ink";import{useEffect as uy,useState as dy}from"react";function vr(e=Date.now){let t=[];return{update(r,n){let o=e();for(t.push({at:o,done:r});t.length>2&&o-(t[1]?.at??o)>=1e4;)t.shift();let i=t[0];if(!i||o-i.at<2e3)return null;let s=(r-i.done)/(o-i.at);return s<=0?null:Math.round(Math.max(0,n-r)/s)}}}function _d(e){return e<6e4?"less than a minute left":e<36e5?`about ${Math.round(e/6e4)} min left`:`about ${Math.round(e/36e5)} h left`}function ta(e,t){return t!==void 0?t:e.total<=0?0:Math.min(100,Math.floor(e.done/e.total*100))}function fn(e,t={}){let r=e.unit==="bytes"?Ot(e.done,e.total,e.estimated):`${e.done} / ${e.total} services`,n=t.etaMs!==void 0&&t.etaMs!==null?` \xB7 ${_d(t.etaMs)}`:"";return`${ta(e,t.percent)}% ${r}${n}`}import{Box as ny,Text as oy}from"ink";import{jsx as Dd}from"react/jsx-runtime";var z=({kind:e})=>Dd(ny,{marginRight:1,children:Dd(oy,{color:Lr[e],children:y[e]})});import{ProgressBar as iy}from"@inkjs/ui";import{Box as Od,Text as sy}from"ink";import{jsx as ra,jsxs as cy}from"react/jsx-runtime";var ay=30,yr=({percent:e,caption:t})=>cy(Od,{children:[ra(Od,{width:ay,children:ra(iy,{value:e})}),ra(sy,{dimColor:!0,children:` ${t??`${e}%`}`})]});import{jsx as R,jsxs as gn}from"react/jsx-runtime";var $d=36,Ld=8,Md=2,Nd=2,py=$d+Ld-Nd,my=1e3,fy=2e3;function na(e){let[t,r]=dy(Date.now());return uy(()=>{if(!e)return;let n=setInterval(()=>r(Date.now()),my);return()=>clearInterval(n)},[e]),t}function gy(e){return e.padEnd(Math.max($d,e.length+Md))}function oa(e,t){return e.startedAt===void 0?"":gt((e.endedAt??t)-e.startedAt)}function hy(e){return e.state==="skipped"?!1:e.minor?Sy(e)>=fy:!0}function Sy(e){return e.startedAt===void 0||e.endedAt===void 0?0:e.endedAt-e.startedAt}function qo(e){let t=e.findIndex(n=>n.state!=="done"&&n.state!=="skipped"),r=t===-1?e.length:t;return{finished:e.slice(0,r).filter(hy),live:e.slice(r)}}var ia=({mark:e,label:t,bold:r=!1,time:n})=>gn(Te,{children:[e,R(wr,{bold:r,children:gy(t)}),R(wr,{dimColor:!0,children:n.padStart(Ld)})]}),Ho=({step:e})=>R(ia,{mark:R(z,{kind:"ok"}),label:e.doneLabel,time:oa(e,Date.now())}),vy=({step:e})=>R(ia,{mark:R(z,{kind:e.state==="failed"?"fail":"cancelled"}),label:e.label,time:oa(e,Date.now())}),Fd=()=>R(Te,{marginRight:1,children:R(ly,{})}),yy=({state:e})=>e==="active"?R(Fd,{}):e==="done"?R(z,{kind:"ok"}):e==="failed"?R(z,{kind:"fail"}):R(Te,{width:2}),wy=({substep:e})=>{let t=e.state!=="active";return gn(Te,{children:[R(yy,{state:e.state}),gn(Te,{width:py,children:[R(Te,{flexGrow:1,flexShrink:0,children:R(wr,{dimColor:t,children:e.label})}),e.note&&R(Te,{flexShrink:1,marginLeft:Md,children:R(wr,{dimColor:!0,wrap:"truncate",children:e.note})})]})]})},Vo=({step:e,waiting:t,status:r})=>{let n=na(!t);if(e.state==="failed"||e.state==="cancelled")return R(vy,{step:e});let o=e.substeps??[],i=o.length>0?void 0:e.detail??(r||void 0);return gn(Te,{flexDirection:"column",children:[R(ia,{mark:t?R(z,{kind:"pending"}):R(Fd,{}),label:e.label,bold:!0,time:t?"":oa(e,n)}),gn(Te,{flexDirection:"column",marginLeft:Nd,children:[e.amount&&R(Te,{marginLeft:2,children:R(yr,{percent:ta(e.amount,e.percent),caption:fn(e.amount,{percent:e.percent,etaMs:e.etaMs})})}),o.map(s=>R(wy,{substep:s},s.id)),i&&R(Te,{marginLeft:2,children:R(wr,{dimColor:!0,wrap:"truncate",children:i})}),e.hint&&R(Te,{marginLeft:2,children:R(wr,{dimColor:!0,children:e.hint})})]})]})};import{Alert as Bd,ConfirmInput as by,Spinner as Gd}from"@inkjs/ui";import{Box as Y,Text as W,useInput as Ey}from"ink";import{jsx as I,jsxs as X}from"react/jsx-runtime";var Wo=({checks:e})=>X(Y,{flexDirection:"column",borderStyle:_,paddingX:1,borderColor:w,children:[I(W,{bold:!0,children:"System Checks"}),X(Y,{flexDirection:"column",marginTop:1,children:[I(sa,{label:"Git",status:e.git}),e.docker&&I(sa,{label:"Docker",status:e.docker}),e.mise&&I(sa,{label:"Mise",status:e.mise})]})]}),Ko=({status:e})=>X(Y,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[I(W,{bold:!0,children:"Environment Setup"}),I(Y,{marginTop:1,children:I(Gd,{label:e||"Configuring environment\u2026"})})]}),Ud=({title:e,progress:t,phase:r})=>X(Y,{flexDirection:"column",borderStyle:_,padding:1,borderColor:w,children:[I(W,{bold:!0,children:e}),X(Y,{marginTop:1,flexDirection:"column",children:[I(yr,{percent:t||0}),r&&I(W,{color:"gray",children:r})]})]}),_e=({message:e})=>{let[t="",...r]=e.split(`
119
+ `),n=Bo();return r.length===0?I(Y,{marginTop:1,width:n,children:I(Bd,{variant:"error",children:t})}):I(Y,{marginTop:1,width:n,children:I(Bd,{variant:"error",title:t,children:r.map((o,i)=>X(W,{color:o.startsWith("Full log:")?"gray":void 0,children:[i>0?`
120
+ `:"",o]},o))})})},xy={success:"ok",error:"fail",missing:"warn"},sa=({label:e,status:t})=>X(Y,{children:[t==="pending"?I(Y,{marginRight:1,children:I(Gd,{type:"dots"})}):I(z,{kind:xy[t]}),I(W,{children:e})]}),br=({portResults:e,onAccept:t,onAbort:r})=>{Ey((o,i)=>{i.return?t():i.escape&&r()});let n=e.filter(o=>!o.available);return X(Y,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:"yellow",children:[I(Y,{marginBottom:1,children:I(W,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(o=>X(Y,{children:[X(W,{color:o.available?"green":o.alternative?"yellow":"red",children:[o.available?y.ok:o.alternative?y.warn:y.fail," "]}),X(W,{children:[o.service," (:",o.port,")"]}),!o.available&&X(W,{color:o.alternative?"gray":"red",children:[" ","- in use",o.usedBy?` by ${o.usedBy}`:"",o.alternative?` \u2192 will use :${o.alternative}`:" \u2014 NO ALTERNATIVE FOUND"]})]},o.port)),n.some(o=>!o.alternative)&&I(Y,{marginTop:1,children:I(W,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!n.some(o=>!o.alternative)&&n.some(o=>o.alternative)&&I(Y,{marginTop:1,children:I(W,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),I(Y,{marginTop:1,children:X(W,{dimColor:!0,children:[I(W,{bold:!0,children:"Enter"})," continue \xB7 ",I(W,{bold:!0,children:"Esc"})," cancel"]})})]})},Iy=({missing:e,onConfirm:t,onDecline:r})=>{let n=e.length>1?"aren't":"isn't";return X(Y,{flexDirection:"column",marginTop:1,children:[X(W,{children:["GAIA needs ",I(W,{bold:!0,children:ur(e)}),", which ",n," ","installed yet."]}),X(Y,{children:[X(W,{children:["Install ",e.length>1?"them":"it"," now?"," ",I(W,{dimColor:!0,children:"(uses sudo, a few minutes)"})," "]}),I(by,{onConfirm:t,onCancel:r})]})]})},Er=({inputId:e,missing:t,onConfirm:r,onDecline:n})=>e!==fs||!t?.length?null:I(Iy,{missing:t,onConfirm:r,onDecline:n});import{useEffect as Ry,useState as Cy}from"react";function Se(e){let[t,r]=Cy(e.currentState);return Ry(()=>{let n=()=>r({...e.currentState});return e.on("change",n),()=>{e.off("change",n)}},[e]),t}import*as Rr from"node:fs";import*as dp from"node:os";import*as Cr from"node:path";import*as jd from"node:os";import*as qd from"node:path";var ky=80,Ay=443,Hd=qd.join(jd.homedir(),"gaia");function Yo(){let e=P()?.repoPath;return e&&cr(e)?e:null}function Vd(e){let t={};return e.domain&&(t[O]=ky,t[Qr]=Ay),e.webPort&&(t[O]=e.webPort),t}function Py(){return P()?.values??{}}function Ty(e){return _n().flatMap(t=>t.variables).find(t=>t.name===e)}function Wd(e){let{repoPath:t,interactive:r=he(),setupMode:n="selfhost"}=e,o=Py(),i=new Set(Br()),s=new Map,a=l=>(s.has(l)||s.set(l,Ty(l)?.required===!0),s.get(l)===!0),c=l=>{let d=o[l]??Fr(l,n);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}}}import*as Wt from"node:fs";import*as rp from"node:http";import*as Kt from"node:path";import{execa as Ir}from"execa";import{z as Qd}from"zod";import*as xr from"node:fs";import*as Kd from"node:os";import*as Yd from"node:path";import{execa as aa}from"execa";var hn="gaia-local-name-ipv6.service",ca=`/etc/systemd/system/${hn}`,_y=["temporary","deprecated","tentative","dadfailed"];function Dy(e){return/\bdev (\S+)/.exec(e)?.[1]??null}function Oy(e,t){let r=e.split(`
121
+ `).map(o=>/^\d+:\s+(\S+)\s+inet6\s+([0-9a-f:]+)\/\d+\s+(.*)$/.exec(o)).filter(o=>o!==null).map(([,o="",i="",s=""])=>({device:o,address:i,flags:s})).filter(({device:o,flags:i})=>!Qi.test(o)&&!_y.some(s=>i.split(/\s+/).includes(s)));return(r.find(({device:o})=>o===t)??r[0])?.address??null}function $y(e,t,r){return`[Unit]
122
122
  Description=Announce ${t}'s IPv6 address over mDNS (GAIA)
123
123
  Requires=avahi-daemon.service
124
124
  After=avahi-daemon.service network-online.target
@@ -131,37 +131,37 @@ RestartSec=2
131
131
 
132
132
  [Install]
133
133
  WantedBy=multi-user.target
134
- `}async function Nd(){let[e,t]=await Promise.all([oa("ip",["-6","-o","addr","show","scope","global"]),oa("ip",["-o","route","show","default"])]);return py(e.stdout,dy(t.stdout))}async function Fd(e,t,r){let{stdout:n}=await oa("sh",["-c","command -v avahi-publish-address"]),o=Md.join(Ld.tmpdir(),hn);Er.writeFileSync(o,my(n.trim(),e,t)),await q("install",["-m","644",o,ia],r),Er.rmSync(o,{force:!0}),await q("systemctl",["daemon-reload"],r),await q("systemctl",["enable",hn],r),await q("systemctl",["restart",hn],r)}async function Bd(e){Er.existsSync(ia)&&(await q("systemctl",["disable","--now",hn],e),await q("rm",["-f",ia],e),await q("systemctl",["daemon-reload"],e))}var Ko="gaia",yt=`${Ko}.local`,Hd=`http://${yt}`,Gd="0.15.8",Ud=24,sa=80,fy=15e3,gy=500,Vd=2e3;function Wd(e){return!e.optedOut&&!e.domain?"set-up":e.setUpBefore?"remove":"none"}function hy(e,t){if(t!=="linux"&&t!=="darwin")return"it works only on Linux and macOS";let r=e.replace(/^v/,"");return Number.parseInt(r,10)<Ud?`it needs Node.js ${Ud} or newer, and this is Node.js ${r}`:null}function Kd(){return Kt.join(Kt.dirname(process.execPath),"npm")}async function Yd(){let{stdout:e}=await xr(Kd(),["root","-g"]);return Kt.join(e.trim(),"portless","dist","cli.js")}function Sy(e){let t=Kt.join(Kt.dirname(e),"..","package.json");return Wt.existsSync(t)?JSON.parse(Wt.readFileSync(t,"utf-8")).version:null}async function vy(e){let t=await Yd();if(Sy(t)===Gd)return t;let r=await xr(Kd(),["install","-g","--no-fund","--no-audit",`portless@${Gd}`],{all:!0,reject:!1});if(Wt.appendFileSync(e,r.all??""),r.failed)throw new Error(`installing portless with npm failed (output in ${e})`);return t}function yy(e){return xr("sh",["-c",`command -v ${e}`],{reject:!1}).then(t=>!t.failed)}async function wy(e){if(process.platform==="linux"&&!await yy("avahi-publish-address")){if(!ms())throw new Error("it needs avahi-utils (avahi-publish-address); install it, then run 'gaia up' again");await q("apt-get",["update"],e),await q("apt-get",["install","-y","avahi-utils"],e)}}async function by(e,t){let r=await xr(process.execPath,[e,...t],{all:!0,reject:!1});if(r.failed)throw new Error(`'portless ${t.join(" ")}' failed: ${(r.all??"").trim()}`)}function zd(){return new Promise(e=>{let t=qd.get({host:"127.0.0.1",port:sa,path:"/health/ready",headers:{Host:yt},timeout:Vd},r=>{r.resume(),e(r.statusCode??null)});t.on("timeout",()=>t.destroy()),t.on("error",()=>e(null))})}async function jd(){return await zd()===200}async function Ey(){return await zd()!==null}async function Xd(e,t){if(process.platform!=="linux")return!0;let r=await xr("avahi-resolve-host-name",[e,yt],{reject:!1,timeout:Vd});if(r.failed)return!1;let[n,o]=r.stdout.trim().split(/\s+/);return n===yt&&(!t||o===t)}async function xy(e){if(process.platform!=="linux")return;let t=await Nd();if(!t)return;let r=()=>Xd("-6",t);if(!await r()&&(await Fd(yt,t,e),!await Wo(r)))throw new Error(`${yt}'s IPv6 address isn't announced, so Apple devices wait ~5s per lookup (log: ${e})`)}async function Wo(e){let t=Date.now()+fy;for(;Date.now()<t;){if(await e())return!0;await new Promise(r=>setTimeout(r,gy))}return e()}async function Jd(e){let t=hy(process.version,process.platform);if(t)throw new Error(t);let r=Ue("local-name"),n=await vy(r);if(!await jd()&&(await wy(r),await q(process.execPath,[n,"service","install","--lan","--no-tls"],r),!await Wo(Ey)))throw new Error(`portless's proxy didn't start on port ${sa}; is another server using it? (log: ${r})`);if(await by(n,["alias",Ko,String(e),"--force"]),!await Wo(jd))throw new Error(`portless's proxy on port ${sa} doesn't route ${yt} to GAIA on port ${e} (log: ${r})`);if(!await Wo(()=>Xd("-4")))throw new Error(`${yt} isn't announced on the network; check that avahi-daemon is running (log: ${r})`);await xy(r)}async function Yo(){let e=await Yd();if(!Wt.existsSync(e))return;let t=await xr(process.execPath,[e,"alias","--remove",Ko],{all:!0,reject:!1});if(t.failed&&!(t.all??"").includes("No alias found"))throw new Error(`'portless alias --remove ${Ko}' failed: ${(t.all??"").trim()}`);let r=Ue("local-name-remove");await q(process.execPath,[e,"service","uninstall"],r),await Bd(r)}var ze={confirm:"uninstall_confirm",deleteData:"uninstall_delete_data",backup:"uninstall_backup"},vn="uninstallOutcome",Sn=kr.join(Qd.homedir(),"gaia-backups"),Iy=["apps/api/.env","infra/docker/.env"],Zd="npm rm -g @heygaia/cli",ep="docker volume rm $(docker volume ls -q --filter label=com.docker.compose.project=gaia-selfhost)";function ky(e,t){if(!t.keepSettings){Ir.rmSync(e,{recursive:!0,force:!0});return}let r=Iy.map(o=>kr.join(e,o)),n=o=>{for(let i of Ir.readdirSync(o)){let s=kr.join(o,i);if(r.includes(s))continue;r.some(c=>c.startsWith(`${s}${kr.sep}`))?n(s):Ir.rmSync(s,{recursive:!0,force:!0})}};n(e)}function Ry(e){return t=>{if(t===ze.confirm&&e.yes)return!0;if(t===ze.deleteData){if(e.deleteData)return!0;if(e.yes)return!1}if(t===ze.backup&&e.yes)return!1}}function Cy(e,t,r,{deleteData:n,backup:o}){let i=[];if(o&&i.push({id:"backup",label:"Backing up your data",doneLabel:`Backed up your data to ${_(Sn)}`,run:()=>Xr({outputDir:Sn})}),t){let s=n?"containers and data":"containers and images";i.push({id:"containers",label:`Removing ${s}`,doneLabel:`Removed ${s}`,run:()=>ro(t,a=>ve(e,"containers",{detail:a}),A(t),{remove:{volumes:n}})})}if(r&&i.push({id:"local-name",label:"Removing the gaia.local name",doneLabel:"Removed the gaia.local name",run:Yo}),t){let s=_(t);i.push({id:"files",label:`Removing ${s}`,doneLabel:n?`Removed ${s}`:`Removed ${s}, except its settings`,minor:!0,run:()=>ky(t,{keepSettings:!n})})}return i.push({id:"config",label:`Removing ${_(Ee)}`,doneLabel:`Removed ${_(Ee)}`,minor:!0,run:()=>Ir.rmSync(Ee,{recursive:!0,force:!0})}),i}async function Ay(e,t){uo(e,t);for(let r of t){me(e,r.id);try{await r.run()}catch(n){return Ve(e,"failed"),e.setError(n),!1}ke(e,r.id)}return!0}async function Py(){let e=Vo();return!e&&!C()?{error:new Error("GAIA isn't installed here, so there is nothing to uninstall.")}:e&&await $(e)==="developer"?{error:new Error(`${_(e)} is a development copy of GAIA, and 'gaia uninstall' removes only self-host installs.
135
- Delete it yourself if you no longer need it.`)}:{installDir:e}}async function Ty(e){if(await e.waitForInput(ze.confirm)!==!0)return null;let t=await e.waitForInput(ze.deleteData)===!0,r=t&&await e.waitForInput(ze.backup)===!0;return{deleteData:t,backup:r}}async function tp(e,t={}){if(!fe()&&!t.yes){e.setError(new Error(`There is no terminal to confirm in.
136
- Rerun with --yes (keeps your data) or --yes --delete-data.`));return}let r=await Py();if("error"in r){e.setError(r.error);return}let{installDir:n}=r,o=C()?.localName===!0;e.updateData("installDir",n),e.pushAnswerResolver(Ry(t));let i=await Ty(e);if(!i){e.setStatus("Nothing was removed."),e.updateData("cancelled",!0);return}if(!await Ay(e,Cy(e,n,o,i)))return;let s={installDir:n,keptData:!i.deleteData,...i.backup?{backupDir:Sn}:{}};e.updateData(vn,s),e.updateData("finished",!0)}var zo="GAIA is uninstalled";function Xo(e){let t=[];if(e.keptData){let r=e.installDir?` with the settings that unlock it in ${_(e.installDir)}`:"";t.push({label:"Your data",text:`kept in Docker volumes${r}; 'gaia up' picks it back up`}),t.push({label:"Delete it later",text:ep,tone:"dim"})}else t.push({label:"Your data",text:"deleted"});return e.backupDir&&t.push({label:"Backup",text:`in ${_(e.backupDir)}; 'gaia restore --from' brings it back`}),t.push({label:"The CLI",text:`remove it too with ${Zd}`,tone:"primary"}),t}import{jsx as ye,jsxs as yn}from"react/jsx-runtime";var rp=2;function Oy(e,t){switch(e){case ze.confirm:return{text:"Remove GAIA from this computer?",detail:`Its containers, networks and images go${t?`, and so does ${_(t)}`:""}. You choose about your data next.`,yesByDefault:!0};case ze.deleteData:return{text:"Delete your data too?",detail:"Accounts, chats, memories and files. This can't be undone. No keeps it, and 'gaia up' picks it back up.",yesByDefault:!1};case ze.backup:return{text:`Back it up to ${_(Sn)} first?`,detail:"Runs 'gaia backup' while GAIA is still running.",yesByDefault:!0};default:return null}}var $y=({store:e,id:t})=>{let r=Oy(t,e.currentState.data.installDir??null);return r?yn(wt,{flexDirection:"column",marginTop:1,children:[ye(aa,{dimColor:!0,children:r.detail}),yn(wt,{children:[yn(aa,{bold:!0,children:[r.text," "]}),ye(_y,{defaultChoice:r.yesByDefault?"confirm":"cancel",onConfirm:()=>e.submitInput(!0),onCancel:()=>e.submitInput(!1)},t)]})]}):null},np=({store:e})=>{let t=Te(e),r=t.data.steps??[],n=t.data[vn],{finished:o,live:i}=Bo(r),s=i.find(a=>a.state!=="pending");return yn(wt,{flexDirection:"column",width:"100%",children:[ye(Dy,{items:o,children:a=>ye(wt,{paddingLeft:rp,children:ye(Uo,{step:a})},a.id)}),yn(wt,{flexDirection:"column",paddingLeft:rp,children:[t.inputRequest&&ye($y,{store:e,id:t.inputRequest.id}),s&&ye(wt,{marginTop:o.length>0?1:0,children:ye(jo,{step:s,counter:Go(r,s),waiting:!1,status:t.status})}),t.data.cancelled===!0&&ye(wt,{marginTop:1,children:ye(aa,{children:t.status})})]}),n&&ye(wt,{marginTop:1,children:ye(Fo,{headline:zo,rows:Xo(n),accent:"green",success:!0})}),t.error&&ye(Pe,{message:t.error.message})]})};import{StatusMessage as Sp}from"@inkjs/ui";import{Box as Le,Static as yw,Text as Pr}from"ink";import{execFile as Xy}from"node:child_process";import*as dp from"node:os";import*as Jo from"node:fs";import*as op from"node:path";var Ly=e=>new Promise(t=>setTimeout(t,e));async function Qo(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 Rr(e,t,r,n,o){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 u of Gr()){let p=Br(u,r);p&&(s[u]=p)}Object.assign(s,Qa(r));let a={};o?.domain&&(a.HOST=`https://${o.domain}`,a.FRONTEND_URL=`https://${o.domain}`),i==="infisical"?(await Ny(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.")):await By(e,a,r,o?.llmProvider===void 0);let c=Jo.existsSync(tt(t))?Jo.readFileSync(tt(t),"utf-8"):null,l=My({defaults:s,existing:Tt(c),existingMode:await $(t),answers:a,setupMode:r});n&&Xa(l,n,r),r==="selfhost"&&Object.assign(l,Bn(c));try{await Gy(e,t,l,r,n,o?.domain)}catch(u){e.setError(u);return}await Ly(1e3)}function My(e){let{defaults:t,existing:r,existingMode:n,answers:o,setupMode:i}=e,s=n===i;return{...s?t:r,...s?r:t,...o,SETUP_MODE:i}}async function Ny(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 Fy(e){let t=[],r=new Set,n=new Set;for(let o of e)if(o.alternativeGroup&&!n.has(o.name)){let i=e.find(s=>s.name===o.alternativeGroup);i&&(t.push([o,i]),r.add(o.name),r.add(i.name),n.add(o.name),n.add(i.name))}return{alternativePairs:t,alternativeGroupNames:r}}async function By(e,t,r,n){e.setStatus("Parsing environment variables\u2026");let o=Ja(An(),r).filter(g=>r!=="selfhost"||g.selfhostSetup),{alternativePairs:i,alternativeGroupNames:s}=Fy(o),a=o.filter(g=>g.variables.length===1&&!s.has(g.name)),c=o.filter(g=>g.variables.length>1&&!s.has(g.name));for(let g of n?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=Gr(),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(x=>x.required),b=v.variables.some(x=>x.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,x]of Object.entries(E)){let B=v.variables.find(N=>N.name===b);(x||B?.required||B?.defaultValue)&&(t[b]=x||B?.defaultValue||"")}}}async function Gy(e,t,r,n,o,i){e.setStatus("Saving GAIA's settings\u2026");try{let s=op.join(t,"apps","api");Ur(s,r),e.setStatus("Saved GAIA's settings")}catch(s){throw new Error(`Failed to write API .env file: ${s.message}`)}if(n==="selfhost"){e.setStatus("Saving Docker's settings\u2026");try{Ii(t,o??{},n,{dockerSocketGid:Ua(),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{rc(t,n,o),e.setStatus("Saved the web app's settings")}catch(s){throw new Error(`Failed to write web .env file: ${s.message}`)}if(o&&Object.keys(o).length>0){e.setStatus("Saving Docker's settings\u2026");try{ac(t),Ii(t,o,n),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}}}import*as sp from"node:path";var la=["openrouter","gemini","openai","ollama","custom"],Uy={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"}},Zo={key:"--llm-key",baseUrl:"--llm-base-url",model:"--llm-model"};function ca(e,t){let r={key:e.llmKey,baseUrl:e.llmBaseUrl,model:e.llmModel}[t];return r!==void 0&&r!==""}function ap(e){let t=Object.keys(Zo);if(!e.llmProvider){let n=t.find(o=>ca(e,o));if(n)throw new Error(`${Zo[n]} requires --llm-provider <${la.join("|")}>.`);return}let r=e.llmProvider;for(let n of t){let o=Uy[r][n];if(o==="required"&&!ca(e,n))throw new Error(`--llm-provider ${r} requires ${Zo[n]}.`);if(o==="unused"&&ca(e,n))throw new Error(`${Zo[n]} 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 jy(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var ip="GAIA_PROVIDER_API_KEY",Cr={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},qy=/Could not save \w+: (.+)/;async function cp(e,t){let r=sp.join(e,"infra/docker");try{await le("docker",[...zi(r),"exec","-T","-e",ip,"gaia-backend","python","-m","app.scripts.save_provider",...jy(t)],r,void 0,void 0,{[ip]:t.llmKey??""})}catch(n){let o=qy.exec(n.message)?.[1];throw o?new Error(o,{cause:n}):n}}var Hy=5e3,Vy=5*6e4,Wy=5e3;async function Ky(e,t={}){let r=t.intervalMs??Hy,n=Date.now()+(t.timeoutMs??Vy),o=new Map(e.map(i=>[i.label,i]));for(;;){if(await Promise.all([...o.values()].map(async i=>{await Yy(i)&&o.delete(i.label)})),o.size===0)return{ready:!0};if(Date.now()>=n)return{ready:!1,stillStarting:[...o.keys()].join(", ")};t.onProgress?.([...o.keys()]),await J(r)}}async function Yy(e){try{let t=await fetch(e.url,{signal:AbortSignal.timeout(Wy)});return e.requireOk?t.ok:!0}catch{return!1}}async function ei(e,t){let r=await Ky([{label:"API",url:`${t.apiUrl}/ping`,requireOk:!0},{label:"Web",url:`http://localhost:${t.webPort}/login`,requireOk:!1}],{onProgress:n=>{zy(e,n)}});return e.updateData("dependencyPhase",r.ready?"GAIA is answering":`Still starting: ${r.stillStarting}`),e.updateData("dependencyComplete",!0),r}function zy(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 pp="gaia up --build",Jy="usually 10-20 minutes \xB7 safe to leave running",da="upNotice";function Qy(e,t,r){let n=e.llmProvider?Cr[e.llmProvider]:null,o={existing:{label:"Finding your install",doneLabel:"Using your install",minor:!0},bundle:{label:"Getting GAIA's setup files",doneLabel:"Got GAIA's setup files",minor:!0},clone:{label:"Downloading GAIA's source",doneLabel:"Downloaded GAIA's source"}}[t];return[{id:"docker",label:"Checking Docker",doneLabel:"Docker is ready",minor:!0},...r==="remove"?[{id:"local-name-off",label:"Removing the gaia.local name",doneLabel:"Removed the gaia.local name",minor:!0}]:[],{id:"files",...o},{id:"configure",label:"Saving your settings",doneLabel:"Saved your settings",minor:!0},...e.noStart?[]:[e.build?{id:"download",label:"Building GAIA",doneLabel:"Built GAIA"}:{id:"download",label:"Downloading GAIA",doneLabel:"Downloaded GAIA"},{id:"start",label:"Starting GAIA",doneLabel:"Started GAIA"},{id:"wait",label:"Almost ready",doneLabel:"GAIA is ready"},...r==="set-up"?[{id:"local-name",label:"Naming GAIA gaia.local on your network",doneLabel:"Named GAIA gaia.local on your network"}]:[]],...n?[{id:"provider",label:`Checking your ${n} key`,doneLabel:`Saved your ${n} key`}]:[]]}function Zy(e,t){return cr(e)?(t&&Xi(e),"existing"):t?"clone":"bundle"}function ew(e){return new Error(`${e} is set up for development (apps/api/.env is in developer mode), and 'gaia up' would overwrite its settings.
137
- Run it with --force-dev-tree to go ahead anyway.`)}function Ar(e,t){Ve(e,"failed"),e.setError(t)}async function mp(e,t={}){ap(t);let r=Math.min(Date.now(),...Object.values(Fn()).map(E=>E.startedAt)),n=Vo(),o=n??Dd,i;try{i=Zy(o,t.build===!0)}catch(E){e.setError(E);return}e.pushAnswerResolver($d({repoPath:o}));let s=t.domain??$n(o),a=rw(t,s);if(uo(e,Qy(t,i,a)),e.setStep("Prerequisites"),!await tw(e,t,i)||!t.build&&!await aw(e,o,i!=="existing")||!await iw(e,a))return;let c=await dr(e,"selfhost");if(c===null){Ve(e,"failed");return}if(Object.assign(c,Od(t)),i==="existing"&&o!==n&&!t.forceDevTree&&await $(o)==="developer"){Ar(e,ew(o));return}if(ke(e,"docker"),e.setStep("Repository Setup"),me(e,"files"),!await lw(e,o,i))return;if(Se(t.codeSandbox===void 0?{repoPath:o}:{repoPath:o,codeSandbox:t.codeSandbox}),ke(e,"files",i==="existing"?`Using your install at ${_(o)}`:void 0),e.setStep("Environment Setup"),me(e,"configure"),await Rr(e,o,"selfhost",c,{llmProvider:t.llmProvider,domain:t.domain}),e.currentState.error){Ve(e,"failed");return}ke(e,"configure");let l=nw(o),u=l.webPort,p={...ow(u,s),noStart:t.noStart===!0,stillStarting:!1,setupComplete:!1,codeSandbox:C()?.codeSandbox===!0,joinedDockerGroup:fc(),elapsedMs:0,startedServices:0};if(t.noStart){up(e,o,{...p,elapsedMs:Date.now()-r});return}e.setStep("Project Setup");try{p.startedServices=await mw(e,o,c,t)}catch(E){Ar(e,E);return}me(e,"wait");let m=l.apiUrl,g=await ei(e,{apiUrl:m,webPort:u});g.ready?ke(e,"wait"):ve(e,"wait",{state:"failed",endedAt:Date.now()}),p.stillStarting=!g.ready,p.setupComplete=g.ready&&await fw(m),Object.assign(p,await sw(e,a,u,g.ready));let v=await dw(e,o,t,g.ready);if(t.llmProvider&&(v?p.unsavedProvider=t.llmProvider:p.savedProvider=t.llmProvider),up(e,o,{...p,elapsedMs:Date.now()-r}),v){e.setError(v);return}g.ready&&uw(p.webUrl,t)}async function tw(e,t,r){me(e,"docker");try{return await mo(e,{needGit:r==="clone",assumeYes:t.yes===!0,rerunCommand:"gaia up",onInstallStart:o=>me(e,"docker",{label:`Installing ${ur(o)}`,doneLabel:`${ur(o)} installed`,minor:!1,startedAt:Date.now()}),onInstallProgress:o=>ve(e,"docker",{label:o.label,detail:o.detail,amount:o.amount})})!=="relaunch"}catch(n){return n instanceof rn?(en(e,"docker"),e.updateData(da,n.message),process.exitCode=1,!1):(Ar(e,n),!1)}}function rw(e,t){return Wd({optedOut:e.localName===!1,domain:t,setUpBefore:C()?.localName===!0})}function nw(e){let t=A(e);return{webPort:t[O]??O,apiUrl:de("selfhost",t)}}function ow(e,t){return{webUrl:Zi(e,t),reachableUrls:Sl(e,t),localCertificate:t!==void 0&&Pn(t)}}async function iw(e,t){if(t!=="remove")return!0;me(e,"local-name-off");try{await Yo()}catch(r){return Ar(e,new Error(`Couldn't remove the gaia.local name: ${r.message}`)),!1}return Se({localName:!1}),ke(e,"local-name-off"),!0}async function sw(e,t,r,n){if(t!=="set-up")return{};if(me(e,"local-name"),!n)return en(e,"local-name"),{localNameProblem:"GAIA didn't answer in time; run 'gaia up' again once 'gaia status' shows it running"};Se({localName:!0});try{await Jd(r)}catch(o){return en(e,"local-name"),{localNameProblem:o.message}}return ke(e,"local-name"),{localUrl:Hd}}async function aw(e,t,r){let n=r?Ge:Be(t);e.setStatus(`Checking that GAIA ${n} is available for this computer\u2026`);let o=await or(n,C()?.bots??[]);if(!o)return!0;let{cause:i,next:s}=rr(o,pp);return Ar(e,new Error(`${i}
138
- ${s}`)),!1}function cw(e,t){let r=vr();return({received:n,total:o})=>ve(e,t,o===null?{detail:`${qe(n)} downloaded`}:{amount:{done:n,total:o,unit:"bytes",estimated:!1},etaMs:r.update(n,o)})}async function lw(e,t,r){if(r==="existing")return!0;try{if(r==="bundle"){let n=await Qn(t,Ge,cw(e,"files"));return await Jn(n.manifest,n.stagingDir,t,[]),Kr(t,Ge),!0}ve(e,"files",{detail:"Connecting to GitHub\u2026"}),await Tc(t,Ac,(n,o)=>{ve(e,"files",o?{percent:n,detail:o}:{percent:n})})}catch(n){return Ar(e,new Error(`Couldn't get GAIA into ${_(t)}: ${n.message}`)),!1}return!0}function uw(e,t){let r=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;!t.yes&&r&&dp.platform()==="darwin"&&Xy("open",[`${e}/setup`],()=>{})}async function dw(e,t,r,n){let{llmProvider:o}=r;if(!o)return null;let i=Cr[o];if(me(e,"provider"),!n)return Ve(e,"failed"),new Error(`GAIA didn't answer in time, so your ${i} key wasn't saved.
139
- Once 'gaia status' shows it running, run 'gaia up' again with the same flags.`);try{await cp(t,{...r,llmProvider:o})}catch(s){return Ve(e,"failed"),new Error(`Your ${i} key wasn't saved: ${s.message}
140
- Check the key and run 'gaia up --llm-provider ${o} --llm-key <key>' again, or add it on the setup page above.`)}return ke(e,"provider"),null}function pw(e){return e.stage==="starting"||e.stage==="stopping"?"start":"download"}function ua(e,t){return(e.currentState.data[Mt]??[]).find(n=>n.id===t)?.state}function lp(e){let t=ua(e,"download");t==="active"&&ke(e,"download"),t==="pending"&&en(e,"download")}async function mw(e,t,r,n){me(e,"download",n.build?{hint:Jy}:{detail:"Checking which images this computer needs"});let o=vr(),i=a=>{let c=pw(a);c==="start"&&lp(e),ua(e,c)!=="active"&&me(e,c);let l=a.amount?.unit==="bytes"?a.amount:void 0;ve(e,c,{detail:a.detail??a.label,percent:a.percent,amount:a.amount,etaMs:l?o.update(l.done,l.total):void 0})},{startedServices:s}=await ce(t,"selfhost",void 0,r,i,{...n.build?{build:!0}:{pull:"missing"},rebuildCommand:pp,onLogFile:a=>e.updateData("logPath",a)});return lp(e),ua(e,"start")!=="active"&&me(e,"start"),ke(e,"start",s===0?"GAIA was already running":void 0),s}async function fw(e){let t=await He(e,"status");return"data"in t&&!t.data.needs_setup}function up(e,t,r){Se({version:R,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 ti=[["gaia status","check health"],["gaia stop","stop GAIA"],["gaia doctor","find problems"],["gaia --help","all commands"]],gw="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 hw(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 ${ft(e.elapsedMs)}`;return e.unsavedProvider?`${t} \xB7 your ${Cr[e.unsavedProvider]} key wasn't saved`:e.startedServices===0?`${t} \xB7 nothing to do`:t}function Sw(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"}var fp="On your network";function vw(e){return e.localNameProblem?{label:fp,text:`gaia.local isn't set up: ${e.localNameProblem}`,tone:"warn"}:e.localUrl?{label:fp,text:`${e.localUrl}, from phones and other computers here`,url:e.localUrl}:null}function ri(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 n=`${e.webUrl}/setup`;t.push(e.setupComplete?{label:"Next",text:`Open ${e.webUrl}`,url:e.webUrl,tone:"primary"}:{label:"Next",text:`Open ${n} to create your admin account and pick an AI model.`,url:n,tone:"primary"});let o=e.reachableUrls.filter(i=>i!==e.webUrl);o.length>0&&t.push({label:"Also at",text:o.join(", "),tone:"dim"})}let r=vw(e);return r&&t.push(r),e.localCertificate&&t.push({label:"Certificate",text:`from GAIA's own certificate authority, so browsers warn until a device trusts it. Copy it with: ${Za}`,tone:"warn"}),e.savedProvider&&t.push({label:"AI",text:`${Cr[e.savedProvider]} key saved \xB7 change it in Settings`}),t.push({label:"Code execution",text:Sw(e.codeSandbox),tone:"dim"}),e.joinedDockerGroup&&t.push({label:"Docker",text:gw,tone:"warn"}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:hw(e),rows:t}}import{jsx as F,jsxs as Yt}from"react/jsx-runtime";var ww={kind:"header"},gp=2,bw=14,hp=30,Ew=({outcome:e})=>{let t=ri(e),r=t.tone==="success"?"green":w;return Yt(Le,{flexDirection:"column",marginTop:1,children:[F(Fo,{headline:t.headline,rows:t.rows,accent:r,success:t.tone==="success"}),F(Le,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:hp*2+4,children:ti.map(([n,o])=>Yt(Le,{width:hp,children:[F(Le,{width:bw,children:F(Pr,{color:w,children:n})}),F(Pr,{color:"gray",children:o})]},n))})]})},xw=({state:e,store:t})=>e.inputRequest?.id==="port_conflicts"?e.data.portConflicts?F(wr,{portResults:e.data.portConflicts,onAccept:()=>t.submitInput("accept"),onAbort:()=>t.submitInput("abort")}):null:F(br,{inputId:e.inputRequest?.id,missing:e.data[Bt],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),Iw=()=>Yt(Le,{flexDirection:"column",marginTop:1,marginBottom:1,children:[Yt(Pr,{children:[F(Pr,{bold:!0,children:"GAIA"}),F(Pr,{dimColor:!0,children:` v${R} \xB7 setting up`})]}),Xn(process.env,R).map(e=>F(Sp,{variant:"warning",children:e},e))]}),vp=({store:e})=>{let t=Te(e),r=t.data.steps??[],n=t.data.upOutcome,o=t.data.logPath,i=t.data[da],s=t.data.finished===!0&&n!==void 0,{finished:a,live:c}=Bo(r),l=c.find(p=>p.state!=="pending"),u=[...Nn()?[]:[ww],...a.map(p=>({kind:"step",step:p}))];return Yt(Le,{flexDirection:"column",width:"100%",children:[F(yw,{items:u,children:p=>F(Le,{paddingLeft:gp,children:p.kind==="header"?F(Iw,{}):F(Uo,{step:p.step})},p.kind==="header"?"header":p.step.id)}),Yt(Le,{flexDirection:"column",paddingLeft:gp,children:[l&&F(Le,{marginTop:a.length>0?1:0,children:F(jo,{step:l,counter:Go(r,l),waiting:t.inputRequest!==null,status:t.status})}),F(xw,{state:t,store:e}),i&&F(Le,{marginTop:1,children:F(Sp,{variant:"warning",children:i})}),o&&!s&&!t.error&&F(Le,{marginTop:1,marginLeft:2,children:Yt(Pr,{dimColor:!0,children:["Full log: ",_(o)]})})]}),s&&F(Ew,{outcome:n}),t.error&&F(Pe,{message:t.error.message})]})};import{Select as fa,Spinner as Uw}from"@inkjs/ui";import{Box as h,Text as f,useInput as _r}from"ink";import bn from"ink-text-input";import{useEffect as ga,useState as we}from"react";import{Box as kw,Text as pa,useInput as Rw}from"ink";import{useEffect as Cw,useRef as Aw,useState as Pw}from"react";import{jsx as Tw,jsxs as ma}from"react/jsx-runtime";var yp=8;function wp(e,t){return`${e} ${t}${e===1?"":"s"}`}var ni=({logs:e})=>{let[t,r]=Pw(0),n=Math.min(e.length,yp),o=e.length>yp,i=Aw(e.length);Cw(()=>{e.length!==i.current&&(i.current=e.length,r(0))},[e.length]),Rw((c,l)=>{o&&(l.upArrow?r(u=>Math.min(u+1,e.length-n)):l.downArrow&&r(u=>Math.max(0,u-1)))});let s=Math.max(0,e.length-n-t),a=e.slice(s,s+n);return ma(kw,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&ma(pa,{color:"gray",children:[wp(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>Tw(pa,{color:"gray",wrap:"truncate",children:c},s+l)),t>0&&ma(pa,{color:"gray",children:[wp(t,"newer line")," (\u2193)"]})]})};import{Box as wn,Text as oi}from"ink";import{Box as _w,Text as Dw}from"ink";import{jsx as bp}from"react/jsx-runtime";var Ow=new Set(["Welcome","Finished"]),Ep=({status:e,step:t})=>Ow.has(t)?null:bp(_w,{width:"100%",paddingX:1,marginTop:1,children:bp(Dw,{color:"gray",dimColor:!0,children:e})});import $w from"chalk";import{Box as Lw,Text as Mw,useStdout as Nw}from"ink";import{useEffect as Fw,useState as xp}from"react";import{jsx as Ip}from"react/jsx-runtime";var Tr=({size:e="small",showStatus:t=!0,showUpdate:r=!0})=>{let{stdout:n}=Nw(),o=$o(),[i,s]=xp(null),[a]=xp(()=>r?co():null);Fw(()=>{if(!t){s(null);return}let l=!0;return ao().then(u=>{l&&s(u)}),()=>{l=!1}},[t]);let c=lo({size:e,level:$w.level,...o,...is(n),version:R,status:t?i:null,update:a});return Ip(Lw,{marginTop:1,children:Ip(Mw,{children:c.join(`
141
- `)})})};import{jsx as bt,jsxs as ii}from"react/jsx-runtime";var Bw=[{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"}],kp=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Gw=({currentStep:e,steps:t})=>{let r=t.findIndex(o=>o.id===e),n=r===t.length-1;return bt(wn,{marginY:1,flexWrap:"wrap",children:t.map(({id:o,label:i},s)=>{let a=s<r||n,c=s===r&&!n;return ii(wn,{flexShrink:0,children:[s>0&&bt(oi,{color:"gray",children:" \xB7 "}),a&&ii(oi,{color:"green",children:[y.ok," ",i]}),c&&bt(oi,{color:w,bold:!0,children:i}),!a&&!c&&bt(oi,{color:"gray",children:i})]},o)})})},si=({children:e,status:t,step:r,steps:n=Bw,header:o})=>ii(wn,{flexDirection:"column",height:"100%",width:"100%",children:[ii(wn,{flexGrow:1,flexDirection:"column",children:[bt(Tr,{...o}),bt(Gw,{currentStep:r,steps:n}),bt(wn,{flexDirection:"column",flexGrow:1,children:e})]}),bt(Ep,{status:t,step:r})]});import{jsx as d,jsxs as S}from"react/jsx-runtime";var jw=({onConfirm:e})=>(_r((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:T,borderColor:w,children:[d(f,{bold:!0,children:"Welcome to GAIA Setup"}),S(h,{flexDirection:"column",marginTop:1,marginBottom:1,children:[d(f,{children:"This wizard will guide you through the setup process:"}),d(f,{children:" 1. Check prerequisites and choose setup mode"}),d(f,{children:" 2. Clone repository"}),d(f,{children:" 3. Configure environment variables"}),d(f,{children:" 4. Install tools and dependencies"})]}),d(f,{dimColor:!0,children:"~5-15 min depending on network speed"}),d(h,{marginTop:1,children:S(f,{color:w,children:[d(f,{bold:!0,children:"Enter"})," to start"]})})]})),qw=({defaultValue:e,onSubmit:t})=>{let[r,n]=we(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(f,{children:"Clone repository to:"}),d(f,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),S(h,{marginTop:1,children:[d(f,{color:w,children:"\u2192 "}),d(bn,{value:r,onChange:n,onSubmit:t})]})]})},Hw=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:"yellow",children:[d(h,{marginBottom:1,children:d(f,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),S(f,{children:["Found a GAIA installation at"," ",d(f,{color:"cyan",bold:!0,children:e})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"What would you like to do?"})}),d(h,{marginTop:1,children:d(fa,{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:n=>t(n)})})]}),Vw=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:n})=>{_r((s,a)=>{a.return&&n()});let o=t?.[3e3]??3e3,i=de(e??"developer",t??{});return e==="selfhost"?S(h,{flexDirection:"column",marginTop:2,borderStyle:T,borderColor:"green",padding:1,children:[d(f,{bold:!0,color:"green",children:r?"GAIA is starting\u2026":"GAIA is running"}),d(h,{marginTop:1,children:d(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:",o,"/setup"]})]}),S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),S(f,{children:["API:"," ",d(f,{color:"cyan",bold:!0,children:i})]})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia doctor"})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," to exit"]})})]}):S(h,{flexDirection:"column",marginTop:2,borderStyle:T,borderColor:w,padding:1,children:[d(f,{color:w,bold:!0,children:"You're all set!"}),S(h,{marginTop:1,children:[d(f,{bold:!0,children:"Run: "}),d(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:",o]})]}),S(f,{children:["API:"," ",d(f,{color:"cyan",bold:!0,children:i})]})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," to exit"]})})]})},ha=({phase:e,progress:t,isComplete:r,logs:n,title:o,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(h,{marginBottom:1,children:d(f,{bold:!0,color:w,children:o||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[d(h,{children:r?S(f,{color:"green",children:[y.ok," ",e]}):d(Uw,{label:e||"Preparing\u2026"})}),!r&&t>0&&d(yr,{percent:t}),!r&&n&&n.length>0&&d(ni,{logs:n}),!r&&d(h,{marginTop:1,children:d(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),Sa=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(f,{bold:!0,children:"Setup Mode"}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"How do you want to run GAIA?"})}),d(h,{marginTop:1,children:d(fa,{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)})})]}),va=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(f,{bold:!0,children:"Environment Variables Setup"}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"Choose how you want to configure environment variables:"})}),d(h,{marginTop:1,children:d(fa,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),S(h,{marginTop:1,flexDirection:"column",children:[d(f,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),d(f,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),ya=({onSubmit:e})=>{let[t,r]=we({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[n,o]=we(0),[i,s]=we(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"}];_r((l,u)=>{if(u.tab||u.downArrow)o(p=>p<a.length-1?p+1:p);else if(u.upArrow)o(p=>p>0?p-1:p);else if(u.return){if(n<a.length-1){o(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&&o(m);return}e(t)}});let c=a[n];return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(h,{marginBottom:1,children:d(f,{bold:!0,color:w,children:"Infisical Configuration"})}),d(h,{marginBottom:1,children:d(f,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),S(h,{marginBottom:1,flexDirection:"column",children:[d(f,{color:"gray",children:"Configure your Infisical credentials."}),S(f,{color:"gray",dimColor:!0,children:["Visit"," ",d(f,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),a.map((l,u)=>{let p=l.key.includes("SECRET")||l.key.includes("TOKEN");return S(h,{flexDirection:"column",marginBottom:1,children:[d(h,{children:S(f,{color:u===n?w:"white",children:[u===n?"\u25B8 ":" ",l.key,":"]})}),d(h,{marginLeft:2,children:d(f,{color:"gray",dimColor:!0,children:l.description})}),u===n?d(h,{marginLeft:2,children:d(bn,{value:t[l.key],onChange:m=>{r(g=>({...g,[l.key]:m})),s(null)},placeholder:"Enter value\u2026",mask:p?"*":void 0})}):d(h,{marginLeft:2,children:d(f,{color:t[l.key]?"green":"gray",children:t[l.key]?p?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[l.key]}`:"(not set)"})})]},l.key)}),i&&d(h,{marginTop:1,children:d(f,{color:"red",children:i})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," confirm \xB7 ",d(f,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},wa=({category:e,currentIndex:t,totalGroups:r,onSubmit:n})=>{let[o,i]=we(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=we(0),[c,l]=we(null);ga(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),_r((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&&!o[E.name]?.trim());if(v.length>0){l(`Required fields cannot be skipped: ${v.map(E=>E.name).join(", ")}`);return}n(o)}});let u=()=>{if(s<e.variables.length-1)a(s+1);else{let m=e.variables.filter(g=>g.required&&!o[g.name]?.trim());if(m.length>0){l(`Required fields are missing: ${m.map(g=>g.name).join(", ")}`);return}l(null),n(o)}},p=e.variables.some(m=>m.required);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,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]})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:e.description})}),d(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&&d(h,{marginLeft:2,children:d(bn,{value:o[m.name]||"",onChange:b=>{i(x=>({...x,[m.name]:b})),c&&l(null)},onSubmit:u,placeholder:E?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&d(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," next \xB7 ",d(f,{bold:!0,children:"\u2191\u2193"})," navigate",!p&&S(f,{children:[" ","\xB7 ",d(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},ba=({alternatives:e,onSubmit:t})=>{let[r,n]=we(new Set),[o,i]=we({}),[s,a]=we(0),[c,l]=we(null);ga(()=>{let b={};for(let x of e)for(let B of x.variables)b[B.name]=B.defaultValue||"";i(b)},[e]);let u=[];for(let b=0;b<e.length;b++)if(u.push({type:"provider",categoryIndex:b}),r.has(b)){let x=e[b];if(x)for(let B=0;B<x.variables.length;B++)u.push({type:"field",categoryIndex:b,fieldIndex:B})}u.push({type:"submit"});let p=u[s],m=p?.type==="field",g=p?.type==="submit";_r((b,x)=>{let B=Math.min(s,u.length-1);if(B!==s){a(B);return}if(m)x.upArrow?a(N=>Math.max(0,N-1)):(x.downArrow||x.tab)&&a(N=>Math.min(u.length-1,N+1));else if(g)x.upArrow?a(N=>Math.max(0,N-1)):(x.return||b===" ")&&E();else if(x.upArrow)a(N=>Math.max(0,N-1));else if(x.downArrow||x.tab)a(N=>Math.min(u.length-1,N+1));else if((x.return||b===" ")&&p?.type==="provider"){let N=p.categoryIndex;n(Rt=>{let G=new Set(Rt);return G.has(N)?G.delete(N):G.add(N),G}),c&&l(null)}});let v=()=>{c&&l(null),a(b=>Math.min(u.length-1,b+1))},E=()=>{let b=[],x={};for(let B of r){let N=e[B];if(!N)continue;if(N.variables.some(G=>o[G.name]?.trim())){b.push(N.name);for(let G of N.variables){let In=o[G.name];In&&(x[G.name]=In)}}}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,x)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:c?"red":w,children:[S(h,{justifyContent:"space-between",children:[d(f,{bold:!0,children:"Configure AI Provider"}),d(f,{color:"yellow",children:"* At least one required"})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),d(h,{marginTop:1,flexDirection:"column",children:e.map((b,x)=>{let B=r.has(x),N=u.findIndex(G=>G.type==="provider"&&G.categoryIndex===x),Rt=s===N;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[d(f,{color:Rt?w:void 0,bold:Rt,children:Rt?"\u279C ":" "}),d(f,{color:B?"green":"gray",children:B?`[${y.ok}]`:"[ ]"}),S(f,{color:B?w:"gray",bold:B,children:[" ",b.name]}),b.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",b.description]})]}),Rt&&b.docsUrl&&S(h,{marginLeft:6,children:[d(f,{color:"yellow",children:"\u{1F4D6} "}),d(f,{color:"blue",underline:!0,children:b.docsUrl})]}),B&&d(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:b.variables.map((G,In)=>{let wm=u.findIndex($r=>$r.type==="field"&&$r.categoryIndex===x&&$r.fieldIndex===In),Qt=s===wm,Ta=!!G.defaultValue,gi=o[G.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Qt?w:"gray",bold:Qt,children:[Qt?" \u279C ":" ",G.name]}),!Qt&&gi&&d(f,{color:"green",children:" \u2713"}),!Qt&&!gi&&Ta&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",G.defaultValue,")"]})]}),Qt&&d(h,{marginLeft:4,children:d(bn,{value:gi,onChange:$r=>{i(bm=>({...bm,[G.name]:$r})),c&&l(null)},onSubmit:v,placeholder:Ta?`Default: ${G.defaultValue}`:"Enter value\u2026"})})]},G.name)})})]},b.name)})}),c&&d(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),S(h,{marginTop:1,children:[d(f,{color:g?w:void 0,bold:g,children:g?"\u279C ":" "}),d(h,{borderStyle:T,borderColor:g?w:"gray",paddingX:2,children:d(f,{color:g?w:"gray",bold:g,children:"Continue \u2192"})})]}),d(h,{marginTop:1,children:d(f,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},Ea=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:n,onSkip:o})=>{let[i,s]=we(e.defaultValue||""),[a,c]=we(null);ga(()=>{s(e.defaultValue||""),c(null)},[e.name]),_r((p,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}o()}});let l=p=>{if(e.required&&!p.trim()){c("This field is required");return}c(null),n(p)},u=!!e.defaultValue;return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:a?"red":w,children:[S(h,{justifyContent:"space-between",children:[S(h,{children:[d(f,{color:w,bold:!0,children:e.name}),e.required?d(f,{color:"red",children:" *"}):S(f,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),S(f,{color:"gray",children:[t+1,"/",r]})]}),d(h,{marginLeft:1,children:d(f,{color:"gray",children:e.description})}),S(h,{marginTop:1,children:[d(f,{color:w,children:"\u2192 "}),d(bn,{value:i,onChange:p=>{s(p),a&&c(null)},onSubmit:l,placeholder:u?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),a&&d(h,{marginTop:1,children:d(f,{color:"red",children:a})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," confirm",!e.required&&S(f,{children:[" ","\xB7 ",d(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Rp=({store:e})=>{let t=Te(e);return S(si,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&d(jw,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&d(qo,{checks:t.data.checks}),d(br,{inputId:t.inputRequest?.id,missing:t.data[Bt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&d(wr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&d(qw,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&d(Hw,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&d(Pd,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&d(Sa,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&d(va,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&d(ya,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&d(Ea,{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&&d(wa,{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&&d(ba,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&d(Ho,{status:t.status}),t.step==="Finished"&&d(Vw,{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")&&d(ha,{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&&d(Pe,{message:t.error.message})]})};import{Spinner as Ww}from"@inkjs/ui";import{Box as zt,Text as Dr}from"ink";import{useState as Kw}from"react";import{jsx as Et,jsxs as Me}from"react/jsx-runtime";var Cp=({store:e})=>{let t=Te(e),r=t.step==="Starting"||t.step==="Stopping",n=t.step==="Running"||t.step==="Stopped",o=t.data.dockerLogs??[],[i]=Kw(Date.now),s=ta(r);return Me(zt,{flexDirection:"column",width:"100%",children:[Et(Tr,{showStatus:n}),r&&!t.error&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[Et(Ww,{label:t.status||"Working\u2026"}),Me(Dr,{color:"gray",children:[" ",ft(s-i)]})]}),o.length>0&&Et(ni,{logs:o})]}),t.step==="Running"&&t.data.started&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[Et(Ae,{kind:"ok"}),Me(Dr,{children:["GAIA is running at"," ",Et(Dr,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),Me(Dr,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[Et(Ae,{kind:"ok"}),Et(Dr,{children:t.status})]}),t.data.stopMode==="force-ports"&&Me(Dr,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&Et(Pe,{message:t.error.message})]})};import{Spinner as Yw}from"@inkjs/ui";import{Box as xt,Text as _e,useInput as zw}from"ink";import{jsx as P,jsxs as Xe}from"react/jsx-runtime";var Ap=({store:e})=>{let t=Te(e);return Xe(si,{status:t.status,step:t.step,steps:kp,children:[t.step==="Detect Repo"&&Xe(xt,{flexDirection:"column",paddingX:2,borderStyle:T,borderColor:w,children:[P(_e,{bold:!0,children:"Detecting GAIA Repository"}),P(xt,{marginTop:1,children:P(Yw,{label:"Searching for repository\u2026"})}),t.data.repoPath&&P(xt,{marginTop:1,children:Xe(_e,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&P(qo,{checks:t.data.checks}),P(br,{inputId:t.inputRequest?.id,missing:t.data[Bt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&P(wr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&P(Sa,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&P(va,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&P(ya,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&P(Ea,{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&&P(wa,{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&&P(ba,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&P(Ho,{status:t.status}),t.step==="Project Setup"&&P(ha,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&P(Xw,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&P(Pe,{message:t.error.message})]})},Xw=({setupMode:e,portOverrides:t,onConfirm:r})=>{zw((s,a)=>{a.return&&r()});let n=t?.[3e3]??3e3,o=de(e??"developer",t??{}),i=e==="selfhost";return Xe(xt,{flexDirection:"column",marginTop:2,borderStyle:T,borderColor:w,padding:1,children:[P(_e,{color:w,bold:!0,children:"Setup Complete!"}),Xe(xt,{marginTop:1,children:[P(_e,{bold:!0,children:"Run: "}),P(_e,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Xe(xt,{marginTop:1,flexDirection:"column",children:[Xe(_e,{children:["Web:"," ",Xe(_e,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),Xe(_e,{children:["API:"," ",P(_e,{color:"cyan",bold:!0,children:o})]})]}),P(xt,{marginTop:1,children:P(_e,{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"})}),P(xt,{marginTop:1,children:Xe(_e,{dimColor:!0,children:[P(_e,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as cb}from"@inkjs/ui";import{Box as re,Text as Je,useInput as lb}from"ink";var Jw=[{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 Pp(e){return Promise.all(Jw.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?Qw(t.name,r,t.path):Zw(t.name,r)}))}async function Qw(e,t,r){let n=Date.now();try{let o=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-n;return{name:e,port:t,status:o.ok?"up":"down",latency:i,details:o.ok?`HTTP ${o.status}`:`HTTP ${o.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function Zw(e,t){let r=await import("node:net"),n=Date.now();return new Promise(o=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let s=Date.now()-n;i.destroy(),o({name:e,port:t,status:"up",latency:s})}),i.on("timeout",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function Tp(e){let t=await Z();if(t!=="ready")return{access:t,problem:await et(t),containers:[]};let r=await Ba(be[e]);return{access:t,containers:r}}var En="statusFacts";async function eb(){let e=L(),t=e?await $(e):null,r=zr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let n=A(e),o=n[O]??O,[i,s,a]=await Promise.all([t==="developer"?Pp(n):[],Tp(t),Oo($t(t,n),be[t])]),c=a.reachable?await He(de(t,n),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:tb(s.containers)}:s,readiness:a,services:i,webUrl:pt(e,o),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function tb(e){let t=(C()?.bots??[]).map(xe).filter(r=>!e.some(n=>n.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function rb(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await eb();e.updateData(En,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function _p(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await rb(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var nb=["gaia-web","gaia-backend","arq_worker","proxy"],ob=["mongo","postgres","redis","rabbitmq","chromadb"];function ai(e,t,r){return t.some(o=>!o.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function Dp(e,t){return t.map(r=>e.find(n=>n.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:je(r.name)}))}function Op(e,t){let r=e.readiness,n=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:Un(i.name)})):Dp(t,ob),o=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return ai("Data",n,o??"See why with: gaia doctor")}function ib(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"}:ai("Bots",t.map(r=>({ok:r.status==="running",name:je(r.name)})),"See why with: gaia doctor")}function $p(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 sb(e,t){let r=t.containers,o=[ai("App",Dp(r,nb),"Start it: gaia start"),Op(e,r),ib(r)],i=$p(e);i&&o.push(i);let s=r.some(c=>c.status==="running"),a=o.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:o,unhealthy:a}:{headline:{kind:"fail",text:"GAIA isn't running \xB7 start it: gaia start"},rows:[],unhealthy:!0}}function ab(e){let t=e.services.map(n=>({ok:n.status==="up",name:`${n.name} :${n.port}`})),r=ai("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 ci(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,n={label:"Docker",items:[],note:t.problem.state,tone:"warn"},o=$p(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?[Op(e,[]),...o?[o]:[],n]:[],unhealthy:!0}}return e.services.length>0?ab(e):sb(e,t??{access:"ready",containers:[]})}import{jsx as M,jsxs as ot}from"react/jsx-runtime";var ub=8,db={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},pb=({row:e})=>ot(re,{children:[M(re,{width:ub,flexShrink:0,children:M(Je,{bold:!0,children:e.label})}),ot(re,{flexDirection:"column",flexShrink:1,children:[e.items.length>0&&M(re,{flexWrap:"wrap",children:e.items.map(t=>ot(re,{marginRight:2,flexShrink:0,children:[M(Ae,{kind:t.ok?"ok":"fail"}),M(Je,{children:t.name})]},t.name))}),e.note&&ot(re,{children:[e.items.length===0&&e.tone!=="dim"&&M(Ae,{kind:e.tone==="warn"?"warn":"ok"}),M(Je,{color:db[e.tone],children:e.note})]})]})]}),Lp=({store:e})=>{let t=Te(e),r=t.data[En],n=t.data.watch===!0,o=t.step==="Results"&&r!==void 0;lb((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:n&&t.inputRequest!==null});let i=r?ci(r):null,s=i?.headline.kind??"ok";return ot(re,{flexDirection:"column",width:"100%",children:[M(Tr,{showStatus:!1}),t.step==="Checking"&&M(re,{marginTop:1,marginLeft:2,children:M(cb,{label:t.status})}),o&&i&&ot(re,{flexDirection:"column",marginTop:1,marginLeft:2,children:[ot(re,{children:[M(Ae,{kind:s==="ok"?"active":s}),M(Je,{bold:!0,children:i.headline.text})]}),i.headline.url&&M(re,{marginLeft:2,children:M(Je,{color:w,children:i.headline.url})}),i.hint&&M(re,{marginLeft:2,children:M(Je,{children:i.hint})}),i.rows.length>0&&M(re,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>M(pb,{row:a},a.label))}),r.installed&&M(re,{marginTop:1,children:ot(Je,{color:"gray",children:["Installed at ",r.install]})}),n&&M(re,{marginTop:1,children:ot(Je,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",M(Je,{bold:!0,children:"r"})," check again \xB7 ",M(Je,{bold:!0,children:"q"})," quit"]})})]}),t.error&&M(Pe,{message:t.error.message})]})};import{defaultTheme as mb,extendTheme as fb}from"@inkjs/ui";var li={success:"ok",error:"fail",warning:"warn",info:"active"},Mp=fb(mb,{components:{Spinner:{styles:{frame:()=>({color:w})}},ProgressBar:{styles:{completed:()=>({color:w})},config:()=>({completedCharacter:hi.done,remainingCharacter:hi.rest})},StatusMessage:{styles:{icon:({variant:e})=>({color:Mr[li[e]]})},config:({variant:e})=>({icon:y[li[e]]})},Alert:{styles:{icon:({variant:e})=>({color:Mr[li[e]]})},config:({variant:e})=>({icon:y[li[e]]})}}});import{jsx as ne,jsxs as Or}from"react/jsx-runtime";var vb=["init","setup","status","start","stop","up","uninstall"],xa=class extends Sb.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Or(ui,{flexDirection:"column",padding:1,children:[ne(Xt,{color:"red",bold:!0,children:"An unexpected error occurred:"}),ne(Xt,{color:"red",children:this.state.error.message}),this.state.error.stack&&ne(ui,{marginTop:1,children:ne(Xt,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},yb=({store:e,command:t})=>{switch(t){case"init":return ne(Rp,{store:e});case"setup":return ne(Ap,{store:e});case"status":return ne(Lp,{store:e});case"start":case"stop":return ne(Cp,{store:e,command:t});case"up":return ne(vp,{store:e});case"uninstall":return ne(np,{store:e});default:return Or(ui,{flexDirection:"column",padding:1,children:[Or(Xt,{color:"red",children:["Unknown command: ",t]}),Or(ui,{marginTop:1,flexDirection:"column",children:[ne(Xt,{bold:!0,children:"Available commands:"}),vb.map(r=>Or(Xt,{children:[" ",ne(Xt,{color:"cyan",children:r})]},r))]})]})}},wb=({onCancel:e})=>(hb((t,r)=>{r.ctrl&&t==="c"&&e()}),null),Np=({store:e,command:t,onCancel:r})=>ne(xa,{children:Or(gb,{theme:Mp,children:[ne(wb,{onCancel:r}),ne(yb,{store:e,command:t})]})});import{EventEmitter as bb}from"events";var Eb=150,Ia=class extends bb{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))},Eb))}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,n){return this.answerResolvers.map(i=>i(t,n)).find(i=>i!==void 0)===void 0&&!this.autoResolveInputs.has(t)&&this.setStatus(r),this.waitForInput(t,n)}waitForInput(t,r,n){if(this.autoResolveInputs.has(t))return this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t));for(let o of this.answerResolvers){let i=o(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(o=>{if(this.inputResolver=o,n!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),o(null))},n),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())}},Fp=()=>new Ia;async function ge(e){let t=Fp();if(e.whenNonInteractive==="fail"){Wl(e.command),await Gp(t,e);return}fe()?await Gp(t,e):await kb(t,e)}async function kb(e,t){Kl(e,Nn());for(let[r,n]of t.autoResolve??[])e.setAutoResolve(r,n);try{await t.runFlow(e);let r=jp(e);r&&await $i(e.currentState.step,r,us(e)),t.onPlainComplete?.(e)}catch(r){e.setError(r)}qp(e)}var Up=30,Rb=Math.ceil(1e3/Up);async function Bp(e){e.flush(),await new Promise(t=>setTimeout(t,2*Rb))}async function Gp(e,t){let r=async()=>{},{unmount:n,clear:o}=xb(Ib.createElement(Np,{store:e,command:t.command,onCancel:()=>void r()}),{exitOnCtrlC:!1,maxFps:Up}),i=async()=>{Ve(e,"cancelled"),await Bp(e),n();let a=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
142
- ${y.cancelled} Cancelled.${a}
143
- `),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 Bp(e);let s=jp(e);s&&(o(),n(),await $i(e.currentState.step,s,us(e))),n(),process.stdout.write(`
144
- `),qp(e)}function jp(e){if(!e.currentState.error)return e.currentState.data.dockerGroupSwitch}function qp(e){let t=e.currentState.error?1:Number(process.exitCode??0),r=[process.stdout,process.stderr].filter(o=>o.writableLength>0);r.length===0&&process.exit(t);let n=r.length;for(let o of r)o.once("drain",()=>{n-=1,n===0&&process.exit(t)})}import*as It from"fs";import*as Hp from"os";import*as Jt from"path";var Cb=process.env.GAIA_CLI_DEV==="true";async function Vp(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input\u2026"),await e.waitForInput("welcome");let r=fo(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await go(e))return;let n=await Qo(e),o=await dr(e,n);if(o===null||n==="developer"&&!await ho(e))return;let i="";if(Cb){if(i=lr()||"",!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 J(500),e.setStatus("Repository ready")}else{e.setStep("Repository Setup");let a=n==="selfhost"?Jt.join(Hp.homedir(),"gaia"):Jt.resolve("gaia"),c=!0;for(i=a;;){if(i=await e.waitForInput("repo_path",{default:a}),Jt.isAbsolute(i)||(i=Jt.resolve(i)),It.existsSync(i)){if(!It.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await J(2e3),e.setError(null);continue}if(sr(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{It.rmSync(i,{recursive:!0,force:!0})}catch(m){e.setError(new Error(`Failed to remove directory: ${m.message}
145
- 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(It.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await J(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 Hn(i,"https://github.com/theexperiencecompany/gaia.git",(l,u)=>{e.updateData("repoProgress",l),u?(e.updateData("repoPhase",u),e.setStatus(`${u}\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 J(1e3),await Rr(e,i,n,o),e.currentState.error)return;if(n==="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=eu(e),c=!1;try{e.setStatus("Pulling pre-built images from registry\u2026"),await ce(i,"selfhost",p=>e.setStatus(p),o,a,{pull:"missing"}),c=!0}catch(p){let m=p.message?.split(`
146
- `)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)\u2026`)}if(!c)try{await ce(i,"selfhost",p=>e.setStatus(p),o,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";Ln({version:R,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",n);let u=await ei(e,{apiUrl:de("selfhost",o),webPort:o[O]??O});e.updateData("stillStarting",!u.ready),e.setStep("Finished"),e.setStatus(u.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 le("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)\u2026"),await le("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 J(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(o).length>0?at(o):void 0;await le("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 J(1e3);let s=e.currentState.data.envMethod||"manual";Ln({version:R,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 Wp(e={}){await ge({command:"init",whenNonInteractive:"fail",runFlow:t=>Vp(t,e.branch)})}import*as Ne from"node:fs";import*as Fe from"node:path";import{execa as di}from"execa";function ka(e){if(e.fromDir){let t=Fe.resolve(e.fromDir),r=La(t);if(!r)return{volumeFiles:[]};let n=Zt(t,r),o=i=>Ne.existsSync(i)?i:void 0;return{mongoFile:e.mongoFile??o(n.mongoFile),postgresFile:e.postgresFile??o(n.postgresFile),apiEnvFile:e.apiEnvFile??o(n.apiEnvFile),volumeFiles:n.volumeFiles.filter(i=>Ne.existsSync(i.file))}}return{mongoFile:e.mongoFile,postgresFile:e.postgresFile,apiEnvFile:e.apiEnvFile,volumeFiles:[]}}function Kp(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 Ra(e){let{mongoFile:t,postgresFile:r,apiEnvFile:n,volumeFiles:o}=e,i=[];n&&i.push(`install -m 600 ${n} ../../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 o)i.push(`docker run --rm -v ${s}:/data -v ${Fe.dirname(a)}:/backups alpine sh -c "${Nr(Fe.basename(a))}"`);return i}async function Yp(e,t){let r=L();if(!r)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let n=Fe.join(r,"infra","docker"),o=Fe.join(n,"docker-compose.selfhost.yml");if(!Ne.existsSync(o))throw new Error(`Compose file not found: ${o}`);let i=ka(e),{mongoFile:s,postgresFile:a,apiEnvFile:c,volumeFiles:l}=i,u=Ra(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(`
147
- `));if(c&&!Ne.existsSync(c))throw new Error(`apps/api/.env backup not found: ${c}`);if(s&&!Ne.existsSync(s))throw new Error(`Mongo backup not found: ${s}`);if(a&&!Ne.existsSync(a))throw new Error(`Postgres backup not found: ${a}`);for(let{label:m,file:g}of l)if(!Ne.existsSync(g))throw new Error(`${m} backup not found: ${g}`);if(e.dryRun)return{...i,commands:u};let p=await Z();if(p!=="ready"){let m=await et(p);throw new Error([`${m.summary}, so nothing can be restored.`,m.fix,"Or run the restore commands yourself:",...u.map(g=>` ${g}`)].join(`
148
- `))}if(c&&Ab(c,r),s)try{let m=di("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","mongo","mongorestore","--archive","--gzip","--drop"],{cwd:n,stdin:"pipe",stderr:"pipe"}),g=Ne.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 di("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph","-c","DROP SCHEMA public CASCADE; CREATE SCHEMA public;"],{cwd:n})}catch(m){throw new Error(`Postgres schema reset failed: ${m.message}`)}try{let m=di("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph"],{cwd:n,stdin:"pipe",stderr:"pipe"}),g=Ne.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 di("docker",["run","--rm","-v",`${g}:/data`,"-v",`${Fe.dirname(m)}:/backups`,"alpine","sh","-c",Nr(Fe.basename(m))],{cwd:n})}catch(E){throw new Error(`${v} restore failed: ${E.message}`)}return t("Restarting services so they load the restored data and settings\u2026"),await ce(r,"selfhost",t,A(r)),{...i,commands:u}}function Ab(e,t){Dn(e,tt(t))}function Qe(e=""){process.stdout.write(`${e}
149
- `)}function Pb(e=""){process.stderr.write(`${e}
150
- `)}async function zp(e={}){let t={mongoFile:e.mongo,postgresFile:e.postgres,apiEnvFile:e.env,fromDir:e.from},r=ka(t);for(let n of Kp(r))Pb(`${y.warn} ${n}`);if(e.dryRun){let n=Ra(r);if(n.length===0){Qe("No backup files resolved. Use --from <dir> or --mongo/--postgres/--env <file>.");return}Qe("Restore commands (dry run \u2014 not executed):");for(let o of n)Qe(` ${o}`);return}try{Qe("Starting GAIA restore\u2026");let n=await Yp(t,o=>Qe(` ${o}`));n.apiEnvFile&&Qe(`Restored apps/api/.env from ${n.apiEnvFile}`),n.mongoFile&&Qe(`Restored MongoDB from ${n.mongoFile}`),n.postgresFile&&Qe(`Restored PostgreSQL from ${n.postgresFile}`);for(let{label:o,file:i}of n.volumeFiles)Qe(`Restored ${o} from ${i}`);Qe("Restore complete. Run 'gaia doctor' to confirm every dependency is ready.")}catch(n){he(n.message),process.exitCode=1}}async function Xp(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository\u2026");let t=lr();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 J(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await go(e))return;let r=await Qo(e),n=await dr(e,r);if(n===null||r==="developer"&&!await ho(e)||(await Rr(e,t,r,n),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 o=fo(e);if(!await tu(e,t,n,o))return;await J(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 Jp(){await ge({command:"setup",whenNonInteractive:"fail",runFlow:Xp})}async function Qp(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository\u2026");let r=L();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r);let n=await $(r);if(!n){e.setError(new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo."));return}if(n==="developer"){e.setError(new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'."));return}if(n==="selfhost"){e.setStatus("Checking Docker\u2026");let s=await Z();if(s!=="ready"){e.setError(await Dt(s));return}}let o=A(r),i=o[O]??O;e.updateData("setupMode",n),e.updateData("webUrl",pt(r,i)),e.updateData("dockerLogs",[]),e.setStatus("Starting GAIA\u2026");try{await ce(r,n,s=>e.setStatus(s),o,(s,a)=>{e.setStatus(s.label),e.updateData("dockerLogs",a.slice(-Lr))},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 Zp(e){await ge({command:"start",whenNonInteractive:"plain",runFlow:t=>Qp(t,e),cancelHint:"GAIA may be partly started. Run 'gaia start' again to finish, or 'gaia stop'."})}var em=8;function kt(e=""){process.stdout.write(`${e}
151
- `)}function tm(e){let t=e.currentState.data[En];return t?{facts:t,report:ci(t)}:null}function Tb(e){let t=tm(e);if(!t)return;let{facts:r,report:n}=t,o=n.headline.kind==="ok"?y.active:y.fail;kt(`${o} ${n.headline.text}`),n.headline.url&&kt(` ${n.headline.url}`),n.hint&&kt(` ${n.hint}`),n.rows.length>0&&kt();for(let i of n.rows){let s=i.items.map(c=>`${c.ok?y.ok:y.fail} ${c.name}`).join(" "),a=i.items.length===0?i.note??"":"";kt(` ${i.label.padEnd(em)}${s}${a}`.trimEnd()),i.items.length>0&&i.note&&kt(` ${" ".repeat(em)}${i.note}`)}r.installed&&(kt(),kt(` Installed at ${r.install}`))}async function rm(e={}){await ge({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:async t=>{await _p(t,e),tm(t)?.report.unhealthy&&(process.exitCode=1)},onPlainComplete:Tb})}async function nm(e,t){e.setStep("Stopping"),e.setStatus("Finding your GAIA install\u2026");let r=L();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 n=A(r);try{await ro(r,o=>e.setStatus(o),n,t)}catch(o){e.setError(new Error(`GAIA didn't stop. ${o.message}`));return}e.setStep("Stopped"),e.setStatus("GAIA stopped. Start it again with 'gaia start'."),e.updateData("stopped",!0)}async function om(e){await ge({command:"stop",whenNonInteractive:"plain",runFlow:t=>nm(t,e),cancelHint:"GAIA may still be partly running. Run 'gaia stop' again."})}import*as pi from"fs";import*as mi from"path";function _b(e){let t=mi.join(e,".env");return pi.existsSync(t)?["--env-file",".env"]:[]}async function im(){let e=L();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await $(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=mi.join(e,"infra","docker"),n=_b(r),o=A(e),i=Object.keys(o).length>0?at(o):void 0;if(t==="selfhost"){await hr("docker",["compose",...ut(ar()),...n,"logs","-f","--tail","200"],r,i);return}let s=["compose",...n,"logs","-f","--tail","200"],a=mi.join(e,nl),c=Yi(e),l=typeof c=="number"&&Zn(c);if(pi.existsSync(a)&&l){console.log("Streaming app and infrastructure logs\u2026"),process.platform==="win32"?await _o([{cmd:"powershell",args:["-Command",`Get-Content -Path '${a.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]):await _o([{cmd:"tail",args:["-n","200","-f",a],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]);return}pi.existsSync(a)&&!l?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await hr("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 hr("docker",s,r,i))}var Db=16;function Ca(e=""){process.stdout.write(`${e}
152
- `)}function Ob(e){let t=e.currentState.data[vn];if(t){Ca(),Ca(`${y.ok} ${zo}`);for(let r of Xo(t))Ca(` ${r.label.padEnd(Db)}${r.text}`)}}async function sm(e={}){await ge({command:"uninstall",whenNonInteractive:"plain",runFlow:t=>tp(t,e),cancelHint:"GAIA may be partly removed. Run 'gaia uninstall' again to finish.",onPlainComplete:Ob})}var $b=16,Lb=14;function xn(e=""){process.stdout.write(`${e}
153
- `)}function Mb(e){let t=e.currentState.data.upOutcome;if(!t)return;let r=ri(t);xn(),xn(`${r.tone==="success"?`${y.ok} `:""}${r.headline}`);for(let n of r.rows)xn(` ${n.label.padEnd($b)}${n.text}`);xn();for(let[n,o]of ti)xn(` ${n.padEnd(Lb)}${o}`)}async function am(e={}){await ge({command:"up",whenNonInteractive:"plain",runFlow:t=>mp(t,e),cancelHint:"GAIA may be partly set up. Run 'gaia up' again to finish, or 'gaia stop'.",onPlainComplete:Mb})}import*as hm from"node:readline";var Nb="https://api.github.com/repos/theexperiencecompany/gaia/releases/tags",Fb=5e3,Bb=5,Gb=["Features","Bug Fixes"],Ub=/^\* (.+)$/,jb=/^\*\*[^*]+:\*\*\s*/,qb=/(\s*\(\[[^\]]+\]\([^)]+\)\))+$/;function Hb(e){let t=e.replace(jb,"").replace(qb,"");return t.charAt(0).toUpperCase()+t.slice(1)}function Vb(e){let t=new Map,r="";for(let n of e.split(`
154
- `)){let o=/^#{2,3} (.+)$/.exec(n.trim());if(o?.[1]){r=o[1];continue}let i=Ub.exec(n.trim())?.[1];i&&t.set(r,[...t.get(r)??[],Hb(i)])}return Gb.flatMap(n=>t.get(n)??[]).slice(0,Bb)}async function cm(e){let t=await fetch(`${Nb}/${ct(e)}`,{headers:{Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Fb)});if(!t.ok)throw new Error(`GitHub answered HTTP ${t.status}`);let{body:r}=await t.json();return Vb(r??"")}import*as lm from"node:fs/promises";import{execa as fi}from"execa";var Wb=["apps/web","apps/api","infra/docker"];function um(e){let{current:t,target:r,explicit:n,gap:o}=e;if(!n){if(mt(t)===null)return{kind:"development-build"};if(!rt(r,t))return{kind:"up-to-date"}}return o?{kind:"unavailable",gap:o}:{kind:"offer",downgrade:rt(t,r)}}async function Aa(e,t){let{stdout:r}=await fi("git",t,{cwd:e});return r.trim()}async function Kb(e){let t=await fi("git",["rev-parse","--is-inside-work-tree"],{cwd:e,reject:!1});return t.exitCode!==0||t.stdout.trim()!=="true"?!1:(await fi("git",["remote","get-url","origin"],{cwd:e,reject:!1})).exitCode===0}function Yb(e){return e.split(`
155
- `).map(t=>t.trim()).filter(Boolean)}async function zb(e,t){let r=await Aa(e,["log",t,"--oneline","--",...Wb]);return{commits:Yb(r)}}async function dm(e,t){ct(t);let r=Be(e),n=Ki(e),o=n?{kind:"bundle",version:n.version,files:n.files}:{kind:"checkout",files:await el(e)};return{repoPath:e,fromVersion:r,toVersion:t,layout:o}}function pm(e){return e.fromVersion===e.toVersion&&e.layout.kind==="bundle"&&e.layout.version===e.toVersion}async function mm(e,t){t.onStatus(`Getting the setup files for GAIA ${e.toVersion}\u2026`);let r=await Qn(e.repoPath,e.toVersion,t.onBundleDownload);try{t.onStatus(`Downloading GAIA ${e.toVersion}\u2026`),await al(e.repoPath,e.toVersion,t.onImagePull)}catch(n){throw await lm.rm(r.stagingDir,{recursive:!0,force:!0}),n}t.onStatus(e.layout.kind==="checkout"?"Moving this install from a git checkout to the release's setup files\u2026":`Switching the setup files to ${e.toVersion}\u2026`),await Jn(r.manifest,r.stagingDir,e.repoPath,e.layout.files),Kr(e.repoPath,e.toVersion),t.onStatus("Restarting GAIA\u2026"),await ce(e.repoPath,"selfhost",t.onStatus,A(e.repoPath),void 0,{pull:"missing"})}async function fm(e){if(!await Kb(e))throw new Error(`${e} is not a git checkout with an origin remote; run 'gaia update' without --git.`);if((await fi("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 Aa(e,["fetch","origin"]),zb(e,"HEAD..@{upstream}")}async function gm(e,t){t("Pulling the latest commits (git pull --ff-only)\u2026"),await Aa(e,["pull","--ff-only"]),t("Rebuilding images from this checkout and restarting\u2026"),await ce(e,"selfhost",t,A(e),void 0,{build:!0})}var Xb=5,Jb="https://docs.heygaia.io/release-notes";function k(e=""){process.stdout.write(`${dt(e)}
156
- `)}async function Qb(e){let t=hm.createInterface({input:process.stdin,output:process.stdout});t.on("SIGINT",()=>{t.close(),k(`
157
- ${y.cancelled} Cancelled \xB7 nothing changed.`),process.exit(130)});let r=await new Promise(o=>{t.question(`${e} [y/N] `,i=>o(i))});t.close();let n=r.trim().toLowerCase();return n==="y"||n==="yes"}function Zb(){let e=process.stdout.isTTY===!0,t=!1;return{show(r){e&&(process.stdout.write(`\r\x1B[K ${r}`),t=!0)},end(){t&&process.stdout.write("\r\x1B[K"),t=!1}}}function eE(){let e=Zb(),t=vr(),r=vr();return{onStatus:n=>{e.end(),k(` ${n}`)},onBundleDownload:({received:n,total:o})=>e.show(o===null?`Setup files: ${qe(n)} downloaded`:`Setup files: ${fn({done:n,total:o,unit:"bytes",estimated:!1},{etaMs:t.update(n,o)})}`),onImagePull:n=>{let o=n.amount;e.show(o?`Images: ${fn(o,{percent:n.percent,etaMs:o.unit==="bytes"?r.update(o.done,o.total):null})} \xB7 ${n.detail??""}`:n.detail??n.label)}}}function tE(e,t){let r=t?e.commits:e.commits.slice(0,Xb);for(let o of r)k(` ${o}`);let n=e.commits.length-r.length;n>0&&k(` and ${n} more (--verbose lists them)`)}async function rE(e){try{for(let t of await cm(e))k(` - ${t}`)}catch(t){k(` (couldn't read what's new in ${e}: ${t.message})`)}}async function Sm(e,t){return e.yes?!0:fe()?Qb(`
158
- ${t}`):(k(`
159
- No terminal to confirm in: rerun with --yes to apply.`),!1)}function nE(e,t){let{fromVersion:r,toVersion:n,layout:o}=e;return r===n&&o.kind==="checkout"?`GAIA ${n} runs from a git checkout. Move it to the release's setup files, so it no longer needs git?`:t?`Switch GAIA ${r} back to ${n}`:`Update available: GAIA ${r} \u2192 ${n}`}async function oE(e,t){let r=Be(e),n=t.version??Ge,o=t.version!==void 0,s=o||mt(r)!==null&&rt(n,r)?await or(n,C()?.bots??[]):null,a=um({current:r,target:n,explicit:o,gap:s});switch(a.kind){case"development-build":k(`This install runs a development build of GAIA (${io(r)}), not a release, so there is nothing to update.`),k(`To switch it to the ${n} release: gaia update --version ${n}`);return;case"up-to-date":k(`GAIA ${r} is up to date.`);for(let u of Pc(R))k(u);return;case"unavailable":k(`${rr(a.gap,"gaia up --build").cause} Nothing was changed.`),o&&(process.exitCode=1);return;case"offer":break}let c=await dm(e,n);if(pm(c)){k(`GAIA ${r} is up to date.`);return}if(k(`
160
- ${nE(c,a.downgrade)}`),await rE(n),k(`What's new: ${Jb}`),k("Your data and settings are kept."),!await Sm(t,"Update and restart now?"))return;let l=eE();await mm(c,l),c.layout.kind==="checkout"&&k(" This install no longer needs git: it now holds only the release's setup files, beside your settings and data."),k(`
161
- ${y.ok} GAIA is on ${n}.`),k("Run 'gaia doctor' to check that everything is ready.")}async function iE(e,t){let r=await fm(e);if(r.commits.length===0){k("Already up to date with the upstream branch.");return}k(`
162
- ${r.commits.length} new commit(s) touch the self-host stack:`),tE(r,t.verbose===!0),k("The images are rebuilt from this checkout (slow on small machines)."),await Sm(t,"Pull, rebuild and restart now?")&&(await gm(e,n=>k(` ${n}`)),k(`
163
- Updated and restarted from source.`))}async function vm(e={}){await Lt({showUpdate:!1});let t=L();if(!t){he(`GAIA isn't installed here, so there is nothing to update.
164
- Install it with 'gaia up'.`),process.exitCode=1;return}if(e.git&&e.version){he(`--version and --git can't be used together.
165
- --version moves to a published release; --git builds from source. Pick one.`),process.exitCode=1;return}for(let r of Xn(process.env,R))k(`${y.warn} ${r}`);k(`Checking for updates in ${_(t)}\u2026`);try{await(e.git?iE(t,e):oE(t,e))}catch(r){k(),he(`GAIA wasn't updated: ${r.message}
166
- Your data is untouched. Fix the cause above, then run 'gaia update' again.`),process.exitCode=1}}var sE={"":1,true:1,false:0,0:0,1:1,2:2,3:3},aE=new Set(["truecolor","24bit"]),cE=new Set(["iTerm.app","WezTerm","vscode","ghostty"]),lE="Apple_Terminal",uE=/-256(color)?$|-direct$|-truecolor$|^tmux|^xterm-kitty$|^xterm-ghostty$|^alacritty|^wezterm|^foot|^contour/,dE=/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/;function ym({env:e,isTTY:t,platform:r}){let n=e.FORCE_COLOR;if(n!==void 0){let i=sE[n];if(i===void 0)throw new Error(`FORCE_COLOR=${JSON.stringify(n)} is not one of 0-3, true or false`);return i}let o=e.TERM??"";return e.NO_COLOR||!t||o==="dumb"?0:aE.has(e.COLORTERM??"")?3:e.TERM_PROGRAM===lE?2:cE.has(e.TERM_PROGRAM??"")||r==="win32"&&(e.WT_SESSION||!o)||uE.test(o)?3:dE.test(o)||e.COLORTERM?1:0}pE.level=ym({env:process.env,isTTY:process.stdout.isTTY===!0,platform:process.platform});var gE=new Set(["-V","--version"]),W=new mE,Pa="For contributors:",hE=20;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").configureHelp({minWidthToWrap:hE}).enablePositionalOptions().addHelpText("after",`
167
- New here? Run: gaia up`);W.command("up").description(U.up).option("--yes","Answer yes to every question, including installing Docker").addOption(new fE("--llm-provider <provider>","AI provider to save once GAIA is running (checked first, as the setup page does)").choices(la)).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("--no-local-name","Don't name GAIA http://gaia.local for other devices on your network (uses port 80 and sudo)").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 am({...r,noStart:t===!1})});W.command("status").description(U.status).option("--watch","Stay open; press r to check again").action(async e=>{await rm({watch:e.watch})});W.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 om({forcePorts:e.forcePorts})});W.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 Zp({build:e.build,pull:e.pull?"always":void 0})});W.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 vm(e)});W.command("doctor").description(U.doctor).action(async()=>{await bd()});W.command("logs").description(U.logs).action(async()=>{try{await im()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});W.addCommand(sn);W.addCommand(td);W.addCommand(nt);W.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 fl({output:e.output,dryRun:e.dryRun})});W.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 zp({mongo:e.mongo,postgres:e.postgres,env:e.env,from:e.from,dryRun:e.dryRun})});W.command("uninstall").description(U.uninstall).option("--yes","Don't ask: uninstall and keep your data (add --delete-data to delete it)").option("--delete-data","Delete your data too: accounts, chats, memories and files (can't be undone)").action(async e=>{await sm(e)});W.command("init").helpGroup(Pa).description(U.init).option("--branch <branch>","Git branch to clone").action(async e=>{await Wp({branch:e.branch})});W.command("setup").helpGroup(Pa).description(U.setup).action(async()=>{await Jp()});W.command("dev [profile]").helpGroup(Pa).description(U.dev).action(async e=>{try{await nd(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});gE.has(process.argv[2]??"")&&(await Ll(),process.exit(0));process.argv.slice(2).length||(W.outputHelp(),process.exit(0));W.parse();
134
+ `}async function zd(){let[e,t]=await Promise.all([aa("ip",["-6","-o","addr","show","scope","global"]),aa("ip",["-o","route","show","default"])]);return Oy(e.stdout,Dy(t.stdout))}async function Xd(e,t,r){let{stdout:n}=await aa("sh",["-c","command -v avahi-publish-address"]),o=Yd.join(Kd.tmpdir(),hn);xr.writeFileSync(o,$y(n.trim(),e,t)),await H("install",["-m","644",o,ca],r),xr.rmSync(o,{force:!0}),await H("systemctl",["daemon-reload"],r),await H("systemctl",["enable",hn],r),await H("systemctl",["restart",hn],r)}async function Jd(e){xr.existsSync(ca)&&(await H("systemctl",["disable","--now",hn],e),await H("rm",["-f",ca],e),await H("systemctl",["daemon-reload"],e))}var Xo="gaia",yt=`${Xo}.local`,np=`http://${yt}`,Zd="0.15.8",ep=24,la=80,Ly=15e3,My=500,op=2e3;function ip(e){return!e.optedOut&&!e.domain?"set-up":e.setUpBefore?"remove":"none"}function Ny(e,t){if(t!=="linux"&&t!=="darwin")return"it works only on Linux and macOS";let r=e.replace(/^v/,"");return Number.parseInt(r,10)<ep?`it needs Node.js ${ep} or newer, and this is Node.js ${r}`:null}function sp(){return Kt.join(Kt.dirname(process.execPath),"npm")}async function ap(){let{stdout:e}=await Ir(sp(),["root","-g"]);return Kt.join(e.trim(),"portless","dist","cli.js")}var Fy=Qd.object({version:Qd.string()});function By(e){let t=Kt.join(Kt.dirname(e),"..","package.json");return Wt.existsSync(t)?Fy.parse(JSON.parse(Wt.readFileSync(t,"utf-8"))).version:null}async function Gy(e){let t=await ap();if(By(t)===Zd)return t;let r=await Ir(sp(),["install","-g","--no-fund","--no-audit",`portless@${Zd}`],{all:!0,reject:!1});if(Wt.appendFileSync(e,r.all??""),r.failed)throw new Error(`installing portless with npm failed (output in ${e})`);return t}function Uy(e){return Ir("sh",["-c",`command -v ${e}`],{reject:!1}).then(t=>!t.failed)}async function jy(e){if(process.platform==="linux"&&!await Uy("avahi-publish-address")){if(!gs())throw new Error("it needs avahi-utils (avahi-publish-address); install it, then run 'gaia up' again");await H("apt-get",["update"],e),await H("apt-get",["install","-y","avahi-utils"],e)}}async function qy(e,t){let r=await Ir(process.execPath,[e,...t],{all:!0,reject:!1});if(r.failed)throw new Error(`'portless ${t.join(" ")}' failed: ${(r.all??"").trim()}`)}function cp(){return new Promise(e=>{let t=rp.get({host:"127.0.0.1",port:la,path:"/health/ready",headers:{Host:yt},timeout:op},r=>{r.resume(),e(r.statusCode??null)});t.on("timeout",()=>t.destroy()),t.on("error",()=>e(null))})}async function tp(){return await cp()===200}async function Hy(){return await cp()!==null}async function lp(e,t){if(process.platform!=="linux")return!0;let r=await Ir("avahi-resolve-host-name",[e,yt],{reject:!1,timeout:op});if(r.failed)return!1;let[n,o]=r.stdout.trim().split(/\s+/);return n===yt&&(!t||o===t)}async function Vy(e){if(process.platform!=="linux")return;let t=await zd();if(!t)return;let r=()=>lp("-6",t);if(!await r()&&(await Xd(yt,t,e),!await zo(r)))throw new Error(`${yt}'s IPv6 address isn't announced, so Apple devices wait ~5s per lookup (log: ${e})`)}async function zo(e){let t=Date.now()+Ly;for(;Date.now()<t;){if(await e())return!0;await new Promise(r=>setTimeout(r,My))}return e()}async function up(e){let t=Ny(process.version,process.platform);if(t)throw new Error(t);let r=qe("local-name"),n=await Gy(r);if(!await tp()&&(await jy(r),await H(process.execPath,[n,"service","install","--lan","--no-tls"],r),!await zo(Hy)))throw new Error(`portless's proxy didn't start on port ${la}; is another server using it? (log: ${r})`);if(await qy(n,["alias",Xo,String(e),"--force"]),!await zo(tp))throw new Error(`portless's proxy on port ${la} doesn't route ${yt} to GAIA on port ${e} (log: ${r})`);if(!await zo(()=>lp("-4")))throw new Error(`${yt} isn't announced on the network; check that avahi-daemon is running (log: ${r})`);await Vy(r)}async function Jo(){let e=await ap();if(!Wt.existsSync(e))return;let t=await Ir(process.execPath,[e,"alias","--remove",Xo],{all:!0,reject:!1});if(t.failed&&!(t.all??"").includes("No alias found"))throw new Error(`'portless alias --remove ${Xo}' failed: ${(t.all??"").trim()}`);let r=qe("local-name-remove");await H(process.execPath,[e,"service","uninstall"],r),await Jd(r)}var ze={confirm:"uninstall_confirm",deleteData:"uninstall_delete_data",backup:"uninstall_backup"},vn="uninstallOutcome",Sn=Cr.join(dp.homedir(),"gaia-backups"),Wy=["apps/api/.env","infra/docker/.env"],pp="npm rm -g @heygaia/cli",mp="docker volume rm $(docker volume ls -q --filter label=com.docker.compose.project=gaia-selfhost)";function Ky(e,t){if(!t.keepSettings){Rr.rmSync(e,{recursive:!0,force:!0});return}let r=Wy.map(i=>Cr.join(e,i)),n=new Set(r),o=i=>{for(let s of Rr.readdirSync(i)){let a=Cr.join(i,s);if(n.has(a))continue;r.some(l=>l.startsWith(`${a}${Cr.sep}`))?o(a):Rr.rmSync(a,{recursive:!0,force:!0})}};o(e)}function Yy(e){return t=>{if(t===ze.confirm&&e.yes)return!0;if(t===ze.deleteData){if(e.deleteData)return!0;if(e.yes)return!1}if(t===ze.backup&&e.yes)return!1}}function zy(e,t,r,{deleteData:n,backup:o}){let i=[];if(o&&i.push({id:"backup",label:"Backing up your data",doneLabel:`Backed up your data to ${F(Sn)}`,run:()=>Xr({outputDir:Sn})}),t){let s=n?"containers and data":"containers and images";i.push({id:"containers",label:`Removing ${s}`,doneLabel:`Removed ${s}`,run:()=>so(t,a=>te(e,"containers",{detail:a}),k(t),{remove:{volumes:n}})})}if(r&&i.push({id:"local-name",label:"Removing the gaia.local name",doneLabel:"Removed the gaia.local name",run:Jo}),t){let s=F(t);i.push({id:"files",label:`Removing ${s}`,doneLabel:n?`Removed ${s}`:`Removed ${s}, except its settings`,minor:!0,run:()=>Ky(t,{keepSettings:!n})})}return i.push({id:"config",label:`Removing ${F(xe)}`,doneLabel:`Removed ${F(xe)}`,minor:!0,run:()=>Rr.rmSync(xe,{recursive:!0,force:!0})}),i}async function Xy(e,t){go(e,t);for(let r of t){ge(e,r.id);try{await r.run()}catch(n){return Ve(e,"failed"),e.setError(n),!1}ke(e,r.id)}return!0}async function Jy(){let e=Yo();return!e&&!P()?{error:new Error("GAIA isn't installed here, so there is nothing to uninstall.")}:e&&await $(e)==="developer"?{error:new Error(`${F(e)} is a development copy of GAIA, and 'gaia uninstall' removes only self-host installs.
135
+ Delete it yourself if you no longer need it.`)}:{installDir:e}}async function Qy(e){if(await e.waitForInput(ze.confirm)!==!0)return null;let t=await e.waitForInput(ze.deleteData)===!0,r=t&&await e.waitForInput(ze.backup)===!0;return{deleteData:t,backup:r}}async function fp(e,t={}){if(!he()&&!t.yes){e.setError(new Error(`There is no terminal to confirm in.
136
+ Rerun with --yes (keeps your data) or --yes --delete-data.`));return}let r=await Jy();if("error"in r){e.setError(r.error);return}let{installDir:n}=r,o=P()?.localName===!0;e.updateData("installDir",n),e.pushAnswerResolver(Yy(t));let i=await Qy(e);if(!i){e.setStatus("Nothing was removed."),e.updateData("cancelled",!0);return}if(!await Xy(e,zy(e,n,o,i)))return;let s={installDir:n,keptData:!i.deleteData,...i.backup?{backupDir:Sn}:{}};e.updateData(vn,s),e.updateData("finished",!0)}var Qo="GAIA is uninstalled";function Zo(e){let t=[];if(e.keptData){let r=e.installDir?` with the settings that unlock it in ${F(e.installDir)}`:"";t.push({label:"Your data",text:`kept in Docker volumes${r}; 'gaia up' picks it back up`}),t.push({label:"Delete it later",text:mp,tone:"dim"})}else t.push({label:"Your data",text:"deleted"});return e.backupDir&&t.push({label:"Backup",text:`in ${F(e.backupDir)}; 'gaia restore --from' brings it back`}),t.push({label:"The CLI",text:`remove it too with ${pp}`,tone:"primary"}),t}import{jsx as De,jsxs as yn}from"react/jsx-runtime";var gp=2;function tw(e,t){switch(e){case ze.confirm:return{text:"Remove GAIA from this computer?",detail:`Its containers, networks and images go${t?`, and so does ${F(t)}`:""}. You choose about your data next.`,yesByDefault:!0};case ze.deleteData:return{text:"Delete your data too?",detail:"Accounts, chats, memories and files. This can't be undone. No keeps it, and 'gaia up' picks it back up.",yesByDefault:!1};case ze.backup:return{text:`Back it up to ${F(Sn)} first?`,detail:"Runs 'gaia backup' while GAIA is still running.",yesByDefault:!0};default:return null}}var rw=({store:e,id:t})=>{let r=tw(t,e.currentState.data.installDir??null);return r?yn(Yt,{flexDirection:"column",marginTop:1,children:[De(ua,{dimColor:!0,children:r.detail}),yn(Yt,{children:[yn(ua,{bold:!0,children:[r.text," "]}),De(Zy,{defaultChoice:r.yesByDefault?"confirm":"cancel",onConfirm:()=>e.submitInput(!0),onCancel:()=>e.submitInput(!1)},t)]})]}):null},hp=({store:e})=>{let t=Se(e),r=t.data.steps??[],n=t.data[vn],{finished:o,live:i}=qo(r),s=i.find(a=>a.state!=="pending");return yn(Yt,{flexDirection:"column",width:"100%",children:[De(ew,{items:o,children:a=>De(Yt,{paddingLeft:gp,children:De(Ho,{step:a})},a.id)}),yn(Yt,{flexDirection:"column",paddingLeft:gp,children:[t.inputRequest&&De(rw,{store:e,id:t.inputRequest.id}),s&&De(Vo,{step:s,waiting:!1,status:t.status}),t.data.cancelled===!0&&De(Yt,{marginTop:1,children:De(ua,{children:t.status})})]}),n&&De(Yt,{marginTop:1,children:De(jo,{headline:Qo,rows:Zo(n),accent:"green",success:!0})}),t.error&&De(_e,{message:t.error.message})]})};import{Box as Xe,Static as Ww,Text as ga}from"ink";import{useState as Kw}from"react";import nw from"chalk";import{Box as ow,Text as iw,useStdout as sw}from"ink";import{useEffect as aw,useState as Sp}from"react";import{jsx as vp}from"react/jsx-runtime";var wt=({showStatus:e=!0,showUpdate:t=!0})=>{let{stdout:r}=sw(),n=Fo(),[o,i]=Sp(null),[s]=Sp(()=>t?mo():null);aw(()=>{if(!e){i(null);return}let c=!0;return po().then(l=>{c&&i(l)}),()=>{c=!1}},[e]);let a=fo({level:nw.level,...n,...as(r),version:A,status:e?o:null,update:s});return vp(ow,{marginTop:1,children:vp(iw,{children:a.join(`
137
+ `)})})};import{execFile as xw}from"node:child_process";import*as Cp from"node:os";import*as ei from"node:fs";import*as yp from"node:path";var cw=e=>new Promise(t=>setTimeout(t,e));async function ti(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 kr(e,t,r,n,o){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 Br()){let p=Fr(d,r);p&&(s[d]=p)}Object.assign(s,rc(r));let a={};o?.domain&&(a.HOST=`https://${o.domain}`,a.FRONTEND_URL=`https://${o.domain}`),i==="infisical"?(await uw(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.")):await pw(e,a,r,o?.llmProvider===void 0);let c=ei.existsSync(rt(t))?ei.readFileSync(rt(t),"utf-8"):null,l=lw({defaults:s,existing:Tt(c),existingMode:await $(t),answers:a,setupMode:r});n&&ec(l,n,r),r==="selfhost"&&Object.assign(l,Hn(c));try{await mw(e,t,l,r,n,o?.domain)}catch(d){e.setError(d);return}await cw(1e3)}function lw(e){let{defaults:t,existing:r,existingMode:n,answers:o,setupMode:i}=e,s=n===i;return{...s?t:r,...s?r:t,...o,SETUP_MODE:i}}async function uw(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 dw(e){let t=[],r=new Set,n=new Set;for(let o of e)if(o.alternativeGroup&&!n.has(o.name)){let i=e.find(s=>s.name===o.alternativeGroup);i&&(t.push([o,i]),r.add(o.name),r.add(i.name),n.add(o.name),n.add(i.name))}return{alternativePairs:t,alternativeGroupNames:r}}async function pw(e,t,r,n){e.setStatus("Parsing environment variables\u2026");let o=tc(_n(),r).filter(g=>r!=="selfhost"||g.selfhostSetup),{alternativePairs:i,alternativeGroupNames:s}=dw(o),a=o.filter(g=>g.variables.length===1&&!s.has(g.name)),c=o.filter(g=>g.variables.length>1&&!s.has(g.name));for(let g of n?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=Br(),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(x=>x.required),b=v.variables.some(x=>x.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,x]of Object.entries(E)){let G=v.variables.find(N=>N.name===b);(x||G?.required||G?.defaultValue)&&(t[b]=x||G?.defaultValue||"")}}}async function mw(e,t,r,n,o,i){e.setStatus("Saving GAIA's settings\u2026");try{let s=yp.join(t,"apps","api");Gr(s,r),e.setStatus("Saved GAIA's settings")}catch(s){throw new Error(`Failed to write API .env file: ${s.message}`)}if(n==="selfhost"){e.setStatus("Saving Docker's settings\u2026");try{ki(t,o??{},n,{dockerSocketGid:Va(),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{sc(t,n,o),e.setStatus("Saved the web app's settings")}catch(s){throw new Error(`Failed to write web .env file: ${s.message}`)}if(o&&Object.keys(o).length>0){e.setStatus("Saving Docker's settings\u2026");try{dc(t),ki(t,o,n),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}}}import*as bp from"node:path";var pa=["openrouter","gemini","openai","ollama","custom"],fw={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"}},ri={key:"--llm-key",baseUrl:"--llm-base-url",model:"--llm-model"};function da(e,t){let r={key:e.llmKey,baseUrl:e.llmBaseUrl,model:e.llmModel}[t];return r!==void 0&&r!==""}function Ep(e){let t=Object.keys(ri);if(!e.llmProvider){let n=t.find(o=>da(e,o));if(n)throw new Error(`${ri[n]} requires --llm-provider <${pa.join("|")}>.`);return}let r=e.llmProvider;for(let n of t){let o=fw[r][n];if(o==="required"&&!da(e,n))throw new Error(`--llm-provider ${r} requires ${ri[n]}.`);if(o==="unused"&&da(e,n))throw new Error(`${ri[n]} 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 gw(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var wp="GAIA_PROVIDER_API_KEY",Ar={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},hw=/Could not save \w+: (.+)/;async function xp(e,t){let r=bp.join(e,"infra/docker");try{await de("docker",[...zi(r),"exec","-T","-e",wp,"gaia-backend","python","-m","app.scripts.save_provider",...gw(t)],r,void 0,void 0,{[wp]:t.llmKey??""})}catch(n){let o=hw.exec(n.message)?.[1];throw o?new Error(o,{cause:n}):n}}var Sw=5e3,vw=5*6e4,yw=5e3;async function ww(e,t={}){let r=t.intervalMs??Sw,n=Date.now()+(t.timeoutMs??vw),o=new Map(e.map(i=>[i.label,i]));for(;;){if(await Promise.all([...o.values()].map(async i=>{await bw(i)&&o.delete(i.label)})),o.size===0)return{ready:!0};if(Date.now()>=n)return{ready:!1,stillStarting:[...o.keys()].join(", ")};t.onProgress?.([...o.keys()]),await Q(r)}}async function bw(e){try{let t=await fetch(e.url,{signal:AbortSignal.timeout(yw)});return e.requireOk?t.ok:!0}catch{return!1}}async function ni(e,t,r){let n=await ww([{label:"API",url:`${t.apiUrl}/ping`,requireOk:!0},{label:"Web",url:`http://localhost:${t.webPort}/login`,requireOk:!1}],{onProgress:o=>{Ew(e,o),r?.(o)}});return e.updateData("dependencyPhase",n.ready?"GAIA is answering":`Still starting: ${n.stillStarting}`),e.updateData("dependencyComplete",!0),n}function Ew(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 kp="gaia up --build",Iw="usually 10-20 minutes \xB7 safe to leave running",fa="upNotice";function Rw(e,t,r){let n=e.llmProvider?Ar[e.llmProvider]:null,o={existing:{label:"Finding your install",doneLabel:"Using your install",minor:!0},bundle:{label:"Getting GAIA's setup files",doneLabel:"Got GAIA's setup files",minor:!0},clone:{label:"Downloading GAIA's source",doneLabel:"Downloaded GAIA's source"}}[t];return[{id:"docker",label:"Checking Docker",doneLabel:"Docker is ready"},...r==="remove"?[{id:"local-name-off",label:"Removing the gaia.local name",doneLabel:"Removed the gaia.local name",minor:!0}]:[],{id:"preflight",label:"Checking GAIA can run here",doneLabel:"GAIA can run here",minor:!0},{id:"files",...o},{id:"configure",label:"Saving your settings",doneLabel:"Saved your settings",minor:!0},...e.noStart?[]:[e.build?{id:"download",label:"Building GAIA",doneLabel:"Built GAIA"}:{id:"download",label:"Downloading GAIA",doneLabel:"Downloaded GAIA"},{id:"start",label:"Starting GAIA",doneLabel:"Started GAIA"},...r==="set-up"?[{id:"local-name",label:"Setting up gaia.local",doneLabel:"gaia.local set up"}]:[]],...n?[{id:"provider",label:`Checking your ${n} key`,doneLabel:`Saved your ${n} key`}]:[]]}function Cw(e,t){return cr(e)?(t&&Xi(e),"existing"):t?"clone":"bundle"}function kw(e){return new Error(`${e} is set up for development (apps/api/.env is in developer mode), and 'gaia up' would overwrite its settings.
138
+ Run it with --force-dev-tree to go ahead anyway.`)}function Pr(e,t){Ve(e,"failed"),e.setError(t)}async function Ap(e,t={}){Ep(t);let r=Math.min(Date.now(),...Object.values(Un()).map(E=>E.startedAt)),n=Yo(),o=n??Hd,i;try{i=Cw(o,t.build===!0)}catch(E){e.setError(E);return}e.pushAnswerResolver(Wd({repoPath:o}));let s=t.domain??Nn(o),a=Tw(t,s);if(go(e,Rw(t,i,a)),e.setStep("Prerequisites"),!await Pw(e,t,i)||(ke(e,"docker"),!await Ow(e,a))||(ge(e,"preflight"),!t.build&&!await Lw(e,o,i!=="existing")))return;let c=await dr(e,"selfhost");if(c===null){Ve(e,"failed");return}if(Object.assign(c,Vd(t)),i==="existing"&&o!==n&&!t.forceDevTree&&await $(o)==="developer"){Pr(e,kw(o));return}if(ke(e,"preflight"),ge(e,"files"),!await Nw(e,o,i))return;if(we(t.codeSandbox===void 0?{repoPath:o}:{repoPath:o,codeSandbox:t.codeSandbox}),ke(e,"files",i==="existing"?`Using your install at ${F(o)}`:void 0),ge(e,"configure"),await kr(e,o,"selfhost",c,{llmProvider:t.llmProvider,domain:t.domain}),e.currentState.error){Ve(e,"failed");return}ke(e,"configure");let l=_w(o),d=l.webPort,p={...Dw(d,s),noStart:t.noStart===!0,stillStarting:!1,setupComplete:!1,elapsedMs:0,startedServices:0};if(t.noStart){Rp(e,o,{...p,elapsedMs:Date.now()-r});return}try{p.startedServices=await Uw(e,o,c,t)}catch(E){Pr(e,E);return}let m=l.apiUrl,g=await Aw(e,{apiUrl:m,webPort:d},p.startedServices);p.stillStarting=!g.ready,p.setupComplete=g.ready&&await jw(m),Object.assign(p,await $w(e,a,d,g.ready));let v=await Bw(e,o,t,g.ready);if(t.llmProvider&&(v?p.unsavedProvider=t.llmProvider:p.savedProvider=t.llmProvider),Rp(e,o,{...p,elapsedMs:Date.now()-r}),v){e.setError(v);return}g.ready&&Fw(p.webUrl,t)}async function Aw(e,t,r){let n=(Pp(e,"start")?.substeps??[]).map(s=>({...s,state:"done",note:void 0})),o=s=>te(e,"start",{substeps:[...n,{id:"answer",label:"Waiting for GAIA to answer",state:"active",...s.length>0?{note:s.join(" and ")}:{}}]});te(e,"start",{detail:void 0,percent:void 0,amount:void 0,etaMs:void 0}),o([]);let i=await ni(e,t,o);return i.ready?ke(e,"start",r===0?"GAIA was already running":void 0):te(e,"start",{state:"failed",endedAt:Date.now()}),i}async function Pw(e,t,r){ge(e,"docker");try{return await So(e,{needGit:r==="clone",assumeYes:t.yes===!0,rerunCommand:"gaia up",onInstallStart:o=>ge(e,"docker",{label:`Installing ${ur(o)}`,doneLabel:`${ur(o)} installed`,startedAt:Date.now()}),onInstallProgress:o=>Ql(e,"docker",hs,o.stage,o.note)})!=="relaunch"}catch(n){return n instanceof rn?(en(e,"docker"),e.updateData(fa,n.message),process.exitCode=1,!1):(Pr(e,n),!1)}}function Tw(e,t){return ip({optedOut:e.localName===!1,domain:t,setUpBefore:P()?.localName===!0})}function _w(e){let t=k(e);return{webPort:t[O]??O,apiUrl:me("selfhost",t)}}function Dw(e,t){return{webUrl:ts(e,t),localhostUrl:Zi(e),lanUrls:es(e),localCertificate:t!==void 0&&Dn(t)}}async function Ow(e,t){if(t!=="remove")return!0;ge(e,"local-name-off");try{await Jo()}catch(r){return Pr(e,new Error(`Couldn't remove the gaia.local name: ${r.message}`)),!1}return we({localName:!1}),ke(e,"local-name-off"),!0}async function $w(e,t,r,n){if(t!=="set-up")return{};if(ge(e,"local-name"),!n)return en(e,"local-name"),{localNameProblem:"GAIA didn't answer in time; run 'gaia up' again once 'gaia status' shows it running"};we({localName:!0});try{await up(r)}catch(o){return en(e,"local-name"),{localNameProblem:o.message}}return ke(e,"local-name"),{localUrl:np}}async function Lw(e,t,r){let n=r?je:Ue(t);e.setStatus(`Checking that GAIA ${n} is available for this computer\u2026`);let o=await or(n,P()?.bots??[]);if(!o)return!0;let{cause:i,next:s}=rr(o,kp);return Pr(e,new Error(`${i}
139
+ ${s}`)),!1}function Mw(e,t){let r=vr();return({received:n,total:o})=>te(e,t,o===null?{detail:`${Re(n)} downloaded`}:{amount:{done:n,total:o,unit:"bytes",estimated:!1},etaMs:r.update(n,o)})}async function Nw(e,t,r){if(r==="existing")return!0;try{if(r==="bundle"){let n=await ro(t,je,Mw(e,"files"));return await to(n.manifest,n.stagingDir,t,[]),Kr(t,je),!0}te(e,"files",{detail:"Connecting to GitHub\u2026"}),await Mc(t,$c,(n,o)=>{te(e,"files",o?{percent:n,detail:o}:{percent:n})})}catch(n){return Pr(e,new Error(`Couldn't get GAIA into ${F(t)}: ${n.message}`)),!1}return!0}function Fw(e,t){let r=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;!t.yes&&r&&Cp.platform()==="darwin"&&xw("open",[`${e}/setup`],()=>{})}async function Bw(e,t,r,n){let{llmProvider:o}=r;if(!o)return null;let i=Ar[o];if(ge(e,"provider"),!n)return Ve(e,"failed"),new Error(`GAIA didn't answer in time, so your ${i} key wasn't saved.
140
+ Once 'gaia status' shows it running, run 'gaia up' again with the same flags.`);try{await xp(t,{...r,llmProvider:o})}catch(s){return Ve(e,"failed"),new Error(`Your ${i} key wasn't saved: ${s.message}
141
+ Check the key and run 'gaia up --llm-provider ${o} --llm-key <key>' again, or add it on the setup page above.`)}return ke(e,"provider"),null}function Gw(e){return e.stage==="starting"||e.stage==="stopping"?"start":"download"}function Pp(e,t){return(e.currentState.data[Nt]??[]).find(n=>n.id===t)}function ma(e,t){return Pp(e,t)?.state}function Ip(e){let t=ma(e,"download");t==="active"&&ke(e,"download"),t==="pending"&&en(e,"download")}async function Uw(e,t,r,n){ge(e,"download",n.build?{hint:Iw}:{detail:"Checking which images this computer needs"});let o=vr(),i=a=>{let c=Gw(a);c==="start"&&Ip(e),ma(e,c)!=="active"&&ge(e,c);let l=a.amount?.unit==="bytes"?a.amount:void 0;te(e,c,{detail:a.parts?void 0:a.detail??a.label,substeps:a.parts,percent:a.percent,amount:l,etaMs:l?o.update(l.done,l.total):void 0})},{startedServices:s}=await ue(t,"selfhost",void 0,r,i,{...n.build?{build:!0}:{pull:"missing"},rebuildCommand:kp});return Ip(e),ma(e,"start")!=="active"&&ge(e,"start"),s}async function jw(e){let t=await He(e,"status");return"data"in t&&!t.data.needs_setup}function Rp(e,t,r){we({version:A,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 oi=[["gaia status","check health"],["gaia stop","stop GAIA"],["gaia doctor","find problems"],["gaia --help","all commands"]];function qw(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 ${gt(e.elapsedMs)}`;return e.unsavedProvider?`${t} \xB7 your ${Ar[e.unsavedProvider]} key wasn't saved`:e.startedServices===0?`${t} \xB7 nothing to do`:t}function Hw(e){return e.localNameProblem?{label:"gaia.local",text:`isn't set up: ${e.localNameProblem}`,tone:"warn"}:null}function Vw(e){let t=e.localUrl??e.webUrl,r=[e.localhostUrl,...e.localUrl?[]:e.lanUrls].filter(n=>n!==t);return{primary:t,others:r}}function ii(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{primary:n,others:o}=Vw(e),i=`${n}/setup`;t.push(e.setupComplete?{label:"Next",text:`Open ${n}`,url:n,tone:"primary"}:{label:"Next",text:`Open ${i} to create your admin account.`,url:i,tone:"primary"}),o.length>0&&t.push({label:"Also at",text:o.join(", "),tone:"dim"})}let r=Hw(e);return r&&t.push(r),e.localCertificate&&t.push({label:"Certificate",text:`from GAIA's own certificate authority, so browsers warn until a device trusts it. Copy it with: ${nc}`,tone:"warn"}),e.savedProvider&&t.push({label:"AI",text:`${Ar[e.savedProvider]} key saved \xB7 change it in Settings`}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:qw(e),rows:t}}import{jsx as B,jsxs as wn}from"react/jsx-runtime";var Yw={kind:"header"},zw="GAIA_CONTINUES_INSTALLER",Tp=2,Xw=14,_p=30,Jw=({outcome:e})=>{let t=ii(e),r=t.tone==="success"?"green":w;return wn(Xe,{flexDirection:"column",marginTop:1,children:[B(jo,{headline:t.headline,rows:t.rows,accent:r,success:t.tone==="success"}),B(Xe,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:_p*2+4,children:oi.map(([n,o])=>wn(Xe,{width:_p,children:[B(Xe,{width:Xw,children:B(ga,{color:w,children:n})}),B(ga,{color:"gray",children:o})]},n))})]})},Qw=({state:e,store:t})=>e.inputRequest?.id==="port_conflicts"?e.data.portConflicts?B(br,{portResults:e.data.portConflicts,onAccept:()=>t.submitInput("accept"),onAbort:()=>t.submitInput("abort")}):null:B(Er,{inputId:e.inputRequest?.id,missing:e.data[Gt],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),Dp=({text:e})=>wn(Xe,{children:[B(z,{kind:"warn"}),B(ga,{children:e})]});function Zw(){if(Gn())return[];let e=eo(process.env,A).map(t=>({kind:"note",text:t}));return process.env[zw]==="1"?e:[Yw,...e]}function eb(e){return e.kind==="step"?e.step.id:e.kind==="note"?e.text:"header"}var tb=({item:e})=>e.kind==="step"?B(Ho,{step:e.step}):e.kind==="note"?B(Dp,{text:e.text}):B(Xe,{marginBottom:1,children:B(wt,{showStatus:!1,showUpdate:!1})}),Op=({store:e})=>{let t=Se(e),r=t.data.steps??[],n=t.data.upOutcome,o=t.data[fa],i=t.data.finished===!0&&n!==void 0,{finished:s,live:a}=qo(r),c=a.find(p=>p.state!=="pending"),[l]=Kw(Zw),d=[...l,...s.map(p=>({kind:"step",step:p}))];return wn(Xe,{flexDirection:"column",width:"100%",children:[B(Ww,{items:d,children:p=>B(Xe,{paddingLeft:Tp,children:B(tb,{item:p})},eb(p))}),wn(Xe,{flexDirection:"column",paddingLeft:Tp,children:[c&&B(Vo,{step:c,waiting:t.inputRequest!==null,status:t.status}),B(Qw,{state:t,store:e}),o&&B(Xe,{marginTop:1,children:B(Dp,{text:o})})]}),i&&B(Jw,{outcome:n}),t.error&&B(_e,{message:t.error.message})]})};import{Select as va,Spinner as db}from"@inkjs/ui";import{Box as h,Text as f,useInput as Tr}from"ink";import En from"ink-text-input";import{useEffect as ya,useState as be}from"react";import{Box as rb,Text as ha,useInput as nb}from"ink";import{useState as ob}from"react";import{jsx as ib,jsxs as Sa}from"react/jsx-runtime";var $p=8;function Lp(e,t){return`${e} ${t}${e===1?"":"s"}`}var si=({logs:e})=>{let[t,r]=ob({offset:0,lineCount:e.length}),n=t.lineCount===e.length?t.offset:0,o=Math.min(e.length,$p),i=e.length>$p;nb((c,l)=>{i&&(l.upArrow?r({offset:Math.min(n+1,e.length-o),lineCount:e.length}):l.downArrow&&r({offset:Math.max(0,n-1),lineCount:e.length}))});let s=Math.max(0,e.length-o-n),a=e.slice(s,s+o);return Sa(rb,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&Sa(ha,{color:"gray",children:[Lp(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>ib(ha,{color:"gray",wrap:"truncate",children:c},s+l)),n>0&&Sa(ha,{color:"gray",children:[Lp(n,"newer line")," (\u2193)"]})]})};import{Box as bn,Text as ai}from"ink";import{Box as sb,Text as ab}from"ink";import{jsx as Mp}from"react/jsx-runtime";var cb=new Set(["Welcome","Finished"]),Np=({status:e,step:t})=>cb.has(t)?null:Mp(sb,{width:"100%",paddingX:1,marginTop:1,children:Mp(ab,{color:"gray",dimColor:!0,children:e})});import{jsx as bt,jsxs as ci}from"react/jsx-runtime";var lb=[{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"}],Fp=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],ub=({currentStep:e,steps:t})=>{let r=t.findIndex(o=>o.id===e),n=r===t.length-1;return bt(bn,{marginY:1,flexWrap:"wrap",children:t.map(({id:o,label:i},s)=>{let a=s<r||n,c=s===r&&!n;return ci(bn,{flexShrink:0,children:[s>0&&bt(ai,{color:"gray",children:" \xB7 "}),a&&ci(ai,{color:"green",children:[y.ok," ",i]}),c&&bt(ai,{color:w,bold:!0,children:i}),!a&&!c&&bt(ai,{color:"gray",children:i})]},o)})})},li=({children:e,status:t,step:r,steps:n=lb,header:o})=>ci(bn,{flexDirection:"column",height:"100%",width:"100%",children:[ci(bn,{flexGrow:1,flexDirection:"column",children:[bt(wt,{...o}),bt(ub,{currentStep:r,steps:n}),bt(bn,{flexDirection:"column",flexGrow:1,children:e})]}),bt(Np,{status:t,step:r})]});import{jsx as u,jsxs as S}from"react/jsx-runtime";var pb=({onConfirm:e})=>(Tr((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:_,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"]})})]})),mb=({defaultValue:e,onSubmit:t})=>{let[r,n]=be(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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(En,{value:r,onChange:n,onSubmit:t})]})]})},fb=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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(va,{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:n=>t(n)})})]}),gb=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:n})=>{Tr((s,a)=>{a.return&&n()});let o=t?.[3e3]??3e3,i=me(e??"developer",t??{});return e==="selfhost"?S(h,{flexDirection:"column",marginTop:2,borderStyle:_,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:",o,"/setup"]})]}),S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),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:_,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:",o]})]}),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"]})})]})},wa=({phase:e,progress:t,isComplete:r,logs:n,title:o,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:w,children:o||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[u(h,{children:r?S(f,{color:"green",children:[y.ok," ",e]}):u(db,{label:e||"Preparing\u2026"})}),!r&&t>0&&u(yr,{percent:t}),!r&&n&&n.length>0&&u(si,{logs:n}),!r&&u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),ba=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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(va,{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)})})]}),Ea=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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(va,{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)"})]})]}),xa=({onSubmit:e})=>{let[t,r]=be({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[n,o]=be(0),[i,s]=be(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"}];Tr((l,d)=>{if(d.tab||d.downArrow)o(p=>p<a.length-1?p+1:p);else if(d.upArrow)o(p=>p>0?p-1:p);else if(d.return){if(n<a.length-1){o(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&&o(m);return}e(t)}});let c=a[n];return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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===n?w:"white",children:[d===n?"\u25B8 ":" ",l.key,":"]})}),u(h,{marginLeft:2,children:u(f,{color:"gray",dimColor:!0,children:l.description})}),d===n?u(h,{marginLeft:2,children:u(En,{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"]})})]})},Ia=({category:e,currentIndex:t,totalGroups:r,onSubmit:n})=>{let[o,i]=be(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=be(0),[c,l]=be(null);ya(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),Tr((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&&!o[E.name]?.trim());if(v.length>0){l(`Required fields cannot be skipped: ${v.map(E=>E.name).join(", ")}`);return}n(o)}});let d=()=>{if(s<e.variables.length-1)a(s+1);else{let m=e.variables.filter(g=>g.required&&!o[g.name]?.trim());if(m.length>0){l(`Required fields are missing: ${m.map(g=>g.name).join(", ")}`);return}l(null),n(o)}},p=e.variables.some(m=>m.required);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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(En,{value:o[m.name]||"",onChange:b=>{i(x=>({...x,[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"]})]})})]})},Ra=({alternatives:e,onSubmit:t})=>{let[r,n]=be(new Set),[o,i]=be({}),[s,a]=be(0),[c,l]=be(null);ya(()=>{let b={};for(let x of e)for(let G of x.variables)b[G.name]=G.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 x=e[b];if(x)for(let G=0;G<x.variables.length;G++)d.push({type:"field",categoryIndex:b,fieldIndex:G})}d.push({type:"submit"});let p=d[s],m=p?.type==="field",g=p?.type==="submit";Tr((b,x)=>{let G=Math.min(s,d.length-1);if(G!==s){a(G);return}if(m)x.upArrow?a(N=>Math.max(0,N-1)):(x.downArrow||x.tab)&&a(N=>Math.min(d.length-1,N+1));else if(g)x.upArrow?a(N=>Math.max(0,N-1)):(x.return||b===" ")&&E();else if(x.upArrow)a(N=>Math.max(0,N-1));else if(x.downArrow||x.tab)a(N=>Math.min(d.length-1,N+1));else if((x.return||b===" ")&&p?.type==="provider"){let N=p.categoryIndex;n(Ct=>{let U=new Set(Ct);return U.has(N)?U.delete(N):U.add(N),U}),c&&l(null)}});let v=()=>{c&&l(null),a(b=>Math.min(d.length-1,b+1))},E=()=>{let b=[],x={};for(let G of r){let N=e[G];if(!N)continue;if(N.variables.some(U=>o[U.name]?.trim())){b.push(N.name);for(let U of N.variables){let Rn=o[U.name];Rn&&(x[U.name]=Rn)}}}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,x)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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,x)=>{let G=r.has(x),N=d.findIndex(U=>U.type==="provider"&&U.categoryIndex===x),Ct=s===N;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[u(f,{color:Ct?w:void 0,bold:Ct,children:Ct?"\u279C ":" "}),u(f,{color:G?"green":"gray",children:G?`[${y.ok}]`:"[ ]"}),S(f,{color:G?w:"gray",bold:G,children:[" ",b.name]}),b.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",b.description]})]}),Ct&&b.docsUrl&&S(h,{marginLeft:6,children:[u(f,{color:"yellow",children:"\u{1F4D6} "}),u(f,{color:"blue",underline:!0,children:b.docsUrl})]}),G&&u(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:b.variables.map((U,Rn)=>{let Dm=d.findIndex(Or=>Or.type==="field"&&Or.categoryIndex===x&&Or.fieldIndex===Rn),Qt=s===Dm,La=!!U.defaultValue,vi=o[U.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Qt?w:"gray",bold:Qt,children:[Qt?" \u279C ":" ",U.name]}),!Qt&&vi&&u(f,{color:"green",children:" \u2713"}),!Qt&&!vi&&La&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",U.defaultValue,")"]})]}),Qt&&u(h,{marginLeft:4,children:u(En,{value:vi,onChange:Or=>{i(Om=>({...Om,[U.name]:Or})),c&&l(null)},onSubmit:v,placeholder:La?`Default: ${U.defaultValue}`:"Enter value\u2026"})})]},U.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:_,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"})})]})},Ca=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:n,onSkip:o})=>{let[i,s]=be(e.defaultValue||""),[a,c]=be(null);ya(()=>{s(e.defaultValue||""),c(null)},[e.name]),Tr((p,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}o()}});let l=p=>{if(e.required&&!p.trim()){c("This field is required");return}c(null),n(p)},d=!!e.defaultValue;return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,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(En,{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"]})]})})]})},Bp=({store:e})=>{let t=Se(e);return S(li,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&u(pb,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&u(Wo,{checks:t.data.checks}),u(Er,{inputId:t.inputRequest?.id,missing:t.data[Gt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&u(br,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&u(mb,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&u(fb,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&u(Ud,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&u(ba,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&u(Ea,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&u(xa,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&u(Ca,{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(Ia,{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(Ra,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&u(Ko,{status:t.status}),t.step==="Finished"&&u(gb,{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(wa,{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(_e,{message:t.error.message})]})};import{Spinner as hb}from"@inkjs/ui";import{Box as zt,Text as _r}from"ink";import{useState as Sb}from"react";import{jsx as Et,jsxs as Fe}from"react/jsx-runtime";var Gp=({store:e})=>{let t=Se(e),r=t.step==="Starting"||t.step==="Stopping",n=t.step==="Running"||t.step==="Stopped",o=t.data.dockerLogs??[],[i]=Sb(Date.now),s=na(r);return Fe(zt,{flexDirection:"column",width:"100%",children:[Et(wt,{showStatus:n}),r&&!t.error&&Fe(zt,{flexDirection:"column",marginTop:1,children:[Fe(zt,{children:[Et(hb,{label:t.status||"Working\u2026"}),Fe(_r,{color:"gray",children:[" ",gt(s-i)]})]}),o.length>0&&Et(si,{logs:o})]}),t.step==="Running"&&t.data.started&&Fe(zt,{flexDirection:"column",marginTop:1,children:[Fe(zt,{children:[Et(z,{kind:"ok"}),Fe(_r,{children:["GAIA is running at"," ",Et(_r,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),Fe(_r,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&Fe(zt,{flexDirection:"column",marginTop:1,children:[Fe(zt,{children:[Et(z,{kind:"ok"}),Et(_r,{children:t.status})]}),t.data.stopMode==="force-ports"&&Fe(_r,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&Et(_e,{message:t.error.message})]})};import{Spinner as vb}from"@inkjs/ui";import{Box as xt,Text as Oe,useInput as yb}from"ink";import{jsx as T,jsxs as Je}from"react/jsx-runtime";var Up=({store:e})=>{let t=Se(e);return Je(li,{status:t.status,step:t.step,steps:Fp,children:[t.step==="Detect Repo"&&Je(xt,{flexDirection:"column",paddingX:2,borderStyle:_,borderColor:w,children:[T(Oe,{bold:!0,children:"Detecting GAIA Repository"}),T(xt,{marginTop:1,children:T(vb,{label:"Searching for repository\u2026"})}),t.data.repoPath&&T(xt,{marginTop:1,children:Je(Oe,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&T(Wo,{checks:t.data.checks}),T(Er,{inputId:t.inputRequest?.id,missing:t.data[Gt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&T(br,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&T(ba,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&T(Ea,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&T(xa,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&T(Ca,{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&&T(Ia,{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&&T(Ra,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&T(Ko,{status:t.status}),t.step==="Project Setup"&&T(wa,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&T(wb,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&T(_e,{message:t.error.message})]})},wb=({setupMode:e,portOverrides:t,onConfirm:r})=>{yb((s,a)=>{a.return&&r()});let n=t?.[3e3]??3e3,o=me(e??"developer",t??{}),i=e==="selfhost";return Je(xt,{flexDirection:"column",marginTop:2,borderStyle:_,borderColor:w,padding:1,children:[T(Oe,{color:w,bold:!0,children:"Setup Complete!"}),Je(xt,{marginTop:1,children:[T(Oe,{bold:!0,children:"Run: "}),T(Oe,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Je(xt,{marginTop:1,flexDirection:"column",children:[Je(Oe,{children:["Web:"," ",Je(Oe,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),Je(Oe,{children:["API:"," ",T(Oe,{color:"cyan",bold:!0,children:o})]})]}),T(xt,{marginTop:1,children:T(Oe,{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"})}),T(xt,{marginTop:1,children:Je(Oe,{dimColor:!0,children:[T(Oe,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as Db}from"@inkjs/ui";import{Box as oe,Text as Qe,useInput as Ob}from"ink";var bb=[{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 jp(e){return Promise.all(bb.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?Eb(t.name,r,t.path):xb(t.name,r)}))}async function Eb(e,t,r){let n=Date.now();try{let o=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-n;return{name:e,port:t,status:o.ok?"up":"down",latency:i,details:o.ok?`HTTP ${o.status}`:`HTTP ${o.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function xb(e,t){let r=await import("node:net"),n=Date.now();return new Promise(o=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let s=Date.now()-n;i.destroy(),o({name:e,port:t,status:"up",latency:s})}),i.on("timeout",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function qp(e){let t=await ee();if(t!=="ready")return{access:t,problem:await tt(t),containers:[]};let r=await qa(Ee[e]);return{access:t,containers:r}}var xn="statusFacts";async function Ib(){let e=L(),t=e?await $(e):null,r=zr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let n=k(e),o=n[O]??O,[i,s,a]=await Promise.all([t==="developer"?jp(n):[],qp(t),No(Lt(t,n),Ee[t])]),c=a.reachable?await He(me(t,n),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:Rb(s.containers)}:s,readiness:a,services:i,webUrl:mt(e,o),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function Rb(e){let t=(P()?.bots??[]).map(Ie).filter(r=>!e.some(n=>n.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function Cb(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await Ib();e.updateData(xn,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function Hp(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await Cb(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var kb=["gaia-web","gaia-backend","arq_worker","proxy"],Ab=["mongo","postgres","redis","rabbitmq","chromadb"];function ui(e,t,r){return t.some(o=>!o.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function Vp(e,t){return t.map(r=>e.find(n=>n.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:$e(r.name)}))}function Wp(e,t){let r=e.readiness,n=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:Wn(i.name)})):Vp(t,Ab),o=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return ui("Data",n,o??"See why with: gaia doctor")}function Pb(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"}:ui("Bots",t.map(r=>({ok:r.status==="running",name:$e(r.name)})),"See why with: gaia doctor")}function Kp(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 Tb(e,t){let r=t.containers,o=[ui("App",Vp(r,kb),"Start it: gaia start"),Wp(e,r),Pb(r)],i=Kp(e);i&&o.push(i);let s=r.some(c=>c.status==="running"),a=o.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:o,unhealthy:a}:{headline:{kind:"fail",text:"GAIA isn't running \xB7 start it: gaia start"},rows:[],unhealthy:!0}}function _b(e){let t=e.services.map(n=>({ok:n.status==="up",name:`${n.name} :${n.port}`})),r=ui("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 di(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,n={label:"Docker",items:[],note:t.problem.state,tone:"warn"},o=Kp(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?[Wp(e,[]),...o?[o]:[],n]:[],unhealthy:!0}}return e.services.length>0?_b(e):Tb(e,t??{access:"ready",containers:[]})}import{jsx as M,jsxs as it}from"react/jsx-runtime";var $b=8,Lb={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},Mb=({row:e})=>it(oe,{children:[M(oe,{width:$b,flexShrink:0,children:M(Qe,{bold:!0,children:e.label})}),it(oe,{flexDirection:"column",flexShrink:1,children:[e.items.length>0&&M(oe,{flexWrap:"wrap",children:e.items.map(t=>it(oe,{marginRight:2,flexShrink:0,children:[M(z,{kind:t.ok?"ok":"fail"}),M(Qe,{children:t.name})]},t.name))}),e.note&&it(oe,{children:[e.items.length===0&&e.tone!=="dim"&&M(z,{kind:e.tone==="warn"?"warn":"ok"}),M(Qe,{color:Lb[e.tone],children:e.note})]})]})]}),Yp=({store:e})=>{let t=Se(e),r=t.data[xn],n=t.data.watch===!0,o=t.step==="Results"&&r!==void 0;Ob((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:n&&t.inputRequest!==null});let i=r?di(r):null,s=i?.headline.kind??"ok";return it(oe,{flexDirection:"column",width:"100%",children:[M(wt,{showStatus:!1}),t.step==="Checking"&&M(oe,{marginTop:1,marginLeft:2,children:M(Db,{label:t.status})}),o&&i&&it(oe,{flexDirection:"column",marginTop:1,marginLeft:2,children:[it(oe,{children:[M(z,{kind:s==="ok"?"active":s}),M(Qe,{bold:!0,children:i.headline.text})]}),i.headline.url&&M(oe,{marginLeft:2,children:M(Qe,{color:w,children:i.headline.url})}),i.hint&&M(oe,{marginLeft:2,children:M(Qe,{children:i.hint})}),i.rows.length>0&&M(oe,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>M(Mb,{row:a},a.label))}),r.installed&&M(oe,{marginTop:1,children:it(Qe,{color:"gray",children:["Installed at ",r.install]})}),n&&M(oe,{marginTop:1,children:it(Qe,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",M(Qe,{bold:!0,children:"r"})," check again \xB7 ",M(Qe,{bold:!0,children:"q"})," quit"]})})]}),t.error&&M(_e,{message:t.error.message})]})};import{defaultTheme as Nb,extendTheme as Fb}from"@inkjs/ui";var pi={success:"ok",error:"fail",warning:"warn",info:"active"},zp=Fb(Nb,{components:{Spinner:{styles:{frame:()=>({color:w})}},ProgressBar:{styles:{completed:()=>({color:w})},config:()=>({completedCharacter:yi.done,remainingCharacter:yi.rest})},StatusMessage:{styles:{icon:({variant:e})=>({color:Lr[pi[e]]})},config:({variant:e})=>({icon:y[pi[e]]})},Alert:{styles:{icon:({variant:e})=>({color:Lr[pi[e]]})},config:({variant:e})=>({icon:y[pi[e]]})}}});import{jsx as ie,jsxs as Dr}from"react/jsx-runtime";var jb=["init","setup","status","start","stop","up","uninstall"],ka=class extends Ub.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Dr(mi,{flexDirection:"column",padding:1,children:[ie(Xt,{color:"red",bold:!0,children:"An unexpected error occurred:"}),ie(Xt,{color:"red",children:this.state.error.message}),this.state.error.stack&&ie(mi,{marginTop:1,children:ie(Xt,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},qb=({store:e,command:t})=>{switch(t){case"init":return ie(Bp,{store:e});case"setup":return ie(Up,{store:e});case"status":return ie(Yp,{store:e});case"start":case"stop":return ie(Gp,{store:e,command:t});case"up":return ie(Op,{store:e});case"uninstall":return ie(hp,{store:e});default:return Dr(mi,{flexDirection:"column",padding:1,children:[Dr(Xt,{color:"red",children:["Unknown command: ",t]}),Dr(mi,{marginTop:1,flexDirection:"column",children:[ie(Xt,{bold:!0,children:"Available commands:"}),jb.map(r=>Dr(Xt,{children:[" ",ie(Xt,{color:"cyan",children:r})]},r))]})]})}},Hb=({onCancel:e})=>(Gb((t,r)=>{r.ctrl&&t==="c"&&e()}),null),Xp=({store:e,command:t,onCancel:r})=>{let n=Se(e);return ie(ka,{children:Dr(Bb,{theme:zp,children:[ie(Hb,{onCancel:r}),n.data[Cn]!==!0&&ie(qb,{store:e,command:t})]})})};import{EventEmitter as Vb}from"events";var Wb=150,Aa=class extends Vb{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))},Wb))}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,n){return this.answerResolvers.map(i=>i(t,n)).find(i=>i!==void 0)===void 0&&!this.autoResolveInputs.has(t)&&this.setStatus(r),this.waitForInput(t,n)}waitForInput(t,r,n){if(this.autoResolveInputs.has(t))return this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t));for(let o of this.answerResolvers){let i=o(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(o=>{if(this.inputResolver=o,n!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),o(null))},n),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())}},Jp=()=>new Aa;async function ve(e){let t=Jp();if(e.whenNonInteractive==="fail"){Zl(e.command),await Qp(t,e);return}he()?await Qp(t,e):await zb(t,e)}async function zb(e,t){eu(e,Gn());for(let[r,n]of t.autoResolve??[])e.setAutoResolve(r,n);try{await t.runFlow(e);let r=em(e);r&&await qn(r,{step:e.currentState.step,steps:ps(e)}),t.onPlainComplete?.(e)}catch(r){e.setError(r)}tm(e)}var Xb="\x1B[1F",Zp=30,Jb=Math.ceil(1e3/Zp);async function Pa(e){e.flush(),await new Promise(t=>setTimeout(t,2*Jb))}async function Qp(e,t){let r=async()=>{},{unmount:n}=Kb(Yb.createElement(Xp,{store:e,command:t.command,onCancel:()=>void r()}),{exitOnCtrlC:!1,maxFps:Zp}),o=async()=>{Ve(e,"cancelled"),await Pa(e),n();let s=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
142
+ ${y.cancelled} Cancelled.${s}
143
+ `),process.exit(130)};r=o,process.once("SIGINT",o),process.once("SIGTERM",o);try{await t.runFlow(e)}catch(s){e.setError(s)}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}await Pa(e);let i=em(e);i&&(e.updateData(Cn,!0),await Pa(e),n(),process.stdout.write(Xb),await qn(i,{step:e.currentState.step,steps:ps(e)})),n(),process.stdout.write(`
144
+ `),tm(e)}function em(e){if(!e.currentState.error)return e.currentState.data.dockerGroupSwitch}function tm(e){let t=e.currentState.error?1:Number(process.exitCode??0),r=[process.stdout,process.stderr].filter(o=>o.writableLength>0);r.length===0&&process.exit(t);let n=r.length;for(let o of r)o.once("drain",()=>{n-=1,n===0&&process.exit(t)})}import*as It from"fs";import*as rm from"os";import*as Jt from"path";var Qb=process.env.GAIA_CLI_DEV==="true";async function nm(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 n=await ti(e),o=await dr(e,n);if(o===null||n==="developer"&&!await wo(e))return;let i="";if(Qb){if(i=lr()||"",!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 Q(500),e.setStatus("Repository ready")}else{e.setStep("Repository Setup");let a=n==="selfhost"?Jt.join(rm.homedir(),"gaia"):Jt.resolve("gaia"),c=!0;for(i=a;;){if(i=await e.waitForInput("repo_path",{default:a}),Jt.isAbsolute(i)||(i=Jt.resolve(i)),It.existsSync(i)){if(!It.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await Q(2e3),e.setError(null);continue}if(sr(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{It.rmSync(i,{recursive:!0,force:!0})}catch(m){e.setError(new Error(`Failed to remove directory: ${m.message}
145
+ 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(It.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await Q(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 Yn(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 Q(1e3),await kr(e,i,n,o),e.currentState.error)return;if(n==="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=cu(e),c=!1;try{e.setStatus("Pulling pre-built images from registry\u2026"),await ue(i,"selfhost",p=>e.setStatus(p),o,a,{pull:"missing"}),c=!0}catch(p){let m=p.message?.split(`
146
+ `)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)\u2026`)}if(!c)try{await ue(i,"selfhost",p=>e.setStatus(p),o,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";Fn({version:A,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",n);let d=await ni(e,{apiUrl:me("selfhost",o),webPort:o[O]??O});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 de("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)\u2026"),await de("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 Q(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(o).length>0?ct(o):void 0;await de("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 Q(1e3);let s=e.currentState.data.envMethod||"manual";Fn({version:A,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 om(e={}){await ve({command:"init",whenNonInteractive:"fail",runFlow:t=>nm(t,e.branch)})}import*as Be from"node:fs";import*as Ge from"node:path";import{execa as fi}from"execa";function Ta(e){if(e.fromDir){let t=Ge.resolve(e.fromDir),r=Ga(t);if(!r)return{volumeFiles:[]};let n=Zt(t,r),o=i=>Be.existsSync(i)?i:void 0;return{mongoFile:e.mongoFile??o(n.mongoFile),postgresFile:e.postgresFile??o(n.postgresFile),apiEnvFile:e.apiEnvFile??o(n.apiEnvFile),volumeFiles:n.volumeFiles.filter(i=>Be.existsSync(i.file))}}return{mongoFile:e.mongoFile,postgresFile:e.postgresFile,apiEnvFile:e.apiEnvFile,volumeFiles:[]}}function im(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 _a(e){let{mongoFile:t,postgresFile:r,apiEnvFile:n,volumeFiles:o}=e,i=[];n&&i.push(`install -m 600 ${n} ../../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 o)i.push(`docker run --rm -v ${s}:/data -v ${Ge.dirname(a)}:/backups alpine sh -c "${Mr(Ge.basename(a))}"`);return i}async function sm(e,t){let r=L();if(!r)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let n=Ge.join(r,"infra","docker"),o=Ge.join(n,"docker-compose.selfhost.yml");if(!Be.existsSync(o))throw new Error(`Compose file not found: ${o}`);let i=Ta(e),{mongoFile:s,postgresFile:a,apiEnvFile:c,volumeFiles:l}=i,d=_a(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(`
147
+ `));if(c&&!Be.existsSync(c))throw new Error(`apps/api/.env backup not found: ${c}`);if(s&&!Be.existsSync(s))throw new Error(`Mongo backup not found: ${s}`);if(a&&!Be.existsSync(a))throw new Error(`Postgres backup not found: ${a}`);for(let{label:m,file:g}of l)if(!Be.existsSync(g))throw new Error(`${m} backup not found: ${g}`);if(e.dryRun)return{...i,commands:d};let p=await ee();if(p!=="ready"){let m=await tt(p);throw new Error([`${m.summary}, so nothing can be restored.`,m.fix,"Or run the restore commands yourself:",...d.map(g=>` ${g}`)].join(`
148
+ `))}if(c&&Zb(c,r),s)try{let m=fi("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","mongo","mongorestore","--archive","--gzip","--drop"],{cwd:n,stdin:"pipe",stderr:"pipe"}),g=Be.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 fi("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph","-c","DROP SCHEMA public CASCADE; CREATE SCHEMA public;"],{cwd:n})}catch(m){throw new Error(`Postgres schema reset failed: ${m.message}`)}try{let m=fi("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph"],{cwd:n,stdin:"pipe",stderr:"pipe"}),g=Be.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 fi("docker",["run","--rm","-v",`${g}:/data`,"-v",`${Ge.dirname(m)}:/backups`,"alpine","sh","-c",Mr(Ge.basename(m))],{cwd:n})}catch(E){throw new Error(`${v} restore failed: ${E.message}`)}return t("Restarting services so they load the restored data and settings\u2026"),await ue(r,"selfhost",t,k(r)),{...i,commands:d}}function Zb(e,t){Ln(e,rt(t))}function Ze(e=""){process.stdout.write(`${e}
149
+ `)}function eE(e=""){process.stderr.write(`${e}
150
+ `)}async function am(e={}){let t={mongoFile:e.mongo,postgresFile:e.postgres,apiEnvFile:e.env,fromDir:e.from},r=Ta(t);for(let n of im(r))eE(`${y.warn} ${n}`);if(e.dryRun){let n=_a(r);if(n.length===0){Ze("No backup files resolved. Use --from <dir> or --mongo/--postgres/--env <file>.");return}Ze("Restore commands (dry run \u2014 not executed):");for(let o of n)Ze(` ${o}`);return}try{Ze("Starting GAIA restore\u2026");let n=await sm(t,o=>Ze(` ${o}`));n.apiEnvFile&&Ze(`Restored apps/api/.env from ${n.apiEnvFile}`),n.mongoFile&&Ze(`Restored MongoDB from ${n.mongoFile}`),n.postgresFile&&Ze(`Restored PostgreSQL from ${n.postgresFile}`);for(let{label:o,file:i}of n.volumeFiles)Ze(`Restored ${o} from ${i}`);Ze("Restore complete. Run 'gaia doctor' to confirm every dependency is ready.")}catch(n){ye(n.message),process.exitCode=1}}async function cm(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository\u2026");let t=lr();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 Q(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await yo(e))return;let r=await ti(e),n=await dr(e,r);if(n===null||r==="developer"&&!await wo(e)||(await kr(e,t,r,n),e.currentState.error))return;if(r==="selfhost"){let a=e.currentState.data.envMethod||"manual";we({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 o=vo(e);if(!await lu(e,t,n,o))return;await Q(1e3);let s=e.currentState.data.envMethod||"manual";we({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 lm(){await ve({command:"setup",whenNonInteractive:"fail",runFlow:cm})}async function um(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository\u2026");let r=L();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r);let n=await $(r);if(!n){e.setError(new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo."));return}if(n==="developer"){e.setError(new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'."));return}if(n==="selfhost"){e.setStatus("Checking Docker\u2026");let s=await ee();if(s!=="ready"){e.setError(await Dt(s));return}}let o=k(r),i=o[O]??O;e.updateData("setupMode",n),e.updateData("webUrl",mt(r,i)),e.updateData("dockerLogs",[]),e.setStatus("Starting GAIA\u2026");try{await ue(r,n,s=>e.setStatus(s),o,(s,a)=>{e.setStatus(s.label),e.updateData("dockerLogs",a.slice(-$r))},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 dm(e){await ve({command:"start",whenNonInteractive:"plain",runFlow:t=>um(t,e),cancelHint:"GAIA may be partly started. Run 'gaia start' again to finish, or 'gaia stop'."})}var pm=8;function Rt(e=""){process.stdout.write(`${e}
151
+ `)}function mm(e){let t=e.currentState.data[xn];return t?{facts:t,report:di(t)}:null}function tE(e){let t=mm(e);if(!t)return;let{facts:r,report:n}=t,o=n.headline.kind==="ok"?y.active:y.fail;Rt(`${o} ${n.headline.text}`),n.headline.url&&Rt(` ${n.headline.url}`),n.hint&&Rt(` ${n.hint}`),n.rows.length>0&&Rt();for(let i of n.rows){let s=i.items.map(c=>`${c.ok?y.ok:y.fail} ${c.name}`).join(" "),a=i.items.length===0?i.note??"":"";Rt(` ${i.label.padEnd(pm)}${s}${a}`.trimEnd()),i.items.length>0&&i.note&&Rt(` ${" ".repeat(pm)}${i.note}`)}r.installed&&(Rt(),Rt(` Installed at ${r.install}`))}async function fm(e={}){await ve({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:async t=>{await Hp(t,e),mm(t)?.report.unhealthy&&(process.exitCode=1)},onPlainComplete:tE})}async function gm(e,t){e.setStep("Stopping"),e.setStatus("Finding your GAIA install\u2026");let r=L();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 n=k(r);try{await so(r,o=>e.setStatus(o),n,t)}catch(o){e.setError(new Error(`GAIA didn't stop. ${o.message}`));return}e.setStep("Stopped"),e.setStatus("GAIA stopped. Start it again with 'gaia start'."),e.updateData("stopped",!0)}async function hm(e){await ve({command:"stop",whenNonInteractive:"plain",runFlow:t=>gm(t,e),cancelHint:"GAIA may still be partly running. Run 'gaia stop' again."})}import*as gi from"fs";import*as hi from"path";function rE(e){let t=hi.join(e,".env");return gi.existsSync(t)?["--env-file",".env"]:[]}async function Sm(){let e=L();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await $(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=hi.join(e,"infra","docker"),n=rE(r),o=k(e),i=Object.keys(o).length>0?ct(o):void 0;if(t==="selfhost"){await hr("docker",["compose",...dt(ar()),...n,"logs","-f","--tail","200"],r,i);return}let s=["compose",...n,"logs","-f","--tail","200"],a=hi.join(e,dl),c=Yi(e),l=typeof c=="number"&&no(c);if(gi.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}gi.existsSync(a)&&!l?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await hr("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 hr("docker",s,r,i))}var nE=16;function Da(e=""){process.stdout.write(`${e}
152
+ `)}function oE(e){let t=e.currentState.data[vn];if(t){Da(),Da(`${y.ok} ${Qo}`);for(let r of Zo(t))Da(` ${r.label.padEnd(nE)}${r.text}`)}}async function vm(e={}){await ve({command:"uninstall",whenNonInteractive:"plain",runFlow:t=>fp(t,e),cancelHint:"GAIA may be partly removed. Run 'gaia uninstall' again to finish.",onPlainComplete:oE})}var iE=16,sE=14;function In(e=""){process.stdout.write(`${e}
153
+ `)}function aE(e){let t=e.currentState.data.upOutcome;if(!t)return;let r=ii(t);In(),In(`${r.tone==="success"?`${y.ok} `:""}${r.headline}`);for(let n of r.rows)In(` ${n.label.padEnd(iE)}${n.text}`);In();for(let[n,o]of oi)In(` ${n.padEnd(sE)}${o}`)}async function ym(e={}){await ve({command:"up",whenNonInteractive:"plain",runFlow:t=>Ap(t,e),cancelHint:"GAIA may be partly set up. Run 'gaia up' again to finish, or 'gaia stop'.",onPlainComplete:aE})}import*as Am from"node:readline";var cE="https://api.github.com/repos/theexperiencecompany/gaia/releases/tags",lE=5e3,uE=5,dE=["Features","Bug Fixes"],pE=/^\* (.+)$/,mE=/^\*\*[^*]+:\*\*\s*/,fE=/(\s*\(\[[^\]]+\]\([^)]+\)\))+$/;function gE(e){let t=e.replace(mE,"").replace(fE,"");return t.charAt(0).toUpperCase()+t.slice(1)}function hE(e){let t=new Map,r="";for(let n of e.split(`
154
+ `)){let o=/^#{2,3} (.+)$/.exec(n.trim());if(o?.[1]){r=o[1];continue}let i=pE.exec(n.trim())?.[1];i&&t.set(r,[...t.get(r)??[],gE(i)])}return dE.flatMap(n=>t.get(n)??[]).slice(0,uE)}async function wm(e){let t=await fetch(`${cE}/${lt(e)}`,{headers:{Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(lE)});if(!t.ok)throw new Error(`GitHub answered HTTP ${t.status}`);let{body:r}=await t.json();return hE(r??"")}import*as bm from"node:fs/promises";import{execa as Si}from"execa";var SE=["apps/web","apps/api","infra/docker"];function Em(e){let{current:t,target:r,explicit:n,gap:o}=e;if(!n){if(ft(t)===null)return{kind:"development-build"};if(!nt(r,t))return{kind:"up-to-date"}}return o?{kind:"unavailable",gap:o}:{kind:"offer",downgrade:nt(t,r)}}async function Oa(e,t){let{stdout:r}=await Si("git",t,{cwd:e});return r.trim()}async function vE(e){let t=await Si("git",["rev-parse","--is-inside-work-tree"],{cwd:e,reject:!1});return t.exitCode!==0||t.stdout.trim()!=="true"?!1:(await Si("git",["remote","get-url","origin"],{cwd:e,reject:!1})).exitCode===0}function yE(e){return e.split(`
155
+ `).map(t=>t.trim()).filter(Boolean)}async function wE(e,t){let r=await Oa(e,["log",t,"--oneline","--",...SE]);return{commits:yE(r)}}async function xm(e,t){lt(t);let r=Ue(e),n=Ki(e),o=n?{kind:"bundle",version:n.version,files:n.files}:{kind:"checkout",files:await cl(e)};return{repoPath:e,fromVersion:r,toVersion:t,layout:o}}function Im(e){return e.fromVersion===e.toVersion&&e.layout.kind==="bundle"&&e.layout.version===e.toVersion}async function Rm(e,t){t.onStatus(`Getting the setup files for GAIA ${e.toVersion}\u2026`);let r=await ro(e.repoPath,e.toVersion,t.onBundleDownload);try{t.onStatus(`Downloading GAIA ${e.toVersion}\u2026`),await gl(e.repoPath,e.toVersion,t.onImagePull)}catch(n){throw await bm.rm(r.stagingDir,{recursive:!0,force:!0}),n}t.onStatus(e.layout.kind==="checkout"?"Moving this install from a git checkout to the release's setup files\u2026":`Switching the setup files to ${e.toVersion}\u2026`),await to(r.manifest,r.stagingDir,e.repoPath,e.layout.files),Kr(e.repoPath,e.toVersion),t.onStatus("Restarting GAIA\u2026"),await ue(e.repoPath,"selfhost",t.onStatus,k(e.repoPath),void 0,{pull:"missing"})}async function Cm(e){if(!await vE(e))throw new Error(`${e} is not a git checkout with an origin remote; run 'gaia update' without --git.`);if((await Si("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 Oa(e,["fetch","origin"]),wE(e,"HEAD..@{upstream}")}async function km(e,t){t("Pulling the latest commits (git pull --ff-only)\u2026"),await Oa(e,["pull","--ff-only"]),t("Rebuilding images from this checkout and restarting\u2026"),await ue(e,"selfhost",t,k(e),void 0,{build:!0})}var bE=5,EE="https://docs.heygaia.io/release-notes";function C(e=""){process.stdout.write(`${pt(e)}
156
+ `)}async function xE(e){let t=Am.createInterface({input:process.stdin,output:process.stdout});t.on("SIGINT",()=>{t.close(),C(`
157
+ ${y.cancelled} Cancelled \xB7 nothing changed.`),process.exit(130)});let r=await new Promise(o=>{t.question(`${e} [y/N] `,i=>o(i))});t.close();let n=r.trim().toLowerCase();return n==="y"||n==="yes"}function IE(){let e=process.stdout.isTTY===!0,t=!1;return{show(r){e&&(process.stdout.write(`\r\x1B[K ${r}`),t=!0)},end(){t&&process.stdout.write("\r\x1B[K"),t=!1}}}function RE(){let e=IE(),t=vr(),r=vr();return{onStatus:n=>{e.end(),C(` ${n}`)},onBundleDownload:({received:n,total:o})=>e.show(o===null?`Setup files: ${Re(n)} downloaded`:`Setup files: ${fn({done:n,total:o,unit:"bytes",estimated:!1},{etaMs:t.update(n,o)})}`),onImagePull:n=>{let o=n.amount;e.show(o?`Images: ${fn(o,{percent:n.percent,etaMs:o.unit==="bytes"?r.update(o.done,o.total):null})} \xB7 ${n.detail??""}`:n.detail??n.label)}}}function CE(e,t){let r=t?e.commits:e.commits.slice(0,bE);for(let o of r)C(` ${o}`);let n=e.commits.length-r.length;n>0&&C(` and ${n} more (--verbose lists them)`)}async function kE(e){try{for(let t of await wm(e))C(` - ${t}`)}catch(t){C(` (couldn't read what's new in ${e}: ${t.message})`)}}async function Pm(e,t){return e.yes?!0:he()?xE(`
158
+ ${t}`):(C(`
159
+ No terminal to confirm in: rerun with --yes to apply.`),!1)}function AE(e,t){let{fromVersion:r,toVersion:n,layout:o}=e;return r===n&&o.kind==="checkout"?`GAIA ${n} runs from a git checkout. Move it to the release's setup files, so it no longer needs git?`:t?`Switch GAIA ${r} back to ${n}`:`Update available: GAIA ${r} \u2192 ${n}`}async function PE(e,t){let r=Ue(e),n=t.version??je,o=t.version!==void 0,s=o||ft(r)!==null&&nt(n,r)?await or(n,P()?.bots??[]):null,a=Em({current:r,target:n,explicit:o,gap:s});switch(a.kind){case"development-build":C(`This install runs a development build of GAIA (${lo(r)}), not a release, so there is nothing to update.`),C(`To switch it to the ${n} release: gaia update --version ${n}`);return;case"up-to-date":C(`GAIA ${r} is up to date.`);for(let d of Lc(A))C(d);return;case"unavailable":C(`${rr(a.gap,"gaia up --build").cause} Nothing was changed.`),o&&(process.exitCode=1);return;case"offer":break}let c=await xm(e,n);if(Im(c)){C(`GAIA ${r} is up to date.`);return}if(C(`
160
+ ${AE(c,a.downgrade)}`),await kE(n),C(`What's new: ${EE}`),C("Your data and settings are kept."),!await Pm(t,"Update and restart now?"))return;let l=RE();await Rm(c,l),c.layout.kind==="checkout"&&C(" This install no longer needs git: it now holds only the release's setup files, beside your settings and data."),C(`
161
+ ${y.ok} GAIA is on ${n}.`),C("Run 'gaia doctor' to check that everything is ready.")}async function TE(e,t){let r=await Cm(e);if(r.commits.length===0){C("Already up to date with the upstream branch.");return}C(`
162
+ ${r.commits.length} new commit(s) touch the self-host stack:`),CE(r,t.verbose===!0),C("The images are rebuilt from this checkout (slow on small machines)."),await Pm(t,"Pull, rebuild and restart now?")&&(await km(e,n=>C(` ${n}`)),C(`
163
+ Updated and restarted from source.`))}async function Tm(e={}){await Mt({showUpdate:!1});let t=L();if(!t){ye(`GAIA isn't installed here, so there is nothing to update.
164
+ Install it with 'gaia up'.`),process.exitCode=1;return}if(e.git&&e.version){ye(`--version and --git can't be used together.
165
+ --version moves to a published release; --git builds from source. Pick one.`),process.exitCode=1;return}for(let r of eo(process.env,A))C(`${y.warn} ${r}`);C(`Checking for updates in ${F(t)}\u2026`);try{await(e.git?TE(t,e):PE(t,e))}catch(r){C(),ye(`GAIA wasn't updated: ${r.message}
166
+ Your data is untouched. Fix the cause above, then run 'gaia update' again.`),process.exitCode=1}}var _E={"":1,true:1,false:0,0:0,1:1,2:2,3:3},DE=new Set(["truecolor","24bit"]),OE=new Set(["iTerm.app","WezTerm","vscode","ghostty"]),$E="Apple_Terminal",LE=/-256(color)?$|-direct$|-truecolor$|^tmux|^xterm-kitty$|^xterm-ghostty$|^alacritty|^wezterm|^foot|^contour/,ME=/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/;function _m({env:e,isTTY:t,platform:r}){let n=e.FORCE_COLOR;if(n!==void 0){let i=_E[n];if(i===void 0)throw new Error(`FORCE_COLOR=${JSON.stringify(n)} is not one of 0-3, true or false`);return i}let o=e.TERM??"";return e.NO_COLOR||!t||o==="dumb"?0:DE.has(e.COLORTERM??"")?3:e.TERM_PROGRAM===$E?2:OE.has(e.TERM_PROGRAM??"")||r==="win32"&&(e.WT_SESSION||!o)||LE.test(o)?3:ME.test(o)||e.COLORTERM?1:0}NE.level=_m({env:process.env,isTTY:process.stdout.isTTY===!0,platform:process.platform});var GE=new Set(["-V","--version"]),K=new FE,$a="For contributors:",UE=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:UE}).enablePositionalOptions().addHelpText("after",`
167
+ New here? Run: gaia up`);K.command("up").description(j.up).option("--yes","Answer yes to every question, including installing Docker").addOption(new BE("--llm-provider <provider>","AI provider to save once GAIA is running (checked first, as the setup page does)").choices(pa)).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("--no-local-name","Don't name GAIA http://gaia.local for other devices on your network (uses port 80 and sudo)").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 ym({...r,noStart:t===!1})});K.command("status").description(j.status).option("--watch","Stay open; press r to check again").action(async e=>{await fm({watch:e.watch})});K.command("stop").description(j.stop).option("--force-ports","Also stop whatever else listens on GAIA's ports (may stop other programs)").action(async e=>{await hm({forcePorts:e.forcePorts})});K.command("start").description(j.start).option("-b, --build","Build GAIA from source before starting (slow)").option("--pull","Download GAIA's images again before starting").action(async e=>{await dm({build:e.build,pull:e.pull?"always":void 0})});K.command("update").description(j.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 Tm(e)});K.command("doctor").description(j.doctor).action(async()=>{await Pd()});K.command("logs").description(j.logs).action(async()=>{try{await Sm()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});K.addCommand(sn);K.addCommand(ld);K.addCommand(ot);K.command("backup").description(j.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 El({output:e.output,dryRun:e.dryRun})});K.command("restore").description(j.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 am({mongo:e.mongo,postgres:e.postgres,env:e.env,from:e.from,dryRun:e.dryRun})});K.command("uninstall").description(j.uninstall).option("--yes","Don't ask: uninstall and keep your data (add --delete-data to delete it)").option("--delete-data","Delete your data too: accounts, chats, memories and files (can't be undone)").action(async e=>{await vm(e)});K.command("init").helpGroup($a).description(j.init).option("--branch <branch>","Git branch to clone").action(async e=>{await om({branch:e.branch})});K.command("setup").helpGroup($a).description(j.setup).action(async()=>{await lm()});K.command("dev [profile]").helpGroup($a).description(j.dev).action(async e=>{try{await dd(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});GE.has(process.argv[2]??"")&&(await Ul(),process.exit(0));process.argv.slice(2).length||(K.outputHelp(),process.exit(0));await xc();K.parse();