@heygaia/cli 0.7.0-beta.4 → 0.7.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +117 -117
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import NE from"chalk";import{Command as FE,Option as BE}from"commander";var j={up:"Install GAIA and start it (or resume an earlier run)",status:"Show whether GAIA is running and healthy",stop:"Stop GAIA (your data is kept)",start:"Start GAIA again after 'gaia stop'",update:"Move GAIA to a newer release (keeps your data and settings)",doctor:"Find problems with your install and how to fix them",logs:"Show GAIA's logs as they happen",bots:"Connect GAIA to Telegram, Discord or Slack",connect:"Import browser logins so GAIA's browser stays signed in",bridge:"Let GAIA use tools and files on this computer",backup:"Save GAIA's data and settings to a folder",restore:"Bring back GAIA's data and settings from a backup",uninstall:"Remove GAIA from this computer (asks before deleting your data)",init:"Set up a development copy of GAIA from scratch",setup:"Configure an existing development copy",dev:"Run GAIA from source with live reload"};import*as bl from"node:path";import $m from"is-unicode-supported";var w="cyan",Cn="handedOver",$r=30,_="round",st=$m(),y={ok:st?"\u2713":"\u221A",fail:st?"\u2717":"x",warn:"!",skip:st?"\u2013":"-",pending:st?"\u25CB":"o",active:st?"\u25CF":"*",cancelled:st?"\u25A0":"#"},yi={done:st?"\u2501":"=",rest:st?"\u2500":"-"},Lr={ok:"green",fail:"red",warn:"yellow",skip:"gray",pending:"gray",active:w,cancelled:"yellow"};function ye(e){let[t="",...r]=e.split(`
|
|
3
3
|
`),n=[`${y.fail} ${t}`,...r.map(o=>` ${o}`)];process.stderr.write(`${n.join(`
|
|
4
4
|
`)}
|
|
5
|
-
`)}var
|
|
6
|
-
`)){if(!r)continue;let[n,o,i]=r.split("|");if(!n||!o)continue;let s=i?.match(
|
|
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(),
|
|
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
|
|
10
|
-
`))}function
|
|
11
|
-
`))}var
|
|
12
|
-
`))}function
|
|
13
|
-
`)){let i=o.trim();if(i&&!i.startsWith("#")){let[s,...a]=i.split("=");if(s&&
|
|
14
|
-
`)}function
|
|
15
|
-
Check the socket's group with 'ls -l /var/run/docker.sock', then log out and back in and rerun.`);if(await
|
|
16
|
-
Run 'sudo usermod -aG ${
|
|
17
|
-
Log out and back in (or run 'newgrp ${
|
|
18
|
-
${t.fix}`)}import{execa as
|
|
19
|
-
Install a released CLI (${Wr("latest")}) and rerun.`):new Error(`Could not read ${n} from ${e}: ${o.stderr.trim()}`)}function Kr(e,t){
|
|
20
|
-
`);for(let o of[
|
|
21
|
-
`)),this.name="ComposeError",this.failure=t,this.logPath=r}};import*as
|
|
22
|
-
Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),
|
|
23
|
-
`);let i=
|
|
24
|
-
`),await new Promise(
|
|
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
|
|
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=>
|
|
5
|
+
`)}var kt=[{volume:"gaia-selfhost_chroma_data",fileSuffix:"chroma_data",label:"Chroma",userData:!1},{volume:"gaia-selfhost_workspace",fileSuffix:"workspace",label:"Workspace",userData:!0},{volume:"gaia-selfhost_files",fileSuffix:"files",label:"Uploaded files",userData:!0}];function Mr(e){return`mkdir -p /tmp/restore && tar xzf /backups/${e} -C /tmp/restore && { rm -rf /data/* 2>/dev/null; rm -rf /data/.[!.]* 2>/dev/null || true; } && cp -a /tmp/restore/. /data/ && rm -rf /tmp/restore`}import*as J from"node:fs";import*as Le from"node:path";import{execa as wl}from"execa";import*as kn from"node:fs";import*as wi from"node:path";var Lm=/^\d{4}-\d{2}-\d{2}(T\d{2}-\d{2}-\d{2}Z)?$/,Mm=".partial",Ma={prefix:"mongo-",suffix:".gz"},Na={prefix:"postgres-",suffix:".sql"},Fa={prefix:"api-env-",suffix:".env"},Ba=".tar.gz",Nm=[Ma,Na,Fa,...kt.map(e=>({prefix:`${e.fileSuffix}-`,suffix:Ba}))];function bi(e=new Date){return`${e.toISOString().slice(0,19).replaceAll(":","-")}Z`}function Zt(e,t){let r=n=>wi.join(e,`${n.prefix}${t}${n.suffix}`);return{mongoFile:r(Ma),postgresFile:r(Na),apiEnvFile:r(Fa),volumeFiles:kt.map(n=>Ei(e,t,n))}}function Ei(e,t,r){return{volume:r.volume,label:r.label,file:wi.join(e,`${r.fileSuffix}-${t}${Ba}`)}}function At(e){return`${e}${Mm}`}function Ga(e){return kn.existsSync(e)?kn.readdirSync(e).flatMap(r=>Nm.flatMap(({prefix:n,suffix:o})=>{if(!r.startsWith(n)||!r.endsWith(o))return[];let i=r.slice(n.length,r.length-o.length);return Lm.test(i)?[i]:[]})).sort().at(-1):void 0}import*as Pn from"node:fs";import*as ja from"node:os";import{execa as er}from"execa";var An="/var/run/docker.sock",Ee={selfhost:"gaia-selfhost",developer:"gaia-dev"},Fm=/\((healthy|unhealthy|health: starting)\)/;async function qa(e){return(await Pt(e)).map(r=>({name:r.service,status:r.state==="running"?"running":"stopped",health:r.health}))}async function Ha(e){let{stdout:t}=await er("docker",["ps","--filter",`label=com.docker.compose.project=${e}`,"--format","{{.Ports}}"]),r=new Set;for(let n of t.matchAll(/:(\d+)->/g))r.add(Number(n[1]));return r}function Va(){return ja.platform()!=="linux"||!Pn.existsSync(An)?0:Pn.statSync(An).gid}async function Pt(e){let{stdout:t}=await er("docker",["ps","-a","--filter",`label=com.docker.compose.project=${e}`,"--format",'{{.Label "com.docker.compose.service"}}|{{.State}}|{{.Status}}']);return Bm(t)}function Bm(e){let t=[];for(let r of e.trim().split(`
|
|
6
|
+
`)){if(!r)continue;let[n,o,i]=r.split("|");if(!n||!o)continue;let s=i?.match(Fm)?.[1];t.push(s?{service:n,state:o,health:s}:{service:n,state:o})}return t}async function Wa(){let{stdout:e}=await er("docker",["info","--format","{{.DockerRootDir}}"]),t=e.trim();if(!t)throw new Error("docker info returned an empty DockerRootDir");return t}async function Ka(e){let{stdout:t}=await er("df",["-k",e]);return t}var Ua=26;async function Gm(){let{stdout:e}=await er("docker",["version","--format","{{.Server.Version}}"]);return e.trim()}async function Ya(){let e=await Gm(),t=Number.parseInt(e,10);if(Number.isNaN(t)||t<Ua)throw new Error(`The code sandbox needs Docker Engine ${Ua} or newer (this daemon is ${e||"unknown"}): it mounts only each user's own files into their sandbox. Upgrade Docker, or run \`gaia up --no-code-sandbox\` and save an E2B key instead.`)}async function Tn(e){let{stdout:t}=await er("docker",["volume","ls","--quiet","--filter",`name=^${e}$`]);return t.trim().split(`
|
|
7
|
+
`).includes(e)}import*as Ic from"node:os";import{execa as sf}from"execa";import{spawn as Jm}from"node:child_process";import{constants as hc,promises as Qm}from"node:fs";import*as jr from"node:os";import{execa as Oi}from"execa";import*as mc from"node:fs";import*as _i from"node:path";import*as et from"fs";import*as pc from"os";import*as Ti from"path";var za={name:"@heygaia/cli",description:"CLI tool for setting up and managing GAIA",version:"0.7.0-beta.6",type:"module",files:["dist","README.md"],scripts:{"bake:logo":"node scripts/bake-logo.mjs",build:"node esbuild.config.mjs && chmod +x dist/index.js",check:"biome check src",dev:"tsx watch src/index.ts",fix:"biome check --write src",format:"biome format --write src",lint:"pnpm run check","lint:fix":"pnpm run fix",prepublishOnly:"pnpm run build",start:"NODE_ENV=production node dist/index.js","type-check":"tsc --noEmit"},dependencies:{"@inkjs/ui":"^2.0.0","@modelcontextprotocol/sdk":"^1.32.0",chalk:"^5.6.2",commander:"^14.0.3",execa:"^9.6.1",ink:"^6.8.0","ink-text-input":"^6.0.0","is-unicode-supported":"^2.1.0",react:"19.1.0","react-dom":"19.1.0",semver:"^7.8.5","simple-git":"^3.36.0","supports-hyperlinks":"^3.2.0","wrap-ansi":"^9.0.2",ws:"^8.21.0",zod:"^4.3.6"},devDependencies:{"@biomejs/biome":"^2.5.7","@gaia/shared":"workspace:*","@resvg/resvg-js":"^2.6.2","@types/node":"^24.13.3","@types/react":"^19.2.17","@types/react-dom":"^19.2.3","@types/semver":"^7.8.0","@types/ws":"^8.18.1",esbuild:"^0.25.12",tsx:"^4.23.11",typescript:"^7.0.2",vite:"^7.3.6",vitest:"^4.1.10"},bin:{gaia:"./dist/index.js"},engines:{node:">=20"},keywords:["ai-assistant","cli","gaia","setup"],license:"MIT",publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/theexperiencecompany/gaia.git",directory:"packages/cli"}};import*as q from"fs";import*as at from"path";import*as Nr from"node:fs";import*as xi from"node:path";var Xa=[{name:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"MONGO_DB",required:!0,category:"MongoDB Connection",description:"MongoDB database connection",affectedFeatures:"All database operations, user data, and application state",docsUrl:"https://www.mongodb.com/docs/manual/reference/connection-string/"}]},{name:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",requiredInProd:!0,allRequired:!0,docsUrl:"https://redis.io/docs/connect/clients/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"REDIS_URL",required:!0,category:"Redis Connection",description:"Redis cache and queue service",affectedFeatures:"Caching, rate limiting, and task scheduling",docsUrl:"https://redis.io/docs/connect/clients/"}]},{name:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"POSTGRES_URL",required:!1,category:"PostgreSQL Connection",description:"PostgreSQL database connection",affectedFeatures:"Relational data storage and queries",docsUrl:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING"}]},{name:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.trychroma.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"CHROMADB_HOST",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"},{name:"CHROMADB_PORT",required:!1,category:"ChromaDB Connection",description:"ChromaDB vector database connection",affectedFeatures:"Vector storage and semantic search capabilities",docsUrl:"https://docs.trychroma.com/"}]},{name:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.rabbitmq.com/uri-spec.html",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RABBITMQ_URL",required:!1,category:"RabbitMQ Connection",description:"RabbitMQ message queue connection",affectedFeatures:"Asynchronous task processing and job queue",docsUrl:"https://www.rabbitmq.com/uri-spec.html"}]},{name:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",requiredInProd:!0,allRequired:!0,docsUrl:"https://workos.com/docs/reference/api-keys",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"WORKOS_API_KEY",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_CLIENT_ID",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"},{name:"WORKOS_COOKIE_PASSWORD",required:!1,category:"WorkOS Authentication",description:"WorkOS authentication service",affectedFeatures:"User authentication, login, and session management",docsUrl:"https://workos.com/docs/reference/api-keys"}]},{name:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",requiredInProd:!0,allRequired:!0,docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"CLOUDINARY_CLOUD_NAME",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_KEY",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"},{name:"CLOUDINARY_API_SECRET",required:!1,category:"Cloudinary Media Storage",description:"Cloudinary media storage service",affectedFeatures:"File uploads, image storage, and support ticket attachments when BLOB_STORE is cloudinary (hosted, or a self-host that chose it)",docsUrl:"https://cloudinary.com/documentation/cloudinary_credentials"}]},{name:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SHARE_GRANT_SECRET",required:!1,category:"File Sharing",description:"HMAC signing secret for single-purpose file-share grants",affectedFeatures:"File attachments fetched by Composio during tool execution",docsUrl:null}]},{name:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",requiredInProd:!0,allRequired:!1,docsUrl:"https://deepgram.com/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"DEEPGRAM_API_KEY",required:!1,category:"Speech Processing",description:"Speech-to-text transcription service",affectedFeatures:"Audio transcription and voice interaction",docsUrl:"https://deepgram.com/"}]},{name:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://platform.openai.com/api-keys",alternativeGroup:"Google AI",selfhostSetup:!0,variables:[{name:"OPENAI_API_KEY",required:!1,category:"OpenAI Integration",description:"OpenAI API integration (alternative to Google AI)",affectedFeatures:"AI chat, text generation, and language processing",docsUrl:"https://platform.openai.com/api-keys"}]},{name:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",requiredInProd:!0,allRequired:!0,docsUrl:"https://console.cloud.google.com/apis/credentials",alternativeGroup:"OpenAI Integration",selfhostSetup:!0,variables:[{name:"GOOGLE_API_KEY",required:!1,category:"Google AI",description:"Google AI services (alternative to OpenAI)",affectedFeatures:"Google AI and ML capabilities",docsUrl:"https://console.cloud.google.com/apis/credentials"}]},{name:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",requiredInProd:!0,allRequired:!0,docsUrl:"https://tavily.com/#api",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"TAVILY_API_KEY",required:!1,category:"Tavily Web Search",description:"Tavily AI-powered web search integration",affectedFeatures:"Web search capabilities, image search, news search, and content extraction",docsUrl:"https://tavily.com/#api"}]},{name:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",requiredInProd:!0,allRequired:!0,docsUrl:"https://www.firecrawl.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"FIRECRAWL_API_KEY",required:!1,category:"Firecrawl Web Scraping",description:"Firecrawl web scraping and content extraction service",affectedFeatures:"Advanced web content extraction, URL processing, and page scraping",docsUrl:"https://www.firecrawl.dev/"}]},{name:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.llamaindex.ai/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"LLAMA_INDEX_KEY",required:!1,category:"Llama Index",description:"Llama Index for document processing and retrieval",affectedFeatures:"Advanced document indexing, RAG capabilities, and structured data retrieval",docsUrl:"https://docs.llamaindex.ai/"}]},{name:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",requiredInProd:!0,allRequired:!0,docsUrl:"https://resend.com/docs/api-reference/api-keys",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"RESEND_API_KEY",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"RESEND_AUDIENCE_ID",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"},{name:"EMAIL_UNSUBSCRIBE_SECRET",required:!1,category:"Resend Email Service",description:"Resend email delivery service",affectedFeatures:"Email notifications and communication",docsUrl:"https://resend.com/docs/api-reference/api-keys"}]},{name:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",requiredInProd:!0,allRequired:!0,docsUrl:"https://openweathermap.org/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"OPENWEATHER_API_KEY",required:!1,category:"Weather Service",description:"OpenWeather API for weather data",affectedFeatures:"Weather forecasts and current conditions",docsUrl:"https://openweathermap.org/api"}]},{name:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.composio.dev/",alternativeGroup:null,selfhostSetup:!0,variables:[{name:"COMPOSIO_KEY",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"},{name:"COMPOSIO_WEBHOOK_SECRET",required:!1,category:"Composio Integration",description:"Composio integration service",affectedFeatures:"Composio platform integration and webhook processing",docsUrl:"https://docs.composio.dev/"}]},{name:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",requiredInProd:!0,allRequired:!0,docsUrl:"https://e2b.dev/docs",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"E2B_API_KEY",required:!1,category:"E2B Code Execution",description:"E2B secure code execution environment",affectedFeatures:"Code execution and sandboxed environments",docsUrl:"https://e2b.dev/docs"}]},{name:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",requiredInProd:!1,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BROWSER_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_HOST_KEY",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null},{name:"BROWSER_FALLBACK_HOST_URL",required:!1,category:"Browser Host",description:"gaia-browser-host: the BROWSER_ENGINE host + the Chromium host",affectedFeatures:"Autonomous browser automation (the browser_task tool)",docsUrl:null}]},{name:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.dodopayments.com/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"DODO_PAYMENTS_API_KEY",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"},{name:"DODO_WEBHOOK_PAYMENTS_SECRET",required:!1,category:"Dodo Payments",description:"Dodo payment processing service",affectedFeatures:"Payment processing and subscription management",docsUrl:"https://docs.dodopayments.com/"}]},{name:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",requiredInProd:!0,allRequired:!0,docsUrl:null,alternativeGroup:null,selfhostSetup:!1,variables:[{name:"BLOG_BEARER_TOKEN",required:!1,category:"Blog Management",description:"Blog content management",affectedFeatures:"Blog creation and management",docsUrl:null}]},{name:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",requiredInProd:!0,allRequired:!0,docsUrl:"https://docs.sentry.io/platforms/python/",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"SENTRY_DSN",required:!1,category:"Sentry Monitoring",description:"Sentry error tracking and monitoring",affectedFeatures:"Error reporting and application monitoring",docsUrl:"https://docs.sentry.io/platforms/python/"}]},{name:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",requiredInProd:!1,allRequired:!0,docsUrl:"https://posthog.com/docs/api",alternativeGroup:null,selfhostSetup:!1,variables:[{name:"POSTHOG_PROJECT_TOKEN",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"},{name:"POSTHOG_HOST",required:!1,category:"Posthog Analytics",description:"Posthog analytics and event tracking",affectedFeatures:"User behavior analytics and event tracking",docsUrl:"https://posthog.com/docs/api"}]}];var Ii={selfhost:{MONGO_DB:"mongodb://mongo:27017/gaia",REDIS_URL:"redis://redis:6379",POSTGRES_URL:"postgresql://postgres:postgres@postgres:5432/langgraph",CHROMADB_HOST:"chromadb",CHROMADB_PORT:"8000",RABBITMQ_URL:"amqp://guest:guest@rabbitmq:5672/"},developer:{MONGO_DB:"mongodb://localhost:27017/gaia",REDIS_URL:"redis://localhost:6379",POSTGRES_URL:"postgresql://postgres:postgres@localhost:5432/postgres",CHROMADB_HOST:"localhost",CHROMADB_PORT:"8080",RABBITMQ_URL:"amqp://guest:guest@localhost:5672/"}},Ja={selfhost:{HOST:"http://localhost:3000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://gaia-backend:8000"},developer:{HOST:"http://localhost:8000",FRONTEND_URL:"http://localhost:3000",GAIA_BACKEND_URL:"http://host.docker.internal:8000"}};function Fr(e,t){return Ii[t][e]??Ja[t][e]}function _n(){return structuredClone(Xa)}function Qa(e){let t=xi.join(e,"apps","web",".env.local"),r=Nr.existsSync(t)?t:xi.join(e,"apps","web",".env");if(!Nr.existsSync(r))return[];let n=Nr.readFileSync(r,"utf-8"),o=[],i="General";for(let s of n.split(`
|
|
8
|
+
`)){let a=s.trim();if(a.startsWith("#")&&!a.startsWith("#=")){let p=a.replace(/^#+\s*/,"").trim();p&&!p.startsWith("These are")&&(i=p);continue}if(!a||a.startsWith("#"))continue;let c=a.indexOf("=");if(c===-1)continue;let l=a.substring(0,c).trim(),d=a.substring(c+1).trim();o.push({name:l,value:d,category:i})}return o}function Za(e,t){return{NEXT_PUBLIC_API_BASE_URL:`http://localhost:${t?.[8e3]??8e3}/api/v1/`}}function ec(e,t,r){let n=r==="selfhost"?new Set(Object.keys(Ii.selfhost)):new Set;for(let[o,i]of Object.entries(t)){let s=Number(o),a=Number(i);for(let[c,l]of Object.entries(e)){if(n.has(c))continue;if(l===String(s)){e[c]=String(a);continue}let d=new RegExp(`:${s}(?=[/\\s]|$)`,"g");e[c]=l.replaceAll(d,`:${a}`)}}}function tc(e,t){return e.map(r=>({...r,variables:r.variables.map(n=>{let o=Fr(n.name,t);return{...n,defaultValue:o||n.defaultValue}})}))}function Br(){return Object.keys(Ii.selfhost)}function rc(e){return{...Ja[e]}}var Hm=[".test",".example",".invalid",".localhost",".local",".internal",".home.arpa"],nc="docker cp gaia-selfhost-proxy-1:/data/caddy/pki/authorities/local/root.crt gaia-root.crt";function Dn(e){let t=e.toLowerCase();return Hm.some(r=>t.endsWith(r))}function Tt(e){let t={};if(!e)return t;for(let r of e.split(`
|
|
9
|
+
`)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<=0)continue;let i=n.substring(0,o).trim(),s=n.substring(o+1).trim().replace(/^["']|["']$/g,"");i&&s&&(t[i]=s)}return t}var Ri=384;function On(e){if(q.existsSync(e)){let t=`${e}.bak`;q.copyFileSync(e,t),q.chmodSync(t,Ri)}}function $n(e,t){q.mkdirSync(at.dirname(e),{recursive:!0}),q.writeFileSync(e,t,{encoding:"utf-8",mode:Ri}),q.chmodSync(e,Ri)}function Ln(e,t){On(t),$n(t,q.readFileSync(e,"utf-8"))}function Gr(e,t){let r=at.join(e,".env");On(r);let n=["# GAIA Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],o=["MONGO","REDIS","POSTGRES","CHROMADB","RABBITMQ","WORKOS","GOOGLE","OPENAI","INFISICAL","LANGSMITH","DISCORD","SLACK","TELEGRAM","CLOUDINARY","COMPOSIO","FIRECRAWL","LIVEKIT","DEEPGRAM","ELEVENLABS","RESEND","SENTRY","POSTHOG","E2B","DODO","NEXT_PUBLIC","GAIA"];function i(a){for(let l of o)if(a===l||a.startsWith(`${l}_`))return l;let c=a.split("_");return c.length===1?"Core":c[0]||"Core"}let s=new Map;for(let[a,c]of Object.entries(t)){let l=i(a);s.has(l)||s.set(l,[]);let p=/[\s#"'\\]/.test(c)||c===""?`"${c.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`:c;s.get(l).push(`${a}=${p}`)}for(let[a,c]of s.entries())n.push(`# ${a} Configuration`),n.push(...c),n.push("");$n(r,n.join(`
|
|
10
|
+
`))}function sc(e,t,r){let n=at.join(e,"apps","web",".env.local");On(n);let o=Qa(e),i=Za(t,r),s=["# GAIA Web App Environment Configuration","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""],a=new Map;for(let c of o){a.has(c.category)||a.set(c.category,[]);let l=i[c.name]??c.value;a.get(c.category).push({name:c.name,value:l})}if(o.length===0){s.push("# Core URLs");for(let[c,l]of Object.entries(i))s.push(`${c}=${l}`);s.push("")}else for(let[c,l]of a.entries()){s.push(`# ${c}`);for(let{name:d,value:p}of l)s.push(`${d}=${p}`);s.push("")}$n(n,s.join(`
|
|
11
|
+
`))}var Ci={8e3:"API_HOST_PORT",5432:"POSTGRES_HOST_PORT",6379:"REDIS_HOST_PORT",27017:"MONGO_HOST_PORT",5672:"RABBITMQ_HOST_PORT",15672:"RABBITMQ_MGMT_PORT",8080:"CHROMADB_HOST_PORT",8083:"MONGO_EXPRESS_HOST_PORT",3e3:"WEB_HOST_PORT",3443:"HTTPS_HOST_PORT"},oc=Object.fromEntries(Object.entries(Ci).map(([e,t])=>[t,Number(e)])),Vm="proxy";function ac(e){return at.join(e,"infra","docker",".env")}function Mn(e){let t=ac(e);return q.existsSync(t)?Tt(q.readFileSync(t,"utf-8")):{}}var _t="GAIA_VERSION",Wm="latest",cc="GAIA_DOMAIN",ic="GAIA_CADDY_GLOBAL_OPTIONS",Km="local_certs";function Nn(e){return Mn(e)[cc]||void 0}function Ue(e){return Mn(e)[_t]??Wm}function lc(e,t){let r=ac(e);On(r);let n=["# Docker Compose environment overrides","# Generated by GAIA CLI",`# Created: ${new Date().toISOString()}`,""];for(let[o,i]of Object.entries(t))n.push(`${o}=${i}`);n.push(""),$n(r,n.join(`
|
|
12
|
+
`))}function uc(e,t,r){lc(e,{...Mn(e),[t]:r})}function ki(e,t,r,n){let{NEXT_PUBLIC_APP_URL:o,...i}=Mn(e);for(let[s,a]of Object.entries(t)){let c=Number(s),l=Ci[c];l&&(i[l]=String(a))}r==="selfhost"&&n&&(i.COMPOSE_PROFILES??=Vm,i.DOCKER_SOCKET_GID=String(n.dockerSocketGid),n.domain&&(i[cc]=n.domain,Dn(n.domain)?i[ic]=Km:delete i[ic])),lc(e,i)}function ct(e){let t={};for(let[r,n]of Object.entries(e)){let o=Number(r),i=Ci[o];i&&(t[i]=String(n))}return t}function dc(e){let t=at.join(e,"infra","docker","docker-compose.yml");if(!q.existsSync(t))return;let r=q.readFileSync(t,"utf-8"),n=[{varName:"API_HOST_PORT",hostPort:8e3,containerPort:80},{varName:"CHROMADB_HOST_PORT",hostPort:8080,containerPort:8e3},{varName:"POSTGRES_HOST_PORT",hostPort:5432,containerPort:5432},{varName:"REDIS_HOST_PORT",hostPort:6379,containerPort:6379},{varName:"MONGO_HOST_PORT",hostPort:27017,containerPort:27017},{varName:"RABBITMQ_HOST_PORT",hostPort:5672,containerPort:5672},{varName:"MONGO_EXPRESS_HOST_PORT",hostPort:8083,containerPort:8081},{varName:"WEB_HOST_PORT",hostPort:3e3,containerPort:3e3}],o=!1;for(let{varName:i,hostPort:s,containerPort:a}of n){let c=`"${s}:${a}"`,l=`"\${${i}:-${s}}:${a}"`;r.includes(c)&&(r=r.replaceAll(c,l),o=!0)}{let i='"15672:15672"';r.includes(i)&&(r=r.replaceAll(i,'"${RABBITMQ_MGMT_PORT:-15672}:15672"'),o=!0)}o&&q.writeFileSync(t,r,"utf-8")}function k(e){let t=at.join(e,"infra","docker",".env"),r={};if(!q.existsSync(t))return r;let n=q.readFileSync(t,"utf-8");for(let o of n.split(`
|
|
13
|
+
`)){let i=o.trim();if(i&&!i.startsWith("#")){let[s,...a]=i.split("=");if(s&&oc[s]){let c=a.join("=").trim().replace(/^["']|["']$/g,""),l=Number(c);!Number.isNaN(l)&&l>0&&l<=65535&&(r[oc[s]]=l)}}}return r}var A=za.version;function Ai(e,t){return e[_t]||`v${t}`}var je=Ai(process.env,A);var xe=Ti.join(pc.homedir(),".gaia"),Pi=Ti.join(xe,"config.json");function zm(){et.existsSync(xe)||et.mkdirSync(xe,{recursive:!0})}function P(){try{if(!et.existsSync(Pi))return null;let e=et.readFileSync(Pi,"utf-8");return JSON.parse(e)}catch{return null}}function Fn(e){zm(),et.writeFileSync(Pi,`${JSON.stringify(e,null,2)}
|
|
14
|
+
`)}function we(e){let r={...P()??{version:A,setupComplete:!1,setupMethod:"manual",repoPath:"",createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()},...e,updatedAt:new Date().toISOString()};Fn(r)}var Ur=_i.join(xe,"logs");function qe(e,t=new Date){mc.mkdirSync(Ur,{recursive:!0});let r=t.toISOString().slice(0,19).replaceAll(":","-");return _i.join(Ur,`${e}-${r}.log`)}function Bn(e){let t="";return r=>{let n=(t+r).split(/\r?\n|\r/);t=n.pop()??"";for(let o of n)o.trim()&&e(o)}}import*as fc from"node:fs";import{execa as Di}from"execa";function gc(){return typeof process.getuid=="function"&&process.getuid()===0}async function Xm(){gc()||!(await Di("sudo",["-n","true"],{reject:!1})).failed||await Di("sudo",["-v","-p","[sudo] password for %u: "],{stdio:"inherit"})}async function H(e,t,r,n){await Xm();let[o,i]=gc()?[e,[...t]]:["sudo",["-n",e,...t]],s=fc.createWriteStream(r,{flags:"a"}),a=Bn(d=>n?.(d)),c=Di(o,i,{all:!0,reject:!1});c.all?.on("data",d=>{s.write(d),a(d.toString())});let l=await c;if(await new Promise(d=>s.end(d)),l.failed)throw new Error(`'${[e,...t].join(" ")}' failed (exit ${l.exitCode??"unknown"}). Its output is in ${r}`)}var se="docker",$i="GAIA_DOCKER_GROUP_RELAUNCHED",Sc="GAIA_RESUMED_STEP",vc="GAIA_RESUMED_STEPS";function Gn(){return process.env[Sc]||void 0}function Un(){let e=process.env[vc];return e?JSON.parse(e):{}}async function jn(){let{stdout:e}=await Oi("id",["-nG",jr.userInfo().username]);return e.split(/\s+/).includes(se)}function yc(e){let t=e.stderr;return typeof t=="string"&&t.toLowerCase().includes("permission denied")}async function wc(){if(process.env[$i]==="1")throw new Error(`Still no access to the Docker socket after joining the '${se}' group.
|
|
15
|
+
Check the socket's group with 'ls -l /var/run/docker.sock', then log out and back in and rerun.`);if(await jn())return;let e=jr.userInfo().username;try{await H("usermod",["-aG",se,e],qe("docker-group"))}catch(t){throw new Error(`Could not add ${e} to the '${se}' group: ${t.message}
|
|
16
|
+
Run 'sudo usermod -aG ${se} ${e}', log out and back in, then rerun.`)}}var Zm=/^[A-Za-z_][A-Za-z0-9_]*$/;async function ef(e){try{return await Oi("sh",["-c",'command -v "$1"',"sh",e]),!0}catch{return!1}}async function tf(){try{return await Oi("sudo",["-l","-g",se,"--",process.execPath]),!0}catch{return!1}}async function bc(){return await ef("sg")?"sg":await tf()?"sudo":null}async function Ec(){let e=await bc();if(e)return e;throw new Error(`Docker access was granted, but this login session predates it and cannot pick it up ('sg' is missing and sudo cannot switch to the '${se}' group).
|
|
17
|
+
Log out and back in (or run 'newgrp ${se}'), then rerun this command.`)}function rf(e){return`'${e.replaceAll("'","'\\''")}'`}function nf(e,t,r){return e==="sg"?["sg",[se,"-c",t.map(rf).join(" ")]]:["sudo",[`--preserve-env=${Object.keys(r).filter(o=>Zm.test(o)).join(",")}`,"-g",se,"--",...t]]}function qn(e,t){let r={...process.env,[$i]:"1",...t&&{[Sc]:t.step,[vc]:JSON.stringify(t.steps)}},[n,o]=nf(e,[process.execPath,...process.argv.slice(1)],r),i=Jm(n,o,{stdio:"inherit",env:r});return new Promise((s,a)=>{i.on("error",a),i.on("exit",(c,l)=>{process.exit(c??(l?1:0))})})}async function of(){try{return await Qm.access(An,hc.R_OK|hc.W_OK),!1}catch(e){let t=e.code;if(t==="ENOENT")return!1;if(t==="EACCES")return!0;throw e}}async function xc(){if(jr.platform()!=="linux"||process.env[$i]==="1"||process.env.DOCKER_HOST||!await of()||!await jn())return;let e=await bc();e&&await qn(e)}var af=5e3,cf="https://orbstack.dev",Li="Run 'gaia up': it installs everything GAIA needs.";async function ee(){try{return await sf("docker",["info"],{timeout:af}),"ready"}catch(e){return e.code==="ENOENT"?"not-installed":yc(e)?"no-permission":"not-running"}}async function tt(e){let t=Ic.platform()==="darwin";switch(e){case"not-installed":return{summary:"Docker isn't installed",state:"isn't installed",fix:t?`Install OrbStack (${cf}) or Docker Desktop, open it, then try again.`:Li};case"not-running":return{summary:"Docker isn't running",state:"isn't running",fix:t?"Open OrbStack or Docker Desktop, then try again.":"Start it with 'sudo systemctl start docker', then try again."};case"no-permission":return{summary:"Docker is running, but your user can't use it yet",state:"is running, but your user can't use it yet",fix:await jn()?`Your user just joined the '${se}' group. Log out and back in (or run 'newgrp ${se}' in this terminal), then try again.`:`Run 'sudo usermod -aG ${se} $USER', log out and back in, then try again.`}}}async function Dt(e){let t=await tt(e);return new Error(`${t.summary}.
|
|
18
|
+
${t.fix}`)}import{execa as Ig}from"execa";import*as Ce from"fs";import*as le from"path";import*as tr from"node:fs";import*as qr from"node:path";import*as Cc from"node:crypto";var Rc=["AGENT_SECRET","BOT_SESSION_TOKEN_SECRET","EMAIL_UNSUBSCRIBE_SECRET","SHARE_GRANT_SECRET","GAIA_BOT_API_KEY"],lf=["INSTANCE_SECRET"];function Mi(){return Cc.randomBytes(32).toString("hex")}function uf(e){return new Set(Object.keys(Tt(e)))}function Hn(e){let t=uf(e),r={},n=e===null?[...Rc,...lf]:Rc;for(let o of n)t.has(o)||(r[o]=Mi());return r}var kc=["telegram","discord","slack"],Ac={telegram:["TELEGRAM_BOT_TOKEN"],discord:["DISCORD_BOT_TOKEN","DISCORD_CLIENT_ID"],slack:["SLACK_BOT_TOKEN","SLACK_APP_TOKEN","SLACK_SIGNING_SECRET"]},Bi={telegram:"TELEGRAM_BOT_USERNAME",discord:"DISCORD_CLIENT_ID",slack:"SLACK_WORKSPACE_URL"},df={GAIA_BOT_API_KEY:"GAIA_BOT_API_KEY",GAIA_FRONTEND_URL:"FRONTEND_URL",RABBITMQ_URL:"RABBITMQ_URL"},pf="BOT_LOG_HASH_SECRET";function Ie(e){return`bot-${e}`}function Hr(e,t){let r=t.find(i=>i.service===Ie(e));if(!r)return{health:"failing",detail:"not created"};let n=[r.state,r.health].filter(Boolean).join(", ");return r.state!=="running"||r.health==="unhealthy"?{health:"failing",detail:n}:{health:r.health===void 0||r.health==="healthy"?"healthy":"starting",detail:n}}function Pc(e){return`docker-compose.${Ie(e)}.yml`}function Ni(e){return qr.join(e,"apps","api")}function mf(e){return qr.join(e,"apps","bots")}function Fi(e){let t=qr.join(e,".env");return tr.existsSync(t)?Tt(tr.readFileSync(t,"utf-8")):{}}function Tc(e,t){let r={...e,...t.set};for(let n of t.unset??[])delete r[n];return r}function Vn(e,t){let r=Ni(e),n=Fi(r),o=Tc(n,t);JSON.stringify(o)!==JSON.stringify(n)&&Gr(r,o)}function Vr(e,t={}){let r=qr.join(Ni(e),".env");if(!tr.existsSync(r))throw new Error(`${r} does not exist; run 'gaia up' to configure the install first.`);let n=Hn(tr.readFileSync(r,"utf-8"));Object.keys(n).length>0&&Vn(e,{set:n});let o=Fi(Ni(e)),i={};for(let[c,l]of Object.entries(df)){let d=o[l];if(!d)throw new Error(`${l} is not set in apps/api/.env; run 'gaia up' to configure the install first.`);i[c]=d}let s=mf(e),a=Tc(Fi(s),t);a[pf]??=Mi(),Gr(s,{...a,...i})}var ff={proxy:"proxy","gaia-web":"web app","gaia-backend":"server",arq_worker:"background jobs",mongo:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB","bot-telegram":"Telegram bot","bot-discord":"Discord bot","bot-slack":"Slack bot"},gf={mongodb:"MongoDB",postgres:"PostgreSQL",redis:"Redis",rabbitmq:"RabbitMQ",chromadb:"ChromaDB"};function $e(e){return ff[e]??e}function Wn(e){return gf[e]??e}import*as _c from"node:os";function F(e,t=_c.homedir()){return e===t?"~":e.startsWith(`${t}/`)?`~${e.slice(t.length)}`:e}import{execa as If}from"execa";import{execa as Sf}from"execa";import Kn from"fs";import vf from"simple-git";var hf={KiB:1024,MiB:1048576,GiB:1073741824};function Re(e){return e>=1e9?`${(e/1e9).toFixed(1)} GB`:`${Math.round(e/1e6)} MB`}function Ot(e,t,r){let[n,o,i]=t>=1e9?[1e9,"GB",1]:t>=1e6?[1e6,"MB",0]:[1e3,"KB",0],s=a=>(a/n).toFixed(i);return`${s(e)} / ${r?"~":""}${s(t)} ${o}`}function Dc(e){let t=/^([\d.]+)\s*(KiB|MiB|GiB)$/.exec(e.trim());return!t?.[1]||!t[2]?null:Number(t[1])*hf[t[2]]}var Gi=.85,yf=/Receiving objects:\s+(\d+)%[^,\r\n]*(?:,\s*([\d.]+\s*[KMG]iB))?/g,wf=/Resolving deltas:\s+(\d+)%/g,bf=/remote: (?:Enumerating|Counting|Compressing) objects:/;function Ef(e){let t=[...e.matchAll(wf)].at(-1);if(t?.[1]){let n=Number(t[1]);return{percent:Math.floor(Gi*100+n*(1-Gi)),label:"Unpacking the files"}}let r=[...e.matchAll(yf)].at(-1);if(r?.[1]){let n=Number(r[1]),o=r[2]?Dc(r[2]):null;return{percent:Math.floor(n*Gi),label:o===null?"Downloading":`${Re(o)} so far`}}return bf.test(e)?{percent:0,label:"GitHub is preparing the download"}:null}async function Yn(e,t,r,n){if(Kn.existsSync(e)){let o=`${e}/.git`;if(!Kn.existsSync(o))throw new Error(`Directory ${e} exists but is not a git repository`);await vf().cwd(e).pull(),r(100,"Already exists, pulled latest")}else try{let o=["clone","--progress"];n&&o.push("--branch",n),o.push(t,e);let i=Sf("git",o);i.stderr?.on("data",s=>{let a=Ef(s.toString());a&&r(a.percent,a.label)}),await i,r(100,"Clone complete")}catch(o){throw Kn.existsSync(e)&&Kn.rmSync(e,{recursive:!0,force:!0}),o}}var $c="https://github.com/theexperiencecompany/gaia.git",Oc="https://heygaia.io/install.sh",Rf=/^\d+\.\d+\.\d+-beta\.\d+$/;function Ui(e){return Rf.test(e)?"beta":"latest"}function Wr(e){return e==="beta"?`curl -fsSL ${Oc} | GAIA_CHANNEL=beta sh`:`curl -fsSL ${Oc} | sh`}function Lc(e){let t=Ui(e),r=[`For a newer release, update the CLI first (${Wr(t)}), then rerun 'gaia update'.`];return t==="beta"&&r.push(`This is a beta CLI. To move to the stable channel once a stable release newer than ${e} is out, install it with ${Wr("latest")} and rerun 'gaia update'.`),r}var Cf=2,kf=/^v\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;function lt(e){if(!kf.test(e))throw new Error(`${e} is not a GAIA release tag (v<major>.<minor>.<patch>, e.g. v0.7.0): only a release has compose files that match its images.`);return`cli-${e}`}async function Af(e,t,r){let n=lt(t),o=await If("git",["ls-remote","--exit-code","--tags",e,`refs/tags/${n}`],{cwd:r,reject:!1});if(o.exitCode!==0)throw o.exitCode===Cf?new Error(`GAIA ${t} has no published release: ${e} has no tag ${n}.
|
|
19
|
+
Install a released CLI (${Wr("latest")}) and rerun.`):new Error(`Could not read ${n} from ${e}: ${o.stderr.trim()}`)}function Kr(e,t){uc(e,_t,t)}async function Mc(e,t,r){await Af(t,je),await Yn(e,t,r,lt(je)),Kr(e,je)}var Pf=/ghcr\.io\/theexperiencecompany\/(gaia[\w-]*):([\w.-]+)/,Tf={gaia:"API","gaia-web":"web app"};function Fc(e){let t=Pf.exec(e);return t?.[1]&&t[2]?{name:t[1],tag:t[2]}:null}function Nc(e){let t=Tf[e];return t?`GAIA's ${t} image (${e})`:`the ${e} image`}function rr(e,t){let[r=e.image,n=""]=e.image.split(":");return e.kind==="wrong-cpu"?{cause:`${Nc(r)} at ${n} has no build for this computer's processor (${e.arch}).`,next:`Build it on this machine instead: ${t} (15-30 minutes).`}:{cause:`GAIA ${n} isn't published: ${Nc(r)} doesn't exist in the registry.`,next:`Update the CLI (${Wr(Ui(A))}) and run it again, or build from source: ${t}.`}}var _f=(e,t)=>{let r=/no matching manifest for linux\/([\w]+)/.exec(e)?.[1];if(!r)return null;let n=Fc(e);return n?rr({kind:"wrong-cpu",image:`${n.name}:${n.tag}`,arch:r},t.rebuildCommand):{cause:`One of GAIA's images has no build for this computer's processor (${r}).`,next:`Build it on this machine instead: ${t.rebuildCommand} (15-30 minutes).`}},Df=(e,t)=>{if(!/manifest unknown|: not found|failed to resolve reference|No such image/.test(e))return null;let r=Fc(e);if(r)return rr({kind:"not-published",image:`${r.name}:${r.tag}`},t.rebuildCommand);let n=/No such image: ([\w./-]+:[\w.-]+)/.exec(e)?.[1];return{cause:n?`The image ${n} was never built on this machine.`:"An image GAIA needs could not be found.",next:`Build the images here: ${t.rebuildCommand}.`}},Of=e=>{let t=/Bind for [\d.:[\]]*:(\d+) failed/.exec(e)?.[1]??/listen tcp[46]? [\d.:[\]]*:(\d+): bind: address already in use/.exec(e)?.[1];return!t&&!/port is already allocated|address already in use/.test(e)?null:{cause:`Port ${t??"GAIA needs"} is already used by another program.`,next:"Stop that program, or pick another port: gaia up --web-port <port>."}},$f=[[/permission denied while trying to connect/i,{cause:"Docker refused your user.",next:"Log out and back in (or run 'newgrp docker'), then try again."}],[/Cannot connect to the Docker daemon|Is the docker daemon running/i,{cause:"Docker stopped running.",next:"Start Docker (sudo systemctl start docker, or open OrbStack / Docker Desktop), then try again."}],[/no space left on device/i,{cause:"The disk is full.",next:"Free some space ('docker system prune' removes unused images), then try again."}],[/toomanyrequests|rate limit/i,{cause:"The image registry is limiting downloads from this network.",next:"Wait a few minutes, then try again."}],[/i\/o timeout|TLS handshake timeout|no such host|network is unreachable|connection reset by peer|dial tcp/i,{cause:"GAIA's images could not be downloaded (network error).",next:"Check this machine's internet connection, then try again."}]],Lf=e=>{let t=/container ([\w-]+?)(?:-\d+)? is unhealthy/.exec(e)?.[1];if(!t)return null;let r=t.replace(/^gaia-(selfhost|dev)-/,"");return{cause:`GAIA's ${$e(r)} didn't start.`,next:"Try: gaia doctor",service:r}};function Mf(e){return([...e].reverse().find(r=>/error|failed|denied/i.test(r))??e.at(-1)??"docker compose failed").trim()}function Bc(e,t,r){let n=[...e,...t].join(`
|
|
20
|
+
`);for(let o of[_f,Df,Of,Lf]){let i=o(n,r);if(i)return i}for(let[o,i]of $f)if(o.test(n))return i;return{cause:`Docker Compose failed: ${e.at(-1)??Mf(t)}`,next:""}}var ut=class extends Error{failure;logPath;constructor(t,r){let n=t.logTail?.length?["Its last log lines:",...t.logTail.map(o=>` ${o}`)]:[];super([t.cause,...n,`Full log: ${F(r)}`,t.next].filter(Boolean).join(`
|
|
21
|
+
`)),this.name="ComposeError",this.failure=t,this.logPath=r}};import*as Xc from"node:fs";import{execa as Jc}from"execa";import Kc from"semver";function jc(e=new Map){return{images:new Map,layers:new Map,steps:new Map,containers:new Map,started:new Set,starting:new Set,awaitingHealth:new Set,stopping:new Map,finished:[],errors:[],expectedLayers:e,downloadTotal:0}}var zn="Image ",qc="Container ",Nf=/^\[[^\]]*\d+\/\d+\]/,Ff=/^gaia-(?:selfhost|dev)-(.+)-\d+$/,Bf=new Set(["Stopping","Removing"]),Gc=new Set(["Stopped","Removed"]),Gf=2;function Hc(e){return e.slice(e.lastIndexOf("/")+1)}function Uf(e){let t=Hc(e.split("@")[0]??e),r=t.indexOf(":");return r===-1?t:t.slice(0,r)}function jf(e,t,r){let n=Math.floor(e/t*100);return`${String(n).padStart(3)}% ${Ot(e,t,r)}`}function Uc(e){let t=[...e.layers];return[...e.images].map(([r,n])=>{let o={id:r,label:Uf(r)},i=t.filter(([,c])=>c.image===r&&!c.present).map(([c,l])=>({layer:l,size:e.expectedLayers.get(c)??l.total})),s=i.reduce((c,{size:l})=>c+l,0),a=i.reduce((c,{layer:l,size:d})=>c+(l.done?d:Math.min(l.current,d)),0);if(n==="ready")return{...o,state:"done",...s>0?{note:Re(s)}:{}};if(n==="building")return{...o,state:"active",note:"building"};if(i.length>0&&i.every(({layer:c})=>c.done))return{...o,state:"active",note:"unpacking"};if(a>0&&s>0){let c=i.some(({size:l})=>l===0);return{...o,state:"active",note:jf(a,s,c)}}return{...o,state:"pending",note:"waiting"}})}function qf(e){return[...e.containers].map(([t,r])=>{let n={id:t,label:$e(t)};return e.awaitingHealth.has(t)?{...n,state:"active",note:"getting ready"}:r?{...n,state:"done"}:e.starting.has(t)?{...n,state:"active",note:"starting"}:{...n,state:"pending",note:"waiting"}})}function Hf(e){let t=e.slice(qc.length);return Ff.exec(t)?.[1]??t}function Vf(e,t){let r=(t.id??"").slice(zn.length);if(t.status==="Error"){e.errors.push(`${r}: ${t.details??t.text??"error"}`);return}e.images.get(r)!=="ready"&&(t.text==="Pulled"||t.text==="Built"?(e.finished.push(`${t.text==="Built"?"Built":"Downloaded"} ${Hc(r)}`),e.images.set(r,"ready")):e.images.set(r,t.text==="Building"?"building":"downloading"))}function Wf(e,t){let r=t.id??"",n=e.layers.get(r)??{image:(t.parent_id??"").slice(zn.length),current:0,total:0,done:!1,present:!1};t.text==="Downloading"&&t.total&&(n.total=t.total,n.current=t.current??n.current),t.text==="Already exists"&&(n.present=!0),(t.text==="Download complete"||t.text==="Pull complete"||t.text==="Already exists")&&(n.done=!0,n.current=n.total),e.layers.set(r,n)}function Kf(e,t){let r=Hf(t.id??""),n=t.text??"";if(Bf.has(n)||Gc.has(n)){e.stopping.set(r,e.stopping.get(r)===!0||Gc.has(n));return}let o=["Started","Running","Healthy"].includes(t.text??"");t.status==="Error"&&e.errors.push(`${r}: ${t.details??t.text??"error"}`),t.text==="Starting"&&e.starting.add(r),o&&e.starting.delete(r),t.text==="Waiting"&&e.awaitingHealth.add(r),t.text==="Healthy"&&e.awaitingHealth.delete(r),t.text==="Started"&&!e.started.has(r)&&(e.started.add(r),e.finished.push(`Started ${$e(r)}`)),e.containers.set(r,e.containers.get(r)===!0||o)}function Vc(e,t){t.error&&t.message&&e.errors.push(t.message);for(let n of t.vertexes??[]){let o=e.steps.get(n.digest),i=n.name??o?.name;!i||!Nf.test(i)||e.steps.set(n.digest,{name:i,done:o?.done===!0||!!n.completed})}let r=t.id??"";return r.startsWith(zn)?Vf(e,t):r.startsWith(qc)?Kf(e,t):t.parent_id?.startsWith(zn)&&Wf(e,t),e}var Yf=99;function zf(e){let t=0,r=0;for(let[n,o]of e.expectedLayers){let i=e.layers.get(n);i?.present||(r+=o,t+=i?.done?o:Math.min(i?.current??0,o))}return{downloaded:t,total:r,estimated:!1}}function Xf(e){let t=[...e.layers.values()].filter(c=>!c.present),r=t.filter(c=>c.total>0),n=r.reduce((c,l)=>c+l.current,0),o=t.filter(c=>c.total===0),i=r.reduce((c,l)=>c+l.total,0),s=r.length>0?i/r.length:0,a=Math.round(i+o.length*s);return e.downloadTotal=Math.max(e.downloadTotal,a),{downloaded:n,total:e.downloadTotal,estimated:o.length>0}}function ji(e){let t=e.slice(0,Gf).map($e),r=e.length-t.length;return r>0?`${t.join(", ")} and ${r} more`:t.join(" and ")}function Jf(e){let t=[...e].filter(([,i])=>!i).map(([i])=>i),r=e.size-t.length,n=`${r} of ${e.size} stopped`,o=Math.floor(r/e.size*100);return t.length===0?{stage:"stopping",label:`Stopping GAIA: ${n}`,percent:o}:{stage:"stopping",label:`Stopping GAIA: waiting on ${ji(t)} (${n})`,percent:o}}function Qf(e){let t=[...e.containers],r=t.filter(([,c])=>c).length,n=`${r} of ${t.length} up`,o=Math.floor(r/t.length*100),i={done:r,total:t.length,unit:"services",estimated:!1},s=t.filter(([,c])=>!c).map(([c])=>c),a=e.awaitingHealth.size>0?`waiting for ${ji([...e.awaitingHealth])} to be ready`:s.length>0?`starting ${ji(s)}`:null;return{stage:"starting",label:a?`Starting GAIA: ${a} (${n})`:`Starting GAIA: ${r} of ${t.length} services up`,detail:a??`${r} of ${t.length} services up`,percent:o,amount:i,parts:qf(e)}}function Zf(e){let t=[...e.layers.values()];return[...e.images].filter(([,n])=>n==="downloading").map(([n])=>n).every(n=>t.some(o=>o.image===n)&&t.every(o=>o.image!==n||o.done))}function Wc(e){if(e.stopping.size>0)return Jf(e.stopping);let t=[...e.steps.values()],r=t.filter(o=>o.done).length;if(t.length>0&&r<t.length)return{stage:"building",label:`Building GAIA from source: step ${r+1} of ${t.length}`,percent:Math.floor(r/t.length*100)};let n=[...e.images.values()];if(n.includes("building")&&!n.includes("downloading"))return{stage:"building",label:"Building GAIA from source: saving the images",percent:99};if(n.includes("downloading")){let o=n.filter(d=>d==="ready").length,i=e.expectedLayers.size>0?zf(e):Xf(e),s={done:i.downloaded,total:i.total,unit:"bytes",estimated:i.estimated},a=s.total>0?Math.min(Yf,Math.floor(s.done/s.total*100)):0,c=`${o} of ${n.length} ready`;return Zf(e)?{stage:"unpacking",label:`Unpacking GAIA's images: ${Re(i.downloaded)} downloaded (${c})`,detail:`Unpacking \xB7 ${o} of ${n.length} images ready`,percent:a,amount:s,parts:Uc(e)}:{stage:"downloading",label:`Downloading GAIA's images: ${s.total>0?Ot(s.done,s.total,s.estimated):"starting"} (${c})`,detail:`${o} of ${n.length} images ready`,percent:a,...s.total>0?{amount:s}:{},parts:Uc(e)}}return e.containers.size>0?Qf(e):null}var Yc="2.29.1",eg=40,zc;function tg(){return zc??=(async()=>{let{stdout:e}=await Jc("docker",["compose","version","--short"]),t=Kc.coerce(e.trim());if(!t||Kc.lt(t,Yc))throw new Error(`GAIA needs Docker Compose ${Yc} or newer; this machine has ${e.trim()||"an unknown version"}.
|
|
22
|
+
Update Docker (https://docs.docker.com/engine/install/), then try again.`)})(),zc}function rg(e){if(!e.startsWith("{"))return null;try{return JSON.parse(e)}catch{return null}}async function Xn(e,t){await tg();let r=qe(t.logName),n=Xc.createWriteStream(r),o=t.pullSize;o&&"unknown"in o&&n.write(`gaia: the download's size is an estimate: ${o.unknown}
|
|
23
|
+
`);let i=jc(o&&"layers"in o?o.layers:void 0),s=[],a=Bn(d=>{let p=rg(d);if(!p){s.push(d),s.length>eg&&s.shift();return}Vc(i,p);let m=Wc(i);m&&t.onProgress?.(m,i.finished)}),c=Jc("docker",["compose","--progress","json",...e],{cwd:t.cwd,env:t.env,all:!0,reject:!1,timeout:t.timeoutMs});c.all?.on("data",d=>{n.write(d),a(d.toString())});let l=await c;if(a(`
|
|
24
|
+
`),await new Promise(d=>n.end(d)),l.timedOut)throw new ut({cause:`Docker Compose was still running after ${Math.round((t.timeoutMs??0)/6e4)} minutes, so it was stopped.`,next:"Run it again; set GAIA_START_TIMEOUT_MIN to allow longer (0 = no limit)."},r);if(l.failed)throw new ut(Bc(i.errors,s,{rebuildCommand:t.rebuildCommand}),r);return{startedServices:i.started.size}}import{execa as ol}from"execa";import*as Zc from"node:os";var el="https://ghcr.io",tl="theexperiencecompany",rl=8e3,ng=["gaia","gaia-web"],og=["application/vnd.oci.image.index.v1+json","application/vnd.docker.distribution.manifest.list.v2+json","application/vnd.oci.image.manifest.v1+json","application/vnd.docker.distribution.manifest.v2+json"].join(",");function nr(e=Zc.arch()){return e==="x64"?"amd64":e}async function ig(e){let t=await fetch(`${el}/token?scope=repository:${tl}/${e}:pull`,{signal:AbortSignal.timeout(rl)});if(!t.ok)throw new Error(`GHCR token request answered HTTP ${t.status}`);return(await t.json()).token}async function Qc(e,t,r){return fetch(`${el}/v2/${tl}/${e}/${t}`,{headers:{Authorization:`Bearer ${r}`,Accept:og},signal:AbortSignal.timeout(rl)})}async function sg(e,t){let r=await ig(e),n=await Qc(e,`manifests/${t}`,r);if(n.status===404)return[];if(!n.ok)throw new Error(`GHCR answered HTTP ${n.status} for ${e}:${t}`);let o=await n.json();if(o.manifests)return o.manifests.map(a=>a.platform?.architecture).filter(a=>!!a&&a!=="unknown");if(!o.config)return[];let i=await Qc(e,`blobs/${o.config.digest}`,r);if(!i.ok)throw new Error(`GHCR answered HTTP ${i.status} for ${e}:${t}'s config`);let{architecture:s}=await i.json();return s?[s]:[]}async function or(e,t=[],r=nr()){let n=[...ng,...t.map(o=>`gaia-bot-${o}`)];for(let o of n){let i=await sg(o,e);if(i.length===0)return{kind:"not-published",image:`${o}:${e}`};if(!i.includes(r))return{kind:"wrong-cpu",image:`${o}:${e}`,arch:r}}return null}var il=8e3,qi="docker.io",ag="registry-1.docker.io",cg=12,lg=["application/vnd.oci.image.index.v1+json","application/vnd.docker.distribution.manifest.list.v2+json","application/vnd.oci.image.manifest.v1+json","application/vnd.docker.distribution.manifest.v2+json"].join(",");function ug(e){let[t=e,r]=e.split("@"),n=t.indexOf("/"),o=n===-1?"":t.slice(0,n),i=o.includes(".")||o.includes(":")||o==="localhost",s=i?o:qi,a=i?t.slice(n+1):t,c=a.lastIndexOf(":"),l=c===-1?"latest":a.slice(c+1);return c!==-1&&(a=a.slice(0,c)),s===qi&&!a.includes("/")&&(a=`library/${a}`),{host:s===qi?ag:s,repository:a,reference:r??l}}function dg(e){if(!e.startsWith("Bearer "))return null;let t=Object.fromEntries([...e.matchAll(/(\w+)="([^"]*)"/g)].map(n=>[n[1],n[2]]));if(!t.realm)return null;let r;try{r=new URL(t.realm)}catch(n){throw new Error(`registry token realm is not a URL: ${t.realm}`,{cause:n})}for(let n of["service","scope"])t[n]&&r.searchParams.set(n,t[n]);return r.toString()}async function sl(e,t,r){return fetch(`https://${e.host}/v2/${e.repository}/manifests/${t}`,{headers:{Accept:lg,...r?{Authorization:`Bearer ${r}`}:{}},signal:AbortSignal.timeout(il)})}async function pg(e){let t=await sl(e,e.reference,null);if(t.status!==401)return null;let r=dg(t.headers.get("www-authenticate")??"");if(!r)throw new Error(`${e.host} asked for credentials it did not name`);let n=await fetch(r,{signal:AbortSignal.timeout(il)});if(!n.ok)throw new Error(`${e.host} token request answered HTTP ${n.status}`);let o=await n.json();return o.token??o.access_token??null}async function nl(e,t,r){let n=await sl(e,t,r);if(!n.ok)throw new Error(`${e.host} answered HTTP ${n.status} for ${e.repository}@${t}`);return await n.json()}async function mg(e,t=nr()){let r=ug(e),n=await pg(r),o=await nl(r,r.reference,n);if(o.manifests){let i=o.manifests.find(s=>s.platform?.os==="linux"&&s.platform.architecture===t);if(!i)throw new Error(`${e} has no linux/${t} image`);o=await nl(r,i.digest,n)}return new Map((o.layers??[]).map(i=>[i.digest.replace(/^sha256:/,"").slice(0,cg),i.size]))}async function fg(e){let t=await Promise.all(e.map(r=>mg(r)));return new Map(t.flatMap(r=>[...r]))}async function gg(e){let t=await Promise.all(e.map(r=>ol("docker",["image","inspect",r],{reject:!1})));return e.filter((r,n)=>t[n]?.exitCode!==0)}async function Hi(e,t,r,n){try{let{stdout:o}=await ol("docker",["compose",...t,"config","--format","json"],{cwd:e,env:r}),{services:i}=JSON.parse(o),s=n.services&&new Set(n.services),a=[...new Set(Object.entries(i).filter(([l])=>!s||s.has(l)).flatMap(([,l])=>l.image?[l.image]:[]))],c=n.always?a:await gg(a);return{layers:await fg(c)}}catch(o){return{unknown:o.message}}}import*as $t from"node:fs";import*as ce from"node:fs/promises";import*as ae from"node:path";import{execa as al}from"execa";import{z as Zn}from"zod";import{createHash as hg}from"node:crypto";var Yr=class extends Error{constructor(r,n,o){super(`Download failed (${r} ${o}): ${n}`);this.status=r;this.url=n;this.name="DownloadError"}};async function ir(e,t){let r=await fetch(e);if(!r.ok||!r.body)throw new Yr(r.status,e,r.statusText);let n=Number(r.headers.get("content-length")),o=Number.isFinite(n)&&n>0?n:null,i=[],s=0;for await(let a of r.body)i.push(a),s+=a.byteLength,t?.({received:s,total:o});return Buffer.concat(i)}function Jn(e,t,r){for(let n of e.split(`
|
|
25
|
+
`)){let[o,...i]=n.trim().split(/\s+/);if(i.join(" ").replace(/^\*/,"")===t&&o!==void 0)return o.toLowerCase()}throw new Error(`${r} has no entry for ${t}.`)}function Qn(e,t,r){let n=hg("sha256").update(e).digest("hex");if(n!==t)throw new Error(`Checksum mismatch for ${r}: expected ${t}, got ${n}. Refusing to use the download.`)}var Wi="gaia-selfhost.json",Vi="GAIA_BUNDLE_BASE_URL",Sg="https://github.com/theexperiencecompany/gaia/releases/download",vg=404,yg=Zn.object({version:Zn.string(),files:Zn.array(Zn.string())});function eo(e,t){let r=[],n=Ai(e,t);n!==`v${t}`&&r.push(`Installing GAIA ${n}'s images, not v${t}'s (${_t})`);let o=e[Vi];return o&&r.push(`Setup files from ${o} (${Vi})`),r}function wg(e,t=process.env){let r=lt(e),n=`gaia-selfhost-${e.slice(1)}.tar.gz`,o=(t[Vi]??`${Sg}/${r}`).replace(/\/+$/,"");return{asset:n,bundle:`${o}/${n}`,checksum:`${o}/${n}.sha256`}}async function bg(e,t){let{asset:r,bundle:n,checksum:o}=wg(e);try{let i=(await ir(o)).toString("utf-8"),s=Jn(i,r,o),a=await ir(n,t);return Qn(a,s,r),a}catch(i){throw i instanceof Yr&&i.status===vg?new Error(`GAIA ${e} has no published setup files: ${i.url} answered 404.`):i}}function Ki(e){let t=ae.join(e,Wi);return $t.existsSync(t)?yg.parse(JSON.parse($t.readFileSync(t,"utf-8"))):null}async function Eg(e,t,r){await ce.rm(t,{recursive:!0,force:!0}),await ce.mkdir(t,{recursive:!0}),await al("tar",["-xzf","-","-C",t],{input:e});let n=Ki(t);if(!n)throw new Error(`The setup files for GAIA ${r} have no manifest.`);if(n.version!==r)throw new Error(`The setup files downloaded for GAIA ${r} are for GAIA ${n.version}, not ${r}.`);let o=n.files.filter(i=>!$t.existsSync(ae.join(t,i)));if(o.length>0)throw new Error(`The setup files for GAIA ${r} are missing ${o.join(", ")}.`);return n}async function xg(e,t){for(let r=t;r.startsWith(`${e}${ae.sep}`);r=ae.dirname(r))if($t.existsSync(r)){if((await ce.readdir(r)).length>0)return;await ce.rmdir(r)}}async function to(e,t,r,n){await ce.mkdir(r,{recursive:!0});let o=new Set(e.files);for(let i of n.filter(s=>!o.has(s))){let s=ae.join(r,i);await ce.rm(s,{recursive:!0,force:!0}),await xg(r,ae.dirname(s))}for(let i of e.files){let s=ae.join(r,i);await ce.mkdir(ae.dirname(s),{recursive:!0}),await ce.rename(ae.join(t,i),s)}await ce.rm(t,{recursive:!0,force:!0})}async function ro(e,t,r){let n=await bg(t,r),o=ae.join(e,".gaia-selfhost-staging");return{manifest:await Eg(n,o,t),stagingDir:o}}async function cl(e){if(!$t.existsSync(ae.join(e,".git")))throw new Error(`${e} holds GAIA's source without its git history, so 'gaia update' can't tell its files from yours.
|
|
26
|
+
Install the release with 'gaia up' in a new directory and copy apps/api/.env into it, or update this one from source.`);let t=s=>al("git",s,{cwd:e,reject:!1}),r=await t(["symbolic-ref","-q","--short","HEAD"]);if(r.exitCode===void 0)throw new Error(`${e} is a git checkout, and moving it to release files needs git to tell its files from yours. Install git and run 'gaia update' again.`);if(r.exitCode===0)throw new Error(`${e} is a source checkout on the branch ${r.stdout.trim()}, and 'gaia update' would replace it with release files.
|
|
27
27
|
Update it from source with 'gaia update --git'.`);let o=(await t(["status","--porcelain","--untracked-files=no"])).stdout.split(`
|
|
28
28
|
`).filter(s=>s.trim());if(o.length>0)throw new Error(`Local changes to these files would be lost when ${e} moves to release files:
|
|
29
29
|
${o.join(`
|
|
30
30
|
`)}
|
|
31
|
-
Commit or discard them, or keep updating from source with 'gaia update --git'.`);let i=await t(["ls-files","-z"]);if(i.exitCode!==0)throw new Error(`Could not list the files of ${e}: ${i.stderr.trim()}`);return[...i.stdout.split("\0").filter(Boolean),".git"]}var
|
|
32
|
-
`).filter(i=>i.trim());return new
|
|
31
|
+
Commit or discard them, or keep updating from source with 'gaia update --git'.`);let i=await t(["ls-files","-z"]);if(i.exitCode!==0)throw new Error(`Could not list the files of ${e}: ${i.stderr.trim()}`);return[...i.stdout.split("\0").filter(Boolean),".git"]}var Rg=e=>new Promise(t=>setTimeout(t,e)),dl="dev-start.log",oo=".gaia-dev.pid",pl="gaia start --build";function Cg(e){return e?.remove?["down","--rmi","all","--remove-orphans",...e.remove.volumes?["--volumes"]:[]]:["down"]}function io(e){let t=le.join(e,".env");return Ce.existsSync(t)?["--env-file",".env"]:[]}var kg=60;function Ag(){let e=process.env.GAIA_START_TIMEOUT_MIN?.trim(),t=e?Number(e):Number.NaN,r=Number.isFinite(t)&&t>=0?t:kg;return r===0?void 0:r*60*1e3}function ar(e={}){let t=P(),r=["docker-compose.selfhost.yml"];return e.build&&r.push("docker-compose.build.yml"),t?.codeSandbox===!0&&r.push("docker-compose.sandbox.yml"),r.push(...(t?.bots??[]).map(Pc)),r}function dt(e){return e.flatMap(t=>["-f",t])}var ml="gaia-sandbox-workspace",ll="/legacy-sandbox-workspace";function Pg(e,t){return["compose",...dt(e),...t,"run","--rm","--no-deps","-v",`${ml}:${ll}:ro`,"gaia-backend","python","-m","app.scripts.migrate_legacy_sandbox_workspace","--legacy-root",ll]}function Tg(e,t,r){let n=[...dt(e),...t,"up","-d","--remove-orphans"];return n.push(r?.build?"--build":"--no-build"),r?.pull&&n.push("--pull",r.pull),n}function Yi(e){let t=le.join(e,oo);if(!Ce.existsSync(t))return null;try{let r=Number.parseInt(Ce.readFileSync(t,"utf-8").trim(),10);return Number.isNaN(r)||r<=0?null:r}catch{return null}}function no(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}async function ue(e,t,r,n,o,i){if(t!=="selfhost")throw r?.("Developer mode must run in foreground."),new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'.");r?.(i?.build?"Building GAIA from source\u2026":"Starting GAIA\u2026");let s=le.join(e,"infra/docker"),a=n&&Object.keys(n).length>0?ct(n):void 0,c=P();c?.codeSandbox===!0&&await Ya(),c?.bots?.length&&Vr(e);let l=ar({build:i?.build});i?.build&&Xi(e);let d=io(s),p=[...dt(l),...d],m=i?.build?void 0:await Hi(s,p,a,{always:i?.pull==="always"}),g=await Xn(Tg(l,d,i),{cwd:s,env:a,timeoutMs:Ag(),logName:i?.build?"compose-build":"compose-up",rebuildCommand:i?.rebuildCommand??pl,onProgress:o,pullSize:m}).catch(async v=>{throw await Dg(v,p,s)});return await Tn(ml)&&(r?.("Moving code-sandbox files into per-user workspaces\u2026"),await de("docker",Pg(l,d),s,void 0,void 0,a)),r?.("GAIA's services are running."),g}var _g=8;async function Dg(e,t,r){if(!(e instanceof ut)||!e.failure.service)return e;let{stdout:n}=await Ig("docker",["compose",...t,"logs","--no-color","--no-log-prefix","--tail",String(_g),e.failure.service],{cwd:r}),o=n.split(`
|
|
32
|
+
`).filter(i=>i.trim());return new ut({...e.failure,logTail:o},e.logPath)}function zi(e){return["compose",...dt(ar()),...io(e)]}async function fl(e,t,r,n){let o=le.join(e,"infra/docker");await de("docker",[...zi(o),"run","--rm","--no-deps",t,...r],o,void 0,n)}var Og=["gaia-backend","arq_worker","gaia-web"];async function gl(e,t,r){let n=le.join(e,"infra/docker"),o=[...dt(ar()),...io(n)],i=[...Og,...(P()?.bots??[]).map(Ie)],s={GAIA_VERSION:t};await Xn([...o,"pull",...i],{cwd:n,env:s,logName:"compose-pull",rebuildCommand:"gaia up --build",onProgress:r,pullSize:await Hi(n,o,s,{services:i,always:!0})})}async function so(e,t,r,n){let o=le.join(e,"infra/docker"),[i,s]=await Promise.all([$(e),ee()]);if(s==="ready"){t?.("Stopping GAIA's containers\u2026");let a=io(o),c=i==="selfhost"?dt(ar()):[];await Xn([...c,...a,...Cg(n)],{cwd:o,logName:"compose-down",rebuildCommand:pl,onProgress:l=>t?.(l.label)})}else{if(i==="selfhost")throw await Dt(s);if(s==="no-permission")throw await Dt(s)}i!=="selfhost"&&await $g(e,t,r,n),t?.("All services stopped.")}async function $g(e,t,r,n){t?.("Stopping GAIA-managed local processes (safe mode)\u2026");let o=Yi(e),i=o!==null&&await Lg(e,o);try{Ce.unlinkSync(le.join(e,oo))}catch{}if(!i){if(n?.forcePorts){t?.("No GAIA PID found. Force-stopping listeners on app ports\u2026"),await Mg(e,[r?.[8e3]??8e3,r?.[3e3]??3e3]);return}t?.(o!==null?"Stored GAIA PID is stale. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.":"No GAIA-managed PID found. Skipping port cleanup in safe mode. Use `gaia stop --force-ports` for aggressive cleanup.")}}async function Lg(e,t){if(!no(t))return!1;try{return process.platform==="win32"?(await de("taskkill",["/PID",String(t),"/T","/F"],e),!0):(ul(t,"SIGTERM"),await Rg(800),no(t)&&ul(t,"SIGKILL"),!0)}catch{return!1}}function ul(e,t){try{process.kill(-e,t)}catch{process.kill(e,t)}}async function Mg(e,t){for(let r of t){let[n,o]=process.platform==="win32"?["powershell",["-Command",`Get-NetTCPConnection -LocalPort ${r} -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue }`]]:["sh",["-c",`lsof -ti :${r} -sTCP:LISTEN | xargs kill 2>/dev/null || true`]];await de(n,o,e)}}async function $(e){let t=rt(e);if(!Ce.existsSync(t))return null;let r=Ce.readFileSync(t,"utf-8"),n=r.match(/^SETUP_MODE=(.+)$/m);if(n?.[1]){let o=n[1].trim().replace(/^["']|["']$/g,"");if(o==="selfhost"||o==="developer")return o}return r.includes("mongodb://mongo:")?"selfhost":(r.includes("mongodb://localhost:"),"developer")}var Ng=8;function Fg(e,t){return e.trimEnd().split(`
|
|
33
33
|
`).slice(-t).join(`
|
|
34
|
-
`)}async function
|
|
35
|
-
${
|
|
36
|
-
Get the source with 'gaia init', then build there.`)}function cr(e){return
|
|
37
|
-
`))}await
|
|
38
|
-
Manual command: ${o[1]}`)}try{await
|
|
39
|
-
Manual command: ${o[2]}`)}let s=[],a=[];for(let c of
|
|
40
|
-
`)}async function
|
|
34
|
+
`)}async function de(e,t,r,n,o,i,s){let{spawn:a}=await import("child_process");return new Promise((c,l)=>{let d=a(e,t,{cwd:r,stdio:["ignore","pipe","pipe"],env:i?{...process.env,...i}:void 0}),p="",m=0,g=!1,v;s&&(v=setTimeout(()=>{g=!0,d.kill("SIGTERM"),l(new Error(`Command timed out after ${Math.round(s/6e4)}m. Check \`docker compose logs\` to debug.`))},s)),d.stdout?.on("data",E=>{let b=E.toString();p+=b,o?.(b),m=Math.min(m+5,95),n?.(m)}),d.stderr?.on("data",E=>{let b=E.toString();p+=b,o?.(b),m=Math.min(m+5,95),n?.(m)}),d.on("close",E=>{v&&clearTimeout(v),!g&&(E===0?(n?.(100),c()):l(new Error(`Command failed with code ${E}:
|
|
35
|
+
${Fg(p,Ng)}`)))}),d.on("error",E=>{v&&clearTimeout(v),!g&&l(E)})})}var Bg="apps/api/app/config/settings_validator.py";function rt(e){return le.join(e,"apps","api",".env")}function sr(e){return Ce.existsSync(le.join(e,Bg))}function Xi(e){if(!sr(e))throw new Error(`Building GAIA needs its source, and ${F(e)} holds only a release's setup files.
|
|
36
|
+
Get the source with 'gaia init', then build there.`)}function cr(e){return Ce.existsSync(le.join(e,Wi))||sr(e)}function hl(e,t){let r=e;for(;r!==le.dirname(r);){if(t(r))return r;r=le.dirname(r)}return null}function Sl(){let e=P();return e?.repoPath?cr(e.repoPath)?e.repoPath:(console.warn(`Warning: Saved repo path "${e.repoPath}" is no longer a valid GAIA installation. Resetting config.`),we({repoPath:"",setupComplete:!1}),null):null}function lr(e){let t=hl(e??process.cwd(),sr);if(t)return t;let r=Sl();return r&&sr(r)?r:null}function L(e){let t=hl(e??process.cwd(),cr);return t&&Ce.existsSync(rt(t))?t:Sl()??t}function zr(e,t){if(!e)return"GAIA isn't installed yet";let r=F(e);return t?`${r} (${t==="selfhost"?"self-host":"developer"})`:`${r} (not set up yet: no apps/api/.env)`}function Gg(e,t=bi()){let r=Zt(e,t);return[`mkdir -p ${e}`,`docker compose -f docker-compose.selfhost.yml exec -T mongo mongodump --archive --gzip > ${r.mongoFile}`,`docker compose -f docker-compose.selfhost.yml exec -T postgres pg_dump -U postgres -d langgraph > ${r.postgresFile}`,`install -m 600 ../../apps/api/.env ${r.apiEnvFile}`,...r.volumeFiles.map(({volume:n,file:o})=>`docker run --rm -v ${n}:/data -v ${e}:/backups alpine tar czf /backups/${Le.basename(o)} -C /data .`)]}function Ug(e){return Le.join(e,"infra","docker")}function jg(e,t){return t?Le.resolve(t):Le.join(e,"backups")}async function Xr(e={}){let t=L();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo or set the recorded install path.");let r=Ug(t),n=Le.join(r,"docker-compose.selfhost.yml");if(!J.existsSync(n))throw new Error(`Compose file not found: ${n}`);let o=jg(t,e.outputDir),i=bi(),s=Zt(o,i),a=Gg(o,i);if(e.dryRun)return{...s,commands:a,warnings:[]};let c=await ee();if(c!=="ready"){let p=await tt(c);throw new Error([`${p.summary}, so the databases cannot be backed up.`,p.fix,"Or run the backup commands yourself:",...a.map(m=>` ${m}`)].join(`
|
|
37
|
+
`))}await J.promises.mkdir(o,{recursive:!0,mode:448});try{J.chmodSync(o,448)}catch{}let l=[s.mongoFile,s.postgresFile,s.apiEnvFile,...s.volumeFiles.map(p=>p.file)],d;try{d=await qg(t,r,o,i,a)}catch(p){for(let m of l)J.rmSync(At(m),{force:!0});throw p}for(let p of[s.mongoFile,s.postgresFile,s.apiEnvFile,...d.volumeFiles.map(m=>m.file)])J.renameSync(At(p),p);return{...s,...d,commands:a}}async function qg(e,t,r,n,o){let i=Zt(r,n);Hg(e,At(i.apiEnvFile));try{await yl("docker",vl("mongo",["mongodump","--archive","--gzip"]),t,At(i.mongoFile))}catch(c){throw new Error(`MongoDB backup failed: ${c.message}
|
|
38
|
+
Manual command: ${o[1]}`)}try{await yl("docker",vl("postgres",["pg_dump","-U","postgres","-d","langgraph"]),t,At(i.postgresFile))}catch(c){throw new Error(`PostgreSQL backup failed: ${c.message}
|
|
39
|
+
Manual command: ${o[2]}`)}let s=[],a=[];for(let c of kt){let l=Ei(r,n,c),d=At(l.file);if(!await Tn(c.volume)){a.push(`${c.label} volume ${c.volume} not found \u2014 nothing to back up`);continue}try{await wl("docker",["run","--rm","-v",`${c.volume}:/data`,"-v",`${Le.dirname(d)}:/backups`,"alpine","tar","czf",`/backups/${Le.basename(d)}`,"-C","/data","."],{cwd:t});try{J.chmodSync(d,384)}catch{}s.push(l)}catch(p){J.rmSync(d,{force:!0});let m=`${c.label} backup failed: ${p.message}`;if(c.userData)throw new Error(m);a.push(m)}}return{volumeFiles:s,warnings:a}}function Hg(e,t){let r=rt(e);if(!J.existsSync(r))throw new Error(`${r} not found \u2014 it holds INSTANCE_SECRET, without which the backup's stored credentials cannot be decrypted. Run gaia up to configure this install.`);Ln(r,t)}function vl(e,t){return["compose","-f","docker-compose.selfhost.yml","exec","-T",e,...t]}async function yl(e,t,r,n){J.writeFileSync(n,"",{mode:384,flag:"wx"});try{await wl(e,t,{cwd:r,stdout:{file:n},buffer:{stdout:!1}})}catch(o){throw J.rmSync(n,{force:!0}),o}}function D(e=""){process.stdout.write(`${e}
|
|
40
|
+
`)}async function El(e={}){if(e.dryRun){let t=await Xr({outputDir:e.output,dryRun:!0});D("Backup commands (dry run \u2014 not executed):");for(let r of t.commands)D(` ${r}`);D(""),D(`Volumes (${kt.map(r=>r.volume).join(", ")}) are backed up via`),D(" docker run --rm -v <volume>:/data -v <output>:/backups alpine tar ..."),D(" and are skipped if the volume does not exist yet."),D(""),D("Run without --dry-run to execute inside the running containers,"),D("or copy-paste the commands from the directory containing infra/docker/");return}try{D("Starting GAIA backup\u2026");let t=await Xr({outputDir:e.output});D(`MongoDB dump: ${t.mongoFile}`),D(`PostgreSQL dump: ${t.postgresFile}`),D(`API settings (apps/api/.env): ${t.apiEnvFile}`);for(let{label:r,file:n}of t.volumeFiles)D(`${r} archive: ${n}`);if(t.warnings.length)for(let r of t.warnings)D(`Note: ${r}`);D(""),D("Backups complete. Store them off-host and access-controlled \u2014"),D(`${t.apiEnvFile} holds INSTANCE_SECRET, which decrypts the stored provider credentials.`),D(""),D("Restore with gaia restore --from <dir>, or manually from the repo root:"),D(` install -m 600 ${t.apiEnvFile} apps/api/.env`),D(` cat ${t.postgresFile} | docker compose -f infra/docker/docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`),D(` docker compose -f infra/docker/docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t.mongoFile}`);for(let{volume:r,file:n}of t.volumeFiles)D(` docker run --rm -v ${r}:/data -v $(dirname ${n}):/backups alpine sh -c "${Mr(bl.basename(n))}"`)}catch(t){ye(t.message),process.exitCode=1}}import{Argument as dS,Command as pS}from"commander";async function pe(e){try{await e()}catch(t){ye(t instanceof Error?t.message:String(t)),process.exit(1)}}import yh from"chalk";import{supportsHyperlink as wh}from"supports-hyperlinks";import Vg from"wrap-ansi";var Wg=40,Kg=80,Yg=24;function Jr(e){return{columns:e.columns||Kg,rows:e.rows||Yg}}function Ji(e,t){return Vg(e,t,{hard:!0})}function pt(e,t=0){let r=process.stdout.isTTY?process.stdout.columns:void 0;return!r||r-t<Wg?e:Ji(e,r-t).split(`
|
|
41
41
|
`).join(`
|
|
42
|
-
${" ".repeat(t)}`)}import{networkInterfaces as
|
|
43
|
-
`)}async function
|
|
42
|
+
${" ".repeat(t)}`)}import{networkInterfaces as xl}from"node:os";var O=3e3,ao=8e3,Qr=3443;function Lt(e,t){return`http://localhost:${e==="selfhost"?t[O]??O:t[ao]??ao}`}function me(e,t){return`${Lt(e,t)}/api/v1`}var Qi=/^(docker\d+|br-[0-9a-f]+)$/;function Zi(e){return`http://localhost:${e}`}function es(e,t=xl()){return Object.entries(t).filter(([r])=>!Qi.test(r)).flatMap(([,r])=>r??[]).filter(r=>r.family==="IPv4"&&!r.internal).map(r=>`http://${r.address}:${e}`)}function zg(e=process.env,t=process.platform){return e.SSH_CONNECTION||e.SSH_TTY?!0:t==="linux"&&!e.DISPLAY&&!e.WAYLAND_DISPLAY}function ts(e,t,r=xl(),n=zg()){if(t)return`https://${t}`;let o=Zi(e);return n?es(e,r)[0]??o:o}function mt(e,t){return ts(t,Nn(e))}async function co(e,t,r=5e3){return fetch(e,{...t,signal:AbortSignal.timeout(r)})}async function He(e,t,r=5e3){try{let n=await co(`${e}/setup/${t}`,void 0,r);return n.ok?{data:await n.json()}:{detail:`HTTP ${n.status} from /api/v1/setup/${t}`}}catch{return{detail:`Could not read setup ${t}`}}}import*as Me from"node:fs";import*as ns from"node:path";import Il from"semver";var Xg="https://registry.npmjs.org/@heygaia/cli/latest",rs=ns.join(xe,"update-check.json"),Jg=ns.join(Ur,"update-check.log"),Qg=1440*60*1e3,Zg=5e3;function ft(e){return/^v\d/.test(e)?Il.parse(e.slice(1)):null}var eh=/^[0-9a-f]{40}$/,th=12;function lo(e){return eh.test(e)?e.slice(0,th):e}function nt(e,t){let r=ft(e),n=ft(t);return r!==null&&n!==null&&Il.gt(r,n)}function Rl(){if(!Me.existsSync(rs))return null;let e=JSON.parse(Me.readFileSync(rs,"utf-8"));return e.arch===nr()?e:null}function Cl(){return Rl()?.latest??null}async function rh(){let e=await fetch(Xg,{signal:AbortSignal.timeout(Zg)});if(!e.ok)throw new Error(`npm answered HTTP ${e.status}`);let{version:t}=await e.json(),r=`v${t}`;return await or(r)===null?r:null}function nh(e){Me.mkdirSync(Ur,{recursive:!0}),Me.appendFileSync(Jg,`${new Date().toISOString()} update check failed: ${e.message}
|
|
43
|
+
`)}async function uo(){let e=Rl();if(e&&Date.now()-Date.parse(e.checkedAt)<Qg)return e.latest;try{let t=await rh();Me.mkdirSync(xe,{recursive:!0});let r={checkedAt:new Date().toISOString(),arch:nr(),latest:t};return Me.writeFileSync(rs,JSON.stringify(r)),t}catch(t){return nh(t),e?.latest??null}}var kl=300,oh="ai_models";function ih(e,t){let r=e.features[oh]?.in_use[0];return r?t?.providers[r]?.label??r:null}async function po(){let e=L(),t=e?await $(e):null;if(!e||!t)return{running:!1,installed:!1};let r=k(e),n=me(t,r),[o,i]=await Promise.all([He(n,"status",kl),He(n,"catalog",kl)]);if("detail"in o)return{running:!1,installed:!0};let s=r[O]??O;return{running:!0,webUrl:mt(e,s),provider:ih(o.data,"data"in i?i.data:null)}}function mo(){uo();let e=L(),t=Cl();return!e||!t?null:nt(t,Ue(e))?t:null}import{Chalk as mh}from"chalk";import{Chalk as sh}from"chalk";var os=[".........mmmmm.........","......mmmmmmmmmmm......",".....mmmmmmmmmmmmm.....","....ddddddmmmllllll....","...ddddddddmllllllll...","...ddddddd...lllllll...","....ddd.........lll....",".lll................dd.",".lll...............ddd.",".llll.............ddddm","mllll.............ddddm","mmlll.............ddddm","mmllll............dddmm",".mmlll...........dddmmm",".mmmml...........dmmmm.",".mmmmmd.........llmmmm.","..mmmmdd.......lllmmmm.","..mmmmddd.....llllmmm..","...mmmdddd...llllmmm...","....mmddddd.lllllmm....",".....mmdddd.llllmm.....","......mmddd.lllmm......"],is={d:"#0f537c",m:"#059cda",l:"#02bdff"},ss={d:24,m:38,l:39};var ah={d:"blue",m:"cyan",l:"cyanBright"},ch={d:"bgBlue",m:"bgCyan",l:"bgCyanBright"},Tl="\u2580",_l="\u2584",lh="\u2588";function Al(e){return e==="d"||e==="m"||e==="l"?e:null}function uh(e,t){return e===null&&t===null?{ch:" ",fg:null,bg:null}:e===t?{ch:" ",fg:null,bg:e}:e===null?{ch:_l,fg:t,bg:null}:{ch:Tl,fg:e,bg:t}}function dh(e,t){return{ch:e!==null&&t!==null?lh:e!==null?Tl:t!==null?_l:" ",fg:null,bg:null}}function Pl(e,{fg:t,bg:r}){let n=e;return t!==null&&(n=e.level===3?n.hex(is[t]):e.level===2?n.ansi256(ss[t]):n[ah[t]]),r!==null&&(n=e.level===3?n.bgHex(is[r]):e.level===2?n.bgAnsi256(ss[r]):n[ch[r]]),n}function ph(e,t){let r="",n="",o=null;for(let i of t)o&&(i.fg!==o.fg||i.bg!==o.bg)&&(r+=Pl(e,o)(n),n=""),o=i,n+=i.ch;return o?r+Pl(e,o)(n):r}var Dl=os[0].length;function Ol(e){let t=os,r=new sh({level:e}),n=[];for(let o=0;o<t.length;o+=2){let i=t[o]??"",s=t[o+1]??"",a=[...i].map((c,l)=>{let d=Al(c),p=Al(s[l]);return e===0?dh(d,p):uh(d,p)});n.push(ph(r,a))}return n}var $l=3,fh=40,Ll=" \xB7 ",Ml="Your proactive personal assistant",Nl={truecolor:"#af8700",ansi256:136};function gh(e,t){return t?`\x1B]8;;${e}\x1B\\${e}\x1B]8;;\x1B\\`:e}function hh(e){return e.level===3?e.hex(Nl.truecolor):e.level===2?e.ansi256(Nl.ansi256):e.yellow}function Fl(e,t){return{plain:`GAIA v${t}`,styled:`${e.bold("GAIA")} ${e.dim(`v${t}`)}`}}function Sh(e,t,r){if(!t.running){let o=t.installed?`${y.pending} Not running \xB7 start it with gaia start`:`${y.pending} Not installed \xB7 set it up with gaia up`;return{plain:o,styled:e.dim(o)}}let n=t.provider?` \xB7 ${t.provider}`:"";return{plain:`\u25CF Running at ${t.webUrl}${n}`,styled:`${e.green("\u25CF")} Running at ${gh(t.webUrl,r)}${e.dim(n)}`}}function Bl(e,t){let r=[];if(e.status&&r.push(Sh(t,e.status,e.hyperlinks)),e.update){let n=`Update available: ${e.update} \xB7 run gaia update`;r.push({plain:n,styled:hh(t)(n)})}return r}function Gl(e){return[...e.plain].length}function vh(e,t){let r=Fl(t,e.version);for(let n of Bl(e,t)){let o={plain:`${r.plain}${Ll}${n.plain}`,styled:`${r.styled}${t.dim(Ll)}${n.styled}`};if(Gl(o)>e.columns)break;r=o}return r.styled}function fo(e){let t=new mh({level:e.level}),r=[Fl(t,e.version),{plain:Ml,styled:t.dim(Ml)},...Bl(e,t)],n=Dl+$l+Math.max(...r.map(Gl));if(!e.isTTY||e.rows<fh||n>e.columns)return[vh(e,t)];let o=Ol(e.level),i=Math.floor((o.length-r.length)/2);return o.map((s,a)=>{let c=r[a-i];return c?`${s}${" ".repeat($l)}${c.styled}`:s})}function as(e){return{isTTY:e.isTTY===!0,hyperlinks:wh(e)}}async function bh({showStatus:e=!0,showUpdate:t=!0}={}){let r={...Jr(process.stdout),...as(process.stdout)},n=e&&r.isTTY?await po():null;return["",...fo({level:yh.level,...r,version:A,status:n,update:t?mo():null}),""]}async function Mt(e){process.stdout.write(`${(await bh(e)).join(`
|
|
44
44
|
`)}
|
|
45
|
-
`)}async function
|
|
46
|
-
`);return}await
|
|
47
|
-
`).map(t=>Number(t.split(" ")[2])).filter(t=>Number.isFinite(t)).reduce((t,r)=>t+r,0)}async function
|
|
48
|
-
`).map(
|
|
49
|
-
Run it from a regular terminal, not a pipe or a script.`),process.exit(1)}function
|
|
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,
|
|
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
|
|
52
|
-
`);if(o.length>1)return o[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function
|
|
53
|
-
\u2022 OrbStack (lightweight): ${
|
|
54
|
-
\u2022 Docker Desktop: ${
|
|
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
|
|
45
|
+
`)}async function Ul(){if(!process.stdout.isTTY){process.stdout.write(`${A}
|
|
46
|
+
`);return}await Mt()}var Eh="2048";function jl(e){let t=new URL("https://discord.com/oauth2/authorize");return t.searchParams.set("client_id",e),t.searchParams.set("scope","bot applications.commands"),t.searchParams.set("permissions",Eh),t.toString()}function ql(e){return`https://t.me/${e}`}async function cs(e,t){let r=await fetch(e,{...t,signal:AbortSignal.timeout(1e4)}),n=r.headers.get("content-type")?.includes("application/json");if(r.ok||n)return await r.json();throw new Error(`${new URL(e).hostname} answered HTTP ${r.status}. Try again in a minute.`)}async function Vl(e){let t=await cs(`https://api.telegram.org/bot${e}/getMe`,{method:"GET"});if(!t.ok||!t.result)throw new Error(`Telegram rejected the bot token: ${t.description??"unknown error"}. Copy it again from @BotFather.`);return t.result.username}async function Wl(e){let t=await cs("https://discord.com/api/v10/applications/@me",{method:"GET",headers:{Authorization:`Bot ${e}`}});if(!t.id)throw new Error(`Discord rejected the bot token: ${t.message??"unknown error"}. Reset and copy it from the Developer Portal's Bot page.`);if(((t.flags??0)&786432)===0)throw new Error("Turn on Message Content Intent in the Discord Developer Portal (Bot page, Privileged Gateway Intents), then rerun this command.");return t.id}async function Hl(e,t){return await cs(`https://slack.com/api/${e}`,{method:"POST",headers:{Authorization:`Bearer ${t}`}})}async function Kl(e,t){let r=await Hl("auth.test",e);if(!r.ok||!r.team||!r.url)throw new Error(`Slack rejected the bot token (xoxb-): ${r.error??"unknown error"}.`);let n=await Hl("apps.connections.open",t);if(!n.ok)throw new Error(`Slack rejected the app token (xapp-): ${n.error??"unknown error"}. Enable Socket Mode and create an app-level token with connections:write.`);return{name:r.team,url:r.url}}import*as tn from"node:fs";import*as nn from"node:os";import*as iu from"node:path";import{execa as Fh}from"execa";import*as fe from"node:fs";import*as Yl from"node:path";import{execa as xh}from"execa";var us="/var/log/dpkg.log",ls="/var/cache/apt/archives",Ih=1e3,Rh=/^\S+ \S+ (unpack|configure) ([^:\s]+)/,Ch={unpack:"unpacking",configure:"setting up"};function kh(e){let t=Rh.exec(e);return!t?.[1]||!t[2]?null:`${Ch[t[1]]} ${t[2]}`}var Ah=/apt-get\s+(?:-\S+\s+)*install\s+([^>]+)/;function zl(e){let t=Ah.exec(e);return t?.[1]?t[1].split(/\s+/).filter(r=>r&&!r.startsWith("-")):null}function Ph(e){return e.split(`
|
|
47
|
+
`).map(t=>Number(t.split(" ")[2])).filter(t=>Number.isFinite(t)).reduce((t,r)=>t+r,0)}async function Xl(e){let{stdout:t}=await xh("apt-get",["install","--print-uris","-qq","-y",...e]);return Ph(t)}function Jl(e){return fe.existsSync(e)?fe.statSync(e).size:0}function Th(e){return fe.existsSync(ls)?fe.readdirSync(ls).filter(t=>t.endsWith(".deb")).map(t=>fe.statSync(Yl.join(ls,t))).filter(t=>t.ctimeMs>=e).reduce((t,r)=>t+r.size,0):0}function _h(e){let t=Jl(us),r=t<e?0:e;if(t===r)return{activity:null,offset:r};let n=Buffer.alloc(t-r),o=fe.openSync(us,"r");try{fe.readSync(o,n,0,n.length,r)}finally{fe.closeSync(o)}return{activity:n.toString().split(`
|
|
48
|
+
`).map(kh).findLast(a=>a!==null)??null,offset:t}}function ds(e){let t=Date.now(),r=Jl(us),n=null,o=setInterval(()=>{let i=_h(r);r=i.offset,n=i.activity??n,e({downloaded:Th(t),dpkg:n})},Ih);return()=>clearInterval(o)}var Nt="steps";function Zr(e){return e.currentState.data[Nt]??[]}function go(e,t){let r=Un();e.updateData(Nt,t.map(n=>({...n,...r[n.id],state:"pending"})))}function ps(e){return Object.fromEntries(Zr(e).flatMap(t=>t.startedAt===void 0?[]:[[t.id,{startedAt:t.startedAt,label:t.label,doneLabel:t.doneLabel,minor:t.minor,substeps:t.substeps}]]))}function te(e,t,r){e.updateData(Nt,Zr(e).map(n=>n.id===t?{...n,...r}:n))}function ge(e,t,r={}){let n=Date.now(),o=Zr(e).find(i=>i.id===t);e.setStatus(""),te(e,t,{state:"active",startedAt:o?.startedAt??n,...r})}function ke(e,t,r){let n=Zr(e).find(o=>o.id===t);te(e,t,{state:"done",endedAt:Date.now(),startedAt:n?.startedAt??Date.now(),detail:void 0,percent:void 0,amount:void 0,etaMs:void 0,hint:void 0,substeps:void 0,...r?{doneLabel:r}:{}})}function Ql(e,t,r,n,o){let i=r.findIndex(s=>s.id===n);te(e,t,{substeps:r.map((s,a)=>({...s,state:a<i?"done":a===i?"active":"pending",...a===i&&o?{note:o}:{}}))})}function en(e,t){te(e,t,{state:"skipped",endedAt:Date.now()})}function Ve(e,t){let r=Zr(e).find(n=>n.state==="active"||n.state==="waiting");r&&te(e,r.id,{state:t,endedAt:Date.now()})}function gt(e){let t=Math.max(0,Math.floor(e/1e3));if(t<60)return`${t}s`;let r=Math.floor(t/60);return r<60?`${r}m ${String(t%60).padStart(2,"0")}s`:`${Math.floor(r/60)}h ${String(r%60).padStart(2,"0")}m`}function Dh(e){let t=e.startedAt!==void 0&&e.endedAt!==void 0?` (${gt(e.endedAt-e.startedAt)})`:"";return e.state==="active"?` ${e.label}\u2026`:e.state==="done"?`${y.ok} ${e.doneLabel}${t}`:e.state==="failed"?`${y.fail} ${e.label}${t}`:e.state==="cancelled"?`${y.cancelled} ${e.label}${t}`:null}function he(){return process.stdin.isTTY===!0&&process.stdout.isTTY===!0}function Zl(e){if(he())return;let t=e?`'gaia ${e}'`:"this command";ye(`${t} needs an interactive terminal to ask its questions.
|
|
49
|
+
Run it from a regular terminal, not a pipe or a script.`),process.exit(1)}function eu(e,t=""){let r=t,n="",o="",i=new Map;e.on("change",s=>{let a=s.data[Nt]??[];for(let c of a){let l=`${c.state}:${c.state==="active"?c.label:""}`;if(i.get(c.id)===l)continue;i.set(c.id,l);let d=Dh(c);d&&console.info(d)}a.length===0&&s.step&&s.step!==r&&(r=s.step,console.info(`
|
|
50
|
+
[${s.step}]`)),s.status&&s.status!==n&&(n=s.status,console.info(` ${s.status}`)),s.error&&s.error.message!==o&&(o=s.error.message,ye(s.error.message))})}import{execa as Ft}from"execa";var We={git:"https://git-scm.com/downloads",docker:"https://docs.docker.com/get-docker/",mise:"https://mise.jdx.dev/getting-started.html"},tu={8e3:"API Server",5432:"PostgreSQL",6379:"Redis",27017:"MongoDB",5672:"RabbitMQ",15672:"RabbitMQ Management",[O]:"Web Frontend",[Qr]:"Web Frontend (HTTPS)",8080:"ChromaDB",8083:"Mongo Express"},Oh={selfhost:[O,Qr],developer:[ao,5432,6379,27017,5672,15672,O,8080,8083]};async function ho(e,t={}){let r=await Ha(Ee[e]),n=Oh[e].map(a=>t[a]??a),o=n.filter(a=>!r.has(a)),i=await $h(o),s=new Map(i.map(a=>[a.port,a]));return n.map(a=>s.get(a)??{port:a,service:tu[a]||`Port ${a}`,available:!0})}async function ms(){try{return await Ft("git",["--version"]),"success"}catch{return"error"}}async function ru(){try{return await Ft("mise",["--version"]),"success"}catch{return"missing"}}async function nu(){if((await import("node:os")).platform()==="win32")try{return await Ft("powershell",["-Command","irm https://mise.jdx.dev/install.ps1 | iex"]),!0}catch{return!1}try{return await Ft("sh",["-c","curl https://mise.jdx.dev/install.sh | sh"]),!0}catch{return!1}}async function $h(e){let t=await import("node:net"),r=[],n=o=>new Promise(i=>{let s=t.createServer();s.once("error",()=>i(!1)),s.once("listening",()=>{s.close(()=>i(!0))}),s.listen(o)});for(let o of e){let i=tu[o]||`Port ${o}`;if(await n(o))r.push({port:o,service:i,available:!0});else{let a=await Lh(o),c=await Mh(o+1,o+100,n);r.push({port:o,service:i,available:!1,usedBy:a,alternative:c||void 0})}}return r}async function Lh(e){if((await import("node:os")).platform()==="win32"){try{let{stdout:n}=await Ft("netstat",["-ano","-p","TCP"]),o=n.trim().split(`
|
|
51
|
+
`);for(let i of o)if(i.includes(`:${e}`)&&i.includes("LISTENING")){let s=i.trim().split(/\s+/),a=s[s.length-1];if(a)try{let{stdout:c}=await Ft("tasklist",["/FI",`PID eq ${a}`,"/FO","CSV","/NH"]);return c.trim().split(",")[0]?.replace(/"/g,"")||`PID ${a}`}catch{return`PID ${a}`}}}catch{}return}try{let{stdout:n}=await Ft("lsof",["-i",`:${e}`,"-sTCP:LISTEN","-P","-n"]),o=n.trim().split(`
|
|
52
|
+
`);if(o.length>1)return o[1]?.split(/\s+/)?.[0]||void 0}catch{}}async function Mh(e,t,r){for(let n=e;n<=t;n++)if(await r(n))return n;return null}var Bh="https://get.docker.com",Gh="https://orbstack.dev",Uh="https://docs.docker.com/desktop/install/mac-install/",jh="setting up docker-ce",qh={git:"Git",docker:"Docker"},fs="prerequisite_install_confirm",Gt="missingPrerequisites",rn=class extends Error{constructor(t){super(t),this.name="PrerequisiteDeclined"}};function gs(){return tn.existsSync("/usr/bin/apt-get")||tn.existsSync("/etc/debian_version")}function Bt(e,t,r){e.updateData("checks",{...e.currentState.data.checks,[t]:r})}function ur(e){return e.map(t=>qh[t]).join(" and ")}function Hh(){throw nn.platform()==="darwin"?new Error(`GAIA runs in Docker, which isn't installed yet.
|
|
53
|
+
\u2022 OrbStack (lightweight): ${Gh}
|
|
54
|
+
\u2022 Docker Desktop: ${Uh}
|
|
55
|
+
Install either, open it, then run this command again.`):new Error(`GAIA runs in Docker, which isn't installed yet. Install it from ${We.docker}, then run this command again.`)}async function Vh(e,t,r){if(r.assumeYes)return;let n=ur(t);if(!he())throw new Error(`GAIA needs ${n}, and there is no terminal to ask before installing.
|
|
56
56
|
Rerun with --yes to install them, or install them first:
|
|
57
57
|
`+t.map(i=>` ${We[i]}`).join(`
|
|
58
|
-
`));for(let i of t)
|
|
59
|
-
Install it by hand following ${We.git}, then run this command again.`)}finally{n()}if(await
|
|
60
|
-
`))}},stop:()=>
|
|
61
|
-
Install it by hand following ${We.docker}, then run this command again.`)}finally{n.stop()}}async function
|
|
62
|
-
`).filter(i=>i.trim()!=="");e.updateData(t,[...n,...o].slice(
|
|
63
|
-
\u2022 Mise: ${We.mise}`)),null):"success"}async function dr(e,t){e.setStatus("Checking Ports\u2026");let r=await
|
|
64
|
-
\u203A `),!process.stdin.isTTY){let t=
|
|
65
|
-
`),t(i)},o=i=>{let s=i.toString("utf-8").replace(
|
|
58
|
+
`));for(let i of t)Bt(e,i,"missing");if(e.updateData(Gt,t),await e.waitForInput(fs)!=="install")throw new rn(`Skipped installing ${n}. Install ${t.length>1?"them":"it"} (${t.map(i=>We[i]).join(", ")}), then run ${r.rerunCommand?`'${r.rerunCommand}'`:"this command"} again.`)}var su={prepare:"Preparing the install",download:"Downloading packages",install:"Installing packages",start:"Starting the Docker service",check:"Checking Docker answers"},hs=["prepare","download","install","start","check"].map(e=>({id:e,label:su[e]}));function au(e){return e.dpkg?.split(" ").at(-1)}async function Wh(e){e({stage:"prepare",note:"package lists"});let t=qe("git-install"),r=!1,n=ds(o=>{r&&e(o.dpkg?{stage:"install",note:au(o)}:{stage:"download",note:Re(o.downloaded)})});try{await H("apt-get",["update"],t),r=!0,e({stage:"download"}),await H("apt-get",["install","-y","git"],t)}catch(o){throw new Error(`Git installation failed: ${o.message}
|
|
59
|
+
Install it by hand following ${We.git}, then run this command again.`)}finally{n()}if(await ms()!=="success")throw new Error(`Git was installed but 'git --version' still fails. Install it by hand following ${We.git}, then run this command again.`)}function Kh(e){if(e.includes("Executing docker install script"))return{stage:"preparing",detail:"running Docker's script"};if(!e.startsWith("+ "))return null;let t=zl(e);return t?.includes("docker-ce")?{stage:"downloading",packages:t}:e.includes("apt-get")&&e.includes("update")?{stage:"preparing",detail:"package lists"}:e.includes("gpg")||e.includes("docker.asc")?{stage:"preparing",detail:"package source"}:t?{stage:"preparing",detail:"what Docker needs"}:e.includes("systemctl")?{stage:"starting"}:null}function Yh(e){let t=hs.map(n=>n.id),r=0;return n=>{let o=t.indexOf(n.stage);o<r||(r=o,e(n))}}function zh(e,t){let r=Yh(e),n=()=>{},o=null,i=a=>{if(a.dpkg===jh){r({stage:"start"});return}if(a.dpkg){r({stage:"install",note:au(a)});return}r({stage:"download",note:o===null?Re(a.downloaded):Ot(a.downloaded,Math.max(o,a.downloaded),!1)})};return{onLine:a=>{let c=Kh(a);if(c){if(c.stage==="preparing"){r({stage:"prepare",note:c.detail});return}if(n(),c.stage==="starting"){r({stage:"start"});return}i({downloaded:0,dpkg:null}),n=ds(i),Xl(c.packages).then(l=>{o=l},l=>tn.appendFileSync(t,`gaia: could not read Docker's download size: ${l.message}
|
|
60
|
+
`))}},stop:()=>n()}}async function Xh(e){let t=iu.join(nn.tmpdir(),"gaia-docker-install.sh"),r=qe("docker-install");e({stage:"prepare",note:"Docker's script"}),await Fh("curl",["-fsSL",Bh,"-o",t]);let n=zh(e,r);try{await H("sh",[t],r,n.onLine)}catch(o){throw new Error(`Docker installation failed: ${o.message}
|
|
61
|
+
Install it by hand following ${We.docker}, then run this command again.`)}finally{n.stop()}}async function ou(e,t,r){Bt(e,t,"pending");try{let n=await r();return Bt(e,t,"success"),n}catch(n){throw Bt(e,t,"error"),n}}async function Jh(e,t){if(t==="no-permission")return e.setStatus("Giving your user access to Docker (the docker group)\u2026"),await wc(),e.updateData("dockerGroupSwitch",await Ec()),e.setStatus("Docker access granted. Continuing with it\u2026"),"relaunch";if(t!=="ready")throw await Dt(t);return"ready"}async function So(e,t){let r=t.needGit&&await ms()!=="success",n=await ee(),o=[];r&&o.push("git"),n==="not-installed"&&o.push("docker");let i=nn.platform()==="linux"&&gs();if(r&&!i)throw Bt(e,"git","error"),new Error(`GAIA needs Git, which isn't installed. Install it from ${We.git}, then run this command again.`);if(n==="not-installed"&&!i&&(Bt(e,"docker","error"),Hh()),o.length>0){try{await Vh(e,o,t)}catch(a){for(let c of o)Bt(e,c,"error");throw a}t.onInstallStart?.(o)}let s=t.onInstallProgress??(a=>e.setStatus(`${su[a.stage]}${a.note?` \xB7 ${a.note}`:""}\u2026`));return t.needGit&&await ou(e,"git",async()=>{r&&await Wh(s)}),ou(e,"docker",async()=>(n==="not-installed"&&(await Xh(s),s({stage:"check"}),n=await ee()),Jh(e,n)))}var Q=e=>new Promise(t=>setTimeout(t,e)),vo=(e,t="dependencyLogs")=>r=>{let n=e.currentState.data[t]||[],o=r.split(`
|
|
62
|
+
`).filter(i=>i.trim()!=="");e.updateData(t,[...n,...o].slice(-$r))};function cu(e){return(t,r)=>{e.updateData("dependencyPhase",t.label),e.updateData("dependencyProgress",t.percent),e.updateData("dependencyLogs",r.slice(-$r))}}async function yo(e){e.updateData("checks",{git:"pending"}),await Q(500);try{return await So(e,{needGit:!0})==="ready"}catch(t){return e.setError(t),!1}}async function wo(e){e.updateData("checks",{...e.currentState.data.checks,mise:"pending"});let t=await ru();return e.updateData("checks",{...e.currentState.data.checks,mise:t}),t==="missing"&&(e.setStatus("Installing Mise\u2026"),t=await nu()?"success":"error",e.updateData("checks",{...e.currentState.data.checks,mise:t})),t==="error"?(e.setError(new Error(`Developer mode requires Mise but it failed to install.
|
|
63
|
+
\u2022 Mise: ${We.mise}`)),null):"success"}async function dr(e,t){e.setStatus("Checking Ports\u2026");let r=await ho(t),n={},o=r.filter(i=>!i.available);if(o.length>0){let i=o.filter(a=>!a.alternative);if(i.length>0)return e.setError(new Error(`Cannot find free alternative ports for: ${i.map(a=>`${a.port} (${a.service})`).join(", ")}. Free these ports and try again.`)),null;if(e.updateData("portConflicts",r),await e.waitForInput("port_conflicts")==="abort")return e.setError(new Error("Port conflicts not resolved. Please free the ports and try again.")),null;for(let a of r)!a.available&&a.alternative&&(n[a.port]=a.alternative)}return e.updateData("portOverrides",n),e.setStatus("Git and Docker are ready"),await Q(1e3),n}async function lu(e,t,r,n){e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration\u2026"),await de("mise",["trust"],t,void 0,n),e.updateData("dependencyProgress",20),e.updateData("dependencyPhase","Installing tools\u2026"),await de("mise",["install"],t,i=>{e.updateData("dependencyProgress",20+i*.3)},n),e.updateData("dependencyPhase","Running mise setup\u2026");let o=Object.keys(r).length>0?ct(r):void 0;return await de("mise",["setup"],t,i=>{e.updateData("dependencyProgress",50+i*.5)},n,o),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0),!0}catch(o){return e.setError(new Error(`Failed to setup project: ${o.message}`)),!1}}import{createInterface as du}from"node:readline/promises";import{Writable as Qh}from"node:stream";async function ht(e,t){let r=du({input:process.stdin,output:process.stdout});try{let n=t?` [${t}]`:"";return(await r.question(`${e}${n}: `)).trim()||t||""}finally{r.close()}}var uu=4,bo="\x1B",Zh="",eS=new Set(["\x7F","\b"]),tS=new RegExp(`${bo}\\[[0-9;]*[A-Za-z~]`,"g");function rS(e){let t=e.length>uu*2?uu:0;return"\u2022".repeat(e.length-t)+e.slice(e.length-t)}async function Eo(e){if(process.stdout.write(`${e}
|
|
64
|
+
\u203A `),!process.stdin.isTTY){let t=du({input:process.stdin,output:new Qh({write:(r,n,o)=>o()})});try{return(await t.question("")).trim()}finally{t.close()}}return new Promise(t=>{let r="",n=(i,s)=>{process.stdin.off("data",o),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`\r\u203A ${s}${bo}[K
|
|
65
|
+
`),t(i)},o=i=>{let s=i.toString("utf-8").replace(tS,"");(s===Zh||s===bo)&&(n("",""),process.stdout.write(`${y.cancelled} Cancelled \xB7 nothing changed.
|
|
66
66
|
`),process.exit(130));for(let a of s){if(a==="\r"||a===`
|
|
67
|
-
`){n(r.trim(),
|
|
67
|
+
`){n(r.trim(),rS(r.trim()));return}eS.has(a)?r=r.slice(0,-1):a>=" "&&(r+=a)}process.stdout.write(`\r\u203A ${"\u2022".repeat(r.length)}${bo}[K`)};process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",o)})}async function St(e,t=!0){let r=await ht(`${e} (${t?"Y/n":"y/N"})`);return r?/^y(es)?$/i.test(r):t}async function xo(e,t){for(process.stdout.write(`
|
|
68
68
|
${e}
|
|
69
69
|
`),t.forEach((r,n)=>{process.stdout.write(` ${n+1}. ${r}
|
|
70
|
-
`)});;){let r=await
|
|
71
|
-
`)}}var
|
|
72
|
-
`)}function
|
|
70
|
+
`)});;){let r=await ht(`Choose 1-${t.length}`),n=Number.parseInt(r,10)-1;if(n>=0&&n<t.length)return n;process.stdout.write(`Invalid choice, try again.
|
|
71
|
+
`)}}var nS={discord:["node","dist/deploy-commands.js"],telegram:["node","dist/set-commands.js"]},oS=12e4,iS=3e3,pu={telegram:[{key:"token",flag:"--token",label:"Telegram bot token",hint:"In Telegram, message @BotFather, send /newbot and copy the token it replies with."}],discord:[{key:"token",flag:"--token",label:"Discord bot token",hint:"At https://discord.com/developers/applications open your app > Bot > Reset Token. Turn on Message Content Intent on the same page."}],slack:[{key:"token",flag:"--token",label:"Slack bot token (xoxb-)",hint:"At https://api.slack.com/apps open your app > OAuth & Permissions > Bot User OAuth Token."},{key:"appToken",flag:"--app-token",label:"Slack app-level token (xapp-)",hint:"Turn on Socket Mode, then Basic Information > App-Level Tokens: create one with the connections:write scope."},{key:"signingSecret",flag:"--signing-secret",label:"Slack signing secret",hint:"Basic Information > App Credentials > Signing Secret."}]};function Ae(e=""){process.stdout.write(`${e}
|
|
72
|
+
`)}function Ss(e,t){if(!e)throw new Error(`Missing ${t}.`);return e}var Ut={telegram:"Telegram",discord:"Discord",slack:"Slack"},sS=3;async function aS(e,t,r){let n={...t},o=0;for(let i of pu[e]){if(n[i.key])continue;if(!he())throw new Error(`Missing ${i.flag}. ${i.hint}`);r&&(o>0&&Ae(),Ae(pt(i.hint))),o++;let s=await Eo(i.label);if(!s)throw new Error(`No ${i.label} entered. Nothing changed.`);n[i.key]=s}return n}async function cS(e,t){for(let r=1;;r++){let n=await aS(e,t,r===1);Ae(`Checking your ${Ut[e]} credentials\u2026`);try{return await lS(e,n)}catch(o){let i=pu[e].filter(a=>!t[a.key]),s=sS-r;if(i.length===0||!he()||s===0)throw o;Ae(pt(`${y.fail} ${o.message} Paste ${i.length===1?"it":"them"} again (${s} ${s===1?"try":"tries"} left), or press Esc to stop.`,2))}}}async function vs(){let e=L();if(!e||await $(e)!=="selfhost")throw new Error("No self-host GAIA install found. Run 'gaia up' first; chat bots run alongside it.");return e}async function lS(e,t){let r=Ss(t.token,"--token");if(e==="telegram"){let s=await Vl(r);return{botsEnv:{TELEGRAM_BOT_TOKEN:r},handle:s,nextSteps:[`Open ${ql(s)} and send /auth to link your GAIA account.`]}}if(e==="discord"){let s=await Wl(r);return{botsEnv:{DISCORD_BOT_TOKEN:r,DISCORD_CLIENT_ID:s},handle:s,nextSteps:[`Add the bot to a server: ${jl(s)}`,"Then run /auth in Discord to link your GAIA account."]}}let n=Ss(t.appToken,"--app-token"),o=Ss(t.signingSecret,"--signing-secret"),i=await Kl(r,n);return{botsEnv:{SLACK_BOT_TOKEN:r,SLACK_APP_TOKEN:n,SLACK_SIGNING_SECRET:o},handle:i.url,nextSteps:[`Running in the ${i.name} workspace. Run /auth in Slack to link your GAIA account.`]}}async function uS(e){let t=Ee.selfhost,r=Date.now()+oS;for(;;){let n=Hr(e,await Pt(t));if(n.health==="healthy")return;if(Date.now()>=r)throw new Error(`The ${Ut[e]} bot did not come up (${n.detail}). See why with 'docker compose -p ${t} logs ${Ie(e)}'; 'gaia bots remove ${e}' undoes the setup.`);await Q(iS)}}async function mu(e){await ue(e,"selfhost",t=>Ae(t),k(e),void 0,{pull:"missing"})}async function fu(e,t){let r=await vs(),n=await cS(e,t);Vr(r,{set:n.botsEnv}),Vn(r,{set:{[Bi[e]]:n.handle}});let o=P()?.bots??[];o.includes(e)||we({bots:[...o,e]}),await mu(r);let i=nS[e];i&&(Ae(`Registering the ${Ut[e]} bot's commands\u2026`),await fl(r,Ie(e),i)),Ae(`Waiting for the ${Ut[e]} bot to connect\u2026`),await uS(e),Ae(`${y.ok} The ${Ut[e]} bot is running`);for(let s of n.nextSteps)Ae(s)}async function gu(e){let t=await vs(),r=P()?.bots??[];if(!r.includes(e))throw new Error(`The ${Ut[e]} bot is not enabled. See 'gaia bots list'.`);we({bots:r.filter(n=>n!==e)}),Vr(t,{unset:Ac[e]}),Vn(t,{unset:[Bi[e]]}),await mu(t),Ae(`${y.ok} The ${Ut[e]} bot is stopped and its credentials are deleted`)}async function hu(){await vs();let e=P()?.bots??[];if(e.length===0){Ae("No chat bots enabled. Add one with: gaia bots add <telegram|discord|slack>");return}let t=await Pt(Ee.selfhost);for(let r of e)Ae(` ${r.padEnd(10)}${Hr(r,t).detail}`)}function Su(){return new dS("<platform>","chat platform").choices(kc)}var sn=new pS("bots").description(j.bots).hook("preAction",()=>Mt()).addHelpText("after",`
|
|
73
73
|
Examples:
|
|
74
74
|
gaia bots add telegram (asks for the token from @BotFather)
|
|
75
75
|
gaia bots add telegram --token <token from @BotFather>
|
|
76
76
|
gaia bots add discord --token <bot token>
|
|
77
77
|
gaia bots add slack --token xoxb-... --app-token xapp-... --signing-secret <secret>
|
|
78
|
-
`);sn.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(
|
|
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
|
|
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
|
|
78
|
+
`);sn.command("add").description("Check the bot's credentials (asked for when not passed), save them and start the bot").addArgument(Su()).option("--token <token>","Bot token (Slack: the xoxb- bot user token)").option("--app-token <token>","Slack: app-level token (xapp-)").option("--signing-secret <secret>","Slack: the app's signing secret").action(async(e,t)=>{await pe(()=>fu(e,t))});sn.command("list").alias("ls").description("Show the enabled bots and whether each is running").action(async()=>{await pe(hu)});sn.command("remove").alias("rm").description("Stop a bot and delete its saved credentials").addArgument(Su()).action(async e=>{await pe(()=>gu(e))});import{Command as wv}from"commander";import{existsSync as To,mkdirSync as $S,readFileSync as Au,writeFileSync as As}from"node:fs";import{homedir as ku}from"node:os";import{join as Ps}from"node:path";import{sep as mS}from"node:path";var V={PING:"ping",MCP_OPEN:"mcp.open",MCP_CLOSE:"mcp.close",MCP_MSG:"mcp.msg",REVOKE:"revoke",SERVER_REMOVE:"server.remove",PONG:"pong",HELLO:"hello",MCP_OPENED:"mcp.opened",MCP_ERROR:"mcp.error",EXEC_OPEN:"exec.open",EXEC_STDOUT:"exec.stdout",EXEC_STDERR:"exec.stderr",EXEC_EXIT:"exec.exit"},ys="https://api.heygaia.io",jt="filesystem",Io=mS,ws=500,bs=6e4,Es=5e3,xs=1e6,Is=5e6,Ro=9e4,Co=1e6;import{homedir as fS}from"node:os";import{join as gS}from"node:path";var hS={info:e=>console.error(e),error:e=>console.error(e)},Rs={},SS=null;function Z(){return SS??hS}function Ke(){return{stateDir:Rs.stateDir??gS(fS(),".gaia","bridge"),env:Rs.env??process.env,shell:Rs.shell??process.env.SHELL??"/bin/sh"}}import{Client as kS}from"@modelcontextprotocol/sdk/client/index.js";import{getDefaultEnvironment as AS,StdioClientTransport as PS}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as TS}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{InMemoryTransport as _S}from"@modelcontextprotocol/sdk/inMemory.js";import{lstat as vS,readdir as bu,readFile as vu,realpath as yS,stat as wS,writeFile as bS}from"node:fs/promises";import{dirname as yu,extname as ES,join as Eu,resolve as xS,sep as Cs}from"node:path";import{McpServer as IS}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as pr}from"zod";var RS={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif"},mr=class extends Error{};async function ks(e){try{return await yS(e)}catch{return null}}async function CS(e){try{return(await vS(e)).isSymbolicLink()}catch{return!1}}function wu(e,t){return t===Cs?e.startsWith(Cs):e===t||e.startsWith(t+Cs)}async function ko(e,t,r){let n=xS(e),o=await ks(n);if(o){if(t.some(s=>wu(o,s)))return o;throw new mr(`Path is outside your approved folders: ${e}`)}if(r)throw new mr(`No such file or directory: ${e}`);let i=await ks(yu(n));if(!i||!t.some(s=>wu(i,s)))throw new mr(`Path is outside your approved folders: ${e}`);if(await CS(n))throw new mr(`Refusing to write through a symlink: ${e}`);return Eu(i,n.slice(yu(n).length+1))}async function xu(e,t,r,n){if(n.length>=r)return;let o;try{o=await bu(e,{withFileTypes:!0})}catch{return}for(let i of o){if(n.length>=r)return;let s=Eu(e,i.name);i.name.toLowerCase().includes(t.toLowerCase())&&n.push(s),i.isDirectory()&&!i.isSymbolicLink()&&await xu(s,t,r,n)}}function Iu(e){let t=new IS({name:"gaia-filesystem",version:"0.1.0"}),r=null,n=()=>(r||(r=Promise.all(e.allow.map(ks)).then(i=>i.filter(s=>s!==null))),r),o=i=>({isError:!0,content:[{type:"text",text:i}]});return t.registerTool("list_directory",{description:"List the entries (files and folders) in a directory on the user's machine.",inputSchema:{path:pr.string().describe("Absolute path to a directory")}},async({path:i})=>{try{let s=await ko(i,await n(),!0);return{content:[{type:"text",text:(await bu(s,{withFileTypes:!0})).map(l=>`${l.isDirectory()?"dir ":"file"} ${l.name}`).join(`
|
|
79
|
+
`)||"(empty)"}]}}catch(s){return o(s instanceof Error?s.message:String(s))}}),t.registerTool("read_file",{description:"Read the contents of a text or image file on the user's machine.",inputSchema:{path:pr.string().describe("Absolute path to a file")}},async({path:i})=>{try{let s=await ko(i,await n(),!0),a=await wS(s);if(!a.isFile())return o(`Not a file: ${i}`);let c=RS[ES(s).toLowerCase()];if(c){if(a.size>Is)return o(`Image is too large to read (${a.size} bytes).`);let d=await vu(s);return{content:[{type:"text",text:`Image file ${s} (${c}, ${a.size} bytes) \u2014 shown below.`},{type:"image",data:d.toString("base64"),mimeType:c}]}}return a.size>xs?o(`File is too large to read (${a.size} bytes).`):{content:[{type:"text",text:await vu(s,"utf-8")}]}}catch(s){return o(s instanceof Error?s.message:String(s))}}),t.registerTool("search_files",{description:"Recursively find files/folders whose name contains a query, under a directory.",inputSchema:{path:pr.string().describe("Absolute path to the directory to search under"),query:pr.string().describe("Substring to match against names")}},async({path:i,query:s})=>{try{let a=await ko(i,await n(),!0),c=[];return await xu(a,s,200,c),{content:[{type:"text",text:c.join(`
|
|
80
|
+
`)||"(no matches)"}]}}catch(a){return o(a instanceof Error?a.message:String(a))}}),e.allowWrite&&t.registerTool("write_file",{description:"Write text to a file on the user's machine (overwrites if it exists).",inputSchema:{path:pr.string().describe("Absolute path to the file to write"),content:pr.string().describe("Text content to write")}},async({path:i,content:s})=>{try{let a=await ko(i,await n(),!1);return await bS(a,s,"utf-8"),{content:[{type:"text",text:`Wrote ${s.length} bytes to ${i}`}]}}catch(a){return o(a instanceof Error?a.message:String(a))}}),t}var DS=new Set(["localhost","127.0.0.1","::1"]),Ru=5;function vt(e){let t=new URL(e);if(t.protocol!=="http:"&&t.protocol!=="https:")throw new Error(`url servers must be http(s), got ${t.protocol}`);let r=t.hostname.replace(/^\[|\]$/g,"");if(!DS.has(r))throw new Error("url servers must point at this machine (localhost / 127.0.0.1 / ::1)");return t}function OS(e){return new URL(typeof e=="string"?e:e instanceof URL?e.href:e.url)}async function Cu(e,t){let r=OS(e),n={...t,redirect:"manual"};for(let o=0;;o++){let i=await fetch(r,n);if(i.status<300||i.status>=400)return i;let s=i.headers.get("location"),a=s?new URL(s,r.href):null;if(await i.body?.cancel(),!a||a.origin!==r.origin)throw new Error(`refusing ${i.status} redirect to ${s??"(no location)"} \u2014 an MCP server must be addressed directly, not via a redirect`);if(o>=Ru)throw new Error(`too many redirects (>${Ru}) \u2014 refusing to follow`);r=a,n={...t,redirect:"manual"}}}async function Ao(e){if(e.type==="url"){let o=vt(e.url),i=new TS(o,{requestInit:{...e.headers?{headers:e.headers}:{}},fetch:Cu});return{transport:i,close:()=>i.close()}}if(e.type==="stdio"){let o=Ke().env,i=new PS({command:e.command,args:e.args,env:{...AS(),...o.PATH!==void 0?{PATH:o.PATH}:{},...o.HOME!==void 0?{HOME:o.HOME}:{},...e.env}});return{transport:i,close:()=>i.close()}}let[t,r]=_S.createLinkedPair(),n=Iu(e);return await n.connect(r),{transport:t,close:async()=>{await n.close(),await t.close()}}}async function Po(e){let t=await Ao(e),r=new kS({name:"gaia-bridge-test",version:"0.1.0"});try{await r.connect(t.transport);let{tools:n}=await r.listTools();return n.map(o=>o.name)}finally{try{await r.close(),await t.close()}catch{}}}function Ts(){return Ke().stateDir}function _s(){return Ps(Ts(),"credentials.json")}function Pu(){return Ps(Ts(),"config.json")}function Tu(){let e=Ts();To(e)||$S(e,{recursive:!0,mode:448})}function Ye(){let e=_s();if(!To(e))return null;try{return JSON.parse(Au(e,"utf-8"))}catch{return null}}function an(e){Tu(),As(_s(),JSON.stringify(e,null,2),{mode:384})}function cn(){let e=_s();To(e)&&As(e,"{}",{mode:384})}function re(){let e=Pu();if(!To(e))return{servers:[]};try{return{servers:JSON.parse(Au(e,"utf-8")).servers??[]}}catch{return{servers:[]}}}function _u(e){Tu(),As(Pu(),JSON.stringify(e,null,2),{mode:384})}function _o(e){e.type==="url"&&vt(e.url);let t=re(),r=t.servers.findIndex(n=>n.key===e.key);r>=0?t.servers[r]=e:t.servers.push(e),_u(t)}function ln(e){let t=re(),r=t.servers.length;return t.servers=t.servers.filter(n=>n.key!==e),_u(t),t.servers.length<r}function Ds(e){return e==="~"?ku():e.startsWith("~/")?Ps(ku(),e.slice(2)):e}function Os(e,t){return{type:"filesystem",key:jt,name:"Local Files",allow:e,allowWrite:t}}function un(e){if(e)return e.replace(/\/$/,"");let t=Ye();return t?.apiUrl?t.apiUrl.replace(/\/$/,""):(process.env.GAIA_API_URL??ys).replace(/\/$/,"")}import{hostname as NS,platform as FS}from"node:os";var Du="x-request-id";function LS(e){if(!e||typeof e!="object")return;let{message:t,code:r}=e;if(!(typeof t!="string"&&typeof r!="string"))return e}var Ne=class e extends Error{status;envelope;body;requestId;constructor(t,r,n={}){super(t,n.cause===void 0?void 0:{cause:n.cause}),this.name="ApiError",this.status=r,this.envelope=n.envelope,this.body=n.body??"",this.requestId=n.requestId}get code(){let t=this.envelope?.code;return typeof t=="string"?t:void 0}static fromBody(t,r,n={}){let o=LS(r),i=o?.message??n.fallbackMessage??`API request failed: ${t}`;return new e(i,t,{envelope:o,body:typeof r=="string"?r:JSON.stringify(r??""),requestId:n.requestId,cause:n.cause})}};async function Ou(e){if(!e.ok){let t=await e.text(),r=t;try{r=JSON.parse(t)}catch{}throw Ne.fromBody(e.status,r,{fallbackMessage:`${e.status} ${e.statusText}`,requestId:e.headers.get(Du)??void 0})}return await e.json()}async function Do(e,t,r,n){let o=await fetch(`${e}/api/v1${t}`,{method:"POST",headers:{"content-type":"application/json",...n?{authorization:`Bearer ${n}`}:{}},body:JSON.stringify(r)});return Ou(o)}async function MS(e,t,r){let n=await fetch(`${e}/api/v1${t}`,{method:"DELETE",headers:{authorization:`Bearer ${r}`}});return Ou(n)}function $s(e,t,r,n){return Do(e,"/device/pair/start",{name:t,platform:r,daemon_version:n})}function Ls(e,t){return Do(e,"/device/pair/poll",{device_code:t})}function Ms(e,t){return Do(e,"/device/token",{refresh_token:t})}function Ns(e,t,r,n,o){return Do(e,"/device/servers",{server_key:r,display_name:n,kind:o},t)}function $u(e,t,r){return MS(e,`/device/servers/${encodeURIComponent(r)}`,t)}async function BS(e){await new Promise(t=>setTimeout(t,e))}function Fs(){return!!Ye()?.refreshToken}async function Lu(e,t){let r=un(t.api),n=t.name||NS(),o=await $s(r,n,FS(),t.daemonVersion);e.onPrompt(o.verification_url,o.user_code),e.onStatus?.("Waiting for approval\u2026");let i=Date.now()+o.expires_in*1e3;for(;Date.now()<i;){await BS(o.interval*1e3);let s;try{s=await Ls(r,o.device_code)}catch(a){Z().error(`[gaia bridge] poll failed, retrying: ${a instanceof Error?a.message:a}`);continue}if(s.status==="approved"&&s.device_id&&s.refresh_token){an({apiUrl:r,deviceId:s.device_id,refreshToken:s.refresh_token}),e.onStatus?.(`
|
|
81
81
|
Paired as "${n}".
|
|
82
|
-
`);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var
|
|
82
|
+
`);return}if(s.status==="expired")throw new Error(`pairing ${s.status}`)}throw new Error("pairing timed out")}var GS={onPrompt(e,t){console.info(`
|
|
83
83
|
To pair this device, open:
|
|
84
84
|
`),console.info(` ${e}`),console.info(`
|
|
85
85
|
and enter this code: ${t}
|
|
86
|
-
`)},onStatus(e){console.info(e)}};async function
|
|
87
|
-
`)}catch{}}async function
|
|
86
|
+
`)},onStatus(e){console.info(e)}};async function US(){let e=L();if(!(!e||await $(e)!=="selfhost"))return Lt("selfhost",k(e))}async function fr(e={}){let t=e.api??(process.env.GAIA_API_URL?void 0:await US());await Lu(GS,{...e,...t!==void 0?{api:t}:{},daemonVersion:A})}import{spawn as ov}from"node:child_process";import{existsSync as Gs,mkdirSync as iv,openSync as sv,readFileSync as av,unlinkSync as ju,writeFileSync as cv}from"node:fs";import{homedir as lv}from"node:os";import{join as Us}from"node:path";import{mkdirSync as Mu,readFileSync as jS,rmSync as Nu,writeFileSync as qS}from"node:fs";import{dirname as HS,join as Fu}from"node:path";var VS=3e4,WS=3e4,KS=50,YS=e=>new Promise(t=>setTimeout(t,e));function Bu(){return Fu(Ke().stateDir,"credentials.lock")}function zS(){return Fu(Bu(),"stamp")}async function XS(e){let t=Bu(),r=zS();Mu(HS(t),{recursive:!0});let n=Date.now()+WS;for(;;){try{Mu(t);break}catch(i){if(i?.code!=="EEXIST")throw i}let o=null;try{let i=Number(jS(r,"utf-8"));o=Number.isFinite(i)?Date.now()-i:Number.POSITIVE_INFINITY}catch(i){i?.code!=="ENOENT"&&(o=Number.POSITIVE_INFINITY)}if(o===null||o<VS){if(Date.now()>n)throw new Error("another gaia process is rotating the device credential \u2014 try again");await YS(KS);continue}try{Nu(t,{recursive:!0,force:!0})}catch{}}try{return qS(r,String(Date.now()),{mode:384}),await e()}finally{try{Nu(t,{recursive:!0,force:!0})}catch{}}}async function dn(){return XS(async()=>{let e=Ye();if(!e?.refreshToken)throw new Ne("not paired \u2014 run: gaia bridge login",401);let t=await Ms(e.apiUrl,e.refreshToken),r={...e,refreshToken:t.refresh_token};return an(r),{creds:r,accessToken:t.access_token}})}async function gr(){let e=re().servers;if(e.length===0)throw new Error("no servers configured \u2014 run: gaia bridge add");let{creds:t,accessToken:r}=await dn();await Promise.all(e.map(n=>Ns(t.apiUrl,r,n.key,n.name,n.type)))}async function Bs(e){let t=ln(e);try{let{creds:r,accessToken:n}=await dn();await $u(r.apiUrl,n,e)}catch(r){Z().info(`[gaia bridge] removed '${e}' locally; the cloud will reconcile on next connect (${r instanceof Error?r.message:String(r)})`)}return t}import{randomInt as nv}from"node:crypto";import Uu from"ws";import{spawn as JS}from"node:child_process";import{appendFileSync as QS,mkdirSync as ZS}from"node:fs";import{homedir as ev}from"node:os";import{join as tv}from"node:path";function rv(e,t){try{let r=Ke().stateDir;ZS(r,{recursive:!0,mode:448});let n=t?` (cwd: ${t})`:"";QS(tv(r,"exec-audit.log"),`${new Date().toISOString()}${n} $ ${e}
|
|
87
|
+
`)}catch{}}async function Gu(e,t,r){rv(e,t);let n=JS(Ke().shell,["-c",e],{cwd:t||ev(),env:Ke().env,stdio:["ignore","pipe","pipe"]}),o=0,i=!1,s=c=>l=>{if(i)return;let d=Co-o,p=l.length>d?l.subarray(0,d):l;p.length>0&&(o+=p.length,r[c](p.toString("utf-8"))),o>=Co&&(i=!0,r.stderr(`
|
|
88
88
|
[gaia bridge] output truncated \u2014 cap reached
|
|
89
89
|
`),n.kill("SIGKILL"))};n.stdout.on("data",s("stdout")),n.stderr.on("data",s("stderr"));let a=setTimeout(()=>{r.stderr(`
|
|
90
|
-
[gaia bridge] killed \u2014 exceeded ${
|
|
91
|
-
`),n.kill("SIGKILL")},
|
|
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=
|
|
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");
|
|
90
|
+
[gaia bridge] killed \u2014 exceeded ${Ro/1e3}s timeout
|
|
91
|
+
`),n.kill("SIGKILL")},Ro);await new Promise(c=>{n.on("error",l=>{clearTimeout(a),r.stderr(`[gaia bridge] could not start command: ${l.message}
|
|
92
|
+
`),r.exit(127),c()}),n.on("close",l=>{clearTimeout(a),r.exit(l??-1),c()})})}var pn=class{constructor(t){this.creds=t}ws=null;sessions=new Map;reconnectDelay=ws;stopped=!1;async run(){for(;!this.stopped;){try{await this.connectOnce()}catch(t){t instanceof Ne&&t.status===401?(Z().error("[gaia bridge] this device is no longer authorized (revoked or unpaired). Re-pair with: gaia bridge login"),this.stopped=!0):Z().error(`[gaia bridge] connection error: ${t instanceof Error?t.message:t}`)}if(this.stopped)break;await this.backoff()}}async stop(){this.stopped=!0,await this.closeAllSessions(),this.ws?.close()}async connectOnce(){let{creds:t,accessToken:r}=await dn();this.creds=t;let n=`${this.creds.apiUrl.replace(/^http/,"ws")}/api/v1/ws/device`,o=new Uu(n,{headers:{authorization:`Bearer ${r}`}});this.ws=o,await new Promise((i,s)=>{let a=!1,c=!1,l=d=>{c||(c=!0,d())};o.on("open",()=>{a=!0,this.reconnectDelay=Es;let d=re().servers.map(p=>p.key);this.send({t:V.HELLO,servers:d}),Z().info(`[gaia bridge] connected \u2014 exposing: ${d.join(", ")||"(nothing configured)"}`)}),o.on("message",d=>{this.guardRejection(this.onFrame(d.toString()),"frame handler error")}),o.on("close",()=>{this.guardRejection(this.closeAllSessions(),"session cleanup error"),this.ws=null,l(()=>a?i():s(new Error("socket closed before open")))}),o.on("error",d=>{a||l(()=>s(d))})})}async onFrame(t){let r;try{r=JSON.parse(t)}catch{return}switch(r.t){case V.PING:this.send({t:V.PONG});return;case V.MCP_OPEN:await this.openSession(r);return;case V.MCP_MSG:await this.forwardToServer(r);return;case V.MCP_CLOSE:await this.closeSession(r.sid);return;case V.EXEC_OPEN:await this.runExec(r);return;case V.REVOKE:Z().error("[gaia bridge] this device was revoked \u2014 exiting."),await this.stop();return;case V.SERVER_REMOVE:r.key&&ln(r.key)&&Z().info(`[gaia bridge] removed server '${r.key}' (deleted in GAIA).`);return;default:return}}async openSession(t){let r=t.sid,n=t.server,o=t.pod;if(!r||!n)return;let i=re().servers.find(a=>a.key===n);if(!i){this.send({t:V.MCP_ERROR,sid:r,pod:o,error:`Unknown server '${n}'`});return}let s=Date.now();Z().info(`[gaia bridge] opening MCP session for '${n}'\u2026`);try{let a=await Ao(i);a.transport.onmessage=c=>{this.send({t:V.MCP_MSG,sid:r,pod:o,data:JSON.stringify(c)})},a.transport.onclose=()=>{this.sessions.has(r)&&this.send({t:V.MCP_ERROR,sid:r,pod:o,error:`Local server '${n}' exited`}),this.guardRejection(this.closeSession(r),"session close error")},await a.transport.start(),this.sessions.set(r,a),this.send({t:V.MCP_OPENED,sid:r,pod:o}),Z().info(`[gaia bridge] MCP session for '${n}' ready in ${Date.now()-s}ms`)}catch(a){let c=a instanceof Error?a.message:String(a);Z().error(`[gaia bridge] MCP session for '${n}' failed after ${Date.now()-s}ms: ${c}`),this.send({t:V.MCP_ERROR,sid:r,pod:o,error:c})}}async forwardToServer(t){let r=t.sid?this.sessions.get(t.sid):void 0;if(!(!r||!t.data))try{let n=JSON.parse(t.data);await r.transport.send(n)}catch(n){Z().error(`[gaia bridge] forward error: ${n instanceof Error?n.message:n}`)}}async runExec(t){let r=t.sid,n=t.pod,o=t.command;!r||!o||await Gu(o,t.cwd,{stdout:i=>this.send({t:V.EXEC_STDOUT,sid:r,pod:n,data:i}),stderr:i=>this.send({t:V.EXEC_STDERR,sid:r,pod:n,data:i}),exit:i=>this.send({t:V.EXEC_EXIT,sid:r,pod:n,code:i})})}async closeSession(t){if(!t)return;let r=this.sessions.get(t);if(r){this.sessions.delete(t);try{await r.close()}catch{}}}async closeAllSessions(){let t=[...this.sessions.keys()];await Promise.all(t.map(r=>this.closeSession(r)))}send(t){this.ws?.readyState===Uu.OPEN&&this.ws.send(JSON.stringify(t))}guardRejection(t,r){t.catch(n=>{Z().error(`[gaia bridge] ${r}: ${n instanceof Error?n.message:n}`)})}async backoff(){let t=nv(this.reconnectDelay);Z().info(`[gaia bridge] reconnecting in ${t}ms\u2026`),await new Promise(r=>setTimeout(r,t)),this.reconnectDelay=Math.min(this.reconnectDelay*2,bs)}};var js=Us(lv(),".gaia","bridge"),qt=Us(js,"daemon.pid"),qu=Us(js,"daemon.log");function qs(){if(!Gs(qt))return null;let e=Number(av(qt,"utf-8").trim());if(!e)return null;try{return process.kill(e,0),e}catch{return null}}function Hu(){let e=qs();return e?`Tunnel: running in the background (pid ${e}) \u2014 stop with: gaia bridge down`:"Tunnel: not running \u2014 start with: gaia bridge up"}function Vu(){let e=qs();if(!e){Gs(qt)&&ju(qt),console.info("No bridge tunnel is running.");return}try{process.kill(e,"SIGTERM")}catch{}Gs(qt)&&ju(qt),console.info(`Stopped the bridge tunnel (pid ${e}).`)}async function Oo(){let e=qs();if(e){console.info(`Bridge tunnel is already running (pid ${e}) \u2014 it already serves your configured servers, including any you just added. Nothing else to do.`);return}console.error("[gaia bridge] connected: GAIA can run commands and access files on this machine.");let t=re().servers.filter(s=>s.type==="url"&&s.headers&&Object.keys(s.headers).length>0);t.length>0&&console.error(`[gaia bridge] forwarding request headers (credentials) to ${t.length} local url server(s).`);try{await gr()}catch(s){if(s instanceof Ne&&s.status===401)console.error(`[gaia bridge] this device is no longer authorized (revoked or unpaired). Let's re-pair.
|
|
93
|
+
`),cn(),await fr(),await gr();else throw s}let r=process.argv[1];if(!r)throw new Error("cannot locate the gaia CLI entrypoint to start the daemon");iv(js,{recursive:!0,mode:448});let n=sv(qu,"a"),o={detached:!0,stdio:["ignore",n,n]},i=ov(process.execPath,[...process.execArgv,r,"bridge","up","--serve"],o);i.unref(),cv(qt,String(i.pid??""),{mode:384}),console.info(`
|
|
94
94
|
Bridge tunnel started in the background (pid ${i.pid}).
|
|
95
|
-
Logs: ${
|
|
96
|
-
Stop: gaia bridge down`)}async function
|
|
97
|
-
The command needs ${o}.`),r[o]=await
|
|
98
|
-
Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await
|
|
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
|
|
100
|
-
Testing the connection (this may download/start the server)\u2026`);try{let t=await
|
|
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
|
|
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
|
|
103
|
-
Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);
|
|
95
|
+
Logs: ${qu}
|
|
96
|
+
Stop: gaia bridge down`)}async function Wu(){let e=Ye();if(!e?.refreshToken)throw new Error("not paired \u2014 run: gaia bridge login");let t=new pn(e),r=async()=>{await t.stop(),process.exit(0)};process.on("SIGINT",()=>void r()),process.on("SIGTERM",()=>void r()),await t.run()}import{basename as Xu}from"node:path";import{resolve as uv}from"node:path";function Hs(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)}function Vs(e){let t=[],r="",n=null;for(let s of e.trim())n?s===n?n=null:r+=s:s==='"'||s==="'"?n=s:/\s/.test(s)?r&&(t.push(r),r=""):r+=s;r&&t.push(r);let[o,...i]=t;if(!o)throw new Error("Empty command");return{command:o,args:i}}function Ku(e,t,r){let n={};for(let o of e??[]){let i=o.indexOf(t);if(i<=0)throw new Error(`invalid ${r} '${o}', expected KEY${t}VALUE`);n[o.slice(0,i).trim()]=o.slice(i+1)}return n}function Yu(e){let t=Hs(e??"");if(!e||!t||t===jt)throw new Error("--name is required and must contain letters or digits");return t}function zu(e){if(e.type==="stdio"){if(!e.command)throw new Error("--command is required for --type stdio");let{command:t,args:r}=Vs(e.command);return{type:"stdio",key:Yu(e.name),name:e.name,command:t,args:r,env:Ku(e.env,"=","--env")}}if(e.type==="url"){if(!e.url)throw new Error("--url is required for --type url");vt(e.url);let t=Ku(e.header,":","--header");return Object.keys(t).length>0&&new URL(e.url).protocol==="http:"&&console.warn("warning: --header values travel unencrypted over local HTTP \u2014 prefer an https: URL for credential headers"),{type:"url",key:Yu(e.name),name:e.name,url:e.url,...Object.keys(t).length?{headers:t}:{}}}if(e.type==="filesystem"){let t=e.path??[];if(t.length===0)throw new Error("--path is required for --type filesystem");let r=t.includes(Io)?[Io]:t.map(n=>uv(Ds(n)));return Os(r,!!e.write)}throw new Error("--type must be one of: stdio, url, filesystem")}function dv(e,t){let n=[...t].reverse().filter(o=>!o.startsWith("-"))[0]??e;return Xu(n).replace(/@[^@]*$/,"")}function pv(e){try{let t=new URL(e);return t.port?`local-${t.port}`:t.hostname}catch{return""}}async function Ju(e){for(;;){let t=await ht("Name for this server",e),r=Hs(t);if(!t||!r||r===jt){console.info("Pick a different name.");continue}if(!(re().servers.some(n=>n.key===r)&&!await St(`'${r}' already exists \u2014 overwrite?`,!1)))return{name:t,key:r}}}function mv(e,t){if(Xu(e)!=="docker")return[];let r=[];for(let n=0;n<t.length;n++){let o=t[n];if(o!==void 0)if(o==="-e"||o==="--env"){let i=t[n+1];i&&!i.includes("=")&&r.push(i)}else o.startsWith("-e")&&o.length>2&&!o.includes("=")&&r.push(o.slice(2))}return[...new Set(r)]}async function Ws(e){let t=process.env[e];if(t!==void 0&&t!==""&&await St(` Found ${e} in your environment \u2014 use that value?`,!0))return t;for(;;){let r=await Eo(` Paste ${e}`);if(r)return console.info(` Got it (${r.length} characters).`),r;console.info(" Empty \u2014 paste the value, or Ctrl+C to abort.")}}async function Qu(e,t){let r={};for(let o of mv(e,t))console.info(`
|
|
97
|
+
The command needs ${o}.`),r[o]=await Ws(o);let n=Object.keys(r).length?"Any other environment variables to add?":"Does the server need environment variables (API keys, tokens\u2026)?";if(!await St(n,!1))return r;for(console.info("Enter each variable's name; leave blank when done.");;){let o=(await ht(" Variable name")).trim();if(!o)break;if(o in r){console.info(" Already added.");continue}r[o]=await Ws(o)}return r}async function fv(){console.info(`
|
|
98
|
+
Examples: npx -y my-mcp-server \xB7 uvx my-server \xB7 docker run -i --rm my/image`);let e=await ht("Command that starts your MCP server");if(!e)throw new Error("a command is required");let{command:t,args:r}=Vs(e),n=await Qu(t,r),{name:o,key:i}=await Ju(dv(t,r));return{type:"stdio",key:i,name:o,command:t,args:r,env:n}}async function gv(){let e={};if(!await St("Does the server need request headers (e.g. Authorization)?",!1))return e;for(console.info("Enter each header's name; leave blank when done.");;){let t=(await ht(" Header name")).trim();if(!t)break;if(t in e){console.info(" Already added.");continue}e[t]=await Ws(t)}return e}async function hv(){let e=await ht("Server URL (e.g. http://localhost:3000/mcp)");if(!e)throw new Error("a URL is required");vt(e);let t=await gv();if(Object.keys(t).length>0&&new URL(e).protocol==="http:"&&(console.info(`
|
|
99
|
+
Heads up: these headers travel unencrypted over local HTTP. Anyone else on this machine (or the receiving server's logs) can read them.`),!await St("Send these headers over unencrypted HTTP anyway?",!1)))throw new Error("aborted \u2014 use an https: URL or drop the headers");let{name:r,key:n}=await Ju(pv(e));return{type:"url",key:n,name:r,url:e,...Object.keys(t).length?{headers:t}:{}}}async function Sv(e){for(;;){console.info(`
|
|
100
|
+
Testing the connection (this may download/start the server)\u2026`);try{let t=await Po(e),r=t.slice(0,5).join(", ");return console.info(`Connected \u2014 ${t.length} tools found${r?` (${r}${t.length>5?", \u2026":""})`:""}.`),!0}catch(t){console.error(`Connection failed: ${t instanceof Error?t.message:t}`);let r=["Retry the test"];e.type==="stdio"&&r.push("Re-enter environment variables"),r.push("Save anyway (fix it later)","Abort");let n=r[await xo("What now?",r)];if(n==="Re-enter environment variables"&&e.type==="stdio")e.env=await Qu(e.command,e.args);else{if(n==="Save anyway (fix it later)")return!0;if(n==="Abort")return!1}}}}async function vv(e){let t=zu(e),r;try{r=await Po(t)}catch(n){throw new Error(`Could not start '${t.key}': ${n instanceof Error?n.message:n}`)}_o(t),await gr(),console.info(`Saved '${t.key}' (${r.length} tools) and registered with GAIA. A running 'gaia bridge up' daemon serves it automatically; otherwise start one.`)}async function Zu(e={}){if(!Fs()){if(e.type)throw new Error("This device isn't paired yet. Run `gaia bridge login` on it first.");console.info("This device isn't paired with GAIA yet, let's do that first."),await fr()}if(e.type){await vv(e);return}let r=await xo("What do you want to connect?",["A command starts an MCP server (stdio) \u2014 npx / uvx / docker / python \u2026","An MCP server already running at a local URL \u2014 e.g. http://localhost:3000/mcp"])===0?await fv():await hv();if(!await Sv(r))throw new Error("aborted");_o(r),console.info(`
|
|
101
|
+
Saved '${r.key}'.`);try{await gr(),console.info("Registered with GAIA.")}catch(n){console.error(`Could not register with GAIA (will retry on \`gaia bridge up\`): ${n instanceof Error?n.message:n}`)}await St("Keep this device connected in the background now?")?await Oo():console.info("Run `gaia bridge up` whenever you're ready.")}function yv(e){let t=e.type==="url"?e.url:e.type==="stdio"?e.command:e.allow.join(", ");return`${e.name} \u2014 ${e.type} (${t})`}async function ed(e){if(e){let o=await Bs(e);console.info(o?`Removed '${e}' from this device and GAIA.`:`No server '${e}'.`);return}let t=re().servers;if(t.length===0){console.info("No servers configured \u2014 nothing to remove.");return}let r=await xo("Which server do you want to remove?",t.map(yv)),n=t[r];if(n){if(!await St(`Remove '${n.key}'?`,!1)){console.info("Left it in place.");return}await Bs(n.key),console.info(`Removed '${n.key}'. The tunnel stops serving it right away, and GAIA drops it too.`)}}function bv(){let e=Ye();console.info(e?.deviceId?`Paired (device ${e.deviceId}, ${un()})`:"Not paired \u2014 run: gaia bridge login"),console.info(Hu());let t=re().servers;if(t.length===0){console.info("No servers configured \u2014 run: gaia bridge add");return}console.info(`
|
|
102
|
+
Configured servers:`);for(let r of t)if(r.type==="filesystem")console.info(` [${r.key}] filesystem${r.allowWrite?" (rw)":" (ro)"}: ${r.allow.join(", ")}`);else if(r.type==="stdio"){let n=Object.keys(r.env);console.info(` [${r.key}] ${r.name}: ${r.command} ${r.args.join(" ")}`),n.length&&console.info(` env: ${n.join(", ")}`)}else{console.info(` [${r.key}] ${r.name}: ${r.url}`);let n=r.headers?Object.keys(r.headers):[];n.length&&console.info(` headers: ${n.join(", ")}`)}}var ot=new wv("bridge").description(j.bridge).addHelpText("after",`
|
|
103
|
+
Revoke a device anytime from GAIA \u2192 Settings \u2192 Devices.`);ot.command("add").description("Connect a local MCP server (guided; or non-interactive with --type)").option("--type <type>","stdio | url \u2014 enables non-interactive mode (no prompts)").option("--name <name>","display name").option("--command <command>","stdio: the command that starts the server").option("--url <url>","url: the local MCP server URL").option("--env <pair...>","stdio: KEY=VALUE env var (repeatable)").option("--header <pair...>","url: Header:Value request header (repeatable)").action(async e=>{await pe(()=>Zu(e))});ot.command("login").description("Pair this machine with your GAIA account").option("--api <url>","GAIA API base URL (default: this machine's self-host install, else GAIA Cloud)").option("--name <name>","Name to show for this device in Settings").action(async e=>{await pe(async()=>{await fr({...e.api!==void 0?{api:e.api}:{},...e.name!==void 0?{name:e.name}:{}}),console.info("Next: gaia bridge add")})});ot.command("ls").alias("list").description("Show pairing status and configured servers").action(async()=>{await pe(bv)});ot.command("remove").alias("rm").description("Remove a configured server (interactive picker if no key given)").argument("[key]","Server key from `gaia bridge ls` (optional)").action(async e=>{await pe(()=>ed(e))});ot.command("up").alias("start").description("Connect with full file access + serve in the background (stop with: gaia bridge down)").option("--serve","(internal) hold the tunnel in the foreground; used by the background daemon").action(async e=>{await pe(e.serve?Wu:Oo)});ot.command("down").alias("stop").description("Stop the background tunnel started by `gaia bridge up`").action(async()=>{await pe(Vu)});ot.command("logout").description("Forget local credentials").action(async()=>{await pe(()=>{cn(),console.info("Logged out. Your device record remains until you revoke it in GAIA settings.")})});import{Command as Rv}from"commander";import*as Pe from"node:fs/promises";import*as sd from"node:path";import*as rd from"node:os";import*as nd from"node:path";var Ev="https://github.com/theexperiencecompany/gaia/releases/download",$o=`cli-v${A}`,Ks="gaia-connect-SHA256SUMS",td={"darwin-arm64":"gaia-connect-darwin-arm64","darwin-x64":"gaia-connect-darwin-amd64","linux-x64":"gaia-connect-linux-amd64","linux-arm64":"gaia-connect-linux-arm64","win32-x64":"gaia-connect-windows-amd64.exe"};function od(e,t){let r=td[`${e}-${t}`];if(r===void 0)throw new Error(`gaia connect is not available for ${e}/${t}. Supported: ${Object.keys(td).join(", ")}.`);return r}function Ys(e){return`${Ev}/${$o}/${e}`}function id(e){let t=e==="win32"?".exe":"";return nd.join(rd.homedir(),".gaia","bin",`gaia-connect-${A}${t}`)}async function xv(e){try{return await Pe.access(e),!0}catch{return!1}}async function ad(e,t){let r=id(e);if(await xv(r))return r;let n=od(e,t);console.info(`Downloading gaia-connect (${$o})\u2026`);let[o,i]=await Promise.all([ir(Ys(n)),ir(Ys(Ks)).then(a=>a.toString("utf-8"))]);Qn(o,Jn(i,n,`${Ks} on release ${$o}`),n),await Pe.mkdir(sd.dirname(r),{recursive:!0});let s=`${r}.${process.pid}.tmp`;try{await Pe.writeFile(s,o),e!=="win32"&&await Pe.chmod(s,448),await Pe.rename(s,r)}catch(a){throw await Pe.rm(s,{force:!0}),a}return r}import{spawn as Iv}from"node:child_process";async function cd(e,t){return await new Promise((r,n)=>{let o=Iv(e,t,{stdio:"inherit",shell:!1}),i=s=>{o.kill(s)};process.on("SIGINT",i),process.on("SIGTERM",i),o.on("error",s=>{process.off("SIGINT",i),process.off("SIGTERM",i),n(s)}),o.on("close",(s,a)=>{if(process.off("SIGINT",i),process.off("SIGTERM",i),a==="SIGINT"||a==="SIGTERM"){r(0);return}r(s??1)})})}async function Cv(e){let t=await ad(process.platform,process.arch);return await cd(t,e)}var ld=new Rv("connect").description(j.connect).allowUnknownOption().allowExcessArguments().argument("[args...]","flags forwarded to gaia-connect").addHelpText("after",`
|
|
104
104
|
Get an import code from GAIA -> Settings -> Browser -> Import, then run:
|
|
105
105
|
npx @heygaia/cli connect --token <code>
|
|
106
106
|
|
|
@@ -112,13 +112,13 @@ Flags forwarded to gaia-connect:
|
|
|
112
112
|
--sites <domains> comma-separated domains to sync (default: all)
|
|
113
113
|
--json robot mode: no TUI, structured JSON on stdout
|
|
114
114
|
--list with --json: list browsers, or sessions with --browser
|
|
115
|
-
`).action(e=>
|
|
116
|
-
`)},process.platform!=="win32")}finally{try{
|
|
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
|
|
118
|
-
`)}var
|
|
119
|
-
`),n=
|
|
120
|
-
`:"",o]},o))})})},
|
|
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)&&!
|
|
115
|
+
`).action(e=>pe(async()=>process.exit(await Cv(e))));import*as Mo from"fs";import*as ud from"path";import{spawn as kv}from"child_process";async function hr(e,t,r,n,o,i=!1){await Lo([{cmd:e,args:t,cwd:r,env:n,onSpawn:o,detached:i}])}async function Lo(e){e.length!==0&&await new Promise((t,r)=>{let n=e.map(p=>kv(p.cmd,p.args,{cwd:p.cwd,stdio:"inherit",shell:!1,detached:p.detached??!1,env:p.env?{...process.env,...p.env}:process.env}));n.forEach((p,m)=>{e[m]?.onSpawn?.(p.pid)});let o=!1,i=0,s=!1,a,c=()=>{process.off("SIGINT",d),process.off("SIGTERM",d)},l=()=>{if(!s){s=!0;for(let[p,m]of n.entries()){let g=e[p];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGTERM"):m.kill("SIGTERM")}catch{}}a=setTimeout(()=>{for(let[p,m]of n.entries()){let g=e[p];try{process.platform!=="win32"&&g?.detached&&typeof m.pid=="number"?process.kill(-m.pid,"SIGKILL"):m.kill("SIGKILL")}catch{}}},1e3)}},d=()=>{l()};process.on("SIGINT",d),process.on("SIGTERM",d),n.forEach((p,m)=>{let g=e[m];p.on("error",v=>{o||(o=!0,c(),l(),r(v))}),p.on("close",(v,E)=>{if(i+=1,!(v===0||(E==="SIGINT"||E==="SIGTERM"||v===130||v===143||s))&&!o){o=!0,c(),l(),r(new Error(`Command failed with code ${String(v)}: ${g?.cmd??"unknown"} ${g?.args.join(" ")??""}`));return}i>=n.length&&!o&&(o=!0,c(),a&&clearTimeout(a),t())})})})}async function dd(e){if(e&&e!=="full")throw new Error(`Invalid developer profile: '${e}'. Use 'gaia dev' or 'gaia dev full'.`);let t=lr();if(!t)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let r=await $(t);if(!r)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");if(r!=="developer")throw new Error("Developer mode is not enabled for this repo. Use 'gaia start' for self-host mode.");let n=ud.join(t,oo);try{await hr("mise",[e==="full"?"dev:full":"dev"],t,void 0,o=>{typeof o=="number"&&o>0&&Mo.writeFileSync(n,`${o}
|
|
116
|
+
`)},process.platform!=="win32")}finally{try{Mo.unlinkSync(n)}catch{}}}import ne from"chalk";import*as md from"node:fs";import*as Ht from"node:os";import{execa as pd}from"execa";var Av={mongodb:{service:"mongo",cause:"a full disk is the usual cause; users, chats and settings live here"},postgres:{service:"postgres",cause:"a full disk is the usual cause; agent state lives here"},redis:{service:"redis",cause:"background jobs and reminders queue here and wait until it is back"},rabbitmq:{service:"rabbitmq",cause:"it takes up to a minute to boot after a restart, so rerun first"},chromadb:{service:"chromadb",cause:"memory and file search stay unavailable until it answers"}};function Pv(e,t){let r=Av[e];return r?`Check its logs: docker compose -p ${t} logs ${r.service} (${r.cause}).`:`Check the API logs: docker compose -p ${t} logs gaia-backend`}async function No(e,t){let r;try{r=await fetch(`${e}/health/ready`,{signal:AbortSignal.timeout(5e3)})}catch(o){return{reachable:!1,detail:`Could not reach ${e}/health/ready: ${o.message}`}}if(!r.ok&&r.status!==503)return{reachable:!1,detail:`HTTP ${r.status} from ${e}/health/ready`};let n=await r.json();return{reachable:!0,ready:n.status==="ready",dependencies:n.dependencies.map(o=>o.ok?o:{...o,fix:Pv(o.name,t)})}}var Tv=2*1024*1024*1024,_v=4*1024*1024*1024,Dv=2*1024*1024*1024,fd={"gaia-selfhost":["chromadb","postgres","redis","mongo","rabbitmq","gaia-backend","gaia-web","arq_worker","proxy"],"gaia-dev":["chromadb","postgres","redis","mongo","rabbitmq"]};function zs(e){return e==="running"?"running":e==="restarting"?"restarting":"stopped"}function Ov(e,t){return t.every(r=>e.some(n=>n.service===r&&zs(n.state)==="running"))}function $v(e,t){return t.map(r=>({service:r,info:e.find(n=>n.service===r)})).filter(({info:r})=>!r||zs(r.state)!=="running").map(({service:r,info:n})=>n?`${r} ${zs(n.state)}`:`${r} missing`).join(", ")}function gd(e,t){return e[t]??t}async function hd(e,t={}){let r={id:"port-conflict",label:"Ports",severity:"blocker"},n;try{n=await ho(e,t)}catch{return{...r,state:"skipped",detail:"Could not check ports"}}let o=n.filter(s=>!s.available);if(o.length===0)return{...r,state:"ok",detail:"no conflicts"};let i=o.map(s=>`:${s.port} in use by ${s.usedBy??"unknown"}`).join(", ");return{...r,state:"fail",detail:i,fix:e==="selfhost"?"Free the port or re-run 'gaia up' with --web-port (or set WEB_HOST_PORT in infra/docker/.env).":"Free the port or set its *_HOST_PORT override in infra/docker/.env."}}function Lv(e){return`Open ${e}/setup in your browser to finish setting GAIA up.`}function Mv(e,t,r){let o=[{label:"LLM provider configured",configured:t.some(i=>e.providers?.[i]?.configured===!0),missing:"no AI provider yet"},{label:"admin account created",configured:e.has_admin_account===!0,missing:"no admin account yet"}];return e.deployment.bills&&o.push({label:"plans seeded",configured:e.plans_seeded,missing:"billing plans not set up yet"}),o.map(i=>({...i,fix:i.configured?"":Lv(r)}))}function Nv(e){let r=e.trim().split(`
|
|
117
|
+
`).filter(i=>i.trim().length>0).at(-1);if(!r)return null;let n=r.trim().split(/\s+/),o=Number(n[3]);return!Number.isFinite(o)||o<0?null:o}async function Sd(e){let t={id:"docker-daemon",label:"Docker",severity:"blocker"};if(e==="ready")return{...t,state:"ok",detail:"running"};let r=await tt(e);return{...t,state:"fail",detail:r.state,fix:r.fix}}async function vd(e){let t={id:"compose-containers",label:"Containers",severity:"blocker"},r;try{r=await Pt(e.project)}catch{return{...t,state:"skipped",detail:"they need Docker"}}return Ov(r,e.expected)?{...t,state:"ok",detail:`${e.expected.length} services running`}:{...t,state:"fail",detail:$v(r,e.expected),fix:`Run 'gaia start' to bring the stack up, or check 'docker compose -p ${e.project} logs'.`}}function yd(e){let t={id:"compose-containers",label:"GAIA",severity:"blocker",state:"fail"};return e?{...t,detail:`${e} isn't set up yet (no apps/api/.env)`,fix:"Run 'gaia up' to finish setting it up, or 'gaia setup' for a development checkout."}:{...t,detail:"isn't installed yet",fix:Li}}async function wd(e,t="gaia start"){let r={id:"api-health",label:"API",severity:"blocker"};try{let n=await co(`${e}/ping`);return n.ok?{...r,state:"ok",detail:`answering at ${e}`}:{...r,state:"fail",detail:`answered HTTP ${n.status} at ${e}/ping`,fix:`See why with 'gaia logs', then restart it with '${t}'.`}}catch{return{...r,state:"fail",detail:`not answering at ${e}`,fix:`Start GAIA with '${t}'.`}}}async function bd(e){let t={id:"dependencies",label:"Dependencies",severity:"blocker"};if(!e.apiHealthy)return[{...t,state:"skipped",detail:"they need GAIA's API"}];let r=await No(e.origin,e.project);return r.reachable?r.dependencies.map(n=>({id:`dependency-${n.name}`,label:Wn(n.name),severity:"blocker",state:n.ok?"ok":"fail",detail:n.ok?`${Math.round(n.latency_ms)} ms`:`${n.error_type??"failed"} after ${Math.round(n.latency_ms)} ms`,fix:n.fix})):[{...t,state:"fail",detail:r.detail,fix:"Run 'gaia update': an API or proxy older than this CLI does not serve /health/ready."}]}async function Ed(e,t="gaia start"){let r={id:"web-reachable",label:"Web app",severity:"blocker"};try{let n=await co(`http://localhost:${e}`,{method:"HEAD"});return n.ok?{...r,state:"ok",detail:`answering at http://localhost:${e}`}:{...r,state:"fail",detail:`answered HTTP ${n.status} at http://localhost:${e}`,fix:`See why with 'gaia logs', then restart it with '${t}'.`}}catch{return{...r,state:"fail",detail:`not answering at http://localhost:${e}`,fix:`Start GAIA with '${t}'.`}}}async function xd(e){let t={id:"setup-readiness",label:"Setup",severity:"warning"};if(!e.apiHealthy)return[{...t,state:"skipped",detail:"they need GAIA's API"}];let[r,n]=await Promise.all([He(e.apiUrl,"status"),He(e.apiUrl,"catalog")]);if("detail"in r)return[{...t,state:"skipped",detail:r.detail}];if("detail"in n)return[{...t,state:"skipped",detail:n.detail}];let o=Mv(r.data,n.data.llm_provider_keys,e.webUrl);if(o.every(s=>s.configured))return[{...t,state:"ok",detail:"finished"}];let i=o.filter(s=>!s.configured);return[{...t,state:"fail",detail:`not finished: ${i.map(s=>s.missing).join(", ")}`,fix:i[0]?.fix}]}async function Xs(e=Tv){let t={id:"disk-headroom",label:"Disk space",severity:"blocker"},r;try{r=await Wa()}catch{return{...t,state:"skipped",detail:"they need Docker"}}let n;try{let i=await Ka(r),s=Nv(i);n=s===null?null:s*1024}catch{n=null}if(n===null)return{...t,state:"skipped",detail:`Could not read disk usage for ${r}`};let o=i=>`${(i/1024**3).toFixed(1)} GB`;return n>=e?{...t,state:"ok",detail:`${o(n)} free at ${r}`}:{...t,state:"fail",detail:`${o(n)} free at ${r}, need \u2265 ${o(e)}`,fix:"Free up disk space (e.g. 'docker system prune') before pulling/building images."}}function Fv(e){let t=e.match(/^MemAvailable:\s+(\d+)\s+kB/m);if(t?.[1]){let n=Number(t[1]);if(Number.isFinite(n)&&n>=0)return n*1024}let r=e.match(/^MemTotal:\s+(\d+)\s+kB/m);if(r?.[1]){let n=Number(r[1]);if(Number.isFinite(n)&&n>=0)return n*1024}return null}function Bv(e){let t=e.match(/page size of (\d+) bytes/),r=t?.[1]?Number(t[1]):4096,n=e.match(/Pages free:\s+(\d+)/),o=e.match(/Pages inactive:\s+(\d+)/),i=e.match(/Pages speculative:\s+(\d+)/);if(!(n||o||i))return null;let s=l=>l?Number(l[1]):0,a=s(n),c=s(o);return!Number.isFinite(a)||!Number.isFinite(c)||!Number.isFinite(r)||r<=0?null:(a+c+s(i))*r}function Js(e){try{return e()}catch{return null}}function Gv(){try{let e=md.readFileSync("/proc/meminfo","utf-8"),t=Fv(e);if(t!==null)return t}catch{}return Js(()=>Ht.freemem())}async function Uv(){try{let{stdout:e}=await pd("vm_stat",[]),t=Bv(e);if(t!==null)return t}catch{}try{let{stdout:e}=await pd("sysctl",["-n","hw.memsize"]),t=Number(e.trim());if(Number.isFinite(t)&&t>0)return t}catch{}return Js(()=>Ht.totalmem())}async function jv(){let e=Ht.platform();return e==="linux"?Gv():e==="darwin"?Uv():Js(()=>Ht.freemem())}async function Qs(){let e=await jv().catch(()=>null);if(e===null)return{id:"memory-headroom",label:"Memory",severity:"blocker",state:"skipped",detail:"Could not read available memory"};let t=r=>`${(r/1024**3).toFixed(1)} GB`;return e<Dv?{id:"memory-headroom",label:"Memory",severity:"blocker",state:"fail",detail:`${t(e)} free; GAIA needs at least 2 GB to start`,fix:"Close other apps or add RAM before starting GAIA."}:e<_v?{id:"memory-headroom",label:"Memory",severity:"warning",state:"fail",detail:`${t(e)} free; GAIA's API uses about 2.5 GB and may run out during chats`,fix:"Close other apps or add RAM."}:{id:"memory-headroom",label:"Memory",severity:"blocker",state:"ok",detail:`${t(e)} free`}}async function Id(e,t,r=uo){let n={id:"gaia-version",label:"GAIA version",severity:"warning"};if(!e)return{...n,state:"skipped",detail:"GAIA isn't installed"};if(t!=="selfhost")return{...n,state:"skipped",detail:"Developer checkout: update it with 'gaia update --git'"};let o=Ue(e);if(ft(o)===null)return{...n,state:"ok",detail:`development build (${lo(o)})`};let i=await r();return i&&nt(i,o)?{...n,state:"fail",detail:`${i} is available (this install runs ${o})`,fix:"Run 'gaia update'. Your data and settings are kept."}:{...n,state:"ok",detail:o}}async function Rd(e,t){if(e.length===0)return[];let r;try{r=await Pt(t)}catch{r=null}return e.map(n=>{let o={id:`bot-${n}`,label:$e(Ie(n)),severity:"warning"};if(!r)return{...o,state:"skipped",detail:"they need Docker"};let{health:i,detail:s}=Hr(n,r);return i!=="failing"?{...o,state:"ok",detail:s}:{...o,state:"fail",detail:s,fix:`A rejected or revoked token keeps the bot restarting: check 'docker compose -p ${t} logs ${Ie(n)}', then rerun 'gaia bots add ${n}' with a fresh token.`}})}function Cd(e){return e.results.some(t=>t.severity==="blocker"&&t.state==="fail")}async function qv(){let e=L(),t=e?k(e):{},r=e?await $(e):null;return{repoPath:e,origin:Lt(r??"selfhost",t),apiUrl:me(r??"selfhost",t),webPort:gd(t,3e3),overrides:t,mode:r,project:r?Ee[r]:null}}async function kd(){let e=[],[t,r]=await Promise.all([qv(),ee()]);if(e.push(await Sd(r)),e.push(r==="ready"?await hd(t.mode??"selfhost",t.overrides):{id:"port-conflict",label:"Ports",severity:"blocker",state:"skipped",detail:"they need Docker"}),!t.repoPath||!t.project||!t.mode){e.push(yd(t.repoPath));for(let i of["API","Setup","Web app"])e.push({label:i,severity:"blocker",state:"skipped",detail:"GAIA isn't installed"});return e.push(await Xs()),e.push(await Qs()),{install:zr(t.repoPath,t.mode),installed:!1,results:e}}let n=t.mode==="developer"?"gaia dev":"gaia start";e.push(await vd({project:t.project,expected:fd[t.project]})),t.project===Ee.selfhost&&e.push(...await Rd(P()?.bots??[],t.project));let o=await wd(t.apiUrl,n);return e.push(o),e.push(...await bd({apiHealthy:o.state==="ok",origin:t.origin,project:t.project})),e.push(...await xd({apiHealthy:o.state==="ok",apiUrl:t.apiUrl,webUrl:mt(t.repoPath,t.webPort)})),e.push(await Ed(t.webPort,n)),e.push(await Xs()),e.push(await Qs()),e.push(await Id(t.repoPath,t.mode)),{install:zr(t.repoPath,t.mode),installed:!0,results:e}}function Vt(e=""){process.stdout.write(`${e}
|
|
118
|
+
`)}var Ad=16,ea=" ",Hv={ok:ne.green,fail:ne.red,warn:ne.yellow,skip:ne.gray,pending:ne.gray,active:ne.cyan,cancelled:ne.yellow};function Vv(e){return e.state==="ok"?"ok":e.state==="skipped"?"skip":e.severity==="warning"?"warn":"fail"}var Zs=ea.length+2+Ad;function Wv(e,t){let r=Vv(e),n=e.detail?ne.gray(pt(e.detail,Zs)):"";Vt(`${ea}${Hv[r](y[r])} ${e.label.padEnd(Ad)}${n}`),e.state==="fail"&&e.fix&&t?.fix!==e.fix&&Vt(`${" ".repeat(Zs)}${pt(e.fix,Zs)}`)}function Kv(e){let t=new Map;for(let r of e){let n=r.detail??"skipped";t.set(n,[...t.get(n)??[],r.label])}for(let[r,n]of t)Vt(`${ea}${ne.gray(y.skip)} ${ne.gray(`Not checked: ${n.join(", ")} (${r})`)}`)}function Yv(e){let t=e.results.filter(o=>o.severity==="blocker"&&o.state==="fail").length,r=e.results.filter(o=>o.severity==="warning"&&o.state==="fail").length;if(t===0&&r===0)return ne.green(`${y.ok} Everything checked out`);let n=[];return t>0&&n.push(ne.red(`${t} problem${t===1?"":"s"}`)),r>0&&n.push(ne.yellow(`${r} warning${r===1?"":"s"}`)),n.join(" \xB7 ")}function zv(e){Vt(e.installed?`${ne.bold("Checking")} ${e.install}`:ne.bold("Checking this computer")),Vt();let t=e.results.filter(r=>r.state!=="skipped");t.forEach((r,n)=>{Wv(r,t[n+1])}),Kv(e.results.filter(r=>r.state==="skipped")),Vt(),Vt(Yv(e))}async function Pd(){await Mt();let e=await kd();zv(e),Cd(e)&&(process.exitCode=1)}import{render as Kb}from"ink";import Yb from"react";import{ThemeProvider as Bb}from"@inkjs/ui";import{Box as mi,Text as Xt,useInput as Gb}from"ink";import Ub from"react";import{ConfirmInput as Zy}from"@inkjs/ui";import{Box as Yt,Static as ew,Text as ua}from"ink";import{Box as Go,Text as mn}from"ink";import{useStdout as Xv}from"ink";import{useEffect as Jv,useState as Qv}from"react";function Fo(){let{stdout:e}=Xv(),[t,r]=Qv(()=>Jr(e));return Jv(()=>{let n=()=>r(Jr(e));return e.on("resize",n),()=>{e.off("resize",n)}},[e]),t}var Zv=100;function Bo(){return Math.min(Fo().columns,Zv)}import{jsx as Sr,jsxs as Uo}from"react/jsx-runtime";var Td=16,ey=6,ty={primary:void 0,warn:"yellow",dim:"gray"},ry=({row:e,width:t})=>{let r=e.tone?ty[e.tone]:void 0,n=Ji(e.text,t);if(!e.url)return Sr(mn,{color:r,children:n});let[o,i]=n.split(e.url);return Uo(mn,{color:r,children:[o,Sr(mn,{color:"cyan",bold:!0,underline:!0,children:e.url}),i]})},jo=({headline:e,rows:t,accent:r,success:n})=>{let o=Bo();return Uo(Go,{flexDirection:"column",borderStyle:_,borderColor:r,paddingX:2,paddingY:1,width:o,children:[Uo(mn,{bold:!0,color:r,children:[n?`${y.ok} `:"",e]}),Sr(Go,{flexDirection:"column",marginTop:1,children:t.map(i=>Uo(Go,{marginBottom:i.tone==="primary"?1:0,children:[Sr(Go,{width:Td,flexShrink:0,children:Sr(mn,{bold:i.tone==="primary",children:i.label})}),Sr(ry,{row:i,width:o-ey-Td})]},i.label))})]})};import{Spinner as ly}from"@inkjs/ui";import{Box as Te,Text as wr}from"ink";import{useEffect as uy,useState as dy}from"react";function vr(e=Date.now){let t=[];return{update(r,n){let o=e();for(t.push({at:o,done:r});t.length>2&&o-(t[1]?.at??o)>=1e4;)t.shift();let i=t[0];if(!i||o-i.at<2e3)return null;let s=(r-i.done)/(o-i.at);return s<=0?null:Math.round(Math.max(0,n-r)/s)}}}function _d(e){return e<6e4?"less than a minute left":e<36e5?`about ${Math.round(e/6e4)} min left`:`about ${Math.round(e/36e5)} h left`}function ta(e,t){return t!==void 0?t:e.total<=0?0:Math.min(100,Math.floor(e.done/e.total*100))}function fn(e,t={}){let r=e.unit==="bytes"?Ot(e.done,e.total,e.estimated):`${e.done} / ${e.total} services`,n=t.etaMs!==void 0&&t.etaMs!==null?` \xB7 ${_d(t.etaMs)}`:"";return`${ta(e,t.percent)}% ${r}${n}`}import{Box as ny,Text as oy}from"ink";import{jsx as Dd}from"react/jsx-runtime";var z=({kind:e})=>Dd(ny,{marginRight:1,children:Dd(oy,{color:Lr[e],children:y[e]})});import{ProgressBar as iy}from"@inkjs/ui";import{Box as Od,Text as sy}from"ink";import{jsx as ra,jsxs as cy}from"react/jsx-runtime";var ay=30,yr=({percent:e,caption:t})=>cy(Od,{children:[ra(Od,{width:ay,children:ra(iy,{value:e})}),ra(sy,{dimColor:!0,children:` ${t??`${e}%`}`})]});import{jsx as R,jsxs as gn}from"react/jsx-runtime";var $d=36,Ld=8,Md=2,Nd=2,py=$d+Ld-Nd,my=1e3,fy=2e3;function na(e){let[t,r]=dy(Date.now());return uy(()=>{if(!e)return;let n=setInterval(()=>r(Date.now()),my);return()=>clearInterval(n)},[e]),t}function gy(e){return e.padEnd(Math.max($d,e.length+Md))}function oa(e,t){return e.startedAt===void 0?"":gt((e.endedAt??t)-e.startedAt)}function hy(e){return e.state==="skipped"?!1:e.minor?Sy(e)>=fy:!0}function Sy(e){return e.startedAt===void 0||e.endedAt===void 0?0:e.endedAt-e.startedAt}function qo(e){let t=e.findIndex(n=>n.state!=="done"&&n.state!=="skipped"),r=t===-1?e.length:t;return{finished:e.slice(0,r).filter(hy),live:e.slice(r)}}var ia=({mark:e,label:t,bold:r=!1,time:n})=>gn(Te,{children:[e,R(wr,{bold:r,children:gy(t)}),R(wr,{dimColor:!0,children:n.padStart(Ld)})]}),Ho=({step:e})=>R(ia,{mark:R(z,{kind:"ok"}),label:e.doneLabel,time:oa(e,Date.now())}),vy=({step:e})=>R(ia,{mark:R(z,{kind:e.state==="failed"?"fail":"cancelled"}),label:e.label,time:oa(e,Date.now())}),Fd=()=>R(Te,{marginRight:1,children:R(ly,{})}),yy=({state:e})=>e==="active"?R(Fd,{}):e==="done"?R(z,{kind:"ok"}):e==="failed"?R(z,{kind:"fail"}):R(Te,{width:2}),wy=({substep:e})=>{let t=e.state!=="active";return gn(Te,{children:[R(yy,{state:e.state}),gn(Te,{width:py,children:[R(Te,{flexGrow:1,flexShrink:0,children:R(wr,{dimColor:t,children:e.label})}),e.note&&R(Te,{flexShrink:1,marginLeft:Md,children:R(wr,{dimColor:!0,wrap:"truncate",children:e.note})})]})]})},Vo=({step:e,waiting:t,status:r})=>{let n=na(!t);if(e.state==="failed"||e.state==="cancelled")return R(vy,{step:e});let o=e.substeps??[],i=o.length>0?void 0:e.detail??(r||void 0);return gn(Te,{flexDirection:"column",children:[R(ia,{mark:t?R(z,{kind:"pending"}):R(Fd,{}),label:e.label,bold:!0,time:t?"":oa(e,n)}),gn(Te,{flexDirection:"column",marginLeft:Nd,children:[e.amount&&R(Te,{marginLeft:2,children:R(yr,{percent:ta(e.amount,e.percent),caption:fn(e.amount,{percent:e.percent,etaMs:e.etaMs})})}),o.map(s=>R(wy,{substep:s},s.id)),i&&R(Te,{marginLeft:2,children:R(wr,{dimColor:!0,wrap:"truncate",children:i})}),e.hint&&R(Te,{marginLeft:2,children:R(wr,{dimColor:!0,children:e.hint})})]})]})};import{Alert as Bd,ConfirmInput as by,Spinner as Gd}from"@inkjs/ui";import{Box as Y,Text as W,useInput as Ey}from"ink";import{jsx as I,jsxs as X}from"react/jsx-runtime";var Wo=({checks:e})=>X(Y,{flexDirection:"column",borderStyle:_,paddingX:1,borderColor:w,children:[I(W,{bold:!0,children:"System Checks"}),X(Y,{flexDirection:"column",marginTop:1,children:[I(sa,{label:"Git",status:e.git}),e.docker&&I(sa,{label:"Docker",status:e.docker}),e.mise&&I(sa,{label:"Mise",status:e.mise})]})]}),Ko=({status:e})=>X(Y,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[I(W,{bold:!0,children:"Environment Setup"}),I(Y,{marginTop:1,children:I(Gd,{label:e||"Configuring environment\u2026"})})]}),Ud=({title:e,progress:t,phase:r})=>X(Y,{flexDirection:"column",borderStyle:_,padding:1,borderColor:w,children:[I(W,{bold:!0,children:e}),X(Y,{marginTop:1,flexDirection:"column",children:[I(yr,{percent:t||0}),r&&I(W,{color:"gray",children:r})]})]}),_e=({message:e})=>{let[t="",...r]=e.split(`
|
|
119
|
+
`),n=Bo();return r.length===0?I(Y,{marginTop:1,width:n,children:I(Bd,{variant:"error",children:t})}):I(Y,{marginTop:1,width:n,children:I(Bd,{variant:"error",title:t,children:r.map((o,i)=>X(W,{color:o.startsWith("Full log:")?"gray":void 0,children:[i>0?`
|
|
120
|
+
`:"",o]},o))})})},xy={success:"ok",error:"fail",missing:"warn"},sa=({label:e,status:t})=>X(Y,{children:[t==="pending"?I(Y,{marginRight:1,children:I(Gd,{type:"dots"})}):I(z,{kind:xy[t]}),I(W,{children:e})]}),br=({portResults:e,onAccept:t,onAbort:r})=>{Ey((o,i)=>{i.return?t():i.escape&&r()});let n=e.filter(o=>!o.available);return X(Y,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:"yellow",children:[I(Y,{marginBottom:1,children:I(W,{bold:!0,color:"yellow",children:"Port Conflicts Detected"})}),e.map(o=>X(Y,{children:[X(W,{color:o.available?"green":o.alternative?"yellow":"red",children:[o.available?y.ok:o.alternative?y.warn:y.fail," "]}),X(W,{children:[o.service," (:",o.port,")"]}),!o.available&&X(W,{color:o.alternative?"gray":"red",children:[" ","- in use",o.usedBy?` by ${o.usedBy}`:"",o.alternative?` \u2192 will use :${o.alternative}`:" \u2014 NO ALTERNATIVE FOUND"]})]},o.port)),n.some(o=>!o.alternative)&&I(Y,{marginTop:1,children:I(W,{color:"red",children:"Some ports have no available alternative. Free them and retry."})}),!n.some(o=>!o.alternative)&&n.some(o=>o.alternative)&&I(Y,{marginTop:1,children:I(W,{color:"gray",children:"Alternative ports will be used for conflicting services."})}),I(Y,{marginTop:1,children:X(W,{dimColor:!0,children:[I(W,{bold:!0,children:"Enter"})," continue \xB7 ",I(W,{bold:!0,children:"Esc"})," cancel"]})})]})},Iy=({missing:e,onConfirm:t,onDecline:r})=>{let n=e.length>1?"aren't":"isn't";return X(Y,{flexDirection:"column",marginTop:1,children:[X(W,{children:["GAIA needs ",I(W,{bold:!0,children:ur(e)}),", which ",n," ","installed yet."]}),X(Y,{children:[X(W,{children:["Install ",e.length>1?"them":"it"," now?"," ",I(W,{dimColor:!0,children:"(uses sudo, a few minutes)"})," "]}),I(by,{onConfirm:t,onCancel:r})]})]})},Er=({inputId:e,missing:t,onConfirm:r,onDecline:n})=>e!==fs||!t?.length?null:I(Iy,{missing:t,onConfirm:r,onDecline:n});import{useEffect as Ry,useState as Cy}from"react";function Se(e){let[t,r]=Cy(e.currentState);return Ry(()=>{let n=()=>r({...e.currentState});return e.on("change",n),()=>{e.off("change",n)}},[e]),t}import*as Rr from"node:fs";import*as dp from"node:os";import*as Cr from"node:path";import*as jd from"node:os";import*as qd from"node:path";var ky=80,Ay=443,Hd=qd.join(jd.homedir(),"gaia");function Yo(){let e=P()?.repoPath;return e&&cr(e)?e:null}function Vd(e){let t={};return e.domain&&(t[O]=ky,t[Qr]=Ay),e.webPort&&(t[O]=e.webPort),t}function Py(){return P()?.values??{}}function Ty(e){return _n().flatMap(t=>t.variables).find(t=>t.name===e)}function Wd(e){let{repoPath:t,interactive:r=he(),setupMode:n="selfhost"}=e,o=Py(),i=new Set(Br()),s=new Map,a=l=>(s.has(l)||s.set(l,Ty(l)?.required===!0),s.get(l)===!0),c=l=>{let d=o[l]??Fr(l,n);if(d)return d;if(!r&&a(l))throw new Error(`${l} is required but could not be resolved in non-interactive mode \u2014 provide it via a GAIA flag or an apps/api/.env file.`);return""};return(l,d)=>{switch(l){case"setup_mode":return"selfhost";case"env_method":return"manual";case"env_alternatives":return{selectedGroups:[],values:{}};case"env_group":return{};case"env_var":{let p=d?.varName;return!p||i.has(p)?"":c(p)}case"repo_path":return t;case"existing_repo":return"use_existing";case"port_conflicts":return"accept";default:return}}}import*as Wt from"node:fs";import*as rp from"node:http";import*as Kt from"node:path";import{execa as Ir}from"execa";import{z as Qd}from"zod";import*as xr from"node:fs";import*as Kd from"node:os";import*as Yd from"node:path";import{execa as aa}from"execa";var hn="gaia-local-name-ipv6.service",ca=`/etc/systemd/system/${hn}`,_y=["temporary","deprecated","tentative","dadfailed"];function Dy(e){return/\bdev (\S+)/.exec(e)?.[1]??null}function Oy(e,t){let r=e.split(`
|
|
121
|
+
`).map(o=>/^\d+:\s+(\S+)\s+inet6\s+([0-9a-f:]+)\/\d+\s+(.*)$/.exec(o)).filter(o=>o!==null).map(([,o="",i="",s=""])=>({device:o,address:i,flags:s})).filter(({device:o,flags:i})=>!Qi.test(o)&&!_y.some(s=>i.split(/\s+/).includes(s)));return(r.find(({device:o})=>o===t)??r[0])?.address??null}function $y(e,t,r){return`[Unit]
|
|
122
122
|
Description=Announce ${t}'s IPv6 address over mDNS (GAIA)
|
|
123
123
|
Requires=avahi-daemon.service
|
|
124
124
|
After=avahi-daemon.service network-online.target
|
|
@@ -131,37 +131,37 @@ RestartSec=2
|
|
|
131
131
|
|
|
132
132
|
[Install]
|
|
133
133
|
WantedBy=multi-user.target
|
|
134
|
-
`}async function
|
|
135
|
-
Delete it yourself if you no longer need it.`)}:{installDir:e}}async function
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
`)})})};import{jsx as bt,jsxs as ii}from"react/jsx-runtime";var Bw=[{id:"Welcome",label:"Welcome"},{id:"Prerequisites",label:"Prereqs"},{id:"Setup Mode",label:"Mode"},{id:"Repository Setup",label:"Repo"},{id:"Environment Setup",label:"Env"},{id:"Install Tools",label:"Tools"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],kp=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Gw=({currentStep:e,steps:t})=>{let r=t.findIndex(o=>o.id===e),n=r===t.length-1;return bt(wn,{marginY:1,flexWrap:"wrap",children:t.map(({id:o,label:i},s)=>{let a=s<r||n,c=s===r&&!n;return ii(wn,{flexShrink:0,children:[s>0&&bt(oi,{color:"gray",children:" \xB7 "}),a&&ii(oi,{color:"green",children:[y.ok," ",i]}),c&&bt(oi,{color:w,bold:!0,children:i}),!a&&!c&&bt(oi,{color:"gray",children:i})]},o)})})},si=({children:e,status:t,step:r,steps:n=Bw,header:o})=>ii(wn,{flexDirection:"column",height:"100%",width:"100%",children:[ii(wn,{flexGrow:1,flexDirection:"column",children:[bt(Tr,{...o}),bt(Gw,{currentStep:r,steps:n}),bt(wn,{flexDirection:"column",flexGrow:1,children:e})]}),bt(Ep,{status:t,step:r})]});import{jsx as d,jsxs as S}from"react/jsx-runtime";var jw=({onConfirm:e})=>(_r((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:T,borderColor:w,children:[d(f,{bold:!0,children:"Welcome to GAIA Setup"}),S(h,{flexDirection:"column",marginTop:1,marginBottom:1,children:[d(f,{children:"This wizard will guide you through the setup process:"}),d(f,{children:" 1. Check prerequisites and choose setup mode"}),d(f,{children:" 2. Clone repository"}),d(f,{children:" 3. Configure environment variables"}),d(f,{children:" 4. Install tools and dependencies"})]}),d(f,{dimColor:!0,children:"~5-15 min depending on network speed"}),d(h,{marginTop:1,children:S(f,{color:w,children:[d(f,{bold:!0,children:"Enter"})," to start"]})})]})),qw=({defaultValue:e,onSubmit:t})=>{let[r,n]=we(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(f,{children:"Clone repository to:"}),d(f,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),S(h,{marginTop:1,children:[d(f,{color:w,children:"\u2192 "}),d(bn,{value:r,onChange:n,onSubmit:t})]})]})},Hw=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:"yellow",children:[d(h,{marginBottom:1,children:d(f,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),S(f,{children:["Found a GAIA installation at"," ",d(f,{color:"cyan",bold:!0,children:e})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"What would you like to do?"})}),d(h,{marginTop:1,children:d(fa,{options:[{label:"Use existing installation",value:"use_existing"},{label:"Delete and re-clone",value:"delete_reclone"},{label:"Choose a different path",value:"different_path"},{label:"Exit setup",value:"exit"}],onChange:n=>t(n)})})]}),Vw=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:n})=>{_r((s,a)=>{a.return&&n()});let o=t?.[3e3]??3e3,i=de(e??"developer",t??{});return e==="selfhost"?S(h,{flexDirection:"column",marginTop:2,borderStyle:T,borderColor:"green",padding:1,children:[d(f,{bold:!0,color:"green",children:r?"GAIA is starting\u2026":"GAIA is running"}),d(h,{marginTop:1,children:d(f,{color:"green",children:r?"Containers are up but not answering yet":"\u2713 All services started"})}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Finish setup in your browser:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o,"/setup"]})]}),S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),S(f,{children:["API:"," ",d(f,{color:"cyan",bold:!0,children:i})]})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia doctor"})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," to exit"]})})]}):S(h,{flexDirection:"column",marginTop:2,borderStyle:T,borderColor:w,padding:1,children:[d(f,{color:w,bold:!0,children:"You're all set!"}),S(h,{marginTop:1,children:[d(f,{bold:!0,children:"Run: "}),d(f,{color:"cyan",children:"$ gaia dev"})]}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),S(f,{children:["API:"," ",d(f,{color:"cyan",bold:!0,children:i})]})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," to exit"]})})]})},ha=({phase:e,progress:t,isComplete:r,logs:n,title:o,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(h,{marginBottom:1,children:d(f,{bold:!0,color:w,children:o||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[d(h,{children:r?S(f,{color:"green",children:[y.ok," ",e]}):d(Uw,{label:e||"Preparing\u2026"})}),!r&&t>0&&d(yr,{percent:t}),!r&&n&&n.length>0&&d(ni,{logs:n}),!r&&d(h,{marginTop:1,children:d(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),Sa=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(f,{bold:!0,children:"Setup Mode"}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"How do you want to run GAIA?"})}),d(h,{marginTop:1,children:d(fa,{options:[{label:"Self-Host \u2014 run everything in Docker",value:"selfhost"},{label:"Developer \u2014 local dev with hot reload",value:"developer"}],onChange:r=>e(r)})})]}),va=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(f,{bold:!0,children:"Environment Variables Setup"}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"Choose how you want to configure environment variables:"})}),d(h,{marginTop:1,children:d(fa,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),S(h,{marginTop:1,flexDirection:"column",children:[d(f,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),d(f,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),ya=({onSubmit:e})=>{let[t,r]=we({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[n,o]=we(0),[i,s]=we(null),a=[{key:"INFISICAL_PROJECT_ID",description:"Found in your Infisical project settings"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_ID",description:"From Access Control \u2192 Machine Identities"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET",description:"Generated when creating the machine identity"}];_r((l,u)=>{if(u.tab||u.downArrow)o(p=>p<a.length-1?p+1:p);else if(u.upArrow)o(p=>p>0?p-1:p);else if(u.return){if(n<a.length-1){o(m=>m+1);return}let p=a.filter(m=>!t[m.key].trim());if(p.length>0){s(`Required: ${p.map(g=>g.key).join(", ")}`);let m=a.findIndex(g=>!t[g.key].trim());m>=0&&o(m);return}e(t)}});let c=a[n];return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:w,children:[d(h,{marginBottom:1,children:d(f,{bold:!0,color:w,children:"Infisical Configuration"})}),d(h,{marginBottom:1,children:d(f,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),S(h,{marginBottom:1,flexDirection:"column",children:[d(f,{color:"gray",children:"Configure your Infisical credentials."}),S(f,{color:"gray",dimColor:!0,children:["Visit"," ",d(f,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),a.map((l,u)=>{let p=l.key.includes("SECRET")||l.key.includes("TOKEN");return S(h,{flexDirection:"column",marginBottom:1,children:[d(h,{children:S(f,{color:u===n?w:"white",children:[u===n?"\u25B8 ":" ",l.key,":"]})}),d(h,{marginLeft:2,children:d(f,{color:"gray",dimColor:!0,children:l.description})}),u===n?d(h,{marginLeft:2,children:d(bn,{value:t[l.key],onChange:m=>{r(g=>({...g,[l.key]:m})),s(null)},placeholder:"Enter value\u2026",mask:p?"*":void 0})}):d(h,{marginLeft:2,children:d(f,{color:t[l.key]?"green":"gray",children:t[l.key]?p?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[l.key]}`:"(not set)"})})]},l.key)}),i&&d(h,{marginTop:1,children:d(f,{color:"red",children:i})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," confirm \xB7 ",d(f,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},wa=({category:e,currentIndex:t,totalGroups:r,onSubmit:n})=>{let[o,i]=we(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=we(0),[c,l]=we(null);ga(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),_r((m,g)=>{if(g.tab||g.downArrow)a(v=>v<e.variables.length-1?v+1:v);else if(g.upArrow)a(v=>v>0?v-1:v);else if(g.escape){let v=e.variables.filter(E=>E.required&&!o[E.name]?.trim());if(v.length>0){l(`Required fields cannot be skipped: ${v.map(E=>E.name).join(", ")}`);return}n(o)}});let u=()=>{if(s<e.variables.length-1)a(s+1);else{let m=e.variables.filter(g=>g.required&&!o[g.name]?.trim());if(m.length>0){l(`Required fields are missing: ${m.map(g=>g.name).join(", ")}`);return}l(null),n(o)}},p=e.variables.some(m=>m.required);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:c?"red":w,children:[S(h,{justifyContent:"space-between",children:[S(f,{bold:!0,children:["Configure ",e.name]}),S(f,{color:"gray",children:["Group ",t+1," / ",r]})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:e.description})}),d(h,{marginTop:1,flexDirection:"column",children:e.variables.map((m,g)=>{let v=g===s,E=!!m.defaultValue;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:v?w:"gray",bold:v,children:[v?"\u279C ":" ",m.name]}),m.required&&S(f,{color:"red",bold:!0,children:[" ","*"]}),E&&!v&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),v&&d(h,{marginLeft:2,children:d(bn,{value:o[m.name]||"",onChange:b=>{i(x=>({...x,[m.name]:b})),c&&l(null)},onSubmit:u,placeholder:E?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&d(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," next \xB7 ",d(f,{bold:!0,children:"\u2191\u2193"})," navigate",!p&&S(f,{children:[" ","\xB7 ",d(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},ba=({alternatives:e,onSubmit:t})=>{let[r,n]=we(new Set),[o,i]=we({}),[s,a]=we(0),[c,l]=we(null);ga(()=>{let b={};for(let x of e)for(let B of x.variables)b[B.name]=B.defaultValue||"";i(b)},[e]);let u=[];for(let b=0;b<e.length;b++)if(u.push({type:"provider",categoryIndex:b}),r.has(b)){let x=e[b];if(x)for(let B=0;B<x.variables.length;B++)u.push({type:"field",categoryIndex:b,fieldIndex:B})}u.push({type:"submit"});let p=u[s],m=p?.type==="field",g=p?.type==="submit";_r((b,x)=>{let B=Math.min(s,u.length-1);if(B!==s){a(B);return}if(m)x.upArrow?a(N=>Math.max(0,N-1)):(x.downArrow||x.tab)&&a(N=>Math.min(u.length-1,N+1));else if(g)x.upArrow?a(N=>Math.max(0,N-1)):(x.return||b===" ")&&E();else if(x.upArrow)a(N=>Math.max(0,N-1));else if(x.downArrow||x.tab)a(N=>Math.min(u.length-1,N+1));else if((x.return||b===" ")&&p?.type==="provider"){let N=p.categoryIndex;n(Rt=>{let G=new Set(Rt);return G.has(N)?G.delete(N):G.add(N),G}),c&&l(null)}});let v=()=>{c&&l(null),a(b=>Math.min(u.length-1,b+1))},E=()=>{let b=[],x={};for(let B of r){let N=e[B];if(!N)continue;if(N.variables.some(G=>o[G.name]?.trim())){b.push(N.name);for(let G of N.variables){let In=o[G.name];In&&(x[G.name]=In)}}}if(b.length===0){r.size===0?l("Enable at least one provider (press Space or Enter)"):l("Enter a value for at least one field");return}t(b,x)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:c?"red":w,children:[S(h,{justifyContent:"space-between",children:[d(f,{bold:!0,children:"Configure AI Provider"}),d(f,{color:"yellow",children:"* At least one required"})]}),d(h,{marginTop:1,children:d(f,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),d(h,{marginTop:1,flexDirection:"column",children:e.map((b,x)=>{let B=r.has(x),N=u.findIndex(G=>G.type==="provider"&&G.categoryIndex===x),Rt=s===N;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[d(f,{color:Rt?w:void 0,bold:Rt,children:Rt?"\u279C ":" "}),d(f,{color:B?"green":"gray",children:B?`[${y.ok}]`:"[ ]"}),S(f,{color:B?w:"gray",bold:B,children:[" ",b.name]}),b.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",b.description]})]}),Rt&&b.docsUrl&&S(h,{marginLeft:6,children:[d(f,{color:"yellow",children:"\u{1F4D6} "}),d(f,{color:"blue",underline:!0,children:b.docsUrl})]}),B&&d(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:b.variables.map((G,In)=>{let wm=u.findIndex($r=>$r.type==="field"&&$r.categoryIndex===x&&$r.fieldIndex===In),Qt=s===wm,Ta=!!G.defaultValue,gi=o[G.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Qt?w:"gray",bold:Qt,children:[Qt?" \u279C ":" ",G.name]}),!Qt&&gi&&d(f,{color:"green",children:" \u2713"}),!Qt&&!gi&&Ta&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",G.defaultValue,")"]})]}),Qt&&d(h,{marginLeft:4,children:d(bn,{value:gi,onChange:$r=>{i(bm=>({...bm,[G.name]:$r})),c&&l(null)},onSubmit:v,placeholder:Ta?`Default: ${G.defaultValue}`:"Enter value\u2026"})})]},G.name)})})]},b.name)})}),c&&d(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),S(h,{marginTop:1,children:[d(f,{color:g?w:void 0,bold:g,children:g?"\u279C ":" "}),d(h,{borderStyle:T,borderColor:g?w:"gray",paddingX:2,children:d(f,{color:g?w:"gray",bold:g,children:"Continue \u2192"})})]}),d(h,{marginTop:1,children:d(f,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},Ea=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:n,onSkip:o})=>{let[i,s]=we(e.defaultValue||""),[a,c]=we(null);ga(()=>{s(e.defaultValue||""),c(null)},[e.name]),_r((p,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}o()}});let l=p=>{if(e.required&&!p.trim()){c("This field is required");return}c(null),n(p)},u=!!e.defaultValue;return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:T,borderColor:a?"red":w,children:[S(h,{justifyContent:"space-between",children:[S(h,{children:[d(f,{color:w,bold:!0,children:e.name}),e.required?d(f,{color:"red",children:" *"}):S(f,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),S(f,{color:"gray",children:[t+1,"/",r]})]}),d(h,{marginLeft:1,children:d(f,{color:"gray",children:e.description})}),S(h,{marginTop:1,children:[d(f,{color:w,children:"\u2192 "}),d(bn,{value:i,onChange:p=>{s(p),a&&c(null)},onSubmit:l,placeholder:u?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),a&&d(h,{marginTop:1,children:d(f,{color:"red",children:a})}),d(h,{marginTop:1,children:S(f,{dimColor:!0,children:[d(f,{bold:!0,children:"Enter"})," confirm",!e.required&&S(f,{children:[" ","\xB7 ",d(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Rp=({store:e})=>{let t=Te(e);return S(si,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&d(jw,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&d(qo,{checks:t.data.checks}),d(br,{inputId:t.inputRequest?.id,missing:t.data[Bt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&d(wr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&d(qw,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&d(Hw,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&d(Pd,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&d(Sa,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&d(va,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&d(ya,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&d(Ea,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&d(wa,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&d(ba,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&d(Ho,{status:t.status}),t.step==="Finished"&&d(Vw,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,stillStarting:t.data.stillStarting===!0,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&d(ha,{title:t.step==="Install Tools"?"Installing Tools":"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.step==="Install Tools"?t.data.toolComplete||!1:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.error&&d(Pe,{message:t.error.message})]})};import{Spinner as Ww}from"@inkjs/ui";import{Box as zt,Text as Dr}from"ink";import{useState as Kw}from"react";import{jsx as Et,jsxs as Me}from"react/jsx-runtime";var Cp=({store:e})=>{let t=Te(e),r=t.step==="Starting"||t.step==="Stopping",n=t.step==="Running"||t.step==="Stopped",o=t.data.dockerLogs??[],[i]=Kw(Date.now),s=ta(r);return Me(zt,{flexDirection:"column",width:"100%",children:[Et(Tr,{showStatus:n}),r&&!t.error&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[Et(Ww,{label:t.status||"Working\u2026"}),Me(Dr,{color:"gray",children:[" ",ft(s-i)]})]}),o.length>0&&Et(ni,{logs:o})]}),t.step==="Running"&&t.data.started&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[Et(Ae,{kind:"ok"}),Me(Dr,{children:["GAIA is running at"," ",Et(Dr,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),Me(Dr,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&Me(zt,{flexDirection:"column",marginTop:1,children:[Me(zt,{children:[Et(Ae,{kind:"ok"}),Et(Dr,{children:t.status})]}),t.data.stopMode==="force-ports"&&Me(Dr,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&Et(Pe,{message:t.error.message})]})};import{Spinner as Yw}from"@inkjs/ui";import{Box as xt,Text as _e,useInput as zw}from"ink";import{jsx as P,jsxs as Xe}from"react/jsx-runtime";var Ap=({store:e})=>{let t=Te(e);return Xe(si,{status:t.status,step:t.step,steps:kp,children:[t.step==="Detect Repo"&&Xe(xt,{flexDirection:"column",paddingX:2,borderStyle:T,borderColor:w,children:[P(_e,{bold:!0,children:"Detecting GAIA Repository"}),P(xt,{marginTop:1,children:P(Yw,{label:"Searching for repository\u2026"})}),t.data.repoPath&&P(xt,{marginTop:1,children:Xe(_e,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&P(qo,{checks:t.data.checks}),P(br,{inputId:t.inputRequest?.id,missing:t.data[Bt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&P(wr,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&P(Sa,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&P(va,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&P(ya,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&P(Ea,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&P(wa,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&P(ba,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&P(Ho,{status:t.status}),t.step==="Project Setup"&&P(ha,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&P(Xw,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&P(Pe,{message:t.error.message})]})},Xw=({setupMode:e,portOverrides:t,onConfirm:r})=>{zw((s,a)=>{a.return&&r()});let n=t?.[3e3]??3e3,o=de(e??"developer",t??{}),i=e==="selfhost";return Xe(xt,{flexDirection:"column",marginTop:2,borderStyle:T,borderColor:w,padding:1,children:[P(_e,{color:w,bold:!0,children:"Setup Complete!"}),Xe(xt,{marginTop:1,children:[P(_e,{bold:!0,children:"Run: "}),P(_e,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Xe(xt,{marginTop:1,flexDirection:"column",children:[Xe(_e,{children:["Web:"," ",Xe(_e,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),Xe(_e,{children:["API:"," ",P(_e,{color:"cyan",bold:!0,children:o})]})]}),P(xt,{marginTop:1,children:P(_e,{color:"gray",children:i?"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup":"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),P(xt,{marginTop:1,children:Xe(_e,{dimColor:!0,children:[P(_e,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as cb}from"@inkjs/ui";import{Box as re,Text as Je,useInput as lb}from"ink";var Jw=[{name:"API",port:8e3,type:"http",path:"/health"},{name:"Web",port:3e3,type:"http",path:"/"},{name:"PostgreSQL",port:5432,type:"tcp"},{name:"Redis",port:6379,type:"tcp"},{name:"MongoDB",port:27017,type:"tcp"},{name:"RabbitMQ",port:5672,type:"tcp"},{name:"ChromaDB",port:8080,type:"tcp"}];async function Pp(e){return Promise.all(Jw.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?Qw(t.name,r,t.path):Zw(t.name,r)}))}async function Qw(e,t,r){let n=Date.now();try{let o=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-n;return{name:e,port:t,status:o.ok?"up":"down",latency:i,details:o.ok?`HTTP ${o.status}`:`HTTP ${o.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function Zw(e,t){let r=await import("node:net"),n=Date.now();return new Promise(o=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let s=Date.now()-n;i.destroy(),o({name:e,port:t,status:"up",latency:s})}),i.on("timeout",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function Tp(e){let t=await Z();if(t!=="ready")return{access:t,problem:await et(t),containers:[]};let r=await Ba(be[e]);return{access:t,containers:r}}var En="statusFacts";async function eb(){let e=L(),t=e?await $(e):null,r=zr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let n=A(e),o=n[O]??O,[i,s,a]=await Promise.all([t==="developer"?Pp(n):[],Tp(t),Oo($t(t,n),be[t])]),c=a.reachable?await He(de(t,n),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:tb(s.containers)}:s,readiness:a,services:i,webUrl:pt(e,o),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function tb(e){let t=(C()?.bots??[]).map(xe).filter(r=>!e.some(n=>n.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function rb(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await eb();e.updateData(En,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function _p(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await rb(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var nb=["gaia-web","gaia-backend","arq_worker","proxy"],ob=["mongo","postgres","redis","rabbitmq","chromadb"];function ai(e,t,r){return t.some(o=>!o.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function Dp(e,t){return t.map(r=>e.find(n=>n.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:je(r.name)}))}function Op(e,t){let r=e.readiness,n=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:Un(i.name)})):Dp(t,ob),o=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return ai("Data",n,o??"See why with: gaia doctor")}function ib(e){let t=e.filter(r=>r.name.startsWith("bot-"));return t.length===0?{label:"Bots",items:[],note:"none \xB7 add one: gaia bots add telegram",tone:"dim"}:ai("Bots",t.map(r=>({ok:r.status==="running",name:je(r.name)})),"See why with: gaia doctor")}function $p(e){return e.setupComplete===null?null:e.setupComplete?{label:"Setup",items:[],note:"finished",tone:"ok"}:{label:"Setup",items:[],note:`not finished \xB7 open ${e.webUrl}/setup`,tone:"warn"}}function sb(e,t){let r=t.containers,o=[ai("App",Dp(r,nb),"Start it: gaia start"),Op(e,r),ib(r)],i=$p(e);i&&o.push(i);let s=r.some(c=>c.status==="running"),a=o.some(c=>c.tone==="fail");return s?{headline:a?{kind:"fail",text:"GAIA is running, but part of it is down"}:{kind:"ok",text:"GAIA is running",url:e.webUrl},rows:o,unhealthy:a}:{headline:{kind:"fail",text:"GAIA isn't running \xB7 start it: gaia start"},rows:[],unhealthy:!0}}function ab(e){let t=e.services.map(n=>({ok:n.status==="up",name:`${n.name} :${n.port}`})),r=ai("Local",t,"Start them: gaia dev");return{headline:r.tone==="fail"?{kind:"fail",text:"Part of the dev stack is down"}:{kind:"ok",text:"The dev stack is running",url:e.webUrl},rows:[r],unhealthy:r.tone==="fail"}}function ci(e){if(!e.installed)return{headline:{kind:"warn",text:`${e.install} \xB7 run: gaia up`},rows:[],unhealthy:!0};let t=e.docker;if(t?.problem){let r=e.readiness?.reachable===!0,n={label:"Docker",items:[],note:t.problem.state,tone:"warn"},o=$p(e);return{headline:r?{kind:"ok",text:"GAIA is running",url:e.webUrl}:{kind:"fail",text:t.problem.summary},hint:t.problem.fix,rows:r?[Op(e,[]),...o?[o]:[],n]:[],unhealthy:!0}}return e.services.length>0?ab(e):sb(e,t??{access:"ready",containers:[]})}import{jsx as M,jsxs as ot}from"react/jsx-runtime";var ub=8,db={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},pb=({row:e})=>ot(re,{children:[M(re,{width:ub,flexShrink:0,children:M(Je,{bold:!0,children:e.label})}),ot(re,{flexDirection:"column",flexShrink:1,children:[e.items.length>0&&M(re,{flexWrap:"wrap",children:e.items.map(t=>ot(re,{marginRight:2,flexShrink:0,children:[M(Ae,{kind:t.ok?"ok":"fail"}),M(Je,{children:t.name})]},t.name))}),e.note&&ot(re,{children:[e.items.length===0&&e.tone!=="dim"&&M(Ae,{kind:e.tone==="warn"?"warn":"ok"}),M(Je,{color:db[e.tone],children:e.note})]})]})]}),Lp=({store:e})=>{let t=Te(e),r=t.data[En],n=t.data.watch===!0,o=t.step==="Results"&&r!==void 0;lb((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:n&&t.inputRequest!==null});let i=r?ci(r):null,s=i?.headline.kind??"ok";return ot(re,{flexDirection:"column",width:"100%",children:[M(Tr,{showStatus:!1}),t.step==="Checking"&&M(re,{marginTop:1,marginLeft:2,children:M(cb,{label:t.status})}),o&&i&&ot(re,{flexDirection:"column",marginTop:1,marginLeft:2,children:[ot(re,{children:[M(Ae,{kind:s==="ok"?"active":s}),M(Je,{bold:!0,children:i.headline.text})]}),i.headline.url&&M(re,{marginLeft:2,children:M(Je,{color:w,children:i.headline.url})}),i.hint&&M(re,{marginLeft:2,children:M(Je,{children:i.hint})}),i.rows.length>0&&M(re,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>M(pb,{row:a},a.label))}),r.installed&&M(re,{marginTop:1,children:ot(Je,{color:"gray",children:["Installed at ",r.install]})}),n&&M(re,{marginTop:1,children:ot(Je,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",M(Je,{bold:!0,children:"r"})," check again \xB7 ",M(Je,{bold:!0,children:"q"})," quit"]})})]}),t.error&&M(Pe,{message:t.error.message})]})};import{defaultTheme as mb,extendTheme as fb}from"@inkjs/ui";var li={success:"ok",error:"fail",warning:"warn",info:"active"},Mp=fb(mb,{components:{Spinner:{styles:{frame:()=>({color:w})}},ProgressBar:{styles:{completed:()=>({color:w})},config:()=>({completedCharacter:hi.done,remainingCharacter:hi.rest})},StatusMessage:{styles:{icon:({variant:e})=>({color:Mr[li[e]]})},config:({variant:e})=>({icon:y[li[e]]})},Alert:{styles:{icon:({variant:e})=>({color:Mr[li[e]]})},config:({variant:e})=>({icon:y[li[e]]})}}});import{jsx as ne,jsxs as Or}from"react/jsx-runtime";var vb=["init","setup","status","start","stop","up","uninstall"],xa=class extends Sb.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Or(ui,{flexDirection:"column",padding:1,children:[ne(Xt,{color:"red",bold:!0,children:"An unexpected error occurred:"}),ne(Xt,{color:"red",children:this.state.error.message}),this.state.error.stack&&ne(ui,{marginTop:1,children:ne(Xt,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},yb=({store:e,command:t})=>{switch(t){case"init":return ne(Rp,{store:e});case"setup":return ne(Ap,{store:e});case"status":return ne(Lp,{store:e});case"start":case"stop":return ne(Cp,{store:e,command:t});case"up":return ne(vp,{store:e});case"uninstall":return ne(np,{store:e});default:return Or(ui,{flexDirection:"column",padding:1,children:[Or(Xt,{color:"red",children:["Unknown command: ",t]}),Or(ui,{marginTop:1,flexDirection:"column",children:[ne(Xt,{bold:!0,children:"Available commands:"}),vb.map(r=>Or(Xt,{children:[" ",ne(Xt,{color:"cyan",children:r})]},r))]})]})}},wb=({onCancel:e})=>(hb((t,r)=>{r.ctrl&&t==="c"&&e()}),null),Np=({store:e,command:t,onCancel:r})=>ne(xa,{children:Or(gb,{theme:Mp,children:[ne(wb,{onCancel:r}),ne(yb,{store:e,command:t})]})});import{EventEmitter as bb}from"events";var Eb=150,Ia=class extends bb{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;autoResolveInputs=new Map;answerResolvers=[];setAutoResolve(t,r="exit"){this.autoResolveInputs.set(t,r)}pushAnswerResolver(t){this.answerResolvers.push(t)}get currentState(){return this.state}scheduleEmit(){this.emitPending=!0,this.emitTimer||(this.emitTimer=setTimeout(()=>{this.emitTimer=null,this.emitPending&&(this.emitPending=!1,this.emit("change",this.state))},Eb))}flush(){this.emitPending&&this.emitNow()}emitNow(){this.emitTimer&&(clearTimeout(this.emitTimer),this.emitTimer=null),this.emitPending=!1,this.emit("change",this.state)}setStep(t){this.state.step=t,this.emitNow()}setStatus(t){this.state.status=t,this.scheduleEmit()}setError(t){this.state.error=t,t!==null&&this.inputResolver&&(this.inputResolver(null),this.inputResolver=null,this.state.inputRequest=null),this.emitNow()}updateData(t,r){this.state.data={...this.state.data,[t]:r},this.scheduleEmit()}ask(t,r,n){return this.answerResolvers.map(i=>i(t,n)).find(i=>i!==void 0)===void 0&&!this.autoResolveInputs.has(t)&&this.setStatus(r),this.waitForInput(t,n)}waitForInput(t,r,n){if(this.autoResolveInputs.has(t))return this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t));for(let o of this.answerResolvers){let i=o(t,r);if(i!==void 0)return this.state.inputRequest=null,this.emitNow(),Promise.resolve(i)}return this.state.inputRequest={id:t,meta:r},this.emitNow(),new Promise(o=>{if(this.inputResolver=o,n!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),o(null))},n),s=this.inputResolver;this.inputResolver=a=>{clearTimeout(i),s(a)}}})}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},Fp=()=>new Ia;async function ge(e){let t=Fp();if(e.whenNonInteractive==="fail"){Wl(e.command),await Gp(t,e);return}fe()?await Gp(t,e):await kb(t,e)}async function kb(e,t){Kl(e,Nn());for(let[r,n]of t.autoResolve??[])e.setAutoResolve(r,n);try{await t.runFlow(e);let r=jp(e);r&&await $i(e.currentState.step,r,us(e)),t.onPlainComplete?.(e)}catch(r){e.setError(r)}qp(e)}var Up=30,Rb=Math.ceil(1e3/Up);async function Bp(e){e.flush(),await new Promise(t=>setTimeout(t,2*Rb))}async function Gp(e,t){let r=async()=>{},{unmount:n,clear:o}=xb(Ib.createElement(Np,{store:e,command:t.command,onCancel:()=>void r()}),{exitOnCtrlC:!1,maxFps:Up}),i=async()=>{Ve(e,"cancelled"),await Bp(e),n();let a=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
|
|
142
|
-
${y.cancelled} Cancelled.${
|
|
143
|
-
`),process.exit(130)};r=
|
|
144
|
-
`),
|
|
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
|
|
146
|
-
`)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)\u2026`)}if(!c)try{await
|
|
147
|
-
`));if(c&&!
|
|
148
|
-
`))}if(c&&
|
|
149
|
-
`)}function
|
|
150
|
-
`)}async function
|
|
151
|
-
`)}function
|
|
152
|
-
`)}function
|
|
153
|
-
`)}function
|
|
154
|
-
`)){let o=/^#{2,3} (.+)$/.exec(n.trim());if(o?.[1]){r=o[1];continue}let i=
|
|
155
|
-
`).map(t=>t.trim()).filter(Boolean)}async function
|
|
156
|
-
`)}async function
|
|
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
|
|
158
|
-
${t}`):(
|
|
159
|
-
No terminal to confirm in: rerun with --yes to apply.`),!1)}function
|
|
160
|
-
${
|
|
161
|
-
${y.ok} GAIA is on ${n}.`),
|
|
162
|
-
${r.commits.length} new commit(s) touch the self-host stack:`),
|
|
163
|
-
Updated and restarted from source.`))}async function
|
|
164
|
-
Install it with 'gaia up'.`),process.exitCode=1;return}if(e.git&&e.version){
|
|
165
|
-
--version moves to a published release; --git builds from source. Pick one.`),process.exitCode=1;return}for(let r of
|
|
166
|
-
Your data is untouched. Fix the cause above, then run 'gaia update' again.`),process.exitCode=1}}var
|
|
167
|
-
New here? Run: gaia up`);
|
|
134
|
+
`}async function zd(){let[e,t]=await Promise.all([aa("ip",["-6","-o","addr","show","scope","global"]),aa("ip",["-o","route","show","default"])]);return Oy(e.stdout,Dy(t.stdout))}async function Xd(e,t,r){let{stdout:n}=await aa("sh",["-c","command -v avahi-publish-address"]),o=Yd.join(Kd.tmpdir(),hn);xr.writeFileSync(o,$y(n.trim(),e,t)),await H("install",["-m","644",o,ca],r),xr.rmSync(o,{force:!0}),await H("systemctl",["daemon-reload"],r),await H("systemctl",["enable",hn],r),await H("systemctl",["restart",hn],r)}async function Jd(e){xr.existsSync(ca)&&(await H("systemctl",["disable","--now",hn],e),await H("rm",["-f",ca],e),await H("systemctl",["daemon-reload"],e))}var Xo="gaia",yt=`${Xo}.local`,np=`http://${yt}`,Zd="0.15.8",ep=24,la=80,Ly=15e3,My=500,op=2e3;function ip(e){return!e.optedOut&&!e.domain?"set-up":e.setUpBefore?"remove":"none"}function Ny(e,t){if(t!=="linux"&&t!=="darwin")return"it works only on Linux and macOS";let r=e.replace(/^v/,"");return Number.parseInt(r,10)<ep?`it needs Node.js ${ep} or newer, and this is Node.js ${r}`:null}function sp(){return Kt.join(Kt.dirname(process.execPath),"npm")}async function ap(){let{stdout:e}=await Ir(sp(),["root","-g"]);return Kt.join(e.trim(),"portless","dist","cli.js")}var Fy=Qd.object({version:Qd.string()});function By(e){let t=Kt.join(Kt.dirname(e),"..","package.json");return Wt.existsSync(t)?Fy.parse(JSON.parse(Wt.readFileSync(t,"utf-8"))).version:null}async function Gy(e){let t=await ap();if(By(t)===Zd)return t;let r=await Ir(sp(),["install","-g","--no-fund","--no-audit",`portless@${Zd}`],{all:!0,reject:!1});if(Wt.appendFileSync(e,r.all??""),r.failed)throw new Error(`installing portless with npm failed (output in ${e})`);return t}function Uy(e){return Ir("sh",["-c",`command -v ${e}`],{reject:!1}).then(t=>!t.failed)}async function jy(e){if(process.platform==="linux"&&!await Uy("avahi-publish-address")){if(!gs())throw new Error("it needs avahi-utils (avahi-publish-address); install it, then run 'gaia up' again");await H("apt-get",["update"],e),await H("apt-get",["install","-y","avahi-utils"],e)}}async function qy(e,t){let r=await Ir(process.execPath,[e,...t],{all:!0,reject:!1});if(r.failed)throw new Error(`'portless ${t.join(" ")}' failed: ${(r.all??"").trim()}`)}function cp(){return new Promise(e=>{let t=rp.get({host:"127.0.0.1",port:la,path:"/health/ready",headers:{Host:yt},timeout:op},r=>{r.resume(),e(r.statusCode??null)});t.on("timeout",()=>t.destroy()),t.on("error",()=>e(null))})}async function tp(){return await cp()===200}async function Hy(){return await cp()!==null}async function lp(e,t){if(process.platform!=="linux")return!0;let r=await Ir("avahi-resolve-host-name",[e,yt],{reject:!1,timeout:op});if(r.failed)return!1;let[n,o]=r.stdout.trim().split(/\s+/);return n===yt&&(!t||o===t)}async function Vy(e){if(process.platform!=="linux")return;let t=await zd();if(!t)return;let r=()=>lp("-6",t);if(!await r()&&(await Xd(yt,t,e),!await zo(r)))throw new Error(`${yt}'s IPv6 address isn't announced, so Apple devices wait ~5s per lookup (log: ${e})`)}async function zo(e){let t=Date.now()+Ly;for(;Date.now()<t;){if(await e())return!0;await new Promise(r=>setTimeout(r,My))}return e()}async function up(e){let t=Ny(process.version,process.platform);if(t)throw new Error(t);let r=qe("local-name"),n=await Gy(r);if(!await tp()&&(await jy(r),await H(process.execPath,[n,"service","install","--lan","--no-tls"],r),!await zo(Hy)))throw new Error(`portless's proxy didn't start on port ${la}; is another server using it? (log: ${r})`);if(await qy(n,["alias",Xo,String(e),"--force"]),!await zo(tp))throw new Error(`portless's proxy on port ${la} doesn't route ${yt} to GAIA on port ${e} (log: ${r})`);if(!await zo(()=>lp("-4")))throw new Error(`${yt} isn't announced on the network; check that avahi-daemon is running (log: ${r})`);await Vy(r)}async function Jo(){let e=await ap();if(!Wt.existsSync(e))return;let t=await Ir(process.execPath,[e,"alias","--remove",Xo],{all:!0,reject:!1});if(t.failed&&!(t.all??"").includes("No alias found"))throw new Error(`'portless alias --remove ${Xo}' failed: ${(t.all??"").trim()}`);let r=qe("local-name-remove");await H(process.execPath,[e,"service","uninstall"],r),await Jd(r)}var ze={confirm:"uninstall_confirm",deleteData:"uninstall_delete_data",backup:"uninstall_backup"},vn="uninstallOutcome",Sn=Cr.join(dp.homedir(),"gaia-backups"),Wy=["apps/api/.env","infra/docker/.env"],pp="npm rm -g @heygaia/cli",mp="docker volume rm $(docker volume ls -q --filter label=com.docker.compose.project=gaia-selfhost)";function Ky(e,t){if(!t.keepSettings){Rr.rmSync(e,{recursive:!0,force:!0});return}let r=Wy.map(i=>Cr.join(e,i)),n=new Set(r),o=i=>{for(let s of Rr.readdirSync(i)){let a=Cr.join(i,s);if(n.has(a))continue;r.some(l=>l.startsWith(`${a}${Cr.sep}`))?o(a):Rr.rmSync(a,{recursive:!0,force:!0})}};o(e)}function Yy(e){return t=>{if(t===ze.confirm&&e.yes)return!0;if(t===ze.deleteData){if(e.deleteData)return!0;if(e.yes)return!1}if(t===ze.backup&&e.yes)return!1}}function zy(e,t,r,{deleteData:n,backup:o}){let i=[];if(o&&i.push({id:"backup",label:"Backing up your data",doneLabel:`Backed up your data to ${F(Sn)}`,run:()=>Xr({outputDir:Sn})}),t){let s=n?"containers and data":"containers and images";i.push({id:"containers",label:`Removing ${s}`,doneLabel:`Removed ${s}`,run:()=>so(t,a=>te(e,"containers",{detail:a}),k(t),{remove:{volumes:n}})})}if(r&&i.push({id:"local-name",label:"Removing the gaia.local name",doneLabel:"Removed the gaia.local name",run:Jo}),t){let s=F(t);i.push({id:"files",label:`Removing ${s}`,doneLabel:n?`Removed ${s}`:`Removed ${s}, except its settings`,minor:!0,run:()=>Ky(t,{keepSettings:!n})})}return i.push({id:"config",label:`Removing ${F(xe)}`,doneLabel:`Removed ${F(xe)}`,minor:!0,run:()=>Rr.rmSync(xe,{recursive:!0,force:!0})}),i}async function Xy(e,t){go(e,t);for(let r of t){ge(e,r.id);try{await r.run()}catch(n){return Ve(e,"failed"),e.setError(n),!1}ke(e,r.id)}return!0}async function Jy(){let e=Yo();return!e&&!P()?{error:new Error("GAIA isn't installed here, so there is nothing to uninstall.")}:e&&await $(e)==="developer"?{error:new Error(`${F(e)} is a development copy of GAIA, and 'gaia uninstall' removes only self-host installs.
|
|
135
|
+
Delete it yourself if you no longer need it.`)}:{installDir:e}}async function Qy(e){if(await e.waitForInput(ze.confirm)!==!0)return null;let t=await e.waitForInput(ze.deleteData)===!0,r=t&&await e.waitForInput(ze.backup)===!0;return{deleteData:t,backup:r}}async function fp(e,t={}){if(!he()&&!t.yes){e.setError(new Error(`There is no terminal to confirm in.
|
|
136
|
+
Rerun with --yes (keeps your data) or --yes --delete-data.`));return}let r=await Jy();if("error"in r){e.setError(r.error);return}let{installDir:n}=r,o=P()?.localName===!0;e.updateData("installDir",n),e.pushAnswerResolver(Yy(t));let i=await Qy(e);if(!i){e.setStatus("Nothing was removed."),e.updateData("cancelled",!0);return}if(!await Xy(e,zy(e,n,o,i)))return;let s={installDir:n,keptData:!i.deleteData,...i.backup?{backupDir:Sn}:{}};e.updateData(vn,s),e.updateData("finished",!0)}var Qo="GAIA is uninstalled";function Zo(e){let t=[];if(e.keptData){let r=e.installDir?` with the settings that unlock it in ${F(e.installDir)}`:"";t.push({label:"Your data",text:`kept in Docker volumes${r}; 'gaia up' picks it back up`}),t.push({label:"Delete it later",text:mp,tone:"dim"})}else t.push({label:"Your data",text:"deleted"});return e.backupDir&&t.push({label:"Backup",text:`in ${F(e.backupDir)}; 'gaia restore --from' brings it back`}),t.push({label:"The CLI",text:`remove it too with ${pp}`,tone:"primary"}),t}import{jsx as De,jsxs as yn}from"react/jsx-runtime";var gp=2;function tw(e,t){switch(e){case ze.confirm:return{text:"Remove GAIA from this computer?",detail:`Its containers, networks and images go${t?`, and so does ${F(t)}`:""}. You choose about your data next.`,yesByDefault:!0};case ze.deleteData:return{text:"Delete your data too?",detail:"Accounts, chats, memories and files. This can't be undone. No keeps it, and 'gaia up' picks it back up.",yesByDefault:!1};case ze.backup:return{text:`Back it up to ${F(Sn)} first?`,detail:"Runs 'gaia backup' while GAIA is still running.",yesByDefault:!0};default:return null}}var rw=({store:e,id:t})=>{let r=tw(t,e.currentState.data.installDir??null);return r?yn(Yt,{flexDirection:"column",marginTop:1,children:[De(ua,{dimColor:!0,children:r.detail}),yn(Yt,{children:[yn(ua,{bold:!0,children:[r.text," "]}),De(Zy,{defaultChoice:r.yesByDefault?"confirm":"cancel",onConfirm:()=>e.submitInput(!0),onCancel:()=>e.submitInput(!1)},t)]})]}):null},hp=({store:e})=>{let t=Se(e),r=t.data.steps??[],n=t.data[vn],{finished:o,live:i}=qo(r),s=i.find(a=>a.state!=="pending");return yn(Yt,{flexDirection:"column",width:"100%",children:[De(ew,{items:o,children:a=>De(Yt,{paddingLeft:gp,children:De(Ho,{step:a})},a.id)}),yn(Yt,{flexDirection:"column",paddingLeft:gp,children:[t.inputRequest&&De(rw,{store:e,id:t.inputRequest.id}),s&&De(Vo,{step:s,waiting:!1,status:t.status}),t.data.cancelled===!0&&De(Yt,{marginTop:1,children:De(ua,{children:t.status})})]}),n&&De(Yt,{marginTop:1,children:De(jo,{headline:Qo,rows:Zo(n),accent:"green",success:!0})}),t.error&&De(_e,{message:t.error.message})]})};import{Box as Xe,Static as Ww,Text as ga}from"ink";import{useState as Kw}from"react";import nw from"chalk";import{Box as ow,Text as iw,useStdout as sw}from"ink";import{useEffect as aw,useState as Sp}from"react";import{jsx as vp}from"react/jsx-runtime";var wt=({showStatus:e=!0,showUpdate:t=!0})=>{let{stdout:r}=sw(),n=Fo(),[o,i]=Sp(null),[s]=Sp(()=>t?mo():null);aw(()=>{if(!e){i(null);return}let c=!0;return po().then(l=>{c&&i(l)}),()=>{c=!1}},[e]);let a=fo({level:nw.level,...n,...as(r),version:A,status:e?o:null,update:s});return vp(ow,{marginTop:1,children:vp(iw,{children:a.join(`
|
|
137
|
+
`)})})};import{execFile as xw}from"node:child_process";import*as Cp from"node:os";import*as ei from"node:fs";import*as yp from"node:path";var cw=e=>new Promise(t=>setTimeout(t,e));async function ti(e){e.setStep("Setup Mode"),e.setStatus("Choose how to run GAIA\u2026");let t=await e.waitForInput("setup_mode");return e.updateData("setupMode",t),t}async function kr(e,t,r,n,o){e.setStep("Environment Setup"),e.setStatus("Configuring GAIA\u2026"),e.updateData("setupMode",r),e.setStatus("Configuring GAIA\u2026");let i=await e.waitForInput("env_method");e.updateData("envMethod",i);let s={ENV:r==="selfhost"?"selfhost":"development"};r==="selfhost"&&(s.AUTH_MODE="local");for(let d of Br()){let p=Fr(d,r);p&&(s[d]=p)}Object.assign(s,rc(r));let a={};o?.domain&&(a.HOST=`https://${o.domain}`,a.FRONTEND_URL=`https://${o.domain}`),i==="infisical"?(await uw(e,a),e.setStatus("Infisical credentials saved. Ensure your Infisical project contains all required variables.")):await pw(e,a,r,o?.llmProvider===void 0);let c=ei.existsSync(rt(t))?ei.readFileSync(rt(t),"utf-8"):null,l=lw({defaults:s,existing:Tt(c),existingMode:await $(t),answers:a,setupMode:r});n&&ec(l,n,r),r==="selfhost"&&Object.assign(l,Hn(c));try{await mw(e,t,l,r,n,o?.domain)}catch(d){e.setError(d);return}await cw(1e3)}function lw(e){let{defaults:t,existing:r,existingMode:n,answers:o,setupMode:i}=e,s=n===i;return{...s?t:r,...s?r:t,...o,SETUP_MODE:i}}async function uw(e,t){e.setStatus("Configuring Infisical\u2026");let r=await e.waitForInput("env_infisical");t.INFISICAL_PROJECT_ID=r.INFISICAL_PROJECT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_ID=r.INFISICAL_MACHINE_IDENTITY_CLIENT_ID,t.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET=r.INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET}function dw(e){let t=[],r=new Set,n=new Set;for(let o of e)if(o.alternativeGroup&&!n.has(o.name)){let i=e.find(s=>s.name===o.alternativeGroup);i&&(t.push([o,i]),r.add(o.name),r.add(i.name),n.add(o.name),n.add(i.name))}return{alternativePairs:t,alternativeGroupNames:r}}async function pw(e,t,r,n){e.setStatus("Parsing environment variables\u2026");let o=tc(_n(),r).filter(g=>r!=="selfhost"||g.selfhostSetup),{alternativePairs:i,alternativeGroupNames:s}=dw(o),a=o.filter(g=>g.variables.length===1&&!s.has(g.name)),c=o.filter(g=>g.variables.length>1&&!s.has(g.name));for(let g of n?i:[]){e.updateData("alternativeGroups",g);let v=await e.ask("env_alternatives","Choose an AI provider\u2026");for(let[E,b]of Object.entries(v.values))b&&(t[E]=b)}let l=Br(),p=[...a.flatMap(g=>g.variables).filter(g=>!l.includes(g.name))].sort((g,v)=>g.required&&!v.required?-1:!g.required&&v.required?1:0);e.updateData("envVarTotal",p.length);for(let g=0;g<p.length;g++){let v=p[g];if(!v)continue;e.updateData("currentEnvVar",v),e.updateData("envVarIndex",g);let E=await e.ask("env_var",`Configuring ${v.name}\u2026`,{varName:v.name});(E||v.required||v.defaultValue)&&(t[v.name]=E||v.defaultValue||"")}let m=[...c].filter(g=>!g.variables.every(v=>l.includes(v.name))).sort((g,v)=>{let E=g.variables.some(x=>x.required),b=v.variables.some(x=>x.required);return E&&!b?-1:!E&&b?1:0});e.updateData("envGroupTotal",m.length);for(let g=0;g<m.length;g++){let v=m[g];if(!v)continue;e.updateData("currentEnvGroup",v),e.updateData("envGroupIndex",g);let E=await e.ask("env_group",`Configuring ${v.name}\u2026`,{groupName:v.name});for(let[b,x]of Object.entries(E)){let G=v.variables.find(N=>N.name===b);(x||G?.required||G?.defaultValue)&&(t[b]=x||G?.defaultValue||"")}}}async function mw(e,t,r,n,o,i){e.setStatus("Saving GAIA's settings\u2026");try{let s=yp.join(t,"apps","api");Gr(s,r),e.setStatus("Saved GAIA's settings")}catch(s){throw new Error(`Failed to write API .env file: ${s.message}`)}if(n==="selfhost"){e.setStatus("Saving Docker's settings\u2026");try{ki(t,o??{},n,{dockerSocketGid:Va(),domain:i}),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}return}e.setStatus("Saving the web app's settings\u2026");try{sc(t,n,o),e.setStatus("Saved the web app's settings")}catch(s){throw new Error(`Failed to write web .env file: ${s.message}`)}if(o&&Object.keys(o).length>0){e.setStatus("Saving Docker's settings\u2026");try{dc(t),ki(t,o,n),e.setStatus("Saved Docker's settings")}catch(s){throw new Error(`Failed to write Docker Compose .env: ${s.message}`)}}}import*as bp from"node:path";var pa=["openrouter","gemini","openai","ollama","custom"],fw={openrouter:{key:"required",baseUrl:"unused",model:"unused"},gemini:{key:"required",baseUrl:"unused",model:"unused"},openai:{key:"required",baseUrl:"unused",model:"unused"},ollama:{key:"unused",baseUrl:"optional",model:"optional"},custom:{key:"required",baseUrl:"required",model:"required"}},ri={key:"--llm-key",baseUrl:"--llm-base-url",model:"--llm-model"};function da(e,t){let r={key:e.llmKey,baseUrl:e.llmBaseUrl,model:e.llmModel}[t];return r!==void 0&&r!==""}function Ep(e){let t=Object.keys(ri);if(!e.llmProvider){let n=t.find(o=>da(e,o));if(n)throw new Error(`${ri[n]} requires --llm-provider <${pa.join("|")}>.`);return}let r=e.llmProvider;for(let n of t){let o=fw[r][n];if(o==="required"&&!da(e,n))throw new Error(`--llm-provider ${r} requires ${ri[n]}.`);if(o==="unused"&&da(e,n))throw new Error(`${ri[n]} is not used with --llm-provider ${r}.`)}if(e.noStart)throw new Error("--llm-provider saves the provider into the running instance, so it cannot be combined with --no-start. Drop --no-start, or configure the provider in the web setup wizard later.")}function gw(e){let t=["--provider",e.llmProvider];return e.llmBaseUrl&&t.push("--base-url",e.llmBaseUrl),e.llmModel&&t.push("--model",e.llmModel),t}var wp="GAIA_PROVIDER_API_KEY",Ar={openrouter:"OpenRouter",gemini:"Gemini",openai:"OpenAI",ollama:"Ollama",custom:"custom provider"},hw=/Could not save \w+: (.+)/;async function xp(e,t){let r=bp.join(e,"infra/docker");try{await de("docker",[...zi(r),"exec","-T","-e",wp,"gaia-backend","python","-m","app.scripts.save_provider",...gw(t)],r,void 0,void 0,{[wp]:t.llmKey??""})}catch(n){let o=hw.exec(n.message)?.[1];throw o?new Error(o,{cause:n}):n}}var Sw=5e3,vw=5*6e4,yw=5e3;async function ww(e,t={}){let r=t.intervalMs??Sw,n=Date.now()+(t.timeoutMs??vw),o=new Map(e.map(i=>[i.label,i]));for(;;){if(await Promise.all([...o.values()].map(async i=>{await bw(i)&&o.delete(i.label)})),o.size===0)return{ready:!0};if(Date.now()>=n)return{ready:!1,stillStarting:[...o.keys()].join(", ")};t.onProgress?.([...o.keys()]),await Q(r)}}async function bw(e){try{let t=await fetch(e.url,{signal:AbortSignal.timeout(yw)});return e.requireOk?t.ok:!0}catch{return!1}}async function ni(e,t,r){let n=await ww([{label:"API",url:`${t.apiUrl}/ping`,requireOk:!0},{label:"Web",url:`http://localhost:${t.webPort}/login`,requireOk:!1}],{onProgress:o=>{Ew(e,o),r?.(o)}});return e.updateData("dependencyPhase",n.ready?"GAIA is answering":`Still starting: ${n.stillStarting}`),e.updateData("dependencyComplete",!0),n}function Ew(e,t){let r=`Waiting for ${t.join(" and ")} to come online\u2026`;e.setStatus(r),e.updateData("dependencyComplete",!1),e.updateData("dependencyPhase",r)}var kp="gaia up --build",Iw="usually 10-20 minutes \xB7 safe to leave running",fa="upNotice";function Rw(e,t,r){let n=e.llmProvider?Ar[e.llmProvider]:null,o={existing:{label:"Finding your install",doneLabel:"Using your install",minor:!0},bundle:{label:"Getting GAIA's setup files",doneLabel:"Got GAIA's setup files",minor:!0},clone:{label:"Downloading GAIA's source",doneLabel:"Downloaded GAIA's source"}}[t];return[{id:"docker",label:"Checking Docker",doneLabel:"Docker is ready"},...r==="remove"?[{id:"local-name-off",label:"Removing the gaia.local name",doneLabel:"Removed the gaia.local name",minor:!0}]:[],{id:"preflight",label:"Checking GAIA can run here",doneLabel:"GAIA can run here",minor:!0},{id:"files",...o},{id:"configure",label:"Saving your settings",doneLabel:"Saved your settings",minor:!0},...e.noStart?[]:[e.build?{id:"download",label:"Building GAIA",doneLabel:"Built GAIA"}:{id:"download",label:"Downloading GAIA",doneLabel:"Downloaded GAIA"},{id:"start",label:"Starting GAIA",doneLabel:"Started GAIA"},...r==="set-up"?[{id:"local-name",label:"Setting up gaia.local",doneLabel:"gaia.local set up"}]:[]],...n?[{id:"provider",label:`Checking your ${n} key`,doneLabel:`Saved your ${n} key`}]:[]]}function Cw(e,t){return cr(e)?(t&&Xi(e),"existing"):t?"clone":"bundle"}function kw(e){return new Error(`${e} is set up for development (apps/api/.env is in developer mode), and 'gaia up' would overwrite its settings.
|
|
138
|
+
Run it with --force-dev-tree to go ahead anyway.`)}function Pr(e,t){Ve(e,"failed"),e.setError(t)}async function Ap(e,t={}){Ep(t);let r=Math.min(Date.now(),...Object.values(Un()).map(E=>E.startedAt)),n=Yo(),o=n??Hd,i;try{i=Cw(o,t.build===!0)}catch(E){e.setError(E);return}e.pushAnswerResolver(Wd({repoPath:o}));let s=t.domain??Nn(o),a=Tw(t,s);if(go(e,Rw(t,i,a)),e.setStep("Prerequisites"),!await Pw(e,t,i)||(ke(e,"docker"),!await Ow(e,a))||(ge(e,"preflight"),!t.build&&!await Lw(e,o,i!=="existing")))return;let c=await dr(e,"selfhost");if(c===null){Ve(e,"failed");return}if(Object.assign(c,Vd(t)),i==="existing"&&o!==n&&!t.forceDevTree&&await $(o)==="developer"){Pr(e,kw(o));return}if(ke(e,"preflight"),ge(e,"files"),!await Nw(e,o,i))return;if(we(t.codeSandbox===void 0?{repoPath:o}:{repoPath:o,codeSandbox:t.codeSandbox}),ke(e,"files",i==="existing"?`Using your install at ${F(o)}`:void 0),ge(e,"configure"),await kr(e,o,"selfhost",c,{llmProvider:t.llmProvider,domain:t.domain}),e.currentState.error){Ve(e,"failed");return}ke(e,"configure");let l=_w(o),d=l.webPort,p={...Dw(d,s),noStart:t.noStart===!0,stillStarting:!1,setupComplete:!1,elapsedMs:0,startedServices:0};if(t.noStart){Rp(e,o,{...p,elapsedMs:Date.now()-r});return}try{p.startedServices=await Uw(e,o,c,t)}catch(E){Pr(e,E);return}let m=l.apiUrl,g=await Aw(e,{apiUrl:m,webPort:d},p.startedServices);p.stillStarting=!g.ready,p.setupComplete=g.ready&&await jw(m),Object.assign(p,await $w(e,a,d,g.ready));let v=await Bw(e,o,t,g.ready);if(t.llmProvider&&(v?p.unsavedProvider=t.llmProvider:p.savedProvider=t.llmProvider),Rp(e,o,{...p,elapsedMs:Date.now()-r}),v){e.setError(v);return}g.ready&&Fw(p.webUrl,t)}async function Aw(e,t,r){let n=(Pp(e,"start")?.substeps??[]).map(s=>({...s,state:"done",note:void 0})),o=s=>te(e,"start",{substeps:[...n,{id:"answer",label:"Waiting for GAIA to answer",state:"active",...s.length>0?{note:s.join(" and ")}:{}}]});te(e,"start",{detail:void 0,percent:void 0,amount:void 0,etaMs:void 0}),o([]);let i=await ni(e,t,o);return i.ready?ke(e,"start",r===0?"GAIA was already running":void 0):te(e,"start",{state:"failed",endedAt:Date.now()}),i}async function Pw(e,t,r){ge(e,"docker");try{return await So(e,{needGit:r==="clone",assumeYes:t.yes===!0,rerunCommand:"gaia up",onInstallStart:o=>ge(e,"docker",{label:`Installing ${ur(o)}`,doneLabel:`${ur(o)} installed`,startedAt:Date.now()}),onInstallProgress:o=>Ql(e,"docker",hs,o.stage,o.note)})!=="relaunch"}catch(n){return n instanceof rn?(en(e,"docker"),e.updateData(fa,n.message),process.exitCode=1,!1):(Pr(e,n),!1)}}function Tw(e,t){return ip({optedOut:e.localName===!1,domain:t,setUpBefore:P()?.localName===!0})}function _w(e){let t=k(e);return{webPort:t[O]??O,apiUrl:me("selfhost",t)}}function Dw(e,t){return{webUrl:ts(e,t),localhostUrl:Zi(e),lanUrls:es(e),localCertificate:t!==void 0&&Dn(t)}}async function Ow(e,t){if(t!=="remove")return!0;ge(e,"local-name-off");try{await Jo()}catch(r){return Pr(e,new Error(`Couldn't remove the gaia.local name: ${r.message}`)),!1}return we({localName:!1}),ke(e,"local-name-off"),!0}async function $w(e,t,r,n){if(t!=="set-up")return{};if(ge(e,"local-name"),!n)return en(e,"local-name"),{localNameProblem:"GAIA didn't answer in time; run 'gaia up' again once 'gaia status' shows it running"};we({localName:!0});try{await up(r)}catch(o){return en(e,"local-name"),{localNameProblem:o.message}}return ke(e,"local-name"),{localUrl:np}}async function Lw(e,t,r){let n=r?je:Ue(t);e.setStatus(`Checking that GAIA ${n} is available for this computer\u2026`);let o=await or(n,P()?.bots??[]);if(!o)return!0;let{cause:i,next:s}=rr(o,kp);return Pr(e,new Error(`${i}
|
|
139
|
+
${s}`)),!1}function Mw(e,t){let r=vr();return({received:n,total:o})=>te(e,t,o===null?{detail:`${Re(n)} downloaded`}:{amount:{done:n,total:o,unit:"bytes",estimated:!1},etaMs:r.update(n,o)})}async function Nw(e,t,r){if(r==="existing")return!0;try{if(r==="bundle"){let n=await ro(t,je,Mw(e,"files"));return await to(n.manifest,n.stagingDir,t,[]),Kr(t,je),!0}te(e,"files",{detail:"Connecting to GitHub\u2026"}),await Mc(t,$c,(n,o)=>{te(e,"files",o?{percent:n,detail:o}:{percent:n})})}catch(n){return Pr(e,new Error(`Couldn't get GAIA into ${F(t)}: ${n.message}`)),!1}return!0}function Fw(e,t){let r=process.stdin.isTTY===!0&&process.stdout.isTTY===!0;!t.yes&&r&&Cp.platform()==="darwin"&&xw("open",[`${e}/setup`],()=>{})}async function Bw(e,t,r,n){let{llmProvider:o}=r;if(!o)return null;let i=Ar[o];if(ge(e,"provider"),!n)return Ve(e,"failed"),new Error(`GAIA didn't answer in time, so your ${i} key wasn't saved.
|
|
140
|
+
Once 'gaia status' shows it running, run 'gaia up' again with the same flags.`);try{await xp(t,{...r,llmProvider:o})}catch(s){return Ve(e,"failed"),new Error(`Your ${i} key wasn't saved: ${s.message}
|
|
141
|
+
Check the key and run 'gaia up --llm-provider ${o} --llm-key <key>' again, or add it on the setup page above.`)}return ke(e,"provider"),null}function Gw(e){return e.stage==="starting"||e.stage==="stopping"?"start":"download"}function Pp(e,t){return(e.currentState.data[Nt]??[]).find(n=>n.id===t)}function ma(e,t){return Pp(e,t)?.state}function Ip(e){let t=ma(e,"download");t==="active"&&ke(e,"download"),t==="pending"&&en(e,"download")}async function Uw(e,t,r,n){ge(e,"download",n.build?{hint:Iw}:{detail:"Checking which images this computer needs"});let o=vr(),i=a=>{let c=Gw(a);c==="start"&&Ip(e),ma(e,c)!=="active"&&ge(e,c);let l=a.amount?.unit==="bytes"?a.amount:void 0;te(e,c,{detail:a.parts?void 0:a.detail??a.label,substeps:a.parts,percent:a.percent,amount:l,etaMs:l?o.update(l.done,l.total):void 0})},{startedServices:s}=await ue(t,"selfhost",void 0,r,i,{...n.build?{build:!0}:{pull:"missing"},rebuildCommand:kp});return Ip(e),ma(e,"start")!=="active"&&ge(e,"start"),s}async function jw(e){let t=await He(e,"status");return"data"in t&&!t.data.needs_setup}function Rp(e,t,r){we({version:A,setupComplete:!0,setupMethod:e.currentState.data.envMethod||"manual",repoPath:t}),e.updateData("setupMode","selfhost"),e.updateData("upOutcome",r),e.updateData("finished",!0),e.setStep("Finished")}var oi=[["gaia status","check health"],["gaia stop","stop GAIA"],["gaia doctor","find problems"],["gaia --help","all commands"]];function qw(e){if(e.noStart)return"GAIA is set up \xB7 nothing was started";if(e.stillStarting)return"GAIA is still starting";let t=e.startedServices===0?"GAIA is already running":`GAIA is running \xB7 ready in ${gt(e.elapsedMs)}`;return e.unsavedProvider?`${t} \xB7 your ${Ar[e.unsavedProvider]} key wasn't saved`:e.startedServices===0?`${t} \xB7 nothing to do`:t}function Hw(e){return e.localNameProblem?{label:"gaia.local",text:`isn't set up: ${e.localNameProblem}`,tone:"warn"}:null}function Vw(e){let t=e.localUrl??e.webUrl,r=[e.localhostUrl,...e.localUrl?[]:e.lanUrls].filter(n=>n!==t);return{primary:t,others:r}}function ii(e){let t=[];if(e.noStart)t.push({label:"Next",text:"Start it with gaia start",tone:"primary"});else{e.stillStarting&&t.push({label:"Status",text:"It is still starting in the background. Check again with gaia status.",tone:"warn"});let{primary:n,others:o}=Vw(e),i=`${n}/setup`;t.push(e.setupComplete?{label:"Next",text:`Open ${n}`,url:n,tone:"primary"}:{label:"Next",text:`Open ${i} to create your admin account.`,url:i,tone:"primary"}),o.length>0&&t.push({label:"Also at",text:o.join(", "),tone:"dim"})}let r=Hw(e);return r&&t.push(r),e.localCertificate&&t.push({label:"Certificate",text:`from GAIA's own certificate authority, so browsers warn until a device trusts it. Copy it with: ${nc}`,tone:"warn"}),e.savedProvider&&t.push({label:"AI",text:`${Ar[e.savedProvider]} key saved \xB7 change it in Settings`}),{tone:e.noStart||e.stillStarting?"pending":"success",headline:qw(e),rows:t}}import{jsx as B,jsxs as wn}from"react/jsx-runtime";var Yw={kind:"header"},zw="GAIA_CONTINUES_INSTALLER",Tp=2,Xw=14,_p=30,Jw=({outcome:e})=>{let t=ii(e),r=t.tone==="success"?"green":w;return wn(Xe,{flexDirection:"column",marginTop:1,children:[B(jo,{headline:t.headline,rows:t.rows,accent:r,success:t.tone==="success"}),B(Xe,{flexDirection:"row",flexWrap:"wrap",marginTop:1,paddingX:2,width:_p*2+4,children:oi.map(([n,o])=>wn(Xe,{width:_p,children:[B(Xe,{width:Xw,children:B(ga,{color:w,children:n})}),B(ga,{color:"gray",children:o})]},n))})]})},Qw=({state:e,store:t})=>e.inputRequest?.id==="port_conflicts"?e.data.portConflicts?B(br,{portResults:e.data.portConflicts,onAccept:()=>t.submitInput("accept"),onAbort:()=>t.submitInput("abort")}):null:B(Er,{inputId:e.inputRequest?.id,missing:e.data[Gt],onConfirm:()=>t.submitInput("install"),onDecline:()=>t.submitInput("decline")}),Dp=({text:e})=>wn(Xe,{children:[B(z,{kind:"warn"}),B(ga,{children:e})]});function Zw(){if(Gn())return[];let e=eo(process.env,A).map(t=>({kind:"note",text:t}));return process.env[zw]==="1"?e:[Yw,...e]}function eb(e){return e.kind==="step"?e.step.id:e.kind==="note"?e.text:"header"}var tb=({item:e})=>e.kind==="step"?B(Ho,{step:e.step}):e.kind==="note"?B(Dp,{text:e.text}):B(Xe,{marginBottom:1,children:B(wt,{showStatus:!1,showUpdate:!1})}),Op=({store:e})=>{let t=Se(e),r=t.data.steps??[],n=t.data.upOutcome,o=t.data[fa],i=t.data.finished===!0&&n!==void 0,{finished:s,live:a}=qo(r),c=a.find(p=>p.state!=="pending"),[l]=Kw(Zw),d=[...l,...s.map(p=>({kind:"step",step:p}))];return wn(Xe,{flexDirection:"column",width:"100%",children:[B(Ww,{items:d,children:p=>B(Xe,{paddingLeft:Tp,children:B(tb,{item:p})},eb(p))}),wn(Xe,{flexDirection:"column",paddingLeft:Tp,children:[c&&B(Vo,{step:c,waiting:t.inputRequest!==null,status:t.status}),B(Qw,{state:t,store:e}),o&&B(Xe,{marginTop:1,children:B(Dp,{text:o})})]}),i&&B(Jw,{outcome:n}),t.error&&B(_e,{message:t.error.message})]})};import{Select as va,Spinner as db}from"@inkjs/ui";import{Box as h,Text as f,useInput as Tr}from"ink";import En from"ink-text-input";import{useEffect as ya,useState as be}from"react";import{Box as rb,Text as ha,useInput as nb}from"ink";import{useState as ob}from"react";import{jsx as ib,jsxs as Sa}from"react/jsx-runtime";var $p=8;function Lp(e,t){return`${e} ${t}${e===1?"":"s"}`}var si=({logs:e})=>{let[t,r]=ob({offset:0,lineCount:e.length}),n=t.lineCount===e.length?t.offset:0,o=Math.min(e.length,$p),i=e.length>$p;nb((c,l)=>{i&&(l.upArrow?r({offset:Math.min(n+1,e.length-o),lineCount:e.length}):l.downArrow&&r({offset:Math.max(0,n-1),lineCount:e.length}))});let s=Math.max(0,e.length-o-n),a=e.slice(s,s+o);return Sa(rb,{flexDirection:"column",marginTop:1,marginLeft:1,children:[s>0&&Sa(ha,{color:"gray",children:[Lp(s,"earlier line")," (\u2191 to scroll)"]}),a.map((c,l)=>ib(ha,{color:"gray",wrap:"truncate",children:c},s+l)),n>0&&Sa(ha,{color:"gray",children:[Lp(n,"newer line")," (\u2193)"]})]})};import{Box as bn,Text as ai}from"ink";import{Box as sb,Text as ab}from"ink";import{jsx as Mp}from"react/jsx-runtime";var cb=new Set(["Welcome","Finished"]),Np=({status:e,step:t})=>cb.has(t)?null:Mp(sb,{width:"100%",paddingX:1,marginTop:1,children:Mp(ab,{color:"gray",dimColor:!0,children:e})});import{jsx as bt,jsxs as ci}from"react/jsx-runtime";var lb=[{id:"Welcome",label:"Welcome"},{id:"Prerequisites",label:"Prereqs"},{id:"Setup Mode",label:"Mode"},{id:"Repository Setup",label:"Repo"},{id:"Environment Setup",label:"Env"},{id:"Install Tools",label:"Tools"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],Fp=[{id:"Detect Repo",label:"Detect"},{id:"Prerequisites",label:"Prereqs"},{id:"Environment Setup",label:"Env"},{id:"Project Setup",label:"Setup"},{id:"Finished",label:"Done"}],ub=({currentStep:e,steps:t})=>{let r=t.findIndex(o=>o.id===e),n=r===t.length-1;return bt(bn,{marginY:1,flexWrap:"wrap",children:t.map(({id:o,label:i},s)=>{let a=s<r||n,c=s===r&&!n;return ci(bn,{flexShrink:0,children:[s>0&&bt(ai,{color:"gray",children:" \xB7 "}),a&&ci(ai,{color:"green",children:[y.ok," ",i]}),c&&bt(ai,{color:w,bold:!0,children:i}),!a&&!c&&bt(ai,{color:"gray",children:i})]},o)})})},li=({children:e,status:t,step:r,steps:n=lb,header:o})=>ci(bn,{flexDirection:"column",height:"100%",width:"100%",children:[ci(bn,{flexGrow:1,flexDirection:"column",children:[bt(wt,{...o}),bt(ub,{currentStep:r,steps:n}),bt(bn,{flexDirection:"column",flexGrow:1,children:e})]}),bt(Np,{status:t,step:r})]});import{jsx as u,jsxs as S}from"react/jsx-runtime";var pb=({onConfirm:e})=>(Tr((t,r)=>{r.return&&e()}),S(h,{flexDirection:"column",paddingX:2,borderStyle:_,borderColor:w,children:[u(f,{bold:!0,children:"Welcome to GAIA Setup"}),S(h,{flexDirection:"column",marginTop:1,marginBottom:1,children:[u(f,{children:"This wizard will guide you through the setup process:"}),u(f,{children:" 1. Check prerequisites and choose setup mode"}),u(f,{children:" 2. Clone repository"}),u(f,{children:" 3. Configure environment variables"}),u(f,{children:" 4. Install tools and dependencies"})]}),u(f,{dimColor:!0,children:"~5-15 min depending on network speed"}),u(h,{marginTop:1,children:S(f,{color:w,children:[u(f,{bold:!0,children:"Enter"})," to start"]})})]})),mb=({defaultValue:e,onSubmit:t})=>{let[r,n]=be(e);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[u(f,{children:"Clone repository to:"}),u(f,{color:"gray",dimColor:!0,children:"Press Enter for default, or type a custom path"}),S(h,{marginTop:1,children:[u(f,{color:w,children:"\u2192 "}),u(En,{value:r,onChange:n,onSubmit:t})]})]})},fb=({repoPath:e,onAction:t})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:"yellow",children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:"yellow",children:"Existing Installation Found"})}),S(f,{children:["Found a GAIA installation at"," ",u(f,{color:"cyan",bold:!0,children:e})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"What would you like to do?"})}),u(h,{marginTop:1,children:u(va,{options:[{label:"Use existing installation",value:"use_existing"},{label:"Delete and re-clone",value:"delete_reclone"},{label:"Choose a different path",value:"different_path"},{label:"Exit setup",value:"exit"}],onChange:n=>t(n)})})]}),gb=({setupMode:e,portOverrides:t,stillStarting:r,onConfirm:n})=>{Tr((s,a)=>{a.return&&n()});let o=t?.[3e3]??3e3,i=me(e??"developer",t??{});return e==="selfhost"?S(h,{flexDirection:"column",marginTop:2,borderStyle:_,borderColor:"green",padding:1,children:[u(f,{bold:!0,color:"green",children:r?"GAIA is starting\u2026":"GAIA is running"}),u(h,{marginTop:1,children:u(f,{color:"green",children:r?"Containers are up but not answering yet":"\u2713 All services started"})}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Finish setup in your browser:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o,"/setup"]})]}),S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia doctor"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]}):S(h,{flexDirection:"column",marginTop:2,borderStyle:_,borderColor:w,padding:1,children:[u(f,{color:w,bold:!0,children:"You're all set!"}),S(h,{marginTop:1,children:[u(f,{bold:!0,children:"Run: "}),u(f,{color:"cyan",children:"$ gaia dev"})]}),S(h,{marginTop:1,flexDirection:"column",children:[S(f,{children:["Web:"," ",S(f,{color:"cyan",bold:!0,children:["http://localhost:",o]})]}),S(f,{children:["API:"," ",u(f,{color:"cyan",bold:!0,children:i})]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," to exit"]})})]})},wa=({phase:e,progress:t,isComplete:r,logs:n,title:o,hint:i})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:w,children:o||"Installing Dependencies"})}),S(h,{flexDirection:"column",gap:1,children:[u(h,{children:r?S(f,{color:"green",children:[y.ok," ",e]}):u(db,{label:e||"Preparing\u2026"})}),!r&&t>0&&u(yr,{percent:t}),!r&&n&&n.length>0&&u(si,{logs:n}),!r&&u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:i||"This may take a few minutes\u2026"})})]})]}),ba=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[u(f,{bold:!0,children:"Setup Mode"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"How do you want to run GAIA?"})}),u(h,{marginTop:1,children:u(va,{options:[{label:"Self-Host \u2014 run everything in Docker",value:"selfhost"},{label:"Developer \u2014 local dev with hot reload",value:"developer"}],onChange:r=>e(r)})})]}),Ea=({onSelect:e})=>S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[u(f,{bold:!0,children:"Environment Variables Setup"}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Choose how you want to configure environment variables:"})}),u(h,{marginTop:1,children:u(va,{options:[{label:"Manual Setup (Recommended)",value:"manual"},{label:"Infisical (Advanced)",value:"infisical"}],onChange:r=>e(r)})}),S(h,{marginTop:1,flexDirection:"column",children:[u(f,{color:"gray",dimColor:!0,children:"Manual Setup: Configure variables interactively (recommended for most users)"}),u(f,{color:"gray",dimColor:!0,children:"Infisical: All secrets managed in Infisical dashboard (requires pre-configuration)"})]})]}),xa=({onSubmit:e})=>{let[t,r]=be({INFISICAL_PROJECT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_ID:"",INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET:""}),[n,o]=be(0),[i,s]=be(null),a=[{key:"INFISICAL_PROJECT_ID",description:"Found in your Infisical project settings"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_ID",description:"From Access Control \u2192 Machine Identities"},{key:"INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET",description:"Generated when creating the machine identity"}];Tr((l,d)=>{if(d.tab||d.downArrow)o(p=>p<a.length-1?p+1:p);else if(d.upArrow)o(p=>p>0?p-1:p);else if(d.return){if(n<a.length-1){o(m=>m+1);return}let p=a.filter(m=>!t[m.key].trim());if(p.length>0){s(`Required: ${p.map(g=>g.key).join(", ")}`);let m=a.findIndex(g=>!t[g.key].trim());m>=0&&o(m);return}e(t)}});let c=a[n];return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:w,children:[u(h,{marginBottom:1,children:u(f,{bold:!0,color:w,children:"Infisical Configuration"})}),u(h,{marginBottom:1,children:u(f,{color:"gray",children:"All secrets managed in your Infisical project. Only credentials stored locally."})}),S(h,{marginBottom:1,flexDirection:"column",children:[u(f,{color:"gray",children:"Configure your Infisical credentials."}),S(f,{color:"gray",dimColor:!0,children:["Visit"," ",u(f,{color:"cyan",underline:!0,children:"app.infisical.com"})," ","to get these values."]})]}),a.map((l,d)=>{let p=l.key.includes("SECRET")||l.key.includes("TOKEN");return S(h,{flexDirection:"column",marginBottom:1,children:[u(h,{children:S(f,{color:d===n?w:"white",children:[d===n?"\u25B8 ":" ",l.key,":"]})}),u(h,{marginLeft:2,children:u(f,{color:"gray",dimColor:!0,children:l.description})}),d===n?u(h,{marginLeft:2,children:u(En,{value:t[l.key],onChange:m=>{r(g=>({...g,[l.key]:m})),s(null)},placeholder:"Enter value\u2026",mask:p?"*":void 0})}):u(h,{marginLeft:2,children:u(f,{color:t[l.key]?"green":"gray",children:t[l.key]?p?`\u2713 ${"*".repeat(8)}`:`\u2713 ${t[l.key]}`:"(not set)"})})]},l.key)}),i&&u(h,{marginTop:1,children:u(f,{color:"red",children:i})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate"]})})]})},Ia=({category:e,currentIndex:t,totalGroups:r,onSubmit:n})=>{let[o,i]=be(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";return m}),[s,a]=be(0),[c,l]=be(null);ya(()=>{let m={};for(let g of e.variables)m[g.name]=g.defaultValue||"";i(m),a(0),l(null)},[e.name]),Tr((m,g)=>{if(g.tab||g.downArrow)a(v=>v<e.variables.length-1?v+1:v);else if(g.upArrow)a(v=>v>0?v-1:v);else if(g.escape){let v=e.variables.filter(E=>E.required&&!o[E.name]?.trim());if(v.length>0){l(`Required fields cannot be skipped: ${v.map(E=>E.name).join(", ")}`);return}n(o)}});let d=()=>{if(s<e.variables.length-1)a(s+1);else{let m=e.variables.filter(g=>g.required&&!o[g.name]?.trim());if(m.length>0){l(`Required fields are missing: ${m.map(g=>g.name).join(", ")}`);return}l(null),n(o)}},p=e.variables.some(m=>m.required);return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:c?"red":w,children:[S(h,{justifyContent:"space-between",children:[S(f,{bold:!0,children:["Configure ",e.name]}),S(f,{color:"gray",children:["Group ",t+1," / ",r]})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:e.description})}),u(h,{marginTop:1,flexDirection:"column",children:e.variables.map((m,g)=>{let v=g===s,E=!!m.defaultValue;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:v?w:"gray",bold:v,children:[v?"\u279C ":" ",m.name]}),m.required&&S(f,{color:"red",bold:!0,children:[" ","*"]}),E&&!v&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",m.defaultValue,")"]})]}),v&&u(h,{marginLeft:2,children:u(En,{value:o[m.name]||"",onChange:b=>{i(x=>({...x,[m.name]:b})),c&&l(null)},onSubmit:d,placeholder:E?`Default: ${m.defaultValue}`:m.required?"Enter a value (required)":"Press Enter to skip"})})]},m.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," next \xB7 ",u(f,{bold:!0,children:"\u2191\u2193"})," navigate",!p&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Ra=({alternatives:e,onSubmit:t})=>{let[r,n]=be(new Set),[o,i]=be({}),[s,a]=be(0),[c,l]=be(null);ya(()=>{let b={};for(let x of e)for(let G of x.variables)b[G.name]=G.defaultValue||"";i(b)},[e]);let d=[];for(let b=0;b<e.length;b++)if(d.push({type:"provider",categoryIndex:b}),r.has(b)){let x=e[b];if(x)for(let G=0;G<x.variables.length;G++)d.push({type:"field",categoryIndex:b,fieldIndex:G})}d.push({type:"submit"});let p=d[s],m=p?.type==="field",g=p?.type==="submit";Tr((b,x)=>{let G=Math.min(s,d.length-1);if(G!==s){a(G);return}if(m)x.upArrow?a(N=>Math.max(0,N-1)):(x.downArrow||x.tab)&&a(N=>Math.min(d.length-1,N+1));else if(g)x.upArrow?a(N=>Math.max(0,N-1)):(x.return||b===" ")&&E();else if(x.upArrow)a(N=>Math.max(0,N-1));else if(x.downArrow||x.tab)a(N=>Math.min(d.length-1,N+1));else if((x.return||b===" ")&&p?.type==="provider"){let N=p.categoryIndex;n(Ct=>{let U=new Set(Ct);return U.has(N)?U.delete(N):U.add(N),U}),c&&l(null)}});let v=()=>{c&&l(null),a(b=>Math.min(d.length-1,b+1))},E=()=>{let b=[],x={};for(let G of r){let N=e[G];if(!N)continue;if(N.variables.some(U=>o[U.name]?.trim())){b.push(N.name);for(let U of N.variables){let Rn=o[U.name];Rn&&(x[U.name]=Rn)}}}if(b.length===0){r.size===0?l("Enable at least one provider (press Space or Enter)"):l("Enter a value for at least one field");return}t(b,x)};return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:c?"red":w,children:[S(h,{justifyContent:"space-between",children:[u(f,{bold:!0,children:"Configure AI Provider"}),u(f,{color:"yellow",children:"* At least one required"})]}),u(h,{marginTop:1,children:u(f,{color:"gray",children:"Enable and configure at least one AI provider below:"})}),u(h,{marginTop:1,flexDirection:"column",children:e.map((b,x)=>{let G=r.has(x),N=d.findIndex(U=>U.type==="provider"&&U.categoryIndex===x),Ct=s===N;return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[u(f,{color:Ct?w:void 0,bold:Ct,children:Ct?"\u279C ":" "}),u(f,{color:G?"green":"gray",children:G?`[${y.ok}]`:"[ ]"}),S(f,{color:G?w:"gray",bold:G,children:[" ",b.name]}),b.description&&S(f,{color:"gray",dimColor:!0,children:[" ","- ",b.description]})]}),Ct&&b.docsUrl&&S(h,{marginLeft:6,children:[u(f,{color:"yellow",children:"\u{1F4D6} "}),u(f,{color:"blue",underline:!0,children:b.docsUrl})]}),G&&u(h,{marginLeft:4,flexDirection:"column",marginTop:1,children:b.variables.map((U,Rn)=>{let Dm=d.findIndex(Or=>Or.type==="field"&&Or.categoryIndex===x&&Or.fieldIndex===Rn),Qt=s===Dm,La=!!U.defaultValue,vi=o[U.name]||"";return S(h,{flexDirection:"column",marginBottom:1,children:[S(h,{children:[S(f,{color:Qt?w:"gray",bold:Qt,children:[Qt?" \u279C ":" ",U.name]}),!Qt&&vi&&u(f,{color:"green",children:" \u2713"}),!Qt&&!vi&&La&&S(f,{color:"gray",dimColor:!0,children:[" ","(default: ",U.defaultValue,")"]})]}),Qt&&u(h,{marginLeft:4,children:u(En,{value:vi,onChange:Or=>{i(Om=>({...Om,[U.name]:Or})),c&&l(null)},onSubmit:v,placeholder:La?`Default: ${U.defaultValue}`:"Enter value\u2026"})})]},U.name)})})]},b.name)})}),c&&u(h,{marginTop:1,children:S(f,{color:"red",bold:!0,children:[y.warn," ",c]})}),S(h,{marginTop:1,children:[u(f,{color:g?w:void 0,bold:g,children:g?"\u279C ":" "}),u(h,{borderStyle:_,borderColor:g?w:"gray",paddingX:2,children:u(f,{color:g?w:"gray",bold:g,children:"Continue \u2192"})})]}),u(h,{marginTop:1,children:u(f,{color:"gray",dimColor:!0,children:"\u2191/\u2193 navigate \u2022 Space/Enter toggle/select \u2022 Tab skip field"})})]})},Ca=({currentVar:e,currentIndex:t,totalCount:r,onSubmit:n,onSkip:o})=>{let[i,s]=be(e.defaultValue||""),[a,c]=be(null);ya(()=>{s(e.defaultValue||""),c(null)},[e.name]),Tr((p,m)=>{if(m.escape){if(e.required&&!i.trim()){c("This field is required and cannot be skipped");return}o()}});let l=p=>{if(e.required&&!p.trim()){c("This field is required");return}c(null),n(p)},d=!!e.defaultValue;return S(h,{flexDirection:"column",marginTop:1,paddingX:1,borderStyle:_,borderColor:a?"red":w,children:[S(h,{justifyContent:"space-between",children:[S(h,{children:[u(f,{color:w,bold:!0,children:e.name}),e.required?u(f,{color:"red",children:" *"}):S(f,{color:"gray",dimColor:!0,children:[" ","optional"]})]}),S(f,{color:"gray",children:[t+1,"/",r]})]}),u(h,{marginLeft:1,children:u(f,{color:"gray",children:e.description})}),S(h,{marginTop:1,children:[u(f,{color:w,children:"\u2192 "}),u(En,{value:i,onChange:p=>{s(p),a&&c(null)},onSubmit:l,placeholder:d?`Default: ${e.defaultValue}`:e.required?"required":"skip with Enter"})]}),a&&u(h,{marginTop:1,children:u(f,{color:"red",children:a})}),u(h,{marginTop:1,children:S(f,{dimColor:!0,children:[u(f,{bold:!0,children:"Enter"})," confirm",!e.required&&S(f,{children:[" ","\xB7 ",u(f,{bold:!0,children:"ESC"})," skip"]})]})})]})},Bp=({store:e})=>{let t=Se(e);return S(li,{status:t.status,step:t.step,children:[t.step==="Welcome"&&t.inputRequest?.id==="welcome"&&u(pb,{onConfirm:()=>e.submitInput(!0)}),t.step==="Prerequisites"&&t.data.checks&&u(Wo,{checks:t.data.checks}),u(Er,{inputId:t.inputRequest?.id,missing:t.data[Gt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&u(br,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="repo_path"&&u(mb,{defaultValue:t.inputRequest.meta.default,onSubmit:r=>e.submitInput(r)}),t.inputRequest?.id==="existing_repo"&&t.data.existingRepoPath&&u(fb,{repoPath:t.data.existingRepoPath,onAction:r=>e.submitInput(r)}),t.step==="Repository Setup"&&!t.inputRequest&&u(Ud,{title:"Cloning Repository",progress:t.data.repoProgress,phase:t.data.repoPhase}),t.inputRequest?.id==="setup_mode"&&u(ba,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&u(Ea,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&u(xa,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&u(Ca,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&u(Ia,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&u(Ra,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&u(Ko,{status:t.status}),t.step==="Finished"&&u(gb,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,stillStarting:t.data.stillStarting===!0,onConfirm:()=>e.submitInput("exit")}),(t.step==="Install Tools"||t.step==="Project Setup")&&u(wa,{title:t.step==="Install Tools"?"Installing Tools":"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.step==="Install Tools"?t.data.toolComplete||!1:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.error&&u(_e,{message:t.error.message})]})};import{Spinner as hb}from"@inkjs/ui";import{Box as zt,Text as _r}from"ink";import{useState as Sb}from"react";import{jsx as Et,jsxs as Fe}from"react/jsx-runtime";var Gp=({store:e})=>{let t=Se(e),r=t.step==="Starting"||t.step==="Stopping",n=t.step==="Running"||t.step==="Stopped",o=t.data.dockerLogs??[],[i]=Sb(Date.now),s=na(r);return Fe(zt,{flexDirection:"column",width:"100%",children:[Et(wt,{showStatus:n}),r&&!t.error&&Fe(zt,{flexDirection:"column",marginTop:1,children:[Fe(zt,{children:[Et(hb,{label:t.status||"Working\u2026"}),Fe(_r,{color:"gray",children:[" ",gt(s-i)]})]}),o.length>0&&Et(si,{logs:o})]}),t.step==="Running"&&t.data.started&&Fe(zt,{flexDirection:"column",marginTop:1,children:[Fe(zt,{children:[Et(z,{kind:"ok"}),Fe(_r,{children:["GAIA is running at"," ",Et(_r,{color:"cyan",bold:!0,children:t.data.webUrl})]})]}),Fe(_r,{color:"gray",children:[" ","gaia status shows its health \xB7 gaia stop shuts it down"]})]}),t.step==="Stopped"&&t.data.stopped&&Fe(zt,{flexDirection:"column",marginTop:1,children:[Fe(zt,{children:[Et(z,{kind:"ok"}),Et(_r,{children:t.status})]}),t.data.stopMode==="force-ports"&&Fe(_r,{color:"yellow",children:[" ","--force-ports also stopped whatever else listened on GAIA's ports."]})]}),t.error&&Et(_e,{message:t.error.message})]})};import{Spinner as vb}from"@inkjs/ui";import{Box as xt,Text as Oe,useInput as yb}from"ink";import{jsx as T,jsxs as Je}from"react/jsx-runtime";var Up=({store:e})=>{let t=Se(e);return Je(li,{status:t.status,step:t.step,steps:Fp,children:[t.step==="Detect Repo"&&Je(xt,{flexDirection:"column",paddingX:2,borderStyle:_,borderColor:w,children:[T(Oe,{bold:!0,children:"Detecting GAIA Repository"}),T(xt,{marginTop:1,children:T(vb,{label:"Searching for repository\u2026"})}),t.data.repoPath&&T(xt,{marginTop:1,children:Je(Oe,{color:"green",children:["Found: ",t.data.repoPath]})})]}),t.step==="Prerequisites"&&t.data.checks&&T(Wo,{checks:t.data.checks}),T(Er,{inputId:t.inputRequest?.id,missing:t.data[Gt],onConfirm:()=>e.submitInput("install"),onDecline:()=>e.submitInput("decline")}),t.inputRequest?.id==="port_conflicts"&&t.data.portConflicts&&T(br,{portResults:t.data.portConflicts,onAccept:()=>e.submitInput("accept"),onAbort:()=>e.submitInput("abort")}),t.inputRequest?.id==="setup_mode"&&T(ba,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_method"&&T(Ea,{onSelect:r=>e.submitInput(r)}),t.inputRequest?.id==="env_infisical"&&T(xa,{onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_var"&&t.data.currentEnvVar&&T(Ca,{categories:t.data.envCategories||[],currentVar:t.data.currentEnvVar,currentIndex:t.data.envVarIndex||0,totalCount:t.data.envVarTotal||0,onSubmit:r=>e.submitInput(r),onSkip:()=>e.submitInput("")}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_group"&&t.data.currentEnvGroup&&T(Ia,{category:t.data.currentEnvGroup,currentIndex:t.data.envGroupIndex||0,totalGroups:t.data.envGroupTotal||0,onSubmit:r=>e.submitInput(r)}),t.step==="Environment Setup"&&t.inputRequest?.id==="env_alternatives"&&t.data.alternativeGroups&&T(Ra,{alternatives:t.data.alternativeGroups,onSubmit:(r,n)=>e.submitInput({selectedGroups:r,values:n})}),t.step==="Environment Setup"&&!t.inputRequest&&T(Ko,{status:t.status}),t.step==="Project Setup"&&T(wa,{title:"Project Setup",phase:t.data.dependencyPhase||"",progress:t.data.dependencyProgress||0,isComplete:t.data.dependencyComplete||!1,logs:t.data.dependencyLogs||[]}),t.step==="Finished"&&T(wb,{setupMode:t.data.setupMode,portOverrides:t.data.portOverrides,onConfirm:()=>e.submitInput("exit")}),t.error&&T(_e,{message:t.error.message})]})},wb=({setupMode:e,portOverrides:t,onConfirm:r})=>{yb((s,a)=>{a.return&&r()});let n=t?.[3e3]??3e3,o=me(e??"developer",t??{}),i=e==="selfhost";return Je(xt,{flexDirection:"column",marginTop:2,borderStyle:_,borderColor:w,padding:1,children:[T(Oe,{color:w,bold:!0,children:"Setup Complete!"}),Je(xt,{marginTop:1,children:[T(Oe,{bold:!0,children:"Run: "}),T(Oe,{color:"cyan",children:i?"$ gaia start":"$ gaia dev"})]}),Je(xt,{marginTop:1,flexDirection:"column",children:[Je(Oe,{children:["Web:"," ",Je(Oe,{color:"cyan",bold:!0,children:["http://localhost:",n]})]}),Je(Oe,{children:["API:"," ",T(Oe,{color:"cyan",bold:!0,children:o})]})]}),T(xt,{marginTop:1,children:T(Oe,{color:"gray",children:i?"gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup":"gaia dev full \xB7 gaia logs \xB7 gaia stop \xB7 gaia status \xB7 gaia setup"})}),T(xt,{marginTop:1,children:Je(Oe,{dimColor:!0,children:[T(Oe,{bold:!0,children:"Enter"})," to exit"]})})]})};import{Spinner as Db}from"@inkjs/ui";import{Box as oe,Text as Qe,useInput as Ob}from"ink";var bb=[{name:"API",port:8e3,type:"http",path:"/health"},{name:"Web",port:3e3,type:"http",path:"/"},{name:"PostgreSQL",port:5432,type:"tcp"},{name:"Redis",port:6379,type:"tcp"},{name:"MongoDB",port:27017,type:"tcp"},{name:"RabbitMQ",port:5672,type:"tcp"},{name:"ChromaDB",port:8080,type:"tcp"}];async function jp(e){return Promise.all(bb.map(t=>{let r=e[t.port]??t.port;return t.type==="http"?Eb(t.name,r,t.path):xb(t.name,r)}))}async function Eb(e,t,r){let n=Date.now();try{let o=await fetch(`http://localhost:${t}${r}`,{signal:AbortSignal.timeout(5e3)}),i=Date.now()-n;return{name:e,port:t,status:o.ok?"up":"down",latency:i,details:o.ok?`HTTP ${o.status}`:`HTTP ${o.status} (error)`}}catch{return{name:e,port:t,status:"down",details:"Connection failed"}}}async function xb(e,t){let r=await import("node:net"),n=Date.now();return new Promise(o=>{let i=new r.Socket;i.setTimeout(3e3),i.on("connect",()=>{let s=Date.now()-n;i.destroy(),o({name:e,port:t,status:"up",latency:s})}),i.on("timeout",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.on("error",()=>{i.destroy(),o({name:e,port:t,status:"down"})}),i.connect(t,"localhost")})}async function qp(e){let t=await ee();if(t!=="ready")return{access:t,problem:await tt(t),containers:[]};let r=await qa(Ee[e]);return{access:t,containers:r}}var xn="statusFacts";async function Ib(){let e=L(),t=e?await $(e):null,r=zr(e,t);if(!e||!t)return{install:r,installed:!1,services:[],setupComplete:null};let n=k(e),o=n[O]??O,[i,s,a]=await Promise.all([t==="developer"?jp(n):[],qp(t),No(Lt(t,n),Ee[t])]),c=a.reachable?await He(me(t,n),"status"):null;return{install:r,installed:!0,docker:t==="selfhost"&&s.access==="ready"?{...s,containers:Rb(s.containers)}:s,readiness:a,services:i,webUrl:mt(e,o),setupComplete:c&&"data"in c?!c.data.needs_setup:null}}function Rb(e){let t=(P()?.bots??[]).map(Ie).filter(r=>!e.some(n=>n.name===r));return[...e,...t.map(r=>({name:r,status:"not_found"}))]}async function Cb(e){e.setStep("Checking"),e.setStatus("Checking GAIA's services\u2026");let t=await Ib();e.updateData(xn,t),e.updateData("checkedAt",new Date().toLocaleTimeString()),e.setStep("Results")}async function Hp(e,t={}){for(e.updateData("watch",t.watch===!0);;)if(await Cb(e),!t.watch||await e.waitForInput("exit_or_refresh")!=="refresh")return}var kb=["gaia-web","gaia-backend","arq_worker","proxy"],Ab=["mongo","postgres","redis","rabbitmq","chromadb"];function ui(e,t,r){return t.some(o=>!o.ok)?{label:e,items:t,note:r,tone:"fail"}:{label:e,items:t,tone:"ok"}}function Vp(e,t){return t.map(r=>e.find(n=>n.name===r)).filter(r=>r!==void 0).map(r=>({ok:r.status==="running",name:$e(r.name)}))}function Wp(e,t){let r=e.readiness,n=r?.reachable===!0?r.dependencies.map(i=>({ok:i.ok,name:Wn(i.name)})):Vp(t,Ab),o=r?.reachable===!0?r.dependencies.find(i=>!i.ok)?.fix:void 0;return ui("Data",n,o??"See why with: gaia doctor")}function Pb(e){let t=e.filter(r=>r.name.startsWith("bot-"));return t.length===0?{label:"Bots",items:[],note:"none \xB7 add one: gaia bots add telegram",tone:"dim"}:ui("Bots",t.map(r=>({ok:r.status==="running",name:$e(r.name)})),"See why with: gaia doctor")}function Kp(e){return e.setupComplete===null?null:e.setupComplete?{label:"Setup",items:[],note:"finished",tone:"ok"}:{label:"Setup",items:[],note:`not finished \xB7 open ${e.webUrl}/setup`,tone:"warn"}}function Tb(e,t){let r=t.containers,o=[ui("App",Vp(r,kb),"Start it: gaia start"),Wp(e,r),Pb(r)],i=Kp(e);i&&o.push(i);let s=r.some(c=>c.status==="running"),a=o.some(c=>c.tone==="fail");return s?{headline:a?{kind:"fail",text:"GAIA is running, but part of it is down"}:{kind:"ok",text:"GAIA is running",url:e.webUrl},rows:o,unhealthy:a}:{headline:{kind:"fail",text:"GAIA isn't running \xB7 start it: gaia start"},rows:[],unhealthy:!0}}function _b(e){let t=e.services.map(n=>({ok:n.status==="up",name:`${n.name} :${n.port}`})),r=ui("Local",t,"Start them: gaia dev");return{headline:r.tone==="fail"?{kind:"fail",text:"Part of the dev stack is down"}:{kind:"ok",text:"The dev stack is running",url:e.webUrl},rows:[r],unhealthy:r.tone==="fail"}}function di(e){if(!e.installed)return{headline:{kind:"warn",text:`${e.install} \xB7 run: gaia up`},rows:[],unhealthy:!0};let t=e.docker;if(t?.problem){let r=e.readiness?.reachable===!0,n={label:"Docker",items:[],note:t.problem.state,tone:"warn"},o=Kp(e);return{headline:r?{kind:"ok",text:"GAIA is running",url:e.webUrl}:{kind:"fail",text:t.problem.summary},hint:t.problem.fix,rows:r?[Wp(e,[]),...o?[o]:[],n]:[],unhealthy:!0}}return e.services.length>0?_b(e):Tb(e,t??{access:"ready",containers:[]})}import{jsx as M,jsxs as it}from"react/jsx-runtime";var $b=8,Lb={ok:void 0,warn:"yellow",fail:"red",dim:"gray"},Mb=({row:e})=>it(oe,{children:[M(oe,{width:$b,flexShrink:0,children:M(Qe,{bold:!0,children:e.label})}),it(oe,{flexDirection:"column",flexShrink:1,children:[e.items.length>0&&M(oe,{flexWrap:"wrap",children:e.items.map(t=>it(oe,{marginRight:2,flexShrink:0,children:[M(z,{kind:t.ok?"ok":"fail"}),M(Qe,{children:t.name})]},t.name))}),e.note&&it(oe,{children:[e.items.length===0&&e.tone!=="dim"&&M(z,{kind:e.tone==="warn"?"warn":"ok"}),M(Qe,{color:Lb[e.tone],children:e.note})]})]})]}),Yp=({store:e})=>{let t=Se(e),r=t.data[xn],n=t.data.watch===!0,o=t.step==="Results"&&r!==void 0;Ob((a,c)=>{a==="q"||c.return||c.escape?e.submitInput("exit"):a==="r"&&e.submitInput("refresh")},{isActive:n&&t.inputRequest!==null});let i=r?di(r):null,s=i?.headline.kind??"ok";return it(oe,{flexDirection:"column",width:"100%",children:[M(wt,{showStatus:!1}),t.step==="Checking"&&M(oe,{marginTop:1,marginLeft:2,children:M(Db,{label:t.status})}),o&&i&&it(oe,{flexDirection:"column",marginTop:1,marginLeft:2,children:[it(oe,{children:[M(z,{kind:s==="ok"?"active":s}),M(Qe,{bold:!0,children:i.headline.text})]}),i.headline.url&&M(oe,{marginLeft:2,children:M(Qe,{color:w,children:i.headline.url})}),i.hint&&M(oe,{marginLeft:2,children:M(Qe,{children:i.hint})}),i.rows.length>0&&M(oe,{flexDirection:"column",marginTop:1,children:i.rows.map(a=>M(Mb,{row:a},a.label))}),r.installed&&M(oe,{marginTop:1,children:it(Qe,{color:"gray",children:["Installed at ",r.install]})}),n&&M(oe,{marginTop:1,children:it(Qe,{color:"gray",children:["checked ",t.data.checkedAt," \xB7 ",M(Qe,{bold:!0,children:"r"})," check again \xB7 ",M(Qe,{bold:!0,children:"q"})," quit"]})})]}),t.error&&M(_e,{message:t.error.message})]})};import{defaultTheme as Nb,extendTheme as Fb}from"@inkjs/ui";var pi={success:"ok",error:"fail",warning:"warn",info:"active"},zp=Fb(Nb,{components:{Spinner:{styles:{frame:()=>({color:w})}},ProgressBar:{styles:{completed:()=>({color:w})},config:()=>({completedCharacter:yi.done,remainingCharacter:yi.rest})},StatusMessage:{styles:{icon:({variant:e})=>({color:Lr[pi[e]]})},config:({variant:e})=>({icon:y[pi[e]]})},Alert:{styles:{icon:({variant:e})=>({color:Lr[pi[e]]})},config:({variant:e})=>({icon:y[pi[e]]})}}});import{jsx as ie,jsxs as Dr}from"react/jsx-runtime";var jb=["init","setup","status","start","stop","up","uninstall"],ka=class extends Ub.Component{constructor(t){super(t),this.state={error:null}}static getDerivedStateFromError(t){return{error:t}}render(){return this.state.error?Dr(mi,{flexDirection:"column",padding:1,children:[ie(Xt,{color:"red",bold:!0,children:"An unexpected error occurred:"}),ie(Xt,{color:"red",children:this.state.error.message}),this.state.error.stack&&ie(mi,{marginTop:1,children:ie(Xt,{color:"gray",dimColor:!0,children:this.state.error.stack})})]}):this.props.children}},qb=({store:e,command:t})=>{switch(t){case"init":return ie(Bp,{store:e});case"setup":return ie(Up,{store:e});case"status":return ie(Yp,{store:e});case"start":case"stop":return ie(Gp,{store:e,command:t});case"up":return ie(Op,{store:e});case"uninstall":return ie(hp,{store:e});default:return Dr(mi,{flexDirection:"column",padding:1,children:[Dr(Xt,{color:"red",children:["Unknown command: ",t]}),Dr(mi,{marginTop:1,flexDirection:"column",children:[ie(Xt,{bold:!0,children:"Available commands:"}),jb.map(r=>Dr(Xt,{children:[" ",ie(Xt,{color:"cyan",children:r})]},r))]})]})}},Hb=({onCancel:e})=>(Gb((t,r)=>{r.ctrl&&t==="c"&&e()}),null),Xp=({store:e,command:t,onCancel:r})=>{let n=Se(e);return ie(ka,{children:Dr(Bb,{theme:zp,children:[ie(Hb,{onCancel:r}),n.data[Cn]!==!0&&ie(qb,{store:e,command:t})]})})};import{EventEmitter as Vb}from"events";var Wb=150,Aa=class extends Vb{state={step:"init",status:"",error:null,data:{},inputRequest:null};inputResolver=null;emitTimer=null;emitPending=!1;autoResolveInputs=new Map;answerResolvers=[];setAutoResolve(t,r="exit"){this.autoResolveInputs.set(t,r)}pushAnswerResolver(t){this.answerResolvers.push(t)}get currentState(){return this.state}scheduleEmit(){this.emitPending=!0,this.emitTimer||(this.emitTimer=setTimeout(()=>{this.emitTimer=null,this.emitPending&&(this.emitPending=!1,this.emit("change",this.state))},Wb))}flush(){this.emitPending&&this.emitNow()}emitNow(){this.emitTimer&&(clearTimeout(this.emitTimer),this.emitTimer=null),this.emitPending=!1,this.emit("change",this.state)}setStep(t){this.state.step=t,this.emitNow()}setStatus(t){this.state.status=t,this.scheduleEmit()}setError(t){this.state.error=t,t!==null&&this.inputResolver&&(this.inputResolver(null),this.inputResolver=null,this.state.inputRequest=null),this.emitNow()}updateData(t,r){this.state.data={...this.state.data,[t]:r},this.scheduleEmit()}ask(t,r,n){return this.answerResolvers.map(i=>i(t,n)).find(i=>i!==void 0)===void 0&&!this.autoResolveInputs.has(t)&&this.setStatus(r),this.waitForInput(t,n)}waitForInput(t,r,n){if(this.autoResolveInputs.has(t))return this.state.inputRequest=null,this.emitNow(),Promise.resolve(this.autoResolveInputs.get(t));for(let o of this.answerResolvers){let i=o(t,r);if(i!==void 0)return this.state.inputRequest=null,this.emitNow(),Promise.resolve(i)}return this.state.inputRequest={id:t,meta:r},this.emitNow(),new Promise(o=>{if(this.inputResolver=o,n!=null){let i=setTimeout(()=>{this.inputResolver&&(this.inputResolver=null,this.state.inputRequest=null,this.emitNow(),o(null))},n),s=this.inputResolver;this.inputResolver=a=>{clearTimeout(i),s(a)}}})}submitInput(t){this.inputResolver&&(this.inputResolver(t),this.inputResolver=null,this.state.inputRequest=null,this.emitNow())}},Jp=()=>new Aa;async function ve(e){let t=Jp();if(e.whenNonInteractive==="fail"){Zl(e.command),await Qp(t,e);return}he()?await Qp(t,e):await zb(t,e)}async function zb(e,t){eu(e,Gn());for(let[r,n]of t.autoResolve??[])e.setAutoResolve(r,n);try{await t.runFlow(e);let r=em(e);r&&await qn(r,{step:e.currentState.step,steps:ps(e)}),t.onPlainComplete?.(e)}catch(r){e.setError(r)}tm(e)}var Xb="\x1B[1F",Zp=30,Jb=Math.ceil(1e3/Zp);async function Pa(e){e.flush(),await new Promise(t=>setTimeout(t,2*Jb))}async function Qp(e,t){let r=async()=>{},{unmount:n}=Kb(Yb.createElement(Xp,{store:e,command:t.command,onCancel:()=>void r()}),{exitOnCtrlC:!1,maxFps:Zp}),o=async()=>{Ve(e,"cancelled"),await Pa(e),n();let s=t.cancelHint?` ${t.cancelHint}`:"";process.stdout.write(`
|
|
142
|
+
${y.cancelled} Cancelled.${s}
|
|
143
|
+
`),process.exit(130)};r=o,process.once("SIGINT",o),process.once("SIGTERM",o);try{await t.runFlow(e)}catch(s){e.setError(s)}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}await Pa(e);let i=em(e);i&&(e.updateData(Cn,!0),await Pa(e),n(),process.stdout.write(Xb),await qn(i,{step:e.currentState.step,steps:ps(e)})),n(),process.stdout.write(`
|
|
144
|
+
`),tm(e)}function em(e){if(!e.currentState.error)return e.currentState.data.dockerGroupSwitch}function tm(e){let t=e.currentState.error?1:Number(process.exitCode??0),r=[process.stdout,process.stderr].filter(o=>o.writableLength>0);r.length===0&&process.exit(t);let n=r.length;for(let o of r)o.once("drain",()=>{n-=1,n===0&&process.exit(t)})}import*as It from"fs";import*as rm from"os";import*as Jt from"path";var Qb=process.env.GAIA_CLI_DEV==="true";async function nm(e,t){e.setStep("Welcome"),e.setStatus("Waiting for user input\u2026"),await e.waitForInput("welcome");let r=vo(e);if(e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await yo(e))return;let n=await ti(e),o=await dr(e,n);if(o===null||n==="developer"&&!await wo(e))return;let i="";if(Qb){if(i=lr()||"",!i){e.setError(new Error("DEV_MODE: Could not find workspace root. Run from within the gaia repo."));return}e.setStep("Repository Setup"),e.setStatus("[DEV MODE] Using current workspace\u2026"),await Q(500),e.setStatus("Repository ready")}else{e.setStep("Repository Setup");let a=n==="selfhost"?Jt.join(rm.homedir(),"gaia"):Jt.resolve("gaia"),c=!0;for(i=a;;){if(i=await e.waitForInput("repo_path",{default:a}),Jt.isAbsolute(i)||(i=Jt.resolve(i)),It.existsSync(i)){if(!It.statSync(i).isDirectory()){e.setError(new Error(`Path ${i} exists and is not a directory.`)),await Q(2e3),e.setError(null);continue}if(sr(i)){e.updateData("existingRepoPath",i);let p=await e.waitForInput("existing_repo");if(p==="use_existing"){c=!1;break}else if(p==="delete_reclone"){e.setStatus("Removing existing installation\u2026");try{It.rmSync(i,{recursive:!0,force:!0})}catch(m){e.setError(new Error(`Failed to remove directory: ${m.message}
|
|
145
|
+
Try removing it manually: rm -rf "${i}"`));return}break}else{if(p==="different_path")continue;e.setError(new Error("Setup cancelled by user."));return}}if(It.readdirSync(i).length>0){e.setError(new Error(`Directory ${i} is not empty and is not a GAIA installation. Please choose another path.`)),await Q(2e3),e.setError(null);continue}}break}if(c){e.setStep("Repository Setup"),e.setStatus("Preparing repository\u2026"),e.updateData("repoProgress",0),e.updateData("repoPhase","");try{await Yn(i,"https://github.com/theexperiencecompany/gaia.git",(l,d)=>{e.updateData("repoProgress",l),d?(e.updateData("repoPhase",d),e.setStatus(`${d}\u2026`)):e.setStatus(`Cloning repository to ${i}... ${l}%`)},t),e.setStatus("Repository ready")}catch(l){e.setError(l);return}}else e.setStatus("Using the existing repository")}if(await Q(1e3),await kr(e,i,n,o),e.currentState.error)return;if(n==="selfhost"){e.setStep("Project Setup"),e.setStatus("Building and starting all services in Docker\u2026"),e.updateData("dependencyPhase","Building and starting Docker services\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]),e.updateData("dependencyComplete",!1);let a=cu(e),c=!1;try{e.setStatus("Pulling pre-built images from registry\u2026"),await ue(i,"selfhost",p=>e.setStatus(p),o,a,{pull:"missing"}),c=!0}catch(p){let m=p.message?.split(`
|
|
146
|
+
`)[0]??"unknown error";e.setStatus(`Registry pull failed (${m}) \u2014 building images locally (this takes a few minutes)\u2026`)}if(!c)try{await ue(i,"selfhost",p=>e.setStatus(p),o,a,{build:!0})}catch(p){e.setError(new Error(`Failed to start services: ${p.message}`));return}e.updateData("dependencyProgress",100),e.updateData("dependencyComplete",!0);let l=e.currentState.data.envMethod||"manual";Fn({version:A,setupComplete:!0,setupMethod:l,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.updateData("setupMode",n);let d=await ni(e,{apiUrl:me("selfhost",o),webPort:o[O]??O});e.updateData("stillStarting",!d.ready),e.setStep("Finished"),e.setStatus(d.ready?"Set up. GAIA is running.":"Containers are up but not answering yet \u2014 give it a minute, then open the setup link below."),await e.waitForInput("exit");return}e.setStep("Install Tools"),e.setStatus("Installing toolchain\u2026"),e.updateData("dependencyPhase","Initializing mise\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyPhase","Trusting mise configuration\u2026"),await de("mise",["trust"],i,void 0,r),e.updateData("dependencyProgress",50),e.updateData("dependencyPhase","Installing tools (node, python, uv, nx)\u2026"),await de("mise",["install"],i,a=>{e.updateData("dependencyProgress",50+a*.5)},r),e.updateData("dependencyProgress",100),e.updateData("toolComplete",!0)}catch(a){e.setError(new Error(`Failed to install tools: ${a.message}`));return}await Q(1e3),e.setStep("Project Setup"),e.updateData("dependencyPhase","Setting up project\u2026"),e.updateData("dependencyProgress",0),e.updateData("dependencyComplete",!1),e.updateData("repoPath",i),e.updateData("dependencyLogs",[]);try{e.updateData("dependencyProgress",0),e.updateData("dependencyPhase","Running mise setup (all dependencies)\u2026");let a=Object.keys(o).length>0?ct(o):void 0;await de("mise",["setup"],i,c=>{e.updateData("dependencyProgress",c)},r,a),e.updateData("dependencyProgress",100),e.updateData("dependencyPhase","Set up"),e.updateData("dependencyComplete",!0)}catch(a){e.setError(new Error(`Failed to setup project: ${a.message}`));return}await Q(1e3);let s=e.currentState.data.envMethod||"manual";Fn({version:A,setupComplete:!0,setupMethod:s,repoPath:i,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function om(e={}){await ve({command:"init",whenNonInteractive:"fail",runFlow:t=>nm(t,e.branch)})}import*as Be from"node:fs";import*as Ge from"node:path";import{execa as fi}from"execa";function Ta(e){if(e.fromDir){let t=Ge.resolve(e.fromDir),r=Ga(t);if(!r)return{volumeFiles:[]};let n=Zt(t,r),o=i=>Be.existsSync(i)?i:void 0;return{mongoFile:e.mongoFile??o(n.mongoFile),postgresFile:e.postgresFile??o(n.postgresFile),apiEnvFile:e.apiEnvFile??o(n.apiEnvFile),volumeFiles:n.volumeFiles.filter(i=>Be.existsSync(i.file))}}return{mongoFile:e.mongoFile,postgresFile:e.postgresFile,apiEnvFile:e.apiEnvFile,volumeFiles:[]}}function im(e){return!e.mongoFile||e.apiEnvFile?[]:["Restoring MongoDB without the backup's apps/api/.env: the stored provider credentials decrypt only under the INSTANCE_SECRET they were saved with. If this install's apps/api/.env is not the one the dump was taken with, they will not decrypt. Pass the backup's api-env-<stamp>.env with --env, or restore with --from <dir>."]}function _a(e){let{mongoFile:t,postgresFile:r,apiEnvFile:n,volumeFiles:o}=e,i=[];n&&i.push(`install -m 600 ${n} ../../apps/api/.env`),t&&i.push(`docker compose -f docker-compose.selfhost.yml exec -T mongo mongorestore --archive --gzip --drop < ${t}`),r&&(i.push("docker compose -f docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'"),i.push(`cat ${r} | docker compose -f docker-compose.selfhost.yml exec -T postgres psql -U postgres -d langgraph`));for(let{volume:s,file:a}of o)i.push(`docker run --rm -v ${s}:/data -v ${Ge.dirname(a)}:/backups alpine sh -c "${Mr(Ge.basename(a))}"`);return i}async function sm(e,t){let r=L();if(!r)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let n=Ge.join(r,"infra","docker"),o=Ge.join(n,"docker-compose.selfhost.yml");if(!Be.existsSync(o))throw new Error(`Compose file not found: ${o}`);let i=Ta(e),{mongoFile:s,postgresFile:a,apiEnvFile:c,volumeFiles:l}=i,d=_a(i);if(!s&&!a&&!c&&l.length===0)throw new Error(["No backup files specified.","Use --mongo <file> --postgres <file> or --from <backup-dir> containing mongo-*.gz and postgres-*.sql.","Example: gaia restore --from backups","Example: gaia restore --mongo backups/mongo-2026-08-27T09-30-00Z.gz --postgres backups/postgres-2026-08-27T09-30-00Z.sql"].join(`
|
|
147
|
+
`));if(c&&!Be.existsSync(c))throw new Error(`apps/api/.env backup not found: ${c}`);if(s&&!Be.existsSync(s))throw new Error(`Mongo backup not found: ${s}`);if(a&&!Be.existsSync(a))throw new Error(`Postgres backup not found: ${a}`);for(let{label:m,file:g}of l)if(!Be.existsSync(g))throw new Error(`${m} backup not found: ${g}`);if(e.dryRun)return{...i,commands:d};let p=await ee();if(p!=="ready"){let m=await tt(p);throw new Error([`${m.summary}, so nothing can be restored.`,m.fix,"Or run the restore commands yourself:",...d.map(g=>` ${g}`)].join(`
|
|
148
|
+
`))}if(c&&Zb(c,r),s)try{let m=fi("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","mongo","mongorestore","--archive","--gzip","--drop"],{cwd:n,stdin:"pipe",stderr:"pipe"}),g=Be.createReadStream(s);if(!m.stdin)throw new Error("Failed to pipe mongo restore stdin");g.pipe(m.stdin),await m}catch(m){throw new Error(`MongoDB restore failed: ${m.message}`)}if(a){try{await fi("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph","-c","DROP SCHEMA public CASCADE; CREATE SCHEMA public;"],{cwd:n})}catch(m){throw new Error(`Postgres schema reset failed: ${m.message}`)}try{let m=fi("docker",["compose","-f","docker-compose.selfhost.yml","exec","-T","postgres","psql","-U","postgres","-d","langgraph"],{cwd:n,stdin:"pipe",stderr:"pipe"}),g=Be.createReadStream(a);if(!m.stdin)throw new Error("Failed to pipe postgres restore stdin");g.pipe(m.stdin),await m}catch(m){throw new Error(`PostgreSQL restore failed: ${m.message}`)}}for(let{file:m,volume:g,label:v}of l)try{await fi("docker",["run","--rm","-v",`${g}:/data`,"-v",`${Ge.dirname(m)}:/backups`,"alpine","sh","-c",Mr(Ge.basename(m))],{cwd:n})}catch(E){throw new Error(`${v} restore failed: ${E.message}`)}return t("Restarting services so they load the restored data and settings\u2026"),await ue(r,"selfhost",t,k(r)),{...i,commands:d}}function Zb(e,t){Ln(e,rt(t))}function Ze(e=""){process.stdout.write(`${e}
|
|
149
|
+
`)}function eE(e=""){process.stderr.write(`${e}
|
|
150
|
+
`)}async function am(e={}){let t={mongoFile:e.mongo,postgresFile:e.postgres,apiEnvFile:e.env,fromDir:e.from},r=Ta(t);for(let n of im(r))eE(`${y.warn} ${n}`);if(e.dryRun){let n=_a(r);if(n.length===0){Ze("No backup files resolved. Use --from <dir> or --mongo/--postgres/--env <file>.");return}Ze("Restore commands (dry run \u2014 not executed):");for(let o of n)Ze(` ${o}`);return}try{Ze("Starting GAIA restore\u2026");let n=await sm(t,o=>Ze(` ${o}`));n.apiEnvFile&&Ze(`Restored apps/api/.env from ${n.apiEnvFile}`),n.mongoFile&&Ze(`Restored MongoDB from ${n.mongoFile}`),n.postgresFile&&Ze(`Restored PostgreSQL from ${n.postgresFile}`);for(let{label:o,file:i}of n.volumeFiles)Ze(`Restored ${o} from ${i}`);Ze("Restore complete. Run 'gaia doctor' to confirm every dependency is ready.")}catch(n){ye(n.message),process.exitCode=1}}async function cm(e){e.setStep("Detect Repo"),e.setStatus("Looking for GAIA repository\u2026");let t=lr();if(!t){e.setError(new Error("Could not find GAIA repository. Run this command from within a cloned gaia repo, or use 'gaia init' to set up from scratch."));return}if(e.updateData("repoPath",t),e.setStatus(`Found repository at ${t}`),await Q(1e3),e.setStep("Prerequisites"),e.setStatus("Checking system requirements\u2026"),!await yo(e))return;let r=await ti(e),n=await dr(e,r);if(n===null||r==="developer"&&!await wo(e)||(await kr(e,t,r,n),e.currentState.error))return;if(r==="selfhost"){let a=e.currentState.data.envMethod||"manual";we({setupComplete:!0,setupMethod:a,repoPath:t}),e.updateData("setupMode",r),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia start' to start GAIA."),await e.waitForInput("exit");return}let o=vo(e);if(!await lu(e,t,n,o))return;await Q(1e3);let s=e.currentState.data.envMethod||"manual";we({setupComplete:!0,setupMethod:s,repoPath:t}),e.updateData("setupMode",r),e.setStep("Finished"),e.setStatus("Set up. Run 'gaia dev' to start development mode."),await e.waitForInput("exit")}async function lm(){await ve({command:"setup",whenNonInteractive:"fail",runFlow:cm})}async function um(e,t){e.setStep("Starting"),e.setStatus("Locating GAIA repository\u2026");let r=L();if(!r){e.setError(new Error("Could not find GAIA repository. Run from within a cloned gaia repo."));return}e.updateData("repoPath",r);let n=await $(r);if(!n){e.setError(new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo."));return}if(n==="developer"){e.setError(new Error("Developer mode runs in foreground. Use 'gaia dev' or 'gaia dev full' instead of 'gaia start'."));return}if(n==="selfhost"){e.setStatus("Checking Docker\u2026");let s=await ee();if(s!=="ready"){e.setError(await Dt(s));return}}let o=k(r),i=o[O]??O;e.updateData("setupMode",n),e.updateData("webUrl",mt(r,i)),e.updateData("dockerLogs",[]),e.setStatus("Starting GAIA\u2026");try{await ue(r,n,s=>e.setStatus(s),o,(s,a)=>{e.setStatus(s.label),e.updateData("dockerLogs",a.slice(-$r))},t)}catch(s){e.setError(new Error(`GAIA didn't start. ${s.message}`));return}e.setStep("Running"),e.setStatus("GAIA is running."),e.updateData("started",!0)}async function dm(e){await ve({command:"start",whenNonInteractive:"plain",runFlow:t=>um(t,e),cancelHint:"GAIA may be partly started. Run 'gaia start' again to finish, or 'gaia stop'."})}var pm=8;function Rt(e=""){process.stdout.write(`${e}
|
|
151
|
+
`)}function mm(e){let t=e.currentState.data[xn];return t?{facts:t,report:di(t)}:null}function tE(e){let t=mm(e);if(!t)return;let{facts:r,report:n}=t,o=n.headline.kind==="ok"?y.active:y.fail;Rt(`${o} ${n.headline.text}`),n.headline.url&&Rt(` ${n.headline.url}`),n.hint&&Rt(` ${n.hint}`),n.rows.length>0&&Rt();for(let i of n.rows){let s=i.items.map(c=>`${c.ok?y.ok:y.fail} ${c.name}`).join(" "),a=i.items.length===0?i.note??"":"";Rt(` ${i.label.padEnd(pm)}${s}${a}`.trimEnd()),i.items.length>0&&i.note&&Rt(` ${" ".repeat(pm)}${i.note}`)}r.installed&&(Rt(),Rt(` Installed at ${r.install}`))}async function fm(e={}){await ve({command:"status",whenNonInteractive:"plain",autoResolve:[["exit_or_refresh","exit"]],runFlow:async t=>{await Hp(t,e),mm(t)?.report.unhealthy&&(process.exitCode=1)},onPlainComplete:tE})}async function gm(e,t){e.setStep("Stopping"),e.setStatus("Finding your GAIA install\u2026");let r=L();if(!r){e.setError(new Error("GAIA isn't installed here, so there is nothing to stop."));return}e.updateData("repoPath",r),e.updateData("stopMode",t?.forcePorts?"force-ports":"safe");let n=k(r);try{await so(r,o=>e.setStatus(o),n,t)}catch(o){e.setError(new Error(`GAIA didn't stop. ${o.message}`));return}e.setStep("Stopped"),e.setStatus("GAIA stopped. Start it again with 'gaia start'."),e.updateData("stopped",!0)}async function hm(e){await ve({command:"stop",whenNonInteractive:"plain",runFlow:t=>gm(t,e),cancelHint:"GAIA may still be partly running. Run 'gaia stop' again."})}import*as gi from"fs";import*as hi from"path";function rE(e){let t=hi.join(e,".env");return gi.existsSync(t)?["--env-file",".env"]:[]}async function Sm(){let e=L();if(!e)throw new Error("Could not find GAIA repository. Run from within a cloned gaia repo.");let t=await $(e);if(!t)throw new Error("No .env file found. Run 'gaia init' for fresh setup, or 'gaia setup' to configure an existing repo.");let r=hi.join(e,"infra","docker"),n=rE(r),o=k(e),i=Object.keys(o).length>0?ct(o):void 0;if(t==="selfhost"){await hr("docker",["compose",...dt(ar()),...n,"logs","-f","--tail","200"],r,i);return}let s=["compose",...n,"logs","-f","--tail","200"],a=hi.join(e,dl),c=Yi(e),l=typeof c=="number"&&no(c);if(gi.existsSync(a)&&l){console.log("Streaming app and infrastructure logs\u2026"),process.platform==="win32"?await Lo([{cmd:"powershell",args:["-Command",`Get-Content -Path '${a.replace(/'/g,"''")}' -Wait -Tail 200`],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]):await Lo([{cmd:"tail",args:["-n","200","-f",a],cwd:e},{cmd:"docker",args:s,cwd:r,env:i}]);return}gi.existsSync(a)&&!l?(console.log("Detected stale developer app logs from a previous run. Streaming Docker logs only."),await hr("docker",s,r,i)):(console.log("No active developer process detected. Streaming Docker service logs. Run `gaia dev` in another terminal for live Nx app logs."),await hr("docker",s,r,i))}var nE=16;function Da(e=""){process.stdout.write(`${e}
|
|
152
|
+
`)}function oE(e){let t=e.currentState.data[vn];if(t){Da(),Da(`${y.ok} ${Qo}`);for(let r of Zo(t))Da(` ${r.label.padEnd(nE)}${r.text}`)}}async function vm(e={}){await ve({command:"uninstall",whenNonInteractive:"plain",runFlow:t=>fp(t,e),cancelHint:"GAIA may be partly removed. Run 'gaia uninstall' again to finish.",onPlainComplete:oE})}var iE=16,sE=14;function In(e=""){process.stdout.write(`${e}
|
|
153
|
+
`)}function aE(e){let t=e.currentState.data.upOutcome;if(!t)return;let r=ii(t);In(),In(`${r.tone==="success"?`${y.ok} `:""}${r.headline}`);for(let n of r.rows)In(` ${n.label.padEnd(iE)}${n.text}`);In();for(let[n,o]of oi)In(` ${n.padEnd(sE)}${o}`)}async function ym(e={}){await ve({command:"up",whenNonInteractive:"plain",runFlow:t=>Ap(t,e),cancelHint:"GAIA may be partly set up. Run 'gaia up' again to finish, or 'gaia stop'.",onPlainComplete:aE})}import*as Am from"node:readline";var cE="https://api.github.com/repos/theexperiencecompany/gaia/releases/tags",lE=5e3,uE=5,dE=["Features","Bug Fixes"],pE=/^\* (.+)$/,mE=/^\*\*[^*]+:\*\*\s*/,fE=/(\s*\(\[[^\]]+\]\([^)]+\)\))+$/;function gE(e){let t=e.replace(mE,"").replace(fE,"");return t.charAt(0).toUpperCase()+t.slice(1)}function hE(e){let t=new Map,r="";for(let n of e.split(`
|
|
154
|
+
`)){let o=/^#{2,3} (.+)$/.exec(n.trim());if(o?.[1]){r=o[1];continue}let i=pE.exec(n.trim())?.[1];i&&t.set(r,[...t.get(r)??[],gE(i)])}return dE.flatMap(n=>t.get(n)??[]).slice(0,uE)}async function wm(e){let t=await fetch(`${cE}/${lt(e)}`,{headers:{Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(lE)});if(!t.ok)throw new Error(`GitHub answered HTTP ${t.status}`);let{body:r}=await t.json();return hE(r??"")}import*as bm from"node:fs/promises";import{execa as Si}from"execa";var SE=["apps/web","apps/api","infra/docker"];function Em(e){let{current:t,target:r,explicit:n,gap:o}=e;if(!n){if(ft(t)===null)return{kind:"development-build"};if(!nt(r,t))return{kind:"up-to-date"}}return o?{kind:"unavailable",gap:o}:{kind:"offer",downgrade:nt(t,r)}}async function Oa(e,t){let{stdout:r}=await Si("git",t,{cwd:e});return r.trim()}async function vE(e){let t=await Si("git",["rev-parse","--is-inside-work-tree"],{cwd:e,reject:!1});return t.exitCode!==0||t.stdout.trim()!=="true"?!1:(await Si("git",["remote","get-url","origin"],{cwd:e,reject:!1})).exitCode===0}function yE(e){return e.split(`
|
|
155
|
+
`).map(t=>t.trim()).filter(Boolean)}async function wE(e,t){let r=await Oa(e,["log",t,"--oneline","--",...SE]);return{commits:yE(r)}}async function xm(e,t){lt(t);let r=Ue(e),n=Ki(e),o=n?{kind:"bundle",version:n.version,files:n.files}:{kind:"checkout",files:await cl(e)};return{repoPath:e,fromVersion:r,toVersion:t,layout:o}}function Im(e){return e.fromVersion===e.toVersion&&e.layout.kind==="bundle"&&e.layout.version===e.toVersion}async function Rm(e,t){t.onStatus(`Getting the setup files for GAIA ${e.toVersion}\u2026`);let r=await ro(e.repoPath,e.toVersion,t.onBundleDownload);try{t.onStatus(`Downloading GAIA ${e.toVersion}\u2026`),await gl(e.repoPath,e.toVersion,t.onImagePull)}catch(n){throw await bm.rm(r.stagingDir,{recursive:!0,force:!0}),n}t.onStatus(e.layout.kind==="checkout"?"Moving this install from a git checkout to the release's setup files\u2026":`Switching the setup files to ${e.toVersion}\u2026`),await to(r.manifest,r.stagingDir,e.repoPath,e.layout.files),Kr(e.repoPath,e.toVersion),t.onStatus("Restarting GAIA\u2026"),await ue(e.repoPath,"selfhost",t.onStatus,k(e.repoPath),void 0,{pull:"missing"})}async function Cm(e){if(!await vE(e))throw new Error(`${e} is not a git checkout with an origin remote; run 'gaia update' without --git.`);if((await Si("git",["symbolic-ref","-q","--short","HEAD"],{cwd:e,reject:!1})).exitCode!==0)throw new Error(`${e} is on a release tag, not a branch. Switch to one first: git -C ${e} checkout master`);return await Oa(e,["fetch","origin"]),wE(e,"HEAD..@{upstream}")}async function km(e,t){t("Pulling the latest commits (git pull --ff-only)\u2026"),await Oa(e,["pull","--ff-only"]),t("Rebuilding images from this checkout and restarting\u2026"),await ue(e,"selfhost",t,k(e),void 0,{build:!0})}var bE=5,EE="https://docs.heygaia.io/release-notes";function C(e=""){process.stdout.write(`${pt(e)}
|
|
156
|
+
`)}async function xE(e){let t=Am.createInterface({input:process.stdin,output:process.stdout});t.on("SIGINT",()=>{t.close(),C(`
|
|
157
|
+
${y.cancelled} Cancelled \xB7 nothing changed.`),process.exit(130)});let r=await new Promise(o=>{t.question(`${e} [y/N] `,i=>o(i))});t.close();let n=r.trim().toLowerCase();return n==="y"||n==="yes"}function IE(){let e=process.stdout.isTTY===!0,t=!1;return{show(r){e&&(process.stdout.write(`\r\x1B[K ${r}`),t=!0)},end(){t&&process.stdout.write("\r\x1B[K"),t=!1}}}function RE(){let e=IE(),t=vr(),r=vr();return{onStatus:n=>{e.end(),C(` ${n}`)},onBundleDownload:({received:n,total:o})=>e.show(o===null?`Setup files: ${Re(n)} downloaded`:`Setup files: ${fn({done:n,total:o,unit:"bytes",estimated:!1},{etaMs:t.update(n,o)})}`),onImagePull:n=>{let o=n.amount;e.show(o?`Images: ${fn(o,{percent:n.percent,etaMs:o.unit==="bytes"?r.update(o.done,o.total):null})} \xB7 ${n.detail??""}`:n.detail??n.label)}}}function CE(e,t){let r=t?e.commits:e.commits.slice(0,bE);for(let o of r)C(` ${o}`);let n=e.commits.length-r.length;n>0&&C(` and ${n} more (--verbose lists them)`)}async function kE(e){try{for(let t of await wm(e))C(` - ${t}`)}catch(t){C(` (couldn't read what's new in ${e}: ${t.message})`)}}async function Pm(e,t){return e.yes?!0:he()?xE(`
|
|
158
|
+
${t}`):(C(`
|
|
159
|
+
No terminal to confirm in: rerun with --yes to apply.`),!1)}function AE(e,t){let{fromVersion:r,toVersion:n,layout:o}=e;return r===n&&o.kind==="checkout"?`GAIA ${n} runs from a git checkout. Move it to the release's setup files, so it no longer needs git?`:t?`Switch GAIA ${r} back to ${n}`:`Update available: GAIA ${r} \u2192 ${n}`}async function PE(e,t){let r=Ue(e),n=t.version??je,o=t.version!==void 0,s=o||ft(r)!==null&&nt(n,r)?await or(n,P()?.bots??[]):null,a=Em({current:r,target:n,explicit:o,gap:s});switch(a.kind){case"development-build":C(`This install runs a development build of GAIA (${lo(r)}), not a release, so there is nothing to update.`),C(`To switch it to the ${n} release: gaia update --version ${n}`);return;case"up-to-date":C(`GAIA ${r} is up to date.`);for(let d of Lc(A))C(d);return;case"unavailable":C(`${rr(a.gap,"gaia up --build").cause} Nothing was changed.`),o&&(process.exitCode=1);return;case"offer":break}let c=await xm(e,n);if(Im(c)){C(`GAIA ${r} is up to date.`);return}if(C(`
|
|
160
|
+
${AE(c,a.downgrade)}`),await kE(n),C(`What's new: ${EE}`),C("Your data and settings are kept."),!await Pm(t,"Update and restart now?"))return;let l=RE();await Rm(c,l),c.layout.kind==="checkout"&&C(" This install no longer needs git: it now holds only the release's setup files, beside your settings and data."),C(`
|
|
161
|
+
${y.ok} GAIA is on ${n}.`),C("Run 'gaia doctor' to check that everything is ready.")}async function TE(e,t){let r=await Cm(e);if(r.commits.length===0){C("Already up to date with the upstream branch.");return}C(`
|
|
162
|
+
${r.commits.length} new commit(s) touch the self-host stack:`),CE(r,t.verbose===!0),C("The images are rebuilt from this checkout (slow on small machines)."),await Pm(t,"Pull, rebuild and restart now?")&&(await km(e,n=>C(` ${n}`)),C(`
|
|
163
|
+
Updated and restarted from source.`))}async function Tm(e={}){await Mt({showUpdate:!1});let t=L();if(!t){ye(`GAIA isn't installed here, so there is nothing to update.
|
|
164
|
+
Install it with 'gaia up'.`),process.exitCode=1;return}if(e.git&&e.version){ye(`--version and --git can't be used together.
|
|
165
|
+
--version moves to a published release; --git builds from source. Pick one.`),process.exitCode=1;return}for(let r of eo(process.env,A))C(`${y.warn} ${r}`);C(`Checking for updates in ${F(t)}\u2026`);try{await(e.git?TE(t,e):PE(t,e))}catch(r){C(),ye(`GAIA wasn't updated: ${r.message}
|
|
166
|
+
Your data is untouched. Fix the cause above, then run 'gaia update' again.`),process.exitCode=1}}var _E={"":1,true:1,false:0,0:0,1:1,2:2,3:3},DE=new Set(["truecolor","24bit"]),OE=new Set(["iTerm.app","WezTerm","vscode","ghostty"]),$E="Apple_Terminal",LE=/-256(color)?$|-direct$|-truecolor$|^tmux|^xterm-kitty$|^xterm-ghostty$|^alacritty|^wezterm|^foot|^contour/,ME=/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/;function _m({env:e,isTTY:t,platform:r}){let n=e.FORCE_COLOR;if(n!==void 0){let i=_E[n];if(i===void 0)throw new Error(`FORCE_COLOR=${JSON.stringify(n)} is not one of 0-3, true or false`);return i}let o=e.TERM??"";return e.NO_COLOR||!t||o==="dumb"?0:DE.has(e.COLORTERM??"")?3:e.TERM_PROGRAM===$E?2:OE.has(e.TERM_PROGRAM??"")||r==="win32"&&(e.WT_SESSION||!o)||LE.test(o)?3:ME.test(o)||e.COLORTERM?1:0}NE.level=_m({env:process.env,isTTY:process.stdout.isTTY===!0,platform:process.platform});var GE=new Set(["-V","--version"]),K=new FE,$a="For contributors:",UE=20;K.name("gaia").description("Run GAIA, your proactive personal assistant, on your own computer or server").option("-V, --version","Show the CLI's version").helpOption("-h, --help","Show help for a command").helpCommand("help [command]","Show help for a command").configureHelp({minWidthToWrap:UE}).enablePositionalOptions().addHelpText("after",`
|
|
167
|
+
New here? Run: gaia up`);K.command("up").description(j.up).option("--yes","Answer yes to every question, including installing Docker").addOption(new BE("--llm-provider <provider>","AI provider to save once GAIA is running (checked first, as the setup page does)").choices(pa)).option("--llm-key <key>","API key for --llm-provider (openrouter, gemini, openai, custom)").option("--llm-base-url <url>","Address of --llm-provider ollama (default http://host.docker.internal:11434) or custom").option("--llm-model <model>","Model for --llm-provider ollama (optional) or custom (required)").option("--web-port <port>","Port GAIA is served on (default 3000)",Number.parseInt).option("--domain <domain>","Serve GAIA at https://<domain> with an automatic certificate (uses ports 80 and 443)").option("-b, --build","Build GAIA from source on this machine instead of downloading it (slow)").option("--code-sandbox","Let GAIA run code in containers on this machine (gives it control of Docker; kept on later starts)").option("--no-code-sandbox","Turn that off again (running code then needs an E2B key)").option("--no-start","Set everything up, but don't start GAIA").option("--no-local-name","Don't name GAIA http://gaia.local for other devices on your network (uses port 80 and sudo)").option("--force-dev-tree","Allow 'gaia up' on a development copy of GAIA that isn't your install").action(async e=>{let{start:t,...r}=e;await ym({...r,noStart:t===!1})});K.command("status").description(j.status).option("--watch","Stay open; press r to check again").action(async e=>{await fm({watch:e.watch})});K.command("stop").description(j.stop).option("--force-ports","Also stop whatever else listens on GAIA's ports (may stop other programs)").action(async e=>{await hm({forcePorts:e.forcePorts})});K.command("start").description(j.start).option("-b, --build","Build GAIA from source before starting (slow)").option("--pull","Download GAIA's images again before starting").action(async e=>{await dm({build:e.build,pull:e.pull?"always":void 0})});K.command("update").description(j.update).option("--yes","Update without asking").option("--version <tag>","Move to this GAIA release (v<x.y.z>) instead of the one this CLI installs").option("--git","For development copies: pull the current branch and rebuild from source").option("--verbose","With --git, list every new commit").action(async e=>{await Tm(e)});K.command("doctor").description(j.doctor).action(async()=>{await Pd()});K.command("logs").description(j.logs).action(async()=>{try{await Sm()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}});K.addCommand(sn);K.addCommand(ld);K.addCommand(ot);K.command("backup").description(j.backup).option("--output <dir>","Folder to save the backup in (default: ./backups)").option("--dry-run","Print the commands without running them").action(async e=>{await El({output:e.output,dryRun:e.dryRun})});K.command("restore").description(j.restore).option("--mongo <file>","MongoDB archive file (mongodump --archive)").option("--postgres <file>","PostgreSQL dump file").option("--env <file>","The backup's apps/api/.env (api-env-<stamp>.env): its INSTANCE_SECRET decrypts the saved keys").option("--from <dir>","Restore everything from a backup folder (its newest backup)").option("--dry-run","Print the commands without running them").action(async e=>{await am({mongo:e.mongo,postgres:e.postgres,env:e.env,from:e.from,dryRun:e.dryRun})});K.command("uninstall").description(j.uninstall).option("--yes","Don't ask: uninstall and keep your data (add --delete-data to delete it)").option("--delete-data","Delete your data too: accounts, chats, memories and files (can't be undone)").action(async e=>{await vm(e)});K.command("init").helpGroup($a).description(j.init).option("--branch <branch>","Git branch to clone").action(async e=>{await om({branch:e.branch})});K.command("setup").helpGroup($a).description(j.setup).action(async()=>{await lm()});K.command("dev [profile]").helpGroup($a).description(j.dev).action(async e=>{try{await dd(e)}catch(t){console.error(t instanceof Error?t.message:String(t)),process.exit(1)}});GE.has(process.argv[2]??"")&&(await Ul(),process.exit(0));process.argv.slice(2).length||(K.outputHelp(),process.exit(0));await xc();K.parse();
|