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

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 +114 -114
  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 SE from"chalk";import{Command as vE,Option as yE}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 Sl from"node:path";import Im from"is-unicode-supported";var w="cyan",Lr=30,T="round",it=Im(),y={ok:it?"\u2713":"\u221A",fail:it?"\u2717":"x",warn:"!",skip:it?"\u2013":"-",pending:it?"\u25CB":"o",active:it?"\u25CF":"*",cancelled:it?"\u25A0":"#"},wi={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(`
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 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 z from"node:fs";import*as _e from"node:path";import{execa as hl}from"execa";import*as Cn from"node:fs";import*as bi from"node:path";var Rm=/^\d{4}-\d{2}-\d{2}(T\d{2}-\d{2}-\d{2}Z)?$/,Cm=".partial",$a={prefix:"mongo-",suffix:".gz"},La={prefix:"postgres-",suffix:".sql"},Ma={prefix:"api-env-",suffix:".env"},Na=".tar.gz",km=[$a,La,Ma,...Ct.map(e=>({prefix:`${e.fileSuffix}-`,suffix:Na}))];function Ei(e=new Date){return`${e.toISOString().slice(0,19).replaceAll(":","-")}Z`}function Zt(e,t){let r=n=>bi.join(e,`${n.prefix}${t}${n.suffix}`);return{mongoFile:r($a),postgresFile:r(La),apiEnvFile:r(Ma),volumeFiles:Ct.map(n=>xi(e,t,n))}}function xi(e,t,r){return{volume:r.volume,label:r.label,file:bi.join(e,`${r.fileSuffix}-${t}${Na}`)}}function kt(e){return`${e}${Cm}`}function Fa(e){return Cn.existsSync(e)?Cn.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 Rm.test(i)?[i]:[]})).sort().at(-1):void 0}import*as An from"node:fs";import*as Ga from"node:os";import{execa as er}from"execa";var kn="/var/run/docker.sock",be={selfhost:"gaia-selfhost",developer:"gaia-dev"},Am=/\((healthy|unhealthy|health: starting)\)/;async function Ua(e){return(await At(e)).map(r=>({name:r.service,status:r.state==="running"?"running":"stopped",health:r.health}))}async function ja(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 qa(){return Ga.platform()!=="linux"||!An.existsSync(kn)?0:An.statSync(kn).gid}async function At(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 Pm(t)}function Pm(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(Am)?.[1];t.push(s?{service:n,state:o,health:s}:{service:n,state:o})}return t}async function Ha(){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 Va(e){let{stdout:t}=await er("df",["-k",e]);return t}var Ba=26;async function Tm(){let{stdout:e}=await er("docker",["version","--format","{{.Server.Version}}"]);return e.trim()}async function Wa(){let e=await Tm(),t=Number.parseInt(e,10);if(Number.isNaN(t)||t<Ba)throw new Error(`The code sandbox needs Docker Engine ${Ba} 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 Pn(e){let{stdout:t}=await er("docker",["volume","ls","--quiet","--filter",`name=^${e}$`]);return t.trim().split(`
7
+ `).includes(e)}import*as Ec from"node:os";import{execa as zm}from"execa";import{spawn as Um}from"node:child_process";import{constants as fc,promises as jm}from"node:fs";import*as qr from"node:os";import{execa as $i}from"execa";import*as dc from"node:fs";import*as Di from"node:path";import*as Ze from"fs";import*as uc from"os";import*as _i from"path";var Ka={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.7.0-beta.5",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 Ii from"node:path";var Ya=[{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 Ri={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/"}},za={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 Ri[t][e]??za[t][e]}function Tn(){return structuredClone(Ya)}function Xa(e){let t=Ii.join(e,"apps","web",".env.local"),r=Fr.existsSync(t)?t:Ii.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 d=a.replace(/^#+\s*/,"").trim();d&&!d.startsWith("These are")&&(i=d);continue}if(!a||a.startsWith("#"))continue;let c=a.indexOf("=");if(c===-1)continue;let l=a.substring(0,c).trim(),p=a.substring(c+1).trim();o.push({name:l,value:p,category:i})}return o}function Ja(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function Qa(e,t,r){let n=r==="selfhost"?new Set(Object.keys(Ri.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 p=new RegExp(`:${s}(?=[/\\s]|$)`,"g");e[c]=l.replaceAll(p,`:${a}`)}}}function Za(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(Ri.selfhost)}function ec(e){return{...za[e]}}var $m=[".test",".example",".invalid",".localhost",".local",".internal",".home.arpa"],tc="docker cp gaia-selfhost-proxy-1:/data/caddy/pki/authorities/local/root.crt gaia-root.crt";function _n(e){let t=e.toLowerCase();return $m.some(r=>t.endsWith(r))}function Pt(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 Ci=384;function Dn(e){if(j.existsSync(e)){let t=`${e}.bak`;j.copyFileSync(e,t),j.chmodSync(t,Ci)}}function On(e,t){j.mkdirSync(st.dirname(e),{recursive:!0}),j.writeFileSync(e,t,{encoding:"utf-8",mode:Ci}),j.chmodSync(e,Ci)}function $n(e,t){Dn(t),On(t,j.readFileSync(e,"utf-8"))}function Ur(e,t){let r=st.join(e,".env");Dn(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 d=/[\s#"'\\]/.test(c)||c===""?`"${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:c;s.get(l).push(`${a}=${d}`)}for(let[a,c]of s.entries())n.push(`# ${a} Configuration`),n.push(...c),n.push("");On(r,n.join(`
10
+ `))}function oc(e,t,r){let n=st.join(e,"apps","web",".env.local");Dn(n);let o=Xa(e),i=Ja(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:p,value:d}of l)s.push(`${p}=${d}`);s.push("")}On(n,s.join(`
11
+ `))}var ki={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"},rc=Object.fromEntries(Object.entries(ki).map(([e,t])=>[t,Number(e)])),Lm="proxy";function ic(e){return st.join(e,"infra","docker",".env")}function Ln(e){let t=ic(e);return j.existsSync(t)?Pt(j.readFileSync(t,"utf-8")):{}}var Tt="GAIA_VERSION",Mm="latest",sc="GAIA_DOMAIN",nc="GAIA_CADDY_GLOBAL_OPTIONS",Nm="local_certs";function Mn(e){return Ln(e)[sc]||void 0}function Be(e){return Ln(e)[Tt]??Mm}function ac(e,t){let r=ic(e);Dn(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(""),On(r,n.join(`
12
+ `))}function cc(e,t,r){ac(e,{...Ln(e),[t]:r})}function Ai(e,t,r,n){let{NEXT_PUBLIC_APP_URL:o,...i}=Ln(e);for(let[s,a]of Object.entries(t)){let c=Number(s),l=ki[c];l&&(i[l]=String(a))}r==="selfhost"&&n&&(i.COMPOSE_PROFILES??=Lm,i.DOCKER_SOCKET_GID=String(n.dockerSocketGid),n.domain&&(i[sc]=n.domain,_n(n.domain)?i[nc]=Nm:delete i[nc])),ac(e,i)}function at(e){let t={};for(let[r,n]of Object.entries(e)){let o=Number(r),i=ki[o];i&&(t[i]=String(n))}return t}function lc(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 k(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&&rc[s]){let c=a.join("=").trim().replace(/^["']|["']$/g,""),l=Number(c);!Number.isNaN(l)&&l>0&&l<=65535&&(r[rc[s]]=l)}}}return r}var C=Ka.version;function Pi(e,t){return e[Tt]||`v${t}`}var Ge=Pi(process.env,C);var Ee=_i.join(uc.homedir(),".gaia"),Ti=_i.join(Ee,"config.json");function Bm(){Ze.existsSync(Ee)||Ze.mkdirSync(Ee,{recursive:!0})}function A(){try{if(!Ze.existsSync(Ti))return null;let e=Ze.readFileSync(Ti,"utf-8");return JSON.parse(e)}catch{return null}}function Nn(e){Bm(),Ze.writeFileSync(Ti,`${JSON.stringify(e,null,2)}
14
+ `)}function Se(e){let r={...A()??{version:C,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Nn(r)}var jr=Di.join(Ee,"logs");function Ue(e,t=new Date){dc.mkdirSync(jr,{recursive:!0});let r=t.toISOString().slice(0,19).replaceAll(":","-");return Di.join(jr,`${e}-${r}.log`)}function Fn(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 pc from"node:fs";import{execa as Oi}from"execa";function mc(){return typeof process.getuid=="function"&&process.getuid()===0}async function Gm(){mc()||!(await Oi("sudo",["-n","true"],{reject:!1})).failed||await Oi("sudo",["-v","-p","[sudo] password for %u: "],{stdio:"inherit"})}async function q(e,t,r,n){await Gm();let[o,i]=mc()?[e,[...t]]:["sudo",["-n",e,...t]],s=pc.createWriteStream(r,{flags:"a"}),a=Fn(p=>n?.(p)),c=Oi(o,i,{all:!0,reject:!1});c.all?.on("data",p=>{s.write(p),a(p.toString())});let l=await c;if(await new Promise(p=>s.end(p)),l.failed)throw new Error(`'${[e,...t].join(" ")}' failed (exit ${l.exitCode??"unknown"}). Its output is in ${r}`)}var oe="docker",Li="GAIA_DOCKER_GROUP_RELAUNCHED",gc="GAIA_RESUMED_STEP",hc="GAIA_RESUMED_STEPS";function Bn(){return process.env[gc]||void 0}function Gn(){let e=process.env[hc];return e?JSON.parse(e):{}}async function Un(){let{stdout:e}=await $i("id",["-nG",qr.userInfo().username]);return e.split(/\s+/).includes(oe)}function Sc(e){let t=e.stderr;return typeof t=="string"&&t.toLowerCase().includes("permission denied")}async function vc(){if(process.env[Li]==="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 Un())return;let e=qr.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 qm=/^[A-Za-z_][A-Za-z0-9_]*$/;async function Hm(e){try{return await $i("sh",["-c",'command -v "$1"',"sh",e]),!0}catch{return!1}}async function Vm(){try{return await $i("sudo",["-l","-g",oe,"--",process.execPath]),!0}catch{return!1}}async function yc(){return await Hm("sg")?"sg":await Vm()?"sudo":null}async function wc(){let e=await yc();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 '${oe}' group).
17
+ Log out and back in (or run 'newgrp ${oe}'), then rerun this command.`)}function Wm(e){return`'${e.replaceAll("'","'\\''")}'`}function Km(e,t,r){return e==="sg"?["sg",[oe,"-c",t.map(Wm).join(" ")]]:["sudo",[`--preserve-env=${Object.keys(r).filter(o=>qm.test(o)).join(",")}`,"-g",oe,"--",...t]]}function jn(e,t){let r={...process.env,[Li]:"1",...t&&{[gc]:t.step,[hc]:JSON.stringify(t.steps)}},[n,o]=Km(e,[process.execPath,...process.argv.slice(1)],r),i=Um(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 Ym(){try{return await jm.access(kn,fc.R_OK|fc.W_OK),!1}catch(e){let t=e.code;if(t==="ENOENT")return!1;if(t==="EACCES")return!0;throw e}}async function bc(){if(qr.platform()!=="linux"||process.env[Li]==="1"||process.env.DOCKER_HOST||!await Ym()||!await Un())return;let e=await yc();e&&await jn(e)}var Xm=5e3,Jm="https://orbstack.dev",Mi="Run 'gaia up': it installs everything GAIA needs.";async function Z(){try{return await zm("docker",["info"],{timeout:Xm}),"ready"}catch(e){return e.code==="ENOENT"?"not-installed":Sc(e)?"no-permission":"not-running"}}async function et(e){let t=Ec.platform()==="darwin";switch(e){case"not-installed":return{summary:"Docker isn't installed",state:"isn't installed",fix:t?`Install OrbStack (${Jm}) or Docker Desktop, open it, then try again.`:Mi};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 Un()?`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 _t(e){let t=await et(e);return new Error(`${t.summary}.
18
+ ${t.fix}`)}import{execa as pg}from"execa";import*as Ie from"fs";import*as ae from"path";import*as tr from"node:fs";import*as Hr from"node:path";import*as Ic from"node:crypto";var xc=["AGENT_SECRET","BOT_SESSION_TOKEN_SECRET","EMAIL_UNSUBSCRIBE_SECRET","SHARE_GRANT_SECRET","GAIA_BOT_API_KEY"],Qm=["INSTANCE_SECRET"];function Ni(){return Ic.randomBytes(32).toString("hex")}function Zm(e){return new Set(Object.keys(Pt(e)))}function qn(e){let t=Zm(e),r={},n=e===null?[...xc,...Qm]:xc;for(let o of n)t.has(o)||(r[o]=Ni());return r}var Rc=["telegram","discord","slack"],Cc={telegram:["TELEGRAM_BOT_TOKEN"],discord:["DISCORD_BOT_TOKEN","DISCORD_CLIENT_ID"],slack:["SLACK_BOT_TOKEN","SLACK_APP_TOKEN","SLACK_SIGNING_SECRET"]},Gi={telegram:"TELEGRAM_BOT_USERNAME",discord:"DISCORD_CLIENT_ID",slack:"SLACK_WORKSPACE_URL"},ef={GAIA_BOT_API_KEY:"GAIA_BOT_API_KEY",GAIA_FRONTEND_URL:"FRONTEND_URL",RABBITMQ_URL:"RABBITMQ_URL"},tf="BOT_LOG_HASH_SECRET";function xe(e){return`bot-${e}`}function Vr(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 kc(e){return`docker-compose.${xe(e)}.yml`}function Fi(e){return Hr.join(e,"apps","api")}function rf(e){return Hr.join(e,"apps","bots")}function Bi(e){let t=Hr.join(e,".env");return tr.existsSync(t)?Pt(tr.readFileSync(t,"utf-8")):{}}function Ac(e,t){let r={...e,...t.set};for(let n of t.unset??[])delete r[n];return r}function Hn(e,t){let r=Fi(e),n=Bi(r),o=Ac(n,t);JSON.stringify(o)!==JSON.stringify(n)&&Ur(r,o)}function Wr(e,t={}){let r=Hr.join(Fi(e),".env");if(!tr.existsSync(r))throw new Error(`${r} does not exist; run 'gaia up' to configure the install first.`);let n=qn(tr.readFileSync(r,"utf-8"));Object.keys(n).length>0&&Hn(e,{set:n});let o=Bi(Fi(e)),i={};for(let[c,l]of Object.entries(ef)){let p=o[l];if(!p)throw new Error(`${l} is not set in apps/api/.env; run 'gaia up' to configure the install first.`);i[c]=p}let s=rf(e),a=Ac(Bi(s),t);a[tf]??=Ni(),Ur(s,{...a,...i})}var nf={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"},of={mongodb:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB"};function je(e){return nf[e]??e}function Vn(e){return of[e]??e}import*as Pc from"node:os";function _(e,t=Pc.homedir()){return e===t?"~":e.startsWith(`${t}/`)?`~${e.slice(t.length)}`:e}import{execa as ff}from"execa";import{execa as af}from"execa";import Kn from"fs";import cf from"simple-git";var sf={KiB:1024,MiB:1048576,GiB:1073741824};function qe(e){return e>=1e9?`${(e/1e9).toFixed(1)} GB`:`${Math.round(e/1e6)} MB`}function Wn(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 Tc(e){let t=/^([\d.]+)\s*(KiB|MiB|GiB)$/.exec(e.trim());return!t?.[1]||!t[2]?null:Number(t[1])*sf[t[2]]}var Ui=.85,lf=/Receiving objects:\s+(\d+)%[^,\r\n]*(?:,\s*([\d.]+\s*[KMG]iB))?/g,uf=/Resolving deltas:\s+(\d+)%/g,df=/remote: (?:Enumerating|Counting|Compressing) objects:/;function pf(e){let t=[...e.matchAll(uf)].at(-1);if(t?.[1]){let n=Number(t[1]);return{percent:Math.floor(Ui*100+n*(1-Ui)),label:"Unpacking the files"}}let r=[...e.matchAll(lf)].at(-1);if(r?.[1]){let n=Number(r[1]),o=r[2]?Tc(r[2]):null;return{percent:Math.floor(n*Ui),label:o===null?"Downloading":`${qe(o)} so far`}}return df.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 cf().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=af("git",o);i.stderr?.on("data",s=>{let a=pf(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 Dc="https://github.com/theexperiencecompany/gaia.git",_c="https://heygaia.io/install.sh",gf=/^\d+\.\d+\.\d+-beta\.\d+$/;function ji(e){return gf.test(e)?"beta":"latest"}function Kr(e){return e==="beta"?`curl -fsSL ${_c} | GAIA_CHANNEL=beta sh`:`curl -fsSL ${_c} | sh`}function Oc(e){let t=ji(e),r=[`For a newer release, update the CLI first (${Kr(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 ${Kr("latest")} and rerun 'gaia update'.`),r}var hf=2,Sf=/^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function ct(e){if(!Sf.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 vf(e,t,r){let n=ct(t),o=await ff("git",["ls-remote","--exit-code","--tags",e,`refs/tags/${n}`],{cwd:r,reject:!1});if(o.exitCode!==0)throw o.exitCode===hf?new Error(`GAIA ${t} has no published release: ${e} has no tag ${n}.
19
+ Install a released CLI (${Kr("latest")}) and rerun.`):new Error(`Could not read ${n} from ${e}: ${o.stderr.trim()}`)}function Yr(e,t){cc(e,Tt,t)}async function $c(e,t,r){await vf(t,Ge),await Yn(e,t,r,ct(Ge)),Yr(e,Ge)}var yf=/ghcr\.io\/theexperiencecompany\/(gaia[\w-]*):([\w.-]+)/,wf={gaia:"API","gaia-web":"web app"};function Mc(e){let t=yf.exec(e);return t?.[1]&&t[2]?{name:t[1],tag:t[2]}:null}function Lc(e){let t=wf[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:`${Lc(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: ${Lc(r)} doesn't exist in the registry.`,next:`Update the CLI (${Kr(ji(C))}) and run it again, or build from source: ${t}.`}}var bf=(e,t)=>{let r=/no matching manifest for linux\/([\w]+)/.exec(e)?.[1];if(!r)return null;let n=Mc(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).`}},Ef=(e,t)=>{if(!/manifest unknown|: not found|failed to resolve reference|No such image/.test(e))return null;let r=Mc(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}.`}},xf=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>."}},If=[[/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."}]],Rf=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 Cf(e){return([...e].reverse().find(r=>/error|failed|denied/i.test(r))??e.at(-1)??"docker compose failed").trim()}function Nc(e,t,r){let n=[...e,...t].join(`
20
+ `);for(let o of[bf,Ef,xf,Rf]){let i=o(n,r);if(i)return i}for(let[o,i]of If)if(o.test(n))return i;return{cause:`Docker Compose failed: ${e.at(-1)??Cf(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 Wc from"node:fs";import{execa as Kc}from"execa";import qc from"semver";function Bc(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 zn="Image ",Gc="Container ",kf=/^\[[^\]]*\d+\/\d+\]/,Af=/^gaia-(?:selfhost|dev)-(.+)-\d+$/,Pf=new Set(["Stopping","Removing"]),Fc=new Set(["Stopped","Removed"]),Tf=2;function _f(e){return e.slice(e.lastIndexOf("/")+1)}function Df(e){let t=e.slice(Gc.length);return Af.exec(t)?.[1]??t}function Of(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"} ${_f(r)}`),e.images.set(r,"ready")):e.images.set(r,t.text==="Building"?"building":"downloading"))}function $f(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 Lf(e,t){let r=Df(t.id??""),n=t.text??"";if(Pf.has(n)||Fc.has(n)){e.stopping.set(r,e.stopping.get(r)===!0||Fc.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 Uc(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||!kf.test(i)||e.steps.set(n.digest,{name:i,done:o?.done===!0||!!n.completed})}let r=t.id??"";return r.startsWith(zn)?Of(e,t):r.startsWith(Gc)?Lf(e,t):t.parent_id?.startsWith(zn)&&$f(e,t),e}var Mf=99;function Nf(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 Ff(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 qi(e){let t=e.slice(0,Tf).map(je),r=e.length-t.length;return r>0?`${t.join(", ")} and ${r} more`:t.join(" and ")}function Bf(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 ${qi(t)} (${n})`,percent:o}}function Gf(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 ${qi([...e.awaitingHealth])} to be ready`:s.length>0?`starting ${qi(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 Uf(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 jc(e){if(e.stopping.size>0)return Bf(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(p=>p==="ready").length,i=e.expectedLayers.size>0?Nf(e):Ff(e),s={done:i.downloaded,total:i.total,unit:"bytes",estimated:i.estimated},a=s.total>0?Math.min(Mf,Math.floor(s.done/s.total*100)):0,c=`${o} of ${n.length} ready`;return Uf(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?Wn(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?Gf(e):null}var Hc="2.29.1",jf=40,Vc;function qf(){return Vc??=(async()=>{let{stdout:e}=await Kc("docker",["compose","version","--short"]),t=qc.coerce(e.trim());if(!t||qc.lt(t,Hc))throw new Error(`GAIA needs Docker Compose ${Hc} or newer; this machine has ${e.trim()||"an unknown version"}.
22
+ Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),Vc}function Hf(e){if(!e.startsWith("{"))return null;try{return JSON.parse(e)}catch{return null}}async function Xn(e,t){await qf();let r=Ue(t.logName),n=Wc.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=Bc(o&&"layers"in o?o.layers:void 0),s=[],a=Fn(p=>{let d=Hf(p);if(!d){s.push(p),s.length>jf&&s.shift();return}Uc(i,d);let m=jc(i);m&&t.onProgress?.(m,i.finished)}),c=Kc("docker",["compose","--progress","json",...e],{cwd:t.cwd,env:t.env,all:!0,reject:!1,timeout:t.timeoutMs});c.all?.on("data",p=>{n.write(p),a(p.toString())});let l=await c;if(a(`
24
+ `),await new Promise(p=>n.end(p)),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(Nc(i.errors,s,{rebuildCommand:t.rebuildCommand}),r);return{startedServices:i.started.size}}import{execa as el}from"execa";import*as zc from"node:os";var Xc="https://ghcr.io",Jc="theexperiencecompany",Qc=8e3,Vf=["gaia","gaia-web"],Wf=["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 Kf(e){let t=await fetch(`${Xc}/token?scope=repository:${Jc}/${e}:pull`,{signal:AbortSignal.timeout(Qc)});if(!t.ok)throw new Error(`GHCR token request answered HTTP ${t.status}`);return(await t.json()).token}async function Yc(e,t,r){return fetch(`${Xc}/v2/${Jc}/${e}/${t}`,{headers:{Authorization:`Bearer ${r}`,Accept:Wf},signal:AbortSignal.timeout(Qc)})}async function Yf(e,t){let r=await Kf(e),n=await Yc(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 Yc(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=[...Vf,...t.map(o=>`gaia-bot-${o}`)];for(let o of n){let i=await Yf(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 tl=8e3,Hi="docker.io",zf="registry-1.docker.io",Xf=12,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 Qf(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:Hi,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===Hi&&!a.includes("/")&&(a=`library/${a}`),{host:s===Hi?zf: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;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 rl(e,t,r){return fetch(`https://${e.host}/v2/${e.repository}/manifests/${t}`,{headers:{Accept:Jf,...r?{Authorization:`Bearer ${r}`}:{}},signal:AbortSignal.timeout(tl)})}async function eg(e){let t=await rl(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(tl)});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 rl(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 tg(e,t=nr()){let r=Qf(e),n=await eg(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,Xf),i.size]))}async function rg(e){let t=await Promise.all(e.map(r=>tg(r)));return new Map(t.flatMap(r=>[...r]))}async function ng(e){let t=await Promise.all(e.map(r=>el("docker",["image","inspect",r],{reject:!1})));return e.filter((r,n)=>t[n]?.exitCode!==0)}async function Vi(e,t,r,n){try{let{stdout:o}=await el("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 ng(a);return{layers:await rg(c)}}catch(o){return{unknown:o.message}}}import*as Dt from"node:fs";import*as se from"node:fs/promises";import*as ie from"node:path";import{execa as nl}from"execa";import{z as Zn}from"zod";import{createHash as og}from"node:crypto";var zr=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 zr(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=og("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 Ki="gaia-selfhost.json",Wi="GAIA_BUNDLE_BASE_URL",ig="https://github.com/theexperiencecompany/gaia/releases/download",sg=404,ag=Zn.object({version:Zn.string(),files:Zn.array(Zn.string())});function eo(e,t){let r=[],n=Pi(e,t);n!==`v${t}`&&r.push(`Installing GAIA ${n}'s images, not v${t}'s (${Tt})`);let o=e[Wi];return o&&r.push(`Setup files from ${o} (${Wi})`),r}function cg(e,t=process.env){let r=ct(e),n=`gaia-selfhost-${e.slice(1)}.tar.gz`,o=(t[Wi]??`${ig}/${r}`).replace(/\/+$/,"");return{asset:n,bundle:`${o}/${n}`,checksum:`${o}/${n}.sha256`}}async function lg(e,t){let{asset:r,bundle:n,checksum:o}=cg(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 zr&&i.status===sg?new Error(`GAIA ${e} has no published setup files: ${i.url} answered 404.`):i}}function Yi(e){let t=ie.join(e,Ki);return Dt.existsSync(t)?ag.parse(JSON.parse(Dt.readFileSync(t,"utf-8"))):null}async function ug(e,t,r){await se.rm(t,{recursive:!0,force:!0}),await se.mkdir(t,{recursive:!0}),await nl("tar",["-xzf","-","-C",t],{input:e});let n=Yi(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=>!Dt.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 dg(e,t){for(let r=t;r.startsWith(`${e}${ie.sep}`);r=ie.dirname(r))if(Dt.existsSync(r)){if((await se.readdir(r)).length>0)return;await se.rmdir(r)}}async function to(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 dg(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 ro(e,t,r){let n=await lg(t,r),o=ie.join(e,".gaia-selfhost-staging");return{manifest:await ug(n,o,t),stagingDir:o}}async function ol(e){if(!Dt.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=>nl("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 mg=e=>new Promise(t=>setTimeout(t,e)),al="dev-start.log",oo=".gaia-dev.pid",cl="gaia start --build";function fg(e){return e?.remove?["down","--rmi","all","--remove-orphans",...e.remove.volumes?["--volumes"]:[]]:["down"]}function io(e){let t=ae.join(e,".env");return Ie.existsSync(t)?["--env-file",".env"]:[]}var gg=60;function hg(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:gg;return r===0?void 0:r*60*1e3}function ar(e={}){let t=A(),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(kc)),r}function ut(e){return e.flatMap(t=>["-f",t])}var ll="gaia-sandbox-workspace",il="/legacy-sandbox-workspace";function Sg(e,t){return["compose",...ut(e),...t,"run","--rm","--no-deps","-v",`${ll}:${il}:ro`,"gaia-backend","python","-m","app.scripts.migrate_legacy_sandbox_workspace","--legacy-root",il]}function vg(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 zi(e){let t=ae.join(e,oo);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 no(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=A();c?.codeSandbox===!0&&await Wa(),c?.bots?.length&&Wr(e);let l=ar({build:i?.build});i?.build&&Ji(e);let p=io(s),d=[...ut(l),...p],m=i?.build?void 0:await Vi(s,d,a,{always:i?.pull==="always"}),g=await Xn(vg(l,p,i),{cwd:s,env:a,timeoutMs:hg(),logName:i?.build?"compose-build":"compose-up",rebuildCommand:i?.rebuildCommand??cl,onLogFile:i?.onLogFile,onProgress:o,pullSize:m}).catch(async v=>{throw await wg(v,d,s)});return await Pn(ll)&&(r?.("Moving code-sandbox files into per-user workspaces\u2026"),await le("docker",Sg(l,p),s,void 0,void 0,a)),r?.("GAIA's services are running."),g}var yg=8;async function wg(e,t,r){if(!(e instanceof lt)||!e.failure.service)return e;let{stdout:n}=await pg("docker",["compose",...t,"logs","--no-color","--no-log-prefix","--tail",String(yg),e.failure.service],{cwd:r}),o=n.split(`
32
+ `).filter(i=>i.trim());return new lt({...e.failure,logTail:o},e.logPath)}function Xi(e){return["compose",...ut(ar()),...io(e)]}async function ul(e,t,r,n){let o=ae.join(e,"infra/docker");await le("docker",[...Xi(o),"run","--rm","--no-deps",t,...r],o,void 0,n)}var bg=["gaia-backend","arq_worker","gaia-web"];async function dl(e,t,r){let n=ae.join(e,"infra/docker"),o=[...ut(ar()),...io(n)],i=[...bg,...(A()?.bots??[]).map(xe)],s={GAIA_VERSION:t};await Xn([...o,"pull",...i],{cwd:n,env:s,logName:"compose-pull",rebuildCommand:"gaia up --build",onProgress:r,pullSize:await Vi(n,o,s,{services:i,always:!0})})}async function so(e,t,r,n){let o=ae.join(e,"infra/docker"),[i,s]=await Promise.all([$(e),Z()]);if(s==="ready"){t?.("Stopping GAIA's containers\u2026");let a=io(o),c=i==="selfhost"?ut(ar()):[];await Xn([...c,...a,...fg(n)],{cwd:o,logName:"compose-down",rebuildCommand:cl,onProgress:l=>t?.(l.label)})}else{if(i==="selfhost")throw await _t(s);if(s==="no-permission")throw await _t(s)}i!=="selfhost"&&await Eg(e,t,r,n),t?.("All services stopped.")}async function Eg(e,t,r,n){t?.("Stopping GAIA-managed local processes (safe mode)\u2026");let o=zi(e),i=o!==null&&await xg(e,o);try{Ie.unlinkSync(ae.join(e,oo))}catch{}if(!i){if(n?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports\u2026"),await Ig(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 xg(e,t){if(!no(t))return!1;try{return process.platform==="win32"?(await le("taskkill",["/PID",String(t),"/T","/F"],e),!0):(sl(t,"SIGTERM"),await mg(800),no(t)&&sl(t,"SIGKILL"),!0)}catch{return!1}}function sl(e,t){try{process.kill(-e,t)}catch{process.kill(e,t)}}async function Ig(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 Rg=8;function Cg(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 le(e,t,r,n,o,i,s){let{spawn:a}=await import("child_process");return new Promise((c,l)=>{let p=a(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],env:i?{...process.env,...i}:void 0}),d="",m=0,g=!1,v;s&&(v=setTimeout(()=>{g=!0,p.kill("SIGTERM"),l(new Error(`Command timed out after ${Math.round(s/6e4)}m. Check \`docker compose logs\` to debug.`))},s)),p.stdout?.on("data",E=>{let b=E.toString();d+=b,o?.(b),m=Math.min(m+5,95),n?.(m)}),p.stderr?.on("data",E=>{let b=E.toString();d+=b,o?.(b),m=Math.min(m+5,95),n?.(m)}),p.on("close",E=>{v&&clearTimeout(v),!g&&(E===0?(n?.(100),c()):l(new Error(`Command failed with code ${E}:
35
+ ${Cg(d,Rg)}`)))}),p.on("error",E=>{v&&clearTimeout(v),!g&&l(E)})})}var kg="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,kg))}function Ji(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,Ki))||sr(e)}function pl(e,t){let r=e;for(;r!==ae.dirname(r);){if(t(r))return r;r=ae.dirname(r)}return null}function ml(){let e=A();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=pl(e??process.cwd(),sr);if(t)return t;let r=ml();return r&&sr(r)?r:null}function L(e){let t=pl(e??process.cwd(),cr);return t&&Ie.existsSync(tt(t))?t:ml()??t}function Xr(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 Ag(e,t=Ei()){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/${_e.basename(o)} -C /data .`)]}function Pg(e){return _e.join(e,"infra","docker")}function Tg(e,t){return t?_e.resolve(t):_e.join(e,"backups")}async function Jr(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=Pg(t),n=_e.join(r,"docker-compose.selfhost.yml");if(!z.existsSync(n))throw new Error(`Compose file not found: ${n}`);let o=Tg(t,e.outputDir),i=Ei(),s=Zt(o,i),a=Ag(o,i);if(e.dryRun)return{...s,commands:a,warnings:[]};let c=await Z();if(c!=="ready"){let d=await et(c);throw new Error([`${d.summary}, so the databases cannot be backed up.`,d.fix,"Or run the backup commands yourself:",...a.map(m=>` ${m}`)].join(`
37
+ `))}await z.promises.mkdir(o,{recursive:!0,mode:448});try{z.chmodSync(o,448)}catch{}let l=[s.mongoFile,s.postgresFile,s.apiEnvFile,...s.volumeFiles.map(d=>d.file)],p;try{p=await _g(t,r,o,i,a)}catch(d){for(let m of l)z.rmSync(kt(m),{force:!0});throw d}for(let d of[s.mongoFile,s.postgresFile,s.apiEnvFile,...p.volumeFiles.map(m=>m.file)])z.renameSync(kt(d),d);return{...s,...p,commands:a}}async function _g(e,t,r,n,o){let i=Zt(r,n);Dg(e,kt(i.apiEnvFile));try{await gl("docker",fl("mongo",["mongodump","--archive","--gzip"]),t,kt(i.mongoFile))}catch(c){throw new Error(`MongoDB backup failed: ${c.message}
38
+ Manual command: ${o[1]}`)}try{await gl("docker",fl("postgres",["pg_dump","-U","postgres","-d","langgraph"]),t,kt(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=xi(r,n,c),p=kt(l.file);if(!await Pn(c.volume)){a.push(`${c.label} volume ${c.volume} not found \u2014 nothing to back up`);continue}try{await hl("docker",["run","--rm","-v",`${c.volume}:/data`,"-v",`${_e.dirname(p)}:/backups`,"alpine","tar","czf",`/backups/${_e.basename(p)}`,"-C","/data","."],{cwd:t});try{z.chmodSync(p,384)}catch{}s.push(l)}catch(d){z.rmSync(p,{force:!0});let m=`${c.label} backup failed: ${d.message}`;if(c.userData)throw new Error(m);a.push(m)}}return{volumeFiles:s,warnings:a}}function Dg(e,t){let r=tt(e);if(!z.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.`);$n(r,t)}function fl(e,t){return["compose","-f","docker-compose.selfhost.yml","exec","-T",e,...t]}async function gl(e,t,r,n){z.writeFileSync(n,"",{mode:384,flag:"wx"});try{await hl(e,t,{cwd:r,stdout:{file:n},buffer:{stdout:!1}})}catch(o){throw z.rmSync(n,{force:!0}),o}}function D(e=""){process.stdout.write(`${e}
40
+ `)}async function vl(e={}){if(e.dryRun){let t=await Jr({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 Jr({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(Sl.basename(n))}"`)}catch(t){he(t.message),process.exitCode=1}}import{Argument as Qh,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 ah from"chalk";import{supportsHyperlink as ch}from"supports-hyperlinks";import Og from"wrap-ansi";var $g=40,Lg=80,Mg=24;function Qr(e){return{columns:e.columns||Lg,rows:e.rows||Mg}}function Qi(e,t){return Og(e,t,{hard:!0})}function dt(e,t=0){let r=process.stdout.isTTY?process.stdout.columns:void 0;return!r||r-t<$g?e:Qi(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 yl}from"node:os";var O=3e3,ao=8e3,Zr=3443;function Ot(e,t){return`http://localhost:${e==="selfhost"?t[O]??O:t[ao]??ao}`}function de(e,t){return`${Ot(e,t)}/api/v1`}var Zi=/^(docker\d+|br-[0-9a-f]+)$/;function es(e){return`http://localhost:${e}`}function ts(e,t=yl()){return Object.entries(t).filter(([r])=>!Zi.test(r)).flatMap(([,r])=>r??[]).filter(r=>r.family==="IPv4"&&!r.internal).map(r=>`http://${r.address}:${e}`)}function Ng(e=process.env,t=process.platform){return e.SSH_CONNECTION||e.SSH_TTY?!0:t==="linux"&&!e.DISPLAY&&!e.WAYLAND_DISPLAY}function rs(e,t,r=yl(),n=Ng()){if(t)return`https://${t}`;let o=es(e);return n?ts(e,r)[0]??o:o}function pt(e,t){return rs(t,Mn(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 De from"node:fs";import*as os from"node:path";import wl from"semver";var Fg="https://registry.npmjs.org/@heygaia/cli/latest",ns=os.join(Ee,"update-check.json"),Bg=os.join(jr,"update-check.log"),Gg=1440*60*1e3,Ug=5e3;function mt(e){return/^v\d/.test(e)?wl.parse(e.slice(1)):null}var jg=/^[0-9a-f]{40}$/,qg=12;function lo(e){return jg.test(e)?e.slice(0,qg):e}function rt(e,t){let r=mt(e),n=mt(t);return r!==null&&n!==null&&wl.gt(r,n)}function bl(){if(!De.existsSync(ns))return null;let e=JSON.parse(De.readFileSync(ns,"utf-8"));return e.arch===nr()?e:null}function El(){return bl()?.latest??null}async function Hg(){let e=await fetch(Fg,{signal:AbortSignal.timeout(Ug)});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 Vg(e){De.mkdirSync(jr,{recursive:!0}),De.appendFileSync(Bg,`${new Date().toISOString()} update check failed: ${e.message}
43
+ `)}async function uo(){let e=bl();if(e&&Date.now()-Date.parse(e.checkedAt)<Gg)return e.latest;try{let t=await Hg();De.mkdirSync(Ee,{recursive:!0});let r={checkedAt:new Date().toISOString(),arch:nr(),latest:t};return De.writeFileSync(ns,JSON.stringify(r)),t}catch(t){return Vg(t),e?.latest??null}}var xl=300,Wg="ai_models";function Kg(e,t){let r=e.features[Wg]?.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=de(t,r),[o,i]=await Promise.all([He(n,"status",xl),He(n,"catalog",xl)]);if("detail"in o)return{running:!1,installed:!0};let s=r[O]??O;return{running:!0,webUrl:pt(e,s),provider:Kg(o.data,"data"in i?i.data:null)}}function mo(){uo();let e=L(),t=El();return!e||!t?null:rt(t,Be(e))?t:null}import{Chalk as th}from"chalk";import{Chalk as Yg}from"chalk";var is={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..."]},ss={d:"#0f537c",m:"#059cda",l:"#02bdff"},as={d:24,m:38,l:39};var zg={d:"blue",m:"cyan",l:"cyanBright"},Xg={d:"bgBlue",m:"bgCyan",l:"bgCyanBright"},Cl="\u2580",kl="\u2584",Jg="\u2588";function Il(e){return e==="d"||e==="m"||e==="l"?e:null}function Qg(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:Cl,fg:e,bg:t}}function Zg(e,t){return{ch:e!==null&&t!==null?Jg:e!==null?Cl:t!==null?kl:" ",fg:null,bg:null}}function Rl(e,{fg:t,bg:r}){let n=e;return t!==null&&(n=e.level===3?n.hex(ss[t]):e.level===2?n.ansi256(as[t]):n[zg[t]]),r!==null&&(n=e.level===3?n.bgHex(ss[r]):e.level===2?n.bgAnsi256(as[r]):n[Xg[r]]),n}function eh(e,t){let r="",n="",o=null;for(let i of t)o&&(i.fg!==o.fg||i.bg!==o.bg)&&(r+=Rl(e,o)(n),n=""),o=i,n+=i.ch;return o?r+Rl(e,o)(n):r}function Al(e){return is[e][0].length}function Pl(e,t){let r=is[e],n=new Yg({level:t}),o=[];for(let i=0;i<r.length;i+=2){let s=r[i]??"",a=r[i+1]??"",c=[...s].map((l,p)=>{let d=Il(l),m=Il(a[p]);return t===0?Zg(d,m):Qg(d,m)});o.push(eh(n,c))}return o}var Tl=3,rh=40,_l=" \xB7 ",Dl="Your proactive personal assistant",Ol={truecolor:"#af8700",ansi256:136};function nh(e,t){return t?`\x1B]8;;${e}\x1B\\${e}\x1B]8;;\x1B\\`:e}function oh(e){return e.level===3?e.hex(Ol.truecolor):e.level===2?e.ansi256(Ol.ansi256):e.yellow}function $l(e,t){return{plain:`GAIA v${t}`,styled:`${e.bold("GAIA")} ${e.dim(`v${t}`)}`}}function ih(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 ${nh(t.webUrl,r)}${e.dim(n)}`}}function Ll(e,t){let r=[];if(e.status&&r.push(ih(t,e.status,e.hyperlinks)),e.update){let n=`Update available: ${e.update} \xB7 run gaia update`;r.push({plain:n,styled:oh(t)(n)})}return r}function Ml(e){return[...e.plain].length}function sh(e,t){let r=$l(t,e.version);for(let n of Ll(e,t)){let o={plain:`${r.plain}${_l}${n.plain}`,styled:`${r.styled}${t.dim(_l)}${n.styled}`};if(Ml(o)>e.columns)break;r=o}return r.styled}function fo(e){let t=new th({level:e.level}),r=[$l(t,e.version),{plain:Dl,styled:t.dim(Dl)},...Ll(e,t)],n=Al(e.size)+Tl+Math.max(...r.map(Ml));if(!e.isTTY||e.rows<rh||n>e.columns)return[sh(e,t)];let o=Pl(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(Tl)}${c.styled}`:s})}function cs(e){return{isTTY:e.isTTY===!0,hyperlinks:ch(e)}}async function lh({size:e="small",showStatus:t=!0,showUpdate:r=!0}={}){let n={...Qr(process.stdout),...cs(process.stdout)},o=t&&n.isTTY?await po():null;return["",...fo({size:e,level:ah.level,...n,version:C,status:o,update:r?mo():null}),""]}async function $t(e){process.stdout.write(`${(await lh(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 Nl(){if(!process.stdout.isTTY){process.stdout.write(`${C}
46
+ `);return}await $t({size:"large"})}var uh="2048";function Fl(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",uh),t.toString()}function Bl(e){return`https://t.me/${e}`}async function ls(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 Ul(e){let t=await ls(`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 jl(e){let t=await ls("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 Gl(e,t){return await ls(`https://slack.com/api/${e}`,{method:"POST",headers:{Authorization:`Bearer ${t}`}})}async function ql(e,t){let r=await Gl("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 Gl("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 rn from"node:fs";import*as on from"node:os";import*as eu from"node:path";import{execa as Ch}from"execa";import*as pe from"node:fs";import*as Hl from"node:path";import{execa as dh}from"execa";var ds="/var/log/dpkg.log",us="/var/cache/apt/archives",ph=1e3,mh=/^\S+ \S+ (unpack|configure) ([^:\s]+)/,fh={unpack:"unpacking",configure:"setting up"};function gh(e){let t=mh.exec(e);return!t?.[1]||!t[2]?null:`${fh[t[1]]} ${t[2]}`}var hh=/apt-get\s+(?:-\S+\s+)*install\s+([^>]+)/;function Vl(e){let t=hh.exec(e);return t?.[1]?t[1].split(/\s+/).filter(r=>r&&!r.startsWith("-")):null}function Sh(e){return e.split(`
47
+ `).map(t=>Number(t.split(" ")[2])).filter(t=>Number.isFinite(t)).reduce((t,r)=>t+r,0)}async function Wl(e){let{stdout:t}=await dh("apt-get",["install","--print-uris","-qq","-y",...e]);return Sh(t)}function Kl(e){return pe.existsSync(e)?pe.statSync(e).size:0}function vh(e){return pe.existsSync(us)?pe.readdirSync(us).filter(t=>t.endsWith(".deb")).map(t=>pe.statSync(Hl.join(us,t))).filter(t=>t.ctimeMs>=e).reduce((t,r)=>t+r.size,0):0}function yh(e){let t=Kl(ds),r=t<e?0:e;if(t===r)return{activity:null,offset:r};let n=Buffer.alloc(t-r),o=pe.openSync(ds,"r");try{pe.readSync(o,n,0,n.length,r)}finally{pe.closeSync(o)}return{activity:n.toString().split(`
48
+ `).map(gh).findLast(a=>a!==null)??null,offset:t}}function ps(e){let t=Date.now(),r=Kl(ds),n=null,o=setInterval(()=>{let i=yh(r);r=i.offset,n=i.activity??n,e({downloaded:vh(t),dpkg:n})},ph);return()=>clearInterval(o)}var Lt="steps";function en(e){return e.currentState.data[Lt]??[]}function go(e,t){let r=Gn();e.updateData(Lt,t.map(n=>({...n,...r[n.id],state:"pending"})))}function ms(e){return Object.fromEntries(en(e).flatMap(t=>t.startedAt===void 0?[]:[[t.id,{startedAt:t.startedAt,doneLabel:t.doneLabel,minor:t.minor}]]))}function me(e,t,r){e.updateData(Lt,en(e).map(n=>n.id===t?{...n,...r}:n))}function ve(e,t,r={}){let n=Date.now(),o=en(e).find(i=>i.id===t);me(e,t,{state:"active",startedAt:o?.startedAt??n,...r})}function Oe(e,t,r){let n=en(e).find(o=>o.id===t);me(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 tn(e,t){me(e,t,{state:"skipped",endedAt:Date.now()})}function Ve(e,t){let r=en(e).find(n=>n.state==="active"||n.state==="waiting");r&&me(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 wh(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 Yl(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 zl(e,t=""){let r=t,n="",o="",i=new Map;e.on("change",s=>{let a=s.data[Lt]??[];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 p=wh(c);p&&console.info(p)}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 Mt}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"},Xl={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",15672:"RabbitMQ Management",[O]:"Web Frontend",[Zr]:"Web Frontend (HTTPS)",8080:"ChromaDB",8083:"Mongo Express"},bh={selfhost:[O,Zr],developer:[ao,5432,6379,27017,5672,15672,O,8080,8083]};async function ho(e,t={}){let r=await ja(be[e]),n=bh[e].map(a=>t[a]??a),o=n.filter(a=>!r.has(a)),i=await Eh(o),s=new Map(i.map(a=>[a.port,a]));return n.map(a=>s.get(a)??{port:a,service:Xl[a]||`Port ${a}`,available:!0})}async function fs(){try{return await Mt("git",["--version"]),"success"}catch{return"error"}}async function Jl(){try{return await Mt("mise",["--version"]),"success"}catch{return"missing"}}async function Ql(){if((await import("node:os")).platform()==="win32")try{return await Mt("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await Mt("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function Eh(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=Xl[o]||`Port ${o}`;if(await n(o))r.push({port:o,service:i,available:!0});else{let a=await xh(o),c=await Ih(o+1,o+100,n);r.push({port:o,service:i,available:!1,usedBy:a,alternative:c||void 0})}}return r}async function xh(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:n}=await Mt("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 Mt("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 Mt("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 Ih(e,t,r){for(let n=e;n<=t;n++)if(await r(n))return n;return null}var kh="https://get.docker.com",Ah="https://orbstack.dev",Ph="https://docs.docker.com/desktop/install/mac-install/",Th="setting up docker-ce",_h={git:"Git",docker:"Docker"},gs="prerequisite_install_confirm",Ft="missingPrerequisites",nn=class extends Error{constructor(t){super(t),this.name="PrerequisiteDeclined"}};function hs(){return rn.existsSync("/usr/bin/apt-get")||rn.existsSync("/etc/debian_version")}function Nt(e,t,r){e.updateData("checks",{...e.currentState.data.checks,[t]:r})}function ur(e){return e.map(t=>_h[t]).join(" and ")}function Dh(){throw on.platform()==="darwin"?new Error(`GAIA runs in Docker, which isn't installed yet.
53
+ \u2022 OrbStack (lightweight): ${Ah}
54
+ \u2022 Docker Desktop: ${Ph}
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 Oh(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.
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)Nt(e,i,"missing");if(e.updateData(Ft,t),await e.waitForInput(gs)!=="install")throw new nn(`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 tu(e){return e.dpkg?e.dpkg:e.downloaded>0?`${qe(e.downloaded)} downloaded`:void 0}async function $h(e){let t="Installing Git";e({label:t,detail:"updating the package list"});let r=Ue("git-install"),n=ps(o=>e({label:t,detail:tu(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 fs()!=="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 Lh(e){if(e.includes("Executing docker install script"))return{stage:"preparing",detail:"starting Docker's installer"};if(!e.startsWith("+ "))return null;let t=Vl(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 Mh(e,t){let r=()=>{},n=null,o=!1,i=a=>{if(a.dpkg&&(o=!0),a.dpkg===Th){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:tu(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=Lh(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=ps(i),Wl(c.packages).then(l=>{n=l},l=>rn.appendFileSync(t,`gaia: could not read Docker's download size: ${l.message}
60
+ `))}},stop:()=>r()}}async function Nh(e){let t=eu.join(on.tmpdir(),"gaia-docker-install.sh"),r=Ue("docker-install");e({label:"Preparing to install Docker",detail:"downloading Docker's installer"}),await Ch("curl",["-fsSL",kh,"-o",t]);let n=Mh(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 Zl(e,t,r){Nt(e,t,"pending");try{let n=await r();return Nt(e,t,"success"),n}catch(n){throw Nt(e,t,"error"),n}}async function Fh(e,t){if(t==="no-permission")return e.setStatus("Giving your user access to Docker (the docker group)\u2026"),await vc(),e.updateData("dockerGroupSwitch",await wc()),e.setStatus("Docker access granted. Continuing with it\u2026"),"relaunch";if(t!=="ready")throw await _t(t);return"ready"}async function So(e,t){let r=t.needGit&&await fs()!=="success",n=await Z(),o=[];r&&o.push("git"),n==="not-installed"&&o.push("docker");let i=on.platform()==="linux"&&hs();if(r&&!i)throw Nt(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&&(Nt(e,"docker","error"),Dh()),o.length>0){try{await Oh(e,o,t)}catch(a){for(let c of o)Nt(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 Zl(e,"git",async()=>{r&&await $h(s)}),Zl(e,"docker",async()=>(n==="not-installed"&&(await Nh(s),e.setStatus("Docker installed. Checking that it runs\u2026"),n=await Z()),Fh(e,n)))}var X=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(-Lr))};function ru(e){return(t,r)=>{e.updateData("dependencyPhase",t.label),e.updateData("dependencyProgress",t.percent),e.updateData("dependencyLogs",r.slice(-Lr))}}async function yo(e){e.updateData("checks",{git:"pending"}),await X(500);try{return await So(e,{needGit:!0})==="ready"}catch(t){return e.setError(t),!1}}async function wo(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await Jl();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise\u2026"),t=await Ql()?"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 X(1e3),n}async function nu(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 iu}from"node:readline/promises";import{Writable as Bh}from"node:stream";async function gt(e,t){let r=iu({input:process.stdin,output:process.stdout});try{let n=t?` [${t}]`:"";return(await r.question(`${e}${n}: `)).trim()||t||""}finally{r.close()}}var ou=4,bo="\x1B",Gh="",Uh=new Set(["\x7F","\b"]),jh=new RegExp(`${bo}\\[[0-9;]*[A-Za-z~]`,"g");function qh(e){let t=e.length>ou*2?ou: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=iu({input:process.stdin,output:new Bh({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(jh,"");(s===Gh||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(),qh(r.trim()));return}Uh.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 ht(e,t=!0){let r=await gt(`${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
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",`
71
+ `)}}var Hh={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},Vh=12e4,Wh=3e3,su={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 Ss(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Bt={telegram:"Telegram",discord:"Discord",slack:"Slack"},Kh=3;async function Yh(e,t,r){let n={...t},o=0;for(let i of su[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 Eo(i.label);if(!s)throw new Error(`No ${i.label} entered. Nothing changed.`);n[i.key]=s}return n}async function zh(e,t){for(let r=1;;r++){let n=await Yh(e,t,r===1);Re(`Checking your ${Bt[e]} credentials\u2026`);try{return await Xh(e,n)}catch(o){let i=su[e].filter(a=>!t[a.key]),s=Kh-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 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 Xh(e,t){let r=Ss(t.token,"--token");if(e==="telegram"){let s=await Ul(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${Bl(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await jl(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${Fl(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 ql(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 Jh(e){let t=be.selfhost,r=Date.now()+Vh;for(;;){let n=Vr(e,await At(t));if(n.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Bt[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 X(Wh)}}async function au(e){await ce(e,"selfhost",t=>Re(t),k(e),void 0,{pull:"missing"})}async function cu(e,t){let r=await vs(),n=await zh(e,t);Wr(r,{set:n.botsEnv}),Hn(r,{set:{[Gi[e]]:n.handle}});let o=A()?.bots??[];o.includes(e)||Se({bots:[...o,e]}),await au(r);let i=Hh[e];i&&(Re(`Registering the ${Bt[e]} bot's commands\u2026`),await ul(r,xe(e),i)),Re(`Waiting for the ${Bt[e]} bot to connect\u2026`),await Jh(e),Re(`${y.ok} The ${Bt[e]} bot is running`);for(let s of n.nextSteps)Re(s)}async function lu(e){let t=await vs(),r=A()?.bots??[];if(!r.includes(e))throw new Error(`The ${Bt[e]} bot is not enabled. See 'gaia bots list'.`);Se({bots:r.filter(n=>n!==e)}),Wr(t,{unset:Cc[e]}),Hn(t,{unset:[Gi[e]]}),await au(t),Re(`${y.ok} The ${Bt[e]} bot is stopped and its credentials are deleted`)}async function uu(){await vs();let e=A()?.bots??[];if(e.length===0){Re("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await At(be.selfhost);for(let r of e)Re(` ${r.padEnd(10)}${Vr(r,t).detail}`)}function du(){return new Qh("<platform>","chat platform").choices(Rc)}var an=new Zh("bots").description(U.bots).hook("preAction",()=>$t()).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
+ `);an.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(du()).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(()=>cu(e,t))});an.command("list").alias("ls").description("Show the enabled bots and whether each is running").action(async()=>{await ue(uu)});an.command("remove").alias("rm").description("Stop a bot and delete its saved credentials").addArgument(du()).action(async e=>{await ue(()=>lu(e))});import{Command as av}from"commander";import{existsSync as To,mkdirSync as bS,readFileSync as Eu,writeFileSync as As}from"node:fs";import{homedir as bu}from"node:os";import{join as Ps}from"node:path";import{sep as eS}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"},ys="https://api.heygaia.io",Gt="filesystem",Io=eS,ws=500,bs=6e4,Es=5e3,xs=1e6,Is=5e6,Ro=9e4,Co=1e6;import{homedir as tS}from"node:os";import{join as rS}from"node:path";var nS={info:e=>console.error(e),error:e=>console.error(e)},Rs={},oS=null;function J(){return oS??nS}function Ke(){return{stateDir:Rs.stateDir??rS(tS(),".gaia","bridge"),env:Rs.env??process.env,shell:Rs.shell??process.env.SHELL??"/bin/sh"}}import{Client as fS}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as gS,StdioClientTransport as hS}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as SS}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as vS}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as iS,readdir as gu,readFile as pu,realpath as sS,stat as aS,writeFile as cS}from"node:fs/promises";import{dirname as mu,extname as lS,join as hu,resolve as uS,sep as Cs}from"node:path";import{McpServer as dS}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as pr}from"zod";var pS={".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 sS(e)}catch{return null}}async function mS(e){try{return(await iS(e)).isSymbolicLink()}catch{return!1}}function fu(e,t){return t===Cs?e.startsWith(Cs):e===t||e.startsWith(t+Cs)}async function ko(e,t,r){let n=uS(e),o=await ks(n);if(o){if(t.some(s=>fu(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(mu(n));if(!i||!t.some(s=>fu(i,s)))throw new mr(`Path is outside your approved folders: ${e}`);if(await mS(n))throw new mr(`Refusing to write through a symlink: ${e}`);return hu(i,n.slice(mu(n).length+1))}async function Su(e,t,r,n){if(n.length>=r)return;let o;try{o=await gu(e,{withFileTypes:!0})}catch{return}for(let i of o){if(n.length>=r)return;let s=hu(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&n.push(s),i.isDirectory()&&!i.isSymbolicLink()&&await Su(s,t,r,n)}}function vu(e){let t=new dS({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 gu(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 aS(s);if(!a.isFile())return o(`Not a file: ${i}`);let c=pS[lS(s).toLowerCase()];if(c){if(a.size>Is)return o(`Image is too large to read (${a.size} bytes).`);let p=await pu(s);return{content:[{type:"text",text:`Image file ${s} (${c}, ${a.size} bytes) \u2014 shown below.`},{type:"image",data:p.toString("base64"),mimeType:c}]}}return a.size>xs?o(`File is too large to read (${a.size} bytes).`):{content:[{type:"text",text:await pu(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 Su(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 cS(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 yS=new Set(["localhost","127.0.0.1","::1"]),yu=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(!yS.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function wS(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function wu(e,t){let r=wS(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>=yu)throw new Error(`too many redirects (>${yu}) \u2014 refusing to follow`);r=a,n={...t,redirect:"manual"}}}async function Ao(e){if(e.type==="url"){let o=St(e.url),i=new SS(o,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:wu});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let o=Ke().env,i=new hS({command:e.command,args:e.args,env:{...gS(),...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]=vS.createLinkedPair(),n=vu(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 fS({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 xu(){return Ps(Ts(),"config.json")}function Iu(){let e=Ts();To(e)||bS(e,{recursive:!0,mode:448})}function Ye(){let e=_s();if(!To(e))return null;try{return JSON.parse(Eu(e,"utf-8"))}catch{return null}}function cn(e){Iu(),As(_s(),JSON.stringify(e,null,2),{mode:384})}function ln(){let e=_s();To(e)&&As(e,"{}",{mode:384})}function ee(){let e=xu();if(!To(e))return{servers:[]};try{return{servers:JSON.parse(Eu(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function Ru(e){Iu(),As(xu(),JSON.stringify(e,null,2),{mode:384})}function _o(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),Ru(t)}function un(e){let t=ee(),r=t.servers.length;return t.servers=t.servers.filter(n=>n.key!==e),Ru(t),t.servers.length<r}function Ds(e){return e==="~"?bu():e.startsWith("~/")?Ps(bu(),e.slice(2)):e}function Os(e,t){return{type:"filesystem",key:Gt,name:"Local Files",allow:e,allowWrite:t}}function dn(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 IS,platform as RS}from"node:os";var Cu="x-request-id";function ES(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=ES(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(Cu)??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 ku(o)}async function xS(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 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 Au(e,t,r){return xS(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function CS(e){await new Promise(t=>setTimeout(t,e))}function Fs(){return!!Ye()?.refreshToken}async function Pu(e,t){let r=dn(t.api),n=t.name||IS(),o=await $s(r,n,RS(),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 CS(o.interval*1e3);let s;try{s=await Ls(r,o.device_code)}catch(a){J().error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(s.status==="approved"&&s.device_id&&s.refresh_token){cn({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 kS={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 AS(){let e=L();if(!(!e||await $(e)!=="selfhost"))return Ot("selfhost",k(e))}async function fr(e={}){let t=e.api??(process.env.GAIA_API_URL?void 0:await AS());await Pu(kS,{...e,...t!==void 0?{api:t}:{},daemonVersion:C})}import{spawn as VS}from"node:child_process";import{existsSync as Gs,mkdirSync as WS,openSync as KS,readFileSync as YS,unlinkSync as Mu,writeFileSync as zS}from"node:fs";import{homedir as XS}from"node:os";import{join as Us}from"node:path";import{mkdirSync as Tu,readFileSync as PS,rmSync as _u,writeFileSync as TS}from"node:fs";import{dirname as _S,join as Du}from"node:path";var DS=3e4,OS=3e4,$S=50,LS=e=>new Promise(t=>setTimeout(t,e));function Ou(){return Du(Ke().stateDir,"credentials.lock")}function MS(){return Du(Ou(),"stamp")}async function NS(e){let t=Ou(),r=MS();Tu(_S(t),{recursive:!0});let n=Date.now()+OS;for(;;){try{Tu(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let o=null;try{let i=Number(PS(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<DS){if(Date.now()>n)throw new Error("another gaia process is rotating the device credential \u2014 try again");await LS($S);continue}try{_u(t,{recursive:!0,force:!0})}catch{}}try{return TS(r,String(Date.now()),{mode:384}),await e()}finally{try{_u(t,{recursive:!0,force:!0})}catch{}}}async function pn(){return NS(async()=>{let e=Ye();if(!e?.refreshToken)throw new $e("not paired \u2014 run: gaia bridge login",401);let t=await Ms(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return cn(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 pn();await Promise.all(e.map(n=>Ns(t.apiUrl,r,n.key,n.name,n.type)))}async function Bs(e){let t=un(e);try{let{creds:r,accessToken:n}=await pn();await Au(r.apiUrl,n,e)}catch(r){J().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 HS}from"node:crypto";import Lu from"ws";import{spawn as FS}from"node:child_process";import{appendFileSync as BS,mkdirSync as GS}from"node:fs";import{homedir as US}from"node:os";import{join as jS}from"node:path";function qS(e,t){try{let r=Ke().stateDir;GS(r,{recursive:!0,mode:448});let n=t?` (cwd: ${t})`:"";BS(jS(r,"exec-audit.log"),`${new Date().toISOString()}${n} $ ${e}
87
+ `)}catch{}}async function $u(e,t,r){qS(e,t);let n=FS(Ke().shell,["-c",e],{cwd:t||US(),env:Ke().env,stdio:["ignore","pipe","pipe"]}),o=0,i=!1,s=c=>l=>{if(i)return;let p=Co-o,d=l.length>p?l.subarray(0,p):l;d.length>0&&(o+=d.length,r[c](d.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 mn=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 $e&&t.status===401?(J().error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):J().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 pn();this.creds=t;let n=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,o=new Lu(n,{headers:{authorization:`Bearer ${r}`}});this.ws=o,await new Promise((i,s)=>{let a=!1,c=!1,l=p=>{c||(c=!0,p())};o.on("open",()=>{a=!0,this.reconnectDelay=Es;let p=ee().servers.map(d=>d.key);this.send({t:H.HELLO,servers:p}),J().info(`[gaia bridge] connected \u2014 exposing: ${p.join(", ")||"(nothing configured)"}`)}),o.on("message",p=>{this.guardRejection(this.onFrame(p.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",p=>{a||l(()=>s(p))})})}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:J().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case H.SERVER_REMOVE:r.key&&un(r.key)&&J().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();J().info(`[gaia bridge] opening MCP session for '${n}'\u2026`);try{let a=await Ao(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}),J().info(`[gaia bridge] MCP session for '${n}' ready in ${Date.now()-s}ms`)}catch(a){let c=a instanceof Error?a.message:String(a);J().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){J().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 $u(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===Lu.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(n=>{J().error(`[gaia bridge] ${r}: ${n instanceof Error?n.message:n}`)})}async backoff(){let t=HS(this.reconnectDelay);J().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(XS(),".gaia","bridge"),Ut=Us(js,"daemon.pid"),Nu=Us(js,"daemon.log");function qs(){if(!Gs(Ut))return null;let e=Number(YS(Ut,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function Fu(){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 Bu(){let e=qs();if(!e){Gs(Ut)&&Mu(Ut),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}Gs(Ut)&&Mu(Ut),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=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
+ `),ln(),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");WS(js,{recursive:!0,mode:448});let n=KS(Nu,"a"),o={detached:!0,stdio:["ignore",n,n]},i=VS(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],o);i.unref(),zS(Ut,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: ${Nu}
96
+ Stop: gaia bridge down`)}async function Gu(){let e=Ye();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new mn(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 Hu}from"node:path";import{resolve as JS}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 Uu(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 ju(e){let t=Hs(e??"");if(!e||!t||t===Gt)throw new Error("--name is required and must contain letters or digits");return t}function qu(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:ju(e.name),name:e.name,command:t,args:r,env:Uu(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");St(e.url);let t=Uu(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:ju(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=>JS(Ds(n)));return Os(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}function QS(e,t){let n=[...t].reverse().filter(o=>!o.startsWith("-"))[0]??e;return Hu(n).replace(/@[^@]*$/,"")}function ZS(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function Vu(e){for(;;){let t=await gt("Name for this server",e),r=Hs(t);if(!t||!r||r===Gt){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 ev(e,t){if(Hu(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 ht(` 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 Wu(e,t){let r={};for(let o of ev(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 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 Ws(o)}return r}async function tv(){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}=Vs(e),n=await Wu(t,r),{name:o,key:i}=await Vu(QS(t,r));return{type:"stdio",key:i,name:o,command:t,args:r,env:n}}async function rv(){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 Ws(t)}return e}async function nv(){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 rv();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 Vu(ZS(e));return{type:"url",key:n,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function ov(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 Wu(e.command,e.args);else{if(n==="Save anyway (fix it later)")return!0;if(n==="Abort")return!1}}}}async function iv(e){let t=qu(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 Ku(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 iv(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 tv():await nv();if(!await ov(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 ht("Keep this device connected in the background now?")?await Oo():console.info("Run `gaia bridge up` whenever you're ready.")}function sv(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 Yu(e){if(e){let o=await Bs(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 xo("Which server do you want to remove?",t.map(sv)),n=t[r];if(n){if(!await ht(`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 cv(){let e=Ye();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${dn()})`:"Not paired \u2014 run: gaia bridge login"),console.info(Fu());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 av("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(()=>Ku(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(cv)});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(()=>Yu(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?Gu:Oo)});nt.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await ue(Bu)});nt.command("logout").description("Forget local credentials").action(async()=>{await ue(()=>{ln(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import{Command as pv}from"commander";import*as Ce from"node:fs/promises";import*as ed from"node:path";import*as Xu from"node:os";import*as Ju from"node:path";var lv="https://github.com/theexperiencecompany/gaia/releases/download",$o=`cli-v${C}`,Ks="gaia-connect-SHA256SUMS",zu={"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 Qu(e,t){let r=zu[`${e}-${t}`];if(r===void 0)throw new Error(`gaia connect is not available for ${e}/${t}. Supported: ${Object.keys(zu).join(", ")}.`);return r}function Ys(e){return`${lv}/${$o}/${e}`}function Zu(e){let t=e==="win32"?".exe":"";return Ju.join(Xu.homedir(),".gaia","bin",`gaia-connect-${C}${t}`)}async function uv(e){try{return await Ce.access(e),!0}catch{return!1}}async function td(e,t){let r=Zu(e);if(await uv(r))return r;let n=Qu(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 Ce.mkdir(ed.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 dv}from"node:child_process";async function rd(e,t){return await new Promise((r,n)=>{let o=dv(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 mv(e){let t=await td(process.platform,process.arch);return await rd(t,e)}var nd=new pv("connect").description(U.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=>ue(async()=>process.exit(await mv(e))));import*as Mo from"fs";import*as od from"path";import{spawn as fv}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(d=>fv(d.cmd,d.args,{cwd:d.cwd,stdio:"inherit",shell:!1,detached:d.detached??!1,env:d.env?{...process.env,...d.env}:process.env}));n.forEach((d,m)=>{e[m]?.onSpawn?.(d.pid)});let o=!1,i=0,s=!1,a,c=()=>{process.off("SIGINT",p),process.off("SIGTERM",p)},l=()=>{if(!s){s=!0;for(let[d,m]of n.entries()){let g=e[d];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGTERM"):m.kill("SIGTERM")}catch{}}a=setTimeout(()=>{for(let[d,m]of n.entries()){let g=e[d];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGKILL"):m.kill("SIGKILL")}catch{}}},1e3)}},p=()=>{l()};process.on("SIGINT",p),process.on("SIGTERM",p),n.forEach((d,m)=>{let g=e[m];d.on("error",v=>{o||(o=!0,c(),l(),r(v))}),d.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 id(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=od.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 te from"chalk";import*as ad from"node:fs";import*as jt from"node:os";import{execa as sd}from"execa";var gv={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 hv(e,t){let r=gv[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:hv(o.name,t)})}}var Sv=2*1024*1024*1024,vv=4*1024*1024*1024,yv=2*1024*1024*1024,cd={"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 wv(e,t){return t.every(r=>e.some(n=>n.service===r&&zs(n.state)==="running"))}function bv(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 ld(e,t){return e[t]??t}async function ud(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 Ev(e){return`Open ${e}/setup in your browser to finish setting GAIA up.`}function xv(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?"":Ev(r)}))}function Iv(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 dd(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 pd(e){let t={id:"compose-containers",label:"Containers",severity:"blocker"},r;try{r=await At(e.project)}catch{return{...t,state:"skipped",detail:"they need Docker"}}return wv(r,e.expected)?{...t,state:"ok",detail:`${e.expected.length} services running`}:{...t,state:"fail",detail:bv(r,e.expected),fix:`Run 'gaia start' to bring the stack up, or check 'docker compose -p ${e.project} logs'.`}}function md(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:Mi}}async function fd(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 gd(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:Vn(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 hd(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 Sd(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=xv(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=Sv){let t={id:"disk-headroom",label:"Disk space",severity:"blocker"},r;try{r=await Ha()}catch{return{...t,state:"skipped",detail:"they need Docker"}}let n;try{let i=await Va(r),s=Iv(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 Rv(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 Cv(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 kv(){try{let e=ad.readFileSync("/proc/meminfo","utf-8"),t=Rv(e);if(t!==null)return t}catch{}return Js(()=>jt.freemem())}async function Av(){try{let{stdout:e}=await sd("vm_stat",[]),t=Cv(e);if(t!==null)return t}catch{}try{let{stdout:e}=await sd("sysctl",["-n","hw.memsize"]),t=Number(e.trim());if(Number.isFinite(t)&&t>0)return t}catch{}return Js(()=>jt.totalmem())}async function Pv(){let e=jt.platform();return e==="linux"?kv():e==="darwin"?Av():Js(()=>jt.freemem())}async function Qs(){let e=await Pv().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<yv?{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<vv?{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 vd(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=Be(e);if(mt(o)===null)return{...n,state:"ok",detail:`development build (${lo(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 yd(e,t){if(e.length===0)return[];let r;try{r=await At(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}=Vr(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 wd(e){return e.results.some(t=>t.severity==="blocker"&&t.state==="fail")}async function Tv(){let e=L(),t=e?k(e):{},r=e?await $(e):null;return{repoPath:e,origin:Ot(r??"selfhost",t),apiUrl:de(r??"selfhost",t),webPort:ld(t,3e3),overrides:t,mode:r,project:r?be[r]:null}}async function bd(){let e=[],[t,r]=await Promise.all([Tv(),Z()]);if(e.push(await dd(r)),e.push(r==="ready"?await ud(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(md(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:Xr(t.repoPath,t.mode),installed:!1,results:e}}let n=t.mode==="developer"?"gaia dev":"gaia start";e.push(await pd({project:t.project,expected:cd[t.project]})),t.project===be.selfhost&&e.push(...await yd(A()?.bots??[],t.project));let o=await fd(t.apiUrl,n);return e.push(o),e.push(...await gd({apiHealthy:o.state==="ok",origin:t.origin,project:t.project})),e.push(...await Sd({apiHealthy:o.state==="ok",apiUrl:t.apiUrl,webUrl:pt(t.repoPath,t.webPort)})),e.push(await hd(t.webPort,n)),e.push(await Xs()),e.push(await Qs()),e.push(await vd(t.repoPath,t.mode)),{install:Xr(t.repoPath,t.mode),installed:!0,results:e}}function qt(e=""){process.stdout.write(`${e}
118
+ `)}var Ed=16,ea=" ",_v={ok:te.green,fail:te.red,warn:te.yellow,skip:te.gray,pending:te.gray,active:te.cyan,cancelled:te.yellow};function Dv(e){return e.state==="ok"?"ok":e.state==="skipped"?"skip":e.severity==="warning"?"warn":"fail"}var Zs=ea.length+2+Ed;function Ov(e,t){let r=Dv(e),n=e.detail?te.gray(dt(e.detail,Zs)):"";qt(`${ea}${_v[r](y[r])} ${e.label.padEnd(Ed)}${n}`),e.state==="fail"&&e.fix&&t?.fix!==e.fix&&qt(`${" ".repeat(Zs)}${dt(e.fix,Zs)}`)}function $v(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)qt(`${ea}${te.gray(y.skip)} ${te.gray(`Not checked: ${n.join(", ")} (${r})`)}`)}function Lv(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 Mv(e){qt(e.installed?`${te.bold("Checking")} ${e.install}`:te.bold("Checking this computer")),qt();let t=e.results.filter(r=>r.state!=="skipped");t.forEach((r,n)=>{Ov(r,t[n+1])}),$v(e.results.filter(r=>r.state==="skipped")),qt(),qt(Lv(e))}async function xd(){await $t();let e=await bd();Mv(e),wd(e)&&(process.exitCode=1)}import{render as Ab}from"ink";import Pb from"react";import{ThemeProvider as wb}from"@inkjs/ui";import{Box as fi,Text as Xt,useInput as bb}from"ink";import Eb from"react";import{ConfirmInput as Fy}from"@inkjs/ui";import{Box as yt,Static as By,Text as ua}from"ink";import{Box as Go,Text as fn}from"ink";import{useStdout as Nv}from"ink";import{useEffect as Fv,useState as Bv}from"react";function Fo(){let{stdout:e}=Nv(),[t,r]=Bv(()=>Qr(e));return Fv(()=>{let n=()=>r(Qr(e));return e.on("resize",n),()=>{e.off("resize",n)}},[e]),t}var Gv=100;function Bo(){return Math.min(Fo().columns,Gv)}import{jsx as Sr,jsxs as Uo}from"react/jsx-runtime";var Id=16,Uv=6,jv={primary:void 0,warn:"yellow",dim:"gray"},qv=({row:e,width:t})=>{let r=e.tone?jv[e.tone]:void 0,n=Qi(e.text,t);if(!e.url)return Sr(fn,{color:r,children:n});let[o,i]=n.split(e.url);return Uo(fn,{color:r,children:[o,Sr(fn,{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:T,borderColor:r,paddingX:2,paddingY:1,width:o,children:[Uo(fn,{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:Id,flexShrink:0,children:Sr(fn,{bold:i.tone==="primary",children:i.label})}),Sr(qv,{row:i,width:o-Uv-Id})]},i.label))})]})};import{Spinner as Xv,StatusMessage as Ad}from"@inkjs/ui";import{Box as Ht,Text as Vt}from"ink";import{useEffect as Jv,useState as Qv}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 Rd(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 gn(e,t={}){let r=e.unit==="bytes"?Wn(e.done,e.total,e.estimated):`${e.done} / ${e.total} services`,n=t.etaMs!==void 0&&t.etaMs!==null?` \xB7 ${Rd(t.etaMs)}`:"";return`${ta(e,t.percent)}% ${r}${n}`}import{Box as Hv,Text as Vv}from"ink";import{jsx as Cd}from"react/jsx-runtime";var ke=({kind:e})=>Cd(Hv,{marginRight:1,children:Cd(Vv,{color:Mr[e],children:y[e]})});import{ProgressBar as Wv}from"@inkjs/ui";import{Box as kd,Text as Kv}from"ink";import{jsx as ra,jsxs as zv}from"react/jsx-runtime";var Yv=30,yr=({percent:e,caption:t})=>zv(kd,{children:[ra(kd,{width:Yv,children:ra(Wv,{value:e})}),ra(Kv,{dimColor:!0,children:` ${t??`${e}%`}`})]});import{jsx as Q,jsxs as hn}from"react/jsx-runtime";var Zv=32,ey=2,ty=1e3,ry=2e3;function na(e){let[t,r]=Qv(Date.now());return Jv(()=>{if(!e)return;let n=setInterval(()=>r(Date.now()),ty);return()=>clearInterval(n)},[e]),t}function oa(e){return e.padEnd(Math.max(Zv,e.length+ey))}function ia(e,t){return e.startedAt===void 0?"":ft((e.endedAt??t)-e.startedAt)}function ny(e){return e.state==="skipped"?!1:e.minor?oy(e)>=ry:!0}function oy(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(ny),live:e.slice(r)}}function Ho(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 Vo=({step:e})=>Q(Ad,{variant:"success",children:hn(Vt,{dimColor:!0,children:[oa(e.doneLabel),ia(e,Date.now())]})}),iy=({step:e})=>{let t=hn(Vt,{children:[oa(e.label),Q(Vt,{dimColor:!0,children:ia(e,Date.now())})]});return e.state==="failed"?Q(Ad,{variant:"error",children:t}):hn(Ht,{children:[Q(ke,{kind:"cancelled"}),t]})},Wo=({step:e,counter:t,waiting:r,status:n})=>{let o=na(!r);if(e.state==="failed"||e.state==="cancelled")return Q(iy,{step:e});let i=e.detail??(n||void 0),s=[t,r?null:ia(e,o)].filter(Boolean).join(" \xB7 ");return hn(Ht,{flexDirection:"column",children:[hn(Ht,{children:[r?Q(ke,{kind:"pending"}):Q(Ht,{marginRight:1,children:Q(Xv,{})}),Q(Vt,{bold:!0,children:oa(e.label)}),Q(Vt,{dimColor:!0,children:s})]}),e.amount&&Q(Ht,{marginLeft:2,marginTop:1,children:Q(yr,{percent:ta(e.amount,e.percent),caption:gn(e.amount,{percent:e.percent,etaMs:e.etaMs})})}),i&&Q(Ht,{marginLeft:2,marginTop:e.amount?0:1,children:Q(Vt,{dimColor:!0,wrap:"truncate",children:i})}),e.hint&&Q(Ht,{marginLeft:2,children:Q(Vt,{dimColor:!0,children:e.hint})})]})};import{Alert as Pd,ConfirmInput as sy,Spinner as Td}from"@inkjs/ui";import{Box as K,Text as V,useInput as ay}from"ink";import{jsx as I,jsxs as Y}from"react/jsx-runtime";var Ko=({checks:e})=>Y(K,{flexDirection:"column",borderStyle:T,paddingX:1,borderColor:w,children:[I(V,{bold:!0,children:"System Checks"}),Y(K,{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})]})]}),Yo=({status:e})=>Y(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(Td,{label:e||"Configuring environment\u2026"})})]}),_d=({title:e,progress:t,phase:r})=>Y(K,{flexDirection:"column",borderStyle:T,padding:1,borderColor:w,children:[I(V,{bold:!0,children:e}),Y(K,{marginTop:1,flexDirection:"column",children:[I(yr,{percent:t||0}),r&&I(V,{color:"gray",children:r})]})]}),Ae=({message:e})=>{let[t="",...r]=e.split(`
119
+ `),n=Bo();return r.length===0?I(K,{marginTop:1,width:n,children:I(Pd,{variant:"error",children:t})}):I(K,{marginTop:1,width:n,children:I(Pd,{variant:"error",title:t,children:r.map((o,i)=>Y(V,{color:o.startsWith("Full log:")?"gray":void 0,children:[i>0?`
120
+ `:"",o]},o))})})},cy={success:"ok",error:"fail",missing:"warn"},sa=({label:e,status:t})=>Y(K,{children:[t==="pending"?I(K,{marginRight:1,children:I(Td,{type:"dots"})}):I(ke,{kind:cy[t]}),I(V,{children:e})]}),wr=({portResults:e,onAccept:t,onAbort:r})=>{ay((o,i)=>{i.return?t():i.escape&&r()});let n=e.filter(o=>!o.available);return Y(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=>Y(K,{children:[Y(V,{color:o.available?"green":o.alternative?"yellow":"red",children:[o.available?y.ok:o.alternative?y.warn:y.fail," "]}),Y(V,{children:[o.service," (:",o.port,")"]}),!o.available&&Y(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:Y(V,{dimColor:!0,children:[I(V,{bold:!0,children:"Enter"})," continue \xB7 ",I(V,{bold:!0,children:"Esc"})," cancel"]})})]})},ly=({missing:e,onConfirm:t,onDecline:r})=>{let n=e.length>1?"aren't":"isn't";return Y(K,{flexDirection:"column",marginTop:1,children:[Y(V,{children:["GAIA needs ",I(V,{bold:!0,children:ur(e)}),", which ",n," ","installed yet."]}),Y(K,{children:[Y(V,{children:["Install ",e.length>1?"them":"it"," now?"," ",I(V,{dimColor:!0,children:"(uses sudo, a few minutes)"})," "]}),I(sy,{onConfirm:t,onCancel:r})]})]})},br=({inputId:e,missing:t,onConfirm:r,onDecline:n})=>e!==gs||!t?.length?null:I(ly,{missing:t,onConfirm:r,onDecline:n});import{useEffect as uy,useState as dy}from"react";function Pe(e){let[t,r]=dy(e.currentState);return uy(()=>{let n=()=>r({...e.currentState});return e.on("change",n),()=>{e.off("change",n)}},[e]),t}import*as Ir from"node:fs";import*as tp from"node:os";import*as Rr from"node:path";import*as Dd from"node:os";import*as Od from"node:path";var py=80,my=443,$d=Od.join(Dd.homedir(),"gaia");function zo(){let e=A()?.repoPath;return e&&cr(e)?e:null}function Ld(e){let t={};return e.domain&&(t[O]=py,t[Zr]=my),e.webPort&&(t[O]=e.webPort),t}function fy(){return A()?.values??{}}function gy(e){return Tn().flatMap(t=>t.variables).find(t=>t.name===e)}function Md(e){let{repoPath:t,interactive:r=fe(),setupMode:n="selfhost"}=e,o=fy(),i=new Set(Gr()),s=new Map,a=l=>(s.has(l)||s.set(l,gy(l)?.required===!0),s.get(l)===!0),c=l=>{let p=o[l]??Br(l,n);if(p)return p;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,p)=>{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 d=p?.varName;return!d||i.has(d)?"":c(d)}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 Wd from"node:http";import*as Kt from"node:path";import{execa as xr}from"execa";import{z as jd}from"zod";import*as Er from"node:fs";import*as Nd from"node:os";import*as Fd from"node:path";import{execa as aa}from"execa";var Sn="gaia-local-name-ipv6.service",ca=`/etc/systemd/system/${Sn}`,hy=["temporary","deprecated","tentative","dadfailed"];function Sy(e){return/\bdev (\S+)/.exec(e)?.[1]??null}function vy(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})=>!Zi.test(o)&&!hy.some(s=>i.split(/\s+/).includes(s)));return(r.find(({device:o})=>o===t)??r[0])?.address??null}function yy(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(`
134
+ `}async function Bd(){let[e,t]=await Promise.all([aa("ip",["-6","-o","addr","show","scope","global"]),aa("ip",["-o","route","show","default"])]);return vy(e.stdout,Sy(t.stdout))}async function Gd(e,t,r){let{stdout:n}=await aa("sh",["-c","command -v avahi-publish-address"]),o=Fd.join(Nd.tmpdir(),Sn);Er.writeFileSync(o,yy(n.trim(),e,t)),await q("install",["-m","644",o,ca],r),Er.rmSync(o,{force:!0}),await q("systemctl",["daemon-reload"],r),await q("systemctl",["enable",Sn],r),await q("systemctl",["restart",Sn],r)}async function Ud(e){Er.existsSync(ca)&&(await q("systemctl",["disable","--now",Sn],e),await q("rm",["-f",ca],e),await q("systemctl",["daemon-reload"],e))}var Jo="gaia",vt=`${Jo}.local`,Kd=`http://${vt}`,qd="0.15.8",Hd=24,la=80,wy=15e3,by=500,Yd=2e3;function zd(e){return!e.optedOut&&!e.domain?"set-up":e.setUpBefore?"remove":"none"}function Ey(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)<Hd?`it needs Node.js ${Hd} or newer, and this is Node.js ${r}`:null}function Xd(){return Kt.join(Kt.dirname(process.execPath),"npm")}async function Jd(){let{stdout:e}=await xr(Xd(),["root","-g"]);return Kt.join(e.trim(),"portless","dist","cli.js")}var xy=jd.object({version:jd.string()});function Iy(e){let t=Kt.join(Kt.dirname(e),"..","package.json");return Wt.existsSync(t)?xy.parse(JSON.parse(Wt.readFileSync(t,"utf-8"))).version:null}async function Ry(e){let t=await Jd();if(Iy(t)===qd)return t;let r=await xr(Xd(),["install","-g","--no-fund","--no-audit",`portless@${qd}`],{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 Cy(e){return xr("sh",["-c",`command -v ${e}`],{reject:!1}).then(t=>!t.failed)}async function ky(e){if(process.platform==="linux"&&!await Cy("avahi-publish-address")){if(!hs())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 Ay(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 Qd(){return new Promise(e=>{let t=Wd.get({host:"127.0.0.1",port:la,path:"/health/ready",headers:{Host:vt},timeout:Yd},r=>{r.resume(),e(r.statusCode??null)});t.on("timeout",()=>t.destroy()),t.on("error",()=>e(null))})}async function Vd(){return await Qd()===200}async function Py(){return await Qd()!==null}async function Zd(e,t){if(process.platform!=="linux")return!0;let r=await xr("avahi-resolve-host-name",[e,vt],{reject:!1,timeout:Yd});if(r.failed)return!1;let[n,o]=r.stdout.trim().split(/\s+/);return n===vt&&(!t||o===t)}async function Ty(e){if(process.platform!=="linux")return;let t=await Bd();if(!t)return;let r=()=>Zd("-6",t);if(!await r()&&(await Gd(vt,t,e),!await Xo(r)))throw new Error(`${vt}'s IPv6 address isn't announced, so Apple devices wait ~5s per lookup (log: ${e})`)}async function Xo(e){let t=Date.now()+wy;for(;Date.now()<t;){if(await e())return!0;await new Promise(r=>setTimeout(r,by))}return e()}async function ep(e){let t=Ey(process.version,process.platform);if(t)throw new Error(t);let r=Ue("local-name"),n=await Ry(r);if(!await Vd()&&(await ky(r),await q(process.execPath,[n,"service","install","--lan","--no-tls"],r),!await Xo(Py)))throw new Error(`portless's proxy didn't start on port ${la}; is another server using it? (log: ${r})`);if(await Ay(n,["alias",Jo,String(e),"--force"]),!await Xo(Vd))throw new Error(`portless's proxy on port ${la} doesn't route ${vt} to GAIA on port ${e} (log: ${r})`);if(!await Xo(()=>Zd("-4")))throw new Error(`${vt} isn't announced on the network; check that avahi-daemon is running (log: ${r})`);await Ty(r)}async function Qo(){let e=await Jd();if(!Wt.existsSync(e))return;let t=await xr(process.execPath,[e,"alias","--remove",Jo],{all:!0,reject:!1});if(t.failed&&!(t.all??"").includes("No alias found"))throw new Error(`'portless alias --remove ${Jo}' failed: ${(t.all??"").trim()}`);let r=Ue("local-name-remove");await q(process.execPath,[e,"service","uninstall"],r),await Ud(r)}var ze={confirm:"uninstall_confirm",deleteData:"uninstall_delete_data",backup:"uninstall_backup"},yn="uninstallOutcome",vn=Rr.join(tp.homedir(),"gaia-backups"),_y=["apps/api/.env","infra/docker/.env"],rp="npm rm -g @heygaia/cli",np="docker volume rm $(docker volume ls -q --filter label=com.docker.compose.project=gaia-selfhost)";function Dy(e,t){if(!t.keepSettings){Ir.rmSync(e,{recursive:!0,force:!0});return}let r=_y.map(i=>Rr.join(e,i)),n=new Set(r),o=i=>{for(let s of Ir.readdirSync(i)){let a=Rr.join(i,s);if(n.has(a))continue;r.some(l=>l.startsWith(`${a}${Rr.sep}`))?o(a):Ir.rmSync(a,{recursive:!0,force:!0})}};o(e)}function Oy(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 $y(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 ${_(vn)}`,run:()=>Jr({outputDir:vn})}),t){let s=n?"containers and data":"containers and images";i.push({id:"containers",label:`Removing ${s}`,doneLabel:`Removed ${s}`,run:()=>so(t,a=>me(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:Qo}),t){let s=_(t);i.push({id:"files",label:`Removing ${s}`,doneLabel:n?`Removed ${s}`:`Removed ${s}, except its settings`,minor:!0,run:()=>Dy(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 Ly(e,t){go(e,t);for(let r of t){ve(e,r.id);try{await r.run()}catch(n){return Ve(e,"failed"),e.setError(n),!1}Oe(e,r.id)}return!0}async function My(){let e=zo();return!e&&!A()?{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 Ny(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 op(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 My();if("error"in r){e.setError(r.error);return}let{installDir:n}=r,o=A()?.localName===!0;e.updateData("installDir",n),e.pushAnswerResolver(Oy(t));let i=await Ny(e);if(!i){e.setStatus("Nothing was removed."),e.updateData("cancelled",!0);return}if(!await Ly(e,$y(e,n,o,i)))return;let s={installDir:n,keptData:!i.deleteData,...i.backup?{backupDir:vn}:{}};e.updateData(yn,s),e.updateData("finished",!0)}var Zo="GAIA is uninstalled";function ei(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:np,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 ${rp}`,tone:"primary"}),t}import{jsx as ye,jsxs as wn}from"react/jsx-runtime";var ip=2;function Gy(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 ${_(vn)} first?`,detail:"Runs 'gaia backup' while GAIA is still running.",yesByDefault:!0};default:return null}}var Uy=({store:e,id:t})=>{let r=Gy(t,e.currentState.data.installDir??null);return r?wn(yt,{flexDirection:"column",marginTop:1,children:[ye(ua,{dimColor:!0,children:r.detail}),wn(yt,{children:[wn(ua,{bold:!0,children:[r.text," "]}),ye(Fy,{defaultChoice:r.yesByDefault?"confirm":"cancel",onConfirm:()=>e.submitInput(!0),onCancel:()=>e.submitInput(!1)},t)]})]}):null},sp=({store:e})=>{let t=Pe(e),r=t.data.steps??[],n=t.data[yn],{finished:o,live:i}=qo(r),s=i.find(a=>a.state!=="pending");return wn(yt,{flexDirection:"column",width:"100%",children:[ye(By,{items:o,children:a=>ye(yt,{paddingLeft:ip,children:ye(Vo,{step:a})},a.id)}),wn(yt,{flexDirection:"column",paddingLeft:ip,children:[t.inputRequest&&ye(Uy,{store:e,id:t.inputRequest.id}),s&&ye(yt,{marginTop:o.length>0?1:0,children:ye(Wo,{step:s,counter:Ho(r,s),waiting:!1,status:t.status})}),t.data.cancelled===!0&&ye(yt,{marginTop:1,children:ye(ua,{children:t.status})})]}),n&&ye(yt,{marginTop:1,children:ye(jo,{headline:Zo,rows:ei(n),accent:"green",success:!0})}),t.error&&ye(Ae,{message:t.error.message})]})};import{StatusMessage as yp}from"@inkjs/ui";import{Box as Le,Static as Cw,Text as Pr}from"ink";import{execFile as nw}from"node:child_process";import*as fp from"node:os";import*as ti from"node:fs";import*as ap from"node:path";var jy=e=>new Promise(t=>setTimeout(t,e));async function ri(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 Cr(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 p of Gr()){let d=Br(p,r);d&&(s[p]=d)}Object.assign(s,ec(r));let a={};o?.domain&&(a.HOST=`https://${o.domain}`,a.FRONTEND_URL=`https://${o.domain}`),i==="infisical"?(await Hy(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.")):await Wy(e,a,r,o?.llmProvider===void 0);let c=ti.existsSync(tt(t))?ti.readFileSync(tt(t),"utf-8"):null,l=qy({defaults:s,existing:Pt(c),existingMode:await $(t),answers:a,setupMode:r});n&&Qa(l,n,r),r==="selfhost"&&Object.assign(l,qn(c));try{await Ky(e,t,l,r,n,o?.domain)}catch(p){e.setError(p);return}await jy(1e3)}function qy(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 Hy(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 Vy(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 Wy(e,t,r,n){e.setStatus("Parsing environment variables\u2026");let o=Za(Tn(),r).filter(g=>r!=="selfhost"||g.selfhostSetup),{alternativePairs:i,alternativeGroupNames:s}=Vy(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(),d=[...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",d.length);for(let g=0;g<d.length;g++){let v=d[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 Ky(e,t,r,n,o,i){e.setStatus("Saving GAIA's settings\u2026");try{let s=ap.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{Ai(t,o??{},n,{dockerSocketGid:qa(),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{oc(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{lc(t),Ai(t,o,n),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}}}import*as lp from"node:path";var pa=["openrouter","gemini","openai","ollama","custom"],Yy={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"}},ni={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 up(e){let t=Object.keys(ni);if(!e.llmProvider){let n=t.find(o=>da(e,o));if(n)throw new Error(`${ni[n]} requires --llm-provider <${pa.join("|")}>.`);return}let r=e.llmProvider;for(let n of t){let o=Yy[r][n];if(o==="required"&&!da(e,n))throw new Error(`--llm-provider ${r} requires ${ni[n]}.`);if(o==="unused"&&da(e,n))throw new Error(`${ni[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 zy(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var cp="GAIA_PROVIDER_API_KEY",kr={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},Xy=/Could not save \w+: (.+)/;async function dp(e,t){let r=lp.join(e,"infra/docker");try{await le("docker",[...Xi(r),"exec","-T","-e",cp,"gaia-backend","python","-m","app.scripts.save_provider",...zy(t)],r,void 0,void 0,{[cp]:t.llmKey??""})}catch(n){let o=Xy.exec(n.message)?.[1];throw o?new Error(o,{cause:n}):n}}var Jy=5e3,Qy=5*6e4,Zy=5e3;async function ew(e,t={}){let r=t.intervalMs??Jy,n=Date.now()+(t.timeoutMs??Qy),o=new Map(e.map(i=>[i.label,i]));for(;;){if(await Promise.all([...o.values()].map(async i=>{await tw(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 X(r)}}async function tw(e){try{let t=await fetch(e.url,{signal:AbortSignal.timeout(Zy)});return e.requireOk?t.ok:!0}catch{return!1}}async function oi(e,t){let r=await ew([{label:"API",url:`${t.apiUrl}/ping`,requireOk:!0},{label:"Web",url:`http://localhost:${t.webPort}/login`,requireOk:!1}],{onProgress:n=>{rw(e,n)}});return e.updateData("dependencyPhase",r.ready?"GAIA is answering":`Still starting: ${r.stillStarting}`),e.updateData("dependencyComplete",!0),r}function rw(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 gp="gaia up --build",ow="usually 10-20 minutes \xB7 safe to leave running",fa="upNotice";function iw(e,t,r){let n=e.llmProvider?kr[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"},...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 sw(e,t){return cr(e)?(t&&Ji(e),"existing"):t?"clone":"bundle"}function aw(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 hp(e,t={}){up(t);let r=Math.min(Date.now(),...Object.values(Gn()).map(E=>E.startedAt)),n=zo(),o=n??$d,i;try{i=sw(o,t.build===!0)}catch(E){e.setError(E);return}e.pushAnswerResolver(Md({repoPath:o}));let s=t.domain??Mn(o),a=uw(t,s);if(go(e,iw(t,i,a)),e.setStep("Prerequisites"),!await lw(e,t,i)||!t.build&&!await gw(e,o,i!=="existing")||!await mw(e,a))return;let c=await dr(e,"selfhost");if(c===null){Ve(e,"failed");return}if(Object.assign(c,Ld(t)),i==="existing"&&o!==n&&!t.forceDevTree&&await $(o)==="developer"){Ar(e,aw(o));return}if(Oe(e,"docker"),e.setStep("Repository Setup"),ve(e,"files"),!await Sw(e,o,i))return;if(Se(t.codeSandbox===void 0?{repoPath:o}:{repoPath:o,codeSandbox:t.codeSandbox}),Oe(e,"files",i==="existing"?`Using your install at ${_(o)}`:void 0),e.setStep("Environment Setup"),ve(e,"configure"),await Cr(e,o,"selfhost",c,{llmProvider:t.llmProvider,domain:t.domain}),e.currentState.error){Ve(e,"failed");return}Oe(e,"configure");let l=dw(o),p=l.webPort,d={...pw(p,s),noStart:t.noStart===!0,stillStarting:!1,setupComplete:!1,elapsedMs:0,startedServices:0};if(t.noStart){mp(e,o,{...d,elapsedMs:Date.now()-r});return}e.setStep("Project Setup");try{d.startedServices=await bw(e,o,c,t)}catch(E){Ar(e,E);return}let m=l.apiUrl,g=await cw(e,{apiUrl:m,webPort:p},d.startedServices);d.stillStarting=!g.ready,d.setupComplete=g.ready&&await Ew(m),Object.assign(d,await fw(e,a,p,g.ready));let v=await yw(e,o,t,g.ready);if(t.llmProvider&&(v?d.unsavedProvider=t.llmProvider:d.savedProvider=t.llmProvider),mp(e,o,{...d,elapsedMs:Date.now()-r}),v){e.setError(v);return}g.ready&&vw(d.webUrl,t)}async function cw(e,t,r){me(e,"start",{detail:void 0,percent:void 0,amount:void 0,etaMs:void 0});let n=await oi(e,t);return n.ready?Oe(e,"start",r===0?"GAIA was already running":void 0):me(e,"start",{state:"failed",endedAt:Date.now()}),n}async function lw(e,t,r){ve(e,"docker");try{return await So(e,{needGit:r==="clone",assumeYes:t.yes===!0,rerunCommand:"gaia up",onInstallStart:o=>ve(e,"docker",{label:`Installing ${ur(o)}`,doneLabel:`${ur(o)} installed`,minor:!1,startedAt:Date.now()}),onInstallProgress:o=>me(e,"docker",{label:o.label,detail:o.detail,amount:o.amount})})!=="relaunch"}catch(n){return n instanceof nn?(tn(e,"docker"),e.updateData(fa,n.message),process.exitCode=1,!1):(Ar(e,n),!1)}}function uw(e,t){return zd({optedOut:e.localName===!1,domain:t,setUpBefore:A()?.localName===!0})}function dw(e){let t=k(e);return{webPort:t[O]??O,apiUrl:de("selfhost",t)}}function pw(e,t){return{webUrl:rs(e,t),localhostUrl:es(e),lanUrls:ts(e),localCertificate:t!==void 0&&_n(t)}}async function mw(e,t){if(t!=="remove")return!0;ve(e,"local-name-off");try{await Qo()}catch(r){return Ar(e,new Error(`Couldn't remove the gaia.local name: ${r.message}`)),!1}return Se({localName:!1}),Oe(e,"local-name-off"),!0}async function fw(e,t,r,n){if(t!=="set-up")return{};if(ve(e,"local-name"),!n)return tn(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 ep(r)}catch(o){return tn(e,"local-name"),{localNameProblem:o.message}}return Oe(e,"local-name"),{localUrl:Kd}}async function gw(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,A()?.bots??[]);if(!o)return!0;let{cause:i,next:s}=rr(o,gp);return Ar(e,new Error(`${i}
138
+ ${s}`)),!1}function hw(e,t){let r=vr();return({received:n,total:o})=>me(e,t,o===null?{detail:`${qe(n)} downloaded`}:{amount:{done:n,total:o,unit:"bytes",estimated:!1},etaMs:r.update(n,o)})}async function Sw(e,t,r){if(r==="existing")return!0;try{if(r==="bundle"){let n=await ro(t,Ge,hw(e,"files"));return await to(n.manifest,n.stagingDir,t,[]),Yr(t,Ge),!0}me(e,"files",{detail:"Connecting to GitHub\u2026"}),await $c(t,Dc,(n,o)=>{me(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 vw(e,t){let r=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;!t.yes&&r&&fp.platform()==="darwin"&&nw("open",[`${e}/setup`],()=>{})}async function yw(e,t,r,n){let{llmProvider:o}=r;if(!o)return null;let i=kr[o];if(ve(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 dp(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 Oe(e,"provider"),null}function ww(e){return e.stage==="starting"||e.stage==="stopping"?"start":"download"}function ma(e,t){return(e.currentState.data[Lt]??[]).find(n=>n.id===t)?.state}function pp(e){let t=ma(e,"download");t==="active"&&Oe(e,"download"),t==="pending"&&tn(e,"download")}async function bw(e,t,r,n){ve(e,"download",n.build?{hint:ow}:{detail:"Checking which images this computer needs"});let o=vr(),i=a=>{let c=ww(a);c==="start"&&pp(e),ma(e,c)!=="active"&&ve(e,c);let l=a.amount?.unit==="bytes"?a.amount:void 0;me(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:gp,onLogFile:a=>e.updateData("logPath",a)});return pp(e),ma(e,"start")!=="active"&&ve(e,"start"),s}async function Ew(e){let t=await He(e,"status");return"data"in t&&!t.data.needs_setup}function mp(e,t,r){Se({version:C,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 ii=[["gaia status","check health"],["gaia stop","stop GAIA"],["gaia doctor","find problems"],["gaia --help","all commands"]];function xw(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 ${kr[e.unsavedProvider]} key wasn't saved`:e.startedServices===0?`${t} \xB7 nothing to do`:t}function Iw(e){return e.localNameProblem?{label:"gaia.local",text:`isn't set up: ${e.localNameProblem}`,tone:"warn"}:null}function Rw(e){let t=e.localUrl??e.webUrl,r=[e.localhostUrl,...e.localUrl?[]:e.lanUrls].filter(n=>n!==t);return{primary:t,others:r}}function si(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}=Rw(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=Iw(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: ${tc}`,tone:"warn"}),e.savedProvider&&t.push({label:"AI",text:`${kr[e.savedProvider]} key saved \xB7 change it in Settings`}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:xw(e),rows:t}}import{jsx as F,jsxs as Yt}from"react/jsx-runtime";var kw={kind:"header"},Sp=2,Aw=14,vp=30,Pw=({outcome:e})=>{let t=si(e),r=t.tone==="success"?"green":w;return Yt(Le,{flexDirection:"column",marginTop:1,children:[F(jo,{headline:t.headline,rows:t.rows,accent:r,success:t.tone==="success"}),F(Le,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:vp*2+4,children:ii.map(([n,o])=>Yt(Le,{width:vp,children:[F(Le,{width:Aw,children:F(Pr,{color:w,children:n})}),F(Pr,{color:"gray",children:o})]},n))})]})},Tw=({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[Ft],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),_w=()=>Yt(Le,{flexDirection:"column",marginTop:1,marginBottom:1,children:[Yt(Pr,{children:[F(Pr,{bold:!0,children:"GAIA"}),F(Pr,{dimColor:!0,children:` v${C} \xB7 setting up`})]}),eo(process.env,C).map(e=>F(yp,{variant:"warning",children:e},e))]}),wp=({store:e})=>{let t=Pe(e),r=t.data.steps??[],n=t.data.upOutcome,o=t.data.logPath,i=t.data[fa],s=t.data.finished===!0&&n!==void 0,{finished:a,live:c}=qo(r),l=c.find(d=>d.state!=="pending"),p=[...Bn()?[]:[kw],...a.map(d=>({kind:"step",step:d}))];return Yt(Le,{flexDirection:"column",width:"100%",children:[F(Cw,{items:p,children:d=>F(Le,{paddingLeft:Sp,children:d.kind==="header"?F(_w,{}):F(Vo,{step:d.step})},d.kind==="header"?"header":d.step.id)}),Yt(Le,{flexDirection:"column",paddingLeft:Sp,children:[l&&F(Le,{marginTop:a.length>0?1:0,children:F(Wo,{step:l,counter:Ho(r,l),waiting:t.inputRequest!==null,status:t.status})}),F(Tw,{state:t,store:e}),i&&F(Le,{marginTop:1,children:F(yp,{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(Pw,{outcome:n}),t.error&&F(Ae,{message:t.error.message})]})};import{Select as Sa,Spinner as Ww}from"@inkjs/ui";import{Box as h,Text as f,useInput as _r}from"ink";import En from"ink-text-input";import{useEffect as va,useState as we}from"react";import{Box as Dw,Text as ga,useInput as Ow}from"ink";import{useState as $w}from"react";import{jsx as Lw,jsxs as ha}from"react/jsx-runtime";var bp=8;function Ep(e,t){return`${e} ${t}${e===1?"":"s"}`}var ai=({logs:e})=>{let[t,r]=$w({offset:0,lineCount:e.length}),n=t.lineCount===e.length?t.offset:0,o=Math.min(e.length,bp),i=e.length>bp;Ow((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 ha(Dw,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&ha(ga,{color:"gray",children:[Ep(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>Lw(ga,{color:"gray",wrap:"truncate",children:c},s+l)),n>0&&ha(ga,{color:"gray",children:[Ep(n,"newer line")," (\u2193)"]})]})};import{Box as bn,Text as ci}from"ink";import{Box as Mw,Text as Nw}from"ink";import{jsx as xp}from"react/jsx-runtime";var Fw=new Set(["Welcome","Finished"]),Ip=({status:e,step:t})=>Fw.has(t)?null:xp(Mw,{width:"100%",paddingX:1,marginTop:1,children:xp(Nw,{color:"gray",dimColor:!0,children:e})});import Bw from"chalk";import{Box as Gw,Text as Uw,useStdout as jw}from"ink";import{useEffect as qw,useState as Rp}from"react";import{jsx as Cp}from"react/jsx-runtime";var Tr=({size:e="small",showStatus:t=!0,showUpdate:r=!0})=>{let{stdout:n}=jw(),o=Fo(),[i,s]=Rp(null),[a]=Rp(()=>r?mo():null);qw(()=>{if(!t){s(null);return}let l=!0;return po().then(p=>{l&&s(p)}),()=>{l=!1}},[t]);let c=fo({size:e,level:Bw.level,...o,...cs(n),version:C,status:t?i:null,update:a});return Cp(Gw,{marginTop:1,children:Cp(Uw,{children:c.join(`
141
+ `)})})};import{jsx as wt,jsxs as li}from"react/jsx-runtime";var Hw=[{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"}],Vw=({currentStep:e,steps:t})=>{let r=t.findIndex(o=>o.id===e),n=r===t.length-1;return wt(bn,{marginY:1,flexWrap:"wrap",children:t.map(({id:o,label:i},s)=>{let a=s<r||n,c=s===r&&!n;return li(bn,{flexShrink:0,children:[s>0&&wt(ci,{color:"gray",children:" \xB7 "}),a&&li(ci,{color:"green",children:[y.ok," ",i]}),c&&wt(ci,{color:w,bold:!0,children:i}),!a&&!c&&wt(ci,{color:"gray",children:i})]},o)})})},ui=({children:e,status:t,step:r,steps:n=Hw,header:o})=>li(bn,{flexDirection:"column",height:"100%",width:"100%",children:[li(bn,{flexGrow:1,flexDirection:"column",children:[wt(Tr,{...o}),wt(Vw,{currentStep:r,steps:n}),wt(bn,{flexDirection:"column",flexGrow:1,children:e})]}),wt(Ip,{status:t,step:r})]});import{jsx as u,jsxs as S}from"react/jsx-runtime";var Kw=({onConfirm:e})=>(_r((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:T,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"]})})]})),Yw=({defaultValue:e,onSubmit:t})=>{let[r,n]=we(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,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})]})]})},zw=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,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(Sa,{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)})})]}),Xw=({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:[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:T,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"]})})]})},ya=({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:[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(Ww,{label:e||"Preparing\u2026"})}),!r&&t>0&&u(yr,{percent:t}),!r&&n&&n.length>0&&u(ai,{logs:n}),!r&&u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),wa=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,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(Sa,{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)})})]}),ba=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,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(Sa,{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)"})]})]}),Ea=({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,p)=>{if(p.tab||p.downArrow)o(d=>d<a.length-1?d+1:d);else if(p.upArrow)o(d=>d>0?d-1:d);else if(p.return){if(n<a.length-1){o(m=>m+1);return}let d=a.filter(m=>!t[m.key].trim());if(d.length>0){s(`Required: ${d.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:[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,p)=>{let d=l.key.includes("SECRET")||l.key.includes("TOKEN");return S(h,{flexDirection:"column",marginBottom:1,children:[u(h,{children:S(f,{color:p===n?w:"white",children:[p===n?"\u25B8 ":" ",l.key,":"]})}),u(h,{marginLeft:2,children:u(f,{color:"gray",dimColor:!0,children:l.description})}),p===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:d?"*":void 0})}):u(h,{marginLeft:2,children:u(f,{color:t[l.key]?"green":"gray",children:t[l.key]?d?`\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"]})})]})},xa=({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);va(()=>{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 p=()=>{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)}},d=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]})]}),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:p,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",!d&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Ia=({alternatives:e,onSubmit:t})=>{let[r,n]=we(new Set),[o,i]=we({}),[s,a]=we(0),[c,l]=we(null);va(()=>{let b={};for(let x of e)for(let B of x.variables)b[B.name]=B.defaultValue||"";i(b)},[e]);let p=[];for(let b=0;b<e.length;b++)if(p.push({type:"provider",categoryIndex:b}),r.has(b)){let x=e[b];if(x)for(let B=0;B<x.variables.length;B++)p.push({type:"field",categoryIndex:b,fieldIndex:B})}p.push({type:"submit"});let d=p[s],m=d?.type==="field",g=d?.type==="submit";_r((b,x)=>{let B=Math.min(s,p.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(p.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(p.length-1,N+1));else if((x.return||b===" ")&&d?.type==="provider"){let N=d.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(p.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 Rn=o[G.name];Rn&&(x[G.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:T,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 B=r.has(x),N=p.findIndex(G=>G.type==="provider"&&G.categoryIndex===x),Rt=s===N;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[u(f,{color:Rt?w:void 0,bold:Rt,children:Rt?"\u279C ":" "}),u(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:[u(f,{color:"yellow",children:"\u{1F4D6} "}),u(f,{color:"blue",underline:!0,children:b.docsUrl})]}),B&&u(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:b.variables.map((G,Rn)=>{let Em=p.findIndex($r=>$r.type==="field"&&$r.categoryIndex===x&&$r.fieldIndex===Rn),Qt=s===Em,Oa=!!G.defaultValue,yi=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&&yi&&u(f,{color:"green",children:" \u2713"}),!Qt&&!yi&&Oa&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",G.defaultValue,")"]})]}),Qt&&u(h,{marginLeft:4,children:u(En,{value:yi,onChange:$r=>{i(xm=>({...xm,[G.name]:$r})),c&&l(null)},onSubmit:v,placeholder:Oa?`Default: ${G.defaultValue}`:"Enter value\u2026"})})]},G.name)})})]},b.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),S(h,{marginTop:1,children:[u(f,{color:g?w:void 0,bold:g,children:g?"\u279C ":" "}),u(h,{borderStyle:T,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"})})]})},Ra=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:n,onSkip:o})=>{let[i,s]=we(e.defaultValue||""),[a,c]=we(null);va(()=>{s(e.defaultValue||""),c(null)},[e.name]),_r((d,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}o()}});let l=d=>{if(e.required&&!d.trim()){c("This field is required");return}c(null),n(d)},p=!!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:[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:d=>{s(d),a&&c(null)},onSubmit:l,placeholder:p?`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"]})]})})]})},Ap=({store:e})=>{let t=Pe(e);return S(ui,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&u(Kw,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&u(Ko,{checks:t.data.checks}),u(br,{inputId:t.inputRequest?.id,missing:t.data[Ft],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&u(wr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&u(Yw,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&u(zw,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&u(_d,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&u(wa,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&u(ba,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&u(Ea,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&u(Ra,{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(xa,{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(Ia,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&u(Yo,{status:t.status}),t.step==="Finished"&&u(Xw,{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(ya,{title:t.step==="Install Tools"?"Installing Tools":"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.step==="Install Tools"?t.data.toolComplete||!1:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.error&&u(Ae,{message:t.error.message})]})};import{Spinner as Jw}from"@inkjs/ui";import{Box as zt,Text as Dr}from"ink";import{useState as Qw}from"react";import{jsx as bt,jsxs as Me}from"react/jsx-runtime";var Pp=({store:e})=>{let t=Pe(e),r=t.step==="Starting"||t.step==="Stopping",n=t.step==="Running"||t.step==="Stopped",o=t.data.dockerLogs??[],[i]=Qw(Date.now),s=na(r);return Me(zt,{flexDirection:"column",width:"100%",children:[bt(Tr,{showStatus:n}),r&&!t.error&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[bt(Jw,{label:t.status||"Working\u2026"}),Me(Dr,{color:"gray",children:[" ",ft(s-i)]})]}),o.length>0&&bt(ai,{logs:o})]}),t.step==="Running"&&t.data.started&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[bt(ke,{kind:"ok"}),Me(Dr,{children:["GAIA is running at"," ",bt(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:[bt(ke,{kind:"ok"}),bt(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&&bt(Ae,{message:t.error.message})]})};import{Spinner as Zw}from"@inkjs/ui";import{Box as Et,Text as Te,useInput as eb}from"ink";import{jsx as P,jsxs as Xe}from"react/jsx-runtime";var Tp=({store:e})=>{let t=Pe(e);return Xe(ui,{status:t.status,step:t.step,steps:kp,children:[t.step==="Detect Repo"&&Xe(Et,{flexDirection:"column",paddingX:2,borderStyle:T,borderColor:w,children:[P(Te,{bold:!0,children:"Detecting GAIA Repository"}),P(Et,{marginTop:1,children:P(Zw,{label:"Searching for repository\u2026"})}),t.data.repoPath&&P(Et,{marginTop:1,children:Xe(Te,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&P(Ko,{checks:t.data.checks}),P(br,{inputId:t.inputRequest?.id,missing:t.data[Ft],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(wa,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&P(ba,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&P(Ea,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&P(Ra,{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(xa,{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(Ia,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&P(Yo,{status:t.status}),t.step==="Project Setup"&&P(ya,{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(tb,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&P(Ae,{message:t.error.message})]})},tb=({setupMode:e,portOverrides:t,onConfirm:r})=>{eb((s,a)=>{a.return&&r()});let n=t?.[3e3]??3e3,o=de(e??"developer",t??{}),i=e==="selfhost";return Xe(Et,{flexDirection:"column",marginTop:2,borderStyle:T,borderColor:w,padding:1,children:[P(Te,{color:w,bold:!0,children:"Setup Complete!"}),Xe(Et,{marginTop:1,children:[P(Te,{bold:!0,children:"Run: "}),P(Te,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Xe(Et,{marginTop:1,flexDirection:"column",children:[Xe(Te,{children:["Web:"," ",Xe(Te,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),Xe(Te,{children:["API:"," ",P(Te,{color:"cyan",bold:!0,children:o})]})]}),P(Et,{marginTop:1,children:P(Te,{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(Et,{marginTop:1,children:Xe(Te,{dimColor:!0,children:[P(Te,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as mb}from"@inkjs/ui";import{Box as re,Text as Je,useInput as fb}from"ink";var rb=[{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 _p(e){return Promise.all(rb.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?nb(t.name,r,t.path):ob(t.name,r)}))}async function nb(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 ob(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 Dp(e){let t=await Z();if(t!=="ready")return{access:t,problem:await et(t),containers:[]};let r=await Ua(be[e]);return{access:t,containers:r}}var xn="statusFacts";async function ib(){let e=L(),t=e?await $(e):null,r=Xr(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"?_p(n):[],Dp(t),No(Ot(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:sb(s.containers)}:s,readiness:a,services:i,webUrl:pt(e,o),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function sb(e){let t=(A()?.bots??[]).map(xe).filter(r=>!e.some(n=>n.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function ab(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 Op(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await ab(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var cb=["gaia-web","gaia-backend","arq_worker","proxy"],lb=["mongo","postgres","redis","rabbitmq","chromadb"];function di(e,t,r){return t.some(o=>!o.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function $p(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 Lp(e,t){let r=e.readiness,n=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:Vn(i.name)})):$p(t,lb),o=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return di("Data",n,o??"See why with: gaia doctor")}function ub(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"}:di("Bots",t.map(r=>({ok:r.status==="running",name:je(r.name)})),"See why with: gaia doctor")}function Mp(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 db(e,t){let r=t.containers,o=[di("App",$p(r,cb),"Start it: gaia start"),Lp(e,r),ub(r)],i=Mp(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 pb(e){let t=e.services.map(n=>({ok:n.status==="up",name:`${n.name} :${n.port}`})),r=di("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 pi(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=Mp(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?[Lp(e,[]),...o?[o]:[],n]:[],unhealthy:!0}}return e.services.length>0?pb(e):db(e,t??{access:"ready",containers:[]})}import{jsx as M,jsxs as ot}from"react/jsx-runtime";var gb=8,hb={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},Sb=({row:e})=>ot(re,{children:[M(re,{width:gb,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(ke,{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(ke,{kind:e.tone==="warn"?"warn":"ok"}),M(Je,{color:hb[e.tone],children:e.note})]})]})]}),Np=({store:e})=>{let t=Pe(e),r=t.data[xn],n=t.data.watch===!0,o=t.step==="Results"&&r!==void 0;fb((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:n&&t.inputRequest!==null});let i=r?pi(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(mb,{label:t.status})}),o&&i&&ot(re,{flexDirection:"column",marginTop:1,marginLeft:2,children:[ot(re,{children:[M(ke,{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(Sb,{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(Ae,{message:t.error.message})]})};import{defaultTheme as vb,extendTheme as yb}from"@inkjs/ui";var mi={success:"ok",error:"fail",warning:"warn",info:"active"},Fp=yb(vb,{components:{Spinner:{styles:{frame:()=>({color:w})}},ProgressBar:{styles:{completed:()=>({color:w})},config:()=>({completedCharacter:wi.done,remainingCharacter:wi.rest})},StatusMessage:{styles:{icon:({variant:e})=>({color:Mr[mi[e]]})},config:({variant:e})=>({icon:y[mi[e]]})},Alert:{styles:{icon:({variant:e})=>({color:Mr[mi[e]]})},config:({variant:e})=>({icon:y[mi[e]]})}}});import{jsx as ne,jsxs as Or}from"react/jsx-runtime";var xb=["init","setup","status","start","stop","up","uninstall"],Ca=class extends Eb.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Or(fi,{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(fi,{marginTop:1,children:ne(Xt,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},Ib=({store:e,command:t})=>{switch(t){case"init":return ne(Ap,{store:e});case"setup":return ne(Tp,{store:e});case"status":return ne(Np,{store:e});case"start":case"stop":return ne(Pp,{store:e,command:t});case"up":return ne(wp,{store:e});case"uninstall":return ne(sp,{store:e});default:return Or(fi,{flexDirection:"column",padding:1,children:[Or(Xt,{color:"red",children:["Unknown command: ",t]}),Or(fi,{marginTop:1,flexDirection:"column",children:[ne(Xt,{bold:!0,children:"Available commands:"}),xb.map(r=>Or(Xt,{children:[" ",ne(Xt,{color:"cyan",children:r})]},r))]})]})}},Rb=({onCancel:e})=>(bb((t,r)=>{r.ctrl&&t==="c"&&e()}),null),Bp=({store:e,command:t,onCancel:r})=>ne(Ca,{children:Or(wb,{theme:Fp,children:[ne(Rb,{onCancel:r}),ne(Ib,{store:e,command:t})]})});import{EventEmitter as Cb}from"events";var kb=150,ka=class extends Cb{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))},kb))}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())}},Gp=()=>new ka;async function ge(e){let t=Gp();if(e.whenNonInteractive==="fail"){Yl(e.command),await jp(t,e);return}fe()?await jp(t,e):await Tb(t,e)}async function Tb(e,t){zl(e,Bn());for(let[r,n]of t.autoResolve??[])e.setAutoResolve(r,n);try{await t.runFlow(e);let r=Hp(e);r&&await jn(r,{step:e.currentState.step,steps:ms(e)}),t.onPlainComplete?.(e)}catch(r){e.setError(r)}Vp(e)}var qp=30,_b=Math.ceil(1e3/qp);async function Up(e){e.flush(),await new Promise(t=>setTimeout(t,2*_b))}async function jp(e,t){let r=async()=>{},{unmount:n,clear:o}=Ab(Pb.createElement(Bp,{store:e,command:t.command,onCancel:()=>void r()}),{exitOnCtrlC:!1,maxFps:qp}),i=async()=>{Ve(e,"cancelled"),await Up(e),n();let a=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
142
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.
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 Up(e);let s=Hp(e);s&&(o(),n(),await jn(s,{step:e.currentState.step,steps:ms(e)})),n(),process.stdout.write(`
144
+ `),Vp(e)}function Hp(e){if(!e.currentState.error)return e.currentState.data.dockerGroupSwitch}function Vp(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 xt from"fs";import*as Wp from"os";import*as Jt from"path";var Db=process.env.GAIA_CLI_DEV==="true";async function Kp(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 ri(e),o=await dr(e,n);if(o===null||n==="developer"&&!await wo(e))return;let i="";if(Db){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 X(500),e.setStatus("Repository ready")}else{e.setStep("Repository Setup");let a=n==="selfhost"?Jt.join(Wp.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)),xt.existsSync(i)){if(!xt.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await X(2e3),e.setError(null);continue}if(sr(i)){e.updateData("existingRepoPath",i);let d=await e.waitForInput("existing_repo");if(d==="use_existing"){c=!1;break}else if(d==="delete_reclone"){e.setStatus("Removing existing installation\u2026");try{xt.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(d==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(xt.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await X(2e3),e.setError(null);continue}}break}if(c){e.setStep("Repository Setup"),e.setStatus("Preparing repository\u2026"),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await Yn(i,"https://github.com/theexperiencecompany/gaia.git",(l,p)=>{e.updateData("repoProgress",l),p?(e.updateData("repoPhase",p),e.setStatus(`${p}\u2026`)):e.setStatus(`Cloning repository to ${i}... ${l}%`)},t),e.setStatus("Repository ready")}catch(l){e.setError(l);return}}else e.setStatus("Using the existing repository")}if(await X(1e3),await Cr(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=ru(e),c=!1;try{e.setStatus("Pulling pre-built images from registry\u2026"),await ce(i,"selfhost",d=>e.setStatus(d),o,a,{pull:"missing"}),c=!0}catch(d){let m=d.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",d=>e.setStatus(d),o,a,{build:!0})}catch(d){e.setError(new Error(`Failed to start services: ${d.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let l=e.currentState.data.envMethod||"manual";Nn({version:C,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",n);let p=await oi(e,{apiUrl:de("selfhost",o),webPort:o[O]??O});e.updateData("stillStarting",!p.ready),e.setStep("Finished"),e.setStatus(p.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 X(1e3),e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("repoPath",i),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyProgress",0),e.updateData("dependencyPhase","Running mise setup (all dependencies)\u2026");let a=Object.keys(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 X(1e3);let s=e.currentState.data.envMethod||"manual";Nn({version:C,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 Yp(e={}){await ge({command:"init",whenNonInteractive:"fail",runFlow:t=>Kp(t,e.branch)})}import*as Ne from"node:fs";import*as Fe from"node:path";import{execa as gi}from"execa";function Aa(e){if(e.fromDir){let t=Fe.resolve(e.fromDir),r=Fa(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 zp(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 Pa(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 Xp(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=Aa(e),{mongoFile:s,postgresFile:a,apiEnvFile:c,volumeFiles:l}=i,p=Pa(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:p};let d=await Z();if(d!=="ready"){let m=await et(d);throw new Error([`${m.summary}, so nothing can be restored.`,m.fix,"Or run the restore commands yourself:",...p.map(g=>` ${g}`)].join(`
148
+ `))}if(c&&Ob(c,r),s)try{let m=gi("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 gi("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=gi("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 gi("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,k(r)),{...i,commands:p}}function Ob(e,t){$n(e,tt(t))}function Qe(e=""){process.stdout.write(`${e}
149
+ `)}function $b(e=""){process.stderr.write(`${e}
150
+ `)}async function Jp(e={}){let t={mongoFile:e.mongo,postgresFile:e.postgres,apiEnvFile:e.env,fromDir:e.from},r=Aa(t);for(let n of zp(r))$b(`${y.warn} ${n}`);if(e.dryRun){let n=Pa(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 Xp(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 Qp(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 X(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await yo(e))return;let r=await ri(e),n=await dr(e,r);if(n===null||r==="developer"&&!await wo(e)||(await Cr(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=vo(e);if(!await nu(e,t,n,o))return;await X(1e3);let s=e.currentState.data.envMethod||"manual";Se({setupComplete:!0,setupMethod:s,repoPath:t}),e.updateData("setupMode",r),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function Zp(){await ge({command:"setup",whenNonInteractive:"fail",runFlow:Qp})}async function em(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 _t(s));return}}let o=k(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 tm(e){await ge({command:"start",whenNonInteractive:"plain",runFlow:t=>em(t,e),cancelHint:"GAIA may be partly started. Run 'gaia start' again to finish, or 'gaia stop'."})}var rm=8;function It(e=""){process.stdout.write(`${e}
151
+ `)}function nm(e){let t=e.currentState.data[xn];return t?{facts:t,report:pi(t)}:null}function Lb(e){let t=nm(e);if(!t)return;let{facts:r,report:n}=t,o=n.headline.kind==="ok"?y.active:y.fail;It(`${o} ${n.headline.text}`),n.headline.url&&It(` ${n.headline.url}`),n.hint&&It(` ${n.hint}`),n.rows.length>0&&It();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??"":"";It(` ${i.label.padEnd(rm)}${s}${a}`.trimEnd()),i.items.length>0&&i.note&&It(` ${" ".repeat(rm)}${i.note}`)}r.installed&&(It(),It(` Installed at ${r.install}`))}async function om(e={}){await ge({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:async t=>{await Op(t,e),nm(t)?.report.unhealthy&&(process.exitCode=1)},onPlainComplete:Lb})}async function im(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 sm(e){await ge({command:"stop",whenNonInteractive:"plain",runFlow:t=>im(t,e),cancelHint:"GAIA may still be partly running. Run 'gaia stop' again."})}import*as hi from"fs";import*as Si from"path";function Mb(e){let t=Si.join(e,".env");return hi.existsSync(t)?["--env-file",".env"]:[]}async function am(){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=Si.join(e,"infra","docker"),n=Mb(r),o=k(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=Si.join(e,al),c=zi(e),l=typeof c=="number"&&no(c);if(hi.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}hi.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 Nb=16;function Ta(e=""){process.stdout.write(`${e}
152
+ `)}function Fb(e){let t=e.currentState.data[yn];if(t){Ta(),Ta(`${y.ok} ${Zo}`);for(let r of ei(t))Ta(` ${r.label.padEnd(Nb)}${r.text}`)}}async function cm(e={}){await ge({command:"uninstall",whenNonInteractive:"plain",runFlow:t=>op(t,e),cancelHint:"GAIA may be partly removed. Run 'gaia uninstall' again to finish.",onPlainComplete:Fb})}var Bb=16,Gb=14;function In(e=""){process.stdout.write(`${e}
153
+ `)}function Ub(e){let t=e.currentState.data.upOutcome;if(!t)return;let r=si(t);In(),In(`${r.tone==="success"?`${y.ok} `:""}${r.headline}`);for(let n of r.rows)In(` ${n.label.padEnd(Bb)}${n.text}`);In();for(let[n,o]of ii)In(` ${n.padEnd(Gb)}${o}`)}async function lm(e={}){await ge({command:"up",whenNonInteractive:"plain",runFlow:t=>hp(t,e),cancelHint:"GAIA may be partly set up. Run 'gaia up' again to finish, or 'gaia stop'.",onPlainComplete:Ub})}import*as vm from"node:readline";var jb="https://api.github.com/repos/theexperiencecompany/gaia/releases/tags",qb=5e3,Hb=5,Vb=["Features","Bug Fixes"],Wb=/^\* (.+)$/,Kb=/^\*\*[^*]+:\*\*\s*/,Yb=/(\s*\(\[[^\]]+\]\([^)]+\)\))+$/;function zb(e){let t=e.replace(Kb,"").replace(Yb,"");return t.charAt(0).toUpperCase()+t.slice(1)}function Xb(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=Wb.exec(n.trim())?.[1];i&&t.set(r,[...t.get(r)??[],zb(i)])}return Vb.flatMap(n=>t.get(n)??[]).slice(0,Hb)}async function um(e){let t=await fetch(`${jb}/${ct(e)}`,{headers:{Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(qb)});if(!t.ok)throw new Error(`GitHub answered HTTP ${t.status}`);let{body:r}=await t.json();return Xb(r??"")}import*as dm from"node:fs/promises";import{execa as vi}from"execa";var Jb=["apps/web","apps/api","infra/docker"];function pm(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 _a(e,t){let{stdout:r}=await vi("git",t,{cwd:e});return r.trim()}async function Qb(e){let t=await vi("git",["rev-parse","--is-inside-work-tree"],{cwd:e,reject:!1});return t.exitCode!==0||t.stdout.trim()!=="true"?!1:(await vi("git",["remote","get-url","origin"],{cwd:e,reject:!1})).exitCode===0}function Zb(e){return e.split(`
155
+ `).map(t=>t.trim()).filter(Boolean)}async function eE(e,t){let r=await _a(e,["log",t,"--oneline","--",...Jb]);return{commits:Zb(r)}}async function mm(e,t){ct(t);let r=Be(e),n=Yi(e),o=n?{kind:"bundle",version:n.version,files:n.files}:{kind:"checkout",files:await ol(e)};return{repoPath:e,fromVersion:r,toVersion:t,layout:o}}function fm(e){return e.fromVersion===e.toVersion&&e.layout.kind==="bundle"&&e.layout.version===e.toVersion}async function gm(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 dl(e.repoPath,e.toVersion,t.onImagePull)}catch(n){throw await dm.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),Yr(e.repoPath,e.toVersion),t.onStatus("Restarting GAIA\u2026"),await ce(e.repoPath,"selfhost",t.onStatus,k(e.repoPath),void 0,{pull:"missing"})}async function hm(e){if(!await Qb(e))throw new Error(`${e} is not a git checkout with an origin remote; run 'gaia update' without --git.`);if((await vi("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 _a(e,["fetch","origin"]),eE(e,"HEAD..@{upstream}")}async function Sm(e,t){t("Pulling the latest commits (git pull --ff-only)\u2026"),await _a(e,["pull","--ff-only"]),t("Rebuilding images from this checkout and restarting\u2026"),await ce(e,"selfhost",t,k(e),void 0,{build:!0})}var tE=5,rE="https://docs.heygaia.io/release-notes";function R(e=""){process.stdout.write(`${dt(e)}
156
+ `)}async function nE(e){let t=vm.createInterface({input:process.stdin,output:process.stdout});t.on("SIGINT",()=>{t.close(),R(`
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 oE(){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 iE(){let e=oE(),t=vr(),r=vr();return{onStatus:n=>{e.end(),R(` ${n}`)},onBundleDownload:({received:n,total:o})=>e.show(o===null?`Setup files: ${qe(n)} downloaded`:`Setup files: ${gn({done:n,total:o,unit:"bytes",estimated:!1},{etaMs:t.update(n,o)})}`),onImagePull:n=>{let o=n.amount;e.show(o?`Images: ${gn(o,{percent:n.percent,etaMs:o.unit==="bytes"?r.update(o.done,o.total):null})} \xB7 ${n.detail??""}`:n.detail??n.label)}}}function sE(e,t){let r=t?e.commits:e.commits.slice(0,tE);for(let o of r)R(` ${o}`);let n=e.commits.length-r.length;n>0&&R(` and ${n} more (--verbose lists them)`)}async function aE(e){try{for(let t of await um(e))R(` - ${t}`)}catch(t){R(` (couldn't read what's new in ${e}: ${t.message})`)}}async function ym(e,t){return e.yes?!0:fe()?nE(`
158
+ ${t}`):(R(`
159
+ No terminal to confirm in: rerun with --yes to apply.`),!1)}function cE(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 lE(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,A()?.bots??[]):null,a=pm({current:r,target:n,explicit:o,gap:s});switch(a.kind){case"development-build":R(`This install runs a development build of GAIA (${lo(r)}), not a release, so there is nothing to update.`),R(`To switch it to the ${n} release: gaia update --version ${n}`);return;case"up-to-date":R(`GAIA ${r} is up to date.`);for(let p of Oc(C))R(p);return;case"unavailable":R(`${rr(a.gap,"gaia up --build").cause} Nothing was changed.`),o&&(process.exitCode=1);return;case"offer":break}let c=await mm(e,n);if(fm(c)){R(`GAIA ${r} is up to date.`);return}if(R(`
160
+ ${cE(c,a.downgrade)}`),await aE(n),R(`What's new: ${rE}`),R("Your data and settings are kept."),!await ym(t,"Update and restart now?"))return;let l=iE();await gm(c,l),c.layout.kind==="checkout"&&R(" This install no longer needs git: it now holds only the release's setup files, beside your settings and data."),R(`
161
+ ${y.ok} GAIA is on ${n}.`),R("Run 'gaia doctor' to check that everything is ready.")}async function uE(e,t){let r=await hm(e);if(r.commits.length===0){R("Already up to date with the upstream branch.");return}R(`
162
+ ${r.commits.length} new commit(s) touch the self-host stack:`),sE(r,t.verbose===!0),R("The images are rebuilt from this checkout (slow on small machines)."),await ym(t,"Pull, rebuild and restart now?")&&(await Sm(e,n=>R(` ${n}`)),R(`
163
+ Updated and restarted from source.`))}async function wm(e={}){await $t({showUpdate:!1});let t=L();if(!t){he(`GAIA isn't installed here, so there is nothing to update.
164
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();
165
+ --version moves to a published release; --git builds from source. Pick one.`),process.exitCode=1;return}for(let r of eo(process.env,C))R(`${y.warn} ${r}`);R(`Checking for updates in ${_(t)}\u2026`);try{await(e.git?uE(t,e):lE(t,e))}catch(r){R(),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 dE={"":1,true:1,false:0,0:0,1:1,2:2,3:3},pE=new Set(["truecolor","24bit"]),mE=new Set(["iTerm.app","WezTerm","vscode","ghostty"]),fE="Apple_Terminal",gE=/-256(color)?$|-direct$|-truecolor$|^tmux|^xterm-kitty$|^xterm-ghostty$|^alacritty|^wezterm|^foot|^contour/,hE=/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/;function bm({env:e,isTTY:t,platform:r}){let n=e.FORCE_COLOR;if(n!==void 0){let i=dE[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:pE.has(e.COLORTERM??"")?3:e.TERM_PROGRAM===fE?2:mE.has(e.TERM_PROGRAM??"")||r==="win32"&&(e.WT_SESSION||!o)||gE.test(o)?3:hE.test(o)||e.COLORTERM?1:0}SE.level=bm({env:process.env,isTTY:process.stdout.isTTY===!0,platform:process.platform});var wE=new Set(["-V","--version"]),W=new vE,Da="For contributors:",bE=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:bE}).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 yE("--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 lm({...r,noStart:t===!1})});W.command("status").description(U.status).option("--watch","Stay open; press r to check again").action(async e=>{await om({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 sm({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 tm({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 wm(e)});W.command("doctor").description(U.doctor).action(async()=>{await xd()});W.command("logs").description(U.logs).action(async()=>{try{await am()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});W.addCommand(an);W.addCommand(nd);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 vl({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 Jp({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 cm(e)});W.command("init").helpGroup(Da).description(U.init).option("--branch <branch>","Git branch to clone").action(async e=>{await Yp({branch:e.branch})});W.command("setup").helpGroup(Da).description(U.setup).action(async()=>{await Zp()});W.command("dev [profile]").helpGroup(Da).description(U.dev).action(async e=>{try{await id(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});wE.has(process.argv[2]??"")&&(await Nl(),process.exit(0));process.argv.slice(2).length||(W.outputHelp(),process.exit(0));await bc();W.parse();